use of org.hibernate.hql.internal.ast.tree.QueryNode in project hibernate-orm by hibernate.
the class QueryTranslatorImpl method list.
@Override
public List list(SharedSessionContractImplementor session, QueryParameters queryParameters) throws HibernateException {
// Delegate to the QueryLoader...
errorIfDML();
final QueryNode query = (QueryNode) sqlAst;
final boolean hasLimit = queryParameters.getRowSelection() != null && queryParameters.getRowSelection().definesLimits();
final boolean needsDistincting = (query.getSelectClause().isDistinct() || hasLimit) && containsCollectionFetches();
QueryParameters queryParametersToUse;
if (hasLimit && containsCollectionFetches()) {
LOG.firstOrMaxResultsSpecifiedWithCollectionFetch();
RowSelection selection = new RowSelection();
selection.setFetchSize(queryParameters.getRowSelection().getFetchSize());
selection.setTimeout(queryParameters.getRowSelection().getTimeout());
queryParametersToUse = queryParameters.createCopyUsing(selection);
} else {
queryParametersToUse = queryParameters;
}
List results = queryLoader.list(session, queryParametersToUse);
if (needsDistincting) {
int includedCount = -1;
// NOTE : firstRow is zero-based
int first = !hasLimit || queryParameters.getRowSelection().getFirstRow() == null ? 0 : queryParameters.getRowSelection().getFirstRow();
int max = !hasLimit || queryParameters.getRowSelection().getMaxRows() == null ? -1 : queryParameters.getRowSelection().getMaxRows();
List tmp = new ArrayList();
IdentitySet distinction = new IdentitySet();
for (final Object result : results) {
if (!distinction.add(result)) {
continue;
}
includedCount++;
if (includedCount < first) {
continue;
}
tmp.add(result);
// NOTE : ( max - 1 ) because first is zero-based while max is not...
if (max >= 0 && (includedCount - first) >= (max - 1)) {
break;
}
}
results = tmp;
}
return results;
}
use of org.hibernate.hql.internal.ast.tree.QueryNode in project hibernate-orm by hibernate.
the class QueryTranslatorImpl method validateScrollability.
@Override
public void validateScrollability() throws HibernateException {
// Impl Note: allows multiple collection fetches as long as the
// entire fecthed graph still "points back" to a single
// root entity for return
errorIfDML();
final QueryNode query = (QueryNode) sqlAst;
// If there are no collection fetches, then no further checks are needed
List collectionFetches = query.getFromClause().getCollectionFetches();
if (collectionFetches.isEmpty()) {
return;
}
// A shallow query is ok (although technically there should be no fetching here...)
if (isShallowQuery()) {
return;
}
// Make sure that there is only a single root entity in the return (no tuples)
if (getReturnTypes().length > 1) {
throw new HibernateException("cannot scroll with collection fetches and returned tuples");
}
FromElement owner = null;
for (Object o : query.getSelectClause().getFromElementsForLoad()) {
// should be the first, but just to be safe...
final FromElement fromElement = (FromElement) o;
if (fromElement.getOrigin() == null) {
owner = fromElement;
break;
}
}
if (owner == null) {
throw new HibernateException("unable to locate collection fetch(es) owner for scrollability checks");
}
// This is not strictly true. We actually just need to make sure that
// it is ordered by root-entity PK and that that order-by comes beforeQuery
// any non-root-entity ordering...
AST primaryOrdering = query.getOrderByClause().getFirstChild();
if (primaryOrdering != null) {
// TODO : this is a bit dodgy, come up with a better way to check this (plus see above comment)
String[] idColNames = owner.getQueryable().getIdentifierColumnNames();
String expectedPrimaryOrderSeq = StringHelper.join(", ", StringHelper.qualify(owner.getTableAlias(), idColNames));
if (!primaryOrdering.getText().startsWith(expectedPrimaryOrderSeq)) {
throw new HibernateException("cannot scroll results with collection fetches which are not ordered primarily by the root entity's PK");
}
}
}
use of org.hibernate.hql.internal.ast.tree.QueryNode in project hibernate-orm by hibernate.
the class HqlSqlWalker method processQuery.
@Override
protected void processQuery(AST select, AST query) throws SemanticException {
if (LOG.isDebugEnabled()) {
LOG.debugf("processQuery() : %s", query.toStringTree());
}
try {
QueryNode qn = (QueryNode) query;
// Was there an explicit select expression?
boolean explicitSelect = select != null && select.getNumberOfChildren() > 0;
// Add in the EntityGraph attribute nodes.
if (queryTranslatorImpl.getEntityGraphQueryHint() != null) {
final boolean oldInEntityGraph = inEntityGraph;
try {
inEntityGraph = true;
qn.getFromClause().getFromElements().addAll(queryTranslatorImpl.getEntityGraphQueryHint().toFromElements(qn.getFromClause(), this));
} finally {
inEntityGraph = oldInEntityGraph;
}
}
if (!explicitSelect) {
// No explicit select expression; render the id and properties
// projection lists for every persister in the from clause into
// a single 'token node'.
//TODO: the only reason we need this stuff now is collection filters,
// we should get rid of derived select clause completely!
createSelectClauseFromFromClause(qn);
} else {
// Use the explicitly declared select expression; determine the
// return types indicated by each select token
useSelectClause(select);
}
// After that, process the JOINs.
// Invoke a delegate to do the work, as this is farily complex.
JoinProcessor joinProcessor = new JoinProcessor(this);
joinProcessor.processJoins(qn);
// Attach any mapping-defined "ORDER BY" fragments
Iterator itr = qn.getFromClause().getProjectionList().iterator();
while (itr.hasNext()) {
final FromElement fromElement = (FromElement) itr.next();
// if ( fromElement.isFetch() && fromElement.isCollectionJoin() ) {
if (fromElement.isFetch() && fromElement.getQueryableCollection() != null) {
// the query's order-by
if (fromElement.getQueryableCollection().hasOrdering()) {
String orderByFragment = fromElement.getQueryableCollection().getSQLOrderByString(fromElement.getCollectionTableAlias());
qn.getOrderByClause().addOrderFragment(orderByFragment);
}
if (fromElement.getQueryableCollection().hasManyToManyOrdering()) {
String orderByFragment = fromElement.getQueryableCollection().getManyToManyOrderByString(fromElement.getTableAlias());
qn.getOrderByClause().addOrderFragment(orderByFragment);
}
}
}
} finally {
popFromClause();
}
}
use of org.hibernate.hql.internal.ast.tree.QueryNode in project hibernate-orm by hibernate.
the class HQLTest method assertInExist.
private void assertInExist(String message, boolean expected, QueryTranslatorImpl translator) {
AST ast = translator.getSqlAST().getWalker().getAST();
QueryNode queryNode = (QueryNode) ast;
AST whereNode = ASTUtil.findTypeInChildren(queryNode, HqlTokenTypes.WHERE);
AST inNode = whereNode.getFirstChild();
assertEquals(message, expected, inNode != null && inNode.getType() == HqlTokenTypes.IN);
}
use of org.hibernate.hql.internal.ast.tree.QueryNode in project hibernate-orm by hibernate.
the class QueryLoader method applyLocks.
@Override
protected String applyLocks(String sql, QueryParameters parameters, Dialect dialect, List<AfterLoadAction> afterLoadActions) throws QueryException {
// can't cache this stuff either (per-invocation)
// we are given a map of user-alias -> lock mode
// create a new map of sql-alias -> lock mode
final LockOptions lockOptions = parameters.getLockOptions();
if (lockOptions == null || (lockOptions.getLockMode() == LockMode.NONE && lockOptions.getAliasLockCount() == 0)) {
return sql;
}
// some dialects wont allow locking with paging...
if (shouldUseFollowOnLocking(parameters, dialect, afterLoadActions)) {
return sql;
}
// there are other conditions we might want to add here, such as checking the result types etc
// but those are better served afterQuery we have redone the SQL generation to use ASTs.
// we need both the set of locks and the columns to reference in locks
// as the ultimate output of this section...
final LockOptions locks = new LockOptions(lockOptions.getLockMode());
final Map<String, String[]> keyColumnNames = dialect.forUpdateOfColumns() ? new HashMap<>() : null;
locks.setScope(lockOptions.getScope());
locks.setTimeOut(lockOptions.getTimeOut());
for (Map.Entry<String, String> entry : sqlAliasByEntityAlias.entrySet()) {
final String userAlias = entry.getKey();
final String drivingSqlAlias = entry.getValue();
if (drivingSqlAlias == null) {
throw new IllegalArgumentException("could not locate alias to apply lock mode : " + userAlias);
}
// at this point we have (drivingSqlAlias) the SQL alias of the driving table
// corresponding to the given user alias. However, the driving table is not
// (necessarily) the table against which we want to apply locks. Mainly,
// the exception case here is joined-subclass hierarchies where we instead
// want to apply the lock against the root table (for all other strategies,
// it just happens that driving and root are the same).
final QueryNode select = (QueryNode) queryTranslator.getSqlAST();
final Lockable drivingPersister = (Lockable) select.getFromClause().findFromElementByUserOrSqlAlias(userAlias, drivingSqlAlias).getQueryable();
final String sqlAlias = drivingPersister.getRootTableAlias(drivingSqlAlias);
final LockMode effectiveLockMode = lockOptions.getEffectiveLockMode(userAlias);
locks.setAliasSpecificLockMode(sqlAlias, effectiveLockMode);
if (keyColumnNames != null) {
keyColumnNames.put(sqlAlias, drivingPersister.getRootTableIdentifierColumnNames());
}
}
// apply the collected locks and columns
return dialect.applyLocksToSql(sql, locks, keyColumnNames);
}
Aggregations