This is an automated email from the ASF dual-hosted git repository.

borinquenkid pushed a commit to branch 8.0.x-hibernate7-dev
in repository https://gitbox.apache.org/repos/asf/grails-core.git

commit fec3c5eaa67ef15740ffbbb52c8bb7b9ea540220
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Wed Mar 4 12:45:52 2026 -0600

    refactor(hibernate7): replace dual-field HibernateHqlQuery with 
HqlQueryDelegate composition
---
 .../orm/hibernate/query/HibernateHqlQuery.java     | 109 +++++++++----------
 .../orm/hibernate/query/HqlQueryDelegate.java      |  86 +++++++++++++++
 .../orm/hibernate/query/MutationQueryDelegate.java |  99 ++++++++++++++++++
 .../orm/hibernate/query/SelectQueryDelegate.java   | 115 +++++++++++++++++++++
 .../hibernate/query/HibernateHqlQuerySpec.groovy   |  36 +++++++
 5 files changed, 392 insertions(+), 53 deletions(-)

diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernateHqlQuery.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernateHqlQuery.java
index f896a0adf2..02e21230fc 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernateHqlQuery.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HibernateHqlQuery.java
@@ -40,33 +40,37 @@ import org.grails.orm.hibernate.HibernateSession;
 import org.grails.orm.hibernate.exceptions.GrailsQueryException;
 import org.hibernate.FlushMode;
 import org.hibernate.SessionFactory;
-import org.hibernate.query.MutationQuery;
 import org.springframework.context.ApplicationEventPublisher;
 
 /**
  * A query implementation for HQL queries.
  *
+ * <p>Hibernate 7 splits query types into {@link org.hibernate.query.Query} 
(SELECT) and
+ * {@link org.hibernate.query.MutationQuery} (UPDATE/DELETE), which are 
siblings under
+ * {@link org.hibernate.query.CommonQueryContract}. This class uses 
composition via
+ * {@link HqlQueryDelegate} to eliminate runtime type-checks and null-field 
branching.
+ *
  * @author Graeme Rocher
  * @since 6.0
  */
 @SuppressWarnings("PMD.AvoidDuplicateLiterals")
 public class HibernateHqlQuery extends Query {
 
-  private final org.hibernate.query.Query<?> query;
-  private final org.hibernate.query.MutationQuery mutationQuery;
+  /** Handles all query operations; the concrete type encodes whether this is 
SELECT or UPDATE/DELETE. */
+  private final HqlQueryDelegate delegate;
 
+  /** Constructs a SELECT query wrapper. */
   public HibernateHqlQuery(
       Session session, PersistentEntity entity, org.hibernate.query.Query<?> 
query) {
     super(session, entity);
-    this.query = query;
-    this.mutationQuery = null;
+    this.delegate = new SelectQueryDelegate(query);
   }
 
+  /** Constructs an UPDATE/DELETE query wrapper. */
   public HibernateHqlQuery(
       Session session, PersistentEntity entity, 
org.hibernate.query.MutationQuery mutationQuery) {
     super(session, entity);
-    this.query = null;
-    this.mutationQuery = mutationQuery;
+    this.delegate = new MutationQueryDelegate(mutationQuery);
   }
 
   @Override
@@ -80,8 +84,8 @@ public class HibernateHqlQuery extends Query {
     Datastore datastore = getSession().getDatastore();
     ApplicationEventPublisher publisher = 
datastore.getApplicationEventPublisher();
     publisher.publishEvent(new PreQueryEvent(datastore, this));
-    if (uniqueResult) query.setMaxResults(1);
-    List results = query.list();
+    if (uniqueResult) delegate.setMaxResults(1);
+    List results = delegate.list();
     publisher.publishEvent(new PostQueryEvent(datastore, this, results));
     return results;
   }
@@ -89,7 +93,7 @@ public class HibernateHqlQuery extends Query {
   // ─── Static factory API ──────────────────────────────────────────────────
 
   /**
-   * Session-bound step — creates the {@link org.hibernate.query.Query} from 
an open {@link
+   * Session-bound step — creates the appropriate Hibernate query from an open 
{@link
    * org.hibernate.Session} and wraps it in a {@link HibernateHqlQuery}.
    */
   protected static HibernateHqlQuery buildQuery(
@@ -98,26 +102,24 @@ public class HibernateHqlQuery extends Query {
       SessionFactory sessionFactory,
       PersistentEntity entity,
       HqlQueryContext ctx) {
-    org.hibernate.query.Query<?> q;
+    HibernateSession hibernateSession = new HibernateSession(dataStore, 
sessionFactory);
     if (StringUtils.isEmpty(ctx.hql())) {
-      q = session.createQuery("from " + ctx.targetClass().getName(), 
ctx.targetClass());
-      return new HibernateHqlQuery(new HibernateSession(dataStore, 
sessionFactory), entity, q);
+      var q = session.createQuery("from " + ctx.targetClass().getName(), 
ctx.targetClass());
+      return new HibernateHqlQuery(hibernateSession, entity, q);
     } else if (ctx.isUpdate()) {
-      org.hibernate.query.MutationQuery mq = 
session.createMutationQuery(ctx.hql());
-      HibernateHqlQuery result =
-          new HibernateHqlQuery(new HibernateSession(dataStore, 
sessionFactory), entity, mq);
+      var mq = session.createMutationQuery(ctx.hql());
+      var result = new HibernateHqlQuery(hibernateSession, entity, mq);
       result.setFlushMode(session.getHibernateFlushMode());
       return result;
     } else {
-      q =
+      var q =
           ctx.isNative()
               ? session.createNativeQuery(ctx.hql(), ctx.targetClass())
               : session.createQuery(ctx.hql(), ctx.targetClass());
+      var result = new HibernateHqlQuery(hibernateSession, entity, q);
+      result.setFlushMode(session.getHibernateFlushMode());
+      return result;
     }
-    HibernateHqlQuery result =
-        new HibernateHqlQuery(new HibernateSession(dataStore, sessionFactory), 
entity, q);
-    result.setFlushMode(session.getHibernateFlushMode());
-    return result;
   }
 
   /**
@@ -135,8 +137,9 @@ public class HibernateHqlQuery extends Query {
       GrailsHibernateTemplate template) {
     HibernateHqlQuery hqlQuery =
         template.execute(session -> buildQuery(session, dataStore, 
sessionFactory, entity, ctx));
-    if (hqlQuery.getQuery() != null) {
-      template.applySettings(hqlQuery.getQuery());
+    var selectQuery = hqlQuery.selectQuery();
+    if (selectQuery != null) {
+      template.applySettings(selectQuery);
     }
     hqlQuery.populateQuerySettings(
         MapUtils.isNotEmpty(args) ? new HashMap<>(args) : 
Collections.emptyMap());
@@ -158,30 +161,20 @@ public class HibernateHqlQuery extends Query {
   }
 
   public void populateQuerySettings(Map<?, ?> args) {
-    if (mutationQuery != null) {
-      ifPresent(args, DynamicFinder.ARGUMENT_TIMEOUT, v -> 
mutationQuery.setTimeout(toInt(v)));
-      ifPresent(
-          args,
-          DynamicFinder.ARGUMENT_FLUSH_MODE,
-          v -> 
mutationQuery.setQueryFlushMode(GrailsHibernateQueryUtils.convertQueryFlushMode(v)));
-      return;
-    }
-    if (query == null) return;
-    ifPresent(args, DynamicFinder.ARGUMENT_MAX, v -> 
query.setMaxResults(toInt(v)));
-    ifPresent(args, DynamicFinder.ARGUMENT_OFFSET, v -> 
query.setFirstResult(toInt(v)));
-    ifPresent(args, DynamicFinder.ARGUMENT_CACHE, v -> 
query.setCacheable(toBool(v)));
-    ifPresent(args, DynamicFinder.ARGUMENT_FETCH_SIZE, v -> 
query.setFetchSize(toInt(v)));
-    ifPresent(args, DynamicFinder.ARGUMENT_TIMEOUT, v -> 
query.setTimeout(toInt(v)));
-    ifPresent(args, DynamicFinder.ARGUMENT_READ_ONLY, v -> 
query.setReadOnly(toBool(v)));
+    ifPresent(args, DynamicFinder.ARGUMENT_MAX, v -> 
delegate.setMaxResults(toInt(v)));
+    ifPresent(args, DynamicFinder.ARGUMENT_OFFSET, v -> 
delegate.setFirstResult(toInt(v)));
+    ifPresent(args, DynamicFinder.ARGUMENT_CACHE, v -> 
delegate.setCacheable(toBool(v)));
+    ifPresent(args, DynamicFinder.ARGUMENT_FETCH_SIZE, v -> 
delegate.setFetchSize(toInt(v)));
+    ifPresent(args, DynamicFinder.ARGUMENT_TIMEOUT, v -> 
delegate.setTimeout(toInt(v)));
+    ifPresent(args, DynamicFinder.ARGUMENT_READ_ONLY, v -> 
delegate.setReadOnly(toBool(v)));
     ifPresent(
         args,
         DynamicFinder.ARGUMENT_FLUSH_MODE,
-        v -> 
query.setQueryFlushMode(GrailsHibernateQueryUtils.convertQueryFlushMode(v)));
+        v -> 
delegate.setQueryFlushMode(GrailsHibernateQueryUtils.convertQueryFlushMode(v)));
   }
 
   public void populateQueryWithNamedArguments(Map<?, ?> namedArgs) {
     if (namedArgs == null) return;
-    org.hibernate.query.CommonQueryContract target = mutationQuery != null ? 
mutationQuery : query;
     namedArgs.forEach(
         (key, value) -> {
           if (!(key instanceof CharSequence)) {
@@ -189,36 +182,46 @@ public class HibernateHqlQuery extends Query {
           }
           String name = key.toString();
           if (value == null) {
-            target.setParameter(name, null);
-          } else if (mutationQuery == null && value instanceof Collection<?> 
col) {
-            query.setParameterList(name, col);
-          } else if (mutationQuery == null && value.getClass().isArray()) {
-            query.setParameterList(name, (Object[]) value);
+            delegate.setParameter(name, null);
+          } else if (value instanceof Collection<?> col) {
+            delegate.setParameterList(name, col);
+          } else if (value.getClass().isArray()) {
+            delegate.setParameterList(name, (Object[]) value);
           } else if (value instanceof CharSequence cs) {
-            target.setParameter(name, cs.toString(), String.class);
+            delegate.setParameter(name, cs.toString(), String.class);
           } else {
-            target.setParameter(name, value);
+            delegate.setParameter(name, value);
           }
         });
   }
 
   public void populateQueryWithIndexedArguments(List<?> params) {
     if (params == null) return;
-    org.hibernate.query.CommonQueryContract target = mutationQuery != null ? 
mutationQuery : query;
     for (int i = 0; i < params.size(); i++) {
       Object val = params.get(i);
-      if (val instanceof CharSequence cs) target.setParameter(i + 1, 
cs.toString(), String.class);
-      else if (val != null) target.setParameter(i + 1, val);
-      else target.setParameter(i + 1, null);
+      if (val instanceof CharSequence cs) delegate.setParameter(i + 1, 
cs.toString(), String.class);
+      else delegate.setParameter(i + 1, val);
     }
   }
 
+  /**
+   * Returns the underlying {@link org.hibernate.query.Query} for SELECT 
queries, or {@code null}
+   * for mutation queries.
+   */
   public org.hibernate.query.Query<?> getQuery() {
-    return query;
+    return delegate.selectQuery();
+  }
+
+  /**
+   * Returns the underlying {@link org.hibernate.query.Query} for SELECT 
queries, or {@code null}
+   * for mutation queries.
+   */
+  public org.hibernate.query.Query<?> selectQuery() {
+    return delegate.selectQuery();
   }
 
   public int executeUpdate() {
-    return mutationQuery != null ? mutationQuery.executeUpdate() : 
query.executeUpdate();
+    return delegate.executeUpdate();
   }
 
   // ─── Private utilities ────────────────────────────────────────────────────
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HqlQueryDelegate.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HqlQueryDelegate.java
new file mode 100644
index 0000000000..42e60fe36d
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HqlQueryDelegate.java
@@ -0,0 +1,86 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.grails.orm.hibernate.query;
+
+import java.util.Collection;
+import java.util.List;
+import org.hibernate.query.QueryFlushMode;
+
+/**
+ * Abstracts over Hibernate's {@link org.hibernate.query.Query} (SELECT) and
+ * {@link org.hibernate.query.MutationQuery} (UPDATE/DELETE). The two types are
+ * siblings under {@link org.hibernate.query.CommonQueryContract} and cannot 
be held
+ * in a single typed field, so {@link HibernateHqlQuery} delegates all query
+ * operations through this interface instead.
+ *
+ * <p>Select-only methods ({@link #setMaxResults}, {@link #setCacheable}, 
etc.) are
+ * no-ops by default; {@link SelectQueryDelegate} overrides them. Mutation-only
+ * operations ({@link #executeUpdate}) throw {@link 
UnsupportedOperationException}
+ * in {@link SelectQueryDelegate} and vice-versa for {@link #list()} in
+ * {@link MutationQueryDelegate}.
+ */
+interface HqlQueryDelegate {
+
+  // ── common ────────────────────────────────────────────────────────────────
+
+  void setTimeout(int timeout);
+
+  void setQueryFlushMode(QueryFlushMode mode);
+
+  void setParameter(String name, Object value);
+
+  <T> void setParameter(String name, T value, Class<T> type);
+
+  void setParameter(int position, Object value);
+
+  <T> void setParameter(int position, T value, Class<T> type);
+
+  // ── select-only (no-ops for mutation queries) ─────────────────────────────
+
+  default void setMaxResults(int n) {}
+
+  default void setFirstResult(int n) {}
+
+  default void setCacheable(boolean b) {}
+
+  default void setFetchSize(int n) {}
+
+  default void setReadOnly(boolean b) {}
+
+  /** Sets a named collection parameter. For mutation queries, falls back to 
{@link #setParameter}. */
+  default void setParameterList(String name, Collection<?> values) {}
+
+  /** Sets a named array parameter. For mutation queries, falls back to {@link 
#setParameter}. */
+  default void setParameterList(String name, Object[] values) {}
+
+  // ── execution ─────────────────────────────────────────────────────────────
+
+  /** Returns all results. Throws {@link UnsupportedOperationException} for 
mutation queries. */
+  @SuppressWarnings("rawtypes")
+  List list();
+
+  /** Executes an UPDATE/DELETE. Throws {@link UnsupportedOperationException} 
for SELECT queries. */
+  int executeUpdate();
+
+  /**
+   * Returns the underlying {@link org.hibernate.query.Query} for SELECT 
queries, or {@code null}
+   * for mutation queries (used by {@link 
org.grails.orm.hibernate.GrailsHibernateTemplate#applySettings}).
+   */
+  org.hibernate.query.Query<?> selectQuery();
+}
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/MutationQueryDelegate.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/MutationQueryDelegate.java
new file mode 100644
index 0000000000..57554ce374
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/MutationQueryDelegate.java
@@ -0,0 +1,99 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.grails.orm.hibernate.query;
+
+import java.util.Collection;
+import java.util.List;
+import org.hibernate.query.MutationQuery;
+import org.hibernate.query.QueryFlushMode;
+
+/**
+ * {@link HqlQueryDelegate} for HQL UPDATE/DELETE queries backed by
+ * {@link org.hibernate.query.MutationQuery}.
+ *
+ * <p>Select-only methods (setMaxResults, setCacheable, etc.) are inherited as 
no-ops since
+ * {@link MutationQuery} does not support them. {@link #setParameterList} 
falls back to
+ * {@link #setParameter} with the collection value as best-effort support for 
IN clauses.
+ */
+final class MutationQueryDelegate implements HqlQueryDelegate {
+
+  private final MutationQuery mutationQuery;
+
+  MutationQueryDelegate(MutationQuery mutationQuery) {
+    this.mutationQuery = mutationQuery;
+  }
+
+  @Override
+  public void setTimeout(int timeout) {
+    mutationQuery.setTimeout(timeout);
+  }
+
+  @Override
+  public void setQueryFlushMode(QueryFlushMode mode) {
+    mutationQuery.setQueryFlushMode(mode);
+  }
+
+  @Override
+  public void setParameter(String name, Object value) {
+    mutationQuery.setParameter(name, value);
+  }
+
+  @Override
+  public <T> void setParameter(String name, T value, Class<T> type) {
+    mutationQuery.setParameter(name, value, type);
+  }
+
+  @Override
+  public void setParameter(int position, Object value) {
+    mutationQuery.setParameter(position, value);
+  }
+
+  @Override
+  public <T> void setParameter(int position, T value, Class<T> type) {
+    mutationQuery.setParameter(position, value, type);
+  }
+
+  @Override
+  public void setParameterList(String name, Collection<?> values) {
+    // MutationQuery has no setParameterList; pass collection directly as 
parameter value
+    mutationQuery.setParameter(name, values);
+  }
+
+  @Override
+  public void setParameterList(String name, Object[] values) {
+    mutationQuery.setParameter(name, values);
+  }
+
+  @Override
+  @SuppressWarnings("rawtypes")
+  public List list() {
+    throw new UnsupportedOperationException(
+        "Mutation query (UPDATE/DELETE) cannot be used for list(); use 
executeUpdate() instead");
+  }
+
+  @Override
+  public int executeUpdate() {
+    return mutationQuery.executeUpdate();
+  }
+
+  @Override
+  public org.hibernate.query.Query<?> selectQuery() {
+    return null;
+  }
+}
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/SelectQueryDelegate.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/SelectQueryDelegate.java
new file mode 100644
index 0000000000..8b9f9518c8
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/SelectQueryDelegate.java
@@ -0,0 +1,115 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.grails.orm.hibernate.query;
+
+import java.util.Collection;
+import java.util.List;
+import org.hibernate.query.QueryFlushMode;
+
+/** {@link HqlQueryDelegate} for HQL SELECT queries backed by {@link 
org.hibernate.query.Query}. */
+final class SelectQueryDelegate implements HqlQueryDelegate {
+
+  private final org.hibernate.query.Query<?> query;
+
+  SelectQueryDelegate(org.hibernate.query.Query<?> query) {
+    this.query = query;
+  }
+
+  @Override
+  public void setTimeout(int timeout) {
+    query.setTimeout(timeout);
+  }
+
+  @Override
+  public void setQueryFlushMode(QueryFlushMode mode) {
+    query.setQueryFlushMode(mode);
+  }
+
+  @Override
+  public void setParameter(String name, Object value) {
+    query.setParameter(name, value);
+  }
+
+  @Override
+  public <T> void setParameter(String name, T value, Class<T> type) {
+    query.setParameter(name, value, type);
+  }
+
+  @Override
+  public void setParameter(int position, Object value) {
+    query.setParameter(position, value);
+  }
+
+  @Override
+  public <T> void setParameter(int position, T value, Class<T> type) {
+    query.setParameter(position, value, type);
+  }
+
+  @Override
+  public void setMaxResults(int n) {
+    query.setMaxResults(n);
+  }
+
+  @Override
+  public void setFirstResult(int n) {
+    query.setFirstResult(n);
+  }
+
+  @Override
+  public void setCacheable(boolean b) {
+    query.setCacheable(b);
+  }
+
+  @Override
+  public void setFetchSize(int n) {
+    query.setFetchSize(n);
+  }
+
+  @Override
+  public void setReadOnly(boolean b) {
+    query.setReadOnly(b);
+  }
+
+  @Override
+  public void setParameterList(String name, Collection<?> values) {
+    query.setParameterList(name, values);
+  }
+
+  @Override
+  public void setParameterList(String name, Object[] values) {
+    query.setParameterList(name, values);
+  }
+
+  @Override
+  @SuppressWarnings("rawtypes")
+  public List list() {
+    return query.list();
+  }
+
+  @Override
+  public int executeUpdate() {
+    throw new UnsupportedOperationException(
+        "SELECT query cannot be used for executeUpdate(); use a MutationQuery 
instead");
+  }
+
+  @Override
+  public org.hibernate.query.Query<?> selectQuery() {
+    return query;
+  }
+}
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/query/HibernateHqlQuerySpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/query/HibernateHqlQuerySpec.groovy
index 6c8941381a..ab22d31c14 100644
--- 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/query/HibernateHqlQuerySpec.groovy
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/query/HibernateHqlQuerySpec.groovy
@@ -197,6 +197,42 @@ class HibernateHqlQuerySpec extends 
HibernateGormDatastoreSpec {
         then:
         thrown(Exception)
     }
+
+    // ─── delegate behaviour ─────────────────────────────────────────────────
+
+    void "selectQuery is non-null for SELECT queries"() {
+        expect:
+        buildHqlQuery("from HibernateHqlQuerySpecBook").selectQuery() != null
+    }
+
+    void "selectQuery is null for UPDATE/DELETE queries"() {
+        expect:
+        buildHqlQuery("update HibernateHqlQuerySpecBook set pages = 1 where 
title = :t",
+                [t: "The Hobbit"], null, [:], true).selectQuery() == null
+    }
+
+    void "populateQuerySettings silently ignores select-only args for mutation 
queries"() {
+        when: "max/offset/cache args passed to an UPDATE query — should not 
throw"
+        buildHqlQuery("update HibernateHqlQuerySpecBook set pages = 1 where 
title = :t",
+                [t: "The Hobbit"], null, [max: 2, offset: 1, cache: true, 
fetchSize: 10, readOnly: true], true)
+        then:
+        noExceptionThrown()
+    }
+
+    void "executeUpdate throws UnsupportedOperationException for SELECT 
query"() {
+        when:
+        buildHqlQuery("from HibernateHqlQuerySpecBook").executeUpdate()
+        then:
+        thrown(UnsupportedOperationException)
+    }
+
+    void "list throws UnsupportedOperationException for UPDATE query"() {
+        when:
+        buildHqlQuery("update HibernateHqlQuerySpecBook set pages = 1 where 
title = :t",
+                [t: "The Hobbit"], null, [:], true).list()
+        then:
+        thrown(UnsupportedOperationException)
+    }
 }
 
 @Entity

Reply via email to