Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,10 @@ default String createTable(TableReference table, List<ColumnDefinition> columns,
cd.columnMetaData().columnDefault().ifPresent(d -> sb.append(" DEFAULT ").append(d));
}
if (primaryKey != null && !primaryKey.columns().isEmpty()) {
sb.append(",\n PRIMARY KEY (");
sb.append(",\n ");
primaryKey.constraintName().filter(n -> supportsNamedPrimaryKey())
.ifPresent(n -> sb.append("CONSTRAINT ").append(quoteIdentifier(n)).append(' '));
sb.append("PRIMARY KEY (");
sb.append(String.join(", ",
primaryKey.columns().stream().map(c -> quoteIdentifier(c.name()).toString()).toList()));
sb.append(")");
Expand Down Expand Up @@ -307,11 +310,19 @@ default String renameTable(TableReference table, String newName) {
.append(quoteIdentifier(newName)).toString();
}

/**
* {@code ALTER INDEX schema.old RENAME TO new}. Index names are schema-scoped
* (PostgreSQL, H2, Oracle), so the old name is qualified with the table's
* schema — unqualified it would only be found on the search path.
*/
default String renameIndex(String oldName, String newName, TableReference table) {
if (!supportsRenameIndex()) {
return null;
}
return new StringBuilder("ALTER INDEX ").append(quoteIdentifier(oldName)).append(" RENAME TO ")
String old = table != null && table.schema().isPresent()
? quoteIdentifier(table.schema().get().name(), oldName).toString()
: quoteIdentifier(oldName);
return new StringBuilder("ALTER INDEX ").append(old).append(" RENAME TO ")
.append(quoteIdentifier(newName)).toString();
}

Expand Down Expand Up @@ -648,6 +659,38 @@ default Optional<String> dropProcedure(String procedureName, String schemaName,
return Optional.empty();
}

// -------------------- comments --------------------

/**
* {@code COMMENT ON TABLE schema.table IS '…'}; a {@code null} comment
* removes it ({@code IS NULL}).
*
* @return empty when the dialect cannot store table comments
*/
default Optional<String> commentOnTable(TableReference table, String comment) {
return Optional.of("COMMENT ON TABLE " + qualified(table) + " IS " + commentLiteral(comment));
}

/**
* {@code COMMENT ON COLUMN schema.table.column IS '…'}; a {@code null}
* comment removes it.
*
* @param currentMeta the column's current definition — required by dialects
* that can only set a column comment by restating the
* whole column (MySQL/MariaDB); may be {@code null} otherwise
* @return empty when the dialect cannot store column comments
*/
default Optional<String> commentOnColumn(TableReference table, String columnName, String comment,
ColumnMetaData currentMeta) {
return Optional.of("COMMENT ON COLUMN " + qualified(table) + "." + quoteIdentifier(columnName) + " IS "
+ commentLiteral(comment));
}

/** ANSI string literal for a comment ({@code '} doubled), or {@code NULL}. */
private static String commentLiteral(String comment) {
return comment == null ? "NULL" : "'" + comment.replace("'", "''") + "'";
}

default java.util.List<String> dropTriggerOnTable(String triggerName, TableReference table, boolean ifExists) {
return java.util.List.of(dropTrigger(triggerName, ifExists));
}
Expand Down Expand Up @@ -1000,6 +1043,15 @@ default boolean supportsRenameConstraint() {
return true;
}

/**
* @return true if {@code createTable} may name the primary key
* ({@code CONSTRAINT name PRIMARY KEY (…)}); without it the
* database picks the name and a later rename or drop by name misses
*/
default boolean supportsNamedPrimaryKey() {
return true;
}

/**
* @return true if {@code renameTables} renders ONE statement that applies all
* renames atomically (MySQL family {@code RENAME TABLE a TO b, c TO d},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/
package org.eclipse.daanse.sql.dialect.api.generator;

import java.util.List;
import java.util.Optional;
import java.util.OptionalLong;

Expand Down Expand Up @@ -61,4 +62,29 @@ default boolean supportsOffset() {
default Optional<String> paginate(long limit) {
return Optional.of(paginate(OptionalLong.of(limit), OptionalLong.empty()));
}

/** Paging clause with placeholders; the returned order lists which parameter comes first. */
default PreparedPaging paginatePrepared(boolean withLimit, boolean withOffset) {
if (withLimit && withOffset) {
return new PreparedPaging(
"OFFSET ? ROWS FETCH NEXT ? ROWS ONLY",
List.of(PagingParam.OFFSET, PagingParam.LIMIT)
);
} else if (withLimit) {
return new PreparedPaging(
"FETCH NEXT ? ROWS ONLY",
List.of(PagingParam.LIMIT)
);
} else if (withOffset) {
return new PreparedPaging(
"OFFSET ? ROWS",
List.of(PagingParam.OFFSET)
);
} else {
return new PreparedPaging("", List.of());
}
}

record PreparedPaging(String clause, List<PagingParam> order) {}
enum PagingParam { LIMIT, OFFSET }
}
Original file line number Diff line number Diff line change
Expand Up @@ -296,4 +296,28 @@ public boolean supportsAtomicMultiRenameTable() {
return true;
}

/** {@code ALTER TABLE t MODIFY COMMENT '…'}; {@code null} clears it. */
@Override
public java.util.Optional<String> commentOnTable(TableReference table, String comment) {
return java.util.Optional.of("ALTER TABLE " + qualified(table) + " MODIFY COMMENT " + chLiteral(comment));
}

/** {@code ALTER TABLE t COMMENT COLUMN c '…'}; {@code null} clears it. */
@Override
public java.util.Optional<String> commentOnColumn(TableReference table, String columnName, String comment,
org.eclipse.daanse.sql.model.schema.ColumnMetaData currentMeta) {
return java.util.Optional.of("ALTER TABLE " + qualified(table) + " COMMENT COLUMN "
+ quoteIdentifier(columnName) + " " + chLiteral(comment));
}

private static String chLiteral(String comment) {
String s = comment == null ? "" : comment;
return "'" + s.replace("\\", "\\\\").replace("'", "\\'") + "'";
}

/** ClickHouse has no named table constraints; the primary key stays unnamed. */
@Override
public boolean supportsNamedPrimaryKey() {
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2026 Contributors to the Eclipse Foundation.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.daanse.sql.dialect.db.clickhouse;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Optional;

import org.eclipse.daanse.sql.model.schema.SchemaReference;
import org.eclipse.daanse.sql.model.schema.TableReference;
import org.junit.jupiter.api.Test;

class ClickHouseDialectCommentTest {

private final ClickHouseDialect d = new ClickHouseDialect();
private final TableReference t = new TableReference(Optional.of(new SchemaReference("s")), "t",
TableReference.TYPE_TABLE);

@Test
void comments() {
assertThat(d.commentOnTable(t, "it's").orElseThrow()).endsWith(" MODIFY COMMENT 'it\\'s'");
assertThat(d.commentOnColumn(t, "c", "x", null).orElseThrow()).endsWith(" COMMENT COLUMN \"c\" 'x'");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,9 @@ void testGenerateListAgg() {
assertEquals("groupArrayArray( column1)", result);
}
}

@Test
void primaryKeyStaysUnnamed() {
assertFalse(dialect.supportsNamedPrimaryKey());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,15 @@ public String renameIndex(String oldName, String newName, TableReference table)
.append(quoteIdentifier(newName)).toString();
}

/** Derby cannot store comments on tables or columns. */
@Override
public java.util.Optional<String> commentOnTable(TableReference table, String comment) {
return java.util.Optional.empty();
}

@Override
public java.util.Optional<String> commentOnColumn(TableReference table, String columnName, String comment,
org.eclipse.daanse.sql.model.schema.ColumnMetaData currentMeta) {
return java.util.Optional.empty();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2026 Contributors to the Eclipse Foundation.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.daanse.sql.dialect.db.derby;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Optional;

import org.eclipse.daanse.sql.model.schema.SchemaReference;
import org.eclipse.daanse.sql.model.schema.TableReference;
import org.junit.jupiter.api.Test;

class DerbyDialectCommentTest {

private final DerbyDialect d = new DerbyDialect();
private final TableReference t = new TableReference(Optional.of(new SchemaReference("s")), "t",
TableReference.TYPE_TABLE);

@Test
void comments() {
assertThat(d.commentOnTable(t, "x")).isEmpty();
assertThat(d.commentOnColumn(t, "c", "x", null)).isEmpty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import org.eclipse.daanse.sql.dialect.api.generator.PaginationGenerator.PagingParam;
import org.eclipse.daanse.sql.dialect.api.generator.PaginationGenerator.PreparedPaging;
import org.eclipse.daanse.sql.dialect.db.common.AbstractJdbcDialect;
import org.eclipse.daanse.sql.dialect.db.common.DialectUtil;
import org.eclipse.daanse.sql.model.sql.BitOperation;
Expand Down Expand Up @@ -251,6 +253,28 @@ public String paginate(java.util.OptionalLong limit, java.util.OptionalLong offs
});
return sb.toString();
}

@Override
public PreparedPaging paginatePrepared(boolean withLimit, boolean withOffset) {
if (withLimit && withOffset) {
return new PreparedPaging(
"LIMIT ? OFFSET ?",
List.of(PagingParam.LIMIT, PagingParam.OFFSET)
);
} else if (withLimit) {
return new PreparedPaging(
"LIMIT ?",
List.of(PagingParam.LIMIT)
);
} else if (withOffset) {
return new PreparedPaging(
"OFFSET ?",
List.of(PagingParam.OFFSET)
);
} else {
return new PreparedPaging("", List.of());
}
}
};
cachedPaginationGenerator = local;
return local;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@

import org.eclipse.daanse.sql.model.sql.BitOperation;
import org.eclipse.daanse.sql.model.sql.OrderedColumn;
import org.eclipse.daanse.sql.dialect.api.generator.PaginationGenerator.PagingParam;
import org.eclipse.daanse.sql.dialect.api.generator.PaginationGenerator.PreparedPaging;
import org.eclipse.daanse.sql.dialect.db.common.AbstractJdbcDialect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class H2Dialect extends AbstractJdbcDialect {

private volatile org.eclipse.daanse.sql.dialect.api.generator.PaginationGenerator cachedPaginationGenerator;
private static final Logger LOGGER = LoggerFactory.getLogger(H2Dialect.class);

private static final String SUPPORTED_PRODUCT_NAME = "H2";
Expand Down Expand Up @@ -221,4 +224,59 @@ public boolean supportsListAgg() {
public String grantRole(String roleName, String grantee, boolean withAdminOption) {
return "GRANT " + quoteIdentifier(roleName) + " TO " + quoteIdentifier(grantee);
}

@Override
public org.eclipse.daanse.sql.dialect.api.generator.PaginationGenerator paginationGenerator() {
var local = cachedPaginationGenerator;
if (local != null)
return local;
local = new org.eclipse.daanse.sql.dialect.api.generator.PaginationGenerator() {
@Override
public String paginate(java.util.OptionalLong limit, java.util.OptionalLong offset) {
if (limit.isEmpty() && offset.isEmpty())
return "";
StringBuilder sb = new StringBuilder();
if (limit.isPresent()) {
long l = limit.getAsLong();
if (l < 0)
throw new IllegalArgumentException("limit must be >= 0");
sb.append(" LIMIT ").append(l);
} else {
sb.append(" LIMIT -1");
}
if (offset.isPresent()) {
long o = offset.getAsLong();
if (o < 0)
throw new IllegalArgumentException("offset must be >= 0");
sb.append(" OFFSET ").append(o);
}
return sb.toString();
}

@Override
public PreparedPaging paginatePrepared(boolean withLimit, boolean withOffset) {
if (withLimit && withOffset) {
return new PreparedPaging(
"LIMIT ? OFFSET ?",
List.of(PagingParam.LIMIT, PagingParam.OFFSET)
);
} else if (withLimit) {
return new PreparedPaging(
"LIMIT ?",
List.of(PagingParam.LIMIT)
);
} else if (withOffset) {
return new PreparedPaging(
"OFFSET ?",
List.of(PagingParam.OFFSET)
);
} else {
return new PreparedPaging("", List.of());
}
}
};
cachedPaginationGenerator = local;
return local;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ void renameColumn_uses_ANSI_default() {
@Test
void renameIndex_uses_ANSI_default() {
assertThat(dialect.ddlGenerator().renameIndex("IDX_OLD", "IDX_NEW", T))
.isEqualTo("ALTER INDEX \"IDX_OLD\" RENAME TO \"IDX_NEW\"");
.isEqualTo("ALTER INDEX \"PUBLIC\".\"IDX_OLD\" RENAME TO \"IDX_NEW\"");
}

@Test
Expand Down
Loading
Loading