Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7d67e06

Browse files
committed
Add \shell and \setshell meta commands to pgbench.
\shell command runs an external shell command.\setshell also does the same and sets the result to a variable.original patch by Michael Paquier with some editorialization by Itagaki,and reviewed by Greg Smith.
1 parentcddca5e commit7d67e06

File tree

2 files changed

+208
-6
lines changed

2 files changed

+208
-6
lines changed

‎contrib/pgbench/pgbench.c

Lines changed: 157 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* A simple benchmark program for PostgreSQL
55
* Originally written by Tatsuo Ishii and enhanced by many contributors.
66
*
7-
* $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.92 2009/12/11 21:50:06 tgl Exp $
7+
* $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.93 2009/12/15 07:17:57 itagaki Exp $
88
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
99
* ALL RIGHTS RESERVED;
1010
*
@@ -159,6 +159,7 @@ typedef struct
159159
}Variable;
160160

161161
#defineMAX_FILES128/* max number of SQL script files allowed */
162+
#defineSHELL_COMMAND_SIZE256/* maximum size allowed for shell command */
162163

163164
/*
164165
* structures used in custom query mode
@@ -467,8 +468,8 @@ putVariable(CState *st, char *name, char *value)
467468
var->name=NULL;
468469
var->value=NULL;
469470

470-
if ((var->name=strdup(name))==NULL
471-
||(var->value=strdup(value))==NULL)
471+
if ((var->name=strdup(name))==NULL||
472+
(var->value=strdup(value))==NULL)
472473
{
473474
free(var->name);
474475
free(var->value);
@@ -590,6 +591,114 @@ getQueryParams(CState *st, const Command *command, const char **params)
590591
params[i]=getVariable(st,command->argv[i+1]);
591592
}
592593

594+
/*
595+
* Run a shell command. The result is assigned to the variable if not NULL.
596+
* Return true if succeeded, or false on error.
597+
*/
598+
staticbool
599+
runShellCommand(CState*st,char*variable,char**argv,intargc)
600+
{
601+
charcommand[SHELL_COMMAND_SIZE];
602+
inti,
603+
len=0;
604+
FILE*fp;
605+
charres[64];
606+
char*endptr;
607+
intretval;
608+
609+
/*
610+
* Join arguments with whilespace separaters. Arguments starting with
611+
* exactly one colon are treated as variables:
612+
*name - append a string "name"
613+
*:var - append a variable named 'var'.
614+
*::name - append a string ":name"
615+
*/
616+
for (i=0;i<argc;i++)
617+
{
618+
char*arg;
619+
intarglen;
620+
621+
if (argv[i][0]!=':')
622+
{
623+
arg=argv[i];/* a string literal */
624+
}
625+
elseif (argv[i][1]==':')
626+
{
627+
arg=argv[i]+1;/* a string literal starting with colons */
628+
}
629+
elseif ((arg=getVariable(st,argv[i]+1))==NULL)
630+
{
631+
fprintf(stderr,"%s: undefined variable %s\n",argv[0],argv[i]);
632+
return false;
633+
}
634+
635+
arglen=strlen(arg);
636+
if (len+arglen+ (i>0 ?1 :0) >=SHELL_COMMAND_SIZE-1)
637+
{
638+
fprintf(stderr,"%s: too long shell command\n",argv[0]);
639+
return false;
640+
}
641+
642+
if (i>0)
643+
command[len++]=' ';
644+
memcpy(command+len,arg,arglen);
645+
len+=arglen;
646+
}
647+
648+
command[len]='\0';
649+
650+
/* Fast path for non-assignment case */
651+
if (variable==NULL)
652+
{
653+
if (system(command))
654+
{
655+
if (!timer_exceeded)
656+
fprintf(stderr,"%s: cannot launch shell command\n",argv[0]);
657+
return false;
658+
}
659+
return true;
660+
}
661+
662+
/* Execute the command with pipe and read the standard output. */
663+
if ((fp=popen(command,"r"))==NULL)
664+
{
665+
fprintf(stderr,"%s: cannot launch shell command\n",argv[0]);
666+
return false;
667+
}
668+
if (fgets(res,sizeof(res),fp)==NULL)
669+
{
670+
if (!timer_exceeded)
671+
fprintf(stderr,"%s: cannot read the result\n",argv[0]);
672+
return false;
673+
}
674+
if (pclose(fp)<0)
675+
{
676+
fprintf(stderr,"%s: cannot close shell command\n",argv[0]);
677+
return false;
678+
}
679+
680+
/* Check whether the result is an integer and assign it to the variable */
681+
retval= (int)strtol(res,&endptr,10);
682+
while (*endptr!='\0'&&isspace((unsignedchar)*endptr))
683+
endptr++;
684+
if (*res=='\0'||*endptr!='\0')
685+
{
686+
fprintf(stderr,"%s: must return an integer ('%s' returned)\n",argv[0],res);
687+
return false;
688+
}
689+
snprintf(res,sizeof(res),"%d",retval);
690+
if (!putVariable(st,variable,res))
691+
{
692+
fprintf(stderr,"%s: out of memory\n",argv[0]);
693+
return false;
694+
}
695+
696+
#ifdefDEBUG
697+
printf("shell parameter name: %s, value: %s\n",argv[1],res);
698+
#endif
699+
return true;
700+
}
701+
593702
#defineMAX_PREPARE_NAME32
594703
staticvoid
595704
preparedStatementName(char*buffer,intfile,intstate)
@@ -992,7 +1101,34 @@ doCustom(CState *st, instr_time *conn_time)
9921101

9931102
st->listen=1;
9941103
}
1104+
elseif (pg_strcasecmp(argv[0],"setshell")==0)
1105+
{
1106+
boolret=runShellCommand(st,argv[1],argv+2,argc-2);
9951107

1108+
if (timer_exceeded)/* timeout */
1109+
returnclientDone(st, true);
1110+
elseif (!ret)/* on error */
1111+
{
1112+
st->ecnt++;
1113+
return true;
1114+
}
1115+
else/* succeeded */
1116+
st->listen=1;
1117+
}
1118+
elseif (pg_strcasecmp(argv[0],"shell")==0)
1119+
{
1120+
boolret=runShellCommand(st,NULL,argv+1,argc-1);
1121+
1122+
if (timer_exceeded)/* timeout */
1123+
returnclientDone(st, true);
1124+
elseif (!ret)/* on error */
1125+
{
1126+
st->ecnt++;
1127+
return true;
1128+
}
1129+
else/* succeeded */
1130+
st->listen=1;
1131+
}
9961132
gototop;
9971133
}
9981134

@@ -1081,8 +1217,8 @@ init(void)
10811217

10821218
for (i=0;i<ntellers*scale;i++)
10831219
{
1084-
snprintf(sql,256,"insert into pgbench_tellers(tid,bid,tbalance) values (%d,%d,0)"
1085-
,i+1,i /ntellers+1);
1220+
snprintf(sql,256,"insert into pgbench_tellers(tid,bid,tbalance) values (%d,%d,0)",
1221+
i+1,i /ntellers+1);
10861222
executeStatement(con,sql);
10871223
}
10881224

@@ -1313,6 +1449,22 @@ process_commands(char *buf)
13131449
fprintf(stderr,"%s: extra argument \"%s\" ignored\n",
13141450
my_commands->argv[0],my_commands->argv[j]);
13151451
}
1452+
elseif (pg_strcasecmp(my_commands->argv[0],"setshell")==0)
1453+
{
1454+
if (my_commands->argc<3)
1455+
{
1456+
fprintf(stderr,"%s: missing argument\n",my_commands->argv[0]);
1457+
returnNULL;
1458+
}
1459+
}
1460+
elseif (pg_strcasecmp(my_commands->argv[0],"shell")==0)
1461+
{
1462+
if (my_commands->argc<1)
1463+
{
1464+
fprintf(stderr,"%s: missing command\n",my_commands->argv[0]);
1465+
returnNULL;
1466+
}
1467+
}
13161468
else
13171469
{
13181470
fprintf(stderr,"Invalid command %s\n",my_commands->argv[0]);

‎doc/src/sgml/pgbench.sgml

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/pgbench.sgml,v 1.10 2009/08/03 18:30:55 tgl Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/pgbench.sgml,v 1.11 2009/12/15 07:17:57 itagaki Exp $ -->
22

33
<sect1 id="pgbench">
44
<title>pgbench</title>
@@ -466,6 +466,56 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
466466
</varlistentry>
467467
</variablelist>
468468

469+
<varlistentry>
470+
<term>
471+
<literal>\setshell <replaceable>varname</> <replaceable>command</> [ <replaceable>argument</> ... ]</literal>
472+
</term>
473+
474+
<listitem>
475+
<para>
476+
Sets variable <replaceable>varname</> to the result of the shell command
477+
<replaceable>command</>. The command must return an integer value
478+
through its standard output.
479+
</para>
480+
481+
<para>
482+
<replaceable>argument</> can be either a text constant or a
483+
<literal>:</><replaceable>variablename</> reference to a variable of
484+
any types. If you want to use <replaceable>argument</> starting with
485+
colons, you need to add an additional colon at the beginning of
486+
<replaceable>argument</>.
487+
</para>
488+
489+
<para>
490+
Example:
491+
<programlisting>
492+
\setshell variable_to_be_assigned command literal_argument :variable ::literal_starting_with_colon
493+
</programlisting>
494+
</para>
495+
</listitem>
496+
</varlistentry>
497+
</variablelist>
498+
499+
<varlistentry>
500+
<term>
501+
<literal>\shell <replaceable>command</> [ <replaceable>argument</> ... ]</literal>
502+
</term>
503+
504+
<listitem>
505+
<para>
506+
Same as <literal>\setshell</literal>, but the result is ignored.
507+
</para>
508+
509+
<para>
510+
Example:
511+
<programlisting>
512+
\shell command literal_argument :variable ::literal_starting_with_colon
513+
</programlisting>
514+
</para>
515+
</listitem>
516+
</varlistentry>
517+
</variablelist>
518+
469519
<para>
470520
As an example, the full definition of the built-in TPC-B-like
471521
transaction is:

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp