2015-11-03 4:16 GMT+01:00 Robert Haas <robertmh...@gmail.com>:

> On Sat, Oct 31, 2015 at 2:50 PM, Pavel Stehule <pavel.steh...@gmail.com>
> wrote:
> > fixed patch attached
>
> The documentation included in this patch doesn't really make it clear
> why -g is different from or better than -c.
>

I wrote some text. But needs some work of native speaker.

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 212dbfa..18ff8e5
*** a/doc/src/sgml/ref/psql-ref.sgml
--- b/doc/src/sgml/ref/psql-ref.sgml
*************** EOF
*** 223,228 ****
--- 223,268 ----
      </varlistentry>
  
      <varlistentry>
+       <term><option>-g <replaceable class="parameter">command(s)</replaceable></></term>
+       <term><option>--group-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>-g</option> options. The option <option>-c</option> can be used
+       only once. The option <option>-g</option> can be used more times.
+       This can simplify writing some non trivial SQL commands. With the
+       <option>-g</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>-g</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>-g</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 -g "VACUUM FULL foo; SELECT pg_relation_size('foo')"
+ psql -Atq -g "VACUUM FULL foo" -g "SELECT pg_relation_size('foo')"
+ </programlisting>
+ 
+       </para>
+ 
+       </listitem>
+     </varlistentry>
+ 
+     <varlistentry>
        <term><option>-h <replaceable class="parameter">hostname</replaceable></></term>
        <term><option>--host=<replaceable class="parameter">hostname</replaceable></></term>
        <listitem>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
new file mode 100644
index 50d3ff5..73ed5c1
*** 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..2ef4ea6
*** a/src/bin/psql/help.c
--- b/src/bin/psql/help.c
*************** usage(unsigned short int pager)
*** 83,88 ****
--- 83,90 ----
  	fprintf(output, _("  -c, --command=COMMAND    run only single command (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, _("  -g, --group-command=COMMAND\n"
+ 					  "                           run more groups of commands (SQL or internal) and exit\n"));
  	fprintf(output, _("  -l, --list               list available databases, then exit\n"));
  	fprintf(output, _("  -v, --set=, --variable=NAME=VALUE\n"
  					  "                           set psql variable NAME to VALUE\n"
diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c
new file mode 100644
index b6cef94..4147238
*** a/src/bin/psql/mainloop.c
--- b/src/bin/psql/mainloop.c
***************
*** 24,31 ****
   * This loop is re-entrant. May be called by \i command
   *	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 */
--- 24,31 ----
   * This loop is re-entrant. May be called by \i command
   *	which reads input from a file.
   */
! static int
! _MainLoop(FILE *source)
  {
  	PsqlScanState scan_state;	/* lexer working state */
  	volatile PQExpBuffer query_buf;		/* buffer for query being accumulated */
*************** MainLoop(FILE *source)
*** 43,48 ****
--- 43,49 ----
  	volatile promptStatus_t prompt_status = PROMPT_READY;
  	volatile int count_eof = 0;
  	volatile bool die_on_error = false;
+ 	GroupCommand *cmd = pset.group_commands;
  
  	/* Save the prior command source */
  	FILE	   *prev_cmd_source;
*************** MainLoop(FILE *source)
*** 135,140 ****
--- 136,155 ----
  				prompt_status = PROMPT_READY;
  			line = gets_interactive(get_prompt(prompt_status));
  		}
+ 		else if (pset.group_commands != NULL)
+ 		{
+ 			/* Is there some unprocessed group command? */
+ 			if (cmd != NULL)
+ 			{
+ 				line = cmd->actions;
+ 				cmd = cmd->next;
+ 			}
+ 			else
+ 			{
+ 				successResult = EXIT_SUCCESS;
+ 				break;
+ 			}
+ 		}
  		else
  		{
  			line = gets_fromFile(source);
*************** MainLoop(FILE *source)
*** 451,456 ****
--- 466,508 ----
  	return successResult;
  }	/* MainLoop() */
  
+ /*
+  * Transactional MainLoop
+  *
+  * allow to execute all statements in single transaction
+  */
+ int
+ MainLoop(FILE *source, bool single_txn)
+ {
+ 	int			result;
+ 	PGresult   *res;
+ 
+ 	if (single_txn)
+ 	{
+ 		if ((res = PSQLexec("BEGIN")) == NULL)
+ 		{
+ 			if (pset.on_error_stop)
+ 				return EXIT_USER;
+ 		}
+ 		else
+ 			PQclear(res);
+ 	}
+ 
+ 	result = _MainLoop(source);
+ 
+ 	if (single_txn)
+ 	{
+ 		if ((res = PSQLexec("COMMIT")) == NULL)
+ 		{
+ 			if (pset.on_error_stop)
+ 				return EXIT_USER;
+ 		}
+ 		else
+ 			PQclear(res);
+ 	}
+ 
+ 	return result;
+ }
  
  /*
   * psqlscan.c is #include'd here instead of being compiled on its own.
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..29455ac
*** a/src/bin/psql/settings.h
--- b/src/bin/psql/settings.h
*************** enum trivalue
*** 77,82 ****
--- 77,88 ----
  	TRI_YES
  };
  
+ typedef struct _GroupCommand
+ {
+ 	char *actions;
+ 	struct _GroupCommand *next;
+ } GroupCommand;
+ 
  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 */
+ 	GroupCommand *group_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..df334b4
*** 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_GROUP_COMMANDS
  };
  
  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.group_commands = NULL;
+ 
  	parse_psql_options(argc, argv, &options);
  
  	/*
*************** main(int argc, char *argv[])
*** 327,332 ****
--- 330,342 ----
  			? EXIT_SUCCESS : EXIT_FAILURE;
  	}
  
+ 	else if (options.action == ACT_GROUP_COMMANDS)
+ 	{
+ 		pset.notty = true;
+ 		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 */
--- 349,355 ----
  		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[
*** 371,376 ****
--- 381,387 ----
  		{"file", required_argument, NULL, 'f'},
  		{"field-separator", required_argument, NULL, 'F'},
  		{"field-separator-zero", no_argument, NULL, 'z'},
+ 		{"group-command", required_argument, NULL, 'g'},
  		{"host", required_argument, NULL, 'h'},
  		{"html", no_argument, NULL, 'H'},
  		{"list", no_argument, NULL, 'l'},
*************** 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)
--- 413,424 ----
  	int			optindex;
  	int			c;
  
+ 	bool			cmd_opt_is_used = false;
+ 	bool			group_cmd_opt_is_used = false;
+ 
  	memset(options, 0, sizeof *options);
  
! 	while ((c = getopt_long(argc, argv, "aAbc:d:eEf:F:g: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 ****
--- 433,440 ----
  				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[
*** 445,450 ****
--- 461,487 ----
  				pset.popt.topt.fieldSep.separator = pg_strdup(optarg);
  				pset.popt.topt.fieldSep.separator_zero = false;
  				break;
+ 			case 'g':
+ 				{
+ 					GroupCommand *cmd = pg_malloc(sizeof(GroupCommand));
+ 					GroupCommand *ptr = pset.group_commands;
+ 
+ 					group_cmd_opt_is_used = true;
+ 
+ 					if (ptr == NULL)
+ 						pset.group_commands = cmd;
+ 					else
+ 					{
+ 						while (ptr->next != NULL)
+ 							ptr =  ptr->next;
+ 
+ 						ptr->next = cmd;
+ 					}
+ 					cmd->next = NULL;
+ 					cmd->actions = pg_strdup(optarg);
+ 					options->action = ACT_GROUP_COMMANDS;
+ 				}
+ 				break;
  			case 'h':
  				options->host = pg_strdup(optarg);
  				break;
*************** parse_psql_options(int argc, char *argv[
*** 601,606 ****
--- 638,650 ----
  		}
  	}
  
+ 	if (cmd_opt_is_used && group_cmd_opt_is_used)
+ 	{
+ 		fprintf(stderr, _("%s: options -c/--command and -g/--group_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

Reply via email to