Commit 9603a325 authored by Tom Lane's avatar Tom Lane

Avoid code duplication in \crosstabview.

In commit 6f0d6a50 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.
parent 4039c736
......@@ -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;
......
......@@ -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 */
......@@ -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.
*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment