Hi 2015-11-05 22:23 GMT+01:00 Robert Haas <robertmh...@gmail.com>:
> On Thu, Nov 5, 2015 at 3:53 PM, Catalin Iacob <iacobcata...@gmail.com> > wrote: > > On Thu, Nov 5, 2015 at 5:27 PM, Robert Haas <robertmh...@gmail.com> > wrote: > >>> I wrote some text. But needs some work of native speaker. > >> > >> It does. It would be nice if some kind reviewer could help volunteer > >> to clean that up. > > > > I'll give it a go sometime next week. > > Thanks, that would be great! > > I recommend comparing the section on -c and the section on -C, and > probably updating the former as well as adjusting the wording of the > latter. We don't want to repeat all the same details in both places, > but we hopefully want to give people a little clue that if they're > thinking about using -c, they may wish to instead consider -C. > -g was replaced by -C option and some other required changes. I have not idea about good long name. In this moment I used "multi-command". Can be changed freely. The name of this patch is same (although it doesn't use "group-command" internally anymore) due better orientation. Regards Pavel > > -- > Robert Haas > EnterpriseDB: http://www.enterprisedb.com > The Enterprise PostgreSQL Company >
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml new file mode 100644 index 5899bb4..3ef32d2 *** a/doc/src/sgml/ref/psql-ref.sgml --- b/doc/src/sgml/ref/psql-ref.sgml *************** EOF *** 132,137 **** --- 132,176 ---- </varlistentry> <varlistentry> + <term><option>-C <replaceable class="parameter">command(s)</replaceable></></term> + <term><option>--multi-command=<replaceable class="parameter">command(s)</replaceable></></term> + <listitem> + <para> + Specifies that <application>psql</application> is to execute one or + more command strings, <replaceable class="parameter">commands</replaceable>, + and then exit. This is useful in shell scripts. Start-up files + (<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>) are + ignored with this option. + </para> + + <para> + There are a few differences between <option>-c</option> and + <option>-C</option> options. The option <option>-c</option> can be used + only once. The option <option>-C</option> can be used more times. + This can simplify writing some non trivial SQL commands. With the + <option>-C</option> option it is possible to call several <application>psql</application> + parametrized backslash commands. When you execute multiple SQL + commands via <option>-c</option> option, only result of last command + is returned. The execution started by <option>-C</option> option shows + result of all commands. + </para> + + <para> + Another difference is in wrapping the transaction. The <option>-c</option> + option runs commands in one transaction. The <option>-C</option> option + uses autocommit mode by default. This allows running multiple commads + which would otherwise not be allowed to execute within one transaction. + This is typical for <command>VACUUM</command> command. + <programlisting> + psql -Atq -C "VACUUM FULL foo; SELECT pg_relation_size('foo')" + psql -Atq -C "VACUUM FULL foo" -C "SELECT pg_relation_size('foo')" + </programlisting> + </para> + + </listitem> + </varlistentry> + + <varlistentry> <term><option>-d <replaceable class="parameter">dbname</replaceable></></term> <term><option>--dbname=<replaceable class="parameter">dbname</replaceable></></term> <listitem> diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c new file mode 100644 index 72c00c1..1bc20d3 *** a/src/bin/psql/command.c --- b/src/bin/psql/command.c *************** process_file(char *filename, bool single *** 2293,2299 **** int result; char *oldfilename; char relpath[MAXPGPATH]; - PGresult *res; if (!filename) { --- 2293,2298 ---- *************** process_file(char *filename, bool single *** 2338,2374 **** oldfilename = pset.inputfile; pset.inputfile = filename; ! if (single_txn) ! { ! if ((res = PSQLexec("BEGIN")) == NULL) ! { ! if (pset.on_error_stop) ! { ! result = EXIT_USER; ! goto error; ! } ! } ! else ! PQclear(res); ! } ! ! result = MainLoop(fd); ! ! if (single_txn) ! { ! if ((res = PSQLexec("COMMIT")) == NULL) ! { ! if (pset.on_error_stop) ! { ! result = EXIT_USER; ! goto error; ! } ! } ! else ! PQclear(res); ! } - error: if (fd != stdin) fclose(fd); --- 2337,2344 ---- oldfilename = pset.inputfile; pset.inputfile = filename; ! result = MainLoop(fd, single_txn); if (fd != stdin) fclose(fd); *************** error: *** 2376,2383 **** return result; } - - static const char * _align2string(enum printFormat in) { --- 2346,2351 ---- diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c new file mode 100644 index 5b63e76..7058ada *** a/src/bin/psql/help.c --- b/src/bin/psql/help.c *************** usage(unsigned short int pager) *** 81,86 **** --- 81,88 ---- if (!env) env = user; fprintf(output, _(" -c, --command=COMMAND run only single command (SQL or internal) and exit\n")); + fprintf(output, _(" -C, --multi-command=COMMAND\n" + " run more multiple commands (SQL or internal) and exit\n")); fprintf(output, _(" -d, --dbname=DBNAME database name to connect to (default: \"%s\")\n"), env); fprintf(output, _(" -f, --file=FILENAME execute commands from file, then exit\n")); fprintf(output, _(" -l, --list list available databases, then exit\n")); diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c new file mode 100644 index b6cef94..930d2c5 *** a/src/bin/psql/mainloop.c --- b/src/bin/psql/mainloop.c *************** *** 25,31 **** * which reads input from a file. */ int ! MainLoop(FILE *source) { PsqlScanState scan_state; /* lexer working state */ volatile PQExpBuffer query_buf; /* buffer for query being accumulated */ --- 25,31 ---- * which reads input from a file. */ int ! MainLoop(FILE *source, bool single_txn) { PsqlScanState scan_state; /* lexer working state */ volatile PQExpBuffer query_buf; /* buffer for query being accumulated */ *************** MainLoop(FILE *source) *** 43,48 **** --- 43,50 ---- volatile promptStatus_t prompt_status = PROMPT_READY; volatile int count_eof = 0; volatile bool die_on_error = false; + Commands *cmds = pset.commands; + PGresult *result; /* Save the prior command source */ FILE *prev_cmd_source; *************** MainLoop(FILE *source) *** 60,65 **** --- 62,79 ---- pset.lineno = 0; pset.stmt_lineno = 1; + /* Start transaction when it is required before any allocation */ + if (single_txn) + { + if ((result = PSQLexec("BEGIN")) == NULL) + { + if (pset.on_error_stop) + return EXIT_USER; + } + else + PQclear(result); + } + /* Create working state */ scan_state = psql_scan_create(); *************** MainLoop(FILE *source) *** 135,140 **** --- 149,168 ---- prompt_status = PROMPT_READY; line = gets_interactive(get_prompt(prompt_status)); } + else if (pset.commands != NULL) + { + /* Is there some unprocessed multi command? */ + if (cmds != NULL) + { + line = cmds->actions; + cmds = cmds->next; + } + else + { + successResult = EXIT_SUCCESS; + break; + } + } else { line = gets_fromFile(source); *************** MainLoop(FILE *source) *** 429,434 **** --- 457,474 ---- successResult = EXIT_BADCONN; } + /* Commit success transaction */ + if (single_txn && successResult == EXIT_SUCCESS) + { + if ((result = PSQLexec("COMMIT")) == NULL) + { + if (die_on_error) + successResult = EXIT_USER; + } + else + PQclear(result); + } + /* * Let's just make real sure the SIGINT handler won't try to use * sigint_interrupt_jmp after we exit this routine. If there is an outer *************** MainLoop(FILE *source) *** 451,457 **** return successResult; } /* MainLoop() */ - /* * psqlscan.c is #include'd here instead of being compiled on its own. * This is because we need postgres_fe.h to be read before any system --- 491,496 ---- diff --git a/src/bin/psql/mainloop.h b/src/bin/psql/mainloop.h new file mode 100644 index 8f1325c..53c9a11 *** a/src/bin/psql/mainloop.h --- b/src/bin/psql/mainloop.h *************** *** 10,15 **** #include "postgres_fe.h" ! int MainLoop(FILE *source); #endif /* MAINLOOP_H */ --- 10,15 ---- #include "postgres_fe.h" ! int MainLoop(FILE *source, bool single_txn); #endif /* MAINLOOP_H */ diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h new file mode 100644 index 1885bb1..39ced85 *** a/src/bin/psql/settings.h --- b/src/bin/psql/settings.h *************** enum trivalue *** 77,82 **** --- 77,88 ---- TRI_YES }; + typedef struct _Commands + { + char *actions; + struct _Commands *next; + } Commands; + typedef struct _psqlSettings { PGconn *db; /* connection to backend */ *************** typedef struct _psqlSettings *** 130,135 **** --- 136,142 ---- const char *prompt3; PGVerbosity verbosity; /* current error verbosity level */ PGContextVisibility show_context; /* current context display level */ + Commands *commands; } PsqlSettings; extern PsqlSettings pset; diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c new file mode 100644 index 7aa997d..6118b07 *** a/src/bin/psql/startup.c --- b/src/bin/psql/startup.c *************** enum _actions *** 54,60 **** ACT_SINGLE_SLASH, ACT_LIST_DB, ACT_SINGLE_QUERY, ! ACT_FILE }; struct adhoc_opts --- 54,61 ---- ACT_SINGLE_SLASH, ACT_LIST_DB, ACT_SINGLE_QUERY, ! ACT_FILE, ! ACT_COMMAND_LINE }; struct adhoc_opts *************** main(int argc, char *argv[]) *** 159,164 **** --- 160,167 ---- SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2); SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3); + pset.commands = NULL; + parse_psql_options(argc, argv, &options); /* *************** main(int argc, char *argv[]) *** 327,332 **** --- 330,344 ---- ? EXIT_SUCCESS : EXIT_FAILURE; } + else if (options.action == ACT_COMMAND_LINE) + { + pset.notty = true; + + /* use singleline mode, doesn't need semicolon on the end line */ + SetVariableBool(pset.vars, "SINGLELINE"); + successResult = MainLoop(NULL, options.single_txn); + } + /* * or otherwise enter interactive main loop */ *************** main(int argc, char *argv[]) *** 339,345 **** if (!pset.quiet) printf(_("Type \"help\" for help.\n\n")); initializeInput(options.no_readline ? 0 : 1); ! successResult = MainLoop(stdin); } /* clean up */ --- 351,357 ---- if (!pset.quiet) printf(_("Type \"help\" for help.\n\n")); initializeInput(options.no_readline ? 0 : 1); ! successResult = MainLoop(stdin, false); } /* clean up */ *************** parse_psql_options(int argc, char *argv[ *** 375,380 **** --- 387,393 ---- {"html", no_argument, NULL, 'H'}, {"list", no_argument, NULL, 'l'}, {"log-file", required_argument, NULL, 'L'}, + {"multi-command", required_argument, NULL, 'C'}, {"no-readline", no_argument, NULL, 'n'}, {"single-transaction", no_argument, NULL, '1'}, {"output", required_argument, NULL, 'o'}, *************** parse_psql_options(int argc, char *argv[ *** 402,410 **** int optindex; int c; memset(options, 0, sizeof *options); ! while ((c = getopt_long(argc, argv, "aAbc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01", long_options, &optindex)) != -1) { switch (c) --- 415,426 ---- int optindex; int c; + bool cmd_opt_is_used = false; + bool commands_opt_is_used = false; + memset(options, 0, sizeof *options); ! while ((c = getopt_long(argc, argv, "aAbc:C:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01", long_options, &optindex)) != -1) { switch (c) *************** parse_psql_options(int argc, char *argv[ *** 419,424 **** --- 435,442 ---- SetVariable(pset.vars, "ECHO", "errors"); break; case 'c': + cmd_opt_is_used = true; + options->action_string = pg_strdup(optarg); if (optarg[0] == '\\') { *************** parse_psql_options(int argc, char *argv[ *** 428,433 **** --- 446,472 ---- else options->action = ACT_SINGLE_QUERY; break; + case 'C': + { + Commands *cmds = pg_malloc(sizeof(Commands)); + Commands *ptr = pset.commands; + + commands_opt_is_used = true; + + if (ptr == NULL) + pset.commands = cmds; + else + { + while (ptr->next != NULL) + ptr = ptr->next; + + ptr->next = cmds; + } + cmds->next = NULL; + cmds->actions = pg_strdup(optarg); + options->action = ACT_COMMAND_LINE; + } + break; case 'd': options->dbname = pg_strdup(optarg); break; *************** parse_psql_options(int argc, char *argv[ *** 601,606 **** --- 640,652 ---- } } + if (cmd_opt_is_used && commands_opt_is_used) + { + fprintf(stderr, _("%s: options -c/--command and -C/--multi_command cannot be used together\n"), + pset.progname); + exit(EXIT_FAILURE); + } + /* * if we still have arguments, use it as the database name and username */
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers