OSDN Git Service

Teach PQescapeByteaConn() to use hex format when the target connection is
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 4 Aug 2009 18:05:42 +0000 (18:05 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 4 Aug 2009 18:05:42 +0000 (18:05 +0000)
to a server >= 8.5.  Per my proposal in discussion of hex-format patch.

src/interfaces/libpq/fe-exec.c

index f1318a4..df9ece0 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.204 2009/08/04 16:08:36 tgl Exp $
+ *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.205 2009/08/04 18:05:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -3058,23 +3058,52 @@ PQescapeString(char *to, const char *from, size_t length)
                                                                  static_std_strings);
 }
 
+
+/* HEX encoding support for bytea */
+static const char hextbl[] = "0123456789abcdef";
+
+static const int8 hexlookup[128] = {
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+       0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
+       -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+
+static inline char
+get_hex(char c)
+{
+       int                     res = -1;
+
+       if (c > 0 && c < 127)
+               res = hexlookup[(unsigned char) c];
+
+       return (char) res;
+}
+
+
 /*
  *             PQescapeBytea   - converts from binary string to the
  *             minimal encoding necessary to include the string in an SQL
  *             INSERT statement with a bytea type column as the target.
  *
- *             The following transformations are applied
+ *             We can use either hex or escape (traditional) encoding.
+ *             In escape mode, the following transformations are applied:
  *             '\0' == ASCII  0 == \000
  *             '\'' == ASCII 39 == ''
  *             '\\' == ASCII 92 == \\
  *             anything < 0x20, or > 0x7e ---> \ooo
  *                                                                             (where ooo is an octal expression)
+ *
  *             If not std_strings, all backslashes sent to the output are doubled.
  */
 static unsigned char *
 PQescapeByteaInternal(PGconn *conn,
                                          const unsigned char *from, size_t from_length,
-                                         size_t *to_length, bool std_strings)
+                                         size_t *to_length, bool std_strings, bool use_hex)
 {
        const unsigned char *vp;
        unsigned char *rp;
@@ -3088,17 +3117,24 @@ PQescapeByteaInternal(PGconn *conn,
         */
        len = 1;
 
-       vp = from;
-       for (i = from_length; i > 0; i--, vp++)
+       if (use_hex)
        {
-               if (*vp < 0x20 || *vp > 0x7e)
-                       len += bslash_len + 3;
-               else if (*vp == '\'')
-                       len += 2;
-               else if (*vp == '\\')
-                       len += bslash_len + bslash_len;
-               else
-                       len++;
+               len += bslash_len + 1 + 2 * from_length;
+       }
+       else
+       {
+               vp = from;
+               for (i = from_length; i > 0; i--, vp++)
+               {
+                       if (*vp < 0x20 || *vp > 0x7e)
+                               len += bslash_len + 3;
+                       else if (*vp == '\'')
+                               len += 2;
+                       else if (*vp == '\\')
+                               len += bslash_len + bslash_len;
+                       else
+                               len++;
+               }
        }
 
        *to_length = len;
@@ -3111,26 +3147,39 @@ PQescapeByteaInternal(PGconn *conn,
                return NULL;
        }
 
+       if (use_hex)
+       {
+               if (!std_strings)
+                       *rp++ = '\\';
+               *rp++ = '\\';
+               *rp++ = 'x';
+       }
+
        vp = from;
        for (i = from_length; i > 0; i--, vp++)
        {
-               if (*vp < 0x20 || *vp > 0x7e)
-               {
-                       int                     val = *vp;
+               unsigned char c = *vp;
 
+               if (use_hex)
+               {
+                       *rp++ = hextbl[(c >> 4) & 0xF];
+                       *rp++ = hextbl[c & 0xF];
+               }
+               else if (c < 0x20 || c > 0x7e)
+               {
                        if (!std_strings)
                                *rp++ = '\\';
                        *rp++ = '\\';
-                       *rp++ = (val >> 6) + '0';
-                       *rp++ = ((val >> 3) & 07) + '0';
-                       *rp++ = (val & 07) + '0';
+                       *rp++ = (c >> 6) + '0';
+                       *rp++ = ((c >> 3) & 07) + '0';
+                       *rp++ = (c & 07) + '0';
                }
-               else if (*vp == '\'')
+               else if (c == '\'')
                {
                        *rp++ = '\'';
                        *rp++ = '\'';
                }
-               else if (*vp == '\\')
+               else if (c == '\\')
                {
                        if (!std_strings)
                        {
@@ -3141,7 +3190,7 @@ PQescapeByteaInternal(PGconn *conn,
                        *rp++ = '\\';
                }
                else
-                       *rp++ = *vp;
+                       *rp++ = c;
        }
        *rp = '\0';
 
@@ -3156,37 +3205,16 @@ PQescapeByteaConn(PGconn *conn,
        if (!conn)
                return NULL;
        return PQescapeByteaInternal(conn, from, from_length, to_length,
-                                                                conn->std_strings);
+                                                                conn->std_strings,
+                                                                (conn->sversion >= 80500));
 }
 
 unsigned char *
 PQescapeBytea(const unsigned char *from, size_t from_length, size_t *to_length)
 {
        return PQescapeByteaInternal(NULL, from, from_length, to_length,
-                                                                static_std_strings);
-}
-
-
-static const int8 hexlookup[128] = {
-       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-       0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-       -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-       -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-};
-
-static inline char
-get_hex(char c)
-{
-       int                     res = -1;
-
-       if (c > 0 && c < 127)
-               res = hexlookup[(unsigned char) c];
-
-       return (char) res;
+                                                                static_std_strings,
+                                                                false /* can't use hex */ );
 }