@@ -566,42 +566,15 @@ psql_scan_slash_option(PsqlScanState state,
566566
567567/*
568568 * If SQL identifier processing was requested, then we strip out
569- * excess double quotes and downcase unquoted letters.
570- * Doubled double-quotes become output double-quotes, per spec.
571- *
572- * Note that a string like FOO"BAR"BAZ will be converted to
573- * fooBARbaz; this is somewhat inconsistent with the SQL spec,
574- * which would have us parse it as several identifiers. But
575- * for psql's purposes, we want a string like "foo"."bar" to
576- * be treated as one option, so there's little choice.
569+ * excess double quotes and optionally downcase unquoted letters.
577570 */
578571if (type == OT_SQLID || type == OT_SQLIDHACK)
579572{
580- bool inquotes =false ;
581- char *cp = mybuf.data ;
582-
583- while (*cp)
584- {
585- if (*cp ==' "' )
586- {
587- if (inquotes && cp[1 ] ==' "' )
588- {
589- /* Keep the first quote, remove the second */
590- cp++;
591- }
592- inquotes = !inquotes;
593- /* Collapse out quote at *cp */
594- memmove (cp, cp +1 ,strlen (cp));
595- mybuf.len --;
596- /* do not advance cp */
597- }
598- else
599- {
600- if (!inquotes && type == OT_SQLID)
601- *cp =pg_tolower ((unsigned char ) *cp);
602- cp +=PQmblen (cp, state->encoding );
603- }
604- }
573+ dequote_downcase_identifier (mybuf.data ,
574+ (type != OT_SQLIDHACK),
575+ state->encoding );
576+ /* update mybuf.len for possible shortening */
577+ mybuf.len =strlen (mybuf.data );
605578}
606579break ;
607580case xslashquote:
@@ -667,6 +640,51 @@ psql_scan_slash_command_end(PsqlScanState state)
667640psql_scan_reselect_sql_lexer (state);
668641}
669642
643+ /*
644+ * De-quote and optionally downcase a SQL identifier.
645+ *
646+ * The string at *str is modified in-place; it can become shorter,
647+ * but not longer.
648+ *
649+ * If downcase is true then non-quoted letters are folded to lower case.
650+ * Ideally this behavior will match the backend's downcase_identifier();
651+ * but note that it could differ if LC_CTYPE is different in the frontend.
652+ *
653+ * Note that a string like FOO"BAR"BAZ will be converted to fooBARbaz;
654+ * this is somewhat inconsistent with the SQL spec, which would have us
655+ * parse it as several identifiers. But for psql's purposes, we want a
656+ * string like "foo"."bar" to be treated as one option, so there's little
657+ * choice; this routine doesn't get to change the token boundaries.
658+ */
659+ void
660+ dequote_downcase_identifier (char *str,bool downcase,int encoding)
661+ {
662+ bool inquotes =false ;
663+ char *cp = str;
664+
665+ while (*cp)
666+ {
667+ if (*cp ==' "' )
668+ {
669+ if (inquotes && cp[1 ] ==' "' )
670+ {
671+ /* Keep the first quote, remove the second */
672+ cp++;
673+ }
674+ inquotes = !inquotes;
675+ /* Collapse out quote at *cp */
676+ memmove (cp, cp +1 ,strlen (cp));
677+ /* do not advance cp */
678+ }
679+ else
680+ {
681+ if (downcase && !inquotes)
682+ *cp =pg_tolower ((unsigned char ) *cp);
683+ cp +=PQmblen (cp, encoding);
684+ }
685+ }
686+ }
687+
670688/*
671689 * Evaluate a backticked substring of a slash command's argument.
672690 *