Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 9603a32

Browse files
committed
Avoid code duplication in \crosstabview.
In commit 6f0d6a5 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.
1 parent 4039c73 commit 9603a32

File tree

3 files changed

+56
-60
lines changed

3 files changed

+56
-60
lines changed

src/bin/psql/crosstabview.c

+3-27
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "common.h"
1313
#include "crosstabview.h"
1414
#include "pqexpbuffer.h"
15+
#include "psqlscanslash.h"
1516
#include "settings.h"
1617

1718

@@ -648,39 +649,14 @@ indexOfColumn(char *arg, const PGresult *res)
648649
}
649650
else
650651
{
651-
bool inquotes = false;
652-
char *cp = arg;
653652
int i;
654653

655654
/*
656655
* Dequote and downcase the column name. By checking for all-digits
657656
* before doing this, we can ensure that a quoted name is treated as a
658-
* name even if it's all digits. This transformation should match
659-
* what psqlscanslash.l does in OT_SQLID mode. (XXX ideally we would
660-
* let the lexer do this, but then we couldn't tell if the name was
661-
* quoted.)
657+
* name even if it's all digits.
662658
*/
663-
while (*cp)
664-
{
665-
if (*cp == '"')
666-
{
667-
if (inquotes && cp[1] == '"')
668-
{
669-
/* Keep the first quote, remove the second */
670-
cp++;
671-
}
672-
inquotes = !inquotes;
673-
/* Collapse out quote at *cp */
674-
memmove(cp, cp + 1, strlen(cp));
675-
/* do not advance cp */
676-
}
677-
else
678-
{
679-
if (!inquotes)
680-
*cp = pg_tolower((unsigned char) *cp);
681-
cp += PQmblen(cp, pset.encoding);
682-
}
683-
}
659+
dequote_downcase_identifier(arg, true, pset.encoding);
684660

685661
/* Now look for match(es) among res' column names */
686662
idx = -1;

src/bin/psql/psqlscanslash.h

+2
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,6 @@ extern char *psql_scan_slash_option(PsqlScanState state,
3232

3333
extern void psql_scan_slash_command_end(PsqlScanState state);
3434

35+
extern void dequote_downcase_identifier(char *str, bool downcase, int encoding);
36+
3537
#endif /* PSQLSCANSLASH_H */

src/bin/psql/psqlscanslash.l

+51-33
Original file line numberDiff line numberDiff line change
@@ -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
*/
578571
if (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
}
606579
break;
607580
case xslashquote:
@@ -667,6 +640,51 @@ psql_scan_slash_command_end(PsqlScanState state)
667640
psql_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
*

0 commit comments

Comments
 (0)