From 8c3852aa5572fe3e07af406c4c5cc248d66ee9c4 Mon Sep 17 00:00:00 2001 From: Corey Huinker Date: Sat, 25 Mar 2017 11:26:41 -0400 Subject: [PATCH 3/3] Encapsulate ignore slash options operations. Other bug fixes. --- src/bin/psql/command.c | 307 +++++++++++-------------------------- src/test/regress/expected/psql.out | 28 ++-- src/test/regress/sql/psql.sql | 27 ++-- 3 files changed, 127 insertions(+), 235 deletions(-) diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index a8b8ec2..6ffddd5 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -210,24 +210,19 @@ static char* gather_boolean_expression(PsqlScanState scan_state, bool expansion, bool warn) { enum slash_option_type slash_opt = (expansion) ? OT_NORMAL : OT_NO_EVAL; - char *expression_buffer = NULL; + PQExpBuffer exp_buf = createPQExpBuffer(); int num_options = 0; char *value; /* digest all options for the conditional command */ while ((value = psql_scan_slash_option(scan_state, slash_opt, NULL, false))) { - num_options++; - - if (expression_buffer) - { - char *old_expr_buf = expression_buffer; - expression_buffer = psprintf("%s %s", old_expr_buf, value); - free(old_expr_buf); - free(value); - } + /* add a space in between subsequent tokens */ + if (num_options == 0) + appendPQExpBuffer(exp_buf, "%s", value); else - expression_buffer = value; + appendPQExpBuffer(exp_buf, " %s", value); + num_options++; } /* currently, we expect exactly one option */ @@ -237,10 +232,10 @@ gather_boolean_expression(PsqlScanState scan_state, bool expansion, bool warn) psql_error("WARNING: Boolean expression with no options"); else if (num_options > 1) psql_error("WARNING: Boolean expression with %d options: %s\n", - num_options, expression_buffer); + num_options, exp_buf->data); } - return expression_buffer; + return exp_buf->data; } /* @@ -249,7 +244,9 @@ gather_boolean_expression(PsqlScanState scan_state, bool expansion, bool warn) static void ignore_boolean_expression(PsqlScanState scan_state) { - free(gather_boolean_expression(scan_state, false, false)); + char *p = gather_boolean_expression(scan_state, false, false); + if (p) + free(p); } /* @@ -263,7 +260,8 @@ read_boolean_expression(PsqlScanState scan_state, char *action, { char *expr = gather_boolean_expression(scan_state, true, true); bool success = ParseVariableBool(expr, action, result); - free(expr); + if (expr) + free(expr); return success; } @@ -299,6 +297,39 @@ is_active_branch(PsqlScanState scan_state) return conditional_active(get_conditional_stack(scan_state)); } +/* + * Ignore exactly one slash command option. Return true if an option was found + */ +static bool +ignore_slash_option(PsqlScanState scan_state) +{ + char *p = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, false); + if (!p) + return false; + free(p); + return true; +} + +/* + * Ignore up to two slash command options. + */ +static void +ignore_2_slash_options(PsqlScanState scan_state) +{ + if (ignore_slash_option(scan_state)) + ignore_slash_option(scan_state); +} + +/* + * Ignore exactly one whole-line slash command option. + */ +static void +ignore_slash_line(PsqlScanState scan_state) +{ + char *p = psql_scan_slash_option(scan_state, OT_WHOLE_LINE, NULL, false); + if (p) + free(p); +} /* * \a -- toggle field alignment This makes little sense but we keep it @@ -333,11 +364,7 @@ exec_command_C(PsqlScanState scan_state) free(opt); } else - { - char *p = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, true); - if (p) - free(p); - } + ignore_slash_option(scan_state); return success; } @@ -366,7 +393,6 @@ exec_command_connect(PsqlScanState scan_state) enum trivalue reuse_previous = TRI_DEFAULT; bool success = true; bool active_branch = is_active_branch(scan_state); - const char *warning_context = (active_branch) ? prefix : NULL; opt1 = read_connect_arg(scan_state); if (opt1 != NULL && strncmp(opt1, prefix, sizeof(prefix) - 1) == 0) @@ -374,7 +400,8 @@ exec_command_connect(PsqlScanState scan_state) bool on_off; success = ParseVariableBool(opt1 + sizeof(prefix) - 1, - warning_context, + ((active_branch) ? + "-reuse-previous" : NULL), &on_off); if (success) { @@ -452,11 +479,7 @@ exec_command_cd(PsqlScanState scan_state, const char *cmd) free(opt); } else - { - char *opt = psql_scan_slash_option(scan_state, - OT_NO_EVAL, NULL, true); - free(opt); - } + ignore_slash_option(scan_state); return success; } @@ -552,12 +575,8 @@ exec_command_crosstabview(PsqlScanState scan_state, backslashResult *status) } else { - char *p; for (i = 0; i < lengthof(pset.ctv_args); i++) - { - p = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, true); - free(p); - } + ignore_slash_option(scan_state); } return true; } @@ -756,14 +775,9 @@ exec_command_d(PsqlScanState scan_state, const char *cmd, else { /* digest and discard options as appropriate */ - char *pattern = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, true); + pattern = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, true); if (pattern && cmd[1] == 'r' && cmd[2] == 'd' && cmd[3] == 's') - { - char *pattern2 = psql_scan_slash_option(scan_state, - OT_NO_EVAL, NULL, true); - free(pattern2); - } - + ignore_slash_option(scan_state); } if (pattern) @@ -840,23 +854,7 @@ exec_command_edit(PsqlScanState scan_state, PQExpBuffer query_buf, else { if (query_buf) - { - char *fname; - - fname = psql_scan_slash_option(scan_state, - OT_NO_EVAL, NULL, true); - if (fname) - { - char *ln; - /* try to get separate lineno arg */ - ln = psql_scan_slash_option(scan_state, - OT_NO_EVAL, NULL, true); - if (ln) - free(ln); - } - if (fname) - free(fname); - } + ignore_2_slash_options(scan_state); } return true; @@ -966,11 +964,8 @@ exec_command_ef(PsqlScanState scan_state, PQExpBuffer query_buf, } } else - { - char *p = psql_scan_slash_option(scan_state, OT_WHOLE_LINE, NULL, true); - if (p) - free(p); - } + ignore_slash_line(scan_state); + return true; } @@ -1049,11 +1044,7 @@ exec_command_ev(PsqlScanState scan_state, PQExpBuffer query_buf, } } else - { - char *p = psql_scan_slash_option(scan_state, OT_WHOLE_LINE, NULL, true); - if (p) - free(p); - } + ignore_slash_line(scan_state); return true; } @@ -1136,11 +1127,7 @@ exec_command_encoding(PsqlScanState scan_state) } } else - { - encoding = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, false); - if (encoding) - free(encoding); - } + ignore_slash_option(scan_state); return true; } @@ -1187,11 +1174,7 @@ exec_command_f(PsqlScanState scan_state) free(fname); } else - { - fname = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, false); - if (fname) - free(fname); - } + ignore_slash_option(scan_state); return success; } @@ -1222,11 +1205,7 @@ exec_command_g(PsqlScanState scan_state, const char *cmd, backslashResult *statu *status = PSQL_CMD_SEND; } else - { - fname = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, false); - if (fname) - free(fname); - } + ignore_slash_option(scan_state); return true; } @@ -1263,9 +1242,7 @@ exec_command_gset(PsqlScanState scan_state, backslashResult *status) *status = PSQL_CMD_SEND; } else - { - prefix = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, false); - } + ignore_slash_option(scan_state); return true; } @@ -1296,11 +1273,7 @@ exec_command_help(PsqlScanState scan_state) free(opt); } else - { - opt = psql_scan_slash_option(scan_state, OT_WHOLE_LINE, NULL, false); - if (opt) - free(opt); - } + ignore_slash_line(scan_state); return true; } @@ -1351,11 +1324,7 @@ exec_command_include(PsqlScanState scan_state, const char *cmd) } } else - { - fname = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, true); - if (fname) - free(fname); - } + ignore_slash_option(scan_state); return success; } @@ -1525,11 +1494,11 @@ exec_command_endif(PsqlScanState scan_state) static bool exec_command_list(PsqlScanState scan_state, const char *cmd) { - char *pattern; bool success = true; if (is_active_branch(scan_state)) { + char *pattern; bool show_verbose; pattern = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true); @@ -1538,14 +1507,12 @@ exec_command_list(PsqlScanState scan_state, const char *cmd) success = listAllDbs(pattern, show_verbose); + if (pattern) + free(pattern); } else - { - pattern = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, true); - } + ignore_slash_option(scan_state); - if (pattern) - free(pattern); return success; } @@ -1615,16 +1582,7 @@ exec_command_lo(PsqlScanState scan_state, const char *cmd, backslashResult *stat free(opt2); } else - { - opt1 = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, true); - if (opt1) - { - free(opt1); - opt2 = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, true); - if (opt2) - free(opt2); - } - } + ignore_2_slash_options(scan_state); return success; } @@ -1646,11 +1604,7 @@ exec_command_out(PsqlScanState scan_state) free(fname); } else - { - fname = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, true); - if (fname) - free(fname); - } + ignore_slash_option(scan_state); return success; } @@ -1732,11 +1686,7 @@ exec_command_password(PsqlScanState scan_state) } } else - { - char *p = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, true); - if (p) - free(p); - } + ignore_slash_option(scan_state); return success; } @@ -1807,16 +1757,7 @@ exec_command_prompt(PsqlScanState scan_state, const char *cmd) } } else - { - arg1 = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, false); - if (arg1) - { - free(arg1); - arg2 = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, false); - if (arg2) - free(arg2); - } - } + ignore_2_slash_options(scan_state); return success; } @@ -1868,17 +1809,7 @@ exec_command_pset(PsqlScanState scan_state) free(opt1); } else - { - opt0 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false); - - if (opt0) - { - free(opt0); - opt1 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false); - if (opt1) - free(opt1); - } - } + ignore_2_slash_options(scan_state); return success; } @@ -1928,11 +1859,7 @@ exec_command_s(PsqlScanState scan_state) free(fname); } else - { - fname = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, true); - if (fname) - free(fname); - } + ignore_slash_option(scan_state); return success; } @@ -1983,11 +1910,8 @@ exec_command_set(PsqlScanState scan_state) free(opt0); } else - { - opt0 = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, false); - if (opt0) - free(opt0); - } + while (ignore_slash_option(scan_state)) + continue; return success; } @@ -2041,17 +1965,7 @@ exec_command_setenv(PsqlScanState scan_state, const char *cmd) free(envval); } else - { - envvar = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, false); - - if (envvar) - { - free(envvar); - envval = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, false); - if (envval) - free(envval); - } - } + ignore_2_slash_options(scan_state); return success; } @@ -2143,11 +2057,7 @@ exec_command_sf(PsqlScanState scan_state, const char *cmd, destroyPQExpBuffer(func_buf); } else - { - func = psql_scan_slash_option(scan_state, OT_WHOLE_LINE, NULL, true); - if (func) - free(func); - } + ignore_slash_line(scan_state); return true; } @@ -2233,12 +2143,7 @@ exec_command_sv(PsqlScanState scan_state, const char *cmd, destroyPQExpBuffer(view_buf); } else - { - view = psql_scan_slash_option(scan_state, - OT_WHOLE_LINE, NULL, true); - if (view) - free(view); - } + ignore_slash_line(scan_state); return true; } @@ -2258,11 +2163,7 @@ exec_command_t(PsqlScanState scan_state) free(opt); } else - { - opt = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, true); - if (opt) - free(opt); - } + ignore_slash_option(scan_state); return success; } @@ -2282,11 +2183,7 @@ exec_command_T(PsqlScanState scan_state) free(value); } else - { - value = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, false); - if (value) - free(value); - } + ignore_slash_option(scan_state); return success; } @@ -2316,11 +2213,7 @@ exec_command_timing(PsqlScanState scan_state) free(opt); } else - { - opt = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, false); - if (opt) - free(opt); - } + ignore_slash_option(scan_state); return success; } @@ -2348,11 +2241,7 @@ exec_command_unset(PsqlScanState scan_state, const char *cmd) free(opt); } else - { - opt = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, false); - if (opt) - free(opt); - } + ignore_slash_option(scan_state); return success; } @@ -2476,11 +2365,7 @@ exec_command_watch(PsqlScanState scan_state, PQExpBuffer query_buf) psql_scan_reset(scan_state); } else - { - opt = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, true); - if (opt) - free(opt); - } + ignore_slash_option(scan_state); return success; } @@ -2500,11 +2385,7 @@ exec_command_x(PsqlScanState scan_state) free(opt); } else - { - opt = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, true); - if (opt) - free(opt); - } + ignore_slash_option(scan_state); return success; } @@ -2525,11 +2406,7 @@ exec_command_z(PsqlScanState scan_state) free(pattern); } else - { - pattern = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, true); - if (pattern) - free(pattern); - } + ignore_slash_option(scan_state); return success; } @@ -2549,11 +2426,7 @@ exec_command_shell_escape(PsqlScanState scan_state) free(opt); } else - { - opt = psql_scan_slash_option(scan_state, OT_WHOLE_LINE, NULL, false); - if (opt) - free(opt); - } + ignore_slash_line(scan_state); return success; } @@ -2576,12 +2449,12 @@ exec_command_slash_command_help(PsqlScanState scan_state) helpVariables(pset.popt.topt.pager); else slashUsage(pset.popt.topt.pager); + + if (opt0) + free(opt0); } else - opt0 = psql_scan_slash_option(scan_state, OT_NO_EVAL, NULL, false); - - if (opt0) - free(opt0); + ignore_slash_option(scan_state); return true; } diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out index c9fb1a0..5774c98 100644 --- a/src/test/regress/expected/psql.out +++ b/src/test/regress/expected/psql.out @@ -2824,16 +2824,26 @@ will print anyway #6-2 \echo 'should print #7-4' should print #7-4 \endif --- show that variables still expand even in false blocks -\set var 'ab''cd' --- select :var; +-- show that vars are not expanded and commands are ignored but args are parsed +\set try_to_quit '\\q' \if false - select :var; --- this will be skipped because of an unterminated string -\endif --- fix the unterminated string -'; --- now the if block can be properly ended + :try_to_quit + \a \C arg1 \c arg1 arg2 arg3 arg4 \cd arg1 \conninfo + \copy arg1 arg2 arg3 arg4 arg5 arg6 + \copyright \dt arg1 \e arg1 arg2 + \ef whole_line + \ev whole_line + \echo arg1 arg2 arg3 arg4 arg5 \echo arg1 \encoding arg1 \errverbose + \g arg1 \gx arg1 \gexec \h \html \i arg1 \ir arg1 \l arg1 \lo arg1 arg2 + \o arg1 \p \password arg1 \prompt arg1 arg2 \pset arg1 arg2 \q + \reset \s arg1 \set arg1 arg2 arg3 arg4 arg5 arg6 arg7 \setenv arg1 arg2 + \sf whole_line + \sv whole_line + \t arg1 \T arg1 \timing arg1 \unset arg1 \w arg1 \watch arg1 \x arg1 + \! whole_line +\else + \echo 'should print #8-1' +should print #8-1 \endif -- SHOW_CONTEXT \set SHOW_CONTEXT never diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql index c812e97..078a76f 100644 --- a/src/test/regress/sql/psql.sql +++ b/src/test/regress/sql/psql.sql @@ -470,16 +470,25 @@ deallocate q; \echo 'should print #7-4' \endif --- show that variables still expand even in false blocks -\set var 'ab''cd' --- select :var; +-- show that vars are not expanded and commands are ignored but args are parsed +\set try_to_quit '\\q' \if false - select :var; --- this will be skipped because of an unterminated string -\endif --- fix the unterminated string -'; --- now the if block can be properly ended + :try_to_quit + \a \C arg1 \c arg1 arg2 arg3 arg4 \cd arg1 \conninfo + \copy arg1 arg2 arg3 arg4 arg5 arg6 + \copyright \dt arg1 \e arg1 arg2 + \ef whole_line + \ev whole_line + \echo arg1 arg2 arg3 arg4 arg5 \echo arg1 \encoding arg1 \errverbose + \g arg1 \gx arg1 \gexec \h \html \i arg1 \ir arg1 \l arg1 \lo arg1 arg2 + \o arg1 \p \password arg1 \prompt arg1 arg2 \pset arg1 arg2 \q + \reset \s arg1 \set arg1 arg2 arg3 arg4 arg5 arg6 arg7 \setenv arg1 arg2 + \sf whole_line + \sv whole_line + \t arg1 \T arg1 \timing arg1 \unset arg1 \w arg1 \watch arg1 \x arg1 + \! whole_line +\else + \echo 'should print #8-1' \endif -- SHOW_CONTEXT -- 2.7.4