@@ -566,42 +566,15 @@ psql_scan_slash_option(PsqlScanState state,
566
566
567
567
/*
568
568
* 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.
577
570
*/
578
571
if (type == OT_SQLID || type == OT_SQLIDHACK)
579
572
{
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 );
605
578
}
606
579
break ;
607
580
case xslashquote:
@@ -667,6 +640,51 @@ psql_scan_slash_command_end(PsqlScanState state)
667
640
psql_scan_reselect_sql_lexer (state);
668
641
}
669
642
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
+
670
688
/*
671
689
* Evaluate a backticked substring of a slash command's argument.
672
690
*
0 commit comments