Commit 0b707d6e authored by Tom Lane's avatar Tom Lane

Be more careful about newline-chomping in pgbench.

process_backslash_command would drop the last character of the input
command on the assumption that it was a newline.  Given a non newline
terminated input file, this could result in dropping the last character
of the command.  Fix that by doing an actual test that we're removing
a newline.

While at it, allow for Windows newlines (\r\n), and suppress multiple
newlines if any.  I do not think either of those cases really occur,
since (a) we read script files in text mode and (b) the lexer stops
when it hits a newline.  But it's cheap enough and it provides a
stronger guarantee about what the result string looks like.

This is just cosmetic, I think, since the possibly-overly-chomped
line was only used for display not for further processing.  So
it doesn't seem necessary to back-patch.

Fabien Coelho, reviewed by Nikolay Shaplov, whacked around a bit by me

Discussion: https://postgr.es/m/alpine.DEB.2.20.1704171422500.4025@lancre
parent c23bb6ba
...@@ -197,7 +197,6 @@ expr_yyerror_more(yyscan_t yyscanner, const char *message, const char *more) ...@@ -197,7 +197,6 @@ expr_yyerror_more(yyscan_t yyscanner, const char *message, const char *more)
int error_detection_offset = expr_scanner_offset(state) - 1; int error_detection_offset = expr_scanner_offset(state) - 1;
YYSTYPE lval; YYSTYPE lval;
char *full_line; char *full_line;
size_t l;
/* /*
* While parsing an expression, we may not have collected the whole line * While parsing an expression, we may not have collected the whole line
...@@ -210,13 +209,11 @@ expr_yyerror_more(yyscan_t yyscanner, const char *message, const char *more) ...@@ -210,13 +209,11 @@ expr_yyerror_more(yyscan_t yyscanner, const char *message, const char *more)
/* skip */ ; /* skip */ ;
} }
/* Extract the line, trimming trailing newline if any */
full_line = expr_scanner_get_substring(state, full_line = expr_scanner_get_substring(state,
expr_start_offset, expr_start_offset,
expr_scanner_offset(state)); expr_scanner_offset(state),
/* Trim trailing newline if any */ true);
l = strlen(full_line);
while (l > 0 && full_line[l - 1] == '\n')
full_line[--l] = '\0';
syntax_error(expr_source, expr_lineno, full_line, expr_command, syntax_error(expr_source, expr_lineno, full_line, expr_command,
message, more, error_detection_offset - expr_start_offset); message, more, error_detection_offset - expr_start_offset);
...@@ -341,19 +338,30 @@ expr_scanner_offset(PsqlScanState state) ...@@ -341,19 +338,30 @@ expr_scanner_offset(PsqlScanState state)
/* /*
* Get a malloc'd copy of the lexer input string from start_offset * Get a malloc'd copy of the lexer input string from start_offset
* to just before end_offset. * to just before end_offset. If chomp is true, drop any trailing
* newline(s).
*/ */
char * char *
expr_scanner_get_substring(PsqlScanState state, expr_scanner_get_substring(PsqlScanState state,
int start_offset, int end_offset) int start_offset, int end_offset,
bool chomp)
{ {
char *result; char *result;
const char *scanptr = state->scanbuf + start_offset;
int slen = end_offset - start_offset; int slen = end_offset - start_offset;
Assert(slen >= 0); Assert(slen >= 0);
Assert(end_offset <= strlen(state->scanbuf)); Assert(end_offset <= strlen(state->scanbuf));
if (chomp)
{
while (slen > 0 &&
(scanptr[slen - 1] == '\n' || scanptr[slen - 1] == '\r'))
slen--;
}
result = (char *) pg_malloc(slen + 1); result = (char *) pg_malloc(slen + 1);
memcpy(result, state->scanbuf + start_offset, slen); memcpy(result, scanptr, slen);
result[slen] = '\0'; result[slen] = '\0';
return result; return result;
......
...@@ -3065,8 +3065,7 @@ process_backslash_command(PsqlScanState sstate, const char *source) ...@@ -3065,8 +3065,7 @@ process_backslash_command(PsqlScanState sstate, const char *source)
PQExpBufferData word_buf; PQExpBufferData word_buf;
int word_offset; int word_offset;
int offsets[MAX_ARGS]; /* offsets of argument words */ int offsets[MAX_ARGS]; /* offsets of argument words */
int start_offset, int start_offset;
end_offset;
int lineno; int lineno;
int j; int j;
...@@ -3120,13 +3119,11 @@ process_backslash_command(PsqlScanState sstate, const char *source) ...@@ -3120,13 +3119,11 @@ process_backslash_command(PsqlScanState sstate, const char *source)
my_command->expr = expr_parse_result; my_command->expr = expr_parse_result;
/* Get location of the ending newline */ /* Save line, trimming any trailing newline */
end_offset = expr_scanner_offset(sstate) - 1;
/* Save line */
my_command->line = expr_scanner_get_substring(sstate, my_command->line = expr_scanner_get_substring(sstate,
start_offset, start_offset,
end_offset); expr_scanner_offset(sstate),
true);
expr_scanner_finish(yyscanner); expr_scanner_finish(yyscanner);
...@@ -3147,13 +3144,11 @@ process_backslash_command(PsqlScanState sstate, const char *source) ...@@ -3147,13 +3144,11 @@ process_backslash_command(PsqlScanState sstate, const char *source)
my_command->argc++; my_command->argc++;
} }
/* Get location of the ending newline */ /* Save line, trimming any trailing newline */
end_offset = expr_scanner_offset(sstate) - 1;
/* Save line */
my_command->line = expr_scanner_get_substring(sstate, my_command->line = expr_scanner_get_substring(sstate,
start_offset, start_offset,
end_offset); expr_scanner_offset(sstate),
true);
if (pg_strcasecmp(my_command->argv[0], "sleep") == 0) if (pg_strcasecmp(my_command->argv[0], "sleep") == 0)
{ {
......
...@@ -128,7 +128,8 @@ extern yyscan_t expr_scanner_init(PsqlScanState state, ...@@ -128,7 +128,8 @@ extern yyscan_t expr_scanner_init(PsqlScanState state,
extern void expr_scanner_finish(yyscan_t yyscanner); extern void expr_scanner_finish(yyscan_t yyscanner);
extern int expr_scanner_offset(PsqlScanState state); extern int expr_scanner_offset(PsqlScanState state);
extern char *expr_scanner_get_substring(PsqlScanState state, extern char *expr_scanner_get_substring(PsqlScanState state,
int start_offset, int end_offset); int start_offset, int end_offset,
bool chomp);
extern int expr_scanner_get_lineno(PsqlScanState state, int offset); extern int expr_scanner_get_lineno(PsqlScanState state, int offset);
extern void syntax_error(const char *source, int lineno, const char *line, extern void syntax_error(const char *source, int lineno, const char *line,
......
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