--- postgresql-8.4.0.orig/contrib/pgbench/pgbench.c	2009-06-11 23:48:51.000000000 +0900
+++ postgresql-8.4.0/contrib/pgbench/pgbench.c	2009-08-06 10:03:42.000000000 +0900
@@ -31,6 +31,7 @@
 #include "libpq-fe.h"
 #include "pqsignal.h"
 
+#include <string.h>
 #include <ctype.h>
 
 #ifdef WIN32
@@ -120,6 +121,7 @@ typedef struct
 } Variable;
 
 #define MAX_FILES		128		/* max number of SQL script files allowed */
+#define SHELL_COMMAND_SIZE	256		/* maximum size allowed for shell command */
 
 /*
  * structures used in custom query mode
@@ -189,6 +191,29 @@ static char *tpc_b = {
 	"END;\n"
 };
 
+/* -P case */
+static char *tpc_pcase = {
+	"\\set nbranches :scale\n"
+	"\\set ntellers 10 * :scale\n"
+	"\\set naccounts 100000 * :scale\n"
+	"\\setrandom aid 1 :naccounts\n"
+	"\\setrandom bid 1 :nbranches\n"
+	"\\setrandom tid 1 :ntellers\n"
+	"\\setrandom delta -5000 5000\n"
+	"\\setrandom txidrand 0 10000\n"
+	"START TRANSACTION;\n"
+	"UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;\n"
+	"SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
+	"SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
+	"UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;\n"
+	"UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;\n"
+	"INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n"
+	"PREPARE TRANSACTION ':txidrand';\n"
+	"\\shell ls -ll >> /tmp/log_data`date '+%Y%m%d'`_`date '+%k%M'`\n"
+	"COMMIT PREPARED ':txidrand';\n"
+};
+
+
 /* -N case */
 static char *simple_update = {
 	"\\set nbranches :scale\n"
@@ -272,6 +297,7 @@ usage(const char *progname)
 		   "               protocol for submitting queries to server (default: simple)\n"
 		   "  -n           do not run VACUUM before tests\n"
 		   "  -N           do not update tables \"pgbench_tellers\" and \"pgbench_branches\"\n"
+		   "  -P           run 2PC transactions with random prepared TXID"
 		   "  -s NUM       report this scale factor in output\n"
 		   "  -S           perform SELECT-only transactions\n"
 	 "  -t NUM       number of transactions each client runs (default: 10)\n"
@@ -984,6 +1010,40 @@ top:
 
 			st->listen = 1;
 		}
+		else if (pg_strcasecmp(argv[0], "shell") == 0)
+		{
+			int	j,
+				retval,
+				retvalglob;
+			char	commandLoc[SHELL_COMMAND_SIZE];
+
+			retval = snprintf(commandLoc,SHELL_COMMAND_SIZE-1,"%s",argv[1]);
+			if (retval < 0
+				|| retval > SHELL_COMMAND_SIZE-1)
+			{
+				fprintf(stderr, "Error launching shell command: too many characters\n");
+				return;
+			}
+			retvalglob = retval;
+
+			for (j = 2; j < argc; j++)
+			{
+				char *commandLoc2 = strdup(commandLoc);
+
+				retval = snprintf(commandLoc,SHELL_COMMAND_SIZE-1,"%s %s", commandLoc2, argv[j]);
+				retvalglob += retval;
+				if (retval < 0
+					|| retvalglob > SHELL_COMMAND_SIZE-1)
+				{
+					fprintf(stderr, "Error launching shell command: too many characters\n");
+					free(commandLoc2);
+					return;
+				}
+				free(commandLoc2);
+			}
+			system(commandLoc);
+			st->listen = 1;
+		}
 
 		goto top;
 	}
@@ -1280,6 +1340,14 @@ process_commands(char *buf)
 				fprintf(stderr, "%s: extra argument \"%s\" ignored\n",
 						my_commands->argv[0], my_commands->argv[j]);
 		}
+		else if (pg_strcasecmp(my_commands->argv[0], "shell") == 0)
+		{
+			if (my_commands->argc < 1)
+			{
+				fprintf(stderr, "%s: missing command\n", my_commands->argv[0]);
+				return NULL;
+			}
+		}
 		else
 		{
 			fprintf(stderr, "Invalid command %s\n", my_commands->argv[0]);
@@ -1472,6 +1540,8 @@ printResults(
 
 	if (ttype == 0)
 		s = "TPC-B (sort of)";
+	else if (ttype == 4)
+		s = "2PC requests";
 	else if (ttype == 2)
 		s = "Update only pgbench_accounts";
 	else if (ttype == 1)
@@ -1576,7 +1646,7 @@ main(int argc, char **argv)
 
 	memset(state, 0, sizeof(*state));
 
-	while ((c = getopt(argc, argv, "ih:nvp:dSNc:Cs:t:T:U:lf:D:F:M:")) != -1)
+	while ((c = getopt(argc, argv, "ih:nvp:dSNPc:Cs:t:T:U:lf:D:F:M:")) != -1)
 	{
 		switch (c)
 		{
@@ -1604,6 +1674,9 @@ main(int argc, char **argv)
 			case 'N':
 				ttype = 2;
 				break;
+			case 'P':
+				ttype = 4;
+				break;
 			case 'c':
 				nclients = atoi(optarg);
 				if (nclients <= 0 || nclients > MAXCLIENTS)
@@ -1922,6 +1995,11 @@ main(int argc, char **argv)
 			num_files = 1;
 			break;
 
+		case 4:
+			num_files = 1;
+			sql_files[0] = process_builtin(tpc_pcase);
+			break;
+
 		default:
 			break;
 	}
