cleanup wrt TableGroup rendering;

better utilize constants when rendering SQL AST
This commit is contained in:
Steve Ebersole 2019-09-23 09:01:53 -05:00
parent 0f5107ca11
commit 25152db2de
9 changed files with 250 additions and 150 deletions

View File

@ -1196,6 +1196,7 @@ public abstract class AbstractEntityPersister
lockMode,
primaryTableReference,
joins,
sqlAliasBase,
getFactory()
);
}

View File

@ -10,6 +10,16 @@ package org.hibernate.query;
* @author Steve Ebersole
*/
public enum UnaryArithmeticOperator {
UNARY_PLUS,
UNARY_MINUS
UNARY_PLUS( '+' ),
UNARY_MINUS( '-' );
private final char operatorChar;
UnaryArithmeticOperator(char operatorChar) {
this.operatorChar = operatorChar;
}
public char getOperatorChar() {
return operatorChar;
}
}

View File

@ -9,6 +9,7 @@ package org.hibernate.query.sqm.sql;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.sql.ast.SqlTreeCreationLogger;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
@ -49,7 +50,11 @@ public class SqlAliasBaseManager implements SqlAliasBaseGenerator {
@Override
public String generateNewAlias() {
synchronized ( this ) {
return stem + '_' + (aliasCount++);
final String alias = stem + '_' + ( aliasCount++ );
if ( SqlTreeCreationLogger.DEBUG_ENABLED ) {
SqlTreeCreationLogger.LOGGER.debugf( "Created new SQL alias : %s", alias );
}
return alias;
}
}
}

View File

@ -57,14 +57,38 @@ import org.hibernate.sql.results.internal.EmptySqlSelection;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators;
import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.sql.ast.spi.SqlAppender.AND_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.ASC_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.AS_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.BETWEEN_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.CASE_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.CLOSE_PARENTHESIS;
import static org.hibernate.sql.ast.spi.SqlAppender.COLLATE_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.COMA_SEPARATOR;
import static org.hibernate.sql.ast.spi.SqlAppender.DESC_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.DISTINCT_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.EMPTY_STRING_SEPARATOR;
import static org.hibernate.sql.ast.spi.SqlAppender.ELSE_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.EMPTY_STRING;
import static org.hibernate.sql.ast.spi.SqlAppender.END_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.ESCAPE_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.FROM_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.IN_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.IS_NOT_NULL_FRAGMENT;
import static org.hibernate.sql.ast.spi.SqlAppender.IS_NULL_FRAGMENT;
import static org.hibernate.sql.ast.spi.SqlAppender.JOIN_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.LIKE_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.NOT_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.NO_SEPARATOR;
import static org.hibernate.sql.ast.spi.SqlAppender.NULL_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.ON_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.OPEN_PARENTHESIS;
import static org.hibernate.sql.ast.spi.SqlAppender.ORDER_BY_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.OR_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.PARAM_MARKER;
import static org.hibernate.sql.ast.spi.SqlAppender.SELECT_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.THEN_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.WHEN_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.WHERE_KEYWORD;
/**
* @author Steve Ebersole
@ -76,13 +100,6 @@ public abstract class AbstractSqlAstWalker
private final SessionFactoryImplementor sessionFactory;
private final SqlAppender sqlAppender = this::appendSql;
// HQL : from Person p where p.name = :name or p.name = :name
// SQL : from person p where (p.fname,p.lname) = (?,?) or (p.fname,p.lname) = (?,?)
// 2 options:
// 1) each parameter in the SQL is a JdbcParameter
// 2) parameters in the SQL are "uniqued" based on their source (here SQM parameters)
// In-flight state
private final StringBuilder sqlBuffer = new StringBuilder();
private final List<JdbcParameterBinder> parameterBinders = new ArrayList<>();
@ -91,30 +108,40 @@ public abstract class AbstractSqlAstWalker
private final Stack<Clause> clauseStack = new StandardStack<>();
@SuppressWarnings("WeakerAccess")
protected AbstractSqlAstWalker(SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// for now, for tests
// for tests, for now
public String getSql() {
return sqlBuffer.toString();
}
@SuppressWarnings("WeakerAccess")
public List<JdbcParameterBinder> getParameterBinders() {
return parameterBinders;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@SuppressWarnings("unused")
protected SqlAppender getSqlAppender() {
return sqlAppender;
}
@SuppressWarnings("WeakerAccess")
protected void appendSql(String fragment) {
sqlBuffer.append( fragment );
}
@SuppressWarnings("WeakerAccess")
protected void appendSql(char fragment) {
sqlBuffer.append( fragment );
}
protected JdbcServices getJdbcServices() {
return getSessionFactory().getJdbcServices();
}
@ -128,10 +155,6 @@ public abstract class AbstractSqlAstWalker
return clauseStack;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Walking
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// QuerySpec
@ -139,14 +162,14 @@ public abstract class AbstractSqlAstWalker
@Override
public void visitQuerySpec(QuerySpec querySpec) {
if ( !querySpec.isRoot() ) {
appendSql( " (" );
appendSql( EMPTY_STRING + OPEN_PARENTHESIS );
}
visitSelectClause( querySpec.getSelectClause() );
visitFromClause( querySpec.getFromClause() );
if ( querySpec.getWhereClauseRestrictions() != null && !querySpec.getWhereClauseRestrictions().isEmpty() ) {
appendSql( " where " );
appendSql( EMPTY_STRING + WHERE_KEYWORD + EMPTY_STRING );
clauseStack.push( Clause.WHERE );
try {
@ -159,7 +182,7 @@ public abstract class AbstractSqlAstWalker
final List<SortSpecification> sortSpecifications = querySpec.getSortSpecifications();
if ( sortSpecifications != null && !sortSpecifications.isEmpty() ) {
appendSql( " order by " );
appendSql( EMPTY_STRING + ORDER_BY_KEYWORD + EMPTY_STRING );
String separator = NO_SEPARATOR;
for (SortSpecification sortSpecification : sortSpecifications ) {
@ -172,10 +195,11 @@ public abstract class AbstractSqlAstWalker
visitLimitOffsetClause( querySpec );
if ( !querySpec.isRoot() ) {
appendSql( ") " );
appendSql( COLLATE_KEYWORD + EMPTY_STRING );
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ORDER BY clause
@ -185,16 +209,16 @@ public abstract class AbstractSqlAstWalker
final String collation = sortSpecification.getCollation();
if ( collation != null ) {
appendSql( " collate " );
appendSql( EMPTY_STRING + COLLATE_KEYWORD + EMPTY_STRING );
appendSql( collation );
}
final SortOrder sortOrder = sortSpecification.getSortOrder();
if ( sortOrder == SortOrder.ASCENDING ) {
appendSql( " asc" );
appendSql( EMPTY_STRING + ASC_KEYWORD );
}
else if ( sortOrder == SortOrder.DESCENDING ) {
appendSql( " desc" );
appendSql( EMPTY_STRING + DESC_KEYWORD );
}
// TODO: null precedence handling
@ -206,18 +230,29 @@ public abstract class AbstractSqlAstWalker
@Override
public void visitLimitOffsetClause(QuerySpec querySpec) {
if ( querySpec.getOffsetClauseExpression() != null ) {
appendSql( " offset " );
querySpec.getOffsetClauseExpression().accept( this );
appendSql( " rows" );
renderOffset( querySpec );
}
if ( querySpec.getLimitClauseExpression() != null ) {
appendSql( " fetch first " );
querySpec.getLimitClauseExpression().accept( this );
appendSql( " rows only" );
renderLimit( querySpec );
}
}
@SuppressWarnings("WeakerAccess")
protected void renderOffset(QuerySpec querySpec) {
appendSql( " offset " );
querySpec.getOffsetClauseExpression().accept( this );
appendSql( " rows" );
}
@SuppressWarnings("WeakerAccess")
protected void renderLimit(QuerySpec querySpec) {
appendSql( " fetch first " );
querySpec.getLimitClauseExpression().accept( this );
appendSql( " rows only" );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// SELECT clause
@ -226,9 +261,9 @@ public abstract class AbstractSqlAstWalker
clauseStack.push( Clause.SELECT );
try {
appendSql( SELECT_KEYWORD );
appendSql( SELECT_KEYWORD + EMPTY_STRING );
if ( selectClause.isDistinct() ) {
appendSql( DISTINCT_KEYWORD );
appendSql( DISTINCT_KEYWORD + EMPTY_STRING );
}
String separator = NO_SEPARATOR;
@ -251,31 +286,79 @@ public abstract class AbstractSqlAstWalker
// do nothing... this is handled #visitSelectClause
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// FROM clause
@Override
public void visitFromClause(FromClause fromClause) {
appendSql( FROM_KEYWORD );
appendSql( EMPTY_STRING + FROM_KEYWORD + EMPTY_STRING );
String separator = NO_SEPARATOR;
for ( TableGroup root : fromClause.getRoots() ) {
appendSql( separator );
processRoot( root );
renderTableGroup( root );
separator = COMA_SEPARATOR;
}
}
protected void processRoot(TableGroup root) {
root.render( sqlAppender, this );
@SuppressWarnings("WeakerAccess")
protected void renderTableGroup(TableGroup tableGroup) {
// NOTE : commented out blocks render the TableGroup as a CTE
processTableGroupJoins( root );
// if ( tableGroup.getGroupAlias() != null ) {
// sqlAppender.appendSql( OPEN_PARENTHESIS );
// }
renderTableReference( tableGroup.getPrimaryTableReference() );
renderTableReferenceJoins( tableGroup );
// if ( tableGroup.getGroupAlias() != null ) {
// sqlAppender.appendSql( CLOSE_PARENTHESIS );
// sqlAppender.appendSql( AS_KEYWORD );
// sqlAppender.appendSql( tableGroup.getGroupAlias() );
// }
processTableGroupJoins( tableGroup );
}
@SuppressWarnings("WeakerAccess")
protected void renderTableReference(TableReference tableReference) {
sqlAppender.appendSql( tableReference.getTableExpression() );
final String identificationVariable = tableReference.getIdentificationVariable();
if ( identificationVariable != null ) {
sqlAppender.appendSql( EMPTY_STRING + AS_KEYWORD + EMPTY_STRING + identificationVariable );
}
}
@SuppressWarnings("WeakerAccess")
protected void renderTableReferenceJoins(TableGroup tableGroup) {
final List<TableReferenceJoin> joins = tableGroup.getTableReferenceJoins();
if ( joins == null || joins.isEmpty() ) {
return;
}
for ( TableReferenceJoin tableJoin : joins ) {
sqlAppender.appendSql( EMPTY_STRING );
sqlAppender.appendSql( tableJoin.getJoinType().getText() );
sqlAppender.appendSql( EMPTY_STRING + JOIN_KEYWORD + EMPTY_STRING);
renderTableReference( tableJoin.getJoinedTableReference() );
if ( tableJoin.getJoinPredicate() != null && !tableJoin.getJoinPredicate().isEmpty() ) {
sqlAppender.appendSql( EMPTY_STRING + ON_KEYWORD + EMPTY_STRING );
tableJoin.getJoinPredicate().accept( this );
}
}
}
@SuppressWarnings("WeakerAccess")
protected void processTableGroupJoins(TableGroup source) {
source.visitTableGroupJoins( this::processTableGroupJoin );
}
@SuppressWarnings("WeakerAccess")
protected void processTableGroupJoin(TableGroupJoin tableGroupJoin) {
final TableGroup joinedGroup = tableGroupJoin.getJoinedGroup();
@ -285,16 +368,16 @@ public abstract class AbstractSqlAstWalker
// todo (6.0) : join predicates?
}
else {
appendSql( EMPTY_STRING_SEPARATOR );
appendSql( EMPTY_STRING );
appendSql( tableGroupJoin.getJoinType().getText() );
appendSql( " join (" );
joinedGroup.render( sqlAppender, this );
appendSql( CLOSE_PARENTHESIS );
appendSql( EMPTY_STRING + JOIN_KEYWORD + EMPTY_STRING);
renderTableGroup( joinedGroup );
clauseStack.push( Clause.WHERE );
try {
if ( tableGroupJoin.getPredicate() != null && !tableGroupJoin.getPredicate().isEmpty() ) {
appendSql( " on " );
appendSql( EMPTY_STRING + ON_KEYWORD + EMPTY_STRING );
tableGroupJoin.getPredicate().accept( this );
}
}
@ -302,8 +385,6 @@ public abstract class AbstractSqlAstWalker
clauseStack.pop();
}
}
processTableGroupJoins( joinedGroup );
}
@Override
@ -334,45 +415,6 @@ public abstract class AbstractSqlAstWalker
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Expressions
// @Override
// public void visitSingularAttributeReference(SingularAttributeReference attributeExpression) {
// // todo : this needs to operate differently in different contexts (mainly for associations)
// // e.g...
// // 1) In the select clause we should render the complete column bindings for associations
// // 2) In join predicates
// renderColumnBindings( attributeExpression.getColumnReferences() );
// }
//
// private void renderColumnBindings(List<ColumnReference> columnBindings) {
// if ( currentlyInPredicate && columnBindings.size() > 1 ) {
// appendSql( "(" );
// }
//
// for ( ColumnReference columnBinding : columnBindings ) {
// appendSql( columnBinding.getColumn().render( columnBinding.getIdentificationVariable() ) );
// }
//
// if ( currentlyInPredicate && columnBindings.size() > 1 ) {
// appendSql( ")" );
// }
// }
//
// @Override
// public void visitEntityExpression(EntityReference entityExpression) {
// renderColumnBindings( entityExpression.getColumnReferences() );
// }
//
// @Override
// public void visitPluralAttributeElement(PluralAttributeElementReference elementExpression) {
// renderColumnBindings( elementExpression.getColumnReferences() );
//
// }
//
// @Override
// public void visitPluralAttributeIndex(PluralAttributeIndexReference indexExpression) {
// renderColumnBindings( indexExpression.getColumnReferences() );
// }
@Override
public void visitColumnReference(ColumnReference columnReference) {
appendSql( columnReference.renderSqlFragment( getSessionFactory() ) );
@ -380,7 +422,7 @@ public abstract class AbstractSqlAstWalker
@Override
public void visitParameter(JdbcParameter jdbcParameter) {
appendSql( "?" );
appendSql( PARAM_MARKER );
parameterBinders.add( jdbcParameter.getParameterBinder() );
jdbcParameters.addParameter( jdbcParameter );
@ -473,7 +515,7 @@ public abstract class AbstractSqlAstWalker
// public void visitCastFunction(CastFunction function) {
// sqlAppender.appendSql( "cast(" );
// function.getExpressionToCast().accept( this );
// sqlAppender.appendSql( " as " );
// sqlAppender.appendSql( AS_KEYWORD );
// sqlAppender.appendSql( determineCastTargetTypeSqlExpression( function ) );
// sqlAppender.appendSql( CLOSE_PARENTHESIS );
// }
@ -722,33 +764,33 @@ public abstract class AbstractSqlAstWalker
@Override
public void visitCaseSearchedExpression(CaseSearchedExpression caseSearchedExpression) {
appendSql( "case " );
appendSql( CASE_KEYWORD + EMPTY_STRING );
for ( CaseSearchedExpression.WhenFragment whenFragment : caseSearchedExpression.getWhenFragments() ) {
appendSql( " when " );
appendSql( EMPTY_STRING + WHEN_KEYWORD + EMPTY_STRING );
whenFragment.getPredicate().accept( this );
appendSql( " then " );
appendSql( EMPTY_STRING + THEN_KEYWORD + EMPTY_STRING );
whenFragment.getResult().accept( this );
}
appendSql( " else " );
appendSql( ELSE_KEYWORD );
caseSearchedExpression.getOtherwise().accept( this );
appendSql( " end" );
appendSql( EMPTY_STRING + END_KEYWORD );
}
@Override
public void visitCaseSimpleExpression(CaseSimpleExpression caseSimpleExpression) {
appendSql( "case " );
appendSql( CASE_KEYWORD + EMPTY_STRING );
caseSimpleExpression.getFixture().accept( this );
for ( CaseSimpleExpression.WhenFragment whenFragment : caseSimpleExpression.getWhenFragments() ) {
appendSql( " when " );
appendSql( EMPTY_STRING + WHEN_KEYWORD + EMPTY_STRING );
whenFragment.getCheckValue().accept( this );
appendSql( " then " );
appendSql( EMPTY_STRING + THEN_KEYWORD + EMPTY_STRING );
whenFragment.getResult().accept( this );
}
appendSql( " else " );
appendSql( EMPTY_STRING + ELSE_KEYWORD + EMPTY_STRING );
caseSimpleExpression.getOtherwise().accept( this );
appendSql( " end" );
appendSql( EMPTY_STRING + END_KEYWORD );
}
@ -814,7 +856,7 @@ public abstract class AbstractSqlAstWalker
private void renderAsLiteral(QueryLiteral<?> queryLiteral) {
if ( queryLiteral.getValue() == null ) {
// todo : not sure we allow this "higher up"
appendSql( "NULL" );
appendSql( SqlAppender.NULL_KEYWORD );
}
else {
assert queryLiteral.getExpressionType().getJdbcTypeCount( getTypeConfiguration() ) == 1;
@ -837,11 +879,12 @@ public abstract class AbstractSqlAstWalker
@Override
public void visitUnaryOperationExpression(UnaryOperation unaryOperationExpression) {
if ( unaryOperationExpression.getOperator() == UnaryArithmeticOperator.UNARY_PLUS ) {
appendSql( "+" );
appendSql( UnaryArithmeticOperator.UNARY_PLUS.getOperatorChar() );
}
else {
appendSql( "-" );
appendSql( UnaryArithmeticOperator.UNARY_MINUS.getOperatorChar() );
}
unaryOperationExpression.getOperand().accept( this );
}
@ -869,11 +912,11 @@ public abstract class AbstractSqlAstWalker
public void visitBetweenPredicate(BetweenPredicate betweenPredicate) {
betweenPredicate.getExpression().accept( this );
if ( betweenPredicate.isNegated() ) {
appendSql( " not" );
appendSql( EMPTY_STRING + NOT_KEYWORD );
}
appendSql( " between " );
appendSql( EMPTY_STRING + BETWEEN_KEYWORD + EMPTY_STRING );
betweenPredicate.getLowerBound().accept( this );
appendSql( " and " );
appendSql( EMPTY_STRING + AND_KEYWORD + EMPTY_STRING );
betweenPredicate.getUpperBound().accept( this );
}
@ -897,11 +940,11 @@ public abstract class AbstractSqlAstWalker
public void visitInListPredicate(InListPredicate inListPredicate) {
inListPredicate.getTestExpression().accept( this );
if ( inListPredicate.isNegated() ) {
appendSql( " not" );
appendSql( NOT_KEYWORD );
}
appendSql( " in (" );
appendSql( IN_KEYWORD + ' ' + OPEN_PARENTHESIS );
if ( inListPredicate.getListExpressions().isEmpty() ) {
appendSql( "null" );
appendSql( NULL_KEYWORD );
}
else {
String separator = NO_SEPARATOR;
@ -918,9 +961,9 @@ public abstract class AbstractSqlAstWalker
public void visitInSubQueryPredicate(InSubQueryPredicate inSubQueryPredicate) {
inSubQueryPredicate.getTestExpression().accept( this );
if ( inSubQueryPredicate.isNegated() ) {
appendSql( " not" );
appendSql( ' ' + NOT_KEYWORD );
}
appendSql( " in " );
appendSql( ' ' + IN_KEYWORD + ' ' );
visitQuerySpec( inSubQueryPredicate.getSubQuery() );
}
@ -934,7 +977,9 @@ public abstract class AbstractSqlAstWalker
for ( Predicate predicate : junction.getPredicates() ) {
appendSql( separator );
predicate.accept( this );
separator = junction.getNature() == Junction.Nature.CONJUNCTION ? " and " : " or ";
separator = junction.getNature() == Junction.Nature.CONJUNCTION
? EMPTY_STRING + AND_KEYWORD + EMPTY_STRING
: EMPTY_STRING + OR_KEYWORD + EMPTY_STRING;
}
}
@ -942,12 +987,12 @@ public abstract class AbstractSqlAstWalker
public void visitLikePredicate(LikePredicate likePredicate) {
likePredicate.getMatchExpression().accept( this );
if ( likePredicate.isNegated() ) {
appendSql( " not" );
appendSql( EMPTY_STRING + NOT_KEYWORD );
}
appendSql( " like " );
appendSql( EMPTY_STRING + LIKE_KEYWORD + EMPTY_STRING );
likePredicate.getPattern().accept( this );
if ( likePredicate.getEscapeCharacter() != null ) {
appendSql( " escape " );
appendSql( EMPTY_STRING + ESCAPE_KEYWORD + EMPTY_STRING );
likePredicate.getEscapeCharacter().accept( this );
}
}
@ -958,7 +1003,7 @@ public abstract class AbstractSqlAstWalker
return;
}
appendSql( "not(" );
appendSql( NOT_KEYWORD + EMPTY_STRING + OPEN_PARENTHESIS );
negatedPredicate.getPredicate().accept( this );
appendSql( CLOSE_PARENTHESIS );
}
@ -967,10 +1012,10 @@ public abstract class AbstractSqlAstWalker
public void visitNullnessPredicate(NullnessPredicate nullnessPredicate) {
nullnessPredicate.getExpression().accept( this );
if ( nullnessPredicate.isNegated() ) {
appendSql( " is not null" );
appendSql( IS_NOT_NULL_FRAGMENT );
}
else {
appendSql( " is null" );
appendSql( IS_NULL_FRAGMENT );
}
}

View File

@ -13,14 +13,53 @@ package org.hibernate.sql.ast.spi;
*/
public interface SqlAppender {
// todo (6.0) : add all the others sql keywords
String SELECT_KEYWORD = "select ";
String DISTINCT_KEYWORD = "distinct ";
String COMA_SEPARATOR = ", ";
String NO_SEPARATOR = "";
String EMPTY_STRING = " ";
String OPEN_PARENTHESIS = "(";
String CLOSE_PARENTHESIS = ")";
String NO_SEPARATOR = "";
String EMPTY_STRING_SEPARATOR = " ";
String FROM_KEYWORD = " from ";
String SELECT_KEYWORD = "select";
String DISTINCT_KEYWORD = "distinct";
String ORDER_BY_KEYWORD = "order by";
String COLLATE_KEYWORD = "collate";
String FROM_KEYWORD = "from";
String JOIN_KEYWORD = "join";
String AS_KEYWORD = "as";
String ON_KEYWORD = "on";
String WHERE_KEYWORD = "where";
String PARAM_MARKER = "?";
String NOT_KEYWORD = "not";
String IS_KEYWORD = "is";
String NULL_KEYWORD = "null";
String IS_NULL_FRAGMENT = IS_KEYWORD + EMPTY_STRING + NULL_KEYWORD;
String IS_NOT_NULL_FRAGMENT = IS_KEYWORD + EMPTY_STRING + NOT_KEYWORD + EMPTY_STRING + NULL_KEYWORD;
String AND_KEYWORD = "and";
String OR_KEYWORD = "or";
String LIKE_KEYWORD = "like";
String ESCAPE_KEYWORD = "escape";
String BETWEEN_KEYWORD = "between";
String IN_KEYWORD = "in";
String CASE_KEYWORD = "case";
String WHEN_KEYWORD = "when";
String THEN_KEYWORD = "then";
String ELSE_KEYWORD = "else";
String END_KEYWORD = "end";
String ASC_KEYWORD = "asc";
String DESC_KEYWORD = "desc";
/**
* Add the passed fragment into the in-flight buffer

View File

@ -14,6 +14,7 @@ import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.SqlAstWalker;
@ -25,6 +26,7 @@ public abstract class AbstractTableGroup extends AbstractColumnReferenceQualifie
private final NavigablePath navigablePath;
private final TableGroupProducer producer;
private final LockMode lockMode;
private final SqlAliasBase sqlAliasBase;
private Set<TableGroupJoin> tableGroupJoins;
private boolean isInnerJoinPossible;
@ -35,8 +37,9 @@ public abstract class AbstractTableGroup extends AbstractColumnReferenceQualifie
NavigablePath navigablePath,
TableGroupProducer producer,
LockMode lockMode,
SqlAliasBase sqlAliasBase,
SessionFactoryImplementor sessionFactory) {
this( navigablePath, producer, lockMode, false, sessionFactory );
this( navigablePath, producer, lockMode, sqlAliasBase, false, sessionFactory );
}
@SuppressWarnings("WeakerAccess")
@ -44,21 +47,32 @@ public abstract class AbstractTableGroup extends AbstractColumnReferenceQualifie
NavigablePath navigablePath,
TableGroupProducer producer,
LockMode lockMode,
SqlAliasBase sqlAliasBase,
boolean isInnerJoinPossible,
SessionFactoryImplementor sessionFactory) {
super();
this.navigablePath = navigablePath;
this.producer = producer;
this.lockMode = lockMode;
this.sqlAliasBase = sqlAliasBase;
this.isInnerJoinPossible = isInnerJoinPossible;
this.sessionFactory = sessionFactory;
}
public SqlAliasBase getSqlAliasBase() {
return sqlAliasBase;
}
@Override
public NavigablePath getNavigablePath() {
return navigablePath;
}
@Override
public String getGroupAlias() {
return sqlAliasBase.getAliasStem();
}
@Override
public TableGroupProducer getModelPart() {
return producer;

View File

@ -17,8 +17,6 @@ import org.hibernate.LockMode;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.SqlAstWalker;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
/**
@ -46,6 +44,12 @@ public class CompositeTableGroup implements VirtualTableGroup {
return navigablePath;
}
@Override
public String getGroupAlias() {
// none, although we could also delegate to the underlyingTableGroup's group-alias
return null;
}
@Override
public ModelPartContainer getModelPart() {
return compositionMapping;
@ -91,11 +95,6 @@ public class CompositeTableGroup implements VirtualTableGroup {
}
}
@Override
public void render(SqlAppender sqlAppender, SqlAstWalker walker) {
walker.visitTableGroup( this );
}
@Override
public void applyAffectedTableNames(Consumer<String> nameCollector) {
underlyingTableGroup.applyAffectedTableNames( nameCollector );

View File

@ -12,8 +12,7 @@ import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlAliasBase;
/**
* @author Steve Ebersole
@ -28,8 +27,9 @@ public class StandardTableGroup extends AbstractTableGroup {
LockMode lockMode,
TableReference primaryTableReference,
List<TableReferenceJoin> tableJoins,
SqlAliasBase sqlAliasBase,
SessionFactoryImplementor sessionFactory) {
super( navigablePath, tableGroupProducer, lockMode, sessionFactory );
super( navigablePath, tableGroupProducer, lockMode, sqlAliasBase, sessionFactory );
this.primaryTableReference = primaryTableReference;
this.tableJoins = tableJoins;
}
@ -39,26 +39,9 @@ public class StandardTableGroup extends AbstractTableGroup {
return (RootTableGroupProducer) super.getModelPart();
}
@Override
public void render(SqlAppender sqlAppender, SqlAstWalker walker) {
renderTableReference( primaryTableReference, sqlAppender, walker );
if ( tableJoins != null ) {
for ( TableReferenceJoin tableJoin : tableJoins ) {
sqlAppender.appendSql( " " );
sqlAppender.appendSql( tableJoin.getJoinType().getText() );
sqlAppender.appendSql( " join " );
renderTableReference( tableJoin.getJoinedTableReference(), sqlAppender, walker );
if ( tableJoin.getJoinPredicate() != null && !tableJoin.getJoinPredicate().isEmpty() ) {
sqlAppender.appendSql( " on " );
tableJoin.getJoinPredicate().accept( walker );
}
}
}
}
@Override
public void applyAffectedTableNames(Consumer<String> nameCollector) {
// todo (6.0) : if we implement dynamic TableReference creation, this still needs to return the expressions for all mapped tables not just the ones with a TableReference at this time
nameCollector.accept( getPrimaryTableReference().getTableExpression() );
for ( TableReferenceJoin tableReferenceJoin : tableJoins ) {
nameCollector.accept( tableReferenceJoin.getJoinedTableReference().getTableExpression() );

View File

@ -14,6 +14,7 @@ import org.hibernate.LockMode;
import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.SqlAstWalker;
import org.hibernate.sql.ast.tree.SqlAstNode;
@ -27,10 +28,15 @@ import org.hibernate.sql.results.spi.DomainResultCreationState;
*
* @author Steve Ebersole
*/
public interface TableGroup
extends SqlAstNode, ColumnReferenceQualifier, DomainResultProducer {
public interface TableGroup extends SqlAstNode, ColumnReferenceQualifier, DomainResultProducer {
NavigablePath getNavigablePath();
/**
* If we want to use CTE for TableGroup rendering we will need to know the
* alias we can use for the group
*/
String getGroupAlias();
ModelPartContainer getModelPart();
LockMode getLockMode();
@ -45,8 +51,6 @@ public interface TableGroup
void visitTableGroupJoins(Consumer<TableGroupJoin> consumer);
void render(SqlAppender sqlAppender, SqlAstWalker walker);
void applyAffectedTableNames(Consumer<String> nameCollector);
TableReference getPrimaryTableReference();