PostgreSQL Source Code  git master
pgbench.c File Reference
#include "postgres_fe.h"
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <signal.h>
#include <time.h>
#include "common/int.h"
#include "common/logging.h"
#include "common/string.h"
#include "common/username.h"
#include "fe_utils/cancel.h"
#include "fe_utils/conditional.h"
#include "getopt_long.h"
#include "libpq-fe.h"
#include "pgbench.h"
#include "port/pg_bitutils.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 THREAD_T   void *
 
#define THREAD_FUNC_RETURN_TYPE   void *
 
#define THREAD_FUNC_RETURN   return NULL
 
#define THREAD_FUNC_CC
 
#define THREAD_BARRIER_T   int
 
#define THREAD_BARRIER_INIT(barrier, n)   (*(barrier) = 0)
 
#define THREAD_BARRIER_WAIT(barrier)
 
#define THREAD_BARRIER_DESTROY(barrier)
 
#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 SQL_COMMAND   1
 
#define META_COMMAND   2
 
#define MAX_ARGS   256
 
#define PG_TIME_GET_DOUBLE(t)   (0.000001 * (t))
 
#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 int64 pg_time_usec_t
 
typedef struct StatsData StatsData
 
typedef struct RandomState RandomState
 
typedef enum MetaCommand MetaCommand
 
typedef enum QueryMode QueryMode
 
typedef struct Command Command
 
typedef struct ParsedScript ParsedScript
 
typedef struct BuiltinScript BuiltinScript
 

Enumerations

enum  partition_method_t { PART_NONE, PART_RANGE, PART_HASH }
 
enum  ConnectionStateEnum {
  CSTATE_CHOOSE_SCRIPT, CSTATE_START_TX, CSTATE_PREPARE_THROTTLE, CSTATE_THROTTLE,
  CSTATE_START_COMMAND, CSTATE_WAIT_RESULT, CSTATE_SLEEP, CSTATE_END_COMMAND,
  CSTATE_SKIP_COMMAND, CSTATE_END_TX, CSTATE_ABORTED, CSTATE_FINISHED
}
 
enum  MetaCommand {
  META_NONE, META_SET, META_SETSHELL, META_SHELL,
  META_SLEEP, META_GSET, META_ASET, META_IF,
  META_ELIF, META_ELSE, META_ENDIF, META_STARTPIPELINE,
  META_ENDPIPELINE
}
 
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, pg_time_usec_t *now)
 
static void doLog (TState *thread, CState *st, StatsData *agg, bool skipped, double latency, double lag)
 
static void processXactStats (TState *thread, CState *st, pg_time_usec_t *now, bool skipped, StatsData *agg)
 
static void addScript (ParsedScript script)
 
static THREAD_FUNC_RETURN_TYPE THREAD_FUNC_CC 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 pg_time_usec_t pg_time_now (void)
 
static void pg_time_now_lazy (pg_time_usec_t *now)
 
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 int64 permute (const int64 val, const int64 isize, const int64 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, pg_time_usec_t start)
 
static void accumStats (StatsData *stats, bool skipped, double lat, double lag)
 
static void executeStatement (PGconn *con, const char *sql)
 
static void tryExecuteStatement (PGconn *con, const char *sql)
 
static PGconndoConnect (void)
 
static int compareVariableNames (const void *v1, const void *v2)
 
static VariablelookupVariable (CState *st, char *name)
 
static char * getVariable (CState *st, char *name)
 
static bool makeVariableValue (Variable *var)
 
static bool valid_variable_name (const char *name)
 
static VariablelookupCreateVariable (CState *st, const char *context, char *name)
 
static bool putVariable (CState *st, const char *context, char *name, const char *value)
 
static bool putVariableValue (CState *st, const char *context, char *name, const PgBenchValue *value)
 
static bool putVariableInt (CState *st, const char *context, char *name, int64 value)
 
static char * parseVariable (const char *sql, int *eaten)
 
static char * replaceVariable (char **sql, char *param, int len, char *value)
 
static char * assignVariables (CState *st, char *sql)
 
static void getQueryParams (CState *st, const Command *command, const char **params)
 
static char * valueTypeName (PgBenchValue *pval)
 
static bool coerceToBool (PgBenchValue *pval, bool *bval)
 
static bool valueTruth (PgBenchValue *pval)
 
static bool coerceToInt (PgBenchValue *pval, int64 *ival)
 
static bool coerceToDouble (PgBenchValue *pval, double *dval)
 
static bool isLazyFunc (PgBenchFunction func)
 
static bool evalLazyFunc (CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
 
static bool evalStandardFunc (CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
 
static bool evalFunc (CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
 
static MetaCommand getMetaCommand (const char *cmd)
 
static bool runShellCommand (CState *st, char *variable, char **argv, int argc)
 
static void preparedStatementName (char *buffer, int file, int state)
 
static void commandFailed (CState *st, const char *cmd, const char *message)
 
static int chooseScript (TState *thread)
 
static bool sendCommand (CState *st, Command *command)
 
static bool readCommandResponse (CState *st, MetaCommand meta, char *varprefix)
 
static bool evaluateSleep (CState *st, int argc, char **argv, int *usecs)
 
static void advanceConnectionState (TState *thread, CState *st, StatsData *agg)
 
static void disconnect_all (CState *state, int length)
 
static void initDropTables (PGconn *con)
 
static void createPartitions (PGconn *con)
 
static void initCreateTables (PGconn *con)
 
static void initTruncateTables (PGconn *con)
 
static void initGenerateDataClientSide (PGconn *con)
 
static void initGenerateDataServerSide (PGconn *con)
 
static void initVacuum (PGconn *con)
 
static void initCreatePKeys (PGconn *con)
 
static void initCreateFKeys (PGconn *con)
 
static void checkInitSteps (const char *initialize_steps)
 
static void runInitSteps (const char *initialize_steps)
 
static void GetTableInfo (PGconn *con, bool scale_given)
 
static bool parseQuery (Command *cmd)
 
void syntax_error (const char *source, int lineno, const char *line, const char *command, const char *msg, const char *more, int column)
 
static char * skip_sql_comments (char *sql_command)
 
static Commandcreate_sql_command (PQExpBuffer buf, const char *source)
 
static void free_command (Command *command)
 
static void postprocess_sql_command (Command *my_command)
 
static Commandprocess_backslash_command (PsqlScanState sstate, const char *source)
 
static void ConditionError (const char *desc, int cmdn, const char *msg)
 
static void CheckConditional (ParsedScript ps)
 
static void ParseScript (const char *script, const char *desc, int weight)
 
static char * read_file_contents (FILE *fd)
 
static void process_file (const char *filename, int weight)
 
static void process_builtin (const BuiltinScript *bi, int weight)
 
static void listAvailableScripts (void)
 
static const BuiltinScriptfindBuiltin (const char *name)
 
static int parseScriptWeight (const char *option, char **script)
 
static void printProgressReport (TState *threads, int64 test_start, pg_time_usec_t now, StatsData *last, int64 *last_report)
 
static void printSimpleStats (const char *prefix, SimpleStats *ss)
 
static void printResults (StatsData *total, pg_time_usec_t total_duration, pg_time_usec_t conn_total_duration, pg_time_usec_t conn_elapsed_duration, 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
 
const char * pghost = NULL
 
const char * pgport = NULL
 
const char * username = NULL
 
const char * dbName = NULL
 
char * logfile_prefix = NULL
 
const char * progname
 
volatile bool timer_exceeded = false
 
static RandomState base_random_sequence
 
static THREAD_BARRIER_T barrier
 
static QueryMode querymode = QUERY_SIMPLE
 
static const char * QUERYMODE [] = {"simple", "extended", "prepared"}
 
static ParsedScript sql_script [MAX_SCRIPTS]
 
static int num_scripts
 
static int64 total_weight = 0
 
static const BuiltinScript builtin_script []
 
static const PsqlScanCallbacks pgbench_callbacks
 

Macro Definition Documentation

◆ ALL_INIT_STEPS

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

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

Referenced by main(), and usage().

◆ DEFAULT_NXACTS

#define DEFAULT_NXACTS   10 /* default nxacts */

Definition at line 174 of file pgbench.c.

Referenced by main().

◆ ERRCODE_UNDEFINED_TABLE

◆ FNV_OFFSET_BASIS

#define FNV_OFFSET_BASIS   UINT64CONST(0xcbf29ce484222325)

Definition at line 82 of file pgbench.c.

Referenced by getHashFnv1a().

◆ FNV_PRIME

#define FNV_PRIME   UINT64CONST(0x100000001b3)

Definition at line 81 of file pgbench.c.

Referenced by getHashFnv1a().

◆ LOG_STEP_SECONDS

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

Definition at line 173 of file pgbench.c.

Referenced by initGenerateDataClientSide().

◆ M_PI

#define M_PI   3.14159265358979323846

Definition at line 73 of file pgbench.c.

Referenced by evalStandardFunc(), and getGaussianRand().

◆ MAX_ARGS

#define MAX_ARGS   256

Definition at line 521 of file pgbench.c.

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

◆ MAX_FARGS

#define MAX_FARGS   16

Definition at line 2047 of file pgbench.c.

Referenced by evalStandardFunc().

◆ MAX_PREPARE_NAME

#define MAX_PREPARE_NAME   32

Definition at line 2819 of file pgbench.c.

Referenced by sendCommand().

◆ MAX_SCRIPTS

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

Definition at line 306 of file pgbench.c.

Referenced by addScript().

◆ MAX_ZIPFIAN_PARAM

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

Definition at line 179 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 176 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 178 of file pgbench.c.

Referenced by evalStandardFunc(), and getZipfianRand().

◆ MM2_MUL

#define MM2_MUL   UINT64CONST(0xc6a4a7935bd1e995)

Definition at line 83 of file pgbench.c.

Referenced by getHashMurmur2().

◆ MM2_MUL_TIMES_8

#define MM2_MUL_TIMES_8   UINT64CONST(0x35253c9ade8f4ca8)

Definition at line 84 of file pgbench.c.

Referenced by getHashMurmur2().

◆ MM2_ROT

#define MM2_ROT   47

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

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

◆ ntellers

#define ntellers   10

Definition at line 253 of file pgbench.c.

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

◆ PARAMS_ARRAY_SIZE

#define PARAMS_ARRAY_SIZE   7

Referenced by doConnect().

◆ PG_TIME_GET_DOUBLE

#define PG_TIME_GET_DOUBLE (   t)    (0.000001 * (t))

◆ POLL_USING_SELECT

#define POLL_USING_SELECT

Definition at line 54 of file pgbench.c.

◆ SCALE_32BIT_THRESHOLD

#define SCALE_32BIT_THRESHOLD   20000

Definition at line 263 of file pgbench.c.

Referenced by initCreateTables().

◆ SHELL_COMMAND_SIZE

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

Definition at line 307 of file pgbench.c.

Referenced by runShellCommand().

◆ SOCKET_WAIT_METHOD

#define SOCKET_WAIT_METHOD   "select"

Definition at line 104 of file pgbench.c.

Referenced by threadRun().

◆ SQL_COMMAND

#define SQL_COMMAND   1

◆ THREAD_BARRIER_DESTROY

#define THREAD_BARRIER_DESTROY (   barrier)

Definition at line 163 of file pgbench.c.

Referenced by main().

◆ THREAD_BARRIER_INIT

#define THREAD_BARRIER_INIT (   barrier,
 
)    (*(barrier) = 0)

Definition at line 161 of file pgbench.c.

Referenced by main().

◆ THREAD_BARRIER_T

#define THREAD_BARRIER_T   int

Definition at line 160 of file pgbench.c.

◆ THREAD_BARRIER_WAIT

#define THREAD_BARRIER_WAIT (   barrier)

Definition at line 162 of file pgbench.c.

Referenced by threadRun().

◆ THREAD_FUNC_CC

#define THREAD_FUNC_CC

Definition at line 159 of file pgbench.c.

Referenced by main().

◆ THREAD_FUNC_RETURN

#define THREAD_FUNC_RETURN   return NULL

Definition at line 158 of file pgbench.c.

Referenced by threadRun().

◆ THREAD_FUNC_RETURN_TYPE

#define THREAD_FUNC_RETURN_TYPE   void *

Definition at line 157 of file pgbench.c.

Referenced by main().

◆ THREAD_T

#define THREAD_T   void *

Definition at line 156 of file pgbench.c.

◆ WSEP

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

Definition at line 285 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

◆ pg_time_usec_t

typedef int64 pg_time_usec_t

Definition at line 329 of file pgbench.c.

◆ 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 362 of file pgbench.c.

363 {
364  /*
365  * The client must first choose a script to execute. Once chosen, it can
366  * either be throttled (state CSTATE_PREPARE_THROTTLE under --rate), start
367  * right away (state CSTATE_START_TX) or not start at all if the timer was
368  * exceeded (state CSTATE_FINISHED).
369  */
371 
372  /*
373  * CSTATE_START_TX performs start-of-transaction processing. Establishes
374  * a new connection for the transaction in --connect mode, records the
375  * transaction start time, and proceed to the first command.
376  *
377  * Note: once a script is started, it will either error or run till its
378  * end, where it may be interrupted. It is not interrupted while running,
379  * so pgbench --time is to be understood as tx are allowed to start in
380  * that time, and will finish when their work is completed.
381  */
383 
384  /*
385  * In CSTATE_PREPARE_THROTTLE state, we calculate when to begin the next
386  * transaction, and advance to CSTATE_THROTTLE. CSTATE_THROTTLE state
387  * sleeps until that moment, then advances to CSTATE_START_TX, or
388  * CSTATE_FINISHED if the next transaction would start beyond the end of
389  * the run.
390  */
393 
394  /*
395  * We loop through these states, to process each command in the script:
396  *
397  * CSTATE_START_COMMAND starts the execution of a command. On a SQL
398  * command, the command is sent to the server, and we move to
399  * CSTATE_WAIT_RESULT state unless in pipeline mode. On a \sleep
400  * meta-command, the timer is set, and we enter the CSTATE_SLEEP state to
401  * wait for it to expire. Other meta-commands are executed immediately. If
402  * the command about to start is actually beyond the end of the script,
403  * advance to CSTATE_END_TX.
404  *
405  * CSTATE_WAIT_RESULT waits until we get a result set back from the server
406  * for the current command.
407  *
408  * CSTATE_SLEEP waits until the end of \sleep.
409  *
410  * CSTATE_END_COMMAND records the end-of-command timestamp, increments the
411  * command counter, and loops back to CSTATE_START_COMMAND state.
412  *
413  * CSTATE_SKIP_COMMAND is used by conditional branches which are not
414  * executed. It quickly skip commands that do not need any evaluation.
415  * This state can move forward several commands, till there is something
416  * to do or the end of the script.
417  */
420  CSTATE_SLEEP,
423 
424  /*
425  * CSTATE_END_TX performs end-of-transaction processing. It calculates
426  * latency, and logs the transaction. In --connect mode, it closes the
427  * current connection.
428  *
429  * Then either starts over in CSTATE_CHOOSE_SCRIPT, or enters
430  * CSTATE_FINISHED if we have no more work to do.
431  */
433 
434  /*
435  * Final states. CSTATE_ABORTED means that the script execution was
436  * aborted because a command failed, CSTATE_FINISHED means success.
437  */
ConnectionStateEnum
Definition: pgbench.c:362

◆ MetaCommand

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

Definition at line 523 of file pgbench.c.

524 {
525  META_NONE, /* not a known meta-command */
526  META_SET, /* \set */
527  META_SETSHELL, /* \setshell */
528  META_SHELL, /* \shell */
529  META_SLEEP, /* \sleep */
530  META_GSET, /* \gset */
531  META_ASET, /* \aset */
532  META_IF, /* \if */
533  META_ELIF, /* \elif */
534  META_ELSE, /* \else */
535  META_ENDIF, /* \endif */
536  META_STARTPIPELINE, /* \startpipeline */
537  META_ENDPIPELINE /* \endpipeline */
538 } MetaCommand;
MetaCommand
Definition: pgbench.c:523

◆ partition_method_t

Enumerator
PART_NONE 
PART_RANGE 
PART_HASH 

Definition at line 234 of file pgbench.c.

235 {
236  PART_NONE, /* no partitioning */
237  PART_RANGE, /* range partitioning */
238  PART_HASH /* hash partitioning */
partition_method_t
Definition: pgbench.c:234

◆ QueryMode

enum QueryMode
Enumerator
QUERY_SIMPLE 
QUERY_EXTENDED 
QUERY_PREPARED 
NUM_QUERYMODE 

Definition at line 540 of file pgbench.c.

541 {
542  QUERY_SIMPLE, /* simple query */
543  QUERY_EXTENDED, /* extended query */
544  QUERY_PREPARED, /* extended query with prepared statements */
546 } QueryMode;
QueryMode
Definition: pgbench.c:540

Function Documentation

◆ accumStats()

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

Definition at line 1295 of file pgbench.c.

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

Referenced by doLog(), and processXactStats().

1296 {
1297  stats->cnt++;
1298 
1299  if (skipped)
1300  {
1301  /* no latency to record on skipped transactions */
1302  stats->skipped++;
1303  }
1304  else
1305  {
1306  addToSimpleStats(&stats->latency, lat);
1307 
1308  /* and possibly the same for schedule lag */
1309  if (throttle_delay)
1310  addToSimpleStats(&stats->lag, lag);
1311  }
1312 }
SimpleStats lag
Definition: pgbench.c:342
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:1251
SimpleStats latency
Definition: pgbench.c:341
double throttle_delay
Definition: pgbench.c:211
int64 cnt
Definition: pgbench.c:338
int64 skipped
Definition: pgbench.c:339

◆ add_socket_to_set()

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

Definition at line 6994 of file pgbench.c.

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

Referenced by setalarm(), and threadRun().

6995 {
6996  if (fd < 0 || fd >= FD_SETSIZE)
6997  {
6998  /*
6999  * Doing a hard exit here is a bit grotty, but it doesn't seem worth
7000  * complicating the API to make it less grotty.
7001  */
7002  pg_log_fatal("too many client connections for select()");
7003  exit(1);
7004  }
7005  FD_SET(fd, &sa->fds);
7006  if (fd > sa->maxfd)
7007  sa->maxfd = fd;
7008 }
static int fd(const char *x, int i)
Definition: preproc-init.c:105
fd_set fds
Definition: pgbench.c:109
int maxfd
Definition: pgbench.c:108
#define pg_log_fatal(...)
Definition: logging.h:76

◆ addScript()

static void addScript ( ParsedScript  script)
static

Definition at line 5379 of file pgbench.c.

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

Referenced by ParseScript().

5380 {
5381  if (script.commands == NULL || script.commands[0] == NULL)
5382  {
5383  pg_log_fatal("empty command list for script \"%s\"", script.desc);
5384  exit(1);
5385  }
5386 
5387  if (num_scripts >= MAX_SCRIPTS)
5388  {
5389  pg_log_fatal("at most %d SQL scripts are allowed", MAX_SCRIPTS);
5390  exit(1);
5391  }
5392 
5393  CheckConditional(script);
5394 
5395  sql_script[num_scripts] = script;
5396  num_scripts++;
5397 }
static int num_scripts
Definition: pgbench.c:593
#define MAX_SCRIPTS
Definition: pgbench.c:306
static void CheckConditional(ParsedScript ps)
Definition: pgbench.c:5029
const char * desc
Definition: pgbench.c:586
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:592
Command ** commands
Definition: pgbench.c:588
#define pg_log_fatal(...)
Definition: logging.h:76

◆ addToSimpleStats()

static void addToSimpleStats ( SimpleStats ss,
double  val 
)
static

Definition at line 1251 of file pgbench.c.

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

Referenced by accumStats(), and advanceConnectionState().

1252 {
1253  if (ss->count == 0 || val < ss->min)
1254  ss->min = val;
1255  if (ss->count == 0 || val > ss->max)
1256  ss->max = val;
1257  ss->count++;
1258  ss->sum += val;
1259  ss->sum2 += val * val;
1260 }
double sum
Definition: pgbench.c:320
int64 count
Definition: pgbench.c:317
double max
Definition: pgbench.c:319
double sum2
Definition: pgbench.c:321
long val
Definition: informix.c:664
double min
Definition: pgbench.c:318

◆ advanceConnectionState()

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

Definition at line 3119 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_duration, 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(), duration, end_time, executeMetaCommand(), finishCon(), getPoissonRand(), CState::id, IFSTATE_ELSE_FALSE, IFSTATE_ELSE_TRUE, IFSTATE_FALSE, IFSTATE_IGNORED, IFSTATE_NONE, IFSTATE_TRUE, is_connect, latency_limit, Command::meta, META_ASET, META_COMMAND, META_ELIF, META_ELSE, META_ENDIF, META_GSET, META_IF, now(), nxacts, pg_log_debug, pg_log_error, PG_TIME_GET_DOUBLE, pg_time_now(), pg_time_now_lazy(), PQ_PIPELINE_OFF, PQ_PIPELINE_ON, PQconsumeInput(), PQisBusy(), PQpipelineStatus(), CState::prepared, processXactStats(), readCommandResponse(), report_per_command, sendCommand(), SQL_COMMAND, CState::state, Command::stats, CState::stmt_begin, throttle_delay, TState::throttle_trigger, timer_exceeded, TState::ts_throttle_rs, CState::txn_begin, CState::txn_scheduled, Command::type, CState::use_file, and Command::varprefix.

Referenced by threadRun().

3120 {
3121 
3122  /*
3123  * gettimeofday() isn't free, so we get the current timestamp lazily the
3124  * first time it's needed, and reuse the same value throughout this
3125  * function after that. This also ensures that e.g. the calculated
3126  * latency reported in the log file and in the totals are the same. Zero
3127  * means "not set yet". Reset "now" when we execute shell commands or
3128  * expressions, which might take a non-negligible amount of time, though.
3129  */
3130  pg_time_usec_t now = 0;
3131 
3132  /*
3133  * Loop in the state machine, until we have to wait for a result from the
3134  * server or have to sleep for throttling or \sleep.
3135  *
3136  * Note: In the switch-statement below, 'break' will loop back here,
3137  * meaning "continue in the state machine". Return is used to return to
3138  * the caller, giving the thread the opportunity to advance another
3139  * client.
3140  */
3141  for (;;)
3142  {
3143  Command *command;
3144 
3145  switch (st->state)
3146  {
3147  /* Select transaction (script) to run. */
3148  case CSTATE_CHOOSE_SCRIPT:
3149  st->use_file = chooseScript(thread);
3151 
3152  pg_log_debug("client %d executing script \"%s\"",
3153  st->id, sql_script[st->use_file].desc);
3154 
3155  /*
3156  * If time is over, we're done; otherwise, get ready to start
3157  * a new transaction, or to get throttled if that's requested.
3158  */
3161  break;
3162 
3163  /* Start new transaction (script) */
3164  case CSTATE_START_TX:
3165  pg_time_now_lazy(&now);
3166 
3167  /* establish connection if needed, i.e. under --connect */
3168  if (st->con == NULL)
3169  {
3170  pg_time_usec_t start = now;
3171 
3172  if ((st->con = doConnect()) == NULL)
3173  {
3174  pg_log_error("client %d aborted while establishing connection", st->id);
3175  st->state = CSTATE_ABORTED;
3176  break;
3177  }
3178 
3179  /* reset now after connection */
3180  now = pg_time_now();
3181 
3182  thread->conn_duration += now - start;
3183 
3184  /* Reset session-local state */
3185  memset(st->prepared, 0, sizeof(st->prepared));
3186  }
3187 
3188  /* record transaction start time */
3189  st->txn_begin = now;
3190 
3191  /*
3192  * When not throttling, this is also the transaction's
3193  * scheduled start time.
3194  */
3195  if (!throttle_delay)
3196  st->txn_scheduled = now;
3197 
3198  /* Begin with the first command */
3200  st->command = 0;
3201  break;
3202 
3203  /*
3204  * Handle throttling once per transaction by sleeping.
3205  */
3207 
3208  /*
3209  * Generate a delay such that the series of delays will
3210  * approximate a Poisson distribution centered on the
3211  * throttle_delay time.
3212  *
3213  * If transactions are too slow or a given wait is shorter
3214  * than a transaction, the next transaction will start right
3215  * away.
3216  */
3217  Assert(throttle_delay > 0);
3218 
3219  thread->throttle_trigger +=
3221  st->txn_scheduled = thread->throttle_trigger;
3222 
3223  /*
3224  * If --latency-limit is used, and this slot is already late
3225  * so that the transaction will miss the latency limit even if
3226  * it completed immediately, skip this time slot and schedule
3227  * to continue running on the next slot that isn't late yet.
3228  * But don't iterate beyond the -t limit, if one is given.
3229  */
3230  if (latency_limit)
3231  {
3232  pg_time_now_lazy(&now);
3233 
3234  while (thread->throttle_trigger < now - latency_limit &&
3235  (nxacts <= 0 || st->cnt < nxacts))
3236  {
3237  processXactStats(thread, st, &now, true, agg);
3238  /* next rendez-vous */
3239  thread->throttle_trigger +=
3241  st->txn_scheduled = thread->throttle_trigger;
3242  }
3243 
3244  /*
3245  * stop client if -t was exceeded in the previous skip
3246  * loop
3247  */
3248  if (nxacts > 0 && st->cnt >= nxacts)
3249  {
3250  st->state = CSTATE_FINISHED;
3251  break;
3252  }
3253  }
3254 
3255  /*
3256  * stop client if next transaction is beyond pgbench end of
3257  * execution; otherwise, throttle it.
3258  */
3259  st->state = end_time > 0 && st->txn_scheduled > end_time ?
3261  break;
3262 
3263  /*
3264  * Wait until it's time to start next transaction.
3265  */
3266  case CSTATE_THROTTLE:
3267  pg_time_now_lazy(&now);
3268 
3269  if (now < st->txn_scheduled)
3270  return; /* still sleeping, nothing to do here */
3271 
3272  /* done sleeping, but don't start transaction if we're done */
3274  break;
3275 
3276  /*
3277  * Send a command to server (or execute a meta-command)
3278  */
3279  case CSTATE_START_COMMAND:
3280  command = sql_script[st->use_file].commands[st->command];
3281 
3282  /* Transition to script end processing if done */
3283  if (command == NULL)
3284  {
3285  st->state = CSTATE_END_TX;
3286  break;
3287  }
3288 
3289  /* record begin time of next command, and initiate it */
3290  if (report_per_command)
3291  {
3292  pg_time_now_lazy(&now);
3293  st->stmt_begin = now;
3294  }
3295 
3296  /* Execute the command */
3297  if (command->type == SQL_COMMAND)
3298  {
3299  /* disallow \aset and \gset in pipeline mode */
3300  if (PQpipelineStatus(st->con) != PQ_PIPELINE_OFF)
3301  {
3302  if (command->meta == META_GSET)
3303  {
3304  commandFailed(st, "gset", "\\gset is not allowed in pipeline mode");
3305  st->state = CSTATE_ABORTED;
3306  break;
3307  }
3308  else if (command->meta == META_ASET)
3309  {
3310  commandFailed(st, "aset", "\\aset is not allowed in pipeline mode");
3311  st->state = CSTATE_ABORTED;
3312  break;
3313  }
3314  }
3315 
3316  if (!sendCommand(st, command))
3317  {
3318  commandFailed(st, "SQL", "SQL command send failed");
3319  st->state = CSTATE_ABORTED;
3320  }
3321  else
3322  {
3323  /* Wait for results, unless in pipeline mode */
3324  if (PQpipelineStatus(st->con) == PQ_PIPELINE_OFF)
3325  st->state = CSTATE_WAIT_RESULT;
3326  else
3327  st->state = CSTATE_END_COMMAND;
3328  }
3329  }
3330  else if (command->type == META_COMMAND)
3331  {
3332  /*-----
3333  * Possible state changes when executing meta commands:
3334  * - on errors CSTATE_ABORTED
3335  * - on sleep CSTATE_SLEEP
3336  * - else CSTATE_END_COMMAND
3337  */
3338  st->state = executeMetaCommand(st, &now);
3339  }
3340 
3341  /*
3342  * We're now waiting for an SQL command to complete, or
3343  * finished processing a metacommand, or need to sleep, or
3344  * something bad happened.
3345  */
3346  Assert(st->state == CSTATE_WAIT_RESULT ||
3347  st->state == CSTATE_END_COMMAND ||
3348  st->state == CSTATE_SLEEP ||
3349  st->state == CSTATE_ABORTED);
3350  break;
3351 
3352  /*
3353  * non executed conditional branch
3354  */
3355  case CSTATE_SKIP_COMMAND:
3357  /* quickly skip commands until something to do... */
3358  while (true)
3359  {
3360  Command *command;
3361 
3362  command = sql_script[st->use_file].commands[st->command];
3363 
3364  /* cannot reach end of script in that state */
3365  Assert(command != NULL);
3366 
3367  /*
3368  * if this is conditional related, update conditional
3369  * state
3370  */
3371  if (command->type == META_COMMAND &&
3372  (command->meta == META_IF ||
3373  command->meta == META_ELIF ||
3374  command->meta == META_ELSE ||
3375  command->meta == META_ENDIF))
3376  {
3377  switch (conditional_stack_peek(st->cstack))
3378  {
3379  case IFSTATE_FALSE:
3380  if (command->meta == META_IF ||
3381  command->meta == META_ELIF)
3382  {
3383  /* we must evaluate the condition */
3385  }
3386  else if (command->meta == META_ELSE)
3387  {
3388  /* we must execute next command */
3392  st->command++;
3393  }
3394  else if (command->meta == META_ENDIF)
3395  {
3398  if (conditional_active(st->cstack))
3400 
3401  /*
3402  * else state remains in
3403  * CSTATE_SKIP_COMMAND
3404  */
3405  st->command++;
3406  }
3407  break;
3408 
3409  case IFSTATE_IGNORED:
3410  case IFSTATE_ELSE_FALSE:
3411  if (command->meta == META_IF)
3413  IFSTATE_IGNORED);
3414  else if (command->meta == META_ENDIF)
3415  {
3418  if (conditional_active(st->cstack))
3420  }
3421  /* could detect "else" & "elif" after "else" */
3422  st->command++;
3423  break;
3424 
3425  case IFSTATE_NONE:
3426  case IFSTATE_TRUE:
3427  case IFSTATE_ELSE_TRUE:
3428  default:
3429 
3430  /*
3431  * inconsistent if inactive, unreachable dead
3432  * code
3433  */
3434  Assert(false);
3435  }
3436  }
3437  else
3438  {
3439  /* skip and consider next */
3440  st->command++;
3441  }
3442 
3443  if (st->state != CSTATE_SKIP_COMMAND)
3444  /* out of quick skip command loop */
3445  break;
3446  }
3447  break;
3448 
3449  /*
3450  * Wait for the current SQL command to complete
3451  */
3452  case CSTATE_WAIT_RESULT:
3453  pg_log_debug("client %d receiving", st->id);
3454  if (!PQconsumeInput(st->con))
3455  {
3456  /* there's something wrong */
3457  commandFailed(st, "SQL", "perhaps the backend died while processing");
3458  st->state = CSTATE_ABORTED;
3459  break;
3460  }
3461  if (PQisBusy(st->con))
3462  return; /* don't have the whole result yet */
3463 
3464  /* store or discard the query results */
3465  if (readCommandResponse(st,
3468  {
3469  /*
3470  * outside of pipeline mode: stop reading results.
3471  * pipeline mode: continue reading results until an
3472  * end-of-pipeline response.
3473  */
3474  if (PQpipelineStatus(st->con) != PQ_PIPELINE_ON)
3475  st->state = CSTATE_END_COMMAND;
3476  }
3477  else
3478  st->state = CSTATE_ABORTED;
3479  break;
3480 
3481  /*
3482  * Wait until sleep is done. This state is entered after a
3483  * \sleep metacommand. The behavior is similar to
3484  * CSTATE_THROTTLE, but proceeds to CSTATE_START_COMMAND
3485  * instead of CSTATE_START_TX.
3486  */
3487  case CSTATE_SLEEP:
3488  pg_time_now_lazy(&now);
3489  if (now < st->sleep_until)
3490  return; /* still sleeping, nothing to do here */
3491  /* Else done sleeping. */
3492  st->state = CSTATE_END_COMMAND;
3493  break;
3494 
3495  /*
3496  * End of command: record stats and proceed to next command.
3497  */
3498  case CSTATE_END_COMMAND:
3499 
3500  /*
3501  * command completed: accumulate per-command execution times
3502  * in thread-local data structure, if per-command latencies
3503  * are requested.
3504  */
3505  if (report_per_command)
3506  {
3507  Command *command;
3508 
3509  pg_time_now_lazy(&now);
3510 
3511  command = sql_script[st->use_file].commands[st->command];
3512  /* XXX could use a mutex here, but we choose not to */
3513  addToSimpleStats(&command->stats,
3514  PG_TIME_GET_DOUBLE(now - st->stmt_begin));
3515  }
3516 
3517  /* Go ahead with next command, to be executed or skipped */
3518  st->command++;
3519  st->state = conditional_active(st->cstack) ?
3521  break;
3522 
3523  /*
3524  * End of transaction (end of script, really).
3525  */
3526  case CSTATE_END_TX:
3527 
3528  /* transaction finished: calculate latency and do log */
3529  processXactStats(thread, st, &now, false, agg);
3530 
3531  /*
3532  * missing \endif... cannot happen if CheckConditional was
3533  * okay
3534  */
3536 
3537  if (is_connect)
3538  {
3539  finishCon(st);
3540  now = 0;
3541  }
3542 
3543  if ((st->cnt >= nxacts && duration <= 0) || timer_exceeded)
3544  {
3545  /* script completed */
3546  st->state = CSTATE_FINISHED;
3547  break;
3548  }
3549 
3550  /* next transaction (script) */
3552 
3553  /*
3554  * Ensure that we always return on this point, so as to avoid
3555  * an infinite loop if the script only contains meta commands.
3556  */
3557  return;
3558 
3559  /*
3560  * Final states. Close the connection if it's still open.
3561  */
3562  case CSTATE_ABORTED:
3563  case CSTATE_FINISHED:
3564  finishCon(st);
3565  return;
3566  }
3567  }
3568 }
#define PG_TIME_GET_DOUBLE(t)
Definition: pgbench.c:689
int64 throttle_trigger
Definition: pgbench.c:497
bool conditional_active(ConditionalStack cstack)
Definition: conditional.c:128
static pg_time_usec_t pg_time_now(void)
Definition: pgbench.c:673
int type
Definition: pgbench.c:575
int id
Definition: pgbench.c:448
static int chooseScript(TState *thread)
Definition: pgbench.c:2835
int64 pg_time_usec_t
Definition: pgbench.c:329
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:57
static void processXactStats(TState *thread, CState *st, pg_time_usec_t *now, bool skipped, StatsData *agg)
Definition: pgbench.c:3856
#define pg_log_error(...)
Definition: logging.h:80
void conditional_stack_push(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:41
static void commandFailed(CState *st, const char *cmd, const char *message)
Definition: pgbench.c:2827
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:1251
pg_time_usec_t conn_duration
Definition: pgbench.c:504
int duration
Definition: pgbench.c:182
ConditionalStack cstack
Definition: pgbench.c:450
static void finishCon(CState *st)
Definition: pgbench.c:6807
bool is_connect
Definition: pgbench.c:274
double throttle_delay
Definition: pgbench.c:211
int64 end_time
Definition: pgbench.c:183
pg_time_usec_t txn_begin
Definition: pgbench.c:469
#define META_COMMAND
Definition: pgbench.c:515
#define pg_log_debug(...)
Definition: logging.h:92
int nxacts
Definition: pgbench.c:181
const char * desc
Definition: pgbench.c:586
int64 cnt
Definition: pgbench.c:475
static bool readCommandResponse(CState *st, MetaCommand meta, char *varprefix)
Definition: pgbench.c:2950
MetaCommand meta
Definition: pgbench.c:576
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:592
static bool sendCommand(CState *st, Command *command)
Definition: pgbench.c:2854
RandomState ts_throttle_rs
Definition: pgbench.c:494
#define SQL_COMMAND
Definition: pgbench.c:514
static void pg_time_now_lazy(pg_time_usec_t *now)
Definition: pgbench.c:683
int PQconsumeInput(PGconn *conn)
Definition: fe-exec.c:1853
int command
Definition: pgbench.c:459
SimpleStats stats
Definition: pgbench.c:581
ConnectionStateEnum state
Definition: pgbench.c:449
ifState conditional_stack_peek(ConditionalStack cstack)
Definition: conditional.c:94
pg_time_usec_t stmt_begin
Definition: pgbench.c:470
PGconn * con
Definition: pgbench.c:447
static PGconn * doConnect(void)
Definition: pgbench.c:1347
#define Assert(condition)
Definition: c.h:804
int PQisBusy(PGconn *conn)
Definition: fe-exec.c:1900
PGpipelineStatus PQpipelineStatus(const PGconn *conn)
Definition: fe-connect.c:6761
bool conditional_stack_poke(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:106
char * varprefix
Definition: pgbench.c:579
volatile bool timer_exceeded
Definition: pgbench.c:287
Command ** commands
Definition: pgbench.c:588
int64 latency_limit
Definition: pgbench.c:219
bool report_per_command
Definition: pgbench.c:275
static int64 getPoissonRand(RandomState *random_state, double center)
Definition: pgbench.c:1021
bool conditional_stack_empty(ConditionalStack cstack)
Definition: conditional.c:118
pg_time_usec_t txn_scheduled
Definition: pgbench.c:467
bool prepared[MAX_SCRIPTS]
Definition: pgbench.c:472
int use_file
Definition: pgbench.c:458
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1544
static ConnectionStateEnum executeMetaCommand(CState *st, pg_time_usec_t *now)
Definition: pgbench.c:3578

◆ alloc_socket_set()

static socket_set * alloc_socket_set ( int  count)
static

Definition at line 6975 of file pgbench.c.

References pg_malloc0().

Referenced by setalarm(), and threadRun().

6976 {
6977  return (socket_set *) pg_malloc0(sizeof(socket_set));
6978 }
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53

◆ assignVariables()

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

Definition at line 1742 of file pgbench.c.

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

Referenced by sendCommand().

1743 {
1744  char *p,
1745  *name,
1746  *val;
1747 
1748  p = sql;
1749  while ((p = strchr(p, ':')) != NULL)
1750  {
1751  int eaten;
1752 
1753  name = parseVariable(p, &eaten);
1754  if (name == NULL)
1755  {
1756  while (*p == ':')
1757  {
1758  p++;
1759  }
1760  continue;
1761  }
1762 
1763  val = getVariable(st, name);
1764  free(name);
1765  if (val == NULL)
1766  {
1767  p++;
1768  continue;
1769  }
1770 
1771  p = replaceVariable(&sql, p, eaten, val);
1772  }
1773 
1774  return sql;
1775 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1447
static char * replaceVariable(char **sql, char *param, int len, char *value)
Definition: pgbench.c:1722
#define free(a)
Definition: header.h:65
static char * parseVariable(const char *sql, int *eaten)
Definition: pgbench.c:1695
const char * name
Definition: encode.c:515
long val
Definition: informix.c:664

◆ CheckConditional()

static void CheckConditional ( ParsedScript  ps)
static

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

5030 {
5031  /* statically check conditional structure */
5033  int i;
5034 
5035  for (i = 0; ps.commands[i] != NULL; i++)
5036  {
5037  Command *cmd = ps.commands[i];
5038 
5039  if (cmd->type == META_COMMAND)
5040  {
5041  switch (cmd->meta)
5042  {
5043  case META_IF:
5045  break;
5046  case META_ELIF:
5047  if (conditional_stack_empty(cs))
5048  ConditionError(ps.desc, i + 1, "\\elif without matching \\if");
5050  ConditionError(ps.desc, i + 1, "\\elif after \\else");
5051  break;
5052  case META_ELSE:
5053  if (conditional_stack_empty(cs))
5054  ConditionError(ps.desc, i + 1, "\\else without matching \\if");
5056  ConditionError(ps.desc, i + 1, "\\else after \\else");
5058  break;
5059  case META_ENDIF:
5060  if (!conditional_stack_pop(cs))
5061  ConditionError(ps.desc, i + 1, "\\endif without matching \\if");
5062  break;
5063  default:
5064  /* ignore anything else... */
5065  break;
5066  }
5067  }
5068  }
5069  if (!conditional_stack_empty(cs))
5070  ConditionError(ps.desc, i + 1, "\\if without matching \\endif");
5072 }
int type
Definition: pgbench.c:575
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:57
static void ConditionError(const char *desc, int cmdn, const char *msg)
Definition: pgbench.c:5018
void conditional_stack_push(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:41
#define META_COMMAND
Definition: pgbench.c:515
const char * desc
Definition: pgbench.c:586
MetaCommand meta
Definition: pgbench.c:576
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:588
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 4374 of file pgbench.c.

References ALL_INIT_STEPS, pg_log_fatal, and pg_log_info.

Referenced by main().

4375 {
4376  if (initialize_steps[0] == '\0')
4377  {
4378  pg_log_fatal("no initialization steps specified");
4379  exit(1);
4380  }
4381 
4382  for (const char *step = initialize_steps; *step != '\0'; step++)
4383  {
4384  if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
4385  {
4386  pg_log_fatal("unrecognized initialization step \"%c\"", *step);
4387  pg_log_info("Allowed step characters are: \"" ALL_INIT_STEPS "\".");
4388  exit(1);
4389  }
4390  }
4391 }
#define ALL_INIT_STEPS
Definition: pgbench.c:171
#define pg_log_info(...)
Definition: logging.h:88
#define pg_log_fatal(...)
Definition: logging.h:76

◆ chooseScript()

static int chooseScript ( TState thread)
static

Definition at line 2835 of file pgbench.c.

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

Referenced by advanceConnectionState().

2836 {
2837  int i = 0;
2838  int64 w;
2839 
2840  if (num_scripts == 1)
2841  return 0;
2842 
2843  w = getrand(&thread->ts_choose_rs, 0, total_weight - 1);
2844  do
2845  {
2846  w -= sql_script[i++].weight;
2847  } while (w >= 0);
2848 
2849  return i - 1;
2850 }
static int num_scripts
Definition: pgbench.c:593
static int64 getrand(RandomState *random_state, int64 min, int64 max)
Definition: pgbench.c:917
int weight
Definition: pgbench.c:587
RandomState ts_choose_rs
Definition: pgbench.c:493
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:592
static int64 total_weight
Definition: pgbench.c:594
int i

◆ clear_socket_set()

static void clear_socket_set ( socket_set sa)
static

Definition at line 6987 of file pgbench.c.

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

Referenced by setalarm(), and threadRun().

6988 {
6989  FD_ZERO(&sa->fds);
6990  sa->maxfd = -1;
6991 }
fd_set fds
Definition: pgbench.c:109
int maxfd
Definition: pgbench.c:108

◆ coerceToBool()

static bool coerceToBool ( PgBenchValue pval,
bool bval 
)
static

Definition at line 1809 of file pgbench.c.

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

Referenced by evalLazyFunc(), and evalStandardFunc().

1810 {
1811  if (pval->type == PGBT_BOOLEAN)
1812  {
1813  *bval = pval->u.bval;
1814  return true;
1815  }
1816  else /* NULL, INT or DOUBLE */
1817  {
1818  pg_log_error("cannot coerce %s to boolean", valueTypeName(pval));
1819  *bval = false; /* suppress uninitialized-variable warnings */
1820  return false;
1821  }
1822 }
#define pg_log_error(...)
Definition: logging.h:80
union PgBenchValue::@31 u
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1787
bool bval
Definition: pgbench.h:51
PgBenchValueType type
Definition: pgbench.h:46

◆ coerceToDouble()

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

Definition at line 1878 of file pgbench.c.

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

Referenced by evalStandardFunc().

1879 {
1880  if (pval->type == PGBT_DOUBLE)
1881  {
1882  *dval = pval->u.dval;
1883  return true;
1884  }
1885  else if (pval->type == PGBT_INT)
1886  {
1887  *dval = (double) pval->u.ival;
1888  return true;
1889  }
1890  else /* BOOLEAN or NULL */
1891  {
1892  pg_log_error("cannot coerce %s to double", valueTypeName(pval));
1893  return false;
1894  }
1895 }
#define pg_log_error(...)
Definition: logging.h:80
union PgBenchValue::@31 u
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1787
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 1850 of file pgbench.c.

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

Referenced by evalStandardFunc().

1851 {
1852  if (pval->type == PGBT_INT)
1853  {
1854  *ival = pval->u.ival;
1855  return true;
1856  }
1857  else if (pval->type == PGBT_DOUBLE)
1858  {
1859  double dval = rint(pval->u.dval);
1860 
1861  if (isnan(dval) || !FLOAT8_FITS_IN_INT64(dval))
1862  {
1863  pg_log_error("double to int overflow for %f", dval);
1864  return false;
1865  }
1866  *ival = (int64) dval;
1867  return true;
1868  }
1869  else /* BOOLEAN or NULL */
1870  {
1871  pg_log_error("cannot coerce %s to int", valueTypeName(pval));
1872  return false;
1873  }
1874 }
#define pg_log_error(...)
Definition: logging.h:80
union PgBenchValue::@31 u
#define FLOAT8_FITS_IN_INT64(num)
Definition: c.h:1107
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1787
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 2827 of file pgbench.c.

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

Referenced by advanceConnectionState(), and executeMetaCommand().

2828 {
2829  pg_log_error("client %d aborted in command %d (%s) of script %d; %s",
2830  st->id, st->command, cmd, st->use_file, message);
2831 }
int id
Definition: pgbench.c:448
#define pg_log_error(...)
Definition: logging.h:80
int command
Definition: pgbench.c:459
int use_file
Definition: pgbench.c:458

◆ compareVariableNames()

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

Definition at line 1412 of file pgbench.c.

References name.

Referenced by lookupVariable().

1413 {
1414  return strcmp(((const Variable *) v1)->name,
1415  ((const Variable *) v2)->name);
1416 }
const char * name
Definition: encode.c:515

◆ computeIterativeZipfian()

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

Definition at line 1043 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by getZipfianRand().

1044 {
1045  double b = pow(2.0, s - 1.0);
1046  double x,
1047  t,
1048  u,
1049  v;
1050 
1051  /* Ensure n is sane */
1052  if (n <= 1)
1053  return 1;
1054 
1055  while (true)
1056  {
1057  /* random variates */
1058  u = pg_erand48(random_state->xseed);
1059  v = pg_erand48(random_state->xseed);
1060 
1061  x = floor(pow(u, -1.0 / (s - 1.0)));
1062 
1063  t = pow(1.0 + 1.0 / x, s - 1.0);
1064  /* reject if too large or out of bound */
1065  if (v * x * (t - 1.0) / (b - 1.0) <= t / b && x <= n)
1066  break;
1067  }
1068  return (int64) x;
1069 }
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
unsigned short xseed[3]
Definition: pgbench.c:350

◆ ConditionError()

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

Definition at line 5018 of file pgbench.c.

References pg_log_fatal.

Referenced by CheckConditional().

5019 {
5020  pg_log_fatal("condition error in script \"%s\" command %d: %s",
5021  desc, cmdn, msg);
5022  exit(1);
5023 }
#define pg_log_fatal(...)
Definition: logging.h:76

◆ create_sql_command()

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

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

4728 {
4729  Command *my_command;
4730  char *p = skip_sql_comments(buf->data);
4731 
4732  if (p == NULL)
4733  return NULL;
4734 
4735  /* Allocate and initialize Command structure */
4736  my_command = (Command *) pg_malloc(sizeof(Command));
4737  initPQExpBuffer(&my_command->lines);
4738  appendPQExpBufferStr(&my_command->lines, p);
4739  my_command->first_line = NULL; /* this is set later */
4740  my_command->type = SQL_COMMAND;
4741  my_command->meta = META_NONE;
4742  my_command->argc = 0;
4743  memset(my_command->argv, 0, sizeof(my_command->argv));
4744  my_command->varprefix = NULL; /* allocated later, if needed */
4745  my_command->expr = NULL;
4746  initSimpleStats(&my_command->stats);
4747 
4748  return my_command;
4749 }
int type
Definition: pgbench.c:575
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:580
static char * skip_sql_comments(char *sql_command)
Definition: pgbench.c:4692
char * argv[MAX_ARGS]
Definition: pgbench.c:578
MetaCommand meta
Definition: pgbench.c:576
PQExpBufferData lines
Definition: pgbench.c:573
int argc
Definition: pgbench.c:577
#define SQL_COMMAND
Definition: pgbench.c:514
SimpleStats stats
Definition: pgbench.c:581
char * varprefix
Definition: pgbench.c:579
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1242
char * first_line
Definition: pgbench.c:574
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ createPartitions()

static void createPartitions ( PGconn con)
static

Definition at line 3936 of file pgbench.c.

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

Referenced by initCreateTables().

3937 {
3938  PQExpBufferData query;
3939 
3940  /* we must have to create some partitions */
3941  Assert(partitions > 0);
3942 
3943  fprintf(stderr, "creating %d partitions...\n", partitions);
3944 
3945  initPQExpBuffer(&query);
3946 
3947  for (int p = 1; p <= partitions; p++)
3948  {
3950  {
3951  int64 part_size = (naccounts * (int64) scale + partitions - 1) / partitions;
3952 
3953  printfPQExpBuffer(&query,
3954  "create%s table pgbench_accounts_%d\n"
3955  " partition of pgbench_accounts\n"
3956  " for values from (",
3957  unlogged_tables ? " unlogged" : "", p);
3958 
3959  /*
3960  * For RANGE, we use open-ended partitions at the beginning and
3961  * end to allow any valid value for the primary key. Although the
3962  * actual minimum and maximum values can be derived from the
3963  * scale, it is more generic and the performance is better.
3964  */
3965  if (p == 1)
3966  appendPQExpBufferStr(&query, "minvalue");
3967  else
3968  appendPQExpBuffer(&query, INT64_FORMAT, (p - 1) * part_size + 1);
3969 
3970  appendPQExpBufferStr(&query, ") to (");
3971 
3972  if (p < partitions)
3973  appendPQExpBuffer(&query, INT64_FORMAT, p * part_size + 1);
3974  else
3975  appendPQExpBufferStr(&query, "maxvalue");
3976 
3977  appendPQExpBufferChar(&query, ')');
3978  }
3979  else if (partition_method == PART_HASH)
3980  printfPQExpBuffer(&query,
3981  "create%s table pgbench_accounts_%d\n"
3982  " partition of pgbench_accounts\n"
3983  " for values with (modulus %d, remainder %d)",
3984  unlogged_tables ? " unlogged" : "", p,
3985  partitions, p - 1);
3986  else /* cannot get there */
3987  Assert(0);
3988 
3989  /*
3990  * Per ddlinfo in initCreateTables, fillfactor is needed on table
3991  * pgbench_accounts.
3992  */
3993  appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
3994 
3995  executeStatement(con, query.data);
3996  }
3997 
3998  termPQExpBuffer(&query);
3999 }
static int partitions
Definition: pgbench.c:231
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
static partition_method_t partition_method
Definition: pgbench.c:241
int scale
Definition: pgbench.c:189
#define fprintf
Definition: port.h:220
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1316
int fillfactor
Definition: pgbench.c:195
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:380
#define naccounts
Definition: pgbench.c:254
#define Assert(condition)
Definition: c.h:804
#define INT64_FORMAT
Definition: c.h:483
bool unlogged_tables
Definition: pgbench.c:200
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ disconnect_all()

static void disconnect_all ( CState state,
int  length 
)
static

Definition at line 3902 of file pgbench.c.

References finishCon(), and i.

Referenced by main(), and threadRun().

3903 {
3904  int i;
3905 
3906  for (i = 0; i < length; i++)
3907  finishCon(&state[i]);
3908 }
static void finishCon(CState *st)
Definition: pgbench.c:6807
int i

◆ doConnect()

static PGconn* doConnect ( void  )
static

Definition at line 1347 of file pgbench.c.

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

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

1348 {
1349  PGconn *conn;
1350  bool new_pass;
1351  static char *password = NULL;
1352 
1353  /*
1354  * Start the connection. Loop until we have a password if requested by
1355  * backend.
1356  */
1357  do
1358  {
1359 #define PARAMS_ARRAY_SIZE 7
1360 
1361  const char *keywords[PARAMS_ARRAY_SIZE];
1362  const char *values[PARAMS_ARRAY_SIZE];
1363 
1364  keywords[0] = "host";
1365  values[0] = pghost;
1366  keywords[1] = "port";
1367  values[1] = pgport;
1368  keywords[2] = "user";
1369  values[2] = username;
1370  keywords[3] = "password";
1371  values[3] = password;
1372  keywords[4] = "dbname";
1373  values[4] = dbName;
1374  keywords[5] = "fallback_application_name";
1375  values[5] = progname;
1376  keywords[6] = NULL;
1377  values[6] = NULL;
1378 
1379  new_pass = false;
1380 
1381  conn = PQconnectdbParams(keywords, values, true);
1382 
1383  if (!conn)
1384  {
1385  pg_log_error("connection to database \"%s\" failed", dbName);
1386  return NULL;
1387  }
1388 
1389  if (PQstatus(conn) == CONNECTION_BAD &&
1390  PQconnectionNeedsPassword(conn) &&
1391  !password)
1392  {
1393  PQfinish(conn);
1394  password = simple_prompt("Password: ", false);
1395  new_pass = true;
1396  }
1397  } while (new_pass);
1398 
1399  /* check to see that the backend connection was successfully made */
1400  if (PQstatus(conn) == CONNECTION_BAD)
1401  {
1402  pg_log_error("%s", PQerrorMessage(conn));
1403  PQfinish(conn);
1404  return NULL;
1405  }
1406 
1407  return conn;
1408 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6727
#define pg_log_error(...)
Definition: logging.h:80
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4221
const char * pghost
Definition: pgbench.c:278
char * simple_prompt(const char *prompt, bool echo)
Definition: sprompt.c:38
const char * dbName
Definition: pgbench.c:281
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:662
PGconn * conn
Definition: streamutil.c:54
static char * password
Definition: streamutil.c:53
#define PARAMS_ARRAY_SIZE
const char * username
Definition: pgbench.c:280
const char * progname
Definition: pgbench.c:283
static Datum values[MAXATTR]
Definition: bootstrap.c:166
int PQconnectionNeedsPassword(const PGconn *conn)
Definition: fe-connect.c:6770
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:6674
const char * pgport
Definition: pgbench.c:279

◆ doLog()

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

Definition at line 3777 of file pgbench.c.

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

Referenced by processXactStats(), and threadRun().

3779 {
3780  FILE *logfile = thread->logfile;
3782 
3783  Assert(use_log);
3784 
3785  /*
3786  * Skip the log entry if sampling is enabled and this row doesn't belong
3787  * to the random sample.
3788  */
3789  if (sample_rate != 0.0 &&
3791  return;
3792 
3793  /* should we aggregate the results or not? */
3794  if (agg_interval > 0)
3795  {
3796  /*
3797  * Loop until we reach the interval of the current moment, and print
3798  * any empty intervals in between (this may happen with very low tps,
3799  * e.g. --rate=0.1).
3800  */
3801 
3802  while (agg->start_time + agg_interval <= now)
3803  {
3804  /* print aggregated report to logfile */
3805  fprintf(logfile, INT64_FORMAT " " INT64_FORMAT " %.0f %.0f %.0f %.0f",
3806  agg->start_time,
3807  agg->cnt,
3808  agg->latency.sum,
3809  agg->latency.sum2,
3810  agg->latency.min,
3811  agg->latency.max);
3812  if (throttle_delay)
3813  {
3814  fprintf(logfile, " %.0f %.0f %.0f %.0f",
3815  agg->lag.sum,
3816  agg->lag.sum2,
3817  agg->lag.min,
3818  agg->lag.max);
3819  if (latency_limit)
3820  fprintf(logfile, " " INT64_FORMAT, agg->skipped);
3821  }
3822  fputc('\n', logfile);
3823 
3824  /* reset data and move to next interval */
3825  initStats(agg, agg->start_time + agg_interval);
3826  }
3827 
3828  /* accumulate the current transaction */
3829  accumStats(agg, skipped, latency, lag);
3830  }
3831  else
3832  {
3833  /* no, print raw transactions */
3834  if (skipped)
3835  fprintf(logfile, "%d " INT64_FORMAT " skipped %d " INT64_FORMAT " "
3836  INT64_FORMAT,
3837  st->id, st->cnt, st->use_file, now / 1000000, now % 1000000);
3838  else
3839  fprintf(logfile, "%d " INT64_FORMAT " %.0f %d " INT64_FORMAT " "
3840  INT64_FORMAT,
3841  st->id, st->cnt, latency, st->use_file,
3842  now / 1000000, now % 1000000);
3843  if (throttle_delay)
3844  fprintf(logfile, " %.0f", lag);
3845  fputc('\n', logfile);
3846  }
3847 }
pg_time_usec_t start_time
Definition: pgbench.c:337
double sample_rate
Definition: pgbench.c:205
static pg_time_usec_t pg_time_now(void)
Definition: pgbench.c:673
int id
Definition: pgbench.c:448
int64 pg_time_usec_t
Definition: pgbench.c:329
SimpleStats lag
Definition: pgbench.c:342
double sum
Definition: pgbench.c:320
RandomState ts_sample_rs
Definition: pgbench.c:495
bool use_log
Definition: pgbench.c:265
static FILE * logfile
Definition: pg_regress.c:102
SimpleStats latency
Definition: pgbench.c:341
#define fprintf
Definition: port.h:220
double throttle_delay
Definition: pgbench.c:211
FILE * logfile
Definition: pgbench.c:498
int64 cnt
Definition: pgbench.c:338
int64 cnt
Definition: pgbench.c:475
int64 skipped
Definition: pgbench.c:339
double max
Definition: pgbench.c:319
static void accumStats(StatsData *stats, bool skipped, double lat, double lag)
Definition: pgbench.c:1295
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
static void initStats(StatsData *sd, pg_time_usec_t start)
Definition: pgbench.c:1282
#define Assert(condition)
Definition: c.h:804
double sum2
Definition: pgbench.c:321
unsigned short xseed[3]
Definition: pgbench.c:350
int64 latency_limit
Definition: pgbench.c:219
#define INT64_FORMAT
Definition: c.h:483
int use_file
Definition: pgbench.c:458
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1544
double min
Definition: pgbench.c:318
int agg_interval
Definition: pgbench.c:267

◆ evalFunc()

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

Definition at line 2619 of file pgbench.c.

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

Referenced by evaluateExpr().

2621 {
2622  if (isLazyFunc(func))
2623  return evalLazyFunc(st, func, args, retval);
2624  else
2625  return evalStandardFunc(st, func, args, retval);
2626 }
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1937
static bool evalStandardFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2054
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:1930

◆ evalLazyFunc()

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

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

1939 {
1940  PgBenchValue a1,
1941  a2;
1942  bool ba1,
1943  ba2;
1944 
1945  Assert(isLazyFunc(func) && args != NULL && args->next != NULL);
1946 
1947  /* args points to first condition */
1948  if (!evaluateExpr(st, args->expr, &a1))
1949  return false;
1950 
1951  /* second condition for AND/OR and corresponding branch for CASE */
1952  args = args->next;
1953 
1954  switch (func)
1955  {
1956  case PGBENCH_AND:
1957  if (a1.type == PGBT_NULL)
1958  {
1959  setNullValue(retval);
1960  return true;
1961  }
1962 
1963  if (!coerceToBool(&a1, &ba1))
1964  return false;
1965 
1966  if (!ba1)
1967  {
1968  setBoolValue(retval, false);
1969  return true;
1970  }
1971 
1972  if (!evaluateExpr(st, args->expr, &a2))
1973  return false;
1974 
1975  if (a2.type == PGBT_NULL)
1976  {
1977  setNullValue(retval);
1978  return true;
1979  }
1980  else if (!coerceToBool(&a2, &ba2))
1981  return false;
1982  else
1983  {
1984  setBoolValue(retval, ba2);
1985  return true;
1986  }
1987 
1988  return true;
1989 
1990  case PGBENCH_OR:
1991 
1992  if (a1.type == PGBT_NULL)
1993  {
1994  setNullValue(retval);
1995  return true;
1996  }
1997 
1998  if (!coerceToBool(&a1, &ba1))
1999  return false;
2000 
2001  if (ba1)
2002  {
2003  setBoolValue(retval, true);
2004  return true;
2005  }
2006 
2007  if (!evaluateExpr(st, args->expr, &a2))
2008  return false;
2009 
2010  if (a2.type == PGBT_NULL)
2011  {
2012  setNullValue(retval);
2013  return true;
2014  }
2015  else if (!coerceToBool(&a2, &ba2))
2016  return false;
2017  else
2018  {
2019  setBoolValue(retval, ba2);
2020  return true;
2021  }
2022 
2023  case PGBENCH_CASE:
2024  /* when true, execute branch */
2025  if (valueTruth(&a1))
2026  return evaluateExpr(st, args->expr, retval);
2027 
2028  /* now args contains next condition or final else expression */
2029  args = args->next;
2030 
2031  /* final else case? */
2032  if (args->next == NULL)
2033  return evaluateExpr(st, args->expr, retval);
2034 
2035  /* no, another when, proceed */
2036  return evalLazyFunc(st, PGBENCH_CASE, args, retval);
2037 
2038  default:
2039  /* internal error, cannot get here */
2040  Assert(0);
2041  break;
2042  }
2043  return false;
2044 }
static bool coerceToBool(PgBenchValue *pval, bool *bval)
Definition: pgbench.c:1809
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1937
static const FormData_pg_attribute a2
Definition: heap.c:166
static bool evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
Definition: pgbench.c:2635
static void setBoolValue(PgBenchValue *pv, bool bval)
Definition: pgbench.c:1907
static void setNullValue(PgBenchValue *pv)
Definition: pgbench.c:1899
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:1930
#define Assert(condition)
Definition: c.h:804
static bool valueTruth(PgBenchValue *pval)
Definition: pgbench.c:1829
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 2054 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, permute(), pg_add_s64_overflow(), PG_INT64_MIN, pg_log_error, pg_mul_s64_overflow(), pg_sub_s64_overflow(), PGBENCH_ABS, PGBENCH_ADD, PGBENCH_BITAND, PGBENCH_BITOR, PGBENCH_BITXOR, PGBENCH_DEBUG, PGBENCH_DIV, PGBENCH_DOUBLE, PGBENCH_EQ, PGBENCH_EXP, PGBENCH_GREATEST, PGBENCH_HASH_FNV1A, PGBENCH_HASH_MURMUR2, PGBENCH_INT, PGBENCH_IS, PGBENCH_LE, PGBENCH_LEAST, PGBENCH_LN, PGBENCH_LSHIFT, PGBENCH_LT, PGBENCH_MOD, PGBENCH_MUL, PGBENCH_NE, PGBENCH_NOT, PGBENCH_PERMUTE, 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().

2057 {
2058  /* evaluate all function arguments */
2059  int nargs = 0;
2060  PgBenchValue vargs[MAX_FARGS];
2061  PgBenchExprLink *l = args;
2062  bool has_null = false;
2063 
2064  for (nargs = 0; nargs < MAX_FARGS && l != NULL; nargs++, l = l->next)
2065  {
2066  if (!evaluateExpr(st, l->expr, &vargs[nargs]))
2067  return false;
2068  has_null |= vargs[nargs].type == PGBT_NULL;
2069  }
2070 
2071  if (l != NULL)
2072  {
2073  pg_log_error("too many function arguments, maximum is %d", MAX_FARGS);
2074  return false;
2075  }
2076 
2077  /* NULL arguments */
2078  if (has_null && func != PGBENCH_IS && func != PGBENCH_DEBUG)
2079  {
2080  setNullValue(retval);
2081  return true;
2082  }
2083 
2084  /* then evaluate function */
2085  switch (func)
2086  {
2087  /* overloaded operators */
2088  case PGBENCH_ADD:
2089  case PGBENCH_SUB:
2090  case PGBENCH_MUL:
2091  case PGBENCH_DIV:
2092  case PGBENCH_MOD:
2093  case PGBENCH_EQ:
2094  case PGBENCH_NE:
2095  case PGBENCH_LE:
2096  case PGBENCH_LT:
2097  {
2098  PgBenchValue *lval = &vargs[0],
2099  *rval = &vargs[1];
2100 
2101  Assert(nargs == 2);
2102 
2103  /* overloaded type management, double if some double */
2104  if ((lval->type == PGBT_DOUBLE ||
2105  rval->type == PGBT_DOUBLE) && func != PGBENCH_MOD)
2106  {
2107  double ld,
2108  rd;
2109 
2110  if (!coerceToDouble(lval, &ld) ||
2111  !coerceToDouble(rval, &rd))
2112  return false;
2113 
2114  switch (func)
2115  {
2116  case PGBENCH_ADD:
2117  setDoubleValue(retval, ld + rd);
2118  return true;
2119 
2120  case PGBENCH_SUB:
2121  setDoubleValue(retval, ld - rd);
2122  return true;
2123 
2124  case PGBENCH_MUL:
2125  setDoubleValue(retval, ld * rd);
2126  return true;
2127 
2128  case PGBENCH_DIV:
2129  setDoubleValue(retval, ld / rd);
2130  return true;
2131 
2132  case PGBENCH_EQ:
2133  setBoolValue(retval, ld == rd);
2134  return true;
2135 
2136  case PGBENCH_NE:
2137  setBoolValue(retval, ld != rd);
2138  return true;
2139 
2140  case PGBENCH_LE:
2141  setBoolValue(retval, ld <= rd);
2142  return true;
2143 
2144  case PGBENCH_LT:
2145  setBoolValue(retval, ld < rd);
2146  return true;
2147 
2148  default:
2149  /* cannot get here */
2150  Assert(0);
2151  }
2152  }
2153  else /* we have integer operands, or % */
2154  {
2155  int64 li,
2156  ri,
2157  res;
2158 
2159  if (!coerceToInt(lval, &li) ||
2160  !coerceToInt(rval, &ri))
2161  return false;
2162 
2163  switch (func)
2164  {
2165  case PGBENCH_ADD:
2166  if (pg_add_s64_overflow(li, ri, &res))
2167  {
2168  pg_log_error("bigint add out of range");
2169  return false;
2170  }
2171  setIntValue(retval, res);
2172  return true;
2173 
2174  case PGBENCH_SUB:
2175  if (pg_sub_s64_overflow(li, ri, &res))
2176  {
2177  pg_log_error("bigint sub out of range");
2178  return false;
2179  }
2180  setIntValue(retval, res);
2181  return true;
2182 
2183  case PGBENCH_MUL:
2184  if (pg_mul_s64_overflow(li, ri, &res))
2185  {
2186  pg_log_error("bigint mul out of range");
2187  return false;
2188  }
2189  setIntValue(retval, res);
2190  return true;
2191 
2192  case PGBENCH_EQ:
2193  setBoolValue(retval, li == ri);
2194  return true;
2195 
2196  case PGBENCH_NE:
2197  setBoolValue(retval, li != ri);
2198  return true;
2199 
2200  case PGBENCH_LE:
2201  setBoolValue(retval, li <= ri);
2202  return true;
2203 
2204  case PGBENCH_LT:
2205  setBoolValue(retval, li < ri);
2206  return true;
2207 
2208  case PGBENCH_DIV:
2209  case PGBENCH_MOD:
2210  if (ri == 0)
2211  {
2212  pg_log_error("division by zero");
2213  return false;
2214  }
2215  /* special handling of -1 divisor */
2216  if (ri == -1)
2217  {
2218  if (func == PGBENCH_DIV)
2219  {
2220  /* overflow check (needed for INT64_MIN) */
2221  if (li == PG_INT64_MIN)
2222  {
2223  pg_log_error("bigint div out of range");
2224  return false;
2225  }
2226  else
2227  setIntValue(retval, -li);
2228  }
2229  else
2230  setIntValue(retval, 0);
2231  return true;
2232  }
2233  /* else divisor is not -1 */
2234  if (func == PGBENCH_DIV)
2235  setIntValue(retval, li / ri);
2236  else /* func == PGBENCH_MOD */
2237  setIntValue(retval, li % ri);
2238 
2239  return true;
2240 
2241  default:
2242  /* cannot get here */
2243  Assert(0);
2244  }
2245  }
2246 
2247  Assert(0);
2248  return false; /* NOTREACHED */
2249  }
2250 
2251  /* integer bitwise operators */
2252  case PGBENCH_BITAND:
2253  case PGBENCH_BITOR:
2254  case PGBENCH_BITXOR:
2255  case PGBENCH_LSHIFT:
2256  case PGBENCH_RSHIFT:
2257  {
2258  int64 li,
2259  ri;
2260 
2261  if (!coerceToInt(&vargs[0], &li) || !coerceToInt(&vargs[1], &ri))
2262  return false;
2263 
2264  if (func == PGBENCH_BITAND)
2265  setIntValue(retval, li & ri);
2266  else if (func == PGBENCH_BITOR)
2267  setIntValue(retval, li | ri);
2268  else if (func == PGBENCH_BITXOR)
2269  setIntValue(retval, li ^ ri);
2270  else if (func == PGBENCH_LSHIFT)
2271  setIntValue(retval, li << ri);
2272  else if (func == PGBENCH_RSHIFT)
2273  setIntValue(retval, li >> ri);
2274  else /* cannot get here */
2275  Assert(0);
2276 
2277  return true;
2278  }
2279 
2280  /* logical operators */
2281  case PGBENCH_NOT:
2282  {
2283  bool b;
2284 
2285  if (!coerceToBool(&vargs[0], &b))
2286  return false;
2287 
2288  setBoolValue(retval, !b);
2289  return true;
2290  }
2291 
2292  /* no arguments */
2293  case PGBENCH_PI:
2294  setDoubleValue(retval, M_PI);
2295  return true;
2296 
2297  /* 1 overloaded argument */
2298  case PGBENCH_ABS:
2299  {
2300  PgBenchValue *varg = &vargs[0];
2301 
2302  Assert(nargs == 1);
2303 
2304  if (varg->type == PGBT_INT)
2305  {
2306  int64 i = varg->u.ival;
2307 
2308  setIntValue(retval, i < 0 ? -i : i);
2309  }
2310  else
2311  {
2312  double d = varg->u.dval;
2313 
2314  Assert(varg->type == PGBT_DOUBLE);
2315  setDoubleValue(retval, d < 0.0 ? -d : d);
2316  }
2317 
2318  return true;
2319  }
2320 
2321  case PGBENCH_DEBUG:
2322  {
2323  PgBenchValue *varg = &vargs[0];
2324 
2325  Assert(nargs == 1);
2326 
2327  fprintf(stderr, "debug(script=%d,command=%d): ",
2328  st->use_file, st->command + 1);
2329 
2330  if (varg->type == PGBT_NULL)
2331  fprintf(stderr, "null\n");
2332  else if (varg->type == PGBT_BOOLEAN)
2333  fprintf(stderr, "boolean %s\n", varg->u.bval ? "true" : "false");
2334  else if (varg->type == PGBT_INT)
2335  fprintf(stderr, "int " INT64_FORMAT "\n", varg->u.ival);
2336  else if (varg->type == PGBT_DOUBLE)
2337  fprintf(stderr, "double %.*g\n", DBL_DIG, varg->u.dval);
2338  else /* internal error, unexpected type */
2339  Assert(0);
2340 
2341  *retval = *varg;
2342 
2343  return true;
2344  }
2345 
2346  /* 1 double argument */
2347  case PGBENCH_DOUBLE:
2348  case PGBENCH_SQRT:
2349  case PGBENCH_LN:
2350  case PGBENCH_EXP:
2351  {
2352  double dval;
2353 
2354  Assert(nargs == 1);
2355 
2356  if (!coerceToDouble(&vargs[0], &dval))
2357  return false;
2358 
2359  if (func == PGBENCH_SQRT)
2360  dval = sqrt(dval);
2361  else if (func == PGBENCH_LN)
2362  dval = log(dval);
2363  else if (func == PGBENCH_EXP)
2364  dval = exp(dval);
2365  /* else is cast: do nothing */
2366 
2367  setDoubleValue(retval, dval);
2368  return true;
2369  }
2370 
2371  /* 1 int argument */
2372  case PGBENCH_INT:
2373  {
2374  int64 ival;
2375 
2376  Assert(nargs == 1);
2377 
2378  if (!coerceToInt(&vargs[0], &ival))
2379  return false;
2380 
2381  setIntValue(retval, ival);
2382  return true;
2383  }
2384 
2385  /* variable number of arguments */
2386  case PGBENCH_LEAST:
2387  case PGBENCH_GREATEST:
2388  {
2389  bool havedouble;
2390  int i;
2391 
2392  Assert(nargs >= 1);
2393 
2394  /* need double result if any input is double */
2395  havedouble = false;
2396  for (i = 0; i < nargs; i++)
2397  {
2398  if (vargs[i].type == PGBT_DOUBLE)
2399  {
2400  havedouble = true;
2401  break;
2402  }
2403  }
2404  if (havedouble)
2405  {
2406  double extremum;
2407 
2408  if (!coerceToDouble(&vargs[0], &extremum))
2409  return false;
2410  for (i = 1; i < nargs; i++)
2411  {
2412  double dval;
2413 
2414  if (!coerceToDouble(&vargs[i], &dval))
2415  return false;
2416  if (func == PGBENCH_LEAST)
2417  extremum = Min(extremum, dval);
2418  else
2419  extremum = Max(extremum, dval);
2420  }
2421  setDoubleValue(retval, extremum);
2422  }
2423  else
2424  {
2425  int64 extremum;
2426 
2427  if (!coerceToInt(&vargs[0], &extremum))
2428  return false;
2429  for (i = 1; i < nargs; i++)
2430  {
2431  int64 ival;
2432 
2433  if (!coerceToInt(&vargs[i], &ival))
2434  return false;
2435  if (func == PGBENCH_LEAST)
2436  extremum = Min(extremum, ival);
2437  else
2438  extremum = Max(extremum, ival);
2439  }
2440  setIntValue(retval, extremum);
2441  }
2442  return true;
2443  }
2444 
2445  /* random functions */
2446  case PGBENCH_RANDOM:
2450  {
2451  int64 imin,
2452  imax;
2453 
2454  Assert(nargs >= 2);
2455 
2456  if (!coerceToInt(&vargs[0], &imin) ||
2457  !coerceToInt(&vargs[1], &imax))
2458  return false;
2459 
2460  /* check random range */
2461  if (imin > imax)
2462  {
2463  pg_log_error("empty range given to random");
2464  return false;
2465  }
2466  else if (imax - imin < 0 || (imax - imin) + 1 < 0)
2467  {
2468  /* prevent int overflows in random functions */
2469  pg_log_error("random range is too large");
2470  return false;
2471  }
2472 
2473  if (func == PGBENCH_RANDOM)
2474  {
2475  Assert(nargs == 2);
2476  setIntValue(retval, getrand(&st->cs_func_rs, imin, imax));
2477  }
2478  else /* gaussian & exponential */
2479  {
2480  double param;
2481 
2482  Assert(nargs == 3);
2483 
2484  if (!coerceToDouble(&vargs[2], &param))
2485  return false;
2486 
2487  if (func == PGBENCH_RANDOM_GAUSSIAN)
2488  {
2489  if (param < MIN_GAUSSIAN_PARAM)
2490  {
2491  pg_log_error("gaussian parameter must be at least %f (not %f)",
2492  MIN_GAUSSIAN_PARAM, param);
2493  return false;
2494  }
2495 
2496  setIntValue(retval,
2498  imin, imax, param));
2499  }
2500  else if (func == PGBENCH_RANDOM_ZIPFIAN)
2501  {
2502  if (param < MIN_ZIPFIAN_PARAM || param > MAX_ZIPFIAN_PARAM)
2503  {
2504  pg_log_error("zipfian parameter must be in range [%.3f, %.0f] (not %f)",
2505  MIN_ZIPFIAN_PARAM, MAX_ZIPFIAN_PARAM, param);
2506  return false;
2507  }
2508 
2509  setIntValue(retval,
2510  getZipfianRand(&st->cs_func_rs, imin, imax, param));
2511  }
2512  else /* exponential */
2513  {
2514  if (param <= 0.0)
2515  {
2516  pg_log_error("exponential parameter must be greater than zero (not %f)",
2517  param);
2518  return false;
2519  }
2520 
2521  setIntValue(retval,
2523  imin, imax, param));
2524  }
2525  }
2526 
2527  return true;
2528  }
2529 
2530  case PGBENCH_POW:
2531  {
2532  PgBenchValue *lval = &vargs[0];
2533  PgBenchValue *rval = &vargs[1];
2534  double ld,
2535  rd;
2536 
2537  Assert(nargs == 2);
2538 
2539  if (!coerceToDouble(lval, &ld) ||
2540  !coerceToDouble(rval, &rd))
2541  return false;
2542 
2543  setDoubleValue(retval, pow(ld, rd));
2544 
2545  return true;
2546  }
2547 
2548  case PGBENCH_IS:
2549  {
2550  Assert(nargs == 2);
2551 
2552  /*
2553  * note: this simple implementation is more permissive than
2554  * SQL
2555  */
2556  setBoolValue(retval,
2557  vargs[0].type == vargs[1].type &&
2558  vargs[0].u.bval == vargs[1].u.bval);
2559  return true;
2560  }
2561 
2562  /* hashing */
2563  case PGBENCH_HASH_FNV1A:
2564  case PGBENCH_HASH_MURMUR2:
2565  {
2566  int64 val,
2567  seed;
2568 
2569  Assert(nargs == 2);
2570 
2571  if (!coerceToInt(&vargs[0], &val) ||
2572  !coerceToInt(&vargs[1], &seed))
2573  return false;
2574 
2575  if (func == PGBENCH_HASH_MURMUR2)
2576  setIntValue(retval, getHashMurmur2(val, seed));
2577  else if (func == PGBENCH_HASH_FNV1A)
2578  setIntValue(retval, getHashFnv1a(val, seed));
2579  else
2580  /* cannot get here */
2581  Assert(0);
2582 
2583  return true;
2584  }
2585 
2586  case PGBENCH_PERMUTE:
2587  {
2588  int64 val,
2589  size,
2590  seed;
2591 
2592  Assert(nargs == 3);
2593 
2594  if (!coerceToInt(&vargs[0], &val) ||
2595  !coerceToInt(&vargs[1], &size) ||
2596  !coerceToInt(&vargs[2], &seed))
2597  return false;
2598 
2599  if (size <= 0)
2600  {
2601  pg_log_error("permute size parameter must be greater than zero");
2602  return false;
2603  }
2604 
2605  setIntValue(retval, permute(val, size, seed));
2606  return true;
2607  }
2608 
2609  default:
2610  /* cannot get here */
2611  Assert(0);
2612  /* dead code to avoid a compiler warning */
2613  return false;
2614  }
2615 }
static bool coerceToBool(PgBenchValue *pval, bool *bval)
Definition: pgbench.c:1809
static bool pg_sub_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:188
#define pg_log_error(...)
Definition: logging.h:80
static int64 getHashMurmur2(int64 val, uint64 seed)
Definition: pgbench.c:1112
static int64 getHashFnv1a(int64 val, uint64 seed)
Definition: pgbench.c:1087
#define Min(x, y)
Definition: c.h:986
static int64 getrand(RandomState *random_state, int64 min, int64 max)
Definition: pgbench.c:917
union PgBenchValue::@31 u
RandomState cs_func_rs
Definition: pgbench.c:456
static bool coerceToDouble(PgBenchValue *pval, double *dval)
Definition: pgbench.c:1878
static void setDoubleValue(PgBenchValue *pv, double dval)
Definition: pgbench.c:1923
#define fprintf
Definition: port.h:220
#define MIN_GAUSSIAN_PARAM
Definition: pgbench.c:176
static int64 getExponentialRand(RandomState *random_state, int64 min, int64 max, double parameter)
Definition: pgbench.c:937
#define MAX_FARGS
Definition: pgbench.c:2047
static bool evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
Definition: pgbench.c:2635
static void setBoolValue(PgBenchValue *pv, bool bval)
Definition: pgbench.c:1907
static int64 getZipfianRand(RandomState *random_state, int64 min, int64 max, double s)
Definition: pgbench.c:1073
#define M_PI
Definition: pgbench.c:73
static void setNullValue(PgBenchValue *pv)
Definition: pgbench.c:1899
static int64 permute(const int64 val, const int64 isize, const int64 seed)
Definition: pgbench.c:1145
#define PG_INT64_MIN
Definition: c.h:526
#define MAX_ZIPFIAN_PARAM
Definition: pgbench.c:179
int command
Definition: pgbench.c:459
#define MIN_ZIPFIAN_PARAM
Definition: pgbench.c:178
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:980
static bool pg_mul_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:215
#define Assert(condition)
Definition: c.h:804
static void setIntValue(PgBenchValue *pv, int64 ival)
Definition: pgbench.c:1915
#define INT64_FORMAT
Definition: c.h:483
static int64 getGaussianRand(RandomState *random_state, int64 min, int64 max, double parameter)
Definition: pgbench.c:961
bool bval
Definition: pgbench.h:51
PgBenchValueType type
Definition: pgbench.h:46
int i
static bool coerceToInt(PgBenchValue *pval, int64 *ival)
Definition: pgbench.c:1850
int64 ival
Definition: pgbench.h:49
int use_file
Definition: pgbench.c:458
long val
Definition: informix.c:664

◆ evaluateExpr()

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

Definition at line 2635 of file pgbench.c.

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

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

2636 {
2637  switch (expr->etype)
2638  {
2639  case ENODE_CONSTANT:
2640  {
2641  *retval = expr->u.constant;
2642  return true;
2643  }
2644 
2645  case ENODE_VARIABLE:
2646  {
2647  Variable *var;
2648 
2649  if ((var = lookupVariable(st, expr->u.variable.varname)) == NULL)
2650  {
2651  pg_log_error("undefined variable \"%s\"", expr->u.variable.varname);
2652  return false;
2653  }
2654 
2655  if (!makeVariableValue(var))
2656  return false;
2657 
2658  *retval = var->value;
2659  return true;
2660  }
2661 
2662  case ENODE_FUNCTION:
2663  return evalFunc(st,
2664  expr->u.function.function,
2665  expr->u.function.args,
2666  retval);
2667 
2668  default:
2669  /* internal error which should never occur */
2670  pg_log_fatal("unexpected enode type in evaluation: %d", expr->etype);
2671  exit(1);
2672  }
2673 }
PgBenchValue constant
Definition: pgbench.h:115
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:1420
#define pg_log_error(...)
Definition: logging.h:80
static bool evalFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2619
struct PgBenchExpr::@32::@33 variable
union PgBenchExpr::@32 u
static bool makeVariableValue(Variable *var)
Definition: pgbench.c:1480
PgBenchValue value
Definition: pgbench.c:303
PgBenchFunction function
Definition: pgbench.h:122
PgBenchExprType etype
Definition: pgbench.h:112
#define pg_log_fatal(...)
Definition: logging.h:76

◆ evaluateSleep()

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

Definition at line 3075 of file pgbench.c.

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

Referenced by executeMetaCommand().

3076 {
3077  char *var;
3078  int usec;
3079 
3080  if (*argv[1] == ':')
3081  {
3082  if ((var = getVariable(st, argv[1] + 1)) == NULL)
3083  {
3084  pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[1] + 1);
3085  return false;
3086  }
3087 
3088  usec = atoi(var);
3089 
3090  /* Raise an error if the value of a variable is not a number */
3091  if (usec == 0 && !isdigit((unsigned char) *var))
3092  {
3093  pg_log_error("%s: invalid sleep time \"%s\" for variable \"%s\"",
3094  argv[0], var, argv[1] + 1);
3095  return false;
3096  }
3097  }
3098  else
3099  usec = atoi(argv[1]);
3100 
3101  if (argc > 2)
3102  {
3103  if (pg_strcasecmp(argv[2], "ms") == 0)
3104  usec *= 1000;
3105  else if (pg_strcasecmp(argv[2], "s") == 0)
3106  usec *= 1000000;
3107  }
3108  else
3109  usec *= 1000000;
3110 
3111  *usecs = usec;
3112  return true;
3113 }
#define pg_log_error(...)
Definition: logging.h:80
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1447
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36

◆ executeMetaCommand()

static ConnectionStateEnum executeMetaCommand ( CState st,
pg_time_usec_t now 
)
static

Definition at line 3578 of file pgbench.c.

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

Referenced by advanceConnectionState().

3579 {
3580  Command *command = sql_script[st->use_file].commands[st->command];
3581  int argc;
3582  char **argv;
3583 
3584  Assert(command != NULL && command->type == META_COMMAND);
3585 
3586  argc = command->argc;
3587  argv = command->argv;
3588 
3590  {
3592 
3593  initPQExpBuffer(&buf);
3594 
3595  printfPQExpBuffer(&buf, "client %d executing \\%s", st->id, argv[0]);
3596  for (int i = 1; i < argc; i++)
3597  appendPQExpBuffer(&buf, " %s", argv[i]);
3598 
3599  pg_log_debug("%s", buf.data);
3600 
3601  termPQExpBuffer(&buf);
3602  }
3603 
3604  if (command->meta == META_SLEEP)
3605  {
3606  int usec;
3607 
3608  /*
3609  * A \sleep doesn't execute anything, we just get the delay from the
3610  * argument, and enter the CSTATE_SLEEP state. (The per-command
3611  * latency will be recorded in CSTATE_SLEEP state, not here, after the
3612  * delay has elapsed.)
3613  */
3614  if (!evaluateSleep(st, argc, argv, &usec))
3615  {
3616  commandFailed(st, "sleep", "execution of meta-command failed");
3617  return CSTATE_ABORTED;
3618  }
3619 
3621  st->sleep_until = (*now) + usec;
3622  return CSTATE_SLEEP;
3623  }
3624  else if (command->meta == META_SET)
3625  {
3626  PgBenchExpr *expr = command->expr;
3627  PgBenchValue result;
3628 
3629  if (!evaluateExpr(st, expr, &result))
3630  {
3631  commandFailed(st, argv[0], "evaluation of meta-command failed");
3632  return CSTATE_ABORTED;
3633  }
3634 
3635  if (!putVariableValue(st, argv[0], argv[1], &result))
3636  {
3637  commandFailed(st, "set", "assignment of meta-command failed");
3638  return CSTATE_ABORTED;
3639  }
3640  }
3641  else if (command->meta == META_IF)
3642  {
3643  /* backslash commands with an expression to evaluate */
3644  PgBenchExpr *expr = command->expr;
3645  PgBenchValue result;
3646  bool cond;
3647 
3648  if (!evaluateExpr(st, expr, &result))
3649  {
3650  commandFailed(st, argv[0], "evaluation of meta-command failed");
3651  return CSTATE_ABORTED;
3652  }
3653 
3654  cond = valueTruth(&result);
3656  }
3657  else if (command->meta == META_ELIF)
3658  {
3659  /* backslash commands with an expression to evaluate */
3660  PgBenchExpr *expr = command->expr;
3661  PgBenchValue result;
3662  bool cond;
3663 
3665  {
3666  /* elif after executed block, skip eval and wait for endif. */
3668  return CSTATE_END_COMMAND;
3669  }
3670 
3671  if (!evaluateExpr(st, expr, &result))
3672  {
3673  commandFailed(st, argv[0], "evaluation of meta-command failed");
3674  return CSTATE_ABORTED;
3675  }
3676 
3677  cond = valueTruth(&result);
3680  }
3681  else if (command->meta == META_ELSE)
3682  {
3683  switch (conditional_stack_peek(st->cstack))
3684  {
3685  case IFSTATE_TRUE:
3687  break;
3688  case IFSTATE_FALSE: /* inconsistent if active */
3689  case IFSTATE_IGNORED: /* inconsistent if active */
3690  case IFSTATE_NONE: /* else without if */
3691  case IFSTATE_ELSE_TRUE: /* else after else */
3692  case IFSTATE_ELSE_FALSE: /* else after else */
3693  default:
3694  /* dead code if conditional check is ok */
3695  Assert(false);
3696  }
3697  }
3698  else if (command->meta == META_ENDIF)
3699  {
3702  }
3703  else if (command->meta == META_SETSHELL)
3704  {
3705  if (!runShellCommand(st, argv[1], argv + 2, argc - 2))
3706  {
3707  commandFailed(st, "setshell", "execution of meta-command failed");
3708  return CSTATE_ABORTED;
3709  }
3710  }
3711  else if (command->meta == META_SHELL)
3712  {
3713  if (!runShellCommand(st, NULL, argv + 1, argc - 1))
3714  {
3715  commandFailed(st, "shell", "execution of meta-command failed");
3716  return CSTATE_ABORTED;
3717  }
3718  }
3719  else if (command->meta == META_STARTPIPELINE)
3720  {
3721  /*
3722  * In pipeline mode, we use a workflow based on libpq pipeline
3723  * functions.
3724  */
3725  if (querymode == QUERY_SIMPLE)
3726  {
3727  commandFailed(st, "startpipeline", "cannot use pipeline mode with the simple query protocol");
3728  return CSTATE_ABORTED;
3729  }
3730 
3731  if (PQpipelineStatus(st->con) != PQ_PIPELINE_OFF)
3732  {
3733  commandFailed(st, "startpipeline", "already in pipeline mode");
3734  return CSTATE_ABORTED;
3735  }
3736  if (PQenterPipelineMode(st->con) == 0)
3737  {
3738  commandFailed(st, "startpipeline", "failed to enter pipeline mode");
3739  return CSTATE_ABORTED;
3740  }
3741  }
3742  else if (command->meta == META_ENDPIPELINE)
3743  {
3744  if (PQpipelineStatus(st->con) != PQ_PIPELINE_ON)
3745  {
3746  commandFailed(st, "endpipeline", "not in pipeline mode");
3747  return CSTATE_ABORTED;
3748  }
3749  if (!PQpipelineSync(st->con))
3750  {
3751  commandFailed(st, "endpipeline", "failed to send a pipeline sync");
3752  return CSTATE_ABORTED;
3753  }
3754  /* Now wait for the PGRES_PIPELINE_SYNC and exit pipeline mode there */
3755  /* collect pending results before getting out of pipeline mode */
3756  return CSTATE_WAIT_RESULT;
3757  }
3758 
3759  /*
3760  * executing the expression or shell command might have taken a
3761  * non-negligible amount of time, so reset 'now'
3762  */
3763  *now = 0;
3764 
3765  return CSTATE_END_COMMAND;
3766 }
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
int type
Definition: pgbench.c:575
int id
Definition: pgbench.c:448
int PQenterPipelineMode(PGconn *conn)
Definition: fe-exec.c:2844
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:57
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
void conditional_stack_push(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:41
static void commandFailed(CState *st, const char *cmd, const char *message)
Definition: pgbench.c:2827
PgBenchExpr * expr
Definition: pgbench.c:580
char * argv[MAX_ARGS]
Definition: pgbench.c:578
ConditionalStack cstack
Definition: pgbench.c:450
static bool evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
Definition: pgbench.c:2635
#define META_COMMAND
Definition: pgbench.c:515
#define pg_log_debug(...)
Definition: logging.h:92
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
static char * buf
Definition: pg_test_fsync.c:68
MetaCommand meta
Definition: pgbench.c:576
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:592
int PQpipelineSync(PGconn *conn)
Definition: fe-exec.c:3027
enum pg_log_level __pg_log_level
Definition: logging.c:21
int argc
Definition: pgbench.c:577
static void pg_time_now_lazy(pg_time_usec_t *now)
Definition: pgbench.c:683
int command
Definition: pgbench.c:459
static bool runShellCommand(CState *st, char *variable, char **argv, int argc)
Definition: pgbench.c:2719
ifState conditional_stack_peek(ConditionalStack cstack)
Definition: conditional.c:94
static bool evaluateSleep(CState *st, int argc, char **argv, int *usecs)
Definition: pgbench.c:3075
PGconn * con
Definition: pgbench.c:447
#define Assert(condition)
Definition: c.h:804
PGpipelineStatus PQpipelineStatus(const PGconn *conn)
Definition: fe-connect.c:6761
static bool valueTruth(PgBenchValue *pval)
Definition: pgbench.c:1829
bool conditional_stack_poke(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:106
Command ** commands
Definition: pgbench.c:588
static QueryMode querymode
Definition: pgbench.c:548
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:1658
#define unlikely(x)
Definition: c.h:273
pg_time_usec_t sleep_until
Definition: pgbench.c:468
int use_file
Definition: pgbench.c:458
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1544
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ executeStatement()

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

Definition at line 1316 of file pgbench.c.

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

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

1317 {
1318  PGresult *res;
1319 
1320  res = PQexec(con, sql);
1321  if (PQresultStatus(res) != PGRES_COMMAND_OK)
1322  {
1323  pg_log_fatal("query failed: %s", PQerrorMessage(con));
1324  pg_log_info("query was: %s", sql);
1325  exit(1);
1326  }
1327  PQclear(res);
1328 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6727
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:3097
void PQclear(PGresult *res)
Definition: fe-exec.c:680
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2142
#define pg_log_info(...)
Definition: logging.h:88
#define pg_log_fatal(...)
Definition: logging.h:76

◆ findBuiltin()

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

Definition at line 5300 of file pgbench.c.

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

Referenced by main().

5301 {
5302  int i,
5303  found = 0,
5304  len = strlen(name);
5305  const BuiltinScript *result = NULL;
5306 
5307  for (i = 0; i < lengthof(builtin_script); i++)
5308  {
5309  if (strncmp(builtin_script[i].name, name, len) == 0)
5310  {
5311  result = &builtin_script[i];
5312  found++;
5313  }
5314  }
5315 
5316  /* ok, unambiguous result */
5317  if (found == 1)
5318  return result;
5319 
5320  /* error cases */
5321  if (found == 0)
5322  pg_log_fatal("no builtin script found for name \"%s\"", name);
5323  else /* found > 1 */
5324  pg_log_fatal("ambiguous builtin name: %d builtin scripts found for prefix \"%s\"", found, name);
5325 
5327  exit(1);
5328 }
static void listAvailableScripts(void)
Definition: pgbench.c:5288
#define lengthof(array)
Definition: c.h:734
static const BuiltinScript builtin_script[]
Definition: pgbench.c:604
const char * name
Definition: encode.c:515
int i
#define pg_log_fatal(...)
Definition: logging.h:76

◆ finishCon()

static void finishCon ( CState st)
static

Definition at line 6807 of file pgbench.c.

References CState::con, and PQfinish().

Referenced by advanceConnectionState(), and disconnect_all().

6808 {
6809  if (st->con != NULL)
6810  {
6811  PQfinish(st->con);
6812  st->con = NULL;
6813  }
6814 }
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4221
PGconn * con
Definition: pgbench.c:447

◆ free_command()

static void free_command ( Command command)
static

Definition at line 4753 of file pgbench.c.

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

Referenced by ParseScript().

4754 {
4755  termPQExpBuffer(&command->lines);
4756  if (command->first_line)
4757  pg_free(command->first_line);
4758  for (int i = 0; i < command->argc; i++)
4759  pg_free(command->argv[i]);
4760  if (command->varprefix)
4761  pg_free(command->varprefix);
4762 
4763  /*
4764  * It should also free expr recursively, but this is currently not needed
4765  * as only gset commands (which do not have an expression) are freed.
4766  */
4767  pg_free(command);
4768 }
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
char * argv[MAX_ARGS]
Definition: pgbench.c:578
PQExpBufferData lines
Definition: pgbench.c:573
int argc
Definition: pgbench.c:577
char * varprefix
Definition: pgbench.c:579
void pg_free(void *ptr)
Definition: fe_memutils.c:105
int i
char * first_line
Definition: pgbench.c:574

◆ free_socket_set()

static void free_socket_set ( socket_set sa)
static

Definition at line 6981 of file pgbench.c.

References pg_free().

Referenced by setalarm(), and threadRun().

6982 {
6983  pg_free(sa);
6984 }
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 937 of file pgbench.c.

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

Referenced by evalStandardFunc().

939 {
940  double cut,
941  uniform,
942  rand;
943 
944  /* abort if wrong parameter, but must really be checked beforehand */
945  Assert(parameter > 0.0);
946  cut = exp(-parameter);
947  /* erand in [0, 1), uniform in (0, 1] */
948  uniform = 1.0 - pg_erand48(random_state->xseed);
949 
950  /*
951  * inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
952  */
953  Assert((1.0 - cut) != 0.0);
954  rand = -log(cut + (1.0 - cut) * uniform) / parameter;
955  /* return int64 random number within between min and max */
956  return min + (int64) ((max - min + 1) * rand);
957 }
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
#define Assert(condition)
Definition: c.h:804
unsigned short xseed[3]
Definition: pgbench.c:350

◆ getGaussianRand()

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

Definition at line 961 of file pgbench.c.

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

Referenced by evalStandardFunc().

963 {
964  double stdev;
965  double rand;
966 
967  /* abort if parameter is too low, but must really be checked beforehand */
968  Assert(parameter >= MIN_GAUSSIAN_PARAM);
969 
970  /*
971  * Get user specified random number from this loop, with -parameter <
972  * stdev <= parameter
973  *
974  * This loop is executed until the number is in the expected range.
975  *
976  * As the minimum parameter is 2.0, the probability of looping is low:
977  * sqrt(-2 ln(r)) <= 2 => r >= e^{-2} ~ 0.135, then when taking the
978  * average sinus multiplier as 2/pi, we have a 8.6% looping probability in
979  * the worst case. For a parameter value of 5.0, the looping probability
980  * is about e^{-5} * 2 / pi ~ 0.43%.
981  */
982  do
983  {
984  /*
985  * pg_erand48 generates [0,1), but for the basic version of the
986  * Box-Muller transform the two uniformly distributed random numbers
987  * are expected in (0, 1] (see
988  * https://en.wikipedia.org/wiki/Box-Muller_transform)
989  */
990  double rand1 = 1.0 - pg_erand48(random_state->xseed);
991  double rand2 = 1.0 - pg_erand48(random_state->xseed);
992 
993  /* Box-Muller basic form transform */
994  double var_sqrt = sqrt(-2.0 * log(rand1));
995 
996  stdev = var_sqrt * sin(2.0 * M_PI * rand2);
997 
998  /*
999  * we may try with cos, but there may be a bias induced if the
1000  * previous value fails the test. To be on the safe side, let us try
1001  * over.
1002  */
1003  }
1004  while (stdev < -parameter || stdev >= parameter);
1005 
1006  /* stdev is in [-parameter, parameter), normalization to [0,1) */
1007  rand = (stdev + parameter) / (parameter * 2.0);
1008 
1009  /* return int64 random number within between min and max */
1010  return min + (int64) ((max - min + 1) * rand);
1011 }
#define MIN_GAUSSIAN_PARAM
Definition: pgbench.c:176
#define M_PI
Definition: pgbench.c:73
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
#define Assert(condition)
Definition: c.h:804
unsigned short xseed[3]
Definition: pgbench.c:350

◆ getHashFnv1a()

static int64 getHashFnv1a ( int64  val,
uint64  seed 
)
static

Definition at line 1087 of file pgbench.c.

References FNV_OFFSET_BASIS, FNV_PRIME, and i.

Referenced by evalStandardFunc().

1088 {
1089  int64 result;
1090  int i;
1091 
1092  result = FNV_OFFSET_BASIS ^ seed;
1093  for (i = 0; i < 8; ++i)
1094  {
1095  int32 octet = val & 0xff;
1096 
1097  val = val >> 8;
1098  result = result ^ octet;
1099  result = result * FNV_PRIME;
1100  }
1101 
1102  return result;
1103 }
#define FNV_PRIME
Definition: pgbench.c:81
#define FNV_OFFSET_BASIS
Definition: pgbench.c:82
signed int int32
Definition: c.h:429
int i
long val
Definition: informix.c:664

◆ getHashMurmur2()

static int64 getHashMurmur2 ( int64  val,
uint64  seed 
)
static

Definition at line 1112 of file pgbench.c.

References MM2_MUL, MM2_MUL_TIMES_8, and MM2_ROT.

Referenced by evalStandardFunc().

1113 {
1114  uint64 result = seed ^ MM2_MUL_TIMES_8; /* sizeof(int64) */
1115  uint64 k = (uint64) val;
1116 
1117  k *= MM2_MUL;
1118  k ^= k >> MM2_ROT;
1119  k *= MM2_MUL;
1120 
1121  result ^= k;
1122  result *= MM2_MUL;
1123 
1124  result ^= result >> MM2_ROT;
1125  result *= MM2_MUL;
1126  result ^= result >> MM2_ROT;
1127 
1128  return (int64) result;
1129 }
#define MM2_MUL_TIMES_8
Definition: pgbench.c:84
#define MM2_ROT
Definition: pgbench.c:85
long val
Definition: informix.c:664
#define MM2_MUL
Definition: pgbench.c:83

◆ getMetaCommand()

static MetaCommand getMetaCommand ( const char *  cmd)
static

Definition at line 2679 of file pgbench.c.

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

Referenced by process_backslash_command().

2680 {
2681  MetaCommand mc;
2682 
2683  if (cmd == NULL)
2684  mc = META_NONE;
2685  else if (pg_strcasecmp(cmd, "set") == 0)
2686  mc = META_SET;
2687  else if (pg_strcasecmp(cmd, "setshell") == 0)
2688  mc = META_SETSHELL;
2689  else if (pg_strcasecmp(cmd, "shell") == 0)
2690  mc = META_SHELL;
2691  else if (pg_strcasecmp(cmd, "sleep") == 0)
2692  mc = META_SLEEP;
2693  else if (pg_strcasecmp(cmd, "if") == 0)
2694  mc = META_IF;
2695  else if (pg_strcasecmp(cmd, "elif") == 0)
2696  mc = META_ELIF;
2697  else if (pg_strcasecmp(cmd, "else") == 0)
2698  mc = META_ELSE;
2699  else if (pg_strcasecmp(cmd, "endif") == 0)
2700  mc = META_ENDIF;
2701  else if (pg_strcasecmp(cmd, "gset") == 0)
2702  mc = META_GSET;
2703  else if (pg_strcasecmp(cmd, "aset") == 0)
2704  mc = META_ASET;
2705  else if (pg_strcasecmp(cmd, "startpipeline") == 0)
2706  mc = META_STARTPIPELINE;
2707  else if (pg_strcasecmp(cmd, "endpipeline") == 0)
2708  mc = META_ENDPIPELINE;
2709  else
2710  mc = META_NONE;
2711  return mc;
2712 }
MetaCommand
Definition: pgbench.c:523
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 1021 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by advanceConnectionState().

1022 {
1023  /*
1024  * Use inverse transform sampling to generate a value > 0, such that the
1025  * expected (i.e. average) value is the given argument.
1026  */
1027  double uniform;
1028 
1029  /* erand in [0, 1), uniform in (0, 1] */
1030  uniform = 1.0 - pg_erand48(random_state->xseed);
1031 
1032  return (int64) (-log(uniform) * center + 0.5);
1033 }
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
unsigned short xseed[3]
Definition: pgbench.c:350

◆ getQueryParams()

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

Definition at line 1778 of file pgbench.c.

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

Referenced by sendCommand().

1779 {
1780  int i;
1781 
1782  for (i = 0; i < command->argc - 1; i++)
1783  params[i] = getVariable(st, command->argv[i + 1]);
1784 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1447
char * argv[MAX_ARGS]
Definition: pgbench.c:578
int argc
Definition: pgbench.c:577
int i

◆ getrand()

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

Definition at line 917 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by chooseScript(), evalStandardFunc(), and permute().

918 {
919  /*
920  * Odd coding is so that min and max have approximately the same chance of
921  * being selected as do numbers between them.
922  *
923  * pg_erand48() is thread-safe and concurrent, which is why we use it
924  * rather than random(), which in glibc is non-reentrant, and therefore
925  * protected by a mutex, and therefore a bottleneck on machines with many
926  * CPUs.
927  */
928  return min + (int64) ((max - min + 1) * pg_erand48(random_state->xseed));
929 }
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
unsigned short xseed[3]
Definition: pgbench.c:350

◆ GetTableInfo()

static void GetTableInfo ( PGconn con,
bool  scale_given 
)
static

Definition at line 4482 of file pgbench.c.

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

Referenced by main().

4483 {
4484  PGresult *res;
4485 
4486  /*
4487  * get the scaling factor that should be same as count(*) from
4488  * pgbench_branches if this is not a custom query
4489  */
4490  res = PQexec(con, "select count(*) from pgbench_branches");
4491  if (PQresultStatus(res) != PGRES_TUPLES_OK)
4492  {
4493  char *sqlState = PQresultErrorField(res, PG_DIAG_SQLSTATE);
4494 
4495  pg_log_fatal("could not count number of branches: %s", PQerrorMessage(con));
4496 
4497  if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) == 0)
4498  pg_log_info("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\"",
4499  PQdb(con));
4500 
4501  exit(1);
4502  }
4503  scale = atoi(PQgetvalue(res, 0, 0));
4504  if (scale < 0)
4505  {
4506  pg_log_fatal("invalid count(*) from pgbench_branches: \"%s\"",
4507  PQgetvalue(res, 0, 0));
4508  exit(1);
4509  }
4510  PQclear(res);
4511 
4512  /* warn if we override user-given -s switch */
4513  if (scale_given)
4514  pg_log_warning("scale option ignored, using count from pgbench_branches table (%d)",
4515  scale);
4516 
4517  /*
4518  * Get the partition information for the first "pgbench_accounts" table
4519  * found in search_path.
4520  *
4521  * The result is empty if no "pgbench_accounts" is found.
4522  *
4523  * Otherwise, it always returns one row even if the table is not
4524  * partitioned (in which case the partition strategy is NULL).
4525  *
4526  * The number of partitions can be 0 even for partitioned tables, if no
4527  * partition is attached.
4528  *
4529  * We assume no partitioning on any failure, so as to avoid failing on an
4530  * old version without "pg_partitioned_table".
4531  */
4532  res = PQexec(con,
4533  "select o.n, p.partstrat, pg_catalog.count(i.inhparent) "
4534  "from pg_catalog.pg_class as c "
4535  "join pg_catalog.pg_namespace as n on (n.oid = c.relnamespace) "
4536  "cross join lateral (select pg_catalog.array_position(pg_catalog.current_schemas(true), n.nspname)) as o(n) "
4537  "left join pg_catalog.pg_partitioned_table as p on (p.partrelid = c.oid) "
4538  "left join pg_catalog.pg_inherits as i on (c.oid = i.inhparent) "
4539  "where c.relname = 'pgbench_accounts' and o.n is not null "
4540  "group by 1, 2 "
4541  "order by 1 asc "
4542  "limit 1");
4543 
4544  if (PQresultStatus(res) != PGRES_TUPLES_OK)
4545  {
4546  /* probably an older version, coldly assume no partitioning */
4548  partitions = 0;
4549  }
4550  else if (PQntuples(res) == 0)
4551  {
4552  /*
4553  * This case is unlikely as pgbench already found "pgbench_branches"
4554  * above to compute the scale.
4555  */
4556  pg_log_fatal("no pgbench_accounts table found in search_path");
4557  pg_log_info("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".", PQdb(con));
4558  exit(1);
4559  }
4560  else /* PQntupes(res) == 1 */
4561  {
4562  /* normal case, extract partition information */
4563  if (PQgetisnull(res, 0, 1))
4565  else
4566  {
4567  char *ps = PQgetvalue(res, 0, 1);
4568 
4569  /* column must be there */
4570  Assert(ps != NULL);
4571 
4572  if (strcmp(ps, "r") == 0)
4574  else if (strcmp(ps, "h") == 0)
4576  else
4577  {
4578  /* possibly a newer version with new partition method */
4579  pg_log_fatal("unexpected partition method: \"%s\"", ps);
4580  exit(1);
4581  }
4582  }
4583 
4584  partitions = atoi(PQgetvalue(res, 0, 2));
4585  }
4586 
4587  PQclear(res);
4588 }
static int partitions
Definition: pgbench.c:231
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6727
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:76
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3561
static partition_method_t partition_method
Definition: pgbench.c:241
int scale
Definition: pgbench.c:189
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3167
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:57
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:3097
void PQclear(PGresult *res)
Definition: fe-exec.c:680
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:6573
char * PQresultErrorField(const PGresult *res, int fieldcode)
Definition: fe-exec.c:3152
#define Assert(condition)
Definition: c.h:804
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2142
#define pg_log_warning(...)
Definition: pgfnames.c:24
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3586
#define pg_log_info(...)
Definition: logging.h:88
#define pg_log_fatal(...)
Definition: logging.h:76

◆ getVariable()

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

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

1448 {
1449  Variable *var;
1450  char stringform[64];
1451 
1452  var = lookupVariable(st, name);
1453  if (var == NULL)
1454  return NULL; /* not found */
1455 
1456  if (var->svalue)
1457  return var->svalue; /* we have it in string form */
1458 
1459  /* We need to produce a string equivalent of the value */
1460  Assert(var->value.type != PGBT_NO_VALUE);
1461  if (var->value.type == PGBT_NULL)
1462  snprintf(stringform, sizeof(stringform), "NULL");
1463  else if (var->value.type == PGBT_BOOLEAN)
1464  snprintf(stringform, sizeof(stringform),
1465  "%s", var->value.u.bval ? "true" : "false");
1466  else if (var->value.type == PGBT_INT)
1467  snprintf(stringform, sizeof(stringform),
1468  INT64_FORMAT, var->value.u.ival);
1469  else if (var->value.type == PGBT_DOUBLE)
1470  snprintf(stringform, sizeof(stringform),
1471  "%.*g", DBL_DIG, var->value.u.dval);
1472  else /* internal error, unexpected type */
1473  Assert(0);
1474  var->svalue = pg_strdup(stringform);
1475  return var->svalue;
1476 }
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:1420
union PgBenchValue::@31 u
char * svalue
Definition: pgbench.c:302
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
PgBenchValue value
Definition: pgbench.c:303
double dval
Definition: pgbench.h:50
#define Assert(condition)
Definition: c.h:804
#define INT64_FORMAT
Definition: c.h:483
const char * name
Definition: encode.c:515
bool bval
Definition: pgbench.h:51
PgBenchValueType type
Definition: pgbench.h:46
int64 ival
Definition: pgbench.h:49
#define snprintf
Definition: port.h:216

◆ getZipfianRand()

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

Definition at line 1073 of file pgbench.c.

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

Referenced by evalStandardFunc().

1074 {
1075  int64 n = max - min + 1;
1076 
1077  /* abort if parameter is invalid */
1079 
1080  return min - 1 + computeIterativeZipfian(random_state, n, s);
1081 }
#define MAX_ZIPFIAN_PARAM
Definition: pgbench.c:179
#define MIN_ZIPFIAN_PARAM
Definition: pgbench.c:178
#define Assert(condition)
Definition: c.h:804
static int64 computeIterativeZipfian(RandomState *random_state, int64 n, double s)
Definition: pgbench.c:1043

◆ handle_sig_alarm()

static void handle_sig_alarm ( SIGNAL_ARGS  )
static

Definition at line 6823 of file pgbench.c.

References timer_exceeded.

Referenced by setalarm().

6824 {
6825  timer_exceeded = true;
6826 }
volatile bool timer_exceeded
Definition: pgbench.c:287

◆ initCreateFKeys()

static void initCreateFKeys ( PGconn con)
static

Definition at line 4348 of file pgbench.c.

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

Referenced by runInitSteps().

4349 {
4350  static const char *const DDLKEYs[] = {
4351  "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
4352  "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
4353  "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
4354  "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
4355  "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
4356  };
4357  int i;
4358 
4359  fprintf(stderr, "creating foreign keys...\n");
4360  for (i = 0; i < lengthof(DDLKEYs); i++)
4361  {
4362  executeStatement(con, DDLKEYs[i]);
4363  }
4364 }
#define lengthof(array)
Definition: c.h:734
#define fprintf
Definition: port.h:220
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1316
int i

◆ initCreatePKeys()

static void initCreatePKeys ( PGconn con)
static

Definition at line 4310 of file pgbench.c.

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

Referenced by runInitSteps().

4311 {
4312  static const char *const DDLINDEXes[] = {
4313  "alter table pgbench_branches add primary key (bid)",
4314  "alter table pgbench_tellers add primary key (tid)",
4315  "alter table pgbench_accounts add primary key (aid)"
4316  };
4317  int i;
4318  PQExpBufferData query;
4319 
4320  fprintf(stderr, "creating primary keys...\n");
4321  initPQExpBuffer(&query);
4322 
4323  for (i = 0; i < lengthof(DDLINDEXes); i++)
4324  {
4325  resetPQExpBuffer(&query);
4326  appendPQExpBufferStr(&query, DDLINDEXes[i]);
4327 
4328  if (index_tablespace != NULL)
4329  {
4330  char *escape_tablespace;
4331 
4332  escape_tablespace = PQescapeIdentifier(con, index_tablespace,
4333  strlen(index_tablespace));
4334  appendPQExpBuffer(&query, " using index tablespace %s", escape_tablespace);
4335  PQfreemem(escape_tablespace);
4336  }
4337 
4338  executeStatement(con, query.data);
4339  }
4340 
4341  termPQExpBuffer(&query);
4342 }
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
#define lengthof(array)
Definition: c.h:734
#define fprintf
Definition: port.h:220
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1316
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:3994
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
char * index_tablespace
Definition: pgbench.c:225
int i
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:148
void PQfreemem(void *ptr)
Definition: fe-exec.c:3715
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ initCreateTables()

static void initCreateTables ( PGconn con)
static

Definition at line 4005 of file pgbench.c.

References appendPQExpBuffer(), createPartitions(), PQExpBufferData::data, executeStatement(), fillfactor, fprintf, i, initPQExpBuffer(), lengthof, PART_NONE, partition_method, PARTITION_METHOD, PQescapeIdentifier(), PQfreemem(), printfPQExpBuffer(), scale, SCALE_32BIT_THRESHOLD, tablespace, termPQExpBuffer(), and unlogged_tables.

Referenced by runInitSteps().

4006 {
4007  /*
4008  * Note: TPC-B requires at least 100 bytes per row, and the "filler"
4009  * fields in these table declarations were intended to comply with that.
4010  * The pgbench_accounts table complies with that because the "filler"
4011  * column is set to blank-padded empty string. But for all other tables
4012  * the columns default to NULL and so don't actually take any space. We
4013  * could fix that by giving them non-null default values. However, that
4014  * would completely break comparability of pgbench results with prior
4015  * versions. Since pgbench has never pretended to be fully TPC-B compliant
4016  * anyway, we stick with the historical behavior.
4017  */
4018  struct ddlinfo
4019  {
4020  const char *table; /* table name */
4021  const char *smcols; /* column decls if accountIDs are 32 bits */
4022  const char *bigcols; /* column decls if accountIDs are 64 bits */
4023  int declare_fillfactor;
4024  };
4025  static const struct ddlinfo DDLs[] = {
4026  {
4027  "pgbench_history",
4028  "tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)",
4029  "tid int,bid int,aid bigint,delta int,mtime timestamp,filler char(22)",
4030  0
4031  },
4032  {
4033  "pgbench_tellers",
4034  "tid int not null,bid int,tbalance int,filler char(84)",
4035  "tid int not null,bid int,tbalance int,filler char(84)",
4036  1
4037  },
4038  {
4039  "pgbench_accounts",
4040  "aid int not null,bid int,abalance int,filler char(84)",
4041  "aid bigint not null,bid int,abalance int,filler char(84)",
4042  1
4043  },
4044  {
4045  "pgbench_branches",
4046  "bid int not null,bbalance int,filler char(88)",
4047  "bid int not null,bbalance int,filler char(88)",
4048  1
4049  }
4050  };
4051  int i;
4052  PQExpBufferData query;
4053 
4054  fprintf(stderr, "creating tables...\n");
4055 
4056  initPQExpBuffer(&query);
4057 
4058  for (i = 0; i < lengthof(DDLs); i++)
4059  {
4060  const struct ddlinfo *ddl = &DDLs[i];
4061 
4062  /* Construct new create table statement. */
4063  printfPQExpBuffer(&query, "create%s table %s(%s)",
4064  unlogged_tables ? " unlogged" : "",
4065  ddl->table,
4066  (scale >= SCALE_32BIT_THRESHOLD) ? ddl->bigcols : ddl->smcols);
4067 
4068  /* Partition pgbench_accounts table */
4069  if (partition_method != PART_NONE && strcmp(ddl->table, "pgbench_accounts") == 0)
4070  appendPQExpBuffer(&query,
4071  " partition by %s (aid)", PARTITION_METHOD[partition_method]);
4072  else if (ddl->declare_fillfactor)
4073  {
4074  /* fillfactor is only expected on actual tables */
4075  appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4076  }
4077 
4078  if (tablespace != NULL)
4079  {
4080  char *escape_tablespace;
4081 
4082  escape_tablespace = PQescapeIdentifier(con, tablespace, strlen(tablespace));
4083  appendPQExpBuffer(&query, " tablespace %s", escape_tablespace);
4084  PQfreemem(escape_tablespace);
4085  }
4086 
4087  executeStatement(con, query.data);
4088  }
4089 
4090  termPQExpBuffer(&query);
4091 
4092  if (partition_method != PART_NONE)
4093  createPartitions(con);
4094 }
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
static partition_method_t partition_method
Definition: pgbench.c:241
int scale
Definition: pgbench.c:189
#define lengthof(array)
Definition: c.h:734
#define fprintf
Definition: port.h:220
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1316
#define SCALE_32BIT_THRESHOLD
Definition: pgbench.c:263
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:3994
int fillfactor
Definition: pgbench.c:195
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
char * tablespace
Definition: pgbench.c:224
static const char * PARTITION_METHOD[]
Definition: pgbench.c:242
bool unlogged_tables
Definition: pgbench.c:200
int i
static void createPartitions(PGconn *con)
Definition: pgbench.c:3936
void PQfreemem(void *ptr)
Definition: fe-exec.c:3715
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ initDropTables()

static void initDropTables ( PGconn con)
static

Definition at line 3914 of file pgbench.c.

References executeStatement(), and fprintf.

Referenced by runInitSteps().

3915 {
3916  fprintf(stderr, "dropping old tables...\n");
3917 
3918  /*
3919  * We drop all the tables in one command, so that whether there are
3920  * foreign key dependencies or not doesn't matter.
3921  */
3922  executeStatement(con, "drop table if exists "
3923  "pgbench_accounts, "
3924  "pgbench_branches, "
3925  "pgbench_history, "
3926  "pgbench_tellers");
3927 }
#define fprintf
Definition: port.h:220
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1316

◆ initGenerateDataClientSide()

static void initGenerateDataClientSide ( PGconn con)
static

Definition at line 4113 of file pgbench.c.

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

Referenced by runInitSteps().

4114 {
4115  PQExpBufferData sql;
4116  PGresult *res;
4117  int i;
4118  int64 k;
4119 
4120  /* used to track elapsed time and estimate of the remaining time */
4121  pg_time_usec_t start;
4122  int log_interval = 1;
4123 
4124  /* Stay on the same line if reporting to a terminal */
4125  char eol = isatty(fileno(stderr)) ? '\r' : '\n';
4126 
4127  fprintf(stderr, "generating data (client-side)...\n");
4128 
4129  /*
4130  * we do all of this in one transaction to enable the backend's
4131  * data-loading optimizations
4132  */
4133  executeStatement(con, "begin");
4134 
4135  /* truncate away any old data */
4136  initTruncateTables(con);
4137 
4138  initPQExpBuffer(&sql);
4139 
4140  /*
4141  * fill branches, tellers, accounts in that order in case foreign keys
4142  * already exist
4143  */
4144  for (i = 0; i < nbranches * scale; i++)
4145  {
4146  /* "filler" column defaults to NULL */
4147  printfPQExpBuffer(&sql,
4148  "insert into pgbench_branches(bid,bbalance) values(%d,0)",
4149  i + 1);
4150  executeStatement(con, sql.data);
4151  }
4152 
4153  for (i = 0; i < ntellers * scale; i++)
4154  {
4155  /* "filler" column defaults to NULL */
4156  printfPQExpBuffer(&sql,
4157  "insert into pgbench_tellers(tid,bid,tbalance) values (%d,%d,0)",
4158  i + 1, i / ntellers + 1);
4159  executeStatement(con, sql.data);
4160  }
4161 
4162  /*
4163  * accounts is big enough to be worth using COPY and tracking runtime
4164  */
4165  res = PQexec(con, "copy pgbench_accounts from stdin");
4166  if (PQresultStatus(res) != PGRES_COPY_IN)
4167  {
4168  pg_log_fatal("unexpected copy in result: %s", PQerrorMessage(con));
4169  exit(1);
4170  }
4171  PQclear(res);
4172 
4173  start = pg_time_now();
4174 
4175  for (k = 0; k < (int64) naccounts * scale; k++)
4176  {
4177  int64 j = k + 1;
4178 
4179  /* "filler" column defaults to blank padded empty string */
4180  printfPQExpBuffer(&sql,
4181  INT64_FORMAT "\t" INT64_FORMAT "\t%d\t\n",
4182  j, k / naccounts + 1, 0);
4183  if (PQputline(con, sql.data))
4184  {
4185  pg_log_fatal("PQputline failed");
4186  exit(1);
4187  }
4188 
4189  if (CancelRequested)
4190  break;
4191 
4192  /*
4193  * If we want to stick with the original logging, print a message each
4194  * 100k inserted rows.
4195  */
4196  if ((!use_quiet) && (j % 100000 == 0))
4197  {
4198  double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
4199  double remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
4200 
4201  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c",
4202  j, (int64) naccounts * scale,
4203  (int) (((int64) j * 100) / (naccounts * (int64) scale)),
4204  elapsed_sec, remaining_sec, eol);
4205  }
4206  /* let's not call the timing for each row, but only each 100 rows */
4207  else if (use_quiet && (j % 100 == 0))
4208  {
4209  double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
4210  double remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
4211 
4212  /* have we reached the next interval (or end)? */
4213  if ((j == scale * naccounts) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS))
4214  {
4215  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c",
4216  j, (int64) naccounts * scale,
4217  (int) (((int64) j * 100) / (naccounts * (int64) scale)), elapsed_sec, remaining_sec, eol);
4218 
4219  /* skip to the next interval */
4220  log_interval = (int) ceil(elapsed_sec / LOG_STEP_SECONDS);
4221  }
4222  }
4223  }
4224 
4225  if (eol != '\n')
4226  fputc('\n', stderr); /* Need to move to next line */
4227 
4228  if (PQputline(con, "\\.\n"))
4229  {
4230  pg_log_fatal("very last PQputline failed");
4231  exit(1);
4232  }
4233  if (PQendcopy(con))
4234  {
4235  pg_log_fatal("PQendcopy failed");
4236  exit(1);
4237  }
4238 
4239  termPQExpBuffer(&sql);
4240 
4241  executeStatement(con, "commit");
4242 }
#define PG_TIME_GET_DOUBLE(t)
Definition: pgbench.c:689
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6727
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
static pg_time_usec_t pg_time_now(void)
Definition: pgbench.c:673
int64 pg_time_usec_t
Definition: pgbench.c:329
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
int scale
Definition: pgbench.c:189
#define LOG_STEP_SECONDS
Definition: pgbench.c:173
#define fprintf
Definition: port.h:220
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:3097
bool use_quiet
Definition: pgbench.c:266
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1316
int PQputline(PGconn *conn, const char *s)
Definition: fe-exec.c:2721
#define nbranches
Definition: pgbench.c:251
#define ntellers
Definition: pgbench.c:253
#define naccounts
Definition: pgbench.c:254
void PQclear(PGresult *res)
Definition: fe-exec.c:680
int PQendcopy(PGconn *conn)
Definition: fe-exec.c:2752
static void initTruncateTables(PGconn *con)
Definition: pgbench.c:4100
#define INT64_FORMAT
Definition: c.h:483
volatile sig_atomic_t CancelRequested
Definition: cancel.c:52
int i
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2142
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
#define pg_log_fatal(...)
Definition: logging.h:76

◆ initGenerateDataServerSide()

static void initGenerateDataServerSide ( PGconn con)
static

Definition at line 4252 of file pgbench.c.

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

Referenced by runInitSteps().

4253 {
4254  PQExpBufferData sql;
4255 
4256  fprintf(stderr, "generating data (server-side)...\n");
4257 
4258  /*
4259  * we do all of this in one transaction to enable the backend's
4260  * data-loading optimizations
4261  */
4262  executeStatement(con, "begin");
4263 
4264  /* truncate away any old data */
4265  initTruncateTables(con);
4266 
4267  initPQExpBuffer(&sql);
4268 
4269  printfPQExpBuffer(&sql,
4270  "insert into pgbench_branches(bid,bbalance) "
4271  "select bid, 0 "
4272  "from generate_series(1, %d) as bid", nbranches * scale);
4273  executeStatement(con, sql.data);
4274 
4275  printfPQExpBuffer(&sql,
4276  "insert into pgbench_tellers(tid,bid,tbalance) "
4277  "select tid, (tid - 1) / %d + 1, 0 "
4278  "from generate_series(1, %d) as tid", ntellers, ntellers * scale);
4279  executeStatement(con, sql.data);
4280 
4281  printfPQExpBuffer(&sql,
4282  "insert into pgbench_accounts(aid,bid,abalance,filler) "
4283  "select aid, (aid - 1) / %d + 1, 0, '' "
4284  "from generate_series(1, " INT64_FORMAT ") as aid",
4285  naccounts, (int64) naccounts * scale);
4286  executeStatement(con, sql.data);
4287 
4288  termPQExpBuffer(&sql);
4289 
4290  executeStatement(con, "commit");
4291 }
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
int scale
Definition: pgbench.c:189
#define fprintf
Definition: port.h:220
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1316
#define nbranches
Definition: pgbench.c:251
#define ntellers
Definition: pgbench.c:253
#define naccounts
Definition: pgbench.c:254
static void initTruncateTables(PGconn *con)
Definition: pgbench.c:4100
#define INT64_FORMAT
Definition: c.h:483
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ initRandomState()

static void initRandomState ( RandomState random_state)
static

Definition at line 898 of file pgbench.c.

References pg_jrand48(), and RandomState::xseed.

Referenced by main().

899 {
900  random_state->xseed[0] = (unsigned short)
902  random_state->xseed[1] = (unsigned short)
904  random_state->xseed[2] = (unsigned short)
906 }
static RandomState base_random_sequence
Definition: pgbench.c:354
unsigned short xseed[3]
Definition: pgbench.c:350
long pg_jrand48(unsigned short xseed[3])
Definition: erand48.c:112

◆ initSimpleStats()

static void initSimpleStats ( SimpleStats ss)
static

Definition at line 1242 of file pgbench.c.

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

1243 {
1244  memset(ss, 0, sizeof(SimpleStats));
1245 }

◆ initStats()

static void initStats ( StatsData sd,
pg_time_usec_t  start 
)
static

Definition at line 1282 of file pgbench.c.

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

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

1283 {
1284  sd->start_time = start;
1285  sd->cnt = 0;
1286  sd->skipped = 0;
1287  initSimpleStats(&sd->latency);
1288  initSimpleStats(&sd->lag);
1289 }
pg_time_usec_t start_time
Definition: pgbench.c:337
SimpleStats lag
Definition: pgbench.c:342
SimpleStats latency
Definition: pgbench.c:341
int64 cnt
Definition: pgbench.c:338
int64 skipped
Definition: pgbench.c:339
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1242

◆ initTruncateTables()

static void initTruncateTables ( PGconn con)
static

Definition at line 4100 of file pgbench.c.

References executeStatement().

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

4101 {
4102  executeStatement(con, "truncate table "
4103  "pgbench_accounts, "
4104  "pgbench_branches, "
4105  "pgbench_history, "
4106  "pgbench_tellers");
4107 }
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1316

◆ initVacuum()

static void initVacuum ( PGconn con)
static

Definition at line 4297 of file pgbench.c.

References executeStatement(), and fprintf.

Referenced by runInitSteps().

4298 {
4299  fprintf(stderr, "vacuuming...\n");
4300  executeStatement(con, "vacuum analyze pgbench_branches");
4301  executeStatement(con, "vacuum analyze pgbench_tellers");
4302  executeStatement(con, "vacuum analyze pgbench_accounts");
4303  executeStatement(con, "vacuum analyze pgbench_history");
4304 }
#define fprintf
Definition: port.h:220
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1316

◆ is_an_int()

static bool is_an_int ( const char *  str)
static

Definition at line 761 of file pgbench.c.

References generate_unaccent_rules::str.

Referenced by makeVariableValue().

762 {
763  const char *ptr = str;
764 
765  /* skip leading spaces; cast is consistent with strtoint64 */
766  while (*ptr && isspace((unsigned char) *ptr))
767  ptr++;
768 
769  /* skip sign */
770  if (*ptr == '+' || *ptr == '-')
771  ptr++;
772 
773  /* at least one digit */
774  if (*ptr && !isdigit((unsigned char) *ptr))
775  return false;
776 
777  /* eat all digits */
778  while (*ptr && isdigit((unsigned char) *ptr))
779  ptr++;
780 
781  /* must have reached end of string */
782  return *ptr == '\0';
783 }

◆ isLazyFunc()

static bool isLazyFunc ( PgBenchFunction  func)
static

Definition at line 1930 of file pgbench.c.

References PGBENCH_AND, PGBENCH_CASE, and PGBENCH_OR.

Referenced by evalFunc(), and evalLazyFunc().

1931 {
1932  return func == PGBENCH_AND || func == PGBENCH_OR || func == PGBENCH_CASE;
1933 }

◆ listAvailableScripts()

static void listAvailableScripts ( void  )
static

Definition at line 5288 of file pgbench.c.

References fprintf, i, lengthof, and name.

Referenced by findBuiltin(), and main().

5289 {
5290  int i;
5291 
5292  fprintf(stderr, "Available builtin scripts:\n");
5293  for (i = 0; i < lengthof(builtin_script); i++)
5294  fprintf(stderr, " %13s: %s\n", builtin_script[i].name, builtin_script[i].desc);
5295  fprintf(stderr, "\n");
5296 }
#define lengthof(array)
Definition: c.h:734
#define fprintf
Definition: port.h:220
static const BuiltinScript builtin_script[]
Definition: pgbench.c:604
const char * name
Definition: encode.c:515
int i

◆ lookupCreateVariable()

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

Definition at line 1590 of file pgbench.c.

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

Referenced by putVariable(), and putVariableValue().

1591 {
1592  Variable *var;
1593 
1594  var = lookupVariable(st, name);
1595  if (var == NULL)
1596  {
1597  Variable *newvars;
1598 
1599  /*
1600  * Check for the name only when declaring a new variable to avoid
1601  * overhead.
1602  */
1603  if (!valid_variable_name(name))
1604  {
1605  pg_log_error("%s: invalid variable name: \"%s\"", context, name);
1606  return NULL;
1607  }
1608 
1609  /* Create variable at the end of the array */
1610  if (st->variables)
1611  newvars = (Variable *) pg_realloc(st->variables,
1612  (st->nvariables + 1) * sizeof(Variable));
1613  else
1614  newvars = (Variable *) pg_malloc(sizeof(Variable));
1615 
1616  st->variables = newvars;
1617 
1618  var = &newvars[st->nvariables];
1619 
1620  var->name = pg_strdup(name);
1621  var->svalue = NULL;
1622  /* caller is expected to initialize remaining fields */
1623 
1624  st->nvariables++;
1625  /* we don't re-sort the array till we have to */
1626  st->vars_sorted = false;
1627  }
1628 
1629  return var;
1630 }
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:1420
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
char * name
Definition: pgbench.c:301
#define pg_log_error(...)
Definition: logging.h:80
static bool valid_variable_name(const char *name)
Definition: pgbench.c:1554
Variable * variables
Definition: pgbench.c:462
bool vars_sorted
Definition: pgbench.c:464
char * svalue
Definition: pgbench.c:302
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:515
int nvariables
Definition: pgbench.c:463

◆ lookupVariable()

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

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

1421 {
1422  Variable key;
1423 
1424  /* On some versions of Solaris, bsearch of zero items dumps core */
1425  if (st->nvariables <= 0)
1426  return NULL;
1427 
1428  /* Sort if we have to */
1429  if (!st->vars_sorted)
1430  {
1431  qsort((void *) st->variables, st->nvariables, sizeof(Variable),
1433  st->vars_sorted = true;
1434  }
1435 
1436  /* Now we can search */
1437  key.name = name;
1438  return (Variable *) bsearch((void *) &key,
1439  (void *) st->variables,
1440  st->nvariables,