Re: Unable to prepare a statement when the object names contain more than one $ symbol - Mailing list pgsql-jdbc

From Michael Paesold
Subject Re: Unable to prepare a statement when the object names contain more than one $ symbol
Date
Msg-id 47178A73.9070500@gmx.at
Whole thread Raw
In response to Re: Unable to prepare a statement when the object names contain more than one $ symbol  (Michael Paesold <mpaesold@gmx.at>)
List pgsql-jdbc
Now including the attachement... ;-)

Michael Paesold wrote:
> I wrote:
> ...
>> 1) In parseDollarQuotes(), we look at the character directly before
>> the $-char and compare it against all valid identifier characters. If
>> it is, we don't have a possible dollar-quote start:
>>
>>  From scan.l:
>> ident_start             [A-Za-z\200-\377_]
>> ident_cont              [A-Za-z\200-\377_0-9\$]
> ...
>> Looking at gram.y and scan.l (...but I'm no expert) I can't see
>> another case of a dollar-character that I missed, except the one
>> allowed in ident_cont... so option 1) seems like the easiest solution.
>> I will send a patch implementing option 1 shortly.
>
> Ok, here is the patch. It also adds your tests exposing the bug to the
> test suite. The patch fixes both test cases and passes all other
> regression tests (at least with JDK 1.5....). Does it look OK to you?
>
> Should we do anything additional about error-ing out when we detect an
> unterminated dollar-quote (see previous mail)?
>
> Best Regards
> Michael Paesold


Fix dollar quote bug (identifiers may continue with a dollar-character)

diff -r ee30bbde84f5 org/postgresql/core/Parser.java
--- a/org/postgresql/core/Parser.java    Thu Oct 18 16:27:52 2007 +0200
+++ b/org/postgresql/core/Parser.java    Thu Oct 18 18:07:50 2007 +0200
@@ -89,7 +89,8 @@ public class Parser {
      * character.
      */
     public static int parseDollarQuotes(final char[] query, int offset) {
-        if (offset + 1 < query.length)
+        if (offset + 1 < query.length
+                && (offset == 0 || !isIdentifierContChar(query[offset-1])))
         {
             int endIdx = -1;
             if (query[offset + 1] == '$')
@@ -205,6 +206,37 @@ public class Parser {
     }

     /**
+     * Checks if a character is valid as the start of an identifier.
+     *
+     * @param c the character to check
+     * @return true if valid as first character of an identifier; false if not
+     */
+    public static boolean isIdentifierStartChar(char c) {
+        /*
+         * Extracted from {ident_start} and {ident_cont} in
+         * pgsql/src/backend/parser/scan.l:
+         * ident_start    [A-Za-z\200-\377_]
+         * ident_cont     [A-Za-z\200-\377_0-9\$]
+         */
+        return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
+                || c == '_' || c > 127 ;
+    }
+
+    /**
+     * Checks if a character is valid as the second or later character of an
+     * identifier.
+     *
+     * @param c the character to check
+     * @return true if valid as second or later character of an identifier; false if not
+     */
+    public static boolean isIdentifierContChar(char c) {
+        return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
+                || c == '_' || c > 127
+                || (c >= '0' && c <= '9')
+                || c == '$';
+    }
+
+    /**
      * @return true if the character terminates an identifier
      */
     public static boolean charTerminatesIdentifier(char c) {
@@ -228,7 +260,7 @@ public class Parser {
     }

     /**
-     * Checks if a character is valid as the second or latter character of a
+     * Checks if a character is valid as the second or later character of a
      * dollar quoting tag.
      *
      * @param c the character to check
diff -r ee30bbde84f5 org/postgresql/test/jdbc2/PreparedStatementTest.java
--- a/org/postgresql/test/jdbc2/PreparedStatementTest.java    Thu Oct 18 16:27:52 2007 +0200
+++ b/org/postgresql/test/jdbc2/PreparedStatementTest.java    Thu Oct 18 17:36:29 2007 +0200
@@ -405,6 +405,27 @@ public class PreparedStatementTest exten
         st.close();
     }

+    public void testDollarQuotesAndIdentifiers() throws SQLException {
+        // dollar-quotes are supported in the backend since version 8.0
+        if (!TestUtil.haveMinimumServerVersion(conn, "8.0"))
+            return;
+
+        PreparedStatement st;
+
+        conn.createStatement().execute("CREATE TEMP TABLE a$b$c(a varchar, b varchar)");
+        st = conn.prepareStatement("INSERT INTO a$b$c (a, b) VALUES (?, ?)");
+        st.setString(1, "a");
+        st.setString(2, "b");
+        st.executeUpdate();
+        st.close();
+
+        conn.createStatement().execute("CREATE TEMP TABLE e$f$g(h varchar, e$f$g varchar) ");
+        st = conn.prepareStatement("UPDATE e$f$g SET h = ? || e$f$g");
+        st.setString(1, "a");
+        st.executeUpdate();
+        st.close();
+    }
+
     public void testComments() throws SQLException {
         PreparedStatement st;
         ResultSet rs;

pgsql-jdbc by date:

Previous
From: Michael Paesold
Date:
Subject: Re: Unable to prepare a statement when the object names contain more than one $ symbol
Next
From: "Andrei Ilitchev"
Date:
Subject: Fw: postgresql experts please help