PostgreSQL Source Code  git master
pgbench.c File Reference
#include "postgres_fe.h"
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <signal.h>
#include <time.h>
#include "common/int.h"
#include "common/logging.h"
#include "common/string.h"
#include "fe_utils/cancel.h"
#include "fe_utils/conditional.h"
#include "getopt_long.h"
#include "libpq-fe.h"
#include "pgbench.h"
#include "portability/instr_time.h"
Include dependency graph for pgbench.c:

Go to the source code of this file.

Data Structures

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

Macros

#define POLL_USING_SELECT
 
#define M_PI   3.14159265358979323846
 
#define ERRCODE_UNDEFINED_TABLE   "42P01"
 
#define FNV_PRIME   UINT64CONST(0x100000001b3)
 
#define FNV_OFFSET_BASIS   UINT64CONST(0xcbf29ce484222325)
 
#define MM2_MUL   UINT64CONST(0xc6a4a7935bd1e995)
 
#define MM2_MUL_TIMES_8   UINT64CONST(0x35253c9ade8f4ca8)
 
#define MM2_ROT   47
 
#define SOCKET_WAIT_METHOD   "select"
 
#define pthread_t   void *
 
#define DEFAULT_INIT_STEPS   "dtgvp" /* default -I setting */
 
#define ALL_INIT_STEPS   "dtgGvpf" /* all possible steps */
 
#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 MIN_ZIPFIAN_PARAM   1.001 /* minimum parameter for zipfian */
 
#define MAX_ZIPFIAN_PARAM   1000.0 /* maximum parameter for zipfian */
 
#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   256
 
#define PARAMS_ARRAY_SIZE   7
 
#define MAX_FARGS   16
 
#define MAX_PREPARE_NAME   32
 
#define COMMANDS_ALLOC_NUM   128
 

Typedefs

typedef struct socket_set socket_set
 
typedef struct SimpleStats SimpleStats
 
typedef struct StatsData StatsData
 
typedef struct RandomState RandomState
 
typedef enum MetaCommand MetaCommand
 
typedef enum QueryMode QueryMode
 
typedef struct Command Command
 
typedef struct ParsedScript ParsedScript
 
typedef struct BuiltinScript BuiltinScript
 

Enumerations

enum  partition_method_t { PART_NONE, PART_RANGE, PART_HASH }
 
enum  ConnectionStateEnum {
  CSTATE_CHOOSE_SCRIPT, CSTATE_START_TX, CSTATE_PREPARE_THROTTLE, CSTATE_THROTTLE,
  CSTATE_START_COMMAND, CSTATE_WAIT_RESULT, CSTATE_SLEEP, CSTATE_END_COMMAND,
  CSTATE_SKIP_COMMAND, CSTATE_END_TX, CSTATE_ABORTED, CSTATE_FINISHED
}
 
enum  MetaCommand {
  META_NONE, META_SET, META_SETSHELL, META_SHELL,
  META_SLEEP, META_GSET, META_ASET, META_IF,
  META_ELIF, META_ELSE, META_ENDIF
}
 
enum  QueryMode { QUERY_SIMPLE, QUERY_EXTENDED, QUERY_PREPARED, NUM_QUERYMODE }
 

Functions

static void setNullValue (PgBenchValue *pv)
 
static void setBoolValue (PgBenchValue *pv, bool bval)
 
static void setIntValue (PgBenchValue *pv, int64 ival)
 
static void setDoubleValue (PgBenchValue *pv, double dval)
 
static bool evaluateExpr (CState *st, PgBenchExpr *expr, PgBenchValue *retval)
 
static ConnectionStateEnum executeMetaCommand (CState *st, instr_time *now)
 
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 addScript (ParsedScript script)
 
static void * threadRun (void *arg)
 
static void finishCon (CState *st)
 
static void setalarm (int seconds)
 
static socket_setalloc_socket_set (int count)
 
static void free_socket_set (socket_set *sa)
 
static void clear_socket_set (socket_set *sa)
 
static void add_socket_to_set (socket_set *sa, int fd, int idx)
 
static int wait_on_socket_set (socket_set *sa, int64 usecs)
 
static bool socket_has_input (socket_set *sa, int fd, int idx)
 
static void usage (void)
 
static bool is_an_int (const char *str)
 
bool strtoint64 (const char *str, bool errorOK, int64 *result)
 
bool strtodouble (const char *str, bool errorOK, double *dv)
 
static void initRandomState (RandomState *random_state)
 
static int64 getrand (RandomState *random_state, int64 min, int64 max)
 
static int64 getExponentialRand (RandomState *random_state, int64 min, int64 max, double parameter)
 
static int64 getGaussianRand (RandomState *random_state, int64 min, int64 max, double parameter)
 
static int64 getPoissonRand (RandomState *random_state, double center)
 
static int64 computeIterativeZipfian (RandomState *random_state, int64 n, double s)
 
static int64 getZipfianRand (RandomState *random_state, int64 min, int64 max, double s)
 
static int64 getHashFnv1a (int64 val, uint64 seed)
 
static int64 getHashMurmur2 (int64 val, uint64 seed)
 
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 int compareVariableNames (const void *v1, const void *v2)
 
static VariablelookupVariable (CState *st, char *name)
 
static char * getVariable (CState *st, char *name)
 
static bool makeVariableValue (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 putVariableValue (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 char * valueTypeName (PgBenchValue *pval)
 
static bool coerceToBool (PgBenchValue *pval, bool *bval)
 
static bool valueTruth (PgBenchValue *pval)
 
static bool coerceToInt (PgBenchValue *pval, int64 *ival)
 
static bool coerceToDouble (PgBenchValue *pval, double *dval)
 
static bool isLazyFunc (PgBenchFunction func)
 
static bool evalLazyFunc (CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
 
static bool evalStandardFunc (CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
 
static bool evalFunc (CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
 
static MetaCommand getMetaCommand (const char *cmd)
 
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, const char *cmd, const char *message)
 
static int chooseScript (TState *thread)
 
static bool sendCommand (CState *st, Command *command)
 
static bool readCommandResponse (CState *st, MetaCommand meta, char *varprefix)
 
static bool evaluateSleep (CState *st, int argc, char **argv, int *usecs)
 
static void advanceConnectionState (TState *thread, CState *st, StatsData *agg)
 
static void disconnect_all (CState *state, int length)
 
static void initDropTables (PGconn *con)
 
static void createPartitions (PGconn *con)
 
static void initCreateTables (PGconn *con)
 
static void initTruncateTables (PGconn *con)
 
static void initGenerateDataClientSide (PGconn *con)
 
static void initGenerateDataServerSide (PGconn *con)
 
static void initVacuum (PGconn *con)
 
static void initCreatePKeys (PGconn *con)
 
static void initCreateFKeys (PGconn *con)
 
static void checkInitSteps (const char *initialize_steps)
 
static void runInitSteps (const char *initialize_steps)
 
static void GetTableInfo (PGconn *con, bool scale_given)
 
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 char * skip_sql_comments (char *sql_command)
 
static Commandcreate_sql_command (PQExpBuffer buf, const char *source)
 
static void free_command (Command *command)
 
static void postprocess_sql_command (Command *my_command)
 
static Commandprocess_backslash_command (PsqlScanState sstate, const char *source)
 
static void ConditionError (const char *desc, int cmdn, const char *msg)
 
static void CheckConditional (ParsedScript ps)
 
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 printProgressReport (TState *threads, int64 test_start, int64 now, StatsData *last, int64 *last_report)
 
static void printSimpleStats (const char *prefix, SimpleStats *ss)
 
static void printResults (StatsData *total, instr_time total_time, instr_time conn_total_time, int64 latency_late)
 
static bool set_random_seed (const char *seed)
 
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
 
bool unlogged_tables = false
 
double sample_rate = 0.0
 
double throttle_delay = 0
 
int64 latency_limit = 0
 
char * tablespace = NULL
 
char * index_tablespace = NULL
 
static int partitions = 0
 
static partition_method_t partition_method = PART_NONE
 
static const char * PARTITION_METHOD [] = {"none", "range", "hash"}
 
int64 random_seed = -1
 
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 report_per_command
 
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 RandomState base_random_sequence
 
static QueryMode querymode = QUERY_SIMPLE
 
static const char * QUERYMODE [] = {"simple", "extended", "prepared"}
 
static ParsedScript sql_script [MAX_SCRIPTS]
 
static int num_scripts
 
static int64 total_weight = 0
 
static const BuiltinScript builtin_script []
 
static const PsqlScanCallbacks pgbench_callbacks
 

Macro Definition Documentation

◆ ALL_INIT_STEPS

#define ALL_INIT_STEPS   "dtgGvpf" /* all possible steps */

Definition at line 136 of file pgbench.c.

Referenced by checkInitSteps(), and usage().

◆ COMMANDS_ALLOC_NUM

#define COMMANDS_ALLOC_NUM   128

Referenced by ParseScript().

◆ DEFAULT_INIT_STEPS

#define DEFAULT_INIT_STEPS   "dtgvp" /* default -I setting */

Definition at line 135 of file pgbench.c.

Referenced by main(), and usage().

◆ DEFAULT_NXACTS

#define DEFAULT_NXACTS   10 /* default nxacts */

Definition at line 139 of file pgbench.c.

Referenced by main().

◆ ERRCODE_UNDEFINED_TABLE

◆ FNV_OFFSET_BASIS

#define FNV_OFFSET_BASIS   UINT64CONST(0xcbf29ce484222325)

Definition at line 80 of file pgbench.c.

Referenced by getHashFnv1a().

◆ FNV_PRIME

#define FNV_PRIME   UINT64CONST(0x100000001b3)

Definition at line 79 of file pgbench.c.

Referenced by getHashFnv1a().

◆ INVALID_THREAD

#define INVALID_THREAD   ((pthread_t) 0)

Definition at line 462 of file pgbench.c.

Referenced by main().

◆ LOG_STEP_SECONDS

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

Definition at line 138 of file pgbench.c.

Referenced by initGenerateDataClientSide().

◆ M_PI

#define M_PI   3.14159265358979323846

Definition at line 71 of file pgbench.c.

Referenced by evalStandardFunc(), and getGaussianRand().

◆ MAX_ARGS

#define MAX_ARGS   256

Definition at line 474 of file pgbench.c.

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

◆ MAX_FARGS

#define MAX_FARGS   16

Definition at line 1860 of file pgbench.c.

Referenced by evalStandardFunc().

◆ MAX_PREPARE_NAME

#define MAX_PREPARE_NAME   32

Definition at line 2605 of file pgbench.c.

Referenced by sendCommand().

◆ MAX_SCRIPTS

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

Definition at line 271 of file pgbench.c.

Referenced by addScript().

◆ MAX_ZIPFIAN_PARAM

#define MAX_ZIPFIAN_PARAM   1000.0 /* maximum parameter for zipfian */

Definition at line 144 of file pgbench.c.

Referenced by evalStandardFunc(), and getZipfianRand().

◆ META_COMMAND

#define META_COMMAND   2

◆ MIN_GAUSSIAN_PARAM

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

Definition at line 141 of file pgbench.c.

Referenced by evalStandardFunc(), and getGaussianRand().

◆ MIN_ZIPFIAN_PARAM

#define MIN_ZIPFIAN_PARAM   1.001 /* minimum parameter for zipfian */

Definition at line 143 of file pgbench.c.

Referenced by evalStandardFunc(), and getZipfianRand().

◆ MM2_MUL

#define MM2_MUL   UINT64CONST(0xc6a4a7935bd1e995)

Definition at line 81 of file pgbench.c.

Referenced by getHashMurmur2().

◆ MM2_MUL_TIMES_8

#define MM2_MUL_TIMES_8   UINT64CONST(0x35253c9ade8f4ca8)

Definition at line 82 of file pgbench.c.

Referenced by getHashMurmur2().

◆ MM2_ROT

#define MM2_ROT   47

Definition at line 83 of file pgbench.c.

Referenced by getHashMurmur2().

◆ naccounts

#define naccounts   100000

◆ nbranches

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

Definition at line 216 of file pgbench.c.

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

◆ ntellers

#define ntellers   10

Definition at line 218 of file pgbench.c.

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

◆ PARAMS_ARRAY_SIZE

#define PARAMS_ARRAY_SIZE   7

Referenced by doConnect().

◆ POLL_USING_SELECT

#define POLL_USING_SELECT

Definition at line 54 of file pgbench.c.

◆ pthread_t

#define pthread_t   void *

Definition at line 128 of file pgbench.c.

Referenced by main(), and socket_has_input().

◆ SCALE_32BIT_THRESHOLD

#define SCALE_32BIT_THRESHOLD   20000

Definition at line 228 of file pgbench.c.

Referenced by initCreateTables().

◆ SHELL_COMMAND_SIZE

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

Definition at line 272 of file pgbench.c.

Referenced by runShellCommand().

◆ SOCKET_WAIT_METHOD

#define SOCKET_WAIT_METHOD   "select"

Definition at line 102 of file pgbench.c.

Referenced by threadRun().

◆ SQL_COMMAND

#define SQL_COMMAND   1

◆ WSEP

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

Definition at line 250 of file pgbench.c.

Referenced by parseScriptWeight().

Typedef Documentation

◆ BuiltinScript

typedef struct BuiltinScript BuiltinScript

◆ Command

typedef struct Command Command

◆ MetaCommand

typedef enum MetaCommand MetaCommand

◆ ParsedScript

typedef struct ParsedScript ParsedScript

◆ QueryMode

typedef enum QueryMode QueryMode

◆ RandomState

typedef struct RandomState RandomState

◆ SimpleStats

typedef struct SimpleStats SimpleStats

◆ socket_set

typedef struct socket_set socket_set

◆ StatsData

typedef struct StatsData StatsData

Enumeration Type Documentation

◆ ConnectionStateEnum

Enumerator
CSTATE_CHOOSE_SCRIPT 
CSTATE_START_TX 
CSTATE_PREPARE_THROTTLE 
CSTATE_THROTTLE 
CSTATE_START_COMMAND 
CSTATE_WAIT_RESULT 
CSTATE_SLEEP 
CSTATE_END_COMMAND 
CSTATE_SKIP_COMMAND 
CSTATE_END_TX 
CSTATE_ABORTED 
CSTATE_FINISHED 

Definition at line 317 of file pgbench.c.

318 {
319  /*
320  * The client must first choose a script to execute. Once chosen, it can
321  * either be throttled (state CSTATE_PREPARE_THROTTLE under --rate), start
322  * right away (state CSTATE_START_TX) or not start at all if the timer was
323  * exceeded (state CSTATE_FINISHED).
324  */
326 
327  /*
328  * CSTATE_START_TX performs start-of-transaction processing. Establishes
329  * a new connection for the transaction in --connect mode, records the
330  * transaction start time, and proceed to the first command.
331  *
332  * Note: once a script is started, it will either error or run till its
333  * end, where it may be interrupted. It is not interrupted while running,
334  * so pgbench --time is to be understood as tx are allowed to start in
335  * that time, and will finish when their work is completed.
336  */
338 
339  /*
340  * In CSTATE_PREPARE_THROTTLE state, we calculate when to begin the next
341  * transaction, and advance to CSTATE_THROTTLE. CSTATE_THROTTLE state
342  * sleeps until that moment, then advances to CSTATE_START_TX, or
343  * CSTATE_FINISHED if the next transaction would start beyond the end of
344  * the run.
345  */
348 
349  /*
350  * We loop through these states, to process each command in the script:
351  *
352  * CSTATE_START_COMMAND starts the execution of a command. On a SQL
353  * command, the command is sent to the server, and we move to
354  * CSTATE_WAIT_RESULT state. On a \sleep meta-command, the timer is set,
355  * and we enter the CSTATE_SLEEP state to wait for it to expire. Other
356  * meta-commands are executed immediately. If the command about to start
357  * is actually beyond the end of the script, advance to CSTATE_END_TX.
358  *
359  * CSTATE_WAIT_RESULT waits until we get a result set back from the server
360  * for the current command.
361  *
362  * CSTATE_SLEEP waits until the end of \sleep.
363  *
364  * CSTATE_END_COMMAND records the end-of-command timestamp, increments the
365  * command counter, and loops back to CSTATE_START_COMMAND state.
366  *
367  * CSTATE_SKIP_COMMAND is used by conditional branches which are not
368  * executed. It quickly skip commands that do not need any evaluation.
369  * This state can move forward several commands, till there is something
370  * to do or the end of the script.
371  */
374  CSTATE_SLEEP,
377 
378  /*
379  * CSTATE_END_TX performs end-of-transaction processing. It calculates
380  * latency, and logs the transaction. In --connect mode, it closes the
381  * current connection.
382  *
383  * Then either starts over in CSTATE_CHOOSE_SCRIPT, or enters
384  * CSTATE_FINISHED if we have no more work to do.
385  */
387 
388  /*
389  * Final states. CSTATE_ABORTED means that the script execution was
390  * aborted because a command failed, CSTATE_FINISHED means success.
391  */
ConnectionStateEnum
Definition: pgbench.c:317

◆ MetaCommand

Enumerator
META_NONE 
META_SET 
META_SETSHELL 
META_SHELL 
META_SLEEP 
META_GSET 
META_ASET 
META_IF 
META_ELIF 
META_ELSE 
META_ENDIF 

Definition at line 476 of file pgbench.c.

477 {
478  META_NONE, /* not a known meta-command */
479  META_SET, /* \set */
480  META_SETSHELL, /* \setshell */
481  META_SHELL, /* \shell */
482  META_SLEEP, /* \sleep */
483  META_GSET, /* \gset */
484  META_ASET, /* \aset */
485  META_IF, /* \if */
486  META_ELIF, /* \elif */
487  META_ELSE, /* \else */
488  META_ENDIF /* \endif */
489 } MetaCommand;
MetaCommand
Definition: pgbench.c:476

◆ partition_method_t

Enumerator
PART_NONE 
PART_RANGE 
PART_HASH 

Definition at line 199 of file pgbench.c.

200 {
201  PART_NONE, /* no partitioning */
202  PART_RANGE, /* range partitioning */
203  PART_HASH /* hash partitioning */
partition_method_t
Definition: pgbench.c:199

◆ QueryMode

enum QueryMode
Enumerator
QUERY_SIMPLE 
QUERY_EXTENDED 
QUERY_PREPARED 
NUM_QUERYMODE 

Definition at line 491 of file pgbench.c.

492 {
493  QUERY_SIMPLE, /* simple query */
494  QUERY_EXTENDED, /* extended query */
495  QUERY_PREPARED, /* extended query with prepared statements */
497 } QueryMode;
QueryMode
Definition: pgbench.c:491

Function Documentation

◆ accumStats()

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

Definition at line 1121 of file pgbench.c.

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

Referenced by doLog(), and processXactStats().

1122 {
1123  stats->cnt++;
1124 
1125  if (skipped)
1126  {
1127  /* no latency to record on skipped transactions */
1128  stats->skipped++;
1129  }
1130  else
1131  {
1132  addToSimpleStats(&stats->latency, lat);
1133 
1134  /* and possibly the same for schedule lag */
1135  if (throttle_delay)
1136  addToSimpleStats(&stats->lag, lag);
1137  }
1138 }
SimpleStats lag
Definition: pgbench.c:300
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:1077
SimpleStats latency
Definition: pgbench.c:299
double throttle_delay
Definition: pgbench.c:176
int64 cnt
Definition: pgbench.c:296
int64 skipped
Definition: pgbench.c:297

◆ add_socket_to_set()

static void add_socket_to_set ( socket_set sa,
int  fd,
int  idx 
)
static

Definition at line 6699 of file pgbench.c.

References fd(), socket_set::fds, socket_set::maxfd, and pg_log_fatal.

Referenced by setalarm(), and threadRun().

6700 {
6701  if (fd < 0 || fd >= FD_SETSIZE)
6702  {
6703  /*
6704  * Doing a hard exit here is a bit grotty, but it doesn't seem worth
6705  * complicating the API to make it less grotty.
6706  */
6707  pg_log_fatal("too many client connections for select()");
6708  exit(1);
6709  }
6710  FD_SET(fd, &sa->fds);
6711  if (fd > sa->maxfd)
6712  sa->maxfd = fd;
6713 }
static int fd(const char *x, int i)
Definition: preproc-init.c:105
fd_set fds
Definition: pgbench.c:107
int maxfd
Definition: pgbench.c:106
#define pg_log_fatal(...)
Definition: logging.h:76

◆ addScript()

static void addScript ( ParsedScript  script)
static

Definition at line 5063 of file pgbench.c.

References CheckConditional(), ParsedScript::commands, ParsedScript::desc, MAX_SCRIPTS, num_scripts, and pg_log_fatal.

Referenced by ParseScript().

5064 {
5065  if (script.commands == NULL || script.commands[0] == NULL)
5066  {
5067  pg_log_fatal("empty command list for script \"%s\"", script.desc);
5068  exit(1);
5069  }
5070 
5071  if (num_scripts >= MAX_SCRIPTS)
5072  {
5073  pg_log_fatal("at most %d SQL scripts are allowed", MAX_SCRIPTS);
5074  exit(1);
5075  }
5076 
5077  CheckConditional(script);
5078 
5079  sql_script[num_scripts] = script;
5080  num_scripts++;
5081 }
static int num_scripts
Definition: pgbench.c:544
#define MAX_SCRIPTS
Definition: pgbench.c:271
static void CheckConditional(ParsedScript ps)
Definition: pgbench.c:4713
const char * desc
Definition: pgbench.c:537
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:543
Command ** commands
Definition: pgbench.c:539
#define pg_log_fatal(...)
Definition: logging.h:76

◆ addToSimpleStats()

static void addToSimpleStats ( SimpleStats ss,
double  val 
)
static

Definition at line 1077 of file pgbench.c.

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

Referenced by accumStats(), and advanceConnectionState().

1078 {
1079  if (ss->count == 0 || val < ss->min)
1080  ss->min = val;
1081  if (ss->count == 0 || val > ss->max)
1082  ss->max = val;
1083  ss->count++;
1084  ss->sum += val;
1085  ss->sum2 += val * val;
1086 }
double sum
Definition: pgbench.c:285
int64 count
Definition: pgbench.c:282
double max
Definition: pgbench.c:284
double sum2
Definition: pgbench.c:286
long val
Definition: informix.c:664
double min
Definition: pgbench.c:283

◆ advanceConnectionState()

static void advanceConnectionState ( TState thread,
CState st,
StatsData agg 
)
static

Definition at line 2877 of file pgbench.c.

References addToSimpleStats(), Assert, chooseScript(), CState::cnt, CState::command, commandFailed(), ParsedScript::commands, CState::con, conditional_active(), conditional_stack_empty(), conditional_stack_peek(), conditional_stack_poke(), conditional_stack_pop(), conditional_stack_push(), TState::conn_time, CState::cstack, CSTATE_ABORTED, CSTATE_CHOOSE_SCRIPT, CSTATE_END_COMMAND, CSTATE_END_TX, CSTATE_FINISHED, CSTATE_PREPARE_THROTTLE, CSTATE_SKIP_COMMAND, CSTATE_SLEEP, CSTATE_START_COMMAND, CSTATE_START_TX, CSTATE_THROTTLE, CSTATE_WAIT_RESULT, ParsedScript::desc, doConnect(), executeMetaCommand(), finishCon(), getPoissonRand(), CState::id, IFSTATE_ELSE_FALSE, IFSTATE_ELSE_TRUE, IFSTATE_FALSE, IFSTATE_IGNORED, IFSTATE_NONE, IFSTATE_TRUE, INSTR_TIME_ACCUM_DIFF, INSTR_TIME_GET_DOUBLE, INSTR_TIME_GET_MICROSEC, INSTR_TIME_SET_CURRENT, INSTR_TIME_SET_CURRENT_LAZY, INSTR_TIME_SET_ZERO, Command::meta, META_COMMAND, META_ELIF, META_ELSE, META_ENDIF, META_IF, now(), pg_log_debug, pg_log_error, PQconsumeInput(), PQisBusy(), CState::prepared, processXactStats(), readCommandResponse(), sendCommand(), CState::sleep_until, SQL_COMMAND, CState::state, Command::stats, CState::stmt_begin, TState::throttle_trigger, TState::ts_throttle_rs, CState::txn_begin, CState::txn_scheduled, Command::type, CState::use_file, and Command::varprefix.

Referenced by threadRun().

2878 {
2879  instr_time now;
2880 
2881  /*
2882  * gettimeofday() isn't free, so we get the current timestamp lazily the
2883  * first time it's needed, and reuse the same value throughout this
2884  * function after that. This also ensures that e.g. the calculated
2885  * latency reported in the log file and in the totals are the same. Zero
2886  * means "not set yet". Reset "now" when we execute shell commands or
2887  * expressions, which might take a non-negligible amount of time, though.
2888  */
2889  INSTR_TIME_SET_ZERO(now);
2890 
2891  /*
2892  * Loop in the state machine, until we have to wait for a result from the
2893  * server or have to sleep for throttling or \sleep.
2894  *
2895  * Note: In the switch-statement below, 'break' will loop back here,
2896  * meaning "continue in the state machine". Return is used to return to
2897  * the caller, giving the thread the opportunity to advance another
2898  * client.
2899  */
2900  for (;;)
2901  {
2902  Command *command;
2903 
2904  switch (st->state)
2905  {
2906  /* Select transaction (script) to run. */
2907  case CSTATE_CHOOSE_SCRIPT:
2908  st->use_file = chooseScript(thread);
2910 
2911  pg_log_debug("client %d executing script \"%s\"",
2912  st->id, sql_script[st->use_file].desc);
2913 
2914  /*
2915  * If time is over, we're done; otherwise, get ready to start
2916  * a new transaction, or to get throttled if that's requested.
2917  */
2920  break;
2921 
2922  /* Start new transaction (script) */
2923  case CSTATE_START_TX:
2924 
2925  /* establish connection if needed, i.e. under --connect */
2926  if (st->con == NULL)
2927  {
2928  instr_time start;
2929 
2931  start = now;
2932  if ((st->con = doConnect()) == NULL)
2933  {
2934  pg_log_error("client %d aborted while establishing connection", st->id);
2935  st->state = CSTATE_ABORTED;
2936  break;
2937  }
2939  INSTR_TIME_ACCUM_DIFF(thread->conn_time, now, start);
2940 
2941  /* Reset session-local state */
2942  memset(st->prepared, 0, sizeof(st->prepared));
2943  }
2944 
2945  /* record transaction start time */
2947  st->txn_begin = now;
2948 
2949  /*
2950  * When not throttling, this is also the transaction's
2951  * scheduled start time.
2952  */
2953  if (!throttle_delay)
2955 
2956  /* Begin with the first command */
2958  st->command = 0;
2959  break;
2960 
2961  /*
2962  * Handle throttling once per transaction by sleeping.
2963  */
2965 
2966  /*
2967  * Generate a delay such that the series of delays will
2968  * approximate a Poisson distribution centered on the
2969  * throttle_delay time.
2970  *
2971  * If transactions are too slow or a given wait is shorter
2972  * than a transaction, the next transaction will start right
2973  * away.
2974  */
2975  Assert(throttle_delay > 0);
2976 
2977  thread->throttle_trigger +=
2979  st->txn_scheduled = thread->throttle_trigger;
2980 
2981  /*
2982  * If --latency-limit is used, and this slot is already late
2983  * so that the transaction will miss the latency limit even if
2984  * it completed immediately, skip this time slot and schedule
2985  * to continue running on the next slot that isn't late yet.
2986  * But don't iterate beyond the -t limit, if one is given.
2987  */
2988  if (latency_limit)
2989  {
2990  int64 now_us;
2991 
2993  now_us = INSTR_TIME_GET_MICROSEC(now);
2994 
2995  while (thread->throttle_trigger < now_us - latency_limit &&
2996  (nxacts <= 0 || st->cnt < nxacts))
2997  {
2998  processXactStats(thread, st, &now, true, agg);
2999  /* next rendez-vous */
3000  thread->throttle_trigger +=
3002  st->txn_scheduled = thread->throttle_trigger;
3003  }
3004 
3005  /*
3006  * stop client if -t was exceeded in the previous skip
3007  * loop
3008  */
3009  if (nxacts > 0 && st->cnt >= nxacts)
3010  {
3011  st->state = CSTATE_FINISHED;
3012  break;
3013  }
3014  }
3015 
3016  /*
3017  * stop client if next transaction is beyond pgbench end of
3018  * execution; otherwise, throttle it.
3019  */
3020  st->state = end_time > 0 && st->txn_scheduled > end_time ?
3022  break;
3023 
3024  /*
3025  * Wait until it's time to start next transaction.
3026  */
3027  case CSTATE_THROTTLE:
3029 
3030  if (INSTR_TIME_GET_MICROSEC(now) < st->txn_scheduled)
3031  return; /* still sleeping, nothing to do here */
3032 
3033  /* done sleeping, but don't start transaction if we're done */
3035  break;
3036 
3037  /*
3038  * Send a command to server (or execute a meta-command)
3039  */
3040  case CSTATE_START_COMMAND:
3041  command = sql_script[st->use_file].commands[st->command];
3042 
3043  /* Transition to script end processing if done */
3044  if (command == NULL)
3045  {
3046  st->state = CSTATE_END_TX;
3047  break;
3048  }
3049 
3050  /* record begin time of next command, and initiate it */
3051  if (report_per_command)
3052  {
3054  st->stmt_begin = now;
3055  }
3056 
3057  /* Execute the command */
3058  if (command->type == SQL_COMMAND)
3059  {
3060  if (!sendCommand(st, command))
3061  {
3062  commandFailed(st, "SQL", "SQL command send failed");
3063  st->state = CSTATE_ABORTED;
3064  }
3065  else
3066  st->state = CSTATE_WAIT_RESULT;
3067  }
3068  else if (command->type == META_COMMAND)
3069  {
3070  /*-----
3071  * Possible state changes when executing meta commands:
3072  * - on errors CSTATE_ABORTED
3073  * - on sleep CSTATE_SLEEP
3074  * - else CSTATE_END_COMMAND
3075  */
3076  st->state = executeMetaCommand(st, &now);
3077  }
3078 
3079  /*
3080  * We're now waiting for an SQL command to complete, or
3081  * finished processing a metacommand, or need to sleep, or
3082  * something bad happened.
3083  */
3084  Assert(st->state == CSTATE_WAIT_RESULT ||
3085  st->state == CSTATE_END_COMMAND ||
3086  st->state == CSTATE_SLEEP ||
3087  st->state == CSTATE_ABORTED);
3088  break;
3089 
3090  /*
3091  * non executed conditional branch
3092  */
3093  case CSTATE_SKIP_COMMAND:
3095  /* quickly skip commands until something to do... */
3096  while (true)
3097  {
3098  Command *command;
3099 
3100  command = sql_script[st->use_file].commands[st->command];
3101 
3102  /* cannot reach end of script in that state */
3103  Assert(command != NULL);
3104 
3105  /*
3106  * if this is conditional related, update conditional
3107  * state
3108  */
3109  if (command->type == META_COMMAND &&
3110  (command->meta == META_IF ||
3111  command->meta == META_ELIF ||
3112  command->meta == META_ELSE ||
3113  command->meta == META_ENDIF))
3114  {
3115  switch (conditional_stack_peek(st->cstack))
3116  {
3117  case IFSTATE_FALSE:
3118  if (command->meta == META_IF ||
3119  command->meta == META_ELIF)
3120  {
3121  /* we must evaluate the condition */
3123  }
3124  else if (command->meta == META_ELSE)
3125  {
3126  /* we must execute next command */
3130  st->command++;
3131  }
3132  else if (command->meta == META_ENDIF)
3133  {
3136  if (conditional_active(st->cstack))
3138 
3139  /*
3140  * else state remains in
3141  * CSTATE_SKIP_COMMAND
3142  */
3143  st->command++;
3144  }
3145  break;
3146 
3147  case IFSTATE_IGNORED:
3148  case IFSTATE_ELSE_FALSE:
3149  if (command->meta == META_IF)
3151  IFSTATE_IGNORED);
3152  else if (command->meta == META_ENDIF)
3153  {
3156  if (conditional_active(st->cstack))
3158  }
3159  /* could detect "else" & "elif" after "else" */
3160  st->command++;
3161  break;
3162 
3163  case IFSTATE_NONE:
3164  case IFSTATE_TRUE:
3165  case IFSTATE_ELSE_TRUE:
3166  default:
3167 
3168  /*
3169  * inconsistent if inactive, unreachable dead
3170  * code
3171  */
3172  Assert(false);
3173  }
3174  }
3175  else
3176  {
3177  /* skip and consider next */
3178  st->command++;
3179  }
3180 
3181  if (st->state != CSTATE_SKIP_COMMAND)
3182  /* out of quick skip command loop */
3183  break;
3184  }
3185  break;
3186 
3187  /*
3188  * Wait for the current SQL command to complete
3189  */
3190  case CSTATE_WAIT_RESULT:
3191  pg_log_debug("client %d receiving", st->id);
3192  if (!PQconsumeInput(st->con))
3193  {
3194  /* there's something wrong */
3195  commandFailed(st, "SQL", "perhaps the backend died while processing");
3196  st->state = CSTATE_ABORTED;
3197  break;
3198  }
3199  if (PQisBusy(st->con))
3200  return; /* don't have the whole result yet */
3201 
3202  /* store or discard the query results */
3203  if (readCommandResponse(st,
3206  st->state = CSTATE_END_COMMAND;
3207  else
3208  st->state = CSTATE_ABORTED;
3209  break;
3210 
3211  /*
3212  * Wait until sleep is done. This state is entered after a
3213  * \sleep metacommand. The behavior is similar to
3214  * CSTATE_THROTTLE, but proceeds to CSTATE_START_COMMAND
3215  * instead of CSTATE_START_TX.
3216  */
3217  case CSTATE_SLEEP:
3219  if (INSTR_TIME_GET_MICROSEC(now) < st->sleep_until)
3220  return; /* still sleeping, nothing to do here */
3221  /* Else done sleeping. */
3222  st->state = CSTATE_END_COMMAND;
3223  break;
3224 
3225  /*
3226  * End of command: record stats and proceed to next command.
3227  */
3228  case CSTATE_END_COMMAND:
3229 
3230  /*
3231  * command completed: accumulate per-command execution times
3232  * in thread-local data structure, if per-command latencies
3233  * are requested.
3234  */
3235  if (report_per_command)
3236  {
3237  Command *command;
3238 
3240 
3241  command = sql_script[st->use_file].commands[st->command];
3242  /* XXX could use a mutex here, but we choose not to */
3243  addToSimpleStats(&command->stats,
3244  INSTR_TIME_GET_DOUBLE(now) -
3246  }
3247 
3248  /* Go ahead with next command, to be executed or skipped */
3249  st->command++;
3250  st->state = conditional_active(st->cstack) ?
3252  break;
3253 
3254  /*
3255  * End of transaction (end of script, really).
3256  */
3257  case CSTATE_END_TX:
3258 
3259  /* transaction finished: calculate latency and do log */
3260  processXactStats(thread, st, &now, false, agg);
3261 
3262  /*
3263  * missing \endif... cannot happen if CheckConditional was
3264  * okay
3265  */
3267 
3268  if (is_connect)
3269  {
3270  finishCon(st);
3271  INSTR_TIME_SET_ZERO(now);
3272  }
3273 
3274  if ((st->cnt >= nxacts && duration <= 0) || timer_exceeded)
3275  {
3276  /* script completed */
3277  st->state = CSTATE_FINISHED;
3278  break;
3279  }
3280 
3281  /* next transaction (script) */
3283 
3284  /*
3285  * Ensure that we always return on this point, so as to avoid
3286  * an infinite loop if the script only contains meta commands.
3287  */
3288  return;
3289 
3290  /*
3291  * Final states. Close the connection if it's still open.
3292  */
3293  case CSTATE_ABORTED:
3294  case CSTATE_FINISHED:
3295  finishCon(st);
3296  return;
3297  }
3298  }
3299 }
int64 throttle_trigger
Definition: pgbench.c:452
bool conditional_active(ConditionalStack cstack)
Definition: conditional.c:128
int type
Definition: pgbench.c:526
int id
Definition: pgbench.c:402
static int chooseScript(TState *thread)
Definition: pgbench.c:2621
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:57
#define pg_log_error(...)
Definition: logging.h:80
void conditional_stack_push(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:41
static void commandFailed(CState *st, const char *cmd, const char *message)
Definition: pgbench.c:2613
struct timeval instr_time
Definition: instr_time.h:150
#define INSTR_TIME_ACCUM_DIFF(x, y, z)
Definition: instr_time.h:182
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:1077
#define INSTR_TIME_SET_ZERO(t)
Definition: instr_time.h:154
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:199
int duration
Definition: pgbench.c:147
ConditionalStack cstack
Definition: pgbench.c:404
static void finishCon(CState *st)
Definition: pgbench.c:6512
bool is_connect
Definition: pgbench.c:239
double throttle_delay
Definition: pgbench.c:176
int64 end_time
Definition: pgbench.c:148
instr_time stmt_begin
Definition: pgbench.c:424
static ConnectionStateEnum executeMetaCommand(CState *st, instr_time *now)
Definition: pgbench.c:3309
#define META_COMMAND
Definition: pgbench.c:468
#define pg_log_debug(...)
Definition: logging.h:92
int nxacts
Definition: pgbench.c:146
const char * desc
Definition: pgbench.c:537
int64 cnt
Definition: pgbench.c:429
static bool readCommandResponse(CState *st, MetaCommand meta, char *varprefix)
Definition: pgbench.c:2723
MetaCommand meta
Definition: pgbench.c:527
int64 txn_scheduled
Definition: pgbench.c:421
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:543
static bool sendCommand(CState *st, Command *command)
Definition: pgbench.c:2640
RandomState ts_throttle_rs
Definition: pgbench.c:449
instr_time txn_begin
Definition: pgbench.c:423
#define SQL_COMMAND
Definition: pgbench.c:467
int PQconsumeInput(PGconn *conn)
Definition: fe-exec.c:1704
int command
Definition: pgbench.c:413
SimpleStats stats
Definition: pgbench.c:532
ConnectionStateEnum state
Definition: pgbench.c:403
ifState conditional_stack_peek(ConditionalStack cstack)
Definition: conditional.c:94
int64 sleep_until
Definition: pgbench.c:422
PGconn * con
Definition: pgbench.c:401
#define INSTR_TIME_SET_CURRENT_LAZY(t)
Definition: instr_time.h:253
static PGconn * doConnect(void)
Definition: pgbench.c:1173
#define Assert(condition)
Definition: c.h:746
int PQisBusy(PGconn *conn)
Definition: fe-exec.c:1754
#define INSTR_TIME_GET_MICROSEC(t)
Definition: instr_time.h:205
bool conditional_stack_poke(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:106
char * varprefix
Definition: pgbench.c:530
volatile bool timer_exceeded
Definition: pgbench.c:252
Command ** commands
Definition: pgbench.c:539
int64 latency_limit
Definition: pgbench.c:184
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
bool report_per_command
Definition: pgbench.c:240
static int64 getPoissonRand(RandomState *random_state, double center)
Definition: pgbench.c:954
bool conditional_stack_empty(ConditionalStack cstack)
Definition: conditional.c:118
instr_time conn_time
Definition: pgbench.c:457
bool prepared[MAX_SCRIPTS]
Definition: pgbench.c:426
static void processXactStats(TState *thread, CState *st, instr_time *now, bool skipped, StatsData *agg)
Definition: pgbench.c:3550
int use_file
Definition: pgbench.c:412
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1542

◆ alloc_socket_set()

static socket_set * alloc_socket_set ( int  count)
static

Definition at line 6680 of file pgbench.c.

References pg_malloc0().

Referenced by setalarm(), and threadRun().

6681 {
6682  return (socket_set *) pg_malloc0(sizeof(socket_set));
6683 }
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53

◆ assignVariables()

static char* assignVariables ( CState st,
char *  sql 
)
static

Definition at line 1555 of file pgbench.c.

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

Referenced by sendCommand().

1556 {
1557  char *p,
1558  *name,
1559  *val;
1560 
1561  p = sql;
1562  while ((p = strchr(p, ':')) != NULL)
1563  {
1564  int eaten;
1565 
1566  name = parseVariable(p, &eaten);
1567  if (name == NULL)
1568  {
1569  while (*p == ':')
1570  {
1571  p++;
1572  }
1573  continue;
1574  }
1575 
1576  val = getVariable(st, name);
1577  free(name);
1578  if (val == NULL)
1579  {
1580  p++;
1581  continue;
1582  }
1583 
1584  p = replaceVariable(&sql, p, eaten, val);
1585  }
1586 
1587  return sql;
1588 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1274
static char * replaceVariable(char **sql, char *param, int len, char *value)
Definition: pgbench.c:1535
#define free(a)
Definition: header.h:65
static char * parseVariable(const char *sql, int *eaten)
Definition: pgbench.c:1512
const char * name
Definition: encode.c:561
long val
Definition: informix.c:664

◆ CheckConditional()

static void CheckConditional ( ParsedScript  ps)
static

Definition at line 4713 of file pgbench.c.

References ParsedScript::commands, conditional_stack_create(), conditional_stack_destroy(), conditional_stack_empty(), conditional_stack_peek(), conditional_stack_poke(), conditional_stack_pop(), conditional_stack_push(), ConditionError(), ParsedScript::desc, i, IFSTATE_ELSE_FALSE, IFSTATE_FALSE, Command::meta, META_COMMAND, META_ELIF, META_ELSE, META_ENDIF, META_IF, and Command::type.

Referenced by addScript().

4714 {
4715  /* statically check conditional structure */
4717  int i;
4718 
4719  for (i = 0; ps.commands[i] != NULL; i++)
4720  {
4721  Command *cmd = ps.commands[i];
4722 
4723  if (cmd->type == META_COMMAND)
4724  {
4725  switch (cmd->meta)
4726  {
4727  case META_IF:
4729  break;
4730  case META_ELIF:
4731  if (conditional_stack_empty(cs))
4732  ConditionError(ps.desc, i + 1, "\\elif without matching \\if");
4734  ConditionError(ps.desc, i + 1, "\\elif after \\else");
4735  break;
4736  case META_ELSE:
4737  if (conditional_stack_empty(cs))
4738  ConditionError(ps.desc, i + 1, "\\else without matching \\if");
4740  ConditionError(ps.desc, i + 1, "\\else after \\else");
4742  break;
4743  case META_ENDIF:
4744  if (!conditional_stack_pop(cs))
4745  ConditionError(ps.desc, i + 1, "\\endif without matching \\if");
4746  break;
4747  default:
4748  /* ignore anything else... */
4749  break;
4750  }
4751  }
4752  }
4753  if (!conditional_stack_empty(cs))
4754  ConditionError(ps.desc, i + 1, "\\if without matching \\endif");
4756 }
int type
Definition: pgbench.c:526
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:57
static void ConditionError(const char *desc, int cmdn, const char *msg)
Definition: pgbench.c:4702
void conditional_stack_push(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:41
#define META_COMMAND
Definition: pgbench.c:468
const char * desc
Definition: pgbench.c:537
MetaCommand meta
Definition: pgbench.c:527
ConditionalStack conditional_stack_create(void)
Definition: conditional.c:18
ifState conditional_stack_peek(ConditionalStack cstack)
Definition: conditional.c:94
bool conditional_stack_poke(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:106
Command ** commands
Definition: pgbench.c:539
void conditional_stack_destroy(ConditionalStack cstack)
Definition: conditional.c:30
bool conditional_stack_empty(ConditionalStack cstack)
Definition: conditional.c:118
int i

◆ checkInitSteps()

static void checkInitSteps ( const char *  initialize_steps)
static

Definition at line 4077 of file pgbench.c.

References ALL_INIT_STEPS, pg_log_fatal, and pg_log_info.

Referenced by main().

4078 {
4079  if (initialize_steps[0] == '\0')
4080  {
4081  pg_log_fatal("no initialization steps specified");
4082  exit(1);
4083  }
4084 
4085  for (const char *step = initialize_steps; *step != '\0'; step++)
4086  {
4087  if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
4088  {
4089  pg_log_fatal("unrecognized initialization step \"%c\"", *step);
4090  pg_log_info("Allowed step characters are: \"" ALL_INIT_STEPS "\".");
4091  exit(1);
4092  }
4093  }
4094 }
#define ALL_INIT_STEPS
Definition: pgbench.c:136
#define pg_log_info(...)
Definition: logging.h:88
#define pg_log_fatal(...)
Definition: logging.h:76

◆ chooseScript()

static int chooseScript ( TState thread)
static

Definition at line 2621 of file pgbench.c.

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

Referenced by advanceConnectionState().

2622 {
2623  int i = 0;
2624  int64 w;
2625 
2626  if (num_scripts == 1)
2627  return 0;
2628 
2629  w = getrand(&thread->ts_choose_rs, 0, total_weight - 1);
2630  do
2631  {
2632  w -= sql_script[i++].weight;
2633  } while (w >= 0);
2634 
2635  return i - 1;
2636 }
static int num_scripts
Definition: pgbench.c:544
static int64 getrand(RandomState *random_state, int64 min, int64 max)
Definition: pgbench.c:850
int weight
Definition: pgbench.c:538
RandomState ts_choose_rs
Definition: pgbench.c:448
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:543
static int64 total_weight
Definition: pgbench.c:545
int i

◆ clear_socket_set()

static void clear_socket_set ( socket_set sa)
static

Definition at line 6692 of file pgbench.c.

References socket_set::fds, and socket_set::maxfd.

Referenced by setalarm(), and threadRun().

6693 {
6694  FD_ZERO(&sa->fds);
6695  sa->maxfd = -1;
6696 }
fd_set fds
Definition: pgbench.c:107
int maxfd
Definition: pgbench.c:106

◆ coerceToBool()

static bool coerceToBool ( PgBenchValue pval,
bool bval 
)
static

Definition at line 1622 of file pgbench.c.

References PgBenchValue::bval, pg_log_error, PGBT_BOOLEAN, PgBenchValue::type, PgBenchValue::u, and valueTypeName().

Referenced by evalLazyFunc(), and evalStandardFunc().

1623 {
1624  if (pval->type == PGBT_BOOLEAN)
1625  {
1626  *bval = pval->u.bval;
1627  return true;
1628  }
1629  else /* NULL, INT or DOUBLE */
1630  {
1631  pg_log_error("cannot coerce %s to boolean", valueTypeName(pval));
1632  *bval = false; /* suppress uninitialized-variable warnings */
1633  return false;
1634  }
1635 }
#define pg_log_error(...)
Definition: logging.h:80
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1600
union PgBenchValue::@38 u
bool bval
Definition: pgbench.h:51
PgBenchValueType type
Definition: pgbench.h:46

◆ coerceToDouble()

static bool coerceToDouble ( PgBenchValue pval,
double *  dval 
)
static

Definition at line 1691 of file pgbench.c.

References PgBenchValue::dval, PgBenchValue::ival, pg_log_error, PGBT_DOUBLE, PGBT_INT, PgBenchValue::type, PgBenchValue::u, and valueTypeName().

Referenced by evalStandardFunc().

1692 {
1693  if (pval->type == PGBT_DOUBLE)
1694  {
1695  *dval = pval->u.dval;
1696  return true;
1697  }
1698  else if (pval->type == PGBT_INT)
1699  {
1700  *dval = (double) pval->u.ival;
1701  return true;
1702  }
1703  else /* BOOLEAN or NULL */
1704  {
1705  pg_log_error("cannot coerce %s to double", valueTypeName(pval));
1706  return false;
1707  }
1708 }
#define pg_log_error(...)
Definition: logging.h:80
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1600
union PgBenchValue::@38 u
double dval
Definition: pgbench.h:50
PgBenchValueType type
Definition: pgbench.h:46
int64 ival
Definition: pgbench.h:49

◆ coerceToInt()

static bool coerceToInt ( PgBenchValue pval,
int64 *  ival 
)
static

Definition at line 1663 of file pgbench.c.

References PgBenchValue::dval, FLOAT8_FITS_IN_INT64, PgBenchValue::ival, pg_log_error, PGBT_DOUBLE, PGBT_INT, PgBenchValue::type, PgBenchValue::u, and valueTypeName().

Referenced by evalStandardFunc().

1664 {
1665  if (pval->type == PGBT_INT)
1666  {
1667  *ival = pval->u.ival;
1668  return true;
1669  }
1670  else if (pval->type == PGBT_DOUBLE)
1671  {
1672  double dval = rint(pval->u.dval);
1673 
1674  if (isnan(dval) || !FLOAT8_FITS_IN_INT64(dval))
1675  {
1676  pg_log_error("double to int overflow for %f", dval);
1677  return false;
1678  }
1679  *ival = (int64) dval;
1680  return true;
1681  }
1682  else /* BOOLEAN or NULL */
1683  {
1684  pg_log_error("cannot coerce %s to int", valueTypeName(pval));
1685  return false;
1686  }
1687 }
#define pg_log_error(...)
Definition: logging.h:80
#define FLOAT8_FITS_IN_INT64(num)
Definition: c.h:1049
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1600
union PgBenchValue::@38 u
double dval
Definition: pgbench.h:50
PgBenchValueType type
Definition: pgbench.h:46
int64 ival
Definition: pgbench.h:49

◆ commandFailed()

static void commandFailed ( CState st,
const char *  cmd,
const char *  message 
)
static

Definition at line 2613 of file pgbench.c.

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

Referenced by advanceConnectionState(), and executeMetaCommand().

2614 {
2615  pg_log_error("client %d aborted in command %d (%s) of script %d; %s",
2616  st->id, st->command, cmd, st->use_file, message);
2617 }
int id
Definition: pgbench.c:402
#define pg_log_error(...)
Definition: logging.h:80
int command
Definition: pgbench.c:413
int use_file
Definition: pgbench.c:412

◆ compareVariableNames()

static int compareVariableNames ( const void *  v1,
const void *  v2 
)
static

Definition at line 1239 of file pgbench.c.

References name.

Referenced by lookupVariable().

1240 {
1241  return strcmp(((const Variable *) v1)->name,
1242  ((const Variable *) v2)->name);
1243 }
const char * name
Definition: encode.c:561

◆ computeIterativeZipfian()

static int64 computeIterativeZipfian ( RandomState random_state,
int64  n,
double  s 
)
static

Definition at line 976 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by getZipfianRand().

977 {
978  double b = pow(2.0, s - 1.0);
979  double x,
980  t,
981  u,
982  v;
983 
984  /* Ensure n is sane */
985  if (n <= 1)
986  return 1;
987 
988  while (true)
989  {
990  /* random variates */
991  u = pg_erand48(random_state->xseed);
992  v = pg_erand48(random_state->xseed);
993 
994  x = floor(pow(u, -1.0 / (s - 1.0)));
995 
996  t = pow(1.0 + 1.0 / x, s - 1.0);
997  /* reject if too large or out of bound */
998  if (v * x * (t - 1.0) / (b - 1.0) <= t / b && x <= n)
999  break;
1000  }
1001  return (int64) x;
1002 }
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
unsigned short xseed[3]
Definition: pgbench.c:308

◆ ConditionError()

static void ConditionError ( const char *  desc,
int  cmdn,
const char *  msg 
)
static

Definition at line 4702 of file pgbench.c.

References pg_log_fatal.

Referenced by CheckConditional().

4703 {
4704  pg_log_fatal("condition error in script \"%s\" command %d: %s",
4705  desc, cmdn, msg);
4706  exit(1);
4707 }
#define pg_log_fatal(...)
Definition: logging.h:76

◆ create_sql_command()

static Command* create_sql_command ( PQExpBuffer  buf,
const char *  source 
)
static

Definition at line 4437 of file pgbench.c.

References appendPQExpBufferStr(), Command::argc, Command::argv, PQExpBufferData::data, Command::expr, Command::first_line, initPQExpBuffer(), initSimpleStats(), Command::lines, Command::meta, META_NONE, pg_malloc(), skip_sql_comments(), SQL_COMMAND, Command::stats, Command::type, and Command::varprefix.

Referenced by ParseScript().

4438 {
4439  Command *my_command;
4440  char *p = skip_sql_comments(buf->data);
4441 
4442  if (p == NULL)
4443  return NULL;
4444 
4445  /* Allocate and initialize Command structure */
4446  my_command = (Command *) pg_malloc(sizeof(Command));
4447  initPQExpBuffer(&my_command->lines);
4448  appendPQExpBufferStr(&my_command->lines, p);
4449  my_command->first_line = NULL; /* this is set later */
4450  my_command->type = SQL_COMMAND;
4451  my_command->meta = META_NONE;
4452  my_command->argc = 0;
4453  memset(my_command->argv, 0, sizeof(my_command->argv));
4454  my_command->varprefix = NULL; /* allocated later, if needed */
4455  my_command->expr = NULL;
4456  initSimpleStats(&my_command->stats);
4457 
4458  return my_command;
4459 }
int type
Definition: pgbench.c:526
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
PgBenchExpr * expr
Definition: pgbench.c:531
static char * skip_sql_comments(char *sql_command)
Definition: pgbench.c:4402
char * argv[MAX_ARGS]
Definition: pgbench.c:529
MetaCommand meta
Definition: pgbench.c:527
PQExpBufferData lines
Definition: pgbench.c:524
int argc
Definition: pgbench.c:528
#define SQL_COMMAND
Definition: pgbench.c:467
SimpleStats stats
Definition: pgbench.c:532
char * varprefix
Definition: pgbench.c:530
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1068
char * first_line
Definition: pgbench.c:525
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ createPartitions()

static void createPartitions ( PGconn con)
static

Definition at line 3630 of file pgbench.c.

References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), Assert, PQExpBufferData::data, executeStatement(), fprintf, initPQExpBuffer(), INT64_FORMAT, naccounts, PART_HASH, PART_RANGE, partitions, printfPQExpBuffer(), and termPQExpBuffer().

Referenced by initCreateTables().

3631 {
3632  PQExpBufferData query;
3633 
3634  /* we must have to create some partitions */
3635  Assert(partitions > 0);
3636 
3637  fprintf(stderr, "creating %d partitions...\n", partitions);
3638 
3639  initPQExpBuffer(&query);
3640 
3641  for (int p = 1; p <= partitions; p++)
3642  {
3644  {
3645  int64 part_size = (naccounts * (int64) scale + partitions - 1) / partitions;
3646 
3647  printfPQExpBuffer(&query,
3648  "create%s table pgbench_accounts_%d\n"
3649  " partition of pgbench_accounts\n"
3650  " for values from (",
3651  unlogged_tables ? " unlogged" : "", p);
3652 
3653  /*
3654  * For RANGE, we use open-ended partitions at the beginning and
3655  * end to allow any valid value for the primary key. Although the
3656  * actual minimum and maximum values can be derived from the
3657  * scale, it is more generic and the performance is better.
3658  */
3659  if (p == 1)
3660  appendPQExpBufferStr(&query, "minvalue");
3661  else
3662  appendPQExpBuffer(&query, INT64_FORMAT, (p - 1) * part_size + 1);
3663 
3664  appendPQExpBufferStr(&query, ") to (");
3665 
3666  if (p < partitions)
3667  appendPQExpBuffer(&query, INT64_FORMAT, p * part_size + 1);
3668  else
3669  appendPQExpBufferStr(&query, "maxvalue");
3670 
3671  appendPQExpBufferChar(&query, ')');
3672  }
3673  else if (partition_method == PART_HASH)
3674  printfPQExpBuffer(&query,
3675  "create%s table pgbench_accounts_%d\n"
3676  " partition of pgbench_accounts\n"
3677  " for values with (modulus %d, remainder %d)",
3678  unlogged_tables ? " unlogged" : "", p,
3679  partitions, p - 1);
3680  else /* cannot get there */
3681  Assert(0);
3682 
3683  /*
3684  * Per ddlinfo in initCreateTables, fillfactor is needed on table
3685  * pgbench_accounts.
3686  */
3687  appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
3688 
3689  executeStatement(con, query.data);
3690  }
3691 
3692  termPQExpBuffer(&query);
3693 }
static int partitions
Definition: pgbench.c:196
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
static partition_method_t partition_method
Definition: pgbench.c:206
int scale
Definition: pgbench.c:154
#define fprintf
Definition: port.h:219
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142
int fillfactor
Definition: pgbench.c:160
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:380
#define naccounts
Definition: pgbench.c:219
#define Assert(condition)
Definition: c.h:746
#define INT64_FORMAT
Definition: c.h:417
bool unlogged_tables
Definition: pgbench.c:165
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ disconnect_all()

static void disconnect_all ( CState state,
int  length 
)
static

Definition at line 3596 of file pgbench.c.

References finishCon(), and i.

Referenced by main(), and threadRun().

3597 {
3598  int i;
3599 
3600  for (i = 0; i < length; i++)
3601  finishCon(&state[i]);
3602 }
static void finishCon(CState *st)
Definition: pgbench.c:6512
int i

◆ doConnect()

static PGconn* doConnect ( void  )
static

Definition at line 1173 of file pgbench.c.

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

Referenced by advanceConnectionState(), main(), runInitSteps(), and threadRun().

1174 {
1175  PGconn *conn;
1176  bool new_pass;
1177  static char *password = NULL;
1178 
1179  /*
1180  * Start the connection. Loop until we have a password if requested by
1181  * backend.
1182  */
1183  do
1184  {
1185 #define PARAMS_ARRAY_SIZE 7
1186 
1187  const char *keywords[PARAMS_ARRAY_SIZE];
1188  const char *values[PARAMS_ARRAY_SIZE];
1189 
1190  keywords[0] = "host";
1191  values[0] = pghost;
1192  keywords[1] = "port";
1193  values[1] = pgport;
1194  keywords[2] = "user";
1195  values[2] = login;
1196  keywords[3] = "password";
1197  values[3] = password;
1198  keywords[4] = "dbname";
1199  values[4] = dbName;
1200  keywords[5] = "fallback_application_name";
1201  values[5] = progname;
1202  keywords[6] = NULL;
1203  values[6] = NULL;
1204 
1205  new_pass = false;
1206 
1207  conn = PQconnectdbParams(keywords, values, true);
1208 
1209  if (!conn)
1210  {
1211  pg_log_error("connection to database \"%s\" failed", dbName);
1212  return NULL;
1213  }
1214 
1215  if (PQstatus(conn) == CONNECTION_BAD &&
1216  PQconnectionNeedsPassword(conn) &&
1217  !password)
1218  {
1219  PQfinish(conn);
1220  password = simple_prompt("Password: ", false);
1221  new_pass = true;
1222  }
1223  } while (new_pass);
1224 
1225  /* check to see that the backend connection was successfully made */
1226  if (PQstatus(conn) == CONNECTION_BAD)
1227  {
1228  pg_log_error("connection to database \"%s\" failed: %s",
1229  dbName, PQerrorMessage(conn));
1230  PQfinish(conn);
1231  return NULL;
1232  }
1233 
1234  return conn;
1235 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6669
#define pg_log_error(...)
Definition: logging.h:80
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4174
char * simple_prompt(const char *prompt, bool echo)
Definition: sprompt.c:38
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:647
PGconn * conn
Definition: streamutil.c:54
static char * password
Definition: streamutil.c:53
#define PARAMS_ARRAY_SIZE
char * pghost
Definition: pgbench.c:243
const char * progname
Definition: pgbench.c:248
static Datum values[MAXATTR]
Definition: bootstrap.c:165
int PQconnectionNeedsPassword(const PGconn *conn)
Definition: fe-connect.c:6703
char * dbName
Definition: pgbench.c:246
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:6616
char * pgport
Definition: pgbench.c:244
char * login
Definition: pgbench.c:245

◆ doLog()

static void doLog ( TState thread,
CState st,
StatsData agg,
bool  skipped,
double  latency,
double  lag 
)
static

Definition at line 3469 of file pgbench.c.

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

Referenced by processXactStats(), and threadRun().

3471 {
3472  FILE *logfile = thread->logfile;
3473 
3474  Assert(use_log);
3475 
3476  /*
3477  * Skip the log entry if sampling is enabled and this row doesn't belong
3478  * to the random sample.
3479  */
3480  if (sample_rate != 0.0 &&
3482  return;
3483 
3484  /* should we aggregate the results or not? */
3485  if (agg_interval > 0)
3486  {
3487  /*
3488  * Loop until we reach the interval of the current moment, and print
3489  * any empty intervals in between (this may happen with very low tps,
3490  * e.g. --rate=0.1).
3491  */
3492  time_t now = time(NULL);
3493 
3494  while (agg->start_time + agg_interval <= now)
3495  {
3496  /* print aggregated report to logfile */
3497  fprintf(logfile, "%ld " INT64_FORMAT " %.0f %.0f %.0f %.0f",
3498  (long) agg->start_time,
3499  agg->cnt,
3500  agg->latency.sum,
3501  agg->latency.sum2,
3502  agg->latency.min,
3503  agg->latency.max);
3504  if (throttle_delay)
3505  {
3506  fprintf(logfile, " %.0f %.0f %.0f %.0f",
3507  agg->lag.sum,
3508  agg->lag.sum2,
3509  agg->lag.min,
3510  agg->lag.max);
3511  if (latency_limit)
3512  fprintf(logfile, " " INT64_FORMAT, agg->skipped);
3513  }
3514  fputc('\n', logfile);
3515 
3516  /* reset data and move to next interval */
3517  initStats(agg, agg->start_time + agg_interval);
3518  }
3519 
3520  /* accumulate the current transaction */
3521  accumStats(agg, skipped, latency, lag);
3522  }
3523  else
3524  {
3525  /* no, print raw transactions */
3526  struct timeval tv;
3527 
3528  gettimeofday(&tv, NULL);
3529  if (skipped)
3530  fprintf(logfile, "%d " INT64_FORMAT " skipped %d %ld %ld",
3531  st->id, st->cnt, st->use_file,
3532  (long) tv.tv_sec, (long) tv.tv_usec);
3533  else
3534  fprintf(logfile, "%d " INT64_FORMAT " %.0f %d %ld %ld",
3535  st->id, st->cnt, latency, st->use_file,
3536  (long) tv.tv_sec, (long) tv.tv_usec);
3537  if (throttle_delay)
3538  fprintf(logfile, " %.0f", lag);
3539  fputc('\n', logfile);
3540  }
3541 }
time_t start_time
Definition: pgbench.c:295
int gettimeofday(struct timeval *tp, struct timezone *tzp)
Definition: gettimeofday.c:104
double sample_rate
Definition: pgbench.c:170
int id
Definition: pgbench.c:402
SimpleStats lag
Definition: pgbench.c:300
static void initStats(StatsData *sd, time_t start_time)
Definition: pgbench.c:1108
double sum
Definition: pgbench.c:285
RandomState ts_sample_rs
Definition: pgbench.c:450
bool use_log
Definition: pgbench.c:230
static FILE * logfile
Definition: pg_regress.c:102
SimpleStats latency
Definition: pgbench.c:299
#define fprintf
Definition: port.h:219
double throttle_delay
Definition: pgbench.c:176
FILE * logfile
Definition: pgbench.c:453
int64 cnt
Definition: pgbench.c:296
int64 cnt
Definition: pgbench.c:429
int64 skipped
Definition: pgbench.c:297
double max
Definition: pgbench.c:284
static void accumStats(StatsData *stats, bool skipped, double lat, double lag)
Definition: pgbench.c:1121
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
#define Assert(condition)
Definition: c.h:746
double sum2
Definition: pgbench.c:286
unsigned short xseed[3]
Definition: pgbench.c:308
int64 latency_limit
Definition: pgbench.c:184
#define INT64_FORMAT
Definition: c.h:417
int use_file
Definition: pgbench.c:412
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1542
double min
Definition: pgbench.c:283
int agg_interval
Definition: pgbench.c:232

◆ evalFunc()

static bool evalFunc ( CState st,
PgBenchFunction  func,
PgBenchExprLink args,
PgBenchValue retval 
)
static

Definition at line 2409 of file pgbench.c.

References evalLazyFunc(), evalStandardFunc(), and isLazyFunc().

Referenced by evaluateExpr().

2411 {
2412  if (isLazyFunc(func))
2413  return evalLazyFunc(st, func, args, retval);
2414  else
2415  return evalStandardFunc(st, func, args, retval);
2416 }
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1750
static bool evalStandardFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1867
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:1743

◆ evalLazyFunc()

static bool evalLazyFunc ( CState st,
PgBenchFunction  func,
PgBenchExprLink args,
PgBenchValue retval 
)
static

Definition at line 1750 of file pgbench.c.

References a1, a2, Assert, coerceToBool(), evaluateExpr(), PgBenchExprLink::expr, isLazyFunc(), PgBenchExprLink::next, PGBENCH_AND, PGBENCH_CASE, PGBENCH_OR, PGBT_NULL, setBoolValue(), setNullValue(), PgBenchValue::type, and valueTruth().

Referenced by evalFunc().

1752 {
1753  PgBenchValue a1,
1754  a2;
1755  bool ba1,
1756  ba2;
1757 
1758  Assert(isLazyFunc(func) && args != NULL && args->next != NULL);
1759 
1760  /* args points to first condition */
1761  if (!evaluateExpr(st, args->expr, &a1))
1762  return false;
1763 
1764  /* second condition for AND/OR and corresponding branch for CASE */
1765  args = args->next;
1766 
1767  switch (func)
1768  {
1769  case PGBENCH_AND:
1770  if (a1.type == PGBT_NULL)
1771  {
1772  setNullValue(retval);
1773  return true;
1774  }
1775 
1776  if (!coerceToBool(&a1, &ba1))
1777  return false;
1778 
1779  if (!ba1)
1780  {
1781  setBoolValue(retval, false);
1782  return true;
1783  }
1784 
1785  if (!evaluateExpr(st, args->expr, &a2))
1786  return false;
1787 
1788  if (a2.type == PGBT_NULL)
1789  {
1790  setNullValue(retval);
1791  return true;
1792  }
1793  else if (!coerceToBool(&a2, &ba2))
1794  return false;
1795  else
1796  {
1797  setBoolValue(retval, ba2);
1798  return true;
1799  }
1800 
1801  return true;
1802 
1803  case PGBENCH_OR:
1804 
1805  if (a1.type == PGBT_NULL)
1806  {
1807  setNullValue(retval);
1808  return true;
1809  }
1810 
1811  if (!coerceToBool(&a1, &ba1))
1812  return false;
1813 
1814  if (ba1)
1815  {
1816  setBoolValue(retval, true);
1817  return true;
1818  }
1819 
1820  if (!evaluateExpr(st, args->expr, &a2))
1821  return false;
1822 
1823  if (a2.type == PGBT_NULL)
1824  {
1825  setNullValue(retval);
1826  return true;
1827  }
1828  else if (!coerceToBool(&a2, &ba2))
1829  return false;
1830  else
1831  {
1832  setBoolValue(retval, ba2);
1833  return true;
1834  }
1835 
1836  case PGBENCH_CASE:
1837  /* when true, execute branch */
1838  if (valueTruth(&a1))
1839  return evaluateExpr(st, args->expr, retval);
1840 
1841  /* now args contains next condition or final else expression */
1842  args = args->next;
1843 
1844  /* final else case? */
1845  if (args->next == NULL)
1846  return evaluateExpr(st, args->expr, retval);
1847 
1848  /* no, another when, proceed */
1849  return evalLazyFunc(st, PGBENCH_CASE, args, retval);
1850 
1851  default:
1852  /* internal error, cannot get here */
1853  Assert(0);
1854  break;
1855  }
1856  return false;
1857 }
static bool coerceToBool(PgBenchValue *pval, bool *bval)
Definition: pgbench.c:1622
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1750
static const FormData_pg_attribute a2
Definition: heap.c:165
static bool evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
Definition: pgbench.c:2425
static void setBoolValue(PgBenchValue *pv, bool bval)
Definition: pgbench.c:1720
static void setNullValue(PgBenchValue *pv)
Definition: pgbench.c:1712
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:1743
#define Assert(condition)
Definition: c.h:746
static bool valueTruth(PgBenchValue *pval)
Definition: pgbench.c:1642
PgBenchValueType type
Definition: pgbench.h:46
static const FormData_pg_attribute a1
Definition: heap.c:151

◆ evalStandardFunc()

static bool evalStandardFunc ( CState st,
PgBenchFunction  func,
PgBenchExprLink args,
PgBenchValue retval 
)
static

Definition at line 1867 of file pgbench.c.

References generate_unaccent_rules::args, Assert, PgBenchValue::bval, coerceToBool(), coerceToDouble(), coerceToInt(), CState::command, CState::cs_func_rs, PgBenchValue::dval, evaluateExpr(), fprintf, getExponentialRand(), getGaussianRand(), getHashFnv1a(), getHashMurmur2(), getrand(), getZipfianRand(), i, INT64_FORMAT, PgBenchValue::ival, M_PI, Max, MAX_FARGS, MAX_ZIPFIAN_PARAM, Min, MIN_GAUSSIAN_PARAM, MIN_ZIPFIAN_PARAM, PgBenchExprLink::next, pg_add_s64_overflow(), PG_INT64_MIN, pg_log_error, pg_mul_s64_overflow(), pg_sub_s64_overflow(), PGBENCH_ABS, PGBENCH_ADD, PGBENCH_BITAND, PGBENCH_BITOR, PGBENCH_BITXOR, PGBENCH_DEBUG, PGBENCH_DIV, PGBENCH_DOUBLE, PGBENCH_EQ, PGBENCH_EXP, PGBENCH_GREATEST, PGBENCH_HASH_FNV1A, PGBENCH_HASH_MURMUR2, PGBENCH_INT, PGBENCH_IS, PGBENCH_LE, PGBENCH_LEAST, PGBENCH_LN, PGBENCH_LSHIFT, PGBENCH_LT, PGBENCH_MOD, PGBENCH_MUL, PGBENCH_NE, PGBENCH_NOT, PGBENCH_PI, PGBENCH_POW, PGBENCH_RANDOM, PGBENCH_RANDOM_EXPONENTIAL, PGBENCH_RANDOM_GAUSSIAN, PGBENCH_RANDOM_ZIPFIAN, PGBENCH_RSHIFT, PGBENCH_SQRT, PGBENCH_SUB, PGBT_BOOLEAN, PGBT_DOUBLE, PGBT_INT, PGBT_NULL, setBoolValue(), setDoubleValue(), setIntValue(), setNullValue(), PgBenchValue::type, generate_unaccent_rules::type, PgBenchValue::u, CState::use_file, and val.

Referenced by evalFunc().

1870 {
1871  /* evaluate all function arguments */
1872  int nargs = 0;
1873  PgBenchValue vargs[MAX_FARGS];
1874  PgBenchExprLink *l = args;
1875  bool has_null = false;
1876 
1877  for (nargs = 0; nargs < MAX_FARGS && l != NULL; nargs++, l = l->next)
1878  {
1879  if (!evaluateExpr(st, l->expr, &vargs[nargs]))
1880  return false;
1881  has_null |= vargs[nargs].type == PGBT_NULL;
1882  }
1883 
1884  if (l != NULL)
1885  {
1886  pg_log_error("too many function arguments, maximum is %d", MAX_FARGS);
1887  return false;
1888  }
1889 
1890  /* NULL arguments */
1891  if (has_null && func != PGBENCH_IS && func != PGBENCH_DEBUG)
1892  {
1893  setNullValue(retval);
1894  return true;
1895  }
1896 
1897  /* then evaluate function */
1898  switch (func)
1899  {
1900  /* overloaded operators */
1901  case PGBENCH_ADD:
1902  case PGBENCH_SUB:
1903  case PGBENCH_MUL:
1904  case PGBENCH_DIV:
1905  case PGBENCH_MOD:
1906  case PGBENCH_EQ:
1907  case PGBENCH_NE:
1908  case PGBENCH_LE:
1909  case PGBENCH_LT:
1910  {
1911  PgBenchValue *lval = &vargs[0],
1912  *rval = &vargs[1];
1913 
1914  Assert(nargs == 2);
1915 
1916  /* overloaded type management, double if some double */
1917  if ((lval->type == PGBT_DOUBLE ||
1918  rval->type == PGBT_DOUBLE) && func != PGBENCH_MOD)
1919  {
1920  double ld,
1921  rd;
1922 
1923  if (!coerceToDouble(lval, &ld) ||
1924  !coerceToDouble(rval, &rd))
1925  return false;
1926 
1927  switch (func)
1928  {
1929  case PGBENCH_ADD:
1930  setDoubleValue(retval, ld + rd);
1931  return true;
1932 
1933  case PGBENCH_SUB:
1934  setDoubleValue(retval, ld - rd);
1935  return true;
1936 
1937  case PGBENCH_MUL:
1938  setDoubleValue(retval, ld * rd);
1939  return true;
1940 
1941  case PGBENCH_DIV:
1942  setDoubleValue(retval, ld / rd);
1943  return true;
1944 
1945  case PGBENCH_EQ:
1946  setBoolValue(retval, ld == rd);
1947  return true;
1948 
1949  case PGBENCH_NE:
1950  setBoolValue(retval, ld != rd);
1951  return true;
1952 
1953  case PGBENCH_LE:
1954  setBoolValue(retval, ld <= rd);
1955  return true;
1956 
1957  case PGBENCH_LT:
1958  setBoolValue(retval, ld < rd);
1959  return true;
1960 
1961  default:
1962  /* cannot get here */
1963  Assert(0);
1964  }
1965  }
1966  else /* we have integer operands, or % */
1967  {
1968  int64 li,
1969  ri,
1970  res;
1971 
1972  if (!coerceToInt(lval, &li) ||
1973  !coerceToInt(rval, &ri))
1974  return false;
1975 
1976  switch (func)
1977  {
1978  case PGBENCH_ADD:
1979  if (pg_add_s64_overflow(li, ri, &res))
1980  {
1981  pg_log_error("bigint add out of range");
1982  return false;
1983  }
1984  setIntValue(retval, res);
1985  return true;
1986 
1987  case PGBENCH_SUB:
1988  if (pg_sub_s64_overflow(li, ri, &res))
1989  {
1990  pg_log_error("bigint sub out of range");
1991  return false;
1992  }
1993  setIntValue(retval, res);
1994  return true;
1995 
1996  case PGBENCH_MUL:
1997  if (pg_mul_s64_overflow(li, ri, &res))
1998  {
1999  pg_log_error("bigint mul out of range");
2000  return false;
2001  }
2002  setIntValue(retval, res);
2003  return true;
2004 
2005  case PGBENCH_EQ:
2006  setBoolValue(retval, li == ri);
2007  return true;
2008 
2009  case PGBENCH_NE:
2010  setBoolValue(retval, li != ri);
2011  return true;
2012 
2013  case PGBENCH_LE:
2014  setBoolValue(retval, li <= ri);
2015  return true;
2016 
2017  case PGBENCH_LT:
2018  setBoolValue(retval, li < ri);
2019  return true;
2020 
2021  case PGBENCH_DIV:
2022  case PGBENCH_MOD:
2023  if (ri == 0)
2024  {
2025  pg_log_error("division by zero");
2026  return false;
2027  }
2028  /* special handling of -1 divisor */
2029  if (ri == -1)
2030  {
2031  if (func == PGBENCH_DIV)
2032  {
2033  /* overflow check (needed for INT64_MIN) */
2034  if (li == PG_INT64_MIN)
2035  {
2036  pg_log_error("bigint div out of range");
2037  return false;
2038  }
2039  else
2040  setIntValue(retval, -li);
2041  }
2042  else
2043  setIntValue(retval, 0);
2044  return true;
2045  }
2046  /* else divisor is not -1 */
2047  if (func == PGBENCH_DIV)
2048  setIntValue(retval, li / ri);
2049  else /* func == PGBENCH_MOD */
2050  setIntValue(retval, li % ri);
2051 
2052  return true;
2053 
2054  default:
2055  /* cannot get here */
2056  Assert(0);
2057  }
2058  }
2059 
2060  Assert(0);
2061  return false; /* NOTREACHED */
2062  }
2063 
2064  /* integer bitwise operators */
2065  case PGBENCH_BITAND:
2066  case PGBENCH_BITOR:
2067  case PGBENCH_BITXOR:
2068  case PGBENCH_LSHIFT:
2069  case PGBENCH_RSHIFT:
2070  {
2071  int64 li,
2072  ri;
2073 
2074  if (!coerceToInt(&vargs[0], &li) || !coerceToInt(&vargs[1], &ri))
2075  return false;
2076 
2077  if (func == PGBENCH_BITAND)
2078  setIntValue(retval, li & ri);
2079  else if (func == PGBENCH_BITOR)
2080  setIntValue(retval, li | ri);
2081  else if (func == PGBENCH_BITXOR)
2082  setIntValue(retval, li ^ ri);
2083  else if (func == PGBENCH_LSHIFT)
2084  setIntValue(retval, li << ri);
2085  else if (func == PGBENCH_RSHIFT)
2086  setIntValue(retval, li >> ri);
2087  else /* cannot get here */
2088  Assert(0);
2089 
2090  return true;
2091  }
2092 
2093  /* logical operators */
2094  case PGBENCH_NOT:
2095  {
2096  bool b;
2097 
2098  if (!coerceToBool(&vargs[0], &b))
2099  return false;
2100 
2101  setBoolValue(retval, !b);
2102  return true;
2103  }
2104 
2105  /* no arguments */
2106  case PGBENCH_PI:
2107  setDoubleValue(retval, M_PI);
2108  return true;
2109 
2110  /* 1 overloaded argument */
2111  case PGBENCH_ABS:
2112  {
2113  PgBenchValue *varg = &vargs[0];
2114 
2115  Assert(nargs == 1);
2116 
2117  if (varg->type == PGBT_INT)
2118  {
2119  int64 i = varg->u.ival;
2120 
2121  setIntValue(retval, i < 0 ? -i : i);
2122  }
2123  else
2124  {
2125  double d = varg->u.dval;
2126 
2127  Assert(varg->type == PGBT_DOUBLE);
2128  setDoubleValue(retval, d < 0.0 ? -d : d);
2129  }
2130 
2131  return true;
2132  }
2133 
2134  case PGBENCH_DEBUG:
2135  {
2136  PgBenchValue *varg = &vargs[0];
2137 
2138  Assert(nargs == 1);
2139 
2140  fprintf(stderr, "debug(script=%d,command=%d): ",
2141  st->use_file, st->command + 1);
2142 
2143  if (varg->type == PGBT_NULL)
2144  fprintf(stderr, "null\n");
2145  else if (varg->type == PGBT_BOOLEAN)
2146  fprintf(stderr, "boolean %s\n", varg->u.bval ? "true" : "false");
2147  else if (varg->type == PGBT_INT)
2148  fprintf(stderr, "int " INT64_FORMAT "\n", varg->u.ival);
2149  else if (varg->type == PGBT_DOUBLE)
2150  fprintf(stderr, "double %.*g\n", DBL_DIG, varg->u.dval);
2151  else /* internal error, unexpected type */
2152  Assert(0);
2153 
2154  *retval = *varg;
2155 
2156  return true;
2157  }
2158 
2159  /* 1 double argument */
2160  case PGBENCH_DOUBLE:
2161  case PGBENCH_SQRT:
2162  case PGBENCH_LN:
2163  case PGBENCH_EXP:
2164  {
2165  double dval;
2166 
2167  Assert(nargs == 1);
2168 
2169  if (!coerceToDouble(&vargs[0], &dval))
2170  return false;
2171 
2172  if (func == PGBENCH_SQRT)
2173  dval = sqrt(dval);
2174  else if (func == PGBENCH_LN)
2175  dval = log(dval);
2176  else if (func == PGBENCH_EXP)
2177  dval = exp(dval);
2178  /* else is cast: do nothing */
2179 
2180  setDoubleValue(retval, dval);
2181  return true;
2182  }
2183 
2184  /* 1 int argument */
2185  case PGBENCH_INT:
2186  {
2187  int64 ival;
2188 
2189  Assert(nargs == 1);
2190 
2191  if (!coerceToInt(&vargs[0], &ival))
2192  return false;
2193 
2194  setIntValue(retval, ival);
2195  return true;
2196  }
2197 
2198  /* variable number of arguments */
2199  case PGBENCH_LEAST:
2200  case PGBENCH_GREATEST:
2201  {
2202  bool havedouble;
2203  int i;
2204 
2205  Assert(nargs >= 1);
2206 
2207  /* need double result if any input is double */
2208  havedouble = false;
2209  for (i = 0; i < nargs; i++)
2210  {
2211  if (vargs[i].type == PGBT_DOUBLE)
2212  {
2213  havedouble = true;
2214  break;
2215  }
2216  }
2217  if (havedouble)
2218  {
2219  double extremum;
2220 
2221  if (!coerceToDouble(&vargs[0], &extremum))
2222  return false;
2223  for (i = 1; i < nargs; i++)
2224  {
2225  double dval;
2226 
2227  if (!coerceToDouble(&vargs[i], &dval))
2228  return false;
2229  if (func == PGBENCH_LEAST)
2230  extremum = Min(extremum, dval);
2231  else
2232  extremum = Max(extremum, dval);
2233  }
2234  setDoubleValue(retval, extremum);
2235  }
2236  else
2237  {
2238  int64 extremum;
2239 
2240  if (!coerceToInt(&vargs[0], &extremum))
2241  return false;
2242  for (i = 1; i < nargs; i++)
2243  {
2244  int64 ival;
2245 
2246  if (!coerceToInt(&vargs[i], &ival))
2247  return false;
2248  if (func == PGBENCH_LEAST)
2249  extremum = Min(extremum, ival);
2250  else
2251  extremum = Max(extremum, ival);
2252  }
2253  setIntValue(retval, extremum);
2254  }
2255  return true;
2256  }
2257 
2258  /* random functions */
2259  case PGBENCH_RANDOM:
2263  {
2264  int64 imin,
2265  imax;
2266 
2267  Assert(nargs >= 2);
2268 
2269  if (!coerceToInt(&vargs[0], &imin) ||
2270  !coerceToInt(&vargs[1], &imax))
2271  return false;
2272 
2273  /* check random range */
2274  if (imin > imax)
2275  {
2276  pg_log_error("empty range given to random");
2277  return false;
2278  }
2279  else if (imax - imin < 0 || (imax - imin) + 1 < 0)
2280  {
2281  /* prevent int overflows in random functions */
2282  pg_log_error("random range is too large");
2283  return false;
2284  }
2285 
2286  if (func == PGBENCH_RANDOM)
2287  {
2288  Assert(nargs == 2);
2289  setIntValue(retval, getrand(&st->cs_func_rs, imin, imax));
2290  }
2291  else /* gaussian & exponential */
2292  {
2293  double param;
2294 
2295  Assert(nargs == 3);
2296 
2297  if (!coerceToDouble(&vargs[2], &param))
2298  return false;
2299 
2300  if (func == PGBENCH_RANDOM_GAUSSIAN)
2301  {
2302  if (param < MIN_GAUSSIAN_PARAM)
2303  {
2304  pg_log_error("gaussian parameter must be at least %f (not %f)",
2305  MIN_GAUSSIAN_PARAM, param);
2306  return false;
2307  }
2308 
2309  setIntValue(retval,
2311  imin, imax, param));
2312  }
2313  else if (func == PGBENCH_RANDOM_ZIPFIAN)
2314  {
2315  if (param < MIN_ZIPFIAN_PARAM || param > MAX_ZIPFIAN_PARAM)
2316  {
2317  pg_log_error("zipfian parameter must be in range [%.3f, %.0f] (not %f)",
2318  MIN_ZIPFIAN_PARAM, MAX_ZIPFIAN_PARAM, param);
2319  return false;
2320  }
2321 
2322  setIntValue(retval,
2323  getZipfianRand(&st->cs_func_rs, imin, imax, param));
2324  }
2325  else /* exponential */
2326  {
2327  if (param <= 0.0)
2328  {
2329  pg_log_error("exponential parameter must be greater than zero (not %f)",
2330  param);
2331  return false;
2332  }
2333 
2334  setIntValue(retval,
2336  imin, imax, param));
2337  }
2338  }
2339 
2340  return true;
2341  }
2342 
2343  case PGBENCH_POW:
2344  {
2345  PgBenchValue *lval = &vargs[0];
2346  PgBenchValue *rval = &vargs[1];
2347  double ld,
2348  rd;
2349 
2350  Assert(nargs == 2);
2351 
2352  if (!coerceToDouble(lval, &ld) ||
2353  !coerceToDouble(rval, &rd))
2354  return false;
2355 
2356  setDoubleValue(retval, pow(ld, rd));
2357 
2358  return true;
2359  }
2360 
2361  case PGBENCH_IS:
2362  {
2363  Assert(nargs == 2);
2364 
2365  /*
2366  * note: this simple implementation is more permissive than
2367  * SQL
2368  */
2369  setBoolValue(retval,
2370  vargs[0].type == vargs[1].type &&
2371  vargs[0].u.bval == vargs[1].u.bval);
2372  return true;
2373  }
2374 
2375  /* hashing */
2376  case PGBENCH_HASH_FNV1A:
2377  case PGBENCH_HASH_MURMUR2:
2378  {
2379  int64 val,
2380  seed;
2381 
2382  Assert(nargs == 2);
2383 
2384  if (!coerceToInt(&vargs[0], &val) ||
2385  !coerceToInt(&vargs[1], &seed))
2386  return false;
2387 
2388  if (func == PGBENCH_HASH_MURMUR2)
2389  setIntValue(retval, getHashMurmur2(val, seed));
2390  else if (func == PGBENCH_HASH_FNV1A)
2391  setIntValue(retval, getHashFnv1a(val, seed));
2392  else
2393  /* cannot get here */
2394  Assert(0);
2395 
2396  return true;
2397  }
2398 
2399  default:
2400  /* cannot get here */
2401  Assert(0);
2402  /* dead code to avoid a compiler warning */
2403  return false;
2404  }
2405 }
static bool coerceToBool(PgBenchValue *pval, bool *bval)
Definition: pgbench.c:1622
static bool pg_sub_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:188
#define pg_log_error(...)
Definition: logging.h:80
static int64 getHashMurmur2(int64 val, uint64 seed)
Definition: pgbench.c:1045
static int64 getHashFnv1a(int64 val, uint64 seed)
Definition: pgbench.c:1020
#define Min(x, y)
Definition: c.h:928
static int64 getrand(RandomState *random_state, int64 min, int64 max)
Definition: pgbench.c:850
RandomState cs_func_rs
Definition: pgbench.c:410
static bool coerceToDouble(PgBenchValue *pval, double *dval)
Definition: pgbench.c:1691
static void setDoubleValue(PgBenchValue *pv, double dval)
Definition: pgbench.c:1736
#define fprintf
Definition: port.h:219
#define MIN_GAUSSIAN_PARAM
Definition: pgbench.c:141
static int64 getExponentialRand(RandomState *random_state, int64 min, int64 max, double parameter)
Definition: pgbench.c:870
#define MAX_FARGS
Definition: pgbench.c:1860
static bool evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
Definition: pgbench.c:2425
static void setBoolValue(PgBenchValue *pv, bool bval)
Definition: pgbench.c:1720
static int64 getZipfianRand(RandomState *random_state, int64 min, int64 max, double s)
Definition: pgbench.c:1006
#define M_PI
Definition: pgbench.c:71
static void setNullValue(PgBenchValue *pv)
Definition: pgbench.c:1712
union PgBenchValue::@38 u
#define PG_INT64_MIN
Definition: c.h:460
#define MAX_ZIPFIAN_PARAM
Definition: pgbench.c:144
int command
Definition: pgbench.c:413
#define MIN_ZIPFIAN_PARAM
Definition: pgbench.c:143
double dval
Definition: pgbench.h:50
static bool pg_add_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:161
#define Max(x, y)
Definition: c.h:922
static bool pg_mul_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:215
#define Assert(condition)
Definition: c.h:746
static void setIntValue(PgBenchValue *pv, int64 ival)
Definition: pgbench.c:1728
#define INT64_FORMAT
Definition: c.h:417
static int64 getGaussianRand(RandomState *random_state, int64 min, int64 max, double parameter)
Definition: pgbench.c:894
bool bval
Definition: pgbench.h:51
PgBenchValueType type
Definition: pgbench.h:46
int i
static bool coerceToInt(PgBenchValue *pval, int64 *ival)
Definition: pgbench.c:1663
int64 ival
Definition: pgbench.h:49
int use_file
Definition: pgbench.c:412
long val
Definition: informix.c:664

◆ evaluateExpr()

static bool evaluateExpr ( CState st,
PgBenchExpr expr,
PgBenchValue retval 
)
static

Definition at line 2425 of file pgbench.c.

References PgBenchExpr::constant, ENODE_CONSTANT, ENODE_FUNCTION, ENODE_VARIABLE, PgBenchExpr::etype, evalFunc(), PgBenchExpr::function, lookupVariable(), makeVariableValue(), pg_log_error, pg_log_fatal, PgBenchExpr::u, Variable::value, and PgBenchExpr::variable.

Referenced by evalLazyFunc(), evalStandardFunc(), and executeMetaCommand().

2426 {
2427  switch (expr->etype)
2428  {
2429  case ENODE_CONSTANT:
2430  {
2431  *retval = expr->u.constant;
2432  return true;
2433  }
2434 
2435  case ENODE_VARIABLE:
2436  {
2437  Variable *var;
2438 
2439  if ((var = lookupVariable(st, expr->u.variable.varname)) == NULL)
2440  {
2441  pg_log_error("undefined variable \"%s\"", expr->u.variable.varname);
2442  return false;
2443  }
2444 
2445  if (!makeVariableValue(var))
2446  return false;
2447 
2448  *retval = var->value;
2449  return true;
2450  }
2451 
2452  case ENODE_FUNCTION:
2453  return evalFunc(st,
2454  expr->u.function.function,
2455  expr->u.function.args,
2456  retval);
2457 
2458  default:
2459  /* internal error which should never occur */
2460  pg_log_fatal("unexpected enode type in evaluation: %d", expr->etype);
2461  exit(1);
2462  }
2463 }
PgBenchValue constant
Definition: pgbench.h:114
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:1247
#define pg_log_error(...)
Definition: logging.h:80
static bool evalFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2409
static bool makeVariableValue(Variable *var)
Definition: pgbench.c:1307
PgBenchValue value
Definition: pgbench.c:268
struct PgBenchExpr::@39::@40 variable
PgBenchFunction function
Definition: pgbench.h:121
union PgBenchExpr::@39 u
PgBenchExprType etype
Definition: pgbench.h:111
#define pg_log_fatal(...)
Definition: logging.h:76

◆ evaluateSleep()

static bool evaluateSleep ( CState st,
int  argc,
char **  argv,
int *  usecs 
)
static

Definition at line 2842 of file pgbench.c.

References getVariable(), pg_log_error, and pg_strcasecmp().

Referenced by executeMetaCommand().

2843 {
2844  char *var;
2845  int usec;
2846 
2847  if (*argv[1] == ':')
2848  {
2849  if ((var = getVariable(st, argv[1] + 1)) == NULL)
2850  {
2851  pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[1] + 1);
2852  return false;
2853  }
2854  usec = atoi(var);
2855  }
2856  else
2857  usec = atoi(argv[1]);
2858 
2859  if (argc > 2)
2860  {
2861  if (pg_strcasecmp(argv[2], "ms") == 0)
2862  usec *= 1000;
2863  else if (pg_strcasecmp(argv[2], "s") == 0)
2864  usec *= 1000000;
2865  }
2866  else
2867  usec *= 1000000;
2868 
2869  *usecs = usec;
2870  return true;
2871 }
#define pg_log_error(...)
Definition: logging.h:80
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1274
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36

◆ executeMetaCommand()

static ConnectionStateEnum executeMetaCommand ( CState st,
instr_time now 
)
static

Definition at line 3309 of file pgbench.c.

References __pg_log_level, appendPQExpBuffer(), Command::argc, Command::argv, Assert, buf, CState::command, commandFailed(), ParsedScript::commands, conditional_stack_empty(), conditional_stack_peek(), conditional_stack_poke(), conditional_stack_pop(), conditional_stack_push(), CState::cstack, CSTATE_ABORTED, CSTATE_END_COMMAND, CSTATE_SLEEP, PQExpBufferData::data, evaluateExpr(), evaluateSleep(), Command::expr, i, CState::id, IFSTATE_ELSE_FALSE, IFSTATE_ELSE_TRUE, IFSTATE_FALSE, IFSTATE_IGNORED, IFSTATE_NONE, IFSTATE_TRUE, initPQExpBuffer(), INSTR_TIME_GET_MICROSEC, INSTR_TIME_SET_CURRENT_LAZY, INSTR_TIME_SET_ZERO, Command::meta, META_COMMAND, META_ELIF, META_ELSE, META_ENDIF, META_IF, META_SET, META_SETSHELL, META_SHELL, META_SLEEP, PG_LOG_DEBUG, pg_log_debug, printfPQExpBuffer(), putVariableValue(), runShellCommand(), CState::sleep_until, termPQExpBuffer(), Command::type, unlikely, CState::use_file, and valueTruth().

Referenced by advanceConnectionState().

3310 {
3311  Command *command = sql_script[st->use_file].commands[st->command];
3312  int argc;
3313  char **argv;
3314 
3315  Assert(command != NULL && command->type == META_COMMAND);
3316 
3317  argc = command->argc;
3318  argv = command->argv;
3319 
3321  {
3323 
3324  initPQExpBuffer(&buf);
3325 
3326  printfPQExpBuffer(&buf, "client %d executing \\%s", st->id, argv[0]);
3327  for (int i = 1; i < argc; i++)
3328  appendPQExpBuffer(&buf, " %s", argv[i]);
3329 
3330  pg_log_debug("%s", buf.data);
3331 
3332  termPQExpBuffer(&buf);
3333  }
3334 
3335  if (command->meta == META_SLEEP)
3336  {
3337  int usec;
3338 
3339  /*
3340  * A \sleep doesn't execute anything, we just get the delay from the
3341  * argument, and enter the CSTATE_SLEEP state. (The per-command
3342  * latency will be recorded in CSTATE_SLEEP state, not here, after the
3343  * delay has elapsed.)
3344  */
3345  if (!evaluateSleep(st, argc, argv, &usec))
3346  {
3347  commandFailed(st, "sleep", "execution of meta-command failed");
3348  return CSTATE_ABORTED;
3349  }
3350 
3352  st->sleep_until = INSTR_TIME_GET_MICROSEC(*now) + usec;
3353  return CSTATE_SLEEP;
3354  }
3355  else if (command->meta == META_SET)
3356  {
3357  PgBenchExpr *expr = command->expr;
3358  PgBenchValue result;
3359 
3360  if (!evaluateExpr(st, expr, &result))
3361  {
3362  commandFailed(st, argv[0], "evaluation of meta-command failed");
3363  return CSTATE_ABORTED;
3364  }
3365 
3366  if (!putVariableValue(st, argv[0], argv[1], &result))
3367  {
3368  commandFailed(st, "set", "assignment of meta-command failed");
3369  return CSTATE_ABORTED;
3370  }
3371  }
3372  else if (command->meta == META_IF)
3373  {
3374  /* backslash commands with an expression to evaluate */
3375  PgBenchExpr *expr = command->expr;
3376  PgBenchValue result;
3377  bool cond;
3378 
3379  if (!evaluateExpr(st, expr, &result))
3380  {
3381  commandFailed(st, argv[0], "evaluation of meta-command failed");
3382  return CSTATE_ABORTED;
3383  }
3384 
3385  cond = valueTruth(&result);
3387  }
3388  else if (command->meta == META_ELIF)
3389  {
3390  /* backslash commands with an expression to evaluate */
3391  PgBenchExpr *expr = command->expr;
3392  PgBenchValue result;
3393  bool cond;
3394 
3396  {
3397  /* elif after executed block, skip eval and wait for endif. */
3399  return CSTATE_END_COMMAND;
3400  }
3401 
3402  if (!evaluateExpr(st, expr, &result))
3403  {
3404  commandFailed(st, argv[0], "evaluation of meta-command failed");
3405  return CSTATE_ABORTED;
3406  }
3407 
3408  cond = valueTruth(&result);
3411  }
3412  else if (command->meta == META_ELSE)
3413  {
3414  switch (conditional_stack_peek(st->cstack))
3415  {
3416  case IFSTATE_TRUE:
3418  break;
3419  case IFSTATE_FALSE: /* inconsistent if active */
3420  case IFSTATE_IGNORED: /* inconsistent if active */
3421  case IFSTATE_NONE: /* else without if */
3422  case IFSTATE_ELSE_TRUE: /* else after else */
3423  case IFSTATE_ELSE_FALSE: /* else after else */
3424  default:
3425  /* dead code if conditional check is ok */
3426  Assert(false);
3427  }
3428  }
3429  else if (command->meta == META_ENDIF)
3430  {
3433  }
3434  else if (command->meta == META_SETSHELL)
3435  {
3436  if (!runShellCommand(st, argv[1], argv + 2, argc - 2))
3437  {
3438  commandFailed(st, "setshell", "execution of meta-command failed");
3439  return CSTATE_ABORTED;
3440  }
3441  }
3442  else if (command->meta == META_SHELL)
3443  {
3444  if (!runShellCommand(st, NULL, argv + 1, argc - 1))
3445  {
3446  commandFailed(st, "shell", "execution of meta-command failed");
3447  return CSTATE_ABORTED;
3448  }
3449  }
3450 
3451  /*
3452  * executing the expression or shell command might have taken a
3453  * non-negligible amount of time, so reset 'now'
3454  */
3456 
3457  return CSTATE_END_COMMAND;
3458 }
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
int type
Definition: pgbench.c:526
int id
Definition: pgbench.c:402
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:57
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
void conditional_stack_push(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:41
static void commandFailed(CState *st, const char *cmd, const char *message)
Definition: pgbench.c:2613
PgBenchExpr * expr
Definition: pgbench.c:531
#define INSTR_TIME_SET_ZERO(t)
Definition: instr_time.h:154
char * argv[MAX_ARGS]
Definition: pgbench.c:529
ConditionalStack cstack
Definition: pgbench.c:404
static bool evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
Definition: pgbench.c:2425
#define META_COMMAND
Definition: pgbench.c:468
#define pg_log_debug(...)
Definition: logging.h:92
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
static char * buf
Definition: pg_test_fsync.c:68
MetaCommand meta
Definition: pgbench.c:527
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:543
enum pg_log_level __pg_log_level
Definition: logging.c:21
int argc
Definition: pgbench.c:528
int command
Definition: pgbench.c:413
static bool runShellCommand(CState *st, char *variable, char **argv, int argc)
Definition: pgbench.c:2505
ifState conditional_stack_peek(ConditionalStack cstack)
Definition: conditional.c:94
int64 sleep_until
Definition: pgbench.c:422
static bool evaluateSleep(CState *st, int argc, char **argv, int *usecs)
Definition: pgbench.c:2842
#define INSTR_TIME_SET_CURRENT_LAZY(t)
Definition: instr_time.h:253
#define Assert(condition)
Definition: c.h:746
#define INSTR_TIME_GET_MICROSEC(t)
Definition: instr_time.h:205
static bool valueTruth(PgBenchValue *pval)
Definition: pgbench.c:1642
bool conditional_stack_poke(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:106
Command ** commands
Definition: pgbench.c:539
bool conditional_stack_empty(ConditionalStack cstack)
Definition: conditional.c:118
int i
static bool putVariableValue(CState *st, const char *context, char *name, const PgBenchValue *value)
Definition: pgbench.c:1475
#define unlikely(x)
Definition: c.h:207
int use_file
Definition: pgbench.c:412
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1542
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ executeStatement()

static void executeStatement ( PGconn con,
const char *  sql 
)
static

Definition at line 1142 of file pgbench.c.

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

Referenced by createPartitions(), initCreateFKeys(), initCreatePKeys(), initCreateTables(), initDropTables(), initGenerateDataClientSide(), initGenerateDataServerSide(), initTruncateTables(), and initVacuum().

1143 {
1144  PGresult *res;
1145 
1146  res = PQexec(con, sql);
1147  if (PQresultStatus(res) != PGRES_COMMAND_OK)
1148  {
1149  pg_log_fatal("query failed: %s", PQerrorMessage(con));
1150  pg_log_info("query was: %s", sql);
1151  exit(1);
1152  }
1153  PQclear(res);
1154 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6669
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2692
void PQclear(PGresult *res)
Definition: fe-exec.c:694
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1939
#define pg_log_info(...)
Definition: logging.h:88
#define pg_log_fatal(...)
Definition: logging.h:76

◆ findBuiltin()

static const BuiltinScript* findBuiltin ( const char *  name)
static

Definition at line 4984 of file pgbench.c.

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

Referenced by main().

4985 {
4986  int i,
4987  found = 0,
4988  len = strlen(name);
4989  const BuiltinScript *result = NULL;
4990 
4991  for (i = 0; i < lengthof(builtin_script); i++)
4992  {
4993  if (strncmp(builtin_script[i].name, name, len) == 0)
4994  {
4995  result = &builtin_script[i];
4996  found++;
4997  }
4998  }
4999 
5000  /* ok, unambiguous result */
5001  if (found == 1)
5002  return result;
5003 
5004  /* error cases */
5005  if (found == 0)
5006  pg_log_fatal("no builtin script found for name \"%s\"", name);
5007  else /* found > 1 */
5008  pg_log_fatal("ambiguous builtin name: %d builtin scripts found for prefix \"%s\"", found, name);
5009 
5011  exit(1);
5012 }
static void listAvailableScripts(void)
Definition: pgbench.c:4972
#define lengthof(array)
Definition: c.h:676
static const BuiltinScript builtin_script[]
Definition: pgbench.c:555
const char * name
Definition: encode.c:561
int i
#define pg_log_fatal(...)
Definition: logging.h:76

◆ finishCon()

static void finishCon ( CState st)
static

Definition at line 6512 of file pgbench.c.

References CState::con, and PQfinish().

Referenced by advanceConnectionState(), and disconnect_all().

6513 {
6514  if (st->con != NULL)
6515  {
6516  PQfinish(st->con);
6517  st->con = NULL;
6518  }
6519 }
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4174
PGconn * con
Definition: pgbench.c:401

◆ free_command()

static void free_command ( Command command)
static

Definition at line 4463 of file pgbench.c.

References Command::argc, Command::argv, Command::first_line, i, Command::lines, pg_free(), termPQExpBuffer(), and Command::varprefix.

Referenced by ParseScript().

4464 {
4465  termPQExpBuffer(&command->lines);
4466  if (command->first_line)
4467  pg_free(command->first_line);
4468  for (int i = 0; i < command->argc; i++)
4469  pg_free(command->argv[i]);
4470  if (command->varprefix)
4471  pg_free(command->varprefix);
4472 
4473  /*
4474  * It should also free expr recursively, but this is currently not needed
4475  * as only gset commands (which do not have an expression) are freed.
4476  */
4477  pg_free(command);
4478 }
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
char * argv[MAX_ARGS]
Definition: pgbench.c:529
PQExpBufferData lines
Definition: pgbench.c:524
int argc
Definition: pgbench.c:528
char * varprefix
Definition: pgbench.c:530
void pg_free(void *ptr)
Definition: fe_memutils.c:105
int i
char * first_line
Definition: pgbench.c:525

◆ free_socket_set()

static void free_socket_set ( socket_set sa)
static

Definition at line 6686 of file pgbench.c.

References pg_free().

Referenced by setalarm(), and threadRun().

6687 {
6688  pg_free(sa);
6689 }
void pg_free(void *ptr)
Definition: fe_memutils.c:105

◆ getExponentialRand()

static int64 getExponentialRand ( RandomState random_state,
int64  min,
int64  max,
double  parameter 
)
static

Definition at line 870 of file pgbench.c.

References Assert, pg_erand48(), and RandomState::xseed.

Referenced by evalStandardFunc().

872 {
873  double cut,
874  uniform,
875  rand;
876 
877  /* abort if wrong parameter, but must really be checked beforehand */
878  Assert(parameter > 0.0);
879  cut = exp(-parameter);
880  /* erand in [0, 1), uniform in (0, 1] */
881  uniform = 1.0 - pg_erand48(random_state->xseed);
882 
883  /*
884  * inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
885  */
886  Assert((1.0 - cut) != 0.0);
887  rand = -log(cut + (1.0 - cut) * uniform) / parameter;
888  /* return int64 random number within between min and max */
889  return min + (int64) ((max - min + 1) * rand);
890 }
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
#define Assert(condition)
Definition: c.h:746
unsigned short xseed[3]
Definition: pgbench.c:308

◆ getGaussianRand()

static int64 getGaussianRand ( RandomState random_state,
int64  min,
int64  max,
double  parameter 
)
static

Definition at line 894 of file pgbench.c.

References Assert, M_PI, MIN_GAUSSIAN_PARAM, pg_erand48(), and RandomState::xseed.

Referenced by evalStandardFunc().

896 {
897  double stdev;
898  double rand;
899 
900  /* abort if parameter is too low, but must really be checked beforehand */
901  Assert(parameter >= MIN_GAUSSIAN_PARAM);
902 
903  /*
904  * Get user specified random number from this loop, with -parameter <
905  * stdev <= parameter
906  *
907  * This loop is executed until the number is in the expected range.
908  *
909  * As the minimum parameter is 2.0, the probability of looping is low:
910  * sqrt(-2 ln(r)) <= 2 => r >= e^{-2} ~ 0.135, then when taking the
911  * average sinus multiplier as 2/pi, we have a 8.6% looping probability in
912  * the worst case. For a parameter value of 5.0, the looping probability
913  * is about e^{-5} * 2 / pi ~ 0.43%.
914  */
915  do
916  {
917  /*
918  * pg_erand48 generates [0,1), but for the basic version of the
919  * Box-Muller transform the two uniformly distributed random numbers
920  * are expected in (0, 1] (see
921  * https://en.wikipedia.org/wiki/Box-Muller_transform)
922  */
923  double rand1 = 1.0 - pg_erand48(random_state->xseed);
924  double rand2 = 1.0 - pg_erand48(random_state->xseed);
925 
926  /* Box-Muller basic form transform */
927  double var_sqrt = sqrt(-2.0 * log(rand1));
928 
929  stdev = var_sqrt * sin(2.0 * M_PI * rand2);
930 
931  /*
932  * we may try with cos, but there may be a bias induced if the
933  * previous value fails the test. To be on the safe side, let us try
934  * over.
935  */
936  }
937  while (stdev < -parameter || stdev >= parameter);
938 
939  /* stdev is in [-parameter, parameter), normalization to [0,1) */
940  rand = (stdev + parameter) / (parameter * 2.0);
941 
942  /* return int64 random number within between min and max */
943  return min + (int64) ((max - min + 1) * rand);
944 }
#define MIN_GAUSSIAN_PARAM
Definition: pgbench.c:141
#define M_PI
Definition: pgbench.c:71
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
#define Assert(condition)
Definition: c.h:746
unsigned short xseed[3]
Definition: pgbench.c:308

◆ getHashFnv1a()

static int64 getHashFnv1a ( int64  val,
uint64  seed 
)
static

Definition at line 1020 of file pgbench.c.

References FNV_OFFSET_BASIS, FNV_PRIME, and i.

Referenced by evalStandardFunc().

1021 {
1022  int64 result;
1023  int i;
1024 
1025  result = FNV_OFFSET_BASIS ^ seed;
1026  for (i = 0; i < 8; ++i)
1027  {
1028  int32 octet = val & 0xff;
1029 
1030  val = val >> 8;
1031  result = result ^ octet;
1032  result = result * FNV_PRIME;
1033  }
1034 
1035  return result;
1036 }
#define FNV_PRIME
Definition: pgbench.c:79
#define FNV_OFFSET_BASIS
Definition: pgbench.c:80
signed int int32
Definition: c.h:363
int i
long val
Definition: informix.c:664

◆ getHashMurmur2()

static int64 getHashMurmur2 ( int64  val,
uint64  seed 
)
static

Definition at line 1045 of file pgbench.c.

References MM2_MUL, MM2_MUL_TIMES_8, and MM2_ROT.

Referenced by evalStandardFunc().

1046 {
1047  uint64 result = seed ^ MM2_MUL_TIMES_8; /* sizeof(int64) */
1048  uint64 k = (uint64) val;
1049 
1050  k *= MM2_MUL;
1051  k ^= k >> MM2_ROT;
1052  k *= MM2_MUL;
1053 
1054  result ^= k;
1055  result *= MM2_MUL;
1056 
1057  result ^= result >> MM2_ROT;
1058  result *= MM2_MUL;
1059  result ^= result >> MM2_ROT;
1060 
1061  return (int64) result;
1062 }
#define MM2_MUL_TIMES_8
Definition: pgbench.c:82
#define MM2_ROT
Definition: pgbench.c:83
long val
Definition: informix.c:664
#define MM2_MUL
Definition: pgbench.c:81

◆ getMetaCommand()

static MetaCommand getMetaCommand ( const char *  cmd)
static

Definition at line 2469 of file pgbench.c.

References META_ASET, META_ELIF, META_ELSE, META_ENDIF, META_GSET, META_IF, META_NONE, META_SET, META_SETSHELL, META_SHELL, META_SLEEP, and pg_strcasecmp().

Referenced by process_backslash_command().

2470 {
2471  MetaCommand mc;
2472 
2473  if (cmd == NULL)
2474  mc = META_NONE;
2475  else if (pg_strcasecmp(cmd, "set") == 0)
2476  mc = META_SET;
2477  else if (pg_strcasecmp(cmd, "setshell") == 0)
2478  mc = META_SETSHELL;
2479  else if (pg_strcasecmp(cmd, "shell") == 0)
2480  mc = META_SHELL;
2481  else if (pg_strcasecmp(cmd, "sleep") == 0)
2482  mc = META_SLEEP;
2483  else if (pg_strcasecmp(cmd, "if") == 0)
2484  mc = META_IF;
2485  else if (pg_strcasecmp(cmd, "elif") == 0)
2486  mc = META_ELIF;
2487  else if (pg_strcasecmp(cmd, "else") == 0)
2488  mc = META_ELSE;
2489  else if (pg_strcasecmp(cmd, "endif") == 0)
2490  mc = META_ENDIF;
2491  else if (pg_strcasecmp(cmd, "gset") == 0)
2492  mc = META_GSET;
2493  else if (pg_strcasecmp(cmd, "aset") == 0)
2494  mc = META_ASET;
2495  else
2496  mc = META_NONE;
2497  return mc;
2498 }
MetaCommand
Definition: pgbench.c:476
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36

◆ getPoissonRand()

static int64 getPoissonRand ( RandomState random_state,
double  center 
)
static

Definition at line 954 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by advanceConnectionState().

955 {
956  /*
957  * Use inverse transform sampling to generate a value > 0, such that the
958  * expected (i.e. average) value is the given argument.
959  */
960  double uniform;
961 
962  /* erand in [0, 1), uniform in (0, 1] */
963  uniform = 1.0 - pg_erand48(random_state->xseed);
964 
965  return (int64) (-log(uniform) * center + 0.5);
966 }
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
unsigned short xseed[3]
Definition: pgbench.c:308

◆ getQueryParams()

static void getQueryParams ( CState st,
const Command command,
const char **  params 
)
static

Definition at line 1591 of file pgbench.c.

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

Referenced by sendCommand().

1592 {
1593  int i;
1594 
1595  for (i = 0; i < command->argc - 1; i++)
1596  params[i] = getVariable(st, command->argv[i + 1]);
1597 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1274
char * argv[MAX_ARGS]
Definition: pgbench.c:529
int argc
Definition: pgbench.c:528
int i

◆ getrand()

static int64 getrand ( RandomState random_state,
int64  min,
int64  max 
)
static

Definition at line 850 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by chooseScript(), and evalStandardFunc().

851 {
852  /*
853  * Odd coding is so that min and max have approximately the same chance of
854  * being selected as do numbers between them.
855  *
856  * pg_erand48() is thread-safe and concurrent, which is why we use it
857  * rather than random(), which in glibc is non-reentrant, and therefore
858  * protected by a mutex, and therefore a bottleneck on machines with many
859  * CPUs.
860  */
861  return min + (int64) ((max - min + 1) * pg_erand48(random_state->xseed));
862 }
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
unsigned short xseed[3]
Definition: pgbench.c:308

◆ GetTableInfo()

static void GetTableInfo ( PGconn con,
bool  scale_given 
)
static

Definition at line 4192 of file pgbench.c.

References Assert, ERRCODE_UNDEFINED_TABLE, PART_HASH, PART_NONE, PART_RANGE, PG_DIAG_SQLSTATE, pg_log_fatal, pg_log_info, pg_log_warning, PGRES_TUPLES_OK, PQclear(), PQdb(), PQerrorMessage(), PQexec(), PQgetisnull(), PQgetvalue(), PQntuples(), PQresultErrorField(), and PQresultStatus().

Referenced by main().

4193 {
4194  PGresult *res;
4195 
4196  /*
4197  * get the scaling factor that should be same as count(*) from
4198  * pgbench_branches if this is not a custom query
4199  */
4200  res = PQexec(con, "select count(*) from pgbench_branches");
4201  if (PQresultStatus(res) != PGRES_TUPLES_OK)
4202  {
4203  char *sqlState = PQresultErrorField(res, PG_DIAG_SQLSTATE);
4204 
4205  pg_log_fatal("could not count number of branches: %s", PQerrorMessage(con));
4206 
4207  if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) == 0)
4208  pg_log_info("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\"",
4209  PQdb(con));
4210 
4211  exit(1);
4212  }
4213  scale = atoi(PQgetvalue(res, 0, 0));
4214  if (scale < 0)
4215  {
4216  pg_log_fatal("invalid count(*) from pgbench_branches: \"%s\"",
4217  PQgetvalue(res, 0, 0));
4218  exit(1);
4219  }
4220  PQclear(res);
4221 
4222  /* warn if we override user-given -s switch */
4223  if (scale_given)
4224  pg_log_warning("scale option ignored, using count from pgbench_branches table (%d)",
4225  scale);
4226 
4227  /*
4228  * Get the partition information for the first "pgbench_accounts" table
4229  * found in search_path.
4230  *
4231  * The result is empty if no "pgbench_accounts" is found.
4232  *
4233  * Otherwise, it always returns one row even if the table is not
4234  * partitioned (in which case the partition strategy is NULL).
4235  *
4236  * The number of partitions can be 0 even for partitioned tables, if no
4237  * partition is attached.
4238  *
4239  * We assume no partitioning on any failure, so as to avoid failing on an
4240  * old version without "pg_partitioned_table".
4241  */
4242  res = PQexec(con,
4243  "select o.n, p.partstrat, pg_catalog.count(i.inhparent) "
4244  "from pg_catalog.pg_class as c "
4245  "join pg_catalog.pg_namespace as n on (n.oid = c.relnamespace) "
4246  "cross join lateral (select pg_catalog.array_position(pg_catalog.current_schemas(true), n.nspname)) as o(n) "
4247  "left join pg_catalog.pg_partitioned_table as p on (p.partrelid = c.oid) "
4248  "left join pg_catalog.pg_inherits as i on (c.oid = i.inhparent) "
4249  "where c.relname = 'pgbench_accounts' and o.n is not null "
4250  "group by 1, 2 "
4251  "order by 1 asc "
4252  "limit 1");
4253 
4254  if (PQresultStatus(res) != PGRES_TUPLES_OK)
4255  {
4256  /* probably an older version, coldly assume no partitioning */
4258  partitions = 0;
4259  }
4260  else if (PQntuples(res) == 0)
4261  {
4262  /*
4263  * This case is unlikely as pgbench already found "pgbench_branches"
4264  * above to compute the scale.
4265  */
4266  pg_log_fatal("no pgbench_accounts table found in search_path");
4267  pg_log_info("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".", PQdb(con));
4268  exit(1);
4269  }
4270  else /* PQntupes(res) == 1 */
4271  {
4272  /* normal case, extract partition information */
4273  if (PQgetisnull(res, 0, 1))
4275  else
4276  {
4277  char *ps = PQgetvalue(res, 0, 1);
4278 
4279  /* column must be there */
4280  Assert(ps != NULL);
4281 
4282  if (strcmp(ps, "r") == 0)
4284  else if (strcmp(ps, "h") == 0)
4286  else
4287  {
4288  /* possibly a newer version with new partition method */
4289  pg_log_fatal("unexpected partition method: \"%s\"", ps);
4290  exit(1);
4291  }
4292  }
4293 
4294  partitions = atoi(PQgetvalue(res, 0, 2));
4295  }
4296 
4297  PQclear(res);
4298 }
static int partitions
Definition: pgbench.c:196
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6669
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:74
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3163
static partition_method_t partition_method
Definition: pgbench.c:206
int scale
Definition: pgbench.c:154
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2769
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:57
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2692
void PQclear(PGresult *res)
Definition: fe-exec.c:694
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:6519
char * PQresultErrorField(const PGresult *res, int fieldcode)
Definition: fe-exec.c:2754
#define Assert(condition)
Definition: c.h:746
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1939
#define pg_log_warning(...)
Definition: pgfnames.c:24
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3188
#define pg_log_info(...)
Definition: logging.h:88
#define pg_log_fatal(...)
Definition: logging.h:76

◆ getVariable()

static char* getVariable ( CState st,
char *  name 
)
static

Definition at line 1274 of file pgbench.c.

References Assert, PgBenchValue::bval, PgBenchValue::dval, INT64_FORMAT, PgBenchValue::ival, lookupVariable(), pg_strdup(), PGBT_BOOLEAN, PGBT_DOUBLE, PGBT_INT, PGBT_NO_VALUE, PGBT_NULL, snprintf, Variable::svalue, PgBenchValue::type, PgBenchValue::u, and Variable::value.

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

1275 {
1276  Variable *var;
1277  char stringform[64];
1278 
1279  var = lookupVariable(st, name);
1280  if (var == NULL)
1281  return NULL; /* not found */
1282 
1283  if (var->svalue)
1284  return var->svalue; /* we have it in string form */
1285 
1286  /* We need to produce a string equivalent of the value */
1287  Assert(var->value.type != PGBT_NO_VALUE);
1288  if (var->value.type == PGBT_NULL)
1289  snprintf(stringform, sizeof(stringform), "NULL");
1290  else if (var->value.type == PGBT_BOOLEAN)
1291  snprintf(stringform, sizeof(stringform),
1292  "%s", var->value.u.bval ? "true" : "false");
1293  else if (var->value.type == PGBT_INT)
1294  snprintf(stringform, sizeof(stringform),
1295  INT64_FORMAT, var->value.u.ival);
1296  else if (var->value.type == PGBT_DOUBLE)
1297  snprintf(stringform, sizeof(stringform),
1298  "%.*g", DBL_DIG, var->value.u.dval);
1299  else /* internal error, unexpected type */
1300  Assert(0);
1301  var->svalue = pg_strdup(stringform);
1302  return var->svalue;
1303 }
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:1247
union PgBenchValue::@38 u
char * svalue
Definition: pgbench.c:267
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
PgBenchValue value
Definition: pgbench.c:268
double dval
Definition: pgbench.h:50
#define Assert(condition)
Definition: c.h:746
#define INT64_FORMAT
Definition: c.h:417
const char * name
Definition: encode.c:561
bool bval
Definition: pgbench.h:51
PgBenchValueType type
Definition: pgbench.h:46
int64 ival
Definition: pgbench.h:49
#define snprintf
Definition: port.h:215

◆ getZipfianRand()

static int64 getZipfianRand ( RandomState random_state,
int64  min,
int64  max,
double  s 
)
static

Definition at line 1006 of file pgbench.c.

References Assert, computeIterativeZipfian(), MAX_ZIPFIAN_PARAM, and MIN_ZIPFIAN_PARAM.

Referenced by evalStandardFunc().

1007 {
1008  int64 n = max - min + 1;
1009 
1010  /* abort if parameter is invalid */
1012 
1013  return min - 1 + computeIterativeZipfian(random_state, n, s);
1014 }
#define MAX_ZIPFIAN_PARAM
Definition: pgbench.c:144
#define MIN_ZIPFIAN_PARAM
Definition: pgbench.c:143
#define Assert(condition)
Definition: c.h:746
static int64 computeIterativeZipfian(RandomState *random_state, int64 n, double s)
Definition: pgbench.c:976

◆ handle_sig_alarm()

static void handle_sig_alarm ( SIGNAL_ARGS  )
static

Definition at line 6528 of file pgbench.c.

Referenced by setalarm().

6529 {
6530  timer_exceeded = true;
6531 }
volatile bool timer_exceeded
Definition: pgbench.c:252

◆ initCreateFKeys()

static void initCreateFKeys ( PGconn con)
static

Definition at line 4051 of file pgbench.c.

References executeStatement(), fprintf, i, and lengthof.

Referenced by runInitSteps().

4052 {
4053  static const char *const DDLKEYs[] = {
4054  "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
4055  "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
4056  "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
4057  "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
4058  "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
4059  };
4060  int i;
4061 
4062  fprintf(stderr, "creating foreign keys...\n");
4063  for (i = 0; i < lengthof(DDLKEYs); i++)
4064  {
4065  executeStatement(con, DDLKEYs[i]);
4066  }
4067 }
#define lengthof(array)
Definition: c.h:676
#define fprintf
Definition: port.h:219
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142
int i

◆ initCreatePKeys()

static void initCreatePKeys ( PGconn con)
static

Definition at line 4013 of file pgbench.c.

References appendPQExpBuffer(), appendPQExpBufferStr(), PQExpBufferData::data, executeStatement(), fprintf, i, initPQExpBuffer(), lengthof, PQescapeIdentifier(), PQfreemem(), resetPQExpBuffer(), and termPQExpBuffer().

Referenced by runInitSteps().

4014 {
4015  static const char *const DDLINDEXes[] = {
4016  "alter table pgbench_branches add primary key (bid)",
4017  "alter table pgbench_tellers add primary key (tid)",
4018  "alter table pgbench_accounts add primary key (aid)"
4019  };
4020  int i;
4021  PQExpBufferData query;
4022 
4023  fprintf(stderr, "creating primary keys...\n");
4024  initPQExpBuffer(&query);
4025 
4026  for (i = 0; i < lengthof(DDLINDEXes); i++)
4027  {
4028  resetPQExpBuffer(&query);
4029  appendPQExpBufferStr(&query, DDLINDEXes[i]);
4030 
4031  if (index_tablespace != NULL)
4032  {
4033  char *escape_tablespace;
4034 
4035  escape_tablespace = PQescapeIdentifier(con, index_tablespace,
4036  strlen(index_tablespace));
4037  appendPQExpBuffer(&query, " using index tablespace %s", escape_tablespace);
4038  PQfreemem(escape_tablespace);
4039  }
4040 
4041  executeStatement(con, query.data);
4042  }
4043 
4044  termPQExpBuffer(&query);
4045 }
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
#define lengthof(array)
Definition: c.h:676
#define fprintf
Definition: port.h:219
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:3570
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
char * index_tablespace
Definition: pgbench.c:190
int i
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:148
void PQfreemem(void *ptr)
Definition: fe-exec.c:3296
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ initCreateTables()

static void initCreateTables ( PGconn con)
static

Definition at line 3699 of file pgbench.c.

References appendPQExpBuffer(), createPartitions(), PQExpBufferData::data, executeStatement(), fprintf, i, initPQExpBuffer(), lengthof, PART_NONE, PQescapeIdentifier(), PQfreemem(), printfPQExpBuffer(), SCALE_32BIT_THRESHOLD, and termPQExpBuffer().

Referenced by runInitSteps().

3700 {
3701  /*
3702  * Note: TPC-B requires at least 100 bytes per row, and the "filler"
3703  * fields in these table declarations were intended to comply with that.
3704  * The pgbench_accounts table complies with that because the "filler"
3705  * column is set to blank-padded empty string. But for all other tables
3706  * the columns default to NULL and so don't actually take any space. We
3707  * could fix that by giving them non-null default values. However, that
3708  * would completely break comparability of pgbench results with prior
3709  * versions. Since pgbench has never pretended to be fully TPC-B compliant
3710  * anyway, we stick with the historical behavior.
3711  */
3712  struct ddlinfo
3713  {
3714  const char *table; /* table name */
3715  const char *smcols; /* column decls if accountIDs are 32 bits */
3716  const char *bigcols; /* column decls if accountIDs are 64 bits */
3717  int declare_fillfactor;
3718  };
3719  static const struct ddlinfo DDLs[] = {
3720  {
3721  "pgbench_history",
3722  "tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)",
3723  "tid int,bid int,aid bigint,delta int,mtime timestamp,filler char(22)",
3724  0
3725  },
3726  {
3727  "pgbench_tellers",
3728  "tid int not null,bid int,tbalance int,filler char(84)",
3729  "tid int not null,bid int,tbalance int,filler char(84)",
3730  1
3731  },
3732  {
3733  "pgbench_accounts",
3734  "aid int not null,bid int,abalance int,filler char(84)",
3735  "aid bigint not null,bid int,abalance int,filler char(84)",
3736  1
3737  },
3738  {
3739  "pgbench_branches",
3740  "bid int not null,bbalance int,filler char(88)",
3741  "bid int not null,bbalance int,filler char(88)",
3742  1
3743  }
3744  };
3745  int i;
3746  PQExpBufferData query;
3747 
3748  fprintf(stderr, "creating tables...\n");
3749 
3750  initPQExpBuffer(&query);
3751 
3752  for (i = 0; i < lengthof(DDLs); i++)
3753  {
3754  const struct ddlinfo *ddl = &DDLs[i];
3755 
3756  /* Construct new create table statement. */
3757  printfPQExpBuffer(&query, "create%s table %s(%s)",
3758  unlogged_tables ? " unlogged" : "",
3759  ddl->table,
3760  (scale >= SCALE_32BIT_THRESHOLD) ? ddl->bigcols : ddl->smcols);
3761 
3762  /* Partition pgbench_accounts table */
3763  if (partition_method != PART_NONE && strcmp(ddl->table, "pgbench_accounts") == 0)
3764  appendPQExpBuffer(&query,
3765  " partition by %s (aid)", PARTITION_METHOD[partition_method]);
3766  else if (ddl->declare_fillfactor)
3767  {
3768  /* fillfactor is only expected on actual tables */
3769  appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
3770  }
3771 
3772  if (tablespace != NULL)
3773  {
3774  char *escape_tablespace;
3775 
3776  escape_tablespace = PQescapeIdentifier(con, tablespace, strlen(tablespace));
3777  appendPQExpBuffer(&query, " tablespace %s", escape_tablespace);
3778  PQfreemem(escape_tablespace);
3779  }
3780 
3781  executeStatement(con, query.data);
3782  }
3783 
3784  termPQExpBuffer(&query);
3785 
3786  if (partition_method != PART_NONE)
3787  createPartitions(con);
3788 }
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
static partition_method_t partition_method
Definition: pgbench.c:206
int scale
Definition: pgbench.c:154
#define lengthof(array)
Definition: c.h:676
#define fprintf
Definition: port.h:219
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142
#define SCALE_32BIT_THRESHOLD
Definition: pgbench.c:228
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:3570
int fillfactor
Definition: pgbench.c:160
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
char * tablespace
Definition: pgbench.c:189
static const char * PARTITION_METHOD[]
Definition: pgbench.c:207
bool unlogged_tables
Definition: pgbench.c:165
int i
static void createPartitions(PGconn *con)
Definition: pgbench.c:3630
void PQfreemem(void *ptr)
Definition: fe-exec.c:3296
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ initDropTables()

static void initDropTables ( PGconn con)
static

Definition at line 3608 of file pgbench.c.

References executeStatement(), and fprintf.

Referenced by runInitSteps().

3609 {
3610  fprintf(stderr, "dropping old tables...\n");
3611 
3612  /*
3613  * We drop all the tables in one command, so that whether there are
3614  * foreign key dependencies or not doesn't matter.
3615  */
3616  executeStatement(con, "drop table if exists "
3617  "pgbench_accounts, "
3618  "pgbench_branches, "
3619  "pgbench_history, "
3620  "pgbench_tellers");
3621 }
#define fprintf
Definition: port.h:219
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142

◆ initGenerateDataClientSide()

static void initGenerateDataClientSide ( PGconn con)
static

Definition at line 3807 of file pgbench.c.

References CancelRequested, PQExpBufferData::data, executeStatement(), fprintf, i, initPQExpBuffer(), initTruncateTables(), INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, INT64_FORMAT, LOG_STEP_SECONDS, naccounts, nbranches, ntellers, pg_log_fatal, PGRES_COPY_IN, PQclear(), PQendcopy(), PQerrorMessage(), PQexec(), PQputline(), PQresultStatus(), printfPQExpBuffer(), scale, and termPQExpBuffer().

Referenced by runInitSteps().

3808 {
3809  PQExpBufferData sql;
3810  PGresult *res;
3811  int i;
3812  int64 k;
3813 
3814  /* used to track elapsed time and estimate of the remaining time */
3815  instr_time start,
3816  diff;
3817  double elapsed_sec,
3818  remaining_sec;
3819  int log_interval = 1;
3820 
3821  /* Stay on the same line if reporting to a terminal */
3822  char eol = isatty(fileno(stderr)) ? '\r' : '\n';
3823 
3824  fprintf(stderr, "generating data (client-side)...\n");
3825 
3826  /*
3827  * we do all of this in one transaction to enable the backend's
3828  * data-loading optimizations
3829  */
3830  executeStatement(con, "begin");
3831 
3832  /* truncate away any old data */
3833  initTruncateTables(con);
3834 
3835  initPQExpBuffer(&sql);
3836 
3837  /*
3838  * fill branches, tellers, accounts in that order in case foreign keys
3839  * already exist
3840  */
3841  for (i = 0; i < nbranches * scale; i++)
3842  {
3843  /* "filler" column defaults to NULL */
3844  printfPQExpBuffer(&sql,
3845  "insert into pgbench_branches(bid,bbalance) values(%d,0)",
3846  i + 1);
3847  executeStatement(con, sql.data);
3848  }
3849 
3850  for (i = 0; i < ntellers * scale; i++)
3851  {
3852  /* "filler" column defaults to NULL */
3853  printfPQExpBuffer(&sql,
3854  "insert into pgbench_tellers(tid,bid,tbalance) values (%d,%d,0)",
3855  i + 1, i / ntellers + 1);
3856  executeStatement(con, sql.data);
3857  }
3858 
3859  /*
3860  * accounts is big enough to be worth using COPY and tracking runtime
3861  */
3862  res = PQexec(con, "copy pgbench_accounts from stdin");
3863  if (PQresultStatus(res) != PGRES_COPY_IN)
3864  {
3865  pg_log_fatal("unexpected copy in result: %s", PQerrorMessage(con));
3866  exit(1);
3867  }
3868  PQclear(res);
3869 
3870  INSTR_TIME_SET_CURRENT(start);
3871 
3872  for (k = 0; k < (int64) naccounts * scale; k++)
3873  {
3874  int64 j = k + 1;
3875 
3876  /* "filler" column defaults to blank padded empty string */
3877  printfPQExpBuffer(&sql,
3878  INT64_FORMAT "\t" INT64_FORMAT "\t%d\t\n",
3879  j, k / naccounts + 1, 0);
3880  if (PQputline(con, sql.data))
3881  {
3882  pg_log_fatal("PQputline failed");
3883  exit(1);
3884  }
3885 
3886  if (CancelRequested)
3887  break;
3888 
3889  /*
3890  * If we want to stick with the original logging, print a message each
3891  * 100k inserted rows.
3892  */
3893  if ((!use_quiet) && (j % 100000 == 0))
3894  {
3895  INSTR_TIME_SET_CURRENT(diff);
3896  INSTR_TIME_SUBTRACT(diff, start);
3897 
3898  elapsed_sec = INSTR_TIME_GET_DOUBLE(diff);
3899  remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
3900 
3901  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c",
3902  j, (int64) naccounts * scale,
3903  (int) (((int64) j * 100) / (naccounts * (int64) scale)),
3904  elapsed_sec, remaining_sec, eol);
3905  }
3906  /* let's not call the timing for each row, but only each 100 rows */
3907  else if (use_quiet && (j % 100 == 0))
3908  {
3909  INSTR_TIME_SET_CURRENT(diff);
3910  INSTR_TIME_SUBTRACT(diff, start);
3911 
3912  elapsed_sec = INSTR_TIME_GET_DOUBLE(diff);
3913  remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
3914 
3915  /* have we reached the next interval (or end)? */
3916  if ((j == scale * naccounts) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS))
3917  {
3918  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c",
3919  j, (int64) naccounts * scale,
3920  (int) (((int64) j * 100) / (naccounts * (int64) scale)), elapsed_sec, remaining_sec, eol);
3921 
3922  /* skip to the next interval */
3923  log_interval = (int) ceil(elapsed_sec / LOG_STEP_SECONDS);
3924  }
3925  }
3926  }
3927 
3928  if (eol != '\n')
3929  fputc('\n', stderr); /* Need to move to next line */
3930 
3931  if (PQputline(con, "\\.\n"))
3932  {
3933  pg_log_fatal("very last PQputline failed");
3934  exit(1);
3935  }
3936  if (PQendcopy(con))
3937  {
3938  pg_log_fatal("PQendcopy failed");
3939  exit(1);
3940  }
3941 
3942  termPQExpBuffer(&sql);
3943 
3944  executeStatement(con, "commit");
3945 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6669
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
struct timeval instr_time
Definition: instr_time.h:150
int scale
Definition: pgbench.c:154
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:199
#define LOG_STEP_SECONDS
Definition: pgbench.c:138
#define fprintf
Definition: port.h:219
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2692
bool use_quiet
Definition: pgbench.c:231
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142
int PQputline(PGconn *conn, const char *s)
Definition: fe-exec.c:2585
#define nbranches
Definition: pgbench.c:216
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:170
#define ntellers
Definition: pgbench.c:218
#define naccounts
Definition: pgbench.c:219
void PQclear(PGresult *res)
Definition: fe-exec.c:694
int PQendcopy(PGconn *conn)
Definition: fe-exec.c:2618
static void initTruncateTables(PGconn *con)
Definition: pgbench.c:3794
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
#define INT64_FORMAT
Definition: c.h:417
volatile sig_atomic_t CancelRequested
Definition: cancel.c:52
int i
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1939
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
#define pg_log_fatal(...)
Definition: logging.h:76

◆ initGenerateDataServerSide()

static void initGenerateDataServerSide ( PGconn con)
static

Definition at line 3955 of file pgbench.c.

References PQExpBufferData::data, executeStatement(), fprintf, initPQExpBuffer(), initTruncateTables(), INT64_FORMAT, naccounts, nbranches, ntellers, printfPQExpBuffer(), and termPQExpBuffer().

Referenced by runInitSteps().

3956 {
3957  PQExpBufferData sql;
3958 
3959  fprintf(stderr, "generating data (server-side)...\n");
3960 
3961  /*
3962  * we do all of this in one transaction to enable the backend's
3963  * data-loading optimizations
3964  */
3965  executeStatement(con, "begin");
3966 
3967  /* truncate away any old data */
3968  initTruncateTables(con);
3969 
3970  initPQExpBuffer(&sql);
3971 
3972  printfPQExpBuffer(&sql,
3973  "insert into pgbench_branches(bid,bbalance) "
3974  "select bid, 0 "
3975  "from generate_series(1, %d) as bid", nbranches * scale);
3976  executeStatement(con, sql.data);
3977 
3978  printfPQExpBuffer(&sql,
3979  "insert into pgbench_tellers(tid,bid,tbalance) "
3980  "select tid, (tid - 1) / %d + 1, 0 "
3981  "from generate_series(1, %d) as tid", ntellers, ntellers * scale);
3982  executeStatement(con, sql.data);
3983 
3984  printfPQExpBuffer(&sql,
3985  "insert into pgbench_accounts(aid,bid,abalance,filler) "
3986  "select aid, (aid - 1) / %d + 1, 0, '' "
3987  "from generate_series(1, " INT64_FORMAT ") as aid",
3988  naccounts, (int64) naccounts * scale);
3989  executeStatement(con, sql.data);
3990 
3991  termPQExpBuffer(&sql);
3992 
3993  executeStatement(con, "commit");
3994 }
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
int scale
Definition: pgbench.c:154
#define fprintf
Definition: port.h:219
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142
#define nbranches
Definition: pgbench.c:216
#define ntellers
Definition: pgbench.c:218
#define naccounts
Definition: pgbench.c:219
static void initTruncateTables(PGconn *con)
Definition: pgbench.c:3794
#define INT64_FORMAT
Definition: c.h:417
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ initRandomState()

static void initRandomState ( RandomState random_state)
static

Definition at line 831 of file pgbench.c.

References pg_jrand48(), and RandomState::xseed.

Referenced by main().

832 {
833  random_state->xseed[0] = (unsigned short)
835  random_state->xseed[1] = (unsigned short)
837  random_state->xseed[2] = (unsigned short)
839 }
static RandomState base_random_sequence
Definition: pgbench.c:312
unsigned short xseed[3]
Definition: pgbench.c:308
long pg_jrand48(unsigned short xseed[3])
Definition: erand48.c:112

◆ initSimpleStats()

static void initSimpleStats ( SimpleStats ss)
static

Definition at line 1068 of file pgbench.c.

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

1069 {
1070  memset(ss, 0, sizeof(SimpleStats));
1071 }

◆ initStats()

static void initStats ( StatsData sd,
time_t  start_time 
)
static

Definition at line 1108 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(), printProgressReport(), and threadRun().

1109 {
1110  sd->start_time = start_time;
1111  sd->cnt = 0;
1112  sd->skipped = 0;
1113  initSimpleStats(&sd->latency);
1114  initSimpleStats(&sd->lag);
1115 }
time_t start_time
Definition: pgbench.c:295
SimpleStats lag
Definition: pgbench.c:300
SimpleStats latency
Definition: pgbench.c:299
static time_t start_time
Definition: pg_ctl.c:99
int64 cnt
Definition: pgbench.c:296
int64 skipped
Definition: pgbench.c:297
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1068

◆ initTruncateTables()

static void initTruncateTables ( PGconn con)
static

Definition at line 3794 of file pgbench.c.

References executeStatement().

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

3795 {
3796  executeStatement(con, "truncate table "
3797  "pgbench_accounts, "
3798  "pgbench_branches, "
3799  "pgbench_history, "
3800  "pgbench_tellers");
3801 }
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142

◆ initVacuum()

static void initVacuum ( PGconn con)
static

Definition at line 4000 of file pgbench.c.

References executeStatement(), and fprintf.

Referenced by runInitSteps().

4001 {
4002  fprintf(stderr, "vacuuming...\n");
4003  executeStatement(con, "vacuum analyze pgbench_branches");
4004  executeStatement(con, "vacuum analyze pgbench_tellers");
4005  executeStatement(con, "vacuum analyze pgbench_accounts");
4006  executeStatement(con, "vacuum analyze pgbench_history");
4007 }
#define fprintf
Definition: port.h:219
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142

◆ is_an_int()

static bool is_an_int ( const char *  str)
static

Definition at line 694 of file pgbench.c.

References generate_unaccent_rules::str.

Referenced by makeVariableValue().

695 {
696  const char *ptr = str;
697 
698  /* skip leading spaces; cast is consistent with strtoint64 */
699  while (*ptr && isspace((unsigned char) *ptr))
700  ptr++;
701 
702  /* skip sign */
703  if (*ptr == '+' || *ptr == '-')
704  ptr++;
705 
706  /* at least one digit */
707  if (*ptr && !isdigit((unsigned char) *ptr))
708  return false;
709 
710  /* eat all digits */
711  while (*ptr && isdigit((unsigned char) *ptr))
712  ptr++;
713 
714  /* must have reached end of string */
715  return *ptr == '\0';
716 }

◆ isLazyFunc()

static bool isLazyFunc ( PgBenchFunction  func)
static

Definition at line 1743 of file pgbench.c.

References PGBENCH_AND, PGBENCH_CASE, and PGBENCH_OR.

Referenced by evalFunc(), and evalLazyFunc().

1744 {
1745  return func == PGBENCH_AND || func == PGBENCH_OR || func == PGBENCH_CASE;
1746 }

◆ listAvailableScripts()

static void listAvailableScripts ( void  )
static

Definition at line 4972 of file pgbench.c.

References fprintf, i, lengthof, and name.

Referenced by findBuiltin(), and main().

4973 {
4974  int i;
4975 
4976  fprintf(stderr, "Available builtin scripts:\n");
4977  for (i = 0; i < lengthof(builtin_script); i++)
4978  fprintf(stderr, " %13s: %s\n", builtin_script[i].name, builtin_script[i].desc);
4979  fprintf(stderr, "\n");
4980 }
#define lengthof(array)
Definition: c.h:676
#define fprintf
Definition: port.h:219
static const BuiltinScript builtin_script[]
Definition: pgbench.c:555
const char * name
Definition: encode.c:561
int i

◆ lookupCreateVariable()

static Variable* lookupCreateVariable ( CState st,
const char *  context,
char *  name 
)
static

Definition at line 1407 of file pgbench.c.

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

Referenced by putVariable(), and putVariableValue().

1408 {
1409  Variable *var;
1410 
1411  var = lookupVariable(st, name);
1412  if (var == NULL)
1413  {
1414  Variable *newvars;
1415 
1416  /*
1417  * Check for the name only when declaring a new variable to avoid
1418  * overhead.
1419  */
1420  if (!valid_variable_name(name))
1421  {
1422  pg_log_error("%s: invalid variable name: \"%s\"", context, name);
1423  return NULL;
1424  }
1425 
1426  /* Create variable at the end of the array */
1427  if (st->variables)
1428  newvars = (Variable *) pg_realloc(st->variables,
1429  (st->nvariables + 1) * sizeof(Variable));
1430  else
1431  newvars = (Variable *) pg_malloc(sizeof(Variable));
1432 
1433  st->variables = newvars;
1434 
1435  var = &newvars[st->nvariables];
1436 
1437  var->name = pg_strdup(name);
1438  var->svalue = NULL;
1439  /* caller is expected to initialize remaining fields */
1440 
1441  st->nvariables++;
1442  /* we don't re-sort the array till we have to */
1443  st->vars_sorted = false;
1444  }
1445 
1446  return var;
1447 }
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:1247
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
char * name
Definition: pgbench.c:266
#define pg_log_error(...)
Definition: logging.h:80
static bool valid_variable_name(const char *name)
Definition: pgbench.c:1380
Variable * variables
Definition: pgbench.c:416
bool vars_sorted
Definition: pgbench.c:418
char * svalue
Definition: pgbench.c:267
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
const char * name
Definition: encode.c:561
int nvariables
Definition: pgbench.c:417

◆ lookupVariable()

static Variable* lookupVariable ( CState st,
char *  name 
)
static

Definition at line 1247 of file pgbench.c.

References compareVariableNames(), sort-test::key, Variable::name, name, CState::nvariables, qsort, CState::variables, and CState::vars_sorted.

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

1248 {
1249  Variable key;
1250 
1251  /* On some versions of Solaris, bsearch of zero items dumps core */
1252  if (st->nvariables <= 0)
1253  return NULL;
1254 
1255  /* Sort if we have to */
1256  if (!st->vars_sorted)
1257  {
1258  qsort((void *) st->variables, st->nvariables, sizeof(Variable),
1260  st->vars_sorted = true;
1261  }
1262 
1263  /* Now we can search */
1264  key.name = name;
1265  return (Variable *) bsearch((void *) &key,
1266  (void *) st->variables,
1267  st->nvariables,
1268  sizeof(Variable),
1270 }
char * name
Definition: pgbench.c:266
static int compareVariableNames(const void *v1, const void *v2)
Definition: pgbench.c:1239
Variable * variables
Definition: pgbench.c:416
bool vars_sorted
Definition: pgbench.c:418
const char * name
Definition: encode.c:561
int nvariables
Definition: pgbench.c:417
#define qsort(a, b, c, d)
Definition: port.h:497

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 5378 of file pgbench.c.

References _, Assert, checkInitSteps(), StatsData::cnt, ParsedScript::commands, conditional_stack_create(), TState::conn_time, CONNECTION_BAD, CState::cstack, CSTATE_ABORTED, DEFAULT_INIT_STEPS, DEFAULT_NXACTS, BuiltinScript::desc, disconnect_all(), doConnect(), findBuiltin(), fprintf, get_progname(), getopt_long(), GetTableInfo(), i, CState::id, initRandomState(), initStats(), INSTR_TIME_ADD, INSTR_TIME_GET_MICROSEC, INSTR_TIME_SET_CURRENT, INSTR_TIME_SET_ZERO, INSTR_TIME_SUBTRACT, INVALID_THREAD, StatsData::lag, StatsData::latency, TState::latency_late, listAvailableScripts(), TState::logfile, login, lookupVariable(), mergeSimpleStats(), Variable::name, BuiltinScript::name, nclients, no_argument, TState::nstate, nthreads, NUM_QUERYMODE, num_scripts, CState::nvariables, optarg, optind, parseScriptWeight(), PART_HASH, PART_NONE, PART_RANGE, pg_free(), pg_jrand48(), pg_log_debug, pg_log_fatal, pg_log_info, pg_logging_increase_verbosity(), pg_logging_init(), pg_malloc(), pg_malloc0(), pg_realloc(), pg_strcasecmp(), pg_strdup(), PGBT_NO_VALUE, postprocess_sql_command(), PQerrorMessage(), PQfinish(), PQstatus(), printResults(), process_builtin(), process_file(), putVariable(), putVariableInt(), putVariableValue(), required_argument, runInitSteps(), BuiltinScript::script, set_random_seed(), setalarm(), StatsData::skipped, SQL_COMMAND, start_time, TState::start_time, CState::state, TState::state, TState::stats, Variable::svalue, TState::thread, threadRun(), TState::tid, tryExecuteStatement(), TState::ts_choose_rs, TState::ts_sample_rs, TState::ts_throttle_rs, PgBenchValue::type, generate_unaccent_rules::type, usage(), Variable::value, CState::variables, ParsedScript::weight, and RandomState::xseed.

5379 {
5380  static struct option long_options[] = {
5381  /* systematic long/short named options */
5382  {"builtin", required_argument, NULL, 'b'},
5383  {"client", required_argument, NULL, 'c'},
5384  {"connect", no_argument, NULL, 'C'},
5385  {"debug", no_argument, NULL, 'd'},
5386  {"define", required_argument, NULL, 'D'},
5387  {"file", required_argument, NULL, 'f'},
5388  {"fillfactor", required_argument, NULL, 'F'},
5389  {"host", required_argument, NULL, 'h'},
5390  {"initialize", no_argument, NULL, 'i'},
5391  {"init-steps", required_argument, NULL, 'I'},
5392  {"jobs", required_argument, NULL, 'j'},
5393  {"log", no_argument, NULL, 'l'},
5394  {"latency-limit", required_argument, NULL, 'L'},
5395  {"no-vacuum", no_argument, NULL, 'n'},
5396  {"port", required_argument, NULL, 'p'},
5397  {"progress", required_argument, NULL, 'P'},
5398  {"protocol", required_argument, NULL, 'M'},
5399  {"quiet", no_argument, NULL, 'q'},
5400  {"report-latencies", no_argument, NULL, 'r'},
5401  {"rate", required_argument, NULL, 'R'},
5402  {"scale", required_argument, NULL, 's'},
5403  {"select-only", no_argument, NULL, 'S'},
5404  {"skip-some-updates", no_argument, NULL, 'N'},
5405  {"time", required_argument, NULL, 'T'},
5406  {"transactions", required_argument, NULL, 't'},
5407  {"username", required_argument, NULL, 'U'},
5408  {"vacuum-all", no_argument, NULL, 'v'},
5409  /* long-named only options */
5410  {"unlogged-tables", no_argument, NULL, 1},
5411  {"tablespace", required_argument, NULL, 2},
5412  {"index-tablespace", required_argument, NULL, 3},
5413  {"sampling-rate", required_argument, NULL, 4},
5414  {"aggregate-interval", required_argument, NULL, 5},
5415  {"progress-timestamp", no_argument, NULL, 6},
5416  {"log-prefix", required_argument, NULL, 7},
5417  {"foreign-keys", no_argument, NULL, 8},
5418  {"random-seed", required_argument, NULL, 9},
5419  {"show-script", required_argument, NULL, 10},
5420  {"partitions", required_argument, NULL, 11},
5421  {"partition-method", required_argument, NULL, 12},
5422  {NULL, 0, NULL, 0}
5423  };
5424 
5425  int c;
5426  bool is_init_mode = false; /* initialize mode? */
5427  char *initialize_steps = NULL;
5428  bool foreign_keys = false;
5429  bool is_no_vacuum = false;
5430  bool do_vacuum_accounts = false; /* vacuum accounts table? */
5431  int optindex;
5432  bool scale_given = false;
5433 
5434  bool benchmarking_option_set = false;
5435  bool initialization_option_set = false;
5436  bool internal_script_used = false;
5437 
5438  CState *state; /* status of clients */
5439  TState *threads; /* array of thread */
5440 
5441  instr_time start_time; /* start up time */
5442  instr_time total_time;
5443  instr_time conn_total_time;
5444  int64 latency_late = 0;
5445  StatsData stats;
5446  int weight;
5447 
5448  int i;
5449  int nclients_dealt;
5450 
5451 #ifdef HAVE_GETRLIMIT
5452  struct rlimit rlim;
5453 #endif
5454 
5455  PGconn *con;
5456  char *env;
5457 
5458  int exit_code = 0;
5459 
5460  pg_logging_init(argv[0]);
5461  progname = get_progname(argv[0]);
5462 
5463  if (argc > 1)
5464  {
5465  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
5466  {
5467  usage();
5468  exit(0);
5469  }
5470  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
5471  {
5472  puts("pgbench (PostgreSQL) " PG_VERSION);
5473  exit(0);
5474  }
5475  }
5476 
5477  if ((env = getenv("PGHOST")) != NULL && *env != '\0')
5478  pghost = env;
5479  if ((env = getenv("PGPORT")) != NULL && *env != '\0')
5480  pgport = env;
5481  else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
5482  login = env;
5483 
5484  state = (CState *) pg_malloc0(sizeof(CState));
5485 
5486  /* set random seed early, because it may be used while parsing scripts. */
5487  if (!set_random_seed(getenv("PGBENCH_RANDOM_SEED")))
5488  {
5489  pg_log_fatal("error while setting random seed from PGBENCH_RANDOM_SEED environment variable");
5490  exit(1);
5491  }
5492 
5493  while ((c = getopt_long(argc, argv, "iI:h:nvp:dqb:SNc:j:Crs:t:T:U:lf:D:F:M:P:R:L:", long_options, &optindex)) != -1)
5494  {
5495  char *script;
5496 
5497  switch (c)
5498  {
5499  case 'i':
5500  is_init_mode = true;
5501  break;
5502  case 'I':
5503  if (initialize_steps)
5504  pg_free(initialize_steps);
5505  initialize_steps = pg_strdup(optarg);
5506  checkInitSteps(initialize_steps);
5507  initialization_option_set = true;
5508  break;
5509  case 'h':
5510  pghost = pg_strdup(optarg);
5511  break;
5512  case 'n':
5513  is_no_vacuum = true;
5514  break;
5515  case 'v':
5516  benchmarking_option_set = true;
5517  do_vacuum_accounts = true;
5518  break;
5519  case 'p':
5520  pgport = pg_strdup(optarg);
5521  break;
5522  case 'd':