]> granicus.if.org Git - postgresql/commitdiff
Avoid code duplication in \crosstabview.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 17 Apr 2016 15:37:58 +0000 (11:37 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 17 Apr 2016 15:37:58 +0000 (11:37 -0400)
In commit 6f0d6a507 I added a duplicate copy of psqlscanslash's identifier
downcasing code, but actually it's not hard to split that out as a callable
subroutine and avoid the duplication.

src/bin/psql/crosstabview.c
src/bin/psql/psqlscanslash.h
src/bin/psql/psqlscanslash.l

index 71abaf3a6fe85b15f7a6507eb1b8a59bf5fcfb27..7685c6e74672f3943106cd3bf3adc158bb5e6625 100644 (file)
@@ -12,6 +12,7 @@
 #include "common.h"
 #include "crosstabview.h"
 #include "pqexpbuffer.h"
+#include "psqlscanslash.h"
 #include "settings.h"
 
 
@@ -648,39 +649,14 @@ indexOfColumn(char *arg, const PGresult *res)
        }
        else
        {
-               bool            inquotes = false;
-               char       *cp = arg;
                int                     i;
 
                /*
                 * Dequote and downcase the column name.  By checking for all-digits
                 * before doing this, we can ensure that a quoted name is treated as a
-                * name even if it's all digits.  This transformation should match
-                * what psqlscanslash.l does in OT_SQLID mode.  (XXX ideally we would
-                * let the lexer do this, but then we couldn't tell if the name was
-                * quoted.)
+                * name even if it's all digits.
                 */
-               while (*cp)
-               {
-                       if (*cp == '"')
-                       {
-                               if (inquotes && cp[1] == '"')
-                               {
-                                       /* Keep the first quote, remove the second */
-                                       cp++;
-                               }
-                               inquotes = !inquotes;
-                               /* Collapse out quote at *cp */
-                               memmove(cp, cp + 1, strlen(cp));
-                               /* do not advance cp */
-                       }
-                       else
-                       {
-                               if (!inquotes)
-                                       *cp = pg_tolower((unsigned char) *cp);
-                               cp += PQmblen(cp, pset.encoding);
-                       }
-               }
+               dequote_downcase_identifier(arg, true, pset.encoding);
 
                /* Now look for match(es) among res' column names */
                idx = -1;
index 48553647a905188bf9dbbf265fbeff37a436f9e7..f078f698e85c773d0314909497311739afe13745 100644 (file)
@@ -32,4 +32,6 @@ extern char *psql_scan_slash_option(PsqlScanState state,
 
 extern void psql_scan_slash_command_end(PsqlScanState state);
 
+extern void dequote_downcase_identifier(char *str, bool downcase, int encoding);
+
 #endif   /* PSQLSCANSLASH_H */
index e3e0db3b2fb50c9389f393a6912d73fe9647956a..90854afeb0e049322d589c45172e1f02b3cef938 100644 (file)
@@ -566,42 +566,15 @@ psql_scan_slash_option(PsqlScanState state,
 
                        /*
                         * If SQL identifier processing was requested, then we strip out
-                        * excess double quotes and downcase unquoted letters.
-                        * Doubled double-quotes become output double-quotes, per spec.
-                        *
-                        * Note that a string like FOO"BAR"BAZ will be converted to
-                        * fooBARbaz; this is somewhat inconsistent with the SQL spec,
-                        * which would have us parse it as several identifiers.  But
-                        * for psql's purposes, we want a string like "foo"."bar" to
-                        * be treated as one option, so there's little choice.
+                        * excess double quotes and optionally downcase unquoted letters.
                         */
                        if (type == OT_SQLID || type == OT_SQLIDHACK)
                        {
-                               bool            inquotes = false;
-                               char       *cp = mybuf.data;
-
-                               while (*cp)
-                               {
-                                       if (*cp == '"')
-                                       {
-                                               if (inquotes && cp[1] == '"')
-                                               {
-                                                       /* Keep the first quote, remove the second */
-                                                       cp++;
-                                               }
-                                               inquotes = !inquotes;
-                                               /* Collapse out quote at *cp */
-                                               memmove(cp, cp + 1, strlen(cp));
-                                               mybuf.len--;
-                                               /* do not advance cp */
-                                       }
-                                       else
-                                       {
-                                               if (!inquotes && type == OT_SQLID)
-                                                       *cp = pg_tolower((unsigned char) *cp);
-                                               cp += PQmblen(cp, state->encoding);
-                                       }
-                               }
+                               dequote_downcase_identifier(mybuf.data,
+                                                                                       (type != OT_SQLIDHACK),
+                                                                                       state->encoding);
+                               /* update mybuf.len for possible shortening */
+                               mybuf.len = strlen(mybuf.data);
                        }
                        break;
                case xslashquote:
@@ -667,6 +640,51 @@ psql_scan_slash_command_end(PsqlScanState state)
        psql_scan_reselect_sql_lexer(state);
 }
 
+/*
+ * De-quote and optionally downcase a SQL identifier.
+ *
+ * The string at *str is modified in-place; it can become shorter,
+ * but not longer.
+ *
+ * If downcase is true then non-quoted letters are folded to lower case.
+ * Ideally this behavior will match the backend's downcase_identifier();
+ * but note that it could differ if LC_CTYPE is different in the frontend.
+ *
+ * Note that a string like FOO"BAR"BAZ will be converted to fooBARbaz;
+ * this is somewhat inconsistent with the SQL spec, which would have us
+ * parse it as several identifiers.  But for psql's purposes, we want a
+ * string like "foo"."bar" to be treated as one option, so there's little
+ * choice; this routine doesn't get to change the token boundaries.
+ */
+void
+dequote_downcase_identifier(char *str, bool downcase, int encoding)
+{
+       bool            inquotes = false;
+       char       *cp = str;
+
+       while (*cp)
+       {
+               if (*cp == '"')
+               {
+                       if (inquotes && cp[1] == '"')
+                       {
+                               /* Keep the first quote, remove the second */
+                               cp++;
+                       }
+                       inquotes = !inquotes;
+                       /* Collapse out quote at *cp */
+                       memmove(cp, cp + 1, strlen(cp));
+                       /* do not advance cp */
+               }
+               else
+               {
+                       if (downcase && !inquotes)
+                               *cp = pg_tolower((unsigned char) *cp);
+                       cp += PQmblen(cp, encoding);
+               }
+       }
+}
+
 /*
  * Evaluate a backticked substring of a slash command's argument.
  *