Trailing semicolons in psql patch
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
How about a patch to strip semicolons in psql? I *know*
some of you have done this before:
\d mytable;
(Did not find any relation named "mytable;")
Since there is no reason to have a table named "mytable;"
why not just have psql do the smart thing and silently
strip the trailing semicolons? The attached patch only addresses
a few backslash commands as a proof of concept, but some others
could probably use it without harm. The patch affects:
\C
\c
\d
\e
\i
\o
\s
\z
Greg Sabino Mullane
greg@turnstep.com
PGP Key: 0x14964AC8 200109271811
P.S. Re: microtiming: EXPLAIN ANALYZE sounds interesting, and as
soon as cvs is fixed so that anoncvs/postgresql works, I'll take
a look at it. :)
-----BEGIN PGP SIGNATURE-----
Comment: http://www.turnstep.com/pgp.html
iQA/AwUBO7OkzrybkGcUlkrIEQIPrgCgurQBAqZLt6m5JvbKOJyVIOx3ZQAAn0Wg
KD097oaniENYAeikbSM7LdZg
=erHC
-----END PGP SIGNATURE-----
I like it. Several people have complained because they forget and add
the semicolon. I like that you made it per-command so commands that
need to see the semicolon see it. I will change it slightly to use
true/false rather than 0/1.
Your patch has been added to the PostgreSQL unapplied patches list at:
http://candle.pha.pa.us/cgi-bin/pgpatches
I will try to apply it within the next 48 hours.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1How about a patch to strip semicolons in psql? I *know*
some of you have done this before:\d mytable;
(Did not find any relation named "mytable;")
Since there is no reason to have a table named "mytable;"
why not just have psql do the smart thing and silently
strip the trailing semicolons? The attached patch only addresses
a few backslash commands as a proof of concept, but some others
could probably use it without harm. The patch affects:\C
\c
\d
\e
\i
\o
\s
\zGreg Sabino Mullane
greg@turnstep.com
PGP Key: 0x14964AC8 200109271811P.S. Re: microtiming: EXPLAIN ANALYZE sounds interesting, and as
soon as cvs is fixed so that anoncvs/postgresql works, I'll take
a look at it. :)-----BEGIN PGP SIGNATURE-----
Comment: http://www.turnstep.com/pgp.htmliQA/AwUBO7OkzrybkGcUlkrIEQIPrgCgurQBAqZLt6m5JvbKOJyVIOx3ZQAAn0Wg
KD097oaniENYAeikbSM7LdZg
=erHC
-----END PGP SIGNATURE-----
*** ./src/bin/psql/command.c.orig Tue Sep 25 13:21:50 2001 --- ./src/bin/psql/command.c Tue Sep 25 18:06:37 2001 *************** *** 55,61 **** { OT_NORMAL, OT_SQLID, OT_FILEPIPE }; ! static char *scan_option(char **string, enum option_type type, char *quote); static char *unescape(const unsigned char *source, size_t len);static bool do_edit(const char *filename_arg, PQExpBuffer query_buf); --- 55,61 ---- { OT_NORMAL, OT_SQLID, OT_FILEPIPE }; ! static char *scan_option(char **string, enum option_type type, char *quote, bool semicolon); static char *unescape(const unsigned char *source, size_t len);static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
***************
*** 216,222 ****
/* \C -- override table title (formerly change HTML caption) */
else if (strcmp(cmd, "C") == 0)
{
! char *opt = scan_option(&string, OT_NORMAL, NULL);success = do_pset("title", opt, &pset.popt, quiet); free(opt); --- 216,222 ---- /* \C -- override table title (formerly change HTML caption) */ else if (strcmp(cmd, "C") == 0) { ! char *opt = scan_option(&string, OT_NORMAL, NULL, 1);success = do_pset("title", opt, &pset.popt, quiet);
free(opt);
***************
*** 238,245 ****
char opt1q,
opt2q;! opt1 = scan_option(&string, OT_NORMAL, &opt1q);
! opt2 = scan_option(&string, OT_NORMAL, &opt2q);if (opt2) /* gave username */ --- 238,245 ---- char opt1q, opt2q;! opt1 = scan_option(&string, OT_NORMAL, &opt1q, 1);
! opt2 = scan_option(&string, OT_NORMAL, &opt2q, 1);if (opt2)
/* gave username */
***************
*** 273,280 ****
{
char *name;
bool show_verbose;- name = scan_option(&string, OT_SQLID, NULL);
show_verbose = strchr(cmd, '+') ? true : false;switch (cmd[1]) --- 273,280 ---- { char *name; bool show_verbose; + name = scan_option(&string, OT_SQLID, NULL, 1);show_verbose = strchr(cmd, '+') ? true : false;
switch (cmd[1]) *************** *** 337,343 **** } else { ! fname = scan_option(&string, OT_NORMAL, NULL); status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR; free(fname); } --- 337,343 ---- } else { ! fname = scan_option(&string, OT_NORMAL, NULL, 1); status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR; free(fname); } *************** *** 356,363 **** fout = pset.queryFout; else fout = stdout; ! ! while ((value = scan_option(&string, OT_NORMAL, "ed))) { if (!quoted && strcmp(value, "-n") == 0) no_newline = true; --- 356,363 ---- fout = pset.queryFout; else fout = stdout; ! ! while ((value = scan_option(&string, OT_NORMAL, "ed, 0))) { if (!quoted && strcmp(value, "-n") == 0) no_newline = true; *************** *** 378,384 **** /* \encoding -- set/show client side encoding */ else if (strcmp(cmd, "encoding") == 0) { ! char *encoding = scan_option(&string, OT_NORMAL, NULL);if (!encoding) /* show encoding */ --- 378,384 ---- /* \encoding -- set/show client side encoding */ else if (strcmp(cmd, "encoding") == 0) { ! char *encoding = scan_option(&string, OT_NORMAL, NULL, 0);if (!encoding)
/* show encoding */
***************
*** 406,412 ****
/* \f -- change field separator */
else if (strcmp(cmd, "f") == 0)
{
! char *fname = scan_option(&string, OT_NORMAL, NULL);success = do_pset("fieldsep", fname, &pset.popt, quiet); free(fname); --- 406,412 ---- /* \f -- change field separator */ else if (strcmp(cmd, "f") == 0) { ! char *fname = scan_option(&string, OT_NORMAL, NULL, 0);success = do_pset("fieldsep", fname, &pset.popt, quiet);
free(fname);
***************
*** 415,421 ****
/* \g means send query */
else if (strcmp(cmd, "g") == 0)
{
! char *fname = scan_option(&string, OT_FILEPIPE, NULL);if (!fname) pset.gfname = NULL; --- 415,421 ---- /* \g means send query */ else if (strcmp(cmd, "g") == 0) { ! char *fname = scan_option(&string, OT_FILEPIPE, NULL, 0);if (!fname)
pset.gfname = NULL;
***************
*** 447,453 ****
/* \i is include file */
else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
{
! char *fname = scan_option(&string, OT_NORMAL, NULL);if (!fname) { --- 447,453 ---- /* \i is include file */ else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0) { ! char *fname = scan_option(&string, OT_NORMAL, NULL, 1);if (!fname)
{
***************
*** 475,482 ****
char *opt1,
*opt2;! opt1 = scan_option(&string, OT_NORMAL, NULL);
! opt2 = scan_option(&string, OT_NORMAL, NULL);if (strcmp(cmd + 3, "export") == 0) { --- 475,482 ---- char *opt1, *opt2;! opt1 = scan_option(&string, OT_NORMAL, NULL, 1);
! opt2 = scan_option(&string, OT_NORMAL, NULL, 1);if (strcmp(cmd + 3, "export") == 0)
{
***************
*** 528,534 ****
/* \o -- set query output */
else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
{
! char *fname = scan_option(&string, OT_FILEPIPE, NULL);success = setQFout(fname); free(fname); --- 528,534 ---- /* \o -- set query output */ else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0) { ! char *fname = scan_option(&string, OT_FILEPIPE, NULL, 1);success = setQFout(fname);
free(fname);
***************
*** 547,554 ****
/* \pset -- set printing parameters */
else if (strcmp(cmd, "pset") == 0)
{
! char *opt0 = scan_option(&string, OT_NORMAL, NULL);
! char *opt1 = scan_option(&string, OT_NORMAL, NULL);if (!opt0) { --- 547,554 ---- /* \pset -- set printing parameters */ else if (strcmp(cmd, "pset") == 0) { ! char *opt0 = scan_option(&string, OT_NORMAL, NULL, 0); ! char *opt1 = scan_option(&string, OT_NORMAL, NULL, 0);if (!opt0)
{
***************
*** 577,583 ****
/* \s save history in a file or show it on the screen */
else if (strcmp(cmd, "s") == 0)
{
! char *fname = scan_option(&string, OT_NORMAL, NULL);success = saveHistory(fname ? fname : "/dev/tty");
--- 577,583 ---- /* \s save history in a file or show it on the screen */ else if (strcmp(cmd, "s") == 0) { ! char *fname = scan_option(&string, OT_NORMAL, NULL, 1);success = saveHistory(fname ? fname : "/dev/tty");
***************
*** 589,595 ****
/* \set -- generalized set variable/option command */
else if (strcmp(cmd, "set") == 0)
{
! char *opt0 = scan_option(&string, OT_NORMAL, NULL);if (!opt0) { --- 589,595 ---- /* \set -- generalized set variable/option command */ else if (strcmp(cmd, "set") == 0) { ! char *opt0 = scan_option(&string, OT_NORMAL, NULL, 0);if (!opt0)
{
***************
*** 614,624 ****
char *newval = NULL;
char *opt;! opt = scan_option(&string, OT_NORMAL, NULL);
newval = xstrdup(opt ? opt : "");
free(opt);! while ((opt = scan_option(&string, OT_NORMAL, NULL))) { newval = realloc(newval, strlen(newval) + strlen(opt) + 1); if (!newval) --- 614,624 ---- char *newval = NULL; char *opt;! opt = scan_option(&string, OT_NORMAL, NULL, 0);
newval = xstrdup(opt ? opt : "");
free(opt);! while ((opt = scan_option(&string, OT_NORMAL, NULL, 0)))
{
newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
if (!newval)
***************
*** 648,654 ****
/* \T -- define html <table ...> attributes */
else if (strcmp(cmd, "T") == 0)
{
! char *value = scan_option(&string, OT_NORMAL, NULL);success = do_pset("tableattr", value, &pset.popt, quiet); free(value); --- 648,654 ---- /* \T -- define html <table ...> attributes */ else if (strcmp(cmd, "T") == 0) { ! char *value = scan_option(&string, OT_NORMAL, NULL, 0);success = do_pset("tableattr", value, &pset.popt, quiet);
free(value);
***************
*** 657,663 ****
/* \unset */
else if (strcmp(cmd, "unset") == 0)
{
! char *opt = scan_option(&string, OT_NORMAL, NULL);if (!opt) { --- 657,663 ---- /* \unset */ else if (strcmp(cmd, "unset") == 0) { ! char *opt = scan_option(&string, OT_NORMAL, NULL, 0);if (!opt)
{
***************
*** 686,692 ****
}
else
{
! fname = scan_option(&string, OT_FILEPIPE, NULL);if (!fname) { --- 686,692 ---- } else { ! fname = scan_option(&string, OT_FILEPIPE, NULL, 1);if (!fname)
{
***************
*** 741,747 ****
/* \z -- list table rights (grant/revoke) */
else if (strcmp(cmd, "z") == 0)
{
! char *opt = scan_option(&string, OT_SQLID, NULL);success = permissionsList(opt); free(opt); --- 741,747 ---- /* \z -- list table rights (grant/revoke) */ else if (strcmp(cmd, "z") == 0) { ! char *opt = scan_option(&string, OT_SQLID, NULL, 1);success = permissionsList(opt);
free(opt);
***************
*** 772,778 ****
char *value;fprintf(stderr, "+ optstr = |%s|\n", options_string); ! while ((value = scan_option(&string, OT_NORMAL, NULL))) { fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value); free(value); --- 772,778 ---- char *value;fprintf(stderr, "+ optstr = |%s|\n", options_string);
! while ((value = scan_option(&string, OT_NORMAL, NULL, 1)))
{
fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value);
free(value);
***************
*** 787,793 ****
status = CMD_ERROR;/* eat the rest of the options string */ ! while ((val = scan_option(&string, OT_NORMAL, NULL))) { if (status != CMD_UNKNOWN) psql_error("\\%s: extra argument '%s' ignored\n", cmd, val); --- 787,793 ---- status = CMD_ERROR;/* eat the rest of the options string */ ! while ((val = scan_option(&string, OT_NORMAL, NULL, 0))) { if (status != CMD_UNKNOWN) psql_error("\\%s: extra argument '%s' ignored\n", cmd, val); *************** *** 806,812 **** * scan_option() */ static char * ! scan_option(char **string, enum option_type type, char *quote) { unsigned int pos = 0; char *options_string; --- 806,812 ---- * scan_option() */ static char * ! scan_option(char **string, enum option_type type, char *quote, bool semicolon) { unsigned int pos = 0; char *options_string; *************** *** 822,827 **** --- 822,835 ---- /* skip leading whitespace */ pos += strspn(options_string + pos, " \t\n\r");+ + /* Strip any trailing semi-colons for some types */ + if (semicolon) { + int i; + for (i = strlen(options_string)-1; i && options_string[i]==';'; i--); + if (i<strlen(options_string)-1) options_string[i+1]='\0'; + } + switch (options_string[pos]) {*************** *** 863,868 **** --- 871,877 ---- * If this is expected to be an SQL identifier like option * then we strip out the double quotes */ + if (type == OT_SQLID) { unsigned int k, *************** *** 894,900 **** *string = options_string + jj + 1; if (quote) *quote = '"'; ! return return_val; }--- 903,909 ---- *string = options_string + jj + 1; if (quote) *quote = '"'; ! return return_val; }
---------------------------(end of broadcast)---------------------------
TIP 2: you can get off all lists at once with the unregister command
(send "unregister YourEmailAddressHere" to majordomo@postgresql.org)
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 853-3000
+ If your life is a hard drive, | 830 Blythe Avenue
+ Christ can be your backup. | Drexel Hill, Pennsylvania 19026
greg@turnstep.com writes:
Since there is no reason to have a table named "mytable;"
why not just have psql do the smart thing and silently
strip the trailing semicolons?
"Stripping" semicolons is one thing, accepting semicolons as command
separators is another. Your patch seems to handle the case of
\d mytable;
but it doesn't handle any of
\d mytable; \d yourtable
\d mytable;<space>
\d mytable; select * from mytable;
Anything short of that plus...
The attached patch only addresses
a few backslash commands as a proof of concept,
...is just going to create some other confusion in place of the current
one.
--
Peter Eisentraut peter_e@gmx.net http://funkturm.homeip.net/~peter
greg@turnstep.com writes:
Since there is no reason to have a table named "mytable;"
why not just have psql do the smart thing and silently
strip the trailing semicolons?"Stripping" semicolons is one thing, accepting semicolons as command
separators is another. Your patch seems to handle the case of\d mytable;
but it doesn't handle any of
\d mytable; \d yourtable
\d mytable;<space>
\d mytable; select * from mytable;Anything short of that plus...
The attached patch only addresses
a few backslash commands as a proof of concept,...is just going to create some other confusion in place of the current
one.
My assumption is that the semicolons used with backslash commands are
just knee-jerk adding of semicolons to the end, not attempts to actually
string backslash commands togeter. His patch does catch those cases.
The basic issue is that I think we can conclude that any trailing
semicolon on a line with a backslash command can be dropped. In fact, I
wouldn't want to catch any of the items you listed above. Let them fail.
We all do this by accident, don't we? I know I do.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 853-3000
+ If your life is a hard drive, | 830 Blythe Avenue
+ Christ can be your backup. | Drexel Hill, Pennsylvania 19026
Bruce Momjian <pgman@candle.pha.pa.us> writes:
The basic issue is that I think we can conclude that any trailing
semicolon on a line with a backslash command can be dropped.
I agree with this premise ... but stated that way, the patch does
entirely the wrong thing, because it's stripping trailing semis at
the word level not the line level. I think it's a lot more surprising
to drop the semi in
\x foo; bar
than when it's actually at the end of the line.
How about stripping trailing semis (perhaps whitespace too?) before
the line is broken into words?
regards, tom lane
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
I agree with this premise ... but stated that way, the patch does
entirely the wrong thing, because it's stripping trailing semis at
the word level not the line level. I think it's a lot more surprising
to drop the semi in\x foo; bar
than when it's actually at the end of the line.
Ah...so what we want then is for all of these cases to work:
\d foo \d bar
\d foo; \d bar
\d foo; \d bar;
\d foo; \d bar
Makes sense...I never combine backslash commands on the same line,
but it is possible. In that case, how about just moving this section:
if (semicolon) {
int i;
for (i = strlen(options_string)-1; i && options_string[i]==';'; i--);
if (i<strlen(options_string)-1) options_string[i+1]='\0';
}
to right after here, where we find a "normal word"?
strncpy(return_val, &options_string[pos], token_end);
return_val[token_end] = 0;
(and changing options_string to return_val)
that should allow us to catch all the cases above, if I am
understanding the objection above correctly.
Greg Sabino Mullane
greg@turnstep.com PGP Key: 0x14964AC8 200110011738
-----BEGIN PGP SIGNATURE-----
Comment: http://www.turnstep.com/pgp.html
iQA/AwUBO7jijLybkGcUlkrIEQIMWwCfYDNNqC/UYKKKaqj5MYrEcg2bGhcAoPUP
cqeF4yXAuPedUpQPLVFsw1lO
=4dGu
-----END PGP SIGNATURE-----
OK, any chance of getting an updated patch. Your patch email is at:
http://candle.pha.pa.us/cgi-bin/pgpatches
I agree with this premise ... but stated that way, the patch does
entirely the wrong thing, because it's stripping trailing semis at
the word level not the line level. I think it's a lot more surprising
to drop the semi in\x foo; bar
than when it's actually at the end of the line.
Ah...so what we want then is for all of these cases to work:
\d foo \d bar
\d foo; \d bar
\d foo; \d bar;
\d foo; \d barMakes sense...I never combine backslash commands on the same line,
but it is possible. In that case, how about just moving this section:if (semicolon) {
int i;
for (i = strlen(options_string)-1; i && options_string[i]==';'; i--);
if (i<strlen(options_string)-1) options_string[i+1]='\0';
}to right after here, where we find a "normal word"?
strncpy(return_val, &options_string[pos], token_end);
return_val[token_end] = 0;(and changing options_string to return_val)
that should allow us to catch all the cases above, if I am
understanding the objection above correctly.Greg Sabino Mullane
greg@turnstep.com PGP Key: 0x14964AC8 200110011738
-- End of PGP signed section.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 853-3000
+ If your life is a hard drive, | 830 Blythe Avenue
+ Christ can be your backup. | Drexel Hill, Pennsylvania 19026
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Attached is the updated version of the patch, which matches
on words as opposed to lines, which means that all of the
following work in psql:
\d foo \d bar
\d foo; \d bar
\d foo \d bar;;
\d foo; <space>
This one also uses "true and false" and strips semicolons
for the following backslash commands: \C \c \d \e \i \o \s \z
Thanks to Bruce Momjian, Peter Eisentraut, and Tom Lane for
the suggestions.
Greg Sabino Mullane
greg@turnstep.com
PGP Key: 0x14964AC8 200110040743
-----BEGIN PGP SIGNATURE-----
Comment: http://www.turnstep.com/pgp.html
iQA+AwUBO7xNp7ybkGcUlkrIEQKzwgCXcaQGh16cXELnjKDs7lpg7BP7twCg1jHW
lDE1BVxPTrLXQZeQRn+ieu4=
=PK53
-----END PGP SIGNATURE-----
Import Notes
Resolved by subject fallback
Your patch has been added to the PostgreSQL unapplied patches list at:
http://candle.pha.pa.us/cgi-bin/pgpatches
I will try to apply it within the next 48 hours.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1Attached is the updated version of the patch, which matches
on words as opposed to lines, which means that all of the
following work in psql:\d foo \d bar
\d foo; \d bar
\d foo \d bar;;
\d foo; <space>This one also uses "true and false" and strips semicolons
for the following backslash commands: \C \c \d \e \i \o \s \zThanks to Bruce Momjian, Peter Eisentraut, and Tom Lane for
the suggestions.Greg Sabino Mullane
greg@turnstep.com
PGP Key: 0x14964AC8 200110040743-----BEGIN PGP SIGNATURE-----
Comment: http://www.turnstep.com/pgp.htmliQA+AwUBO7xNp7ybkGcUlkrIEQKzwgCXcaQGh16cXELnjKDs7lpg7BP7twCg1jHW
lDE1BVxPTrLXQZeQRn+ieu4=
=PK53
-----END PGP SIGNATURE-----
*** ./src/bin/psql/command.c.orig Thu Oct 4 07:26:30 2001 --- ./src/bin/psql/command.c Thu Oct 4 07:30:37 2001 *************** *** 55,61 **** { OT_NORMAL, OT_SQLID, OT_FILEPIPE }; ! static char *scan_option(char **string, enum option_type type, char *quote); static char *unescape(const unsigned char *source, size_t len);static bool do_edit(const char *filename_arg, PQExpBuffer query_buf); --- 55,61 ---- { OT_NORMAL, OT_SQLID, OT_FILEPIPE }; ! static char *scan_option(char **string, enum option_type type, char *quote, bool semicolon); static char *unescape(const unsigned char *source, size_t len);static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
***************
*** 216,222 ****
/* \C -- override table title (formerly change HTML caption) */
else if (strcmp(cmd, "C") == 0)
{
! char *opt = scan_option(&string, OT_NORMAL, NULL);success = do_pset("title", opt, &pset.popt, quiet); free(opt); --- 216,222 ---- /* \C -- override table title (formerly change HTML caption) */ else if (strcmp(cmd, "C") == 0) { ! char *opt = scan_option(&string, OT_NORMAL, NULL, true);success = do_pset("title", opt, &pset.popt, quiet);
free(opt);
***************
*** 238,245 ****
char opt1q,
opt2q;! opt1 = scan_option(&string, OT_NORMAL, &opt1q);
! opt2 = scan_option(&string, OT_NORMAL, &opt2q);if (opt2) /* gave username */ --- 238,245 ---- char opt1q, opt2q;! opt1 = scan_option(&string, OT_NORMAL, &opt1q, true);
! opt2 = scan_option(&string, OT_NORMAL, &opt2q, true);if (opt2)
/* gave username */
***************
*** 273,280 ****
{
char *name;
bool show_verbose;- name = scan_option(&string, OT_SQLID, NULL);
show_verbose = strchr(cmd, '+') ? true : false;switch (cmd[1]) --- 273,280 ---- { char *name; bool show_verbose; + name = scan_option(&string, OT_SQLID, NULL, true);show_verbose = strchr(cmd, '+') ? true : false;
switch (cmd[1]) *************** *** 337,343 **** } else { ! fname = scan_option(&string, OT_NORMAL, NULL); status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR; free(fname); } --- 337,343 ---- } else { ! fname = scan_option(&string, OT_NORMAL, NULL, true); status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR; free(fname); } *************** *** 356,363 **** fout = pset.queryFout; else fout = stdout; ! ! while ((value = scan_option(&string, OT_NORMAL, "ed))) { if (!quoted && strcmp(value, "-n") == 0) no_newline = true; --- 356,363 ---- fout = pset.queryFout; else fout = stdout; ! ! while ((value = scan_option(&string, OT_NORMAL, "ed, false))) { if (!quoted && strcmp(value, "-n") == 0) no_newline = true; *************** *** 378,384 **** /* \encoding -- set/show client side encoding */ else if (strcmp(cmd, "encoding") == 0) { ! char *encoding = scan_option(&string, OT_NORMAL, NULL);if (!encoding) /* show encoding */ --- 378,384 ---- /* \encoding -- set/show client side encoding */ else if (strcmp(cmd, "encoding") == 0) { ! char *encoding = scan_option(&string, OT_NORMAL, NULL, false);if (!encoding)
/* show encoding */
***************
*** 406,412 ****
/* \f -- change field separator */
else if (strcmp(cmd, "f") == 0)
{
! char *fname = scan_option(&string, OT_NORMAL, NULL);success = do_pset("fieldsep", fname, &pset.popt, quiet); free(fname); --- 406,412 ---- /* \f -- change field separator */ else if (strcmp(cmd, "f") == 0) { ! char *fname = scan_option(&string, OT_NORMAL, NULL, false);success = do_pset("fieldsep", fname, &pset.popt, quiet);
free(fname);
***************
*** 415,421 ****
/* \g means send query */
else if (strcmp(cmd, "g") == 0)
{
! char *fname = scan_option(&string, OT_FILEPIPE, NULL);if (!fname) pset.gfname = NULL; --- 415,421 ---- /* \g means send query */ else if (strcmp(cmd, "g") == 0) { ! char *fname = scan_option(&string, OT_FILEPIPE, NULL, false);if (!fname)
pset.gfname = NULL;
***************
*** 447,453 ****
/* \i is include file */
else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
{
! char *fname = scan_option(&string, OT_NORMAL, NULL);if (!fname) { --- 447,453 ---- /* \i is include file */ else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0) { ! char *fname = scan_option(&string, OT_NORMAL, NULL, true);if (!fname)
{
***************
*** 475,482 ****
char *opt1,
*opt2;! opt1 = scan_option(&string, OT_NORMAL, NULL);
! opt2 = scan_option(&string, OT_NORMAL, NULL);if (strcmp(cmd + 3, "export") == 0) { --- 475,482 ---- char *opt1, *opt2;! opt1 = scan_option(&string, OT_NORMAL, NULL, true);
! opt2 = scan_option(&string, OT_NORMAL, NULL, true);if (strcmp(cmd + 3, "export") == 0)
{
***************
*** 525,531 ****
/* \o -- set query output */
else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
{
! char *fname = scan_option(&string, OT_FILEPIPE, NULL);success = setQFout(fname); free(fname); --- 525,531 ---- /* \o -- set query output */ else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0) { ! char *fname = scan_option(&string, OT_FILEPIPE, NULL, true);success = setQFout(fname);
free(fname);
***************
*** 544,551 ****
/* \pset -- set printing parameters */
else if (strcmp(cmd, "pset") == 0)
{
! char *opt0 = scan_option(&string, OT_NORMAL, NULL);
! char *opt1 = scan_option(&string, OT_NORMAL, NULL);if (!opt0) { --- 544,551 ---- /* \pset -- set printing parameters */ else if (strcmp(cmd, "pset") == 0) { ! char *opt0 = scan_option(&string, OT_NORMAL, NULL, false); ! char *opt1 = scan_option(&string, OT_NORMAL, NULL, false);if (!opt0)
{
***************
*** 574,580 ****
/* \s save history in a file or show it on the screen */
else if (strcmp(cmd, "s") == 0)
{
! char *fname = scan_option(&string, OT_NORMAL, NULL);success = saveHistory(fname ? fname : "/dev/tty");
--- 574,580 ---- /* \s save history in a file or show it on the screen */ else if (strcmp(cmd, "s") == 0) { ! char *fname = scan_option(&string, OT_NORMAL, NULL, true);success = saveHistory(fname ? fname : "/dev/tty");
***************
*** 586,592 ****
/* \set -- generalized set variable/option command */
else if (strcmp(cmd, "set") == 0)
{
! char *opt0 = scan_option(&string, OT_NORMAL, NULL);if (!opt0) { --- 586,592 ---- /* \set -- generalized set variable/option command */ else if (strcmp(cmd, "set") == 0) { ! char *opt0 = scan_option(&string, OT_NORMAL, NULL, false);if (!opt0)
{
***************
*** 611,621 ****
char *newval = NULL;
char *opt;! opt = scan_option(&string, OT_NORMAL, NULL);
newval = xstrdup(opt ? opt : "");
free(opt);! while ((opt = scan_option(&string, OT_NORMAL, NULL))) { newval = realloc(newval, strlen(newval) + strlen(opt) + 1); if (!newval) --- 611,621 ---- char *newval = NULL; char *opt;! opt = scan_option(&string, OT_NORMAL, NULL, false);
newval = xstrdup(opt ? opt : "");
free(opt);! while ((opt = scan_option(&string, OT_NORMAL, NULL, false)))
{
newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
if (!newval)
***************
*** 645,651 ****
/* \T -- define html <table ...> attributes */
else if (strcmp(cmd, "T") == 0)
{
! char *value = scan_option(&string, OT_NORMAL, NULL);success = do_pset("tableattr", value, &pset.popt, quiet); free(value); --- 645,651 ---- /* \T -- define html <table ...> attributes */ else if (strcmp(cmd, "T") == 0) { ! char *value = scan_option(&string, OT_NORMAL, NULL, false);success = do_pset("tableattr", value, &pset.popt, quiet);
free(value);
***************
*** 654,660 ****
/* \unset */
else if (strcmp(cmd, "unset") == 0)
{
! char *opt = scan_option(&string, OT_NORMAL, NULL);if (!opt) { --- 654,660 ---- /* \unset */ else if (strcmp(cmd, "unset") == 0) { ! char *opt = scan_option(&string, OT_NORMAL, NULL, false);if (!opt)
{
***************
*** 683,689 ****
}
else
{
! fname = scan_option(&string, OT_FILEPIPE, NULL);if (!fname) { --- 683,689 ---- } else { ! fname = scan_option(&string, OT_FILEPIPE, NULL, true);if (!fname)
{
***************
*** 738,744 ****
/* \z -- list table rights (grant/revoke) */
else if (strcmp(cmd, "z") == 0)
{
! char *opt = scan_option(&string, OT_SQLID, NULL);success = permissionsList(opt); free(opt); --- 738,744 ---- /* \z -- list table rights (grant/revoke) */ else if (strcmp(cmd, "z") == 0) { ! char *opt = scan_option(&string, OT_SQLID, NULL, true);success = permissionsList(opt);
free(opt);
***************
*** 769,775 ****
char *value;fprintf(stderr, "+ optstr = |%s|\n", options_string); ! while ((value = scan_option(&string, OT_NORMAL, NULL))) { fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value); free(value); --- 769,775 ---- char *value;fprintf(stderr, "+ optstr = |%s|\n", options_string);
! while ((value = scan_option(&string, OT_NORMAL, NULL, true)))
{
fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value);
free(value);
***************
*** 784,790 ****
status = CMD_ERROR;/* eat the rest of the options string */ ! while ((val = scan_option(&string, OT_NORMAL, NULL))) { if (status != CMD_UNKNOWN) psql_error("\\%s: extra argument '%s' ignored\n", cmd, val); --- 784,790 ---- status = CMD_ERROR;/* eat the rest of the options string */ ! while ((val = scan_option(&string, OT_NORMAL, NULL, false))) { if (status != CMD_UNKNOWN) psql_error("\\%s: extra argument '%s' ignored\n", cmd, val); *************** *** 803,809 **** * scan_option() */ static char * ! scan_option(char **string, enum option_type type, char *quote) { unsigned int pos = 0; char *options_string; --- 803,809 ---- * scan_option() */ static char * ! scan_option(char **string, enum option_type type, char *quote, bool semicolon) { unsigned int pos = 0; char *options_string; *************** *** 860,865 **** --- 860,866 ---- * If this is expected to be an SQL identifier like option * then we strip out the double quotes */ + if (type == OT_SQLID) { unsigned int k, *************** *** 891,897 **** *string = options_string + jj + 1; if (quote) *quote = '"'; ! return return_val; }--- 892,898 ---- *string = options_string + jj + 1; if (quote) *quote = '"'; ! return return_val; }*************** *** 1071,1076 **** --- 1072,1084 ---- } strncpy(return_val, &options_string[pos], token_end); return_val[token_end] = 0; + + /* Strip any trailing semi-colons for some types */ + if (semicolon) { + int i; + for (i = strlen(return_val)-1; i && return_val[i]==';'; i--); + if (i<strlen(return_val)-1) return_val[i+1]='\0'; + }if (type == OT_SQLID)
for (cp = return_val; *cp; cp += PQmblen(cp, pset.encoding))
---------------------------(end of broadcast)---------------------------
TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 853-3000
+ If your life is a hard drive, | 830 Blythe Avenue
+ Christ can be your backup. | Drexel Hill, Pennsylvania 19026
Patch applied. Thanks.
Also, seems there is now a \cd command. I assume the param for that
would be 'true'.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1Attached is the updated version of the patch, which matches
on words as opposed to lines, which means that all of the
following work in psql:\d foo \d bar
\d foo; \d bar
\d foo \d bar;;
\d foo; <space>This one also uses "true and false" and strips semicolons
for the following backslash commands: \C \c \d \e \i \o \s \zThanks to Bruce Momjian, Peter Eisentraut, and Tom Lane for
the suggestions.Greg Sabino Mullane
greg@turnstep.com
PGP Key: 0x14964AC8 200110040743-----BEGIN PGP SIGNATURE-----
Comment: http://www.turnstep.com/pgp.htmliQA+AwUBO7xNp7ybkGcUlkrIEQKzwgCXcaQGh16cXELnjKDs7lpg7BP7twCg1jHW
lDE1BVxPTrLXQZeQRn+ieu4=
=PK53
-----END PGP SIGNATURE-----
*** ./src/bin/psql/command.c.orig Thu Oct 4 07:26:30 2001 --- ./src/bin/psql/command.c Thu Oct 4 07:30:37 2001 *************** *** 55,61 **** { OT_NORMAL, OT_SQLID, OT_FILEPIPE }; ! static char *scan_option(char **string, enum option_type type, char *quote); static char *unescape(const unsigned char *source, size_t len);static bool do_edit(const char *filename_arg, PQExpBuffer query_buf); --- 55,61 ---- { OT_NORMAL, OT_SQLID, OT_FILEPIPE }; ! static char *scan_option(char **string, enum option_type type, char *quote, bool semicolon); static char *unescape(const unsigned char *source, size_t len);static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
***************
*** 216,222 ****
/* \C -- override table title (formerly change HTML caption) */
else if (strcmp(cmd, "C") == 0)
{
! char *opt = scan_option(&string, OT_NORMAL, NULL);success = do_pset("title", opt, &pset.popt, quiet); free(opt); --- 216,222 ---- /* \C -- override table title (formerly change HTML caption) */ else if (strcmp(cmd, "C") == 0) { ! char *opt = scan_option(&string, OT_NORMAL, NULL, true);success = do_pset("title", opt, &pset.popt, quiet);
free(opt);
***************
*** 238,245 ****
char opt1q,
opt2q;! opt1 = scan_option(&string, OT_NORMAL, &opt1q);
! opt2 = scan_option(&string, OT_NORMAL, &opt2q);if (opt2) /* gave username */ --- 238,245 ---- char opt1q, opt2q;! opt1 = scan_option(&string, OT_NORMAL, &opt1q, true);
! opt2 = scan_option(&string, OT_NORMAL, &opt2q, true);if (opt2)
/* gave username */
***************
*** 273,280 ****
{
char *name;
bool show_verbose;- name = scan_option(&string, OT_SQLID, NULL);
show_verbose = strchr(cmd, '+') ? true : false;switch (cmd[1]) --- 273,280 ---- { char *name; bool show_verbose; + name = scan_option(&string, OT_SQLID, NULL, true);show_verbose = strchr(cmd, '+') ? true : false;
switch (cmd[1]) *************** *** 337,343 **** } else { ! fname = scan_option(&string, OT_NORMAL, NULL); status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR; free(fname); } --- 337,343 ---- } else { ! fname = scan_option(&string, OT_NORMAL, NULL, true); status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR; free(fname); } *************** *** 356,363 **** fout = pset.queryFout; else fout = stdout; ! ! while ((value = scan_option(&string, OT_NORMAL, "ed))) { if (!quoted && strcmp(value, "-n") == 0) no_newline = true; --- 356,363 ---- fout = pset.queryFout; else fout = stdout; ! ! while ((value = scan_option(&string, OT_NORMAL, "ed, false))) { if (!quoted && strcmp(value, "-n") == 0) no_newline = true; *************** *** 378,384 **** /* \encoding -- set/show client side encoding */ else if (strcmp(cmd, "encoding") == 0) { ! char *encoding = scan_option(&string, OT_NORMAL, NULL);if (!encoding) /* show encoding */ --- 378,384 ---- /* \encoding -- set/show client side encoding */ else if (strcmp(cmd, "encoding") == 0) { ! char *encoding = scan_option(&string, OT_NORMAL, NULL, false);if (!encoding)
/* show encoding */
***************
*** 406,412 ****
/* \f -- change field separator */
else if (strcmp(cmd, "f") == 0)
{
! char *fname = scan_option(&string, OT_NORMAL, NULL);success = do_pset("fieldsep", fname, &pset.popt, quiet); free(fname); --- 406,412 ---- /* \f -- change field separator */ else if (strcmp(cmd, "f") == 0) { ! char *fname = scan_option(&string, OT_NORMAL, NULL, false);success = do_pset("fieldsep", fname, &pset.popt, quiet);
free(fname);
***************
*** 415,421 ****
/* \g means send query */
else if (strcmp(cmd, "g") == 0)
{
! char *fname = scan_option(&string, OT_FILEPIPE, NULL);if (!fname) pset.gfname = NULL; --- 415,421 ---- /* \g means send query */ else if (strcmp(cmd, "g") == 0) { ! char *fname = scan_option(&string, OT_FILEPIPE, NULL, false);if (!fname)
pset.gfname = NULL;
***************
*** 447,453 ****
/* \i is include file */
else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
{
! char *fname = scan_option(&string, OT_NORMAL, NULL);if (!fname) { --- 447,453 ---- /* \i is include file */ else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0) { ! char *fname = scan_option(&string, OT_NORMAL, NULL, true);if (!fname)
{
***************
*** 475,482 ****
char *opt1,
*opt2;! opt1 = scan_option(&string, OT_NORMAL, NULL);
! opt2 = scan_option(&string, OT_NORMAL, NULL);if (strcmp(cmd + 3, "export") == 0) { --- 475,482 ---- char *opt1, *opt2;! opt1 = scan_option(&string, OT_NORMAL, NULL, true);
! opt2 = scan_option(&string, OT_NORMAL, NULL, true);if (strcmp(cmd + 3, "export") == 0)
{
***************
*** 525,531 ****
/* \o -- set query output */
else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
{
! char *fname = scan_option(&string, OT_FILEPIPE, NULL);success = setQFout(fname); free(fname); --- 525,531 ---- /* \o -- set query output */ else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0) { ! char *fname = scan_option(&string, OT_FILEPIPE, NULL, true);success = setQFout(fname);
free(fname);
***************
*** 544,551 ****
/* \pset -- set printing parameters */
else if (strcmp(cmd, "pset") == 0)
{
! char *opt0 = scan_option(&string, OT_NORMAL, NULL);
! char *opt1 = scan_option(&string, OT_NORMAL, NULL);if (!opt0) { --- 544,551 ---- /* \pset -- set printing parameters */ else if (strcmp(cmd, "pset") == 0) { ! char *opt0 = scan_option(&string, OT_NORMAL, NULL, false); ! char *opt1 = scan_option(&string, OT_NORMAL, NULL, false);if (!opt0)
{
***************
*** 574,580 ****
/* \s save history in a file or show it on the screen */
else if (strcmp(cmd, "s") == 0)
{
! char *fname = scan_option(&string, OT_NORMAL, NULL);success = saveHistory(fname ? fname : "/dev/tty");
--- 574,580 ---- /* \s save history in a file or show it on the screen */ else if (strcmp(cmd, "s") == 0) { ! char *fname = scan_option(&string, OT_NORMAL, NULL, true);success = saveHistory(fname ? fname : "/dev/tty");
***************
*** 586,592 ****
/* \set -- generalized set variable/option command */
else if (strcmp(cmd, "set") == 0)
{
! char *opt0 = scan_option(&string, OT_NORMAL, NULL);if (!opt0) { --- 586,592 ---- /* \set -- generalized set variable/option command */ else if (strcmp(cmd, "set") == 0) { ! char *opt0 = scan_option(&string, OT_NORMAL, NULL, false);if (!opt0)
{
***************
*** 611,621 ****
char *newval = NULL;
char *opt;! opt = scan_option(&string, OT_NORMAL, NULL);
newval = xstrdup(opt ? opt : "");
free(opt);! while ((opt = scan_option(&string, OT_NORMAL, NULL))) { newval = realloc(newval, strlen(newval) + strlen(opt) + 1); if (!newval) --- 611,621 ---- char *newval = NULL; char *opt;! opt = scan_option(&string, OT_NORMAL, NULL, false);
newval = xstrdup(opt ? opt : "");
free(opt);! while ((opt = scan_option(&string, OT_NORMAL, NULL, false)))
{
newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
if (!newval)
***************
*** 645,651 ****
/* \T -- define html <table ...> attributes */
else if (strcmp(cmd, "T") == 0)
{
! char *value = scan_option(&string, OT_NORMAL, NULL);success = do_pset("tableattr", value, &pset.popt, quiet); free(value); --- 645,651 ---- /* \T -- define html <table ...> attributes */ else if (strcmp(cmd, "T") == 0) { ! char *value = scan_option(&string, OT_NORMAL, NULL, false);success = do_pset("tableattr", value, &pset.popt, quiet);
free(value);
***************
*** 654,660 ****
/* \unset */
else if (strcmp(cmd, "unset") == 0)
{
! char *opt = scan_option(&string, OT_NORMAL, NULL);if (!opt) { --- 654,660 ---- /* \unset */ else if (strcmp(cmd, "unset") == 0) { ! char *opt = scan_option(&string, OT_NORMAL, NULL, false);if (!opt)
{
***************
*** 683,689 ****
}
else
{
! fname = scan_option(&string, OT_FILEPIPE, NULL);if (!fname) { --- 683,689 ---- } else { ! fname = scan_option(&string, OT_FILEPIPE, NULL, true);if (!fname)
{
***************
*** 738,744 ****
/* \z -- list table rights (grant/revoke) */
else if (strcmp(cmd, "z") == 0)
{
! char *opt = scan_option(&string, OT_SQLID, NULL);success = permissionsList(opt); free(opt); --- 738,744 ---- /* \z -- list table rights (grant/revoke) */ else if (strcmp(cmd, "z") == 0) { ! char *opt = scan_option(&string, OT_SQLID, NULL, true);success = permissionsList(opt);
free(opt);
***************
*** 769,775 ****
char *value;fprintf(stderr, "+ optstr = |%s|\n", options_string); ! while ((value = scan_option(&string, OT_NORMAL, NULL))) { fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value); free(value); --- 769,775 ---- char *value;fprintf(stderr, "+ optstr = |%s|\n", options_string);
! while ((value = scan_option(&string, OT_NORMAL, NULL, true)))
{
fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value);
free(value);
***************
*** 784,790 ****
status = CMD_ERROR;/* eat the rest of the options string */ ! while ((val = scan_option(&string, OT_NORMAL, NULL))) { if (status != CMD_UNKNOWN) psql_error("\\%s: extra argument '%s' ignored\n", cmd, val); --- 784,790 ---- status = CMD_ERROR;/* eat the rest of the options string */ ! while ((val = scan_option(&string, OT_NORMAL, NULL, false))) { if (status != CMD_UNKNOWN) psql_error("\\%s: extra argument '%s' ignored\n", cmd, val); *************** *** 803,809 **** * scan_option() */ static char * ! scan_option(char **string, enum option_type type, char *quote) { unsigned int pos = 0; char *options_string; --- 803,809 ---- * scan_option() */ static char * ! scan_option(char **string, enum option_type type, char *quote, bool semicolon) { unsigned int pos = 0; char *options_string; *************** *** 860,865 **** --- 860,866 ---- * If this is expected to be an SQL identifier like option * then we strip out the double quotes */ + if (type == OT_SQLID) { unsigned int k, *************** *** 891,897 **** *string = options_string + jj + 1; if (quote) *quote = '"'; ! return return_val; }--- 892,898 ---- *string = options_string + jj + 1; if (quote) *quote = '"'; ! return return_val; }*************** *** 1071,1076 **** --- 1072,1084 ---- } strncpy(return_val, &options_string[pos], token_end); return_val[token_end] = 0; + + /* Strip any trailing semi-colons for some types */ + if (semicolon) { + int i; + for (i = strlen(return_val)-1; i && return_val[i]==';'; i--); + if (i<strlen(return_val)-1) return_val[i+1]='\0'; + }if (type == OT_SQLID)
for (cp = return_val; *cp; cp += PQmblen(cp, pset.encoding))
---------------------------(end of broadcast)---------------------------
TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 853-3000
+ If your life is a hard drive, | 830 Blythe Avenue
+ Christ can be your backup. | Drexel Hill, Pennsylvania 19026