Skip to content

IGNITE-28556 Calcite. Support wrap_key and wrap_value flags#13037

Open
zstan wants to merge 3 commits intoapache:masterfrom
zstan:ignite-28556
Open

IGNITE-28556 Calcite. Support wrap_key and wrap_value flags#13037
zstan wants to merge 3 commits intoapache:masterfrom
zstan:ignite-28556

Conversation

@zstan
Copy link
Copy Markdown
Contributor

@zstan zstan commented Apr 16, 2026

No description provided.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Calcite-side support for wrap_key / wrap_value CREATE TABLE options (parsing, command propagation, and validation), plus tests to verify wrapping behavior and related DDL constraints.

Changes:

  • Extend Calcite CREATE TABLE option set with WRAP_KEY and WRAP_VALUE and parse them into CreateTableCommand.
  • Add DDL-time validation for invalid wrap combinations and implement wrap_value=false mapping to a “flat” value field.
  • Add/adjust JDBC and integration tests covering wrapping combinations and error scenarios.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java Minor test Callable signature adjustment.
modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicColumnsAbstractTest.java Minor test Callable signature adjustment.
modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java Javadoc punctuation fix.
modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/jdbc/JdbcQueryTest.java Adds JDBC tests for wrapped/unwrapped key/value behavior (incl. UUID).
modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/TableDdlIntegrationTest.java Adds integration tests for wrap options and constraints; re-enables an ALTER TABLE test.
modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/sql/IgniteSqlCreateTableOptionEnum.java Adds WRAP_KEY / WRAP_VALUE option enums.
modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/ddl/DdlSqlToCommandConverter.java Adds parsing/validation for wrap options.
modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/ddl/CreateTableCommand.java Adds wrap flags to the DDL command model (defaults: key=false, value=true).
modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ddl/DdlCommandHandler.java Validates wrap flags and applies wrap_value=false mapping; updates ALTER TABLE ADD error message.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@zstan zstan force-pushed the ignite-28556 branch 3 times, most recently from f375220 to abd690c Compare April 16, 2026 08:49
@sonarqubecloud
Copy link
Copy Markdown

throwOptionParsingException(opt, SIMPLE_PREDICATE, ctx.query());

String simple = ((SqlIdentifier)val).getSimple().toLowerCase(Locale.ROOT);
if (!"true".equals(simple) && !"false".equals(simple))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

equalsIgnoreCase?

private String paramIsSqlIdentifierValidator(IgniteSqlCreateTableOption opt, PlanningContext ctx) {
if (!(opt.value() instanceof SqlIdentifier) || !((SqlIdentifier)opt.value()).isSimple())
throwOptionParsingException(opt, "a simple identifier", ctx.query());
throwOptionParsingException(opt, SIMPLE_PREDICATE, ctx.query());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is not used, but can be used to simplify VALUE_IS_IDENTIFIER_VALIDATOR and VALUE_IS_BOOL_IDENTIFIER_VALIDATOR

private Boolean wrapKey;

/** Wrap value flag. */
private boolean wrapValue = true;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should use Boolean here and move default logic to command handler? This class is a representation of parsed command, if WRAP_VALUE is not provided it's more correct to see null here.
Let's also add the same comment as for H2 somewhere:
By default value is always wrapped to allow for ALTER TABLE ADD COLUMN commands.


/** */
@SuppressWarnings("ThrowableNotThrown")
private static void assertThrowsSqlException(Callable<?> call, @Nullable String msg) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have assertThrows(sql, cls, msg) in parent class, why do we need yet another method?

*/
@Test
public void testAlterTableFailOnSingleCacheValue() {
CacheConfiguration c =
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add generics

res = new QueryEntityEx(res).implicitPk(true);
}

if (!cmd.wrapValue()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrapKey is not handled. Only validated.

Comment on lines +502 to +551
public void testInlineSizeNoWrap() {
try {
sql("CREATE TABLE IF NOT EXISTS T ( " +
" id varchar(15), " +
" col varchar(100), " +
" PRIMARY KEY(id) ) ");
assertEquals(18, sql(
"select INLINE_SIZE from SYS.INDEXES where TABLE_NAME = 'T' and IS_PK = true").get(0).get(0));
}
finally {
sql("DROP TABLE IF EXISTS T");
}
}

/**
* Test single column PK with wrapping calculate correct inline size.
*/
@Test
public void testInlineSizeWrap() {
try {
sql("CREATE TABLE IF NOT EXISTS T ( " +
" id varchar(15), " +
" col varchar(100), " +
" PRIMARY KEY(id) ) WITH \"wrap_key=true\"");
assertEquals(18, sql(
"select INLINE_SIZE from SYS.INDEXES where TABLE_NAME = 'T' and IS_PK = true").get(0).get(0));
}
finally {
sql("DROP TABLE IF EXISTS T");
}
}

/**
* Test two column PK with wrapping calculate correct inline size.
*/
@Test
public void testInlineSizeWrapMultiPk() {
try {
sql("CREATE TABLE IF NOT EXISTS T ( " +
" id varchar(15), " +
" id2 uuid, " +
" col varchar(100), " +
" PRIMARY KEY(id, id2) ) WITH \"wrap_key=true\"");
assertEquals(35, sql(
"select INLINE_SIZE from SYS.INDEXES where TABLE_NAME = 'T' and IS_PK = true").get(0).get(0));
}
finally {
sql("DROP TABLE IF EXISTS T");
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not a correct tests for wrapping. PK index is always unwrapped if table was created via DDL. You can change wrap_key to false in all these test and get the same result. To test wrap_key correctly you can iterate over cache values and check key, if it primitive type or binary object.

* @param wrapVal Whether value wrap should be enforced.
* @throws SQLException if failed.
*/
private void doTestKeyValueWrap(boolean wrapKey, boolean wrapVal, boolean testUuid) throws SQLException {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like it's not related to JDBC somehow, just ordinal integration test.


UUID guid = UUID.randomUUID();

if (wrapKey)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Case with wrap_key=true and without key_type is not covered (and has errors, since wrap_key=true never handled)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants