You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2026/04/18 21:19:29 UTC

(groovy) branch master updated (22c9a9196b -> 4a57272e43)

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

paulk-asert pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


    from 22c9a9196b GROOVY-9295: add end-to-end test for Map-params path (additional test case)
     new e316cd7096 GROOVY-9701: ExtractIndexAndSql does not recognize double-quoted SQL identifiers
     new 4a57272e43 GROOVY-7768: regression test for callWithAllRows with input-only params

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../main/java/groovy/sql/ExtractIndexAndSql.java   | 27 +++++++++
 .../groovy/sql/ExtractIndexAndSqlTest.groovy       | 64 ++++++++++++++++++++++
 .../src/test/groovy/groovy/sql/SqlCallTest.groovy  | 14 +++++
 3 files changed, 105 insertions(+)


(groovy) 01/02: GROOVY-9701: ExtractIndexAndSql does not recognize double-quoted SQL identifiers

Posted by pa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

paulk-asert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit e316cd7096cf266f159bfc874bc3708f33afa9d6
Author: Paul King <pa...@asert.com.au>
AuthorDate: Sun Apr 19 07:01:58 2026 +1000

    GROOVY-9701: ExtractIndexAndSql does not recognize double-quoted SQL identifiers
---
 .../main/java/groovy/sql/ExtractIndexAndSql.java   | 27 +++++++++
 .../groovy/sql/ExtractIndexAndSqlTest.groovy       | 64 ++++++++++++++++++++++
 2 files changed, 91 insertions(+)

diff --git a/subprojects/groovy-sql/src/main/java/groovy/sql/ExtractIndexAndSql.java b/subprojects/groovy-sql/src/main/java/groovy/sql/ExtractIndexAndSql.java
index df88743938..b0bd9c094a 100644
--- a/subprojects/groovy-sql/src/main/java/groovy/sql/ExtractIndexAndSql.java
+++ b/subprojects/groovy-sql/src/main/java/groovy/sql/ExtractIndexAndSql.java
@@ -36,6 +36,7 @@ class ExtractIndexAndSql {
 
     private static final Pattern NAMED_QUERY_PATTERN = Pattern.compile("(?<!:)(:)(\\w+)|\\?(\\d*)(?:\\.(\\w+))?");
     private static final char QUOTE = '\'';
+    private static final char DOUBLE_QUOTE = '"';
 
     private final String sql;
     private List<Tuple<?>> indexPropList;
@@ -90,6 +91,11 @@ class ExtractIndexAndSql {
                     currentChunk = new StringBuilder();
                     appendToEndOfString(sb);
                     break;
+                case DOUBLE_QUOTE:
+                    sb.append(adaptForNamedParams(currentChunk.toString(), indexPropList));
+                    currentChunk = new StringBuilder();
+                    appendToEndOfIdentifier(sb);
+                    break;
                 case '-':
                     if (next() == '-') {
                         sb.append(adaptForNamedParams(currentChunk.toString(), indexPropList));
@@ -157,6 +163,27 @@ class ExtractIndexAndSql {
         return (index - 1) - pos;
     }
 
+    // Skip past a double-quoted identifier (SQL-standard delimited identifier).
+    // Contents are opaque: a doubled "" is an embedded quote; a lone " ends the identifier.
+    private void appendToEndOfIdentifier(StringBuilder buffer) {
+        buffer.append(DOUBLE_QUOTE);
+        ++index;
+        while (index < sql.length()) {
+            char c = sql.charAt(index);
+            buffer.append(c);
+            if (c == DOUBLE_QUOTE) {
+                if (next() == DOUBLE_QUOTE) {
+                    buffer.append(DOUBLE_QUOTE);
+                    ++index;
+                } else {
+                    return;
+                }
+            }
+            ++index;
+        }
+        throw new IllegalStateException("Failed to process query. Unterminated \" character?");
+    }
+
     private void appendToEndOfComment(StringBuilder buffer) {
         while (index < sql.length()) {
             char c = sql.charAt(index);
diff --git a/subprojects/groovy-sql/src/test/groovy/groovy/sql/ExtractIndexAndSqlTest.groovy b/subprojects/groovy-sql/src/test/groovy/groovy/sql/ExtractIndexAndSqlTest.groovy
index f5ff1881c2..b3bb203c51 100644
--- a/subprojects/groovy-sql/src/test/groovy/groovy/sql/ExtractIndexAndSqlTest.groovy
+++ b/subprojects/groovy-sql/src/test/groovy/groovy/sql/ExtractIndexAndSqlTest.groovy
@@ -305,4 +305,68 @@ ORDER BY
 
         assert query == ExtractIndexAndSql.from(query).newSql
     }
+
+    // GROOVY-9701: double-quoted SQL identifier containing a single quote
+    @Test
+    void testDoubleQuotedIdentifierContainingSingleQuote() {
+        String query = '''select "it's" from t where id=:id'''
+        String expected = '''select "it's" from t where id=?'''
+
+        assert expected == ExtractIndexAndSql.from(query).newSql
+    }
+
+    // GROOVY-9701: double-quoted identifier with embedded named-param-like colon is opaque
+    @Test
+    void testDoubleQuotedIdentifierWithColonIsOpaque() {
+        String query = '''select "foo:bar" from t where id=:id'''
+        String expected = '''select "foo:bar" from t where id=?'''
+
+        assert expected == ExtractIndexAndSql.from(query).newSql
+    }
+
+    // GROOVY-9701: SQL-standard doubled-quote escape inside a delimited identifier
+    @Test
+    void testDoubleQuotedIdentifierWithEscapedQuote() {
+        String query = '''select "a""b" from t where id=:id'''
+        String expected = '''select "a""b" from t where id=?'''
+
+        assert expected == ExtractIndexAndSql.from(query).newSql
+    }
+
+    // GROOVY-9701: unterminated double-quoted identifier surfaces as parse error
+    @Test
+    void testUnterminatedDoubleQuotedIdentifier() {
+        String query = 'select "oops from t where id=:id'
+
+        shouldFail(IllegalStateException) {
+            ExtractIndexAndSql.from(query)
+        }
+    }
+
+    // GROOVY-9701: reporter's case — mixes '-string containing " and "-identifier containing '.
+    // Five single quotes total; only parses cleanly once "-identifiers are recognized.
+    @Test
+    void testReporterCaseMixedQuotes() {
+        String query = '''select 'NAME' = str_replace(str_replace(name, '"', null), "'", null) from Address'''
+
+        assert query == ExtractIndexAndSql.from(query).newSql
+    }
+
+    // GROOVY-9701: line-comment marker inside a double-quoted identifier must not start a comment
+    @Test
+    void testDoubleQuotedIdentifierWithDashDashIsOpaque() {
+        String query = 'select "a--b" from t where id=:id'
+        String expected = 'select "a--b" from t where id=?'
+
+        assert expected == ExtractIndexAndSql.from(query).newSql
+    }
+
+    // GROOVY-9701: block-comment start inside a double-quoted identifier must not start a comment
+    @Test
+    void testDoubleQuotedIdentifierWithSlashStarIsOpaque() {
+        String query = 'select "a/*b*/c" from t where id=:id'
+        String expected = 'select "a/*b*/c" from t where id=?'
+
+        assert expected == ExtractIndexAndSql.from(query).newSql
+    }
 }


(groovy) 02/02: GROOVY-7768: regression test for callWithAllRows with input-only params

Posted by pa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

paulk-asert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 4a57272e43772bc4991712df921a49ff8eb0de36
Author: Paul King <pa...@asert.com.au>
AuthorDate: Sun Apr 19 07:02:05 2026 +1000

    GROOVY-7768: regression test for callWithAllRows with input-only params
    
    The reporter's original failure was driver-specific (SQL Server + non-portable
    `sp_who ?` syntax rather than the JDBC escape `{call sp_who(?)}`). The HSQLDB
    equivalent using the portable syntax returns rows correctly, so this commit
    adds coverage to lock in that behaviour. Propose closing GROOVY-7768 as
    Cannot Reproduce.
---
 .../src/test/groovy/groovy/sql/SqlCallTest.groovy          | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/subprojects/groovy-sql/src/test/groovy/groovy/sql/SqlCallTest.groovy b/subprojects/groovy-sql/src/test/groovy/groovy/sql/SqlCallTest.groovy
index 2b1bac7969..b61e78ebab 100644
--- a/subprojects/groovy-sql/src/test/groovy/groovy/sql/SqlCallTest.groovy
+++ b/subprojects/groovy-sql/src/test/groovy/groovy/sql/SqlCallTest.groovy
@@ -300,6 +300,20 @@ class SqlCallTest extends GroovyTestCase {
         assert lastRows[0].lastname == 'Ventura'
     }
 
+    // GROOVY-7768
+    void testCallWithAllRowsWithInputParamOnly() {
+        List<List<GroovyRowResult>> rowList = sql.callWithAllRows('{call FindAllByFirst(?)}', ['J'], { /* no out params */ })
+        assert rowList.size() == 1
+        def rows = rowList[0]
+        assert rows.size() == 2
+        assert rows[0].id == 1
+        assert rows[0].firstname == 'James'
+        assert rows[0].lastname == 'Strachan'
+        assert rows[1].id == 4
+        assert rows[1].firstname == 'Jean'
+        assert rows[1].lastname == 'Gabin'
+    }
+
     void testCallWithStatementCaching() {
         String sqlText = '{call FindByFirst(?, ?)}'
         CallableStatement statement = null