Automatic transactions in psql

Started by Greg Sabino Mullanealmost 24 years ago9 messages
#1Greg Sabino Mullane
greg@turnstep.com
1 attachment(s)

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

The attached patch actually does two related things. First,
it keeps track of whether or not you are in a trnasaction
and modifies the prompt slightly when you are by putting
an asterick at the very front of it.

Secondly, it adds a "begin transaction" option that, when
enabled, ensures that you are always inside a transaction
while in psql, so you can always rollback. It does this
by issuing a BEGIN at the appropriate times. This patch
(if ever accepted) conflicts a bit with LO_RTANSACTION:
psql now *does* have a way to know if it is in a
transaction or not, so that part may need to get rewritten.

Greg Sabino Mullane greg@turnstep.com
PGP Key: 0x14964AC8 200202061602

-----BEGIN PGP SIGNATURE-----
Comment: http://www.turnstep.com/pgp.html

iQA/AwUBPGGZ37ybkGcUlkrIEQJhJQCgr2TEKcvPakEIC8Exn09pInLLOywAoL4I
uGv3TL6hUm/O1oSPrDVdmdc4
=rmRt
-----END PGP SIGNATURE-----

Attachments:

patchtext/plain; charset=us-ascii; name=patchDownload
*** ./doc/src/sgml/ref/psql-ref.sgml.orig	Wed Feb  6 14:29:27 2002
--- ./doc/src/sgml/ref/psql-ref.sgml	Wed Feb  6 14:31:40 2002
***************
*** 103,109 ****
      <para>
      In normal operation, <application>psql</application> provides a prompt with
      the name of the database to which <application>psql</application> is currently
!     connected, followed by the string <literal>=&gt;</literal>. For example,
  <programlisting>
  $ <userinput>psql testdb</userinput>
  Welcome to psql, the PostgreSQL interactive terminal.
--- 103,113 ----
      <para>
      In normal operation, <application>psql</application> provides a prompt with
      the name of the database to which <application>psql</application> is currently
!     connected, followed by the string <literal>=&gt;</literal>. An asterick 
!     at the beginning of the prompt inicates that you are currently inside of a 
!     transaction.
! 
! For example,
  <programlisting>
  $ <userinput>psql testdb</userinput>
  Welcome to psql, the PostgreSQL interactive terminal.
***************
*** 213,218 ****
--- 217,237 ----
  	If it is not unaligned, set it to unaligned. This command is
  	kept for backwards compatibility. See <command>\pset</command> for a
  	general solution.
+         </para>
+         </listitem>
+       </varlistentry>
+ 
+       <varlistentry>
+         <term><literal>\b</literal></term>
+         <listitem>
+         <para>
+ 	Toggles the creation of automatic transactions. When this is enabled, 
+ 	a <command>BEGIN TRANSACTION</command> command is automatically issued 
+ 	so that every command is automatically inside a transaction. When a 
+ 	<command>COMMIT</command> or a <command>ROLLBACK</command> is issued, 
+ 	a <command>BEGIN TRANSACTION</command> is automatically issued afterwards. 
+ 	The prompt will begin with an asterick (*) when you are inside a 
+ 	transaction.
          </para>
          </listitem>
        </varlistentry>
*** ./src/bin/psql/command.c.orig	Wed Feb  6 14:09:11 2002
--- ./src/bin/psql/command.c	Wed Feb  6 14:08:15 2002
***************
*** 218,223 ****
--- 218,242 ----
  			success = do_pset("format", "unaligned", &pset.popt, quiet);
  	}
  
+ 	/*
+ 	 * \b -- toggle automatic BEGIN TRANSACTION
+ 	 */
+ 	if (strcmp(cmd, "b") == 0)
+ 	{
+ 		pset.begin = !pset.begin;
+ 		if (!quiet)
+ 		{
+ 			if (pset.begin)
+ 			{
+ 				puts(gettext(("Transactions will be started automatically.")));
+ 			}
+ 			else
+ 			{
+ 				puts(gettext(("Transactions will not be started automatically.")));
+ 			}
+ 		}
+ 	}
+ 
  	/* \C -- override table title (formerly change HTML caption) */
  	else if (strcmp(cmd, "C") == 0)
  	{
*** ./src/bin/psql/common.c.orig	Wed Feb  6 14:10:28 2002
--- ./src/bin/psql/common.c	Wed Feb  6 14:15:55 2002
***************
*** 495,505 ****
--- 495,515 ----
  			case PGRES_COMMAND_OK:
  				{
  					char		buf[10];
+ 					char		notice[9];
  
  					success = true;
  					sprintf(buf, "%u", (unsigned int) PQoidValue(results));
  					if (!QUIET())
  						fprintf(pset.queryFout, "%s\n", PQcmdStatus(results));
+  					strncpy(notice, PQcmdStatus(results), 8);
+ 					notice[8] = '\0';
+ 					if (strcmp(notice,"BEGIN") == 0) {
+ 						pset.intrans = true;
+ 					}
+ 					else if (strcmp(notice,"ROLLBACK") == 0 ||
+ 							 strcmp(notice,"COMMIT") == 0) {
+ 						pset.intrans = false;
+ 					}
  					SetVariable(pset.vars, "LASTOID", buf);
  					break;
  				}
***************
*** 535,540 ****
--- 543,549 ----
  			}
  			fputs(gettext("The connection to the server was lost. Attempting reset: "), stderr);
  			PQreset(pset.db);
+ 			pset.intrans = false;
  			if (PQstatus(pset.db) == CONNECTION_BAD)
  			{
  				fputs(gettext("Failed.\n"), stderr);
*** ./src/bin/psql/help.c.orig	Wed Feb  6 14:12:33 2002
--- ./src/bin/psql/help.c	Wed Feb  6 14:23:58 2002
***************
*** 34,41 ****
  /*
   * PLEASE:
   * If you change something in this file, also make the same changes
!  * in the DocBook documentation, file ref/psql-ref.sgml. If you don't
!  * know how to do it, please find someone who can help you.
   */
  
  
--- 34,41 ----
  /*
   * PLEASE:
   * If you change something in this file, also make the same changes
!  * in the DocBook documentation, file doc/src/sgml/ref/psql-ref.sgml.
!  * If you don't know how to do it, please find someone who can help you.
   */
  
  
***************
*** 81,86 ****
--- 81,87 ----
  	puts(_("Options:"));
  	puts(_("  -a              Echo all input from script"));
  	puts(_("  -A              Unaligned table output mode (-P format=unaligned)"));
+ 	puts(_("  -b              Automatically begin transactions"));
  	puts(_("  -c COMMAND      Run only single command (SQL or internal) and exit"));
  
  	/* Display default database */
***************
*** 177,183 ****
  	if (pset.notty == 0 &&
  		(pagerenv = getenv("PAGER")) &&
  		(pagerenv[0] != '\0') &&
! 		screen_size.ws_row <= 39 &&
  		(fout = popen(pagerenv, "w")))
  	{
  		usePipe = true;
--- 178,184 ----
  	if (pset.notty == 0 &&
  		(pagerenv = getenv("PAGER")) &&
  		(pagerenv[0] != '\0') &&
! 		screen_size.ws_row <= 40 &&
  		(fout = popen(pagerenv, "w")))
  	{
  		usePipe = true;
***************
*** 193,198 ****
--- 194,201 ----
  	fprintf(fout, _(" \\c[onnect] [DBNAME|- [USER]]\n"
  		 "                connect to new database (currently \"%s\")\n"),
  			PQdb(pset.db));
+ 	fprintf(fout, _(" \\b             toggle automatic BEGIN TRANSACTION (currently %s)\n"),
+ 			ON(pset.begin));
  	fprintf(fout, _(" \\C TITLE       set table title\n"));
  	fprintf(fout, _(" \\cd [DIRNAME]  change the current working directory\n"));
  	fprintf(fout, _(" \\copy ...      perform SQL COPY with data stream to the client host\n"));
*** ./src/bin/psql/mainloop.c.orig	Wed Feb  6 14:11:37 2002
--- ./src/bin/psql/mainloop.c	Wed Feb  6 14:19:23 2002
***************
*** 161,166 ****
--- 161,175 ----
  		{
  			fflush(stdout);
  
+ 			/* Issue a begin if in "auto-transaction" mode */
+ 			if (!pset.intrans && pset.begin) {
+ 				PGresult   *results;
+ 				results = PSQLexec("BEGIN");
+ 				if (!QUIET())
+ 					fprintf(pset.queryFout, "%s\n", PQcmdStatus(results));
+ 				pset.intrans=true;
+ 			}
+ 
  			/*
  			 * otherwise, set interactive prompt if necessary and get
  			 * another line
*** ./src/bin/psql/prompt.c.orig	Wed Feb  6 14:11:11 2002
--- ./src/bin/psql/prompt.c	Wed Feb  6 14:17:47 2002
***************
*** 80,87 ****
  	else
  		prompt_string = "? ";
  
! 
! 	destination[0] = '\0';
  
  	for (p = prompt_string;
  		 p && *p && strlen(destination) < MAX_PROMPT_SIZE;
--- 80,89 ----
  	else
  		prompt_string = "? ";
  
! 	if (pset.intrans)
! 		strcpy(destination, "*");
! 	else
! 		destination[0] = '\0';
  
  	for (p = prompt_string;
  		 p && *p && strlen(destination) < MAX_PROMPT_SIZE;
*** ./src/bin/psql/settings.h.orig	Wed Feb  6 14:12:58 2002
--- ./src/bin/psql/settings.h	Wed Feb  6 14:25:13 2002
***************
*** 50,55 ****
--- 50,58 ----
  
  	bool		issuper;		/* is the current user a superuser? (used
  								 * to form the prompt) */
+ 
+ 	bool		intrans;		/* are we in a transaction? */
+ 	bool        begin;          /* force BEGIN TRANSACTION */
  } PsqlSettings;
  
  extern PsqlSettings pset;
*** ./src/bin/psql/startup.c.orig	Wed Feb  6 14:12:13 2002
--- ./src/bin/psql/startup.c	Wed Feb  6 14:21:45 2002
***************
*** 279,284 ****
--- 279,285 ----
  	else
  	{
  		pset.issuper = test_superuser(PQuser(pset.db));
+         pset.intrans = false;
  		if (!QUIET() && !pset.notty)
  		{
  			printf(gettext("Welcome to %s, the PostgreSQL interactive terminal.\n\n"
***************
*** 374,387 ****
  	memset(options, 0, sizeof *options);
  
  #ifdef HAVE_GETOPT_LONG
! 	while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:h:Hlno:p:P:qR:sStT:uU:v:VWxX?", long_options, &optindex)) != -1)
  #else							/* not HAVE_GETOPT_LONG */
  
  	/*
  	 * Be sure to leave the '-' in here, so we can catch accidental long
  	 * options.
  	 */
! 	while ((c = getopt(argc, argv, "aAc:d:eEf:F:h:Hlno:p:P:qR:sStT:uU:v:VWxX?-")) != -1)
  #endif   /* not HAVE_GETOPT_LONG */
  	{
  		switch (c)
--- 375,388 ----
  	memset(options, 0, sizeof *options);
  
  #ifdef HAVE_GETOPT_LONG
! 	while ((c = getopt_long(argc, argv, "aAc:bd:eEf:F:h:Hlno:p:P:qR:sStT:uU:v:VWxX?", long_options, &optindex)) != -1)
  #else							/* not HAVE_GETOPT_LONG */
  
  	/*
  	 * Be sure to leave the '-' in here, so we can catch accidental long
  	 * options.
  	 */
! 	while ((c = getopt(argc, argv, "aAc:bd:eEf:F:h:Hlno:p:P:qR:sStT:uU:v:VWxX?-")) != -1)
  #endif   /* not HAVE_GETOPT_LONG */
  	{
  		switch (c)
***************
*** 392,397 ****
--- 393,400 ----
  			case 'A':
  				pset.popt.topt.format = PRINT_UNALIGNED;
  				break;
+ 			case 'b':
+ 				pset.begin = true;
  			case 'c':
  				options->action_string = optarg;
  				if (optarg[0] == '\\')
#2Peter Eisentraut
peter_e@gmx.net
In reply to: Greg Sabino Mullane (#1)
Re: Automatic transactions in psql

Greg Sabino Mullane writes:

The attached patch actually does two related things. First,
it keeps track of whether or not you are in a trnasaction
and modifies the prompt slightly when you are by putting
an asterick at the very front of it.

This is an interesting idea, although you may want to give the user the
option to customize his prompt. Add an escape, maybe %* or %t, with the
meaning "resolves to * if in a transaction block and to the empty string
if not". (The existing escapes were all stolen from tcsh, so look there
if you need an idea.)

Secondly, it adds a "begin transaction" option that, when
enabled, ensures that you are always inside a transaction
while in psql, so you can always rollback.

This should be done in the backend.

--
Peter Eisentraut peter_e@gmx.net

#3Christopher Kings-Lynne
chriskl@familyhealth.com.au
In reply to: Greg Sabino Mullane (#1)
Re: Automatic transactions in psql

Secondly, it adds a "begin transaction" option that, when
enabled, ensures that you are always inside a transaction
while in psql, so you can always rollback. It does this
by issuing a BEGIN at the appropriate times. This patch
(if ever accepted) conflicts a bit with LO_RTANSACTION:
psql now *does* have a way to know if it is in a
transaction or not, so that part may need to get rewritten.

Sweeeet. I've gone mad trying to get people with access to our production
databases to do _everything_ within a transaction when they start fiddling
around!

Chris

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: Peter Eisentraut (#2)
Re: Automatic transactions in psql

Peter Eisentraut <peter_e@gmx.net> writes:

This is an interesting idea, although you may want to give the user the
option to customize his prompt.

Seems cool. I am a bit worried about whether the transaction-block
detection mechanism is reliable, though. We might need to add something
to the FE/BE protocol to make this work correctly.

Secondly, it adds a "begin transaction" option that, when
enabled, ensures that you are always inside a transaction
while in psql, so you can always rollback.

This should be done in the backend.

Agreed. If I recall recent discussions correctly, the spec says that
certain SQL commands should open a transaction and others should not.
It's not reasonable to have that logic in psql rather than the backend.

regards, tom lane

#5Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Greg Sabino Mullane (#1)
Re: Automatic transactions in psql

Thread added.

This has been saved for the 7.3 release:

http://candle.pha.pa.us/cgi-bin/pgpatches2

---------------------------------------------------------------------------

Greg Sabino Mullane wrote:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

The attached patch actually does two related things. First,
it keeps track of whether or not you are in a trnasaction
and modifies the prompt slightly when you are by putting
an asterick at the very front of it.

Secondly, it adds a "begin transaction" option that, when
enabled, ensures that you are always inside a transaction
while in psql, so you can always rollback. It does this
by issuing a BEGIN at the appropriate times. This patch
(if ever accepted) conflicts a bit with LO_RTANSACTION:
psql now *does* have a way to know if it is in a
transaction or not, so that part may need to get rewritten.

Greg Sabino Mullane greg@turnstep.com
PGP Key: 0x14964AC8 200202061602

-----BEGIN PGP SIGNATURE-----
Comment: http://www.turnstep.com/pgp.html

iQA/AwUBPGGZ37ybkGcUlkrIEQJhJQCgr2TEKcvPakEIC8Exn09pInLLOywAoL4I
uGv3TL6hUm/O1oSPrDVdmdc4
=rmRt
-----END PGP SIGNATURE-----

[ Attachment, skipping... ]

---------------------------(end of broadcast)---------------------------
TIP 4: Don't 'kill -9' the postmaster

-- 
  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
#6Thomas Lockhart
lockhart@fourpalms.org
In reply to: Bruce Momjian (#5)
Re: [PATCHES] Automatic transactions in psql

...

Secondly, it adds a "begin transaction" option that, when
enabled, ensures that you are always inside a transaction
while in psql, so you can always rollback. It does this
by issuing a BEGIN at the appropriate times. This patch
(if ever accepted) conflicts a bit with LO_RTANSACTION:
psql now *does* have a way to know if it is in a
transaction or not, so that part may need to get rewritten.

This part of the feature (corresponding to the Ingres "autocommit = off"
feature) should be implemented in the backend rather than in psql. I've
had a moderate interest in doing this but haven't gotten to it; if
someone wants to pick it up I'm sure it would be well received...

- Thomas

#7Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Thomas Lockhart (#6)
Re: [PATCHES] Automatic transactions in psql

Thomas Lockhart wrote:

...

Secondly, it adds a "begin transaction" option that, when
enabled, ensures that you are always inside a transaction
while in psql, so you can always rollback. It does this
by issuing a BEGIN at the appropriate times. This patch
(if ever accepted) conflicts a bit with LO_RTANSACTION:
psql now *does* have a way to know if it is in a
transaction or not, so that part may need to get rewritten.

This part of the feature (corresponding to the Ingres "autocommit = off"
feature) should be implemented in the backend rather than in psql. I've
had a moderate interest in doing this but haven't gotten to it; if
someone wants to pick it up I'm sure it would be well received...

Agreed. I wondered whether we could use the psql status part of this
patch. We currently cound parens and quotes, and show that in the psql
prompt. Could we do that for transaction status? Considering we
already track the parens/quotes, another level of status on the psql
display seems a bit much, even if we could do it reliably. Comments?

-- 
  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
#8Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Tom Lane (#4)
Re: Automatic transactions in psql

Tom Lane wrote:

Peter Eisentraut <peter_e@gmx.net> writes:

This is an interesting idea, although you may want to give the user the
option to customize his prompt.

Seems cool. I am a bit worried about whether the transaction-block
detection mechanism is reliable, though. We might need to add something
to the FE/BE protocol to make this work correctly.

OK, status on this? Seems we can't apply the patch as-is because of
reliability of the status display. Do people wnat a TODO item? I don't
think I want to make an incompatible protocol change for this feature.

-- 
  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
#9Tom Lane
tgl@sss.pgh.pa.us
In reply to: Bruce Momjian (#8)
Re: Automatic transactions in psql

Bruce Momjian <pgman@candle.pha.pa.us> writes:

OK, status on this? Seems we can't apply the patch as-is because of
reliability of the status display. Do people wnat a TODO item? I don't
think I want to make an incompatible protocol change for this feature.

I believe Fernando Nasser at Red Hat is currently working on backend
changes to do this properly; so I recommend we not apply the psql hack.

The notion of customizing the psql prompt based on
in-an-xact-block-or-not seems cool; but I do not see how to do it
reliably without a protocol change, and it's not worth that.

regards, tom lane