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 <sys/resource.h>
#include <sys/select.h>
#include "common/int.h"
#include "common/logging.h"
#include "common/pg_prng.h"
#include "common/string.h"
#include "common/username.h"
#include "fe_utils/cancel.h"
#include "fe_utils/conditional.h"
#include "fe_utils/option_utils.h"
#include "fe_utils/string_utils.h"
#include "getopt_long.h"
#include "libpq-fe.h"
#include "pgbench.h"
#include "port/pg_bitutils.h"
#include "portability/instr_time.h"
#include "port/pg_pthread.h"
Include dependency graph for pgbench.c:

Go to the source code of this file.

Data Structures

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

Macros

#define POLL_USING_SELECT
 
#define M_PI   3.14159265358979323846
 
#define ERRCODE_T_R_SERIALIZATION_FAILURE   "40001"
 
#define ERRCODE_T_R_DEADLOCK_DETECTED   "40P01"
 
#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   pthread_t
 
#define THREAD_FUNC_RETURN_TYPE   void *
 
#define THREAD_FUNC_RETURN   return NULL
 
#define THREAD_FUNC_CC
 
#define THREAD_CREATE(handle, function, arg)    pthread_create((handle), NULL, (function), (arg))
 
#define THREAD_JOIN(handle)    pthread_join((handle), NULL)
 
#define THREAD_BARRIER_T   pthread_barrier_t
 
#define THREAD_BARRIER_INIT(barrier, n)    pthread_barrier_init((barrier), NULL, (n))
 
#define THREAD_BARRIER_WAIT(barrier)   pthread_barrier_wait((barrier))
 
#define THREAD_BARRIER_DESTROY(barrier)   pthread_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 VARIABLES_ALLOC_MARGIN   8
 
#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 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 enum EStatus EStatus
 
typedef enum TStatus TStatus
 
typedef enum MetaCommand MetaCommand
 
typedef enum QueryMode QueryMode
 
typedef struct Command Command
 
typedef struct ParsedScript ParsedScript
 
typedef struct BuiltinScript BuiltinScript
 
typedef void(* initRowMethod) (PQExpBufferData *sql, int64 curr)
 

Enumerations

enum  partition_method_t { PART_NONE , PART_RANGE , PART_HASH }
 
enum  EStatus {
  ESTATUS_NO_ERROR = 0 , ESTATUS_META_COMMAND_ERROR , ESTATUS_SERIALIZATION_ERROR , ESTATUS_DEADLOCK_ERROR ,
  ESTATUS_OTHER_SQL_ERROR
}
 
enum  TStatus { TSTATUS_IDLE , TSTATUS_IN_BLOCK , TSTATUS_CONN_ERROR , TSTATUS_OTHER_ERROR }
 
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_ERROR , CSTATE_WAIT_ROLLBACK_RESULT , CSTATE_RETRY ,
  CSTATE_FAILURE , 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 (const 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 (pg_prng_state *state)
 
static int64 getrand (pg_prng_state *state, int64 min, int64 max)
 
static int64 getExponentialRand (pg_prng_state *state, int64 min, int64 max, double parameter)
 
static int64 getGaussianRand (pg_prng_state *state, int64 min, int64 max, double parameter)
 
static int64 getPoissonRand (pg_prng_state *state, double center)
 
static int64 computeIterativeZipfian (pg_prng_state *state, int64 n, double s)
 
static int64 getZipfianRand (pg_prng_state *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, EStatus estatus, int64 tries)
 
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 (Variables *variables, char *name)
 
static char * getVariable (Variables *variables, char *name)
 
static bool makeVariableValue (Variable *var)
 
static bool valid_variable_name (const char *name)
 
static void enlargeVariables (Variables *variables, int needed)
 
static VariablelookupCreateVariable (Variables *variables, const char *context, char *name)
 
static bool putVariable (Variables *variables, const char *context, char *name, const char *value)
 
static bool putVariableValue (Variables *variables, const char *context, char *name, const PgBenchValue *value)
 
static bool putVariableInt (Variables *variables, 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 (Variables *variables, char *sql)
 
static void getQueryParams (Variables *variables, 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 (Variables *variables, char *variable, char **argv, int argc)
 
static void commandFailed (CState *st, const char *cmd, const char *message)
 
static void commandError (CState *st, const char *message)
 
static int chooseScript (TState *thread)
 
static void allocCStatePrepared (CState *st)
 
static void prepareCommand (CState *st, int command_num)
 
static void prepareCommandsInPipeline (CState *st)
 
static bool sendCommand (CState *st, Command *command)
 
static EStatus getSQLErrorStatus (const char *sqlState)
 
static bool canRetryError (EStatus estatus)
 
static bool readCommandResponse (CState *st, MetaCommand meta, char *varprefix)
 
static bool evaluateSleep (Variables *variables, int argc, char **argv, int *usecs)
 
static bool doRetry (CState *st, pg_time_usec_t *now)
 
static int discardUntilSync (CState *st)
 
static TStatus getTransactionStatus (PGconn *con)
 
static void printVerboseErrorMessages (CState *st, pg_time_usec_t *now, bool is_retry)
 
static void advanceConnectionState (TState *thread, CState *st, StatsData *agg)
 
static int64 getFailures (const StatsData *stats)
 
static const char * getResultString (bool skipped, EStatus estatus)
 
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 initBranch (PQExpBufferData *sql, int64 curr)
 
static void initTeller (PQExpBufferData *sql, int64 curr)
 
static void initAccount (PQExpBufferData *sql, int64 curr)
 
static void initPopulateTable (PGconn *con, const char *table, int64 base, initRowMethod init_row)
 
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 (const 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 printVersion (PGconn *con)
 
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 *const 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 = false
 
int main_pid
 
uint32 max_tries = 1
 
bool failures_detailed = false
 
const char * pghost = NULL
 
const char * pgport = NULL
 
const char * username = NULL
 
const char * dbName = NULL
 
char * logfile_prefix = NULL
 
const char * progname
 
volatile sig_atomic_t timer_exceeded = false
 
pg_time_usec_t epoch_shift
 
static pg_prng_state base_random_sequence
 
static THREAD_BARRIER_T barrier
 
static QueryMode querymode = QUERY_SIMPLE
 
static const char *const QUERYMODE [] = {"simple", "extended", "prepared"}
 
static ParsedScript sql_script [MAX_SCRIPTS]
 
static int num_scripts
 
static int64 total_weight = 0
 
static bool verbose_errors = false
 
static bool exit_on_abort = false
 
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 163 of file pgbench.c.

◆ COMMANDS_ALLOC_NUM

#define COMMANDS_ALLOC_NUM   128

◆ DEFAULT_INIT_STEPS

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

Definition at line 162 of file pgbench.c.

◆ DEFAULT_NXACTS

#define DEFAULT_NXACTS   10 /* default nxacts */

Definition at line 166 of file pgbench.c.

◆ ERRCODE_T_R_DEADLOCK_DETECTED

#define ERRCODE_T_R_DEADLOCK_DETECTED   "40P01"

Definition at line 77 of file pgbench.c.

◆ ERRCODE_T_R_SERIALIZATION_FAILURE

#define ERRCODE_T_R_SERIALIZATION_FAILURE   "40001"

Definition at line 76 of file pgbench.c.

◆ ERRCODE_UNDEFINED_TABLE

#define ERRCODE_UNDEFINED_TABLE   "42P01"

Definition at line 78 of file pgbench.c.

◆ FNV_OFFSET_BASIS

#define FNV_OFFSET_BASIS   UINT64CONST(0xcbf29ce484222325)

Definition at line 84 of file pgbench.c.

◆ FNV_PRIME

#define FNV_PRIME   UINT64CONST(0x100000001b3)

Definition at line 83 of file pgbench.c.

◆ LOG_STEP_SECONDS

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

Definition at line 165 of file pgbench.c.

◆ M_PI

#define M_PI   3.14159265358979323846

Definition at line 73 of file pgbench.c.

◆ MAX_ARGS

#define MAX_ARGS   256

Definition at line 683 of file pgbench.c.

◆ MAX_FARGS

#define MAX_FARGS   16

Definition at line 2238 of file pgbench.c.

◆ MAX_SCRIPTS

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

Definition at line 346 of file pgbench.c.

◆ MAX_ZIPFIAN_PARAM

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

Definition at line 171 of file pgbench.c.

◆ META_COMMAND

#define META_COMMAND   2

Definition at line 677 of file pgbench.c.

◆ MIN_GAUSSIAN_PARAM

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

Definition at line 168 of file pgbench.c.

◆ MIN_ZIPFIAN_PARAM

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

Definition at line 170 of file pgbench.c.

◆ MM2_MUL

#define MM2_MUL   UINT64CONST(0xc6a4a7935bd1e995)

Definition at line 85 of file pgbench.c.

◆ MM2_MUL_TIMES_8

#define MM2_MUL_TIMES_8   UINT64CONST(0x35253c9ade8f4ca8)

Definition at line 86 of file pgbench.c.

◆ MM2_ROT

#define MM2_ROT   47

Definition at line 87 of file pgbench.c.

◆ naccounts

#define naccounts   100000

Definition at line 245 of file pgbench.c.

◆ nbranches

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

Definition at line 243 of file pgbench.c.

◆ ntellers

#define ntellers   10

Definition at line 244 of file pgbench.c.

◆ PARAMS_ARRAY_SIZE

#define PARAMS_ARRAY_SIZE   7

◆ PG_TIME_GET_DOUBLE

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

Definition at line 864 of file pgbench.c.

◆ POLL_USING_SELECT

#define POLL_USING_SELECT

Definition at line 52 of file pgbench.c.

◆ SCALE_32BIT_THRESHOLD

#define SCALE_32BIT_THRESHOLD   20000

Definition at line 254 of file pgbench.c.

◆ SHELL_COMMAND_SIZE

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

Definition at line 347 of file pgbench.c.

◆ SOCKET_WAIT_METHOD

#define SOCKET_WAIT_METHOD   "select"

Definition at line 106 of file pgbench.c.

◆ SQL_COMMAND

#define SQL_COMMAND   1

Definition at line 676 of file pgbench.c.

◆ THREAD_BARRIER_DESTROY

#define THREAD_BARRIER_DESTROY (   barrier)    pthread_barrier_destroy((barrier))

Definition at line 155 of file pgbench.c.

◆ THREAD_BARRIER_INIT

#define THREAD_BARRIER_INIT (   barrier,
 
)     pthread_barrier_init((barrier), NULL, (n))

Definition at line 152 of file pgbench.c.

◆ THREAD_BARRIER_T

#define THREAD_BARRIER_T   pthread_barrier_t

Definition at line 151 of file pgbench.c.

◆ THREAD_BARRIER_WAIT

#define THREAD_BARRIER_WAIT (   barrier)    pthread_barrier_wait((barrier))

Definition at line 154 of file pgbench.c.

◆ THREAD_CREATE

#define THREAD_CREATE (   handle,
  function,
  arg 
)     pthread_create((handle), NULL, (function), (arg))

Definition at line 147 of file pgbench.c.

◆ THREAD_FUNC_CC

#define THREAD_FUNC_CC

Definition at line 146 of file pgbench.c.

◆ THREAD_FUNC_RETURN

#define THREAD_FUNC_RETURN   return NULL

Definition at line 145 of file pgbench.c.

◆ THREAD_FUNC_RETURN_TYPE

#define THREAD_FUNC_RETURN_TYPE   void *

Definition at line 144 of file pgbench.c.

◆ THREAD_JOIN

#define THREAD_JOIN (   handle)     pthread_join((handle), NULL)

Definition at line 149 of file pgbench.c.

◆ THREAD_T

#define THREAD_T   pthread_t

Definition at line 143 of file pgbench.c.

◆ VARIABLES_ALLOC_MARGIN

#define VARIABLES_ALLOC_MARGIN   8

Definition at line 309 of file pgbench.c.

◆ WSEP

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

Definition at line 301 of file pgbench.c.

Typedef Documentation

◆ BuiltinScript

typedef struct BuiltinScript BuiltinScript

◆ Command

typedef struct Command Command

◆ EStatus

typedef enum EStatus EStatus

◆ initRowMethod

typedef void(* initRowMethod) (PQExpBufferData *sql, int64 curr)

Definition at line 840 of file pgbench.c.

◆ MetaCommand

typedef enum MetaCommand MetaCommand

◆ ParsedScript

typedef struct ParsedScript ParsedScript

◆ pg_time_usec_t

typedef int64 pg_time_usec_t

Definition at line 369 of file pgbench.c.

◆ QueryMode

typedef enum QueryMode QueryMode

◆ SimpleStats

typedef struct SimpleStats SimpleStats

◆ socket_set

typedef struct socket_set socket_set

◆ StatsData

typedef struct StatsData StatsData

◆ TStatus

typedef enum TStatus TStatus

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_ERROR 
CSTATE_WAIT_ROLLBACK_RESULT 
CSTATE_RETRY 
CSTATE_FAILURE 
CSTATE_END_TX 
CSTATE_ABORTED 
CSTATE_FINISHED 

Definition at line 484 of file pgbench.c.

486 {
487  /*
488  * The client must first choose a script to execute. Once chosen, it can
489  * either be throttled (state CSTATE_PREPARE_THROTTLE under --rate), start
490  * right away (state CSTATE_START_TX) or not start at all if the timer was
491  * exceeded (state CSTATE_FINISHED).
492  */
494 
495  /*
496  * CSTATE_START_TX performs start-of-transaction processing. Establishes
497  * a new connection for the transaction in --connect mode, records the
498  * transaction start time, and proceed to the first command.
499  *
500  * Note: once a script is started, it will either error or run till its
501  * end, where it may be interrupted. It is not interrupted while running,
502  * so pgbench --time is to be understood as tx are allowed to start in
503  * that time, and will finish when their work is completed.
504  */
506 
507  /*
508  * In CSTATE_PREPARE_THROTTLE state, we calculate when to begin the next
509  * transaction, and advance to CSTATE_THROTTLE. CSTATE_THROTTLE state
510  * sleeps until that moment, then advances to CSTATE_START_TX, or
511  * CSTATE_FINISHED if the next transaction would start beyond the end of
512  * the run.
513  */
516 
517  /*
518  * We loop through these states, to process each command in the script:
519  *
520  * CSTATE_START_COMMAND starts the execution of a command. On a SQL
521  * command, the command is sent to the server, and we move to
522  * CSTATE_WAIT_RESULT state unless in pipeline mode. On a \sleep
523  * meta-command, the timer is set, and we enter the CSTATE_SLEEP state to
524  * wait for it to expire. Other meta-commands are executed immediately. If
525  * the command about to start is actually beyond the end of the script,
526  * advance to CSTATE_END_TX.
527  *
528  * CSTATE_WAIT_RESULT waits until we get a result set back from the server
529  * for the current command.
530  *
531  * CSTATE_SLEEP waits until the end of \sleep.
532  *
533  * CSTATE_END_COMMAND records the end-of-command timestamp, increments the
534  * command counter, and loops back to CSTATE_START_COMMAND state.
535  *
536  * CSTATE_SKIP_COMMAND is used by conditional branches which are not
537  * executed. It quickly skip commands that do not need any evaluation.
538  * This state can move forward several commands, till there is something
539  * to do or the end of the script.
540  */
543  CSTATE_SLEEP,
546 
547  /*
548  * States for failed commands.
549  *
550  * If the SQL/meta command fails, in CSTATE_ERROR clean up after an error:
551  * (1) clear the conditional stack; (2) if we have an unterminated
552  * (possibly failed) transaction block, send the rollback command to the
553  * server and wait for the result in CSTATE_WAIT_ROLLBACK_RESULT. If
554  * something goes wrong with rolling back, go to CSTATE_ABORTED.
555  *
556  * But if everything is ok we are ready for future transactions: if this
557  * is a serialization or deadlock error and we can re-execute the
558  * transaction from the very beginning, go to CSTATE_RETRY; otherwise go
559  * to CSTATE_FAILURE.
560  *
561  * In CSTATE_RETRY report an error, set the same parameters for the
562  * transaction execution as in the previous tries and process the first
563  * transaction command in CSTATE_START_COMMAND.
564  *
565  * In CSTATE_FAILURE report a failure, set the parameters for the
566  * transaction execution as they were before the first run of this
567  * transaction (except for a random state) and go to CSTATE_END_TX to
568  * complete this transaction.
569  */
570  CSTATE_ERROR,
572  CSTATE_RETRY,
574 
575  /*
576  * CSTATE_END_TX performs end-of-transaction processing. It calculates
577  * latency, and logs the transaction. In --connect mode, it closes the
578  * current connection.
579  *
580  * Then either starts over in CSTATE_CHOOSE_SCRIPT, or enters
581  * CSTATE_FINISHED if we have no more work to do.
582  */
584 
585  /*
586  * Final states. CSTATE_ABORTED means that the script execution was
587  * aborted because a command failed, CSTATE_FINISHED means success.
588  */
@ CSTATE_START_TX
Definition: pgbench.c:504
@ CSTATE_END_TX
Definition: pgbench.c:582
@ CSTATE_RETRY
Definition: pgbench.c:571
@ CSTATE_FINISHED
Definition: pgbench.c:589
@ CSTATE_SKIP_COMMAND
Definition: pgbench.c:544
@ CSTATE_THROTTLE
Definition: pgbench.c:514
@ CSTATE_FAILURE
Definition: pgbench.c:572
@ CSTATE_START_COMMAND
Definition: pgbench.c:540
@ CSTATE_END_COMMAND
Definition: pgbench.c:543
@ CSTATE_WAIT_RESULT
Definition: pgbench.c:541
@ CSTATE_CHOOSE_SCRIPT
Definition: pgbench.c:492
@ CSTATE_WAIT_ROLLBACK_RESULT
Definition: pgbench.c:570
@ CSTATE_ABORTED
Definition: pgbench.c:588
@ CSTATE_PREPARE_THROTTLE
Definition: pgbench.c:513
@ CSTATE_SLEEP
Definition: pgbench.c:542
@ CSTATE_ERROR
Definition: pgbench.c:569

◆ EStatus

enum EStatus
Enumerator
ESTATUS_NO_ERROR 
ESTATUS_META_COMMAND_ERROR 
ESTATUS_SERIALIZATION_ERROR 
ESTATUS_DEADLOCK_ERROR 
ESTATUS_OTHER_SQL_ERROR 

Definition at line 453 of file pgbench.c.

455 {
456  ESTATUS_NO_ERROR = 0,
458 
459  /* SQL errors */
@ ESTATUS_DEADLOCK_ERROR
Definition: pgbench.c:460
@ ESTATUS_META_COMMAND_ERROR
Definition: pgbench.c:456
@ ESTATUS_OTHER_SQL_ERROR
Definition: pgbench.c:461
@ ESTATUS_NO_ERROR
Definition: pgbench.c:455
@ ESTATUS_SERIALIZATION_ERROR
Definition: pgbench.c:459

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

687 {
688  META_NONE, /* not a known meta-command */
689  META_SET, /* \set */
690  META_SETSHELL, /* \setshell */
691  META_SHELL, /* \shell */
692  META_SLEEP, /* \sleep */
693  META_GSET, /* \gset */
694  META_ASET, /* \aset */
695  META_IF, /* \if */
696  META_ELIF, /* \elif */
697  META_ELSE, /* \else */
698  META_ENDIF, /* \endif */
699  META_STARTPIPELINE, /* \startpipeline */
700  META_ENDPIPELINE /* \endpipeline */
@ META_ELSE
Definition: pgbench.c:696
@ META_SETSHELL
Definition: pgbench.c:689
@ META_ENDIF
Definition: pgbench.c:697
@ META_SHELL
Definition: pgbench.c:690
@ META_STARTPIPELINE
Definition: pgbench.c:698
@ META_SET
Definition: pgbench.c:688
@ META_ELIF
Definition: pgbench.c:695
@ META_SLEEP
Definition: pgbench.c:691
@ META_NONE
Definition: pgbench.c:687
@ META_IF
Definition: pgbench.c:694
@ META_ENDPIPELINE
Definition: pgbench.c:699
@ META_ASET
Definition: pgbench.c:693
@ META_GSET
Definition: pgbench.c:692

◆ partition_method_t

Enumerator
PART_NONE 
PART_RANGE 
PART_HASH 

Definition at line 226 of file pgbench.c.

227 {
228  PART_NONE, /* no partitioning */
229  PART_RANGE, /* range partitioning */
230  PART_HASH /* hash partitioning */
partition_method_t
Definition: pgbench.c:227
@ PART_NONE
Definition: pgbench.c:228
@ PART_RANGE
Definition: pgbench.c:229
@ PART_HASH
Definition: pgbench.c:230

◆ QueryMode

enum QueryMode
Enumerator
QUERY_SIMPLE 
QUERY_EXTENDED 
QUERY_PREPARED 
NUM_QUERYMODE 

Definition at line 702 of file pgbench.c.

704 {
705  QUERY_SIMPLE, /* simple query */
706  QUERY_EXTENDED, /* extended query */
707  QUERY_PREPARED, /* extended query with prepared statements */
@ QUERY_PREPARED
Definition: pgbench.c:706
@ NUM_QUERYMODE
Definition: pgbench.c:707
@ QUERY_SIMPLE
Definition: pgbench.c:704
@ QUERY_EXTENDED
Definition: pgbench.c:705

◆ TStatus

enum TStatus
Enumerator
TSTATUS_IDLE 
TSTATUS_IN_BLOCK 
TSTATUS_CONN_ERROR 
TSTATUS_OTHER_ERROR 

Definition at line 467 of file pgbench.c.

469 {
470  TSTATUS_IDLE,
@ TSTATUS_CONN_ERROR
Definition: pgbench.c:471
@ TSTATUS_IDLE
Definition: pgbench.c:469
@ TSTATUS_IN_BLOCK
Definition: pgbench.c:470
@ TSTATUS_OTHER_ERROR
Definition: pgbench.c:472

Function Documentation

◆ accumStats()

static void accumStats ( StatsData stats,
bool  skipped,
double  lat,
double  lag,
EStatus  estatus,
int64  tries 
)
static

Definition at line 1447 of file pgbench.c.

1450 {
1451  /* Record the skipped transaction */
1452  if (skipped)
1453  {
1454  /* no latency to record on skipped transactions */
1455  stats->skipped++;
1456  return;
1457  }
1458 
1459  /*
1460  * Record the number of retries regardless of whether the transaction was
1461  * successful or failed.
1462  */
1463  if (tries > 1)
1464  {
1465  stats->retries += (tries - 1);
1466  stats->retried++;
1467  }
1468 
1469  switch (estatus)
1470  {
1471  /* Record the successful transaction */
1472  case ESTATUS_NO_ERROR:
1473  stats->cnt++;
1474 
1475  addToSimpleStats(&stats->latency, lat);
1476 
1477  /* and possibly the same for schedule lag */
1478  if (throttle_delay)
1479  addToSimpleStats(&stats->lag, lag);
1480  break;
1481 
1482  /* Record the failed transaction */
1484  stats->serialization_failures++;
1485  break;
1487  stats->deadlock_failures++;
1488  break;
1489  default:
1490  /* internal error which should never occur */
1491  pg_fatal("unexpected error status: %d", estatus);
1492  }
#define pg_fatal(...)
double throttle_delay
Definition: pgbench.c:203
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:1399
int64 serialization_failures
Definition: pgbench.c:434
int64 cnt
Definition: pgbench.c:424
int64 retried
Definition: pgbench.c:430
int64 deadlock_failures
Definition: pgbench.c:437
int64 skipped
Definition: pgbench.c:426
SimpleStats lag
Definition: pgbench.c:441
int64 retries
Definition: pgbench.c:428
SimpleStats latency
Definition: pgbench.c:440

References addToSimpleStats(), StatsData::cnt, StatsData::deadlock_failures, ESTATUS_DEADLOCK_ERROR, ESTATUS_NO_ERROR, ESTATUS_SERIALIZATION_ERROR, StatsData::lag, StatsData::latency, pg_fatal, StatsData::retried, StatsData::retries, StatsData::serialization_failures, StatsData::skipped, and throttle_delay.

Referenced by doLog(), and processXactStats().

◆ add_socket_to_set()

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

Definition at line 7837 of file pgbench.c.

7839 {
7840  if (fd < 0 || fd >= FD_SETSIZE)
7841  {
7842  /*
7843  * Doing a hard exit here is a bit grotty, but it doesn't seem worth
7844  * complicating the API to make it less grotty.
7845  */
7846  pg_fatal("too many client connections for select()");
7847  }
7848  FD_SET(fd, &sa->fds);
7849  if (fd > sa->maxfd)
7850  sa->maxfd = fd;
static int fd(const char *x, int i)
Definition: preproc-init.c:105

References fd(), and pg_fatal.

Referenced by threadRun().

◆ addScript()

static void addScript ( const ParsedScript script)
static

Definition at line 6158 of file pgbench.c.

6160 {
6161  if (script->commands == NULL || script->commands[0] == NULL)
6162  pg_fatal("empty command list for script \"%s\"", script->desc);
6163 
6164  if (num_scripts >= MAX_SCRIPTS)
6165  pg_fatal("at most %d SQL scripts are allowed", MAX_SCRIPTS);
6166 
6167  CheckConditional(script);
6168 
6169  sql_script[num_scripts] = *script;
6170  num_scripts++;
static void CheckConditional(const ParsedScript *ps)
Definition: pgbench.c:5820
#define MAX_SCRIPTS
Definition: pgbench.c:346
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:761
static int num_scripts
Definition: pgbench.c:762
const char * desc
Definition: pgbench.c:755
Command ** commands
Definition: pgbench.c:757

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

Referenced by ParseScript().

◆ addToSimpleStats()

static void addToSimpleStats ( SimpleStats ss,
double  val 
)
static

Definition at line 1399 of file pgbench.c.

1401 {
1402  if (ss->count == 0 || val < ss->min)
1403  ss->min = val;
1404  if (ss->count == 0 || val > ss->max)
1405  ss->max = val;
1406  ss->count++;
1407  ss->sum += val;
1408  ss->sum2 += val * val;
long val
Definition: informix.c:664
int64 count
Definition: pgbench.c:357
double sum
Definition: pgbench.c:360
double min
Definition: pgbench.c:358
double max
Definition: pgbench.c:359
double sum2
Definition: pgbench.c:361

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

Referenced by accumStats(), and advanceConnectionState().

◆ advanceConnectionState()

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

Definition at line 3581 of file pgbench.c.

3583 {
3584 
3585  /*
3586  * gettimeofday() isn't free, so we get the current timestamp lazily the
3587  * first time it's needed, and reuse the same value throughout this
3588  * function after that. This also ensures that e.g. the calculated
3589  * latency reported in the log file and in the totals are the same. Zero
3590  * means "not set yet". Reset "now" when we execute shell commands or
3591  * expressions, which might take a non-negligible amount of time, though.
3592  */
3593  pg_time_usec_t now = 0;
3594 
3595  /*
3596  * Loop in the state machine, until we have to wait for a result from the
3597  * server or have to sleep for throttling or \sleep.
3598  *
3599  * Note: In the switch-statement below, 'break' will loop back here,
3600  * meaning "continue in the state machine". Return is used to return to
3601  * the caller, giving the thread the opportunity to advance another
3602  * client.
3603  */
3604  for (;;)
3605  {
3606  Command *command;
3607 
3608  switch (st->state)
3609  {
3610  /* Select transaction (script) to run. */
3611  case CSTATE_CHOOSE_SCRIPT:
3612  st->use_file = chooseScript(thread);
3614 
3615  /* reset transaction variables to default values */
3616  st->estatus = ESTATUS_NO_ERROR;
3617  st->tries = 1;
3618 
3619  pg_log_debug("client %d executing script \"%s\"",
3620  st->id, sql_script[st->use_file].desc);
3621 
3622  /*
3623  * If time is over, we're done; otherwise, get ready to start
3624  * a new transaction, or to get throttled if that's requested.
3625  */
3628  break;
3629 
3630  /* Start new transaction (script) */
3631  case CSTATE_START_TX:
3633 
3634  /* establish connection if needed, i.e. under --connect */
3635  if (st->con == NULL)
3636  {
3637  pg_time_usec_t start = now;
3638 
3639  if ((st->con = doConnect()) == NULL)
3640  {
3641  /*
3642  * as the bench is already running, we do not abort
3643  * the process
3644  */
3645  pg_log_error("client %d aborted while establishing connection", st->id);
3646  st->state = CSTATE_ABORTED;
3647  break;
3648  }
3649 
3650  /* reset now after connection */
3651  now = pg_time_now();
3652 
3653  thread->conn_duration += now - start;
3654 
3655  /* Reset session-local state */
3656  pg_free(st->prepared);
3657  st->prepared = NULL;
3658  }
3659 
3660  /*
3661  * It is the first try to run this transaction. Remember the
3662  * random state: maybe it will get an error and we will need
3663  * to run it again.
3664  */
3665  st->random_state = st->cs_func_rs;
3666 
3667  /* record transaction start time */
3668  st->txn_begin = now;
3669 
3670  /*
3671  * When not throttling, this is also the transaction's
3672  * scheduled start time.
3673  */
3674  if (!throttle_delay)
3675  st->txn_scheduled = now;
3676 
3677  /* Begin with the first command */
3679  st->command = 0;
3680  break;
3681 
3682  /*
3683  * Handle throttling once per transaction by sleeping.
3684  */
3686 
3687  /*
3688  * Generate a delay such that the series of delays will
3689  * approximate a Poisson distribution centered on the
3690  * throttle_delay time.
3691  *
3692  * If transactions are too slow or a given wait is shorter
3693  * than a transaction, the next transaction will start right
3694  * away.
3695  */
3696  Assert(throttle_delay > 0);
3697 
3698  thread->throttle_trigger +=
3700  st->txn_scheduled = thread->throttle_trigger;
3701 
3702  /*
3703  * If --latency-limit is used, and this slot is already late
3704  * so that the transaction will miss the latency limit even if
3705  * it completed immediately, skip this time slot and loop to
3706  * reschedule.
3707  */
3708  if (latency_limit)
3709  {
3711 
3712  if (thread->throttle_trigger < now - latency_limit)
3713  {
3714  processXactStats(thread, st, &now, true, agg);
3715 
3716  /*
3717  * Finish client if -T or -t was exceeded.
3718  *
3719  * Stop counting skipped transactions under -T as soon
3720  * as the timer is exceeded. Because otherwise it can
3721  * take a very long time to count all of them
3722  * especially when quite a lot of them happen with
3723  * unrealistically high rate setting in -R, which
3724  * would prevent pgbench from ending immediately.
3725  * Because of this behavior, note that there is no
3726  * guarantee that all skipped transactions are counted
3727  * under -T though there is under -t. This is OK in
3728  * practice because it's very unlikely to happen with
3729  * realistic setting.
3730  */
3731  if (timer_exceeded || (nxacts > 0 && st->cnt >= nxacts))
3732  st->state = CSTATE_FINISHED;
3733 
3734  /* Go back to top of loop with CSTATE_PREPARE_THROTTLE */
3735  break;
3736  }
3737  }
3738 
3739  /*
3740  * stop client if next transaction is beyond pgbench end of
3741  * execution; otherwise, throttle it.
3742  */
3743  st->state = end_time > 0 && st->txn_scheduled > end_time ?
3745  break;
3746 
3747  /*
3748  * Wait until it's time to start next transaction.
3749  */
3750  case CSTATE_THROTTLE:
3752 
3753  if (now < st->txn_scheduled)
3754  return; /* still sleeping, nothing to do here */
3755 
3756  /* done sleeping, but don't start transaction if we're done */
3758  break;
3759 
3760  /*
3761  * Send a command to server (or execute a meta-command)
3762  */
3763  case CSTATE_START_COMMAND:
3764  command = sql_script[st->use_file].commands[st->command];
3765 
3766  /* Transition to script end processing if done */
3767  if (command == NULL)
3768  {
3769  st->state = CSTATE_END_TX;
3770  break;
3771  }
3772 
3773  /* record begin time of next command, and initiate it */
3774  if (report_per_command)
3775  {
3777  st->stmt_begin = now;
3778  }
3779 
3780  /* Execute the command */
3781  if (command->type == SQL_COMMAND)
3782  {
3783  /* disallow \aset and \gset in pipeline mode */
3784  if (PQpipelineStatus(st->con) != PQ_PIPELINE_OFF)
3785  {
3786  if (command->meta == META_GSET)
3787  {
3788  commandFailed(st, "gset", "\\gset is not allowed in pipeline mode");
3789  st->state = CSTATE_ABORTED;
3790  break;
3791  }
3792  else if (command->meta == META_ASET)
3793  {
3794  commandFailed(st, "aset", "\\aset is not allowed in pipeline mode");
3795  st->state = CSTATE_ABORTED;
3796  break;
3797  }
3798  }
3799 
3800  if (!sendCommand(st, command))
3801  {
3802  commandFailed(st, "SQL", "SQL command send failed");
3803  st->state = CSTATE_ABORTED;
3804  }
3805  else
3806  {
3807  /* Wait for results, unless in pipeline mode */
3808  if (PQpipelineStatus(st->con) == PQ_PIPELINE_OFF)
3809  st->state = CSTATE_WAIT_RESULT;
3810  else
3811  st->state = CSTATE_END_COMMAND;
3812  }
3813  }
3814  else if (command->type == META_COMMAND)
3815  {
3816  /*-----
3817  * Possible state changes when executing meta commands:
3818  * - on errors CSTATE_ABORTED
3819  * - on sleep CSTATE_SLEEP
3820  * - else CSTATE_END_COMMAND
3821  */
3822  st->state = executeMetaCommand(st, &now);
3823  if (st->state == CSTATE_ABORTED)
3825  }
3826 
3827  /*
3828  * We're now waiting for an SQL command to complete, or
3829  * finished processing a metacommand, or need to sleep, or
3830  * something bad happened.
3831  */
3832  Assert(st->state == CSTATE_WAIT_RESULT ||
3833  st->state == CSTATE_END_COMMAND ||
3834  st->state == CSTATE_SLEEP ||
3835  st->state == CSTATE_ABORTED);
3836  break;
3837 
3838  /*
3839  * non executed conditional branch
3840  */
3841  case CSTATE_SKIP_COMMAND:
3843  /* quickly skip commands until something to do... */
3844  while (true)
3845  {
3846  command = sql_script[st->use_file].commands[st->command];
3847 
3848  /* cannot reach end of script in that state */
3849  Assert(command != NULL);
3850 
3851  /*
3852  * if this is conditional related, update conditional
3853  * state
3854  */
3855  if (command->type == META_COMMAND &&
3856  (command->meta == META_IF ||
3857  command->meta == META_ELIF ||
3858  command->meta == META_ELSE ||
3859  command->meta == META_ENDIF))
3860  {
3861  switch (conditional_stack_peek(st->cstack))
3862  {
3863  case IFSTATE_FALSE:
3864  if (command->meta == META_IF ||
3865  command->meta == META_ELIF)
3866  {
3867  /* we must evaluate the condition */
3869  }
3870  else if (command->meta == META_ELSE)
3871  {
3872  /* we must execute next command */
3876  st->command++;
3877  }
3878  else if (command->meta == META_ENDIF)
3879  {
3882  if (conditional_active(st->cstack))
3884 
3885  /*
3886  * else state remains in
3887  * CSTATE_SKIP_COMMAND
3888  */
3889  st->command++;
3890  }
3891  break;
3892 
3893  case IFSTATE_IGNORED:
3894  case IFSTATE_ELSE_FALSE:
3895  if (command->meta == META_IF)
3897  IFSTATE_IGNORED);
3898  else if (command->meta == META_ENDIF)
3899  {
3902  if (conditional_active(st->cstack))
3904  }
3905  /* could detect "else" & "elif" after "else" */
3906  st->command++;
3907  break;
3908 
3909  case IFSTATE_NONE:
3910  case IFSTATE_TRUE:
3911  case IFSTATE_ELSE_TRUE:
3912  default:
3913 
3914  /*
3915  * inconsistent if inactive, unreachable dead
3916  * code
3917  */
3918  Assert(false);
3919  }
3920  }
3921  else
3922  {
3923  /* skip and consider next */
3924  st->command++;
3925  }
3926 
3927  if (st->state != CSTATE_SKIP_COMMAND)
3928  /* out of quick skip command loop */
3929  break;
3930  }
3931  break;
3932 
3933  /*
3934  * Wait for the current SQL command to complete
3935  */
3936  case CSTATE_WAIT_RESULT:
3937  pg_log_debug("client %d receiving", st->id);
3938 
3939  /*
3940  * Only check for new network data if we processed all data
3941  * fetched prior. Otherwise we end up doing a syscall for each
3942  * individual pipelined query, which has a measurable
3943  * performance impact.
3944  */
3945  if (PQisBusy(st->con) && !PQconsumeInput(st->con))
3946  {
3947  /* there's something wrong */
3948  commandFailed(st, "SQL", "perhaps the backend died while processing");
3949  st->state = CSTATE_ABORTED;
3950  break;
3951  }
3952  if (PQisBusy(st->con))
3953  return; /* don't have the whole result yet */
3954 
3955  /* store or discard the query results */
3956  if (readCommandResponse(st,
3959  {
3960  /*
3961  * outside of pipeline mode: stop reading results.
3962  * pipeline mode: continue reading results until an
3963  * end-of-pipeline response.
3964  */
3965  if (PQpipelineStatus(st->con) != PQ_PIPELINE_ON)
3966  st->state = CSTATE_END_COMMAND;
3967  }
3968  else if (canRetryError(st->estatus))
3969  st->state = CSTATE_ERROR;
3970  else
3971  st->state = CSTATE_ABORTED;
3972  break;
3973 
3974  /*
3975  * Wait until sleep is done. This state is entered after a
3976  * \sleep metacommand. The behavior is similar to
3977  * CSTATE_THROTTLE, but proceeds to CSTATE_START_COMMAND
3978  * instead of CSTATE_START_TX.
3979  */
3980  case CSTATE_SLEEP:
3982  if (now < st->sleep_until)
3983  return; /* still sleeping, nothing to do here */
3984  /* Else done sleeping. */
3985  st->state = CSTATE_END_COMMAND;
3986  break;
3987 
3988  /*
3989  * End of command: record stats and proceed to next command.
3990  */
3991  case CSTATE_END_COMMAND:
3992 
3993  /*
3994  * command completed: accumulate per-command execution times
3995  * in thread-local data structure, if per-command latencies
3996  * are requested.
3997  */
3998  if (report_per_command)
3999  {
4001 
4002  command = sql_script[st->use_file].commands[st->command];
4003  /* XXX could use a mutex here, but we choose not to */
4004  addToSimpleStats(&command->stats,
4006  }
4007 
4008  /* Go ahead with next command, to be executed or skipped */
4009  st->command++;
4010  st->state = conditional_active(st->cstack) ?
4012  break;
4013 
4014  /*
4015  * Clean up after an error.
4016  */
4017  case CSTATE_ERROR:
4018  {
4019  TStatus tstatus;
4020 
4022 
4023  /* Clear the conditional stack */
4025 
4026  /* Read and discard until a sync point in pipeline mode */
4027  if (PQpipelineStatus(st->con) != PQ_PIPELINE_OFF)
4028  {
4029  if (!discardUntilSync(st))
4030  {
4031  st->state = CSTATE_ABORTED;
4032  break;
4033  }
4034  }
4035 
4036  /*
4037  * Check if we have a (failed) transaction block or not,
4038  * and roll it back if any.
4039  */
4040  tstatus = getTransactionStatus(st->con);
4041  if (tstatus == TSTATUS_IN_BLOCK)
4042  {
4043  /* Try to rollback a (failed) transaction block. */
4044  if (!PQsendQuery(st->con, "ROLLBACK"))
4045  {
4046  pg_log_error("client %d aborted: failed to send sql command for rolling back the failed transaction",
4047  st->id);
4048  st->state = CSTATE_ABORTED;
4049  }
4050  else
4052  }
4053  else if (tstatus == TSTATUS_IDLE)
4054  {
4055  /*
4056  * If time is over, we're done; otherwise, check if we
4057  * can retry the error.
4058  */
4061  }
4062  else
4063  {
4064  if (tstatus == TSTATUS_CONN_ERROR)
4065  pg_log_error("perhaps the backend died while processing");
4066 
4067  pg_log_error("client %d aborted while receiving the transaction status", st->id);
4068  st->state = CSTATE_ABORTED;
4069  }
4070  break;
4071  }
4072 
4073  /*
4074  * Wait for the rollback command to complete
4075  */
4077  {
4078  PGresult *res;
4079 
4080  pg_log_debug("client %d receiving", st->id);
4081  if (!PQconsumeInput(st->con))
4082  {
4083  pg_log_error("client %d aborted while rolling back the transaction after an error; perhaps the backend died while processing",
4084  st->id);
4085  st->state = CSTATE_ABORTED;
4086  break;
4087  }
4088  if (PQisBusy(st->con))
4089  return; /* don't have the whole result yet */
4090 
4091  /*
4092  * Read and discard the query result;
4093  */
4094  res = PQgetResult(st->con);
4095  switch (PQresultStatus(res))
4096  {
4097  case PGRES_COMMAND_OK:
4098  /* OK */
4099  PQclear(res);
4100  /* null must be returned */
4101  res = PQgetResult(st->con);
4102  Assert(res == NULL);
4103 
4104  /*
4105  * If time is over, we're done; otherwise, check
4106  * if we can retry the error.
4107  */
4110  break;
4111  default:
4112  pg_log_error("client %d aborted while rolling back the transaction after an error; %s",
4113  st->id, PQerrorMessage(st->con));
4114  PQclear(res);
4115  st->state = CSTATE_ABORTED;
4116  break;
4117  }
4118  break;
4119  }
4120 
4121  /*
4122  * Retry the transaction after an error.
4123  */
4124  case CSTATE_RETRY:
4125  command = sql_script[st->use_file].commands[st->command];
4126 
4127  /*
4128  * Inform that the transaction will be retried after the
4129  * error.
4130  */
4131  if (verbose_errors)
4132  printVerboseErrorMessages(st, &now, true);
4133 
4134  /* Count tries and retries */
4135  st->tries++;
4136  command->retries++;
4137 
4138  /*
4139  * Reset the random state as they were at the beginning of the
4140  * transaction.
4141  */
4142  st->cs_func_rs = st->random_state;
4143 
4144  /* Process the first transaction command. */
4145  st->command = 0;
4146  st->estatus = ESTATUS_NO_ERROR;
4148  break;
4149 
4150  /*
4151  * Record a failed transaction.
4152  */
4153  case CSTATE_FAILURE:
4154  command = sql_script[st->use_file].commands[st->command];
4155 
4156  /* Accumulate the failure. */
4157  command->failures++;
4158 
4159  /*
4160  * Inform that the failed transaction will not be retried.
4161  */
4162  if (verbose_errors)
4163  printVerboseErrorMessages(st, &now, false);
4164 
4165  /* End the failed transaction. */
4166  st->state = CSTATE_END_TX;
4167  break;
4168 
4169  /*
4170  * End of transaction (end of script, really).
4171  */
4172  case CSTATE_END_TX:
4173  {
4174  TStatus tstatus;
4175 
4176  /* transaction finished: calculate latency and do log */
4177  processXactStats(thread, st, &now, false, agg);
4178 
4179  /*
4180  * missing \endif... cannot happen if CheckConditional was
4181  * okay
4182  */
4184 
4185  /*
4186  * We must complete all the transaction blocks that were
4187  * started in this script.
4188  */
4189  tstatus = getTransactionStatus(st->con);
4190  if (tstatus == TSTATUS_IN_BLOCK)
4191  {
4192  pg_log_error("client %d aborted: end of script reached without completing the last transaction",
4193  st->id);
4194  st->state = CSTATE_ABORTED;
4195  break;
4196  }
4197  else if (tstatus != TSTATUS_IDLE)
4198  {
4199  if (tstatus == TSTATUS_CONN_ERROR)
4200  pg_log_error("perhaps the backend died while processing");
4201 
4202  pg_log_error("client %d aborted while receiving the transaction status", st->id);
4203  st->state = CSTATE_ABORTED;
4204  break;
4205  }
4206 
4207  if (is_connect)
4208  {
4209  pg_time_usec_t start = now;
4210 
4211  pg_time_now_lazy(&start);
4212  finishCon(st);
4213  now = pg_time_now();
4214  thread->conn_duration += now - start;
4215  }
4216 
4217  if ((st->cnt >= nxacts && duration <= 0) || timer_exceeded)
4218  {
4219  /* script completed */
4220  st->state = CSTATE_FINISHED;
4221  break;
4222  }
4223 
4224  /* next transaction (script) */
4226 
4227  /*
4228  * Ensure that we always return on this point, so as to
4229  * avoid an infinite loop if the script only contains meta
4230  * commands.
4231  */
4232  return;
4233  }
4234 
4235  /*
4236  * Final states. Close the connection if it's still open.
4237  */
4238  case CSTATE_ABORTED:
4239  case CSTATE_FINISHED:
4240 
4241  /*
4242  * Don't measure the disconnection delays here even if in
4243  * CSTATE_FINISHED and -C/--connect option is specified.
4244  * Because in this case all the connections that this thread
4245  * established are closed at the end of transactions and the
4246  * disconnection delays should have already been measured at
4247  * that moment.
4248  *
4249  * In CSTATE_ABORTED state, the measurement is no longer
4250  * necessary because we cannot report complete results anyways
4251  * in this case.
4252  */
4253  finishCon(st);
4254  return;
4255  }
4256  }
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1547
ifState conditional_stack_peek(ConditionalStack cstack)
Definition: conditional.c:106
void conditional_stack_push(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:53
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:69
bool conditional_active(ConditionalStack cstack)
Definition: conditional.c:140
void conditional_stack_reset(ConditionalStack cstack)
Definition: conditional.c:30
bool conditional_stack_poke(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:118
bool conditional_stack_empty(ConditionalStack cstack)
Definition: conditional.c:130
@ IFSTATE_FALSE
Definition: conditional.h:34
@ IFSTATE_ELSE_TRUE
Definition: conditional.h:40
@ IFSTATE_IGNORED
Definition: conditional.h:37
@ IFSTATE_TRUE
Definition: conditional.h:32
@ IFSTATE_NONE
Definition: conditional.h:31
@ IFSTATE_ELSE_FALSE
Definition: conditional.h:42
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:7248
PGpipelineStatus PQpipelineStatus(const PGconn *conn)
Definition: fe-connect.c:7290
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:3325
int PQconsumeInput(PGconn *conn)
Definition: fe-exec.c:1957
int PQsendQuery(PGconn *conn, const char *query)
Definition: fe-exec.c:1422
int PQisBusy(PGconn *conn)
Definition: fe-exec.c:2004
PGresult * PQgetResult(PGconn *conn)
Definition: fe-exec.c:2035
void pg_free(void *ptr)
Definition: fe_memutils.c:105
@ PGRES_COMMAND_OK
Definition: libpq-fe.h:97
@ PQ_PIPELINE_OFF
Definition: libpq-fe.h:158
@ PQ_PIPELINE_ON
Definition: libpq-fe.h:159
Assert(fmt[strlen(fmt) - 1] !='\n')
#define pg_log_error(...)
Definition: logging.h:106
#define pg_log_debug(...)
Definition: logging.h:133
static pg_time_usec_t pg_time_now(void)
Definition: pgbench.c:848
static void printVerboseErrorMessages(CState *st, pg_time_usec_t *now, bool is_retry)
Definition: pgbench.c:3543
int64 latency_limit
Definition: pgbench.c:211
static TStatus getTransactionStatus(PGconn *con)
Definition: pgbench.c:3506
int64 end_time
Definition: pgbench.c:175
static bool doRetry(CState *st, pg_time_usec_t *now)
Definition: pgbench.c:3420
static bool sendCommand(CState *st, Command *command)
Definition: pgbench.c:3149
TStatus
Definition: pgbench.c:468
static void finishCon(CState *st)
Definition: pgbench.c:7653
int64 pg_time_usec_t
Definition: pgbench.c:369
bool is_connect
Definition: pgbench.c:265
int nxacts
Definition: pgbench.c:173
bool report_per_command
Definition: pgbench.c:266
#define PG_TIME_GET_DOUBLE(t)
Definition: pgbench.c:864
static int discardUntilSync(CState *st)
Definition: pgbench.c:3466
static ConnectionStateEnum executeMetaCommand(CState *st, pg_time_usec_t *now)
Definition: pgbench.c:4266
static bool canRetryError(EStatus estatus)
Definition: pgbench.c:3219
static void commandFailed(CState *st, const char *cmd, const char *message)
Definition: pgbench.c:3022
static int chooseScript(TState *thread)
Definition: pgbench.c:3041
#define SQL_COMMAND
Definition: pgbench.c:676
volatile sig_atomic_t timer_exceeded
Definition: pgbench.c:303
static void processXactStats(TState *thread, CState *st, pg_time_usec_t *now, bool skipped, StatsData *agg)
Definition: pgbench.c:4632
int duration
Definition: pgbench.c:174
static void pg_time_now_lazy(pg_time_usec_t *now)
Definition: pgbench.c:858
static bool verbose_errors
Definition: pgbench.c:765
static int64 getPoissonRand(pg_prng_state *state, double center)
Definition: pgbench.c:1175
static PGconn * doConnect(void)
Definition: pgbench.c:1527
#define META_COMMAND
Definition: pgbench.c:677
static bool readCommandResponse(CState *st, MetaCommand meta, char *varprefix)
Definition: pgbench.c:3235
int64 cnt
Definition: pgbench.c:635
int id
Definition: pgbench.c:598
pg_time_usec_t txn_scheduled
Definition: pgbench.c:615
pg_time_usec_t stmt_begin
Definition: pgbench.c:618
int command
Definition: pgbench.c:609
int use_file
Definition: pgbench.c:608
ConditionalStack cstack
Definition: pgbench.c:600
pg_prng_state random_state
Definition: pgbench.c:630
pg_time_usec_t txn_begin
Definition: pgbench.c:617
EStatus estatus
Definition: pgbench.c:627
PGconn * con
Definition: pgbench.c:597
pg_prng_state cs_func_rs
Definition: pgbench.c:606
uint32 tries
Definition: pgbench.c:631
bool ** prepared
Definition: pgbench.c:621
ConnectionStateEnum state
Definition: pgbench.c:599
int64 retries
Definition: pgbench.c:749
char * varprefix
Definition: pgbench.c:746
int type
Definition: pgbench.c:741
MetaCommand meta
Definition: pgbench.c:742
SimpleStats stats
Definition: pgbench.c:748
int64 failures
Definition: pgbench.c:750
int64 throttle_trigger
Definition: pgbench.c:659
pg_prng_state ts_throttle_rs
Definition: pgbench.c:656
pg_time_usec_t conn_duration
Definition: pgbench.c:666

References addToSimpleStats(), Assert(), canRetryError(), 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(), conditional_stack_reset(), TState::conn_duration, CState::cs_func_rs, CState::cstack, CSTATE_ABORTED, CSTATE_CHOOSE_SCRIPT, CSTATE_END_COMMAND, CSTATE_END_TX, CSTATE_ERROR, CSTATE_FAILURE, CSTATE_FINISHED, CSTATE_PREPARE_THROTTLE, CSTATE_RETRY, CSTATE_SKIP_COMMAND, CSTATE_SLEEP, CSTATE_START_COMMAND, CSTATE_START_TX, CSTATE_THROTTLE, CSTATE_WAIT_RESULT, CSTATE_WAIT_ROLLBACK_RESULT, ParsedScript::desc, discardUntilSync(), doConnect(), doRetry(), duration, end_time, CState::estatus, ESTATUS_META_COMMAND_ERROR, ESTATUS_NO_ERROR, executeMetaCommand(), Command::failures, finishCon(), getPoissonRand(), getTransactionStatus(), 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_free(), pg_log_debug, pg_log_error, PG_TIME_GET_DOUBLE, pg_time_now(), pg_time_now_lazy(), PGRES_COMMAND_OK, PQ_PIPELINE_OFF, PQ_PIPELINE_ON, PQclear(), PQconsumeInput(), PQerrorMessage(), PQgetResult(), PQisBusy(), PQpipelineStatus(), PQresultStatus(), PQsendQuery(), CState::prepared, printVerboseErrorMessages(), processXactStats(), CState::random_state, readCommandResponse(), report_per_command, res, Command::retries, sendCommand(), SQL_COMMAND, sql_script, CState::state, Command::stats, CState::stmt_begin, throttle_delay, TState::throttle_trigger, timer_exceeded, CState::tries, TState::ts_throttle_rs, TSTATUS_CONN_ERROR, TSTATUS_IDLE, TSTATUS_IN_BLOCK, CState::txn_begin, CState::txn_scheduled, Command::type, CState::use_file, Command::varprefix, and verbose_errors.

Referenced by threadRun().

◆ alloc_socket_set()

static socket_set * alloc_socket_set ( int  count)
static

Definition at line 7818 of file pgbench.c.

7820 {
7821  return (socket_set *) pg_malloc0(sizeof(socket_set));
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53

References pg_malloc0().

Referenced by threadRun().

◆ allocCStatePrepared()

static void allocCStatePrepared ( CState st)
static

Definition at line 3063 of file pgbench.c.

3065 {
3066  Assert(st->prepared == NULL);
3067 
3068  st->prepared = pg_malloc(sizeof(bool *) * num_scripts);
3069  for (int i = 0; i < num_scripts; i++)
3070  {
3071  ParsedScript *script = &sql_script[i];
3072  int numcmds;
3073 
3074  for (numcmds = 0; script->commands[numcmds] != NULL; numcmds++)
3075  ;
3076  st->prepared[i] = pg_malloc0(sizeof(bool) * numcmds);
3077  }
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
int i
Definition: isn.c:73

References Assert(), ParsedScript::commands, i, num_scripts, pg_malloc(), pg_malloc0(), CState::prepared, and sql_script.

Referenced by prepareCommand(), and prepareCommandsInPipeline().

◆ assignVariables()

static char* assignVariables ( Variables variables,
char *  sql 
)
static

Definition at line 1932 of file pgbench.c.

1934 {
1935  char *p,
1936  *name,
1937  *val;
1938 
1939  p = sql;
1940  while ((p = strchr(p, ':')) != NULL)
1941  {
1942  int eaten;
1943 
1944  name = parseVariable(p, &eaten);
1945  if (name == NULL)
1946  {
1947  while (*p == ':')
1948  {
1949  p++;
1950  }
1951  continue;
1952  }
1953 
1954  val = getVariable(variables, name);
1955  free(name);
1956  if (val == NULL)
1957  {
1958  p++;
1959  continue;
1960  }
1961 
1962  p = replaceVariable(&sql, p, eaten, val);
1963  }
1964 
1965  return sql;
#define free(a)
Definition: header.h:65
static char * getVariable(Variables *variables, char *name)
Definition: pgbench.c:1627
static char * parseVariable(const char *sql, int *eaten)
Definition: pgbench.c:1885
static char * replaceVariable(char **sql, char *param, int len, char *value)
Definition: pgbench.c:1912
const char * name

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

Referenced by sendCommand().

◆ canRetryError()

static bool canRetryError ( EStatus  estatus)
static

Definition at line 3219 of file pgbench.c.

3221 {
3222  return (estatus == ESTATUS_SERIALIZATION_ERROR ||
3223  estatus == ESTATUS_DEADLOCK_ERROR);

References ESTATUS_DEADLOCK_ERROR, and ESTATUS_SERIALIZATION_ERROR.

Referenced by advanceConnectionState(), doRetry(), and readCommandResponse().

◆ CheckConditional()

static void CheckConditional ( const ParsedScript ps)
static

Definition at line 5820 of file pgbench.c.

5822 {
5823  /* statically check conditional structure */
5825  int i;
5826 
5827  for (i = 0; ps->commands[i] != NULL; i++)
5828  {
5829  Command *cmd = ps->commands[i];
5830 
5831  if (cmd->type == META_COMMAND)
5832  {
5833  switch (cmd->meta)
5834  {
5835  case META_IF:
5837  break;
5838  case META_ELIF:
5839  if (conditional_stack_empty(cs))
5840  ConditionError(ps->desc, i + 1, "\\elif without matching \\if");
5842  ConditionError(ps->desc, i + 1, "\\elif after \\else");
5843  break;
5844  case META_ELSE:
5845  if (conditional_stack_empty(cs))
5846  ConditionError(ps->desc, i + 1, "\\else without matching \\if");
5848  ConditionError(ps->desc, i + 1, "\\else after \\else");
5850  break;
5851  case META_ENDIF:
5852  if (!conditional_stack_pop(cs))
5853  ConditionError(ps->desc, i + 1, "\\endif without matching \\if");
5854  break;
5855  default:
5856  /* ignore anything else... */
5857  break;
5858  }
5859  }
5860  }
5861  if (!conditional_stack_empty(cs))
5862  ConditionError(ps->desc, i + 1, "\\if without matching \\endif");
ConditionalStack conditional_stack_create(void)
Definition: conditional.c:18
void conditional_stack_destroy(ConditionalStack cstack)
Definition: conditional.c:43
struct parser_state ps
static void ConditionError(const char *desc, int cmdn, const char *msg)
Definition: pgbench.c:5810

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

Referenced by addScript().

◆ checkInitSteps()

static void checkInitSteps ( const char *  initialize_steps)
static

Definition at line 5169 of file pgbench.c.

5171 {
5172  if (initialize_steps[0] == '\0')
5173  pg_fatal("no initialization steps specified");
5174 
5175  for (const char *step = initialize_steps; *step != '\0'; step++)
5176  {
5177  if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
5178  {
5179  pg_log_error("unrecognized initialization step \"%c\"", *step);
5180  pg_log_error_detail("Allowed step characters are: \"" ALL_INIT_STEPS "\".");
5181  exit(1);
5182  }
5183  }
exit(1)
#define pg_log_error_detail(...)
Definition: logging.h:109
#define ALL_INIT_STEPS
Definition: pgbench.c:163

References ALL_INIT_STEPS, exit(), pg_fatal, pg_log_error, and pg_log_error_detail.

Referenced by main().

◆ chooseScript()

static int chooseScript ( TState thread)
static

Definition at line 3041 of file pgbench.c.

3043 {
3044  int i = 0;
3045  int64 w;
3046 
3047  if (num_scripts == 1)
3048  return 0;
3049 
3050  w = getrand(&thread->ts_choose_rs, 0, total_weight - 1);
3051  do
3052  {
3053  w -= sql_script[i++].weight;
3054  } while (w >= 0);
3055 
3056  return i - 1;
static int64 total_weight
Definition: pgbench.c:763
static int64 getrand(pg_prng_state *state, int64 min, int64 max)
Definition: pgbench.c:1098
int weight
Definition: pgbench.c:756
pg_prng_state ts_choose_rs
Definition: pgbench.c:655

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

Referenced by advanceConnectionState().

◆ clear_socket_set()

static void clear_socket_set ( socket_set sa)
static

Definition at line 7830 of file pgbench.c.

7832 {
7833  FD_ZERO(&sa->fds);
7834  sa->maxfd = -1;

Referenced by threadRun().

◆ coerceToBool()

static bool coerceToBool ( PgBenchValue pval,
bool bval 
)
static

Definition at line 2000 of file pgbench.c.

2002 {
2003  if (pval->type == PGBT_BOOLEAN)
2004  {
2005  *bval = pval->u.bval;
2006  return true;
2007  }
2008  else /* NULL, INT or DOUBLE */
2009  {
2010  pg_log_error("cannot coerce %s to boolean", valueTypeName(pval));
2011  *bval = false; /* suppress uninitialized-variable warnings */
2012  return false;
2013  }
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1978
@ PGBT_BOOLEAN
Definition: pgbench.h:40
PgBenchValueType type
Definition: pgbench.h:46
bool bval
Definition: pgbench.h:51
union PgBenchValue::@33 u

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

Referenced by evalLazyFunc(), and evalStandardFunc().

◆ coerceToDouble()

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

Definition at line 2069 of file pgbench.c.

2071 {
2072  if (pval->type == PGBT_DOUBLE)
2073  {
2074  *dval = pval->u.dval;
2075  return true;
2076  }
2077  else if (pval->type == PGBT_INT)
2078  {
2079  *dval = (double) pval->u.ival;
2080  return true;
2081  }
2082  else /* BOOLEAN or NULL */
2083  {
2084  pg_log_error("cannot coerce %s to double", valueTypeName(pval));
2085  return false;
2086  }
@ PGBT_INT
Definition: pgbench.h:38
@ PGBT_DOUBLE
Definition: pgbench.h:39
int64 ival
Definition: pgbench.h:49
double dval
Definition: pgbench.h:50

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

Referenced by evalStandardFunc().

◆ coerceToInt()

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

Definition at line 2041 of file pgbench.c.

2043 {
2044  if (pval->type == PGBT_INT)
2045  {
2046  *ival = pval->u.ival;
2047  return true;
2048  }
2049  else if (pval->type == PGBT_DOUBLE)
2050  {
2051  double dval = rint(pval->u.dval);
2052 
2053  if (isnan(dval) || !FLOAT8_FITS_IN_INT64(dval))
2054  {
2055  pg_log_error("double to int overflow for %f", dval);
2056  return false;
2057  }
2058  *ival = (int64) dval;
2059  return true;
2060  }
2061  else /* BOOLEAN or NULL */
2062  {
2063  pg_log_error("cannot coerce %s to int", valueTypeName(pval));
2064  return false;
2065  }
#define FLOAT8_FITS_IN_INT64(num)
Definition: c.h:1105

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

◆ commandError()

static void commandError ( CState st,
const char *  message 
)
static

Definition at line 3032 of file pgbench.c.

3034 {
3036  pg_log_info("client %d got an error in command %d (SQL) of script %d; %s",
3037  st->id, st->command, st->use_file, message);
#define pg_log_info(...)
Definition: logging.h:124

References Assert(), CState::command, ParsedScript::commands, CState::id, pg_log_info, SQL_COMMAND, sql_script, Command::type, and CState::use_file.

Referenced by readCommandResponse().

◆ commandFailed()

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

Definition at line 3022 of file pgbench.c.

3024 {
3025  pg_log_error("client %d aborted in command %d (%s) of script %d; %s",
3026  st->id, st->command, cmd, st->use_file, message);

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

Referenced by advanceConnectionState(), and executeMetaCommand().

◆ compareVariableNames()

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

Definition at line 1592 of file pgbench.c.

1594 {
1595  return strcmp(((const Variable *) v1)->name,
1596  ((const Variable *) v2)->name);

References name.

Referenced by lookupVariable().

◆ computeIterativeZipfian()

static int64 computeIterativeZipfian ( pg_prng_state state,
int64  n,
double  s 
)
static

Definition at line 1197 of file pgbench.c.

1199 {
1200  double b = pow(2.0, s - 1.0);
1201  double x,
1202  t,
1203  u,
1204  v;
1205 
1206  /* Ensure n is sane */
1207  if (n <= 1)
1208  return 1;
1209 
1210  while (true)
1211  {
1212  /* random variates */
1213  u = pg_prng_double(state);
1214  v = pg_prng_double(state);
1215 
1216  x = floor(pow(u, -1.0 / (s - 1.0)));
1217 
1218  t = pow(1.0 + 1.0 / x, s - 1.0);
1219  /* reject if too large or out of bound */
1220  if (v * x * (t - 1.0) / (b - 1.0) <= t / b && x <= n)
1221  break;
1222  }
1223  return (int64) x;
int b
Definition: isn.c:70
int x
Definition: isn.c:71
double pg_prng_double(pg_prng_state *state)
Definition: pg_prng.c:232
Definition: regguts.h:323

References b, pg_prng_double(), and x.

Referenced by getZipfianRand().

◆ ConditionError()

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

Definition at line 5810 of file pgbench.c.

5812 {
5813  pg_fatal("condition error in script \"%s\" command %d: %s",
5814  desc, cmdn, msg);

References pg_fatal.

Referenced by CheckConditional().

◆ create_sql_command()

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

Definition at line 5515 of file pgbench.c.

5517 {
5518  Command *my_command;
5519  char *p = skip_sql_comments(buf->data);
5520 
5521  if (p == NULL)
5522  return NULL;
5523 
5524  /* Allocate and initialize Command structure */
5525  my_command = (Command *) pg_malloc(sizeof(Command));
5526  initPQExpBuffer(&my_command->lines);
5527  appendPQExpBufferStr(&my_command->lines, p);
5528  my_command->first_line = NULL; /* this is set later */
5529  my_command->type = SQL_COMMAND;
5530  my_command->meta = META_NONE;
5531  my_command->argc = 0;
5532  my_command->retries = 0;
5533  my_command->failures = 0;
5534  memset(my_command->argv, 0, sizeof(my_command->argv));
5535  my_command->varprefix = NULL; /* allocated later, if needed */
5536  my_command->expr = NULL;
5537  initSimpleStats(&my_command->stats);
5538  my_command->prepname = NULL; /* set later, if needed */
5539 
5540  return my_command;
static char * buf
Definition: pg_test_fsync.c:67
static char * skip_sql_comments(char *sql_command)
Definition: pgbench.c:5480
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1390
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:90
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367
PQExpBufferData lines
Definition: pgbench.c:739
PgBenchExpr * expr
Definition: pgbench.c:747
char * argv[MAX_ARGS]
Definition: pgbench.c:744
char * first_line
Definition: pgbench.c:740
int argc
Definition: pgbench.c:743
char * prepname
Definition: pgbench.c:745

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

Referenced by ParseScript().

◆ createPartitions()

static void createPartitions ( PGconn con)
static

Definition at line 4705 of file pgbench.c.

4707 {
4708  PQExpBufferData query;
4709 
4710  /* we must have to create some partitions */
4711  Assert(partitions > 0);
4712 
4713  fprintf(stderr, "creating %d partitions...\n", partitions);
4714 
4715  initPQExpBuffer(&query);
4716 
4717  for (int p = 1; p <= partitions; p++)
4718  {
4720  {
4721  int64 part_size = (naccounts * (int64) scale + partitions - 1) / partitions;
4722 
4723  printfPQExpBuffer(&query,
4724  "create%s table pgbench_accounts_%d\n"
4725  " partition of pgbench_accounts\n"
4726  " for values from (",
4727  unlogged_tables ? " unlogged" : "", p);
4728 
4729  /*
4730  * For RANGE, we use open-ended partitions at the beginning and
4731  * end to allow any valid value for the primary key. Although the
4732  * actual minimum and maximum values can be derived from the
4733  * scale, it is more generic and the performance is better.
4734  */
4735  if (p == 1)
4736  appendPQExpBufferStr(&query, "minvalue");
4737  else
4738  appendPQExpBuffer(&query, INT64_FORMAT, (p - 1) * part_size + 1);
4739 
4740  appendPQExpBufferStr(&query, ") to (");
4741 
4742  if (p < partitions)
4743  appendPQExpBuffer(&query, INT64_FORMAT, p * part_size + 1);
4744  else
4745  appendPQExpBufferStr(&query, "maxvalue");
4746 
4747  appendPQExpBufferChar(&query, ')');
4748  }
4749  else if (partition_method == PART_HASH)
4750  printfPQExpBuffer(&query,
4751  "create%s table pgbench_accounts_%d\n"
4752  " partition of pgbench_accounts\n"
4753  " for values with (modulus %d, remainder %d)",
4754  unlogged_tables ? " unlogged" : "", p,
4755  partitions, p - 1);
4756  else /* cannot get there */
4757  Assert(0);
4758 
4759  /*
4760  * Per ddlinfo in initCreateTables, fillfactor is needed on table
4761  * pgbench_accounts.
4762  */
4763  appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4764 
4765  executeStatement(con, query.data);
4766  }
4767 
4768  termPQExpBuffer(&query);
#define INT64_FORMAT
Definition: c.h:537
int scale
Definition: pgbench.c:181
static int partitions
Definition: pgbench.c:223
int fillfactor
Definition: pgbench.c:187
static partition_method_t partition_method
Definition: pgbench.c:233
bool unlogged_tables
Definition: pgbench.c:192
#define naccounts
Definition: pgbench.c:245
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1496
#define fprintf
Definition: port.h:242
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:235
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:265
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:378
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:129

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

◆ discardUntilSync()

static int discardUntilSync ( CState st)
static

Definition at line 3466 of file pgbench.c.

3468 {
3469  /* send a sync */
3470  if (!PQpipelineSync(st->con))
3471  {
3472  pg_log_error("client %d aborted: failed to send a pipeline sync",
3473  st->id);
3474  return 0;
3475  }
3476 
3477  /* receive PGRES_PIPELINE_SYNC and null following it */
3478  for (;;)
3479  {
3480  PGresult *res = PQgetResult(st->con);
3481 
3483  {
3484  PQclear(res);
3485  res = PQgetResult(st->con);
3486  Assert(res == NULL);
3487  break;
3488  }
3489  PQclear(res);
3490  }
3491 
3492  /* exit pipeline */
3493  if (PQexitPipelineMode(st->con) != 1)
3494  {
3495  pg_log_error("client %d aborted: failed to exit pipeline mode for rolling back the failed transaction",
3496  st->id);
3497  return 0;
3498  }
3499  return 1;
int PQexitPipelineMode(PGconn *conn)
Definition: fe-exec.c:3039
int PQpipelineSync(PGconn *conn)
Definition: fe-exec.c:3226
@ PGRES_PIPELINE_SYNC
Definition: libpq-fe.h:111

References Assert(), CState::con, CState::id, pg_log_error, PGRES_PIPELINE_SYNC, PQclear(), PQexitPipelineMode(), PQgetResult(), PQpipelineSync(), PQresultStatus(), and res.

Referenced by advanceConnectionState().

◆ disconnect_all()

static void disconnect_all ( CState state,
int  length 
)
static

Definition at line 4671 of file pgbench.c.

4673 {
4674  int i;
4675 
4676  for (i = 0; i < length; i++)
4677  finishCon(&state[i]);

References finishCon(), and i.

Referenced by main(), and threadRun().

◆ doConnect()

static PGconn* doConnect ( void  )
static

Definition at line 1527 of file pgbench.c.

1529 {
1530  PGconn *conn;
1531  bool new_pass;
1532  static char *password = NULL;
1533 
1534  /*
1535  * Start the connection. Loop until we have a password if requested by
1536  * backend.
1537  */
1538  do
1539  {
1540 #define PARAMS_ARRAY_SIZE 7
1541 
1542  const char *keywords[PARAMS_ARRAY_SIZE];
1543  const char *values[PARAMS_ARRAY_SIZE];
1544 
1545  keywords[0] = "host";
1546  values[0] = pghost;
1547  keywords[1] = "port";
1548  values[1] = pgport;
1549  keywords[2] = "user";
1550  values[2] = username;
1551  keywords[3] = "password";
1552  values[3] = password;
1553  keywords[4] = "dbname";
1554  values[4] = dbName;
1555  keywords[5] = "fallback_application_name";
1556  values[5] = progname;
1557  keywords[6] = NULL;
1558  values[6] = NULL;
1559 
1560  new_pass = false;
1561 
1562  conn = PQconnectdbParams(keywords, values, true);
1563 
1564  if (!conn)
1565  {
1566  pg_log_error("connection to database \"%s\" failed", dbName);
1567  return NULL;
1568  }
1569 
1570  if (PQstatus(conn) == CONNECTION_BAD &&
1572  !password)
1573  {
1574  PQfinish(conn);
1575  password = simple_prompt("Password: ", false);
1576  new_pass = true;
1577  }
1578  } while (new_pass);
1579 
1580  /* check to see that the backend connection was successfully made */
1581  if (PQstatus(conn) == CONNECTION_BAD)
1582  {
1584  PQfinish(conn);
1585  return NULL;
1586  }
1587 
1588  return conn;
static Datum values[MAXATTR]
Definition: bootstrap.c:156
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:676
int PQconnectionNeedsPassword(const PGconn *conn)
Definition: fe-connect.c:7299
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:7195
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4602
@ CONNECTION_BAD
Definition: libpq-fe.h:61
#define PARAMS_ARRAY_SIZE
const char * pghost
Definition: pgbench.c:294
const char * username
Definition: pgbench.c:296
const char * progname
Definition: pgbench.c:299
const char * pgport
Definition: pgbench.c:295
const char * dbName
Definition: pgbench.c:297
char * simple_prompt(const char *prompt, bool echo)
Definition: sprompt.c:38
static char * password
Definition: streamutil.c:53
PGconn * conn
Definition: streamutil.c:54

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

◆ doLog()

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

Definition at line 4512 of file pgbench.c.

4515 {
4516  FILE *logfile = thread->logfile;
4518 
4519  Assert(use_log);
4520 
4521  /*
4522  * Skip the log entry if sampling is enabled and this row doesn't belong
4523  * to the random sample.
4524  */
4525  if (sample_rate != 0.0 &&
4527  return;
4528 
4529  /* should we aggregate the results or not? */
4530  if (agg_interval > 0)
4531  {
4533 
4534  /*
4535  * Loop until we reach the interval of the current moment, and print
4536  * any empty intervals in between (this may happen with very low tps,
4537  * e.g. --rate=0.1).
4538  */
4539 
4540  while ((next = agg->start_time + agg_interval * INT64CONST(1000000)) <= now)
4541  {
4542  double lag_sum = 0.0;
4543  double lag_sum2 = 0.0;
4544  double lag_min = 0.0;
4545  double lag_max = 0.0;
4546  int64 skipped = 0;
4547  int64 serialization_failures = 0;
4548  int64 deadlock_failures = 0;
4549  int64 retried = 0;
4550  int64 retries = 0;
4551 
4552  /* print aggregated report to logfile */
4553  fprintf(logfile, INT64_FORMAT " " INT64_FORMAT " %.0f %.0f %.0f %.0f",
4554  agg->start_time / 1000000, /* seconds since Unix epoch */
4555  agg->cnt,
4556  agg->latency.sum,
4557  agg->latency.sum2,
4558  agg->latency.min,
4559  agg->latency.max);
4560 
4561  if (throttle_delay)
4562  {
4563  lag_sum = agg->lag.sum;
4564  lag_sum2 = agg->lag.sum2;
4565  lag_min = agg->lag.min;
4566  lag_max = agg->lag.max;
4567  }
4568  fprintf(logfile, " %.0f %.0f %.0f %.0f",
4569  lag_sum,
4570  lag_sum2,
4571  lag_min,
4572  lag_max);
4573 
4574  if (latency_limit)
4575  skipped = agg->skipped;
4576  fprintf(logfile, " " INT64_FORMAT, skipped);
4577 
4578  if (max_tries != 1)
4579  {
4580  retried = agg->retried;
4581  retries = agg->retries;
4582  }
4583  fprintf(logfile, " " INT64_FORMAT " " INT64_FORMAT, retried, retries);
4584 
4585  if (failures_detailed)
4586  {
4587  serialization_failures = agg->serialization_failures;
4588  deadlock_failures = agg->deadlock_failures;
4589  }
4591  serialization_failures,
4592  deadlock_failures);
4593 
4594  fputc('\n', logfile);
4595 
4596  /* reset data and move to next interval */
4597  initStats(agg, next);
4598  }
4599 
4600  /* accumulate the current transaction */
4601  accumStats(agg, skipped, latency, lag, st->estatus, st->tries);
4602  }
4603  else
4604  {
4605  /* no, print raw transactions */
4606  if (!skipped && st->estatus == ESTATUS_NO_ERROR)
4607  fprintf(logfile, "%d " INT64_FORMAT " %.0f %d " INT64_FORMAT " "
4608  INT64_FORMAT,
4609  st->id, st->cnt, latency, st->use_file,
4610  now / 1000000, now % 1000000);
4611  else
4612  fprintf(logfile, "%d " INT64_FORMAT " %s %d " INT64_FORMAT " "
4613  INT64_FORMAT,
4614  st->id, st->cnt, getResultString(skipped, st->estatus),
4615  st->use_file, now / 1000000, now % 1000000);
4616 
4617  if (throttle_delay)
4618  fprintf(logfile, " %.0f", lag);
4619  if (max_tries != 1)
4620  fprintf(logfile, " %u", st->tries - 1);
4621  fputc('\n', logfile);
4622  }
static int32 next
Definition: blutils.c:219
static FILE * logfile
Definition: pg_regress.c:119
static void accumStats(StatsData *stats, bool skipped, double lat, double lag, EStatus estatus, int64 tries)
Definition: pgbench.c:1447
uint32 max_tries
Definition: pgbench.c:289
bool use_log
Definition: pgbench.c:256
int agg_interval
Definition: pgbench.c:258
static const char * getResultString(bool skipped, EStatus estatus)
Definition: pgbench.c:4481
static void initStats(StatsData *sd, pg_time_usec_t start)
Definition: pgbench.c:1430
double sample_rate
Definition: pgbench.c:197
bool failures_detailed
Definition: pgbench.c:291
pg_time_usec_t epoch_shift
Definition: pgbench.c:448
pg_time_usec_t start_time
Definition: pgbench.c:377
FILE * logfile
Definition: pgbench.c:660
pg_prng_state ts_sample_rs
Definition: pgbench.c:657

References accumStats(), agg_interval, Assert(), StatsData::cnt, CState::cnt, StatsData::deadlock_failures, epoch_shift, CState::estatus, ESTATUS_NO_ERROR, failures_detailed, fprintf, getResultString(), CState::id, initStats(), INT64_FORMAT, StatsData::lag, StatsData::latency, latency_limit, TState::logfile, logfile, SimpleStats::max, max_tries, SimpleStats::min, next, now(), pg_prng_double(), pg_time_now(), StatsData::retried, StatsData::retries, sample_rate, StatsData::serialization_failures, StatsData::skipped, StatsData::start_time, SimpleStats::sum, SimpleStats::sum2, throttle_delay, CState::tries, TState::ts_sample_rs, CState::use_file, and use_log.

Referenced by processXactStats(), and threadRun().

◆ doRetry()

static bool doRetry ( CState st,
pg_time_usec_t now 
)
static

Definition at line 3420 of file pgbench.c.

3422 {
3424 
3425  /* We can only retry serialization or deadlock errors. */
3426  if (!canRetryError(st->estatus))
3427  return false;
3428 
3429  /*
3430  * We must have at least one option to limit the retrying of transactions
3431  * that got an error.
3432  */
3434 
3435  /*
3436  * We cannot retry the error if we have reached the maximum number of
3437  * tries.
3438  */
3439  if (max_tries && st->tries >= max_tries)
3440  return false;
3441 
3442  /*
3443  * We cannot retry the error if we spent too much time on this
3444  * transaction.
3445  */
3446  if (latency_limit)
3447  {
3449  if (*now - st->txn_scheduled > latency_limit)
3450  return false;
3451  }
3452 
3453  /*
3454  * We cannot retry the error if the benchmark duration is over.
3455  */
3456  if (timer_exceeded)
3457  return false;
3458 
3459  /* OK */
3460  return true;

References Assert(), canRetryError(), duration, CState::estatus, ESTATUS_NO_ERROR, latency_limit, max_tries, now(), pg_time_now_lazy(), timer_exceeded, CState::tries, and CState::txn_scheduled.

Referenced by advanceConnectionState().

◆ enlargeVariables()

static void enlargeVariables ( Variables variables,
int  needed 
)
static

Definition at line 1769 of file pgbench.c.

1771 {
1772  /* total number of variables required now */
1773  needed += variables->nvars;
1774 
1775  if (variables->max_vars < needed)
1776  {
1777  variables->max_vars = needed + VARIABLES_ALLOC_MARGIN;
1778  variables->vars = (Variable *)
1779  pg_realloc(variables->vars, variables->max_vars * sizeof(Variable));
1780  }
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
#define VARIABLES_ALLOC_MARGIN
Definition: pgbench.c:309
Variable * vars
Definition: pgbench.c:333
int nvars
Definition: pgbench.c:334
int max_vars
Definition: pgbench.c:341

References Variables::max_vars, Variables::nvars, pg_realloc(), VARIABLES_ALLOC_MARGIN, and Variables::vars.

Referenced by lookupCreateVariable().

◆ evalFunc()

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

Definition at line 2817 of file pgbench.c.

2820 {
2821  if (isLazyFunc(func))
2822  return evalLazyFunc(st, func, args, retval);
2823  else
2824  return evalStandardFunc(st, func, args, retval);
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:2121
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2128
static bool evalStandardFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2245

References generate_unaccent_rules::args, evalLazyFunc(), evalStandardFunc(), and isLazyFunc().

Referenced by evaluateExpr().

◆ evalLazyFunc()

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

Definition at line 2128 of file pgbench.c.

2131 {
2132  PgBenchValue a1,
2133  a2;
2134  bool ba1,
2135  ba2;
2136 
2137  Assert(isLazyFunc(func) && args != NULL && args->next != NULL);
2138 
2139  /* args points to first condition */
2140  if (!evaluateExpr(st, args->expr, &a1))
2141  return false;
2142 
2143  /* second condition for AND/OR and corresponding branch for CASE */
2144  args = args->next;
2145 
2146  switch (func)
2147  {
2148  case PGBENCH_AND:
2149  if (a1.type == PGBT_NULL)
2150  {
2151  setNullValue(retval);
2152  return true;
2153  }
2154 
2155  if (!coerceToBool(&a1, &ba1))
2156  return false;
2157 
2158  if (!ba1)
2159  {
2160  setBoolValue(retval, false);
2161  return true;
2162  }
2163 
2164  if (!evaluateExpr(st, args->expr, &a2))
2165  return false;
2166 
2167  if (a2.type == PGBT_NULL)
2168  {
2169  setNullValue(retval);
2170  return true;
2171  }
2172  else if (!coerceToBool(&a2, &ba2))
2173  return false;
2174  else
2175  {
2176  setBoolValue(retval, ba2);
2177  return true;
2178  }
2179 
2180  return true;
2181 
2182  case PGBENCH_OR:
2183 
2184  if (a1.type == PGBT_NULL)
2185  {
2186  setNullValue(retval);
2187  return true;
2188  }
2189 
2190  if (!coerceToBool(&a1, &ba1))
2191  return false;
2192 
2193  if (ba1)
2194  {
2195  setBoolValue(retval, true);
2196  return true;
2197  }
2198 
2199  if (!evaluateExpr(st, args->expr, &a2))
2200  return false;
2201 
2202  if (a2.type == PGBT_NULL)
2203  {
2204  setNullValue(retval);
2205  return true;
2206  }
2207  else if (!coerceToBool(&a2, &ba2))
2208  return false;
2209  else
2210  {
2211  setBoolValue(retval, ba2);
2212  return true;
2213  }
2214 
2215  case PGBENCH_CASE:
2216  /* when true, execute branch */
2217  if (valueTruth(&a1))
2218  return evaluateExpr(st, args->expr, retval);
2219 
2220  /* now args contains next condition or final else expression */
2221  args = args->next;
2222 
2223  /* final else case? */
2224  if (args->next == NULL)
2225  return evaluateExpr(st, args->expr, retval);
2226 
2227  /* no, another when, proceed */
2228  return evalLazyFunc(st, PGBENCH_CASE, args, retval);
2229 
2230  default:
2231  /* internal error, cannot get here */
2232  Assert(0);
2233  break;
2234  }
2235  return false;
static const FormData_pg_attribute a1
Definition: heap.c:141
static const FormData_pg_attribute a2
Definition: heap.c:155
static void setNullValue(PgBenchValue *pv)
Definition: pgbench.c:2090
static bool evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
Definition: pgbench.c:2833
static void setBoolValue(PgBenchValue *pv, bool bval)
Definition: pgbench.c:2098
static bool valueTruth(PgBenchValue *pval)
Definition: pgbench.c:2020
static bool coerceToBool(PgBenchValue *pval, bool *bval)
Definition: pgbench.c:2000
@ PGBT_NULL
Definition: pgbench.h:37
@ PGBENCH_AND
Definition: pgbench.h:87
@ PGBENCH_OR
Definition: pgbench.h:88
@ PGBENCH_CASE
Definition: pgbench.h:100

References a1, a2, generate_unaccent_rules::args, Assert(), coerceToBool(), evaluateExpr(), isLazyFunc(), PGBENCH_AND, PGBENCH_CASE, PGBENCH_OR, PGBT_NULL, setBoolValue(), setNullValue(), and valueTruth().

Referenced by evalFunc().

◆ evalStandardFunc()

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

Definition at line 2245 of file pgbench.c.

2249 {
2250  /* evaluate all function arguments */
2251  int nargs = 0;
2252  PgBenchExprLink *l = args;
2253  bool has_null = false;
2254 
2255  /*
2256  * This value is double braced to workaround GCC bug 53119, which seems to
2257  * exist at least on gcc (Debian 4.7.2-5) 4.7.2, 32-bit.
2258  */
2259  PgBenchValue vargs[MAX_FARGS] = {{0}};
2260 
2261  for (nargs = 0; nargs < MAX_FARGS && l != NULL; nargs++, l = l->next)
2262  {
2263  if (!evaluateExpr(st, l->expr, &vargs[nargs]))
2264  return false;
2265  has_null |= vargs[nargs].type == PGBT_NULL;
2266  }
2267 
2268  if (l != NULL)
2269  {
2270  pg_log_error("too many function arguments, maximum is %d", MAX_FARGS);
2271  return false;
2272  }
2273 
2274  /* NULL arguments */
2275  if (has_null && func != PGBENCH_IS && func != PGBENCH_DEBUG)
2276  {
2277  setNullValue(retval);
2278  return true;
2279  }
2280 
2281  /* then evaluate function */
2282  switch (func)
2283  {
2284  /* overloaded operators */
2285  case PGBENCH_ADD:
2286  case PGBENCH_SUB:
2287  case PGBENCH_MUL:
2288  case PGBENCH_DIV:
2289  case PGBENCH_MOD:
2290  case PGBENCH_EQ:
2291  case PGBENCH_NE:
2292  case PGBENCH_LE:
2293  case PGBENCH_LT:
2294  {
2295  PgBenchValue *lval = &vargs[0],
2296  *rval = &vargs[1];
2297 
2298  Assert(nargs == 2);
2299 
2300  /* overloaded type management, double if some double */
2301  if ((lval->type == PGBT_DOUBLE ||
2302  rval->type == PGBT_DOUBLE) && func != PGBENCH_MOD)
2303  {
2304  double ld,
2305  rd;
2306 
2307  if (!coerceToDouble(lval, &ld) ||
2308  !coerceToDouble(rval, &rd))
2309  return false;
2310 
2311  switch (func)
2312  {
2313  case PGBENCH_ADD:
2314  setDoubleValue(retval, ld + rd);
2315  return true;
2316 
2317  case PGBENCH_SUB:
2318  setDoubleValue(retval, ld - rd);
2319  return true;
2320 
2321  case PGBENCH_MUL:
2322  setDoubleValue(retval, ld * rd);
2323  return true;
2324 
2325  case PGBENCH_DIV:
2326  setDoubleValue(retval, ld / rd);
2327  return true;
2328 
2329  case PGBENCH_EQ:
2330  setBoolValue(retval, ld == rd);
2331  return true;
2332 
2333  case PGBENCH_NE:
2334  setBoolValue(retval, ld != rd);
2335  return true;
2336 
2337  case PGBENCH_LE:
2338  setBoolValue(retval, ld <= rd);
2339  return true;
2340 
2341  case PGBENCH_LT:
2342  setBoolValue(retval, ld < rd);
2343  return true;
2344 
2345  default:
2346  /* cannot get here */
2347  Assert(0);
2348  }
2349  }
2350  else /* we have integer operands, or % */
2351  {
2352  int64 li,
2353  ri,
2354  res;
2355 
2356  if (!coerceToInt(lval, &li) ||
2357  !coerceToInt(rval, &ri))
2358  return false;
2359 
2360  switch (func)
2361  {
2362  case PGBENCH_ADD:
2363  if (pg_add_s64_overflow(li, ri, &res))
2364  {
2365  pg_log_error("bigint add out of range");
2366  return false;
2367  }
2368  setIntValue(retval, res);
2369  return true;
2370 
2371  case PGBENCH_SUB:
2372  if (pg_sub_s64_overflow(li, ri, &res))
2373  {
2374  pg_log_error("bigint sub out of range");
2375  return false;
2376  }
2377  setIntValue(retval, res);
2378  return true;
2379 
2380  case PGBENCH_MUL:
2381  if (pg_mul_s64_overflow(li, ri, &res))
2382  {
2383  pg_log_error("bigint mul out of range");
2384  return false;
2385  }
2386  setIntValue(retval, res);
2387  return true;
2388 
2389  case PGBENCH_EQ:
2390  setBoolValue(retval, li == ri);
2391  return true;
2392 
2393  case PGBENCH_NE:
2394  setBoolValue(retval, li != ri);
2395  return true;
2396 
2397  case PGBENCH_LE:
2398  setBoolValue(retval, li <= ri);
2399  return true;
2400 
2401  case PGBENCH_LT:
2402  setBoolValue(retval, li < ri);
2403  return true;
2404 
2405  case PGBENCH_DIV:
2406  case PGBENCH_MOD:
2407  if (ri == 0)
2408  {
2409  pg_log_error("division by zero");
2410  return false;
2411  }
2412  /* special handling of -1 divisor */
2413  if (ri == -1)
2414  {
2415  if (func == PGBENCH_DIV)
2416  {
2417  /* overflow check (needed for INT64_MIN) */
2418  if (li == PG_INT64_MIN)
2419  {
2420  pg_log_error("bigint div out of range");
2421  return false;
2422  }
2423  else
2424  setIntValue(retval, -li);
2425  }
2426  else
2427  setIntValue(retval, 0);
2428  return true;
2429  }
2430  /* else divisor is not -1 */
2431  if (func == PGBENCH_DIV)
2432  setIntValue(retval, li / ri);
2433  else /* func == PGBENCH_MOD */
2434  setIntValue(retval, li % ri);
2435 
2436  return true;
2437 
2438  default:
2439  /* cannot get here */
2440  Assert(0);
2441  }
2442  }
2443 
2444  Assert(0);
2445  return false; /* NOTREACHED */
2446  }
2447 
2448  /* integer bitwise operators */
2449  case PGBENCH_BITAND:
2450  case PGBENCH_BITOR:
2451  case PGBENCH_BITXOR:
2452  case PGBENCH_LSHIFT:
2453  case PGBENCH_RSHIFT:
2454  {
2455  int64 li,
2456  ri;
2457 
2458  if (!coerceToInt(&vargs[0], &li) || !coerceToInt(&vargs[1], &ri))
2459  return false;
2460 
2461  if (func == PGBENCH_BITAND)
2462  setIntValue(retval, li & ri);
2463  else if (func == PGBENCH_BITOR)
2464  setIntValue(retval, li | ri);
2465  else if (func == PGBENCH_BITXOR)
2466  setIntValue(retval, li ^ ri);
2467  else if (func == PGBENCH_LSHIFT)
2468  setIntValue(retval, li << ri);
2469  else if (func == PGBENCH_RSHIFT)
2470  setIntValue(retval, li >> ri);
2471  else /* cannot get here */
2472  Assert(0);
2473 
2474  return true;
2475  }
2476 
2477  /* logical operators */
2478  case PGBENCH_NOT:
2479  {
2480  bool b;
2481 
2482  if (!coerceToBool(&vargs[0], &b))
2483  return false;
2484 
2485  setBoolValue(retval, !b);
2486  return true;
2487  }
2488 
2489  /* no arguments */
2490  case PGBENCH_PI:
2491  setDoubleValue(retval, M_PI);
2492  return true;
2493 
2494  /* 1 overloaded argument */
2495  case PGBENCH_ABS:
2496  {
2497  PgBenchValue *varg = &vargs[0];
2498 
2499  Assert(nargs == 1);
2500 
2501  if (varg->type == PGBT_INT)
2502  {
2503  int64 i = varg->u.ival;
2504 
2505  setIntValue(retval, i < 0 ? -i : i);
2506  }
2507  else
2508  {
2509  double d = varg->u.dval;
2510 
2511  Assert(varg->type == PGBT_DOUBLE);
2512  setDoubleValue(retval, d < 0.0 ? -d : d);
2513  }
2514 
2515  return true;
2516  }
2517 
2518  case PGBENCH_DEBUG:
2519  {
2520  PgBenchValue *varg = &vargs[0];
2521 
2522  Assert(nargs == 1);
2523 
2524  fprintf(stderr, "debug(script=%d,command=%d): ",
2525  st->use_file, st->command + 1);
2526 
2527  if (varg->type == PGBT_NULL)
2528  fprintf(stderr, "null\n");
2529  else if (varg->type == PGBT_BOOLEAN)
2530  fprintf(stderr, "boolean %s\n", varg->u.bval ? "true" : "false");
2531  else if (varg->type == PGBT_INT)
2532  fprintf(stderr, "int " INT64_FORMAT "\n", varg->u.ival);
2533  else if (varg->type == PGBT_DOUBLE)
2534  fprintf(stderr, "double %.*g\n", DBL_DIG, varg->u.dval);
2535  else /* internal error, unexpected type */
2536  Assert(0);
2537 
2538  *retval = *varg;
2539 
2540  return true;
2541  }
2542 
2543  /* 1 double argument */
2544  case PGBENCH_DOUBLE:
2545  case PGBENCH_SQRT:
2546  case PGBENCH_LN:
2547  case PGBENCH_EXP:
2548  {
2549  double dval;
2550 
2551  Assert(nargs == 1);
2552 
2553  if (!coerceToDouble(&vargs[0], &dval))
2554  return false;
2555 
2556  if (func == PGBENCH_SQRT)
2557  dval = sqrt(dval);
2558  else if (func == PGBENCH_LN)
2559  dval = log(dval);
2560  else if (func == PGBENCH_EXP)
2561  dval = exp(dval);
2562  /* else is cast: do nothing */
2563 
2564  setDoubleValue(retval, dval);
2565  return true;
2566  }
2567 
2568  /* 1 int argument */
2569  case PGBENCH_INT:
2570  {
2571  int64 ival;
2572 
2573  Assert(nargs == 1);
2574 
2575  if (!coerceToInt(&vargs[0], &ival))
2576  return false;
2577 
2578  setIntValue(retval, ival);
2579  return true;
2580  }
2581 
2582  /* variable number of arguments */
2583  case PGBENCH_LEAST:
2584  case PGBENCH_GREATEST:
2585  {
2586  bool havedouble;
2587  int i;
2588 
2589  Assert(nargs >= 1);
2590 
2591  /* need double result if any input is double */
2592  havedouble = false;
2593  for (i = 0; i < nargs; i++)
2594  {
2595  if (vargs[i].type == PGBT_DOUBLE)
2596  {
2597  havedouble = true;
2598  break;
2599  }
2600  }
2601  if (havedouble)
2602  {
2603  double extremum;
2604 
2605  if (!coerceToDouble(&vargs[0], &extremum))
2606  return false;
2607  for (i = 1; i < nargs; i++)
2608  {
2609  double dval;
2610 
2611  if (!coerceToDouble(&vargs[i], &dval))
2612  return false;
2613  if (func == PGBENCH_LEAST)
2614  extremum = Min(extremum, dval);
2615  else
2616  extremum = Max(extremum, dval);
2617  }
2618  setDoubleValue(retval, extremum);
2619  }
2620  else
2621  {
2622  int64 extremum;
2623 
2624  if (!coerceToInt(&vargs[0], &extremum))
2625  return false;
2626  for (i = 1; i < nargs; i++)
2627  {
2628  int64 ival;
2629 
2630  if (!coerceToInt(&vargs[i], &ival))
2631  return false;
2632  if (func == PGBENCH_LEAST)
2633  extremum = Min(extremum, ival);
2634  else
2635  extremum = Max(extremum, ival);
2636  }
2637  setIntValue(retval, extremum);
2638  }
2639  return true;
2640  }
2641 
2642  /* random functions */
2643  case PGBENCH_RANDOM:
2647  {
2648  int64 imin,
2649  imax,
2650  delta;
2651 
2652  Assert(nargs >= 2);
2653 
2654  if (!coerceToInt(&vargs[0], &imin) ||
2655  !coerceToInt(&vargs[1], &imax))
2656  return false;
2657 
2658  /* check random range */
2659  if (unlikely(imin > imax))
2660  {
2661  pg_log_error("empty range given to random");
2662  return false;
2663  }
2664  else if (unlikely(pg_sub_s64_overflow(imax, imin, &delta) ||
2665  pg_add_s64_overflow(delta, 1, &delta)))
2666  {
2667  /* prevent int overflows in random functions */
2668  pg_log_error("random range is too large");
2669  return false;
2670  }
2671 
2672  if (func == PGBENCH_RANDOM)
2673  {
2674  Assert(nargs == 2);
2675  setIntValue(retval, getrand(&st->cs_func_rs, imin, imax));
2676  }
2677  else /* gaussian & exponential */
2678  {
2679  double param;
2680 
2681  Assert(nargs == 3);
2682 
2683  if (!coerceToDouble(&vargs[2], &param))
2684  return false;
2685 
2686  if (func == PGBENCH_RANDOM_GAUSSIAN)
2687  {
2688  if (param < MIN_GAUSSIAN_PARAM)
2689  {
2690  pg_log_error("gaussian parameter must be at least %f (not %f)",
2691  MIN_GAUSSIAN_PARAM, param);
2692  return false;
2693  }
2694 
2695  setIntValue(retval,
2697  imin, imax, param));
2698  }
2699  else if (func == PGBENCH_RANDOM_ZIPFIAN)
2700  {
2701  if (param < MIN_ZIPFIAN_PARAM || param > MAX_ZIPFIAN_PARAM)
2702  {
2703  pg_log_error("zipfian parameter must be in range [%.3f, %.0f] (not %f)",
2705  return false;
2706  }
2707 
2708  setIntValue(retval,
2709  getZipfianRand(&st->cs_func_rs, imin, imax, param));
2710  }
2711  else /* exponential */
2712  {
2713  if (param <= 0.0)
2714  {
2715  pg_log_error("exponential parameter must be greater than zero (not %f)",
2716  param);
2717  return false;
2718  }
2719 
2720  setIntValue(retval,
2722  imin, imax, param));
2723  }
2724  }
2725 
2726  return true;
2727  }
2728 
2729  case PGBENCH_POW:
2730  {
2731  PgBenchValue *lval = &vargs[0];
2732  PgBenchValue *rval = &vargs[1];
2733  double ld,
2734  rd;
2735 
2736  Assert(nargs == 2);
2737 
2738  if (!coerceToDouble(lval, &ld) ||
2739  !coerceToDouble(rval, &rd))
2740  return false;
2741 
2742  setDoubleValue(retval, pow(ld, rd));
2743 
2744  return true;
2745  }
2746 
2747  case PGBENCH_IS:
2748  {
2749  Assert(nargs == 2);
2750 
2751  /*
2752  * note: this simple implementation is more permissive than
2753  * SQL
2754  */
2755  setBoolValue(retval,
2756  vargs[0].type == vargs[1].type &&
2757  vargs[0].u.bval == vargs[1].u.bval);
2758  return true;
2759  }
2760 
2761  /* hashing */
2762  case PGBENCH_HASH_FNV1A:
2763  case PGBENCH_HASH_MURMUR2:
2764  {
2765  int64 val,
2766  seed;
2767 
2768  Assert(nargs == 2);
2769 
2770  if (!coerceToInt(&vargs[0], &val) ||
2771  !coerceToInt(&vargs[1], &seed))
2772  return false;
2773 
2774  if (func == PGBENCH_HASH_MURMUR2)
2775  setIntValue(retval, getHashMurmur2(val, seed));
2776  else if (func == PGBENCH_HASH_FNV1A)
2777  setIntValue(retval, getHashFnv1a(val, seed));
2778  else
2779  /* cannot get here */
2780  Assert(0);
2781 
2782  return true;
2783  }
2784 
2785  case PGBENCH_PERMUTE:
2786  {
2787  int64 val,
2788  size,
2789  seed;
2790 
2791  Assert(nargs == 3);
2792 
2793  if (!coerceToInt(&vargs[0], &val) ||
2794  !coerceToInt(&vargs[1], &size) ||
2795  !coerceToInt(&vargs[2], &seed))
2796  return false;
2797 
2798  if (size <= 0)
2799  {
2800  pg_log_error("permute size parameter must be greater than zero");
2801  return false;
2802  }
2803 
2804  setIntValue(retval, permute(val, size, seed));
2805  return true;
2806  }
2807 
2808  default:
2809  /* cannot get here */
2810  Assert(0);
2811  /* dead code to avoid a compiler warning */
2812  return false;
2813  }
#define Min(x, y)
Definition: c.h:993
#define Max(x, y)
Definition: c.h:987
#define PG_INT64_MIN
Definition: c.h:580
#define unlikely(x)
Definition: c.h:300
static bool pg_mul_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:215
static bool pg_sub_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:188
static bool pg_add_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:161
static int64 getZipfianRand(pg_prng_state *state, int64 min, int64 max, double s)
Definition: pgbench.c:1227
static void setIntValue(PgBenchValue *pv, int64 ival)
Definition: pgbench.c:2106
static bool coerceToInt(PgBenchValue *pval, int64 *ival)
Definition: pgbench.c:2041
static int64 getExponentialRand(pg_prng_state *state, int64 min, int64 max, double parameter)
Definition: pgbench.c:1109
static void setDoubleValue(PgBenchValue *pv, double dval)
Definition: pgbench.c:2114
#define MIN_ZIPFIAN_PARAM
Definition: pgbench.c:170
static int64 permute(const int64 val, const int64 isize, const int64 seed)
Definition: pgbench.c:1299
#define MAX_FARGS
Definition: pgbench.c:2238
static int64 getHashMurmur2(int64 val, uint64 seed)
Definition: pgbench.c:1266
static int64 getGaussianRand(pg_prng_state *state, int64 min, int64 max, double parameter)
Definition: pgbench.c:1133
#define MIN_GAUSSIAN_PARAM
Definition: pgbench.c:168
#define M_PI
Definition: pgbench.c:73
static int64 getHashFnv1a(int64 val, uint64 seed)
Definition: pgbench.c:1241
static bool coerceToDouble(PgBenchValue *pval, double *dval)
Definition: pgbench.c:2069
#define MAX_ZIPFIAN_PARAM
Definition: pgbench.c:171
@ PGBENCH_DIV
Definition: pgbench.h:70
@ PGBENCH_DOUBLE
Definition: pgbench.h:77
@ PGBENCH_LT
Definition: pgbench.h:98
@ PGBENCH_LN
Definition: pgbench.h:80
@ PGBENCH_RANDOM_EXPONENTIAL
Definition: pgbench.h:84
@ PGBENCH_RSHIFT
Definition: pgbench.h:94
@ PGBENCH_DEBUG
Definition: pgbench.h:72
@ PGBENCH_MOD
Definition: pgbench.h:71
@ PGBENCH_GREATEST
Definition: pgbench.h:75
@ PGBENCH_BITXOR
Definition: pgbench.h:92
@ PGBENCH_RANDOM_ZIPFIAN
Definition: pgbench.h:85
@ PGBENCH_INT
Definition: pgbench.h:76
@ PGBENCH_NE
Definition: pgbench.h:96
@ PGBENCH_LE
Definition: pgbench.h:97
@ PGBENCH_EXP
Definition: pgbench.h:81
@ PGBENCH_PI
Definition: pgbench.h:78
@ PGBENCH_ADD
Definition: pgbench.h:67
@ PGBENCH_EQ
Definition: pgbench.h:95
@ PGBENCH_LSHIFT
Definition: pgbench.h:93
@ PGBENCH_RANDOM
Definition: pgbench.h:82
@ PGBENCH_POW
Definition: pgbench.h:86
@ PGBENCH_IS
Definition: pgbench.h:99
@ PGBENCH_SUB
Definition: pgbench.h:68
@ PGBENCH_HASH_MURMUR2
Definition: pgbench.h:102
@ PGBENCH_ABS
Definition: pgbench.h:73
@ PGBENCH_BITOR
Definition: pgbench.h:91
@ PGBENCH_SQRT
Definition: pgbench.h:79
@ PGBENCH_LEAST
Definition: pgbench.h:74
@ PGBENCH_PERMUTE
Definition: pgbench.h:103
@ PGBENCH_HASH_FNV1A
Definition: pgbench.h:101
@ PGBENCH_NOT
Definition: pgbench.h:89
@ PGBENCH_BITAND
Definition: pgbench.h:90
@ PGBENCH_RANDOM_GAUSSIAN
Definition: pgbench.h:83
@ PGBENCH_MUL
Definition: pgbench.h:69
const char * type

References generate_unaccent_rules::args, Assert(), b, PgBenchValue::bval, coerceToBool(), coerceToDouble(), coerceToInt(), CState::command, CState::cs_func_rs, PgBenchValue::dval, evaluateExpr(), PgBenchExprLink::expr, 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, res, setBoolValue(), setDoubleValue(), setIntValue(), setNullValue(), type, PgBenchValue::type, PgBenchValue::u, unlikely, CState::use_file, and val.

Referenced by evalFunc().

◆ evaluateExpr()

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

Definition at line 2833 of file pgbench.c.

2835 {
2836  switch (expr->etype)
2837  {
2838  case ENODE_CONSTANT:
2839  {
2840  *retval = expr->u.constant;
2841  return true;
2842  }
2843 
2844  case ENODE_VARIABLE:
2845  {
2846  Variable *var;
2847 
2848  if ((var = lookupVariable(&st->variables, expr->u.variable.varname)) == NULL)
2849  {
2850  pg_log_error("undefined variable \"%s\"", expr->u.variable.varname);
2851  return false;
2852  }
2853 
2854  if (!makeVariableValue(var))
2855  return false;
2856 
2857  *retval = var->value;
2858  return true;
2859  }
2860 
2861  case ENODE_FUNCTION:
2862  return evalFunc(st,
2863  expr->u.function.function,
2864  expr->u.function.args,
2865  retval);
2866 
2867  default:
2868  /* internal error which should never occur */
2869  pg_fatal("unexpected enode type in evaluation: %d", expr->etype);
2870  }
static Variable * lookupVariable(Variables *variables, char *name)
Definition: pgbench.c:1600
static bool evalFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2817
static bool makeVariableValue(Variable *var)
Definition: pgbench.c:1660
@ ENODE_VARIABLE
Definition: pgbench.h:60
@ ENODE_CONSTANT
Definition: pgbench.h:59
@ ENODE_FUNCTION
Definition: pgbench.h:61
Variables variables
Definition: pgbench.c:612
PgBenchValue constant
Definition: pgbench.h:115
PgBenchFunction function
Definition: pgbench.h:122
PgBenchExprType etype
Definition: pgbench.h:112
struct PgBenchExpr::@34::@35 variable
union PgBenchExpr::@34 u
PgBenchValue value
Definition: pgbench.c:325

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

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

◆ evaluateSleep()

static bool evaluateSleep ( Variables variables,
int  argc,
char **  argv,
int *  usecs 
)
static

Definition at line 3375 of file pgbench.c.

3377 {
3378  char *var;
3379  int usec;
3380 
3381  if (*argv[1] == ':')
3382  {
3383  if ((var = getVariable(variables, argv[1] + 1)) == NULL)
3384  {
3385  pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[1] + 1);
3386  return false;
3387  }
3388 
3389  usec = atoi(var);
3390 
3391  /* Raise an error if the value of a variable is not a number */
3392  if (usec == 0 && !isdigit((unsigned char) *var))
3393  {
3394  pg_log_error("%s: invalid sleep time \"%s\" for variable \"%s\"",
3395  argv[0], var, argv[1] + 1);
3396  return false;
3397  }
3398  }
3399  else
3400  usec = atoi(argv[1]);
3401 
3402  if (argc > 2)
3403  {
3404  if (pg_strcasecmp(argv[2], "ms") == 0)
3405  usec *= 1000;
3406  else if (pg_strcasecmp(argv[2], "s") == 0)
3407  usec *= 1000000;
3408  }
3409  else
3410  usec *= 1000000;
3411 
3412  *usecs = usec;
3413  return true;
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36

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

Referenced by executeMetaCommand().

◆ executeMetaCommand()

static ConnectionStateEnum executeMetaCommand ( CState st,
pg_time_usec_t now 
)
static

Definition at line 4266 of file pgbench.c.

4268 {
4269  Command *command = sql_script[st->use_file].commands[st->command];
4270  int argc;
4271  char **argv;
4272 
4273  Assert(command != NULL && command->type == META_COMMAND);
4274 
4275  argc = command->argc;
4276  argv = command->argv;
4277 
4279  {
4281 
4282  initPQExpBuffer(&buf);
4283 
4284  printfPQExpBuffer(&buf, "client %d executing \\%s", st->id, argv[0]);
4285  for (int i = 1; i < argc; i++)
4286  appendPQExpBuffer(&buf, " %s", argv[i]);
4287 
4288  pg_log_debug("%s", buf.data);
4289 
4290  termPQExpBuffer(&buf);
4291  }
4292 
4293  if (command->meta == META_SLEEP)
4294  {
4295  int usec;
4296 
4297  /*
4298  * A \sleep doesn't execute anything, we just get the delay from the
4299  * argument, and enter the CSTATE_SLEEP state. (The per-command
4300  * latency will be recorded in CSTATE_SLEEP state, not here, after the
4301  * delay has elapsed.)
4302  */
4303  if (!evaluateSleep(&st->variables, argc, argv, &usec))
4304  {
4305  commandFailed(st, "sleep", "execution of meta-command failed");
4306  return CSTATE_ABORTED;
4307  }
4308 
4310  st->sleep_until = (*now) + usec;
4311  return CSTATE_SLEEP;
4312  }
4313  else if (command->meta == META_SET)
4314  {
4315  PgBenchExpr *expr = command->expr;
4316  PgBenchValue result;
4317 
4318  if (!evaluateExpr(st, expr, &result))
4319  {
4320  commandFailed(st, argv[0], "evaluation of meta-command failed");
4321  return CSTATE_ABORTED;
4322  }
4323 
4324  if (!putVariableValue(&st->variables, argv[0], argv[1], &result))
4325  {
4326  commandFailed(st, "set", "assignment of meta-command failed");
4327  return CSTATE_ABORTED;
4328  }
4329  }
4330  else if (command->meta == META_IF)
4331  {
4332  /* backslash commands with an expression to evaluate */
4333  PgBenchExpr *expr = command->expr;
4334  PgBenchValue result;
4335  bool cond;
4336 
4337  if (!evaluateExpr(st, expr, &result))
4338  {
4339  commandFailed(st, argv[0], "evaluation of meta-command failed");
4340  return CSTATE_ABORTED;
4341  }
4342 
4343  cond = valueTruth(&result);
4345  }
4346  else if (command->meta == META_ELIF)
4347  {
4348  /* backslash commands with an expression to evaluate */
4349  PgBenchExpr *expr = command->expr;
4350  PgBenchValue result;
4351  bool cond;
4352 
4354  {
4355  /* elif after executed block, skip eval and wait for endif. */
4357  return CSTATE_END_COMMAND;
4358  }
4359 
4360  if (!evaluateExpr(st, expr, &result))
4361  {
4362  commandFailed(st, argv[0], "evaluation of meta-command failed");
4363  return CSTATE_ABORTED;
4364  }
4365 
4366  cond = valueTruth(&result);
4369  }
4370  else if (command->meta == META_ELSE)
4371  {
4372  switch (conditional_stack_peek(st->cstack))
4373  {
4374  case IFSTATE_TRUE:
4376  break;
4377  case IFSTATE_FALSE: /* inconsistent if active */
4378  case IFSTATE_IGNORED: /* inconsistent if active */
4379  case IFSTATE_NONE: /* else without if */
4380  case IFSTATE_ELSE_TRUE: /* else after else */
4381  case IFSTATE_ELSE_FALSE: /* else after else */
4382  default:
4383  /* dead code if conditional check is ok */
4384  Assert(false);
4385  }
4386  }
4387  else if (command->meta == META_ENDIF)
4388  {
4391  }
4392  else if (command->meta == META_SETSHELL)
4393  {
4394  if (!runShellCommand(&st->variables, argv[1], argv + 2, argc - 2))
4395  {
4396  commandFailed(st, "setshell", "execution of meta-command failed");
4397  return CSTATE_ABORTED;
4398  }
4399  }
4400  else if (command->meta == META_SHELL)
4401  {
4402  if (!runShellCommand(&st->variables, NULL, argv + 1, argc - 1))
4403  {
4404  commandFailed(st, "shell", "execution of meta-command failed");
4405  return CSTATE_ABORTED;
4406  }
4407  }
4408  else if (command->meta == META_STARTPIPELINE)
4409  {
4410  /*
4411  * In pipeline mode, we use a workflow based on libpq pipeline
4412  * functions.
4413  */
4414  if (querymode == QUERY_SIMPLE)
4415  {
4416  commandFailed(st, "startpipeline", "cannot use pipeline mode with the simple query protocol");
4417  return CSTATE_ABORTED;
4418  }
4419 
4420  /*
4421  * If we're in prepared-query mode, we need to prepare all the
4422  * commands that are inside the pipeline before we actually start the
4423  * pipeline itself. This solves the problem that running BEGIN
4424  * ISOLATION LEVEL SERIALIZABLE in a pipeline would fail due to a
4425  * snapshot having been acquired by the prepare within the pipeline.
4426  */
4427  if (querymode == QUERY_PREPARED)
4429 
4430  if (PQpipelineStatus(st->con) != PQ_PIPELINE_OFF)
4431  {
4432  commandFailed(st, "startpipeline", "already in pipeline mode");
4433  return CSTATE_ABORTED;
4434  }
4435  if (PQenterPipelineMode(st->con) == 0)
4436  {
4437  commandFailed(st, "startpipeline", "failed to enter pipeline mode");
4438  return CSTATE_ABORTED;
4439  }
4440  }
4441  else if (command->meta == META_ENDPIPELINE)
4442  {
4443  if (PQpipelineStatus(st->con) != PQ_PIPELINE_ON)
4444  {
4445  commandFailed(st, "endpipeline", "not in pipeline mode");
4446  return CSTATE_ABORTED;
4447  }
4448  if (!PQpipelineSync(st->con))
4449  {
4450  commandFailed(st, "endpipeline", "failed to send a pipeline sync");
4451  return CSTATE_ABORTED;
4452  }
4453  /* Now wait for the PGRES_PIPELINE_SYNC and exit pipeline mode there */
4454  /* collect pending results before getting out of pipeline mode */
4455  return CSTATE_WAIT_RESULT;
4456  }
4457 
4458  /*
4459  * executing the expression or shell command might have taken a
4460  * non-negligible amount of time, so reset 'now'
4461  */
4462  *now = 0;
4463 
4464  return CSTATE_END_COMMAND;
int PQenterPipelineMode(PGconn *conn)
Definition: fe-exec.c:3008
enum pg_log_level __pg_log_level
Definition: logging.c:21
@ PG_LOG_DEBUG
Definition: logging.h:26
static QueryMode querymode
Definition: pgbench.c:710
static void prepareCommandsInPipeline(CState *st)
Definition: pgbench.c:3116
static bool runShellCommand(Variables *variables, char *variable, char **argv, int argc)
Definition: pgbench.c:2916
static bool evaluateSleep(Variables *variables, int argc, char **argv, int *usecs)
Definition: pgbench.c:3375
static bool putVariableValue(Variables *variables, const char *context, char *name, const PgBenchValue *value)
Definition: pgbench.c:1848
pg_time_usec_t sleep_until
Definition: pgbench.c:616

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, 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, now(), PG_LOG_DEBUG, pg_log_debug, pg_time_now_lazy(), PQ_PIPELINE_OFF, PQ_PIPELINE_ON, PQenterPipelineMode(), PQpipelineStatus(), PQpipelineSync(), prepareCommandsInPipeline(), printfPQExpBuffer(), putVariableValue(), QUERY_PREPARED, QUERY_SIMPLE, querymode, runShellCommand(), CState::sleep_until, sql_script, termPQExpBuffer(), Command::type, unlikely, CState::use_file, valueTruth(), and CState::variables.

Referenced by advanceConnectionState().

◆ executeStatement()

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

Definition at line 1496 of file pgbench.c.

1498 {
1499  PGresult *res;
1500 
1501  res = PQexec(con, sql);
1503  {
1504  pg_log_error("query failed: %s", PQerrorMessage(con));
1505  pg_log_error_detail("Query was: %s", sql);
1506  exit(1);
1507  }
1508  PQclear(res);
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2228

References exit(), pg_log_error, pg_log_error_detail, PGRES_COMMAND_OK, PQclear(), PQerrorMessage(), PQexec(), PQresultStatus(), and res.

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

◆ findBuiltin()

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

Definition at line 6085 of file pgbench.c.

6087 {
6088  int i,
6089  found = 0,
6090  len = strlen(name);
6091  const BuiltinScript *result = NULL;
6092 
6093  for (i = 0; i < lengthof(builtin_script); i++)
6094  {
6095  if (strncmp(builtin_script[i].name, name, len) == 0)
6096  {
6097  result = &builtin_script[i];
6098  found++;
6099  }
6100  }
6101 
6102  /* ok, unambiguous result */
6103  if (found == 1)
6104  return result;
6105 
6106  /* error cases */
6107  if (found == 0)
6108  pg_log_error("no builtin script found for name \"%s\"", name);
6109  else /* found > 1 */
6110  pg_log_error("ambiguous builtin name: %d builtin scripts found for prefix \"%s\"", found, name);
6111 
6113  exit(1);
#define lengthof(array)
Definition: c.h:777
const void size_t len
static void listAvailableScripts(void)
Definition: pgbench.c:6073
static const BuiltinScript builtin_script[]
Definition: pgbench.c:777

References builtin_script, exit(), i, len, lengthof, listAvailableScripts(), name, and pg_log_error.

Referenced by main().

◆ finishCon()

static void finishCon ( CState st)
static

Definition at line 7653 of file pgbench.c.

7655 {
7656  if (st->con != NULL)
7657  {
7658  PQfinish(st->con);
7659  st->con = NULL;
7660  }

References CState::con, and PQfinish().

Referenced by advanceConnectionState(), and disconnect_all().

◆ free_command()

static void free_command ( Command command)
static

Definition at line 5544 of file pgbench.c.

5546 {
5547  termPQExpBuffer(&command->lines);
5548  pg_free(command->first_line);
5549  for (int i = 0; i < command->argc; i++)
5550  pg_free(command->argv[i]);
5551  pg_free(command->varprefix);
5552 
5553  /*
5554  * It should also free expr recursively, but this is currently not needed
5555  * as only gset commands (which do not have an expression) are freed.
5556  */
5557  pg_free(command);

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

Referenced by ParseScript().

◆ free_socket_set()

static void free_socket_set ( socket_set sa)
static

Definition at line 7824 of file pgbench.c.

7826 {
7827  pg_free(sa);

References pg_free().

Referenced by threadRun().

◆ getExponentialRand()

static int64 getExponentialRand ( pg_prng_state state,
int64  min,
int64  max,
double  parameter 
)
static

Definition at line 1109 of file pgbench.c.

1112 {
1113  double cut,
1114  uniform,
1115  rand;
1116 
1117  /* abort if wrong parameter, but must really be checked beforehand */
1118  Assert(parameter > 0.0);
1119  cut = exp(-parameter);
1120  /* pg_prng_double value in [0, 1), uniform in (0, 1] */
1121  uniform = 1.0 - pg_prng_double(state);
1122 
1123  /*
1124  * inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
1125  */
1126  Assert((1.0 - cut) != 0.0);
1127  rand = -log(cut + (1.0 - cut) * uniform) / parameter;
1128  /* return int64 random number within between min and max */
1129  return min + (int64) ((max - min + 1) * rand);

References Assert(), and pg_prng_double().

Referenced by evalStandardFunc().

◆ getFailures()

static int64 getFailures ( const StatsData stats)
static

Definition at line 4470 of file pgbench.c.

4472 {
4473  return (stats->serialization_failures +
4474  stats->deadlock_failures);

References StatsData::deadlock_failures, and StatsData::serialization_failures.

Referenced by printProgressReport(), and printResults().

◆ getGaussianRand()

static int64 getGaussianRand ( pg_prng_state state,
int64  min,
int64  max,
double  parameter 
)
static

Definition at line 1133 of file pgbench.c.

1136 {
1137  double stdev;
1138  double rand;
1139 
1140  /* abort if parameter is too low, but must really be checked beforehand */
1141  Assert(parameter >= MIN_GAUSSIAN_PARAM);
1142 
1143  /*
1144  * Get normally-distributed random number in the range -parameter <= stdev
1145  * < parameter.
1146  *
1147  * This loop is executed until the number is in the expected range.
1148  *
1149  * As the minimum parameter is 2.0, the probability of looping is low:
1150  * sqrt(-2 ln(r)) <= 2 => r >= e^{-2} ~ 0.135, then when taking the
1151  * average sinus multiplier as 2/pi, we have a 8.6% looping probability in
1152  * the worst case. For a parameter value of 5.0, the looping probability
1153  * is about e^{-5} * 2 / pi ~ 0.43%.
1154  */
1155  do
1156  {
1157  stdev = pg_prng_double_normal(state);
1158  }
1159  while (stdev < -parameter || stdev >= parameter);
1160 
1161  /* stdev is in [-parameter, parameter), normalization to [0,1) */
1162  rand = (stdev + parameter) / (parameter * 2.0);
1163 
1164  /* return int64 random number within between min and max */
1165  return min + (int64) ((max - min + 1) * rand);
double pg_prng_double_normal(pg_prng_state *state)
Definition: pg_prng.c:254

References Assert(), MIN_GAUSSIAN_PARAM, and pg_prng_double_normal().

Referenced by evalStandardFunc().

◆ getHashFnv1a()

static int64 getHashFnv1a ( int64  val,
uint64  seed 
)
static

Definition at line 1241 of file pgbench.c.

1243 {
1244  int64 result;
1245  int i;
1246 
1247  result = FNV_OFFSET_BASIS ^ seed;
1248  for (i = 0; i < 8; ++i)
1249  {
1250  int32 octet = val & 0xff;
1251 
1252  val = val >> 8;
1253  result = result ^ octet;
1254  result = result * FNV_PRIME;
1255  }
1256 
1257  return result;
signed int int32
Definition: c.h:483
#define FNV_OFFSET_BASIS
Definition: pgbench.c:84
#define FNV_PRIME
Definition: pgbench.c:83

References FNV_OFFSET_BASIS, FNV_PRIME, i, and val.

Referenced by evalStandardFunc().

◆ getHashMurmur2()

static int64 getHashMurmur2 ( int64  val,
uint64  seed 
)
static

Definition at line 1266 of file pgbench.c.

1268 {
1269  uint64 result = seed ^ MM2_MUL_TIMES_8; /* sizeof(int64) */
1270  uint64 k = (uint64) val;
1271 
1272  k *= MM2_MUL;
1273  k ^= k >> MM2_ROT;
1274  k *= MM2_MUL;
1275 
1276  result ^= k;
1277  result *= MM2_MUL;
1278 
1279  result ^= result >> MM2_ROT;
1280  result *= MM2_MUL;
1281  result ^= result >> MM2_ROT;
1282 
1283  return (int64) result;
#define MM2_MUL_TIMES_8
Definition: pgbench.c:86
#define MM2_ROT
Definition: pgbench.c:87
#define MM2_MUL
Definition: pgbench.c:85

References MM2_MUL, MM2_MUL_TIMES_8, MM2_ROT, and val.

Referenced by evalStandardFunc().

◆ getMetaCommand()

static MetaCommand getMetaCommand ( const char *  cmd)
static

Definition at line 2876 of file pgbench.c.

2878 {
2879  MetaCommand mc;
2880 
2881  if (cmd == NULL)
2882  mc = META_NONE;
2883  else if (pg_strcasecmp(cmd, "set") == 0)
2884  mc = META_SET;
2885  else if (pg_strcasecmp(cmd, "setshell") == 0)
2886  mc = META_SETSHELL;
2887  else if (pg_strcasecmp(cmd, "shell") == 0)
2888  mc = META_SHELL;
2889  else if (pg_strcasecmp(cmd, "sleep") == 0)
2890  mc = META_SLEEP;
2891  else if (pg_strcasecmp(cmd, "if") == 0)
2892  mc = META_IF;
2893  else if (pg_strcasecmp(cmd, "elif") == 0)
2894  mc = META_ELIF;
2895  else if (pg_strcasecmp(cmd, "else") == 0)
2896  mc = META_ELSE;
2897  else if (pg_strcasecmp(cmd, "endif") == 0)
2898  mc = META_ENDIF;
2899  else if (pg_strcasecmp(cmd, "gset") == 0)
2900  mc = META_GSET;
2901  else if (pg_strcasecmp(cmd, "aset") == 0)
2902  mc = META_ASET;
2903  else if (pg_strcasecmp(cmd, "startpipeline") == 0)
2904  mc = META_STARTPIPELINE;
2905  else if (pg_strcasecmp(cmd, "endpipeline") == 0)
2906  mc = META_ENDPIPELINE;
2907  else
2908  mc = META_NONE;
2909  return mc;
MetaCommand
Definition: pgbench.c:686

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

◆ getPoissonRand()

static int64 getPoissonRand ( pg_prng_state state,
double  center 
)
static

Definition at line 1175 of file pgbench.c.

1177 {
1178  /*
1179  * Use inverse transform sampling to generate a value > 0, such that the
1180  * expected (i.e. average) value is the given argument.
1181  */
1182  double uniform;
1183 
1184  /* pg_prng_double value in [0, 1), uniform in (0, 1] */
1185  uniform = 1.0 - pg_prng_double(state);
1186 
1187  return (int64) (-log(uniform) * center + 0.5);

References pg_prng_double().

Referenced by advanceConnectionState().

◆ getQueryParams()

static void getQueryParams ( Variables variables,
const Command command,
const char **  params 
)
static

Definition at line 1968 of file pgbench.c.

1971 {
1972  int i;
1973 
1974  for (i = 0; i < command->argc - 1; i++)
1975  params[i] = getVariable(variables, command->argv[i + 1]);

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

Referenced by sendCommand().

◆ getrand()

static int64 getrand ( pg_prng_state state,
int64  min,
int64  max 
)
static

Definition at line 1098 of file pgbench.c.

1100 {
1101  return min + (int64) pg_prng_uint64_range(state, 0, max - min);
uint64 pg_prng_uint64_range(pg_prng_state *state, uint64 rmin, uint64 rmax)
Definition: pg_prng.c:144

References pg_prng_uint64_range().

Referenced by chooseScript(), and evalStandardFunc().

◆ getResultString()

static const char* getResultString ( bool  skipped,
EStatus  estatus 
)
static

Definition at line 4481 of file pgbench.c.

4483 {
4484  if (skipped)
4485  return "skipped";
4486  else if (failures_detailed)
4487  {
4488  switch (estatus)
4489  {
4491  return "serialization";
4493  return "deadlock";
4494  default:
4495  /* internal error which should never occur */
4496  pg_fatal("unexpected error status: %d", estatus);
4497  }
4498  }
4499  else
4500  return "failed";

References ESTATUS_DEADLOCK_ERROR, ESTATUS_SERIALIZATION_ERROR, failures_detailed, and pg_fatal.

Referenced by doLog().

◆ getSQLErrorStatus()

static EStatus getSQLErrorStatus ( const char *  sqlState)
static

Definition at line 3202 of file pgbench.c.

3204 {
3205  if (sqlState != NULL)
3206  {
3207  if (strcmp(sqlState, ERRCODE_T_R_SERIALIZATION_FAILURE) == 0)
3209  else if (strcmp(sqlState, ERRCODE_T_R_DEADLOCK_DETECTED) == 0)
3210  return ESTATUS_DEADLOCK_ERROR;
3211  }
3212 
3213  return ESTATUS_OTHER_SQL_ERROR;
#define ERRCODE_T_R_DEADLOCK_DETECTED
Definition: pgbench.c:77
#define ERRCODE_T_R_SERIALIZATION_FAILURE
Definition: pgbench.c:76

References ERRCODE_T_R_DEADLOCK_DETECTED, ERRCODE_T_R_SERIALIZATION_FAILURE, ESTATUS_DEADLOCK_ERROR, ESTATUS_OTHER_SQL_ERROR, and ESTATUS_SERIALIZATION_ERROR.

Referenced by readCommandResponse().

◆ GetTableInfo()

static void GetTableInfo ( PGconn con,
bool  scale_given 
)
static

Definition at line 5274 of file pgbench.c.

5276 {
5277  PGresult *res;
5278 
5279  /*
5280  * get the scaling factor that should be same as count(*) from
5281  * pgbench_branches if this is not a custom query
5282  */
5283  res = PQexec(con, "select count(*) from pgbench_branches");
5285  {
5286  char *sqlState = PQresultErrorField(res, PG_DIAG_SQLSTATE);
5287 
5288  pg_log_error("could not count number of branches: %s", PQerrorMessage(con));
5289 
5290  if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) == 0)
5291  pg_log_error_hint("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".",
5292  PQdb(con));
5293 
5294  exit(1);
5295  }
5296  scale = atoi(PQgetvalue(res, 0, 0));
5297  if (scale < 0)
5298  pg_fatal("invalid count(*) from pgbench_branches: \"%s\"",
5299  PQgetvalue(res, 0, 0));
5300  PQclear(res);
5301 
5302  /* warn if we override user-given -s switch */
5303  if (scale_given)
5304  pg_log_warning("scale option ignored, using count from pgbench_branches table (%d)",
5305  scale);
5306 
5307  /*
5308  * Get the partition information for the first "pgbench_accounts" table
5309  * found in search_path.
5310  *
5311  * The result is empty if no "pgbench_accounts" is found.
5312  *
5313  * Otherwise, it always returns one row even if the table is not
5314  * partitioned (in which case the partition strategy is NULL).
5315  *
5316  * The number of partitions can be 0 even for partitioned tables, if no
5317  * partition is attached.
5318  *
5319  * We assume no partitioning on any failure, so as to avoid failing on an
5320  * old version without "pg_partitioned_table".
5321  */
5322  res = PQexec(con,
5323  "select o.n, p.partstrat, pg_catalog.count(i.inhparent) "
5324  "from pg_catalog.pg_class as c "
5325  "join pg_catalog.pg_namespace as n on (n.oid = c.relnamespace) "
5326  "cross join lateral (select pg_catalog.array_position(pg_catalog.current_schemas(true), n.nspname)) as o(n) "
5327  "left join pg_catalog.pg_partitioned_table as p on (p.partrelid = c.oid) "
5328  "left join pg_catalog.pg_inherits as i on (c.oid = i.inhparent) "
5329  "where c.relname = 'pgbench_accounts' and o.n is not null "
5330  "group by 1, 2 "
5331  "order by 1 asc "
5332  "limit 1");
5333 
5335  {
5336  /* probably an older version, coldly assume no partitioning */
5338  partitions = 0;
5339  }
5340  else if (PQntuples(res) == 0)
5341  {
5342  /*
5343  * This case is unlikely as pgbench already found "pgbench_branches"
5344  * above to compute the scale.
5345  */
5346  pg_log_error("no pgbench_accounts table found in search_path");
5347  pg_log_error_hint("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".", PQdb(con));
5348  exit(1);
5349  }
5350  else /* PQntuples(res) == 1 */
5351  {
5352  /* normal case, extract partition information */
5353  if (PQgetisnull(res, 0, 1))
5355  else
5356  {
5357  char *ps = PQgetvalue(res, 0, 1);
5358 
5359  /* column must be there */
5360  Assert(ps != NULL);
5361 
5362  if (strcmp(ps, "r") == 0)
5364  else if (strcmp(ps, "h") == 0)
5366  else
5367  {
5368  /* possibly a newer version with new partition method */
5369  pg_fatal("unexpected partition method: \"%s\"", ps);
5370  }
5371  }
5372 
5373  partitions = atoi(PQgetvalue(res, 0, 2));
5374  }
5375 
5376  PQclear(res);
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:7094
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3395
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3790
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3815
char * PQresultErrorField(const PGresult *res, int fieldcode)
Definition: fe-exec.c:3380
@ PGRES_TUPLES_OK
Definition: libpq-fe.h:100
#define pg_log_error_hint(...)
Definition: logging.h:112
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:78
#define pg_log_warning(...)
Definition: pgfnames.c:24
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:56

References Assert(), ERRCODE_UNDEFINED_TABLE, exit(), PART_HASH, PART_NONE, PART_RANGE, partition_method, partitions, PG_DIAG_SQLSTATE, pg_fatal, pg_log_error, pg_log_error_hint, pg_log_warning, PGRES_TUPLES_OK, PQclear(), PQdb(), PQerrorMessage(), PQexec(), PQgetisnull(), PQgetvalue(), PQntuples(), PQresultErrorField(), PQresultStatus(), ps, res, and scale.

Referenced by main().

◆ getTransactionStatus()

static TStatus getTransactionStatus ( PGconn con)
static

Definition at line 3506 of file pgbench.c.

3508 {
3509  PGTransactionStatusType tx_status;
3510 
3511  tx_status = PQtransactionStatus(con);
3512  switch (tx_status)
3513  {
3514  case PQTRANS_IDLE:
3515  return TSTATUS_IDLE;
3516  case PQTRANS_INTRANS:
3517  case PQTRANS_INERROR:
3518  return TSTATUS_IN_BLOCK;
3519  case PQTRANS_UNKNOWN:
3520  /* PQTRANS_UNKNOWN is expected given a broken connection */
3521  if (PQstatus(con) == CONNECTION_BAD)
3522  return TSTATUS_CONN_ERROR;
3523  /* fall through */
3524  case PQTRANS_ACTIVE:
3525  default:
3526 
3527  /*
3528  * We cannot find out whether we are in a transaction block or
3529  * not. Internal error which should never occur.
3530  */
3531  pg_log_error("unexpected transaction status %d", tx_status);
3532  return TSTATUS_OTHER_ERROR;
3533  }
3534 
3535  /* not reached */
3536  Assert(false);
3537  return TSTATUS_OTHER_ERROR;
PGTransactionStatusType PQtransactionStatus(const PGconn *conn)
Definition: fe-connect.c:7203
PGTransactionStatusType
Definition: libpq-fe.h:117
@ PQTRANS_INTRANS
Definition: libpq-fe.h:120
@ PQTRANS_IDLE
Definition: libpq-fe.h:118
@ PQTRANS_ACTIVE
Definition: libpq-fe.h:119
@ PQTRANS_UNKNOWN
Definition: libpq-fe.h:122
@ PQTRANS_INERROR
Definition: libpq-fe.h:121

References Assert(), CONNECTION_BAD, pg_log_error, PQstatus(), PQTRANS_ACTIVE, PQTRANS_IDLE, PQTRANS_INERROR, PQTRANS_INTRANS, PQTRANS_UNKNOWN, PQtransactionStatus(), TSTATUS_CONN_ERROR, TSTATUS_IDLE, TSTATUS_IN_BLOCK, and TSTATUS_OTHER_ERROR.

Referenced by advanceConnectionState().

◆ getVariable()

static char* getVariable ( Variables variables,
char *  name 
)
static

Definition at line 1627 of file pgbench.c.

1629 {
1630  Variable *var;
1631  char stringform[64];
1632 
1633  var = lookupVariable(variables, name);
1634  if (var == NULL)
1635  return NULL; /* not found */
1636 
1637  if (var->svalue)
1638  return var->svalue; /* we have it in string form */
1639 
1640  /* We need to produce a string equivalent of the value */
1641  Assert(var->value.type != PGBT_NO_VALUE);
1642  if (var->value.type == PGBT_NULL)
1643  snprintf(stringform, sizeof(stringform), "NULL");
1644  else if (var->value.type == PGBT_BOOLEAN)
1645  snprintf(stringform, sizeof(stringform),
1646  "%s", var->value.u.bval ? "true" : "false");
1647  else if (var->value.type == PGBT_INT)
1648  snprintf(stringform, sizeof(stringform),
1649  INT64_FORMAT, var->value.u.ival);
1650  else if (var->value.type == PGBT_DOUBLE)
1651  snprintf(stringform, sizeof(stringform),
1652  "%.*g", DBL_DIG, var->value.u.dval);
1653  else /* internal error, unexpected type */
1654  Assert(0);
1655  var->svalue = pg_strdup(stringform);
1656  return var->svalue;
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
@ PGBT_NO_VALUE
Definition: pgbench.h:36
#define snprintf
Definition: port.h:238
char * svalue
Definition: pgbench.c:324

References Assert(), PgBenchValue::bval, PgBenchValue::dval, INT64_FORMAT, PgBenchValue::ival, lookupVariable(), name, 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().

◆ getZipfianRand()

static int64 getZipfianRand ( pg_prng_state state,
int64  min,
int64  max,
double  s 
)
static

Definition at line 1227 of file pgbench.c.

1229 {
1230  int64 n = max - min + 1;
1231 
1232  /* abort if parameter is invalid */
1234 
1235  return min - 1 + computeIterativeZipfian(state, n, s);
static int64 computeIterativeZipfian(pg_prng_state *state, int64 n, double s)
Definition: pgbench.c:1197

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

Referenced by evalStandardFunc().

◆ handle_sig_alarm()

static void handle_sig_alarm ( SIGNAL_ARGS  )
static

Definition at line 7669 of file pgbench.c.

7671 {
7672  timer_exceeded = true;

References timer_exceeded.

Referenced by setalarm().

◆ initAccount()

static void initAccount ( PQExpBufferData sql,
int64  curr 
)
static

Definition at line 4897 of file pgbench.c.

4899 {
4900  /* "filler" column defaults to blank padded empty string */
4901  printfPQExpBuffer(sql,
4902  INT64_FORMAT "\t" INT64_FORMAT "\t0\t\n",
4903  curr + 1, curr / naccounts + 1);

References INT64_FORMAT, naccounts, and printfPQExpBuffer().

Referenced by initGenerateDataClientSide().

◆ initBranch()

static void initBranch ( PQExpBufferData sql,
int64  curr 
)
static

Definition at line 4879 of file pgbench.c.

4881 {
4882  /* "filler" column uses NULL */
4883  printfPQExpBuffer(sql,
4884  INT64_FORMAT "\t0\t\\N\n",
4885  curr + 1);

References INT64_FORMAT, and printfPQExpBuffer().

Referenced by initGenerateDataClientSide().

◆ initCreateFKeys()

static void initCreateFKeys ( PGconn con)
static

Definition at line 5143 of file pgbench.c.

5145 {
5146  static const char *const DDLKEYs[] = {
5147  "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
5148  "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
5149  "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
5150  "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
5151  "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
5152  };
5153  int i;
5154 
5155  fprintf(stderr, "creating foreign keys...\n");
5156  for (i = 0; i < lengthof(DDLKEYs); i++)
5157  {
5158  executeStatement(con, DDLKEYs[i]);
5159  }

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

Referenced by runInitSteps().

◆ initCreatePKeys()

static void initCreatePKeys ( PGconn con)
static

Definition at line 5105 of file pgbench.c.

5107 {
5108  static const char *const DDLINDEXes[] = {
5109  "alter table pgbench_branches add primary key (bid)",
5110  "alter table pgbench_tellers add primary key (tid)",
5111  "alter table pgbench_accounts add primary key (aid)"
5112  };
5113  int i;
5114  PQExpBufferData query;
5115 
5116  fprintf(stderr, "creating primary keys...\n");
5117  initPQExpBuffer(&query);
5118 
5119  for (i = 0; i < lengthof(DDLINDEXes); i++)
5120  {
5121  resetPQExpBuffer(&query);
5122  appendPQExpBufferStr(&query, DDLINDEXes[i]);
5123 
5124  if (index_tablespace != NULL)
5125  {
5126  char *escape_tablespace;
5127 
5128  escape_tablespace = PQescapeIdentifier(con, index_tablespace,
5129  strlen(index_tablespace));
5130  appendPQExpBuffer(&query, " using index tablespace %s", escape_tablespace);
5131  PQfreemem(escape_tablespace);
5132  }
5133 
5134  executeStatement(con, query.data);
5135  }
5136 
5137  termPQExpBuffer(&query);
void PQfreemem(void *ptr)
Definition: fe-exec.c:3946
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:4224
char * index_tablespace
Definition: pgbench.c:217
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:146

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

Referenced by runInitSteps().

◆ initCreateTables()

static void initCreateTables ( PGconn con)
static

Definition at line 4774 of file pgbench.c.

4776 {
4777  /*
4778  * Note: TPC-B requires at least 100 bytes per row, and the "filler"
4779  * fields in these table declarations were intended to comply with that.
4780  * The pgbench_accounts table complies with that because the "filler"
4781  * column is set to blank-padded empty string. But for all other tables
4782  * the columns default to NULL and so don't actually take any space. We
4783  * could fix that by giving them non-null default values. However, that
4784  * would completely break comparability of pgbench results with prior
4785  * versions. Since pgbench has never pretended to be fully TPC-B compliant
4786  * anyway, we stick with the historical behavior.
4787  */
4788  struct ddlinfo
4789  {
4790  const char *table; /* table name */
4791  const char *smcols; /* column decls if accountIDs are 32 bits */
4792  const char *bigcols; /* column decls if accountIDs are 64 bits */
4793  int declare_fillfactor;
4794  };
4795  static const struct ddlinfo DDLs[] = {
4796  {
4797  "pgbench_history",
4798  "tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)",
4799  "tid int,bid int,aid bigint,delta int,mtime timestamp,filler char(22)",
4800  0
4801  },
4802  {
4803  "pgbench_tellers",
4804  "tid int not null,bid int,tbalance int,filler char(84)",
4805  "tid int not null,bid int,tbalance int,filler char(84)",
4806  1
4807  },
4808  {
4809  "pgbench_accounts",
4810  "aid int not null,bid int,abalance int,filler char(84)",
4811  "aid bigint not null,bid int,abalance int,filler char(84)",
4812  1
4813  },
4814  {
4815  "pgbench_branches",
4816  "bid int not null,bbalance int,filler char(88)",
4817  "bid int not null,bbalance int,filler char(88)",
4818  1
4819  }
4820  };
4821  int i;
4822  PQExpBufferData query;
4823 
4824  fprintf(stderr, "creating tables...\n");
4825 
4826  initPQExpBuffer(&query);
4827 
4828  for (i = 0; i < lengthof(DDLs); i++)
4829  {
4830  const struct ddlinfo *ddl = &DDLs[i];
4831 
4832  /* Construct new create table statement. */
4833  printfPQExpBuffer(&query, "create%s table %s(%s)",
4834  unlogged_tables ? " unlogged" : "",
4835  ddl->table,
4836  (scale >= SCALE_32BIT_THRESHOLD) ? ddl->bigcols : ddl->smcols);
4837 
4838  /* Partition pgbench_accounts table */
4839  if (partition_method != PART_NONE && strcmp(ddl->table, "pgbench_accounts") == 0)
4840  appendPQExpBuffer(&query,
4841  " partition by %s (aid)", PARTITION_METHOD[partition_method]);
4842  else if (ddl->declare_fillfactor)
4843  {
4844  /* fillfactor is only expected on actual tables */
4845  appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4846  }
4847 
4848  if (tablespace != NULL)
4849  {
4850  char *escape_tablespace;
4851 
4852  escape_tablespace = PQescapeIdentifier(con, tablespace, strlen(tablespace));
4853  appendPQExpBuffer(&query, " tablespace %s", escape_tablespace);
4854  PQfreemem(escape_tablespace);
4855  }
4856 
4857  executeStatement(con, query.data);
4858  }
4859 
4860  termPQExpBuffer(&query);
4861 
4862  if (partition_method != PART_NONE)
4863  createPartitions(con);
static void createPartitions(PGconn *con)
Definition: pgbench.c:4705
static const char *const PARTITION_METHOD[]
Definition: pgbench.c:234
#define SCALE_32BIT_THRESHOLD
Definition: pgbench.c:254
char * tablespace
Definition: pgbench.c:216

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

◆ initDropTables()

static void initDropTables ( PGconn con)
static

Definition at line 4683 of file pgbench.c.

4685 {
4686  fprintf(stderr, "dropping old tables...\n");
4687 
4688  /*
4689  * We drop all the tables in one command, so that whether there are
4690  * foreign key dependencies or not doesn't matter.
4691  */
4692  executeStatement(con, "drop table if exists "
4693  "pgbench_accounts, "
4694  "pgbench_branches, "
4695  "pgbench_history, "
4696  "pgbench_tellers");

References executeStatement(), and fprintf.

Referenced by runInitSteps().

◆ initGenerateDataClientSide()

static void initGenerateDataClientSide ( PGconn con)
static

Definition at line 5015 of file pgbench.c.

5017 {
5018  fprintf(stderr, "generating data (client-side)...\n");
5019 
5020  /*
5021  * we do all of this in one transaction to enable the backend's
5022  * data-loading optimizations
5023  */
5024  executeStatement(con, "begin");
5025 
5026  /* truncate away any old data */
5027  initTruncateTables(con);
5028 
5029  /*
5030  * fill branches, tellers, accounts in that order in case foreign keys
5031  * already exist
5032  */
5033  initPopulateTable(con, "pgbench_branches", nbranches, initBranch);
5034  initPopulateTable(con, "pgbench_tellers", ntellers, initTeller);
5035  initPopulateTable(con, "pgbench_accounts", naccounts, initAccount);
5036 
5037  executeStatement(con, "commit");
static void initTeller(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:4888
static void initBranch(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:4879
#define ntellers
Definition: pgbench.c:244
static void initTruncateTables(PGconn *con)
Definition: pgbench.c:4869
static void initAccount(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:4897
#define nbranches
Definition: pgbench.c:243
static void initPopulateTable(PGconn *con, const char *table, int64 base, initRowMethod init_row)
Definition: pgbench.c:4906

References executeStatement(), fprintf, initAccount(), initBranch(), initPopulateTable(), initTeller(), initTruncateTables(), naccounts, nbranches, and ntellers.

Referenced by runInitSteps().

◆ initGenerateDataServerSide()

static void initGenerateDataServerSide ( PGconn con)
static

Definition at line 5047 of file pgbench.c.

5049 {
5050  PQExpBufferData sql;
5051 
5052  fprintf(stderr, "generating data (server-side)...\n");
5053 
5054  /*
5055  * we do all of this in one transaction to enable the backend's
5056  * data-loading optimizations
5057  */
5058  executeStatement(con, "begin");
5059 
5060  /* truncate away any old data */
5061  initTruncateTables(con);
5062 
5063  initPQExpBuffer(&sql);
5064 
5065  printfPQExpBuffer(&sql,
5066  "insert into pgbench_branches(bid,bbalance) "
5067  "select bid, 0 "
5068  "from generate_series(1, %d) as bid", nbranches * scale);
5069  executeStatement(con, sql.data);
5070 
5071  printfPQExpBuffer(&sql,
5072  "insert into pgbench_tellers(tid,bid,tbalance) "
5073  "select tid, (tid - 1) / %d + 1, 0 "
5074  "from generate_series(1, %d) as tid", ntellers, ntellers * scale);
5075  executeStatement(con, sql.data);
5076 
5077  printfPQExpBuffer(&sql,
5078  "insert into pgbench_accounts(aid,bid,abalance,filler) "
5079  "select aid, (aid - 1) / %d + 1, 0, '' "
5080  "from generate_series(1, " INT64_FORMAT ") as aid",
5081  naccounts, (int64) naccounts * scale);
5082  executeStatement(con, sql.data);
5083 
5084  termPQExpBuffer(&sql);
5085 
5086  executeStatement(con, "commit");

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

Referenced by runInitSteps().

◆ initPopulateTable()

static void initPopulateTable ( PGconn con,
const char *  table,
int64  base,
initRowMethod  init_row 
)
static

Definition at line 4906 of file pgbench.c.

4909 {
4910  int n;
4911  int k;
4912  int chars = 0;
4913  PGresult *res;
4914  PQExpBufferData sql;
4915  char copy_statement[256];
4916  const char *copy_statement_fmt = "copy %s from stdin";
4917  int64 total = base * scale;
4918 
4919  /* used to track elapsed time and estimate of the remaining time */