org.hibernate.community.dialect.SybaseAnywhereSqlAstTranslator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hibernate-community-dialects Show documentation
Show all versions of hibernate-community-dialects Show documentation
Hibernate's community supported dialects
The newest version!
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.community.dialect;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.sqm.ComparisonOperator;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
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.BinaryArithmeticExpression;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
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.from.NamedTableReference;
import org.hibernate.sql.ast.tree.from.UnionTableReference;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SelectClause;
import org.hibernate.sql.exec.spi.JdbcOperation;
/**
* A SQL AST translator for Sybase Anywhere.
*
* @author Christian Beikov
*/
public class SybaseAnywhereSqlAstTranslator extends AbstractSqlAstTranslator {
private static final String UNION_ALL = " union all ";
public SybaseAnywhereSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) {
super( sessionFactory, statement );
}
// Sybase Anywhere does not allow CASE expressions where all result arms contain plain parameters.
// At least one result arm must provide some type context for inference,
// so we cast the first result arm if we encounter this condition
@Override
protected void visitAnsiCaseSearchedExpression(
CaseSearchedExpression caseSearchedExpression,
Consumer resultRenderer) {
if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSearchedExpression ) ) {
final List whenFragments = caseSearchedExpression.getWhenFragments();
final Expression firstResult = whenFragments.get( 0 ).getResult();
super.visitAnsiCaseSearchedExpression(
caseSearchedExpression,
e -> {
if ( e == firstResult ) {
renderCasted( e );
}
else {
resultRenderer.accept( e );
}
}
);
}
else {
super.visitAnsiCaseSearchedExpression( caseSearchedExpression, resultRenderer );
}
}
@Override
protected void visitAnsiCaseSimpleExpression(
CaseSimpleExpression caseSimpleExpression,
Consumer resultRenderer) {
if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSimpleExpression ) ) {
final List whenFragments = caseSimpleExpression.getWhenFragments();
final Expression firstResult = whenFragments.get( 0 ).getResult();
super.visitAnsiCaseSimpleExpression(
caseSimpleExpression,
e -> {
if ( e == firstResult ) {
renderCasted( e );
}
else {
resultRenderer.accept( e );
}
}
);
}
else {
super.visitAnsiCaseSimpleExpression( caseSimpleExpression, resultRenderer );
}
}
@Override
protected boolean renderNamedTableReference(NamedTableReference tableReference, LockMode lockMode) {
if ( getDialect().getVersion().isBefore( 10 ) ) {
final String tableExpression = tableReference.getTableExpression();
if ( tableReference instanceof UnionTableReference && lockMode != LockMode.NONE && tableExpression.charAt( 0 ) == '(' ) {
// SQL Server requires to push down the lock hint to the actual table names
int searchIndex = 0;
int unionIndex;
while ( ( unionIndex = tableExpression.indexOf( UNION_ALL, searchIndex ) ) != -1 ) {
append( tableExpression, searchIndex, unionIndex );
renderLockHint( lockMode );
appendSql( UNION_ALL );
searchIndex = unionIndex + UNION_ALL.length();
}
append( tableExpression, searchIndex, tableExpression.length() - 1 );
renderLockHint( lockMode );
appendSql( " )" );
registerAffectedTable( tableReference );
renderTableReferenceIdentificationVariable( tableReference );
}
else {
super.renderNamedTableReference( tableReference, lockMode );
renderLockHint( lockMode );
}
// Just always return true because SQL Server doesn't support the FOR UPDATE clause
return true;
}
super.renderNamedTableReference( tableReference, lockMode );
return false;
}
private void renderLockHint(LockMode lockMode) {
if ( LockMode.READ.lessThan( lockMode ) ) {
appendSql( " holdlock" );
}
}
@Override
protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) {
if ( getDialect().getVersion().isBefore( 10 ) ) {
return;
}
super.renderForUpdateClause( querySpec, forUpdateClause );
}
@Override
protected boolean needsRowsToSkip() {
return getDialect().getVersion().isBefore( 9 );
}
@Override
protected void renderFetchPlusOffsetExpression(
Expression fetchClauseExpression,
Expression offsetClauseExpression,
int offset) {
renderFetchPlusOffsetExpressionAsSingleParameter( fetchClauseExpression, offsetClauseExpression, offset );
}
@Override
protected void visitSqlSelections(SelectClause selectClause) {
if ( getDialect().getVersion().isBefore( 9 ) ) {
renderTopClause( (QuerySpec) getQueryPartStack().getCurrent(), true, true );
}
else {
renderTopStartAtClause( (QuerySpec) getQueryPartStack().getCurrent() );
}
super.visitSqlSelections( selectClause );
}
@Override
protected void renderTopClause(QuerySpec querySpec, boolean addOffset, boolean needsParenthesis) {
assertRowsOnlyFetchClauseType( querySpec );
super.renderTopClause( querySpec, addOffset, needsParenthesis );
}
@Override
protected void renderTopStartAtClause(QuerySpec querySpec) {
assertRowsOnlyFetchClauseType( querySpec );
super.renderTopStartAtClause( querySpec );
}
@Override
public void visitOffsetFetchClause(QueryPart queryPart) {
// Sybase Anywhere only supports the TOP clause
if ( getDialect().getVersion().isBefore( 9 ) && !queryPart.isRoot()
&& useOffsetFetchClause( queryPart ) && queryPart.getOffsetClauseExpression() != null ) {
throw new IllegalArgumentException( "Can't emulate offset clause in subquery" );
}
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonEmulateIntersect( lhs, operator, rhs );
}
@Override
protected void renderSelectTupleComparison(
List lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateSelectTupleComparison( 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
public void visitBinaryArithmeticExpression(BinaryArithmeticExpression arithmeticExpression) {
appendSql( OPEN_PARENTHESIS );
visitArithmeticOperand( arithmeticExpression.getLeftHandOperand() );
appendSql( arithmeticExpression.getOperator().getOperatorSqlTextString() );
visitArithmeticOperand( arithmeticExpression.getRightHandOperand() );
appendSql( CLOSE_PARENTHESIS );
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
}