*** c/src/bin/psql/command.c
--- w/src/bin/psql/command.c
***************
*** 1393,1398 **** exec_command(const char *cmd,
--- 1393,1492 ----
  		free(fname);
  	}
  
+ 	/* \watch -- execute a query every N seconds */
+ 	else if (strcmp(cmd, "watch") == 0)
+ 	{
+ 		char					*value;
+ 		PQExpBufferData			 buf;
+ 
+ 		/* Volatile to prevent clobbering by by longjmp. */
+ 		volatile PGresult		*res   = NULL;
+ 		printQueryOpt			 myopt = pset.popt;
+ 		char					 quoted;
+ 		bool					 first = true;
+ 		long					 sleep = 2;
+ 		char					 title[50];
+ 		time_t					 timer;
+ 
+ 		const int		max_watch_delay = 86400;		/* seconds in a day */
+ 
+ 
+ 		initPQExpBuffer(&buf);
+ 
+ 		while ((value = psql_scan_slash_option(scan_state,
+ 											   OT_NORMAL, &quoted, false)))
+ 		{
+ 			/*
+ 			 * If the first value scans as an integer, adjust the watch delay
+ 			 * time.  Otherwise, use a default.
+ 			 */
+ 			if (first && strtol(value, NULL, 10))
+ 			{
+ 				first = false;
+ 
+ 				sleep = strtol(value, NULL, 10);
+ 
+ 				if (sleep < 0)
+ 					sleep = 0;
+ 				else if (sleep > max_watch_delay)
+ 					sleep = max_watch_delay;
+ 			}
+ 			else
+ 			{
+ 				appendPQExpBufferStr(&buf, " ");
+ 				appendPQExpBufferStr(&buf, value);
+ 			}
+ 
+ 			free(value);
+ 		}
+ 
+ 		/*
+ 		 * Set up rendering options, in particular, disable the pager, because
+ 		 * nobody wants to be prompted while watching the output of 'watch'.
+ 		 */
+ 		myopt.nullPrint = NULL;
+ 		myopt.topt.pager = 0;
+ 
+ 		/* Set up cancellation of 'watch' via SIGINT. */
+ 		if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
+ 			goto cleanup;
+ 
+ 		while (true)
+ 		{
+ 			timer = time(NULL);
+ 			snprintf(title, sizeof(title), "Watch every %lds\t%s", sleep,
+ 					 asctime(localtime(&timer)));
+ 			myopt.title = title;
+ 			res = PSQLexec(buf.data, false);
+ 
+ 			/*
+ 			 * If SIGINT is sent while the query is processing, PSQLexec will
+ 			 * consume the interrupt.  The user's intention, though, is to
+ 			 * cancel the entire watch process, so detect a sent cancellation
+ 			 * request and exit in this case.
+ 			 */
+ 			if (cancel_pressed)
+ 				goto cleanup;
+ 
+ 			if (res)
+ 				printQuery((PGresult *) res, &myopt, pset.queryFout,
+ 						   pset.logfile);
+ 
+ 			/*
+ 			 * Enable 'watch' cancellations and wait a while before running the
+ 			 * query again.
+ 			 */
+ 			sigint_interrupt_enabled = true;
+ 			pg_usleep(1000000 * sleep);
+ 			sigint_interrupt_enabled = false;
+ 		}
+ 
+ 	cleanup:
+ 		termPQExpBuffer(&buf);
+ 		if (res)
+ 			PQclear((PGresult *) res);
+ 	}
+ 
  	/* \x -- set or toggle expanded table representation */
  	else if (strcmp(cmd, "x") == 0)
  	{
*** c/src/bin/psql/help.c
--- w/src/bin/psql/help.c
***************
*** 191,196 **** slashUsage(unsigned short int pager)
--- 191,197 ----
  	fprintf(output, _("  \\ir FILE               as \\i, but relative to location of current script\n"));
  	fprintf(output, _("  \\o [FILE]              send all query results to file or |pipe\n"));
  	fprintf(output, _("  \\qecho [STRING]        write string to query output stream (see \\o)\n"));
+ 	fprintf(output, _("  \\watch [SEC] STRING    execute query every SEC seconds\n"));
  	fprintf(output, "\n");
  
  	fprintf(output, _("Informational\n"));
*** c/src/bin/psql/tab-complete.c
--- w/src/bin/psql/tab-complete.c
***************
*** 860,866 **** psql_completion(char *text, int start, int end)
  		"\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
  		"\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
  		"\\set", "\\sf", "\\t", "\\T",
! 		"\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
  	};
  
  	(void) end;					/* not used */
--- 860,866 ----
  		"\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
  		"\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
  		"\\set", "\\sf", "\\t", "\\T",
! 		"\\timing", "\\unset", "\\x", "\\w", "\\watch", "\\z", "\\!", NULL
  	};
  
  	(void) end;					/* not used */
