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 "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_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 append_fillfactor (char *opts, int len)
 
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, 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 int debug = 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 135 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 134 of file pgbench.c.

Referenced by main(), and usage().

◆ DEFAULT_NXACTS

#define DEFAULT_NXACTS   10 /* default nxacts */

Definition at line 138 of file pgbench.c.

Referenced by main().

◆ ERRCODE_UNDEFINED_TABLE

◆ FNV_OFFSET_BASIS

#define FNV_OFFSET_BASIS   UINT64CONST(0xcbf29ce484222325)

Definition at line 79 of file pgbench.c.

Referenced by getHashFnv1a().

◆ FNV_PRIME

#define FNV_PRIME   UINT64CONST(0x100000001b3)

Definition at line 78 of file pgbench.c.

Referenced by getHashFnv1a().

◆ INVALID_THREAD

#define INVALID_THREAD   ((pthread_t) 0)

Definition at line 461 of file pgbench.c.

Referenced by main().

◆ LOG_STEP_SECONDS

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

Definition at line 137 of file pgbench.c.

Referenced by initGenerateDataClientSide().

◆ M_PI

#define M_PI   3.14159265358979323846

Definition at line 69 of file pgbench.c.

Referenced by evalStandardFunc(), and getGaussianRand().

◆ MAX_ARGS

#define MAX_ARGS   256

Definition at line 473 of file pgbench.c.

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

◆ MAX_FARGS

#define MAX_FARGS   16

Definition at line 1866 of file pgbench.c.

Referenced by evalStandardFunc().

◆ MAX_PREPARE_NAME

#define MAX_PREPARE_NAME   32

Definition at line 2619 of file pgbench.c.

Referenced by sendCommand().

◆ MAX_SCRIPTS

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

Definition at line 270 of file pgbench.c.

Referenced by addScript().

◆ MAX_ZIPFIAN_PARAM

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

Definition at line 143 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 140 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 142 of file pgbench.c.

Referenced by evalStandardFunc(), and getZipfianRand().

◆ MM2_MUL

#define MM2_MUL   UINT64CONST(0xc6a4a7935bd1e995)

Definition at line 80 of file pgbench.c.

Referenced by getHashMurmur2().

◆ MM2_MUL_TIMES_8

#define MM2_MUL_TIMES_8   UINT64CONST(0x35253c9ade8f4ca8)

Definition at line 81 of file pgbench.c.

Referenced by getHashMurmur2().

◆ MM2_ROT

#define MM2_ROT   47

Definition at line 82 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 215 of file pgbench.c.

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

◆ ntellers

#define ntellers   10

Definition at line 217 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 127 of file pgbench.c.

Referenced by main(), and socket_has_input().

◆ SCALE_32BIT_THRESHOLD

#define SCALE_32BIT_THRESHOLD   20000

Definition at line 227 of file pgbench.c.

Referenced by initCreateTables().

◆ SHELL_COMMAND_SIZE

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

Definition at line 271 of file pgbench.c.

Referenced by runShellCommand().

◆ SOCKET_WAIT_METHOD

#define SOCKET_WAIT_METHOD   "select"

Definition at line 101 of file pgbench.c.

Referenced by threadRun().

◆ SQL_COMMAND

#define SQL_COMMAND   1

◆ WSEP

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

Definition at line 249 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 316 of file pgbench.c.

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

◆ MetaCommand

Enumerator
META_NONE 
META_SET 
META_SETSHELL 
META_SHELL 
META_SLEEP 
META_GSET 
META_IF 
META_ELIF 
META_ELSE 
META_ENDIF 

Definition at line 475 of file pgbench.c.

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

◆ partition_method_t

Enumerator
PART_NONE 
PART_RANGE 
PART_HASH 

Definition at line 198 of file pgbench.c.

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

◆ QueryMode

enum QueryMode
Enumerator
QUERY_SIMPLE 
QUERY_EXTENDED 
QUERY_PREPARED 
NUM_QUERYMODE 

Definition at line 489 of file pgbench.c.

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

Function Documentation

◆ accumStats()

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

Definition at line 1123 of file pgbench.c.

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

Referenced by doLog(), and processXactStats().

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

◆ add_socket_to_set()

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

Definition at line 6714 of file pgbench.c.

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

Referenced by setalarm(), and threadRun().

6715 {
6716  if (fd < 0 || fd >= FD_SETSIZE)
6717  {
6718  /*
6719  * Doing a hard exit here is a bit grotty, but it doesn't seem worth
6720  * complicating the API to make it less grotty.
6721  */
6722  fprintf(stderr, "too many client connections for select()\n");
6723  exit(1);
6724  }
6725  FD_SET(fd, &sa->fds);
6726  if (fd > sa->maxfd)
6727  sa->maxfd = fd;
6728 }
#define fprintf
Definition: port.h:196
static int fd(const char *x, int i)
Definition: preproc-init.c:105
fd_set fds
Definition: pgbench.c:106
int maxfd
Definition: pgbench.c:105

◆ addScript()

static void addScript ( ParsedScript  script)
static

Definition at line 5060 of file pgbench.c.

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

Referenced by ParseScript().

5061 {
5062  if (script.commands == NULL || script.commands[0] == NULL)
5063  {
5064  fprintf(stderr, "empty command list for script \"%s\"\n", script.desc);
5065  exit(1);
5066  }
5067 
5068  if (num_scripts >= MAX_SCRIPTS)
5069  {
5070  fprintf(stderr, "at most %d SQL scripts are allowed\n", MAX_SCRIPTS);
5071  exit(1);
5072  }
5073 
5074  CheckConditional(script);
5075 
5076  sql_script[num_scripts] = script;
5077  num_scripts++;
5078 }
static int num_scripts
Definition: pgbench.c:540
#define MAX_SCRIPTS
Definition: pgbench.c:270
#define fprintf
Definition: port.h:196
static void CheckConditional(ParsedScript ps)
Definition: pgbench.c:4709
const char * desc
Definition: pgbench.c:533
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:539
Command ** commands
Definition: pgbench.c:535

◆ addToSimpleStats()

static void addToSimpleStats ( SimpleStats ss,
double  val 
)
static

Definition at line 1079 of file pgbench.c.

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

Referenced by accumStats(), and advanceConnectionState().

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

◆ advanceConnectionState()

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

Definition at line 2887 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(), fprintf, 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(), 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().

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

◆ alloc_socket_set()

static socket_set * alloc_socket_set ( int  count)
static

Definition at line 6695 of file pgbench.c.

References pg_malloc0().

Referenced by setalarm(), and threadRun().

6696 {
6697  return (socket_set *) pg_malloc0(sizeof(socket_set));
6698 }
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53

◆ append_fillfactor()

static void append_fillfactor ( char *  opts,
int  len 
)
static

Definition at line 3800 of file pgbench.c.

References snprintf.

Referenced by createPartitions(), and initCreateTables().

3801 {
3802  snprintf(opts + strlen(opts), len - strlen(opts),
3803  " with (fillfactor=%d)", fillfactor);
3804 }
int fillfactor
Definition: pgbench.c:159
#define snprintf
Definition: port.h:192

◆ assignVariables()

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

Definition at line 1561 of file pgbench.c.

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

Referenced by sendCommand().

1562 {
1563  char *p,
1564  *name,
1565  *val;
1566 
1567  p = sql;
1568  while ((p = strchr(p, ':')) != NULL)
1569  {
1570  int eaten;
1571 
1572  name = parseVariable(p, &eaten);
1573  if (name == NULL)
1574  {
1575  while (*p == ':')
1576  {
1577  p++;
1578  }
1579  continue;
1580  }
1581 
1582  val = getVariable(st, name);
1583  free(name);
1584  if (val == NULL)
1585  {
1586  p++;
1587  continue;
1588  }
1589 
1590  p = replaceVariable(&sql, p, eaten, val);
1591  }
1592 
1593  return sql;
1594 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1278
static char * replaceVariable(char **sql, char *param, int len, char *value)
Definition: pgbench.c:1541
#define free(a)
Definition: header.h:65
static char * parseVariable(const char *sql, int *eaten)
Definition: pgbench.c:1518
const char * name
Definition: encode.c:521
long val
Definition: informix.c:684

◆ CheckConditional()

static void CheckConditional ( ParsedScript  ps)
static

Definition at line 4709 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().

4710 {
4711  /* statically check conditional structure */
4713  int i;
4714 
4715  for (i = 0; ps.commands[i] != NULL; i++)
4716  {
4717  Command *cmd = ps.commands[i];
4718 
4719  if (cmd->type == META_COMMAND)
4720  {
4721  switch (cmd->meta)
4722  {
4723  case META_IF:
4725  break;
4726  case META_ELIF:
4727  if (conditional_stack_empty(cs))
4728  ConditionError(ps.desc, i + 1, "\\elif without matching \\if");
4730  ConditionError(ps.desc, i + 1, "\\elif after \\else");
4731  break;
4732  case META_ELSE:
4733  if (conditional_stack_empty(cs))
4734  ConditionError(ps.desc, i + 1, "\\else without matching \\if");
4736  ConditionError(ps.desc, i + 1, "\\else after \\else");
4738  break;
4739  case META_ENDIF:
4740  if (!conditional_stack_pop(cs))
4741  ConditionError(ps.desc, i + 1, "\\endif without matching \\if");
4742  break;
4743  default:
4744  /* ignore anything else... */
4745  break;
4746  }
4747  }
4748  }
4749  if (!conditional_stack_empty(cs))
4750  ConditionError(ps.desc, i + 1, "\\if without matching \\endif");
4752 }
int type
Definition: pgbench.c:522
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:57
static void ConditionError(const char *desc, int cmdn, const char *msg)
Definition: pgbench.c:4697
void conditional_stack_push(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:41
#define META_COMMAND
Definition: pgbench.c:467
const char * desc
Definition: pgbench.c:533
MetaCommand meta
Definition: pgbench.c:523
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:535
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 4073 of file pgbench.c.

References ALL_INIT_STEPS, and fprintf.

Referenced by main().

4074 {
4075  if (initialize_steps[0] == '\0')
4076  {
4077  fprintf(stderr, "no initialization steps specified\n");
4078  exit(1);
4079  }
4080 
4081  for (const char *step = initialize_steps; *step != '\0'; step++)
4082  {
4083  if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
4084  {
4085  fprintf(stderr,
4086  "unrecognized initialization step \"%c\"\n",
4087  *step);
4088  fprintf(stderr,
4089  "Allowed step characters are: \"" ALL_INIT_STEPS "\".\n");
4090  exit(1);
4091  }
4092  }
4093 }
#define ALL_INIT_STEPS
Definition: pgbench.c:135
#define fprintf
Definition: port.h:196

◆ chooseScript()

static int chooseScript ( TState thread)
static

Definition at line 2636 of file pgbench.c.

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

Referenced by advanceConnectionState().

2637 {
2638  int i = 0;
2639  int64 w;
2640 
2641  if (num_scripts == 1)
2642  return 0;
2643 
2644  w = getrand(&thread->ts_choose_rs, 0, total_weight - 1);
2645  do
2646  {
2647  w -= sql_script[i++].weight;
2648  } while (w >= 0);
2649 
2650  return i - 1;
2651 }
static int num_scripts
Definition: pgbench.c:540
static int64 getrand(RandomState *random_state, int64 min, int64 max)
Definition: pgbench.c:852
int weight
Definition: pgbench.c:534
RandomState ts_choose_rs
Definition: pgbench.c:447
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:539
static int64 total_weight
Definition: pgbench.c:541
int i

◆ clear_socket_set()

static void clear_socket_set ( socket_set sa)
static

Definition at line 6707 of file pgbench.c.

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

Referenced by setalarm(), and threadRun().

6708 {
6709  FD_ZERO(&sa->fds);
6710  sa->maxfd = -1;
6711 }
fd_set fds
Definition: pgbench.c:106
int maxfd
Definition: pgbench.c:105

◆ coerceToBool()

static bool coerceToBool ( PgBenchValue pval,
bool bval 
)
static

Definition at line 1628 of file pgbench.c.

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

Referenced by evalLazyFunc(), and evalStandardFunc().

1629 {
1630  if (pval->type == PGBT_BOOLEAN)
1631  {
1632  *bval = pval->u.bval;
1633  return true;
1634  }
1635  else /* NULL, INT or DOUBLE */
1636  {
1637  fprintf(stderr, "cannot coerce %s to boolean\n", valueTypeName(pval));
1638  *bval = false; /* suppress uninitialized-variable warnings */
1639  return false;
1640  }
1641 }
union PgBenchValue::@39 u
#define fprintf
Definition: port.h:196
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1606
bool bval
Definition: pgbench.h:51
PgBenchValueType type
Definition: pgbench.h:46

◆ coerceToDouble()

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

Definition at line 1697 of file pgbench.c.

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

Referenced by evalStandardFunc().

1698 {
1699  if (pval->type == PGBT_DOUBLE)
1700  {
1701  *dval = pval->u.dval;
1702  return true;
1703  }
1704  else if (pval->type == PGBT_INT)
1705  {
1706  *dval = (double) pval->u.ival;
1707  return true;
1708  }
1709  else /* BOOLEAN or NULL */
1710  {
1711  fprintf(stderr, "cannot coerce %s to double\n", valueTypeName(pval));
1712  return false;
1713  }
1714 }
union PgBenchValue::@39 u
#define fprintf
Definition: port.h:196
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1606
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 1669 of file pgbench.c.

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

Referenced by evalStandardFunc().

1670 {
1671  if (pval->type == PGBT_INT)
1672  {
1673  *ival = pval->u.ival;
1674  return true;
1675  }
1676  else if (pval->type == PGBT_DOUBLE)
1677  {
1678  double dval = rint(pval->u.dval);
1679 
1680  if (isnan(dval) || !FLOAT8_FITS_IN_INT64(dval))
1681  {
1682  fprintf(stderr, "double to int overflow for %f\n", dval);
1683  return false;
1684  }
1685  *ival = (int64) dval;
1686  return true;
1687  }
1688  else /* BOOLEAN or NULL */
1689  {
1690  fprintf(stderr, "cannot coerce %s to int\n", valueTypeName(pval));
1691  return false;
1692  }
1693 }
union PgBenchValue::@39 u
#define fprintf
Definition: port.h:196
#define FLOAT8_FITS_IN_INT64(num)
Definition: c.h:1055
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1606
double rint(double x)
Definition: rint.c:21
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 2627 of file pgbench.c.

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

Referenced by advanceConnectionState(), and executeMetaCommand().

2628 {
2629  fprintf(stderr,
2630  "client %d aborted in command %d (%s) of script %d; %s\n",
2631  st->id, st->command, cmd, st->use_file, message);
2632 }
int id
Definition: pgbench.c:401
#define fprintf
Definition: port.h:196
int command
Definition: pgbench.c:412
int use_file
Definition: pgbench.c:411

◆ compareVariableNames()

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

Definition at line 1243 of file pgbench.c.

References name.

Referenced by lookupVariable().

1244 {
1245  return strcmp(((const Variable *) v1)->name,
1246  ((const Variable *) v2)->name);
1247 }
const char * name
Definition: encode.c:521

◆ computeIterativeZipfian()

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

Definition at line 978 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by getZipfianRand().

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

◆ ConditionError()

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

Definition at line 4697 of file pgbench.c.

References fprintf.

Referenced by CheckConditional().

4698 {
4699  fprintf(stderr,
4700  "condition error in script \"%s\" command %d: %s\n",
4701  desc, cmdn, msg);
4702  exit(1);
4703 }
#define fprintf
Definition: port.h:196

◆ create_sql_command()

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

Definition at line 4432 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().

4433 {
4434  Command *my_command;
4435  char *p = skip_sql_comments(buf->data);
4436 
4437  if (p == NULL)
4438  return NULL;
4439 
4440  /* Allocate and initialize Command structure */
4441  my_command = (Command *) pg_malloc(sizeof(Command));
4442  initPQExpBuffer(&my_command->lines);
4443  appendPQExpBufferStr(&my_command->lines, p);
4444  my_command->first_line = NULL; /* this is set later */
4445  my_command->type = SQL_COMMAND;
4446  my_command->meta = META_NONE;
4447  my_command->argc = 0;
4448  memset(my_command->argv, 0, sizeof(my_command->argv));
4449  my_command->varprefix = NULL; /* allocated later, if needed */
4450  my_command->expr = NULL;
4451  initSimpleStats(&my_command->stats);
4452 
4453  return my_command;
4454 }
int type
Definition: pgbench.c:522
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:527
static char * skip_sql_comments(char *sql_command)
Definition: pgbench.c:4397
char * argv[MAX_ARGS]
Definition: pgbench.c:525
MetaCommand meta
Definition: pgbench.c:523
PQExpBufferData lines
Definition: pgbench.c:520
int argc
Definition: pgbench.c:524
#define SQL_COMMAND
Definition: pgbench.c:466
SimpleStats stats
Definition: pgbench.c:528
char * varprefix
Definition: pgbench.c:526
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1070
char * first_line
Definition: pgbench.c:521
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ createPartitions()

static void createPartitions ( PGconn con)
static

Definition at line 3634 of file pgbench.c.

References append_fillfactor(), Assert, executeStatement(), fprintf, INT64_FORMAT, naccounts, PART_HASH, PART_RANGE, partitions, snprintf, and sprintf.

Referenced by initCreateTables().

3635 {
3636  char ff[64];
3637 
3638  ff[0] = '\0';
3639 
3640  /*
3641  * Per ddlinfo in initCreateTables, fillfactor is needed on table
3642  * pgbench_accounts.
3643  */
3644  append_fillfactor(ff, sizeof(ff));
3645 
3646  /* we must have to create some partitions */
3647  Assert(partitions > 0);
3648 
3649  fprintf(stderr, "creating %d partitions...\n", partitions);
3650 
3651  for (int p = 1; p <= partitions; p++)
3652  {
3653  char query[256];
3654 
3656  {
3657  int64 part_size = (naccounts * (int64) scale + partitions - 1) / partitions;
3658  char minvalue[32],
3659  maxvalue[32];
3660 
3661  /*
3662  * For RANGE, we use open-ended partitions at the beginning and
3663  * end to allow any valid value for the primary key. Although the
3664  * actual minimum and maximum values can be derived from the
3665  * scale, it is more generic and the performance is better.
3666  */
3667  if (p == 1)
3668  sprintf(minvalue, "minvalue");
3669  else
3670  sprintf(minvalue, INT64_FORMAT, (p - 1) * part_size + 1);
3671 
3672  if (p < partitions)
3673  sprintf(maxvalue, INT64_FORMAT, p * part_size + 1);
3674  else
3675  sprintf(maxvalue, "maxvalue");
3676 
3677  snprintf(query, sizeof(query),
3678  "create%s table pgbench_accounts_%d\n"
3679  " partition of pgbench_accounts\n"
3680  " for values from (%s) to (%s)%s\n",
3681  unlogged_tables ? " unlogged" : "", p,
3682  minvalue, maxvalue, ff);
3683  }
3684  else if (partition_method == PART_HASH)
3685  snprintf(query, sizeof(query),
3686  "create%s table pgbench_accounts_%d\n"
3687  " partition of pgbench_accounts\n"
3688  " for values with (modulus %d, remainder %d)%s\n",
3689  unlogged_tables ? " unlogged" : "", p,
3690  partitions, p - 1, ff);
3691  else /* cannot get there */
3692  Assert(0);
3693 
3694  executeStatement(con, query);
3695  }
3696 }
static int partitions
Definition: pgbench.c:195
static partition_method_t partition_method
Definition: pgbench.c:205
int scale
Definition: pgbench.c:153
#define fprintf
Definition: port.h:196
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1144
#define sprintf
Definition: port.h:194
static void append_fillfactor(char *opts, int len)
Definition: pgbench.c:3800
#define naccounts
Definition: pgbench.c:218
#define Assert(condition)
Definition: c.h:733
#define INT64_FORMAT
Definition: c.h:401
bool unlogged_tables
Definition: pgbench.c:164
#define snprintf
Definition: port.h:192

◆ disconnect_all()

static void disconnect_all ( CState state,
int  length 
)
static

Definition at line 3600 of file pgbench.c.

References finishCon(), and i.

Referenced by main(), and threadRun().

3601 {
3602  int i;
3603 
3604  for (i = 0; i < length; i++)
3605  finishCon(&state[i]);
3606 }
static void finishCon(CState *st)
Definition: pgbench.c:6527
int i

◆ doConnect()

static PGconn* doConnect ( void  )
static

Definition at line 1174 of file pgbench.c.

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

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

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

◆ doLog()

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

Definition at line 3473 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().

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

◆ evalFunc()

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

Definition at line 2420 of file pgbench.c.

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

Referenced by evaluateExpr().

2422 {
2423  if (isLazyFunc(func))
2424  return evalLazyFunc(st, func, args, retval);
2425  else
2426  return evalStandardFunc(st, func, args, retval);
2427 }
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1756
static bool evalStandardFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1873
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:1749

◆ evalLazyFunc()

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

Definition at line 1756 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().

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

◆ evalStandardFunc()

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

Definition at line 1873 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_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().

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

◆ evaluateExpr()

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

Definition at line 2436 of file pgbench.c.

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

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

2437 {
2438  switch (expr->etype)
2439  {
2440  case ENODE_CONSTANT:
2441  {
2442  *retval = expr->u.constant;
2443  return true;
2444  }
2445 
2446  case ENODE_VARIABLE:
2447  {
2448  Variable *var;
2449 
2450  if ((var = lookupVariable(st, expr->u.variable.varname)) == NULL)
2451  {
2452  fprintf(stderr, "undefined variable \"%s\"\n",
2453  expr->u.variable.varname);
2454  return false;
2455  }
2456 
2457  if (!makeVariableValue(var))
2458  return false;
2459 
2460  *retval = var->value;
2461  return true;
2462  }
2463 
2464  case ENODE_FUNCTION:
2465  return evalFunc(st,
2466  expr->u.function.function,
2467  expr->u.function.args,
2468  retval);
2469 
2470  default:
2471  /* internal error which should never occur */
2472  fprintf(stderr, "unexpected enode type in evaluation: %d\n",
2473  expr->etype);
2474  exit(1);
2475  }
2476 }
PgBenchValue constant
Definition: pgbench.h:114
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:1251
struct PgBenchExpr::@40::@41 variable
#define fprintf
Definition: port.h:196
static bool evalFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2420
static bool makeVariableValue(Variable *var)
Definition: pgbench.c:1311
PgBenchValue value
Definition: pgbench.c:267
PgBenchFunction function
Definition: pgbench.h:121
union PgBenchExpr::@40 u
PgBenchExprType etype
Definition: pgbench.h:111

◆ evaluateSleep()

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

Definition at line 2851 of file pgbench.c.

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

Referenced by executeMetaCommand().

2852 {
2853  char *var;
2854  int usec;
2855 
2856  if (*argv[1] == ':')
2857  {
2858  if ((var = getVariable(st, argv[1] + 1)) == NULL)
2859  {
2860  fprintf(stderr, "%s: undefined variable \"%s\"\n",
2861  argv[0], argv[1]);
2862  return false;
2863  }
2864  usec = atoi(var);
2865  }
2866  else
2867  usec = atoi(argv[1]);
2868 
2869  if (argc > 2)
2870  {
2871  if (pg_strcasecmp(argv[2], "ms") == 0)
2872  usec *= 1000;
2873  else if (pg_strcasecmp(argv[2], "s") == 0)
2874  usec *= 1000000;
2875  }
2876  else
2877  usec *= 1000000;
2878 
2879  *usecs = usec;
2880  return true;
2881 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1278
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
#define fprintf
Definition: port.h:196

◆ executeMetaCommand()

static ConnectionStateEnum executeMetaCommand ( CState st,
instr_time now 
)
static

Definition at line 3320 of file pgbench.c.

References Command::argc, Command::argv, Assert, 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, evaluateExpr(), evaluateSleep(), Command::expr, fprintf, i, CState::id, IFSTATE_ELSE_FALSE, IFSTATE_ELSE_TRUE, IFSTATE_FALSE, IFSTATE_IGNORED, IFSTATE_NONE, IFSTATE_TRUE, 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, putVariableValue(), runShellCommand(), CState::sleep_until, Command::type, CState::use_file, and valueTruth().

Referenced by advanceConnectionState().

3321 {
3322  Command *command = sql_script[st->use_file].commands[st->command];
3323  int argc;
3324  char **argv;
3325 
3326  Assert(command != NULL && command->type == META_COMMAND);
3327 
3328  argc = command->argc;
3329  argv = command->argv;
3330 
3331  if (debug)
3332  {
3333  fprintf(stderr, "client %d executing \\%s", st->id, argv[0]);
3334  for (int i = 1; i < argc; i++)
3335  fprintf(stderr, " %s", argv[i]);
3336  fprintf(stderr, "\n");
3337  }
3338 
3339  if (command->meta == META_SLEEP)
3340  {
3341  int usec;
3342 
3343  /*
3344  * A \sleep doesn't execute anything, we just get the delay from the
3345  * argument, and enter the CSTATE_SLEEP state. (The per-command
3346  * latency will be recorded in CSTATE_SLEEP state, not here, after the
3347  * delay has elapsed.)
3348  */
3349  if (!evaluateSleep(st, argc, argv, &usec))
3350  {
3351  commandFailed(st, "sleep", "execution of meta-command failed");
3352  return CSTATE_ABORTED;
3353  }
3354 
3356  st->sleep_until = INSTR_TIME_GET_MICROSEC(*now) + usec;
3357  return CSTATE_SLEEP;
3358  }
3359  else if (command->meta == META_SET)
3360  {
3361  PgBenchExpr *expr = command->expr;
3362  PgBenchValue result;
3363 
3364  if (!evaluateExpr(st, expr, &result))
3365  {
3366  commandFailed(st, argv[0], "evaluation of meta-command failed");
3367  return CSTATE_ABORTED;
3368  }
3369 
3370  if (!putVariableValue(st, argv[0], argv[1], &result))
3371  {
3372  commandFailed(st, "set", "assignment of meta-command failed");
3373  return CSTATE_ABORTED;
3374  }
3375  }
3376  else if (command->meta == META_IF)
3377  {
3378  /* backslash commands with an expression to evaluate */
3379  PgBenchExpr *expr = command->expr;
3380  PgBenchValue result;
3381  bool cond;
3382 
3383  if (!evaluateExpr(st, expr, &result))
3384  {
3385  commandFailed(st, argv[0], "evaluation of meta-command failed");
3386  return CSTATE_ABORTED;
3387  }
3388 
3389  cond = valueTruth(&result);
3391  }
3392  else if (command->meta == META_ELIF)
3393  {
3394  /* backslash commands with an expression to evaluate */
3395  PgBenchExpr *expr = command->expr;
3396  PgBenchValue result;
3397  bool cond;
3398 
3400  {
3401  /* elif after executed block, skip eval and wait for endif. */
3403  return CSTATE_END_COMMAND;
3404  }
3405 
3406  if (!evaluateExpr(st, expr, &result))
3407  {
3408  commandFailed(st, argv[0], "evaluation of meta-command failed");
3409  return CSTATE_ABORTED;
3410  }
3411 
3412  cond = valueTruth(&result);
3415  }
3416  else if (command->meta == META_ELSE)
3417  {
3418  switch (conditional_stack_peek(st->cstack))
3419  {
3420  case IFSTATE_TRUE:
3422  break;
3423  case IFSTATE_FALSE: /* inconsistent if active */
3424  case IFSTATE_IGNORED: /* inconsistent if active */
3425  case IFSTATE_NONE: /* else without if */
3426  case IFSTATE_ELSE_TRUE: /* else after else */
3427  case IFSTATE_ELSE_FALSE: /* else after else */
3428  default:
3429  /* dead code if conditional check is ok */
3430  Assert(false);
3431  }
3432  }
3433  else if (command->meta == META_ENDIF)
3434  {
3437  }
3438  else if (command->meta == META_SETSHELL)
3439  {
3440  if (!runShellCommand(st, argv[1], argv + 2, argc - 2))
3441  {
3442  commandFailed(st, "setshell", "execution of meta-command failed");
3443  return CSTATE_ABORTED;
3444  }
3445  }
3446  else if (command->meta == META_SHELL)
3447  {
3448  if (!runShellCommand(st, NULL, argv + 1, argc - 1))
3449  {
3450  commandFailed(st, "shell", "execution of meta-command failed");
3451  return CSTATE_ABORTED;
3452  }
3453  }
3454 
3455  /*
3456  * executing the expression or shell command might have taken a
3457  * non-negligible amount of time, so reset 'now'
3458  */
3460 
3461  return CSTATE_END_COMMAND;
3462 }
int type
Definition: pgbench.c:522
int id
Definition: pgbench.c:401
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:57
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:2627
PgBenchExpr * expr
Definition: pgbench.c:527
#define INSTR_TIME_SET_ZERO(t)
Definition: instr_time.h:154
#define fprintf
Definition: port.h:196
char * argv[MAX_ARGS]
Definition: pgbench.c:525
ConditionalStack cstack
Definition: pgbench.c:403
static bool evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
Definition: pgbench.c:2436
#define META_COMMAND
Definition: pgbench.c:467
static int debug
Definition: pgbench.c:543
MetaCommand meta
Definition: pgbench.c:523
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:539
int argc
Definition: pgbench.c:524
int command
Definition: pgbench.c:412
static bool runShellCommand(CState *st, char *variable, char **argv, int argc)
Definition: pgbench.c:2516
ifState conditional_stack_peek(ConditionalStack cstack)
Definition: conditional.c:94
int64 sleep_until
Definition: pgbench.c:421
static bool evaluateSleep(CState *st, int argc, char **argv, int *usecs)
Definition: pgbench.c:2851
#define INSTR_TIME_SET_CURRENT_LAZY(t)
Definition: instr_time.h:253
#define Assert(condition)
Definition: c.h:733
#define INSTR_TIME_GET_MICROSEC(t)
Definition: instr_time.h:205
static bool valueTruth(PgBenchValue *pval)
Definition: pgbench.c:1648
bool conditional_stack_poke(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:106
Command ** commands
Definition: pgbench.c:535
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:1481
int use_file
Definition: pgbench.c:411
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1547

◆ executeStatement()

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

Definition at line 1144 of file pgbench.c.

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

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

1145 {
1146  PGresult *res;
1147 
1148  res = PQexec(con, sql);
1149  if (PQresultStatus(res) != PGRES_COMMAND_OK)
1150  {
1151  fprintf(stderr, "%s", PQerrorMessage(con));
1152  exit(1);
1153  }
1154  PQclear(res);
1155 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6617
#define fprintf
Definition: port.h:196
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

◆ findBuiltin()

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

Definition at line 4979 of file pgbench.c.

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

Referenced by main().

4980 {
4981  int i,
4982  found = 0,
4983  len = strlen(name);
4984  const BuiltinScript *result = NULL;
4985 
4986  for (i = 0; i < lengthof(builtin_script); i++)
4987  {
4988  if (strncmp(builtin_script[i].name, name, len) == 0)
4989  {
4990  result = &builtin_script[i];
4991  found++;
4992  }
4993  }
4994 
4995  /* ok, unambiguous result */
4996  if (found == 1)
4997  return result;
4998 
4999  /* error cases */
5000  if (found == 0)
5001  fprintf(stderr, "no builtin script found for name \"%s\"\n", name);
5002  else /* found > 1 */
5003  fprintf(stderr,
5004  "ambiguous builtin name: %d builtin scripts found for prefix \"%s\"\n", found, name);
5005 
5007  exit(1);
5008 }
static void listAvailableScripts(void)
Definition: pgbench.c:4967
#define lengthof(array)
Definition: c.h:663
#define fprintf
Definition: port.h:196
static const BuiltinScript builtin_script[]
Definition: pgbench.c:553
const char * name
Definition: encode.c:521
int i

◆ finishCon()

static void finishCon ( CState st)
static

Definition at line 6527 of file pgbench.c.

References CState::con, and PQfinish().

Referenced by advanceConnectionState(), and disconnect_all().

6528 {
6529  if (st->con != NULL)
6530  {
6531  PQfinish(st->con);
6532  st->con = NULL;
6533  }
6534 }
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4119
PGconn * con
Definition: pgbench.c:400

◆ free_command()

static void free_command ( Command command)
static

Definition at line 4458 of file pgbench.c.

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

Referenced by ParseScript().

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

◆ free_socket_set()

static void free_socket_set ( socket_set sa)
static

Definition at line 6701 of file pgbench.c.

References pg_free().

Referenced by setalarm(), and threadRun().

6702 {
6703  pg_free(sa);
6704 }
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 872 of file pgbench.c.

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

Referenced by evalStandardFunc().

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

◆ getGaussianRand()

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

Definition at line 896 of file pgbench.c.

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

Referenced by evalStandardFunc().

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

◆ getHashFnv1a()

static int64 getHashFnv1a ( int64  val,
uint64  seed 
)
static

Definition at line 1022 of file pgbench.c.

References FNV_OFFSET_BASIS, FNV_PRIME, and i.

Referenced by evalStandardFunc().

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

◆ getHashMurmur2()

static int64 getHashMurmur2 ( int64  val,
uint64  seed 
)
static

Definition at line 1047 of file pgbench.c.

References MM2_MUL, MM2_MUL_TIMES_8, and MM2_ROT.

Referenced by evalStandardFunc().

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

◆ getMetaCommand()

static MetaCommand getMetaCommand ( const char *  cmd)
static

Definition at line 2482 of file pgbench.c.

References 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().

2483 {
2484  MetaCommand mc;
2485 
2486  if (cmd == NULL)
2487  mc = META_NONE;
2488  else if (pg_strcasecmp(cmd, "set") == 0)
2489  mc = META_SET;
2490  else if (pg_strcasecmp(cmd, "setshell") == 0)
2491  mc = META_SETSHELL;
2492  else if (pg_strcasecmp(cmd, "shell") == 0)
2493  mc = META_SHELL;
2494  else if (pg_strcasecmp(cmd, "sleep") == 0)
2495  mc = META_SLEEP;
2496  else if (pg_strcasecmp(cmd, "if") == 0)
2497  mc = META_IF;
2498  else if (pg_strcasecmp(cmd, "elif") == 0)
2499  mc = META_ELIF;
2500  else if (pg_strcasecmp(cmd, "else") == 0)
2501  mc = META_ELSE;
2502  else if (pg_strcasecmp(cmd, "endif") == 0)
2503  mc = META_ENDIF;
2504  else if (pg_strcasecmp(cmd, "gset") == 0)
2505  mc = META_GSET;
2506  else
2507  mc = META_NONE;
2508  return mc;
2509 }
MetaCommand
Definition: pgbench.c:475
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 956 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by advanceConnectionState().

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

◆ getQueryParams()

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

Definition at line 1597 of file pgbench.c.

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

Referenced by sendCommand().

1598 {
1599  int i;
1600 
1601  for (i = 0; i < command->argc - 1; i++)
1602  params[i] = getVariable(st, command->argv[i + 1]);
1603 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1278
char * argv[MAX_ARGS]
Definition: pgbench.c:525
int argc
Definition: pgbench.c:524
int i

◆ getrand()

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

Definition at line 852 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by chooseScript(), and evalStandardFunc().

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

◆ GetTableInfo()

static void GetTableInfo ( PGconn con,
bool  scale_given 
)
static

Definition at line 4188 of file pgbench.c.

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

Referenced by main().

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

◆ getVariable()

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

Definition at line 1278 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().

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

◆ getZipfianRand()

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

Definition at line 1008 of file pgbench.c.

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

Referenced by evalStandardFunc().

1009 {
1010  int64 n = max - min + 1;
1011 
1012  /* abort if parameter is invalid */
1014 
1015  return min - 1 + computeIterativeZipfian(random_state, n, s);
1016 }
#define MAX_ZIPFIAN_PARAM
Definition: pgbench.c:143
#define MIN_ZIPFIAN_PARAM
Definition: pgbench.c:142
#define Assert(condition)
Definition: c.h:733
static int64 computeIterativeZipfian(RandomState *random_state, int64 n, double s)
Definition: pgbench.c:978

◆ handle_sig_alarm()

static void handle_sig_alarm ( SIGNAL_ARGS  )
static

Definition at line 6543 of file pgbench.c.

Referenced by setalarm().

6544 {
6545  timer_exceeded = true;
6546 }
volatile bool timer_exceeded
Definition: pgbench.c:251

◆ initCreateFKeys()

static void initCreateFKeys ( PGconn con)
static

Definition at line 4047 of file pgbench.c.

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

Referenced by runInitSteps().

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

◆ initCreatePKeys()

static void initCreatePKeys ( PGconn con)
static

Definition at line 4012 of file pgbench.c.

References executeStatement(), fprintf, i, lengthof, PQescapeIdentifier(), PQfreemem(), snprintf, and strlcpy().

Referenced by runInitSteps().

4013 {
4014  static const char *const DDLINDEXes[] = {
4015  "alter table pgbench_branches add primary key (bid)",
4016  "alter table pgbench_tellers add primary key (tid)",
4017  "alter table pgbench_accounts add primary key (aid)"
4018  };
4019  int i;
4020 
4021  fprintf(stderr, "creating primary keys...\n");
4022  for (i = 0; i < lengthof(DDLINDEXes); i++)
4023  {
4024  char buffer[256];
4025 
4026  strlcpy(buffer, DDLINDEXes[i], sizeof(buffer));
4027 
4028  if (index_tablespace != NULL)
4029  {
4030  char *escape_tablespace;
4031 
4032  escape_tablespace = PQescapeIdentifier(con, index_tablespace,
4033  strlen(index_tablespace));
4034  snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer),
4035  " using index tablespace %s", escape_tablespace);
4036  PQfreemem(escape_tablespace);
4037  }
4038 
4039  executeStatement(con, buffer);
4040  }
4041 }
#define lengthof(array)
Definition: c.h:663
#define fprintf
Definition: port.h:196
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1144
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:3570
char * index_tablespace
Definition: pgbench.c:189
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
int i
#define snprintf
Definition: port.h:192
void PQfreemem(void *ptr)
Definition: fe-exec.c:3296

◆ initCreateTables()

static void initCreateTables ( PGconn con)
static

Definition at line 3702 of file pgbench.c.

References append_fillfactor(), createPartitions(), executeStatement(), fprintf, i, lengthof, PART_NONE, partition_method, PQescapeIdentifier(), PQfreemem(), SCALE_32BIT_THRESHOLD, and snprintf.

Referenced by runInitSteps().

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

◆ initDropTables()

static void initDropTables ( PGconn con)
static

Definition at line 3612 of file pgbench.c.

References executeStatement(), and fprintf.

Referenced by runInitSteps().

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

◆ initGenerateDataClientSide()

static void initGenerateDataClientSide ( PGconn con)
static

Definition at line 3823 of file pgbench.c.

References executeStatement(), fprintf, i, initTruncateTables(), INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, INT64_FORMAT, LOG_STEP_SECONDS, naccounts, nbranches, ntellers, PGRES_COPY_IN, PQclear(), PQendcopy(), PQerrorMessage(), PQexec(), PQputline(), PQresultStatus(), scale, and snprintf.

Referenced by runInitSteps().

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

◆ initGenerateDataServerSide()

static void initGenerateDataServerSide ( PGconn con)
static

Definition at line 3958 of file pgbench.c.

References executeStatement(), fprintf, initTruncateTables(), INT64_FORMAT, naccounts, nbranches, ntellers, and snprintf.

Referenced by runInitSteps().

3959 {
3960  char sql[256];
3961 
3962  fprintf(stderr, "generating data (server-side)...\n");
3963 
3964  /*
3965  * we do all of this in one transaction to enable the backend's
3966  * data-loading optimizations
3967  */
3968  executeStatement(con, "begin");
3969 
3970  /* truncate away any old data */
3971  initTruncateTables(con);
3972 
3973  snprintf(sql, sizeof(sql),
3974  "insert into pgbench_branches(bid,bbalance) "
3975  "select bid, 0 "
3976  "from generate_series(1, %d) as bid", nbranches * scale);
3977  executeStatement(con, sql);
3978 
3979  snprintf(sql, sizeof(sql),
3980  "insert into pgbench_tellers(tid,bid,tbalance) "
3981  "select tid, (tid - 1) / %d + 1, 0 "
3982  "from generate_series(1, %d) as tid", ntellers, ntellers * scale);
3983  executeStatement(con, sql);
3984 
3985  snprintf(sql, sizeof(sql),
3986  "insert into pgbench_accounts(aid,bid,abalance,filler) "
3987  "select aid, (aid - 1) / %d + 1, 0, '' "
3988  "from generate_series(1, "INT64_FORMAT") as aid",
3989  naccounts, (int64) naccounts * scale);
3990  executeStatement(con, sql);
3991 
3992  executeStatement(con, "commit");
3993 }
int scale
Definition: pgbench.c:153
#define fprintf
Definition: port.h:196
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1144
#define nbranches
Definition: pgbench.c:215
#define ntellers
Definition: pgbench.c:217
#define naccounts
Definition: pgbench.c:218
static void initTruncateTables(PGconn *con)
Definition: pgbench.c:3810
#define INT64_FORMAT
Definition: c.h:401
#define snprintf
Definition: port.h:192

◆ initRandomState()

static void initRandomState ( RandomState random_state)
static

Definition at line 833 of file pgbench.c.

References pg_jrand48(), and RandomState::xseed.

Referenced by main().

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

◆ initSimpleStats()

static void initSimpleStats ( SimpleStats ss)
static

Definition at line 1070 of file pgbench.c.

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

1071 {
1072  memset(ss, 0, sizeof(SimpleStats));
1073 }

◆ initStats()

static void initStats ( StatsData sd,
time_t  start_time 
)
static

Definition at line 1110 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().

1111 {
1112  sd->start_time = start_time;
1113  sd->cnt = 0;
1114  sd->skipped = 0;
1115  initSimpleStats(&sd->latency);
1116  initSimpleStats(&sd->lag);
1117 }
time_t start_time
Definition: pgbench.c:294
SimpleStats lag
Definition: pgbench.c:299
SimpleStats latency
Definition: pgbench.c:298
static time_t start_time
Definition: pg_ctl.c:99
int64 cnt
Definition: pgbench.c:295
int64 skipped
Definition: pgbench.c:296
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1070

◆ initTruncateTables()

static void initTruncateTables ( PGconn con)
static

Definition at line 3810 of file pgbench.c.

References executeStatement().

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

3811 {
3812  executeStatement(con, "truncate table "
3813  "pgbench_accounts, "
3814  "pgbench_branches, "
3815  "pgbench_history, "
3816  "pgbench_tellers");
3817 }
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1144

◆ initVacuum()

static void initVacuum ( PGconn con)
static

Definition at line 3999 of file pgbench.c.

References executeStatement(), and fprintf.

Referenced by runInitSteps().

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

◆ is_an_int()

static bool is_an_int ( const char *  str)
static

Definition at line 692 of file pgbench.c.

References generate_unaccent_rules::str.

Referenced by makeVariableValue().

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

◆ isLazyFunc()

static bool isLazyFunc ( PgBenchFunction  func)
static

Definition at line 1749 of file pgbench.c.

References PGBENCH_AND, PGBENCH_CASE, and PGBENCH_OR.

Referenced by evalFunc(), and evalLazyFunc().

1750 {
1751  return func == PGBENCH_AND || func == PGBENCH_OR || func == PGBENCH_CASE;
1752 }

◆ listAvailableScripts()

static void listAvailableScripts ( void  )
static

Definition at line 4967 of file pgbench.c.

References fprintf, i, lengthof, and name.

Referenced by findBuiltin(), and main().

4968 {
4969  int i;
4970 
4971  fprintf(stderr, "Available builtin scripts:\n");
4972  for (i = 0; i < lengthof(builtin_script); i++)
4973  fprintf(stderr, " %13s: %s\n", builtin_script[i].name, builtin_script[i].desc);
4974  fprintf(stderr, "\n");
4975 }
#define lengthof(array)
Definition: c.h:663
#define fprintf
Definition: port.h:196
static const BuiltinScript builtin_script[]
Definition: pgbench.c:553
const char * name
Definition: encode.c:521
int i

◆ lookupCreateVariable()

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

Definition at line 1412 of file pgbench.c.

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

Referenced by putVariable(), and putVariableValue().

1413 {
1414  Variable *var;
1415 
1416  var = lookupVariable(st, name);
1417  if (var == NULL)
1418  {
1419  Variable *newvars;
1420 
1421  /*
1422  * Check for the name only when declaring a new variable to avoid
1423  * overhead.
1424  */
1425  if (!valid_variable_name(name))
1426  {
1427  fprintf(stderr, "%s: invalid variable name: \"%s\"\n",
1428  context, name);
1429  return NULL;
1430  }
1431 
1432  /* Create variable at the end of the array */
1433  if (st->variables)
1434  newvars = (Variable *) pg_realloc(st->variables,
1435  (st->nvariables + 1) * sizeof(Variable));
1436  else
1437  newvars = (Variable *) pg_malloc(sizeof(Variable));
1438 
1439  st->variables = newvars;
1440 
1441  var = &newvars[st->nvariables];
1442 
1443  var->name = pg_strdup(name);
1444  var->svalue = NULL;
1445  /* caller is expected to initialize remaining fields */
1446 
1447  st->nvariables++;
1448  /* we don't re-sort the array till we have to */
1449  st->vars_sorted = false;
1450  }
1451 
1452  return var;
1453 }
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:1251
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
char * name
Definition: pgbench.c:265
#define fprintf
Definition: port.h:196
static bool valid_variable_name(const char *name)
Definition: pgbench.c:1385
Variable * variables
Definition: pgbench.c:415
bool vars_sorted
Definition: pgbench.c:417
char * svalue
Definition: pgbench.c:266
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:521
int nvariables
Definition: pgbench.c:416

◆ lookupVariable()

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

Definition at line 1251 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().

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

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 5376 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_logging_init(), pg_malloc(), pg_malloc0(), pg_realloc(), pg_strcasecmp(), pg_strdup(), PGBT_NO_VALUE, postprocess_sql_command(), PQerrorMessage(), PQfinish(), PQstatus(), printf, 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, strerror, 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.

5377 {
5378  static struct option long_options[] = {
5379  /* systematic long/short named options */
5380  {"builtin", required_argument, NULL, 'b'},
5381  {"client", required_argument, NULL, 'c'},
5382  {"connect", no_argument, NULL, 'C'},
5383  {"debug", no_argument, NULL, 'd'},
5384  {"define", required_argument, NULL, 'D'},
5385  {"file", required_argument, NULL, 'f'},
5386  {"fillfactor", required_argument, NULL, 'F'},
5387  {"host", required_argument, NULL, 'h'},
5388  {"initialize", no_argument, NULL, 'i'},
5389  {"init-steps", required_argument, NULL, 'I'},
5390  {"jobs", required_argument, NULL, 'j'},
5391  {"log", no_argument, NULL, 'l'},
5392  {"latency-limit", required_argument, NULL, 'L'},
5393  {"no-vacuum", no_argument, NULL, 'n'},
5394  {"port", required_argument, NULL, 'p'},
5395  {"progress", required_argument, NULL, 'P'},
5396  {"protocol", required_argument, NULL, 'M'},
5397  {"quiet", no_argument, NULL, 'q'},
5398  {"report-latencies", no_argument, NULL, 'r'},
5399  {"rate", required_argument, NULL, 'R'},
5400  {"scale", required_argument, NULL, 's'},
5401  {"select-only", no_argument, NULL, 'S'},
5402  {"skip-some-updates", no_argument, NULL, 'N'},
5403  {"time", required_argument, NULL, 'T'},
5404  {"transactions", required_argument, NULL, 't'},
5405  {"username", required_argument, NULL, 'U'},
5406  {"vacuum-all", no_argument, NULL, 'v'},
5407  /* long-named only options */
5408  {"unlogged-tables", no_argument, NULL, 1},
5409  {"tablespace", required_argument, NULL, 2},
5410  {"index-tablespace", required_argument, NULL, 3},
5411  {"sampling-rate", required_argument, NULL, 4},
5412  {"aggregate-interval", required_argument, NULL, 5},
5413  {"progress-timestamp", no_argument, NULL, 6},
5414  {"log-prefix", required_argument, NULL, 7},
5415  {"foreign-keys", no_argument, NULL, 8},
5416  {"random-seed", required_argument, NULL, 9},
5417  {"show-script", required_argument, NULL, 10},
5418  {"partitions", required_argument, NULL, 11},
5419  {"partition-method", required_argument, NULL, 12},
5420  {NULL, 0, NULL, 0}
5421  };
5422 
5423  int c;
5424  bool is_init_mode = false; /* initialize mode? */
5425  char *initialize_steps = NULL;
5426  bool foreign_keys = false;
5427  bool is_no_vacuum = false;
5428  bool do_vacuum_accounts = false; /* vacuum accounts table? */
5429  int optindex;
5430  bool scale_given = false;
5431 
5432  bool benchmarking_option_set = false;
5433  bool initialization_option_set = false;
5434  bool internal_script_used = false;
5435 
5436  CState *state; /* status of clients */
5437  TState *threads; /* array of thread */
5438 
5439  instr_time start_time; /* start up time */
5440  instr_time total_time;
5441  instr_time conn_total_time;
5442  int64 latency_late = 0;
5443  StatsData stats;
5444  int weight;
5445 
5446  int i;
5447  int nclients_dealt;
5448 
5449 #ifdef HAVE_GETRLIMIT
5450  struct rlimit rlim;
5451 #endif
5452 
5453  PGconn *con;
5454  char *env;
5455 
5456  int exit_code = 0;
5457 
5458  pg_logging_init(argv[0]);
5459  progname = get_progname(argv[0]);
5460 
5461  if (argc > 1)
5462  {
5463  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
5464  {
5465  usage();
5466  exit(0);
5467  }
5468  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
5469  {
5470  puts("pgbench (PostgreSQL) " PG_VERSION);
5471  exit(0);
5472  }
5473  }
5474 
5475  if ((env = getenv("PGHOST")) != NULL && *env != '\0')
5476  pghost = env;
5477  if ((env = getenv("PGPORT")) != NULL && *env != '\0')
5478  pgport = env;
5479  else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
5480  login = env;
5481 
5482  state = (CState *) pg_malloc0(sizeof(CState));
5483 
5484  /* set random seed early, because it may be used while parsing scripts. */
5485  if (!set_random_seed(getenv("PGBENCH_RANDOM_SEED")))
5486  {
5487  fprintf(stderr, "error while setting random seed from PGBENCH_RANDOM_SEED environment variable\n");
5488  exit(1);
5489  }
5490 
5491  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)
5492  {
5493  char *script;
5494 
5495  switch (c)
5496  {
5497  case 'i':
5498  is_init_mode = true;
5499  break;
5500  case 'I':
5501  if (initialize_steps)
5502  pg_free(initialize_steps);
5503  initialize_steps = pg_strdup(optarg);
5504  checkInitSteps(initialize_steps);
5505  initialization_option_set = true;
5506  break;
5507  case 'h':
5508  pghost = pg_strdup(optarg);
5509  break;
5510  case 'n':
5511  is_no_vacuum = true;
5512  break;
5513  case 'v':
5514  benchmarking_option_set = true;
5515  do_vacuum_accounts = true;
5516  break;
5517  case 'p':
5518  pgport = pg_strdup(optarg);
5519  break;
5520  case 'd':
5521  debug++;
5522  break;
5523  case 'c':
5524  benchmarking_option_set = true;
5525  nclients = atoi(optarg);
5526  if (nclients <= 0)
5527  {
5528  fprintf(stderr, "invalid number of clients: \"%s\"\n",
5529  optarg);
5530  exit(1);
5531  }
5532 #ifdef HAVE_GETRLIMIT
5533 #ifdef RLIMIT_NOFILE /* most platforms use RLIMIT_NOFILE */
5534  if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
5535 #else /* but BSD doesn't ... */
5536  if (getrlimit(RLIMIT_OFILE, &rlim) == -1)
5537 #endif /* RLIMIT_NOFILE */
5538  {
5539  fprintf(stderr, "getrlimit failed: %s\n", strerror(errno));
5540  exit(1);
5541  }
5542  if (rlim.rlim_cur < nclients + 3)
5543  {
5544  fprintf(stderr, "need at least %d open files, but system limit is %ld\n",
5545  nclients + 3, (long) rlim.rlim_cur);
5546  fprintf(stderr, "Reduce number of clients, or use limit/ulimit to increase the system limit.\n");
5547  exit(1);
5548  }
5549 #endif /* HAVE_GETRLIMIT */
5550  break;
5551  case 'j': /* jobs */
5552  benchmarking_option_set = true;
5553  nthreads = atoi(optarg);
5554  if (nthreads <= 0)
5555  {
5556  fprintf(stderr, "invalid number of threads: \"%s\"\n",
5557  optarg);
5558  exit(1);
5559  }
5560 #ifndef ENABLE_THREAD_SAFETY
5561  if (nthreads != 1)
5562  {
5563  fprintf(stderr, "threads are not supported on this platform; use -j1\n");
5564  exit(1);
5565  }
5566 #endif /* !ENABLE_THREAD_SAFETY */
5567  break;
5568  case 'C':
5569  benchmarking_option_set = true;
5570  is_connect = true;
5571  break;
5572  case 'r':
5573  benchmarking_option_set = true;
5574  report_per_command = true;
5575  break;
5576  case 's':
5577  scale_given = true;
5578  scale = atoi(optarg);
5579  if (scale <= 0)
5580  {
5581  fprintf(stderr, "invalid scaling factor: \"%s\"\n", optarg);
5582  exit(1);
5583  }
5584  break;
5585  case 't':
5586  benchmarking_option_set = true;
5587  nxacts = atoi(optarg);
5588  if (nxacts <= 0)
5589  {
5590  fprintf(stderr, "invalid number of transactions: \"%s\"\n",
5591  optarg);
5592  exit(1);
5593  }
5594  break;
5595  case 'T':
5596  benchmarking_option_set = true;
5597  duration = atoi(optarg);
5598  if (duration <= 0)
5599  {
5600  fprintf(stderr, "invalid duration: \"%s\"\n", optarg);
5601  exit(1);
5602  }
5603  break;
5604  case 'U':
5605  login = pg_strdup(optarg);
5606  break;
5607  case 'l':
5608  benchmarking_option_set = true;
5609  use_log = true;
5610  break;
5611  case 'q':
5612  initialization_option_set = true;
5613  use_quiet = true;
5614  break;
5615  case 'b':
5616  if (strcmp(optarg, "list") == 0)
5617  {
5619  exit(0);
5620  }
5621  weight = parseScriptWeight(optarg, &script);
5622  process_builtin(findBuiltin(script), weight);
5623  benchmarking_option_set = true;
5624  internal_script_used = true;
5625  break;
5626  case 'S':