diff --git a/dialect/db/hive/pom.xml b/dialect/db/hive/pom.xml
new file mode 100644
index 0000000..f1cd519
--- /dev/null
+++ b/dialect/db/hive/pom.xml
@@ -0,0 +1,92 @@
+
+
+
+ 4.0.0
+
+ org.eclipse.daanse
+ org.eclipse.daanse.sql.dialect.db
+ ${revision}
+ ../pom.xml
+
+ org.eclipse.daanse.sql.dialect.db.hive
+ Eclipse Daanse JDBC DB Dialect Hive
+
+
+ 4.2.0
+
+
+
+
+ org.slf4j
+ slf4j-api
+
+
+ org.eclipse.daanse
+ org.eclipse.daanse.sql.dialect.api
+ ${revision}
+
+
+ org.eclipse.daanse
+ org.eclipse.daanse.sql.dialect.db.common
+ ${revision}
+
+
+ biz.aQute.bnd
+ biz.aQute.bndlib
+
+
+
+ org.apache.hive
+ hive-jdbc
+ ${hive-jdbc.version}
+ standalone
+ test
+
+
+ *
+ *
+
+
+
+
+ org.testcontainers
+ junit-jupiter
+ 1.19.7
+ test
+
+
+ org.eclipse.daanse
+ org.eclipse.daanse.sql.jdbc.record
+ ${project.version}
+ test
+
+
+
+
+
+ maven-surefire-plugin
+
+
+
+ ${env.DOCKER_HOST}
+
+
+
+
+
+
diff --git a/dialect/db/hive/src/main/java/org/eclipse/daanse/sql/dialect/db/hive/HiveDialect.java b/dialect/db/hive/src/main/java/org/eclipse/daanse/sql/dialect/db/hive/HiveDialect.java
new file mode 100644
index 0000000..b2b940a
--- /dev/null
+++ b/dialect/db/hive/src/main/java/org/eclipse/daanse/sql/dialect/db/hive/HiveDialect.java
@@ -0,0 +1,123 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * SmartCity Jena - initial
+ * Stefan Bischof (bipolis.org) - initial
+ */
+package org.eclipse.daanse.sql.dialect.db.hive;
+
+import java.sql.Date;
+import java.sql.Timestamp;
+import java.util.List;
+
+import org.eclipse.daanse.sql.dialect.api.DialectInitData;
+import org.eclipse.daanse.sql.dialect.api.IdentifierCaseFolding;
+import org.eclipse.daanse.sql.dialect.db.common.AbstractJdbcDialect;
+import org.eclipse.daanse.sql.dialect.db.common.DialectUtil;
+
+/**
+ * Dialect for the Apache Hive database (HiveQL over HiveServer2).
+ */
+public class HiveDialect extends AbstractJdbcDialect {
+
+ private static final String SUPPORTED_PRODUCT_NAME = "HIVE";
+
+ /** JDBC-free constructor for SQL generation. Uses HiveQL backtick quoting. */
+ public HiveDialect() {
+ super(DialectInitData.ansiDefaults().withQuoteIdentifierString("`"));
+ }
+
+ /** Construct from a captured snapshot — the canonical entry point. */
+ public HiveDialect(DialectInitData init) {
+ super(init);
+ }
+
+ @Override
+ public boolean supportsResultSetConcurrency(int type, int concurrency) {
+ return false;
+ }
+
+ @Override
+ public boolean allowsCompoundCountDistinct() {
+ return true;
+ }
+
+ @Override
+ public boolean requiresAliasForFromQuery() {
+ return true;
+ }
+
+ @Override
+ public boolean requiresOrderByAlias() {
+ return true;
+ }
+
+ // Explicit even though it matches the derived default here: a subclass that
+ // flips requiresOrderByAlias() to false must keep ORDER BY aliases allowed.
+ @Override
+ public boolean allowsOrderByAlias() {
+ return true;
+ }
+
+ @Override
+ public boolean requiresUnionOrderByExprInSelect() {
+ return false;
+ }
+
+ @Override
+ public boolean requiresUnionOrderByOrdinal() {
+ return false;
+ }
+
+ @Override
+ public boolean allowsJoinOn() {
+ return false;
+ }
+
+ @Override
+ public StringBuilder generateInline(List columnNames, List columnTypes, List valueList) {
+ // The legacy (Mondrian-era) form appended " from dual", which fails on
+ // any modern Hive ("Table not found 'dual'" — verified against Hive 4);
+ // Hive supports FROM-less SELECTs since 0.13.
+ return new StringBuilder("select * from (")
+ .append(generateInlineGeneric(columnNames, columnTypes, valueList, null, false))
+ .append(") x limit ").append(valueList.size());
+ }
+
+ @Override
+ protected void quoteDateLiteral(StringBuilder buf, Date date) {
+ // Hive doesn't support Date type; treat date as a string '2008-01-23'
+ DialectUtil.singleQuoteString(date.toString(), buf);
+ }
+
+ @Override
+ protected void quoteTimestampLiteral(StringBuilder buf, String value, Timestamp timestamp) {
+ buf.append("cast( ");
+ DialectUtil.singleQuoteString(value, buf);
+ buf.append(" as timestamp )");
+ }
+
+ @Override
+ public StringBuilder generateOrderByNulls(CharSequence expr, boolean ascending, boolean collateNullsLast) {
+ // In Hive, Null values are worth negative infinity.
+ return DialectUtil.generateOrderByNullsWithIsnull(expr, ascending, collateNullsLast);
+ }
+
+ @Override
+ public IdentifierCaseFolding caseFolding() {
+ return IdentifierCaseFolding.PRESERVE;
+ }
+
+ @Override
+ public String name() {
+ return SUPPORTED_PRODUCT_NAME.toLowerCase();
+ }
+
+}
diff --git a/dialect/db/hive/src/main/java/org/eclipse/daanse/sql/dialect/db/hive/HiveDialectFactory.java b/dialect/db/hive/src/main/java/org/eclipse/daanse/sql/dialect/db/hive/HiveDialectFactory.java
new file mode 100644
index 0000000..2ee6dec
--- /dev/null
+++ b/dialect/db/hive/src/main/java/org/eclipse/daanse/sql/dialect/db/hive/HiveDialectFactory.java
@@ -0,0 +1,34 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * SmartCity Jena - initial
+ * Stefan Bischof (bipolis.org) - initial
+ */
+package org.eclipse.daanse.sql.dialect.db.hive;
+
+import java.util.function.Function;
+
+import org.eclipse.daanse.sql.dialect.api.DialectFactory;
+import org.eclipse.daanse.sql.dialect.api.DialectInitData;
+import org.eclipse.daanse.sql.dialect.api.DialectName;
+import org.eclipse.daanse.sql.dialect.db.common.AbstractDialectFactory;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ServiceScope;
+
+@Component(service = DialectFactory.class, scope = ServiceScope.SINGLETON)
+@DialectName("HIVE")
+public class HiveDialectFactory extends AbstractDialectFactory {
+
+ @Override
+ public Function getConstructorFunction() {
+ return HiveDialect::new;
+ }
+
+}
diff --git a/dialect/db/hive/src/main/java/org/eclipse/daanse/sql/dialect/db/hive/package-info.java b/dialect/db/hive/src/main/java/org/eclipse/daanse/sql/dialect/db/hive/package-info.java
new file mode 100644
index 0000000..0c94ecb
--- /dev/null
+++ b/dialect/db/hive/src/main/java/org/eclipse/daanse/sql/dialect/db/hive/package-info.java
@@ -0,0 +1,17 @@
+/*
+* 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
+*
+* Contributors:
+* SmartCity Jena - initial
+* Stefan Bischof (bipolis.org) - initial
+*/
+
+@org.osgi.annotation.bundle.Export
+@org.osgi.annotation.versioning.Version("0.0.1")
+package org.eclipse.daanse.sql.dialect.db.hive;
diff --git a/dialect/db/hive/src/test/java/org/eclipse/daanse/sql/dialect/db/hive/HiveDialectQuotingPolicyTest.java b/dialect/db/hive/src/test/java/org/eclipse/daanse/sql/dialect/db/hive/HiveDialectQuotingPolicyTest.java
new file mode 100644
index 0000000..ec28df6
--- /dev/null
+++ b/dialect/db/hive/src/test/java/org/eclipse/daanse/sql/dialect/db/hive/HiveDialectQuotingPolicyTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.hive;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.eclipse.daanse.sql.dialect.api.IdentifierQuotingPolicy;
+import org.eclipse.daanse.sql.model.schema.SchemaReference;
+import org.eclipse.daanse.sql.model.schema.TableReference;
+import org.junit.jupiter.api.Test;
+
+class HiveDialectQuotingPolicyTest {
+
+ private static final SchemaReference S = new SchemaReference(Optional.empty(), "TEST");
+ private static final TableReference EMP = new TableReference(Optional.of(S), "EMPLOYEES",
+ TableReference.TYPE_TABLE);
+ private static final TableReference DEPT = new TableReference(Optional.of(S), "DEPARTMENTS",
+ TableReference.TYPE_TABLE);
+
+ private HiveDialect dialectNever() {
+ HiveDialect d = new HiveDialect();
+ d.setQuotingPolicy(IdentifierQuotingPolicy.NEVER);
+ return d;
+ }
+
+ @Test
+ void primaryKey_unquoted() {
+ assertThat(dialectNever().ddlGenerator().addPrimaryKeyConstraint(EMP, "PK_EMP", List.of("ID")))
+ .doesNotContain("`").contains("EMPLOYEES").contains("PK_EMP").contains("ID");
+ }
+
+ @Test
+ void uniqueConstraint_unquoted() {
+ assertThat(dialectNever().ddlGenerator().addUniqueConstraint(EMP, "UQ_EMP", List.of("EMAIL")))
+ .doesNotContain("`").contains("EMPLOYEES").contains("UQ_EMP").contains("EMAIL");
+ }
+
+ @Test
+ void foreignKey_unquoted() {
+ assertThat(dialectNever().ddlGenerator().addForeignKeyConstraint(EMP, "FK_EMP_DEPT", List.of("DEPT_ID"), DEPT,
+ List.of("ID"), "NO ACTION", "NO ACTION")).doesNotContain("`").contains("EMPLOYEES")
+ .contains("FK_EMP_DEPT").contains("DEPARTMENTS");
+ }
+
+ @Test
+ void renameTable_unquoted() {
+ assertThat(dialectNever().ddlGenerator().renameTable(EMP, "PERSON")).doesNotContain("`").contains("EMPLOYEES")
+ .contains("PERSON");
+ }
+
+ @Test
+ void createIndex_unquoted() {
+ assertThat(dialectNever().ddlGenerator().createIndex("IDX_EMP", EMP, List.of("NAME"), false, false))
+ .doesNotContain("`").contains("EMPLOYEES").contains("IDX_EMP").contains("NAME");
+ }
+
+ @Test
+ void dropConstraint_unquoted() {
+ assertThat(dialectNever().ddlGenerator().dropConstraint(EMP, "PK_EMP", true)).doesNotContain("`")
+ .contains("EMPLOYEES").contains("PK_EMP");
+ }
+}
diff --git a/dialect/db/hive/src/test/java/org/eclipse/daanse/sql/dialect/db/hive/HiveDialectTest.java b/dialect/db/hive/src/test/java/org/eclipse/daanse/sql/dialect/db/hive/HiveDialectTest.java
new file mode 100644
index 0000000..1b128da
--- /dev/null
+++ b/dialect/db/hive/src/test/java/org/eclipse/daanse/sql/dialect/db/hive/HiveDialectTest.java
@@ -0,0 +1,141 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * SmartCity Jena - initial
+ * Stefan Bischof (bipolis.org) - initial
+ */
+package org.eclipse.daanse.sql.dialect.db.hive;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.sql.ResultSet;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class HiveDialectTest {
+
+ private HiveDialect dialect;
+
+ @BeforeEach
+ void setUp() {
+ dialect = new HiveDialect();
+ }
+
+ @Test
+ void testName() {
+ assertEquals("hive", dialect.name());
+ }
+
+ @Test
+ void testQuoteIdentifierString() {
+ assertEquals("`", dialect.getQuoteIdentifierString());
+ }
+
+ @Test
+ void testSupportsResultSetConcurrency() {
+ assertFalse(dialect.supportsResultSetConcurrency(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY));
+ }
+
+ @Test
+ void testRequiresAliasForFromQuery() {
+ assertTrue(dialect.requiresAliasForFromQuery());
+ }
+
+ @Test
+ void testRequiresOrderByAlias() {
+ assertTrue(dialect.requiresOrderByAlias());
+ }
+
+ @Test
+ void testAllowsOrderByAlias() {
+ assertTrue(dialect.allowsOrderByAlias());
+ }
+
+ @Test
+ void testRequiresGroupByAlias() {
+ assertFalse(dialect.requiresGroupByAlias());
+ }
+
+ @Test
+ void testAllowsCompoundCountDistinct() {
+ assertTrue(dialect.allowsCompoundCountDistinct());
+ }
+
+ @Test
+ void testAllowsJoinOn() {
+ assertFalse(dialect.allowsJoinOn());
+ }
+
+ @Test
+ void testRequiresUnionOrderByExprInSelect() {
+ assertFalse(dialect.requiresUnionOrderByExprInSelect());
+ }
+
+ @Test
+ void testRequiresUnionOrderByOrdinal() {
+ assertFalse(dialect.requiresUnionOrderByOrdinal());
+ }
+
+ @Test
+ void testQuoteDateLiteral() {
+ StringBuilder buf = new StringBuilder();
+ dialect.quoteDateLiteral(buf, java.sql.Date.valueOf("2024-01-15"));
+ assertEquals("'2024-01-15'", buf.toString());
+ }
+
+ @Test
+ void testQuoteTimestampLiteral() {
+ StringBuilder buf = new StringBuilder();
+ // The public overload normalizes through Timestamp.toString(), hence the ".0".
+ dialect.quoteTimestampLiteral(buf, "2024-01-15 10:30:00");
+ assertEquals("cast( '2024-01-15 10:30:00.0' as timestamp )", buf.toString());
+ }
+
+ @Test
+ void testQuoteTimestampLiteral_InvalidFormat() {
+ StringBuilder buf = new StringBuilder();
+ assertThrows(NumberFormatException.class, () -> dialect.quoteTimestampLiteral(buf, "invalid"));
+ }
+
+ @Test
+ void testGenerateOrderByNulls_AscNullsLast() {
+ assertEquals("ISNULL(column1) ASC, column1 ASC", dialect.generateOrderByNulls("column1", true, true).toString());
+ }
+
+ @Test
+ void testGenerateOrderByNulls_AscNullsFirst() {
+ assertEquals("column1 ASC", dialect.generateOrderByNulls("column1", true, false).toString());
+ }
+
+ @Test
+ void testGenerateOrderByNulls_DescNullsLast() {
+ assertEquals("column1 DESC", dialect.generateOrderByNulls("column1", false, true).toString());
+ }
+
+ @Test
+ void testGenerateOrderByNulls_DescNullsFirst() {
+ assertEquals("ISNULL(column1) DESC, column1 DESC", dialect.generateOrderByNulls("column1", false, false).toString());
+ }
+
+ @Test
+ void testGenerateInline() {
+ String sql = dialect
+ .generateInline(java.util.List.of("c1"), java.util.List.of("String"),
+ java.util.List.of(new String[] { "a" }))
+ .toString();
+ assertTrue(sql.startsWith("select * from ("));
+ assertTrue(sql.endsWith(") x limit 1"));
+ assertFalse(sql.contains("dual")); // no built-in dual table in Hive — verified against Hive 4
+ }
+}
diff --git a/dialect/db/hive/src/test/java/org/eclipse/daanse/sql/dialect/db/hive/integration/ServiceTest.java b/dialect/db/hive/src/test/java/org/eclipse/daanse/sql/dialect/db/hive/integration/ServiceTest.java
new file mode 100644
index 0000000..608933f
--- /dev/null
+++ b/dialect/db/hive/src/test/java/org/eclipse/daanse/sql/dialect/db/hive/integration/ServiceTest.java
@@ -0,0 +1,30 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * SmartCity Jena - initial
+ * Stefan Bischof (bipolis.org) - initial
+ */
+package org.eclipse.daanse.sql.dialect.db.hive.integration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+
+import org.eclipse.daanse.sql.dialect.api.DialectFactory;
+import org.eclipse.daanse.sql.dialect.db.hive.HiveDialectFactory;
+import org.junit.jupiter.api.Test;
+import org.osgi.test.common.annotation.InjectService;
+
+class ServiceTest {
+ @Test
+ void serviceExists(@InjectService List dialects) throws Exception {
+ assertThat(dialects).isNotNull().isNotEmpty().anyMatch(HiveDialectFactory.class::isInstance);
+ }
+}
diff --git a/dialect/db/hive/src/test/java/org/eclipse/daanse/sql/dialect/db/hive/sqlgen/HiveDdlRoundTripTest.java b/dialect/db/hive/src/test/java/org/eclipse/daanse/sql/dialect/db/hive/sqlgen/HiveDdlRoundTripTest.java
new file mode 100644
index 0000000..68836d8
--- /dev/null
+++ b/dialect/db/hive/src/test/java/org/eclipse/daanse/sql/dialect/db/hive/sqlgen/HiveDdlRoundTripTest.java
@@ -0,0 +1,188 @@
+/*
+ * 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.hive.sqlgen;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.sql.Connection;
+import java.sql.JDBCType;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Timestamp;
+import java.time.Duration;
+import java.util.List;
+import java.util.Optional;
+import java.util.OptionalInt;
+import java.util.Properties;
+
+import org.apache.hive.jdbc.HiveDriver;
+import org.eclipse.daanse.sql.dialect.api.Dialect;
+import org.eclipse.daanse.sql.dialect.db.hive.HiveDialect;
+import org.eclipse.daanse.sql.model.schema.ColumnDefinition;
+import org.eclipse.daanse.sql.model.schema.ColumnMetaData;
+import org.eclipse.daanse.sql.model.schema.ColumnReference;
+import org.eclipse.daanse.sql.model.schema.SchemaReference;
+import org.eclipse.daanse.sql.model.schema.TableReference;
+import org.eclipse.daanse.sql.jdbc.record.schema.ColumnDefinitionRecord;
+import org.eclipse.daanse.sql.jdbc.record.schema.ColumnMetaDataRecord;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestInstance.Lifecycle;
+import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+/**
+ * Round trip against a real HiveServer2 (apache/hive quickstart image,
+ * standalone local execution). Hive has no enforced unique/foreign keys and no
+ * CREATE INDEX (removed in Hive 3), so the trip covers what the dialect
+ * actually emits for Hive: schema + table DDL, backtick quoting, the
+ * ISNULL-based ORDER BY NULLS emulation, the {@code cast(... as timestamp)}
+ * literal form, a view, and the drops.
+ */
+@Testcontainers
+@EnabledIfSystemProperty(named = "integration.docker", matches = "true")
+@TestInstance(Lifecycle.PER_CLASS)
+class HiveDdlRoundTripTest {
+
+ private static final int HS2_PORT = 10000;
+
+ @Container
+ @SuppressWarnings("resource")
+ static final GenericContainer> CONTAINER = new GenericContainer<>("apache/hive:4.2.0")
+ .withEnv("SERVICE_NAME", "hiveserver2").withExposedPorts(HS2_PORT)
+ .waitingFor(Wait.forListeningPort()).withStartupTimeout(Duration.ofMinutes(5));
+
+ private static final SchemaReference SCHEMA = new SchemaReference(Optional.empty(), "RT_TEST");
+ private static final TableReference CUSTOMERS = new TableReference(Optional.of(SCHEMA), "CUSTOMERS",
+ TableReference.TYPE_TABLE);
+ private static final TableReference VIEW = new TableReference(Optional.of(SCHEMA), "CUSTOMER_NAMES",
+ TableReference.TYPE_VIEW);
+
+ private Dialect dialect;
+ private Connection connection;
+
+ @BeforeAll
+ void setUp() throws Exception {
+ this.dialect = new HiveDialect();
+ String url = "jdbc:hive2://" + CONTAINER.getHost() + ":" + CONTAINER.getMappedPort(HS2_PORT) + "/default";
+ // HS2 accepts TCP before sessions work — retry until a statement runs.
+ HiveDriver driver = new HiveDriver();
+ SQLException last = null;
+ for (int i = 0; i < 48; i++) {
+ try {
+ Connection c = driver.connect(url, new Properties());
+ try (Statement s = c.createStatement()) {
+ s.execute("SELECT 1");
+ }
+ this.connection = c;
+ return;
+ } catch (SQLException e) {
+ last = e;
+ Thread.sleep(5000);
+ }
+ }
+ throw new IllegalStateException("HiveServer2 did not become ready", last);
+ }
+
+ @AfterAll
+ void tearDown() throws Exception {
+ if (connection != null && !connection.isClosed())
+ connection.close();
+ }
+
+ private static ColumnDefinition col(TableReference table, String name, JDBCType jdbc,
+ ColumnMetaData.Nullability nullability, OptionalInt size, OptionalInt scale) {
+ ColumnReference ref = new ColumnReference(Optional.of(table), name);
+ ColumnMetaData meta = new ColumnMetaDataRecord(jdbc, jdbc.getName(), size, scale, OptionalInt.empty(),
+ nullability, OptionalInt.empty(), Optional.empty(), Optional.empty(),
+ ColumnMetaData.AutoIncrement.UNKNOWN, ColumnMetaData.GeneratedColumn.UNKNOWN);
+ return new ColumnDefinitionRecord(ref, meta);
+ }
+
+ private void execute(String sql) throws SQLException {
+ try (Statement s = connection.createStatement()) {
+ s.execute(sql);
+ }
+ }
+
+ @Test
+ void full_round_trip() throws Exception {
+ List custCols = List.of(
+ col(CUSTOMERS, "ID", JDBCType.INTEGER, ColumnMetaData.Nullability.NO_NULLS, OptionalInt.empty(),
+ OptionalInt.empty()),
+ col(CUSTOMERS, "EMAIL", JDBCType.VARCHAR, ColumnMetaData.Nullability.NO_NULLS, OptionalInt.of(100),
+ OptionalInt.empty()),
+ col(CUSTOMERS, "NAME", JDBCType.VARCHAR, ColumnMetaData.Nullability.NULLABLE, OptionalInt.of(50),
+ OptionalInt.empty()));
+
+ // CREATE — no PK: Hive constraints are informational only.
+ execute(dialect.ddlGenerator().createSchema(SCHEMA.name(), true));
+ execute(dialect.ddlGenerator().createTable(CUSTOMERS, custCols, null, true));
+
+ String qC = dialect.quoteIdentifier(SCHEMA.name(), CUSTOMERS.name());
+
+ // INSERT — multi-row VALUES; runs through Hive's local execution.
+ execute("INSERT INTO " + qC + " VALUES (1, 'alice@example.com', 'Alice'), (2, 'bob@example.com', NULL)");
+
+ // ORDER BY through the dialect's ISNULL-based NULLS LAST emulation.
+ String orderItem = dialect.orderByGenerator()
+ .generateOrderItem(dialect.quoteIdentifier("NAME"), true, true, true).toString();
+ assertThat(orderItem).contains("ISNULL");
+ try (Statement s = connection.createStatement();
+ ResultSet rs = s.executeQuery(
+ "SELECT " + dialect.quoteIdentifier("NAME") + " FROM " + qC + " ORDER BY " + orderItem)) {
+ assertThat(rs.next()).isTrue();
+ assertThat(rs.getString(1)).isEqualTo("Alice");
+ assertThat(rs.next()).isTrue();
+ assertThat(rs.getString(1)).isNull();
+ assertThat(rs.next()).isFalse();
+ }
+
+ // Timestamp literal — Hive form cast( '...' as timestamp ).
+ StringBuilder ts = new StringBuilder();
+ dialect.quoteTimestampLiteral(ts, "2024-01-15 10:30:00");
+ try (Statement s = connection.createStatement(); ResultSet rs = s.executeQuery("SELECT " + ts)) {
+ assertThat(rs.next()).isTrue();
+ assertThat(rs.getTimestamp(1)).isEqualTo(Timestamp.valueOf("2024-01-15 10:30:00"));
+ }
+
+ // VIEW.
+ execute(dialect.ddlGenerator().createView(VIEW,
+ "SELECT " + dialect.quoteIdentifier("NAME") + " FROM " + qC, false));
+ try (Statement s = connection.createStatement();
+ ResultSet rs = s.executeQuery(
+ "SELECT COUNT(*) FROM " + dialect.quoteIdentifier(SCHEMA.name(), VIEW.name()))) {
+ assertThat(rs.next()).isTrue();
+ assertThat(rs.getInt(1)).isEqualTo(2);
+ }
+
+ // Inline VALUES through the dialect's generateInline form.
+ String inlineSql = dialect.sqlGenerator()
+ .generateInline(List.of("C1", "C2"), List.of("Varchar", "Numeric"),
+ List.of(new String[] { "x", "1" }, new String[] { "y", "2" }))
+ .toString();
+ try (Statement s = connection.createStatement(); ResultSet rs = s.executeQuery(inlineSql)) {
+ assertThat(rs.next()).isTrue();
+ assertThat(rs.next()).isTrue();
+ assertThat(rs.next()).isFalse();
+ }
+
+ // DROP — reverse order; DROP SCHEMA ... CASCADE cleans up whatever remains.
+ execute(dialect.ddlGenerator().dropView(VIEW, true));
+ execute(dialect.ddlGenerator().dropTable(CUSTOMERS, true));
+ execute(dialect.ddlGenerator().dropSchema(SCHEMA.name(), true, true));
+ }
+}
diff --git a/dialect/db/impala/pom.xml b/dialect/db/impala/pom.xml
new file mode 100644
index 0000000..60de3ea
--- /dev/null
+++ b/dialect/db/impala/pom.xml
@@ -0,0 +1,51 @@
+
+
+
+ 4.0.0
+
+ org.eclipse.daanse
+ org.eclipse.daanse.sql.dialect.db
+ ${revision}
+ ../pom.xml
+
+ org.eclipse.daanse.sql.dialect.db.impala
+ Eclipse Daanse JDBC DB Dialect Impala
+
+
+
+ org.slf4j
+ slf4j-api
+
+
+ org.eclipse.daanse
+ org.eclipse.daanse.sql.dialect.api
+ ${revision}
+
+
+ org.eclipse.daanse
+ org.eclipse.daanse.sql.dialect.db.common
+ ${revision}
+
+
+ org.eclipse.daanse
+ org.eclipse.daanse.sql.dialect.db.hive
+ ${revision}
+
+
+ biz.aQute.bnd
+ biz.aQute.bndlib
+
+
+
diff --git a/dialect/db/impala/src/main/java/org/eclipse/daanse/sql/dialect/db/impala/ImpalaDialect.java b/dialect/db/impala/src/main/java/org/eclipse/daanse/sql/dialect/db/impala/ImpalaDialect.java
new file mode 100644
index 0000000..445caf2
--- /dev/null
+++ b/dialect/db/impala/src/main/java/org/eclipse/daanse/sql/dialect/db/impala/ImpalaDialect.java
@@ -0,0 +1,183 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * SmartCity Jena - initial
+ * Stefan Bischof (bipolis.org) - initial
+ */
+package org.eclipse.daanse.sql.dialect.db.impala;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.eclipse.daanse.sql.dialect.api.DialectInitData;
+import org.eclipse.daanse.sql.dialect.db.common.DialectUtil;
+import org.eclipse.daanse.sql.dialect.db.hive.HiveDialect;
+
+/**
+ * Dialect for Apache Impala. Connections are expected through the Apache
+ * Hive JDBC driver (HiveServer2 protocol, port 21050, {@code auth=noSasl});
+ * Impala has no single-argument {@code ISNULL}, so NULL ordering uses the
+ * CASE WHEN sentinels of {@link #generateOrderItem} instead of Hive's form.
+ */
+public class ImpalaDialect extends HiveDialect {
+
+ private static final String SUPPORTED_PRODUCT_NAME = "IMPALA";
+ public static final String CAST = "cast(";
+ public static final String AS_STRING = " as string)";
+
+ /** JDBC-free constructor for SQL generation. Uses Impala backtick quoting. */
+ public ImpalaDialect() {
+ super(DialectInitData.ansiDefaults().withQuoteIdentifierString("`"));
+ }
+
+ /** Construct from a captured snapshot — the canonical entry point. */
+ public ImpalaDialect(DialectInitData init) {
+ super(init);
+ }
+
+ @Override
+ public StringBuilder generateOrderByNulls(CharSequence expr, boolean ascending, boolean collateNullsLast) {
+ StringBuilder sb = new StringBuilder(expr);
+ if (ascending) {
+ return sb.append(" ASC");
+ } else {
+ return sb.append(" DESC");
+ }
+ }
+
+ @Override
+ public StringBuilder generateOrderItem(CharSequence expr, boolean nullable, boolean ascending,
+ boolean collateNullsLast) {
+ StringBuilder ret = new StringBuilder();
+
+ if (nullable && collateNullsLast) {
+ ret.append("CASE WHEN ").append(expr).append(" IS NULL THEN 1 ELSE 0 END, ");
+ } else {
+ ret.append("CASE WHEN ").append(expr).append(" IS NULL THEN 0 ELSE 1 END, ");
+ }
+
+ if (ascending) {
+ ret.append(expr).append(" ASC");
+ } else {
+ ret.append(expr).append(" DESC");
+ }
+
+ return ret;
+ }
+
+ @Override
+ public boolean allowsMultipleCountDistinct() {
+ return false;
+ }
+
+ @Override
+ public boolean requiresOrderByAlias() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsGroupByExpressions() {
+ return false;
+ }
+
+ @Override
+ public boolean allowsSelectNotInGroupBy() {
+ return false;
+ }
+
+ @Override
+ public StringBuilder generateInline(List columnNames, List columnTypes, List valueList) {
+ return generateInlineGeneric(columnNames, columnTypes, valueList, null, false);
+ }
+
+ @Override
+ public void quoteStringLiteral(StringBuilder buf, String value) {
+ String quote = "\'";
+ String s0 = value;
+
+ if (s0.contains("\\")) {
+ // NOTE: no-op replacement, kept for behavioral fidelity with the
+ // legacy (Mondrian-era) dialect — backslashes are never doubled.
+ s0 = s0.replace("\\\\", "\\\\");
+ }
+ if (s0.contains(quote)) {
+ s0 = s0.replace(quote, "\\\\" + quote);
+ }
+
+ buf.append(quote);
+
+ buf.append(s0);
+
+ buf.append(quote);
+ }
+
+ @Override
+ public boolean allowsRegularExpressionInWhereClause() {
+ return true;
+ }
+
+ @Override
+ public Optional generateRegularExpression(String source, String javaRegex) {
+ try {
+ Pattern.compile(javaRegex);
+ } catch (PatternSyntaxException e) {
+ // Not a valid Java regex. Too risky to continue.
+ return Optional.empty();
+ }
+ javaRegex = DialectUtil.cleanUnicodeAwareCaseFlag(javaRegex);
+ // We might have to use case-insensitive matching
+ StringBuilder mappedFlags = new StringBuilder();
+ String[][] mapping = new String[][] { { "i", "i" } };
+ javaRegex = extractEmbeddedFlags(javaRegex, mapping, mappedFlags);
+ boolean caseSensitive = true;
+ if (mappedFlags.toString().contains("i")) {
+ caseSensitive = false;
+ }
+ final Matcher escapeMatcher = DialectUtil.ESCAPE_PATTERN.matcher(javaRegex);
+ while (escapeMatcher.find()) {
+ javaRegex = javaRegex.replace(escapeMatcher.group(1), escapeMatcher.group(2));
+ }
+
+ final StringBuilder sb = new StringBuilder();
+ // Now build the string.
+ sb.append(CAST);
+ sb.append(source);
+ sb.append(AS_STRING);
+ sb.append(" IS NOT NULL AND ");
+ if (caseSensitive) {
+ sb.append(CAST).append(source).append(AS_STRING);
+ } else {
+ sb.append("UPPER(");
+ sb.append(CAST).append(source).append(AS_STRING);
+ sb.append(")");
+ }
+ sb.append(" REGEXP ");
+ if (caseSensitive) {
+ quoteStringLiteral(sb, javaRegex);
+ } else {
+ quoteStringLiteral(sb, javaRegex.toUpperCase());
+ }
+ return Optional.of(sb.toString());
+ }
+
+ @Override
+ public boolean supportsDdl() {
+ return true;
+ }
+
+ @Override
+ public String name() {
+ return SUPPORTED_PRODUCT_NAME.toLowerCase();
+ }
+
+}
diff --git a/dialect/db/impala/src/main/java/org/eclipse/daanse/sql/dialect/db/impala/ImpalaDialectFactory.java b/dialect/db/impala/src/main/java/org/eclipse/daanse/sql/dialect/db/impala/ImpalaDialectFactory.java
new file mode 100644
index 0000000..45b36fc
--- /dev/null
+++ b/dialect/db/impala/src/main/java/org/eclipse/daanse/sql/dialect/db/impala/ImpalaDialectFactory.java
@@ -0,0 +1,34 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * SmartCity Jena - initial
+ * Stefan Bischof (bipolis.org) - initial
+ */
+package org.eclipse.daanse.sql.dialect.db.impala;
+
+import java.util.function.Function;
+
+import org.eclipse.daanse.sql.dialect.api.DialectFactory;
+import org.eclipse.daanse.sql.dialect.api.DialectInitData;
+import org.eclipse.daanse.sql.dialect.api.DialectName;
+import org.eclipse.daanse.sql.dialect.db.common.AbstractDialectFactory;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ServiceScope;
+
+@Component(service = DialectFactory.class, scope = ServiceScope.SINGLETON)
+@DialectName("IMPALA")
+public class ImpalaDialectFactory extends AbstractDialectFactory {
+
+ @Override
+ public Function getConstructorFunction() {
+ return ImpalaDialect::new;
+ }
+
+}
diff --git a/dialect/db/impala/src/main/java/org/eclipse/daanse/sql/dialect/db/impala/package-info.java b/dialect/db/impala/src/main/java/org/eclipse/daanse/sql/dialect/db/impala/package-info.java
new file mode 100644
index 0000000..c52cf30
--- /dev/null
+++ b/dialect/db/impala/src/main/java/org/eclipse/daanse/sql/dialect/db/impala/package-info.java
@@ -0,0 +1,17 @@
+/*
+* 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
+*
+* Contributors:
+* SmartCity Jena - initial
+* Stefan Bischof (bipolis.org) - initial
+*/
+
+@org.osgi.annotation.bundle.Export
+@org.osgi.annotation.versioning.Version("0.0.1")
+package org.eclipse.daanse.sql.dialect.db.impala;
diff --git a/dialect/db/impala/src/test/java/org/eclipse/daanse/sql/dialect/db/impala/ImpalaDialectQuotingPolicyTest.java b/dialect/db/impala/src/test/java/org/eclipse/daanse/sql/dialect/db/impala/ImpalaDialectQuotingPolicyTest.java
new file mode 100644
index 0000000..cbf6574
--- /dev/null
+++ b/dialect/db/impala/src/test/java/org/eclipse/daanse/sql/dialect/db/impala/ImpalaDialectQuotingPolicyTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.impala;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.eclipse.daanse.sql.dialect.api.IdentifierQuotingPolicy;
+import org.eclipse.daanse.sql.model.schema.SchemaReference;
+import org.eclipse.daanse.sql.model.schema.TableReference;
+import org.junit.jupiter.api.Test;
+
+class ImpalaDialectQuotingPolicyTest {
+
+ private static final SchemaReference S = new SchemaReference(Optional.empty(), "TEST");
+ private static final TableReference EMP = new TableReference(Optional.of(S), "EMPLOYEES",
+ TableReference.TYPE_TABLE);
+ private static final TableReference DEPT = new TableReference(Optional.of(S), "DEPARTMENTS",
+ TableReference.TYPE_TABLE);
+
+ private ImpalaDialect dialectNever() {
+ ImpalaDialect d = new ImpalaDialect();
+ d.setQuotingPolicy(IdentifierQuotingPolicy.NEVER);
+ return d;
+ }
+
+ @Test
+ void primaryKey_unquoted() {
+ assertThat(dialectNever().ddlGenerator().addPrimaryKeyConstraint(EMP, "PK_EMP", List.of("ID")))
+ .doesNotContain("`").contains("EMPLOYEES").contains("PK_EMP").contains("ID");
+ }
+
+ @Test
+ void uniqueConstraint_unquoted() {
+ assertThat(dialectNever().ddlGenerator().addUniqueConstraint(EMP, "UQ_EMP", List.of("EMAIL")))
+ .doesNotContain("`").contains("EMPLOYEES").contains("UQ_EMP").contains("EMAIL");
+ }
+
+ @Test
+ void foreignKey_unquoted() {
+ assertThat(dialectNever().ddlGenerator().addForeignKeyConstraint(EMP, "FK_EMP_DEPT", List.of("DEPT_ID"), DEPT,
+ List.of("ID"), "NO ACTION", "NO ACTION")).doesNotContain("`").contains("EMPLOYEES")
+ .contains("FK_EMP_DEPT").contains("DEPARTMENTS");
+ }
+
+ @Test
+ void renameTable_unquoted() {
+ assertThat(dialectNever().ddlGenerator().renameTable(EMP, "PERSON")).doesNotContain("`").contains("EMPLOYEES")
+ .contains("PERSON");
+ }
+
+ @Test
+ void createIndex_unquoted() {
+ assertThat(dialectNever().ddlGenerator().createIndex("IDX_EMP", EMP, List.of("NAME"), false, false))
+ .doesNotContain("`").contains("EMPLOYEES").contains("IDX_EMP").contains("NAME");
+ }
+
+ @Test
+ void dropConstraint_unquoted() {
+ assertThat(dialectNever().ddlGenerator().dropConstraint(EMP, "PK_EMP", true)).doesNotContain("`")
+ .contains("EMPLOYEES").contains("PK_EMP");
+ }
+}
diff --git a/dialect/db/impala/src/test/java/org/eclipse/daanse/sql/dialect/db/impala/ImpalaDialectTest.java b/dialect/db/impala/src/test/java/org/eclipse/daanse/sql/dialect/db/impala/ImpalaDialectTest.java
new file mode 100644
index 0000000..854feb7
--- /dev/null
+++ b/dialect/db/impala/src/test/java/org/eclipse/daanse/sql/dialect/db/impala/ImpalaDialectTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * SmartCity Jena - initial
+ * Stefan Bischof (bipolis.org) - initial
+ */
+package org.eclipse.daanse.sql.dialect.db.impala;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Optional;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class ImpalaDialectTest {
+
+ private ImpalaDialect dialect;
+
+ @BeforeEach
+ void setUp() {
+ dialect = new ImpalaDialect();
+ }
+
+ @Test
+ void testName() {
+ assertEquals("impala", dialect.name());
+ }
+
+ @Test
+ void testQuoteIdentifierString() {
+ assertEquals("`", dialect.getQuoteIdentifierString());
+ }
+
+ @Test
+ void testAllowsRegularExpressionInWhereClause() {
+ assertTrue(dialect.allowsRegularExpressionInWhereClause());
+ }
+
+ @Test
+ void testGenerateRegularExpression_InvalidRegex() {
+ assertEquals(Optional.empty(), dialect.generateRegularExpression("table.column", "(a"));
+ }
+
+ @Test
+ void testGenerateRegularExpression_CaseInsensitive() {
+ String sql = dialect.generateRegularExpression("table.column", "(?i)|(?u).*a.*").orElseThrow();
+ assertTrue(sql.contains("UPPER"));
+ assertTrue(sql.contains("cast(table.column as string)"));
+ assertTrue(sql.contains("REGEXP"));
+ assertTrue(sql.contains("'.*A.*'"));
+ }
+
+ @Test
+ void testGenerateRegularExpression_CaseSensitive() {
+ String sql = dialect.generateRegularExpression("table.column", ".*1.*").orElseThrow();
+ assertFalse(sql.contains("UPPER"));
+ assertTrue(sql.contains("cast(table.column as string)"));
+ assertTrue(sql.contains("REGEXP"));
+ assertTrue(sql.contains("'.*1.*'"));
+ }
+
+ @Test
+ void testGenerateOrderByNulls() {
+ assertEquals("column1 ASC", dialect.generateOrderByNulls("column1", true, true).toString());
+ assertEquals("column1 DESC", dialect.generateOrderByNulls("column1", false, false).toString());
+ }
+
+ @Test
+ void testGenerateOrderByNulls_NeverEmitsIsnull() {
+ // Impala has no single-argument ISNULL(x) — Hive's emulation must not leak through.
+ for (boolean asc : new boolean[] { true, false }) {
+ for (boolean nullsLast : new boolean[] { true, false }) {
+ assertFalse(dialect.generateOrderByNulls("column1", asc, nullsLast).toString().contains("ISNULL"));
+ }
+ }
+ }
+
+ @Test
+ void testGenerateOrderItem_NullableNullsLast() {
+ assertEquals("CASE WHEN column1 IS NULL THEN 1 ELSE 0 END, column1 ASC",
+ dialect.generateOrderItem("column1", true, true, true).toString());
+ }
+
+ @Test
+ void testGenerateOrderItem_NullableNullsFirst() {
+ assertEquals("CASE WHEN column1 IS NULL THEN 0 ELSE 1 END, column1 DESC",
+ dialect.generateOrderItem("column1", true, false, false).toString());
+ }
+
+ @Test
+ void testQuoteStringLiteral() {
+ StringBuilder buf = new StringBuilder();
+ dialect.quoteStringLiteral(buf, "it's");
+ assertEquals("'it\\\\'s'", buf.toString());
+ }
+
+ @Test
+ void testAllowsMultipleCountDistinct() {
+ assertFalse(dialect.allowsMultipleCountDistinct());
+ }
+
+ @Test
+ void testAllowsCompoundCountDistinct() {
+ assertTrue(dialect.allowsCompoundCountDistinct());
+ }
+
+ @Test
+ void testRequiresOrderByAlias() {
+ assertFalse(dialect.requiresOrderByAlias());
+ }
+
+ @Test
+ void testAllowsOrderByAlias() {
+ // Inherited explicitly from HiveDialect — must not flip with requiresOrderByAlias().
+ assertTrue(dialect.allowsOrderByAlias());
+ }
+
+ @Test
+ void testRequiresAliasForFromQuery() {
+ assertTrue(dialect.requiresAliasForFromQuery());
+ }
+
+ @Test
+ void testSupportsGroupByExpressions() {
+ assertFalse(dialect.supportsGroupByExpressions());
+ }
+
+ @Test
+ void testAllowsSelectNotInGroupBy() {
+ assertFalse(dialect.allowsSelectNotInGroupBy());
+ }
+
+ @Test
+ void testAllowsJoinOn() {
+ assertFalse(dialect.allowsJoinOn());
+ }
+
+ @Test
+ void testSupportsDdl() {
+ assertTrue(dialect.supportsDdl());
+ }
+}
diff --git a/dialect/db/impala/src/test/java/org/eclipse/daanse/sql/dialect/db/impala/integration/ServiceTest.java b/dialect/db/impala/src/test/java/org/eclipse/daanse/sql/dialect/db/impala/integration/ServiceTest.java
new file mode 100644
index 0000000..75c0b88
--- /dev/null
+++ b/dialect/db/impala/src/test/java/org/eclipse/daanse/sql/dialect/db/impala/integration/ServiceTest.java
@@ -0,0 +1,30 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * SmartCity Jena - initial
+ * Stefan Bischof (bipolis.org) - initial
+ */
+package org.eclipse.daanse.sql.dialect.db.impala.integration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+
+import org.eclipse.daanse.sql.dialect.api.DialectFactory;
+import org.eclipse.daanse.sql.dialect.db.impala.ImpalaDialectFactory;
+import org.junit.jupiter.api.Test;
+import org.osgi.test.common.annotation.InjectService;
+
+class ServiceTest {
+ @Test
+ void serviceExists(@InjectService List dialects) throws Exception {
+ assertThat(dialects).isNotNull().isNotEmpty().anyMatch(ImpalaDialectFactory.class::isInstance);
+ }
+}
diff --git a/dialect/db/pom.xml b/dialect/db/pom.xml
index 35a7ea1..f9d3e46 100644
--- a/dialect/db/pom.xml
+++ b/dialect/db/pom.xml
@@ -31,6 +31,8 @@
derby
duckdb
h2
+ hive
+ impala
mariadb
mssqlserver
mysql