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

Reply via email to