This is an automated email from the ASF dual-hosted git repository.

adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git


The following commit(s) were added to refs/heads/develop by this push:
     new ee31ff0ed FINERACT-1911: Alter datatable - column update, delete fix
ee31ff0ed is described below

commit ee31ff0ed8ab82932e6882af6ba0aaff45e5f57a
Author: jmarta <[email protected]>
AuthorDate: Sat Aug 19 01:26:28 2023 +0200

    FINERACT-1911: Alter datatable - column update, delete fix
---
 .../core/service/database/JdbcJavaType.java        |   6 +-
 .../service/database/PostgreSQLQueryService.java   |   6 +-
 .../service/ReadWriteNonCoreDataServiceImpl.java   | 360 ++++++++++-----------
 .../common/system/DatatableHelper.java             |   5 +-
 .../datatable/DatatableIntegrationTest.java        |  64 +++-
 .../DatatableUniqueAndIndexColumnTest.java         |   1 +
 6 files changed, 236 insertions(+), 206 deletions(-)

diff --git 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/JdbcJavaType.java
 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/JdbcJavaType.java
index 76bb960ee..ebfbade9d 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/JdbcJavaType.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/JdbcJavaType.java
@@ -78,12 +78,12 @@ public enum JdbcJavaType {
     // seconds field, but by default, there is no explicit bound on precision
     TIME(JavaType.LOCAL_TIME, new DialectType(JDBCType.TIME), new 
DialectType(JDBCType.TIME, null, "TIME WITHOUT TIME ZONE")), //
     TIME_WITH_TIMEZONE(JavaType.OFFSET_TIME, new 
DialectType(JDBCType.TIME_WITH_TIMEZONE, "TIME"),
-            new DialectType(JDBCType.TIME_WITH_TIMEZONE, null, "TIME WITH TIME 
ZONE")), //
+            new DialectType(JDBCType.TIME_WITH_TIMEZONE, "TIME WITH TIME 
ZONE")), //
     TIMESTAMP(JavaType.LOCAL_DATETIME, new DialectType(JDBCType.TIMESTAMP),
             new DialectType(JDBCType.TIMESTAMP, null, "TIMESTAMP WITHOUT TIME 
ZONE")), //
     DATETIME(JavaType.LOCAL_DATETIME, new DialectType(JDBCType.TIMESTAMP, 
"DATETIME"), new DialectType(JDBCType.TIMESTAMP)), //
-    TIMESTAMP_WITH_TIMEZONE(JavaType.OFFSET_DATETIME, new 
DialectType(JDBCType.TIMESTAMP_WITH_TIMEZONE, null, "DATETIME"),
-            new DialectType(JDBCType.TIMESTAMP_WITH_TIMEZONE, null, "TIMESTAMP 
WITH TIME ZONE", "TIMESTAMPTZ")), //
+    TIMESTAMP_WITH_TIMEZONE(JavaType.OFFSET_DATETIME, new 
DialectType(JDBCType.TIMESTAMP_WITH_TIMEZONE, "DATETIME"),
+            new DialectType(JDBCType.TIMESTAMP_WITH_TIMEZONE, "TIMESTAMP WITH 
TIME ZONE", "TIMESTAMPTZ")), //
     INTERVAL(JavaType.TIME, new DialectType(JDBCType.TIME), new 
DialectType(JDBCType.TIME, "INTERVAL")), //
     BINARY(JavaType.BINARY, new DialectType(JDBCType.BINARY, true), new 
DialectType(JDBCType.BINARY, "BYTEA")), //
     VARBINARY(JavaType.BINARY, new DialectType(JDBCType.VARBINARY, true), new 
DialectType(JDBCType.VARBINARY, "BYTEA")), //
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/PostgreSQLQueryService.java
 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/PostgreSQLQueryService.java
index 9ab2b5b05..db611f421 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/PostgreSQLQueryService.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/PostgreSQLQueryService.java
@@ -54,8 +54,10 @@ public class PostgreSQLQueryService implements 
DatabaseQueryService {
     @Override
     public SqlRowSet getTableColumns(DataSource dataSource, String tableName) {
         JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
-        String sql = "SELECT attname AS COLUMN_NAME, not attnotnull AS 
IS_NULLABLE, atttypid::regtype  AS DATATYPE, attlen AS 
CHARACTER_MAXIMUM_LENGTH, attnum = 1 AS COLUMN_KEY FROM pg_attribute WHERE 
attrelid = '\""
-                + tableName + "\"'::regclass AND attnum > 0 AND NOT 
attisdropped ORDER BY attnum";
+        String sql = "SELECT column_name, is_nullable, data_type,"
+                + " coalesce(character_maximum_length, numeric_precision, 
datetime_precision) AS max_length, ordinal_position = 1 AS column_key"
+                + " FROM information_schema.columns WHERE table_catalog = 
current_catalog AND table_schema = current_schema AND table_name = '"
+                + tableName + "' ORDER BY ordinal_position";
         final SqlRowSet columnDefinitions = jdbcTemplate.queryForRowSet(sql); 
// NOSONAR
         if (columnDefinitions.next()) {
             return columnDefinitions;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java
index d62d3090f..000433a52 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java
@@ -520,7 +520,6 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
     }
 
     private String datatableColumnNameToCodeValueName(final String columnName, 
final String code) {
-
         return code + "_cd_" + columnName;
     }
 
@@ -537,17 +536,17 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
         String name = column.has(API_FIELD_NAME) ? 
column.get(API_FIELD_NAME).getAsString() : null;
         final String type = column.has(API_FIELD_TYPE) ? 
column.get(API_FIELD_TYPE).getAsString().toLowerCase() : null;
         final Integer length = column.has(API_FIELD_LENGTH) ? 
column.get(API_FIELD_LENGTH).getAsInt() : null;
-        final Boolean mandatory = column.has(API_FIELD_MANDATORY) ? 
column.get(API_FIELD_MANDATORY).getAsBoolean() : false;
-        final Boolean unique = column.has(API_FIELD_UNIQUE) ? 
column.get(API_FIELD_UNIQUE).getAsBoolean() : false;
+        final boolean mandatory = column.has(API_FIELD_MANDATORY) && 
column.get(API_FIELD_MANDATORY).getAsBoolean();
+        final boolean unique = column.has(API_FIELD_UNIQUE) && 
column.get(API_FIELD_UNIQUE).getAsBoolean();
         final String code = column.has(API_FIELD_CODE) ? 
column.get(API_FIELD_CODE).getAsString() : null;
 
         if (StringUtils.isNotBlank(code)) {
             if (isConstraintApproach) {
                 codeMappings.put(dataTableNameAlias + "_" + name, 
this.codeReadPlatformService.retriveCode(code).getId());
                 String fkName = "fk_" + dataTableNameAlias + "_" + name;
-                constrainBuilder.append(", CONSTRAINT 
").append(sqlGenerator.escape(fkName)).append(" ")
-                        .append("FOREIGN KEY (" + sqlGenerator.escape(name) + 
") ").append("REFERENCES ")
-                        
.append(sqlGenerator.escape(CODE_VALUES_TABLE)).append(" (id)");
+                constrainBuilder.append(", CONSTRAINT 
").append(sqlGenerator.escape(fkName)).append(" ").append("FOREIGN KEY (")
+                        .append(sqlGenerator.escape(name)).append(") 
").append("REFERENCES ").append(sqlGenerator.escape(CODE_VALUES_TABLE))
+                        .append(" (id)");
             } else {
                 name = datatableColumnNameToCodeValueName(name, code);
             }
@@ -602,7 +601,7 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
             final String dataTableNameAlias = 
datatableName.toLowerCase().replaceAll("\\s", "_");
             final String fkName = dataTableNameAlias + "_" + fkColumnName;
             StringBuilder sqlBuilder = new StringBuilder();
-            sqlBuilder.append("CREATE TABLE " + 
sqlGenerator.escape(datatableName) + " (");
+            sqlBuilder.append("CREATE TABLE 
").append(sqlGenerator.escape(datatableName)).append(" (");
 
             if (multiRow) {
                 if (databaseTypeResolver.isMySQL()) {
@@ -614,7 +613,7 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
                     throw new IllegalStateException("Current database is not 
supported");
                 }
             }
-            sqlBuilder.append(sqlGenerator.escape(fkColumnName) + " BIGINT NOT 
NULL, ");
+            sqlBuilder.append(sqlGenerator.escape(fkColumnName)).append(" 
BIGINT NOT NULL, ");
 
             // Add Created At and Updated At
             columns.add(addColumn(DataTableApiConstant.CREATEDAT_FIELD_NAME, 
DATETIME, false, null, false, false));
@@ -628,25 +627,23 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
             }
 
             // Remove trailing comma and space
-            sqlBuilder = sqlBuilder.delete(sqlBuilder.length() - 2, 
sqlBuilder.length());
+            sqlBuilder.delete(sqlBuilder.length() - 2, sqlBuilder.length());
 
             String fullFkName = "fk_" + fkName;
             if (multiRow) {
                 sqlBuilder.append(", PRIMARY KEY 
(").append(TABLE_FIELD_ID).append(")");
                 if (databaseTypeResolver.isMySQL()) {
-                    sqlBuilder
-                            .append(", KEY " + sqlGenerator.escape("fk_" + 
fkColumnName) + " (" + sqlGenerator.escape(fkColumnName) + ")");
+                    sqlBuilder.append(", KEY 
").append(sqlGenerator.escape("fk_" + fkColumnName)).append(" (")
+                            
.append(sqlGenerator.escape(fkColumnName)).append(")");
                 }
-                sqlBuilder.append(", CONSTRAINT " + 
sqlGenerator.escape(fullFkName) + " ")
-                        .append("FOREIGN KEY (" + 
sqlGenerator.escape(fkColumnName) + ") ")
-                        .append("REFERENCES " + 
sqlGenerator.escape(entityTable.getApptableName()) + " 
(").append(TABLE_FIELD_ID)
-                        .append(")");
+                sqlBuilder.append(", CONSTRAINT 
").append(sqlGenerator.escape(fullFkName)).append(" FOREIGN KEY (")
+                        .append(sqlGenerator.escape(fkColumnName)).append(") 
").append("REFERENCES ")
+                        
.append(sqlGenerator.escape(entityTable.getApptableName())).append(" 
(").append(TABLE_FIELD_ID).append(")");
             } else {
-                sqlBuilder.append(", PRIMARY KEY (" + 
sqlGenerator.escape(fkColumnName) + ")")
-                        .append(", CONSTRAINT " + 
sqlGenerator.escape(fullFkName) + " ")
-                        .append("FOREIGN KEY (" + 
sqlGenerator.escape(fkColumnName) + ") ")
-                        .append("REFERENCES " + 
sqlGenerator.escape(entityTable.getApptableName()) + " 
(").append(TABLE_FIELD_ID)
-                        .append(")");
+                sqlBuilder.append(", PRIMARY KEY 
(").append(sqlGenerator.escape(fkColumnName)).append(")").append(", CONSTRAINT 
")
+                        .append(sqlGenerator.escape(fullFkName)).append(" 
FOREIGN KEY (").append(sqlGenerator.escape(fkColumnName))
+                        .append(") ").append("REFERENCES 
").append(sqlGenerator.escape(entityTable.getApptableName())).append(" (")
+                        .append(TABLE_FIELD_ID).append(")");
             }
 
             sqlBuilder.append(constrainBuilder);
@@ -661,12 +658,10 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
             // create indexes
             if (multiRow) {
                 createFkIndex(datatableName, fkColumnName);
-            } else {
-                /*
-                 * in case of non-multirow, the primary key of the table is 
the FK and MySQL and PostgreSQL
-                 * automatically puts an index onto it so no need to create it 
explicitly
-                 */
             }
+            // in case of non-multirow, the primary key of the table is the FK 
and MySQL and PostgreSQL
+            // automatically puts an index onto it so no need to create it 
explicitly
+
             createIndexesForTable(datatableName, columns);
             registerDatatable(datatableName, entityName, entitySubType);
             registerColumnCodeMapping(codeMappings);
@@ -705,13 +700,11 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
 
     private void createIndexForColumn(String datatableName, JsonObject column) 
{
         String name = column.has(API_FIELD_NAME) ? 
column.get(API_FIELD_NAME).getAsString() : null;
-        final Boolean unique = column.has(API_FIELD_UNIQUE) ? 
column.get(API_FIELD_UNIQUE).getAsBoolean() : false;
-        final Boolean indexed = column.has(API_FIELD_INDEXED) ? 
column.get(API_FIELD_INDEXED).getAsBoolean() : false;
-        if (indexed) {
-            if (!unique) {
-                String indexName = 
datatableKeywordGenerator.generateIndexName(datatableName, name);
-                createIndex(indexName, datatableName, name);
-            }
+        final boolean unique = column.has(API_FIELD_UNIQUE) && 
column.get(API_FIELD_UNIQUE).getAsBoolean();
+        final boolean indexed = column.has(API_FIELD_INDEXED) && 
column.get(API_FIELD_INDEXED).getAsBoolean();
+        if (!unique && indexed) {
+            String indexName = 
datatableKeywordGenerator.generateIndexName(datatableName, name);
+            createIndex(indexName, datatableName, name);
         }
     }
 
@@ -719,7 +712,7 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
         KeyHolder keyHolder = new GeneratedKeyHolder();
         int insertsCount = this.jdbcTemplate.update(c -> 
c.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS), keyHolder);
         if (insertsCount == 1) {
-            Number assignedKey = null;
+            Number assignedKey;
             if (keyHolder.getKeys().size() > 1) {
                 assignedKey = (Long) keyHolder.getKeys().get(TABLE_FIELD_ID);
             } else {
@@ -734,48 +727,52 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
     }
 
     private void parseDatatableColumnForUpdate(final JsonObject column,
-            final Map<String, ResultsetColumnHeaderData> 
mapColumnNameDefinition, StringBuilder sqlBuilder, final String datatableName,
-            final StringBuilder constrainBuilder, final Map<String, Long> 
codeMappings, final List<String> removeMappings,
-            final boolean isConstraintApproach) {
-        String name = column.has(API_FIELD_NAME) ? 
column.get(API_FIELD_NAME).getAsString() : null;
+            final Map<String, ResultsetColumnHeaderData> 
mapColumnNameDefinition, final String datatableName, StringBuilder 
renameBuilder,
+            StringBuilder changeBuilder, final StringBuilder constrainBuilder, 
final Map<String, Long> codeMappings,
+            final List<String> removeMappings, final boolean 
isConstraintApproach) {
+        String oldName = column.has(API_FIELD_NAME) ? 
column.get(API_FIELD_NAME).getAsString() : null;
+        if (!mapColumnNameDefinition.containsKey(oldName)) {
+            throw new 
PlatformDataIntegrityException("error.msg.datatable.column.missing.update.parse",
+                    "Column " + oldName + " does not exist.", oldName);
+        }
         final String lengthStr = column.has(API_FIELD_LENGTH) ? 
column.get(API_FIELD_LENGTH).getAsString() : null;
-        Integer length = StringUtils.isNotBlank(lengthStr) ? 
Integer.parseInt(lengthStr) : null;
-        String newName = column.has(API_FIELD_NEWNAME) ? 
column.get(API_FIELD_NEWNAME).getAsString() : name;
-        final Boolean mandatory = column.has(API_FIELD_MANDATORY) ? 
column.get(API_FIELD_MANDATORY).getAsBoolean() : false;
+        Long length = StringUtils.isNotBlank(lengthStr) ? 
Long.parseLong(lengthStr) : null;
+        String newName = column.has(API_FIELD_NEWNAME) ? 
column.get(API_FIELD_NEWNAME).getAsString() : null;
+        final Boolean newMandatory = column.has(API_FIELD_MANDATORY) ? 
column.get(API_FIELD_MANDATORY).getAsBoolean() : null;
         final String after = column.has(API_FIELD_AFTER) ? 
column.get(API_FIELD_AFTER).getAsString() : null;
         final String code = column.has(API_FIELD_CODE) ? 
column.get(API_FIELD_CODE).getAsString() : null;
         final String newCode = column.has(API_FIELD_NEWCODE) ? 
column.get(API_FIELD_NEWCODE).getAsString() : null;
         final String dataTableNameAlias = 
datatableName.toLowerCase().replaceAll("\\s", "_");
         if (isConstraintApproach) {
             if (StringUtils.isBlank(newName)) {
-                newName = name;
+                newName = oldName;
             }
-            String fkName = "fk_" + dataTableNameAlias + "_" + name;
+            String fkName = "fk_" + dataTableNameAlias + "_" + oldName;
             String newFkName = "fk_" + dataTableNameAlias + "_" + newName;
-            if (!StringUtils.equalsIgnoreCase(code, newCode) || 
!StringUtils.equalsIgnoreCase(name, newName)) {
+            if (!StringUtils.equalsIgnoreCase(code, newCode) || 
!StringUtils.equalsIgnoreCase(oldName, newName)) {
                 if (StringUtils.equalsIgnoreCase(code, newCode)) {
-                    final int codeId = getCodeIdForColumn(dataTableNameAlias, 
name);
+                    final int codeId = getCodeIdForColumn(dataTableNameAlias, 
oldName);
                     if (codeId > 0) {
-                        removeMappings.add(dataTableNameAlias + "_" + name);
-                        constrainBuilder.append(", DROP FOREIGN KEY 
").append(sqlGenerator.escape(fkName)).append(" ");
+                        removeMappings.add(dataTableNameAlias + "_" + oldName);
+                        constrainBuilder.append(", DROP CONSTRAINT 
").append(sqlGenerator.escape(fkName)).append(" ");
                         codeMappings.put(dataTableNameAlias + "_" + newName, 
(long) codeId);
-                        constrainBuilder.append(",ADD CONSTRAINT 
").append(sqlGenerator.escape(newFkName)).append(" ")
-                                .append("FOREIGN KEY (" + 
sqlGenerator.escape(newName) + ") ").append("REFERENCES ")
+                        constrainBuilder.append(", ADD CONSTRAINT 
").append(sqlGenerator.escape(newFkName)).append(" ")
+                                .append("FOREIGN KEY 
(").append(sqlGenerator.escape(newName)).append(") ").append("REFERENCES ")
                                 
.append(sqlGenerator.escape(CODE_VALUES_TABLE)).append(" 
(").append(TABLE_FIELD_ID).append(")");
                     }
 
                 } else {
                     if (code != null) {
-                        removeMappings.add(dataTableNameAlias + "_" + name);
-                        if (newCode == null || 
!StringUtils.equalsIgnoreCase(name, newName)) {
-                            constrainBuilder.append(", DROP FOREIGN KEY 
").append(sqlGenerator.escape(fkName)).append(" ");
+                        removeMappings.add(dataTableNameAlias + "_" + oldName);
+                        if (newCode == null || 
!StringUtils.equalsIgnoreCase(oldName, newName)) {
+                            constrainBuilder.append(", DROP CONSTRAINT 
").append(sqlGenerator.escape(fkName)).append(" ");
                         }
                     }
                     if (newCode != null) {
                         codeMappings.put(dataTableNameAlias + "_" + newName, 
this.codeReadPlatformService.retriveCode(newCode).getId());
-                        if (code == null || 
!StringUtils.equalsIgnoreCase(name, newName)) {
-                            constrainBuilder.append(",ADD CONSTRAINT  
").append(sqlGenerator.escape(newFkName)).append(" ")
-                                    .append("FOREIGN KEY (" + 
sqlGenerator.escape(newName) + ") ").append("REFERENCES ")
+                        if (code == null || 
!StringUtils.equalsIgnoreCase(oldName, newName)) {
+                            constrainBuilder.append(", ADD CONSTRAINT  
").append(sqlGenerator.escape(newFkName)).append(" ")
+                                    .append("FOREIGN KEY 
(").append(sqlGenerator.escape(newName)).append(") ").append("REFERENCES ")
                                     
.append(sqlGenerator.escape(CODE_VALUES_TABLE)).append(" 
(").append(TABLE_FIELD_ID).append(")");
                         }
                     }
@@ -783,7 +780,7 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
             }
         } else {
             if (StringUtils.isNotBlank(code)) {
-                name = datatableColumnNameToCodeValueName(name, code);
+                oldName = datatableColumnNameToCodeValueName(oldName, code);
                 if (StringUtils.isNotBlank(newCode)) {
                     newName = datatableColumnNameToCodeValueName(newName, 
newCode);
                 } else {
@@ -791,38 +788,45 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
                 }
             }
         }
-        if (!mapColumnNameDefinition.containsKey(name)) {
-            throw new 
PlatformDataIntegrityException("error.msg.datatable.column.missing.update.parse",
-                    "Column " + name + " does not exist.", name);
-        }
-        final JdbcJavaType type = 
mapColumnNameDefinition.get(name).getColumnType();
         DatabaseType dialect = databaseTypeResolver.databaseType();
-        if (length == null && type.hasPrecision(dialect)) {
-            Long columnLength = 
mapColumnNameDefinition.get(name).getColumnLength();
-            length = columnLength == null ? null : columnLength.intValue();
-        }
-
-        if (databaseTypeResolver.isMySQL()) {
-            sqlBuilder.append(", CHANGE 
").append(sqlGenerator.escape(name)).append(" 
").append(sqlGenerator.escape(newName)).append(" ")
-                    .append(type);
-        } else if (databaseTypeResolver.isPostgreSQL()) {
-            sqlBuilder.append(", RENAME 
").append(sqlGenerator.escape(name)).append(" TO 
").append(sqlGenerator.escape(newName));
-        }
-        if (length != null && length > 0) {
+        ResultsetColumnHeaderData columnHeader = 
mapColumnNameDefinition.get(oldName);
+        final JdbcJavaType type = columnHeader.getColumnType();
+        boolean nameChanged = !StringUtils.isBlank(newName) && 
!newName.equals(oldName);
+        boolean lengthChanged = length != null && 
!length.equals(columnHeader.getColumnLength()) && type.hasPrecision(dialect);
+        boolean nullityChanged = newMandatory != null && newMandatory != 
columnHeader.isMandatory();
+        boolean afterChanged = after != null && databaseTypeResolver.isMySQL();
+        if (nameChanged || lengthChanged || nullityChanged || afterChanged) {
+            Integer precision = length == null ? null : length.intValue();
+            Integer scale = null;
             if (type.isDecimalType()) {
-                sqlBuilder.append(" ").append(type.formatSql(dialect, 19, 6));
+                precision = 19;
+                scale = 6;
+            }
+            String colName = StringUtils.isBlank(newName) ? oldName : newName;
+            boolean mandatory = newMandatory == null ? 
columnHeader.isMandatory() : newMandatory;
+            if (databaseTypeResolver.isMySQL()) {
+                String modifySql = nameChanged ? ("CHANGE " + 
sqlGenerator.escape(oldName) + " " + sqlGenerator.escape(colName))
+                        : (" MODIFY " + sqlGenerator.escape(colName));
+                changeBuilder.append(", ").append(modifySql).append(" 
").append(type.formatSql(dialect, precision, scale))
+                        .append(mandatory ? " NOT NULL" : " DEFAULT NULL");
+                if (after != null) {
+                    changeBuilder.append(" AFTER 
").append(sqlGenerator.escape(after));
+                }
             } else {
-                sqlBuilder.append(" ").append(type.formatSql(dialect, length));
+                if (nameChanged) {
+                    renameBuilder.append("ALTER TABLE 
").append(sqlGenerator.escape(datatableName)).append(" RENAME COLUMN ")
+                            .append(sqlGenerator.escape(oldName)).append(" TO 
").append(sqlGenerator.escape(newName)).append("; ");
+                }
+                if (lengthChanged) {
+                    changeBuilder.append(", ALTER 
").append(sqlGenerator.escape(colName)).append(" type ")
+                            .append(type.formatSql(dialect, precision, scale));
+                }
+                if (nullityChanged) {
+                    changeBuilder.append(", ALTER 
").append(sqlGenerator.escape(colName))
+                            .append(mandatory ? " set not null" : " drop not 
null");
+                }
             }
         }
-
-        if (databaseTypeResolver.isMySQL()) {
-            sqlBuilder.append(mandatory ? " NOT NULL" : " DEFAULT NULL");
-        }
-
-        if (after != null) {
-            sqlBuilder.append(" AFTER " + sqlGenerator.escape(after));
-        }
     }
 
     private int getCodeIdForColumn(final String dataTableNameAlias, final 
String name) {
@@ -844,8 +848,8 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
         String name = column.has(API_FIELD_NAME) ? 
column.get(API_FIELD_NAME).getAsString() : null;
         final String type = column.has(API_FIELD_TYPE) ? 
column.get(API_FIELD_TYPE).getAsString().toLowerCase() : null;
         final Integer length = column.has(API_FIELD_LENGTH) ? 
column.get(API_FIELD_LENGTH).getAsInt() : null;
-        final Boolean mandatory = column.has(API_FIELD_MANDATORY) ? 
column.get(API_FIELD_MANDATORY).getAsBoolean() : false;
-        final Boolean unique = column.has(API_FIELD_UNIQUE) ? 
column.get(API_FIELD_UNIQUE).getAsBoolean() : false;
+        final boolean mandatory = column.has(API_FIELD_MANDATORY) && 
column.get(API_FIELD_MANDATORY).getAsBoolean();
+        final boolean unique = column.has(API_FIELD_UNIQUE) && 
column.get(API_FIELD_UNIQUE).getAsBoolean();
         final String after = column.has(API_FIELD_AFTER) ? 
column.get(API_FIELD_AFTER).getAsString() : null;
         final String code = column.has(API_FIELD_CODE) ? 
column.get(API_FIELD_CODE).getAsString() : null;
 
@@ -853,9 +857,9 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
             if (isConstraintApproach) {
                 String fkName = "fk_" + dataTableNameAlias + "_" + name;
                 codeMappings.put(dataTableNameAlias + "_" + name, 
this.codeReadPlatformService.retriveCode(code).getId());
-                constrainBuilder.append(",ADD CONSTRAINT  
").append(sqlGenerator.escape(fkName)).append(" ")
-                        .append("FOREIGN KEY (" + sqlGenerator.escape(name) + 
") ").append("REFERENCES ")
-                        
.append(sqlGenerator.escape(CODE_VALUES_TABLE)).append(" 
(").append(TABLE_FIELD_ID).append(")");
+                constrainBuilder.append(",ADD CONSTRAINT  
").append(sqlGenerator.escape(fkName)).append(" ").append("FOREIGN KEY (")
+                        .append(sqlGenerator.escape(name)).append(") 
").append("REFERENCES ").append(sqlGenerator.escape(CODE_VALUES_TABLE))
+                        .append(" (").append(TABLE_FIELD_ID).append(")");
             } else {
                 name = datatableColumnNameToCodeValueName(name, code);
             }
@@ -864,8 +868,8 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
 
         if (unique) {
             String uniqueKeyName = 
datatableKeywordGenerator.generateUniqueKeyName(dataTableNameAlias, name);
-            constrainBuilder.append(",ADD CONSTRAINT  
").append(sqlGenerator.escape(uniqueKeyName)).append(" ")
-                    .append("UNIQUE (" + sqlGenerator.escape(name) + ")");
+            constrainBuilder.append(",ADD CONSTRAINT  
").append(sqlGenerator.escape(uniqueKeyName)).append(" ").append("UNIQUE (")
+                    .append(sqlGenerator.escape(name)).append(")");
         }
 
         if (mandatory) {
@@ -875,7 +879,7 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
         }
 
         if (after != null) {
-            sqlBuilder.append(" AFTER " + sqlGenerator.escape(after));
+            sqlBuilder.append(" AFTER ").append(sqlGenerator.escape(after));
         }
     }
 
@@ -883,14 +887,20 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
             final StringBuilder constrainBuilder, final List<String> 
codeMappings) {
         final String datatableAlias = 
datatableName.toLowerCase().replaceAll("\\s", "_");
         final String name = column.has(API_FIELD_NAME) ? 
column.get(API_FIELD_NAME).getAsString() : null;
-        final StringBuilder findFKSql = new StringBuilder();
-        findFKSql.append("SELECT count(*)").append("FROM 
information_schema.TABLE_CONSTRAINTS i")
-                .append(" WHERE i.CONSTRAINT_TYPE = 'FOREIGN KEY'").append(" 
AND i.TABLE_SCHEMA = DATABASE()")
-                .append(" AND i.TABLE_NAME = 
'").append(datatableName).append("' AND i.CONSTRAINT_NAME = 
'fk_").append(datatableAlias)
-                .append("_").append(name).append("' ");
-        final int count = 
this.jdbcTemplate.queryForObject(findFKSql.toString(), Integer.class);
+        if (name == null) {
+            throw new 
GeneralPlatformDomainRuleException("error.msg.missing.datatable.column.name",
+                    "Datatable column name to drop is missing.");
+        }
+        sqlBuilder.append(", DROP COLUMN 
").append(sqlGenerator.escape(name)).append(" ");
+
+        String fkName = "fk_" + datatableAlias + "_" + name;
+        String schemaSql = databaseTypeResolver.isMySQL() ? "i.TABLE_SCHEMA = 
SCHEMA()"
+                : "i.table_catalog = current_catalog AND i.table_schema = 
current_schema";
+        String findFKSql = "SELECT count(*) FROM 
information_schema.TABLE_CONSTRAINTS i" + " WHERE i.CONSTRAINT_TYPE = 'FOREIGN 
KEY' AND "
+                + schemaSql + " AND i.TABLE_NAME = '" + datatableName + "' AND 
i.CONSTRAINT_NAME = '" + fkName + "' ";
+
+        final int count = this.jdbcTemplate.queryForObject(findFKSql, 
Integer.class);
         if (count > 0) {
-            String fkName = "fk_" + datatableAlias + "_" + name;
             codeMappings.add(datatableAlias + "_" + name);
             constrainBuilder.append(", DROP FOREIGN KEY 
").append(sqlGenerator.escape(fkName)).append(" ");
         }
@@ -985,25 +995,22 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
                     String fullNewFk = "fk_" + newFKName;
                     String fullNewConstraint = "fk_" + newConstraintName;
                     if (mapColumnNameDefinition.containsKey(TABLE_FIELD_ID)) {
-                        sqlBuilder.append("ALTER TABLE " + 
sqlGenerator.escape(datatableName) + " ")
-                                .append("DROP KEY " + 
sqlGenerator.escape(fullOldFk) + ",")
-                                .append("DROP FOREIGN KEY " + 
sqlGenerator.escape(fullOldConstraint) + ",")
-                                .append("CHANGE COLUMN " + 
sqlGenerator.escape(oldFKName) + " " + sqlGenerator.escape(newFKName)
-                                        + " BIGINT NOT NULL,")
-                                .append("ADD KEY " + 
sqlGenerator.escape(fullNewFk) + " (" + sqlGenerator.escape(newFKName) + "),")
-                                .append("ADD CONSTRAINT " + 
sqlGenerator.escape(fullNewConstraint) + " ")
-                                .append("FOREIGN KEY (" + 
sqlGenerator.escape(newFKName) + ") ")
-                                .append("REFERENCES " + 
sqlGenerator.escape(entityTable.getApptableName()) + " 
(").append(TABLE_FIELD_ID)
-                                .append(")");
+                        sqlBuilder.append("ALTER TABLE 
").append(sqlGenerator.escape(datatableName)).append(" DROP KEY ")
+                                
.append(sqlGenerator.escape(fullOldFk)).append(",").append("DROP FOREIGN KEY ")
+                                
.append(sqlGenerator.escape(fullOldConstraint)).append(",").append("CHANGE 
COLUMN ")
+                                
.append(sqlGenerator.escape(oldFKName)).append(" 
").append(sqlGenerator.escape(newFKName))
+                                .append(" BIGINT NOT NULL,").append("ADD KEY 
").append(sqlGenerator.escape(fullNewFk)).append(" (")
+                                
.append(sqlGenerator.escape(newFKName)).append("),").append("ADD CONSTRAINT ")
+                                
.append(sqlGenerator.escape(fullNewConstraint)).append(" FOREIGN KEY (")
+                                
.append(sqlGenerator.escape(newFKName)).append(") ").append("REFERENCES ")
+                                
.append(sqlGenerator.escape(entityTable.getApptableName())).append(" 
(").append(TABLE_FIELD_ID).append(")");
                     } else {
-                        sqlBuilder.append("ALTER TABLE " + 
sqlGenerator.escape(datatableName) + " ")
-                                .append("DROP FOREIGN KEY " + 
sqlGenerator.escape(fullOldConstraint) + ",")
-                                .append("CHANGE COLUMN " + 
sqlGenerator.escape(oldFKName) + " " + sqlGenerator.escape(newFKName)
-                                        + " BIGINT NOT NULL,")
-                                .append("ADD CONSTRAINT " + 
sqlGenerator.escape(fullNewConstraint) + " ")
-                                .append("FOREIGN KEY (" + 
sqlGenerator.escape(newFKName) + ") ")
-                                .append("REFERENCES " + 
sqlGenerator.escape(entityTable.getApptableName()) + " 
(").append(TABLE_FIELD_ID)
-                                .append(")");
+                        sqlBuilder.append("ALTER TABLE 
").append(sqlGenerator.escape(datatableName)).append(" DROP FOREIGN KEY ")
+                                
.append(sqlGenerator.escape(fullOldConstraint)).append(",").append("CHANGE 
COLUMN ")
+                                
.append(sqlGenerator.escape(oldFKName)).append(" 
").append(sqlGenerator.escape(newFKName))
+                                .append(" BIGINT NOT NULL,").append("ADD 
CONSTRAINT ").append(sqlGenerator.escape(fullNewConstraint))
+                                .append(" FOREIGN KEY 
(").append(sqlGenerator.escape(newFKName)).append(") ").append("REFERENCES ")
+                                
.append(sqlGenerator.escape(entityTable.getApptableName())).append(" 
(").append(TABLE_FIELD_ID).append(")");
                     }
 
                     this.jdbcTemplate.execute(sqlBuilder.toString());
@@ -1032,14 +1039,13 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
                 // Remove the first comma, right after ALTER TABLE datatable
                 final int indexOfFirstComma = sqlBuilder.indexOf(",");
                 if (indexOfFirstComma != -1) {
-                    sqlBuilder = sqlBuilder.deleteCharAt(indexOfFirstComma);
+                    sqlBuilder.deleteCharAt(indexOfFirstComma);
                 }
                 sqlBuilder.append(constrainBuilder);
                 this.jdbcTemplate.execute(sqlBuilder.toString());
                 deleteColumnCodeMapping(codeMappings);
             }
             if (addColumns != null) {
-
                 StringBuilder sqlBuilder = new StringBuilder("ALTER TABLE " + 
sqlGenerator.escape(datatableName));
                 final StringBuilder constrainBuilder = new StringBuilder();
                 final Map<String, Long> codeMappings = new HashMap<>();
@@ -1056,7 +1062,7 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
                 // Remove the first comma, right after ALTER TABLE datatable
                 final int indexOfFirstComma = sqlBuilder.indexOf(",");
                 if (indexOfFirstComma != -1) {
-                    sqlBuilder = sqlBuilder.deleteCharAt(indexOfFirstComma);
+                    sqlBuilder.deleteCharAt(indexOfFirstComma);
                 }
                 sqlBuilder.append(constrainBuilder);
                 jdbcTemplate.execute(sqlBuilder.toString());
@@ -1064,26 +1070,34 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
                 registerColumnCodeMapping(codeMappings);
             }
             if (changeColumns != null) {
-                StringBuilder sqlBuilder = new StringBuilder("ALTER TABLE " + 
sqlGenerator.escape(datatableName));
+                final StringBuilder renameBuilder = new StringBuilder();
+                StringBuilder changeBuilder = new StringBuilder();
                 final StringBuilder constrainBuilder = new StringBuilder();
                 final Map<String, Long> codeMappings = new HashMap<>();
                 final List<String> removeMappings = new ArrayList<>();
                 for (final JsonElement column : changeColumns) {
                     // remove NULL values from column where mandatory is true
                     removeNullValuesFromStringColumn(datatableName, 
column.getAsJsonObject(), mapColumnNameDefinition);
-
-                    parseDatatableColumnForUpdate(column.getAsJsonObject(), 
mapColumnNameDefinition, sqlBuilder, datatableName,
-                            constrainBuilder, codeMappings, removeMappings, 
isConstraintApproach);
+                    parseDatatableColumnForUpdate(column.getAsJsonObject(), 
mapColumnNameDefinition, datatableName, renameBuilder,
+                            changeBuilder, constrainBuilder, codeMappings, 
removeMappings, isConstraintApproach);
                 }
 
                 // Remove the first comma, right after ALTER TABLE datatable
-                final int indexOfFirstComma = sqlBuilder.indexOf(",");
-                if (indexOfFirstComma != -1) {
-                    sqlBuilder = sqlBuilder.deleteCharAt(indexOfFirstComma);
+                StringBuilder sqlBuilder = renameBuilder;
+                if (!changeBuilder.isEmpty() || !constrainBuilder.isEmpty()) {
+                    int idx = changeBuilder.indexOf(",");
+                    if (idx > -1) {
+                        changeBuilder.deleteCharAt(idx);
+                    } else if ((idx = constrainBuilder.indexOf(",")) > -1) {
+                        constrainBuilder.deleteCharAt(idx);
+                    }
+                    sqlBuilder.append("ALTER TABLE " + 
sqlGenerator.escape(datatableName)).append(changeBuilder).append(constrainBuilder);
                 }
-                sqlBuilder.append(constrainBuilder);
+
                 try {
-                    jdbcTemplate.execute(sqlBuilder.toString());
+                    if (!sqlBuilder.isEmpty()) {
+                        jdbcTemplate.execute(sqlBuilder.toString());
+                    }
                     deleteColumnCodeMapping(removeMappings);
                     registerColumnCodeMapping(codeMappings);
                     // update unique constraint
@@ -1160,8 +1174,9 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
         // check for unique constraint update
         String name = column.has(API_FIELD_NAME) ? 
column.get(API_FIELD_NAME).getAsString() : null;
         String columnNewName = column.has(API_FIELD_NEWNAME) ? 
column.get(API_FIELD_NEWNAME).getAsString() : null;
-        final Boolean setUnique = column.has(API_FIELD_UNIQUE) ? 
column.get(API_FIELD_UNIQUE).getAsBoolean() : false;
-        final Boolean isAlreadyUnique = 
genericDataService.isExplicitlyUnique(datatableName, name);
+
+        final boolean isAlreadyUnique = 
genericDataService.isExplicitlyUnique(datatableName, name);
+        boolean setUnique = column.has(API_FIELD_UNIQUE) ? 
column.get(API_FIELD_UNIQUE).getAsBoolean() : isAlreadyUnique;
         String uniqueKeyName = 
datatableKeywordGenerator.generateUniqueKeyName(datatableName, name);
 
         if (isAlreadyUnique) {
@@ -1172,10 +1187,8 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
                 // if columnname changed
                 checkColumnRenameAndModifyUniqueConstraint(datatableName, 
columnNewName, uniqueKeyName);
             }
-        } else {
-            if (setUnique) {
-                checkColumnRenameAndCreateUniqueConstraint(datatableName, 
name, columnNewName, uniqueKeyName);
-            }
+        } else if (setUnique) {
+            checkColumnRenameAndCreateUniqueConstraint(datatableName, name, 
columnNewName, uniqueKeyName);
         }
     }
 
@@ -1201,17 +1214,14 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
     }
 
     private void createUniqueConstraint(String datatableName, String 
columnName, String uniqueKeyName) {
-        StringBuilder constrainBuilder = new StringBuilder();
-        constrainBuilder.append("ALTER TABLE 
").append(sqlGenerator.escape(datatableName)).append(" ADD CONSTRAINT ")
-                .append(sqlGenerator.escape(uniqueKeyName)).append(" UNIQUE (" 
+ sqlGenerator.escape(columnName) + ");");
-        this.jdbcTemplate.execute(constrainBuilder.toString());
+        String sql = "ALTER TABLE " + sqlGenerator.escape(datatableName) + " 
ADD CONSTRAINT " + sqlGenerator.escape(uniqueKeyName)
+                + " UNIQUE (" + sqlGenerator.escape(columnName) + ");";
+        this.jdbcTemplate.execute(sql);
     }
 
     private void dropUniqueConstraint(String datatableName, String 
uniqueKeyName) {
-        StringBuilder constrainBuilder = new StringBuilder();
-        constrainBuilder.append("ALTER TABLE 
").append(sqlGenerator.escape(datatableName)).append(" DROP CONSTRAINT ")
-                .append(sqlGenerator.escape(uniqueKeyName)).append(";");
-        this.jdbcTemplate.execute(constrainBuilder.toString());
+        String sql = "ALTER TABLE " + sqlGenerator.escape(datatableName) + " 
DROP CONSTRAINT " + sqlGenerator.escape(uniqueKeyName) + ";";
+        this.jdbcTemplate.execute(sql);
     }
 
     private void updateIndexesForTable(String datatableName, JsonArray 
changeColumns,
@@ -1230,24 +1240,24 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
     private void updateIndexForColumn(String datatableName, JsonObject column, 
ResultsetColumnHeaderData columnMetaData) {
         String name = column.has(API_FIELD_NAME) ? 
column.get(API_FIELD_NAME).getAsString() : null;
         String columnNewName = column.has(API_FIELD_NEWNAME) ? 
column.get(API_FIELD_NEWNAME).getAsString() : null;
-        final Boolean setForUnique = column.has(API_FIELD_UNIQUE) ? 
column.get(API_FIELD_UNIQUE).getAsBoolean() : false;
-        final Boolean setForIndexed = column.has(API_FIELD_INDEXED) ? 
column.get(API_FIELD_INDEXED).getAsBoolean() : false;
-        if (!setForUnique) {
-            final Boolean isAlreadyIndexed = 
genericDataService.isExplicitlyIndexed(datatableName, name);
-            String indexName = 
datatableKeywordGenerator.generateIndexName(datatableName, name);
-            if (isAlreadyIndexed) {
-                if (!setForIndexed) {
-                    // drop index
-                    dropIndex(datatableName, indexName);
-                } else { // if column name changed
-                    checkColumnRenameAndModifyIndex(datatableName, 
columnNewName, indexName);
-                }
-
-            } else {
-                if (setForIndexed) {
-                    checkColumnRenameAndCreateIndex(datatableName, name, 
columnNewName, indexName);
-                }
+        final boolean isAlreadyUnique = 
genericDataService.isExplicitlyUnique(datatableName, name);
+        final boolean setForUnique = column.has(API_FIELD_UNIQUE) ? 
column.get(API_FIELD_UNIQUE).getAsBoolean() : isAlreadyUnique;
+        if (setForUnique) {
+            return;
+        }
+        final boolean isAlreadyIndexed = 
genericDataService.isExplicitlyIndexed(datatableName, name);
+        boolean setForIndexed = column.has(API_FIELD_INDEXED) ? 
column.get(API_FIELD_INDEXED).getAsBoolean() : isAlreadyIndexed;
+
+        String indexName = 
datatableKeywordGenerator.generateIndexName(datatableName, name);
+        if (isAlreadyIndexed) {
+            if (!setForIndexed) {
+                // drop index
+                dropIndex(datatableName, indexName);
+            } else { // if column name changed
+                checkColumnRenameAndModifyIndex(datatableName, columnNewName, 
indexName);
             }
+        } else if (setForIndexed) {
+            checkColumnRenameAndCreateIndex(datatableName, name, 
columnNewName, indexName);
         }
     }
 
@@ -1297,7 +1307,7 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
             validateDatatableRegistered(datatableName);
             assertDataTableEmpty(datatableName);
             deregisterDatatable(datatableName);
-            String[] sqlArray = null;
+            String[] sqlArray;
             if 
(this.configurationDomainService.isConstraintApproachEnabledForDatatables()) {
                 final String deleteColumnCodeSql = "delete from 
x_table_column_code_mappings where column_alias_name like'"
                         + datatableName.toLowerCase().replaceAll("\\s", "_") + 
"_%'";
@@ -1600,7 +1610,6 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
 
     private String getAddSql(final List<ResultsetColumnHeaderData> 
columnHeaders, final String datatable, final String fkName,
             final Long appTableId, final Map<String, String> queryParams) {
-
         final Map<String, Object> affectedColumns = 
getAffectedColumns(columnHeaders, queryParams, fkName);
 
         String pValueWrite = "";
@@ -1626,12 +1635,10 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
                         } else {
                             throw new IllegalStateException("Current database 
is not supported");
                         }
-
                     } else {
                         pValueWrite = singleQuote + 
this.genericDataService.replace(pValue, singleQuote, singleQuote + singleQuote)
                                 + singleQuote;
                     }
-
                 }
                 columnName = sqlGenerator.escape(key);
                 insertColumns += ", " + columnName;
@@ -1645,12 +1652,10 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
                 }
             }
         }
-
         addSql = "insert into " + sqlGenerator.escape(datatable) + " (" + 
sqlGenerator.escape(fkName) + " " + insertColumns + ")"
                 + " select " + appTableId + " as id" + selectColumns;
 
         log.debug("{}", addSql);
-
         return addSql;
     }
 
@@ -1666,7 +1671,6 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
      */
     public String getAddSqlWithScore(final List<ResultsetColumnHeaderData> 
columnHeaders, final String datatable, final String fkName,
             final Long appTableId, final Map<String, String> queryParams) {
-
         final Map<String, Object> affectedColumns = 
getAffectedColumns(columnHeaders, queryParams, fkName);
 
         String pValueWrite = "";
@@ -1700,13 +1704,11 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
                 + " , ( SELECT SUM( code_score ) FROM m_code_value WHERE 
m_code_value.id IN (" + scoresId + " ) ) as score";
 
         log.debug("{}", vaddSql);
-
         return vaddSql;
     }
 
     private String getUpdateSql(List<ResultsetColumnHeaderData> columnHeaders, 
final String datatable, final String keyFieldName,
             final Long keyFieldValue, final Map<String, Object> 
changedColumns) {
-
         // just updating fields that have changed since pre-update read - 
though
         // its possible these values are different from the page the user was
         // looking at and even different from the current db values (if some
@@ -1765,7 +1767,6 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
         }
 
         sql += " where " + keyFieldName + " = " + keyFieldValue;
-
         return sql;
     }
 
@@ -1780,21 +1781,17 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
                 affectedAndChangedColumns.put(key, columnValue);
             }
         }
-
         return affectedAndChangedColumns;
     }
 
     private boolean columnChanged(final String key, final Object value, final 
GenericResultsetData grs) {
         final List<Object> columnValues = grs.getData().get(0).getRow();
 
-        Object columnValue = null;
         for (int i = 0; i < grs.getColumnHeaders().size(); i++) {
             if (key.equals(grs.getColumnHeaders().get(i).getColumnName())) {
-                columnValue = columnValues.get(i);
-                return notTheSame(columnValue, value);
+                return notTheSame(columnValues.get(i), value);
             }
         }
-
         throw new 
PlatformDataIntegrityException("error.msg.invalid.columnName", "Parameter 
Column Name: " + key + " not found");
     }
 
@@ -1885,26 +1882,23 @@ public class ReadWriteNonCoreDataServiceImpl implements 
ReadWriteNonCoreDataServ
 
     @Override
     public Long countDatatableEntries(final String datatableName, final Long 
appTableId, String foreignKeyColumn) {
-
         final String sqlString = "SELECT COUNT(" + 
sqlGenerator.escape(foreignKeyColumn) + ") FROM " + 
sqlGenerator.escape(datatableName)
-                + " WHERE " + sqlGenerator.escape(foreignKeyColumn) + "=" + 
appTableId;
-        final Long count = this.jdbcTemplate.queryForObject(sqlString, 
Long.class); // NOSONAR
-        return count;
+                + " WHERE " + sqlGenerator.escape(foreignKeyColumn) + " = " + 
appTableId;
+        return this.jdbcTemplate.queryForObject(sqlString, Long.class); // 
NOSONAR
     }
 
     public boolean isDatatableAttachedToEntityDatatableCheck(final String 
datatableName) {
-        StringBuilder builder = new StringBuilder();
-        builder.append(" SELECT COUNT(edc.x_registered_table_name) FROM 
x_registered_table xrt");
-        builder.append(" JOIN m_entity_datatable_check edc ON 
edc.x_registered_table_name = xrt.registered_table_name");
-        builder.append(" WHERE edc.x_registered_table_name = '" + 
datatableName + "'");
-        final Long count = 
this.jdbcTemplate.queryForObject(builder.toString(), Long.class);
+        String sql = "SELECT COUNT(edc.x_registered_table_name) FROM 
x_registered_table xrt"
+                + " JOIN m_entity_datatable_check edc ON 
edc.x_registered_table_name = xrt.registered_table_name"
+                + " WHERE edc.x_registered_table_name = '" + datatableName + 
"'";
+        final Long count = this.jdbcTemplate.queryForObject(sql, Long.class);
         return count > 0;
     }
 
     // --- DbUtils ---
 
     @NotNull
-    private String mapApiTypeToDbType(@NotNull String apiType, Integer length) 
{
+    private String mapApiTypeToDbType(String apiType, Integer length) {
         if (StringUtils.isEmpty(apiType)) {
             return "";
         }
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/system/DatatableHelper.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/system/DatatableHelper.java
index c8c6c4bc7..22eae4d56 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/system/DatatableHelper.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/system/DatatableHelper.java
@@ -231,11 +231,12 @@ public class DatatableHelper extends IntegrationTest {
 
     public static List<HashMap<String, Object>> 
addDatatableColumns(List<HashMap<String, Object>> datatableColumnsList, String 
columnName,
             String columnType, boolean isMandatory, Integer length, String 
codeName) {
-
         final HashMap<String, Object> datatableColumnMap = new HashMap<>();
 
         datatableColumnMap.put("name", columnName);
-        datatableColumnMap.put("type", columnType);
+        if (columnType != null) {
+            datatableColumnMap.put("type", columnType);
+        }
         datatableColumnMap.put("mandatory", isMandatory);
         if (length != null) {
             datatableColumnMap.put("length", length);
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/datatable/DatatableIntegrationTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/datatable/DatatableIntegrationTest.java
index 09ca16a77..dbca64a63 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/datatable/DatatableIntegrationTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/datatable/DatatableIntegrationTest.java
@@ -37,14 +37,17 @@ import java.text.DateFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import org.apache.fineract.client.models.GetDataTablesResponse;
 import org.apache.fineract.client.models.PostDataTablesAppTableIdResponse;
 import org.apache.fineract.client.models.PostDataTablesResponse;
 import 
org.apache.fineract.client.models.PutDataTablesAppTableIdDatatableIdResponse;
 import org.apache.fineract.client.models.PutDataTablesResponse;
+import org.apache.fineract.client.models.ResultsetColumnHeaderData;
 import org.apache.fineract.client.util.Calls;
 import org.apache.fineract.integrationtests.client.IntegrationTest;
 import org.apache.fineract.integrationtests.common.ClientHelper;
@@ -311,7 +314,6 @@ public class DatatableIntegrationTest extends 
IntegrationTest {
 
     @Test
     public void validateCreateReadDeleteDatatableWithCaseSensitive() throws 
ParseException {
-
         // creating datatable for client entity
         final HashMap<String, Object> columnMap = new HashMap<>();
         final List<HashMap<String, Object>> datatableColumnsList = new 
ArrayList<>();
@@ -546,7 +548,7 @@ public class DatatableIntegrationTest extends 
IntegrationTest {
         final boolean genericResultSet = true;
 
         HashMap<String, Object> columnMap = new HashMap<>();
-        List<HashMap<String, Object>> datatableColumnsList = new ArrayList<>();
+        ArrayList<HashMap<String, Object>> datatableColumnsList = new 
ArrayList<>();
         columnMap.put("datatableName", datatableName);
         columnMap.put("apptableName", CLIENT_APP_TABLE_NAME);
         columnMap.put("entitySubType", CLIENT_PERSON_SUBTYPE_NAME);
@@ -562,10 +564,10 @@ public class DatatableIntegrationTest extends 
IntegrationTest {
         DatatableHelper.verifyDatatableCreatedOnServer(this.requestSpec, 
this.responseSpec, datatableName);
 
         // Insert first values
-        final String value = Utils.randomStringGenerator("Q", 8);
+        final String randomString = Utils.randomStringGenerator("Q", 8);
         HashMap<String, Object> datatableEntryMap = new HashMap<>();
         datatableEntryMap.put("itsANumber", randomNumber);
-        datatableEntryMap.put("itsAString", value);
+        datatableEntryMap.put("itsAString", randomString);
 
         datatableEntryMap.put("locale", "en");
         datatableEntryMap.put("dateFormat", "yyyy-MM-dd");
@@ -578,12 +580,14 @@ public class DatatableIntegrationTest extends 
IntegrationTest {
         // Read the Datatable entry generated with genericResultSet in true 
(default)
         HashMap<String, Object> items = 
this.datatableHelper.readDatatableEntry(datatableName, clientId, 
genericResultSet, null, "");
         assertNotNull(items);
-        assertEquals(1, ((List) items.get("data")).size());
-        LOG.info("Record created at {}", ((List) ((Map) ((List) 
items.get("data")).get(0)).get("row")).get(3));
-        LOG.info("Record updated at {}", ((List) ((Map) ((List) 
items.get("data")).get(0)).get("row")).get(4));
+        List data = (List) items.get("data");
+        assertEquals(1, data.size());
+        List records = (List) ((Map) data.get(0)).get("row");
+        LOG.info("Record created at {}", records.get(3));
+        LOG.info("Record updated at {}", records.get(4));
 
-        assertEquals(clientId, ((List) ((Map) ((List) 
items.get("data")).get(0)).get("row")).get(0));
-        assertEquals(value, ((List) ((Map) ((List) 
items.get("data")).get(0)).get("row")).get(2));
+        assertEquals(clientId, records.get(0));
+        assertEquals(randomString, records.get(2));
 
         // Update DataTable
         columnMap = new HashMap<>();
@@ -600,7 +604,7 @@ public class DatatableIntegrationTest extends 
IntegrationTest {
 
         // Update DataTable Entry after Update DataTable schema
         datatableEntryMap = new HashMap<>();
-        final String textValue = Utils.randomStringGenerator(value, 120);
+        final String textValue = Utils.randomStringGenerator(randomString, 
120);
         datatableEntryMap.put("itsAText", textValue);
         datatableEntryMap.put("locale", "en");
         datatableEntryMap.put("dateFormat", "yyyy-MM-dd");
@@ -615,13 +619,41 @@ public class DatatableIntegrationTest extends 
IntegrationTest {
         // Read the Datatable entry generated with genericResultSet in true 
(default)
         items = this.datatableHelper.readDatatableEntry(datatableName, 
clientId, genericResultSet, null, "");
         assertNotNull(items);
-        assertEquals(1, ((List) items.get("data")).size());
-        LOG.info("Record created at {}", ((List) ((Map) ((List) 
items.get("data")).get(0)).get("row")).get(3));
-        LOG.info("Record updated at {}", ((List) ((Map) ((List) 
items.get("data")).get(0)).get("row")).get(4));
+        data = (List) items.get("data");
+        assertEquals(1, data.size());
+
+        records = (List) ((Map) data.get(0)).get("row");
+        LOG.info("Record created at {}", records.get(3));
+        LOG.info("Record updated at {}", records.get(4));
+
+        assertEquals(clientId, records.get(0));
+        assertEquals(randomString, records.get(2));
+        assertEquals(textValue, records.get(5));
+
+        Integer resourceId = 
this.datatableHelper.deleteDatatableEntries(datatableName, clientId, 
"resourceId");
+        assertEquals(clientId, resourceId, "ERROR IN DELETING THE DATATABLE 
ENTRIES");
+
+        // Update - update, delete DataTable columns
+        columnMap = new HashMap<>();
+        columnMap.put("apptableName", CLIENT_APP_TABLE_NAME);
+        columnMap.put("entitySubType", CLIENT_PERSON_SUBTYPE_NAME);
+        List<Map<String, Object>> dropColumnsList = 
Collections.singletonList(Collections.singletonMap("name", "itsANumber"));
+        columnMap.put("dropColumns", dropColumnsList);
+        ArrayList<HashMap<String, Object>> changeColumnsList = new 
ArrayList<>();
+        DatatableHelper.addDatatableColumns(changeColumnsList, "itsAString", 
null, false, 100, null);
+        columnMap.put("changeColumns", changeColumnsList);
+        datatabelRequestJsonString = new Gson().toJson(columnMap);
+        LOG.info("map to update : {}", datatabelRequestJsonString);
+        datatableUpdateResponse = 
this.datatableHelper.updateDatatable(datatableName, datatabelRequestJsonString);
+        assertNotNull(datatableUpdateResponse);
+        assertEquals(datatableName, 
datatableUpdateResponse.getResourceIdentifier());
 
-        assertEquals(clientId, ((List) ((Map) ((List) 
items.get("data")).get(0)).get("row")).get(0));
-        assertEquals(value, ((List) ((Map) ((List) 
items.get("data")).get(0)).get("row")).get(2));
-        assertEquals(textValue, ((List) ((Map) ((List) 
items.get("data")).get(0)).get("row")).get(5));
+        GetDataTablesResponse dataTable = 
datatableHelper.getDataTableDetails(datatableName);
+        List<ResultsetColumnHeaderData> columnHeaders = 
dataTable.getColumnHeaderData();
+        assertEquals(5, columnHeaders.size());
+        ResultsetColumnHeaderData stringColumn = columnHeaders.get(1);
+        assertEquals("itsAString", stringColumn.getColumnName());
+        assertEquals(100, stringColumn.getColumnLength());
     }
 
     @Test
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/datatable/DatatableUniqueAndIndexColumnTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/datatable/DatatableUniqueAndIndexColumnTest.java
index 050910d5b..8f62551c1 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/datatable/DatatableUniqueAndIndexColumnTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/datatable/DatatableUniqueAndIndexColumnTest.java
@@ -176,6 +176,7 @@ public class DatatableUniqueAndIndexColumnTest {
         changeColumns.setName(column1Name);
         String newColumnName = column1Name + "new";
         changeColumns.setNewName(newColumnName);
+        changeColumns.setUnique(false);
         changeColumns.setIndexed(true);
 
         updateRequest.addChangeColumnsItem(changeColumns);

Reply via email to