This is an automated email from the ASF dual-hosted git repository.
jooger 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 7bee0308b32 IGNITE-27809 Add support for EXISTS keyword for SQL
add/drop column (#7585)
7bee0308b32 is described below
commit 7bee0308b32456b8f3e2c85a7b2dbed66e16b2c9
Author: Ivan Zlenko <[email protected]>
AuthorDate: Fri Feb 13 17:31:14 2026 +0500
IGNITE-27809 Add support for EXISTS keyword for SQL add/drop column (#7585)
---
.../commands/AlterTableAddColumnCommand.java | 37 +++++++---
.../AlterTableAddColumnCommandBuilder.java | 3 +
.../commands/AlterTableDropColumnCommand.java | 78 ++++++++++++++++------
.../AlterTableDropColumnCommandBuilder.java | 3 +
.../AlterTableAddColumnCommandValidationTest.java | 22 ++++++
.../AlterTableDropColumnCommandValidationTest.java | 20 ++++++
.../ignite/internal/sql/api/ItSqlApiBaseTest.java | 4 ++
.../src/main/codegen/includes/parserImpls.ftl | 10 +--
.../prepare/ddl/DdlSqlToCommandConverter.java | 2 +
.../engine/sql/IgniteSqlAlterTableAddColumn.java | 42 ++++++++++--
.../engine/sql/IgniteSqlAlterTableDropColumn.java | 42 ++++++++++--
.../internal/sql/engine/sql/SqlDdlParserTest.java | 41 ++++++++++++
12 files changed, 261 insertions(+), 43 deletions(-)
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 4d6f4fceb1f..195ee1b9512 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
@@ -50,6 +50,8 @@ public class AlterTableAddColumnCommand extends
AbstractTableCommand {
private final List<ColumnParams> columns;
+ private final boolean ifColumnNotExists;
+
/**
* Constructs the object.
*
@@ -63,12 +65,15 @@ public class AlterTableAddColumnCommand extends
AbstractTableCommand {
String tableName,
String schemaName,
boolean ifTableExists,
- List<ColumnParams> columns
+ List<ColumnParams> columns,
+ boolean ifColumnNotExists
) throws CatalogValidationException {
super(schemaName, tableName, ifTableExists, true);
this.columns = copyOrNull(columns);
+ this.ifColumnNotExists = ifColumnNotExists;
+
validate();
}
@@ -88,16 +93,22 @@ public class AlterTableAddColumnCommand extends
AbstractTableCommand {
List<CatalogTableColumnDescriptor> columnDescriptors = new
ArrayList<>();
for (ColumnParams column : columns) {
- if (table.column(column.name()) != null) {
+ CatalogTableColumnDescriptor columnDescriptor =
table.column(column.name());
+
+ if (columnDescriptor != null && !ifColumnNotExists) {
throw new CatalogValidationException("Column with name '{}'
already exists.", column.name());
+ } else if (columnDescriptor == null) {
+ columnDescriptors.add(fromParams(column));
}
-
- columnDescriptors.add(fromParams(column));
}
- return List.of(
- new NewColumnsEntry(table.id(), columnDescriptors)
- );
+ if (columnDescriptors.isEmpty()) {
+ return List.of();
+ } else {
+ return List.of(
+ new NewColumnsEntry(table.id(), columnDescriptors)
+ );
+ }
}
private void validate() {
@@ -129,6 +140,8 @@ public class AlterTableAddColumnCommand extends
AbstractTableCommand {
private boolean ifTableExists;
+ private boolean ifColumnNotExists;
+
@Override
public AlterTableAddColumnCommandBuilder schemaName(String schemaName)
{
this.schemaName = schemaName;
@@ -157,13 +170,21 @@ public class AlterTableAddColumnCommand extends
AbstractTableCommand {
return this;
}
+ @Override
+ public AlterTableAddColumnCommandBuilder ifColumnNotExists(boolean
notExists) {
+ this.ifColumnNotExists = notExists;
+
+ return this;
+ }
+
@Override
public CatalogCommand build() {
return new AlterTableAddColumnCommand(
tableName,
schemaName,
ifTableExists,
- columns
+ columns,
+ ifColumnNotExists
);
}
}
diff --git
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableAddColumnCommandBuilder.java
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableAddColumnCommandBuilder.java
index c5952106097..20fb61eed44 100644
---
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableAddColumnCommandBuilder.java
+++
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableAddColumnCommandBuilder.java
@@ -29,4 +29,7 @@ import java.util.List;
public interface AlterTableAddColumnCommandBuilder extends
AbstractTableCommandBuilder<AlterTableAddColumnCommandBuilder> {
/** List of columns to add to the table. There must be at least one
column. */
AlterTableAddColumnCommandBuilder columns(List<ColumnParams> columns);
+
+ /** The flag indicating that the command should not fail if a column with
the same name already exists. */
+ AlterTableAddColumnCommandBuilder ifColumnNotExists(boolean notExists);
}
diff --git
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableDropColumnCommand.java
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableDropColumnCommand.java
index 9e4d53dc908..e2fd5046292 100644
---
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableDropColumnCommand.java
+++
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableDropColumnCommand.java
@@ -26,6 +26,7 @@ import static
org.apache.ignite.internal.util.CollectionUtils.nullOrEmpty;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@@ -43,6 +44,7 @@ import
org.apache.ignite.internal.catalog.descriptors.CatalogTableColumnDescript
import org.apache.ignite.internal.catalog.descriptors.CatalogTableDescriptor;
import org.apache.ignite.internal.catalog.storage.DropColumnsEntry;
import org.apache.ignite.internal.catalog.storage.UpdateEntry;
+import org.jetbrains.annotations.Nullable;
/**
* A command that deletes columns from the table.
@@ -55,6 +57,8 @@ public class AlterTableDropColumnCommand extends
AbstractTableCommand {
private final Set<String> columns;
+ private final boolean ifColumnExists;
+
/**
* Constructs the object.
*
@@ -68,7 +72,8 @@ public class AlterTableDropColumnCommand extends
AbstractTableCommand {
String tableName,
String schemaName,
boolean ifTableExists,
- Set<String> columns
+ Set<String> columns,
+ boolean ifColumnExists
) throws CatalogValidationException {
super(schemaName, tableName, ifTableExists, true);
@@ -76,6 +81,8 @@ public class AlterTableDropColumnCommand extends
AbstractTableCommand {
validate(columns);
this.columns = copyOrNull(columns);
+
+ this.ifColumnExists = ifColumnExists;
}
@Override
@@ -96,31 +103,52 @@ public class AlterTableDropColumnCommand extends
AbstractTableCommand {
.collect(IntOpenHashSet::new, IntSet::add, IntSet::addAll);
// To validate always in the same order let's sort given columns
- columns.stream().sorted().forEach(columnName -> {
- CatalogTableColumnDescriptor column = table.column(columnName);
- if (column == null) {
+ Set<String> columnsToDrop = columns.stream()
+ .sorted()
+ .map(columnName -> retrieveValidatedColumnName(columnName,
catalog, table, indexedColumns))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toSet());
+
+ if (columnsToDrop.isEmpty()) {
+ return List.of();
+ } else {
+ return List.of(
+ new DropColumnsEntry(table.id(), columnsToDrop)
+ );
+ }
+ }
+
+ private @Nullable String retrieveValidatedColumnName(
+ String columnName,
+ Catalog catalog,
+ CatalogTableDescriptor table,
+ IntSet indexedColumns
+ ) {
+ CatalogTableColumnDescriptor column = table.column(columnName);
+ if (column == null) {
+ if (ifColumnExists) {
+ return null;
+ } else {
throw new CatalogValidationException(
"Column with name '{}' not found in table '{}.{}'.",
columnName, schemaName, tableName);
}
+ }
- if (table.isPrimaryKeyColumn(columnName)) {
- throw new CatalogValidationException("Deleting column `{}`
belonging to primary key is not allowed.", columnName);
- }
+ if (table.isPrimaryKeyColumn(columnName)) {
+ throw new CatalogValidationException("Deleting column `{}`
belonging to primary key is not allowed.", columnName);
+ }
- if (indexedColumns.contains(column.id())) {
- List<String> indexesNames = aliveIndexesForTable(catalog,
table.id())
- .filter(index -> indexColumnIds(index).anyMatch(id ->
id == column.id()))
- .map(CatalogIndexDescriptor::name)
- .collect(Collectors.toList());
+ if (indexedColumns.contains(column.id())) {
+ List<String> indexesNames = aliveIndexesForTable(catalog,
table.id())
+ .filter(index -> indexColumnIds(index).anyMatch(id -> id
== column.id()))
+ .map(CatalogIndexDescriptor::name)
+ .collect(Collectors.toList());
- throw new CatalogValidationException("Deleting column '{}'
used by index(es) {}, it is not allowed.",
- columnName, indexesNames);
- }
- });
+ throw new CatalogValidationException("Deleting column '{}' used by
index(es) {}, it is not allowed.",
+ columnName, indexesNames);
+ }
- return List.of(
- new DropColumnsEntry(table.id(), columns)
- );
+ return column.name();
}
private static Stream<CatalogIndexDescriptor> aliveIndexesForTable(Catalog
catalog, int tableId) {
@@ -162,6 +190,8 @@ public class AlterTableDropColumnCommand extends
AbstractTableCommand {
private boolean ifTableExists;
+ private boolean ifColumnExists;
+
@Override
public AlterTableDropColumnCommandBuilder schemaName(String
schemaName) {
this.schemaName = schemaName;
@@ -190,13 +220,21 @@ public class AlterTableDropColumnCommand extends
AbstractTableCommand {
return this;
}
+ @Override
+ public AlterTableDropColumnCommandBuilder ifColumnExists(boolean
ifColumnExists) {
+ this.ifColumnExists = ifColumnExists;
+
+ return this;
+ }
+
@Override
public CatalogCommand build() {
return new AlterTableDropColumnCommand(
tableName,
schemaName,
ifTableExists,
- columns
+ columns,
+ ifColumnExists
);
}
}
diff --git
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableDropColumnCommandBuilder.java
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableDropColumnCommandBuilder.java
index cde3f509dd8..90387a5116f 100644
---
a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableDropColumnCommandBuilder.java
+++
b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/commands/AlterTableDropColumnCommandBuilder.java
@@ -29,4 +29,7 @@ import java.util.Set;
public interface AlterTableDropColumnCommandBuilder extends
AbstractTableCommandBuilder<AlterTableDropColumnCommandBuilder> {
/** Set of the columns to delete. There must be at least one column. */
AlterTableDropColumnCommandBuilder columns(Set<String> columns);
+
+ /** The flag indicating that the command should not fail if a column with
the specified name does not exist. */
+ AlterTableDropColumnCommandBuilder ifColumnExists(boolean ifColumnExists);
}
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 a59fea2f73e..e3df89d26f0 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
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.catalog.commands;
import static
org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrowsWithCause;
import static org.apache.ignite.sql.ColumnType.INT32;
import static org.apache.ignite.sql.ColumnType.STRING;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import java.util.List;
import org.apache.ignite.internal.catalog.Catalog;
@@ -171,6 +172,27 @@ public class AlterTableAddColumnCommandValidationTest
extends AbstractCommandVal
);
}
+ @Test
+ void
exceptionNotThrownIfColumnWithGivenNameAlreadyExistsWithIfColumnNotExists() {
+ String tableName = "TEST";
+ String columnName = "TEST";
+ ColumnParams columnParams =
ColumnParams.builder().name(columnName).type(INT32).build();
+ Catalog catalog = catalogWithTable(builder -> builder
+ .schemaName(SCHEMA_NAME)
+ .tableName(tableName)
+ .columns(List.of(columnParams))
+ .primaryKey(primaryKey(columnName))
+ );
+
+ AlterTableAddColumnCommandBuilder builder =
AlterTableAddColumnCommand.builder()
+ .schemaName(SCHEMA_NAME)
+ .tableName(tableName)
+ .columns(List.of(columnParams))
+ .ifColumnNotExists(true);
+
+ assertDoesNotThrow(() -> builder.build().get(new
UpdateContext(catalog)));
+ }
+
@Test
void cannotAddColumnWithFunctionalDefault() {
String tableName = "TEST";
diff --git
a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/AlterTableDropColumnCommandValidationTest.java
b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/AlterTableDropColumnCommandValidationTest.java
index 6c430f4cdd9..647056e5a7f 100644
---
a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/AlterTableDropColumnCommandValidationTest.java
+++
b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/AlterTableDropColumnCommandValidationTest.java
@@ -175,6 +175,26 @@ public class AlterTableDropColumnCommandValidationTest
extends AbstractCommandVa
);
}
+ @Test
+ void
exceptionDoesNotThrownIfColumnWithGivenNameNotExistsWithIfColumnExists() {
+ String tableName = "TEST";
+ String columnName = "TEST";
+ Catalog catalog = catalogWithTable(builder -> builder
+ .schemaName(SCHEMA_NAME)
+ .tableName(tableName)
+
.columns(List.of(ColumnParams.builder().name(columnName).type(INT32).build()))
+ .primaryKey(primaryKey(columnName))
+ );
+
+ AlterTableDropColumnCommandBuilder builder =
AlterTableDropColumnCommand.builder()
+ .schemaName(SCHEMA_NAME)
+ .tableName(tableName)
+ .columns(Set.of(columnName + "_UNK"))
+ .ifColumnExists(true);
+
+ assertDoesNotThrow(() -> builder.build().get(new
UpdateContext(catalog)));
+ }
+
@Test
void exceptionIsThrownIfColumnBelongsToPrimaryKey() {
String tableName = "TEST";
diff --git
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlApiBaseTest.java
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlApiBaseTest.java
index a55e9adf73b..adc3c22cb60 100644
---
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlApiBaseTest.java
+++
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlApiBaseTest.java
@@ -127,6 +127,7 @@ public abstract class ItSqlApiBaseTest extends
BaseSqlIntegrationTest {
// ADD COLUMN
checkDdl(true, sql, "ALTER TABLE TEST ADD COLUMN VAL1 VARCHAR");
+ checkDdl(true, sql, "ALTER TABLE TEST ADD COLUMN (VAL2 VARCHAR, VAL3
VARCHAR)");
checkSqlError(
Sql.STMT_VALIDATION_ERR,
"Table with name 'PUBLIC.NOT_EXISTS_TABLE' not found",
@@ -140,6 +141,8 @@ public abstract class ItSqlApiBaseTest extends
BaseSqlIntegrationTest {
sql,
"ALTER TABLE TEST ADD COLUMN VAL1 INT"
);
+ checkDdl(false, sql, "ALTER TABLE TEST ADD COLUMN IF NOT EXISTS VAL1
INT");
+ checkDdl(true, sql, "ALTER TABLE TEST ADD COLUMN IF NOT EXISTS (VAL1
INT, VAL4 INT)");
// CREATE INDEX
checkDdl(true, sql, "CREATE INDEX TEST_IDX ON TEST(VAL0)");
@@ -200,6 +203,7 @@ public abstract class ItSqlApiBaseTest extends
BaseSqlIntegrationTest {
sql,
"ALTER TABLE TEST DROP COLUMN VAL1"
);
+ checkDdl(false, sql, "ALTER TABLE TEST DROP COLUMN IF EXISTS VAL1");
// DROP TABLE
checkDdl(false, sql, "DROP TABLE IF EXISTS NOT_EXISTS_TABLE");
diff --git a/modules/sql-engine/src/main/codegen/includes/parserImpls.ftl
b/modules/sql-engine/src/main/codegen/includes/parserImpls.ftl
index b1d9d3d7fe6..d483044a1a7 100644
--- a/modules/sql-engine/src/main/codegen/includes/parserImpls.ftl
+++ b/modules/sql-engine/src/main/codegen/includes/parserImpls.ftl
@@ -513,17 +513,19 @@ SqlNode SqlAlterTable() :
SqlNode col;
SqlNodeList cols;
SqlNodeList propertyList;
+ final boolean ifColumnNotExists;
+ final boolean ifColumnExists;
}
{
<ALTER> { s = span(); }
<TABLE> ifExists = IfExistsOpt() id = CompoundIdentifier()
(
- <ADD> [<COLUMN>] cols = ColumnWithTypeOrList() {
- return new IgniteSqlAlterTableAddColumn(s.end(this), ifExists, id,
cols);
+ <ADD> [<COLUMN>] ifColumnNotExists = IfNotExistsOpt() cols =
ColumnWithTypeOrList() {
+ return new IgniteSqlAlterTableAddColumn(s.end(this), ifExists, id,
cols, ifColumnNotExists);
}
|
- <DROP> [<COLUMN>] cols = SimpleIdentifierOrList() {
- return new IgniteSqlAlterTableDropColumn(s.end(this), ifExists,
id, cols);
+ <DROP> [<COLUMN>] ifColumnExists = IfExistsOpt() cols =
SimpleIdentifierOrList() {
+ return new IgniteSqlAlterTableDropColumn(s.end(this), ifExists,
id, cols, ifColumnExists);
}
|
<ALTER> [<COLUMN>] {
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverter.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverter.java
index b000db18c3a..cfea9272fe3 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverter.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverter.java
@@ -565,6 +565,7 @@ public class DdlSqlToCommandConverter {
builder.schemaName(deriveSchemaName(alterTblNode.name(), ctx));
builder.tableName(deriveObjectName(alterTblNode.name(), ctx, "table
name"));
builder.ifTableExists(alterTblNode.ifExists());
+ builder.ifColumnNotExists(alterTblNode.ifColumnNotExists());
List<ColumnParams> columns = new
ArrayList<>(alterTblNode.columns().size());
@@ -672,6 +673,7 @@ public class DdlSqlToCommandConverter {
builder.schemaName(deriveSchemaName(alterTblNode.name(), ctx));
builder.tableName(deriveObjectName(alterTblNode.name(), ctx, "table
name"));
builder.ifTableExists(alterTblNode.ifExists());
+ builder.ifColumnExists(alterTblNode.ifColumnExists());
Set<String> cols = new HashSet<>(alterTblNode.columns().size());
alterTblNode.columns().forEach(c -> cols.add(((SqlIdentifier)
c).getSimple()));
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterTableAddColumn.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterTableAddColumn.java
index 2763c214b59..ea0a6706540 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterTableAddColumn.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterTableAddColumn.java
@@ -39,27 +39,48 @@ public class IgniteSqlAlterTableAddColumn extends
IgniteAbstractSqlAlterTable {
/** ALTER TABLE ... ADD COLUMN operator. */
protected static class Operator extends IgniteDdlOperator {
+ private final boolean columnNotExistFlag;
/** Constructor. */
- protected Operator(boolean existFlag) {
+ protected Operator(boolean existFlag, boolean columnNotExistFlag) {
super("ALTER TABLE", SqlKind.ALTER_TABLE, existFlag);
+
+ this.columnNotExistFlag = columnNotExistFlag;
}
/** {@inheritDoc} */
@Override
public SqlCall createCall(@Nullable SqlLiteral functionQualifier,
SqlParserPos pos, @Nullable SqlNode... operands) {
- return new IgniteSqlAlterTableAddColumn(pos, existFlag(),
(SqlIdentifier) operands[0], (SqlNodeList) operands[1]);
+ return new IgniteSqlAlterTableAddColumn(
+ pos,
+ existFlag(),
+ (SqlIdentifier) operands[0],
+ (SqlNodeList) operands[1],
+ columnNotExistFlag()
+ );
+ }
+
+ boolean columnNotExistFlag() {
+ return columnNotExistFlag;
}
}
/** Introduced columns. */
private final SqlNodeList columns;
+ private final boolean ifColumnNotExists;
+
/** Constructor. */
- public IgniteSqlAlterTableAddColumn(SqlParserPos pos, boolean ifExists,
SqlIdentifier tblName,
- SqlNodeList columns) {
- super(new Operator(ifExists), pos, tblName);
+ public IgniteSqlAlterTableAddColumn(
+ SqlParserPos pos,
+ boolean ifExists,
+ SqlIdentifier tblName,
+ SqlNodeList columns,
+ boolean ifColumnNotExists
+ ) {
+ super(new Operator(ifExists, ifColumnNotExists), pos, tblName);
this.columns = Objects.requireNonNull(columns, "columns list");
+ this.ifColumnNotExists = ifColumnNotExists;
}
/** {@inheritDoc} */
@@ -74,6 +95,12 @@ public class IgniteSqlAlterTableAddColumn extends
IgniteAbstractSqlAlterTable {
writer.keyword("ADD");
writer.keyword("COLUMN");
+ if (ifColumnNotExists) {
+ writer.keyword("IF");
+ writer.keyword("NOT");
+ writer.keyword("EXISTS");
+ }
+
columns.unparse(writer, leftPrec, rightPrec);
}
@@ -81,4 +108,9 @@ public class IgniteSqlAlterTableAddColumn extends
IgniteAbstractSqlAlterTable {
public SqlNodeList columns() {
return columns;
}
+
+ /** If not exists flag for the column. */
+ public boolean ifColumnNotExists() {
+ return ifColumnNotExists;
+ }
}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterTableDropColumn.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterTableDropColumn.java
index 8e790eadf51..ae80e692824 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterTableDropColumn.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterTableDropColumn.java
@@ -36,30 +36,50 @@ import org.jetbrains.annotations.Nullable;
*/
@DdlBatchAware
public class IgniteSqlAlterTableDropColumn extends IgniteAbstractSqlAlterTable
{
-
/** ALTER TABLE operator. */
protected static class Operator extends IgniteDdlOperator {
+ private final boolean columnExistFlag;
/** Constructor. */
- protected Operator(boolean existFlag) {
+ protected Operator(boolean existFlag, boolean columnExistFlag) {
super("ALTER TABLE", SqlKind.ALTER_TABLE, existFlag);
+
+ this.columnExistFlag = columnExistFlag;
}
/** {@inheritDoc} */
@Override
public SqlCall createCall(@Nullable SqlLiteral functionQualifier,
SqlParserPos pos, @Nullable SqlNode... operands) {
- return new IgniteSqlAlterTableDropColumn(pos, existFlag(),
(SqlIdentifier) operands[0], (SqlNodeList) operands[1]);
+ return new IgniteSqlAlterTableDropColumn(
+ pos,
+ existFlag(),
+ (SqlIdentifier) operands[0],
+ (SqlNodeList) operands[1],
+ columnExistFlag()
+ );
+ }
+
+ boolean columnExistFlag() {
+ return columnExistFlag;
}
}
/** Columns to drop. */
private final SqlNodeList columns;
+ private final boolean ifColumnExists;
+
/** Constructor. */
- public IgniteSqlAlterTableDropColumn(SqlParserPos pos, boolean ifExists,
SqlIdentifier tblName,
- SqlNodeList columns) {
- super(new Operator(ifExists), pos, tblName);
+ public IgniteSqlAlterTableDropColumn(
+ SqlParserPos pos,
+ boolean ifExists,
+ SqlIdentifier tblName,
+ SqlNodeList columns,
+ boolean ifColumnExists
+ ) {
+ super(new Operator(ifExists, ifColumnExists), pos, tblName);
this.columns = Objects.requireNonNull(columns, "columns list");
+ this.ifColumnExists = ifColumnExists;
}
/** {@inheritDoc} */
@@ -74,6 +94,11 @@ public class IgniteSqlAlterTableDropColumn extends
IgniteAbstractSqlAlterTable {
writer.keyword("DROP");
writer.keyword("COLUMN");
+ if (ifColumnExists) {
+ writer.keyword("IF");
+ writer.keyword("EXISTS");
+ }
+
columns.unparse(writer, leftPrec, rightPrec);
}
@@ -81,4 +106,9 @@ public class IgniteSqlAlterTableDropColumn extends
IgniteAbstractSqlAlterTable {
public SqlNodeList columns() {
return columns;
}
+
+ /** If exists flag for column. */
+ public boolean ifColumnExists() {
+ return ifColumnExists;
+ }
}
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/SqlDdlParserTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/SqlDdlParserTest.java
index 3ec7347c5cb..3eb7745d6fa 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/SqlDdlParserTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/SqlDdlParserTest.java
@@ -1115,6 +1115,7 @@ public class SqlDdlParserTest extends AbstractParserTest {
SqlColumnDeclaration declaration = (SqlColumnDeclaration)
addColumn.columns().get(0);
assertThat(addColumn.name.names, is(List.of("T")));
+ assertThat(addColumn.ifColumnNotExists(), is(false));
expectColumnBasic(declaration, "C", ColumnStrategy.NULLABLE,
"INTEGER", true);
assertThat(declaration.expression, is(nullValue()));
@@ -1122,6 +1123,22 @@ public class SqlDdlParserTest extends AbstractParserTest
{
expectUnparsed(addColumn, "ALTER TABLE \"T\" ADD COLUMN \"C\"
INTEGER");
}
+ @Test
+ public void alterTableAddColumnIfNotExists() {
+ SqlNode sqlNode = parse("ALTER TABLE t ADD COLUMN IF NOT EXISTS c
INT");
+
+ IgniteSqlAlterTableAddColumn addColumn =
assertInstanceOf(IgniteSqlAlterTableAddColumn.class, sqlNode);
+ SqlColumnDeclaration declaration = (SqlColumnDeclaration)
addColumn.columns().get(0);
+
+ assertThat(addColumn.name.names, is(List.of("T")));
+ assertThat(addColumn.ifColumnNotExists(), is(true));
+
+ expectColumnBasic(declaration, "C", ColumnStrategy.NULLABLE,
"INTEGER", true);
+ assertThat(declaration.expression, is(nullValue()));
+
+ expectUnparsed(addColumn, "ALTER TABLE \"T\" ADD COLUMN IF NOT EXISTS
\"C\" INTEGER");
+ }
+
@Test
public void alterTableAddColumnNull() {
SqlNode sqlNode = parse("ALTER TABLE t ADD COLUMN c INT NULL");
@@ -1152,6 +1169,30 @@ public class SqlDdlParserTest extends AbstractParserTest
{
expectUnparsed(addColumn, "ALTER TABLE \"T\" ADD COLUMN \"C\" INTEGER
NOT NULL");
}
+ @Test
+ public void alterTableDropColumn() {
+ SqlNode sqlNode = parse("ALTER TABLE t DROP COLUMN c");
+
+ IgniteSqlAlterTableDropColumn dropColumn =
assertInstanceOf(IgniteSqlAlterTableDropColumn.class, sqlNode);
+
+ assertThat(dropColumn.name.names, is(List.of("T")));
+ assertThat(dropColumn.ifColumnExists(), is(false));
+
+ expectUnparsed(dropColumn, "ALTER TABLE \"T\" DROP COLUMN \"C\"");
+ }
+
+ @Test
+ public void alterTableDropColumnIfExists() {
+ SqlNode sqlNode = parse("ALTER TABLE t DROP COLUMN IF EXISTS c");
+
+ IgniteSqlAlterTableDropColumn dropColumn =
assertInstanceOf(IgniteSqlAlterTableDropColumn.class, sqlNode);
+
+ assertThat(dropColumn.name.names, is(List.of("T")));
+ assertThat(dropColumn.ifColumnExists(), is(true));
+
+ expectUnparsed(dropColumn, "ALTER TABLE \"T\" DROP COLUMN IF EXISTS
\"C\"");
+ }
+
/**
* CHAR datatype has certain storage assignment rules, namely it requires
value to be padded with `space` character up to declared
* length. This currently not supported in storage, thus let's forbid
usage of CHAR datatype for table's columns.