You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by zs...@apache.org on 2023/09/28 09:27:40 UTC

[ignite-3] branch main updated: IGNITE-19938 Sql. Improve catalog validation for columns parameters (#2593)

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

zstan pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new bea77037cf IGNITE-19938 Sql. Improve catalog validation for columns parameters (#2593)
bea77037cf is described below

commit bea77037cfaacc9478c812dc37845aaea9e86d48
Author: Evgeniy Stanilovskiy <st...@gmail.com>
AuthorDate: Thu Sep 28 12:27:34 2023 +0300

    IGNITE-19938 Sql. Improve catalog validation for columns parameters (#2593)
---
 .../java/org/apache/ignite/sql/ColumnType.java     | 140 ++++++-----------
 .../internal/TestClassHierarchyArchTest.java       |   3 +-
 .../catalog/CatalogParamsValidationUtils.java      |  16 --
 .../commands/AlterTableAddColumnCommand.java       |   3 -
 .../commands/AlterTableAlterColumnCommand.java     |   2 -
 .../internal/catalog/commands/CatalogUtils.java    |  71 ++++-----
 .../internal/catalog/commands/ColumnParams.java    |  92 ++++++++++-
 .../catalog/commands/CreateSystemViewCommand.java  |   3 -
 .../catalog/commands/CreateTableCommand.java       |   3 -
 .../internal/catalog/CatalogManagerSelfTest.java   | 175 +++++++++++++++------
 .../internal/catalog/CatalogSystemViewTest.java    |  15 +-
 .../catalog/ColumnConstructionValidatorTest.java   | 149 ++++++++++++++++++
 .../AlterTableAddColumnCommandValidationTest.java  |  37 -----
 ...AlterTableAlterColumnCommandValidationTest.java |  26 +--
 .../CreateSystemViewCommandValidationTest.java     |  29 ----
 .../commands/CreateTableCommandValidationTest.java |  37 -----
 .../internal/catalog/BaseCatalogManagerTest.java   |  33 ----
 .../ignite/internal/catalog/CatalogTestUtils.java  |  95 +++++++++++
 .../ignite/internal/jdbc/JdbcConverterUtils.java   |   2 +-
 .../internal/client/sql/ClientColumnMetadata.java  |   2 +-
 .../DistributionZoneRebalanceEngineTest.java       |   2 +-
 .../ignite/internal/index/IndexManagerTest.java    |   4 +-
 .../Sql/IgniteDbDataReaderTests.cs                 |   2 +-
 .../runner/app/ItIgniteNodeRestartTest.java        |   2 +
 .../runner/app/PlatformTestNodeRunner.java         |  36 ++---
 .../ignite/internal/sql/api/ItCommonApiTest.java   |   5 +-
 .../internal/sql/engine/ItCreateTableDdlTest.java  |  13 ++
 .../engine/datatypes/tests/DataTypeTestSpec.java   |   2 +-
 .../apache/ignite/internal/schema/NativeType.java  |   1 -
 .../apache/ignite/internal/schema/NativeTypes.java |  10 +-
 .../schema/AbstractSchemaConverterTest.java        |  43 -----
 .../CatalogToSchemaDescriptorConverterTest.java    |   1 +
 .../schema/serializer/AbstractSerializerTest.java  |  44 +-----
 .../ignite/internal/schema/SchemaTestUtils.java    |  42 +++++
 .../schema/testutils/definition/ColumnType.java    |  36 ++---
 .../internal/sql/api/ColumnMetadataImpl.java       |   2 +-
 .../exec/ddl/DdlToCatalogCommandConverter.java     |   2 +-
 .../sql/engine/prepare/ddl/ColumnDefinition.java   |  37 ++++-
 .../internal/sql/engine/type/IgniteTypeSystem.java |   6 +-
 .../ignite/internal/sql/engine/util/TypeUtils.java |   2 +-
 .../sql/engine/util/ProjectedTupleTest.java        |  46 +-----
 .../internal/sql/engine/util/MetadataMatcher.java  |   2 +-
 .../internal/sql/engine/util/QueryCheckerImpl.java |   3 +-
 .../storage/AbstractMvTableStorageTest.java        |   4 +-
 .../storage/index/AbstractIndexStorageTest.java    |  11 +-
 .../ignite/internal/table/ItColocationTest.java    |  47 +-----
 .../internal/table/MutableRowTupleAdapterTest.java |   7 +-
 47 files changed, 719 insertions(+), 626 deletions(-)

diff --git a/modules/api/src/main/java/org/apache/ignite/sql/ColumnType.java b/modules/api/src/main/java/org/apache/ignite/sql/ColumnType.java
index 683dbe264f..87bdeb5f13 100644
--- a/modules/api/src/main/java/org/apache/ignite/sql/ColumnType.java
+++ b/modules/api/src/main/java/org/apache/ignite/sql/ColumnType.java
@@ -33,134 +33,98 @@ import java.util.UUID;
  */
 public enum ColumnType {
     /** Boolean. */
-    BOOLEAN,
+    BOOLEAN(Boolean.class, false, false, false),
 
     /** 8-bit signed integer. */
-    INT8,
+    INT8(Byte.class, false, false, false),
 
     /** 16-bit signed integer. */
-    INT16,
+    INT16(Short.class, false, false, false),
 
     /** 32-bit signed integer. */
-    INT32,
+    INT32(Integer.class, false, false, false),
 
     /** 64-bit signed integer. */
-    INT64,
+    INT64(Long.class, false, false, false),
 
     /** 32-bit single-precision floating-point number. */
-    FLOAT,
+    FLOAT(Float.class, false, false, false),
 
-    /** 64-bit double-precision floating-point number. */
-    DOUBLE,
+    /**
+     * 64-bit double-precision floating-point number.
+     *
+     * <p>SQL`16 part 2 section 6.1 syntax rule 31, implementation-defined precision
+     */
+    DOUBLE(Double.class, false, false, false),
 
     /** Arbitrary-precision signed decimal number. */
-    DECIMAL,
+    DECIMAL(BigDecimal.class, true, true, false),
 
     /** Timezone-free date. */
-    DATE,
+    DATE(LocalDate.class, false, false, false),
 
     /** Timezone-free time with precision. */
-    TIME,
+    TIME(LocalTime.class, true, false, false),
 
     /** Timezone-free datetime. */
-    DATETIME,
+    DATETIME(LocalDateTime.class, true, false, false),
 
     /** Point on the time-line. Number of ticks since {@code 1970-01-01T00:00:00Z}. Tick unit depends on precision. */
-    TIMESTAMP,
+    TIMESTAMP(Instant.class, true, false, false),
 
     /** 128-bit UUID. */
-    UUID,
+    UUID(UUID.class, false, false, false),
 
     /** Bit mask. */
-    BITMASK,
+    BITMASK(BitSet.class, false, false, true),
 
     /** String. */
-    STRING,
+    STRING(String.class, false, false, true),
 
     /** Binary data. */
-    BYTE_ARRAY,
+    BYTE_ARRAY(byte[].class, false, false, true),
 
     /** Date interval. */
-    PERIOD,
+    PERIOD(Period.class, true, false, false),
 
     /** Time interval. */
-    DURATION,
+    DURATION(Duration.class, true, false, false),
 
     /** Number. */
-    NUMBER,
+    NUMBER(BigInteger.class, true, false, false),
 
     /** Null. */
-    NULL;
-
-    /**
-     * Column type to Java class.
-     */
-    public static Class<?> columnTypeToClass(ColumnType type) {
-        assert type != null;
-
-        switch (type) {
-            case BOOLEAN:
-                return Boolean.class;
-
-            case INT8:
-                return Byte.class;
-
-            case INT16:
-                return Short.class;
-
-            case INT32:
-                return Integer.class;
-
-            case INT64:
-                return Long.class;
-
-            case FLOAT:
-                return Float.class;
-
-            case DOUBLE:
-                return Double.class;
-
-            case NUMBER:
-                return BigInteger.class;
-
-            case DECIMAL:
-                return BigDecimal.class;
-
-            case UUID:
-                return UUID.class;
-
-            case STRING:
-                return String.class;
-
-            case BYTE_ARRAY:
-                return byte[].class;
-
-            case BITMASK:
-                return BitSet.class;
-
-            case DATE:
-                return LocalDate.class;
-
-            case TIME:
-                return LocalTime.class;
-
-            case DATETIME:
-                return LocalDateTime.class;
-
-            case TIMESTAMP:
-                return Instant.class;
+    NULL(Void.class, false, false, false);
+
+    private final Class<?> javaClass;
+    private final boolean precisionAllowed;
+    private final boolean scaleAllowed;
+    private final boolean lengthAllowed;
+
+    ColumnType(Class<?> clazz, boolean precisionDefined, boolean scaleDefined, boolean lengthDefined) {
+        javaClass = clazz;
+        this.precisionAllowed = precisionDefined;
+        this.scaleAllowed = scaleDefined;
+        this.lengthAllowed = lengthDefined;
+    }
 
-            case PERIOD:
-                return Period.class;
+    /** Appropriate java match type. */
+    public Class<?> javaClass() {
+        return javaClass;
+    }
 
-            case DURATION:
-                return Duration.class;
+    /** If {@code true} precision need to be specified, {@code false} otherwise. */
+    public boolean precisionAllowed() {
+        return precisionAllowed;
+    }
 
-            case NULL:
-                return Void.class;
+    /** If {@code true} scale need to be specified, {@code false} otherwise. */
+    public boolean scaleAllowed() {
+        return scaleAllowed;
+    }
 
-            default:
-                throw new IllegalArgumentException("Unsupported type " + type);
-        }
+    /** If {@code true} length need to be specified, {@code false} otherwise. */
+    public boolean lengthAllowed() {
+        return lengthAllowed;
     }
 }
diff --git a/modules/arch-test/src/test/java/org/apache/ignite/internal/TestClassHierarchyArchTest.java b/modules/arch-test/src/test/java/org/apache/ignite/internal/TestClassHierarchyArchTest.java
index 84a26c265b..d111bd8519 100644
--- a/modules/arch-test/src/test/java/org/apache/ignite/internal/TestClassHierarchyArchTest.java
+++ b/modules/arch-test/src/test/java/org/apache/ignite/internal/TestClassHierarchyArchTest.java
@@ -58,5 +58,6 @@ public class TestClassHierarchyArchTest {
             .and(hasMockitoDependency)
             .should()
             .beAssignableTo(BaseIgniteAbstractTest.class)
-            .as("Test classes which use Mockito must extends BaseIgniteAbstractTest");
+            .as("Test classes which use Mockito must extends BaseIgniteAbstractTest.\n"
+                    + "This is a workaround for memory leaks in Mockito, see MockitoFramework#clearInlineMocks for details.");
 }
diff --git a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogParamsValidationUtils.java b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogParamsValidationUtils.java
index 7f8ab4a8f4..5d1620eba5 100644
--- a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogParamsValidationUtils.java
+++ b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/CatalogParamsValidationUtils.java
@@ -23,7 +23,6 @@ import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
 import com.jayway.jsonpath.InvalidPathException;
 import com.jayway.jsonpath.JsonPath;
 import org.apache.ignite.internal.catalog.commands.AlterZoneParams;
-import org.apache.ignite.internal.catalog.commands.ColumnParams;
 import org.apache.ignite.internal.catalog.commands.CreateZoneParams;
 import org.apache.ignite.internal.catalog.commands.DropZoneParams;
 import org.apache.ignite.internal.catalog.commands.RenameZoneParams;
@@ -191,21 +190,6 @@ public class CatalogParamsValidationUtils {
         }
     }
 
-    /**
-     * Validates given column parameters.
-     *
-     * @param params Parameters to validate.
-     * @throws CatalogValidationException If validation has failed.
-     */
-    // TODO: IGNITE-19938 Add validation column length, precision and scale
-    public static void validateColumnParams(ColumnParams params) {
-        validateIdentifier(params.name(), "Name of the column");
-
-        if (params.type() == null) {
-            throw new CatalogValidationException("Missing column type: " + params.name());
-        }
-    }
-
     /**
      * Validates that given schema doesn't contain any relation with specified name.
      *
diff --git a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableAddColumnCommand.java b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableAddColumnCommand.java
index 3869162941..e5e166ac47 100644
--- a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableAddColumnCommand.java
+++ b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableAddColumnCommand.java
@@ -17,7 +17,6 @@
 
 package org.apache.ignite.internal.catalog.commands;
 
-import static org.apache.ignite.internal.catalog.CatalogParamsValidationUtils.validateColumnParams;
 import static org.apache.ignite.internal.catalog.commands.CatalogUtils.fromParams;
 import static org.apache.ignite.internal.catalog.commands.CatalogUtils.schemaOrThrow;
 import static org.apache.ignite.internal.catalog.commands.CatalogUtils.tableOrThrow;
@@ -100,8 +99,6 @@ public class AlterTableAddColumnCommand extends AbstractTableCommand {
         Set<String> columnNames = new HashSet<>();
 
         for (ColumnParams column : columns) {
-            validateColumnParams(column);
-
             if (!columnNames.add(column.name())) {
                 throw new CatalogValidationException(format("Column with name '{}' specified more than once", column.name()));
             }
diff --git a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableAlterColumnCommand.java b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableAlterColumnCommand.java
index ddd7204d30..1906ea3d59 100644
--- a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableAlterColumnCommand.java
+++ b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableAlterColumnCommand.java
@@ -115,8 +115,6 @@ public class AlterTableAlterColumnCommand extends AbstractTableCommand {
 
     private void validate() {
         validateIdentifier(columnName, "Name of the column");
-
-        // TODO: IGNITE-19938 Add validation column length, precision and scale
     }
 
     private CatalogTableColumnDescriptor createNewTableColumn(CatalogTableColumnDescriptor origin) {
diff --git a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CatalogUtils.java b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CatalogUtils.java
index 36f02fafa5..a858bc37f6 100644
--- a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CatalogUtils.java
+++ b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CatalogUtils.java
@@ -71,26 +71,8 @@ public class CatalogUtils {
     /** Max number of distribution zone partitions. */
     public static final int MAX_PARTITION_COUNT = 65_000;
 
-    /**
-     * Default TIMESTAMP type precision: microseconds.
-     *
-     * <p>SQL`16 part 2 section 6.1 syntax rule 36
-     */
-    public static final int DEFAULT_TIMESTAMP_PRECISION = 6;
-
-    /**
-     * Default TIME type precision: seconds.
-     *
-     * <p>SQL`16 part 2 section 6.1 syntax rule 36
-     */
-    public static final int DEFAULT_TIME_PRECISION = 0;
-
-    /**
-     * Default DECIMAL precision is implementation-defined.
-     *
-     * <p>SQL`16 part 2 section 6.1 syntax rule 20
-     */
-    public static final int DEFAULT_DECIMAL_PRECISION = 19;
+    /** Precision if not specified. */
+    public static final int DEFAULT_PRECISION = 0;
 
     /**
      * Default scale is 0.
@@ -120,6 +102,20 @@ public class CatalogUtils {
      */
     public static final int MAX_DECIMAL_SCALE = Short.MAX_VALUE;
 
+    /**
+     * Default TIMESTAMP type precision: microseconds.
+     *
+     * <p>SQL`16 part 2 section 6.1 syntax rule 36
+     */
+    public static final int DEFAULT_TIMESTAMP_PRECISION = 6;
+
+    /**
+     * Default TIME type precision: seconds.
+     *
+     * <p>SQL`16 part 2 section 6.1 syntax rule 36
+     */
+    public static final int DEFAULT_TIME_PRECISION = 0;
+
     /**
      * Default length is `1` if implicit.
      *
@@ -197,14 +193,13 @@ public class CatalogUtils {
     /**
      * Converts AlterTableAdd command columns parameters to column descriptor.
      *
-     * @param params Parameters.
+     * @param params Column description.
      * @return Column descriptor.
      */
-    // FIXME: IGNITE-20105 Default values should be taken from the SQL standard
     public static CatalogTableColumnDescriptor fromParams(ColumnParams params) {
-        int precision = Objects.requireNonNullElse(params.precision(), defaultPrecision(params.type()));
+        int precision = Objects.requireNonNullElse(params.precision(), DEFAULT_PRECISION);
         int scale = Objects.requireNonNullElse(params.scale(), DEFAULT_SCALE);
-        int length = Objects.requireNonNullElse(params.length(), defaultLength(params.type()));
+        int length = Objects.requireNonNullElse(params.length(), defaultLength(params.type(), precision));
 
         DefaultValue defaultValue = params.defaultValueDefinition();
 
@@ -244,31 +239,21 @@ public class CatalogUtils {
         }).collect(toList());
     }
 
-    private static int defaultPrecision(ColumnType columnType) {
-        //TODO IGNITE-19938: Add REAL,FLOAT and DOUBLE precision. See SQL`16 part 2 section 6.1 syntax rule 29-31
-        switch (columnType) {
-            case NUMBER:
-            case DECIMAL:
-                return DEFAULT_DECIMAL_PRECISION;
-            case TIME:
-                return DEFAULT_TIME_PRECISION;
-            case TIMESTAMP:
-            case DATETIME:
-                return DEFAULT_TIMESTAMP_PRECISION;
-            default:
-                return 0;
-        }
-    }
-
-    private static int defaultLength(ColumnType columnType) {
-        //TODO IGNITE-19938: Return length for other types. See SQL`16 part 2 section 6.1 syntax rule 39
+    /**
+     * Return default length according to supplied type.
+     *
+     * @param columnType Column type.
+     * @param precision Type precision.
+     */
+    public static int defaultLength(ColumnType columnType, int precision) {
+        //TODO IGNITE-20432: Return length for other types. See SQL`16 part 2 section 6.1 syntax rule 39
         switch (columnType) {
             case BITMASK:
             case STRING:
             case BYTE_ARRAY:
                 return DEFAULT_VARLEN_LENGTH;
             default:
-                return Math.max(DEFAULT_LENGTH, defaultPrecision(columnType));
+                return Math.max(DEFAULT_LENGTH, precision);
         }
     }
 
diff --git a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/ColumnParams.java b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/ColumnParams.java
index 9b4da640e4..d0d9df81ea 100644
--- a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/ColumnParams.java
+++ b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/ColumnParams.java
@@ -17,12 +17,20 @@
 
 package org.apache.ignite.internal.catalog.commands;
 
+import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
+
 import java.util.Objects;
+import org.apache.ignite.internal.catalog.CatalogParamsValidationUtils;
+import org.apache.ignite.internal.catalog.CatalogValidationException;
 import org.apache.ignite.sql.ColumnType;
 import org.jetbrains.annotations.Nullable;
 
 /** Defines a particular column within table. */
 public class ColumnParams {
+    public static final String ERR_COL_PARAM_NOT_APPLICABLE = "{} is not applicable for column '{}' of type '{}'";
+    public static final String ERR_COL_PARAM_VALIDATION = "{} for column '{}' of type '{}' must be non-negative";
+    public static final String ERR_COL_PARAM_DEFINITION = "{} definition is necessary for column '{}' of type '{}'";
+
     /** Creates parameters builder. */
     public static Builder builder() {
         return new Builder();
@@ -174,7 +182,7 @@ public class ColumnParams {
          * @param precision Column precision.
          * @return {@code this}.
          */
-        public Builder precision(Integer precision) {
+        public Builder precision(@Nullable Integer precision) {
             params.precision = precision;
 
             return this;
@@ -186,7 +194,7 @@ public class ColumnParams {
          * @param scale Column scale.
          * @return {@code this}.
          */
-        public Builder scale(Integer scale) {
+        public Builder scale(@Nullable Integer scale) {
             params.scale = scale;
 
             return this;
@@ -198,7 +206,7 @@ public class ColumnParams {
          * @param length Column length.
          * @return {@code this}.
          */
-        public Builder length(Integer length) {
+        public Builder length(@Nullable Integer length) {
             params.length = length;
 
             return this;
@@ -206,9 +214,87 @@ public class ColumnParams {
 
         /** Builds parameters. */
         public ColumnParams build() {
+            validate();
+
             ColumnParams params0 = params;
             params = null;
             return params0;
         }
+
+        private void validate() {
+            CatalogParamsValidationUtils.validateIdentifier(params.name(), "Column name");
+
+            if (params.type == null) {
+                throw new CatalogValidationException(format("Type is not specified for column '{}'", params.name()));
+            }
+
+            if (params.type == ColumnType.NULL) {
+                throw new CatalogValidationException(format("Type NULL is not applicable for column '{}'", params.name()));
+            }
+
+            boolean validatePrecision = params.type.precisionAllowed();
+            boolean validateScale = params.type.scaleAllowed();
+            boolean validateLenght = params.type.lengthAllowed();
+
+            if (validateLenght) {
+                if (params.length() == null) {
+                    throw new CatalogValidationException(format(ERR_COL_PARAM_DEFINITION, "Length", params.name(), params.type()));
+                }
+
+                if (params.length() < 0) {
+                    throw new CatalogValidationException(format(ERR_COL_PARAM_VALIDATION, "Length", params.name(), params.type()));
+                }
+            } else {
+                if (params.length() != null) {
+                    throw new CatalogValidationException(format(ERR_COL_PARAM_NOT_APPLICABLE, "Length", params.name(), params.type()));
+                }
+            }
+
+            if (validatePrecision) {
+                validatePrecision(params);
+
+                if (params.scale() != null && !validateScale) {
+                    throw new CatalogValidationException(format(ERR_COL_PARAM_NOT_APPLICABLE, "Scale", params.name(), params.type()));
+                }
+            }
+
+            if (validateScale) {
+                validateScale(params);
+            }
+
+            if (!validatePrecision && !validateScale) {
+                if (params.precision() != null) {
+                    throw new CatalogValidationException(format(ERR_COL_PARAM_NOT_APPLICABLE, "Precision", params.name(), params.type()));
+                }
+
+                if (params.scale() != null) {
+                    throw new CatalogValidationException(format(ERR_COL_PARAM_NOT_APPLICABLE, "Scale", params.name(), params.type()));
+                }
+            }
+        }
+
+        private static void validatePrecision(ColumnParams params) {
+            Integer precision = params.precision();
+
+            if (precision == null) {
+                throw new CatalogValidationException(format(ERR_COL_PARAM_DEFINITION, "Precision", params.name(), params.type()));
+            }
+
+            if (precision < 0) {
+                throw new CatalogValidationException(format(ERR_COL_PARAM_VALIDATION, "Precision", params.name(), params.type()));
+            }
+        }
+
+        private static void validateScale(ColumnParams params) {
+            Integer scale = params.scale();
+
+            if (scale == null) {
+                throw new CatalogValidationException(format(ERR_COL_PARAM_DEFINITION, "Scale", params.name(), params.type()));
+            }
+
+            if (scale < 0) {
+                throw new CatalogValidationException(format(ERR_COL_PARAM_VALIDATION, "Scale", params.name(), params.type()));
+            }
+        }
     }
 }
diff --git a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CreateSystemViewCommand.java b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CreateSystemViewCommand.java
index 8752761f8a..efe6e63e24 100644
--- a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CreateSystemViewCommand.java
+++ b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CreateSystemViewCommand.java
@@ -18,7 +18,6 @@
 package org.apache.ignite.internal.catalog.commands;
 
 import static java.util.stream.Collectors.toList;
-import static org.apache.ignite.internal.catalog.CatalogParamsValidationUtils.validateColumnParams;
 import static org.apache.ignite.internal.catalog.CatalogParamsValidationUtils.validateIdentifier;
 import static org.apache.ignite.internal.catalog.commands.CatalogUtils.schemaOrThrow;
 import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
@@ -141,8 +140,6 @@ public class CreateSystemViewCommand implements CatalogCommand {
         Set<String> columnNames = new HashSet<>();
 
         for (ColumnParams column : columns) {
-            validateColumnParams(column);
-
             if (!columnNames.add(column.name())) {
                 throw new CatalogValidationException(format("Column with name '{}' specified more than once", column.name()));
             }
diff --git a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CreateTableCommand.java b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CreateTableCommand.java
index d6a5a0c57b..bc78766dd2 100644
--- a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CreateTableCommand.java
+++ b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/CreateTableCommand.java
@@ -20,7 +20,6 @@ package org.apache.ignite.internal.catalog.commands;
 import static java.util.Objects.requireNonNullElse;
 import static java.util.stream.Collectors.toList;
 import static org.apache.ignite.internal.catalog.CatalogParamsValidationUtils.ensureNoTableIndexOrSysViewExistsWithGivenName;
-import static org.apache.ignite.internal.catalog.CatalogParamsValidationUtils.validateColumnParams;
 import static org.apache.ignite.internal.catalog.commands.CatalogUtils.schemaOrThrow;
 import static org.apache.ignite.internal.catalog.commands.CatalogUtils.zoneOrThrow;
 import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
@@ -141,8 +140,6 @@ public class CreateTableCommand extends AbstractTableCommand {
         Set<String> columnNames = new HashSet<>();
 
         for (ColumnParams column : columns) {
-            validateColumnParams(column);
-
             if (!columnNames.add(column.name())) {
                 throw new CatalogValidationException(format("Column with name '{}' specified more than once", column.name()));
             }
diff --git a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogManagerSelfTest.java b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogManagerSelfTest.java
index 48e802c9d0..c76af57621 100644
--- a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogManagerSelfTest.java
+++ b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogManagerSelfTest.java
@@ -23,18 +23,28 @@ import static java.util.stream.Collectors.toList;
 import static org.apache.ignite.internal.catalog.CatalogService.DEFAULT_SCHEMA_NAME;
 import static org.apache.ignite.internal.catalog.CatalogService.DEFAULT_ZONE_NAME;
 import static org.apache.ignite.internal.catalog.CatalogService.SYSTEM_SCHEMA_NAME;
+import static org.apache.ignite.internal.catalog.CatalogTestUtils.addColumnParams;
+import static org.apache.ignite.internal.catalog.CatalogTestUtils.applyNecessaryLength;
+import static org.apache.ignite.internal.catalog.CatalogTestUtils.applyNecessaryPrecision;
+import static org.apache.ignite.internal.catalog.CatalogTestUtils.columnParams;
+import static org.apache.ignite.internal.catalog.CatalogTestUtils.columnParamsBuilder;
+import static org.apache.ignite.internal.catalog.CatalogTestUtils.dropColumnParams;
+import static org.apache.ignite.internal.catalog.CatalogTestUtils.dropTableCommand;
+import static org.apache.ignite.internal.catalog.CatalogTestUtils.initializeColumnWithDefaults;
 import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_DATA_REGION;
 import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_FILTER;
 import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_PARTITION_COUNT;
+import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_PRECISION;
 import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_REPLICA_COUNT;
+import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_SCALE;
 import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_STORAGE_ENGINE;
-import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_VARLEN_LENGTH;
 import static org.apache.ignite.internal.catalog.commands.CatalogUtils.IMMEDIATE_TIMER_VALUE;
 import static org.apache.ignite.internal.catalog.commands.CatalogUtils.INFINITE_TIMER_VALUE;
 import static org.apache.ignite.internal.catalog.commands.DefaultValue.constant;
 import static org.apache.ignite.internal.catalog.descriptors.CatalogColumnCollation.ASC_NULLS_LAST;
 import static org.apache.ignite.internal.catalog.descriptors.CatalogColumnCollation.DESC_NULLS_FIRST;
 import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
+import static org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrowsWithCause;
 import static org.apache.ignite.internal.testframework.matchers.CompletableFutureExceptionMatcher.willThrow;
 import static org.apache.ignite.internal.testframework.matchers.CompletableFutureExceptionMatcher.willThrowFast;
 import static org.apache.ignite.internal.testframework.matchers.CompletableFutureMatcher.willBe;
@@ -84,6 +94,7 @@ import org.apache.ignite.internal.catalog.commands.AlterTableAlterColumnCommandB
 import org.apache.ignite.internal.catalog.commands.AlterZoneParams;
 import org.apache.ignite.internal.catalog.commands.CatalogUtils;
 import org.apache.ignite.internal.catalog.commands.ColumnParams;
+import org.apache.ignite.internal.catalog.commands.ColumnParams.Builder;
 import org.apache.ignite.internal.catalog.commands.CreateZoneParams;
 import org.apache.ignite.internal.catalog.commands.DataStorageParams;
 import org.apache.ignite.internal.catalog.commands.DefaultValue;
@@ -134,6 +145,7 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
     private static final String TABLE_NAME_2 = "myTable2";
     private static final String NEW_COLUMN_NAME = "NEWCOL";
     private static final String NEW_COLUMN_NAME_2 = "NEWCOL2";
+    private static final int DFLT_TEST_PRECISION = 11;
 
     @Test
     public void testEmptyCatalog() {
@@ -231,6 +243,11 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
         assertEquals(table.primaryKeyColumns(), pkIndex.columns());
         assertTrue(pkIndex.unique());
 
+        CatalogTableColumnDescriptor desc = table.columnDescriptor("key1");
+        assertNotNull(desc);
+        // INT32 key
+        assertThat(desc.precision(), is(DEFAULT_PRECISION));
+
         // Validate another table creation.
         assertThat(manager.execute(simpleTable(TABLE_NAME_2)), willBe(nullValue()));
 
@@ -337,8 +354,8 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
         long beforeAddedTimestamp = clock.nowLong();
 
         assertThat(
-                manager.execute(addColumnParams(
-                        columnParamsBuilder(NEW_COLUMN_NAME, STRING, true).defaultValue(constant("Ignite!")).build()
+                manager.execute(addColumnParams(TABLE_NAME,
+                        columnParamsBuilder(NEW_COLUMN_NAME, STRING, 11, true).defaultValue(constant("Ignite!")).build()
                 )),
                 willBe(nullValue())
         );
@@ -365,9 +382,9 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
         assertEquals(DefaultValue.Type.CONSTANT, column.defaultValue().type());
         assertEquals("Ignite!", ((DefaultValue.ConstantValue) column.defaultValue()).value());
 
-        assertEquals(DEFAULT_VARLEN_LENGTH, column.length());
-        assertEquals(0, column.precision());
-        assertEquals(0, column.scale());
+        assertEquals(11, column.length());
+        assertEquals(DEFAULT_PRECISION, column.precision());
+        assertEquals(DEFAULT_SCALE, column.scale());
     }
 
     @Test
@@ -376,7 +393,7 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
 
         long beforeAddedTimestamp = clock.nowLong();
 
-        assertThat(manager.execute(dropColumnParams("VAL")), willBe(nullValue()));
+        assertThat(manager.execute(dropColumnParams(TABLE_NAME, "VAL")), willBe(nullValue()));
 
         // Validate catalog version from the past.
         CatalogSchemaDescriptor schema = manager.activeSchema(beforeAddedTimestamp);
@@ -399,7 +416,7 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
 
         // Add duplicate column.
         assertThat(
-                manager.execute(addColumnParams(columnParams(NEW_COLUMN_NAME, INT32, true), columnParams("VAL", INT32, true))),
+                manager.execute(addColumnParams(TABLE_NAME, columnParams(NEW_COLUMN_NAME, INT32, true), columnParams("VAL", INT32, true))),
                 willThrow(CatalogValidationException.class)
         );
 
@@ -410,7 +427,7 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
 
         // Add multiple columns.
         assertThat(
-                manager.execute(addColumnParams(
+                manager.execute(addColumnParams(TABLE_NAME,
                         columnParams(NEW_COLUMN_NAME, INT32, true), columnParams(NEW_COLUMN_NAME_2, INT32, true)
                 )),
                 willBe(nullValue())
@@ -423,7 +440,7 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
         assertNotNull(schema.table(TABLE_NAME).column(NEW_COLUMN_NAME_2));
 
         // Drop multiple columns.
-        assertThat(manager.execute(dropColumnParams(NEW_COLUMN_NAME, NEW_COLUMN_NAME_2)), willBe(nullValue()));
+        assertThat(manager.execute(dropColumnParams(TABLE_NAME, NEW_COLUMN_NAME, NEW_COLUMN_NAME_2)), willBe(nullValue()));
 
         // Validate both columns dropped.
         schema = manager.activeSchema(clock.nowLong());
@@ -521,31 +538,46 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
     @Test
     public void testAlterColumnTypePrecision() {
         ColumnParams pkCol = columnParams("ID", INT32);
-        ColumnParams col = columnParamsBuilder("COL_DECIMAL", DECIMAL).precision(10).build();
+        ColumnParams col1 = columnParamsBuilder("COL_DECIMAL1", DECIMAL).precision(DFLT_TEST_PRECISION - 1).scale(1).build();
+        ColumnParams col2 = columnParamsBuilder("COL_DECIMAL2", DECIMAL).precision(DFLT_TEST_PRECISION).scale(1).build();
 
-        assertThat(manager.execute(simpleTable(TABLE_NAME, List.of(pkCol, col))), willBe(nullValue()));
+        assertThat(manager.execute(simpleTable(TABLE_NAME, List.of(pkCol, col1, col2))), willBe(nullValue()));
 
         int schemaVer = 1;
         assertNotNull(manager.schema(schemaVer));
         assertNull(manager.schema(schemaVer + 1));
 
-        // 10 ->11 : Ok.
+        // precision increment : Ok.
         assertThat(
-                changeColumn(TABLE_NAME, col.name(), new TestColumnTypeParams(col.type(), 11, null, null), null, null),
+                changeColumn(TABLE_NAME, col1.name(), new TestColumnTypeParams(col1.type(), DFLT_TEST_PRECISION, null, null), null, null),
                 willBe(nullValue())
         );
         assertNotNull(manager.schema(++schemaVer));
 
+        assertThat(
+                changeColumn(TABLE_NAME, col2.name(), new TestColumnTypeParams(col2.type(), DFLT_TEST_PRECISION, null, null), null, null),
+                willBe(nullValue())
+        );
+        assertNull(manager.schema(schemaVer + 1));
+
         // No change.
         assertThat(
-                changeColumn(TABLE_NAME, col.name(), new TestColumnTypeParams(col.type(), 11, null, null), null, null),
+                changeColumn(TABLE_NAME, col1.name(), new TestColumnTypeParams(col1.type(), DFLT_TEST_PRECISION, null, null), null, null),
                 willBe(nullValue())
         );
         assertNull(manager.schema(schemaVer + 1));
 
-        // 11 -> 10 : Forbidden because this change lead to incompatible schemas.
+        // precision decrement : Forbidden because this change lead to incompatible schemas.
+        assertThat(
+                changeColumn(TABLE_NAME, col1.name(),
+                        new TestColumnTypeParams(col1.type(), DFLT_TEST_PRECISION - 1, null, null), null, null),
+                willThrowFast(CatalogValidationException.class, "Decreasing the precision is not allowed")
+        );
+        assertNull(manager.schema(schemaVer + 1));
+
         assertThat(
-                changeColumn(TABLE_NAME, col.name(), new TestColumnTypeParams(col.type(), 10, null, null), null, null),
+                changeColumn(TABLE_NAME, col2.name(),
+                        new TestColumnTypeParams(col2.type(), DFLT_TEST_PRECISION - 1, null, null), null, null),
                 willThrowFast(CatalogValidationException.class, "Decreasing the precision is not allowed")
         );
         assertNull(manager.schema(schemaVer + 1));
@@ -558,29 +590,39 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
     @EnumSource(value = ColumnType.class, names = {"NULL", "DECIMAL"}, mode = Mode.EXCLUDE)
     public void testAlterColumnTypeAnyPrecisionChangeIsRejected(ColumnType type) {
         ColumnParams pkCol = columnParams("ID", INT32);
-        ColumnParams col = columnParams("COL", type);
-        ColumnParams colWithPrecision = columnParamsBuilder("COL_PRECISION", type).precision(3).build();
+        ColumnParams colWithPrecision;
+        Builder colWithPrecisionBuilder = columnParamsBuilder("COL_PRECISION", type).precision(3);
+        applyNecessaryLength(type, colWithPrecisionBuilder);
+
+        if (type.scaleAllowed()) {
+            colWithPrecisionBuilder.scale(0);
+        }
+
+        if (!type.precisionAllowed() && !type.scaleAllowed()) {
+            assertThrowsWithCause(colWithPrecisionBuilder::build, CatalogValidationException.class);
+            return;
+        }
+
+        colWithPrecision = colWithPrecisionBuilder.build();
 
         assertThat(manager.execute(
-                simpleTable(TABLE_NAME, List.of(pkCol, col, colWithPrecision))), willBe(nullValue())
+                simpleTable(TABLE_NAME, List.of(pkCol, colWithPrecision))), willBe(nullValue())
         );
 
         int schemaVer = 1;
         assertNotNull(manager.schema(schemaVer));
         assertNull(manager.schema(schemaVer + 1));
 
-        assertThat(changeColumn(TABLE_NAME, col.name(), new TestColumnTypeParams(type, 3, null, null), null, null),
-                willThrowFast(CatalogValidationException.class,
-                        "Changing the precision for column of type '" + col.type() + "' is not allowed"));
-
-        assertThat(changeColumn(TABLE_NAME, colWithPrecision.name(), new TestColumnTypeParams(type, 3, null, null), null, null),
-                willBe(nullValue()));
+        int origPrecision = colWithPrecision.precision() == null ? 11 : colWithPrecision.precision();
 
-        assertThat(changeColumn(TABLE_NAME, colWithPrecision.name(), new TestColumnTypeParams(type, 2, null, null), null, null),
+        // change precision different from default
+        assertThat(changeColumn(TABLE_NAME, colWithPrecision.name(),
+                        new TestColumnTypeParams(type, origPrecision - 1, null, null), null, null),
                 willThrowFast(CatalogValidationException.class,
                         "Changing the precision for column of type '" + colWithPrecision.type() + "' is not allowed"));
 
-        assertThat(changeColumn(TABLE_NAME, colWithPrecision.name(), new TestColumnTypeParams(type, 4, null, null), null, null),
+        assertThat(changeColumn(TABLE_NAME, colWithPrecision.name(),
+                        new TestColumnTypeParams(type, origPrecision + 1, null, null), null, null),
                 willThrowFast(CatalogValidationException.class,
                         "Changing the precision for column of type '" + colWithPrecision.type() + "' is not allowed"));
 
@@ -647,11 +689,25 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
      * Changing length is forbidden for all types other than STRING and BYTE_ARRAY.
      */
     @ParameterizedTest
-    @EnumSource(value = ColumnType.class, names = {"NULL", "STRING", "BYTE_ARRAY"}, mode = Mode.EXCLUDE)
+    @EnumSource(value = ColumnType.class, names = {"STRING", "BYTE_ARRAY", "NULL"}, mode = Mode.EXCLUDE)
     public void testAlterColumnTypeAnyLengthChangeIsRejected(ColumnType type) {
         ColumnParams pkCol = columnParams("ID", INT32);
-        ColumnParams col = columnParams("COL", type);
-        ColumnParams colWithLength = columnParamsBuilder("COL_PRECISION", type).length(10).build();
+        Builder colBuilder = columnParamsBuilder("COL", type);
+        Builder colWithLengthBuilder = columnParamsBuilder("COL_PRECISION", type).length(10);
+
+        applyNecessaryLength(type, colWithLengthBuilder);
+
+        initializeColumnWithDefaults(type, colBuilder);
+        initializeColumnWithDefaults(type, colWithLengthBuilder);
+
+        ColumnParams col = colBuilder.build();
+
+        if (!type.lengthAllowed()) {
+            assertThrowsWithCause(colWithLengthBuilder::build, CatalogValidationException.class);
+            return;
+        }
+
+        ColumnParams colWithLength = colWithLengthBuilder.build();
 
         assertThat(
                 manager.execute(simpleTable(TABLE_NAME, List.of(pkCol, col, colWithLength))),
@@ -662,11 +718,11 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
         assertNotNull(manager.schema(schemaVer));
         assertNull(manager.schema(schemaVer + 1));
 
-        assertThat(changeColumn(TABLE_NAME, col.name(), new TestColumnTypeParams(type, null, 10, null), null, null),
+        assertThat(changeColumn(TABLE_NAME, col.name(), new TestColumnTypeParams(type, null, 1 << 6, null), null, null),
                 willThrowFast(CatalogValidationException.class,
                         "Changing the length for column of type '" + col.type() + "' is not allowed"));
 
-        assertThat(changeColumn(TABLE_NAME, colWithLength.name(), new TestColumnTypeParams(type, null, 10, null), null, null),
+        assertThat(changeColumn(TABLE_NAME, colWithLength.name(), new TestColumnTypeParams(type, null, 1 << 5, null), null, null),
                 willBe(nullValue()));
 
         assertThat(changeColumn(TABLE_NAME, colWithLength.name(), new TestColumnTypeParams(type, null, 9, null), null, null),
@@ -684,10 +740,22 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
      * Changing scale is incompatible change, thus it's forbidden for all types.
      */
     @ParameterizedTest
-    @EnumSource(value = ColumnType.class, names = "NULL", mode = Mode.EXCLUDE)
+    @EnumSource(ColumnType.class)
     public void testAlterColumnTypeScaleIsRejected(ColumnType type) {
         ColumnParams pkCol = columnParams("ID", INT32);
-        ColumnParams col = columnParamsBuilder("COL_" + type, type).scale(3).build();
+        Builder colWithPrecisionBuilder = columnParamsBuilder("COL_" + type, type).scale(3);
+        ColumnParams col;
+
+        applyNecessaryPrecision(type, colWithPrecisionBuilder);
+        applyNecessaryLength(type, colWithPrecisionBuilder);
+
+        if (!type.scaleAllowed()) {
+            assertThrowsWithCause(colWithPrecisionBuilder::build, CatalogValidationException.class);
+            return;
+        }
+
+        col = colWithPrecisionBuilder.build();
+
         assertThat(manager.execute(simpleTable(TABLE_NAME, List.of(pkCol, col))), willBe(nullValue()));
 
         int schemaVer = 1;
@@ -732,7 +800,8 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
         types.remove(NULL);
 
         List<ColumnParams> testColumns = types.stream()
-                .map(t -> columnParams("COL_" + t, t))
+                .map(t -> initializeColumnWithDefaults(t, columnParamsBuilder("COL_" + t, t)))
+                .map(Builder::build)
                 .collect(toList());
 
         List<ColumnParams> tableColumns = new ArrayList<>(List.of(columnParams("ID", INT32)));
@@ -756,9 +825,9 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
                         format("Changing the type from {} to {} is not allowed", col.type(), target));
             }
 
-            TestColumnTypeParams tyoeParams = new TestColumnTypeParams(target);
+            TestColumnTypeParams typeParams = new TestColumnTypeParams(target);
 
-            assertThat(col.type() + " -> " + target, changeColumn(TABLE_NAME, col.name(), tyoeParams, null, null), matcher);
+            assertThat(col.type() + " -> " + target, changeColumn(TABLE_NAME, col.name(), typeParams, null, null), matcher);
             assertNotNull(manager.schema(schemaVer));
             assertNull(manager.schema(schemaVer + 1));
         }
@@ -1348,7 +1417,7 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
         manager.listen(CatalogEvent.TABLE_ALTER, eventListener);
 
         // Try to add column without table.
-        assertThat(manager.execute(addColumnParams(columnParams(NEW_COLUMN_NAME, INT32))),
+        assertThat(manager.execute(addColumnParams(TABLE_NAME, columnParams(NEW_COLUMN_NAME, INT32))),
                 willThrow(TableNotFoundValidationException.class));
         verifyNoInteractions(eventListener);
 
@@ -1356,11 +1425,11 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
         assertThat(manager.execute(simpleTable(TABLE_NAME)), willBe(nullValue()));
 
         // Add column.
-        assertThat(manager.execute(addColumnParams(columnParams(NEW_COLUMN_NAME, INT32))), willBe(nullValue()));
+        assertThat(manager.execute(addColumnParams(TABLE_NAME, columnParams(NEW_COLUMN_NAME, INT32))), willBe(nullValue()));
         verify(eventListener).notify(any(AddColumnEventParameters.class), isNull());
 
         // Drop column.
-        assertThat(manager.execute(dropColumnParams(NEW_COLUMN_NAME)), willBe(nullValue()));
+        assertThat(manager.execute(dropColumnParams(TABLE_NAME, NEW_COLUMN_NAME)), willBe(nullValue()));
         verify(eventListener).notify(any(DropColumnEventParameters.class), isNull());
 
         verifyNoMoreInteractions(eventListener);
@@ -1511,7 +1580,7 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
     public void addColumnIncrementsTableVersion() {
         createSomeTable(TABLE_NAME);
 
-        assertThat(manager.execute(addColumnParams(columnParams("val2", INT32))), willCompleteSuccessfully());
+        assertThat(manager.execute(addColumnParams(TABLE_NAME, columnParams("val2", INT32))), willCompleteSuccessfully());
 
         CatalogTableDescriptor table = manager.table(TABLE_NAME, Long.MAX_VALUE);
 
@@ -1522,7 +1591,7 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
     public void dropColumnIncrementsTableVersion() {
         createSomeTable(TABLE_NAME);
 
-        assertThat(manager.execute(dropColumnParams("val1")), willCompleteSuccessfully());
+        assertThat(manager.execute(dropColumnParams(TABLE_NAME, "val1")), willCompleteSuccessfully());
 
         CatalogTableDescriptor table = manager.table(TABLE_NAME, Long.MAX_VALUE);
 
@@ -1653,14 +1722,14 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
 
     @Test
     void testDropColumnWithNotExistingTable() {
-        assertThat(manager.execute(dropColumnParams("key")), willThrowFast(TableNotFoundValidationException.class));
+        assertThat(manager.execute(dropColumnParams(TABLE_NAME, "key")), willThrowFast(TableNotFoundValidationException.class));
     }
 
     @Test
     void testDropColumnWithMissingTableColumns() {
         assertThat(manager.execute(simpleTable(TABLE_NAME)), willCompleteSuccessfully());
 
-        assertThat(manager.execute(dropColumnParams("fake")), willThrowFast(CatalogValidationException.class));
+        assertThat(manager.execute(dropColumnParams(TABLE_NAME, "fake")), willThrowFast(CatalogValidationException.class));
     }
 
     @Test
@@ -1668,7 +1737,7 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
         assertThat(manager.execute(simpleTable(TABLE_NAME)), willCompleteSuccessfully());
 
         assertThat(
-                manager.execute(dropColumnParams("ID")),
+                manager.execute(dropColumnParams(TABLE_NAME, "ID")),
                 willThrowFast(CatalogValidationException.class, "Deleting column belonging to primary key is not allowed")
         );
     }
@@ -1679,7 +1748,7 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
         assertThat(manager.execute(simpleIndex()), willCompleteSuccessfully());
 
         assertThat(
-                manager.execute(dropColumnParams("VAL")),
+                manager.execute(dropColumnParams(TABLE_NAME, "VAL")),
                 willThrowFast(
                         CatalogValidationException.class,
                         "Deleting indexed column is not allowed"
@@ -1689,14 +1758,16 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
 
     @Test
     void testAddColumnWithNotExistingTable() {
-        assertThat(manager.execute(addColumnParams(columnParams("key", INT32))), willThrowFast(TableNotFoundValidationException.class));
+        assertThat(manager.execute(addColumnParams(TABLE_NAME, columnParams("key", INT32))),
+                willThrowFast(TableNotFoundValidationException.class));
     }
 
     @Test
     void testAddColumnWithExistingName() {
         assertThat(manager.execute(simpleTable(TABLE_NAME)), willCompleteSuccessfully());
 
-        assertThat(manager.execute(addColumnParams(columnParams("ID", INT32))), willThrowFast(CatalogValidationException.class));
+        assertThat(manager.execute(addColumnParams(TABLE_NAME, columnParams("ID", INT32))),
+                willThrowFast(CatalogValidationException.class));
     }
 
 
@@ -1828,9 +1899,9 @@ public class CatalogManagerSelfTest extends BaseCatalogManagerTest {
                 columnParams("ID", INT32),
                 columnParamsBuilder("VAL", INT32, true).defaultValue(constant(null)).build(),
                 columnParamsBuilder("VAL_NOT_NULL", INT32).defaultValue(constant(1)).build(),
-                columnParams("DEC", DECIMAL, true),
-                columnParams("STR", STRING, true),
-                columnParamsBuilder("DEC_SCALE", DECIMAL).scale(3).build()
+                columnParams("DEC", DECIMAL, true, 11, 2),
+                columnParams("STR", STRING, 101, true),
+                columnParamsBuilder("DEC_SCALE", DECIMAL).precision(12).scale(3).build()
         );
 
         return simpleTable(name, cols);
diff --git a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogSystemViewTest.java b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogSystemViewTest.java
index bcbda28738..856e0d5e0b 100644
--- a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogSystemViewTest.java
+++ b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/CatalogSystemViewTest.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.catalog;
 import static java.util.concurrent.CompletableFuture.completedFuture;
 import static java.util.stream.Collectors.toList;
 import static org.apache.ignite.internal.catalog.CatalogService.SYSTEM_SCHEMA_NAME;
+import static org.apache.ignite.internal.catalog.CatalogTestUtils.columnParams;
 import static org.apache.ignite.internal.testframework.matchers.CompletableFutureMatcher.willCompleteSuccessfully;
 import static org.apache.ignite.sql.ColumnType.INT32;
 import static org.apache.ignite.sql.ColumnType.STRING;
@@ -83,7 +84,7 @@ public class CatalogSystemViewTest extends BaseCatalogManagerTest {
                 .name(SYS_VIEW_NAME)
                 .columns(List.of(
                         ColumnParams.builder().name("col1").type(INT32).build(),
-                        ColumnParams.builder().name("col2").type(STRING).build()
+                        ColumnParams.builder().name("col2").type(STRING).length(1 << 5).build()
                 ))
                 .type(type)
                 .build();
@@ -159,7 +160,7 @@ public class CatalogSystemViewTest extends BaseCatalogManagerTest {
 
         private static final List<ColumnParams> COLUMNS = List.of(
                 ColumnParams.builder().name("col1").type(INT32).build(),
-                ColumnParams.builder().name("col2").type(STRING).build()
+                ColumnParams.builder().name("col2").type(STRING).length(1 << 5).build()
         );
 
         static CreateSystemViewCommandBuilder newSystemView() {
@@ -179,6 +180,7 @@ public class CatalogSystemViewTest extends BaseCatalogManagerTest {
                     ColumnParams column = ColumnParams.builder()
                             .name("col-x")
                             .type(ColumnType.BYTE_ARRAY)
+                            .length(1 << 5)
                             .build();
 
                     List<ColumnParams> columns = new ArrayList<>(COLUMNS);
@@ -198,6 +200,7 @@ public class CatalogSystemViewTest extends BaseCatalogManagerTest {
                     ColumnParams column = ColumnParams.builder()
                             .name(COLUMNS.get(0).name())
                             .type(ColumnType.BYTE_ARRAY)
+                            .length(1 << 5)
                             .build();
 
                     List<ColumnParams> columns = new ArrayList<>(COLUMNS);
@@ -224,7 +227,7 @@ public class CatalogSystemViewTest extends BaseCatalogManagerTest {
                 .name(SYS_VIEW_NAME)
                 .columns(List.of(
                         ColumnParams.builder().name("col1").type(INT32).build(),
-                        ColumnParams.builder().name("col2").type(STRING).build()
+                        ColumnParams.builder().name("col2").type(STRING).length(1 << 5).build()
                 ))
                 .type(type)
                 .build();
@@ -274,7 +277,7 @@ public class CatalogSystemViewTest extends BaseCatalogManagerTest {
                 .name(TABLE_NAME)
                 .columns(List.of(
                         ColumnParams.builder().name("col1").type(INT32).build(),
-                        ColumnParams.builder().name("col2").type(STRING).build()
+                        ColumnParams.builder().name("col2").type(STRING).length(1 << 5).build()
                 ))
                 .type(type)
                 .build();
@@ -289,7 +292,7 @@ public class CatalogSystemViewTest extends BaseCatalogManagerTest {
                 .name(SYS_VIEW_NAME)
                 .columns(List.of(
                         ColumnParams.builder().name("col1").type(INT32).build(),
-                        ColumnParams.builder().name("col2").type(STRING).build()
+                        ColumnParams.builder().name("col2").type(STRING).length(1 << 5).build()
                 ))
                 .type(type)
                 .build();
@@ -316,7 +319,7 @@ public class CatalogSystemViewTest extends BaseCatalogManagerTest {
                 .name(SYS_VIEW_NAME)
                 .columns(List.of(
                         ColumnParams.builder().name("col1").type(INT32).build(),
-                        ColumnParams.builder().name("col2").type(STRING).build()
+                        ColumnParams.builder().name("col2").type(STRING).length(1 << 5).build()
                 ))
                 .type(type)
                 .build();
diff --git a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/ColumnConstructionValidatorTest.java b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/ColumnConstructionValidatorTest.java
new file mode 100644
index 0000000000..ba8214952e
--- /dev/null
+++ b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/ColumnConstructionValidatorTest.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.catalog;
+
+import static org.apache.ignite.internal.catalog.CatalogTestUtils.DEFAULT_NULLABLE;
+import static org.apache.ignite.internal.catalog.CatalogTestUtils.columnParamsBuilder;
+import static org.apache.ignite.internal.catalog.CatalogTestUtils.initializeColumnWithDefaults;
+import static org.apache.ignite.internal.catalog.commands.ColumnParams.ERR_COL_PARAM_DEFINITION;
+import static org.apache.ignite.internal.catalog.commands.ColumnParams.ERR_COL_PARAM_NOT_APPLICABLE;
+import static org.apache.ignite.internal.catalog.commands.ColumnParams.ERR_COL_PARAM_VALIDATION;
+import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
+import static org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrowsWithCause;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import org.apache.ignite.internal.catalog.commands.ColumnParams;
+import org.apache.ignite.internal.catalog.commands.ColumnParams.Builder;
+import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest;
+import org.apache.ignite.sql.ColumnType;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+import org.junit.jupiter.params.provider.EnumSource.Mode;
+
+/** Test {@link ColumnParams} assembly and validation. */
+public class ColumnConstructionValidatorTest extends BaseIgniteAbstractTest {
+    @ParameterizedTest
+    @EnumSource(value = ColumnType.class, names = "NULL", mode = Mode.EXCLUDE)
+    public void testColumnSetPrecision(ColumnType type) {
+        Builder noPrecision = columnParamsBuilder("COL", type, DEFAULT_NULLABLE);
+        Builder invalidPrecision = columnParamsBuilder("COL", type, DEFAULT_NULLABLE);
+        Builder correctPrecision = columnParamsBuilder("COL", type, DEFAULT_NULLABLE);
+
+        initializeColumnWithDefaults(type, noPrecision);
+        initializeColumnWithDefaults(type, invalidPrecision);
+        initializeColumnWithDefaults(type, correctPrecision);
+
+        noPrecision.precision(null);
+        invalidPrecision.precision(-1);
+
+        if (type.precisionAllowed()) {
+            assertThrowsWithCause(noPrecision::build, CatalogValidationException.class,
+                    format(ERR_COL_PARAM_DEFINITION, "Precision", "COL", type.name()));
+
+            assertThrowsWithCause(invalidPrecision::build, CatalogValidationException.class,
+                    format(ERR_COL_PARAM_VALIDATION, "Precision", "COL", type.name()));
+
+            ColumnParams col = correctPrecision.build();
+            assertNotNull(col.precision());
+        } else {
+            correctPrecision.precision(1);
+
+            assertThrowsWithCause(correctPrecision::build, CatalogValidationException.class,
+                    format(ERR_COL_PARAM_NOT_APPLICABLE, "Precision", "COL", type.name()));
+        }
+    }
+
+    @ParameterizedTest
+    @EnumSource(value = ColumnType.class, names = "NULL", mode = Mode.EXCLUDE)
+    public void testColumnSetScale(ColumnType type) {
+        Builder noScale = columnParamsBuilder("COL", type, DEFAULT_NULLABLE);
+        Builder invalidScale = columnParamsBuilder("COL", type, DEFAULT_NULLABLE);
+        Builder correctScale = columnParamsBuilder("COL", type, DEFAULT_NULLABLE);
+
+        initializeColumnWithDefaults(type, noScale);
+        initializeColumnWithDefaults(type, invalidScale);
+        initializeColumnWithDefaults(type, correctScale);
+
+        noScale.scale(null);
+        invalidScale.scale(-1);
+
+        if (type.scaleAllowed()) {
+            assertThrowsWithCause(noScale::build, CatalogValidationException.class,
+                    format(ERR_COL_PARAM_DEFINITION, "Scale", "COL", type.name()));
+
+            assertThrowsWithCause(invalidScale::build, CatalogValidationException.class,
+                    format(ERR_COL_PARAM_VALIDATION, "Scale", "COL", type.name()));
+
+            ColumnParams col = correctScale.build();
+            assertNotNull(col.scale());
+        } else {
+            correctScale.scale(1);
+
+            assertThrowsWithCause(correctScale::build, CatalogValidationException.class,
+                    format(ERR_COL_PARAM_NOT_APPLICABLE, "Scale", "COL", type.name()));
+        }
+    }
+
+    @ParameterizedTest
+    @EnumSource(value = ColumnType.class, names = "NULL", mode = Mode.EXCLUDE)
+    public void testColumnSetLength(ColumnType type) {
+        Builder noLength = columnParamsBuilder("COL", type, DEFAULT_NULLABLE);
+        Builder invalidLength = columnParamsBuilder("COL", type, DEFAULT_NULLABLE);
+        Builder correctLength = columnParamsBuilder("COL", type, DEFAULT_NULLABLE);
+
+        initializeColumnWithDefaults(type, noLength);
+        initializeColumnWithDefaults(type, invalidLength);
+        initializeColumnWithDefaults(type, correctLength);
+
+        noLength.length(null);
+        invalidLength.length(-1);
+
+        if (type.lengthAllowed()) {
+            assertThrowsWithCause(noLength::build, CatalogValidationException.class,
+                    format(ERR_COL_PARAM_DEFINITION, "Length", "COL", type.name()));
+
+            assertThrowsWithCause(invalidLength::build, CatalogValidationException.class,
+                    format(ERR_COL_PARAM_VALIDATION, "Length", "COL", type.name()));
+
+            ColumnParams col = correctLength.build();
+            assertNotNull(col.length());
+        } else {
+            correctLength.length(1);
+
+            assertThrowsWithCause(correctLength::build, CatalogValidationException.class,
+                    format(ERR_COL_PARAM_NOT_APPLICABLE, "Length", "COL", type.name()));
+        }
+    }
+
+    @ParameterizedTest
+    @EnumSource(value = ColumnType.class, names = "NULL", mode = Mode.EXCLUDE)
+    public void testColumnEmptyName(ColumnType type) {
+        Builder colBuilder = columnParamsBuilder(null, type, DEFAULT_NULLABLE);
+        initializeColumnWithDefaults(type, colBuilder);
+
+        assertThrowsWithCause(colBuilder::build, CatalogValidationException.class, "Column name");
+    }
+
+    @Test
+    public void testColumnEmptyType() {
+        Builder colBuilder = columnParamsBuilder("COL", null, DEFAULT_NULLABLE);
+
+        assertThrowsWithCause(colBuilder::build, CatalogValidationException.class, "Type is not specified for column 'COL'");
+    }
+}
diff --git a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/AlterTableAddColumnCommandValidationTest.java b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/AlterTableAddColumnCommandValidationTest.java
index 41cb225f37..2ad5410fa9 100644
--- a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/AlterTableAddColumnCommandValidationTest.java
+++ b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/AlterTableAddColumnCommandValidationTest.java
@@ -81,43 +81,6 @@ public class AlterTableAddColumnCommandValidationTest extends AbstractCommandVal
         );
     }
 
-    @ParameterizedTest(name = "[{index}] ''{argumentsWithNames}''")
-    @MethodSource("nullAndBlankStrings")
-    void tableColumnNameMustNotBeNullOrBlank(String name) {
-        AlterTableAddColumnCommandBuilder builder = AlterTableAddColumnCommand.builder();
-
-        builder = fillProperties(builder);
-
-        builder.columns(List.of(
-                ColumnParams.builder().name(name).build()
-        ));
-
-        assertThrowsWithCause(
-                builder::build,
-                CatalogValidationException.class,
-                "Name of the column can't be null or blank"
-        );
-    }
-
-    @Test
-    void tableColumnShouldHaveType() {
-        AlterTableAddColumnCommandBuilder builder = AlterTableAddColumnCommand.builder();
-
-        builder = fillProperties(builder)
-                .columns(List.of(
-                        ColumnParams.builder()
-                                .name("C")
-                                .type(null)
-                                .build()
-                ));
-
-        assertThrowsWithCause(
-                builder::build,
-                CatalogValidationException.class,
-                "Missing column type: C"
-        );
-    }
-
     @Test
     void columnShouldNotHaveDuplicates() {
         AlterTableAddColumnCommandBuilder builder = AlterTableAddColumnCommand.builder();
diff --git a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/AlterTableAlterColumnCommandValidationTest.java b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/AlterTableAlterColumnCommandValidationTest.java
index a09b6465e8..50a00716dc 100644
--- a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/AlterTableAlterColumnCommandValidationTest.java
+++ b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/AlterTableAlterColumnCommandValidationTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.catalog.commands;
 
+import static org.apache.ignite.internal.catalog.CatalogTestUtils.initializeColumnWithDefaults;
 import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
 import static org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrowsWithCause;
 
@@ -180,7 +181,7 @@ public class AlterTableAlterColumnCommandValidationTest extends AbstractCommandV
                 .schemaName(SCHEMA_NAME)
                 .tableName(tableName)
                 .columns(List.of(
-                        ColumnParams.builder().name(columnName).type(ColumnType.DECIMAL).precision(10).build())
+                        ColumnParams.builder().name(columnName).type(ColumnType.DECIMAL).precision(10).scale(0).build())
                 )
                 .primaryKeyColumns(List.of(columnName))
         );
@@ -280,9 +281,9 @@ public class AlterTableAlterColumnCommandValidationTest extends AbstractCommandV
                                 .name("ID")
                                 .type(ColumnType.INT32)
                                 .build(),
-                        ColumnParams.builder()
+                        initializeColumnWithDefaults(from, ColumnParams.builder()
                                 .name(columnName)
-                                .type(from)
+                                .type(from))
                                 .build())
                 )
                 .primaryKeyColumns(List.of("ID"))
@@ -305,7 +306,7 @@ public class AlterTableAlterColumnCommandValidationTest extends AbstractCommandV
     }
 
     @ParameterizedTest
-    @EnumSource(mode = Mode.EXCLUDE, value = ColumnType.class, names = "DECIMAL")
+    @EnumSource(mode = Mode.EXCLUDE, value = ColumnType.class, names = {"DECIMAL", "NULL"})
     void precisionCannotBeChangedIfTypeIsNotDecimal(ColumnType type) {
         String tableName = "TEST";
         String columnName = "VAL";
@@ -313,13 +314,13 @@ public class AlterTableAlterColumnCommandValidationTest extends AbstractCommandV
                 .schemaName(SCHEMA_NAME)
                 .tableName(tableName)
                 .columns(List.of(
-                        ColumnParams.builder()
+                        initializeColumnWithDefaults(ColumnType.INT64, ColumnParams.builder()
                                 .name("ID")
-                                .type(ColumnType.INT64)
+                                .type(ColumnType.INT64))
                                 .build(),
-                        ColumnParams.builder()
+                        initializeColumnWithDefaults(type, ColumnParams.builder()
                                 .name(columnName)
-                                .type(type)
+                                .type(type))
                                 .build())
                 )
                 .primaryKeyColumns(List.of("ID"))
@@ -356,6 +357,7 @@ public class AlterTableAlterColumnCommandValidationTest extends AbstractCommandV
                         ColumnParams.builder()
                                 .name(columnName)
                                 .type(ColumnType.DECIMAL)
+                                .scale(0)
                                 .precision(10)
                                 .build())
                 )
@@ -419,7 +421,7 @@ public class AlterTableAlterColumnCommandValidationTest extends AbstractCommandV
     }
 
     @ParameterizedTest
-    @EnumSource(mode = Mode.EXCLUDE, value = ColumnType.class, names = {"STRING", "BYTE_ARRAY"})
+    @EnumSource(mode = Mode.EXCLUDE, value = ColumnType.class, names = {"STRING", "BYTE_ARRAY", "NULL"})
     void lengthCannotBeChangedForNonVariableTypes(ColumnType type) {
         String tableName = "TEST";
         String columnName = "VAL";
@@ -431,9 +433,9 @@ public class AlterTableAlterColumnCommandValidationTest extends AbstractCommandV
                                 .name("ID")
                                 .type(ColumnType.INT64)
                                 .build(),
-                        ColumnParams.builder()
+                        initializeColumnWithDefaults(type, ColumnParams.builder()
                                 .name(columnName)
-                                .type(type)
+                                .type(type))
                                 .build())
                 )
                 .primaryKeyColumns(List.of("ID"))
@@ -533,7 +535,7 @@ public class AlterTableAlterColumnCommandValidationTest extends AbstractCommandV
         List<Arguments> arguments = new ArrayList<>();
         for (ColumnType from : ColumnType.values()) {
             for (ColumnType to : ColumnType.values()) {
-                if (from != to && !CatalogUtils.isSupportedColumnTypeChange(from, to)) {
+                if (from != to && !CatalogUtils.isSupportedColumnTypeChange(from, to) && from != ColumnType.NULL) {
                     arguments.add(Arguments.of(from, to));
                 }
             }
diff --git a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/CreateSystemViewCommandValidationTest.java b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/CreateSystemViewCommandValidationTest.java
index bff36ed3da..88e7255cc8 100644
--- a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/CreateSystemViewCommandValidationTest.java
+++ b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/CreateSystemViewCommandValidationTest.java
@@ -58,35 +58,6 @@ public class CreateSystemViewCommandValidationTest extends AbstractCommandValida
         expectValidationError(builder::build, "System view should have at least one column");
     }
 
-    @ParameterizedTest(name = "[{index}] ''{argumentsWithNames}''")
-    @MethodSource("nullAndBlankStrings")
-    void columnNameMustNotBeNullOrBlank(String name) {
-        CreateSystemViewCommandBuilder builder = CreateSystemViewCommand.builder();
-
-        builder = fillProperties(builder);
-
-        builder.columns(List.of(
-                ColumnParams.builder().name(name).build()
-        ));
-
-        expectValidationError(builder::build, "Name of the column can't be null or blank");
-    }
-
-    @Test
-    void columnShouldHaveType() {
-        CreateSystemViewCommandBuilder builder = CreateSystemViewCommand.builder();
-
-        builder = fillProperties(builder)
-                .columns(List.of(
-                        ColumnParams.builder()
-                                .name("C")
-                                .type(null)
-                                .build()
-                ));
-
-        expectValidationError(builder::build, "Missing column type: C");
-    }
-
     @Test
     void columnShouldNotHaveDuplicates() {
         CreateSystemViewCommandBuilder builder = CreateSystemViewCommand.builder();
diff --git a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/CreateTableCommandValidationTest.java b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/CreateTableCommandValidationTest.java
index f4ad02a8f0..7d76984d11 100644
--- a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/CreateTableCommandValidationTest.java
+++ b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/CreateTableCommandValidationTest.java
@@ -81,43 +81,6 @@ public class CreateTableCommandValidationTest extends AbstractCommandValidationT
         );
     }
 
-    @ParameterizedTest(name = "[{index}] ''{argumentsWithNames}''")
-    @MethodSource("nullAndBlankStrings")
-    void tableColumnNameMustNotBeNullOrBlank(String name) {
-        CreateTableCommandBuilder builder = CreateTableCommand.builder();
-
-        builder = fillProperties(builder);
-
-        builder.columns(List.of(
-                ColumnParams.builder().name(name).build()
-        ));
-
-        assertThrowsWithCause(
-                builder::build,
-                CatalogValidationException.class,
-                "Name of the column can't be null or blank"
-        );
-    }
-
-    @Test
-    void tableColumnShouldHaveType() {
-        CreateTableCommandBuilder builder = CreateTableCommand.builder();
-
-        builder = fillProperties(builder)
-                .columns(List.of(
-                        ColumnParams.builder()
-                                .name("C")
-                                .type(null)
-                                .build()
-                ));
-
-        assertThrowsWithCause(
-                builder::build,
-                CatalogValidationException.class,
-                "Missing column type: C"
-        );
-    }
-
     @Test
     void columnShouldNotHaveDuplicates() {
         CreateTableCommandBuilder builder = CreateTableCommand.builder();
diff --git a/modules/catalog/src/testFixtures/java/org/apache/ignite/internal/catalog/BaseCatalogManagerTest.java b/modules/catalog/src/testFixtures/java/org/apache/ignite/internal/catalog/BaseCatalogManagerTest.java
index 997406ba46..f3d4e7bbab 100644
--- a/modules/catalog/src/testFixtures/java/org/apache/ignite/internal/catalog/BaseCatalogManagerTest.java
+++ b/modules/catalog/src/testFixtures/java/org/apache/ignite/internal/catalog/BaseCatalogManagerTest.java
@@ -25,16 +25,12 @@ import static org.mockito.Mockito.spy;
 
 import java.util.List;
 import java.util.Objects;
-import java.util.Set;
 import java.util.stream.Stream;
-import org.apache.ignite.internal.catalog.commands.AlterTableAddColumnCommand;
-import org.apache.ignite.internal.catalog.commands.AlterTableDropColumnCommand;
 import org.apache.ignite.internal.catalog.commands.ColumnParams;
 import org.apache.ignite.internal.catalog.commands.CreateHashIndexCommand;
 import org.apache.ignite.internal.catalog.commands.CreateSortedIndexCommand;
 import org.apache.ignite.internal.catalog.commands.CreateTableCommand;
 import org.apache.ignite.internal.catalog.commands.CreateTableCommandBuilder;
-import org.apache.ignite.internal.catalog.commands.DropTableCommand;
 import org.apache.ignite.internal.catalog.descriptors.CatalogColumnCollation;
 import org.apache.ignite.internal.catalog.storage.UpdateLog;
 import org.apache.ignite.internal.catalog.storage.UpdateLogImpl;
@@ -47,7 +43,6 @@ import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest;
 import org.apache.ignite.internal.util.IgniteUtils;
 import org.apache.ignite.internal.vault.VaultManager;
 import org.apache.ignite.internal.vault.inmemory.InMemoryVaultService;
-import org.apache.ignite.sql.ColumnType;
 import org.jetbrains.annotations.Nullable;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
@@ -168,32 +163,4 @@ public abstract class BaseCatalogManagerTest extends BaseIgniteAbstractTest {
                 .primaryKeyColumns(primaryKeys)
                 .colocationColumns(colocationColumns);
     }
-
-    protected static ColumnParams columnParams(String name, ColumnType type) {
-        return columnParams(name, type, false);
-    }
-
-    protected static ColumnParams columnParams(String name, ColumnType type, boolean nullable) {
-        return columnParamsBuilder(name, type, nullable).build();
-    }
-
-    protected static ColumnParams.Builder columnParamsBuilder(String name, ColumnType type) {
-        return columnParamsBuilder(name, type, false);
-    }
-
-    protected static ColumnParams.Builder columnParamsBuilder(String name, ColumnType type, boolean nullable) {
-        return ColumnParams.builder().name(name).nullable(nullable).type(type);
-    }
-
-    protected static CatalogCommand dropTableCommand(String tableName) {
-        return DropTableCommand.builder().schemaName(DEFAULT_SCHEMA_NAME).tableName(tableName).build();
-    }
-
-    protected static CatalogCommand dropColumnParams(String... columns) {
-        return AlterTableDropColumnCommand.builder().schemaName(DEFAULT_SCHEMA_NAME).tableName(TABLE_NAME).columns(Set.of(columns)).build();
-    }
-
-    protected static CatalogCommand addColumnParams(ColumnParams... columns) {
-        return AlterTableAddColumnCommand.builder().schemaName(DEFAULT_SCHEMA_NAME).tableName(TABLE_NAME).columns(List.of(columns)).build();
-    }
 }
diff --git a/modules/catalog/src/testFixtures/java/org/apache/ignite/internal/catalog/CatalogTestUtils.java b/modules/catalog/src/testFixtures/java/org/apache/ignite/internal/catalog/CatalogTestUtils.java
index 03b15ac741..475a73e79d 100644
--- a/modules/catalog/src/testFixtures/java/org/apache/ignite/internal/catalog/CatalogTestUtils.java
+++ b/modules/catalog/src/testFixtures/java/org/apache/ignite/internal/catalog/CatalogTestUtils.java
@@ -17,9 +17,17 @@
 
 package org.apache.ignite.internal.catalog;
 
+import static org.apache.ignite.internal.catalog.CatalogService.DEFAULT_SCHEMA_NAME;
 import static org.apache.ignite.internal.testframework.matchers.CompletableFutureMatcher.willCompleteSuccessfully;
 import static org.hamcrest.MatcherAssert.assertThat;
 
+import java.util.List;
+import java.util.Set;
+import org.apache.ignite.internal.catalog.commands.AlterTableAddColumnCommand;
+import org.apache.ignite.internal.catalog.commands.AlterTableDropColumnCommand;
+import org.apache.ignite.internal.catalog.commands.ColumnParams;
+import org.apache.ignite.internal.catalog.commands.ColumnParams.Builder;
+import org.apache.ignite.internal.catalog.commands.DropTableCommand;
 import org.apache.ignite.internal.catalog.storage.UpdateLogImpl;
 import org.apache.ignite.internal.hlc.HybridClock;
 import org.apache.ignite.internal.metastorage.MetaStorageManager;
@@ -27,6 +35,7 @@ import org.apache.ignite.internal.metastorage.impl.StandaloneMetaStorageManager;
 import org.apache.ignite.internal.metastorage.server.SimpleInMemoryKeyValueStorage;
 import org.apache.ignite.internal.vault.VaultManager;
 import org.apache.ignite.internal.vault.inmemory.InMemoryVaultService;
+import org.apache.ignite.sql.ColumnType;
 
 /**
  * Utilities for working with the catalog in tests.
@@ -114,4 +123,90 @@ public class CatalogTestUtils {
             }
         };
     }
+
+    /** Default nullable behavior. */
+    public static final boolean DEFAULT_NULLABLE = false;
+
+    /** Append precision\scale according to type requirement. */
+    public static Builder initializeColumnWithDefaults(ColumnType type, Builder colBuilder) {
+        if (type.precisionAllowed()) {
+            colBuilder.precision(11);
+        }
+
+        if (type.scaleAllowed()) {
+            colBuilder.scale(0);
+        }
+
+        if (type.lengthAllowed()) {
+            colBuilder.length(1 << 5);
+        }
+
+        return colBuilder;
+    }
+
+    /** Append precision according to type requirement. */
+    public static void applyNecessaryPrecision(ColumnType type, Builder colBuilder) {
+        if (type.precisionAllowed()) {
+            colBuilder.precision(11);
+        }
+    }
+
+    /** Append length according to type requirement. */
+    public static void applyNecessaryLength(ColumnType type, Builder colBuilder) {
+        if (type.lengthAllowed()) {
+            colBuilder.length(1 << 5);
+        }
+    }
+
+    static ColumnParams columnParams(String name, ColumnType type) {
+        return columnParams(name, type, DEFAULT_NULLABLE);
+    }
+
+    static ColumnParams columnParams(String name, ColumnType type, boolean nullable) {
+        return columnParamsBuilder(name, type, nullable).build();
+    }
+
+    static ColumnParams columnParams(String name, ColumnType type, boolean nullable, int precision) {
+        return columnParamsBuilder(name, type, nullable, precision).build();
+    }
+
+    static ColumnParams columnParams(String name, ColumnType type, boolean nullable, int precision, int scale) {
+        return columnParamsBuilder(name, type, nullable, precision, scale).build();
+    }
+
+    static ColumnParams columnParams(String name, ColumnType type, int length, boolean nullable) {
+        return columnParamsBuilder(name, type, length, nullable).build();
+    }
+
+    static ColumnParams.Builder columnParamsBuilder(String name, ColumnType type) {
+        return columnParamsBuilder(name, type, DEFAULT_NULLABLE);
+    }
+
+    static ColumnParams.Builder columnParamsBuilder(String name, ColumnType type, boolean nullable) {
+        return ColumnParams.builder().name(name).nullable(nullable).type(type);
+    }
+
+    static ColumnParams.Builder columnParamsBuilder(String name, ColumnType type, boolean nullable, int precision) {
+        return ColumnParams.builder().name(name).nullable(nullable).type(type).precision(precision);
+    }
+
+    static ColumnParams.Builder columnParamsBuilder(String name, ColumnType type, boolean nullable, int precision, int scale) {
+        return ColumnParams.builder().name(name).nullable(nullable).type(type).precision(precision).scale(scale);
+    }
+
+    static ColumnParams.Builder columnParamsBuilder(String name, ColumnType type, int length, boolean nullable) {
+        return ColumnParams.builder().name(name).nullable(nullable).type(type).length(length);
+    }
+
+    static CatalogCommand dropTableCommand(String tableName) {
+        return DropTableCommand.builder().schemaName(DEFAULT_SCHEMA_NAME).tableName(tableName).build();
+    }
+
+    static CatalogCommand dropColumnParams(String tableName, String... columns) {
+        return AlterTableDropColumnCommand.builder().schemaName(DEFAULT_SCHEMA_NAME).tableName(tableName).columns(Set.of(columns)).build();
+    }
+
+    static CatalogCommand addColumnParams(String tableName, ColumnParams... columns) {
+        return AlterTableAddColumnCommand.builder().schemaName(DEFAULT_SCHEMA_NAME).tableName(tableName).columns(List.of(columns)).build();
+    }
 }
diff --git a/modules/client-common/src/main/java/org/apache/ignite/internal/jdbc/JdbcConverterUtils.java b/modules/client-common/src/main/java/org/apache/ignite/internal/jdbc/JdbcConverterUtils.java
index c0c77cd82e..96bbd477fe 100644
--- a/modules/client-common/src/main/java/org/apache/ignite/internal/jdbc/JdbcConverterUtils.java
+++ b/modules/client-common/src/main/java/org/apache/ignite/internal/jdbc/JdbcConverterUtils.java
@@ -41,7 +41,7 @@ public class JdbcConverterUtils {
             case TIMESTAMP:
                 return Timestamp.class;
             default:
-                return ColumnType.columnTypeToClass(type);
+                return type.javaClass();
         }
     }
 }
diff --git a/modules/client/src/main/java/org/apache/ignite/internal/client/sql/ClientColumnMetadata.java b/modules/client/src/main/java/org/apache/ignite/internal/client/sql/ClientColumnMetadata.java
index 397187e3ce..bd1a8e8e14 100644
--- a/modules/client/src/main/java/org/apache/ignite/internal/client/sql/ClientColumnMetadata.java
+++ b/modules/client/src/main/java/org/apache/ignite/internal/client/sql/ClientColumnMetadata.java
@@ -80,7 +80,7 @@ public class ClientColumnMetadata implements ColumnMetadata {
     /** {@inheritDoc} */
     @Override
     public Class<?> valueClass() {
-        return ColumnType.columnTypeToClass(type);
+        return type.javaClass();
     }
 
     /** {@inheritDoc} */
diff --git a/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/rebalance/DistributionZoneRebalanceEngineTest.java b/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/rebalance/DistributionZoneRebalanceEngineTest.java
index acf9e9180d..74a0037207 100644
--- a/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/rebalance/DistributionZoneRebalanceEngineTest.java
+++ b/modules/distribution-zones/src/test/java/org/apache/ignite/internal/distributionzones/rebalance/DistributionZoneRebalanceEngineTest.java
@@ -508,7 +508,7 @@ public class DistributionZoneRebalanceEngineTest extends IgniteAbstractTest {
                 DEFAULT_SCHEMA_NAME,
                 zoneName,
                 tableName,
-                List.of(ColumnParams.builder().name("k1").type(STRING).build()),
+                List.of(ColumnParams.builder().name("k1").type(STRING).length(100).build()),
                 List.of("k1")
         );
     }
diff --git a/modules/index/src/test/java/org/apache/ignite/internal/index/IndexManagerTest.java b/modules/index/src/test/java/org/apache/ignite/internal/index/IndexManagerTest.java
index 1da4ee14c7..7f35f260d9 100644
--- a/modules/index/src/test/java/org/apache/ignite/internal/index/IndexManagerTest.java
+++ b/modules/index/src/test/java/org/apache/ignite/internal/index/IndexManagerTest.java
@@ -131,8 +131,8 @@ public class IndexManagerTest extends BaseIgniteAbstractTest {
                 DEFAULT_ZONE_NAME,
                 TABLE_NAME,
                 List.of(
-                        ColumnParams.builder().name("c1").type(STRING).build(),
-                        ColumnParams.builder().name("c2").type(STRING).build()
+                        ColumnParams.builder().name("c1").length(100).type(STRING).build(),
+                        ColumnParams.builder().name("c2").length(100).type(STRING).build()
                 ),
                 List.of("c1")
         );
diff --git a/modules/platforms/dotnet/Apache.Ignite.Tests/Sql/IgniteDbDataReaderTests.cs b/modules/platforms/dotnet/Apache.Ignite.Tests/Sql/IgniteDbDataReaderTests.cs
index 0ab4ab8d9e..8767ae3273 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Tests/Sql/IgniteDbDataReaderTests.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Tests/Sql/IgniteDbDataReaderTests.cs
@@ -401,7 +401,7 @@ public class IgniteDbDataReaderTests : IgniteTestsBase
         Assert.AreEqual(typeof(string), schema[1].DataType);
         Assert.AreEqual("varchar", schema[1].DataTypeName);
         Assert.IsTrue(schema[1].AllowDBNull);
-        Assert.AreEqual(65536, schema[1].NumericPrecision);
+        Assert.AreEqual(1000, schema[1].NumericPrecision);
         Assert.IsNull(schema[1].NumericScale);
         Assert.IsNotNull((schema[1] as IgniteDbColumn)?.ColumnMetadata);
     }
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItIgniteNodeRestartTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItIgniteNodeRestartTest.java
index 4eab7d6de6..eb3da1667c 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItIgniteNodeRestartTest.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItIgniteNodeRestartTest.java
@@ -870,6 +870,8 @@ public class ItIgniteNodeRestartTest extends BaseIgniteRestartTest {
         for (int i = 0; i < 100; i++) {
             Tuple row = table.keyValueView().get(null, Tuple.create().set("id", i + 500));
 
+            Objects.requireNonNull(row, "row");
+
             assertEquals(VALUE_PRODUCER.apply(i + 500), row.stringValue("name"));
         }
     }
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/PlatformTestNodeRunner.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/PlatformTestNodeRunner.java
index bb9c871f9d..b23505bca1 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/PlatformTestNodeRunner.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/PlatformTestNodeRunner.java
@@ -19,6 +19,7 @@ package org.apache.ignite.internal.runner.app;
 
 import static java.util.stream.Collectors.toList;
 import static org.apache.ignite.internal.catalog.CatalogService.DEFAULT_SCHEMA_NAME;
+import static org.apache.ignite.internal.catalog.commands.CatalogUtils.MAX_TIME_PRECISION;
 import static org.apache.ignite.internal.distributionzones.DistributionZonesTestUtil.createZone;
 import static org.apache.ignite.internal.table.TableTestUtils.createTable;
 import static org.apache.ignite.internal.testframework.IgniteTestUtils.escapeWindowsPath;
@@ -70,7 +71,6 @@ import org.apache.ignite.internal.schema.SchemaDescriptor;
 import org.apache.ignite.internal.schema.marshaller.TupleMarshallerException;
 import org.apache.ignite.internal.schema.marshaller.TupleMarshallerImpl;
 import org.apache.ignite.internal.schema.row.Row;
-import org.apache.ignite.internal.schema.testutils.definition.ColumnType.TemporalColumnType;
 import org.apache.ignite.internal.table.RecordBinaryViewImpl;
 import org.apache.ignite.internal.table.impl.DummySchemaManagerImpl;
 import org.apache.ignite.internal.testframework.IgniteTestUtils;
@@ -284,12 +284,12 @@ public class PlatformTestNodeRunner {
                 TABLE_NAME,
                 List.of(
                         ColumnParams.builder().name(keyCol).type(INT64).build(),
-                        ColumnParams.builder().name("VAL").type(STRING).nullable(true).build()
+                        ColumnParams.builder().name("VAL").type(STRING).length(1000).nullable(true).build()
                 ),
                 List.of(keyCol)
         );
 
-        int maxTimePrecision = TemporalColumnType.MAX_TIME_PRECISION;
+        int maxTimePrecision = MAX_TIME_PRECISION;
 
         createTable(
                 ignite.catalogManager(),
@@ -298,7 +298,7 @@ public class PlatformTestNodeRunner {
                 TABLE_NAME_ALL_COLUMNS,
                 List.of(
                         ColumnParams.builder().name(keyCol).type(INT64).build(),
-                        ColumnParams.builder().name("STR").type(STRING).nullable(true).build(),
+                        ColumnParams.builder().name("STR").type(STRING).nullable(true).length(1000).build(),
                         ColumnParams.builder().name("INT8").type(INT8).nullable(true).build(),
                         ColumnParams.builder().name("INT16").type(INT16).nullable(true).build(),
                         ColumnParams.builder().name("INT32").type(INT32).nullable(true).build(),
@@ -307,14 +307,14 @@ public class PlatformTestNodeRunner {
                         ColumnParams.builder().name("DOUBLE").type(DOUBLE).nullable(true).build(),
                         ColumnParams.builder().name("UUID").type(UUID).nullable(true).build(),
                         ColumnParams.builder().name("DATE").type(DATE).nullable(true).build(),
-                        ColumnParams.builder().name("BITMASK").type(BITMASK).length(64).nullable(true).build(),
+                        ColumnParams.builder().name("BITMASK").type(BITMASK).length(1000).nullable(true).build(),
                         ColumnParams.builder().name("TIME").type(TIME).precision(maxTimePrecision).nullable(true).build(),
                         ColumnParams.builder().name("TIME2").type(TIME).precision(2).nullable(true).build(),
                         ColumnParams.builder().name("DATETIME").type(DATETIME).precision(maxTimePrecision).nullable(true).build(),
                         ColumnParams.builder().name("DATETIME2").type(DATETIME).precision(3).nullable(true).build(),
                         ColumnParams.builder().name("TIMESTAMP").type(TIMESTAMP).precision(maxTimePrecision).nullable(true).build(),
                         ColumnParams.builder().name("TIMESTAMP2").type(TIMESTAMP).precision(4).nullable(true).build(),
-                        ColumnParams.builder().name("BLOB").type(BYTE_ARRAY).nullable(true).build(),
+                        ColumnParams.builder().name("BLOB").type(BYTE_ARRAY).length(1000).nullable(true).build(),
                         ColumnParams.builder().name("DECIMAL").type(DECIMAL).precision(19).scale(3).nullable(true).build(),
                         ColumnParams.builder().name("BOOLEAN").type(BOOLEAN).nullable(true).build()
                 ),
@@ -329,7 +329,7 @@ public class PlatformTestNodeRunner {
                 TABLE_NAME_ALL_COLUMNS_SQL,
                 List.of(
                         ColumnParams.builder().name(keyCol).type(INT64).build(),
-                        ColumnParams.builder().name("STR").type(STRING).nullable(true).build(),
+                        ColumnParams.builder().name("STR").type(STRING).length(1000).nullable(true).build(),
                         ColumnParams.builder().name("INT8").type(INT8).nullable(true).build(),
                         ColumnParams.builder().name("INT16").type(INT16).nullable(true).build(),
                         ColumnParams.builder().name("INT32").type(INT32).nullable(true).build(),
@@ -344,7 +344,7 @@ public class PlatformTestNodeRunner {
                         ColumnParams.builder().name("DATETIME2").type(DATETIME).precision(maxTimePrecision).nullable(true).build(),
                         ColumnParams.builder().name("TIMESTAMP").type(TIMESTAMP).precision(maxTimePrecision).nullable(true).build(),
                         ColumnParams.builder().name("TIMESTAMP2").type(TIMESTAMP).precision(maxTimePrecision).nullable(true).build(),
-                        ColumnParams.builder().name("BLOB").type(BYTE_ARRAY).nullable(true).build(),
+                        ColumnParams.builder().name("BLOB").type(BYTE_ARRAY).length(1000).nullable(true).build(),
                         ColumnParams.builder().name("DECIMAL").type(DECIMAL).precision(19).scale(3).nullable(true).build(),
                         ColumnParams.builder().name("BOOLEAN").type(BOOLEAN).nullable(true).build()
                 ),
@@ -395,8 +395,8 @@ public class PlatformTestNodeRunner {
 
         createTwoColumnTable(
                 ignite,
-                ColumnParams.builder().name("KEY").type(org.apache.ignite.sql.ColumnType.UUID).build(),
-                ColumnParams.builder().name("VAL").type(org.apache.ignite.sql.ColumnType.UUID).nullable(true).build()
+                ColumnParams.builder().name("KEY").type(UUID).build(),
+                ColumnParams.builder().name("VAL").type(UUID).nullable(true).build()
         );
 
         createTwoColumnTable(
@@ -407,8 +407,8 @@ public class PlatformTestNodeRunner {
 
         createTwoColumnTable(
                 ignite,
-                ColumnParams.builder().name("KEY").type(STRING).build(),
-                ColumnParams.builder().name("VAL").type(STRING).nullable(true).build()
+                ColumnParams.builder().name("KEY").type(STRING).length(1000).build(),
+                ColumnParams.builder().name("VAL").type(STRING).length(1000).nullable(true).build()
         );
 
         createTwoColumnTable(
@@ -437,20 +437,20 @@ public class PlatformTestNodeRunner {
 
         createTwoColumnTable(
                 ignite,
-                ColumnParams.builder().name("KEY").type(NUMBER).precision(Integer.MAX_VALUE).build(),
-                ColumnParams.builder().name("VAL").type(NUMBER).precision(Integer.MAX_VALUE).nullable(true).build()
+                ColumnParams.builder().name("KEY").type(NUMBER).precision(15).build(),
+                ColumnParams.builder().name("VAL").type(NUMBER).precision(15).nullable(true).build()
         );
 
         createTwoColumnTable(
                 ignite,
-                ColumnParams.builder().name("KEY").type(BYTE_ARRAY).build(),
-                ColumnParams.builder().name("VAL").type(BYTE_ARRAY).nullable(true).build()
+                ColumnParams.builder().name("KEY").type(BYTE_ARRAY).length(1000).build(),
+                ColumnParams.builder().name("VAL").type(BYTE_ARRAY).length(1000).nullable(true).build()
         );
 
         createTwoColumnTable(
                 ignite,
-                ColumnParams.builder().name("KEY").type(BITMASK).length(32).build(),
-                ColumnParams.builder().name("VAL").type(BITMASK).length(32).nullable(true).build()
+                ColumnParams.builder().name("KEY").type(BITMASK).length(1000).build(),
+                ColumnParams.builder().name("VAL").type(BITMASK).length(1000).nullable(true).build()
         );
     }
 
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItCommonApiTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItCommonApiTest.java
index d733a5dda7..6c298a6b4e 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItCommonApiTest.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItCommonApiTest.java
@@ -109,8 +109,7 @@ public class ItCommonApiTest extends ClusterPerClassIntegrationTest {
 
         // TODO: https://issues.apache.org/jira/browse/IGNITE-19162 Trim all less than millisecond information from timestamp
         //String tsStr = "2023-03-29T08:22:33.005007Z";
-        // TODO: IGNITE-20105 it should be "2023-03-29T08:22:33.005Z";
-        String tsStr = "2023-03-29T08:22:33Z";
+        String tsStr = "2023-03-29T08:22:33.005Z";
 
         Instant ins = Instant.parse(tsStr);
 
@@ -123,7 +122,7 @@ public class ItCommonApiTest extends ClusterPerClassIntegrationTest {
 
         Tuple rec = Tuple.create()
                 .set("KEY", 1)
-                .set("TIMESTAMP", LocalDateTime.of(2023, 3, 29, 8, 22, 33));
+                .set("TIMESTAMP", LocalDateTime.of(2023, 3, 29, 8, 22, 33, 5000000));
 
         tbl.recordView().insert(null, rec);
 
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItCreateTableDdlTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItCreateTableDdlTest.java
index 9ec47e0147..d03d2255a4 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItCreateTableDdlTest.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItCreateTableDdlTest.java
@@ -238,4 +238,17 @@ public class ItCreateTableDdlTest extends ClusterPerClassIntegrationTest {
                 () -> sql("create table t (id varchar primary key, val varchar default gen_random_uuid)")
         );
     }
+
+    @Test
+    public void dummyAlterColumnDataType() {
+        sql("CREATE TABLE t0 (ID INT PRIMARY KEY, C2 varbinary, C3 varchar, C4 varbinary(10), C5 varchar(11))");
+        sql("ALTER TABLE t0 ALTER COLUMN C2 SET DATA TYPE varbinary");
+        sql("ALTER TABLE t0 ALTER COLUMN C4 SET DATA TYPE varbinary(10)");
+        sql("ALTER TABLE t0 ALTER COLUMN C5 SET DATA TYPE varchar(11)");
+
+        sql("CREATE TABLE t1 (ID INT PRIMARY KEY, DECIMAL_C2 DECIMAL(2))");
+        sql("ALTER TABLE t1 ALTER COLUMN DECIMAL_C2 SET DATA TYPE DECIMAL");
+        assertThrowsSqlException(Sql.STMT_VALIDATION_ERR, "Decreasing the precision is not allowed",
+                () -> sql("ALTER TABLE t1 ALTER COLUMN DECIMAL_C2 SET DATA TYPE DECIMAL(1)"));
+    }
 }
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/datatypes/tests/DataTypeTestSpec.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/datatypes/tests/DataTypeTestSpec.java
index e6a540c1c6..2dfe70a0d1 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/datatypes/tests/DataTypeTestSpec.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/datatypes/tests/DataTypeTestSpec.java
@@ -47,7 +47,7 @@ public abstract class DataTypeTestSpec<T extends Comparable<T>> {
         // javaType is only used to restrict the generic parameter.
         this.columnType = columnType;
         this.typeName = typeName;
-        this.storageType = ColumnType.columnTypeToClass(columnType);
+        this.storageType = columnType.javaClass();
     }
 
     /** {@link ColumnType}. */
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/NativeType.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/NativeType.java
index 08662cfefe..d6dda099f3 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/NativeType.java
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/NativeType.java
@@ -145,5 +145,4 @@ public class NativeType implements Comparable<NativeType> {
                 "sizeInBytes", size,
                 "fixed", typeSpec.fixedLength());
     }
-
 }
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/NativeTypes.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/NativeTypes.java
index 6e2f635a98..e6d42bfd26 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/NativeTypes.java
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/NativeTypes.java
@@ -17,10 +17,12 @@
 
 package org.apache.ignite.internal.schema;
 
+import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_TIMESTAMP_PRECISION;
+import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_TIME_PRECISION;
+
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.BitSet;
-import org.apache.ignite.internal.catalog.commands.CatalogUtils;
 import org.jetbrains.annotations.Contract;
 import org.jetbrains.annotations.Nullable;
 
@@ -153,7 +155,7 @@ public class NativeTypes {
      * @see #time(int)
      */
     public static NativeType time() {
-        return TemporalNativeType.time(CatalogUtils.DEFAULT_TIME_PRECISION);
+        return TemporalNativeType.time(DEFAULT_TIME_PRECISION);
     }
 
     /**
@@ -173,7 +175,7 @@ public class NativeTypes {
      * @see #datetime(int)
      */
     public static NativeType datetime() {
-        return TemporalNativeType.datetime(CatalogUtils.DEFAULT_TIMESTAMP_PRECISION);
+        return TemporalNativeType.datetime(DEFAULT_TIMESTAMP_PRECISION);
     }
 
     /**
@@ -193,7 +195,7 @@ public class NativeTypes {
      * @see #timestamp(int)
      */
     public static NativeType timestamp() {
-        return TemporalNativeType.timestamp(CatalogUtils.DEFAULT_TIMESTAMP_PRECISION);
+        return TemporalNativeType.timestamp(DEFAULT_TIMESTAMP_PRECISION);
     }
 
     /**
diff --git a/modules/schema/src/test/java/org/apache/ignite/internal/schema/AbstractSchemaConverterTest.java b/modules/schema/src/test/java/org/apache/ignite/internal/schema/AbstractSchemaConverterTest.java
index 0135c76e79..ba18efd3f3 100644
--- a/modules/schema/src/test/java/org/apache/ignite/internal/schema/AbstractSchemaConverterTest.java
+++ b/modules/schema/src/test/java/org/apache/ignite/internal/schema/AbstractSchemaConverterTest.java
@@ -35,7 +35,6 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
-import org.apache.ignite.internal.catalog.commands.CatalogUtils;
 import org.apache.ignite.internal.schema.testutils.definition.ColumnType.DecimalColumnType;
 import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest;
 import org.apache.ignite.internal.util.ArrayUtils;
@@ -118,48 +117,6 @@ public class AbstractSchemaConverterTest extends BaseIgniteAbstractTest {
         return val;
     }
 
-    /** Creates a native type from given type spec. */
-    protected static NativeType specToType(NativeTypeSpec spec) {
-        switch (spec) {
-            case BOOLEAN:
-                return NativeTypes.BOOLEAN;
-            case INT8:
-                return NativeTypes.INT8;
-            case INT16:
-                return NativeTypes.INT16;
-            case INT32:
-                return NativeTypes.INT32;
-            case INT64:
-                return NativeTypes.INT64;
-            case FLOAT:
-                return NativeTypes.FLOAT;
-            case DOUBLE:
-                return NativeTypes.DOUBLE;
-            case DECIMAL:
-                return NativeTypes.decimalOf(10, 3);
-            case DATE:
-                return NativeTypes.DATE;
-            case TIME:
-                return NativeTypes.time();
-            case DATETIME:
-                return NativeTypes.datetime();
-            case TIMESTAMP:
-                return NativeTypes.timestamp();
-            case NUMBER:
-                return NativeTypes.numberOf(CatalogUtils.DEFAULT_DECIMAL_PRECISION);
-            case STRING:
-                return NativeTypes.stringOf(8);
-            case UUID:
-                return NativeTypes.UUID;
-            case BYTES:
-                return NativeTypes.blobOf(8);
-            case BITMASK:
-                return NativeTypes.bitmaskOf(10);
-            default:
-                throw new IllegalStateException("Unknown type spec [spec=" + spec + ']');
-        }
-    }
-
     /**
      * Converts the given value to a string representation.
      *
diff --git a/modules/schema/src/test/java/org/apache/ignite/internal/schema/catalog/CatalogToSchemaDescriptorConverterTest.java b/modules/schema/src/test/java/org/apache/ignite/internal/schema/catalog/CatalogToSchemaDescriptorConverterTest.java
index ee87e1ab30..581fa466f6 100644
--- a/modules/schema/src/test/java/org/apache/ignite/internal/schema/catalog/CatalogToSchemaDescriptorConverterTest.java
+++ b/modules/schema/src/test/java/org/apache/ignite/internal/schema/catalog/CatalogToSchemaDescriptorConverterTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.schema.catalog;
 
+import static org.apache.ignite.internal.schema.SchemaTestUtils.specToType;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.is;
diff --git a/modules/schema/src/test/java/org/apache/ignite/internal/schema/serializer/AbstractSerializerTest.java b/modules/schema/src/test/java/org/apache/ignite/internal/schema/serializer/AbstractSerializerTest.java
index 3e5a08fa73..8e7590ca7c 100644
--- a/modules/schema/src/test/java/org/apache/ignite/internal/schema/serializer/AbstractSerializerTest.java
+++ b/modules/schema/src/test/java/org/apache/ignite/internal/schema/serializer/AbstractSerializerTest.java
@@ -21,6 +21,7 @@ import static java.math.RoundingMode.HALF_UP;
 import static org.apache.ignite.internal.schema.DefaultValueGenerator.GEN_RANDOM_UUID;
 import static org.apache.ignite.internal.schema.DefaultValueProvider.constantProvider;
 import static org.apache.ignite.internal.schema.DefaultValueProvider.forValueGenerator;
+import static org.apache.ignite.internal.schema.SchemaTestUtils.specToType;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.empty;
 import static org.hamcrest.Matchers.equalTo;
@@ -45,7 +46,6 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
-import org.apache.ignite.internal.catalog.commands.CatalogUtils;
 import org.apache.ignite.internal.schema.Column;
 import org.apache.ignite.internal.schema.DefaultValueProvider.Type;
 import org.apache.ignite.internal.schema.NativeType;
@@ -320,48 +320,6 @@ public class AbstractSerializerTest {
         return val;
     }
 
-    /** Creates a column type from given type spec. */
-    protected static NativeType specToType(NativeTypeSpec spec) {
-        switch (spec) {
-            case BOOLEAN:
-                return NativeTypes.BOOLEAN;
-            case INT8:
-                return NativeTypes.INT8;
-            case INT16:
-                return NativeTypes.INT16;
-            case INT32:
-                return NativeTypes.INT32;
-            case INT64:
-                return NativeTypes.INT64;
-            case FLOAT:
-                return NativeTypes.FLOAT;
-            case DOUBLE:
-                return NativeTypes.DOUBLE;
-            case DECIMAL:
-                return NativeTypes.decimalOf(CatalogUtils.DEFAULT_DECIMAL_PRECISION, CatalogUtils.DEFAULT_SCALE);
-            case DATE:
-                return NativeTypes.DATE;
-            case TIME:
-                return NativeTypes.time();
-            case DATETIME:
-                return NativeTypes.datetime();
-            case TIMESTAMP:
-                return NativeTypes.timestamp();
-            case NUMBER:
-                return NativeTypes.numberOf(CatalogUtils.DEFAULT_DECIMAL_PRECISION);
-            case STRING:
-                return NativeTypes.stringOf(Byte.MAX_VALUE);
-            case UUID:
-                return NativeTypes.UUID;
-            case BYTES:
-                return NativeTypes.blobOf(Byte.MAX_VALUE);
-            case BITMASK:
-                return NativeTypes.bitmaskOf(Byte.MAX_VALUE);
-            default:
-                throw new IllegalStateException("Unknown type spec [spec=" + spec + ']');
-        }
-    }
-
     /** Creates a bit set from binary string. */
     private static BitSet fromBinString(String binString) {
         var bs = new BitSet();
diff --git a/modules/schema/src/testFixtures/java/org/apache/ignite/internal/schema/SchemaTestUtils.java b/modules/schema/src/testFixtures/java/org/apache/ignite/internal/schema/SchemaTestUtils.java
index 8fc609b339..fe5ca51dbd 100644
--- a/modules/schema/src/testFixtures/java/org/apache/ignite/internal/schema/SchemaTestUtils.java
+++ b/modules/schema/src/testFixtures/java/org/apache/ignite/internal/schema/SchemaTestUtils.java
@@ -150,6 +150,48 @@ public final class SchemaTestUtils {
         }
     }
 
+    /** Creates a native type from given type spec. */
+    public static NativeType specToType(NativeTypeSpec spec) {
+        switch (spec) {
+            case BOOLEAN:
+                return NativeTypes.BOOLEAN;
+            case INT8:
+                return NativeTypes.INT8;
+            case INT16:
+                return NativeTypes.INT16;
+            case INT32:
+                return NativeTypes.INT32;
+            case INT64:
+                return NativeTypes.INT64;
+            case FLOAT:
+                return NativeTypes.FLOAT;
+            case DOUBLE:
+                return NativeTypes.DOUBLE;
+            case DECIMAL:
+                return NativeTypes.decimalOf(10, 3);
+            case DATE:
+                return NativeTypes.DATE;
+            case TIME:
+                return NativeTypes.time();
+            case DATETIME:
+                return NativeTypes.datetime();
+            case TIMESTAMP:
+                return NativeTypes.timestamp();
+            case NUMBER:
+                return NativeTypes.numberOf(10);
+            case STRING:
+                return NativeTypes.stringOf(8);
+            case UUID:
+                return NativeTypes.UUID;
+            case BYTES:
+                return NativeTypes.blobOf(8);
+            case BITMASK:
+                return NativeTypes.bitmaskOf(16);
+            default:
+                throw new IllegalStateException("Unknown type spec [spec=" + spec + ']');
+        }
+    }
+
     /**
      * Ensure specified columns contains all type spec, presented in NativeTypeSpec.
      *
diff --git a/modules/schema/src/testFixtures/java/org/apache/ignite/internal/schema/testutils/definition/ColumnType.java b/modules/schema/src/testFixtures/java/org/apache/ignite/internal/schema/testutils/definition/ColumnType.java
index 96c795d463..ae31af2610 100644
--- a/modules/schema/src/testFixtures/java/org/apache/ignite/internal/schema/testutils/definition/ColumnType.java
+++ b/modules/schema/src/testFixtures/java/org/apache/ignite/internal/schema/testutils/definition/ColumnType.java
@@ -17,9 +17,12 @@
 
 package org.apache.ignite.internal.schema.testutils.definition;
 
+import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_TIMESTAMP_PRECISION;
+import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_TIME_PRECISION;
 import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_VARLEN_LENGTH;
 
 import java.util.Objects;
+import org.apache.ignite.internal.catalog.commands.CatalogUtils;
 
 /**
  * Predefined column types.
@@ -171,11 +174,11 @@ public class ColumnType {
      * of 0 (seconds).
      *
      * @return Native type.
-     * @see TemporalColumnType#DEFAULT_TIME_PRECISION
+     * @see CatalogUtils#DEFAULT_TIME_PRECISION
      * @see #time(int)
      */
     public static TemporalColumnType time() {
-        return new TemporalColumnType(ColumnTypeSpec.TIME, TemporalColumnType.DEFAULT_TIME_PRECISION);
+        return new TemporalColumnType(ColumnTypeSpec.TIME, DEFAULT_TIME_PRECISION);
     }
 
     /**
@@ -199,11 +202,11 @@ public class ColumnType {
      * Returns timezone-free datetime encoded as (date, time) with the default time precision of 6 (microseconds).
      *
      * @return Native type.
-     * @see TemporalColumnType#DEFAULT_TIMESTAMP_PRECISION
+     * @see CatalogUtils#DEFAULT_TIMESTAMP_PRECISION
      * @see #datetime(int)
      */
     public static TemporalColumnType datetime() {
-        return new TemporalColumnType(ColumnTypeSpec.DATETIME, TemporalColumnType.DEFAULT_TIMESTAMP_PRECISION);
+        return new TemporalColumnType(ColumnTypeSpec.DATETIME, DEFAULT_TIMESTAMP_PRECISION);
     }
 
     /**
@@ -229,11 +232,11 @@ public class ColumnType {
      * (microseconds).
      *
      * @return Native type.
-     * @see TemporalColumnType#DEFAULT_TIMESTAMP_PRECISION
+     * @see CatalogUtils#DEFAULT_TIMESTAMP_PRECISION
      * @see #timestamp(int)
      */
     public static TemporalColumnType timestamp() {
-        return new TemporalColumnType(ColumnTypeSpec.TIMESTAMP, TemporalColumnType.DEFAULT_TIMESTAMP_PRECISION);
+        return new TemporalColumnType(ColumnTypeSpec.TIMESTAMP, DEFAULT_TIMESTAMP_PRECISION);
     }
 
     /**
@@ -453,27 +456,6 @@ public class ColumnType {
      * Column type of variable length.
      */
     public static class TemporalColumnType extends ColumnType {
-        /**
-         * Default TIMESTAMP type precision: microseconds.
-         *
-         * <p>SQL99 part 2 section 6.1 syntax rule 30
-         */
-        public static final int DEFAULT_TIMESTAMP_PRECISION = 6;
-
-        /**
-         * Default TIME type precision: seconds.
-         *
-         * <p>SQL99 part 2 section 6.1 syntax rule 30
-         */
-        public static final int DEFAULT_TIME_PRECISION = 0;
-
-        /**
-         * Max TIME precision.
-         *
-         * <p>SQL99 part 2 section 6.1 syntax rule 32
-         */
-        public static final int MAX_TIME_PRECISION = 9;
-
         /** Fractional seconds precision. */
         private final int precision;
 
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/ColumnMetadataImpl.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/ColumnMetadataImpl.java
index 977814dd6d..4d87d46848 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/ColumnMetadataImpl.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/ColumnMetadataImpl.java
@@ -109,7 +109,7 @@ public class ColumnMetadataImpl implements ColumnMetadata {
     /** {@inheritDoc} */
     @Override
     public Class<?> valueClass() {
-        return ColumnType.columnTypeToClass(type);
+        return type.javaClass();
     }
 
     /** {@inheritDoc} */
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ddl/DdlToCatalogCommandConverter.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ddl/DdlToCatalogCommandConverter.java
index fa82855561..4f32a0d3ce 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ddl/DdlToCatalogCommandConverter.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ddl/DdlToCatalogCommandConverter.java
@@ -236,7 +236,7 @@ class DdlToCatalogCommandConverter {
                 .nullable(def.nullable())
                 .precision(def.precision())
                 .scale(def.scale())
-                .length(def.precision())
+                .length(def.length())
                 .defaultValue(convert(def.defaultValueDefinition()))
                 .build();
     }
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/ColumnDefinition.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/ColumnDefinition.java
index a999b727a1..a9e8bb96ea 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/ColumnDefinition.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/ColumnDefinition.java
@@ -17,8 +17,16 @@
 
 package org.apache.ignite.internal.sql.engine.prepare.ddl;
 
+import static org.apache.calcite.rel.type.RelDataType.PRECISION_NOT_SPECIFIED;
+import static org.apache.calcite.rel.type.RelDataType.SCALE_NOT_SPECIFIED;
+import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_LENGTH;
+import static org.apache.ignite.internal.catalog.commands.CatalogUtils.defaultLength;
+import static org.apache.ignite.internal.sql.engine.util.TypeUtils.columnType;
+
 import java.util.Objects;
 import org.apache.calcite.rel.type.RelDataType;
+import org.apache.ignite.sql.ColumnType;
+import org.jetbrains.annotations.Nullable;
 
 /** Defines a particular column within table. */
 public class ColumnDefinition {
@@ -28,6 +36,8 @@ public class ColumnDefinition {
 
     private final DefaultValueDefinition defaultValueDefinition;
 
+    private ColumnType colType;
+
     /** Creates a column definition. */
     public ColumnDefinition(String name, RelDataType type, DefaultValueDefinition defaultValueDefinition) {
         this.name = Objects.requireNonNull(name, "name");
@@ -70,14 +80,33 @@ public class ColumnDefinition {
     /**
      * Get column's precision.
      */
-    public Integer precision() {
-        return type.getPrecision() != RelDataType.PRECISION_NOT_SPECIFIED ? type.getPrecision() : null;
+    public @Nullable Integer precision() {
+        colType = Objects.requireNonNullElse(colType, Objects.requireNonNull(columnType(type()), "colType"));
+        Integer precision = colType.lengthAllowed() ? PRECISION_NOT_SPECIFIED : type.getPrecision();
+        precision = precision == PRECISION_NOT_SPECIFIED ? null : precision;
+
+        return type.getSqlTypeName().allowsPrec() ? precision : null;
     }
 
     /**
      * Get column's scale.
      */
-    public Integer scale() {
-        return type.getScale() != RelDataType.SCALE_NOT_SPECIFIED ? type.getScale() : null;
+    public @Nullable Integer scale() {
+        colType = Objects.requireNonNullElse(colType, Objects.requireNonNull(columnType(type()), "colType"));
+        Integer scale = colType.lengthAllowed() ? SCALE_NOT_SPECIFIED : type.getScale();
+        scale = scale == SCALE_NOT_SPECIFIED ? null : scale;
+
+        return type.getSqlTypeName().allowsScale() ? scale : null;
+    }
+
+    /**
+     * Get column's length.
+     */
+    public @Nullable Integer length() {
+        colType = Objects.requireNonNullElse(colType, Objects.requireNonNull(columnType(type()), "colType"));
+        int length = type.getPrecision();
+        length = length == PRECISION_NOT_SPECIFIED ? defaultLength(colType, DEFAULT_LENGTH) : length;
+
+        return colType.lengthAllowed() ? length : null;
     }
 }
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteTypeSystem.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteTypeSystem.java
index 84e4b2bc38..fbec33afcd 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteTypeSystem.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteTypeSystem.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.internal.sql.engine.type;
 
+import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_TIMESTAMP_PRECISION;
+
 import java.io.Serializable;
 import java.math.BigDecimal;
 import org.apache.calcite.rel.type.RelDataType;
@@ -44,7 +46,6 @@ public class IgniteTypeSystem extends RelDataTypeSystemImpl implements Serializa
         return CatalogUtils.MAX_DECIMAL_PRECISION;
     }
 
-
     /** {@inheritDoc} */
     @Override
     public int getMaxPrecision(SqlTypeName typeName) {
@@ -65,7 +66,7 @@ public class IgniteTypeSystem extends RelDataTypeSystemImpl implements Serializa
         switch (typeName) {
             case TIMESTAMP: // DATETIME
             case TIMESTAMP_WITH_LOCAL_TIME_ZONE: // TIMESTAMP
-                return CatalogUtils.DEFAULT_TIMESTAMP_PRECISION;
+                return DEFAULT_TIMESTAMP_PRECISION;
             case FLOAT:
                 // TODO: https://issues.apache.org/jira/browse/IGNITE-18556
                 // Fixes leastRestrictive(FLOAT, DOUBLE) != leastRestrictive(DOUBLE, FLOAT).
@@ -146,5 +147,4 @@ public class IgniteTypeSystem extends RelDataTypeSystemImpl implements Serializa
 
         return typeFactory.createTypeWithNullability(sumType, argumentType.isNullable());
     }
-
 }
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/TypeUtils.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/TypeUtils.java
index 7e2c96cf8e..3a8724d11b 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/TypeUtils.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/TypeUtils.java
@@ -104,7 +104,7 @@ public class TypeUtils {
         static final Set<Class<?>> supportedParamClasses;
 
         static {
-            supportedParamClasses = Arrays.stream(ColumnType.values()).map(ColumnType::columnTypeToClass).collect(Collectors.toSet());
+            supportedParamClasses = Arrays.stream(ColumnType.values()).map(ColumnType::javaClass).collect(Collectors.toSet());
             supportedParamClasses.add(boolean.class);
             supportedParamClasses.add(byte.class);
             supportedParamClasses.add(short.class);
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/util/ProjectedTupleTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/util/ProjectedTupleTest.java
index 99bd0e2a6a..b50f4ca32d 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/util/ProjectedTupleTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/util/ProjectedTupleTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.sql.engine.util;
 
+import static org.apache.ignite.internal.schema.SchemaTestUtils.specToType;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.empty;
 import static org.hamcrest.Matchers.equalTo;
@@ -34,9 +35,7 @@ import org.apache.ignite.internal.schema.BinaryRowConverter;
 import org.apache.ignite.internal.schema.BinaryTuple;
 import org.apache.ignite.internal.schema.BinaryTupleSchema;
 import org.apache.ignite.internal.schema.BinaryTupleSchema.Element;
-import org.apache.ignite.internal.schema.NativeType;
 import org.apache.ignite.internal.schema.NativeTypeSpec;
-import org.apache.ignite.internal.schema.NativeTypes;
 import org.apache.ignite.internal.schema.SchemaTestUtils;
 import org.apache.ignite.internal.schema.row.InternalTuple;
 import org.junit.jupiter.api.BeforeAll;
@@ -70,7 +69,7 @@ class ProjectedTupleTest {
         for (int i = 0; i < ALL_TYPES_SCHEMA.elementCount(); i++) {
             Element e = ALL_TYPES_SCHEMA.element(i);
 
-            BinaryRowConverter.appendValue(builder, e, SchemaTestUtils.generateRandomValue(RND, fromElement(e)));
+            BinaryRowConverter.appendValue(builder, e, SchemaTestUtils.generateRandomValue(RND, specToType(e.typeSpec())));
         }
 
         TUPLE = new BinaryTuple(ALL_TYPES_SCHEMA.elementCount(), builder.build());
@@ -135,45 +134,4 @@ class ProjectedTupleTest {
         assertThat(projectedSchema.value(restored, 1), equalTo(ALL_TYPES_SCHEMA.value(TUPLE, f2)));
         assertThat(projectedSchema.value(restored, 2), equalTo(ALL_TYPES_SCHEMA.value(TUPLE, f3)));
     }
-
-    private static NativeType fromElement(Element element) {
-        switch (element.typeSpec()) {
-            case BOOLEAN:
-                return NativeTypes.BOOLEAN;
-            case INT8:
-                return NativeTypes.INT8;
-            case INT16:
-                return NativeTypes.INT16;
-            case INT32:
-                return NativeTypes.INT32;
-            case INT64:
-                return NativeTypes.INT64;
-            case FLOAT:
-                return NativeTypes.FLOAT;
-            case DOUBLE:
-                return NativeTypes.DOUBLE;
-            case DECIMAL:
-                return NativeTypes.decimalOf(20, element.decimalScale());
-            case NUMBER:
-                return NativeTypes.numberOf(20);
-            case DATE:
-                return NativeTypes.DATE;
-            case TIME:
-                return NativeTypes.time();
-            case DATETIME:
-                return NativeTypes.datetime();
-            case TIMESTAMP:
-                return NativeTypes.timestamp();
-            case UUID:
-                return NativeTypes.UUID;
-            case BITMASK:
-                return NativeTypes.bitmaskOf(256);
-            case STRING:
-                return NativeTypes.stringOf(256);
-            case BYTES:
-                return NativeTypes.blobOf(256);
-            default:
-                throw new IllegalArgumentException("Unknown type: " + element.typeSpec());
-        }
-    }
 }
diff --git a/modules/sql-engine/src/testFixtures/java/org/apache/ignite/internal/sql/engine/util/MetadataMatcher.java b/modules/sql-engine/src/testFixtures/java/org/apache/ignite/internal/sql/engine/util/MetadataMatcher.java
index bc78b1ff0f..e4d4d7e05d 100644
--- a/modules/sql-engine/src/testFixtures/java/org/apache/ignite/internal/sql/engine/util/MetadataMatcher.java
+++ b/modules/sql-engine/src/testFixtures/java/org/apache/ignite/internal/sql/engine/util/MetadataMatcher.java
@@ -143,7 +143,7 @@ public class MetadataMatcher implements ColumnMatcher {
         if (type != NO_CHECK) {
             ColumnType type0 = (ColumnType) type;
             matchers.add(() -> assertSame(type0, actualMeta.type(), "type"));
-            matchers.add(() -> assertSame(ColumnType.columnTypeToClass(type0), actualMeta.valueClass(), "value class"));
+            matchers.add(() -> assertSame(type0.javaClass(), actualMeta.valueClass(), "value class"));
         }
 
         if (precision != NO_CHECK) {
diff --git a/modules/sql-engine/src/testFixtures/java/org/apache/ignite/internal/sql/engine/util/QueryCheckerImpl.java b/modules/sql-engine/src/testFixtures/java/org/apache/ignite/internal/sql/engine/util/QueryCheckerImpl.java
index 57f3211555..eb11526fda 100644
--- a/modules/sql-engine/src/testFixtures/java/org/apache/ignite/internal/sql/engine/util/QueryCheckerImpl.java
+++ b/modules/sql-engine/src/testFixtures/java/org/apache/ignite/internal/sql/engine/util/QueryCheckerImpl.java
@@ -46,7 +46,6 @@ import org.apache.ignite.internal.sql.engine.session.SessionId;
 import org.apache.ignite.internal.util.ArrayUtils;
 import org.apache.ignite.internal.util.CollectionUtils;
 import org.apache.ignite.sql.ColumnMetadata;
-import org.apache.ignite.sql.ColumnType;
 import org.apache.ignite.sql.ResultSetMetadata;
 import org.apache.ignite.tx.IgniteTransactions;
 import org.apache.ignite.tx.Transaction;
@@ -205,7 +204,7 @@ abstract class QueryCheckerImpl implements QueryChecker {
 
         metadataMatchers = Arrays.stream(columns)
                 .map(t -> (ColumnMatcher) columnMetadata -> {
-                    Class<?> type = ColumnType.columnTypeToClass(columnMetadata.type());
+                    Class<?> type = columnMetadata.type().javaClass();
 
                     assertThat("Column type don't match", type, equalTo(t));
                 })
diff --git a/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/AbstractMvTableStorageTest.java b/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/AbstractMvTableStorageTest.java
index b6eda2f2b1..356e20db5b 100644
--- a/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/AbstractMvTableStorageTest.java
+++ b/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/AbstractMvTableStorageTest.java
@@ -775,9 +775,9 @@ public abstract class AbstractMvTableStorageTest extends BaseMvStoragesTest {
                 1,
                 List.of(
                         CatalogUtils.fromParams(ColumnParams.builder().name("INTKEY").type(INT32).build()),
-                        CatalogUtils.fromParams(ColumnParams.builder().name("STRKEY").type(STRING).build()),
+                        CatalogUtils.fromParams(ColumnParams.builder().name("STRKEY").length(100).type(STRING).build()),
                         CatalogUtils.fromParams(ColumnParams.builder().name("INTVAL").type(INT32).build()),
-                        CatalogUtils.fromParams(ColumnParams.builder().name("STRVAL").type(STRING).build())
+                        CatalogUtils.fromParams(ColumnParams.builder().name("STRVAL").length(100).type(STRING).build())
                 ),
                 List.of("INTKEY"),
                 null
diff --git a/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/index/AbstractIndexStorageTest.java b/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/index/AbstractIndexStorageTest.java
index a2b0bf34a0..37b27a7870 100644
--- a/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/index/AbstractIndexStorageTest.java
+++ b/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/index/AbstractIndexStorageTest.java
@@ -20,7 +20,6 @@ package org.apache.ignite.internal.storage.index;
 import static java.util.stream.Collectors.toList;
 import static java.util.stream.Collectors.toUnmodifiableList;
 import static org.apache.ignite.internal.storage.BaseMvStoragesTest.getOrCreateMvPartition;
-import static org.apache.ignite.sql.ColumnType.INT32;
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -93,10 +92,10 @@ public abstract class AbstractIndexStorageTest<S extends IndexStorage, D extends
                 columnParamsBuilder(ColumnType.DOUBLE).nullable(true).build(),
                 columnParamsBuilder(ColumnType.UUID).nullable(true).build(),
                 columnParamsBuilder(ColumnType.DATE).nullable(true).build(),
-                columnParamsBuilder(ColumnType.BITMASK).length(32).nullable(true).build(),
-                columnParamsBuilder(ColumnType.STRING).nullable(true).build(),
-                columnParamsBuilder(ColumnType.BYTE_ARRAY).nullable(true).build(),
-                columnParamsBuilder(ColumnType.NUMBER).precision(Integer.MAX_VALUE).nullable(true).build(),
+                columnParamsBuilder(ColumnType.BITMASK).length(100).nullable(true).build(),
+                columnParamsBuilder(ColumnType.STRING).length(100).nullable(true).build(),
+                columnParamsBuilder(ColumnType.BYTE_ARRAY).length(100).nullable(true).build(),
+                columnParamsBuilder(ColumnType.NUMBER).precision(10).nullable(true).build(),
                 columnParamsBuilder(ColumnType.DECIMAL).precision(19).scale(3).nullable(true).build(),
                 columnParamsBuilder(ColumnType.TIME).precision(0).nullable(true).build(),
                 columnParamsBuilder(ColumnType.DATETIME).precision(6).nullable(true).build(),
@@ -146,7 +145,7 @@ public abstract class AbstractIndexStorageTest<S extends IndexStorage, D extends
      * Configures a test table with columns of all supported types.
      */
     private static void createTestTable(CatalogService catalogService, AtomicInteger catalogId) {
-        ColumnParams pkColumn = ColumnParams.builder().name("pk").type(INT32).nullable(false).build();
+        ColumnParams pkColumn = ColumnParams.builder().name("pk").type(ColumnType.INT32).nullable(false).build();
 
         int tableId = catalogId.getAndIncrement();
         int zoneId = catalogId.getAndIncrement();
diff --git a/modules/table/src/integrationTest/java/org/apache/ignite/internal/table/ItColocationTest.java b/modules/table/src/integrationTest/java/org/apache/ignite/internal/table/ItColocationTest.java
index 934b183be0..1ba89fb948 100644
--- a/modules/table/src/integrationTest/java/org/apache/ignite/internal/table/ItColocationTest.java
+++ b/modules/table/src/integrationTest/java/org/apache/ignite/internal/table/ItColocationTest.java
@@ -19,6 +19,7 @@ package org.apache.ignite.internal.table;
 
 import static java.util.concurrent.CompletableFuture.completedFuture;
 import static java.util.stream.Collectors.toMap;
+import static org.apache.ignite.internal.schema.SchemaTestUtils.specToType;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.instanceOf;
 import static org.hamcrest.Matchers.is;
@@ -64,7 +65,6 @@ import org.apache.ignite.internal.replicator.TablePartitionId;
 import org.apache.ignite.internal.replicator.message.ReplicaRequest;
 import org.apache.ignite.internal.schema.BinaryRowEx;
 import org.apache.ignite.internal.schema.Column;
-import org.apache.ignite.internal.schema.NativeType;
 import org.apache.ignite.internal.schema.NativeTypeSpec;
 import org.apache.ignite.internal.schema.NativeTypes;
 import org.apache.ignite.internal.schema.SchemaDescriptor;
@@ -258,47 +258,6 @@ public class ItColocationTest extends BaseIgniteAbstractTest {
         CMDS_MAP.clear();
     }
 
-    private static NativeType nativeType(NativeTypeSpec type) {
-        switch (type) {
-            case BOOLEAN:
-                return NativeTypes.BOOLEAN;
-            case INT8:
-                return NativeTypes.INT8;
-            case INT16:
-                return NativeTypes.INT16;
-            case INT32:
-                return NativeTypes.INT32;
-            case INT64:
-                return NativeTypes.INT64;
-            case FLOAT:
-                return NativeTypes.FLOAT;
-            case DOUBLE:
-                return NativeTypes.DOUBLE;
-            case DECIMAL:
-                return NativeTypes.decimalOf(10, 3);
-            case UUID:
-                return NativeTypes.UUID;
-            case STRING:
-                return NativeTypes.STRING;
-            case BYTES:
-                return NativeTypes.BYTES;
-            case BITMASK:
-                return NativeTypes.bitmaskOf(16);
-            case NUMBER:
-                return NativeTypes.numberOf(10);
-            case DATE:
-                return NativeTypes.DATE;
-            case TIME:
-                return NativeTypes.time();
-            case DATETIME:
-                return NativeTypes.datetime();
-            case TIMESTAMP:
-                return NativeTypes.timestamp();
-            default:
-                throw new IllegalStateException("Unexpected type: " + type);
-        }
-    }
-
     private static Object generateValueByType(int i, NativeTypeSpec type) {
         switch (type) {
             case BOOLEAN:
@@ -424,8 +383,8 @@ public class ItColocationTest extends BaseIgniteAbstractTest {
         schema = new SchemaDescriptor(1,
                 new Column[]{
                         new Column("ID", NativeTypes.INT64, false),
-                        new Column("ID0", nativeType(t0), false),
-                        new Column("ID1", nativeType(t1), false)
+                        new Column("ID0", specToType(t0), false),
+                        new Column("ID1", specToType(t1), false)
                 },
                 new String[]{"ID1", "ID0"},
                 new Column[]{
diff --git a/modules/table/src/test/java/org/apache/ignite/internal/table/MutableRowTupleAdapterTest.java b/modules/table/src/test/java/org/apache/ignite/internal/table/MutableRowTupleAdapterTest.java
index 94fbb2a1dc..39a2ee1ccb 100644
--- a/modules/table/src/test/java/org/apache/ignite/internal/table/MutableRowTupleAdapterTest.java
+++ b/modules/table/src/test/java/org/apache/ignite/internal/table/MutableRowTupleAdapterTest.java
@@ -18,6 +18,8 @@
 package org.apache.ignite.internal.table;
 
 import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_TIMESTAMP_PRECISION;
+import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_TIME_PRECISION;
 import static org.apache.ignite.internal.schema.NativeTypes.BYTES;
 import static org.apache.ignite.internal.schema.NativeTypes.DATE;
 import static org.apache.ignite.internal.schema.NativeTypes.DOUBLE;
@@ -63,7 +65,6 @@ import org.apache.ignite.internal.schema.marshaller.TupleMarshaller;
 import org.apache.ignite.internal.schema.marshaller.TupleMarshallerException;
 import org.apache.ignite.internal.schema.marshaller.TupleMarshallerImpl;
 import org.apache.ignite.internal.schema.row.Row;
-import org.apache.ignite.internal.schema.testutils.definition.ColumnType;
 import org.apache.ignite.internal.table.impl.DummySchemaManagerImpl;
 import org.apache.ignite.internal.testframework.IgniteTestUtils;
 import org.apache.ignite.table.Tuple;
@@ -640,8 +641,8 @@ public class MutableRowTupleAdapterTest {
     }
 
     private <T extends Temporal> T truncateToDefaultPrecision(T temporal) {
-        int precision = temporal instanceof Instant ? ColumnType.TemporalColumnType.DEFAULT_TIMESTAMP_PRECISION
-                : ColumnType.TemporalColumnType.DEFAULT_TIME_PRECISION;
+        int precision = temporal instanceof Instant ? DEFAULT_TIMESTAMP_PRECISION
+                : DEFAULT_TIME_PRECISION;
 
         return (T) temporal.with(NANO_OF_SECOND,
                 truncatePrecision(temporal.get(NANO_OF_SECOND), tailFactor(precision)));