PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
pgbench.c File Reference
#include "postgres_fe.h"
#include "getopt_long.h"
#include "libpq-fe.h"
#include "portability/instr_time.h"
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <signal.h>
#include <time.h>
#include "pgbench.h"
Include dependency graph for pgbench.c:

Go to the source code of this file.

Data Structures

struct  Variable
 
struct  SimpleStats
 
struct  StatsData
 
struct  CState
 
struct  TState
 
struct  Command
 
struct  ParsedScript
 
struct  BuiltinScript
 

Macros

#define M_PI   3.14159265358979323846
 
#define ERRCODE_UNDEFINED_TABLE   "42P01"
 
#define pthread_t   void *
 
#define MAXCLIENTS   1024
 
#define LOG_STEP_SECONDS   5 /* seconds between log messages */
 
#define DEFAULT_NXACTS   10 /* default nxacts */
 
#define MIN_GAUSSIAN_PARAM   2.0 /* minimum parameter for gauss */
 
#define nbranches
 
#define ntellers   10
 
#define naccounts   100000
 
#define SCALE_32BIT_THRESHOLD   20000
 
#define WSEP   '@' /* weight separator */
 
#define MAX_SCRIPTS   128 /* max number of SQL scripts allowed */
 
#define SHELL_COMMAND_SIZE   256 /* maximum size allowed for shell command */
 
#define INVALID_THREAD   ((pthread_t) 0)
 
#define SQL_COMMAND   1
 
#define META_COMMAND   2
 
#define MAX_ARGS   10
 
#define PARAMS_ARRAY_SIZE   7
 
#define MAX_FARGS   16
 
#define MAX_PREPARE_NAME   32
 
#define SCALE_32BIT_THRESHOLD   20000
 
#define COMMANDS_ALLOC_NUM   128
 

Typedefs

typedef struct SimpleStats SimpleStats
 
typedef struct StatsData StatsData
 
typedef enum QueryMode QueryMode
 
typedef struct ParsedScript ParsedScript
 
typedef struct BuiltinScript BuiltinScript
 

Enumerations

enum  ConnectionStateEnum {
  CSTATE_CHOOSE_SCRIPT, CSTATE_START_THROTTLE, CSTATE_THROTTLE, CSTATE_START_TX,
  CSTATE_START_COMMAND, CSTATE_WAIT_RESULT, CSTATE_SLEEP, CSTATE_END_COMMAND,
  CSTATE_END_TX, CSTATE_ABORTED, CSTATE_FINISHED
}
 
enum  QueryMode { QUERY_SIMPLE, QUERY_EXTENDED, QUERY_PREPARED, NUM_QUERYMODE }
 

Functions

static void setIntValue (PgBenchValue *pv, int64 ival)
 
static void setDoubleValue (PgBenchValue *pv, double dval)
 
static bool evaluateExpr (TState *, CState *, PgBenchExpr *, PgBenchValue *)
 
static void doLog (TState *thread, CState *st, StatsData *agg, bool skipped, double latency, double lag)
 
static void processXactStats (TState *thread, CState *st, instr_time *now, bool skipped, StatsData *agg)
 
static void pgbench_error (const char *fmt,...) pg_attribute_printf(1
 
static void static void addScript (ParsedScript script)
 
static void * threadRun (void *arg)
 
static void setalarm (int seconds)
 
static void usage (void)
 
static bool is_an_int (const char *str)
 
int64 strtoint64 (const char *str)
 
static int64 getrand (TState *thread, int64 min, int64 max)
 
static int64 getExponentialRand (TState *thread, int64 min, int64 max, double parameter)
 
static int64 getGaussianRand (TState *thread, int64 min, int64 max, double parameter)
 
static int64 getPoissonRand (TState *thread, int64 center)
 
static void initSimpleStats (SimpleStats *ss)
 
static void addToSimpleStats (SimpleStats *ss, double val)
 
static void mergeSimpleStats (SimpleStats *acc, SimpleStats *ss)
 
static void initStats (StatsData *sd, time_t start_time)
 
static void accumStats (StatsData *stats, bool skipped, double lat, double lag)
 
static void executeStatement (PGconn *con, const char *sql)
 
static void tryExecuteStatement (PGconn *con, const char *sql)
 
static PGconndoConnect (void)
 
static void discard_response (CState *state)
 
static int compareVariableNames (const void *v1, const void *v2)
 
static VariablelookupVariable (CState *st, char *name)
 
static char * getVariable (CState *st, char *name)
 
static bool makeVariableNumeric (Variable *var)
 
static bool valid_variable_name (const char *name)
 
static VariablelookupCreateVariable (CState *st, const char *context, char *name)
 
static bool putVariable (CState *st, const char *context, char *name, const char *value)
 
static bool putVariableNumber (CState *st, const char *context, char *name, const PgBenchValue *value)
 
static bool putVariableInt (CState *st, const char *context, char *name, int64 value)
 
static char * parseVariable (const char *sql, int *eaten)
 
static char * replaceVariable (char **sql, char *param, int len, char *value)
 
static char * assignVariables (CState *st, char *sql)
 
static void getQueryParams (CState *st, const Command *command, const char **params)
 
static bool coerceToInt (PgBenchValue *pval, int64 *ival)
 
static bool coerceToDouble (PgBenchValue *pval, double *dval)
 
static bool evalFunc (TState *thread, CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
 
static bool runShellCommand (CState *st, char *variable, char **argv, int argc)
 
static void preparedStatementName (char *buffer, int file, int state)
 
static void commandFailed (CState *st, char *message)
 
static int chooseScript (TState *thread)
 
static bool sendCommand (CState *st, Command *command)
 
static bool evaluateSleep (CState *st, int argc, char **argv, int *usecs)
 
static void doCustom (TState *thread, CState *st, StatsData *agg)
 
static void disconnect_all (CState *state, int length)
 
static void init (bool is_no_vacuum)
 
static bool parseQuery (Command *cmd)
 
void syntax_error (const char *source, int lineno, const char *line, const char *command, const char *msg, const char *more, int column)
 
static Commandprocess_sql_command (PQExpBuffer buf, const char *source)
 
static Commandprocess_backslash_command (PsqlScanState sstate, const char *source)
 
static void ParseScript (const char *script, const char *desc, int weight)
 
static char * read_file_contents (FILE *fd)
 
static void process_file (const char *filename, int weight)
 
static void process_builtin (const BuiltinScript *bi, int weight)
 
static void listAvailableScripts (void)
 
static const BuiltinScriptfindBuiltin (const char *name)
 
static int parseScriptWeight (const char *option, char **script)
 
static void printSimpleStats (char *prefix, SimpleStats *ss)
 
static void printResults (TState *threads, StatsData *total, instr_time total_time, instr_time conn_total_time, int latency_late)
 
int main (int argc, char **argv)
 
static void handle_sig_alarm (SIGNAL_ARGS)
 

Variables

int nxacts = 0
 
int duration = 0
 
int64 end_time = 0
 
int scale = 1
 
int fillfactor = 100
 
int foreign_keys = 0
 
int unlogged_tables = 0
 
double sample_rate = 0.0
 
int64 throttle_delay = 0
 
int64 latency_limit = 0
 
char * tablespace = NULL
 
char * index_tablespace = NULL
 
bool use_log
 
bool use_quiet
 
int agg_interval
 
bool per_script_stats = false
 
int progress = 0
 
bool progress_timestamp = false
 
int nclients = 1
 
int nthreads = 1
 
bool is_connect
 
bool is_latencies
 
int main_pid
 
char * pghost = ""
 
char * pgport = ""
 
char * login = NULL
 
char * dbName
 
char * logfile_prefix = NULL
 
const char * progname
 
volatile bool timer_exceeded = false
 
static QueryMode querymode = QUERY_SIMPLE
 
static const char * QUERYMODE [] = {"simple", "extended", "prepared"}
 
static ParsedScript sql_script [MAX_SCRIPTS]
 
static int num_scripts
 
static int num_commands = 0
 
static int64 total_weight = 0
 
static int debug = 0
 
static const BuiltinScript builtin_script []
 
static const PsqlScanCallbacks pgbench_callbacks
 

Macro Definition Documentation

#define COMMANDS_ALLOC_NUM   128

Referenced by ParseScript().

#define DEFAULT_NXACTS   10 /* default nxacts */

Definition at line 94 of file pgbench.c.

Referenced by main().

#define INVALID_THREAD   ((pthread_t) 0)

Definition at line 356 of file pgbench.c.

Referenced by main().

#define LOG_STEP_SECONDS   5 /* seconds between log messages */

Definition at line 93 of file pgbench.c.

Referenced by init().

#define M_PI   3.14159265358979323846

Definition at line 56 of file pgbench.c.

Referenced by evalFunc(), and getGaussianRand().

#define MAX_ARGS   10

Definition at line 363 of file pgbench.c.

Referenced by parseQuery(), process_backslash_command(), and sendCommand().

#define MAX_FARGS   16

Definition at line 1315 of file pgbench.c.

Referenced by evalFunc().

#define MAX_PREPARE_NAME   32

Definition at line 1832 of file pgbench.c.

Referenced by sendCommand().

#define MAX_SCRIPTS   128 /* max number of SQL scripts allowed */

Definition at line 207 of file pgbench.c.

Referenced by addScript().

#define MAXCLIENTS   1024

Definition at line 90 of file pgbench.c.

Referenced by main().

#define META_COMMAND   2

Definition at line 362 of file pgbench.c.

Referenced by doCustom(), and process_backslash_command().

#define MIN_GAUSSIAN_PARAM   2.0 /* minimum parameter for gauss */

Definition at line 96 of file pgbench.c.

Referenced by evalFunc(), and getGaussianRand().

#define naccounts   100000

Definition at line 156 of file pgbench.c.

Referenced by init().

#define nbranches
Value:
1 /* Makes little sense to change this. Change
* -s instead */

Definition at line 153 of file pgbench.c.

Referenced by init().

#define ntellers   10

Definition at line 155 of file pgbench.c.

Referenced by init().

#define PARAMS_ARRAY_SIZE   7

Referenced by doConnect().

#define pthread_t   void *

Definition at line 79 of file pgbench.c.

Referenced by main().

#define SCALE_32BIT_THRESHOLD   20000

Definition at line 165 of file pgbench.c.

Referenced by init().

#define SCALE_32BIT_THRESHOLD   20000

Definition at line 165 of file pgbench.c.

#define SHELL_COMMAND_SIZE   256 /* maximum size allowed for shell command */

Definition at line 208 of file pgbench.c.

Referenced by runShellCommand().

#define SQL_COMMAND   1

Definition at line 361 of file pgbench.c.

Referenced by doCustom(), main(), process_sql_command(), and sendCommand().

#define WSEP   '@' /* weight separator */

Definition at line 187 of file pgbench.c.

Referenced by parseScriptWeight().

Typedef Documentation

Enumeration Type Documentation

Enumerator
CSTATE_CHOOSE_SCRIPT 
CSTATE_START_THROTTLE 
CSTATE_THROTTLE 
CSTATE_START_TX 
CSTATE_START_COMMAND 
CSTATE_WAIT_RESULT 
CSTATE_SLEEP 
CSTATE_END_COMMAND 
CSTATE_END_TX 
CSTATE_ABORTED 
CSTATE_FINISHED 

Definition at line 242 of file pgbench.c.

243 {
244  /*
245  * The client must first choose a script to execute. Once chosen, it can
246  * either be throttled (state CSTATE_START_THROTTLE under --rate) or start
247  * right away (state CSTATE_START_TX).
248  */
250 
251  /*
252  * In CSTATE_START_THROTTLE state, we calculate when to begin the next
253  * transaction, and advance to CSTATE_THROTTLE. CSTATE_THROTTLE state
254  * sleeps until that moment. (If throttling is not enabled, doCustom()
255  * falls directly through from CSTATE_START_THROTTLE to CSTATE_START_TX.)
256  */
259 
260  /*
261  * CSTATE_START_TX performs start-of-transaction processing. Establishes
262  * a new connection for the transaction, in --connect mode, and records
263  * the transaction start time.
264  */
266 
267  /*
268  * We loop through these states, to process each command in the script:
269  *
270  * CSTATE_START_COMMAND starts the execution of a command. On a SQL
271  * command, the command is sent to the server, and we move to
272  * CSTATE_WAIT_RESULT state. On a \sleep meta-command, the timer is set,
273  * and we enter the CSTATE_SLEEP state to wait for it to expire. Other
274  * meta-commands are executed immediately.
275  *
276  * CSTATE_WAIT_RESULT waits until we get a result set back from the server
277  * for the current command.
278  *
279  * CSTATE_SLEEP waits until the end of \sleep.
280  *
281  * CSTATE_END_COMMAND records the end-of-command timestamp, increments the
282  * command counter, and loops back to CSTATE_START_COMMAND state.
283  */
286  CSTATE_SLEEP,
288 
289  /*
290  * CSTATE_END_TX performs end-of-transaction processing. Calculates
291  * latency, and logs the transaction. In --connect mode, closes the
292  * current connection. Chooses the next script to execute and starts over
293  * in CSTATE_START_THROTTLE state, or enters CSTATE_FINISHED if we have no
294  * more work to do.
295  */
297 
298  /*
299  * Final states. CSTATE_ABORTED means that the script execution was
300  * aborted because a command failed, CSTATE_FINISHED means success.
301  */
ConnectionStateEnum
Definition: pgbench.c:242
enum QueryMode
Enumerator
QUERY_SIMPLE 
QUERY_EXTENDED 
QUERY_PREPARED 
NUM_QUERYMODE 

Definition at line 365 of file pgbench.c.

366 {
367  QUERY_SIMPLE, /* simple query */
368  QUERY_EXTENDED, /* extended query */
369  QUERY_PREPARED, /* extended query with prepared statements */
371 } QueryMode;
QueryMode
Definition: pgbench.c:365

Function Documentation

static void accumStats ( StatsData stats,
bool  skipped,
double  lat,
double  lag 
)
static

Definition at line 797 of file pgbench.c.

References addToSimpleStats(), StatsData::cnt, StatsData::lag, StatsData::latency, and StatsData::skipped.

Referenced by doLog(), and processXactStats().

798 {
799  stats->cnt++;
800 
801  if (skipped)
802  {
803  /* no latency to record on skipped transactions */
804  stats->skipped++;
805  }
806  else
807  {
808  addToSimpleStats(&stats->latency, lat);
809 
810  /* and possibly the same for schedule lag */
811  if (throttle_delay)
812  addToSimpleStats(&stats->lag, lag);
813  }
814 }
SimpleStats lag
Definition: pgbench.c:236
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:753
SimpleStats latency
Definition: pgbench.c:235
int64 cnt
Definition: pgbench.c:232
int64 skipped
Definition: pgbench.c:233
int64 throttle_delay
Definition: pgbench.c:133
static void addScript ( ParsedScript  script)
static

Definition at line 3488 of file pgbench.c.

References ParsedScript::commands, ParsedScript::desc, MAX_SCRIPTS, and num_scripts.

Referenced by ParseScript().

3489 {
3490  if (script.commands == NULL || script.commands[0] == NULL)
3491  {
3492  fprintf(stderr, "empty command list for script \"%s\"\n", script.desc);
3493  exit(1);
3494  }
3495 
3496  if (num_scripts >= MAX_SCRIPTS)
3497  {
3498  fprintf(stderr, "at most %d SQL scripts are allowed\n", MAX_SCRIPTS);
3499  exit(1);
3500  }
3501 
3502  sql_script[num_scripts] = script;
3503  num_scripts++;
3504 }
static int num_scripts
Definition: pgbench.c:396
#define MAX_SCRIPTS
Definition: pgbench.c:207
const char * desc
Definition: pgbench.c:389
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:395
Command ** commands
Definition: pgbench.c:391
static void addToSimpleStats ( SimpleStats ss,
double  val 
)
static

Definition at line 753 of file pgbench.c.

References SimpleStats::count, SimpleStats::max, SimpleStats::min, SimpleStats::sum, SimpleStats::sum2, and val.

Referenced by accumStats(), and doCustom().

754 {
755  if (ss->count == 0 || val < ss->min)
756  ss->min = val;
757  if (ss->count == 0 || val > ss->max)
758  ss->max = val;
759  ss->count++;
760  ss->sum += val;
761  ss->sum2 += val * val;
762 }
double sum
Definition: pgbench.c:221
int64 count
Definition: pgbench.c:218
double max
Definition: pgbench.c:220
double sum2
Definition: pgbench.c:222
long val
Definition: informix.c:689
double min
Definition: pgbench.c:219
static char* assignVariables ( CState st,
char *  sql 
)
static

Definition at line 1213 of file pgbench.c.

References free, getVariable(), name, parseVariable(), replaceVariable(), and val.

Referenced by sendCommand().

1214 {
1215  char *p,
1216  *name,
1217  *val;
1218 
1219  p = sql;
1220  while ((p = strchr(p, ':')) != NULL)
1221  {
1222  int eaten;
1223 
1224  name = parseVariable(p, &eaten);
1225  if (name == NULL)
1226  {
1227  while (*p == ':')
1228  {
1229  p++;
1230  }
1231  continue;
1232  }
1233 
1234  val = getVariable(st, name);
1235  free(name);
1236  if (val == NULL)
1237  {
1238  p++;
1239  continue;
1240  }
1241 
1242  p = replaceVariable(&sql, p, eaten, val);
1243  }
1244 
1245  return sql;
1246 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:966
static char * replaceVariable(char **sql, char *param, int len, char *value)
Definition: pgbench.c:1193
#define free(a)
Definition: header.h:65
static char * parseVariable(const char *sql, int *eaten)
Definition: pgbench.c:1170
const char * name
Definition: encode.c:521
long val
Definition: informix.c:689
static int chooseScript ( TState thread)
static

Definition at line 1849 of file pgbench.c.

References getrand(), i, and ParsedScript::weight.

Referenced by doCustom().

1850 {
1851  int i = 0;
1852  int64 w;
1853 
1854  if (num_scripts == 1)
1855  return 0;
1856 
1857  w = getrand(thread, 0, total_weight - 1);
1858  do
1859  {
1860  w -= sql_script[i++].weight;
1861  } while (w >= 0);
1862 
1863  return i - 1;
1864 }
static int64 getrand(TState *thread, int64 min, int64 max)
Definition: pgbench.c:627
static int num_scripts
Definition: pgbench.c:396
int weight
Definition: pgbench.c:390
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:395
static int64 total_weight
Definition: pgbench.c:398
int i
static bool coerceToDouble ( PgBenchValue pval,
double *  dval 
)
static

Definition at line 1283 of file pgbench.c.

References Assert, PgBenchValue::dval, PgBenchValue::ival, PGBT_DOUBLE, PGBT_INT, PgBenchValue::type, and PgBenchValue::u.

Referenced by evalFunc().

1284 {
1285  if (pval->type == PGBT_DOUBLE)
1286  {
1287  *dval = pval->u.dval;
1288  return true;
1289  }
1290  else
1291  {
1292  Assert(pval->type == PGBT_INT);
1293  *dval = (double) pval->u.ival;
1294  return true;
1295  }
1296 }
union PgBenchValue::@39 u
double dval
Definition: pgbench.h:47
#define Assert(condition)
Definition: c.h:664
PgBenchValueType type
Definition: pgbench.h:43
int64 ival
Definition: pgbench.h:46
static bool coerceToInt ( PgBenchValue pval,
int64 *  ival 
)
static

Definition at line 1259 of file pgbench.c.

References Assert, PgBenchValue::dval, PgBenchValue::ival, PG_INT64_MAX, PG_INT64_MIN, PGBT_DOUBLE, PGBT_INT, PgBenchValue::type, and PgBenchValue::u.

Referenced by evalFunc().

1260 {
1261  if (pval->type == PGBT_INT)
1262  {
1263  *ival = pval->u.ival;
1264  return true;
1265  }
1266  else
1267  {
1268  double dval = pval->u.dval;
1269 
1270  Assert(pval->type == PGBT_DOUBLE);
1271  if (dval < PG_INT64_MIN || PG_INT64_MAX < dval)
1272  {
1273  fprintf(stderr, "double to int overflow for %f\n", dval);
1274  return false;
1275  }
1276  *ival = (int64) dval;
1277  return true;
1278  }
1279 }
#define PG_INT64_MAX
Definition: c.h:328
union PgBenchValue::@39 u
#define PG_INT64_MIN
Definition: c.h:327
double dval
Definition: pgbench.h:47
#define Assert(condition)
Definition: c.h:664
PgBenchValueType type
Definition: pgbench.h:43
int64 ival
Definition: pgbench.h:46
static void commandFailed ( CState st,
char *  message 
)
static

Definition at line 1840 of file pgbench.c.

References CState::command, CState::id, and CState::use_file.

Referenced by doCustom().

1841 {
1842  fprintf(stderr,
1843  "client %d aborted in command %d of script %d; %s\n",
1844  st->id, st->command, st->use_file, message);
1845 }
int id
Definition: pgbench.c:312
int command
Definition: pgbench.c:316
int use_file
Definition: pgbench.c:315
static int compareVariableNames ( const void *  v1,
const void *  v2 
)
static

Definition at line 931 of file pgbench.c.

References name.

Referenced by lookupVariable().

932 {
933  return strcmp(((const Variable *) v1)->name,
934  ((const Variable *) v2)->name);
935 }
const char * name
Definition: encode.c:521
static void discard_response ( CState state)
static

Definition at line 917 of file pgbench.c.

References CState::con, PQclear(), and PQgetResult().

Referenced by doCustom().

918 {
919  PGresult *res;
920 
921  do
922  {
923  res = PQgetResult(state->con);
924  if (res)
925  PQclear(res);
926  } while (res);
927 }
void PQclear(PGresult *res)
Definition: fe-exec.c:671
PGconn * con
Definition: pgbench.c:311
PGresult * PQgetResult(PGconn *conn)
Definition: fe-exec.c:1753
static void disconnect_all ( CState state,
int  length 
)
static

Definition at line 2594 of file pgbench.c.

References CState::con, i, length(), and PQfinish().

Referenced by main(), and threadRun().

2595 {
2596  int i;
2597 
2598  for (i = 0; i < length; i++)
2599  {
2600  if (state[i].con)
2601  {
2602  PQfinish(state[i].con);
2603  state[i].con = NULL;
2604  }
2605  }
2606 }
int length(const List *list)
Definition: list.c:1271
void PQfinish(PGconn *conn)
Definition: fe-connect.c:3630
PGconn * con
Definition: pgbench.c:311
int i
static PGconn* doConnect ( void  )
static

Definition at line 848 of file pgbench.c.

References conn, CONNECTION_BAD, dbName, have_password, login, PARAMS_ARRAY_SIZE, password, pghost, pgport, PQconnectdbParams(), PQconnectionNeedsPassword(), PQerrorMessage(), PQfinish(), PQstatus(), progname, simple_prompt(), and values.

Referenced by doCustom(), init(), main(), and threadRun().

849 {
850  PGconn *conn;
851  bool new_pass;
852  static bool have_password = false;
853  static char password[100];
854 
855  /*
856  * Start the connection. Loop until we have a password if requested by
857  * backend.
858  */
859  do
860  {
861 #define PARAMS_ARRAY_SIZE 7
862 
863  const char *keywords[PARAMS_ARRAY_SIZE];
864  const char *values[PARAMS_ARRAY_SIZE];
865 
866  keywords[0] = "host";
867  values[0] = pghost;
868  keywords[1] = "port";
869  values[1] = pgport;
870  keywords[2] = "user";
871  values[2] = login;
872  keywords[3] = "password";
873  values[3] = have_password ? password : NULL;
874  keywords[4] = "dbname";
875  values[4] = dbName;
876  keywords[5] = "fallback_application_name";
877  values[5] = progname;
878  keywords[6] = NULL;
879  values[6] = NULL;
880 
881  new_pass = false;
882 
883  conn = PQconnectdbParams(keywords, values, true);
884 
885  if (!conn)
886  {
887  fprintf(stderr, "connection to database \"%s\" failed\n",
888  dbName);
889  return NULL;
890  }
891 
892  if (PQstatus(conn) == CONNECTION_BAD &&
894  !have_password)
895  {
896  PQfinish(conn);
897  simple_prompt("Password: ", password, sizeof(password), false);
898  have_password = true;
899  new_pass = true;
900  }
901  } while (new_pass);
902 
903  /* check to see that the backend connection was successfully made */
904  if (PQstatus(conn) == CONNECTION_BAD)
905  {
906  fprintf(stderr, "connection to database \"%s\" failed:\n%s",
907  dbName, PQerrorMessage(conn));
908  PQfinish(conn);
909  return NULL;
910  }
911 
912  return conn;
913 }
static char password[100]
Definition: streamutil.c:42
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6097
void PQfinish(PGconn *conn)
Definition: fe-connect.c:3630
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:529
PGconn * conn
Definition: streamutil.c:43
void simple_prompt(const char *prompt, char *destination, size_t destlen, bool echo)
Definition: sprompt.c:37
#define PARAMS_ARRAY_SIZE
char * pghost
Definition: pgbench.c:180
static bool have_password
Definition: streamutil.c:41
const char * progname
Definition: pgbench.c:185
static Datum values[MAXATTR]
Definition: bootstrap.c:163
int PQconnectionNeedsPassword(const PGconn *conn)
Definition: fe-connect.c:6131
char * dbName
Definition: pgbench.c:183
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:6044
char * pgport
Definition: pgbench.c:181
char * login
Definition: pgbench.c:182
static void doCustom ( TState thread,
CState st,
StatsData agg 
)
static

Definition at line 1987 of file pgbench.c.

References addToSimpleStats(), Command::argc, Command::argv, Assert, chooseScript(), CState::cnt, CState::command, commandFailed(), ParsedScript::commands, CState::con, TState::conn_time, CSTATE_ABORTED, CSTATE_CHOOSE_SCRIPT, CSTATE_END_COMMAND, CSTATE_END_TX, CSTATE_FINISHED, CSTATE_SLEEP, CSTATE_START_COMMAND, CSTATE_START_THROTTLE, CSTATE_START_TX, CSTATE_THROTTLE, CSTATE_WAIT_RESULT, ParsedScript::desc, discard_response(), doConnect(), evaluateExpr(), evaluateSleep(), Command::expr, getPoissonRand(), i, CState::id, INSTR_TIME_ACCUM_DIFF, INSTR_TIME_GET_DOUBLE, INSTR_TIME_GET_MICROSEC, INSTR_TIME_IS_ZERO, INSTR_TIME_SET_CURRENT, INSTR_TIME_SET_ZERO, INT64_FORMAT, META_COMMAND, now(), pg_strcasecmp(), PGRES_COMMAND_OK, PGRES_EMPTY_QUERY, PGRES_TUPLES_OK, PQclear(), PQconsumeInput(), PQerrorMessage(), PQfinish(), PQgetResult(), PQisBusy(), PQresultStatus(), CState::prepared, processXactStats(), putVariableNumber(), result, runShellCommand(), sendCommand(), CState::sleep_until, SQL_COMMAND, CState::state, Command::stats, CState::stmt_begin, TState::throttle_trigger, CState::txn_begin, CState::txn_scheduled, Command::type, and CState::use_file.

Referenced by threadRun().

1988 {
1989  PGresult *res;
1990  Command *command;
1991  instr_time now;
1992  bool end_tx_processed = false;
1993  int64 wait;
1994 
1995  /*
1996  * gettimeofday() isn't free, so we get the current timestamp lazily the
1997  * first time it's needed, and reuse the same value throughout this
1998  * function after that. This also ensures that e.g. the calculated
1999  * latency reported in the log file and in the totals are the same. Zero
2000  * means "not set yet". Reset "now" when we execute shell commands or
2001  * expressions, which might take a non-negligible amount of time, though.
2002  */
2003  INSTR_TIME_SET_ZERO(now);
2004 
2005  /*
2006  * Loop in the state machine, until we have to wait for a result from the
2007  * server (or have to sleep, for throttling or for \sleep).
2008  *
2009  * Note: In the switch-statement below, 'break' will loop back here,
2010  * meaning "continue in the state machine". Return is used to return to
2011  * the caller.
2012  */
2013  for (;;)
2014  {
2015  switch (st->state)
2016  {
2017  /*
2018  * Select transaction to run.
2019  */
2020  case CSTATE_CHOOSE_SCRIPT:
2021 
2022  st->use_file = chooseScript(thread);
2023 
2024  if (debug)
2025  fprintf(stderr, "client %d executing script \"%s\"\n", st->id,
2026  sql_script[st->use_file].desc);
2027 
2028  if (throttle_delay > 0)
2030  else
2031  st->state = CSTATE_START_TX;
2032  break;
2033 
2034  /*
2035  * Handle throttling once per transaction by sleeping.
2036  */
2037  case CSTATE_START_THROTTLE:
2038 
2039  /*
2040  * Generate a delay such that the series of delays will
2041  * approximate a Poisson distribution centered on the
2042  * throttle_delay time.
2043  *
2044  * If transactions are too slow or a given wait is shorter
2045  * than a transaction, the next transaction will start right
2046  * away.
2047  */
2048  Assert(throttle_delay > 0);
2049  wait = getPoissonRand(thread, throttle_delay);
2050 
2051  thread->throttle_trigger += wait;
2052  st->txn_scheduled = thread->throttle_trigger;
2053 
2054  /*
2055  * stop client if next transaction is beyond pgbench end of
2056  * execution
2057  */
2058  if (duration > 0 && st->txn_scheduled > end_time)
2059  {
2060  st->state = CSTATE_FINISHED;
2061  break;
2062  }
2063 
2064  /*
2065  * If --latency-limit is used, and this slot is already late
2066  * so that the transaction will miss the latency limit even if
2067  * it completed immediately, we skip this time slot and
2068  * iterate till the next slot that isn't late yet. But don't
2069  * iterate beyond the -t limit, if one is given.
2070  */
2071  if (latency_limit)
2072  {
2073  int64 now_us;
2074 
2075  if (INSTR_TIME_IS_ZERO(now))
2077  now_us = INSTR_TIME_GET_MICROSEC(now);
2078  while (thread->throttle_trigger < now_us - latency_limit &&
2079  (nxacts <= 0 || st->cnt < nxacts))
2080  {
2081  processXactStats(thread, st, &now, true, agg);
2082  /* next rendez-vous */
2083  wait = getPoissonRand(thread, throttle_delay);
2084  thread->throttle_trigger += wait;
2085  st->txn_scheduled = thread->throttle_trigger;
2086  }
2087  /* stop client if -t exceeded */
2088  if (nxacts > 0 && st->cnt >= nxacts)
2089  {
2090  st->state = CSTATE_FINISHED;
2091  break;
2092  }
2093  }
2094 
2095  st->state = CSTATE_THROTTLE;
2096  if (debug)
2097  fprintf(stderr, "client %d throttling " INT64_FORMAT " us\n",
2098  st->id, wait);
2099  break;
2100 
2101  /*
2102  * Wait until it's time to start next transaction.
2103  */
2104  case CSTATE_THROTTLE:
2105  if (INSTR_TIME_IS_ZERO(now))
2107  if (INSTR_TIME_GET_MICROSEC(now) < st->txn_scheduled)
2108  return; /* Still sleeping, nothing to do here */
2109 
2110  /* Else done sleeping, start the transaction */
2111  st->state = CSTATE_START_TX;
2112  break;
2113 
2114  /* Start new transaction */
2115  case CSTATE_START_TX:
2116 
2117  /*
2118  * Establish connection on first call, or if is_connect is
2119  * true.
2120  */
2121  if (st->con == NULL)
2122  {
2123  instr_time start;
2124 
2125  if (INSTR_TIME_IS_ZERO(now))
2127  start = now;
2128  if ((st->con = doConnect()) == NULL)
2129  {
2130  fprintf(stderr, "client %d aborted while establishing connection\n",
2131  st->id);
2132  st->state = CSTATE_ABORTED;
2133  break;
2134  }
2136  INSTR_TIME_ACCUM_DIFF(thread->conn_time, now, start);
2137 
2138  /* Reset session-local state */
2139  memset(st->prepared, 0, sizeof(st->prepared));
2140  }
2141 
2142  /*
2143  * Record transaction start time under logging, progress or
2144  * throttling.
2145  */
2148  {
2149  if (INSTR_TIME_IS_ZERO(now))
2151  st->txn_begin = now;
2152 
2153  /*
2154  * When not throttling, this is also the transaction's
2155  * scheduled start time.
2156  */
2157  if (!throttle_delay)
2159  }
2160 
2161  /* Begin with the first command */
2162  st->command = 0;
2164  break;
2165 
2166  /*
2167  * Send a command to server (or execute a meta-command)
2168  */
2169  case CSTATE_START_COMMAND:
2170  command = sql_script[st->use_file].commands[st->command];
2171 
2172  /*
2173  * If we reached the end of the script, move to end-of-xact
2174  * processing.
2175  */
2176  if (command == NULL)
2177  {
2178  st->state = CSTATE_END_TX;
2179  break;
2180  }
2181 
2182  /*
2183  * Record statement start time if per-command latencies are
2184  * requested
2185  */
2186  if (is_latencies)
2187  {
2188  if (INSTR_TIME_IS_ZERO(now))
2190  st->stmt_begin = now;
2191  }
2192 
2193  if (command->type == SQL_COMMAND)
2194  {
2195  if (!sendCommand(st, command))
2196  {
2197  /*
2198  * Failed. Stay in CSTATE_START_COMMAND state, to
2199  * retry. ??? What the point or retrying? Should
2200  * rather abort?
2201  */
2202  return;
2203  }
2204  else
2205  st->state = CSTATE_WAIT_RESULT;
2206  }
2207  else if (command->type == META_COMMAND)
2208  {
2209  int argc = command->argc,
2210  i;
2211  char **argv = command->argv;
2212 
2213  if (debug)
2214  {
2215  fprintf(stderr, "client %d executing \\%s", st->id, argv[0]);
2216  for (i = 1; i < argc; i++)
2217  fprintf(stderr, " %s", argv[i]);
2218  fprintf(stderr, "\n");
2219  }
2220 
2221  if (pg_strcasecmp(argv[0], "sleep") == 0)
2222  {
2223  /*
2224  * A \sleep doesn't execute anything, we just get the
2225  * delay from the argument, and enter the CSTATE_SLEEP
2226  * state. (The per-command latency will be recorded
2227  * in CSTATE_SLEEP state, not here, after the delay
2228  * has elapsed.)
2229  */
2230  int usec;
2231 
2232  if (!evaluateSleep(st, argc, argv, &usec))
2233  {
2234  commandFailed(st, "execution of meta-command 'sleep' failed");
2235  st->state = CSTATE_ABORTED;
2236  break;
2237  }
2238 
2239  if (INSTR_TIME_IS_ZERO(now))
2241  st->sleep_until = INSTR_TIME_GET_MICROSEC(now) + usec;
2242  st->state = CSTATE_SLEEP;
2243  break;
2244  }
2245  else
2246  {
2247  if (pg_strcasecmp(argv[0], "set") == 0)
2248  {
2249  PgBenchExpr *expr = command->expr;
2251 
2252  if (!evaluateExpr(thread, st, expr, &result))
2253  {
2254  commandFailed(st, "evaluation of meta-command 'set' failed");
2255  st->state = CSTATE_ABORTED;
2256  break;
2257  }
2258 
2259  if (!putVariableNumber(st, argv[0], argv[1], &result))
2260  {
2261  commandFailed(st, "assignment of meta-command 'set' failed");
2262  st->state = CSTATE_ABORTED;
2263  break;
2264  }
2265  }
2266  else if (pg_strcasecmp(argv[0], "setshell") == 0)
2267  {
2268  bool ret = runShellCommand(st, argv[1], argv + 2, argc - 2);
2269 
2270  if (timer_exceeded) /* timeout */
2271  {
2272  st->state = CSTATE_FINISHED;
2273  break;
2274  }
2275  else if (!ret) /* on error */
2276  {
2277  commandFailed(st, "execution of meta-command 'setshell' failed");
2278  st->state = CSTATE_ABORTED;
2279  break;
2280  }
2281  else
2282  {
2283  /* succeeded */
2284  }
2285  }
2286  else if (pg_strcasecmp(argv[0], "shell") == 0)
2287  {
2288  bool ret = runShellCommand(st, NULL, argv + 1, argc - 1);
2289 
2290  if (timer_exceeded) /* timeout */
2291  {
2292  st->state = CSTATE_FINISHED;
2293  break;
2294  }
2295  else if (!ret) /* on error */
2296  {
2297  commandFailed(st, "execution of meta-command 'shell' failed");
2298  st->state = CSTATE_ABORTED;
2299  break;
2300  }
2301  else
2302  {
2303  /* succeeded */
2304  }
2305  }
2306 
2307  /*
2308  * executing the expression or shell command might
2309  * take a non-negligible amount of time, so reset
2310  * 'now'
2311  */
2312  INSTR_TIME_SET_ZERO(now);
2313 
2314  st->state = CSTATE_END_COMMAND;
2315  }
2316  }
2317  break;
2318 
2319  /*
2320  * Wait for the current SQL command to complete
2321  */
2322  case CSTATE_WAIT_RESULT:
2323  command = sql_script[st->use_file].commands[st->command];
2324  if (debug)
2325  fprintf(stderr, "client %d receiving\n", st->id);
2326  if (!PQconsumeInput(st->con))
2327  { /* there's something wrong */
2328  commandFailed(st, "perhaps the backend died while processing");
2329  st->state = CSTATE_ABORTED;
2330  break;
2331  }
2332  if (PQisBusy(st->con))
2333  return; /* don't have the whole result yet */
2334 
2335  /*
2336  * Read and discard the query result;
2337  */
2338  res = PQgetResult(st->con);
2339  switch (PQresultStatus(res))
2340  {
2341  case PGRES_COMMAND_OK:
2342  case PGRES_TUPLES_OK:
2343  case PGRES_EMPTY_QUERY:
2344  /* OK */
2345  PQclear(res);
2346  discard_response(st);
2347  st->state = CSTATE_END_COMMAND;
2348  break;
2349  default:
2350  commandFailed(st, PQerrorMessage(st->con));
2351  PQclear(res);
2352  st->state = CSTATE_ABORTED;
2353  break;
2354  }
2355  break;
2356 
2357  /*
2358  * Wait until sleep is done. This state is entered after a
2359  * \sleep metacommand. The behavior is similar to
2360  * CSTATE_THROTTLE, but proceeds to CSTATE_START_COMMAND
2361  * instead of CSTATE_START_TX.
2362  */
2363  case CSTATE_SLEEP:
2364  if (INSTR_TIME_IS_ZERO(now))
2366  if (INSTR_TIME_GET_MICROSEC(now) < st->sleep_until)
2367  return; /* Still sleeping, nothing to do here */
2368  /* Else done sleeping. */
2369  st->state = CSTATE_END_COMMAND;
2370  break;
2371 
2372  /*
2373  * End of command: record stats and proceed to next command.
2374  */
2375  case CSTATE_END_COMMAND:
2376 
2377  /*
2378  * command completed: accumulate per-command execution times
2379  * in thread-local data structure, if per-command latencies
2380  * are requested.
2381  */
2382  if (is_latencies)
2383  {
2384  if (INSTR_TIME_IS_ZERO(now))
2386 
2387  /* XXX could use a mutex here, but we choose not to */
2388  command = sql_script[st->use_file].commands[st->command];
2389  addToSimpleStats(&command->stats,
2390  INSTR_TIME_GET_DOUBLE(now) -
2392  }
2393 
2394  /* Go ahead with next command */
2395  st->command++;
2397  break;
2398 
2399  /*
2400  * End of transaction.
2401  */
2402  case CSTATE_END_TX:
2403 
2404  /* transaction finished: calculate latency and do log */
2405  processXactStats(thread, st, &now, false, agg);
2406 
2407  if (is_connect)
2408  {
2409  PQfinish(st->con);
2410  st->con = NULL;
2411  INSTR_TIME_SET_ZERO(now);
2412  }
2413 
2414  if ((st->cnt >= nxacts && duration <= 0) || timer_exceeded)
2415  {
2416  /* exit success */
2417  st->state = CSTATE_FINISHED;
2418  break;
2419  }
2420 
2421  /*
2422  * No transaction is underway anymore.
2423  */
2425 
2426  /*
2427  * If we paced through all commands in the script in this
2428  * loop, without returning to the caller even once, do it now.
2429  * This gives the thread a chance to process other
2430  * connections, and to do progress reporting. This can
2431  * currently only happen if the script consists entirely of
2432  * meta-commands.
2433  */
2434  if (end_tx_processed)
2435  return;
2436  else
2437  {
2438  end_tx_processed = true;
2439  break;
2440  }
2441 
2442  /*
2443  * Final states. Close the connection if it's still open.
2444  */
2445  case CSTATE_ABORTED:
2446  case CSTATE_FINISHED:
2447  if (st->con != NULL)
2448  {
2449  PQfinish(st->con);
2450  st->con = NULL;
2451  }
2452  return;
2453  }
2454  }
2455 }
static bool evaluateExpr(TState *, CState *, PgBenchExpr *, PgBenchValue *)
Definition: pgbench.c:1682
int64 throttle_trigger
Definition: pgbench.c:346
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6097
static bool putVariableNumber(CState *st, const char *context, char *name, const PgBenchValue *value)
Definition: pgbench.c:1132
int type
Definition: pgbench.c:380
int id
Definition: pgbench.c:312
static int chooseScript(TState *thread)
Definition: pgbench.c:1849
static void discard_response(CState *state)
Definition: pgbench.c:917
struct timeval instr_time
Definition: instr_time.h:147
PgBenchExpr * expr
Definition: pgbench.c:383
#define INSTR_TIME_ACCUM_DIFF(x, y, z)
Definition: instr_time.h:179
void PQfinish(PGconn *conn)
Definition: fe-connect.c:3630
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:753
return result
Definition: formatting.c:1633
#define INSTR_TIME_SET_ZERO(t)
Definition: instr_time.h:151
bool use_log
Definition: pgbench.c:167
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:196
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
bool per_script_stats
Definition: pgbench.c:171
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2647
char * argv[MAX_ARGS]
Definition: pgbench.c:382
int duration
Definition: pgbench.c:99
static void commandFailed(CState *st, char *message)
Definition: pgbench.c:1840
#define INSTR_TIME_IS_ZERO(t)
Definition: instr_time.h:149
bool is_connect
Definition: pgbench.c:176
int64 end_time
Definition: pgbench.c:100
instr_time stmt_begin
Definition: pgbench.c:327
#define META_COMMAND
Definition: pgbench.c:362
static int debug
Definition: pgbench.c:400
int nxacts
Definition: pgbench.c:98
const char * desc
Definition: pgbench.c:389
int64 cnt
Definition: pgbench.c:332
int64 txn_scheduled
Definition: pgbench.c:324
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:395
static bool sendCommand(CState *st, Command *command)
Definition: pgbench.c:1868
int progress
Definition: pgbench.c:172
instr_time txn_begin
Definition: pgbench.c:326
int argc
Definition: pgbench.c:381
#define SQL_COMMAND
Definition: pgbench.c:361
int PQconsumeInput(PGconn *conn)
Definition: fe-exec.c:1682
int command
Definition: pgbench.c:316
SimpleStats stats
Definition: pgbench.c:384
ConnectionStateEnum state
Definition: pgbench.c:313
static bool runShellCommand(CState *st, char *variable, char **argv, int argc)
Definition: pgbench.c:1729
static int64 getPoissonRand(TState *thread, int64 center)
Definition: pgbench.c:726
void PQclear(PGresult *res)
Definition: fe-exec.c:671
int64 sleep_until
Definition: pgbench.c:325
static bool evaluateSleep(CState *st, int argc, char **argv, int *usecs)
Definition: pgbench.c:1951
PGconn * con
Definition: pgbench.c:311
static PGconn * doConnect(void)
Definition: pgbench.c:848
#define Assert(condition)
Definition: c.h:664
int PQisBusy(PGconn *conn)
Definition: fe-exec.c:1732
#define INSTR_TIME_GET_MICROSEC(t)
Definition: instr_time.h:202
volatile bool timer_exceeded
Definition: pgbench.c:189
Command ** commands
Definition: pgbench.c:391
int64 latency_limit
Definition: pgbench.c:141
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:153
#define INT64_FORMAT
Definition: c.h:300
int64 throttle_delay
Definition: pgbench.c:133
int i
instr_time conn_time
Definition: pgbench.c:351
bool prepared[MAX_SCRIPTS]
Definition: pgbench.c:329
static void processXactStats(TState *thread, CState *st, instr_time *now, bool skipped, StatsData *agg)
Definition: pgbench.c:2547
int use_file
Definition: pgbench.c:315
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1534
PGresult * PQgetResult(PGconn *conn)
Definition: fe-exec.c:1753
bool is_latencies
Definition: pgbench.c:177
static void doLog ( TState thread,
CState st,
StatsData agg,
bool  skipped,
double  latency,
double  lag 
)
static

Definition at line 2466 of file pgbench.c.

References accumStats(), Assert, StatsData::cnt, CState::cnt, gettimeofday(), CState::id, initStats(), INT64_FORMAT, StatsData::lag, StatsData::latency, logfile, TState::logfile, SimpleStats::max, SimpleStats::min, now(), pg_erand48(), TState::random_state, StatsData::skipped, StatsData::start_time, SimpleStats::sum, SimpleStats::sum2, and CState::use_file.

Referenced by processXactStats(), and threadRun().

2468 {
2469  FILE *logfile = thread->logfile;
2470 
2471  Assert(use_log);
2472 
2473  /*
2474  * Skip the log entry if sampling is enabled and this row doesn't belong
2475  * to the random sample.
2476  */
2477  if (sample_rate != 0.0 &&
2478  pg_erand48(thread->random_state) > sample_rate)
2479  return;
2480 
2481  /* should we aggregate the results or not? */
2482  if (agg_interval > 0)
2483  {
2484  /*
2485  * Loop until we reach the interval of the current moment, and print
2486  * any empty intervals in between (this may happen with very low tps,
2487  * e.g. --rate=0.1).
2488  */
2489  time_t now = time(NULL);
2490 
2491  while (agg->start_time + agg_interval <= now)
2492  {
2493  /* print aggregated report to logfile */
2494  fprintf(logfile, "%ld " INT64_FORMAT " %.0f %.0f %.0f %.0f",
2495  (long) agg->start_time,
2496  agg->cnt,
2497  agg->latency.sum,
2498  agg->latency.sum2,
2499  agg->latency.min,
2500  agg->latency.max);
2501  if (throttle_delay)
2502  {
2503  fprintf(logfile, " %.0f %.0f %.0f %.0f",
2504  agg->lag.sum,
2505  agg->lag.sum2,
2506  agg->lag.min,
2507  agg->lag.max);
2508  if (latency_limit)
2509  fprintf(logfile, " " INT64_FORMAT, agg->skipped);
2510  }
2511  fputc('\n', logfile);
2512 
2513  /* reset data and move to next interval */
2514  initStats(agg, agg->start_time + agg_interval);
2515  }
2516 
2517  /* accumulate the current transaction */
2518  accumStats(agg, skipped, latency, lag);
2519  }
2520  else
2521  {
2522  /* no, print raw transactions */
2523  struct timeval tv;
2524 
2525  gettimeofday(&tv, NULL);
2526  if (skipped)
2527  fprintf(logfile, "%d " INT64_FORMAT " skipped %d %ld %ld",
2528  st->id, st->cnt, st->use_file,
2529  (long) tv.tv_sec, (long) tv.tv_usec);
2530  else
2531  fprintf(logfile, "%d " INT64_FORMAT " %.0f %d %ld %ld",
2532  st->id, st->cnt, latency, st->use_file,
2533  (long) tv.tv_sec, (long) tv.tv_usec);
2534  if (throttle_delay)
2535  fprintf(logfile, " %.0f", lag);
2536  fputc('\n', logfile);
2537  }
2538 }
time_t start_time
Definition: pgbench.c:231
int gettimeofday(struct timeval *tp, struct timezone *tzp)
Definition: gettimeofday.c:105
double sample_rate
Definition: pgbench.c:127
int id
Definition: pgbench.c:312
unsigned short random_state[3]
Definition: pgbench.c:345
SimpleStats lag
Definition: pgbench.c:236
static void initStats(StatsData *sd, time_t start_time)
Definition: pgbench.c:784
double sum
Definition: pgbench.c:221
bool use_log
Definition: pgbench.c:167
static FILE * logfile
Definition: pg_regress.c:99
SimpleStats latency
Definition: pgbench.c:235
FILE * logfile
Definition: pgbench.c:347
int64 cnt
Definition: pgbench.c:232
int64 cnt
Definition: pgbench.c:332
int64 skipped
Definition: pgbench.c:233
double max
Definition: pgbench.c:220
static void accumStats(StatsData *stats, bool skipped, double lat, double lag)
Definition: pgbench.c:797
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:79
#define Assert(condition)
Definition: c.h:664
double sum2
Definition: pgbench.c:222
int64 latency_limit
Definition: pgbench.c:141
#define INT64_FORMAT
Definition: c.h:300
int64 throttle_delay
Definition: pgbench.c:133
int use_file
Definition: pgbench.c:315
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1534
double min
Definition: pgbench.c:219
int agg_interval
Definition: pgbench.c:169
static bool evalFunc ( TState thread,
CState st,
PgBenchFunction  func,
PgBenchExprLink args,
PgBenchValue retval 
)
static

Definition at line 1321 of file pgbench.c.

References generate_unaccent_rules::args, Assert, coerceToDouble(), coerceToInt(), CState::command, PgBenchValue::dval, evaluateExpr(), getExponentialRand(), getGaussianRand(), getrand(), i, INT64_FORMAT, PgBenchValue::ival, M_PI, Max, MAX_FARGS, Min, MIN_GAUSSIAN_PARAM, PgBenchExprLink::next, PG_INT64_MIN, PGBENCH_ABS, PGBENCH_ADD, PGBENCH_DEBUG, PGBENCH_DIV, PGBENCH_DOUBLE, PGBENCH_GREATEST, PGBENCH_INT, PGBENCH_LEAST, PGBENCH_MOD, PGBENCH_MUL, PGBENCH_PI, PGBENCH_RANDOM, PGBENCH_RANDOM_EXPONENTIAL, PGBENCH_RANDOM_GAUSSIAN, PGBENCH_SQRT, PGBENCH_SUB, PGBT_DOUBLE, PGBT_INT, setDoubleValue(), setIntValue(), PgBenchValue::type, PgBenchValue::u, and CState::use_file.

Referenced by evaluateExpr().

1323 {
1324  /* evaluate all function arguments */
1325  int nargs = 0;
1326  PgBenchValue vargs[MAX_FARGS];
1327  PgBenchExprLink *l = args;
1328 
1329  for (nargs = 0; nargs < MAX_FARGS && l != NULL; nargs++, l = l->next)
1330  if (!evaluateExpr(thread, st, l->expr, &vargs[nargs]))
1331  return false;
1332 
1333  if (l != NULL)
1334  {
1335  fprintf(stderr,
1336  "too many function arguments, maximum is %d\n", MAX_FARGS);
1337  return false;
1338  }
1339 
1340  /* then evaluate function */
1341  switch (func)
1342  {
1343  /* overloaded operators */
1344  case PGBENCH_ADD:
1345  case PGBENCH_SUB:
1346  case PGBENCH_MUL:
1347  case PGBENCH_DIV:
1348  case PGBENCH_MOD:
1349  {
1350  PgBenchValue *lval = &vargs[0],
1351  *rval = &vargs[1];
1352 
1353  Assert(nargs == 2);
1354 
1355  /* overloaded type management, double if some double */
1356  if ((lval->type == PGBT_DOUBLE ||
1357  rval->type == PGBT_DOUBLE) && func != PGBENCH_MOD)
1358  {
1359  double ld,
1360  rd;
1361 
1362  if (!coerceToDouble(lval, &ld) ||
1363  !coerceToDouble(rval, &rd))
1364  return false;
1365 
1366  switch (func)
1367  {
1368  case PGBENCH_ADD:
1369  setDoubleValue(retval, ld + rd);
1370  return true;
1371 
1372  case PGBENCH_SUB:
1373  setDoubleValue(retval, ld - rd);
1374  return true;
1375 
1376  case PGBENCH_MUL:
1377  setDoubleValue(retval, ld * rd);
1378  return true;
1379 
1380  case PGBENCH_DIV:
1381  setDoubleValue(retval, ld / rd);
1382  return true;
1383 
1384  default:
1385  /* cannot get here */
1386  Assert(0);
1387  }
1388  }
1389  else /* we have integer operands, or % */
1390  {
1391  int64 li,
1392  ri;
1393 
1394  if (!coerceToInt(lval, &li) ||
1395  !coerceToInt(rval, &ri))
1396  return false;
1397 
1398  switch (func)
1399  {
1400  case PGBENCH_ADD:
1401  setIntValue(retval, li + ri);
1402  return true;
1403 
1404  case PGBENCH_SUB:
1405  setIntValue(retval, li - ri);
1406  return true;
1407 
1408  case PGBENCH_MUL:
1409  setIntValue(retval, li * ri);
1410  return true;
1411 
1412  case PGBENCH_DIV:
1413  case PGBENCH_MOD:
1414  if (ri == 0)
1415  {
1416  fprintf(stderr, "division by zero\n");
1417  return false;
1418  }
1419  /* special handling of -1 divisor */
1420  if (ri == -1)
1421  {
1422  if (func == PGBENCH_DIV)
1423  {
1424  /* overflow check (needed for INT64_MIN) */
1425  if (li == PG_INT64_MIN)
1426  {
1427  fprintf(stderr, "bigint out of range\n");
1428  return false;
1429  }
1430  else
1431  setIntValue(retval, -li);
1432  }
1433  else
1434  setIntValue(retval, 0);
1435  return true;
1436  }
1437  /* else divisor is not -1 */
1438  if (func == PGBENCH_DIV)
1439  setIntValue(retval, li / ri);
1440  else /* func == PGBENCH_MOD */
1441  setIntValue(retval, li % ri);
1442 
1443  return true;
1444 
1445  default:
1446  /* cannot get here */
1447  Assert(0);
1448  }
1449  }
1450  }
1451 
1452  /* no arguments */
1453  case PGBENCH_PI:
1454  setDoubleValue(retval, M_PI);
1455  return true;
1456 
1457  /* 1 overloaded argument */
1458  case PGBENCH_ABS:
1459  {
1460  PgBenchValue *varg = &vargs[0];
1461 
1462  Assert(nargs == 1);
1463 
1464  if (varg->type == PGBT_INT)
1465  {
1466  int64 i = varg->u.ival;
1467 
1468  setIntValue(retval, i < 0 ? -i : i);
1469  }
1470  else
1471  {
1472  double d = varg->u.dval;
1473 
1474  Assert(varg->type == PGBT_DOUBLE);
1475  setDoubleValue(retval, d < 0.0 ? -d : d);
1476  }
1477 
1478  return true;
1479  }
1480 
1481  case PGBENCH_DEBUG:
1482  {
1483  PgBenchValue *varg = &vargs[0];
1484 
1485  Assert(nargs == 1);
1486 
1487  fprintf(stderr, "debug(script=%d,command=%d): ",
1488  st->use_file, st->command + 1);
1489 
1490  if (varg->type == PGBT_INT)
1491  fprintf(stderr, "int " INT64_FORMAT "\n", varg->u.ival);
1492  else
1493  {
1494  Assert(varg->type == PGBT_DOUBLE);
1495  fprintf(stderr, "double %.*g\n", DBL_DIG, varg->u.dval);
1496  }
1497 
1498  *retval = *varg;
1499 
1500  return true;
1501  }
1502 
1503  /* 1 double argument */
1504  case PGBENCH_DOUBLE:
1505  case PGBENCH_SQRT:
1506  {
1507  double dval;
1508 
1509  Assert(nargs == 1);
1510 
1511  if (!coerceToDouble(&vargs[0], &dval))
1512  return false;
1513 
1514  if (func == PGBENCH_SQRT)
1515  dval = sqrt(dval);
1516 
1517  setDoubleValue(retval, dval);
1518  return true;
1519  }
1520 
1521  /* 1 int argument */
1522  case PGBENCH_INT:
1523  {
1524  int64 ival;
1525 
1526  Assert(nargs == 1);
1527 
1528  if (!coerceToInt(&vargs[0], &ival))
1529  return false;
1530 
1531  setIntValue(retval, ival);
1532  return true;
1533  }
1534 
1535  /* variable number of arguments */
1536  case PGBENCH_LEAST:
1537  case PGBENCH_GREATEST:
1538  {
1539  bool havedouble;
1540  int i;
1541 
1542  Assert(nargs >= 1);
1543 
1544  /* need double result if any input is double */
1545  havedouble = false;
1546  for (i = 0; i < nargs; i++)
1547  {
1548  if (vargs[i].type == PGBT_DOUBLE)
1549  {
1550  havedouble = true;
1551  break;
1552  }
1553  }
1554  if (havedouble)
1555  {
1556  double extremum;
1557 
1558  if (!coerceToDouble(&vargs[0], &extremum))
1559  return false;
1560  for (i = 1; i < nargs; i++)
1561  {
1562  double dval;
1563 
1564  if (!coerceToDouble(&vargs[i], &dval))
1565  return false;
1566  if (func == PGBENCH_LEAST)
1567  extremum = Min(extremum, dval);
1568  else
1569  extremum = Max(extremum, dval);
1570  }
1571  setDoubleValue(retval, extremum);
1572  }
1573  else
1574  {
1575  int64 extremum;
1576 
1577  if (!coerceToInt(&vargs[0], &extremum))
1578  return false;
1579  for (i = 1; i < nargs; i++)
1580  {
1581  int64 ival;
1582 
1583  if (!coerceToInt(&vargs[i], &ival))
1584  return false;
1585  if (func == PGBENCH_LEAST)
1586  extremum = Min(extremum, ival);
1587  else
1588  extremum = Max(extremum, ival);
1589  }
1590  setIntValue(retval, extremum);
1591  }
1592  return true;
1593  }
1594 
1595  /* random functions */
1596  case PGBENCH_RANDOM:
1599  {
1600  int64 imin,
1601  imax;
1602 
1603  Assert(nargs >= 2);
1604 
1605  if (!coerceToInt(&vargs[0], &imin) ||
1606  !coerceToInt(&vargs[1], &imax))
1607  return false;
1608 
1609  /* check random range */
1610  if (imin > imax)
1611  {
1612  fprintf(stderr, "empty range given to random\n");
1613  return false;
1614  }
1615  else if (imax - imin < 0 || (imax - imin) + 1 < 0)
1616  {
1617  /* prevent int overflows in random functions */
1618  fprintf(stderr, "random range is too large\n");
1619  return false;
1620  }
1621 
1622  if (func == PGBENCH_RANDOM)
1623  {
1624  Assert(nargs == 2);
1625  setIntValue(retval, getrand(thread, imin, imax));
1626  }
1627  else /* gaussian & exponential */
1628  {
1629  double param;
1630 
1631  Assert(nargs == 3);
1632 
1633  if (!coerceToDouble(&vargs[2], &param))
1634  return false;
1635 
1636  if (func == PGBENCH_RANDOM_GAUSSIAN)
1637  {
1638  if (param < MIN_GAUSSIAN_PARAM)
1639  {
1640  fprintf(stderr,
1641  "gaussian parameter must be at least %f "
1642  "(not %f)\n", MIN_GAUSSIAN_PARAM, param);
1643  return false;
1644  }
1645 
1646  setIntValue(retval,
1647  getGaussianRand(thread, imin, imax, param));
1648  }
1649  else /* exponential */
1650  {
1651  if (param <= 0.0)
1652  {
1653  fprintf(stderr,
1654  "exponential parameter must be greater than zero"
1655  " (got %f)\n", param);
1656  return false;
1657  }
1658 
1659  setIntValue(retval,
1660  getExponentialRand(thread, imin, imax, param));
1661  }
1662  }
1663 
1664  return true;
1665  }
1666 
1667  default:
1668  /* cannot get here */
1669  Assert(0);
1670  /* dead code to avoid a compiler warning */
1671  return false;
1672  }
1673 }
static bool evaluateExpr(TState *, CState *, PgBenchExpr *, PgBenchValue *)
Definition: pgbench.c:1682
static int64 getrand(TState *thread, int64 min, int64 max)
Definition: pgbench.c:627
#define Min(x, y)
Definition: c.h:795
union PgBenchValue::@39 u
static bool coerceToDouble(PgBenchValue *pval, double *dval)
Definition: pgbench.c:1283
static void setDoubleValue(PgBenchValue *pv, double dval)
Definition: pgbench.c:1308
#define MIN_GAUSSIAN_PARAM
Definition: pgbench.c:96
static int64 getGaussianRand(TState *thread, int64 min, int64 max, double parameter)
Definition: pgbench.c:670
#define MAX_FARGS
Definition: pgbench.c:1315
#define M_PI
Definition: pgbench.c:56
#define PG_INT64_MIN
Definition: c.h:327
int command
Definition: pgbench.c:316
double dval
Definition: pgbench.h:47
#define Max(x, y)
Definition: c.h:789
#define Assert(condition)
Definition: c.h:664
static void setIntValue(PgBenchValue *pv, int64 ival)
Definition: pgbench.c:1300
#define INT64_FORMAT
Definition: c.h:300
PgBenchValueType type
Definition: pgbench.h:43
static int64 getExponentialRand(TState *thread, int64 min, int64 max, double parameter)
Definition: pgbench.c:647
int i
static bool coerceToInt(PgBenchValue *pval, int64 *ival)
Definition: pgbench.c:1259
int64 ival
Definition: pgbench.h:46
int use_file
Definition: pgbench.c:315
static bool evaluateExpr ( TState thread,
CState st,
PgBenchExpr expr,
PgBenchValue retval 
)
static

Definition at line 1682 of file pgbench.c.

References PgBenchExpr::constant, ENODE_CONSTANT, ENODE_FUNCTION, ENODE_VARIABLE, PgBenchExpr::etype, evalFunc(), PgBenchExpr::function, lookupVariable(), makeVariableNumeric(), Variable::num_value, PgBenchExpr::u, and PgBenchExpr::variable.

Referenced by doCustom(), and evalFunc().

1683 {
1684  switch (expr->etype)
1685  {
1686  case ENODE_CONSTANT:
1687  {
1688  *retval = expr->u.constant;
1689  return true;
1690  }
1691 
1692  case ENODE_VARIABLE:
1693  {
1694  Variable *var;
1695 
1696  if ((var = lookupVariable(st, expr->u.variable.varname)) == NULL)
1697  {
1698  fprintf(stderr, "undefined variable \"%s\"\n",
1699  expr->u.variable.varname);
1700  return false;
1701  }
1702 
1703  if (!makeVariableNumeric(var))
1704  return false;
1705 
1706  *retval = var->num_value;
1707  return true;
1708  }
1709 
1710  case ENODE_FUNCTION:
1711  return evalFunc(thread, st,
1712  expr->u.function.function,
1713  expr->u.function.args,
1714  retval);
1715 
1716  default:
1717  /* internal error which should never occur */
1718  fprintf(stderr, "unexpected enode type in evaluation: %d\n",
1719  expr->etype);
1720  exit(1);
1721  }
1722 }
PgBenchValue constant
Definition: pgbench.h:90
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:939
struct PgBenchExpr::@40::@41 variable
static bool makeVariableNumeric(Variable *var)
Definition: pgbench.c:995
static bool evalFunc(TState *thread, CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1321
PgBenchFunction function
Definition: pgbench.h:97
union PgBenchExpr::@40 u
PgBenchValue num_value
Definition: pgbench.c:204
PgBenchExprType etype
Definition: pgbench.h:87
static bool evaluateSleep ( CState st,
int  argc,
char **  argv,
int *  usecs 
)
static

Definition at line 1951 of file pgbench.c.

References getVariable(), and pg_strcasecmp().

Referenced by doCustom().

1952 {
1953  char *var;
1954  int usec;
1955 
1956  if (*argv[1] == ':')
1957  {
1958  if ((var = getVariable(st, argv[1] + 1)) == NULL)
1959  {
1960  fprintf(stderr, "%s: undefined variable \"%s\"\n",
1961  argv[0], argv[1]);
1962  return false;
1963  }
1964  usec = atoi(var);
1965  }
1966  else
1967  usec = atoi(argv[1]);
1968 
1969  if (argc > 2)
1970  {
1971  if (pg_strcasecmp(argv[2], "ms") == 0)
1972  usec *= 1000;
1973  else if (pg_strcasecmp(argv[2], "s") == 0)
1974  usec *= 1000000;
1975  }
1976  else
1977  usec *= 1000000;
1978 
1979  *usecs = usec;
1980  return true;
1981 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:966
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
static void executeStatement ( PGconn con,
const char *  sql 
)
static

Definition at line 818 of file pgbench.c.

References PGRES_COMMAND_OK, PQclear(), PQerrorMessage(), PQexec(), and PQresultStatus().

Referenced by init().

819 {
820  PGresult *res;
821 
822  res = PQexec(con, sql);
823  if (PQresultStatus(res) != PGRES_COMMAND_OK)
824  {
825  fprintf(stderr, "%s", PQerrorMessage(con));
826  exit(1);
827  }
828  PQclear(res);
829 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6097
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2647
void PQclear(PGresult *res)
Definition: fe-exec.c:671
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1897
static const BuiltinScript* findBuiltin ( const char *  name)
static

Definition at line 3407 of file pgbench.c.

References i, lengthof, listAvailableScripts(), and result.

Referenced by main().

3408 {
3409  int i,
3410  found = 0,
3411  len = strlen(name);
3412  const BuiltinScript *result = NULL;
3413 
3414  for (i = 0; i < lengthof(builtin_script); i++)
3415  {
3416  if (strncmp(builtin_script[i].name, name, len) == 0)
3417  {
3418  result = &builtin_script[i];
3419  found++;
3420  }
3421  }
3422 
3423  /* ok, unambiguous result */
3424  if (found == 1)
3425  return result;
3426 
3427  /* error cases */
3428  if (found == 0)
3429  fprintf(stderr, "no builtin script found for name \"%s\"\n", name);
3430  else /* found > 1 */
3431  fprintf(stderr,
3432  "ambiguous builtin name: %d builtin scripts found for prefix \"%s\"\n", found, name);
3433 
3435  exit(1);
3436 }
static void listAvailableScripts(void)
Definition: pgbench.c:3395
return result
Definition: formatting.c:1633
#define lengthof(array)
Definition: c.h:556
static const BuiltinScript builtin_script[]
Definition: pgbench.c:410
const char * name
Definition: encode.c:521
int i
static int64 getExponentialRand ( TState thread,
int64  min,
int64  max,
double  parameter 
)
static

Definition at line 647 of file pgbench.c.

References Assert, pg_erand48(), and TState::random_state.

Referenced by evalFunc().

648 {
649  double cut,
650  uniform,
651  rand;
652 
653  /* abort if wrong parameter, but must really be checked beforehand */
654  Assert(parameter > 0.0);
655  cut = exp(-parameter);
656  /* erand in [0, 1), uniform in (0, 1] */
657  uniform = 1.0 - pg_erand48(thread->random_state);
658 
659  /*
660  * inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
661  */
662  Assert((1.0 - cut) != 0.0);
663  rand = -log(cut + (1.0 - cut) * uniform) / parameter;
664  /* return int64 random number within between min and max */
665  return min + (int64) ((max - min + 1) * rand);
666 }
unsigned short random_state[3]
Definition: pgbench.c:345
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:79
#define Assert(condition)
Definition: c.h:664
static int64 getGaussianRand ( TState thread,
int64  min,
int64  max,
double  parameter 
)
static

Definition at line 670 of file pgbench.c.

References Assert, M_PI, MIN_GAUSSIAN_PARAM, pg_erand48(), and TState::random_state.

Referenced by evalFunc().

671 {
672  double stdev;
673  double rand;
674 
675  /* abort if parameter is too low, but must really be checked beforehand */
676  Assert(parameter >= MIN_GAUSSIAN_PARAM);
677 
678  /*
679  * Get user specified random number from this loop, with -parameter <
680  * stdev <= parameter
681  *
682  * This loop is executed until the number is in the expected range.
683  *
684  * As the minimum parameter is 2.0, the probability of looping is low:
685  * sqrt(-2 ln(r)) <= 2 => r >= e^{-2} ~ 0.135, then when taking the
686  * average sinus multiplier as 2/pi, we have a 8.6% looping probability in
687  * the worst case. For a parameter value of 5.0, the looping probability
688  * is about e^{-5} * 2 / pi ~ 0.43%.
689  */
690  do
691  {
692  /*
693  * pg_erand48 generates [0,1), but for the basic version of the
694  * Box-Muller transform the two uniformly distributed random numbers
695  * are expected in (0, 1] (see
696  * http://en.wikipedia.org/wiki/Box_muller)
697  */
698  double rand1 = 1.0 - pg_erand48(thread->random_state);
699  double rand2 = 1.0 - pg_erand48(thread->random_state);
700 
701  /* Box-Muller basic form transform */
702  double var_sqrt = sqrt(-2.0 * log(rand1));
703 
704  stdev = var_sqrt * sin(2.0 * M_PI * rand2);
705 
706  /*
707  * we may try with cos, but there may be a bias induced if the
708  * previous value fails the test. To be on the safe side, let us try
709  * over.
710  */
711  }
712  while (stdev < -parameter || stdev >= parameter);
713 
714  /* stdev is in [-parameter, parameter), normalization to [0,1) */
715  rand = (stdev + parameter) / (parameter * 2.0);
716 
717  /* return int64 random number within between min and max */
718  return min + (int64) ((max - min + 1) * rand);
719 }
unsigned short random_state[3]
Definition: pgbench.c:345
#define MIN_GAUSSIAN_PARAM
Definition: pgbench.c:96
#define M_PI
Definition: pgbench.c:56
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:79
#define Assert(condition)
Definition: c.h:664
static int64 getPoissonRand ( TState thread,
int64  center 
)
static

Definition at line 726 of file pgbench.c.

References pg_erand48(), and TState::random_state.

Referenced by doCustom().

727 {
728  /*
729  * Use inverse transform sampling to generate a value > 0, such that the
730  * expected (i.e. average) value is the given argument.
731  */
732  double uniform;
733 
734  /* erand in [0, 1), uniform in (0, 1] */
735  uniform = 1.0 - pg_erand48(thread->random_state);
736 
737  return (int64) (-log(uniform) * ((double) center) + 0.5);
738 }
unsigned short random_state[3]
Definition: pgbench.c:345
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:79
static void getQueryParams ( CState st,
const Command command,
const char **  params 
)
static

Definition at line 1249 of file pgbench.c.

References Command::argc, Command::argv, getVariable(), and i.

Referenced by sendCommand().

1250 {
1251  int i;
1252 
1253  for (i = 0; i < command->argc - 1; i++)
1254  params[i] = getVariable(st, command->argv[i + 1]);
1255 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:966
char * argv[MAX_ARGS]
Definition: pgbench.c:382
int argc
Definition: pgbench.c:381
int i
static int64 getrand ( TState thread,
int64  min,
int64  max 
)
static

Definition at line 627 of file pgbench.c.

References pg_erand48(), and TState::random_state.

Referenced by chooseScript(), and evalFunc().

628 {
629  /*
630  * Odd coding is so that min and max have approximately the same chance of
631  * being selected as do numbers between them.
632  *
633  * pg_erand48() is thread-safe and concurrent, which is why we use it
634  * rather than random(), which in glibc is non-reentrant, and therefore
635  * protected by a mutex, and therefore a bottleneck on machines with many
636  * CPUs.
637  */
638  return min + (int64) ((max - min + 1) * pg_erand48(thread->random_state));
639 }
unsigned short random_state[3]
Definition: pgbench.c:345
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:79
static char* getVariable ( CState st,
char *  name 
)
static

Definition at line 966 of file pgbench.c.

References Assert, PgBenchValue::dval, INT64_FORMAT, Variable::is_numeric, PgBenchValue::ival, lookupVariable(), Variable::num_value, pg_strdup(), PGBT_DOUBLE, PGBT_INT, snprintf(), PgBenchValue::type, PgBenchValue::u, and Variable::value.

Referenced by assignVariables(), evaluateSleep(), getQueryParams(), and runShellCommand().

967 {
968  Variable *var;
969  char stringform[64];
970 
971  var = lookupVariable(st, name);
972  if (var == NULL)
973  return NULL; /* not found */
974 
975  if (var->value)
976  return var->value; /* we have it in string form */
977 
978  /* We need to produce a string equivalent of the numeric value */
979  Assert(var->is_numeric);
980  if (var->num_value.type == PGBT_INT)
981  snprintf(stringform, sizeof(stringform),
982  INT64_FORMAT, var->num_value.u.ival);
983  else
984  {
985  Assert(var->num_value.type == PGBT_DOUBLE);
986  snprintf(stringform, sizeof(stringform),
987  "%.*g", DBL_DIG, var->num_value.u.dval);
988  }
989  var->value = pg_strdup(stringform);
990  return var->value;
991 }
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:939
union PgBenchValue::@39 u
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
bool is_numeric
Definition: pgbench.c:203
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
char * value
Definition: pgbench.c:202
double dval
Definition: pgbench.h:47
#define Assert(condition)
Definition: c.h:664
#define INT64_FORMAT
Definition: c.h:300
const char * name
Definition: encode.c:521
PgBenchValueType type
Definition: pgbench.h:43
int64 ival
Definition: pgbench.h:46
PgBenchValue num_value
Definition: pgbench.c:204
static void handle_sig_alarm ( SIGNAL_ARGS  )
static

Definition at line 4772 of file pgbench.c.

Referenced by setalarm().

4773 {
4774  timer_exceeded = true;
4775 }
volatile bool timer_exceeded
Definition: pgbench.c:189
static void init ( bool  is_no_vacuum)
static

Definition at line 2610 of file pgbench.c.

References buffer, doConnect(), executeStatement(), i, INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, INT64_FORMAT, lengthof, LOG_STEP_SECONDS, naccounts, nbranches, ntellers, PGRES_COPY_IN, PQclear(), PQendcopy(), PQerrorMessage(), PQescapeIdentifier(), PQexec(), PQfinish(), PQfreemem(), PQputline(), PQresultStatus(), scale, SCALE_32BIT_THRESHOLD, snprintf(), and strlcpy().

Referenced by from_char_parse_int_len(), heap_multi_insert(), log_heap_update(), main(), and pg_attribute_unused().

2611 {
2612 /*
2613  * The scale factor at/beyond which 32-bit integers are insufficient for
2614  * storing TPC-B account IDs.
2615  *
2616  * Although the actual threshold is 21474, we use 20000 because it is easier to
2617  * document and remember, and isn't that far away from the real threshold.
2618  */
2619 #define SCALE_32BIT_THRESHOLD 20000
2620 
2621  /*
2622  * Note: TPC-B requires at least 100 bytes per row, and the "filler"
2623  * fields in these table declarations were intended to comply with that.
2624  * The pgbench_accounts table complies with that because the "filler"
2625  * column is set to blank-padded empty string. But for all other tables
2626  * the columns default to NULL and so don't actually take any space. We
2627  * could fix that by giving them non-null default values. However, that
2628  * would completely break comparability of pgbench results with prior
2629  * versions. Since pgbench has never pretended to be fully TPC-B compliant
2630  * anyway, we stick with the historical behavior.
2631  */
2632  struct ddlinfo
2633  {
2634  const char *table; /* table name */
2635  const char *smcols; /* column decls if accountIDs are 32 bits */
2636  const char *bigcols; /* column decls if accountIDs are 64 bits */
2637  int declare_fillfactor;
2638  };
2639  static const struct ddlinfo DDLs[] = {
2640  {
2641  "pgbench_history",
2642  "tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)",
2643  "tid int,bid int,aid bigint,delta int,mtime timestamp,filler char(22)",
2644  0
2645  },
2646  {
2647  "pgbench_tellers",
2648  "tid int not null,bid int,tbalance int,filler char(84)",
2649  "tid int not null,bid int,tbalance int,filler char(84)",
2650  1
2651  },
2652  {
2653  "pgbench_accounts",
2654  "aid int not null,bid int,abalance int,filler char(84)",
2655  "aid bigint not null,bid int,abalance int,filler char(84)",
2656  1
2657  },
2658  {
2659  "pgbench_branches",
2660  "bid int not null,bbalance int,filler char(88)",
2661  "bid int not null,bbalance int,filler char(88)",
2662  1
2663  }
2664  };
2665  static const char *const DDLINDEXes[] = {
2666  "alter table pgbench_branches add primary key (bid)",
2667  "alter table pgbench_tellers add primary key (tid)",
2668  "alter table pgbench_accounts add primary key (aid)"
2669  };
2670  static const char *const DDLKEYs[] = {
2671  "alter table pgbench_tellers add foreign key (bid) references pgbench_branches",
2672  "alter table pgbench_accounts add foreign key (bid) references pgbench_branches",
2673  "alter table pgbench_history add foreign key (bid) references pgbench_branches",
2674  "alter table pgbench_history add foreign key (tid) references pgbench_tellers",
2675  "alter table pgbench_history add foreign key (aid) references pgbench_accounts"
2676  };
2677 
2678  PGconn *con;
2679  PGresult *res;
2680  char sql[256];
2681  int i;
2682  int64 k;
2683 
2684  /* used to track elapsed time and estimate of the remaining time */
2685  instr_time start,
2686  diff;
2687  double elapsed_sec,
2688  remaining_sec;
2689  int log_interval = 1;
2690 
2691  if ((con = doConnect()) == NULL)
2692  exit(1);
2693 
2694  for (i = 0; i < lengthof(DDLs); i++)
2695  {
2696  char opts[256];
2697  char buffer[256];
2698  const struct ddlinfo *ddl = &DDLs[i];
2699  const char *cols;
2700 
2701  /* Remove old table, if it exists. */
2702  snprintf(buffer, sizeof(buffer), "drop table if exists %s", ddl->table);
2703  executeStatement(con, buffer);
2704 
2705  /* Construct new create table statement. */
2706  opts[0] = '\0';
2707  if (ddl->declare_fillfactor)
2708  snprintf(opts + strlen(opts), sizeof(opts) - strlen(opts),
2709  " with (fillfactor=%d)", fillfactor);
2710  if (tablespace != NULL)
2711  {
2712  char *escape_tablespace;
2713 
2714  escape_tablespace = PQescapeIdentifier(con, tablespace,
2715  strlen(tablespace));
2716  snprintf(opts + strlen(opts), sizeof(opts) - strlen(opts),
2717  " tablespace %s", escape_tablespace);
2718  PQfreemem(escape_tablespace);
2719  }
2720 
2721  cols = (scale >= SCALE_32BIT_THRESHOLD) ? ddl->bigcols : ddl->smcols;
2722 
2723  snprintf(buffer, sizeof(buffer), "create%s table %s(%s)%s",
2724  unlogged_tables ? " unlogged" : "",
2725  ddl->table, cols, opts);
2726 
2727  executeStatement(con, buffer);
2728  }
2729 
2730  executeStatement(con, "begin");
2731 
2732  for (i = 0; i < nbranches * scale; i++)
2733  {
2734  /* "filler" column defaults to NULL */
2735  snprintf(sql, sizeof(sql),
2736  "insert into pgbench_branches(bid,bbalance) values(%d,0)",
2737  i + 1);
2738  executeStatement(con, sql);
2739  }
2740 
2741  for (i = 0; i < ntellers * scale; i++)
2742  {
2743  /* "filler" column defaults to NULL */
2744  snprintf(sql, sizeof(sql),
2745  "insert into pgbench_tellers(tid,bid,tbalance) values (%d,%d,0)",
2746  i + 1, i / ntellers + 1);
2747  executeStatement(con, sql);
2748  }
2749 
2750  executeStatement(con, "commit");
2751 
2752  /*
2753  * fill the pgbench_accounts table with some data
2754  */
2755  fprintf(stderr, "creating tables...\n");
2756 
2757  executeStatement(con, "begin");
2758  executeStatement(con, "truncate pgbench_accounts");
2759 
2760  res = PQexec(con, "copy pgbench_accounts from stdin");
2761  if (PQresultStatus(res) != PGRES_COPY_IN)
2762  {
2763  fprintf(stderr, "%s", PQerrorMessage(con));
2764  exit(1);
2765  }
2766  PQclear(res);
2767 
2768  INSTR_TIME_SET_CURRENT(start);
2769 
2770  for (k = 0; k < (int64) naccounts * scale; k++)
2771  {
2772  int64 j = k + 1;
2773 
2774  /* "filler" column defaults to blank padded empty string */
2775  snprintf(sql, sizeof(sql),
2776  INT64_FORMAT "\t" INT64_FORMAT "\t%d\t\n",
2777  j, k / naccounts + 1, 0);
2778  if (PQputline(con, sql))
2779  {
2780  fprintf(stderr, "PQputline failed\n");
2781  exit(1);
2782  }
2783 
2784  /*
2785  * If we want to stick with the original logging, print a message each
2786  * 100k inserted rows.
2787  */
2788  if ((!use_quiet) && (j % 100000 == 0))
2789  {
2790  INSTR_TIME_SET_CURRENT(diff);
2791  INSTR_TIME_SUBTRACT(diff, start);
2792 
2793  elapsed_sec = INSTR_TIME_GET_DOUBLE(diff);
2794  remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
2795 
2796  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)\n",
2797  j, (int64) naccounts * scale,
2798  (int) (((int64) j * 100) / (naccounts * (int64) scale)),
2799  elapsed_sec, remaining_sec);
2800  }
2801  /* let's not call the timing for each row, but only each 100 rows */
2802  else if (use_quiet && (j % 100 == 0))
2803  {
2804  INSTR_TIME_SET_CURRENT(diff);
2805  INSTR_TIME_SUBTRACT(diff, start);
2806 
2807  elapsed_sec = INSTR_TIME_GET_DOUBLE(diff);
2808  remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
2809 
2810  /* have we reached the next interval (or end)? */
2811  if ((j == scale * naccounts) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS))
2812  {
2813  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)\n",
2814  j, (int64) naccounts * scale,
2815  (int) (((int64) j * 100) / (naccounts * (int64) scale)), elapsed_sec, remaining_sec);
2816 
2817  /* skip to the next interval */
2818  log_interval = (int) ceil(elapsed_sec / LOG_STEP_SECONDS);
2819  }
2820  }
2821 
2822  }
2823  if (PQputline(con, "\\.\n"))
2824  {
2825  fprintf(stderr, "very last PQputline failed\n");
2826  exit(1);
2827  }
2828  if (PQendcopy(con))
2829  {
2830  fprintf(stderr, "PQendcopy failed\n");
2831  exit(1);
2832  }
2833  executeStatement(con, "commit");
2834 
2835  /* vacuum */
2836  if (!is_no_vacuum)
2837  {
2838  fprintf(stderr, "vacuum...\n");
2839  executeStatement(con, "vacuum analyze pgbench_branches");
2840  executeStatement(con, "vacuum analyze pgbench_tellers");
2841  executeStatement(con, "vacuum analyze pgbench_accounts");
2842  executeStatement(con, "vacuum analyze pgbench_history");
2843  }
2844 
2845  /*
2846  * create indexes
2847  */
2848  fprintf(stderr, "set primary keys...\n");
2849  for (i = 0; i < lengthof(DDLINDEXes); i++)
2850  {
2851  char buffer[256];
2852 
2853  strlcpy(buffer, DDLINDEXes[i], sizeof(buffer));
2854 
2855  if (index_tablespace != NULL)
2856  {
2857  char *escape_tablespace;
2858 
2859  escape_tablespace = PQescapeIdentifier(con, index_tablespace,
2860  strlen(index_tablespace));
2861  snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer),
2862  " using index tablespace %s", escape_tablespace);
2863  PQfreemem(escape_tablespace);
2864  }
2865 
2866  executeStatement(con, buffer);
2867  }
2868 
2869  /*
2870  * create foreign keys
2871  */
2872  if (foreign_keys)
2873  {
2874  fprintf(stderr, "set foreign keys...\n");
2875  for (i = 0; i < lengthof(DDLKEYs); i++)
2876  {
2877  executeStatement(con, DDLKEYs[i]);
2878  }
2879  }
2880 
2881  fprintf(stderr, "done.\n");
2882  PQfinish(con);
2883 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6097
int unlogged_tables
Definition: pgbench.c:122
struct timeval instr_time
Definition: instr_time.h:147
void PQfinish(PGconn *conn)
Definition: fe-connect.c:3630
int scale
Definition: pgbench.c:106
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:196
#define lengthof(array)
Definition: c.h:556
#define LOG_STEP_SECONDS
Definition: pgbench.c:93
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2647
bool use_quiet
Definition: pgbench.c:168
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:818
#define SCALE_32BIT_THRESHOLD
Definition: pgbench.c:165
int PQputline(PGconn *conn, const char *s)
Definition: fe-exec.c:2540
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:3525
#define nbranches
Definition: pgbench.c:153
int foreign_keys
Definition: pgbench.c:117
int fillfactor
Definition: pgbench.c:112
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:167
char * tablespace
Definition: pgbench.c:146
char * index_tablespace
Definition: pgbench.c:147
#define ntellers
Definition: pgbench.c:155
#define naccounts
Definition: pgbench.c:156
void PQclear(PGresult *res)
Definition: fe-exec.c:671
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
int PQendcopy(PGconn *conn)
Definition: fe-exec.c:2573
static PGconn * doConnect(void)
Definition: pgbench.c:848
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:153
#define INT64_FORMAT
Definition: c.h:300
int i
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1897
void PQfreemem(void *ptr)
Definition: fe-exec.c:3251
static void initSimpleStats ( SimpleStats ss)
static

Definition at line 744 of file pgbench.c.

Referenced by initStats(), process_backslash_command(), and process_sql_command().

745 {
746  memset(ss, 0, sizeof(SimpleStats));
747 }
static void initStats ( StatsData sd,
time_t  start_time 
)
static

Definition at line 784 of file pgbench.c.

References StatsData::cnt, initSimpleStats(), StatsData::lag, StatsData::latency, StatsData::skipped, start_time, and StatsData::start_time.

Referenced by doLog(), main(), ParseScript(), and threadRun().

785 {
786  sd->start_time = start_time;
787  sd->cnt = 0;
788  sd->skipped = 0;
789  initSimpleStats(&sd->latency);
790  initSimpleStats(&sd->lag);
791 }
time_t start_time
Definition: pgbench.c:231
SimpleStats lag
Definition: pgbench.c:236
SimpleStats latency
Definition: pgbench.c:235
static time_t start_time
Definition: pg_ctl.c:103
int64 cnt
Definition: pgbench.c:232
int64 skipped
Definition: pgbench.c:233
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:744
static bool is_an_int ( const char *  str)
static

Definition at line 532 of file pgbench.c.

Referenced by makeVariableNumeric().

533 {
534  const char *ptr = str;
535 
536  /* skip leading spaces; cast is consistent with strtoint64 */
537  while (*ptr && isspace((unsigned char) *ptr))
538  ptr++;
539 
540  /* skip sign */
541  if (*ptr == '+' || *ptr == '-')
542  ptr++;
543 
544  /* at least one digit */
545  if (*ptr && !isdigit((unsigned char) *ptr))
546  return false;
547 
548  /* eat all digits */
549  while (*ptr && isdigit((unsigned char) *ptr))
550  ptr++;
551 
552  /* must have reached end of string */
553  return *ptr == '\0';
554 }
static void listAvailableScripts ( void  )
static

Definition at line 3395 of file pgbench.c.

References i, lengthof, and name.

Referenced by findBuiltin(), and main().

3396 {
3397  int i;
3398 
3399  fprintf(stderr, "Available builtin scripts:\n");
3400  for (i = 0; i < lengthof(builtin_script); i++)
3401  fprintf(stderr, "\t%s\n", builtin_script[i].name);
3402  fprintf(stderr, "\n");
3403 }
#define lengthof(array)
Definition: c.h:556
static const BuiltinScript builtin_script[]
Definition: pgbench.c:410
const char * name
Definition: encode.c:521
int i
static Variable* lookupCreateVariable ( CState st,
const char *  context,
char *  name 
)
static

Definition at line 1063 of file pgbench.c.

References lookupVariable(), Variable::name, CState::nvariables, pg_malloc(), pg_realloc(), pg_strdup(), valid_variable_name(), Variable::value, CState::variables, and CState::vars_sorted.

Referenced by putVariable(), and putVariableNumber().

1064 {
1065  Variable *var;
1066 
1067  var = lookupVariable(st, name);
1068  if (var == NULL)
1069  {
1070  Variable *newvars;
1071 
1072  /*
1073  * Check for the name only when declaring a new variable to avoid
1074  * overhead.
1075  */
1076  if (!valid_variable_name(name))
1077  {
1078  fprintf(stderr, "%s: invalid variable name: \"%s\"\n",
1079  context, name);
1080  return NULL;
1081  }
1082 
1083  /* Create variable at the end of the array */
1084  if (st->variables)
1085  newvars = (Variable *) pg_realloc(st->variables,
1086  (st->nvariables + 1) * sizeof(Variable));
1087  else
1088  newvars = (Variable *) pg_malloc(sizeof(Variable));
1089 
1090  st->variables = newvars;
1091 
1092  var = &newvars[st->nvariables];
1093 
1094  var->name = pg_strdup(name);
1095  var->value = NULL;
1096  /* caller is expected to initialize remaining fields */
1097 
1098  st->nvariables++;
1099  /* we don't re-sort the array till we have to */
1100  st->vars_sorted = false;
1101  }
1102 
1103  return var;
1104 }
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:939
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
char * name
Definition: pgbench.c:201
static bool valid_variable_name(const char *name)
Definition: pgbench.c:1036
Variable * variables
Definition: pgbench.c:319
bool vars_sorted
Definition: pgbench.c:321
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
char * value
Definition: pgbench.c:202
const char * name
Definition: encode.c:521
int nvariables
Definition: pgbench.c:320
static Variable* lookupVariable ( CState st,
char *  name 
)
static

Definition at line 939 of file pgbench.c.

References compareVariableNames(), Variable::name, name, CState::nvariables, qsort, CState::variables, and CState::vars_sorted.

Referenced by evaluateExpr(), getVariable(), lookupCreateVariable(), and main().

940 {
941  Variable key;
942 
943  /* On some versions of Solaris, bsearch of zero items dumps core */
944  if (st->nvariables <= 0)
945  return NULL;
946 
947  /* Sort if we have to */
948  if (!st->vars_sorted)
949  {
950  qsort((void *) st->variables, st->nvariables, sizeof(Variable),
952  st->vars_sorted = true;
953  }
954 
955  /* Now we can search */
956  key.name = name;
957  return (Variable *) bsearch((void *) &key,
958  (void *) st->variables,
959  st->nvariables,
960  sizeof(Variable),
962 }
char * name
Definition: pgbench.c:201
static int compareVariableNames(const void *v1, const void *v2)
Definition: pgbench.c:931
Variable * variables
Definition: pgbench.c:319
bool vars_sorted
Definition: pgbench.c:321
const char * name
Definition: encode.c:521
int nvariables
Definition: pgbench.c:320
#define qsort(a, b, c, d)
Definition: port.h:443
int main ( int  argc,
char **  argv 
)

Definition at line 3638 of file pgbench.c.

References _, Assert, StatsData::cnt, ParsedScript::commands, TState::conn_time, CONNECTION_BAD, DEFAULT_NXACTS, disconnect_all(), doConnect(), ERRCODE_UNDEFINED_TABLE, findBuiltin(), foreign_keys, get_progname(), getopt_long(), i, CState::id, init(), initStats(), INSTR_TIME_ADD, INSTR_TIME_GET_MICROSEC, INSTR_TIME_SET_CURRENT, INSTR_TIME_SET_ZERO, INSTR_TIME_SUBTRACT, INVALID_THREAD, Variable::is_numeric, StatsData::lag, StatsData::latency, TState::latency_late, listAvailableScripts(), TState::logfile, login, lookupVariable(), MAXCLIENTS, mergeSimpleStats(), Variable::name, nclients, no_argument, TState::nstate, nthreads, NUM_QUERYMODE, num_scripts, Variable::num_value, CState::nvariables, optarg, optind, parseQuery(), parseScriptWeight(), PG_DIAG_SQLSTATE, pg_malloc(), pg_realloc(), pg_strdup(), PGRES_TUPLES_OK, PQclear(), PQdb(), PQerrorMessage(), PQexec(), PQfinish(), PQgetvalue(), PQresultErrorField(), PQresultStatus(), PQstatus(), printResults(), process_builtin(), process_file(), putVariable(), putVariableInt(), putVariableNumber(), QUERY_SIMPLE, random(), TState::random_state, required_argument, setalarm(), StatsData::skipped, SQL_COMMAND, srandom(), start_time, TState::start_time, TState::state, TState::stats, strerror(), TState::thread, threadRun(), TState::tid, tryExecuteStatement(), unlogged_tables, usage(), Variable::value, and CState::variables.

3639 {
3640  static struct option long_options[] = {
3641  /* systematic long/short named options */
3642  {"builtin", required_argument, NULL, 'b'},
3643  {"client", required_argument, NULL, 'c'},
3644  {"connect", no_argument, NULL, 'C'},
3645  {"debug", no_argument, NULL, 'd'},
3646  {"define", required_argument, NULL, 'D'},
3647  {"file", required_argument, NULL, 'f'},
3648  {"fillfactor", required_argument, NULL, 'F'},
3649  {"host", required_argument, NULL, 'h'},
3650  {"initialize", no_argument, NULL, 'i'},
3651  {"jobs", required_argument, NULL, 'j'},
3652  {"log", no_argument, NULL, 'l'},
3653  {"latency-limit", required_argument, NULL, 'L'},
3654  {"no-vacuum", no_argument, NULL, 'n'},
3655  {"port", required_argument, NULL, 'p'},
3656  {"progress", required_argument, NULL, 'P'},
3657  {"protocol", required_argument, NULL, 'M'},
3658  {"quiet", no_argument, NULL, 'q'},
3659  {"report-latencies", no_argument, NULL, 'r'},
3660  {"rate", required_argument, NULL, 'R'},
3661  {"scale", required_argument, NULL, 's'},
3662  {"select-only", no_argument, NULL, 'S'},
3663  {"skip-some-updates", no_argument, NULL, 'N'},
3664  {"time", required_argument, NULL, 'T'},
3665  {"transactions", required_argument, NULL, 't'},
3666  {"username", required_argument, NULL, 'U'},
3667  {"vacuum-all", no_argument, NULL, 'v'},
3668  /* long-named only options */
3669  {"foreign-keys", no_argument, &foreign_keys, 1},
3670  {"index-tablespace", required_argument, NULL, 3},
3671  {"tablespace", required_argument, NULL, 2},
3672  {"unlogged-tables", no_argument, &unlogged_tables, 1},
3673  {"sampling-rate", required_argument, NULL, 4},
3674  {"aggregate-interval", required_argument, NULL, 5},
3675  {"progress-timestamp", no_argument, NULL, 6},
3676  {"log-prefix", required_argument, NULL, 7},
3677  {NULL, 0, NULL, 0}
3678  };
3679 
3680  int c;
3681  int is_init_mode = 0; /* initialize mode? */
3682  int is_no_vacuum = 0; /* no vacuum at all before testing? */
3683  int do_vacuum_accounts = 0; /* do vacuum accounts before testing? */
3684  int optindex;
3685  bool scale_given = false;
3686 
3687  bool benchmarking_option_set = false;
3688  bool initialization_option_set = false;
3689  bool internal_script_used = false;
3690 
3691  CState *state; /* status of clients */
3692  TState *threads; /* array of thread */
3693 
3694  instr_time start_time; /* start up time */
3695  instr_time total_time;
3696  instr_time conn_total_time;
3697  int64 latency_late = 0;
3698  StatsData stats;
3699  int weight;
3700 
3701  int i;
3702  int nclients_dealt;
3703 
3704 #ifdef HAVE_GETRLIMIT
3705  struct rlimit rlim;
3706 #endif
3707 
3708  PGconn *con;
3709  PGresult *res;
3710  char *env;
3711 
3712  progname = get_progname(argv[0]);
3713 
3714  if (argc > 1)
3715  {
3716  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
3717  {
3718  usage();
3719  exit(0);
3720  }
3721  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
3722  {
3723  puts("pgbench (PostgreSQL) " PG_VERSION);
3724  exit(0);
3725  }
3726  }
3727 
3728 #ifdef WIN32
3729  /* stderr is buffered on Win32. */
3730  setvbuf(stderr, NULL, _IONBF, 0);
3731 #endif
3732 
3733  if ((env = getenv("PGHOST")) != NULL && *env != '\0')
3734  pghost = env;
3735  if ((env = getenv("PGPORT")) != NULL && *env != '\0')
3736  pgport = env;
3737  else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
3738  login = env;
3739 
3740  state = (CState *) pg_malloc(sizeof(CState));
3741  memset(state, 0, sizeof(CState));
3742 
3743  while ((c = getopt_long(argc, argv, "ih:nvp:dqb:SNc:j:Crs:t:T:U:lf:D:F:M:P:R:L:", long_options, &optindex)) != -1)
3744  {
3745  char *script;
3746 
3747  switch (c)
3748  {
3749  case 'i':
3750  is_init_mode++;
3751  break;
3752  case 'h':
3753  pghost = pg_strdup(optarg);
3754  break;
3755  case 'n':
3756  is_no_vacuum++;
3757  break;
3758  case 'v':
3759  do_vacuum_accounts++;
3760  break;
3761  case 'p':
3762  pgport = pg_strdup(optarg);
3763  break;
3764  case 'd':
3765  debug++;
3766  break;
3767  case 'c':
3768  benchmarking_option_set = true;
3769  nclients = atoi(optarg);
3770  if (nclients <= 0 || nclients > MAXCLIENTS)
3771  {
3772  fprintf(stderr, "invalid number of clients: \"%s\"\n",
3773  optarg);
3774  exit(1);
3775  }
3776 #ifdef HAVE_GETRLIMIT
3777 #ifdef RLIMIT_NOFILE /* most platforms use RLIMIT_NOFILE */
3778  if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
3779 #else /* but BSD doesn't ... */
3780  if (getrlimit(RLIMIT_OFILE, &rlim) == -1)
3781 #endif /* RLIMIT_NOFILE */
3782  {
3783  fprintf(stderr, "getrlimit failed: %s\n", strerror(errno));
3784  exit(1);
3785  }
3786  if (rlim.rlim_cur < nclients + 3)
3787  {
3788  fprintf(stderr, "need at least %d open files, but system limit is %ld\n",
3789  nclients + 3, (long) rlim.rlim_cur);
3790  fprintf(stderr, "Reduce number of clients, or use limit/ulimit to increase the system limit.\n");
3791  exit(1);
3792  }
3793 #endif /* HAVE_GETRLIMIT */
3794  break;
3795  case 'j': /* jobs */
3796  benchmarking_option_set = true;
3797  nthreads = atoi(optarg);
3798  if (nthreads <= 0)
3799  {
3800  fprintf(stderr, "invalid number of threads: \"%s\"\n",
3801  optarg);
3802  exit(1);
3803  }
3804 #ifndef ENABLE_THREAD_SAFETY
3805  if (nthreads != 1)
3806  {
3807  fprintf(stderr, "threads are not supported on this platform; use -j1\n");
3808  exit(1);
3809  }
3810 #endif /* !ENABLE_THREAD_SAFETY */
3811  break;
3812  case 'C':
3813  benchmarking_option_set = true;
3814  is_connect = true;
3815  break;
3816  case 'r':
3817  benchmarking_option_set = true;
3818  per_script_stats = true;
3819  is_latencies = true;
3820  break;
3821  case 's':
3822  scale_given = true;
3823  scale = atoi(optarg);
3824  if (scale <= 0)
3825  {
3826  fprintf(stderr, "invalid scaling factor: \"%s\"\n", optarg);
3827  exit(1);
3828  }
3829  break;
3830  case 't':
3831  benchmarking_option_set = true;
3832  if (duration > 0)
3833  {
3834  fprintf(stderr, "specify either a number of transactions (-t) or a duration (-T), not both\n");
3835  exit(1);
3836  }
3837  nxacts = atoi(optarg);
3838  if (nxacts <= 0)
3839  {
3840  fprintf(stderr, "invalid number of transactions: \"%s\"\n",
3841  optarg);
3842  exit(1);
3843  }
3844  break;
3845  case 'T':
3846  benchmarking_option_set = true;
3847  if (nxacts > 0)
3848  {
3849  fprintf(stderr, "specify either a number of transactions (-t) or a duration (-T), not both\n");
3850  exit(1);
3851  }
3852  duration = atoi(optarg);
3853  if (duration <= 0)
3854  {
3855  fprintf(stderr, "invalid duration: \"%s\"\n", optarg);
3856  exit(1);
3857  }
3858  break;
3859  case 'U':
3860  login = pg_strdup(optarg);
3861  break;
3862  case 'l':
3863  benchmarking_option_set = true;
3864  use_log = true;
3865  break;
3866  case 'q':
3867  initialization_option_set = true;
3868  use_quiet = true;
3869  break;
3870 
3871  case 'b':
3872  if (strcmp(optarg, "list") == 0)
3873  {
3875  exit(0);
3876  }
3877 
3878  weight = parseScriptWeight(optarg, &script);
3879  process_builtin(findBuiltin(script), weight);
3880  benchmarking_option_set = true;
3881  internal_script_used = true;
3882  break;
3883 
3884  case 'S':
3885  process_builtin(findBuiltin("select-only"), 1);
3886  benchmarking_option_set = true;
3887  internal_script_used = true;
3888  break;
3889  case 'N':
3890  process_builtin(findBuiltin("simple-update"), 1);
3891  benchmarking_option_set = true;
3892  internal_script_used = true;
3893  break;
3894  case 'f':
3895  weight = parseScriptWeight(optarg, &script);
3896  process_file(script, weight);
3897  benchmarking_option_set = true;
3898  break;
3899  case 'D':
3900  {
3901  char *p;
3902 
3903  benchmarking_option_set = true;
3904 
3905  if ((p = strchr(optarg, '=')) == NULL || p == optarg || *(p + 1) == '\0')
3906  {
3907  fprintf(stderr, "invalid variable definition: \"%s\"\n",
3908  optarg);
3909  exit(1);
3910  }
3911 
3912  *p++ = '\0';
3913  if (!putVariable(&state[0], "option", optarg, p))
3914  exit(1);
3915  }
3916  break;
3917  case 'F':
3918  initialization_option_set = true;
3919  fillfactor = atoi(optarg);
3920  if (fillfactor < 10 || fillfactor > 100)
3921  {
3922  fprintf(stderr, "invalid fillfactor: \"%s\"\n", optarg);
3923  exit(1);
3924  }
3925  break;
3926  case 'M':
3927  benchmarking_option_set = true;
3928  for (querymode = 0; querymode < NUM_QUERYMODE; querymode++)
3929  if (strcmp(optarg, QUERYMODE[querymode]) == 0)
3930  break;
3931  if (querymode >= NUM_QUERYMODE)
3932  {
3933  fprintf(stderr, "invalid query mode (-M): \"%s\"\n",
3934  optarg);
3935  exit(1);
3936  }
3937  break;
3938  case 'P':
3939  benchmarking_option_set = true;
3940  progress = atoi(optarg);
3941  if (progress <= 0)
3942  {
3943  fprintf(stderr, "invalid thread progress delay: \"%s\"\n",
3944  optarg);
3945  exit(1);
3946  }
3947  break;
3948  case 'R':
3949  {
3950  /* get a double from the beginning of option value */
3951  double throttle_value = atof(optarg);
3952 
3953  benchmarking_option_set = true;
3954 
3955  if (throttle_value <= 0.0)
3956  {
3957  fprintf(stderr, "invalid rate limit: \"%s\"\n", optarg);
3958  exit(1);
3959  }
3960  /* Invert rate limit into a time offset */
3961  throttle_delay = (int64) (1000000.0 / throttle_value);
3962  }
3963  break;
3964  case 'L':
3965  {
3966  double limit_ms = atof(optarg);
3967 
3968  if (limit_ms <= 0.0)
3969  {
3970  fprintf(stderr, "invalid latency limit: \"%s\"\n",
3971  optarg);
3972  exit(1);
3973  }
3974  benchmarking_option_set = true;
3975  latency_limit = (int64) (limit_ms * 1000);
3976  }
3977  break;
3978  case 0:
3979  /* This covers long options which take no argument. */
3981  initialization_option_set = true;
3982  break;
3983  case 2: /* tablespace */
3984  initialization_option_set = true;
3986  break;
3987  case 3: /* index-tablespace */
3988  initialization_option_set = true;
3990  break;
3991  case 4:
3992  benchmarking_option_set = true;
3993  sample_rate = atof(optarg);
3994  if (sample_rate <= 0.0 || sample_rate > 1.0)
3995  {
3996  fprintf(stderr, "invalid sampling rate: \"%s\"\n", optarg);
3997  exit(1);
3998  }
3999  break;
4000  case 5:
4001  benchmarking_option_set = true;
4002  agg_interval = atoi(optarg);
4003  if (agg_interval <= 0)
4004  {
4005  fprintf(stderr, "invalid number of seconds for aggregation: \"%s\"\n",
4006  optarg);
4007  exit(1);
4008  }
4009  break;
4010  case 6:
4011  progress_timestamp = true;
4012  benchmarking_option_set = true;
4013  break;
4014  case 7:
4015  benchmarking_option_set = true;
4017  break;
4018  default:
4019  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
4020  exit(1);
4021  break;
4022  }
4023  }
4024 
4025  /* set default script if none */
4026  if (num_scripts == 0 && !is_init_mode)
4027  {
4028  process_builtin(findBuiltin("tpcb-like"), 1);
4029  benchmarking_option_set = true;
4030  internal_script_used = true;
4031  }
4032 
4033  /* if not simple query mode, parse the script(s) to find parameters */
4034  if (querymode != QUERY_SIMPLE)
4035  {
4036  for (i = 0; i < num_scripts; i++)
4037  {
4038  Command **commands = sql_script[i].commands;
4039  int j;
4040 
4041  for (j = 0; commands[j] != NULL; j++)
4042  {
4043  if (commands[j]->type != SQL_COMMAND)
4044  continue;
4045  if (!parseQuery(commands[j]))
4046  exit(1);
4047  }
4048  }
4049  }
4050 
4051  /* compute total_weight */
4052  for (i = 0; i < num_scripts; i++)
4053  /* cannot overflow: weight is 32b, total_weight 64b */
4054  total_weight += sql_script[i].weight;
4055 
4056  if (total_weight == 0 && !is_init_mode)
4057  {
4058  fprintf(stderr, "total script weight must not be zero\n");
4059  exit(1);
4060  }
4061 
4062  /* show per script stats if several scripts are used */
4063  if (num_scripts > 1)
4064  per_script_stats = true;
4065 
4066  /*
4067  * Don't need more threads than there are clients. (This is not merely an
4068  * optimization; throttle_delay is calculated incorrectly below if some
4069  * threads have no clients assigned to them.)
4070  */
4071  if (nthreads > nclients)
4072  nthreads = nclients;
4073 
4074  /* compute a per thread delay */
4076 
4077  if (argc > optind)
4078  dbName = argv[optind];
4079  else
4080  {
4081  if ((env = getenv("PGDATABASE")) != NULL && *env != '\0')
4082  dbName = env;
4083  else if (login != NULL && *login != '\0')
4084  dbName = login;
4085  else
4086  dbName = "";
4087  }
4088 
4089  if (is_init_mode)
4090  {
4091  if (benchmarking_option_set)
4092  {
4093  fprintf(stderr, "some of the specified options cannot be used in initialization (-i) mode\n");
4094  exit(1);
4095  }
4096 
4097  init(is_no_vacuum);
4098  exit(0);
4099  }
4100  else
4101  {
4102  if (initialization_option_set)
4103  {
4104  fprintf(stderr, "some of the specified options cannot be used in benchmarking mode\n");
4105  exit(1);
4106  }
4107  }
4108 
4109  /* Use DEFAULT_NXACTS if neither nxacts nor duration is specified. */
4110  if (nxacts <= 0 && duration <= 0)
4112 
4113  /* --sampling-rate may be used only with -l */
4114  if (sample_rate > 0.0 && !use_log)
4115  {
4116  fprintf(stderr, "log sampling (--sampling-rate) is allowed only when logging transactions (-l)\n");
4117  exit(1);
4118  }
4119 
4120  /* --sampling-rate may not be used with --aggregate-interval */
4121  if (sample_rate > 0.0 && agg_interval > 0)
4122  {
4123  fprintf(stderr, "log sampling (--sampling-rate) and aggregation (--aggregate-interval) cannot be used at the same time\n");
4124  exit(1);
4125  }
4126 
4127  if (agg_interval > 0 && !use_log)
4128  {
4129  fprintf(stderr, "log aggregation is allowed only when actually logging transactions\n");
4130  exit(1);
4131  }
4132 
4133  if (!use_log && logfile_prefix)
4134  {
4135  fprintf(stderr, "log file prefix (--log-prefix) is allowed only when logging transactions (-l)\n");
4136  exit(1);
4137  }
4138 
4139  if (duration > 0 && agg_interval > duration)
4140  {
4141  fprintf(stderr, "number of seconds for aggregation (%d) must not be higher than test duration (%d)\n", agg_interval, duration);
4142  exit(1);
4143  }
4144 
4145  if (duration > 0 && agg_interval > 0 && duration % agg_interval != 0)
4146  {
4147  fprintf(stderr, "duration (%d) must be a multiple of aggregation interval (%d)\n", duration, agg_interval);
4148  exit(1);
4149  }
4150 
4151  if (progress_timestamp && progress == 0)
4152  {
4153  fprintf(stderr, "--progress-timestamp is allowed only under --progress\n");
4154  exit(1);
4155  }
4156 
4157  /*
4158  * save main process id in the global variable because process id will be
4159  * changed after fork.
4160  */
4161  main_pid = (int) getpid();
4162 
4163  if (nclients > 1)
4164  {
4165  state = (CState *) pg_realloc(state, sizeof(CState) * nclients);
4166  memset(state + 1, 0, sizeof(CState) * (nclients - 1));
4167 
4168  /* copy any -D switch values to all clients */
4169  for (i = 1; i < nclients; i++)
4170  {
4171  int j;
4172 
4173  state[i].id = i;
4174  for (j = 0; j < state[0].nvariables; j++)
4175  {
4176  Variable *var = &state[0].variables[j];
4177 
4178  if (var->is_numeric)
4179  {
4180  if (!putVariableNumber(&state[i], "startup",
4181  var->name, &var->num_value))
4182  exit(1);
4183  }
4184  else
4185  {
4186  if (!putVariable(&state[i], "startup",
4187  var->name, var->value))
4188  exit(1);
4189  }
4190  }
4191  }
4192  }
4193 
4194  if (debug)
4195  {
4196  if (duration <= 0)
4197  printf("pghost: %s pgport: %s nclients: %d nxacts: %d dbName: %s\n",
4198  pghost, pgport, nclients, nxacts, dbName);
4199  else
4200  printf("pghost: %s pgport: %s nclients: %d duration: %d dbName: %s\n",
4201  pghost, pgport, nclients, duration, dbName);
4202  }
4203 
4204  /* opening connection... */
4205  con = doConnect();
4206  if (con == NULL)
4207  exit(1);
4208 
4209  if (PQstatus(con) == CONNECTION_BAD)
4210  {
4211  fprintf(stderr, "connection to database \"%s\" failed\n", dbName);
4212  fprintf(stderr, "%s", PQerrorMessage(con));
4213  exit(1);
4214  }
4215 
4216  if (internal_script_used)
4217  {
4218  /*
4219  * get the scaling factor that should be same as count(*) from
4220  * pgbench_branches if this is not a custom query
4221  */
4222  res = PQexec(con, "select count(*) from pgbench_branches");
4223  if (PQresultStatus(res) != PGRES_TUPLES_OK)
4224  {
4225  char *sqlState = PQresultErrorField(res, PG_DIAG_SQLSTATE);
4226 
4227  fprintf(stderr, "%s", PQerrorMessage(con));
4228  if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) == 0)
4229  {
4230  fprintf(stderr, "Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\"\n", PQdb(con));
4231  }
4232 
4233  exit(1);
4234  }
4235  scale = atoi(PQgetvalue(res, 0, 0));
4236  if (scale < 0)
4237  {
4238  fprintf(stderr, "invalid count(*) from pgbench_branches: \"%s\"\n",
4239  PQgetvalue(res, 0, 0));
4240  exit(1);
4241  }
4242  PQclear(res);
4243 
4244  /* warn if we override user-given -s switch */
4245  if (scale_given)
4246  fprintf(stderr,
4247  "scale option ignored, using count from pgbench_branches table (%d)\n",
4248  scale);
4249  }
4250 
4251  /*
4252  * :scale variables normally get -s or database scale, but don't override
4253  * an explicit -D switch
4254  */
4255  if (lookupVariable(&state[0], "scale") == NULL)
4256  {
4257  for (i = 0; i < nclients; i++)
4258  {
4259  if (!putVariableInt(&state[i], "startup", "scale", scale))
4260  exit(1);
4261  }
4262  }
4263 
4264  /*
4265  * Define a :client_id variable that is unique per connection. But don't
4266  * override an explicit -D switch.
4267  */
4268  if (lookupVariable(&state[0], "client_id") == NULL)
4269  {
4270  for (i = 0; i < nclients; i++)
4271  {
4272  if (!putVariableInt(&state[i], "startup", "client_id", i))
4273  exit(1);
4274  }
4275  }
4276 
4277  if (!is_no_vacuum)
4278  {
4279  fprintf(stderr, "starting vacuum...");
4280  tryExecuteStatement(con, "vacuum pgbench_branches");
4281  tryExecuteStatement(con, "vacuum pgbench_tellers");
4282  tryExecuteStatement(con, "truncate pgbench_history");
4283  fprintf(stderr, "end.\n");
4284 
4285  if (do_vacuum_accounts)
4286  {
4287  fprintf(stderr, "starting vacuum pgbench_accounts...");
4288  tryExecuteStatement(con, "vacuum analyze pgbench_accounts");
4289  fprintf(stderr, "end.\n");
4290  }
4291  }
4292  PQfinish(con);
4293 
4294  /* set random seed */
4295  INSTR_TIME_SET_CURRENT(start_time);
4296  srandom((unsigned int) INSTR_TIME_GET_MICROSEC(start_time));
4297 
4298  /* set up thread data structures */
4299  threads = (TState *) pg_malloc(sizeof(TState) * nthreads);
4300  nclients_dealt = 0;
4301 
4302  for (i = 0; i < nthreads; i++)
4303  {
4304  TState *thread = &threads[i];
4305 
4306  thread->tid = i;
4307  thread->state = &state[nclients_dealt];
4308  thread->nstate =
4309  (nclients - nclients_dealt + nthreads - i - 1) / (nthreads - i);
4310  thread->random_state[0] = random();
4311  thread->random_state[1] = random();
4312  thread->random_state[2] = random();
4313  thread->logfile = NULL; /* filled in later */
4314  thread->latency_late = 0;
4315  initStats(&thread->stats, 0);
4316 
4317  nclients_dealt += thread->nstate;
4318  }
4319 
4320  /* all clients must be assigned to a thread */
4321  Assert(nclients_dealt == nclients);
4322 
4323  /* get start up time */
4324  INSTR_TIME_SET_CURRENT(start_time);
4325 
4326  /* set alarm if duration is specified. */
4327  if (duration > 0)
4328  setalarm(duration);
4329 
4330  /* start threads */
4331 #ifdef ENABLE_THREAD_SAFETY
4332  for (i = 0; i < nthreads; i++)
4333  {
4334  TState *thread = &threads[i];
4335 
4337 
4338  /* compute when to stop */
4339  if (duration > 0)
4341  (int64) 1000000 * duration;
4342 
4343  /* the first thread (i = 0) is executed by main thread */
4344  if (i > 0)
4345  {
4346  int err = pthread_create(&thread->thread, NULL, threadRun, thread);
4347 
4348  if (err != 0 || thread->thread == INVALID_THREAD)
4349  {
4350  fprintf(stderr, "could not create thread: %s\n", strerror(err));
4351  exit(1);
4352  }
4353  }
4354  else
4355  {
4356  thread->thread = INVALID_THREAD;
4357  }
4358  }
4359 #else
4360  INSTR_TIME_SET_CURRENT(threads[0].start_time);
4361  /* compute when to stop */
4362  if (duration > 0)
4363  end_time = INSTR_TIME_GET_MICROSEC(threads[0].start_time) +
4364  (int64) 1000000 * duration;
4365  threads[0].thread = INVALID_THREAD;
4366 #endif /* ENABLE_THREAD_SAFETY */
4367 
4368  /* wait for threads and accumulate results */
4369  initStats(&stats, 0);
4370  INSTR_TIME_SET_ZERO(conn_total_time);
4371  for (i = 0; i < nthreads; i++)
4372  {
4373  TState *thread = &threads[i];
4374 
4375 #ifdef ENABLE_THREAD_SAFETY
4376  if (threads[i].thread == INVALID_THREAD)
4377  /* actually run this thread directly in the main thread */
4378  (void) threadRun(thread);
4379  else
4380  /* wait of other threads. should check that 0 is returned? */
4381  pthread_join(thread->thread, NULL);
4382 #else
4383  (void) threadRun(thread);
4384 #endif /* ENABLE_THREAD_SAFETY */
4385 
4386  /* aggregate thread level stats */
4387  mergeSimpleStats(&stats.latency, &thread->stats.latency);
4388  mergeSimpleStats(&stats.lag, &thread->stats.lag);
4389  stats.cnt += thread->stats.cnt;
4390  stats.skipped += thread->stats.skipped;
4391  latency_late += thread->latency_late;
4392  INSTR_TIME_ADD(conn_total_time, thread->conn_time);
4393  }
4394  disconnect_all(state, nclients);
4395 
4396  /*
4397  * XXX We compute results as though every client of every thread started
4398  * and finished at the same time. That model can diverge noticeably from
4399  * reality for a short benchmark run involving relatively many threads.
4400  * The first thread may process notably many transactions before the last
4401  * thread begins. Improving the model alone would bring limited benefit,
4402  * because performance during those periods of partial thread count can
4403  * easily exceed steady state performance. This is one of the many ways
4404  * short runs convey deceptive performance figures.
4405  */
4406  INSTR_TIME_SET_CURRENT(total_time);
4407  INSTR_TIME_SUBTRACT(total_time, start_time);
4408  printResults(threads, &stats, total_time, conn_total_time, latency_late);
4409 
4410  return 0;
4411 }
static const BuiltinScript * findBuiltin(const char *name)
Definition: pgbench.c:3407
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6097
int unlogged_tables
Definition: pgbench.c:122
double sample_rate
Definition: pgbench.c:127
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:939
static bool putVariableNumber(CState *st, const char *context, char *name, const PgBenchValue *value)
Definition: pgbench.c:1132
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:61
#define INVALID_THREAD
Definition: pgbench.c:356
int id
Definition: pgbench.c:312
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3118
static int num_scripts
Definition: pgbench.c:396
unsigned short random_state[3]
Definition: pgbench.c:345
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
static void listAvailableScripts(void)
Definition: pgbench.c:3395
char * name
Definition: pgbench.c:201
int nclients
Definition: pgbench.c:174
const char * get_progname(const char *argv0)
Definition: path.c:453
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:57
long random(void)
Definition: random.c:22
static int parseScriptWeight(const char *option, char **script)
Definition: pgbench.c:3444
struct timeval instr_time
Definition: instr_time.h:147
int64 latency_late
Definition: pgbench.c:353
SimpleStats lag
Definition: pgbench.c:236
static void initStats(StatsData *sd, time_t start_time)
Definition: pgbench.c:784
void PQfinish(PGconn *conn)
Definition: fe-connect.c:3630
int scale
Definition: pgbench.c:106
#define INSTR_TIME_SET_ZERO(t)
Definition: instr_time.h:151
bool use_log
Definition: pgbench.c:167
static bool putVariable(CState *st, const char *context, char *name, const char *value)
Definition: pgbench.c:1109
SimpleStats latency
Definition: pgbench.c:235
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:57
static void process_file(const char *filename, int weight)
Definition: pgbench.c:3354
bool per_script_stats
Definition: pgbench.c:171
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2647
bool use_quiet
Definition: pgbench.c:168
int duration
Definition: pgbench.c:99
static time_t start_time
Definition: pg_ctl.c:103
bool is_connect
Definition: pgbench.c:176
Variable * variables
Definition: pgbench.c:319
int nstate
Definition: pgbench.c:344
static const char * QUERYMODE[]
Definition: pgbench.c:374
int64 end_time
Definition: pgbench.c:100
#define required_argument
Definition: getopt_long.h:25
FILE * logfile
Definition: pgbench.c:347
static void mergeSimpleStats(SimpleStats *acc, SimpleStats *ss)
Definition: pgbench.c:768
int foreign_keys
Definition: pgbench.c:117
int optind
Definition: getopt.c:51
int64 cnt
Definition: pgbench.c:232
CState * state
Definition: pgbench.c:343
int fillfactor
Definition: pgbench.c:112
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:167
static int debug
Definition: pgbench.c:400
char * c
int nxacts
Definition: pgbench.c:98
#define INSTR_TIME_ADD(x, y)
Definition: instr_time.h:155
static void disconnect_all(CState *state, int length)
Definition: pgbench.c:2594
bool is_numeric
Definition: pgbench.c:203
char * tablespace
Definition: pgbench.c:146
static void usage(void)
Definition: pgbench.c:471
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
instr_time start_time
Definition: pgbench.c:350
char * index_tablespace
Definition: pgbench.c:147
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
int nthreads
Definition: pgbench.c:175
char * value
Definition: pgbench.c:202
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:395
static bool parseQuery(Command *cmd)
Definition: pgbench.c:2890
int64 skipped
Definition: pgbench.c:233
static int64 total_weight
Definition: pgbench.c:398
char * pghost
Definition: pgbench.c:180
int progress
Definition: pgbench.c:172
#define no_argument
Definition: getopt_long.h:24
static bool putVariableInt(CState *st, const char *context, char *name, int64 value)
Definition: pgbench.c:1153
#define SQL_COMMAND
Definition: pgbench.c:361
static void * threadRun(void *arg)
Definition: pgbench.c:4414
#define MAXCLIENTS
Definition: pgbench.c:90
void PQclear(PGresult *res)
Definition: fe-exec.c:671
static void printResults(TState *threads, StatsData *total, instr_time total_time, instr_time conn_total_time, int latency_late)
Definition: pgbench.c:3519
bool progress_timestamp
Definition: pgbench.c:173
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:5965
char * PQresultErrorField(const PGresult *res, int fieldcode)
Definition: fe-exec.c:2709
static PGconn * doConnect(void)
Definition: pgbench.c:848
#define Assert(condition)
Definition: c.h:664
Definition: regguts.h:298
const char * progname
Definition: pgbench.c:185
char * logfile_prefix
Definition: pgbench.c:184
#define INSTR_TIME_GET_MICROSEC(t)
Definition: instr_time.h:202
Command ** commands
Definition: pgbench.c:391
static void init(bool is_no_vacuum)
Definition: pgbench.c:2610
static QueryMode querymode
Definition: pgbench.c:373
int64 latency_limit
Definition: pgbench.c:141
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:153
pthread_t thread
Definition: pgbench.c:342
int main_pid
Definition: pgbench.c:178
int nvariables
Definition: pgbench.c:320
char * dbName
Definition: pgbench.c:183
int64 throttle_delay
Definition: pgbench.c:133
char * optarg
Definition: getopt.c:53
StatsData stats
Definition: pgbench.c:352
int i
const char * strerror(int errnum)
Definition: strerror.c:19
static void process_builtin(const BuiltinScript *bi, int weight)
Definition: pgbench.c:3388
instr_time conn_time
Definition: pgbench.c:351
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1897
void srandom(unsigned int seed)
Definition: srandom.c:22
int tid
Definition: pgbench.c:341
static void tryExecuteStatement(PGconn *con, const char *sql)
Definition: pgbench.c:833
#define DEFAULT_NXACTS
Definition: pgbench.c:94
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:6044
static void setalarm(int seconds)
Definition: pgbench.c:4778
#define _(x)
Definition: elog.c:84
char * pgport
Definition: pgbench.c:181
bool is_latencies
Definition: pgbench.c:177
char * login
Definition: pgbench.c:182
int agg_interval
Definition: pgbench.c:169
PgBenchValue num_value
Definition: pgbench.c:204
static bool makeVariableNumeric ( Variable var)
static

Definition at line 995 of file pgbench.c.

References is_an_int(), Variable::is_numeric, Variable::name, Variable::num_value, setDoubleValue(), setIntValue(), strtoint64(), and Variable::value.

Referenced by evaluateExpr().

996 {
997  if (var->is_numeric)
998  return true; /* no work */
999 
1000  if (is_an_int(var->value))
1001  {
1002  setIntValue(&var->num_value, strtoint64(var->value));
1003  var->is_numeric = true;
1004  }
1005  else /* type should be double */
1006  {
1007  double dv;
1008  char xs;
1009 
1010  if (sscanf(var->value, "%lf%c", &dv, &xs) != 1)
1011  {
1012  fprintf(stderr,
1013  "malformed variable \"%s\" value: \"%s\"\n",
1014  var->name, var->value);
1015  return false;
1016  }
1017  setDoubleValue(&var->num_value, dv);
1018  var->is_numeric = true;
1019  }
1020  return true;
1021 }
char * name
Definition: pgbench.c:201
static void setDoubleValue(PgBenchValue *pv, double dval)
Definition: pgbench.c:1308
int64 strtoint64(const char *str)
Definition: pgbench.c:564
bool is_numeric
Definition: pgbench.c:203
char * value
Definition: pgbench.c:202
static bool is_an_int(const char *str)
Definition: pgbench.c:532
static void setIntValue(PgBenchValue *pv, int64 ival)
Definition: pgbench.c:1300
PgBenchValue num_value
Definition: pgbench.c:204
static void mergeSimpleStats ( SimpleStats acc,
SimpleStats ss 
)
static

Definition at line 768 of file pgbench.c.

References SimpleStats::count, SimpleStats::max, SimpleStats::min, SimpleStats::sum, and SimpleStats::sum2.

Referenced by main(), and threadRun().

769 {
770  if (acc->count == 0 || ss->min < acc->min)
771  acc->min = ss->min;
772  if (acc->count == 0 || ss->max > acc->max)
773  acc->max = ss->max;
774  acc->count += ss->count;
775  acc->sum += ss->sum;
776  acc->sum2 += ss->sum2;
777 }
double sum
Definition: pgbench.c:221
int64 count
Definition: pgbench.c:218
double max
Definition: pgbench.c:220
double sum2
Definition: pgbench.c:222
double min
Definition: pgbench.c:219
static bool parseQuery ( Command cmd)
static

Definition at line 2890 of file pgbench.c.

References Command::argc, Command::argv, MAX_ARGS, name, parseVariable(), pg_free(), pg_strdup(), and replaceVariable().

Referenced by main().

2891 {
2892  char *sql,
2893  *p;
2894 
2895  /* We don't want to scribble on cmd->argv[0] until done */
2896  sql = pg_strdup(cmd->argv[0]);
2897 
2898  cmd->argc = 1;
2899 
2900  p = sql;
2901  while ((p = strchr(p, ':')) != NULL)
2902  {
2903  char var[12];
2904  char *name;
2905  int eaten;
2906 
2907  name = parseVariable(p, &eaten);
2908  if (name == NULL)
2909  {
2910  while (*p == ':')
2911  {
2912  p++;
2913  }
2914  continue;
2915  }
2916 
2917  if (cmd->argc >= MAX_ARGS)
2918  {
2919  fprintf(stderr, "statement has too many arguments (maximum is %d): %s\n",
2920  MAX_ARGS - 1, cmd->argv[0]);
2921  pg_free(name);
2922  return false;
2923  }
2924 
2925  sprintf(var, "$%d", cmd->argc);
2926  p = replaceVariable(&sql, p, eaten, var);
2927 
2928  cmd->argv[cmd->argc] = name;
2929  cmd->argc++;
2930  }
2931 
2932  pg_free(cmd->argv[0]);
2933  cmd->argv[0] = sql;
2934  return true;
2935 }
char * argv[MAX_ARGS]
Definition: pgbench.c:382
#define MAX_ARGS
Definition: pgbench.c:363
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
static char * replaceVariable(char **sql, char *param, int len, char *value)
Definition: pgbench.c:1193
int argc
Definition: pgbench.c:381
void pg_free(void *ptr)
Definition: fe_memutils.c:105
static char * parseVariable(const char *sql, int *eaten)
Definition: pgbench.c:1170
const char * name
Definition: encode.c:521
static void ParseScript ( const char *  script,
const char *  desc,
int  weight 
)
static

Definition at line 3222 of file pgbench.c.

References addScript(), ParsedScript::commands, COMMANDS_ALLOC_NUM, ParsedScript::desc, initPQExpBuffer(), initStats(), pg_malloc(), pg_realloc(), pgbench_callbacks, process_backslash_command(), process_sql_command(), PSCAN_BACKSLASH, PSCAN_EOL, PSCAN_INCOMPLETE, psql_scan(), psql_scan_create(), psql_scan_destroy(), psql_scan_finish(), psql_scan_setup(), resetPQExpBuffer(), ParsedScript::stats, termPQExpBuffer(), and ParsedScript::weight.

Referenced by process_builtin(), and process_file().

3223 {
3224  ParsedScript ps;
3225  PsqlScanState sstate;
3226  PQExpBufferData line_buf;
3227  int alloc_num;
3228  int index;
3229 
3230 #define COMMANDS_ALLOC_NUM 128
3231  alloc_num = COMMANDS_ALLOC_NUM;
3232 
3233  /* Initialize all fields of ps */
3234  ps.desc = desc;
3235  ps.weight = weight;
3236  ps.commands = (Command **) pg_malloc(sizeof(Command *) * alloc_num);
3237  initStats(&ps.stats, 0);
3238 
3239  /* Prepare to parse script */
3241 
3242  /*
3243  * Ideally, we'd scan scripts using the encoding and stdstrings settings
3244  * we get from a DB connection. However, without major rearrangement of
3245  * pgbench's argument parsing, we can't have a DB connection at the time
3246  * we parse scripts. Using SQL_ASCII (encoding 0) should work well enough
3247  * with any backend-safe encoding, though conceivably we could be fooled
3248  * if a script file uses a client-only encoding. We also assume that
3249  * stdstrings should be true, which is a bit riskier.
3250  */
3251  psql_scan_setup(sstate, script, strlen(script), 0, true);
3252 
3253  initPQExpBuffer(&line_buf);
3254 
3255  index = 0;
3256 
3257  for (;;)
3258  {
3259  PsqlScanResult sr;
3260  promptStatus_t prompt;
3261  Command *command;
3262 
3263  resetPQExpBuffer(&line_buf);
3264 
3265  sr = psql_scan(sstate, &line_buf, &prompt);
3266 
3267  /* If we collected a SQL command, process that */
3268  command = process_sql_command(&line_buf, desc);
3269  if (command)
3270  {
3271  ps.commands[index] = command;
3272  index++;
3273 
3274  if (index >= alloc_num)
3275  {
3276  alloc_num += COMMANDS_ALLOC_NUM;
3277  ps.commands = (Command **)
3278  pg_realloc(ps.commands, sizeof(Command *) * alloc_num);
3279  }
3280  }
3281 
3282  /* If we reached a backslash, process that */
3283  if (sr == PSCAN_BACKSLASH)
3284  {
3285  command = process_backslash_command(sstate, desc);
3286  if (command)
3287  {
3288  ps.commands[index] = command;
3289  index++;
3290 
3291  if (index >= alloc_num)
3292  {
3293  alloc_num += COMMANDS_ALLOC_NUM;
3294  ps.commands = (Command **)
3295  pg_realloc(ps.commands, sizeof(Command *) * alloc_num);
3296  }
3297  }
3298  }
3299 
3300  /* Done if we reached EOF */
3301  if (sr == PSCAN_INCOMPLETE || sr == PSCAN_EOL)
3302  break;
3303  }
3304 
3305  ps.commands[index] = NULL;
3306 
3307  addScript(ps);
3308 
3309  termPQExpBuffer(&line_buf);
3310  psql_scan_finish(sstate);
3311  psql_scan_destroy(sstate);
3312 }
PsqlScanResult
Definition: psqlscan.h:30
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
static Command * process_sql_command(PQExpBuffer buf, const char *source)
Definition: pgbench.c:2999
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:128
PsqlScanState psql_scan_create(const PsqlScanCallbacks *callbacks)
static void static void addScript(ParsedScript script)
Definition: pgbench.c:3488
static const PsqlScanCallbacks pgbench_callbacks
Definition: pgbench.c:464
#define COMMANDS_ALLOC_NUM
StatsData stats
Definition: pgbench.c:392
static void initStats(StatsData *sd, time_t start_time)
Definition: pgbench.c:784
int weight
Definition: pgbench.c:390
Definition: type.h:89
const char * desc
Definition: pgbench.c:389
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
void psql_scan_destroy(PsqlScanState state)
enum _promptStatus promptStatus_t
Command ** commands
Definition: pgbench.c:391
PsqlScanResult psql_scan(PsqlScanState state, PQExpBuffer query_buf, promptStatus_t *prompt)
static Command * process_backslash_command(PsqlScanState sstate, const char *source)
Definition: pgbench.c:3062
void psql_scan_setup(PsqlScanState state, const char *line, int line_len, int encoding, bool std_strings)
void psql_scan_finish(PsqlScanState state)
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:145
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:89
static int parseScriptWeight ( const char *  option,
char **  script 
)
static

Definition at line 3444 of file pgbench.c.

References INT64_FORMAT, pg_malloc(), pg_strdup(), and WSEP.

Referenced by main().

3445 {
3446  char *sep;
3447  int weight;
3448 
3449  if ((sep = strrchr(option, WSEP)))
3450  {
3451  int namelen = sep - option;
3452  long wtmp;
3453  char *badp;
3454 
3455  /* generate the script name */
3456  *script = pg_malloc(namelen + 1);
3457  strncpy(*script, option, namelen);
3458  (*script)[namelen] = '\0';
3459 
3460  /* process digits of the weight spec */
3461  errno = 0;
3462  wtmp = strtol(sep + 1, &badp, 10);
3463  if (errno != 0 || badp == sep + 1 || *badp != '\0')
3464  {
3465  fprintf(stderr, "invalid weight specification: %s\n", sep);
3466  exit(1);
3467  }
3468  if (wtmp > INT_MAX || wtmp < 0)
3469  {
3470  fprintf(stderr,
3471  "weight specification out of range (0 .. %u): " INT64_FORMAT "\n",
3472  INT_MAX, (int64) wtmp);
3473  exit(1);
3474  }
3475  weight = wtmp;
3476  }
3477  else
3478  {
3479  *script = pg_strdup(option);
3480  weight = 1;
3481  }
3482 
3483  return weight;
3484 }
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
#define WSEP
Definition: pgbench.c:187
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
#define INT64_FORMAT
Definition: c.h:300
static char* parseVariable ( const char *  sql,
int *  eaten 
)
static

Definition at line 1170 of file pgbench.c.

References i, IS_HIGHBIT_SET, name, and pg_malloc().

Referenced by assignVariables(), and parseQuery().

1171 {
1172  int i = 0;
1173  char *name;
1174 
1175  do
1176  {
1177  i++;
1178  } while (IS_HIGHBIT_SET(sql[i]) ||
1179  strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1180  "_0123456789", sql[i]) != NULL);
1181  if (i == 1)
1182  return NULL; /* no valid variable name chars */
1183 
1184  name = pg_malloc(i);
1185  memcpy(name, &sql[1], i - 1);
1186  name[i - 1] = '\0';
1187 
1188  *eaten = i;
1189  return name;
1190 }
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
#define IS_HIGHBIT_SET(ch)
Definition: c.h:962
const char * name
Definition: encode.c:521
int i
static void pgbench_error ( const char *  fmt,
  ... 
)
static

Definition at line 2941 of file pgbench.c.

References _.

2942 {
2943  va_list ap;
2944 
2945  fflush(stdout);
2946  va_start(ap, fmt);
2947  vfprintf(stderr, _(fmt), ap);
2948  va_end(ap);
2949 }
#define _(x)
Definition: elog.c:84
static void preparedStatementName ( char *  buffer,
int  file,
int  state 
)
static

Definition at line 1834 of file pgbench.c.

Referenced by sendCommand().

1835 {
1836  sprintf(buffer, "P%d_%d", file, state);
1837 }
Definition: regguts.h:298
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
static void printResults ( TState threads,
StatsData total,
instr_time  total_time,
instr_time  conn_total_time,
int  latency_late 
)
static

Definition at line 3519 of file pgbench.c.

References StatsData::cnt, i, INSTR_TIME_GET_DOUBLE, INT64_FORMAT, StatsData::lag, StatsData::latency, SimpleStats::max, nclients, num_scripts, printSimpleStats(), StatsData::skipped, ParsedScript::stats, and SimpleStats::sum.

Referenced by main().

3521 {
3522  double time_include,
3523  tps_include,
3524  tps_exclude;
3525 
3526  time_include = INSTR_TIME_GET_DOUBLE(total_time);
3527  tps_include = total->cnt / time_include;
3528  tps_exclude = total->cnt / (time_include -
3529  (INSTR_TIME_GET_DOUBLE(conn_total_time) / nclients));
3530 
3531  /* Report test parameters. */
3532  printf("transaction type: %s\n",
3533  num_scripts == 1 ? sql_script[0].desc : "multiple scripts");
3534  printf("scaling factor: %d\n", scale);
3535  printf("query mode: %s\n", QUERYMODE[querymode]);
3536  printf("number of clients: %d\n", nclients);
3537  printf("number of threads: %d\n", nthreads);
3538  if (duration <= 0)
3539  {
3540  printf("number of transactions per client: %d\n", nxacts);
3541  printf("number of transactions actually processed: " INT64_FORMAT "/%d\n",
3542  total->cnt - total->skipped, nxacts * nclients);
3543  }
3544  else
3545  {
3546  printf("duration: %d s\n", duration);
3547  printf("number of transactions actually processed: " INT64_FORMAT "\n",
3548  total->cnt);
3549  }
3550 
3551  /* Remaining stats are nonsensical if we failed to execute any xacts */
3552  if (total->cnt <= 0)
3553  return;
3554 
3556  printf("number of transactions skipped: " INT64_FORMAT " (%.3f %%)\n",
3557  total->skipped,
3558  100.0 * total->skipped / total->cnt);
3559 
3560  if (latency_limit)
3561  printf("number of transactions above the %.1f ms latency limit: %d (%.3f %%)\n",
3562  latency_limit / 1000.0, latency_late,
3563  100.0 * latency_late / total->cnt);
3564 
3566  printSimpleStats("latency", &total->latency);
3567  else
3568  {
3569  /* no measurement, show average latency computed from run time */
3570  printf("latency average = %.3f ms\n",
3571  1000.0 * time_include * nclients / total->cnt);
3572  }
3573 
3574  if (throttle_delay)
3575  {
3576  /*
3577  * Report average transaction lag under rate limit throttling. This
3578  * is the delay between scheduled and actual start times for the
3579  * transaction. The measured lag may be caused by thread/client load,
3580  * the database load, or the Poisson throttling process.
3581  */
3582  printf("rate limit schedule lag: avg %.3f (max %.3f) ms\n",
3583  0.001 * total->lag.sum / total->cnt, 0.001 * total->lag.max);
3584  }
3585 
3586  printf("tps = %f (including connections establishing)\n", tps_include);
3587  printf("tps = %f (excluding connections establishing)\n", tps_exclude);
3588 
3589  /* Report per-script/command statistics */
3591  {
3592  int i;
3593 
3594  for (i = 0; i < num_scripts; i++)
3595  {
3596  if (num_scripts > 1)
3597  printf("SQL script %d: %s\n"
3598  " - weight: %d (targets %.1f%% of total)\n"
3599  " - " INT64_FORMAT " transactions (%.1f%% of total, tps = %f)\n",
3600  i + 1, sql_script[i].desc,
3601  sql_script[i].weight,
3602  100.0 * sql_script[i].weight / total_weight,
3603  sql_script[i].stats.cnt,
3604  100.0 * sql_script[i].stats.cnt / total->cnt,
3605  sql_script[i].stats.cnt / time_include);
3606  else
3607  printf("script statistics:\n");
3608 
3609  if (latency_limit)
3610  printf(" - number of transactions skipped: " INT64_FORMAT " (%.3f%%)\n",
3611  sql_script[i].stats.skipped,
3612  100.0 * sql_script[i].stats.skipped / sql_script[i].stats.cnt);
3613 
3614  if (num_scripts > 1)
3615  printSimpleStats(" - latency", &sql_script[i].stats.latency);
3616 
3617  /* Report per-command latencies */
3618  if (is_latencies)
3619  {
3620  Command **commands;
3621 
3622  printf(" - statement latencies in milliseconds:\n");
3623 
3624  for (commands = sql_script[i].commands;
3625  *commands != NULL;
3626  commands++)
3627  printf(" %11.3f %s\n",
3628  1000.0 * (*commands)->stats.sum /
3629  (*commands)->stats.count,
3630  (*commands)->line);
3631  }
3632  }
3633  }
3634 }
static int num_scripts
Definition: pgbench.c:396
int nclients
Definition: pgbench.c:174
SimpleStats lag
Definition: pgbench.c:236
StatsData stats
Definition: pgbench.c:392
double sum
Definition: pgbench.c:221
int scale
Definition: pgbench.c:106
SimpleStats latency
Definition: pgbench.c:235
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:196
bool per_script_stats
Definition: pgbench.c:171
int duration
Definition: pgbench.c:99
static const char * QUERYMODE[]
Definition: pgbench.c:374
int64 cnt
Definition: pgbench.c:232
static void printSimpleStats(char *prefix, SimpleStats *ss)
Definition: pgbench.c:3507
int nxacts
Definition: pgbench.c:98
int nthreads
Definition: pgbench.c:175
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:395
int64 skipped
Definition: pgbench.c:233
static int64 total_weight
Definition: pgbench.c:398
int progress
Definition: pgbench.c:172
double max
Definition: pgbench.c:220
static QueryMode querymode
Definition: pgbench.c:373
int64 latency_limit
Definition: pgbench.c:141
#define INT64_FORMAT
Definition: c.h:300
int64 throttle_delay
Definition: pgbench.c:133
int i
bool is_latencies
Definition: pgbench.c:177
static void printSimpleStats ( char *  prefix,
SimpleStats ss 
)
static

Definition at line 3507 of file pgbench.c.

References SimpleStats::count, SimpleStats::sum, and SimpleStats::sum2.

Referenced by printResults().

3508 {
3509  /* print NaN if no transactions where executed */
3510  double latency = ss->sum / ss->count;
3511  double stddev = sqrt(ss->sum2 / ss->count - latency * latency);
3512 
3513  printf("%s average = %.3f ms\n", prefix, 0.001 * latency);
3514  printf("%s stddev = %.3f ms\n", prefix, 0.001 * stddev);
3515 }
double sum
Definition: pgbench.c:221
int64 count
Definition: pgbench.c:218
double sum2
Definition: pgbench.c:222
static Command* process_backslash_command ( PsqlScanState  sstate,
const char *  source 
)
static

Definition at line 3062 of file pgbench.c.

References Command::argc, Command::argv, Command::command_num, PQExpBufferData::data, Command::expr, expr_lex_one_word(), expr_parse_result, expr_scanner_finish(), expr_scanner_get_lineno(), expr_scanner_get_substring(), expr_scanner_init(), expr_scanner_offset(), expr_yyparse(), initPQExpBuffer(), initSimpleStats(), Command::line, MAX_ARGS, META_COMMAND, pg_malloc0(), pg_strcasecmp(), pg_strdup(), Command::stats, syntax_error(), termPQExpBuffer(), Command::type, and yyscanner.

Referenced by ParseScript().

3063 {
3064  Command *my_command;
3065  PQExpBufferData word_buf;
3066  int word_offset;
3067  int offsets[MAX_ARGS]; /* offsets of argument words */
3068  int start_offset;
3069  int lineno;
3070  int j;
3071 
3072  initPQExpBuffer(&word_buf);
3073 
3074  /* Remember location of the backslash */
3075  start_offset = expr_scanner_offset(sstate) - 1;
3076  lineno = expr_scanner_get_lineno(sstate, start_offset);
3077 
3078  /* Collect first word of command */
3079  if (!expr_lex_one_word(sstate, &word_buf, &word_offset))
3080  {
3081  termPQExpBuffer(&word_buf);
3082  return NULL;
3083  }
3084 
3085  /* Allocate and initialize Command structure */
3086  my_command = (Command *) pg_malloc0(sizeof(Command));
3087  my_command->command_num = num_commands++;
3088  my_command->type = META_COMMAND;
3089  my_command->argc = 0;
3090  initSimpleStats(&my_command->stats);
3091 
3092  /* Save first word (command name) */
3093  j = 0;
3094  offsets[j] = word_offset;
3095  my_command->argv[j++] = pg_strdup(word_buf.data);
3096  my_command->argc++;
3097 
3098  if (pg_strcasecmp(my_command->argv[0], "set") == 0)
3099  {
3100  /* For \set, collect var name, then lex the expression. */
3102 
3103  if (!expr_lex_one_word(sstate, &word_buf, &word_offset))
3104  syntax_error(source, lineno, my_command->line, my_command->argv[0],
3105  "missing argument", NULL, -1);
3106 
3107  offsets[j] = word_offset;
3108  my_command->argv[j++] = pg_strdup(word_buf.data);
3109  my_command->argc++;
3110 
3111  yyscanner = expr_scanner_init(sstate, source, lineno, start_offset,
3112  my_command->argv[0]);
3113 
3114  if (expr_yyparse(yyscanner) != 0)
3115  {
3116  /* dead code: exit done from syntax_error called by yyerror */
3117  exit(1);
3118  }
3119 
3120  my_command->expr = expr_parse_result;
3121 
3122  /* Save line, trimming any trailing newline */
3123  my_command->line = expr_scanner_get_substring(sstate,
3124  start_offset,
3125  expr_scanner_offset(sstate),
3126  true);
3127 
3128  expr_scanner_finish(yyscanner);
3129 
3130  termPQExpBuffer(&word_buf);
3131 
3132  return my_command;
3133  }
3134 
3135  /* For all other commands, collect remaining words. */
3136  while (expr_lex_one_word(sstate, &word_buf, &word_offset))
3137  {
3138  if (j >= MAX_ARGS)
3139  syntax_error(source, lineno, my_command->line, my_command->argv[0],
3140  "too many arguments", NULL, -1);
3141 
3142  offsets[j] = word_offset;
3143  my_command->argv[j++] = pg_strdup(word_buf.data);
3144  my_command->argc++;
3145  }
3146 
3147  /* Save line, trimming any trailing newline */
3148  my_command->line = expr_scanner_get_substring(sstate,
3149  start_offset,
3150  expr_scanner_offset(sstate),
3151  true);
3152 
3153  if (pg_strcasecmp(my_command->argv[0], "sleep") == 0)
3154  {
3155  if (my_command->argc < 2)
3156  syntax_error(source, lineno, my_command->line, my_command->argv[0],
3157  "missing argument", NULL, -1);
3158 
3159  if (my_command->argc > 3)
3160  syntax_error(source, lineno, my_command->line, my_command->argv[0],
3161  "too many arguments", NULL,
3162  offsets[3] - start_offset);
3163 
3164  /*
3165  * Split argument into number and unit to allow "sleep 1ms" etc. We
3166  * don't have to terminate the number argument with null because it
3167  * will be parsed with atoi, which ignores trailing non-digit
3168  * characters.
3169  */
3170  if (my_command->argc == 2 && my_command->argv[1][0] != ':')
3171  {
3172  char *c = my_command->argv[1];
3173 
3174  while (isdigit((unsigned char) *c))
3175  c++;
3176  if (*c)
3177  {
3178  my_command->argv[2] = c;
3179  offsets[2] = offsets[1] + (c - my_command->argv[1]);
3180  my_command->argc = 3;
3181  }
3182  }
3183 
3184  if (my_command->argc == 3)
3185  {
3186  if (pg_strcasecmp(my_command->argv[2], "us") != 0 &&
3187  pg_strcasecmp(my_command->argv[2], "ms") != 0 &&
3188  pg_strcasecmp(my_command->argv[2], "s") != 0)
3189  syntax_error(source, lineno, my_command->line, my_command->argv[0],
3190  "unrecognized time unit, must be us, ms or s",
3191  my_command->argv[2], offsets[2] - start_offset);
3192  }
3193  }
3194  else if (pg_strcasecmp(my_command->argv[0], "setshell") == 0)
3195  {
3196  if (my_command->argc < 3)
3197  syntax_error(source, lineno, my_command->line, my_command->argv[0],
3198  "missing argument", NULL, -1);
3199  }
3200  else if (pg_strcasecmp(my_command->argv[0], "shell") == 0)
3201  {
3202  if (my_command->argc < 2)
3203  syntax_error(source, lineno, my_command->line, my_command->argv[0],
3204  "missing command", NULL, -1);
3205  }
3206  else
3207  {
3208  syntax_error(source, lineno, my_command->line, my_command->argv[0],
3209  "invalid command", NULL, -1);
3210  }
3211 
3212  termPQExpBuffer(&word_buf);
3213 
3214  return my_command;
3215 }
void expr_scanner_finish(yyscan_t yyscanner)
int type
Definition: pgbench.c:380
int command_num
Definition: pgbench.c:379
int expr_yyparse(yyscan_t yyscanner)
char * line
Definition: pgbench.c:378
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:128
yyscan_t expr_scanner_init(PsqlScanState state, const char *source, int lineno, int start_offset, const char *command)
void syntax_error(const char *source, int lineno, const char *line, const char *command, const char *msg, const char *more, int column)
Definition: pgbench.c:2964
PgBenchExpr * expr
Definition: pgbench.c:383
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
char * argv[MAX_ARGS]
Definition: pgbench.c:382
#define MAX_ARGS
Definition: pgbench.c:363
int expr_scanner_get_lineno(PsqlScanState state, int offset)
#define META_COMMAND
Definition: pgbench.c:362
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53
char * c
PgBenchExpr * expr_parse_result
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
int expr_scanner_offset(PsqlScanState state)
int argc
Definition: pgbench.c:381
SimpleStats stats
Definition: pgbench.c:384
void * yyscan_t
Definition: psqlscan_int.h:60
char * expr_scanner_get_substring(PsqlScanState state, int start_offset, int end_offset, bool chomp)
static core_yyscan_t yyscanner
Definition: pl_scanner.c:210
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:744
static int num_commands
Definition: pgbench.c:397
bool expr_lex_one_word(PsqlScanState state, PQExpBuffer word_buf, int *offset)
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:89
static void process_builtin ( const BuiltinScript bi,
int  weight 
)
static

Definition at line 3388 of file pgbench.c.

References BuiltinScript::desc, ParseScript(), and BuiltinScript::script.

Referenced by main().

3389 {
3390  ParseScript(bi->script, bi->desc, weight);
3391 }
static void ParseScript(const char *script, const char *desc, int weight)
Definition: pgbench.c:3222
const char * desc
Definition: pgbench.c:406
const char * script
Definition: pgbench.c:407
static void process_file ( const char *  filename,
int  weight 
)
static

Definition at line 3354 of file pgbench.c.

References buf, fd(), free, ParseScript(), read_file_contents(), and strerror().

Referenced by main(), and process_psqlrc_file().

3355 {
3356  FILE *fd;
3357  char *buf;
3358 
3359  /* Slurp the file contents into "buf" */
3360  if (strcmp(filename, "-") == 0)
3361  fd = stdin;
3362  else if ((fd = fopen(filename, "r")) == NULL)
3363  {
3364  fprintf(stderr, "could not open file \"%s\": %s\n",
3365  filename, strerror(errno));
3366  exit(1);
3367  }
3368 
3369  buf = read_file_contents(fd);
3370 
3371  if (ferror(fd))
3372  {
3373  fprintf(stderr, "could not read file \"%s\": %s\n",
3374  filename, strerror(errno));
3375  exit(1);
3376  }
3377 
3378  if (fd != stdin)
3379  fclose(fd);
3380 
3381  ParseScript(buf, filename, weight);
3382 
3383  free(buf);
3384 }
static void ParseScript(const char *script, const char *desc, int weight)
Definition: pgbench.c:3222
static int fd(const char *x, int i)
Definition: preproc-init.c:105
static char * buf
Definition: pg_test_fsync.c:67
#define free(a)
Definition: header.h:65
static char * read_file_contents(FILE *fd)
Definition: pgbench.c:3321
static char * filename
Definition: pg_dumpall.c:90
const char * strerror(int errnum)
Definition: strerror.c:19
static Command* process_sql_command ( PQExpBuffer  buf,
const char *  source 
)
static

Definition at line 2999 of file pgbench.c.

References Command::argc, Command::argv, Command::command_num, PQExpBufferData::data, initSimpleStats(), Command::line, pg_malloc(), pg_malloc0(), pg_strdup(), SQL_COMMAND, Command::stats, and Command::type.

Referenced by ParseScript().

3000 {
3001  Command *my_command;
3002  char *p;
3003  char *nlpos;
3004 
3005  /* Skip any leading whitespace, as well as "--" style comments */
3006  p = buf->data;
3007  for (;;)
3008  {
3009  if (isspace((unsigned char) *p))
3010  p++;
3011  else if (strncmp(p, "--", 2) == 0)
3012  {
3013  p = strchr(p, '\n');
3014  if (p == NULL)
3015  return NULL;
3016  p++;
3017  }
3018  else
3019  break;
3020  }
3021 
3022  /* If there's nothing but whitespace and comments, we're done */
3023  if (*p == '\0')
3024  return NULL;
3025 
3026  /* Allocate and initialize Command structure */
3027  my_command = (Command *) pg_malloc0(sizeof(Command));
3028  my_command->command_num = num_commands++;
3029  my_command->type = SQL_COMMAND;
3030  initSimpleStats(&my_command->stats);
3031 
3032  /*
3033  * Install query text as the sole argv string. If we are using a
3034  * non-simple query mode, we'll extract parameters from it later.
3035  */
3036  my_command->argv[0] = pg_strdup(p);
3037  my_command->argc = 1;
3038 
3039  /*
3040  * If SQL command is multi-line, we only want to save the first line as
3041  * the "line" label.
3042  */
3043  nlpos = strchr(p, '\n');
3044  if (nlpos)
3045  {
3046  my_command->line = pg_malloc(nlpos - p + 1);
3047  memcpy(my_command->line, p, nlpos - p);
3048  my_command->line[nlpos - p] = '\0';
3049  }
3050  else
3051  my_command->line = pg_strdup(p);
3052 
3053  return my_command;
3054 }
int type
Definition: pgbench.c:380
int command_num
Definition: pgbench.c:379
char * line
Definition: pgbench.c:378
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
char * argv[MAX_ARGS]
Definition: pgbench.c:382
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
int argc
Definition: pgbench.c:381
#define SQL_COMMAND
Definition: pgbench.c:361
SimpleStats stats
Definition: pgbench.c:384
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:744
static int num_commands
Definition: pgbench.c:397
static void processXactStats ( TState thread,
CState st,
instr_time now,
bool  skipped,
StatsData agg 
)
static

Definition at line 2547 of file pgbench.c.

References accumStats(), StatsData::cnt, CState::cnt, doLog(), INSTR_TIME_GET_MICROSEC, INSTR_TIME_IS_ZERO, INSTR_TIME_SET_CURRENT, TState::latency_late, latency_limit, per_script_stats, TState::stats, ParsedScript::stats, CState::txn_begin, CState::txn_scheduled, and CState::use_file.

Referenced by doCustom().

2549 {
2550  double latency = 0.0,
2551  lag = 0.0;
2552  bool thread_details = progress || throttle_delay || latency_limit,
2553  detailed = thread_details || use_log || per_script_stats;
2554 
2555  if (detailed && !skipped)
2556  {
2557  if (INSTR_TIME_IS_ZERO(*now))
2559 
2560  /* compute latency & lag */
2561  latency = INSTR_TIME_GET_MICROSEC(*now) - st->txn_scheduled;
2563  }
2564 
2565  if (thread_details)
2566  {
2567  /* keep detailed thread stats */
2568  accumStats(&thread->stats, skipped, latency, lag);
2569 
2570  /* count transactions over the latency limit, if needed */
2571  if (latency_limit && latency > latency_limit)
2572  thread->latency_late++;
2573  }
2574  else
2575  {
2576  /* no detailed stats, just count */
2577  thread->stats.cnt++;
2578  }
2579 
2580  /* client stat is just counting */
2581  st->cnt++;
2582 
2583  if (use_log)
2584  doLog(thread, st, agg, skipped, latency, lag);
2585 
2586  /* XXX could use a mutex here, but we choose not to */
2587  if (per_script_stats)
2588  accumStats(&sql_script[st->use_file].stats, skipped, latency, lag);
2589 }
int64 latency_late
Definition: pgbench.c:353
StatsData stats
Definition: pgbench.c:392
bool use_log
Definition: pgbench.c:167
bool per_script_stats
Definition: pgbench.c:171
#define INSTR_TIME_IS_ZERO(t)
Definition: instr_time.h:149
int64 cnt
Definition: pgbench.c:232
int64 cnt
Definition: pgbench.c:332
int64 txn_scheduled
Definition: pgbench.c:324
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:395
int progress
Definition: pgbench.c:172
static void doLog(TState *thread, CState *st, StatsData *agg, bool skipped, double latency, double lag)
Definition: pgbench.c:2466
instr_time txn_begin
Definition: pgbench.c:326
static void accumStats(StatsData *stats, bool skipped, double lat, double lag)
Definition: pgbench.c:797
#define INSTR_TIME_GET_MICROSEC(t)
Definition: instr_time.h:202
int64 latency_limit
Definition: pgbench.c:141
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:153
int64 throttle_delay
Definition: pgbench.c:133
StatsData stats
Definition: pgbench.c:352
int use_file
Definition: pgbench.c:315
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1534
static bool putVariable ( CState st,
const char *  context,
char *  name,
const char *  value 
)
static

Definition at line 1109 of file pgbench.c.

References free, Variable::is_numeric, lookupCreateVariable(), pg_strdup(), val, and Variable::value.

Referenced by main().

1110 {
1111  Variable *var;
1112  char *val;
1113 
1114  var = lookupCreateVariable(st, context, name);
1115  if (!var)
1116  return false;
1117 
1118  /* dup then free, in case value is pointing at this variable */
1119  val = pg_strdup(value);
1120 
1121  if (var->value)
1122  free(var->value);
1123  var->value = val;
1124  var->is_numeric = false;
1125 
1126  return true;
1127 }
static struct @121 value
bool is_numeric
Definition: pgbench.c:203
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
char * value
Definition: pgbench.c:202
static Variable * lookupCreateVariable(CState *st, const char *context, char *name)
Definition: pgbench.c:1063
#define free(a)
Definition: header.h:65
const char * name
Definition: encode.c:521
long val
Definition: informix.c:689
static bool putVariableInt ( CState st,
const char *  context,
char *  name,
int64  value 
)
static

Definition at line 1153 of file pgbench.c.

References putVariableNumber(), setIntValue(), and val.

Referenced by main(), and runShellCommand().

1154 {
1155  PgBenchValue val;
1156 
1157  setIntValue(&val, value);
1158  return putVariableNumber(st, context, name, &val);
1159 }
static bool putVariableNumber(CState *st, const char *context, char *name, const PgBenchValue *value)
Definition: pgbench.c:1132
static struct @121 value
static void setIntValue(PgBenchValue *pv, int64 ival)
Definition: pgbench.c:1300
const char * name
Definition: encode.c:521
long val
Definition: informix.c:689
static bool putVariableNumber ( CState st,
const char *  context,
char *  name,
const PgBenchValue value 
)
static

Definition at line 1132 of file pgbench.c.

References free, Variable::is_numeric, lookupCreateVariable(), Variable::num_value, Variable::value, and value.

Referenced by doCustom(), main(), and putVariableInt().

1134 {
1135  Variable *var;
1136 
1137  var = lookupCreateVariable(st, context, name);
1138  if (!var)
1139  return false;
1140 
1141  if (var->value)
1142  free(var->value);
1143  var->value = NULL;
1144  var->is_numeric = true;
1145  var->num_value = *value;
1146 
1147  return true;
1148 }
static struct @121 value
bool is_numeric
Definition: pgbench.c:203
char * value
Definition: pgbench.c:202
static Variable * lookupCreateVariable(CState *st, const char *context, char *name)
Definition: pgbench.c:1063
#define free(a)
Definition: header.h:65
const char * name
Definition: encode.c:521
PgBenchValue num_value
Definition: pgbench.c:204
static char* read_file_contents ( FILE *  fd)
static

Definition at line 3321 of file pgbench.c.

References buf, pg_malloc(), and pg_realloc().

Referenced by process_file().

3322 {
3323  char *buf;
3324  size_t buflen = BUFSIZ;
3325  size_t used = 0;
3326 
3327  buf = (char *) pg_malloc(buflen);
3328 
3329  for (;;)
3330  {
3331  size_t nread;
3332 
3333  nread = fread(buf + used, 1, BUFSIZ, fd);
3334  used += nread;
3335  /* If fread() read less than requested, must be EOF or error */
3336  if (nread < BUFSIZ)
3337  break;
3338  /* Enlarge buf so we can read some more */
3339  buflen += BUFSIZ;
3340  buf = (char *) pg_realloc(buf, buflen);
3341  }
3342  /* There is surely room for a terminator */
3343  buf[used] = '\0';
3344 
3345  return buf;
3346 }
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
static int fd(const char *x, int i)
Definition: preproc-init.c:105
static char * buf
Definition: pg_test_fsync.c:67
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
static char* replaceVariable ( char **  sql,
char *  param,
int  len,
char *  value 
)
static

Definition at line 1193 of file pgbench.c.

References memmove, and pg_realloc().

Referenced by assignVariables(), and parseQuery().

1194 {
1195  int valueln = strlen(value);
1196 
1197  if (valueln > len)
1198  {
1199  size_t offset = param - *sql;
1200 
1201  *sql = pg_realloc(*sql, strlen(*sql) - len + valueln + 1);
1202  param = *sql + offset;
1203  }
1204 
1205  if (valueln != len)
1206  memmove(param + valueln, param + len, strlen(param + len) + 1);
1207  memcpy(param, value, valueln);
1208 
1209  return param + valueln;
1210 }
static struct @121 value
#define memmove(d, s, c)
Definition: c.h:1047
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
static bool runShellCommand ( CState st,
char *  variable,
char **  argv,
int  argc 
)
static

Definition at line 1729 of file pgbench.c.

References arg, getVariable(), i, putVariableInt(), and SHELL_COMMAND_SIZE.

Referenced by doCustom().

1730 {
1731  char command[SHELL_COMMAND_SIZE];
1732  int i,
1733  len = 0;
1734  FILE *fp;
1735  char res[64];
1736  char *endptr;
1737  int retval;
1738 
1739  /*----------
1740  * Join arguments with whitespace separators. Arguments starting with
1741  * exactly one colon are treated as variables:
1742  * name - append a string "name"
1743  * :var - append a variable named 'var'
1744  * ::name - append a string ":name"
1745  *----------
1746  */
1747  for (i = 0; i < argc; i++)
1748  {
1749  char *arg;
1750  int arglen;
1751 
1752  if (argv[i][0] != ':')
1753  {
1754  arg = argv[i]; /* a string literal */
1755  }
1756  else if (argv[i][1] == ':')
1757  {
1758  arg = argv[i] + 1; /* a string literal starting with colons */
1759  }
1760  else if ((arg = getVariable(st, argv[i] + 1)) == NULL)
1761  {
1762  fprintf(stderr, "%s: undefined variable \"%s\"\n",
1763  argv[0], argv[i]);
1764  return false;
1765  }
1766 
1767  arglen = strlen(arg);
1768  if (len + arglen + (i > 0 ? 1 : 0) >= SHELL_COMMAND_SIZE - 1)
1769  {
1770  fprintf(stderr, "%s: shell command is too long\n", argv[0]);
1771  return false;
1772  }
1773 
1774  if (i > 0)
1775  command[len++] = ' ';
1776  memcpy(command + len, arg, arglen);
1777  len += arglen;
1778  }
1779 
1780  command[len] = '\0';
1781 
1782  /* Fast path for non-assignment case */
1783  if (variable == NULL)
1784  {
1785  if (system(command))
1786  {
1787  if (!timer_exceeded)
1788  fprintf(stderr, "%s: could not launch shell command\n", argv[0]);
1789  return false;
1790  }
1791  return true;
1792  }
1793 
1794  /* Execute the command with pipe and read the standard output. */
1795  if ((fp = popen(command, "r")) == NULL)
1796  {
1797  fprintf(stderr, "%s: could not launch shell command\n", argv[0]);
1798  return false;
1799  }
1800  if (fgets(res, sizeof(res), fp) == NULL)
1801  {
1802  if (!timer_exceeded)
1803  fprintf(stderr, "%s: could not read result of shell command\n", argv[0]);
1804  (void) pclose(fp);
1805  return false;
1806  }
1807  if (pclose(fp) < 0)
1808  {
1809  fprintf(stderr, "%s: could not close shell command\n", argv[0]);
1810  return false;
1811  }
1812 
1813  /* Check whether the result is an integer and assign it to the variable */
1814  retval = (int) strtol(res, &endptr, 10);
1815  while (*endptr != '\0' && isspace((unsigned char) *endptr))
1816  endptr++;
1817  if (*res == '\0' || *endptr != '\0')
1818  {
1819  fprintf(stderr, "%s: shell command must return an integer (not \"%s\")\n",
1820  argv[0], res);
1821  return false;
1822  }
1823  if (!putVariableInt(st, "setshell", variable, retval))
1824  return false;
1825 
1826 #ifdef DEBUG
1827  printf("shell parameter name: \"%s\", value: \"%s\"\n", argv[1], res);
1828 #endif
1829  return true;
1830 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:966
#define SHELL_COMMAND_SIZE
Definition: pgbench.c:208
static bool putVariableInt(CState *st, const char *context, char *name, int64 value)
Definition: pgbench.c:1153
volatile bool timer_exceeded
Definition: pgbench.c:189
int i
void * arg
static bool sendCommand ( CState st,
Command command 
)
static

Definition at line 1868 of file pgbench.c.

References Command::argc, Command::argv, assignVariables(), CState::command, ParsedScript::commands, CState::con, CState::ecnt, free, getQueryParams(), CState::id, MAX_ARGS, MAX_PREPARE_NAME, name, pg_strdup(), PGRES_COMMAND_OK, PQclear(), PQerrorMessage(), PQprepare(), PQresultStatus(), PQsendQuery(), PQsendQueryParams(), PQsendQueryPrepared(), CState::prepared, preparedStatementName(), QUERY_EXTENDED, QUERY_PREPARED, QUERY_SIMPLE, SQL_COMMAND, and CState::use_file.

Referenced by doCustom().

1869 {
1870  int r;
1871 
1872  if (querymode == QUERY_SIMPLE)
1873  {
1874  char *sql;
1875 
1876  sql = pg_strdup(command->argv[0]);
1877  sql = assignVariables(st, sql);
1878 
1879  if (debug)
1880  fprintf(stderr, "client %d sending %s\n", st->id, sql);
1881  r = PQsendQuery(st->con, sql);
1882  free(sql);
1883  }
1884  else if (querymode == QUERY_EXTENDED)
1885  {
1886  const char *sql = command->argv[0];
1887  const char *params[MAX_ARGS];
1888 
1889  getQueryParams(st, command, params);
1890 
1891  if (debug)
1892  fprintf(stderr, "client %d sending %s\n", st->id, sql);
1893  r = PQsendQueryParams(st->con, sql, command->argc - 1,
1894  NULL, params, NULL, NULL, 0);
1895  }
1896  else if (querymode == QUERY_PREPARED)
1897  {
1898  char name[MAX_PREPARE_NAME];
1899  const char *params[MAX_ARGS];
1900 
1901  if (!st->prepared[st->use_file])
1902  {
1903  int j;
1904  Command **commands = sql_script[st->use_file].commands;
1905 
1906  for (j = 0; commands[j] != NULL; j++)
1907  {
1908  PGresult *res;
1909  char name[MAX_PREPARE_NAME];
1910 
1911  if (commands[j]->type != SQL_COMMAND)
1912  continue;
1913  preparedStatementName(name, st->use_file, j);
1914  res = PQprepare(st->con, name,
1915  commands[j]->argv[0], commands[j]->argc - 1, NULL);
1916  if (PQresultStatus(res) != PGRES_COMMAND_OK)
1917  fprintf(stderr, "%s", PQerrorMessage(st->con));
1918  PQclear(res);
1919  }
1920  st->prepared[st->use_file] = true;
1921  }
1922 
1923  getQueryParams(st, command, params);
1924  preparedStatementName(name, st->use_file, st->command);
1925 
1926  if (debug)
1927  fprintf(stderr, "client %d sending %s\n", st->id, name);
1928  r = PQsendQueryPrepared(st->con, name, command->argc - 1,
1929  params, NULL, NULL, 0);
1930  }
1931  else /* unknown sql mode */
1932  r = 0;
1933 
1934