Merge branch '!master' into ignite-11402

# Conflicts:
#	modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/BasicIndexTest.java
diff --git a/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java b/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java
index 41a4b4c..f7f3824 100644
--- a/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java
+++ b/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java
@@ -104,6 +104,20 @@
     private Map<String, Integer> fieldsScale = new HashMap<>();
 
     /**
+     * Used for composite primary key.
+     * {@code true} if the PK index is created on fields of PK.
+     * {@code false} in case the PK index is created on the whole key (composite binary object).
+     * {@code null} - compatible behavior (unwrap for a table created by SQL and wrapped key for a table created by API).
+     */
+    private Boolean unwrapPk;
+
+    /** INLINE_SIZE for PK index. */
+    private Integer pkInlineSize;
+
+    /** INLINE_SIZE for affinity field index. */
+    private Integer affFieldInlineSize;
+
+    /**
      * Creates an empty query entity.
      */
     public QueryEntity() {
@@ -138,6 +152,10 @@
         fieldsPrecision = other.fieldsPrecision != null ? new HashMap<>(other.fieldsPrecision) : new HashMap<>();
 
         fieldsScale = other.fieldsScale != null ? new HashMap<>(other.fieldsScale) : new HashMap<>();
+
+        unwrapPk = other.unwrapPk;
+        pkInlineSize = other.pkInlineSize != null ? other.pkInlineSize : -1;
+        affFieldInlineSize = other.affFieldInlineSize != null ? other.affFieldInlineSize : -1;
     }
 
     /**
@@ -670,6 +688,84 @@
     }
 
     /**
+     * Returns INLINE_SIZE for PK index.
+     *
+     * @return INLINE_SIZE for PK index.
+     */
+    public Integer getPrimaryKeyInlineSize() {
+        return pkInlineSize;
+    }
+
+    /**
+     * Sets INLINE_SIZE for PK index.
+     *
+     * @param pkInlineSize INLINE_SIZE for PK index, when {@code null} - inline size is calculated automativally.
+     * @return {@code this} for chaining.
+     */
+    public QueryEntity setPrimaryKeyInlineSize(Integer pkInlineSize) {
+        if (pkInlineSize != null && pkInlineSize < 0) {
+            throw new CacheException("Inline size for sorted primary key cannot be negative. "
+                    + "[inlineSize=" + pkInlineSize + ']');
+        }
+
+        this.pkInlineSize = pkInlineSize;
+
+        return this;
+    }
+
+    /**
+     * Returns INLINE_SIZE for affinity field index.
+     *
+     * @return INLINE_SIZE for affinity field index.
+     */
+    public Integer getAffinityFieldInlineSize() {
+        return affFieldInlineSize;
+    }
+
+    /**
+     * Sets INLINE_SIZE for AFFINITY_KEY index.
+     *
+     * @param affFieldInlineSize INLINE_SIZE for AFFINITY_KEY index, when {@code null} - inline size is calculated automativally.
+     * @return {@code this} for chaining.
+     */
+    public QueryEntity setAffinityKeyInlineSize(Integer affFieldInlineSize) {
+        if (affFieldInlineSize != null && affFieldInlineSize < 0) {
+            throw new CacheException("Inline size for affinity filed index cannot be negative. "
+                    + "[inlineSize=" + affFieldInlineSize + ']');
+        }
+
+        this.affFieldInlineSize = affFieldInlineSize;
+
+        return this;
+    }
+
+    /**
+     * The property is used for sorted index and composite primary key.
+     *
+     * @return  {@code true} if the PK index is created on fields of PK.
+     * {@code false} in case the PK index is created on the whole key (composite binary object).
+     * {@code null} - compatible behavior (unwrap for a table created by SQL and wrapped key for a table created by API).
+     */
+    public Boolean getUnwrapPrimaryKeyFieldsForSortedIndex() {
+        return unwrapPk;
+    }
+
+    /**
+     * The property is used for sorted index and composite primary key.
+     *
+     * @param unwrapPk {@code true} if the PK index is created on fields of PK.
+     *      {@code false} in case the PK index is created on the whole key (composite binary object).
+     *      {@code null} - compatible behavior (unwrap for a table created by SQL and wrapped key
+     *      for a table created by API).
+     * @return {@code this} for chaining.
+     */
+    public QueryEntity setUnwrapPrimaryKeyFieldsForSortedIndex(Boolean unwrapPk) {
+        this.unwrapPk = unwrapPk;
+
+        return this;
+    }
+
+    /**
      * @param desc Type descriptor.
      * @return Type metadata.
      */
@@ -919,13 +1015,17 @@
             F.eq(_notNullFields, entity._notNullFields) &&
             F.eq(defaultFieldValues, entity.defaultFieldValues) &&
             F.eq(fieldsPrecision, entity.fieldsPrecision) &&
-            F.eq(fieldsScale, entity.fieldsScale);
+            F.eq(fieldsScale, entity.fieldsScale) &&
+            F.eq(unwrapPk, entity.unwrapPk) &&
+            F.eq(pkInlineSize, entity.pkInlineSize) &&
+            F.eq(affFieldInlineSize, entity.affFieldInlineSize);
     }
 
     /** {@inheritDoc} */
     @Override public int hashCode() {
         return Objects.hash(keyType, valType, keyFieldName, valueFieldName, fields, keyFields, aliases, idxs,
-            tableName, _notNullFields, defaultFieldValues, fieldsPrecision, fieldsScale);
+            tableName, _notNullFields, defaultFieldValues, fieldsPrecision, fieldsScale,
+            unwrapPk, pkInlineSize, affFieldInlineSize);
     }
 
     /** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryTypeDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryTypeDescriptor.java
index c8b2cc7..f99e5ee 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryTypeDescriptor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryTypeDescriptor.java
@@ -211,4 +211,42 @@
      * @param keys Primary keys.
      */
     public void primaryKeyFields(Set<String> keys);
+
+    /**
+     * Gets primary key index INLINE_SIZE.
+     */
+    public int primaryKeyInlineSize();
+
+    /**
+     * Sets primary key index INLINE_SIZE.
+     */
+    public void primaryKeyInlineSize(int pkInlineSize);
+
+    /**
+     * Gets affinity fields index INLINE_SIZE.
+     */
+    public int affinityFieldInlineSize();
+
+    /**
+     * Sets affinity fields index INLINE_SIZE.
+     */
+    public void affinityFieldInlineSize(int affFieldInlineSize);
+
+    /**
+     * Sets property 'unwrap primary key fields'.
+     * Used for compisite primary key.
+     * {@code true} if the PK index is created on fields of PK;
+     * {@code false} in case the PK index is created on the whole key (composite binary object).
+     * {@code null} - compatible behavior (unwrap for a table created by SQL and wrapped key for a table created by API).
+     */
+    public Boolean unwrapPrimaryKeyFields();
+
+    /**
+     * Gets property 'unwrap primary key fields'.
+     * Used for compisite primary key.
+     * {@code true} if the PK index is created on fields of PK;
+     * {@code false} in case the PK index is created on the whole key (composite binary object).
+     * {@code null} - compatible behavior (unwrap for a table created by SQL and wrapped key for a table created by API).
+     */
+    public void unwrapPrimaryKeyFields(Boolean unwrapPk);
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryTypeDescriptorImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryTypeDescriptorImpl.java
index 7f162f1..308e736 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryTypeDescriptorImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryTypeDescriptorImpl.java
@@ -138,6 +138,15 @@
     /** Primary key fields. */
     private Set<String> pkFields;
 
+    /** */
+    private int pkInlineSize;
+
+    /** */
+    private int affFieldInlineSize;
+
+    /** */
+    private Boolean unwrapPk;
+
     /** Logger. */
     private final IgniteLogger log;
 
@@ -764,4 +773,34 @@
     @Override public void primaryKeyFields(Set<String> keys) {
         pkFields = keys;
     }
+
+    /** {@inheritDoc} */
+    @Override public int primaryKeyInlineSize() {
+        return pkInlineSize;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void primaryKeyInlineSize(int pkInlineSize) {
+        this.pkInlineSize = pkInlineSize;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int affinityFieldInlineSize() {
+        return affFieldInlineSize;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void affinityFieldInlineSize(int affFieldInlineSize) {
+        this.affFieldInlineSize = affFieldInlineSize;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Boolean unwrapPrimaryKeyFields() {
+        return unwrapPk;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unwrapPrimaryKeyFields(Boolean unwrapPk) {
+        this.unwrapPk = unwrapPk;
+    }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
index 073cbc7..dea8255 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
@@ -328,6 +328,9 @@
         normalEntity.setDefaultFieldValues(entity.getDefaultFieldValues());
         normalEntity.setFieldsPrecision(entity.getFieldsPrecision());
         normalEntity.setFieldsScale(entity.getFieldsScale());
+        normalEntity.setUnwrapPrimaryKeyFieldsForSortedIndex(entity.getUnwrapPrimaryKeyFieldsForSortedIndex());
+        normalEntity.setPrimaryKeyInlineSize(entity.getPrimaryKeyInlineSize());
+        normalEntity.setAffinityKeyInlineSize(entity.getAffinityFieldInlineSize());
 
         // Normalize table name.
         String normalTblName = entity.getTableName();
@@ -598,6 +601,10 @@
 
         desc.typeId(valTypeId);
 
+        desc.unwrapPrimaryKeyFields(qryEntity.getUnwrapPrimaryKeyFieldsForSortedIndex());
+        desc.primaryKeyInlineSize(qryEntity.getPrimaryKeyInlineSize() != null ? qryEntity.getPrimaryKeyInlineSize() : -1);
+        desc.affinityFieldInlineSize(qryEntity.getAffinityFieldInlineSize() != null ? qryEntity.getAffinityFieldInlineSize() : -1);
+
         return new QueryTypeCandidate(typeId, altTypeId, desc);
     }
 
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/CommandProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/CommandProcessor.java
index e5bf0b8..27691da 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/CommandProcessor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/CommandProcessor.java
@@ -25,6 +25,7 @@
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
@@ -1238,6 +1239,14 @@
         if (!F.isEmpty(notNullFields))
             res.setNotNullFields(notNullFields);
 
+        res.setUnwrapPrimaryKeyFieldsForSortedIndex(createTbl.unwrapPrimaryKeyFields());
+
+        if (Objects.nonNull(createTbl.primaryKeyInlineSize()))
+            res.setPrimaryKeyInlineSize(createTbl.primaryKeyInlineSize());
+
+        if (Objects.nonNull(createTbl.affinityKeyInlineSize()))
+            res.setAffinityKeyInlineSize(createTbl.affinityKeyInlineSize());
+
         return res;
     }
 
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableDescriptor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableDescriptor.java
index 0fc8713..e879c40 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableDescriptor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableDescriptor.java
@@ -239,7 +239,7 @@
             false,
             unwrappedKeyAndAffinityCols,
             wrappedKeyCols,
-            -1,
+            tbl.rowDescriptor().tableDescriptor().type().primaryKeyInlineSize(),
             null
         );
 
@@ -304,7 +304,7 @@
                     true,
                     colsWithUnwrappedKey,
                     cols,
-                    -1,
+                    tbl.rowDescriptor().tableDescriptor().type().affinityFieldInlineSize(),
                     null)
                 );
             }
@@ -325,7 +325,7 @@
     @NotNull private List<IndexColumn> extractKeyColumns(GridH2Table tbl, IndexColumn keyCol, IndexColumn affCol) {
         ArrayList<IndexColumn> keyCols;
 
-        if (isSql) {
+        if (isUnwrapPrimaryKey()) {
             keyCols = new ArrayList<>(type.fields().size() + 1);
 
             // Check if key is simple type.
@@ -464,6 +464,11 @@
         return null;
     }
 
+    /** */
+    public boolean isUnwrapPrimaryKey() {
+        return type().unwrapPrimaryKeyFields() != null ? type().unwrapPrimaryKeyFields() : isSql;
+    }
+
     /**
      * Handle drop.
      */
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java
index 0fd3607..2737bd3 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java
@@ -998,9 +998,9 @@
     @NotNull public static IndexColumn[] unwrapKeyColumns(GridH2Table tbl, IndexColumn[] idxCols) {
         ArrayList<IndexColumn> keyCols = new ArrayList<>();
 
-        boolean isSql = tbl.rowDescriptor().tableDescriptor().sql();
+        boolean isUnwrapPk = tbl.rowDescriptor().tableDescriptor().isUnwrapPrimaryKey();
 
-        if (!isSql)
+        if (!isUnwrapPk)
             return idxCols;
 
         GridQueryTypeDescriptor type = tbl.rowDescriptor().type();
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java
index 3a216fd..df8614e 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java
@@ -22,6 +22,7 @@
 import java.util.List;
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheWriteSynchronizationMode;
+import org.apache.ignite.cache.QueryEntity;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.jetbrains.annotations.Nullable;
 
@@ -91,6 +92,15 @@
     /** See {@link CacheConfiguration#getQueryParallelism()}. */
     private Integer parallelism;
 
+    /** See {@link QueryEntity#getUnwrapPrimaryKeyFieldsForSortedIndex()}. */
+    private Boolean unwrapPk;
+
+    /** See {@link QueryEntity#getPrimaryKeyInlineSize()}. */
+    private Integer pkInlineSize;
+
+    /** See {@link QueryEntity#getAffinityFieldInlineSize()}. */
+    private Integer affInlineSize;
+
     /**
      * @return Cache name upon which new cache configuration for this table must be based.
      */
@@ -371,6 +381,36 @@
         this.parallelism = parallelism;
     }
 
+    /** */
+    public Boolean unwrapPrimaryKeyFields() {
+        return unwrapPk;
+    }
+
+    /** */
+    public void unwrapPrimaryKeyFields(Boolean unwrapPk) {
+        this.unwrapPk = unwrapPk;
+    }
+
+    /** */
+    public Integer primaryKeyInlineSize() {
+        return pkInlineSize;
+    }
+
+    /** */
+    public void primaryKeyInlineSize(Integer pkInlineSize) {
+        this.pkInlineSize = pkInlineSize;
+    }
+
+    /** */
+    public Integer affinityKeyInlineSize() {
+        return affInlineSize;
+    }
+
+    /** */
+    public void affinityKeyInlineSize(Integer affInlineSize) {
+        this.affInlineSize = affInlineSize;
+    }
+
     /** {@inheritDoc} */
     @Override public String getSQL() {
         return null;
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
index 62cde59..ed422d6 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
@@ -524,6 +524,15 @@
     private static final String PARAM_PARALLELISM = "PARALLELISM";
 
     /** */
+    private static final String PARAM_PK_INLINE_SIZE = "PK_INLINE_SIZE";
+
+    /** */
+    private static final String PARAM_AFFINITY_INDEX_INLINE_SIZE = "AFFINITY_INDEX_INLINE_SIZE";
+
+    /** */
+    private static final String PARAM_PK_INDEX_UNWRAP_FILEDS = "PK_INDEX_UNWRAP_FILEDS";
+
+    /** */
     private final IdentityHashMap<Object, Object> h2ObjToGridObj = new IdentityHashMap<>();
 
     /** */
@@ -1691,6 +1700,33 @@
 
                 break;
 
+            case PARAM_PK_INDEX_UNWRAP_FILEDS:
+                ensureNotEmpty(name, val);
+
+                boolean unwrapPk = parseBooleanParam(PARAM_PK_INDEX_UNWRAP_FILEDS, val);
+
+                res.unwrapPrimaryKeyFields(unwrapPk);
+
+                break;
+
+            case PARAM_PK_INLINE_SIZE:
+                ensureNotEmpty(name, val);
+
+                int pkInlineSize = parseIntParam(PARAM_PK_INLINE_SIZE, val);
+
+                res.primaryKeyInlineSize(pkInlineSize);
+
+                break;
+
+            case PARAM_AFFINITY_INDEX_INLINE_SIZE:
+                ensureNotEmpty(name, val);
+
+                int affInlineSize = parseIntParam(PARAM_AFFINITY_INDEX_INLINE_SIZE, val);
+
+                res.affinityKeyInlineSize(affInlineSize);
+
+                break;
+
             default:
                 throw new IgniteSQLException("Unsupported parameter: " + name, IgniteQueryErrorCode.PARSING);
         }
@@ -1723,6 +1759,23 @@
     }
 
     /**
+     * Parse given value as boolean, or throw an {@link IgniteSQLException} if it's not of matching format.
+     * @param name param name.
+     * @param val param value.
+     * @return parsed int value.
+     */
+    private static boolean parseBooleanParam(String name, String val) {
+        if ("true".equalsIgnoreCase(val) || "1".equals(val))
+            return true;
+        else if ("false".equalsIgnoreCase(val) || "0".equals(val))
+            return false;
+        else {
+            throw new IgniteSQLException("Parameter value must be an boolean [name=" + name + ", value=" + val + ']',
+                    IgniteQueryErrorCode.PARSING);
+        }
+    }
+
+    /**
      * @param sortOrder Sort order.
      * @param qry Query.
      */
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/BasicIndexTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/BasicIndexTest.java
index 81586bd..9bfac4d 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/BasicIndexTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/BasicIndexTest.java
@@ -23,16 +23,18 @@
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Objects;
 import java.util.UUID;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
-
 import javax.cache.CacheException;
+
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.binary.BinaryObjectBuilder;
+import org.apache.ignite.cache.CacheKeyConfiguration;
 import org.apache.ignite.cache.QueryEntity;
 import org.apache.ignite.cache.QueryIndex;
 import org.apache.ignite.cache.QueryIndexType;
@@ -48,9 +50,12 @@
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.processors.query.GridQueryProcessor;
 import org.apache.ignite.internal.processors.query.IgniteSQLException;
+import org.apache.ignite.internal.processors.query.QueryEntityEx;
 import org.apache.ignite.internal.processors.query.QueryUtils;
 import org.apache.ignite.internal.processors.query.h2.H2TableDescriptor;
 import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing;
+import org.apache.ignite.internal.processors.query.h2.database.H2TreeIndex;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.testframework.GridTestUtils;
@@ -1521,7 +1526,7 @@
 
         assertNull(GridTestUtils.getFieldValue(tblDesc1, "luceneIdx"));
     }
-    
+
     /**
      * Checks that part of the composite key assembled in BinaryObjectBuilder can pass the validation correctly
      * if you specify Object type when creating the index.
@@ -1531,9 +1536,9 @@
     @Test
     public void testCacheSecondaryCompositeIndex() throws Exception {
         inlineSize = 70;
-        
+
         startGrid();
-        
+
         String cacheName = "TEST";
 
         List<QueryIndex> indexes = Collections.singletonList(
@@ -1554,15 +1559,15 @@
                 .setIndexes(indexes)
             ))
         );
-        
+
         BinaryObjectBuilder bob = grid().binary().builder("TEST_VAL_SECONDARY_COMPOSITE");
         BinaryObjectBuilder bobInner = grid().binary().builder("inner");
-        
+
         bobInner.setField("inner_k", 0);
         bobInner.setField("inner_uuid", UUID.randomUUID());
-        
+
         bob.setField("val_obj", bobInner.build());
-        
+
         IgniteCache<Object, Object> cache = grid().cache(cacheName);
 
         cache.put(0, bob.build());
@@ -1588,6 +1593,102 @@
     }
 
     /** */
+    @Test
+    public void testCreateSystemIndexWithSpecifiedInlineSizeByApi() throws Exception {
+        inlineSize = 10;
+
+        final int pkInlineSize = 22;
+        final int affInlineSize = 23;
+
+        IgniteEx ign = startGrid();
+
+        ign.createCache(
+            new CacheConfiguration<>()
+                    .setName("test")
+                    .setQueryEntities(Collections.singleton(
+                            new QueryEntityEx(
+                                    new QueryEntity()
+                                            .setKeyType("TestKeyType")
+                                            .setValueType("TestValType")
+                                            .addQueryField("ID", String.class.getName(), null)
+                                            .addQueryField("ID_AFF", Integer.class.getName(), null)
+                                            .addQueryField("VAL", Integer.class.getName(), null)
+                                            .setKeyFields(new LinkedHashSet<>(Arrays.asList("ID", "ID_AFF")))
+                                            .setTableName("TEST")
+                            )
+                                    .setPrimaryKeyInlineSize(pkInlineSize)
+                                    .setAffinityKeyInlineSize(affInlineSize)
+                    ))
+                    .setSqlSchema("PUBLIC")
+                    .setKeyConfiguration(new CacheKeyConfiguration("TestKeyType", "ID_AFF"))
+        );
+
+        GridH2Table tbl = ((IgniteH2Indexing)ign.context().query().getIndexing()).schemaManager().dataTable("PUBLIC", "TEST");
+
+        assertEquals(pkInlineSize, ((H2TreeIndex)tbl.getIndex("_key_PK")).inlineSize());
+        assertEquals(affInlineSize, ((H2TreeIndex)tbl.getIndex("AFFINITY_KEY")).inlineSize());
+    }
+
+    /** */
+    @Test
+    public void testCreateSystemIndexWithSpecifiedInlineSizeByDdl() throws Exception {
+        inlineSize = 10;
+
+        final int pkInlineSize = 22;
+        final int affInlineSize = 23;
+
+        IgniteEx ign = startGrid();
+
+        sql("CREATE TABLE TEST (ID VARCHAR, ID_AFF INT, VAL INT, "
+                + "PRIMARY KEY (ID, ID_AFF)) WITH"
+                + "\""
+                + "AFFINITY_KEY=ID_AFF,"
+                + "PK_INLINE_SIZE=" + pkInlineSize + ","
+                + "AFFINITY_INDEX_INLINE_SIZE=" + affInlineSize
+                + "\""
+        );
+
+        GridH2Table tbl = ((IgniteH2Indexing)ign.context().query().getIndexing()).schemaManager().dataTable("PUBLIC", "TEST");
+
+        assertEquals(pkInlineSize, ((H2TreeIndex)tbl.getIndex("_key_PK")).inlineSize());
+        assertEquals(affInlineSize, ((H2TreeIndex)tbl.getIndex("AFFINITY_KEY")).inlineSize());
+    }
+
+    /** */
+    @Test
+    public void testCreateWrappedPkIndexByDdl() throws Exception {
+        inlineSize = 10;
+
+        IgniteEx ign = startGrid();
+
+        sql("CREATE TABLE TEST_WRAP (ID0 VARCHAR, ID1 INT, VAL INT, "
+                + "PRIMARY KEY (ID0, ID1)) WITH"
+                + "\""
+                + "PK_INDEX_UNWRAP_FILEDS=false"
+                + "\""
+        );
+
+        sql("CREATE TABLE TEST_UNWRAP_EXPLICIT (ID0 VARCHAR, ID1 INT, VAL INT, "
+                + "PRIMARY KEY (ID0, ID1)) WITH"
+                + "\""
+                + "PK_INDEX_UNWRAP_FILEDS=true"
+                + "\""
+        );
+
+        GridH2Table tblWrap = ((IgniteH2Indexing)ign.context().query().getIndexing()).schemaManager()
+                .dataTable("PUBLIC", "TEST_WRAP");
+        GridH2Table tblUnwrapExplicit = ((IgniteH2Indexing)ign.context().query().getIndexing()).schemaManager()
+                .dataTable("PUBLIC", "TEST_UNWRAP_EXPLICIT");
+
+        assertEquals(1, tblWrap.getIndex("_key_PK").getColumns().length);
+        assertEquals("_KEY", tblWrap.getIndex("_key_PK").getColumns()[0].getName());
+
+        assertEquals(2, tblUnwrapExplicit.getIndex("_key_PK").getColumns().length);
+        assertEquals("ID0", tblUnwrapExplicit.getIndex("_key_PK").getColumns()[0].getName());
+        assertEquals("ID1", tblUnwrapExplicit.getIndex("_key_PK").getColumns()[1].getName());
+    }
+
+    /** */
     private void checkAll() {
         IgniteCache<Key, Val> cache = grid(0).cache(DEFAULT_CACHE_NAME);
 
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/QueryEntityValidationSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/QueryEntityValidationSelfTest.java
index 13ea5f4..a740f3e 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/QueryEntityValidationSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/QueryEntityValidationSelfTest.java
@@ -235,6 +235,31 @@
     }
 
     /**
+     * Test to check validation of system indexes inline size.
+     */
+    @Test
+    public void testInlineSizeValidation() {
+        new QueryEntity().setPrimaryKeyInlineSize(0);
+        new QueryEntity().setAffinityKeyInlineSize(0);
+        new QueryEntity().setPrimaryKeyInlineSize(null);
+        new QueryEntity().setAffinityKeyInlineSize(null);
+
+        GridTestUtils.assertThrows(
+                log,
+                ()  -> new QueryEntity().setPrimaryKeyInlineSize(-1),
+                CacheException.class,
+                "Inline size for sorted primary key cannot be negative."
+        );
+
+        GridTestUtils.assertThrows(
+                log,
+                ()  -> new QueryEntity().setAffinityKeyInlineSize(-1),
+                CacheException.class,
+                "Inline size for affinity filed index cannot be negative."
+        );
+    }
+
+    /**
      * Test class for sql queryable test key with not unique annotation's name property.
      */
     private static class TestKeyWithNotUniqueName {