HHH-11692 Introduce DISTINCT predicate in HQL and implement emulations

This commit is contained in:
Christian Beikov 2021-03-15 10:26:28 +01:00
parent e67d10ee6c
commit 06b5eb43c6
50 changed files with 2081 additions and 241 deletions

View File

@ -415,6 +415,8 @@ comparisonOperator
| GREATER_EQUAL
| LESS
| LESS_EQUAL
| IS DISTINCT FROM
| IS NOT DISTINCT FROM
;
inList

View File

@ -6,10 +6,18 @@
*/
package org.hibernate.dialect;
import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -38,4 +46,60 @@ protected void renderSearchClause(CteStatement cte) {
protected void renderCycleClause(CteStatement cte) {
// CUBRID does not support this, but it can be emulated
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonEmulateIntersect( lhs, operator, rhs );
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "'0' || '0'" );
}
else if ( expression instanceof Summarization ) {
// This could theoretically be emulated by rendering all grouping variations of the query and
// connect them via union all but that's probably pretty inefficient and would have to happen
// on the query spec level
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
@Override
protected String getFromDual() {
//TODO: is this really needed?
//TODO: would "from table({0})" be better?
return " from db_root";
}
@Override
protected String getFromDualForSelectOnly() {
return getFromDual();
}
}

View File

@ -6,11 +6,18 @@
*/
package org.hibernate.dialect;
import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SelectClause;
@ -69,4 +76,48 @@ protected void renderSearchClause(CteStatement cte) {
protected void renderCycleClause(CteStatement cte) {
// Cache does not support this, but it can be emulated
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonEmulateIntersect( lhs, operator, rhs );
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "'0' || '0'" );
}
else if ( expression instanceof Summarization ) {
// This could theoretically be emulated by rendering all grouping variations of the query and
// connect them via union all but that's probably pretty inefficient and would have to happen
// on the query spec level
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
}

View File

@ -10,6 +10,9 @@
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
@ -68,4 +71,25 @@ protected void renderSearchClause(CteStatement cte) {
protected void renderCycleClause(CteStatement cte) {
// Cockroach does not support this, but it can be emulated
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "'0' || '0'" );
}
else if ( expression instanceof Summarization ) {
// This could theoretically be emulated by rendering all grouping variations of the query and
// connect them via union all but that's probably pretty inefficient and would have to happen
// on the query spec level
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
}

View File

@ -10,12 +10,20 @@
import org.hibernate.query.FetchClauseType;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.MutationStatement;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.delete.DeleteStatement;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.NullnessLiteral;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.insert.InsertStatement;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
@ -134,6 +142,86 @@ protected boolean renderReturningClause(MutationStatement statement) {
return true;
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
if ( getDialect().getVersion() >= 1110 ) {
renderComparisonStandard( lhs, operator, rhs );
}
else {
renderComparisonEmulateDecode( lhs, operator, rhs );
}
}
@Override
protected void renderSelectExpression(Expression expression) {
// Null literals have to be casted in the select clause
if ( expression instanceof Literal ) {
final Literal literal = (Literal) expression;
if ( literal.getLiteralValue() == null ) {
renderCasted( literal );
}
else {
renderLiteral( literal, true );
}
}
else if ( expression instanceof NullnessLiteral || expression instanceof JdbcParameter || expression instanceof SqmParameterInterpretation ) {
renderCasted( expression );
}
else {
expression.accept( this );
}
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "()" );
}
else if ( expression instanceof Summarization ) {
Summarization summarization = (Summarization) expression;
appendSql( summarization.getKind().name().toLowerCase() );
appendSql( OPEN_PARENTHESIS );
renderCommaSeparated( summarization.getGroupings() );
appendSql( CLOSE_PARENTHESIS );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
@Override
protected String getFromDual() {
return " from sysibm.dual";
}
@Override
protected String getFromDualForSelectOnly() {
return getFromDual();
}
@Override
protected void visitReturningColumns(MutationStatement mutationStatement) {
// For DB2 we use #renderReturningClause to render a wrapper around the DML statement

View File

@ -7,7 +7,9 @@
package org.hibernate.dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -41,5 +43,9 @@ protected boolean supportsOffsetClause() {
return version >= 710;
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonStandard( lhs, operator, rhs );
}
}

View File

@ -7,7 +7,9 @@
package org.hibernate.dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -42,4 +44,10 @@ protected boolean supportsOffsetClause() {
return version >= 1200;
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
// Supported at least since DB2 z/OS 9.0
renderComparisonStandard( lhs, operator, rhs );
}
}

View File

@ -6,12 +6,22 @@
*/
package org.hibernate.dialect;
import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteContainer;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.NullnessLiteral;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -76,6 +86,81 @@ protected void renderOffsetExpression(Expression offsetExpression) {
}
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonEmulateIntersect( lhs, operator, rhs );
}
@Override
protected void renderSelectExpression(Expression expression) {
// Null literals have to be casted in the select clause
if ( expression instanceof Literal ) {
final Literal literal = (Literal) expression;
if ( literal.getLiteralValue() == null ) {
renderCasted( literal );
}
else {
renderLiteral( literal, true );
}
}
else if ( expression instanceof NullnessLiteral || expression instanceof JdbcParameter || expression instanceof SqmParameterInterpretation ) {
renderCasted( expression );
}
else {
expression.accept( this );
}
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "'0'" );
}
else if ( expression instanceof Summarization ) {
Summarization summarization = (Summarization) expression;
appendSql( summarization.getKind().name().toLowerCase() );
appendSql( OPEN_PARENTHESIS );
renderCommaSeparated( summarization.getGroupings() );
appendSql( CLOSE_PARENTHESIS );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
@Override
protected String getFromDual() {
return " from (values 0) as dual";
}
@Override
protected String getFromDualForSelectOnly() {
return getFromDual();
}
@Override
protected boolean needsRowsToSkip() {
return !supportsOffsetFetchClause();

View File

@ -73,6 +73,7 @@
import org.hibernate.sql.*;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.ANSICaseExpressionWalker;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.CaseExpressionWalker;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl;
@ -1517,12 +1518,18 @@ public String getSelectGUIDString() {
* there are no tables in the from clause.
*
* @return the SQL equivalent to Oracle's {@code from dual}.
* @deprecated Moved to {@link AbstractSqlAstTranslator}
*/
@Deprecated
public String getFromDual() {
// The standard SQL solution to get a dual table is to use the VALUES clause
return "from (values (0)) as dual";
}
/**
* @deprecated Moved to {@link AbstractSqlAstTranslator}
*/
@Deprecated
public boolean supportsSelectQueryWithoutFromClause() {
return true;
}
@ -1895,12 +1902,6 @@ public String getCreateMultisetTableString() {
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
EntityMappingType entityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
if ( entityDescriptor.getIdentifierMapping() instanceof CompositeIdentifierMapping) {
if ( !supportsTuplesInSubqueries() ) {
return new InlineStrategy( this );
}
}
return new PersistentTableStrategy(
new IdTable( entityDescriptor, name -> name, this ),
AfterUseAction.CLEAN,
@ -2836,7 +2837,9 @@ public boolean areStringComparisonsCaseInsensitive() {
* @return True if this SQL dialect is known to support "row value
* constructor" syntax; false otherwise.
* @since 3.2
* @deprecated Moved to {@link AbstractSqlAstTranslator}
*/
@Deprecated
public boolean supportsRowValueConstructorSyntax() {
// return false here, as most databases do not properly support this construct...
return false;
@ -2850,7 +2853,9 @@ public boolean supportsRowValueConstructorSyntax() {
* "... SET (FIRST_NAME, LAST_NAME) = ('Steve', 'Ebersole') ...".
*
* @return True if this SQL dialect is known to support "row value constructor" syntax in the SET clause; false otherwise.
* @deprecated Moved to {@link AbstractSqlAstTranslator}
*/
@Deprecated
public boolean supportsRowValueConstructorSyntaxInSet() {
return supportsRowValueConstructorSyntax();
}
@ -2865,7 +2870,9 @@ public boolean supportsRowValueConstructorSyntaxInSet() {
* @return True if this SQL dialect is known to support "row value
* constructor" syntax with quantified predicates; false otherwise.
* @since 6.0
* @deprecated Moved to {@link AbstractSqlAstTranslator}
*/
@Deprecated
public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
// return false here, as most databases do not properly support this construct...
return false;
@ -2880,11 +2887,17 @@ public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
* @return True if this SQL dialect is known to support "row value
* constructor" syntax in the IN list; false otherwise.
* @since 3.2
* @deprecated Moved to {@link AbstractSqlAstTranslator}
*/
@Deprecated
public boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
/**
* @deprecated Moved to {@link AbstractSqlAstTranslator}
*/
@Deprecated
public boolean supportsRowValueConstructorSyntaxInInSubquery() {
return supportsRowValueConstructorSyntaxInInList();
}
@ -2893,7 +2906,9 @@ public boolean supportsRowValueConstructorSyntaxInInSubquery() {
* The strategy to use for rendering summarizations in the GROUP BY clause.
*
* @since 6.0
* @deprecated Moved to {@link AbstractSqlAstTranslator}
*/
@Deprecated
public GroupBySummarizationRenderingStrategy getGroupBySummarizationRenderingStrategy() {
return GroupBySummarizationRenderingStrategy.NONE;
}
@ -2902,7 +2917,9 @@ public GroupBySummarizationRenderingStrategy getGroupBySummarizationRenderingStr
* The strategy to use for rendering constants in the GROUP BY clause.
*
* @since 6.0
* @deprecated Moved to {@link AbstractSqlAstTranslator}
*/
@Deprecated
public GroupByConstantRenderingStrategy getGroupByConstantRenderingStrategy() {
return GroupByConstantRenderingStrategy.CONSTANT_EXPRESSION;
}
@ -3006,7 +3023,9 @@ public String renderOrderByElement(String expression, String collation, String o
*
* @return True if select clause parameter must be cast()ed
* @since 3.2
* @deprecated Moved to {@link AbstractSqlAstTranslator}
*/
@Deprecated
public boolean requiresCastingOfParametersInSelectClause() {
return false;
}
@ -3364,7 +3383,9 @@ public ScrollMode defaultScrollMode() {
* delete from Table1 where (col1, col2) in (select col1, col2 from Table2)
*
* @return boolean
* @deprecated See {@link #supportsRowValueConstructorSyntaxInInSubquery()}
*/
@Deprecated
public boolean supportsTuplesInSubqueries() {
return true;
}

View File

@ -614,7 +614,7 @@ public LimitHandler getLimitHandler() {
public String getSelectGUIDString() {
return getVersion() < 210
? super.getSelectGUIDString()
: "select uuid_to_char(gen_uuid()) " + getFromDual();
: "select uuid_to_char(gen_uuid()) from rdb$database";
}
@Override
@ -637,7 +637,7 @@ public boolean supportsCurrentTimestampSelection() {
@Override
public String getCurrentTimestampSelectString() {
return "select current_timestamp " + getFromDual();
return "select current_timestamp from rdb$database";
}
@Override

View File

@ -13,10 +13,13 @@
import org.hibernate.internal.util.collections.Stack;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.CastTarget;
@ -27,6 +30,12 @@
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
import org.hibernate.sql.ast.tree.expression.SelfRenderingExpression;
import org.hibernate.sql.ast.tree.predicate.SelfRenderingPredicate;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.NullnessLiteral;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
@ -126,6 +135,75 @@ protected boolean supportsSimpleQueryGrouping() {
return false;
}
@Override
protected void renderSelectExpression(Expression expression) {
// Null literals have to be casted in the select clause
if ( expression instanceof Literal ) {
final Literal literal = (Literal) expression;
if ( literal.getLiteralValue() == null ) {
renderCasted( literal );
}
else {
renderLiteral( literal, true );
}
}
else if ( expression instanceof NullnessLiteral || expression instanceof JdbcParameter || expression instanceof SqmParameterInterpretation ) {
renderCasted( expression );
}
else {
expression.accept( this );
}
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "'0' || '0'" );
}
else if ( expression instanceof Summarization ) {
// This could theoretically be emulated by rendering all grouping variations of the query and
// connect them via union all but that's probably pretty inefficient and would have to happen
// on the query spec level
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
@Override
protected String getFromDual() {
return " from rdb$database";
}
@Override
protected String getFromDualForSelectOnly() {
return getFromDual();
}
private boolean supportsOffsetFetchClause() {
return getDialect().getVersion() >= 300;
}

View File

@ -6,10 +6,18 @@
*/
package org.hibernate.dialect;
import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -55,6 +63,50 @@ protected void renderCycleClause(CteStatement cte) {
// H2 does not support this, but it can be emulated
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "'0' || '0'" );
}
else if ( expression instanceof Summarization ) {
// This could theoretically be emulated by rendering all grouping variations of the query and
// connect them via union all but that's probably pretty inefficient and would have to happen
// on the query spec level
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
@Override
protected String getFromDual() {
return " from dual";
}
private boolean supportsOffsetFetchClause() {
return getDialect().getVersion() >= 104195;
}

View File

@ -7,9 +7,13 @@
package org.hibernate.dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
@ -69,4 +73,37 @@ protected void renderSearchClause(CteStatement cte) {
protected void renderCycleClause(CteStatement cte) {
// HANA does not support this, but it can be emulated
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonEmulateIntersect( lhs, operator, rhs );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "()" );
}
else if ( expression instanceof Summarization ) {
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
@Override
protected String getFromDual() {
return " from sys.dummy";
}
@Override
protected String getFromDualForSelectOnly() {
return getFromDual();
}
}

View File

@ -6,10 +6,21 @@
*/
package org.hibernate.dialect;
import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.NullnessLiteral;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -45,6 +56,75 @@ protected void renderCycleClause(CteStatement cte) {
// HSQL does not support this, but it can be emulated
}
@Override
protected void renderSelectExpression(Expression expression) {
// Null literals have to be casted in the select clause
if ( expression instanceof Literal ) {
final Literal literal = (Literal) expression;
if ( literal.getLiteralValue() == null ) {
renderCasted( literal );
}
else {
renderLiteral( literal, true );
}
}
else if ( expression instanceof NullnessLiteral || expression instanceof JdbcParameter || expression instanceof SqmParameterInterpretation ) {
renderCasted( expression );
}
else {
expression.accept( this );
}
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "'0' || '0'" );
}
else if ( expression instanceof Summarization ) {
// This could theoretically be emulated by rendering all grouping variations of the query and
// connect them via union all but that's probably pretty inefficient and would have to happen
// on the query spec level
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
@Override
protected String getFromDual() {
return " from (values(0))";
}
@Override
protected String getFromDualForSelectOnly() {
return getFromDual();
}
private boolean supportsOffsetFetchClause() {
return getDialect().getVersion() >= 250;
}

View File

@ -6,11 +6,18 @@
*/
package org.hibernate.dialect;
import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SelectClause;
@ -89,6 +96,66 @@ protected void renderCycleClause(CteStatement cte) {
// Informix does not support this, but it can be emulated
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonEmulateIntersect( lhs, operator, rhs );
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
// We render an empty group instead of literals as some DBs don't support grouping by literals
// Note that integer literals, which refer to select item positions, are handled in #visitGroupByClause
if ( expression instanceof Literal ) {
// todo (6.0): We need to introduce a dummy from clause item
// String fromItem = ", (select 1 x " + dialect.getFromDual() + ") dummy";
// sqlBuffer.insert( fromEndIndex, fromItem );
// appendSql( "dummy.x" );
throw new UnsupportedOperationException( "Column reference strategy is not yet implemented!" );
}
else if ( expression instanceof Summarization ) {
// This could theoretically be emulated by rendering all grouping variations of the query and
// connect them via union all but that's probably pretty inefficient and would have to happen
// on the query spec level
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
@Override
protected String getFromDual() {
return " from (select 0 from systables where tabid = 1) as dual";
}
@Override
protected String getFromDualForSelectOnly() {
return getFromDual();
}
private boolean supportsParameterOffsetFetchExpression() {
return getDialect().getVersion() >= 11;
}

View File

@ -6,11 +6,18 @@
*/
package org.hibernate.dialect;
import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SelectClause;
@ -83,6 +90,65 @@ protected void renderCycleClause(CteStatement cte) {
// Ingres does not support this, but it can be emulated
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonEmulateIntersect( lhs, operator, rhs );
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
// todo (6.0): We need to introduce a dummy from clause item
// String fromItem = ", (select 1 x " + dialect.getFromDual() + ") dummy";
// sqlBuffer.insert( fromEndIndex, fromItem );
// appendSql( "dummy.x" );
throw new UnsupportedOperationException( "Column reference strategy is not yet implemented!" );
}
else if ( expression instanceof Summarization ) {
// This could theoretically be emulated by rendering all grouping variations of the query and
// connect them via union all but that's probably pretty inefficient and would have to happen
// on the query spec level
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
@Override
protected String getFromDual() {
//this is only necessary if the query has a where clause
return " from (select 0) as dual";
}
@Override
protected String getFromDualForSelectOnly() {
return getFromDual();
}
@Override
protected boolean needsRowsToSkip() {
return !supportsOffsetFetchClause();

View File

@ -7,9 +7,13 @@
package org.hibernate.dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
@ -68,6 +72,37 @@ protected void renderCycleClause(CteStatement cte) {
// MariaDB does not support this, but it can be emulated
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonDistinctOperator( lhs, operator, rhs );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "'0'" );
}
else if ( expression instanceof Summarization ) {
Summarization summarization = (Summarization) expression;
renderCommaSeparated( summarization.getGroupings() );
appendSql( " with " );
appendSql( summarization.getKind().name().toLowerCase() );
}
else {
expression.accept( this );
}
}
@Override
public boolean supportsRowValueConstructorSyntaxInSet() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
private boolean supportsWindowFunctions() {
return getDialect().getVersion() >= 1020;
}

View File

@ -6,10 +6,18 @@
*/
package org.hibernate.dialect;
import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -38,4 +46,58 @@ protected void renderSearchClause(CteStatement cte) {
protected void renderCycleClause(CteStatement cte) {
// MaxDB does not support this, but it can be emulated
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonEmulateIntersect( lhs, operator, rhs );
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "'0' || '0'" );
}
else if ( expression instanceof Summarization ) {
// This could theoretically be emulated by rendering all grouping variations of the query and
// connect them via union all but that's probably pretty inefficient and would have to happen
// on the query spec level
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
@Override
public String getFromDual() {
return " from dual";
}
@Override
protected String getFromDualForSelectOnly() {
return getFromDual();
}
}

View File

@ -6,10 +6,18 @@
*/
package org.hibernate.dialect;
import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -39,4 +47,58 @@ protected void renderSearchClause(CteStatement cte) {
protected void renderCycleClause(CteStatement cte) {
// MimerSQL does not support this, but it can be emulated
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonEmulateIntersect( lhs, operator, rhs );
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "'0' || '0'" );
}
else if ( expression instanceof Summarization ) {
// This could theoretically be emulated by rendering all grouping variations of the query and
// connect them via union all but that's probably pretty inefficient and would have to happen
// on the query spec level
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
@Override
protected String getFromDual() {
return " from (values(0))";
}
@Override
protected String getFromDualForSelectOnly() {
return getFromDual();
}
}

View File

@ -7,9 +7,13 @@
package org.hibernate.dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
@ -69,6 +73,47 @@ protected void renderCycleClause(CteStatement cte) {
// MySQL does not support this, but it can be emulated
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonDistinctOperator( lhs, operator, rhs );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "'0'" );
}
else if ( expression instanceof Summarization ) {
Summarization summarization = (Summarization) expression;
renderCommaSeparated( summarization.getGroupings() );
appendSql( " with " );
appendSql( summarization.getKind().name().toLowerCase() );
}
else {
expression.accept( this );
}
}
@Override
public boolean supportsRowValueConstructorSyntaxInSet() {
return false;
}
@Override
public boolean supportsRowValueConstructorSyntaxInInList() {
return getDialect().getVersion() >= 570;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
@Override
protected String getFromDual() {
return " from dual";
}
private boolean supportsWindowFunctions() {
return getDialect().getVersion() >= 802;
}

View File

@ -21,6 +21,6 @@
public class Oracle10gDialect extends OracleDialect {
public Oracle10gDialect() {
super(10);
super( 1000 );
}
}

View File

@ -17,6 +17,6 @@
public class Oracle12cDialect extends OracleDialect {
public Oracle12cDialect() {
super(12);
super( 1200 );
}
}

View File

@ -15,7 +15,7 @@
public class Oracle8iDialect extends OracleDialect {
public Oracle8iDialect() {
super(8);
super( 800 );
}
}

View File

@ -20,7 +20,7 @@
public class Oracle9iDialect extends OracleDialect {
public Oracle9iDialect() {
super(9);
super( 900 );
}
}

View File

@ -94,7 +94,7 @@ public class OracleDialect extends Dialect {
private final int version;
public OracleDialect(DialectResolutionInfo info) {
this( info.getDatabaseMajorVersion() );
this( info.getDatabaseMajorVersion() * 100 + info.getDatabaseMinorVersion() );
}
private static final Pattern DISTINCT_KEYWORD_PATTERN = Pattern.compile( "\\bdistinct\\b" );
@ -114,7 +114,7 @@ public OracleDialect(DialectResolutionInfo info) {
private final LimitHandler limitHandler;
public OracleDialect() {
this(8);
this( 800 );
}
public OracleDialect(int version) {
@ -128,7 +128,7 @@ public OracleDialect(int version) {
registerReverseHibernateTypeMappings();
registerDefaultProperties();
limitHandler = getVersion() < 12
limitHandler = getVersion() < 1200
? new LegacyOracleLimitHandler( getVersion() )
: OffsetFetchLimitHandler.INSTANCE;
}
@ -182,7 +182,7 @@ public void initializeFunctionRegistry(QueryEngine queryEngine) {
CommonFunctionFactory.corr( queryEngine );
CommonFunctionFactory.regrLinearRegressionAggregates( queryEngine );
if ( getVersion() < 9 ) {
if ( getVersion() < 900 ) {
queryEngine.getSqmFunctionRegistry().register( "coalesce", new NvlCoalesceEmulation() );
}
else {
@ -211,7 +211,7 @@ protected <T extends JdbcOperation> SqlAstTranslator<T> buildTranslator(
@Override
public String currentDate() {
return getVersion() < 9 ? currentTimestamp() : "current_date";
return getVersion() < 900 ? currentTimestamp() : "current_date";
}
@Override
@ -221,7 +221,7 @@ public String currentTime() {
@Override
public String currentTimestamp() {
return getVersion() < 9 ? "sysdate" : currentTimestampWithTimeZone();
return getVersion() < 900 ? "sysdate" : currentTimestampWithTimeZone();
}
@Override
@ -231,12 +231,12 @@ public String currentLocalTime() {
@Override
public String currentLocalTimestamp() {
return getVersion() < 9 ? currentTimestamp() : "localtimestamp";
return getVersion() < 900 ? currentTimestamp() : "localtimestamp";
}
@Override
public String currentTimestampWithTimeZone() {
return getVersion() < 9 ? currentTimestamp() : "current_timestamp";
return getVersion() < 900 ? currentTimestamp() : "current_timestamp";
}
@ -523,7 +523,7 @@ private void extractField(
}
protected void registerCharacterTypeMappings() {
if ( getVersion() < 9) {
if ( getVersion() < 900) {
registerColumnType( Types.VARCHAR, 4000, "varchar2($l)" );
registerColumnType( Types.VARCHAR, "clob" );
}
@ -549,7 +549,7 @@ protected void registerNumericTypeMappings() {
}
protected void registerDateTimeTypeMappings() {
if ( getVersion() < 9 ) {
if ( getVersion() < 900 ) {
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "date" );
registerColumnType( Types.TIMESTAMP, "date" );
@ -567,7 +567,7 @@ protected void registerDateTimeTypeMappings() {
@Override
public boolean supportsTimezoneTypes() {
return getVersion() >= 9;
return getVersion() >= 900;
}
protected void registerBinaryTypeMappings() {
@ -585,7 +585,7 @@ protected void registerDefaultProperties() {
getDefaultProperties().setProperty( Environment.USE_STREAMS_FOR_BINARY, "true" );
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
if ( getVersion() < 12 ) {
if ( getVersion() < 1200 ) {
// Oracle driver reports to support getGeneratedKeys(), but they only
// support the version taking an array of the names of the columns to
// be returned (via its RETURNING clause). No other driver seems to
@ -641,7 +641,7 @@ public boolean supportsBitType() {
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contributeTypes( typeContributions, serviceRegistry );
if ( getVersion() >= 12 ) {
if ( getVersion() >= 1200 ) {
// account for Oracle's deprecated support for LONGVARBINARY
// prefer BLOB, unless the user explicitly opts out
boolean preferLong = serviceRegistry.getService( ConfigurationService.class ).getSetting(
@ -745,7 +745,7 @@ public String getTableAliasSeparator() {
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return getVersion() < 12
return getVersion() < 1200
? super.getIdentityColumnSupport()
: new Oracle12cIdentityColumnSupport();
}
@ -753,12 +753,12 @@ public IdentityColumnSupport getIdentityColumnSupport() {
@Override
@SuppressWarnings("deprecation")
public JoinFragment createOuterJoinFragment() {
return getVersion() < 10 ? new OracleJoinFragment() : new ANSIJoinFragment();
return getVersion() < 1000 ? new OracleJoinFragment() : new ANSIJoinFragment();
}
@Override
public String getCrossJoinSeparator() {
return getVersion() < 10 ? ", " : " cross join ";
return getVersion() < 1000 ? ", " : " cross join ";
}
/**
@ -770,7 +770,7 @@ public String getCrossJoinSeparator() {
@Override
@SuppressWarnings("deprecation")
public CaseFragment createCaseFragment() {
return getVersion() < 9
return getVersion() < 900
? new DecodeCaseFragment()
// Oracle did add support for ANSI CASE statements in 9i
: new ANSICaseFragment();
@ -783,7 +783,7 @@ public LimitHandler getLimitHandler() {
@Override
public String getSelectClauseNullString(int sqlType) {
if ( getVersion() >= 9 ) {
if ( getVersion() >= 900 ) {
return super.getSelectClauseNullString(sqlType);
}
else {
@ -804,7 +804,7 @@ public String getSelectClauseNullString(int sqlType) {
@Override
public String getCurrentTimestampSelectString() {
return getVersion() < 9
return getVersion() < 900
? "select sysdate from dual"
: "select systimestamp from dual";
}
@ -812,7 +812,7 @@ public String getCurrentTimestampSelectString() {
@Override
@SuppressWarnings("deprecation")
public String getCurrentTimestampSQLFunctionName() {
return getVersion() < 9
return getVersion() < 900
? "sysdate"
// the standard SQL function name is current_timestamp...
: "current_timestamp";
@ -1118,7 +1118,7 @@ public boolean supportsRowValueConstructorSyntaxInInList() {
@Override
public boolean supportsRowValueConstructorSyntaxInInSubquery() {
return getVersion() >= 9;
return getVersion() >= 900;
}
@Override
@ -1128,12 +1128,12 @@ public boolean supportsTupleDistinctCounts() {
@Override
public boolean supportsNoWait() {
return getVersion() >= 9;
return getVersion() >= 900;
}
@Override
public boolean supportsSkipLocked() {
return getVersion() >= 10;
return getVersion() >= 1000;
}
@Override

View File

@ -10,9 +10,15 @@
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.collections.Stack;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.insert.Values;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
@ -104,8 +110,68 @@ protected void renderRowNumber(SelectClause selectClause, QueryPart queryPart) {
}
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonEmulateDecode( lhs, operator, rhs );
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "()" );
}
else if ( expression instanceof Summarization ) {
Summarization summarization = (Summarization) expression;
appendSql( summarization.getKind().name().toLowerCase() );
appendSql( OPEN_PARENTHESIS );
renderCommaSeparated( summarization.getGroupings() );
appendSql( CLOSE_PARENTHESIS );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return getDialect().getVersion() >= 820;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInSubQuery() {
return getDialect().getVersion() >= 900;
}
@Override
protected String getFromDual() {
return " from dual";
}
@Override
protected String getFromDualForSelectOnly() {
return getFromDual();
}
private boolean supportsOffsetFetchClause() {
return getDialect().getVersion() >= 12;
return getDialect().getVersion() >= 1200;
}
}

View File

@ -11,6 +11,9 @@
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
@ -85,6 +88,40 @@ protected void renderCycleClause(CteStatement cte) {
// PostgreSQL does not support this, but it can be emulated
}
@Override
protected void renderPartitionItem(Expression expression) {
// We render an empty group instead of literals as some DBs don't support grouping by literals
// Note that integer literals, which refer to select item positions, are handled in #visitGroupByClause
if ( expression instanceof Literal ) {
if ( getDialect().getVersion() >= 950 ) {
appendSql( "()" );
}
else {
appendSql( "(select 1" );
appendSql( getFromDualForSelectOnly() );
appendSql( ')' );
}
}
else if ( expression instanceof Summarization ) {
Summarization summarization = (Summarization) expression;
if ( getDialect().getVersion() >= 950 ) {
appendSql( summarization.getKind().name().toLowerCase() );
appendSql( OPEN_PARENTHESIS );
renderCommaSeparated( summarization.getGroupings() );
appendSql( CLOSE_PARENTHESIS );
}
else {
// This could theoretically be emulated by rendering all grouping variations of the query and
// connect them via union all but that's probably pretty inefficient and would have to happen
// on the query spec level
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
}
else {
expression.accept( this );
}
}
private boolean supportsOffsetFetchClause() {
return getDialect().getVersion() >= 840;
}

View File

@ -6,12 +6,20 @@
*/
package org.hibernate.dialect;
import java.util.List;
import org.hibernate.query.FetchClauseType;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.query.Limit;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -64,4 +72,58 @@ protected void renderSearchClause(CteStatement cte) {
protected void renderCycleClause(CteStatement cte) {
// Unisys 2200 does not support this, but it can be emulated
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonEmulateIntersect( lhs, operator, rhs );
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "'0' || '0'" );
}
else if ( expression instanceof Summarization ) {
// This could theoretically be emulated by rendering all grouping variations of the query and
// connect them via union all but that's probably pretty inefficient and would have to happen
// on the query spec level
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
@Override
protected String getFromDual() {
return " from rdms.rdms_dummy where key_col = 1";
}
@Override
protected String getFromDualForSelectOnly() {
return getFromDual();
}
}

View File

@ -10,11 +10,16 @@
import org.hibernate.query.FetchClauseType;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
@ -203,6 +208,50 @@ protected void renderCycleClause(CteStatement cte) {
// SQL Server does not support this, but it can be emulated
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonEmulateIntersect( lhs, operator, rhs );
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "()" );
}
else if ( expression instanceof Summarization ) {
Summarization summarization = (Summarization) expression;
renderCommaSeparated( summarization.getGroupings() );
appendSql( " with " );
appendSql( summarization.getKind().name().toLowerCase() );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
enum OffsetFetchClauseMode {
STANDARD,
TOP_ONLY,

View File

@ -6,10 +6,18 @@
*/
package org.hibernate.dialect;
import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -38,4 +46,48 @@ protected void renderSearchClause(CteStatement cte) {
protected void renderCycleClause(CteStatement cte) {
// Spanner does not support this, but it can be emulated
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonEmulateIntersect( lhs, operator, rhs );
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "'0' || '0'" );
}
else if ( expression instanceof Summarization ) {
// This could theoretically be emulated by rendering all grouping variations of the query and
// connect them via union all but that's probably pretty inefficient and would have to happen
// on the query spec level
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
}

View File

@ -6,11 +6,18 @@
*/
package org.hibernate.dialect;
import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SelectClause;
@ -83,6 +90,39 @@ protected void renderOffsetExpression(Expression offsetExpression) {
}
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonEmulateIntersect( lhs, operator, rhs );
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
// todo (6.0): We need to introduce a dummy from clause item
// String fromItem = ", (select 1 x " + dialect.getFromDual() + ") dummy";
// sqlBuffer.insert( fromEndIndex, fromItem );
// appendSql( "dummy.x" );
throw new UnsupportedOperationException( "Column reference strategy is not yet implemented!" );
}
else if ( expression instanceof Summarization ) {
// This could theoretically be emulated by rendering all grouping variations of the query and
// connect them via union all but that's probably pretty inefficient and would have to happen
// on the query spec level
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
else {
expression.accept( this );
}
}
@Override
protected boolean needsRowsToSkip() {
return true;
@ -93,6 +133,21 @@ protected boolean needsMaxRows() {
return !supportsTopClause();
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
private boolean supportsTopClause() {
return getDialect().getVersion() >= 1250;
}

View File

@ -6,11 +6,18 @@
*/
package org.hibernate.dialect;
import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SelectClause;
@ -81,4 +88,58 @@ protected void renderSearchClause(CteStatement cte) {
protected void renderCycleClause(CteStatement cte) {
// Sybase Anywhere does not support this, but it can be emulated
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonEmulateIntersect( lhs, operator, rhs );
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "()" );
}
else if ( expression instanceof Summarization ) {
// This could theoretically be emulated by rendering all grouping variations of the query and
// connect them via union all but that's probably pretty inefficient and would have to happen
// on the query spec level
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
@Override
protected String getFromDual() {
return " from sys.dummy";
}
@Override
protected String getFromDualForSelectOnly() {
return getFromDual();
}
}

View File

@ -6,10 +6,18 @@
*/
package org.hibernate.dialect;
import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -42,6 +50,54 @@ public void visitOffsetFetchClause(QueryPart queryPart) {
}
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonEmulateIntersect( lhs, operator, rhs );
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
// todo (6.0): We need to introduce a dummy from clause item
// String fromItem = ", (select 1 x " + dialect.getFromDual() + ") dummy";
// sqlBuffer.insert( fromEndIndex, fromItem );
// appendSql( "dummy.x" );
throw new UnsupportedOperationException( "Column reference strategy is not yet implemented!" );
}
else if ( expression instanceof Summarization ) {
// This could theoretically be emulated by rendering all grouping variations of the query and
// connect them via union all but that's probably pretty inefficient and would have to happen
// on the query spec level
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
@Override
protected boolean needsRowsToSkip() {
return true;

View File

@ -6,11 +6,18 @@
*/
package org.hibernate.dialect;
import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SelectClause;
@ -63,4 +70,48 @@ protected void renderSearchClause(CteStatement cte) {
protected void renderCycleClause(CteStatement cte) {
// Teradata does not support this, but it can be emulated
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonEmulateIntersect( lhs, operator, rhs );
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "()" );
}
else if ( expression instanceof Summarization ) {
// This could theoretically be emulated by rendering all grouping variations of the query and
// connect them via union all but that's probably pretty inefficient and would have to happen
// on the query spec level
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
}

View File

@ -6,11 +6,18 @@
*/
package org.hibernate.dialect;
import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SelectClause;
@ -55,4 +62,48 @@ protected void renderFetchPlusOffsetExpression(
public void visitOffsetFetchClause(QueryPart queryPart) {
// TimesTen uses ROWS TO clause
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonEmulateIntersect( lhs, operator, rhs );
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "'0' || '0'" );
}
else if ( expression instanceof Summarization ) {
// This could theoretically be emulated by rendering all grouping variations of the query and
// connect them via union all but that's probably pretty inefficient and would have to happen
// on the query spec level
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
else {
expression.accept( this );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
}

View File

@ -16,7 +16,7 @@
*/
public class LegacyOracleLimitHandler extends AbstractLimitHandler {
private int version;
private final int version;
public LegacyOracleLimitHandler(int version) {
this.version = version;
@ -39,7 +39,7 @@ public String processSql(String sql, RowSelection selection) {
final StringBuilder pagingSelect = new StringBuilder( sql.length() + 100 );
if ( hasOffset ) {
pagingSelect.append( "select * from (select row_.*, rownum rownum_ from (" ).append( sql );
if ( version < 9 ) {
if ( version < 900 ) {
pagingSelect.append( ") row_) where rownum_ <= ? and rownum_ > ?" );
}
else {
@ -74,7 +74,7 @@ public String processSql(String sql, Limit limit) {
final StringBuilder pagingSelect = new StringBuilder( sql.length() + 100 );
if ( hasOffset ) {
pagingSelect.append( "select * from (select row_.*, rownum rownum_ from (" ).append( sql );
if ( version < 9 ) {
if ( version < 900 ) {
pagingSelect.append( ") row_) where rownum_ <= ? and rownum_ > ?" );
}
else {

View File

@ -64,6 +64,59 @@ public String sqlText() {
return "!=";
}
},
NOT_DISTINCT_FROM {
@Override
public ComparisonOperator negated() {
return DISTINCT_FROM;
}
@Override
public ComparisonOperator invert() {
return NOT_DISTINCT_FROM;
}
@Override
public ComparisonOperator broader() {
return NOT_DISTINCT_FROM;
}
@Override
public ComparisonOperator sharper() {
return NOT_DISTINCT_FROM;
}
@Override
public String sqlText() {
return "is not distinct from";
}
},
DISTINCT_FROM {
@Override
public ComparisonOperator negated() {
return NOT_DISTINCT_FROM;
}
@Override
public ComparisonOperator invert() {
return DISTINCT_FROM;
}
@Override
public ComparisonOperator broader() {
return DISTINCT_FROM;
}
@Override
public ComparisonOperator sharper() {
return DISTINCT_FROM;
}
@Override
public String sqlText() {
return "is distinct from";
}
},
LESS_THAN {
@Override

View File

@ -512,6 +512,14 @@ <R> JpaCompoundSelection<R> tuple(
@Override
JpaPredicate notEqual(Expression<?> x, Object y);
JpaPredicate distinctFrom(Expression<?> x, Expression<?> y);
JpaPredicate distinctFrom(Expression<?> x, Object y);
JpaPredicate notDistinctFrom(Expression<?> x, Expression<?> y);
JpaPredicate notDistinctFrom(Expression<?> x, Object y);
@Override
<Y extends Comparable<? super Y>> JpaPredicate greaterThan(
Expression<? extends Y> x,

View File

@ -1624,27 +1624,28 @@ public SqmEmptinessPredicate visitIsEmptyPredicate(HqlParser.IsEmptyPredicateCon
@Override
public Object visitComparisonOperator(HqlParser.ComparisonOperatorContext ctx) {
if ( ctx.EQUAL()!=null ) {
return ComparisonOperator.EQUAL;
}
else if ( ctx.NOT_EQUAL()!=null ) {
return ComparisonOperator.NOT_EQUAL;
}
else if ( ctx.LESS()!=null ) {
return ComparisonOperator.LESS_THAN;
}
else if ( ctx.LESS_EQUAL()!=null ) {
return ComparisonOperator.LESS_THAN_OR_EQUAL;
}
else if ( ctx.GREATER()!=null ) {
return ComparisonOperator.GREATER_THAN;
}
else if ( ctx.GREATER_EQUAL()!=null ) {
return ComparisonOperator.GREATER_THAN_OR_EQUAL;
}
else {
throw new QueryException("missing operator");
final TerminalNode firstToken = (TerminalNode) ctx.getChild( 0 );
switch ( firstToken.getSymbol().getType() ) {
case HqlLexer.EQUAL:
return ComparisonOperator.EQUAL;
case HqlLexer.NOT_EQUAL:
return ComparisonOperator.NOT_EQUAL;
case HqlLexer.LESS:
return ComparisonOperator.LESS_THAN;
case HqlLexer.LESS_EQUAL:
return ComparisonOperator.LESS_THAN_OR_EQUAL;
case HqlLexer.GREATER:
return ComparisonOperator.GREATER_THAN;
case HqlLexer.GREATER_EQUAL:
return ComparisonOperator.GREATER_THAN_OR_EQUAL;
case HqlLexer.IS: {
final TerminalNode secondToken = (TerminalNode) ctx.getChild( 1 );
return secondToken.getSymbol().getType() == HqlLexer.NOT
? ComparisonOperator.NOT_DISTINCT_FROM
: ComparisonOperator.DISTINCT_FROM;
}
}
throw new QueryException("missing operator");
}
@Override
@ -1657,7 +1658,9 @@ public SqmPredicate visitComparisonPredicate(HqlParser.ComparisonPredicateContex
final HqlParser.ExpressionContext rightExpressionContext = expressionContexts.get( 1 );
switch (comparisonOperator) {
case EQUAL:
case NOT_EQUAL: {
case NOT_EQUAL:
case DISTINCT_FROM:
case NOT_DISTINCT_FROM: {
Map<Class<?>, Enum<?>> possibleEnumValues;
if ( ( possibleEnumValues = getPossibleEnumValues( leftExpressionContext ) ) != null ) {
right = (SqmExpression) rightExpressionContext.accept( this );
@ -1683,14 +1686,16 @@ else if ( ( possibleEnumValues = getPossibleEnumValues( rightExpressionContext )
if ( left instanceof SqmLiteralNull<?> ) {
return new SqmNullnessPredicate(
right,
comparisonOperator == ComparisonOperator.NOT_EQUAL,
comparisonOperator == ComparisonOperator.NOT_EQUAL
|| comparisonOperator == ComparisonOperator.DISTINCT_FROM,
creationContext.getNodeBuilder()
);
}
else if ( right instanceof SqmLiteralNull<?> ) {
return new SqmNullnessPredicate(
left,
comparisonOperator == ComparisonOperator.NOT_EQUAL,
comparisonOperator == ComparisonOperator.NOT_EQUAL
|| comparisonOperator == ComparisonOperator.DISTINCT_FROM,
creationContext.getNodeBuilder()
);
}

View File

@ -466,6 +466,18 @@ <R> SqmTuple<R> tuple(
@Override
SqmPredicate notEqual(Expression<?> x, Object y);
@Override
SqmPredicate distinctFrom(Expression<?> x, Expression<?> y);
@Override
SqmPredicate distinctFrom(Expression<?> x, Object y);
@Override
SqmPredicate notDistinctFrom(Expression<?> x, Expression<?> y);
@Override
SqmPredicate notDistinctFrom(Expression<?> x, Object y);
@Override
<Y extends Comparable<? super Y>> SqmPredicate greaterThan(Expression<? extends Y> x, Expression<? extends Y> y);

View File

@ -1710,6 +1710,46 @@ public SqmPredicate notEqual(Expression<?> x, Object y) {
);
}
@Override
public SqmPredicate distinctFrom(Expression<?> x, Expression<?> y) {
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.DISTINCT_FROM,
(SqmExpression<?>) y,
this
);
}
@Override
public SqmPredicate distinctFrom(Expression<?> x, Object y) {
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.DISTINCT_FROM,
value( y ),
this
);
}
@Override
public SqmPredicate notDistinctFrom(Expression<?> x, Expression<?> y) {
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.NOT_DISTINCT_FROM,
(SqmExpression<?>) y,
this
);
}
@Override
public SqmPredicate notDistinctFrom(Expression<?> x, Object y) {
return new SqmComparisonPredicate(
(SqmExpression<?>) x,
ComparisonOperator.NOT_DISTINCT_FROM,
value( y ),
this
);
}
@Override
public <Y extends Comparable<? super Y>> SqmPredicate greaterThan(Expression<? extends Y> x, Expression<? extends Y> y) {
return new SqmComparisonPredicate(

View File

@ -411,6 +411,12 @@ else if ( expression instanceof JdbcParameter ) {
}
return (R) getParameterBindValue( (JdbcParameter) expression );
}
else if ( expression instanceof SqmParameterInterpretation ) {
if ( jdbcParameterBindings == null ) {
throw new IllegalArgumentException( "Can't interpret expression because no parameter bindings are available!" );
}
return (R) getParameterBindValue( (JdbcParameter) ( (SqmParameterInterpretation) expression).getResolvedExpression() );
}
throw new UnsupportedOperationException( "Can't interpret expression: " + expression );
}
@ -427,6 +433,14 @@ else if ( expression instanceof JdbcParameter ) {
renderAsLiteral( parameter, getParameterBindValue( parameter ) );
return;
}
else if ( expression instanceof SqmParameterInterpretation ) {
if ( jdbcParameterBindings == null ) {
throw new IllegalArgumentException( "Can't interpret expression because no parameter bindings are available!" );
}
final JdbcParameter parameter = (JdbcParameter) ( (SqmParameterInterpretation) expression).getResolvedExpression();
renderAsLiteral( parameter, getParameterBindValue( parameter ) );
return;
}
throw new UnsupportedOperationException( "Can't render expression as literal: " + expression );
}
@ -1219,56 +1233,15 @@ protected final void visitPartitionExpressions(List<Expression> partitionExpress
}
protected void renderPartitionItem(Expression expression) {
// We render an empty group instead of literals as some DBs don't support grouping by literals
// Note that integer literals, which refer to select item positions, are handled in #visitGroupByClause
if ( expression instanceof Literal ) {
switch ( dialect.getGroupByConstantRenderingStrategy() ) {
case CONSTANT:
appendSql( "'0'" );
break;
case CONSTANT_EXPRESSION:
appendSql( "'0' || '0'" );
break;
case EMPTY_GROUPING:
appendSql( "()" );
break;
case SUBQUERY:
appendSql( "(select 1" );
final String fromDual = dialect.getFromDual();
if ( !fromDual.isEmpty() ) {
appendSql( " " );
appendSql( fromDual );
}
appendSql( ')' );
break;
case COLUMN_REFERENCE:
// todo (6.0): We need to introduce a dummy from clause item
// String fromItem = ", (select 1 x " + dialect.getFromDual() + ") dummy";
// sqlBuffer.insert( fromEndIndex, fromItem );
// appendSql( "dummy.x" );
throw new UnsupportedOperationException( "Column reference strategy is not yet implemented!" );
}
appendSql( "()" );
}
else if ( expression instanceof Summarization ) {
Summarization summarization = (Summarization) expression;
switch ( dialect.getGroupBySummarizationRenderingStrategy() ) {
case FUNCTION:
appendSql( summarization.getKind().name().toLowerCase() );
appendSql( OPEN_PARENTHESIS );
renderCommaSeparated( summarization.getGroupings() );
appendSql( CLOSE_PARENTHESIS );
break;
case CLAUSE:
renderCommaSeparated( summarization.getGroupings() );
appendSql( " with " );
appendSql( summarization.getKind().name().toLowerCase() );
break;
default:
// This could theoretically be emulated by rendering all grouping variations of the query and
// connect them via union all but that's probably pretty inefficient and would have to happen
// on the query spec level
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
}
appendSql( summarization.getKind().name().toLowerCase() );
appendSql( OPEN_PARENTHESIS );
renderCommaSeparated( summarization.getGroupings() );
appendSql( CLOSE_PARENTHESIS );
}
else {
expression.accept( this );
@ -1331,8 +1304,8 @@ protected void renderOrderBy(boolean addWhitespace, List<SortSpecification> sort
* For <code>(a, b, c) &gt; (1, 2, 3)</code> we use the broad predicate <code>a &gt;= 1</code> and then want to remove rows where <code>a = 1 and (b, c) &lt;= (2, 3)</code>
*/
protected void emulateTupleComparison(
final List<? extends Expression> lhsExpressions,
final List<? extends Expression> rhsExpressions,
final List<? extends SqlAstNode> lhsExpressions,
final List<? extends SqlAstNode> rhsExpressions,
ComparisonOperator operator,
boolean indexOptimized) {
final boolean isCurrentWhereClause = clauseStack.getCurrent() == Clause.WHERE;
@ -1343,6 +1316,18 @@ protected void emulateTupleComparison(
final int size = lhsExpressions.size();
assert size == rhsExpressions.size();
switch ( operator ) {
case DISTINCT_FROM:
appendSql( "not " );
case NOT_DISTINCT_FROM: {
appendSql( "exists (select " );
renderCommaSeparatedSelectExpression( lhsExpressions );
appendSql( getFromDualForSelectOnly() );
appendSql( " intersect select " );
renderCommaSeparatedSelectExpression( rhsExpressions );
appendSql( getFromDualForSelectOnly() );
appendSql( ")" );
break;
}
case EQUAL:
case NOT_EQUAL: {
final String operatorText = operator.sqlText();
@ -1406,12 +1391,8 @@ protected void renderExpressionsAsSubquery(final List<? extends Expression> expr
try {
appendSql( "select " );
renderCommaSeparated( expressions );
final String fromDual = dialect.getFromDual();
if ( !fromDual.isEmpty() ) {
appendSql( " " );
appendSql( fromDual );
}
renderCommaSeparatedSelectExpression( expressions );
appendSql( getFromDualForSelectOnly() );
}
finally {
clauseStack.pop();
@ -1419,8 +1400,8 @@ protected void renderExpressionsAsSubquery(final List<? extends Expression> expr
}
private void emulateTupleComparisonSimple(
final List<? extends Expression> lhsExpressions,
final List<? extends Expression> rhsExpressions,
final List<? extends SqlAstNode> lhsExpressions,
final List<? extends SqlAstNode> rhsExpressions,
final String operatorText,
final String finalOperatorText,
final boolean optimized) {
@ -1478,30 +1459,118 @@ private void emulateTupleComparisonSimple(
}
protected void renderSelectTupleComparison(final List<SqlSelection> lhsExpressions, SqlTuple tuple, ComparisonOperator operator) {
if ( dialect.supportsRowValueConstructorSyntax() ) {
appendSql( OPEN_PARENTHESIS );
String separator = NO_SEPARATOR;
for ( SqlSelection lhsExpression : lhsExpressions ) {
appendSql( separator );
lhsExpression.getExpression().accept( this );
separator = COMA_SEPARATOR;
}
appendSql( CLOSE_PARENTHESIS );
appendSql( " " );
appendSql( operator.sqlText() );
appendSql( " " );
tuple.accept( this );
}
else {
final List<Expression> lhs = new ArrayList<>( lhsExpressions.size() );
for ( SqlSelection lhsExpression : lhsExpressions ) {
lhs.add( lhsExpression.getExpression() );
}
renderTupleComparisonStandard( lhsExpressions, tuple, operator );
}
emulateTupleComparison( lhs, tuple.getExpressions(), operator, true );
protected void renderTupleComparisonStandard(
final List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
appendSql( OPEN_PARENTHESIS );
String separator = NO_SEPARATOR;
for ( SqlSelection lhsExpression : lhsExpressions ) {
appendSql( separator );
lhsExpression.getExpression().accept( this );
separator = COMA_SEPARATOR;
}
appendSql( CLOSE_PARENTHESIS );
appendSql( " " );
appendSql( operator.sqlText() );
appendSql( " " );
tuple.accept( this );
}
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonStandard( lhs, operator, rhs );
}
protected void renderComparisonStandard(Expression lhs, ComparisonOperator operator, Expression rhs) {
lhs.accept( this );
appendSql( " " );
appendSql( operator.sqlText() );
appendSql( " " );
rhs.accept( this );
}
protected void renderComparisonDistinctOperator(Expression lhs, ComparisonOperator operator, Expression rhs) {
final boolean notWrapper;
final String operatorText;
switch ( operator ) {
case DISTINCT_FROM:
notWrapper = true;
operatorText = "<=>";
break;
case NOT_DISTINCT_FROM:
notWrapper = false;
operatorText = "<=>";
break;
default:
notWrapper = false;
operatorText = operator.sqlText();
break;
}
if ( notWrapper ) {
appendSql( "not(" );
}
lhs.accept( this );
appendSql( ' ' );
appendSql( operatorText );
appendSql( ' ' );
rhs.accept( this );
if ( notWrapper ) {
appendSql( ')' );
}
}
protected void renderComparisonEmulateDecode(Expression lhs, ComparisonOperator operator, Expression rhs) {
switch ( operator ) {
case DISTINCT_FROM:
appendSql( "decode(" );
lhs.accept( this );
appendSql( ',' );
rhs.accept( this );
appendSql( ",0,1)=1" );
break;
case NOT_DISTINCT_FROM:
appendSql( "decode(" );
lhs.accept( this );
appendSql( ',' );
rhs.accept( this );
appendSql( ",0,1)=0" );
break;
default:
lhs.accept( this );
appendSql( ' ' );
appendSql( operator.sqlText() );
appendSql( ' ' );
rhs.accept( this );
break;
}
}
protected void renderComparisonEmulateIntersect(Expression lhs, ComparisonOperator operator, Expression rhs) {
switch ( operator ) {
case DISTINCT_FROM:
appendSql( "not " );
case NOT_DISTINCT_FROM: {
appendSql( "exists (select " );
clauseStack.push( Clause.SELECT );
renderSelectExpression( lhs );
appendSql( getFromDualForSelectOnly() );
appendSql( " intersect select " );
renderSelectExpression( rhs );
appendSql( getFromDualForSelectOnly() );
clauseStack.pop();
appendSql( ")" );
return;
}
}
lhs.accept( this );
appendSql( " " );
appendSql( operator.sqlText() );
appendSql( " " );
rhs.accept( this );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ORDER BY clause
@ -2414,26 +2483,14 @@ protected List<SortSpecification> getSortSpecificationsRowNumbering(
@Override
public void visitSqlSelection(SqlSelection sqlSelection) {
final Expression expression = sqlSelection.getExpression();
// Null literals have to be casted in the select clause
if ( expression instanceof Literal ) {
final Literal literal = (Literal) expression;
if ( literal.getLiteralValue() == null ) {
renderNullCast( literal );
}
else {
renderLiteral( literal, dialect.requiresCastingOfParametersInSelectClause() );
}
}
else if ( expression instanceof NullnessLiteral ) {
renderNullCast( expression );
}
else {
expression.accept( this );
}
renderSelectExpression( sqlSelection.getExpression() );
}
protected void renderNullCast(Expression expression) {
protected void renderSelectExpression(Expression expression) {
expression.accept( this );
}
protected void renderCasted(Expression expression) {
final List<SqlAstNode> arguments = new ArrayList<>( 2 );
arguments.add( expression );
arguments.add( new CastTarget( (BasicValuedMapping) expression.getExpressionType() ) );
@ -2482,10 +2539,7 @@ protected void renderLiteral(Literal literal, boolean castParameter) {
@Override
public void visitFromClause(FromClause fromClause) {
if ( fromClause == null || fromClause.getRoots().isEmpty() ) {
if ( !getDialect().supportsSelectQueryWithoutFromClause() ) {
appendSql( " " );
appendSql( getDialect().getFromDual() );
}
appendSql( getFromDualForSelectOnly() );
}
else {
appendSql( " from " );
@ -2857,15 +2911,29 @@ public void visitTuple(SqlTuple tuple) {
}
}
private void renderCommaSeparated(Iterable<? extends Expression> expressions) {
protected final void renderCommaSeparated(Iterable<? extends SqlAstNode> expressions) {
String separator = NO_SEPARATOR;
for ( Expression expression : expressions ) {
for ( SqlAstNode expression : expressions ) {
appendSql( separator );
expression.accept( this );
separator = COMA_SEPARATOR;
}
}
protected final void renderCommaSeparatedSelectExpression(Iterable<? extends SqlAstNode> expressions) {
String separator = NO_SEPARATOR;
for ( SqlAstNode expression : expressions ) {
appendSql( separator );
if ( expression instanceof Expression ) {
renderSelectExpression( (Expression) expression );
}
else {
expression.accept( this );
}
separator = COMA_SEPARATOR;
}
}
@Override
public void visitCollate(Collate collate) {
collate.getExpression().accept( this );
@ -3381,12 +3449,12 @@ public void visitInListPredicate(InListPredicate inListPredicate) {
}
appendSql( CLOSE_PARENTHESIS );
}
else if ( !dialect.supportsRowValueConstructorSyntaxInInList() ) {
else if ( !supportsRowValueConstructorSyntaxInInList() ) {
final ComparisonOperator comparisonOperator = inListPredicate.isNegated() ?
ComparisonOperator.NOT_EQUAL :
ComparisonOperator.EQUAL;
// Some DBs like Oracle support tuples only for the IN subquery predicate
if ( dialect.supportsRowValueConstructorSyntaxInInSubquery() && dialect.supportsUnionAll() ) {
if ( supportsRowValueConstructorSyntaxInInSubQuery() && dialect.supportsUnionAll() ) {
inListPredicate.getTestExpression().accept( this );
if ( inListPredicate.isNegated() ) {
appendSql( " not" );
@ -3469,7 +3537,7 @@ public void visitInSubQueryPredicate(InSubQueryPredicate inSubQueryPredicate) {
appendSql( " in " );
inSubQueryPredicate.getSubQuery().accept( this );
}
else if ( !dialect.supportsRowValueConstructorSyntaxInInSubquery() ) {
else if ( !supportsRowValueConstructorSyntaxInInSubQuery() ) {
emulateTupleSubQueryPredicate(
inSubQueryPredicate,
inSubQueryPredicate.isNegated(),
@ -3582,7 +3650,7 @@ protected void emulateTupleSubQueryPredicate(
}
/**
* An optimized emulation for relational tuple subquery comparisons.
* An optimized emulation for relational tuple sub-query comparisons.
* The idea of this method is to use limit 1 to select the max or min tuple and only compare against that.
*/
protected void emulateQuantifiedTupleSubQueryPredicate(
@ -3593,7 +3661,7 @@ protected void emulateQuantifiedTupleSubQueryPredicate(
final QuerySpec subQuery;
if ( queryPart instanceof QuerySpec && queryPart.getFetchClauseExpression() == null && queryPart.getOffsetClauseExpression() == null ) {
subQuery = (QuerySpec) queryPart;
// We can only emulate the tuple sub query predicate as exists predicate when there are no limit/offsets
// We can only emulate the tuple sub query predicate comparing against the top element when there are no limit/offsets
lhsTuple.accept( this );
appendSql( " " );
appendSql( tupleComparisonOperator.sqlText() );
@ -3656,15 +3724,14 @@ public void visitJunction(Junction junction) {
return;
}
String separator = NO_SEPARATOR;
for ( Predicate predicate : junction.getPredicates() ) {
appendSql( separator );
predicate.accept( this );
if ( separator == NO_SEPARATOR ) {
separator = junction.getNature() == Junction.Nature.CONJUNCTION
final String separator = junction.getNature() == Junction.Nature.CONJUNCTION
? " and "
: " or ";
}
final List<Predicate> predicates = junction.getPredicates();
predicates.get( 0 ).accept( this );
for ( int i = 1; i < predicates.size(); i++ ) {
appendSql( separator );
predicates.get( i ).accept( this );
}
}
@ -3763,42 +3830,48 @@ else if ( rhsExpression instanceof Any ) {
final ComparisonOperator operator = comparisonPredicate.getOperator();
if ( lhsTuple.getExpressions().size() == 1 ) {
// Special case for tuples with arity 1 as any DBMS supports scalar IN predicates
lhsTuple.getExpressions().get( 0 ).accept( this );
appendSql( " " );
appendSql( operator.sqlText() );
appendSql( " " );
if ( subquery == null ) {
getTuple( comparisonPredicate.getRightHandExpression() ).getExpressions().get( 0 ).accept( this );
renderComparison(
lhsTuple.getExpressions().get( 0 ),
operator,
getTuple( comparisonPredicate.getRightHandExpression() ).getExpressions().get( 0 )
);
}
else {
rhsExpression.accept( this );
renderComparison( lhsTuple.getExpressions().get( 0 ), operator, rhsExpression );
}
}
else if ( subquery != null && !dialect.supportsRowValueConstructorSyntaxInQuantifiedPredicates() ) {
else if ( subquery != null && !supportsRowValueConstructorSyntaxInQuantifiedPredicates() ) {
// For quantified relational comparisons, we can do an optimized emulation
if ( all && operator != ComparisonOperator.EQUAL && operator != ComparisonOperator.NOT_EQUAL && dialect.supportsRowValueConstructorSyntax() ) {
emulateQuantifiedTupleSubQueryPredicate(
comparisonPredicate,
subquery,
lhsTuple,
operator
);
}
else {
emulateTupleSubQueryPredicate(
comparisonPredicate,
all,
subquery,
lhsTuple,
all ? operator.negated() : operator
);
if ( supportsRowValueConstructorSyntax() && all ) {
switch ( operator ) {
case LESS_THAN:
case LESS_THAN_OR_EQUAL:
case GREATER_THAN:
case GREATER_THAN_OR_EQUAL: {
emulateQuantifiedTupleSubQueryPredicate(
comparisonPredicate,
subquery,
lhsTuple,
operator
);
return;
}
}
}
emulateTupleSubQueryPredicate(
comparisonPredicate,
all,
subquery,
lhsTuple,
all ? operator.negated() : operator
);
}
else if ( !dialect.supportsRowValueConstructorSyntax() ) {
else if ( !supportsRowValueConstructorSyntax() ) {
rhsTuple = getTuple( rhsExpression );
assert rhsTuple != null;
// Some DBs like Oracle support tuples only for the IN subquery predicate
if ( ( operator == ComparisonOperator.EQUAL || operator == ComparisonOperator.NOT_EQUAL ) && dialect.supportsRowValueConstructorSyntaxInInSubquery() ) {
if ( ( operator == ComparisonOperator.EQUAL || operator == ComparisonOperator.NOT_EQUAL ) && supportsRowValueConstructorSyntaxInInSubQuery() ) {
comparisonPredicate.getLeftHandExpression().accept( this );
if ( operator == ComparisonOperator.NOT_EQUAL ) {
appendSql( " not" );
@ -3817,11 +3890,7 @@ else if ( !dialect.supportsRowValueConstructorSyntax() ) {
}
}
else {
comparisonPredicate.getLeftHandExpression().accept( this );
appendSql( " " );
appendSql( operator.sqlText() );
appendSql( " " );
rhsExpression.accept( this );
renderComparison( comparisonPredicate.getLeftHandExpression(), operator, rhsExpression );
}
}
else if ( ( rhsTuple = getTuple( comparisonPredicate.getRightHandExpression() ) ) != null ) {
@ -3832,18 +3901,18 @@ else if ( ( rhsTuple = getTuple( comparisonPredicate.getRightHandExpression() )
if ( rhsTuple.getExpressions().size() == 1 ) {
// Special case for tuples with arity 1 as any DBMS supports scalar IN predicates
lhsExpression.accept( this );
appendSql( " " );
appendSql( comparisonPredicate.getOperator().sqlText() );
appendSql( " " );
rhsTuple.getExpressions().get( 0 ).accept( this );
renderComparison(
lhsExpression,
comparisonPredicate.getOperator(),
rhsTuple.getExpressions().get( 0 )
);
}
else if ( dialect.supportsRowValueConstructorSyntax() ) {
lhsExpression.accept( this );
appendSql( " " );
appendSql( comparisonPredicate.getOperator().sqlText() );
appendSql( " " );
comparisonPredicate.getRightHandExpression().accept( this );
else if ( supportsRowValueConstructorSyntax() ) {
renderComparison(
lhsExpression,
comparisonPredicate.getOperator(),
comparisonPredicate.getRightHandExpression()
);
}
else {
emulateTupleSubQueryPredicate(
@ -3862,12 +3931,93 @@ else if ( dialect.supportsRowValueConstructorSyntax() ) {
}
}
else {
comparisonPredicate.getLeftHandExpression().accept( this );
appendSql( " " );
appendSql( comparisonPredicate.getOperator().sqlText() );
appendSql( " " );
comparisonPredicate.getRightHandExpression().accept( this );
renderComparison(
comparisonPredicate.getLeftHandExpression(),
comparisonPredicate.getOperator(),
comparisonPredicate.getRightHandExpression()
);
}
}
/**
* Is this dialect known to support what ANSI-SQL terms "row value
* constructor" syntax; sometimes called tuple syntax.
* <p/>
* Basically, does it support syntax like
* "... where (FIRST_NAME, LAST_NAME) = ('Steve', 'Ebersole') ...".
*
* @return True if this SQL dialect is known to support "row value
* constructor" syntax; false otherwise.
*/
protected boolean supportsRowValueConstructorSyntax() {
return true;
}
/**
* Is this dialect known to support what ANSI-SQL terms "row value constructor" syntax,
* sometimes called tuple syntax, in the SET clause;
* <p/>
* Basically, does it support syntax like
* "... SET (FIRST_NAME, LAST_NAME) = ('Steve', 'Ebersole') ...".
*
* @return True if this SQL dialect is known to support "row value constructor" syntax in the SET clause; false otherwise.
*/
protected boolean supportsRowValueConstructorSyntaxInSet() {
return supportsRowValueConstructorSyntax();
}
/**
* Is this dialect known to support what ANSI-SQL terms "row value
* constructor" syntax; sometimes called tuple syntax with quantified predicates.
* <p/>
* Basically, does it support syntax like
* "... where (FIRST_NAME, LAST_NAME) = ALL (select ...) ...".
*
* @return True if this SQL dialect is known to support "row value
* constructor" syntax with quantified predicates; false otherwise.
*/
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return true;
}
/**
* If the dialect supports {@link #supportsRowValueConstructorSyntax() row values},
* does it offer such support in IN lists as well?
* <p/>
* For example, "... where (FIRST_NAME, LAST_NAME) IN ( (?, ?), (?, ?) ) ..."
*
* @return True if this SQL dialect is known to support "row value
* constructor" syntax in the IN list; false otherwise.
*/
protected boolean supportsRowValueConstructorSyntaxInInList() {
return true;
}
/**
* If the dialect supports {@link #supportsRowValueConstructorSyntax() row values},
* does it offer such support in IN subqueries as well?
* <p/>
* For example, "... where (FIRST_NAME, LAST_NAME) IN ( select ... ) ..."
*
* @return True if this SQL dialect is known to support "row value
* constructor" syntax in the IN subqueries; false otherwise.
*/
protected boolean supportsRowValueConstructorSyntaxInInSubQuery() {
return supportsRowValueConstructorSyntaxInInList();
}
/**
* Some databases require a bit of syntactic noise when
* there are no tables in the from clause.
*
* @return the SQL equivalent to Oracle's {@code from dual}.
*/
protected String getFromDual() {
return " from (values (0)) as dual";
}
protected String getFromDualForSelectOnly() {
return "";
}
}

View File

@ -8,6 +8,7 @@
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
@ -28,7 +29,7 @@
*
* @author Steve Ebersole
*/
public interface SqlSelection {
public interface SqlSelection extends SqlAstNode {
/**
* Get the extractor that can be used to extract JDBC values for this selection
*/

View File

@ -15,7 +15,7 @@
*/
public class ComparisonPredicate implements Predicate {
private final Expression leftHandExpression;
private ComparisonOperator operator;
private final ComparisonOperator operator;
private final Expression rightHandExpression;
public ComparisonPredicate(

View File

@ -0,0 +1,90 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.query.hql;
import org.hibernate.testing.orm.domain.StandardDomainModel;
import org.hibernate.testing.orm.domain.gambit.EntityOfBasics;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
/**
* @author Christian Beikov
*/
@ServiceRegistry
@DomainModel(standardModels = StandardDomainModel.GAMBIT)
@SessionFactory
public class DistinctFromTest {
@BeforeAll
public void prepareData(SessionFactoryScope scope) {
scope.inTransaction(
em -> {
EntityOfBasics entity1 = new EntityOfBasics();
entity1.setId( 123 );
em.persist( entity1 );
EntityOfBasics entity = new EntityOfBasics();
entity.setId( 456 );
entity.setTheString( "abc" );
em.persist( entity );
}
);
}
@Test
public void testDistinctFrom(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
Assertions.assertEquals(
456,
session.createQuery(
"select e.id from EntityOfBasics e where e.theString is distinct from :param",
Integer.class
)
.setParameter( "param", null )
.list()
.get( 0 )
);
Assertions.assertEquals(
123,
session.createQuery(
"select e.id from EntityOfBasics e where e.theString is distinct from :param",
Integer.class
)
.setParameter( "param", "abc" )
.list()
.get( 0 )
);
Assertions.assertEquals(
123,
session.createQuery(
"select e.id from EntityOfBasics e where e.theString is not distinct from :param",
Integer.class
)
.setParameter( "param", null )
.list()
.get( 0 )
);
Assertions.assertEquals(
456,
session.createQuery(
"select e.id from EntityOfBasics e where e.theString is not distinct from :param",
Integer.class
)
.setParameter( "param", "abc" )
.list()
.get( 0 )
);
}
);
}
}

View File

@ -53,8 +53,8 @@ public void setUp(SessionFactoryScope scope) {
@AfterEach
public void tearDown(SessionFactoryScope scope) {
scope.inTransaction(
sesison ->
sesison.createQuery( "delete from EmbeddedIdEntity" ).executeUpdate()
session ->
session.createQuery( "delete from EmbeddedIdEntity" ).executeUpdate()
);
}

View File

@ -24,6 +24,7 @@
import org.hibernate.mapping.Formula;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.FailureExpected;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.TestForIssue;
@ -214,7 +215,7 @@ public void testComponentFormulaQuery() {
// .add( Property.forName("person.yob").between( new Integer(1999), new Integer(2002) ) )
// .list();
if ( getDialect().supportsRowValueConstructorSyntax() ) {
if ( new DialectChecks.SupportsRowValueConstructorSyntaxCheck().isMatch( getDialect() ) ) {
s.createQuery("from User u where u.person = ('gavin', :dob, 'Peachtree Rd', 'Karbarook Ave', 1974, 34, 'Peachtree Rd')")
.setParameter("dob", new Date("March 25, 1974")).list();
s.createQuery("from User where person = ('gavin', :dob, 'Peachtree Rd', 'Karbarook Ave', 1974, 34, 'Peachtree Rd')")

View File

@ -13,6 +13,7 @@
import org.hibernate.query.Query;
import org.hibernate.Session;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
@ -54,7 +55,7 @@ public void testHqlIdPropertyReferences() {
count = extractCount( s, "select count(*) from LineItem l where l.id = '456'" );
assertEquals( "LineItem by id prop (non-identifier", 1, count );
if ( getDialect().supportsRowValueConstructorSyntax() ) {
if ( new DialectChecks.SupportsRowValueConstructorSyntaxCheck().isMatch( getDialect() ) ) {
Query q = s.createQuery( "select count(*) from LineItem l where l.pk = (:order, :product)" )
.setParameter( "order", o )
.setParameter( "product", "my-product" );

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.testing;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.dialect.CockroachDialect;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.Dialect;
@ -17,6 +18,7 @@
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.OracleDialect;
import org.hibernate.dialect.PostgreSQL81Dialect;
import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.dialect.SybaseDialect;
import org.hibernate.dialect.TeradataDialect;
import org.hibernate.dialect.TimesTenDialect;
@ -132,7 +134,10 @@ public boolean isMatch(Dialect dialect) {
public static class SupportsRowValueConstructorSyntaxCheck implements DialectCheck {
public boolean isMatch(Dialect dialect) {
return dialect.supportsRowValueConstructorSyntax();
return dialect instanceof AbstractHANADialect
|| dialect instanceof CockroachDialect
|| dialect instanceof MySQLDialect
|| dialect instanceof PostgreSQLDialect;
}
}
@ -203,12 +208,6 @@ public boolean isMatch(Dialect dialect) {
}
}
public static class DoesNotSupportRowValueConstructorSyntax implements DialectCheck {
public boolean isMatch(Dialect dialect) {
return dialect.supportsRowValueConstructorSyntax() == false;
}
}
public static class DoesNotSupportFollowOnLocking implements DialectCheck {
public boolean isMatch(Dialect dialect) {
return !dialect.useFollowOnLocking( null, null );

View File

@ -137,7 +137,10 @@ public boolean apply(Dialect dialect) {
public static class SupportsRowValueConstructorSyntaxCheck implements DialectFeatureCheck {
public boolean apply(Dialect dialect) {
return dialect.supportsRowValueConstructorSyntax();
return dialect instanceof AbstractHANADialect
|| dialect instanceof CockroachDialect
|| dialect instanceof MySQLDialect
|| dialect instanceof PostgreSQLDialect;
}
}
@ -240,18 +243,22 @@ public boolean apply(Dialect dialect) {
public static class SupportsGroupByRollup implements DialectFeatureCheck {
public boolean apply(Dialect dialect) {
return dialect.getGroupBySummarizationRenderingStrategy() != GroupBySummarizationRenderingStrategy.NONE;
return dialect instanceof DB2Dialect
|| dialect instanceof OracleDialect
|| dialect instanceof PostgreSQLDialect && dialect.getVersion() >= 950
|| dialect instanceof SQLServerDialect
|| dialect instanceof DerbyDialect
|| dialect instanceof MySQLDialect
|| dialect instanceof MariaDBDialect;
}
}
public static class SupportsGroupByGroupingSets implements DialectFeatureCheck {
public boolean apply(Dialect dialect) {
return dialect.getGroupBySummarizationRenderingStrategy() != GroupBySummarizationRenderingStrategy.NONE
&& !( dialect instanceof DerbyDialect )
// MariaDB only supports ROLLUP
&& !( dialect instanceof MariaDBDialect )
// MySQL only supports ROLLUP
&& !( dialect instanceof MySQLDialect );
return dialect instanceof DB2Dialect
|| dialect instanceof OracleDialect
|| dialect instanceof PostgreSQLDialect && dialect.getVersion() >= 950
|| dialect instanceof SQLServerDialect;
}
}