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
92 changes: 92 additions & 0 deletions dialect/db/hive/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?xml version="1.0"?>
<!--
/*********************************************************************
* 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
**********************************************************************/
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.daanse</groupId>
<artifactId>org.eclipse.daanse.sql.dialect.db</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>org.eclipse.daanse.sql.dialect.db.hive</artifactId>
<name>Eclipse Daanse JDBC DB Dialect Hive</name>

<properties>
<hive-jdbc.version>4.2.0</hive-jdbc.version>
</properties>

<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.daanse</groupId>
<artifactId>org.eclipse.daanse.sql.dialect.api</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.eclipse.daanse</groupId>
<artifactId>org.eclipse.daanse.sql.dialect.db.common</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>biz.aQute.bnd</groupId>
<artifactId>biz.aQute.bndlib</artifactId>
</dependency>
<!-- Round-trip test (Testcontainer-backed, gated by -Dintegration.docker=true).
JUnit + assertj come from parent. The standalone classifier is the shaded
driver jar; the wildcard exclusion keeps the Hadoop tree out. -->
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-jdbc</artifactId>
<version>${hive-jdbc.version}</version>
<classifier>standalone</classifier>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.19.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.daanse</groupId>
<artifactId>org.eclipse.daanse.sql.jdbc.record</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<environmentVariables>
<!-- Passed through so Testcontainers reaches a non-default engine
socket, e.g. rootless Podman (DOCKER_HOST=unix:///run/user/<uid>/podman/podman.sock). -->
<DOCKER_HOST>${env.DOCKER_HOST}</DOCKER_HOST>
</environmentVariables>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -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<String> columnNames, List<String> columnTypes, List<String[]> 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();
}

}
Original file line number Diff line number Diff line change
@@ -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<HiveDialect> {

@Override
public Function<DialectInitData, HiveDialect> getConstructorFunction() {
return HiveDialect::new;
}

}
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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");
}
}
Loading
Loading