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

yesamer pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie.git


The following commit(s) were added to refs/heads/main by this push:
     new a68b7c1b126 performance(kie-dmn-feel): Performance regression in 
Drools v10+ with DMN models   (#6871)
a68b7c1b126 is described below

commit a68b7c1b126b1f51bd761dc124c0b17194061a24
Author: Yeser Amer <[email protected]>
AuthorDate: Fri Aug 7 12:55:41 2026 +0200

    performance(kie-dmn-feel): Performance regression in Drools v10+ with DMN 
models   (#6871)
    
    * Improve replace and matches functions performances
    
    * Additional improvements
    
    * Doc changes
    
    * MInor
    
    * Minor
    
    * Tests added.
    
    * minor
    
    * Change Request
---
 .../java/org/kie/dmn/feel/util/XQueryImplUtil.java | 57 +++++++++++++++-------
 .../org/kie/dmn/feel/util/XQueryImplUtilTest.java  | 40 +++++++++++++++
 kie-parent/pom.xml                                 |  2 +-
 3 files changed, 80 insertions(+), 19 deletions(-)

diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/XQueryImplUtil.java 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/XQueryImplUtil.java
index e617ae77c1a..f8d28507f18 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/XQueryImplUtil.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/XQueryImplUtil.java
@@ -26,11 +26,18 @@ import net.sf.saxon.s9api.XQueryEvaluator;
 import net.sf.saxon.s9api.XQueryExecutable;
 import net.sf.saxon.s9api.SaxonApiException;
 
-import java.util.regex.Pattern;
-
 public class XQueryImplUtil {
 
-    private static final Pattern XML_CHARACTER_REFERENCES_PATTERN = 
Pattern.compile("['\"&<>]");
+    /** Shared across all calls. Thread-safe; expensive to construct. One 
instance per JVM is sufficient.
+     * See Saxon s9api {@link net.sf.saxon.s9api.Processor} Javadoc. */
+    private static final Processor PROCESSOR = new Processor(false);
+
+    /**
+     * Shared across all calls. Concurrent use is permitted, but error 
messages may not be
+     * attributed to the correct thread under concurrent error conditions.
+     * See Saxon s9api {@link net.sf.saxon.s9api.XQueryCompiler} Javadoc.
+     */
+    private static final XQueryCompiler COMPILER = 
PROCESSOR.newXQueryCompiler();
 
     private XQueryImplUtil() {
         // Util class with static methods only.
@@ -50,9 +57,7 @@ public class XQueryImplUtil {
 
      static <T> T evaluateXQueryExpression(String expression, Class<T> 
expectedTypeResult) {
          try {
-             Processor processor = new Processor(false);
-             XQueryCompiler compiler = processor.newXQueryCompiler();
-             XQueryExecutable executable = compiler.compile(expression);
+             XQueryExecutable executable = COMPILER.compile(expression);
              XQueryEvaluator queryEvaluator = executable.load();
              XdmItem resultItem = queryEvaluator.evaluateSingle();
 
@@ -66,22 +71,38 @@ public class XQueryImplUtil {
          } catch (SaxonApiException e) {
              throw new IllegalArgumentException(e);
          }
-    }
+     }
 
     /**
-     * It replaces all the XML Character References (&, ", ', <, >) in a given 
input string with their "escaping" characters.
-     * This is required to run XPath functions containing XML Character 
References.
-     * @param input A string input representing one of the parameter of 
managed functions
-     * @return A sanitized string
+     * Escapes XML special characters ({@code & " ' < >}) so the value is safe 
to embed
+     * as an XPath string literal. Returns {@code null} unchanged; returns the 
original
+     * reference if no escaping is needed.
      */
     static String escapeXmlCharactersReferencesForXPath(String input) {
-        if (input != null && 
XML_CHARACTER_REFERENCES_PATTERN.matcher(input).find()) {
-            input = input.contains("&") ? input.replace("&", "&amp;") : input;
-            input = input.contains("\"") ? input.replace("\"",  "&quot;") : 
input;
-            input = input.contains("'") ? input.replace("'",  "&apos;") : 
input;
-            input = input.contains("<") ? input.replace("<",  "&lt;") : input;
-            input = input.contains(">") ? input.replace(">",  "&gt;") : input;
+        if (input == null) {
+            return null;
+        }
+        StringBuilder sb = null;
+        for (int i = 0; i < input.length(); i++) {
+            char ch = input.charAt(i);
+            String replacement = switch (ch) {
+                case '&'  -> "&amp;";
+                case '"'  -> "&quot;";
+                case '\'' -> "&apos;";
+                case '<'  -> "&lt;";
+                case '>'  -> "&gt;";
+                default   -> null;
+            };
+            if (replacement != null) {
+                if (sb == null) {
+                    sb = new StringBuilder(input.length() + 16);
+                    sb.append(input, 0, i);
+                }
+                sb.append(replacement);
+            } else if (sb != null) {
+                sb.append(ch);
+            }
         }
-        return input;
+        return sb != null ? sb.toString() : input;
     }
 }
diff --git 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/XQueryImplUtilTest.java
 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/XQueryImplUtilTest.java
index c196d33588a..c968a7da262 100644
--- 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/XQueryImplUtilTest.java
+++ 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/XQueryImplUtilTest.java
@@ -37,6 +37,18 @@ class XQueryImplUtilTest {
                 { "test", "^test", "i", true },
                 { "fo\nbar", "o.b", null, false },
                 { "TEST", "test", "i", true },
+                // flags
+                { "test", "^test", "", true },                          // 
flags = "" explicitly
+                { "FO\nBAR", "fo.bar", "si", true },                   // 
dotall + case-insensitive
+                { "hello\nworld", "^WORLD", "mi", true },              // 
multiline + case-insensitive
+                // XML special characters in input — exercises the 
escape→embed→evaluate pipeline
+                { "it's", "it.s", "", true },                          // 
single quote in input
+                { "say \"hi\"", "say .hi.", "", true },                // 
double quote in input
+                { "a&b", "a.b", "", true },                            // 
ampersand in input
+                { "a<b", "a.b", "", true },                            // 
less-than in input
+                { "a>b", "a.b", "", true },                            // 
greater-than in input
+                // XML special characters in pattern
+                { "<tag>", "<tag>", "", true },                        // 
angle brackets in pattern
         };
     }
 
@@ -66,6 +78,16 @@ class XQueryImplUtilTest {
         return new Object[][] {
                 { "testString", "^test", "ttt", "", "tttString" },
                 { "fo\nbar", "o.b", "ttt", "s", "ftttar" },
+                // flags
+                { "FO\nBAR", "fo.bar", "X", "si", "X" },              // 
dotall + case-insensitive
+                // XML special characters in input — exercises the 
escape→embed→evaluate pipeline
+                { "a&b", "a.b", "X", "", "X" },                       // 
ampersand in input
+                { "it's", "it.s", "X", "", "X" },                     // 
single quote in input
+                // XML special characters in replacement
+                { "hello", "hello", "a&b", "", "a&b" },               // 
ampersand in replacement
+                { "hello", "hello", "it's", "", "it's" },             // 
single quote in replacement
+                // backreference in replacement
+                { "hello", "(h)", "$1$1", "", "hhello" },             // $1 
backreference
         };
     }
 
@@ -122,12 +144,30 @@ class XQueryImplUtilTest {
 
     private static Object[][] escapeXmlCharactersReferencesForXPathTestData() {
         return new Object[][] {
+                // null / empty
                 { null, null },
                 { "", "" },
+                // no special chars — original reference must be returned 
unchanged
                 { "lolASD", "lolASD" },
+                // each of the five special characters in isolation 
(single-char string)
+                { "&", "&amp;" },
+                { "\"", "&quot;" },
+                { "'", "&apos;" },
+                { "<", "&lt;" },
+                { ">", "&gt;" },
+                // mixed: < and > (no &, no quotes)
                 { "List<String>", "List&lt;String&gt;" },
+                // mixed: " only
                 { "\"Mr.Y\"", "&quot;Mr.Y&quot;" },
+                // mixed: all five present — ' < & > ' (missing " in a 
multi-char mix)
                 { "'<&>'", "&apos;&lt;&amp;&gt;&apos;" },
+                // mixed: all five chars including " alongside others
+                { "a&b\"c'<d>", "a&amp;b&quot;c&apos;&lt;d&gt;" },
+                // special char first, last, and in the middle
+                { "&start", "&amp;start" },
+                { "end&", "end&amp;" },
+                { "mid&dle", "mid&amp;dle" },
+                { "no special chars here 1234", "no special chars here 1234" },
         };
     }
 
diff --git a/kie-parent/pom.xml b/kie-parent/pom.xml
index 6fc5792f80b..9c7aa2c2d1f 100644
--- a/kie-parent/pom.xml
+++ b/kie-parent/pom.xml
@@ -205,7 +205,7 @@
     <version.net.byte-buddy>1.17.6</version.net.byte-buddy>
     <version.net.java.dev.glazedlists>1.8.0</version.net.java.dev.glazedlists>
     <version.net.minidev.jsonsmart>2.4.10</version.net.minidev.jsonsmart>
-    <version.net.sf.saxon.Saxon-HE>12.7</version.net.sf.saxon.Saxon-HE>
+    <version.net.sf.saxon.Saxon-HE>12.10</version.net.sf.saxon.Saxon-HE>
     
<version.net.thisptr.jackson-jq>1.0.0-preview.20240207</version.net.thisptr.jackson-jq>
     <version.org.antlr>3.5.2</version.org.antlr>
     <version.org.antlr.ST4>4.0.7</version.org.antlr.ST4>


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to