|
4 | 4 | * A simple benchmark program for PostgreSQL
|
5 | 5 | * Originally written by Tatsuo Ishii and enhanced by many contributors.
|
6 | 6 | *
|
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 $ |
8 | 8 | * Copyright (c) 2000-2009, PostgreSQL Global Development Group
|
9 | 9 | * ALL RIGHTS RESERVED;
|
10 | 10 | *
|
@@ -159,6 +159,7 @@ typedef struct
|
159 | 159 | }Variable;
|
160 | 160 |
|
161 | 161 | #defineMAX_FILES128/* max number of SQL script files allowed */
|
| 162 | +#defineSHELL_COMMAND_SIZE256/* maximum size allowed for shell command */ |
162 | 163 |
|
163 | 164 | /*
|
164 | 165 | * structures used in custom query mode
|
@@ -467,8 +468,8 @@ putVariable(CState *st, char *name, char *value)
|
467 | 468 | var->name=NULL;
|
468 | 469 | var->value=NULL;
|
469 | 470 |
|
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) |
472 | 473 | {
|
473 | 474 | free(var->name);
|
474 | 475 | free(var->value);
|
@@ -590,6 +591,114 @@ getQueryParams(CState *st, const Command *command, const char **params)
|
590 | 591 | params[i]=getVariable(st,command->argv[i+1]);
|
591 | 592 | }
|
592 | 593 |
|
| 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 | + |
593 | 702 | #defineMAX_PREPARE_NAME32
|
594 | 703 | staticvoid
|
595 | 704 | preparedStatementName(char*buffer,intfile,intstate)
|
@@ -992,7 +1101,34 @@ doCustom(CState *st, instr_time *conn_time)
|
992 | 1101 |
|
993 | 1102 | st->listen=1;
|
994 | 1103 | }
|
| 1104 | +elseif (pg_strcasecmp(argv[0],"setshell")==0) |
| 1105 | +{ |
| 1106 | +boolret=runShellCommand(st,argv[1],argv+2,argc-2); |
995 | 1107 |
|
| 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 | +} |
996 | 1132 | gototop;
|
997 | 1133 | }
|
998 | 1134 |
|
@@ -1081,8 +1217,8 @@ init(void)
|
1081 | 1217 |
|
1082 | 1218 | for (i=0;i<ntellers*scale;i++)
|
1083 | 1219 | {
|
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); |
1086 | 1222 | executeStatement(con,sql);
|
1087 | 1223 | }
|
1088 | 1224 |
|
@@ -1313,6 +1449,22 @@ process_commands(char *buf)
|
1313 | 1449 | fprintf(stderr,"%s: extra argument \"%s\" ignored\n",
|
1314 | 1450 | my_commands->argv[0],my_commands->argv[j]);
|
1315 | 1451 | }
|
| 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 | +} |
1316 | 1468 | else
|
1317 | 1469 | {
|
1318 | 1470 | fprintf(stderr,"Invalid command %s\n",my_commands->argv[0]);
|
|