jamesfredley commented on code in PR #16816:
URL: https://github.com/apache/grails-core/pull/16816#discussion_r4475314067


##########
grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/query/jpa/JpaQueryBuilder.java:
##########
@@ -961,4 +1031,29 @@ else if (criterion instanceof AssociationCriteria) {
 
         return position;
     }
+
+    private static String functionOperator(Query.PropertyCriterion wrapped) {
+        if (wrapped instanceof Query.Equals) {
+            return " = ";
+        }
+        if (wrapped instanceof Query.NotEquals) {
+            return " != ";
+        }
+        if (wrapped instanceof Query.GreaterThan) {
+            return " > ";
+        }
+        if (wrapped instanceof Query.GreaterThanEquals) {
+            return " >= ";
+        }
+        if (wrapped instanceof Query.LessThan) {
+            return " < ";
+        }
+        if (wrapped instanceof Query.LessThanEquals) {
+            return " <= ";
+        }
+        if (wrapped instanceof Query.Like) {

Review Comment:
   A function around an rlike comparison, then deleteAll(), deletes nothing 
when the name matches the regular expression. RLike is a Like, so this branch 
emits LIKE. Handle the regular expression before this branch. A read of the 
same criterion already uses the regular expression.



##########
grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/query/jpa/JpaQueryBuilder.java:
##########
@@ -605,6 +606,73 @@ public int handle(PersistentEntity entity, Query.Criterion 
criterion, StringBuil
             }
         });
 
+        queryHandlers.put(FunctionCallingCriterion.class, new QueryHandler() {
+            public int handle(PersistentEntity entity, Query.Criterion 
criterion, StringBuilder q, StringBuilder whereClause, String logicalName, int 
position, List parameters, ConversionService conversionService, boolean 
allowJoins, boolean hibernateCompatible) {
+                FunctionCallingCriterion functionCriterion = 
(FunctionCallingCriterion) criterion;
+                String name = functionCriterion.getProperty();
+                validateProperty(entity, name, FunctionCallingCriterion.class);
+                if (functionCriterion.isOnValue()) {
+                    throw new InvalidDataAccessResourceUsageException("A 
function on the value of a comparison is not supported: " + 
functionCriterion.getFunctionName());
+                }
+                Query.PropertyCriterion wrapped = 
functionCriterion.getPropertyCriterion();
+                if (wrapped instanceof Query.ILike) {
+                    whereClause.append("lower(")
+                               .append(functionCriterion.getFunctionName())
+                               .append(OPEN_BRACKET)
+                               .append(logicalName)
+                               .append(DOT)
+                               .append(name)
+                               .append(CLOSE_BRACKET)
+                               .append(") like lower(")
+                               .append(PARAMETER_PREFIX)
+                               .append(++position)
+                               .append(CLOSE_BRACKET);
+                    parameters.add(wrapped.getValue());
+                    return position;
+                }
+                whereClause.append(functionCriterion.getFunctionName())
+                           .append(OPEN_BRACKET)
+                           .append(logicalName)
+                           .append(DOT)
+                           .append(name)
+                           .append(CLOSE_BRACKET);
+                if (wrapped instanceof Query.In in) {
+                    whereClause.append(" IN (");
+                    QueryableCriteria subquery = in.getSubquery();
+                    if (subquery != null) {
+                        buildSubQuery(q, whereClause, position, parameters, 
conversionService, allowJoins, hibernateCompatible, subquery);
+                        position = parameters.size();
+                    }
+                    else {
+                        for (Iterator i = in.getValues().iterator(); 
i.hasNext();) {
+                            Object val = i.next();
+                            
whereClause.append(PARAMETER_PREFIX).append(++position);
+                            if (i.hasNext()) {
+                                whereClause.append(COMMA);
+                            }
+                            parameters.add(val);
+                        }
+                    }
+                    whereClause.append(CLOSE_BRACKET);
+                }
+                else if (wrapped instanceof Query.Equals && wrapped.getValue() 
== null) {
+                    whereClause.append(" IS NULL");
+                }
+                else if (wrapped instanceof Query.NotEquals && 
wrapped.getValue() == null) {
+                    whereClause.append(" IS NOT NULL");
+                }
+                else {
+                    String operator = functionOperator(wrapped);
+                    if (operator == null) {
+                        throw new 
InvalidDataAccessResourceUsageException("Unsupported criterion in a function 
call: " + wrapped.getClass().getSimpleName());
+                    }
+                    
whereClause.append(operator).append(PARAMETER_PREFIX).append(++position);
+                    parameters.add(wrapped.getValue());

Review Comment:
   A function around an equality whose value is a one-row detached criteria, 
then deleteAll(), binds the criteria object as the parameter and the update 
fails. Render that value as a subquery, as the read path does.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to