PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 "catalog/pg_class_d.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_CONN_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_SYNCPIPELINE , 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 char get_table_relkind (PGconn *con, const char *table)
 
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 void discardAvailableResults (CState *st)
 
static EStatus getSQLErrorStatus (CState *st, const char *sqlState)
 
static bool canRetryError (EStatus estatus)
 
static bool canContinueOnError (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)
 
static void free_command (Command *command)
 
static void postprocess_sql_command (Command *my_command)
 
static Commandprocess_backslash_command (PsqlScanState sstate, const char *source, int lineno, int start_offset)
 
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

static int nxacts = 0
 
static int duration = 0
 
static int64 end_time = 0
 
static int scale = 1
 
static int fillfactor = 100
 
static bool unlogged_tables = false
 
static double sample_rate = 0.0
 
static double throttle_delay = 0
 
static int64 latency_limit = 0
 
static char * tablespace = NULL
 
static 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"}
 
static int64 random_seed = -1
 
static bool use_log
 
static bool use_quiet
 
static int agg_interval
 
static bool per_script_stats = false
 
static int progress = 0
 
static bool progress_timestamp = false
 
static int nclients = 1
 
static int nthreads = 1
 
static bool is_connect
 
static bool report_per_command = false
 
static int main_pid
 
static uint32 max_tries = 1
 
static bool failures_detailed = false
 
static const char * pghost = NULL
 
static const char * pgport = NULL
 
static const char * username = NULL
 
static const char * dbName = NULL
 
static char * logfile_prefix = NULL
 
static const char * progname
 
static volatile sig_atomic_t timer_exceeded = false
 
static 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 bool continue_on_error = 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 164 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 163 of file pgbench.c.

◆ DEFAULT_NXACTS

#define DEFAULT_NXACTS   10 /* default nxacts */

Definition at line 167 of file pgbench.c.

◆ ERRCODE_T_R_DEADLOCK_DETECTED

#define ERRCODE_T_R_DEADLOCK_DETECTED   "40P01"

Definition at line 78 of file pgbench.c.

◆ ERRCODE_T_R_SERIALIZATION_FAILURE

#define ERRCODE_T_R_SERIALIZATION_FAILURE   "40001"

Definition at line 77 of file pgbench.c.

◆ ERRCODE_UNDEFINED_TABLE

#define ERRCODE_UNDEFINED_TABLE   "42P01"

Definition at line 79 of file pgbench.c.

◆ FNV_OFFSET_BASIS

#define FNV_OFFSET_BASIS   UINT64CONST(0xcbf29ce484222325)

Definition at line 85 of file pgbench.c.

◆ FNV_PRIME

#define FNV_PRIME   UINT64CONST(0x100000001b3)

Definition at line 84 of file pgbench.c.

◆ LOG_STEP_SECONDS

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

Definition at line 166 of file pgbench.c.

◆ M_PI

#define M_PI   3.14159265358979323846

Definition at line 74 of file pgbench.c.

◆ MAX_ARGS

#define MAX_ARGS   256

Definition at line 693 of file pgbench.c.

◆ MAX_FARGS

#define MAX_FARGS   16

Definition at line 2281 of file pgbench.c.

◆ MAX_SCRIPTS

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

Definition at line 348 of file pgbench.c.

◆ MAX_ZIPFIAN_PARAM

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

Definition at line 172 of file pgbench.c.

◆ META_COMMAND

#define META_COMMAND   2

Definition at line 687 of file pgbench.c.

◆ MIN_GAUSSIAN_PARAM

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

Definition at line 169 of file pgbench.c.

◆ MIN_ZIPFIAN_PARAM

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

Definition at line 171 of file pgbench.c.

◆ MM2_MUL

#define MM2_MUL   UINT64CONST(0xc6a4a7935bd1e995)

Definition at line 86 of file pgbench.c.

◆ MM2_MUL_TIMES_8

#define MM2_MUL_TIMES_8   UINT64CONST(0x35253c9ade8f4ca8)

Definition at line 87 of file pgbench.c.

◆ MM2_ROT

#define MM2_ROT   47

Definition at line 88 of file pgbench.c.

◆ naccounts

#define naccounts   100000

Definition at line 246 of file pgbench.c.

◆ nbranches

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

Definition at line 244 of file pgbench.c.

◆ ntellers

#define ntellers   10

Definition at line 245 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 901 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 255 of file pgbench.c.

◆ SHELL_COMMAND_SIZE

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

Definition at line 349 of file pgbench.c.

◆ SOCKET_WAIT_METHOD

#define SOCKET_WAIT_METHOD   "select"

Definition at line 107 of file pgbench.c.

◆ SQL_COMMAND

#define SQL_COMMAND   1

Definition at line 686 of file pgbench.c.

◆ THREAD_BARRIER_DESTROY

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

Definition at line 156 of file pgbench.c.

◆ THREAD_BARRIER_INIT

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

Definition at line 153 of file pgbench.c.

◆ THREAD_BARRIER_T

#define THREAD_BARRIER_T   pthread_barrier_t

Definition at line 152 of file pgbench.c.

◆ THREAD_BARRIER_WAIT

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

Definition at line 155 of file pgbench.c.

◆ THREAD_CREATE

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

Definition at line 148 of file pgbench.c.

◆ THREAD_FUNC_CC

#define THREAD_FUNC_CC

Definition at line 147 of file pgbench.c.

◆ THREAD_FUNC_RETURN

#define THREAD_FUNC_RETURN   return NULL

Definition at line 146 of file pgbench.c.

◆ THREAD_FUNC_RETURN_TYPE

#define THREAD_FUNC_RETURN_TYPE   void *

Definition at line 145 of file pgbench.c.

◆ THREAD_JOIN

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

Definition at line 150 of file pgbench.c.

◆ THREAD_T

#define THREAD_T   pthread_t

Definition at line 144 of file pgbench.c.

◆ VARIABLES_ALLOC_MARGIN

#define VARIABLES_ALLOC_MARGIN   8

Definition at line 311 of file pgbench.c.

◆ WSEP

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

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

◆ MetaCommand

typedef enum MetaCommand MetaCommand

◆ ParsedScript

typedef struct ParsedScript ParsedScript

◆ pg_time_usec_t

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

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

◆ EStatus

enum EStatus
Enumerator
ESTATUS_NO_ERROR 
ESTATUS_META_COMMAND_ERROR 
ESTATUS_CONN_ERROR 
ESTATUS_SERIALIZATION_ERROR 
ESTATUS_DEADLOCK_ERROR 
ESTATUS_OTHER_SQL_ERROR 

Definition at line 461 of file pgbench.c.

463{
467
468 /* SQL errors */
@ ESTATUS_DEADLOCK_ERROR
Definition: pgbench.c:469
@ ESTATUS_META_COMMAND_ERROR
Definition: pgbench.c:464
@ ESTATUS_CONN_ERROR
Definition: pgbench.c:465
@ ESTATUS_OTHER_SQL_ERROR
Definition: pgbench.c:470
@ ESTATUS_NO_ERROR
Definition: pgbench.c:463
@ ESTATUS_SERIALIZATION_ERROR
Definition: pgbench.c:468

◆ 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_SYNCPIPELINE 
META_ENDPIPELINE 

Definition at line 695 of file pgbench.c.

697{
698 META_NONE, /* not a known meta-command */
699 META_SET, /* \set */
700 META_SETSHELL, /* \setshell */
701 META_SHELL, /* \shell */
702 META_SLEEP, /* \sleep */
703 META_GSET, /* \gset */
704 META_ASET, /* \aset */
705 META_IF, /* \if */
706 META_ELIF, /* \elif */
707 META_ELSE, /* \else */
708 META_ENDIF, /* \endif */
709 META_STARTPIPELINE, /* \startpipeline */
710 META_SYNCPIPELINE, /* \syncpipeline */
711 META_ENDPIPELINE, /* \endpipeline */
@ META_ELSE
Definition: pgbench.c:706
@ META_SETSHELL
Definition: pgbench.c:699
@ META_ENDIF
Definition: pgbench.c:707
@ META_SHELL
Definition: pgbench.c:700
@ META_STARTPIPELINE
Definition: pgbench.c:708
@ META_SET
Definition: pgbench.c:698
@ META_ELIF
Definition: pgbench.c:705
@ META_SYNCPIPELINE
Definition: pgbench.c:709
@ META_SLEEP
Definition: pgbench.c:701
@ META_NONE
Definition: pgbench.c:697
@ META_IF
Definition: pgbench.c:704
@ META_ENDPIPELINE
Definition: pgbench.c:710
@ META_ASET
Definition: pgbench.c:703
@ META_GSET
Definition: pgbench.c:702

◆ partition_method_t

Enumerator
PART_NONE 
PART_RANGE 
PART_HASH 

Definition at line 227 of file pgbench.c.

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

◆ QueryMode

enum QueryMode
Enumerator
QUERY_SIMPLE 
QUERY_EXTENDED 
QUERY_PREPARED 
NUM_QUERYMODE 

Definition at line 713 of file pgbench.c.

715{
716 QUERY_SIMPLE, /* simple query */
717 QUERY_EXTENDED, /* extended query */
718 QUERY_PREPARED, /* extended query with prepared statements */
@ QUERY_PREPARED
Definition: pgbench.c:717
@ NUM_QUERYMODE
Definition: pgbench.c:718
@ QUERY_SIMPLE
Definition: pgbench.c:715
@ QUERY_EXTENDED
Definition: pgbench.c:716

◆ TStatus

enum TStatus
Enumerator
TSTATUS_IDLE 
TSTATUS_IN_BLOCK 
TSTATUS_CONN_ERROR 
TSTATUS_OTHER_ERROR 

Definition at line 476 of file pgbench.c.

478{
@ TSTATUS_CONN_ERROR
Definition: pgbench.c:480
@ TSTATUS_IDLE
Definition: pgbench.c:478
@ TSTATUS_IN_BLOCK
Definition: pgbench.c:479
@ TSTATUS_OTHER_ERROR
Definition: pgbench.c:481

Function Documentation

◆ accumStats()

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

Definition at line 1487 of file pgbench.c.

1490{
1491 /* Record the skipped transaction */
1492 if (skipped)
1493 {
1494 /* no latency to record on skipped transactions */
1495 stats->skipped++;
1496 return;
1497 }
1498
1499 /*
1500 * Record the number of retries regardless of whether the transaction was
1501 * successful or failed.
1502 */
1503 if (tries > 1)
1504 {
1505 stats->retries += (tries - 1);
1506 stats->retried++;
1507 }
1508
1509 switch (estatus)
1510 {
1511 /* Record the successful transaction */
1512 case ESTATUS_NO_ERROR:
1513 stats->cnt++;
1514
1515 addToSimpleStats(&stats->latency, lat);
1516
1517 /* and possibly the same for schedule lag */
1518 if (throttle_delay)
1519 addToSimpleStats(&stats->lag, lag);
1520 break;
1521
1522 /* Record the failed transaction */
1524 stats->serialization_failures++;
1525 break;
1527 stats->deadlock_failures++;
1528 break;
1530 stats->other_sql_failures++;
1531 break;
1532 default:
1533 /* internal error which should never occur */
1534 pg_fatal("unexpected error status: %d", estatus);
1535 }
#define pg_fatal(...)
static double throttle_delay
Definition: pgbench.c:204
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:1438
int64 serialization_failures
Definition: pgbench.c:437
int64 cnt
Definition: pgbench.c:427
int64 retried
Definition: pgbench.c:433
int64 deadlock_failures
Definition: pgbench.c:440
int64 skipped
Definition: pgbench.c:429
int64 other_sql_failures
Definition: pgbench.c:443
SimpleStats lag
Definition: pgbench.c:449
int64 retries
Definition: pgbench.c:431
SimpleStats latency
Definition: pgbench.c:448

References addToSimpleStats(), StatsData::cnt, StatsData::deadlock_failures, ESTATUS_DEADLOCK_ERROR, ESTATUS_NO_ERROR, ESTATUS_OTHER_SQL_ERROR, ESTATUS_SERIALIZATION_ERROR, StatsData::lag, StatsData::latency, StatsData::other_sql_failures, 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 8057 of file pgbench.c.

8059{
8060 /* See connect_slot() for background on this code. */
8061#ifdef WIN32
8062 if (sa->fds.fd_count + 1 >= FD_SETSIZE)
8063 {
8064 pg_log_error("too many concurrent database clients for this platform: %d",
8065 sa->fds.fd_count + 1);
8066 exit(1);
8067 }
8068#else
8069 if (fd < 0 || fd >= FD_SETSIZE)
8070 {
8071 pg_log_error("socket file descriptor out of range for select(): %d",
8072 fd);
8073 pg_log_error_hint("Try fewer concurrent database clients.");
8074 exit(1);
8075 }
8076#endif
8077 FD_SET(fd, &sa->fds);
8078 if (fd > sa->maxfd)
8079 sa->maxfd = fd;
#define pg_log_error(...)
Definition: logging.h:106
#define pg_log_error_hint(...)
Definition: logging.h:112
static int fd(const char *x, int i)
Definition: preproc-init.c:105

References fd(), pg_log_error, and pg_log_error_hint.

Referenced by threadRun().

◆ addScript()

static void addScript ( const ParsedScript script)
static

Definition at line 6336 of file pgbench.c.

6338{
6339 if (script->commands == NULL || script->commands[0] == NULL)
6340 pg_fatal("empty command list for script \"%s\"", script->desc);
6341
6342 if (num_scripts >= MAX_SCRIPTS)
6343 pg_fatal("at most %d SQL scripts are allowed", MAX_SCRIPTS);
6344
6345 CheckConditional(script);
6346
6347 sql_script[num_scripts] = *script;
6348 num_scripts++;
static void CheckConditional(const ParsedScript *ps)
Definition: pgbench.c:5994
#define MAX_SCRIPTS
Definition: pgbench.c:348
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:772
static int num_scripts
Definition: pgbench.c:773
const char * desc
Definition: pgbench.c:766
Command ** commands
Definition: pgbench.c:768

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

1440{
1441 if (ss->count == 0 || val < ss->min)
1442 ss->min = val;
1443 if (ss->count == 0 || val > ss->max)
1444 ss->max = val;
1445 ss->count++;
1446 ss->sum += val;
1447 ss->sum2 += val * val;
long val
Definition: informix.c:689
int64 count
Definition: pgbench.c:359
double sum
Definition: pgbench.c:362
double min
Definition: pgbench.c:360
double max
Definition: pgbench.c:361
double sum2
Definition: pgbench.c:363

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

3715{
3716
3717 /*
3718 * gettimeofday() isn't free, so we get the current timestamp lazily the
3719 * first time it's needed, and reuse the same value throughout this
3720 * function after that. This also ensures that e.g. the calculated
3721 * latency reported in the log file and in the totals are the same. Zero
3722 * means "not set yet". Reset "now" when we execute shell commands or
3723 * expressions, which might take a non-negligible amount of time, though.
3724 */
3725 pg_time_usec_t now = 0;
3726
3727 /*
3728 * Loop in the state machine, until we have to wait for a result from the
3729 * server or have to sleep for throttling or \sleep.
3730 *
3731 * Note: In the switch-statement below, 'break' will loop back here,
3732 * meaning "continue in the state machine". Return is used to return to
3733 * the caller, giving the thread the opportunity to advance another
3734 * client.
3735 */
3736 for (;;)
3737 {
3738 Command *command;
3739
3740 switch (st->state)
3741 {
3742 /* Select transaction (script) to run. */
3744 st->use_file = chooseScript(thread);
3746
3747 /* reset transaction variables to default values */
3749 st->tries = 1;
3750
3751 pg_log_debug("client %d executing script \"%s\"",
3752 st->id, sql_script[st->use_file].desc);
3753
3754 /*
3755 * If time is over, we're done; otherwise, get ready to start
3756 * a new transaction, or to get throttled if that's requested.
3757 */
3760 break;
3761
3762 /* Start new transaction (script) */
3763 case CSTATE_START_TX:
3765
3766 /* establish connection if needed, i.e. under --connect */
3767 if (st->con == NULL)
3768 {
3770
3771 if ((st->con = doConnect()) == NULL)
3772 {
3773 /*
3774 * as the bench is already running, we do not abort
3775 * the process
3776 */
3777 pg_log_error("client %d aborted while establishing connection", st->id);
3778 st->state = CSTATE_ABORTED;
3779 break;
3780 }
3781
3782 /* reset now after connection */
3783 now = pg_time_now();
3784
3785 thread->conn_duration += now - start;
3786
3787 /* Reset session-local state */
3788 pg_free(st->prepared);
3789 st->prepared = NULL;
3790 }
3791
3792 /*
3793 * It is the first try to run this transaction. Remember the
3794 * random state: maybe it will get an error and we will need
3795 * to run it again.
3796 */
3797 st->random_state = st->cs_func_rs;
3798
3799 /* record transaction start time */
3800 st->txn_begin = now;
3801
3802 /*
3803 * When not throttling, this is also the transaction's
3804 * scheduled start time.
3805 */
3806 if (!throttle_delay)
3807 st->txn_scheduled = now;
3808
3809 /* Begin with the first command */
3811 st->command = 0;
3812 break;
3813
3814 /*
3815 * Handle throttling once per transaction by sleeping.
3816 */
3818
3819 /*
3820 * Generate a delay such that the series of delays will
3821 * approximate a Poisson distribution centered on the
3822 * throttle_delay time.
3823 *
3824 * If transactions are too slow or a given wait is shorter
3825 * than a transaction, the next transaction will start right
3826 * away.
3827 */
3829
3830 thread->throttle_trigger +=
3832 st->txn_scheduled = thread->throttle_trigger;
3833
3834 /*
3835 * If --latency-limit is used, and this slot is already late
3836 * so that the transaction will miss the latency limit even if
3837 * it completed immediately, skip this time slot and loop to
3838 * reschedule.
3839 */
3840 if (latency_limit)
3841 {
3843
3844 if (thread->throttle_trigger < now - latency_limit)
3845 {
3846 processXactStats(thread, st, &now, true, agg);
3847
3848 /*
3849 * Finish client if -T or -t was exceeded.
3850 *
3851 * Stop counting skipped transactions under -T as soon
3852 * as the timer is exceeded. Because otherwise it can
3853 * take a very long time to count all of them
3854 * especially when quite a lot of them happen with
3855 * unrealistically high rate setting in -R, which
3856 * would prevent pgbench from ending immediately.
3857 * Because of this behavior, note that there is no
3858 * guarantee that all skipped transactions are counted
3859 * under -T though there is under -t. This is OK in
3860 * practice because it's very unlikely to happen with
3861 * realistic setting.
3862 */
3863 if (timer_exceeded || (nxacts > 0 && st->cnt >= nxacts))
3864 st->state = CSTATE_FINISHED;
3865
3866 /* Go back to top of loop with CSTATE_PREPARE_THROTTLE */
3867 break;
3868 }
3869 }
3870
3871 /*
3872 * stop client if next transaction is beyond pgbench end of
3873 * execution; otherwise, throttle it.
3874 */
3875 st->state = end_time > 0 && st->txn_scheduled > end_time ?
3877 break;
3878
3879 /*
3880 * Wait until it's time to start next transaction.
3881 */
3882 case CSTATE_THROTTLE:
3884
3885 if (now < st->txn_scheduled)
3886 return; /* still sleeping, nothing to do here */
3887
3888 /* done sleeping, but don't start transaction if we're done */
3890 break;
3891
3892 /*
3893 * Send a command to server (or execute a meta-command)
3894 */
3896 command = sql_script[st->use_file].commands[st->command];
3897
3898 /*
3899 * Transition to script end processing if done, but close up
3900 * shop if a pipeline is open at this point.
3901 */
3902 if (command == NULL)
3903 {
3905 st->state = CSTATE_END_TX;
3906 else
3907 {
3908 pg_log_error("client %d aborted: end of script reached with pipeline open",
3909 st->id);
3910 st->state = CSTATE_ABORTED;
3911 }
3912
3913 break;
3914 }
3915
3916 /* record begin time of next command, and initiate it */
3918 {
3920 st->stmt_begin = now;
3921 }
3922
3923 /* Execute the command */
3924 if (command->type == SQL_COMMAND)
3925 {
3926 /* disallow \aset and \gset in pipeline mode */
3928 {
3929 if (command->meta == META_GSET)
3930 {
3931 commandFailed(st, "gset", "\\gset is not allowed in pipeline mode");
3932 st->state = CSTATE_ABORTED;
3933 break;
3934 }
3935 else if (command->meta == META_ASET)
3936 {
3937 commandFailed(st, "aset", "\\aset is not allowed in pipeline mode");
3938 st->state = CSTATE_ABORTED;
3939 break;
3940 }
3941 }
3942
3943 if (!sendCommand(st, command))
3944 {
3945 commandFailed(st, "SQL", "SQL command send failed");
3946 st->state = CSTATE_ABORTED;
3947 }
3948 else
3949 {
3950 /* Wait for results, unless in pipeline mode */
3953 else
3955 }
3956 }
3957 else if (command->type == META_COMMAND)
3958 {
3959 /*-----
3960 * Possible state changes when executing meta commands:
3961 * - on errors CSTATE_ABORTED
3962 * - on sleep CSTATE_SLEEP
3963 * - else CSTATE_END_COMMAND
3964 */
3965 st->state = executeMetaCommand(st, &now);
3966 if (st->state == CSTATE_ABORTED)
3968 }
3969
3970 /*
3971 * We're now waiting for an SQL command to complete, or
3972 * finished processing a metacommand, or need to sleep, or
3973 * something bad happened.
3974 */
3976 st->state == CSTATE_END_COMMAND ||
3977 st->state == CSTATE_SLEEP ||
3978 st->state == CSTATE_ABORTED);
3979 break;
3980
3981 /*
3982 * non executed conditional branch
3983 */
3986 /* quickly skip commands until something to do... */
3987 while (true)
3988 {
3989 command = sql_script[st->use_file].commands[st->command];
3990
3991 /* cannot reach end of script in that state */
3992 Assert(command != NULL);
3993
3994 /*
3995 * if this is conditional related, update conditional
3996 * state
3997 */
3998 if (command->type == META_COMMAND &&
3999 (command->meta == META_IF ||
4000 command->meta == META_ELIF ||
4001 command->meta == META_ELSE ||
4002 command->meta == META_ENDIF))
4003 {
4004 switch (conditional_stack_peek(st->cstack))
4005 {
4006 case IFSTATE_FALSE:
4007 if (command->meta == META_IF)
4008 {
4009 /* nested if in skipped branch - ignore */
4012 st->command++;
4013 }
4014 else if (command->meta == META_ELIF)
4015 {
4016 /* we must evaluate the condition */
4018 }
4019 else if (command->meta == META_ELSE)
4020 {
4021 /* we must execute next command */
4025 st->command++;
4026 }
4027 else if (command->meta == META_ENDIF)
4028 {
4031 if (conditional_active(st->cstack))
4033 /* else state remains CSTATE_SKIP_COMMAND */
4034 st->command++;
4035 }
4036 break;
4037
4038 case IFSTATE_IGNORED:
4039 case IFSTATE_ELSE_FALSE:
4040 if (command->meta == META_IF)
4043 else if (command->meta == META_ENDIF)
4044 {
4047 if (conditional_active(st->cstack))
4049 }
4050 /* could detect "else" & "elif" after "else" */
4051 st->command++;
4052 break;
4053
4054 case IFSTATE_NONE:
4055 case IFSTATE_TRUE:
4056 case IFSTATE_ELSE_TRUE:
4057 default:
4058
4059 /*
4060 * inconsistent if inactive, unreachable dead
4061 * code
4062 */
4063 Assert(false);
4064 }
4065 }
4066 else
4067 {
4068 /* skip and consider next */
4069 st->command++;
4070 }
4071
4072 if (st->state != CSTATE_SKIP_COMMAND)
4073 /* out of quick skip command loop */
4074 break;
4075 }
4076 break;
4077
4078 /*
4079 * Wait for the current SQL command to complete
4080 */
4081 case CSTATE_WAIT_RESULT:
4082 pg_log_debug("client %d receiving", st->id);
4083
4084 /*
4085 * Only check for new network data if we processed all data
4086 * fetched prior. Otherwise we end up doing a syscall for each
4087 * individual pipelined query, which has a measurable
4088 * performance impact.
4089 */
4090 if (PQisBusy(st->con) && !PQconsumeInput(st->con))
4091 {
4092 /* there's something wrong */
4093 commandFailed(st, "SQL", "perhaps the backend died while processing");
4094 st->state = CSTATE_ABORTED;
4095 break;
4096 }
4097 if (PQisBusy(st->con))
4098 return; /* don't have the whole result yet */
4099
4100 /* store or discard the query results */
4101 if (readCommandResponse(st,
4104 {
4105 /*
4106 * outside of pipeline mode: stop reading results.
4107 * pipeline mode: continue reading results until an
4108 * end-of-pipeline response.
4109 */
4112 }
4113 else if (canRetryError(st->estatus) || canContinueOnError(st->estatus))
4114 st->state = CSTATE_ERROR;
4115 else
4116 st->state = CSTATE_ABORTED;
4117 break;
4118
4119 /*
4120 * Wait until sleep is done. This state is entered after a
4121 * \sleep metacommand. The behavior is similar to
4122 * CSTATE_THROTTLE, but proceeds to CSTATE_START_COMMAND
4123 * instead of CSTATE_START_TX.
4124 */
4125 case CSTATE_SLEEP:
4127 if (now < st->sleep_until)
4128 return; /* still sleeping, nothing to do here */
4129 /* Else done sleeping. */
4131 break;
4132
4133 /*
4134 * End of command: record stats and proceed to next command.
4135 */
4136 case CSTATE_END_COMMAND:
4137
4138 /*
4139 * command completed: accumulate per-command execution times
4140 * in thread-local data structure, if per-command latencies
4141 * are requested.
4142 */
4144 {
4146
4147 command = sql_script[st->use_file].commands[st->command];
4148 /* XXX could use a mutex here, but we choose not to */
4149 addToSimpleStats(&command->stats,
4151 }
4152
4153 /* Go ahead with next command, to be executed or skipped */
4154 st->command++;
4155 st->state = conditional_active(st->cstack) ?
4157 break;
4158
4159 /*
4160 * Clean up after an error.
4161 */
4162 case CSTATE_ERROR:
4163 {
4164 TStatus tstatus;
4165
4167
4168 /* Clear the conditional stack */
4170
4171 /* Read and discard until a sync point in pipeline mode */
4173 {
4174 if (!discardUntilSync(st))
4175 {
4176 st->state = CSTATE_ABORTED;
4177 break;
4178 }
4179 }
4180
4181 /*
4182 * Check if we have a (failed) transaction block or not,
4183 * and roll it back if any.
4184 */
4185 tstatus = getTransactionStatus(st->con);
4186 if (tstatus == TSTATUS_IN_BLOCK)
4187 {
4188 /* Try to rollback a (failed) transaction block. */
4189 if (!PQsendQuery(st->con, "ROLLBACK"))
4190 {
4191 pg_log_error("client %d aborted: failed to send sql command for rolling back the failed transaction",
4192 st->id);
4193 st->state = CSTATE_ABORTED;
4194 }
4195 else
4197 }
4198 else if (tstatus == TSTATUS_IDLE)
4199 {
4200 /*
4201 * If time is over, we're done; otherwise, check if we
4202 * can retry the error.
4203 */
4206 }
4207 else
4208 {
4209 if (tstatus == TSTATUS_CONN_ERROR)
4210 pg_log_error("perhaps the backend died while processing");
4211
4212 pg_log_error("client %d aborted while receiving the transaction status", st->id);
4213 st->state = CSTATE_ABORTED;
4214 }
4215 break;
4216 }
4217
4218 /*
4219 * Wait for the rollback command to complete
4220 */
4222 {
4223 PGresult *res;
4224
4225 pg_log_debug("client %d receiving", st->id);
4226 if (!PQconsumeInput(st->con))
4227 {
4228 pg_log_error("client %d aborted while rolling back the transaction after an error; perhaps the backend died while processing",
4229 st->id);
4230 st->state = CSTATE_ABORTED;
4231 break;
4232 }
4233 if (PQisBusy(st->con))
4234 return; /* don't have the whole result yet */
4235
4236 /*
4237 * Read and discard the query result;
4238 */
4239 res = PQgetResult(st->con);
4240 switch (PQresultStatus(res))
4241 {
4242 case PGRES_COMMAND_OK:
4243 /* OK */
4244 PQclear(res);
4245 /* null must be returned */
4246 res = PQgetResult(st->con);
4247 Assert(res == NULL);
4248
4249 /*
4250 * If time is over, we're done; otherwise, check
4251 * if we can retry the error.
4252 */
4255 break;
4256 default:
4257 pg_log_error("client %d aborted while rolling back the transaction after an error; %s",
4258 st->id, PQerrorMessage(st->con));
4259 PQclear(res);
4260 st->state = CSTATE_ABORTED;
4261 break;
4262 }
4263 break;
4264 }
4265
4266 /*
4267 * Retry the transaction after an error.
4268 */
4269 case CSTATE_RETRY:
4270 command = sql_script[st->use_file].commands[st->command];
4271
4272 /*
4273 * Inform that the transaction will be retried after the
4274 * error.
4275 */
4276 if (verbose_errors)
4277 printVerboseErrorMessages(st, &now, true);
4278
4279 /* Count tries and retries */
4280 st->tries++;
4281 command->retries++;
4282
4283 /*
4284 * Reset the random state as they were at the beginning of the
4285 * transaction.
4286 */
4287 st->cs_func_rs = st->random_state;
4288
4289 /* Process the first transaction command. */
4290 st->command = 0;
4293 break;
4294
4295 /*
4296 * Record a failed transaction.
4297 */
4298 case CSTATE_FAILURE:
4299 command = sql_script[st->use_file].commands[st->command];
4300
4301 /* Accumulate the failure. */
4302 command->failures++;
4303
4304 /*
4305 * Inform that the failed transaction will not be retried.
4306 */
4307 if (verbose_errors)
4308 printVerboseErrorMessages(st, &now, false);
4309
4310 /* End the failed transaction. */
4311 st->state = CSTATE_END_TX;
4312 break;
4313
4314 /*
4315 * End of transaction (end of script, really).
4316 */
4317 case CSTATE_END_TX:
4318 {
4319 TStatus tstatus;
4320
4321 /* transaction finished: calculate latency and do log */
4322 processXactStats(thread, st, &now, false, agg);
4323
4324 /*
4325 * missing \endif... cannot happen if CheckConditional was
4326 * okay
4327 */
4329
4330 /*
4331 * We must complete all the transaction blocks that were
4332 * started in this script.
4333 */
4334 tstatus = getTransactionStatus(st->con);
4335 if (tstatus == TSTATUS_IN_BLOCK)
4336 {
4337 pg_log_error("client %d aborted: end of script reached without completing the last transaction",
4338 st->id);
4339 st->state = CSTATE_ABORTED;
4340 break;
4341 }
4342 else if (tstatus != TSTATUS_IDLE)
4343 {
4344 if (tstatus == TSTATUS_CONN_ERROR)
4345 pg_log_error("perhaps the backend died while processing");
4346
4347 pg_log_error("client %d aborted while receiving the transaction status", st->id);
4348 st->state = CSTATE_ABORTED;
4349 break;
4350 }
4351
4352 if (is_connect)
4353 {
4355
4357 finishCon(st);
4358 now = pg_time_now();
4359 thread->conn_duration += now - start;
4360 }
4361
4362 if ((st->cnt >= nxacts && duration <= 0) || timer_exceeded)
4363 {
4364 /* script completed */
4365 st->state = CSTATE_FINISHED;
4366 break;
4367 }
4368
4369 /* next transaction (script) */
4371
4372 /*
4373 * Ensure that we always return on this point, so as to
4374 * avoid an infinite loop if the script only contains meta
4375 * commands.
4376 */
4377 return;
4378 }
4379
4380 /*
4381 * Final states. Close the connection if it's still open.
4382 */
4383 case CSTATE_ABORTED:
4384 case CSTATE_FINISHED:
4385
4386 /*
4387 * Don't measure the disconnection delays here even if in
4388 * CSTATE_FINISHED and -C/--connect option is specified.
4389 * Because in this case all the connections that this thread
4390 * established are closed at the end of transactions and the
4391 * disconnection delays should have already been measured at
4392 * that moment.
4393 *
4394 * In CSTATE_ABORTED state, the measurement is no longer
4395 * necessary because we cannot report complete results anyways
4396 * in this case.
4397 */
4398 finishCon(st);
4399 return;
4400 }
4401 }
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1609
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
PGpipelineStatus PQpipelineStatus(const PGconn *conn)
Definition: fe-connect.c:7748
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:7704
int PQconsumeInput(PGconn *conn)
Definition: fe-exec.c:2000
int PQsendQuery(PGconn *conn, const char *query)
Definition: fe-exec.c:1432
int PQisBusy(PGconn *conn)
Definition: fe-exec.c:2047
void pg_free(void *ptr)
Definition: fe_memutils.c:105
Assert(PointerIsAligned(start, uint64))
return str start
#define PQgetResult
Definition: libpq-be-fe.h:246
#define PQclear
Definition: libpq-be-fe.h:245
#define PQresultStatus
Definition: libpq-be-fe.h:247
@ PGRES_COMMAND_OK
Definition: libpq-fe.h:125
@ PQ_PIPELINE_OFF
Definition: libpq-fe.h:187
@ PQ_PIPELINE_ON
Definition: libpq-fe.h:188
#define pg_log_debug(...)
Definition: logging.h:133
static pg_time_usec_t pg_time_now(void)
Definition: pgbench.c:885
static void printVerboseErrorMessages(CState *st, pg_time_usec_t *now, bool is_retry)
Definition: pgbench.c:3675
static int64 latency_limit
Definition: pgbench.c:212
static TStatus getTransactionStatus(PGconn *con)
Definition: pgbench.c:3638
static int64 end_time
Definition: pgbench.c:176
static bool doRetry(CState *st, pg_time_usec_t *now)
Definition: pgbench.c:3522
static bool sendCommand(CState *st, Command *command)
Definition: pgbench.c:3196
TStatus
Definition: pgbench.c:477
static void finishCon(CState *st)
Definition: pgbench.c:7873
int64 pg_time_usec_t
Definition: pgbench.c:371
static bool is_connect
Definition: pgbench.c:266
static int nxacts
Definition: pgbench.c:174
static bool report_per_command
Definition: pgbench.c:267
#define PG_TIME_GET_DOUBLE(t)
Definition: pgbench.c:901
static int discardUntilSync(CState *st)
Definition: pgbench.c:3568
static ConnectionStateEnum executeMetaCommand(CState *st, pg_time_usec_t *now)
Definition: pgbench.c:4411
static bool canRetryError(EStatus estatus)
Definition: pgbench.c:3298
static void commandFailed(CState *st, const char *cmd, const char *message)
Definition: pgbench.c:3062
static int chooseScript(TState *thread)
Definition: pgbench.c:3088
#define SQL_COMMAND
Definition: pgbench.c:686
static volatile sig_atomic_t timer_exceeded
Definition: pgbench.c:304
static void processXactStats(TState *thread, CState *st, pg_time_usec_t *now, bool skipped, StatsData *agg)
Definition: pgbench.c:4798
static int duration
Definition: pgbench.c:175
static PGconn * doConnect(void)
Definition: pgbench.c:1570
static void pg_time_now_lazy(pg_time_usec_t *now)
Definition: pgbench.c:895
static bool verbose_errors
Definition: pgbench.c:776
static bool canContinueOnError(EStatus estatus)
Definition: pgbench.c:3309
static int64 getPoissonRand(pg_prng_state *state, double center)
Definition: pgbench.c:1214
#define META_COMMAND
Definition: pgbench.c:687
static bool readCommandResponse(CState *st, MetaCommand meta, char *varprefix)
Definition: pgbench.c:3325
int64 cnt
Definition: pgbench.c:645
int id
Definition: pgbench.c:607
pg_time_usec_t txn_scheduled
Definition: pgbench.c:625
pg_time_usec_t stmt_begin
Definition: pgbench.c:628
int command
Definition: pgbench.c:618
int use_file
Definition: pgbench.c:617
ConditionalStack cstack
Definition: pgbench.c:609
pg_prng_state random_state
Definition: pgbench.c:640
pg_time_usec_t txn_begin
Definition: pgbench.c:627
EStatus estatus
Definition: pgbench.c:637
PGconn * con
Definition: pgbench.c:606
pg_prng_state cs_func_rs
Definition: pgbench.c:615
uint32 tries
Definition: pgbench.c:641
bool ** prepared
Definition: pgbench.c:631
ConnectionStateEnum state
Definition: pgbench.c:608
int64 retries
Definition: pgbench.c:760
char * varprefix
Definition: pgbench.c:757
int type
Definition: pgbench.c:752
MetaCommand meta
Definition: pgbench.c:753
SimpleStats stats
Definition: pgbench.c:759
int64 failures
Definition: pgbench.c:761
int64 throttle_trigger
Definition: pgbench.c:669
pg_prng_state ts_throttle_rs
Definition: pgbench.c:666
pg_time_usec_t conn_duration
Definition: pgbench.c:676

References addToSimpleStats(), Assert(), canContinueOnError(), 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, Command::retries, sendCommand(), SQL_COMMAND, sql_script, start, 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 8038 of file pgbench.c.

8040{
8041 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 3110 of file pgbench.c.

3112{
3113 Assert(st->prepared == NULL);
3114
3115 st->prepared = pg_malloc(sizeof(bool *) * num_scripts);
3116 for (int i = 0; i < num_scripts; i++)
3117 {
3118 ParsedScript *script = &sql_script[i];
3119 int numcmds;
3120
3121 for (numcmds = 0; script->commands[numcmds] != NULL; numcmds++)
3122 ;
3123 st->prepared[i] = pg_malloc0(sizeof(bool) * numcmds);
3124 }
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
int i
Definition: isn.c:77

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

1977{
1978 char *p,
1979 *name,
1980 *val;
1981
1982 p = sql;
1983 while ((p = strchr(p, ':')) != NULL)
1984 {
1985 int eaten;
1986
1987 name = parseVariable(p, &eaten);
1988 if (name == NULL)
1989 {
1990 while (*p == ':')
1991 {
1992 p++;
1993 }
1994 continue;
1995 }
1996
1997 val = getVariable(variables, name);
1998 free(name);
1999 if (val == NULL)
2000 {
2001 p++;
2002 continue;
2003 }
2004
2005 p = replaceVariable(&sql, p, eaten, val);
2006 }
2007
2008 return sql;
#define free(a)
Definition: header.h:65
static char * parseVariable(const char *sql, int *eaten)
Definition: pgbench.c:1928
static char * getVariable(Variables *variables, char *name)
Definition: pgbench.c:1670
static char * replaceVariable(char **sql, char *param, int len, char *value)
Definition: pgbench.c:1955
const char * name

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

Referenced by sendCommand().

◆ canContinueOnError()

static bool canContinueOnError ( EStatus  estatus)
static

Definition at line 3309 of file pgbench.c.

3311{
3312 return (continue_on_error &&
3313 estatus == ESTATUS_OTHER_SQL_ERROR);
static bool continue_on_error
Definition: pgbench.c:779

References continue_on_error, and ESTATUS_OTHER_SQL_ERROR.

Referenced by advanceConnectionState(), and readCommandResponse().

◆ canRetryError()

static bool canRetryError ( EStatus  estatus)
static

Definition at line 3298 of file pgbench.c.

3300{
3301 return (estatus == ESTATUS_SERIALIZATION_ERROR ||
3302 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 5994 of file pgbench.c.

5996{
5997 /* statically check conditional structure */
5999 int i;
6000
6001 for (i = 0; ps->commands[i] != NULL; i++)
6002 {
6003 Command *cmd = ps->commands[i];
6004
6005 if (cmd->type == META_COMMAND)
6006 {
6007 switch (cmd->meta)
6008 {
6009 case META_IF:
6011 break;
6012 case META_ELIF:
6014 ConditionError(ps->desc, i + 1, "\\elif without matching \\if");
6016 ConditionError(ps->desc, i + 1, "\\elif after \\else");
6017 break;
6018 case META_ELSE:
6020 ConditionError(ps->desc, i + 1, "\\else without matching \\if");
6022 ConditionError(ps->desc, i + 1, "\\else after \\else");
6024 break;
6025 case META_ENDIF:
6026 if (!conditional_stack_pop(cs))
6027 ConditionError(ps->desc, i + 1, "\\endif without matching \\if");
6028 break;
6029 default:
6030 /* ignore anything else... */
6031 break;
6032 }
6033 }
6034 }
6035 if (!conditional_stack_empty(cs))
6036 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:5984

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

5353{
5354 if (initialize_steps[0] == '\0')
5355 pg_fatal("no initialization steps specified");
5356
5357 for (const char *step = initialize_steps; *step != '\0'; step++)
5358 {
5359 if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
5360 {
5361 pg_log_error("unrecognized initialization step \"%c\"", *step);
5362 pg_log_error_detail("Allowed step characters are: \"" ALL_INIT_STEPS "\".");
5363 exit(1);
5364 }
5365 }
#define pg_log_error_detail(...)
Definition: logging.h:109
#define ALL_INIT_STEPS
Definition: pgbench.c:164

References ALL_INIT_STEPS, pg_fatal, pg_log_error, and pg_log_error_detail.

Referenced by main().

◆ chooseScript()

static int chooseScript ( TState thread)
static

Definition at line 3088 of file pgbench.c.

3090{
3091 int i = 0;
3092 int64 w;
3093
3094 if (num_scripts == 1)
3095 return 0;
3096
3097 w = getrand(&thread->ts_choose_rs, 0, total_weight - 1);
3098 do
3099 {
3100 w -= sql_script[i++].weight;
3101 } while (w >= 0);
3102
3103 return i - 1;
int64_t int64
Definition: c.h:539
static int64 total_weight
Definition: pgbench.c:774
static int64 getrand(pg_prng_state *state, int64 min, int64 max)
Definition: pgbench.c:1137
int weight
Definition: pgbench.c:767
pg_prng_state ts_choose_rs
Definition: pgbench.c:665

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

8052{
8053 FD_ZERO(&sa->fds);
8054 sa->maxfd = -1;

Referenced by threadRun().

◆ coerceToBool()

static bool coerceToBool ( PgBenchValue pval,
bool *  bval 
)
static

Definition at line 2043 of file pgbench.c.

2045{
2046 if (pval->type == PGBT_BOOLEAN)
2047 {
2048 *bval = pval->u.bval;
2049 return true;
2050 }
2051 else /* NULL, INT or DOUBLE */
2052 {
2053 pg_log_error("cannot coerce %s to boolean", valueTypeName(pval));
2054 *bval = false; /* suppress uninitialized-variable warnings */
2055 return false;
2056 }
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:2021
@ PGBT_BOOLEAN
Definition: pgbench.h:40
PgBenchValueType type
Definition: pgbench.h:46
bool bval
Definition: pgbench.h:51
union PgBenchValue::@37 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 2112 of file pgbench.c.

2114{
2115 if (pval->type == PGBT_DOUBLE)
2116 {
2117 *dval = pval->u.dval;
2118 return true;
2119 }
2120 else if (pval->type == PGBT_INT)
2121 {
2122 *dval = (double) pval->u.ival;
2123 return true;
2124 }
2125 else /* BOOLEAN or NULL */
2126 {
2127 pg_log_error("cannot coerce %s to double", valueTypeName(pval));
2128 return false;
2129 }
@ 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 2084 of file pgbench.c.

2086{
2087 if (pval->type == PGBT_INT)
2088 {
2089 *ival = pval->u.ival;
2090 return true;
2091 }
2092 else if (pval->type == PGBT_DOUBLE)
2093 {
2094 double dval = rint(pval->u.dval);
2095
2096 if (isnan(dval) || !FLOAT8_FITS_IN_INT64(dval))
2097 {
2098 pg_log_error("double to int overflow for %f", dval);
2099 return false;
2100 }
2101 *ival = (int64) dval;
2102 return true;
2103 }
2104 else /* BOOLEAN or NULL */
2105 {
2106 pg_log_error("cannot coerce %s to int", valueTypeName(pval));
2107 return false;
2108 }
#define FLOAT8_FITS_IN_INT64(num)
Definition: c.h:1095

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

3074{
3075 /*
3076 * Errors should only be detected during an SQL command or the
3077 * \endpipeline meta command. Any other case triggers an assertion
3078 * failure.
3079 */
3082
3083 pg_log_info("client %d got an error in command %d (SQL) of script %d; %s",
3084 st->id, st->command, st->use_file, message);
#define pg_log_info(...)
Definition: logging.h:124

References Assert(), CState::command, ParsedScript::commands, CState::id, Command::meta, META_ENDPIPELINE, 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 3062 of file pgbench.c.

3064{
3065 pg_log_error("client %d aborted in command %d (%s) of script %d; %s",
3066 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 1635 of file pgbench.c.

1637{
1638 return strcmp(((const Variable *) v1)->name,
1639 ((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 1236 of file pgbench.c.

1238{
1239 double b = pow(2.0, s - 1.0);
1240 double x,
1241 t,
1242 u,
1243 v;
1244
1245 /* Ensure n is sane */
1246 if (n <= 1)
1247 return 1;
1248
1249 while (true)
1250 {
1251 /* random variates */
1252 u = pg_prng_double(state);
1253 v = pg_prng_double(state);
1254
1255 x = floor(pow(u, -1.0 / (s - 1.0)));
1256
1257 t = pow(1.0 + 1.0 / x, s - 1.0);
1258 /* reject if too large or out of bound */
1259 if (v * x * (t - 1.0) / (b - 1.0) <= t / b && x <= n)
1260 break;
1261 }
1262 return (int64) x;
int b
Definition: isn.c:74
int x
Definition: isn.c:75
double pg_prng_double(pg_prng_state *state)
Definition: pg_prng.c:268
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 5984 of file pgbench.c.

5986{
5987 pg_fatal("condition error in script \"%s\" command %d: %s",
5988 desc, cmdn, msg);

References pg_fatal.

Referenced by CheckConditional().

◆ create_sql_command()

static Command * create_sql_command ( PQExpBuffer  buf)
static

Definition at line 5697 of file pgbench.c.

5699{
5700 Command *my_command;
5701 char *p = skip_sql_comments(buf->data);
5702
5703 if (p == NULL)
5704 return NULL;
5705
5706 /* Allocate and initialize Command structure */
5707 my_command = (Command *) pg_malloc(sizeof(Command));
5708 initPQExpBuffer(&my_command->lines);
5709 appendPQExpBufferStr(&my_command->lines, p);
5710 my_command->first_line = NULL; /* this is set later */
5711 my_command->type = SQL_COMMAND;
5712 my_command->meta = META_NONE;
5713 my_command->argc = 0;
5714 my_command->retries = 0;
5715 my_command->failures = 0;
5716 memset(my_command->argv, 0, sizeof(my_command->argv));
5717 my_command->varprefix = NULL; /* allocated later, if needed */
5718 my_command->expr = NULL;
5719 initSimpleStats(&my_command->stats);
5720 my_command->prepname = NULL; /* set later, if needed */
5721
5722 return my_command;
static char * buf
Definition: pg_test_fsync.c:72
static char * skip_sql_comments(char *sql_command)
Definition: pgbench.c:5662
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1429
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:90
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367
PQExpBufferData lines
Definition: pgbench.c:750
PgBenchExpr * expr
Definition: pgbench.c:758
char * argv[MAX_ARGS]
Definition: pgbench.c:755
char * first_line
Definition: pgbench.c:751
int argc
Definition: pgbench.c:754
char * prepname
Definition: pgbench.c:756

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

4873{
4874 PQExpBufferData query;
4875
4876 /* we must have to create some partitions */
4877 Assert(partitions > 0);
4878
4879 fprintf(stderr, "creating %d partitions...\n", partitions);
4880
4881 initPQExpBuffer(&query);
4882
4883 for (int p = 1; p <= partitions; p++)
4884 {
4886 {
4887 int64 part_size = (naccounts * (int64) scale + partitions - 1) / partitions;
4888
4889 printfPQExpBuffer(&query,
4890 "create%s table pgbench_accounts_%d\n"
4891 " partition of pgbench_accounts\n"
4892 " for values from (",
4893 unlogged_tables ? " unlogged" : "", p);
4894
4895 /*
4896 * For RANGE, we use open-ended partitions at the beginning and
4897 * end to allow any valid value for the primary key. Although the
4898 * actual minimum and maximum values can be derived from the
4899 * scale, it is more generic and the performance is better.
4900 */
4901 if (p == 1)
4902 appendPQExpBufferStr(&query, "minvalue");
4903 else
4904 appendPQExpBuffer(&query, INT64_FORMAT, (p - 1) * part_size + 1);
4905
4906 appendPQExpBufferStr(&query, ") to (");
4907
4908 if (p < partitions)
4909 appendPQExpBuffer(&query, INT64_FORMAT, p * part_size + 1);
4910 else
4911 appendPQExpBufferStr(&query, "maxvalue");
4912
4913 appendPQExpBufferChar(&query, ')');
4914 }
4915 else if (partition_method == PART_HASH)
4916 printfPQExpBuffer(&query,
4917 "create%s table pgbench_accounts_%d\n"
4918 " partition of pgbench_accounts\n"
4919 " for values with (modulus %d, remainder %d)",
4920 unlogged_tables ? " unlogged" : "", p,
4921 partitions, p - 1);
4922 else /* cannot get there */
4923 Assert(0);
4924
4925 /*
4926 * Per ddlinfo in initCreateTables, fillfactor is needed on table
4927 * pgbench_accounts.
4928 */
4929 appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4930
4931 executeStatement(con, query.data);
4932 }
4933
4934 termPQExpBuffer(&query);
#define INT64_FORMAT
Definition: c.h:560
#define fprintf(file, fmt, msg)
Definition: cubescan.l:21
static int scale
Definition: pgbench.c:182
static int partitions
Definition: pgbench.c:224
static int fillfactor
Definition: pgbench.c:188
static partition_method_t partition_method
Definition: pgbench.c:234
static bool unlogged_tables
Definition: pgbench.c:193
#define naccounts
Definition: pgbench.c:246
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1539
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().

◆ discardAvailableResults()

static void discardAvailableResults ( CState st)
static

Definition at line 3249 of file pgbench.c.

3251{
3252 PGresult *res = NULL;
3253
3254 for (;;)
3255 {
3256 res = PQgetResult(st->con);
3257
3258 /*
3259 * Read and discard results until PQgetResult() returns NULL (no more
3260 * results) or a connection failure is detected. If the pipeline
3261 * status is PQ_PIPELINE_ABORTED, more results may still be available
3262 * even after PQgetResult() returns NULL, so continue reading in that
3263 * case.
3264 */
3265 if ((res == NULL && PQpipelineStatus(st->con) != PQ_PIPELINE_ABORTED) ||
3266 PQstatus(st->con) == CONNECTION_BAD)
3267 break;
3268
3269 PQclear(res);
3270 }
3271 PQclear(res);
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:7641
@ CONNECTION_BAD
Definition: libpq-fe.h:85
@ PQ_PIPELINE_ABORTED
Definition: libpq-fe.h:189

References CState::con, CONNECTION_BAD, PQ_PIPELINE_ABORTED, PQclear, PQgetResult, PQpipelineStatus(), and PQstatus().

Referenced by getSQLErrorStatus(), and readCommandResponse().

◆ discardUntilSync()

static int discardUntilSync ( CState st)
static

Definition at line 3568 of file pgbench.c.

3570{
3571 bool received_sync = false;
3572
3573 /*
3574 * Send a Sync message to ensure at least one PGRES_PIPELINE_SYNC is
3575 * received and to avoid an infinite loop, since all earlier ones may have
3576 * already been received.
3577 */
3578 if (!PQpipelineSync(st->con))
3579 {
3580 pg_log_error("client %d aborted: failed to send a pipeline sync",
3581 st->id);
3582 return 0;
3583 }
3584
3585 /*
3586 * Continue reading results until the last sync point, i.e., until
3587 * reaching null just after PGRES_PIPELINE_SYNC.
3588 */
3589 for (;;)
3590 {
3591 PGresult *res = PQgetResult(st->con);
3592
3593 if (PQstatus(st->con) == CONNECTION_BAD)
3594 {
3595 pg_log_error("client %d aborted while rolling back the transaction after an error; perhaps the backend died while processing",
3596 st->id);
3597 PQclear(res);
3598 return 0;
3599 }
3600
3602 received_sync = true;
3603 else if (received_sync && res == NULL)
3604 {
3605 /*
3606 * Reset ongoing sync count to 0 since all PGRES_PIPELINE_SYNC
3607 * results have been discarded.
3608 */
3609 st->num_syncs = 0;
3610 break;
3611 }
3612 else
3613 {
3614 /*
3615 * If a PGRES_PIPELINE_SYNC is followed by something other than
3616 * PGRES_PIPELINE_SYNC or NULL, another PGRES_PIPELINE_SYNC will
3617 * appear later. Reset received_sync to false to wait for it.
3618 */
3619 received_sync = false;
3620 }
3621 PQclear(res);
3622 }
3623
3624 /* exit pipeline */
3625 if (PQexitPipelineMode(st->con) != 1)
3626 {
3627 pg_log_error("client %d aborted: failed to exit pipeline mode for rolling back the failed transaction",
3628 st->id);
3629 return 0;
3630 }
3631 return 1;
int PQexitPipelineMode(PGconn *conn)
Definition: fe-exec.c:3089
int PQpipelineSync(PGconn *conn)
Definition: fe-exec.c:3288
@ PGRES_PIPELINE_SYNC
Definition: libpq-fe.h:139
int num_syncs
Definition: pgbench.c:619

References CState::con, CONNECTION_BAD, CState::id, CState::num_syncs, pg_log_error, PGRES_PIPELINE_SYNC, PQclear, PQexitPipelineMode(), PQgetResult, PQpipelineSync(), PQresultStatus, and PQstatus().

Referenced by advanceConnectionState().

◆ disconnect_all()

static void disconnect_all ( CState state,
int  length 
)
static

Definition at line 4837 of file pgbench.c.

4839{
4840 int i;
4841
4842 for (i = 0; i < length; i++)
4843 finishCon(&state[i]);

References finishCon(), and i.

Referenced by main(), and threadRun().

◆ doConnect()

static PGconn * doConnect ( void  )
static

Definition at line 1570 of file pgbench.c.

1572{
1573 PGconn *conn;
1574 bool new_pass;
1575 static char *password = NULL;
1576
1577 /*
1578 * Start the connection. Loop until we have a password if requested by
1579 * backend.
1580 */
1581 do
1582 {
1583#define PARAMS_ARRAY_SIZE 7
1584
1585 const char *keywords[PARAMS_ARRAY_SIZE];
1586 const char *values[PARAMS_ARRAY_SIZE];
1587
1588 keywords[0] = "host";
1589 values[0] = pghost;
1590 keywords[1] = "port";
1591 values[1] = pgport;
1592 keywords[2] = "user";
1593 values[2] = username;
1594 keywords[3] = "password";
1595 values[3] = password;
1596 keywords[4] = "dbname";
1597 values[4] = dbName;
1598 keywords[5] = "fallback_application_name";
1599 values[5] = progname;
1600 keywords[6] = NULL;
1601 values[6] = NULL;
1602
1603 new_pass = false;
1604
1606
1607 if (!conn)
1608 {
1609 pg_log_error("connection to database \"%s\" failed", dbName);
1610 return NULL;
1611 }
1612
1613 if (PQstatus(conn) == CONNECTION_BAD &&
1615 !password)
1616 {
1617 PQfinish(conn);
1618 password = simple_prompt("Password: ", false);
1619 new_pass = true;
1620 }
1621 } while (new_pass);
1622
1623 /* check to see that the backend connection was successfully made */
1625 {
1627 PQfinish(conn);
1628 return NULL;
1629 }
1630
1631 return conn;
static Datum values[MAXATTR]
Definition: bootstrap.c:153
int PQconnectionNeedsPassword(const PGconn *conn)
Definition: fe-connect.c:7757
void PQfinish(PGconn *conn)
Definition: fe-connect.c:5316
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:770
static const JsonPathKeyword keywords[]
#define PARAMS_ARRAY_SIZE
static const char * pghost
Definition: pgbench.c:295
static const char * username
Definition: pgbench.c:297
static const char * progname
Definition: pgbench.c:300
static const char * pgport
Definition: pgbench.c:296
static const char * dbName
Definition: pgbench.c:298
char * simple_prompt(const char *prompt, bool echo)
Definition: sprompt.c:38
static char * password
Definition: streamutil.c:51
PGconn * conn
Definition: streamutil.c:52

References conn, CONNECTION_BAD, dbName, keywords, 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 4675 of file pgbench.c.

4678{
4679 FILE *logfile = thread->logfile;
4681
4682 Assert(use_log);
4683
4684 /*
4685 * Skip the log entry if sampling is enabled and this row doesn't belong
4686 * to the random sample.
4687 */
4688 if (sample_rate != 0.0 &&
4690 return;
4691
4692 /* should we aggregate the results or not? */
4693 if (agg_interval > 0)
4694 {
4696
4697 /*
4698 * Loop until we reach the interval of the current moment, and print
4699 * any empty intervals in between (this may happen with very low tps,
4700 * e.g. --rate=0.1).
4701 */
4702
4703 while ((next = agg->start_time + agg_interval * INT64CONST(1000000)) <= now)
4704 {
4705 double lag_sum = 0.0;
4706 double lag_sum2 = 0.0;
4707 double lag_min = 0.0;
4708 double lag_max = 0.0;
4709 int64 skipped = 0;
4710 int64 serialization_failures = 0;
4711 int64 deadlock_failures = 0;
4712 int64 other_sql_failures = 0;
4713 int64 retried = 0;
4714 int64 retries = 0;
4715
4716 /* print aggregated report to logfile */
4717 fprintf(logfile, INT64_FORMAT " " INT64_FORMAT " %.0f %.0f %.0f %.0f",
4718 agg->start_time / 1000000, /* seconds since Unix epoch */
4719 agg->cnt,
4720 agg->latency.sum,
4721 agg->latency.sum2,
4722 agg->latency.min,
4723 agg->latency.max);
4724
4725 if (throttle_delay)
4726 {
4727 lag_sum = agg->lag.sum;
4728 lag_sum2 = agg->lag.sum2;
4729 lag_min = agg->lag.min;
4730 lag_max = agg->lag.max;
4731 }
4732 fprintf(logfile, " %.0f %.0f %.0f %.0f",
4733 lag_sum,
4734 lag_sum2,
4735 lag_min,
4736 lag_max);
4737
4738 if (latency_limit)
4739 skipped = agg->skipped;
4740 fprintf(logfile, " " INT64_FORMAT, skipped);
4741
4742 if (max_tries != 1)
4743 {
4744 retried = agg->retried;
4745 retries = agg->retries;
4746 }
4747 fprintf(logfile, " " INT64_FORMAT " " INT64_FORMAT, retried, retries);
4748
4750 {
4751 serialization_failures = agg->serialization_failures;
4752 deadlock_failures = agg->deadlock_failures;
4753 other_sql_failures = agg->other_sql_failures;
4754 }
4756 serialization_failures,
4757 deadlock_failures,
4758 other_sql_failures);
4759
4760 fputc('\n', logfile);
4761
4762 /* reset data and move to next interval */
4763 initStats(agg, next);
4764 }
4765
4766 /* accumulate the current transaction */
4767 accumStats(agg, skipped, latency, lag, st->estatus, st->tries);
4768 }
4769 else
4770 {
4771 /* no, print raw transactions */
4772 if (!skipped && st->estatus == ESTATUS_NO_ERROR)
4773 fprintf(logfile, "%d " INT64_FORMAT " %.0f %d " INT64_FORMAT " "
4775 st->id, st->cnt, latency, st->use_file,
4776 now / 1000000, now % 1000000);
4777 else
4778 fprintf(logfile, "%d " INT64_FORMAT " %s %d " INT64_FORMAT " "
4780 st->id, st->cnt, getResultString(skipped, st->estatus),
4781 st->use_file, now / 1000000, now % 1000000);
4782
4783 if (throttle_delay)
4784 fprintf(logfile, " %.0f", lag);
4785 if (max_tries != 1)
4786 fprintf(logfile, " %u", st->tries - 1);
4787 fputc('\n', logfile);
4788 }
static int32 next
Definition: blutils.c:224
#define INT64CONST(x)
Definition: c.h:556
static FILE * logfile
Definition: pg_regress.c:126
static void accumStats(StatsData *stats, bool skipped, double lat, double lag, EStatus estatus, int64 tries)
Definition: pgbench.c:1487
static uint32 max_tries
Definition: pgbench.c:290
static bool use_log
Definition: pgbench.c:257
static int agg_interval
Definition: pgbench.c:259
static void initStats(StatsData *sd, pg_time_usec_t start)
Definition: pgbench.c:1469
static double sample_rate
Definition: pgbench.c:198
static bool failures_detailed
Definition: pgbench.c:292
static pg_time_usec_t epoch_shift
Definition: pgbench.c:456
static const char * getResultString(bool skipped, EStatus estatus)
Definition: pgbench.c:4642
pg_time_usec_t start_time
Definition: pgbench.c:379
FILE * logfile
Definition: pgbench.c:670
pg_prng_state ts_sample_rs
Definition: pgbench.c:667

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, INT64CONST, StatsData::lag, StatsData::latency, latency_limit, TState::logfile, logfile, SimpleStats::max, max_tries, SimpleStats::min, next, now(), StatsData::other_sql_failures, 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 3522 of file pgbench.c.

3524{
3526
3527 /* We can only retry serialization or deadlock errors. */
3528 if (!canRetryError(st->estatus))
3529 return false;
3530
3531 /*
3532 * We must have at least one option to limit the retrying of transactions
3533 * that got an error.
3534 */
3536
3537 /*
3538 * We cannot retry the error if we have reached the maximum number of
3539 * tries.
3540 */
3541 if (max_tries && st->tries >= max_tries)
3542 return false;
3543
3544 /*
3545 * We cannot retry the error if we spent too much time on this
3546 * transaction.
3547 */
3548 if (latency_limit)
3549 {
3551 if (*now - st->txn_scheduled > latency_limit)
3552 return false;
3553 }
3554
3555 /*
3556 * We cannot retry the error if the benchmark duration is over.
3557 */
3558 if (timer_exceeded)
3559 return false;
3560
3561 /* OK */
3562 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 1812 of file pgbench.c.

1814{
1815 /* total number of variables required now */
1816 needed += variables->nvars;
1817
1818 if (variables->max_vars < needed)
1819 {
1820 variables->max_vars = needed + VARIABLES_ALLOC_MARGIN;
1821 variables->vars = (Variable *)
1822 pg_realloc(variables->vars, variables->max_vars * sizeof(Variable));
1823 }
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
#define VARIABLES_ALLOC_MARGIN
Definition: pgbench.c:311
Variable * vars
Definition: pgbench.c:335
int nvars
Definition: pgbench.c:336
int max_vars
Definition: pgbench.c:343

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

2858{
2859 if (isLazyFunc(func))
2860 return evalLazyFunc(st, func, args, retval);
2861 else
2862 return evalStandardFunc(st, func, args, retval);
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:2164
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2171
static bool evalStandardFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2288

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

2174{
2176 a2;
2177 bool ba1,
2178 ba2;
2179
2180 Assert(isLazyFunc(func) && args != NULL && args->next != NULL);
2181
2182 /* args points to first condition */
2183 if (!evaluateExpr(st, args->expr, &a1))
2184 return false;
2185
2186 /* second condition for AND/OR and corresponding branch for CASE */
2187 args = args->next;
2188
2189 switch (func)
2190 {
2191 case PGBENCH_AND:
2192 if (a1.type == PGBT_NULL)
2193 {
2194 setNullValue(retval);
2195 return true;
2196 }
2197
2198 if (!coerceToBool(&a1, &ba1))
2199 return false;
2200
2201 if (!ba1)
2202 {
2203 setBoolValue(retval, false);
2204 return true;
2205 }
2206
2207 if (!evaluateExpr(st, args->expr, &a2))
2208 return false;
2209
2210 if (a2.type == PGBT_NULL)
2211 {
2212 setNullValue(retval);
2213 return true;
2214 }
2215 else if (!coerceToBool(&a2, &ba2))
2216 return false;
2217 else
2218 {
2219 setBoolValue(retval, ba2);
2220 return true;
2221 }
2222
2223 return true;
2224
2225 case PGBENCH_OR:
2226
2227 if (a1.type == PGBT_NULL)
2228 {
2229 setNullValue(retval);
2230 return true;
2231 }
2232
2233 if (!coerceToBool(&a1, &ba1))
2234 return false;
2235
2236 if (ba1)
2237 {
2238 setBoolValue(retval, true);
2239 return true;
2240 }
2241
2242 if (!evaluateExpr(st, args->expr, &a2))
2243 return false;
2244
2245 if (a2.type == PGBT_NULL)
2246 {
2247 setNullValue(retval);
2248 return true;
2249 }
2250 else if (!coerceToBool(&a2, &ba2))
2251 return false;
2252 else
2253 {
2254 setBoolValue(retval, ba2);
2255 return true;
2256 }
2257
2258 case PGBENCH_CASE:
2259 /* when true, execute branch */
2260 if (valueTruth(&a1))
2261 return evaluateExpr(st, args->expr, retval);
2262
2263 /* now args contains next condition or final else expression */
2264 args = args->next;
2265
2266 /* final else case? */
2267 if (args->next == NULL)
2268 return evaluateExpr(st, args->expr, retval);
2269
2270 /* no, another when, proceed */
2271 return evalLazyFunc(st, PGBENCH_CASE, args, retval);
2272
2273 default:
2274 /* internal error, cannot get here */
2275 Assert(0);
2276 break;
2277 }
2278 return false;
static const FormData_pg_attribute a1
Definition: heap.c:144
static const FormData_pg_attribute a2
Definition: heap.c:157
static void setNullValue(PgBenchValue *pv)
Definition: pgbench.c:2133
static bool evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
Definition: pgbench.c:2871
static void setBoolValue(PgBenchValue *pv, bool bval)
Definition: pgbench.c:2141
static bool valueTruth(PgBenchValue *pval)
Definition: pgbench.c:2063
static bool coerceToBool(PgBenchValue *pval, bool *bval)
Definition: pgbench.c:2043
@ 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(), evalLazyFunc(), evaluateExpr(), isLazyFunc(), PGBENCH_AND, PGBENCH_CASE, PGBENCH_OR, PGBT_NULL, setBoolValue(), setNullValue(), and valueTruth().

Referenced by evalFunc(), and evalLazyFunc().

◆ evalStandardFunc()

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

Definition at line 2288 of file pgbench.c.

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

2873{
2874 switch (expr->etype)
2875 {
2876 case ENODE_CONSTANT:
2877 {
2878 *retval = expr->u.constant;
2879 return true;
2880 }
2881
2882 case ENODE_VARIABLE:
2883 {
2884 Variable *var;
2885
2886 if ((var = lookupVariable(&st->variables, expr->u.variable.varname)) == NULL)
2887 {
2888 pg_log_error("undefined variable \"%s\"", expr->u.variable.varname);
2889 return false;
2890 }
2891
2892 if (!makeVariableValue(var))
2893 return false;
2894
2895 *retval = var->value;
2896 return true;
2897 }
2898
2899 case ENODE_FUNCTION:
2900 return evalFunc(st,
2901 expr->u.function.function,
2902 expr->u.function.args,
2903 retval);
2904
2905 default:
2906 /* internal error which should never occur */
2907 pg_fatal("unexpected enode type in evaluation: %d", expr->etype);
2908 }
static bool evalFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2855
static bool makeVariableValue(Variable *var)
Definition: pgbench.c:1703
static Variable * lookupVariable(Variables *variables, char *name)
Definition: pgbench.c:1643
@ ENODE_VARIABLE
Definition: pgbench.h:60
@ ENODE_CONSTANT
Definition: pgbench.h:59
@ ENODE_FUNCTION
Definition: pgbench.h:61
Variables variables
Definition: pgbench.c:622
struct PgBenchExpr::@38::@39 variable
PgBenchValue constant
Definition: pgbench.h:115
char * varname
Definition: pgbench.h:118
PgBenchFunction function
Definition: pgbench.h:122
PgBenchExprType etype
Definition: pgbench.h:112
union PgBenchExpr::@38 u
PgBenchValue value
Definition: pgbench.c:327

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, CState::variables, and PgBenchExpr::varname.

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

◆ evaluateSleep()

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

Definition at line 3477 of file pgbench.c.

3479{
3480 char *var;
3481 int usec;
3482
3483 if (*argv[1] == ':')
3484 {
3485 if ((var = getVariable(variables, argv[1] + 1)) == NULL)
3486 {
3487 pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[1] + 1);
3488 return false;
3489 }
3490
3491 usec = atoi(var);
3492
3493 /* Raise an error if the value of a variable is not a number */
3494 if (usec == 0 && !isdigit((unsigned char) *var))
3495 {
3496 pg_log_error("%s: invalid sleep time \"%s\" for variable \"%s\"",
3497 argv[0], var, argv[1] + 1);
3498 return false;
3499 }
3500 }
3501 else
3502 usec = atoi(argv[1]);
3503
3504 if (argc > 2)
3505 {
3506 if (pg_strcasecmp(argv[2], "ms") == 0)
3507 usec *= 1000;
3508 else if (pg_strcasecmp(argv[2], "s") == 0)
3509 usec *= 1000000;
3510 }
3511 else
3512 usec *= 1000000;
3513
3514 *usecs = usec;
3515 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 4411 of file pgbench.c.

4413{
4414 Command *command = sql_script[st->use_file].commands[st->command];
4415 int argc;
4416 char **argv;
4417
4418 Assert(command != NULL && command->type == META_COMMAND);
4419
4420 argc = command->argc;
4421 argv = command->argv;
4422
4424 {
4426
4428
4429 printfPQExpBuffer(&buf, "client %d executing \\%s", st->id, argv[0]);
4430 for (int i = 1; i < argc; i++)
4431 appendPQExpBuffer(&buf, " %s", argv[i]);
4432
4433 pg_log_debug("%s", buf.data);
4434
4436 }
4437
4438 if (command->meta == META_SLEEP)
4439 {
4440 int usec;
4441
4442 /*
4443 * A \sleep doesn't execute anything, we just get the delay from the
4444 * argument, and enter the CSTATE_SLEEP state. (The per-command
4445 * latency will be recorded in CSTATE_SLEEP state, not here, after the
4446 * delay has elapsed.)
4447 */
4448 if (!evaluateSleep(&st->variables, argc, argv, &usec))
4449 {
4450 commandFailed(st, "sleep", "execution of meta-command failed");
4451 return CSTATE_ABORTED;
4452 }
4453
4455 st->sleep_until = (*now) + usec;
4456 return CSTATE_SLEEP;
4457 }
4458 else if (command->meta == META_SET)
4459 {
4460 PgBenchExpr *expr = command->expr;
4461 PgBenchValue result;
4462
4463 if (!evaluateExpr(st, expr, &result))
4464 {
4465 commandFailed(st, argv[0], "evaluation of meta-command failed");
4466 return CSTATE_ABORTED;
4467 }
4468
4469 if (!putVariableValue(&st->variables, argv[0], argv[1], &result))
4470 {
4471 commandFailed(st, "set", "assignment of meta-command failed");
4472 return CSTATE_ABORTED;
4473 }
4474 }
4475 else if (command->meta == META_IF)
4476 {
4477 /* backslash commands with an expression to evaluate */
4478 PgBenchExpr *expr = command->expr;
4479 PgBenchValue result;
4480 bool cond;
4481
4482 if (!evaluateExpr(st, expr, &result))
4483 {
4484 commandFailed(st, argv[0], "evaluation of meta-command failed");
4485 return CSTATE_ABORTED;
4486 }
4487
4488 cond = valueTruth(&result);
4490 }
4491 else if (command->meta == META_ELIF)
4492 {
4493 /* backslash commands with an expression to evaluate */
4494 PgBenchExpr *expr = command->expr;
4495 PgBenchValue result;
4496 bool cond;
4497
4499 {
4500 /* elif after executed block, skip eval and wait for endif. */
4502 return CSTATE_END_COMMAND;
4503 }
4504
4505 if (!evaluateExpr(st, expr, &result))
4506 {
4507 commandFailed(st, argv[0], "evaluation of meta-command failed");
4508 return CSTATE_ABORTED;
4509 }
4510
4511 cond = valueTruth(&result);
4514 }
4515 else if (command->meta == META_ELSE)
4516 {
4517 switch (conditional_stack_peek(st->cstack))
4518 {
4519 case IFSTATE_TRUE:
4521 break;
4522 case IFSTATE_FALSE: /* inconsistent if active */
4523 case IFSTATE_IGNORED: /* inconsistent if active */
4524 case IFSTATE_NONE: /* else without if */
4525 case IFSTATE_ELSE_TRUE: /* else after else */
4526 case IFSTATE_ELSE_FALSE: /* else after else */
4527 default:
4528 /* dead code if conditional check is ok */
4529 Assert(false);
4530 }
4531 }
4532 else if (command->meta == META_ENDIF)
4533 {
4536 }
4537 else if (command->meta == META_SETSHELL)
4538 {
4539 if (!runShellCommand(&st->variables, argv[1], argv + 2, argc - 2))
4540 {
4541 commandFailed(st, "setshell", "execution of meta-command failed");
4542 return CSTATE_ABORTED;
4543 }
4544 }
4545 else if (command->meta == META_SHELL)
4546 {
4547 if (!runShellCommand(&st->variables, NULL, argv + 1, argc - 1))
4548 {
4549 commandFailed(st, "shell", "execution of meta-command failed");
4550 return CSTATE_ABORTED;
4551 }
4552 }
4553 else if (command->meta == META_STARTPIPELINE)
4554 {
4555 /*
4556 * In pipeline mode, we use a workflow based on libpq pipeline
4557 * functions.
4558 */
4559 if (querymode == QUERY_SIMPLE)
4560 {
4561 commandFailed(st, "startpipeline", "cannot use pipeline mode with the simple query protocol");
4562 return CSTATE_ABORTED;
4563 }
4564
4565 /*
4566 * If we're in prepared-query mode, we need to prepare all the
4567 * commands that are inside the pipeline before we actually start the
4568 * pipeline itself. This solves the problem that running BEGIN
4569 * ISOLATION LEVEL SERIALIZABLE in a pipeline would fail due to a
4570 * snapshot having been acquired by the prepare within the pipeline.
4571 */
4574
4576 {
4577 commandFailed(st, "startpipeline", "already in pipeline mode");
4578 return CSTATE_ABORTED;
4579 }
4580 if (PQenterPipelineMode(st->con) == 0)
4581 {
4582 commandFailed(st, "startpipeline", "failed to enter pipeline mode");
4583 return CSTATE_ABORTED;
4584 }
4585 }
4586 else if (command->meta == META_SYNCPIPELINE)
4587 {
4589 {
4590 commandFailed(st, "syncpipeline", "not in pipeline mode");
4591 return CSTATE_ABORTED;
4592 }
4593 if (PQsendPipelineSync(st->con) == 0)
4594 {
4595 commandFailed(st, "syncpipeline", "failed to send a pipeline sync");
4596 return CSTATE_ABORTED;
4597 }
4598 st->num_syncs++;
4599 }
4600 else if (command->meta == META_ENDPIPELINE)
4601 {
4603 {
4604 commandFailed(st, "endpipeline", "not in pipeline mode");
4605 return CSTATE_ABORTED;
4606 }
4607 if (!PQpipelineSync(st->con))
4608 {
4609 commandFailed(st, "endpipeline", "failed to send a pipeline sync");
4610 return CSTATE_ABORTED;
4611 }
4612 st->num_syncs++;
4613 /* Now wait for the PGRES_PIPELINE_SYNC and exit pipeline mode there */
4614 /* collect pending results before getting out of pipeline mode */
4615 return CSTATE_WAIT_RESULT;
4616 }
4617
4618 /*
4619 * executing the expression or shell command might have taken a
4620 * non-negligible amount of time, so reset 'now'
4621 */
4622 *now = 0;
4623
4624 return CSTATE_END_COMMAND;
int PQenterPipelineMode(PGconn *conn)
Definition: fe-exec.c:3058
int PQsendPipelineSync(PGconn *conn)
Definition: fe-exec.c:3298
enum pg_log_level __pg_log_level
Definition: logging.c:21
@ PG_LOG_DEBUG
Definition: logging.h:26
static QueryMode querymode
Definition: pgbench.c:721
static void prepareCommandsInPipeline(CState *st)
Definition: pgbench.c:3163
static bool runShellCommand(Variables *variables, char *variable, char **argv, int argc)
Definition: pgbench.c:2956
static bool evaluateSleep(Variables *variables, int argc, char **argv, int *usecs)
Definition: pgbench.c:3477
static bool putVariableValue(Variables *variables, const char *context, char *name, const PgBenchValue *value)
Definition: pgbench.c:1891
pg_time_usec_t sleep_until
Definition: pgbench.c:626

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, META_SYNCPIPELINE, now(), CState::num_syncs, PG_LOG_DEBUG, pg_log_debug, pg_time_now_lazy(), PQ_PIPELINE_OFF, PQ_PIPELINE_ON, PQenterPipelineMode(), PQpipelineStatus(), PQpipelineSync(), PQsendPipelineSync(), 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 1539 of file pgbench.c.

1541{
1542 PGresult *res;
1543
1544 res = PQexec(con, sql);
1545 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1546 {
1547 pg_log_error("query failed: %s", PQerrorMessage(con));
1548 pg_log_error_detail("Query was: %s", sql);
1549 exit(1);
1550 }
1551 PQclear(res);
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2278

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

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

◆ findBuiltin()

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

Definition at line 6263 of file pgbench.c.

6265{
6266 int i,
6267 found = 0,
6268 len = strlen(name);
6269 const BuiltinScript *result = NULL;
6270
6271 for (i = 0; i < lengthof(builtin_script); i++)
6272 {
6273 if (strncmp(builtin_script[i].name, name, len) == 0)
6274 {
6275 result = &builtin_script[i];
6276 found++;
6277 }
6278 }
6279
6280 /* ok, unambiguous result */
6281 if (found == 1)
6282 return result;
6283
6284 /* error cases */
6285 if (found == 0)
6286 pg_log_error("no builtin script found for name \"%s\"", name);
6287 else /* found > 1 */
6288 pg_log_error("ambiguous builtin name: %d builtin scripts found for prefix \"%s\"", found, name);
6289
6291 exit(1);
#define lengthof(array)
Definition: c.h:791
const void size_t len
static void listAvailableScripts(void)
Definition: pgbench.c:6251
static const BuiltinScript builtin_script[]
Definition: pgbench.c:789

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

Referenced by main().

◆ finishCon()

static void finishCon ( CState st)
static

Definition at line 7873 of file pgbench.c.

7875{
7876 if (st->con != NULL)
7877 {
7878 PQfinish(st->con);
7879 st->con = NULL;
7880 }

References CState::con, and PQfinish().

Referenced by advanceConnectionState(), and disconnect_all().

◆ free_command()

static void free_command ( Command command)
static

Definition at line 5726 of file pgbench.c.

5728{
5729 termPQExpBuffer(&command->lines);
5730 pg_free(command->first_line);
5731 for (int i = 0; i < command->argc; i++)
5732 pg_free(command->argv[i]);
5733 pg_free(command->varprefix);
5734
5735 /*
5736 * It should also free expr recursively, but this is currently not needed
5737 * as only gset commands (which do not have an expression) are freed.
5738 */
5739 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 8044 of file pgbench.c.

8046{
8047 pg_free(sa);

References pg_free().

Referenced by threadRun().

◆ get_table_relkind()

static char get_table_relkind ( PGconn con,
const char *  table 
)
static

Definition at line 860 of file pgbench.c.

862{
863 PGresult *res;
864 char *val;
865 char relkind;
866 const char *params[1] = {table};
867 const char *sql =
868 "SELECT relkind FROM pg_catalog.pg_class WHERE oid=$1::pg_catalog.regclass";
869
870 res = PQexecParams(con, sql, 1, NULL, params, NULL, NULL, 0);
872 {
873 pg_log_error("query failed: %s", PQerrorMessage(con));
874 pg_log_error_detail("Query was: %s", sql);
875 exit(1);
876 }
877 val = PQgetvalue(res, 0, 0);
878 Assert(strlen(val) == 1);
879 relkind = val[0];
880 PQclear(res);
881
882 return relkind;
PGresult * PQexecParams(PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char *const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat)
Definition: fe-exec.c:2292
#define PQgetvalue
Definition: libpq-be-fe.h:253
@ PGRES_TUPLES_OK
Definition: libpq-fe.h:128
static const struct lconv_member_info table[]

References Assert(), pg_log_error, pg_log_error_detail, PGRES_TUPLES_OK, PQclear, PQerrorMessage(), PQexecParams(), PQgetvalue, PQresultStatus, table, and val.

Referenced by initPopulateTable().

◆ getExponentialRand()

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

Definition at line 1148 of file pgbench.c.

1151{
1152 double cut,
1153 uniform,
1154 rand;
1155
1156 /* abort if wrong parameter, but must really be checked beforehand */
1157 Assert(parameter > 0.0);
1158 cut = exp(-parameter);
1159 /* pg_prng_double value in [0, 1), uniform in (0, 1] */
1160 uniform = 1.0 - pg_prng_double(state);
1161
1162 /*
1163 * inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
1164 */
1165 Assert((1.0 - cut) != 0.0);
1166 rand = -log(cut + (1.0 - cut) * uniform) / parameter;
1167 /* return int64 random number within between min and max */
1168 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 4630 of file pgbench.c.

4632{
4633 return (stats->serialization_failures +
4634 stats->deadlock_failures +
4635 stats->other_sql_failures);

References StatsData::deadlock_failures, StatsData::other_sql_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 1172 of file pgbench.c.

1175{
1176 double stdev;
1177 double rand;
1178
1179 /* abort if parameter is too low, but must really be checked beforehand */
1180 Assert(parameter >= MIN_GAUSSIAN_PARAM);
1181
1182 /*
1183 * Get normally-distributed random number in the range -parameter <= stdev
1184 * < parameter.
1185 *
1186 * This loop is executed until the number is in the expected range.
1187 *
1188 * As the minimum parameter is 2.0, the probability of looping is low:
1189 * sqrt(-2 ln(r)) <= 2 => r >= e^{-2} ~ 0.135, then when taking the
1190 * average sinus multiplier as 2/pi, we have a 8.6% looping probability in
1191 * the worst case. For a parameter value of 5.0, the looping probability
1192 * is about e^{-5} * 2 / pi ~ 0.43%.
1193 */
1194 do
1195 {
1197 }
1198 while (stdev < -parameter || stdev >= parameter);
1199
1200 /* stdev is in [-parameter, parameter), normalization to [0,1) */
1201 rand = (stdev + parameter) / (parameter * 2.0);
1202
1203 /* return int64 random number within between min and max */
1204 return min + (int64) ((max - min + 1) * rand);
double pg_prng_double_normal(pg_prng_state *state)
Definition: pg_prng.c:290

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

1282{
1283 int64 result;
1284 int i;
1285
1286 result = FNV_OFFSET_BASIS ^ seed;
1287 for (i = 0; i < 8; ++i)
1288 {
1289 int32 octet = val & 0xff;
1290
1291 val = val >> 8;
1292 result = result ^ octet;
1293 result = result * FNV_PRIME;
1294 }
1295
1296 return result;
int32_t int32
Definition: c.h:538
#define FNV_OFFSET_BASIS
Definition: pgbench.c:85
#define FNV_PRIME
Definition: pgbench.c:84

References FNV_OFFSET_BASIS, FNV_PRIME, i, and val.

Referenced by evalStandardFunc().

◆ getHashMurmur2()

static int64 getHashMurmur2 ( int64  val,
uint64  seed 
)
static

Definition at line 1305 of file pgbench.c.

1307{
1308 uint64 result = seed ^ MM2_MUL_TIMES_8; /* sizeof(int64) */
1309 uint64 k = (uint64) val;
1310
1311 k *= MM2_MUL;
1312 k ^= k >> MM2_ROT;
1313 k *= MM2_MUL;
1314
1315 result ^= k;
1316 result *= MM2_MUL;
1317
1318 result ^= result >> MM2_ROT;
1319 result *= MM2_MUL;
1320 result ^= result >> MM2_ROT;
1321
1322 return (int64) result;
uint64_t uint64
Definition: c.h:543
#define MM2_MUL_TIMES_8
Definition: pgbench.c:87
#define MM2_ROT
Definition: pgbench.c:88
#define MM2_MUL
Definition: pgbench.c:86

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

2916{
2917 MetaCommand mc;
2918
2919 if (cmd == NULL)
2920 mc = META_NONE;
2921 else if (pg_strcasecmp(cmd, "set") == 0)
2922 mc = META_SET;
2923 else if (pg_strcasecmp(cmd, "setshell") == 0)
2924 mc = META_SETSHELL;
2925 else if (pg_strcasecmp(cmd, "shell") == 0)
2926 mc = META_SHELL;
2927 else if (pg_strcasecmp(cmd, "sleep") == 0)
2928 mc = META_SLEEP;
2929 else if (pg_strcasecmp(cmd, "if") == 0)
2930 mc = META_IF;
2931 else if (pg_strcasecmp(cmd, "elif") == 0)
2932 mc = META_ELIF;
2933 else if (pg_strcasecmp(cmd, "else") == 0)
2934 mc = META_ELSE;
2935 else if (pg_strcasecmp(cmd, "endif") == 0)
2936 mc = META_ENDIF;
2937 else if (pg_strcasecmp(cmd, "gset") == 0)
2938 mc = META_GSET;
2939 else if (pg_strcasecmp(cmd, "aset") == 0)
2940 mc = META_ASET;
2941 else if (pg_strcasecmp(cmd, "startpipeline") == 0)
2942 mc = META_STARTPIPELINE;
2943 else if (pg_strcasecmp(cmd, "syncpipeline") == 0)
2944 mc = META_SYNCPIPELINE;
2945 else if (pg_strcasecmp(cmd, "endpipeline") == 0)
2946 mc = META_ENDPIPELINE;
2947 else
2948 mc = META_NONE;
2949 return mc;
MetaCommand
Definition: pgbench.c:696

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, META_SYNCPIPELINE, and pg_strcasecmp().

Referenced by process_backslash_command().

◆ getPoissonRand()

static int64 getPoissonRand ( pg_prng_state state,
double  center 
)
static

Definition at line 1214 of file pgbench.c.

1216{
1217 /*
1218 * Use inverse transform sampling to generate a value > 0, such that the
1219 * expected (i.e. average) value is the given argument.
1220 */
1221 double uniform;
1222
1223 /* pg_prng_double value in [0, 1), uniform in (0, 1] */
1224 uniform = 1.0 - pg_prng_double(state);
1225
1226 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 2011 of file pgbench.c.

2014{
2015 int i;
2016
2017 for (i = 0; i < command->argc - 1; i++)
2018 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 1137 of file pgbench.c.

1139{
1140 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 4642 of file pgbench.c.

4644{
4645 if (skipped)
4646 return "skipped";
4647 else if (failures_detailed)
4648 {
4649 switch (estatus)
4650 {
4652 return "serialization";
4654 return "deadlock";
4656 return "other";
4657 default:
4658 /* internal error which should never occur */
4659 pg_fatal("unexpected error status: %d", estatus);
4660 }
4661 }
4662 else
4663 return "failed";

References ESTATUS_DEADLOCK_ERROR, ESTATUS_OTHER_SQL_ERROR, ESTATUS_SERIALIZATION_ERROR, failures_detailed, and pg_fatal.

Referenced by doLog().

◆ getSQLErrorStatus()

static EStatus getSQLErrorStatus ( CState st,
const char *  sqlState 
)
static

Definition at line 3277 of file pgbench.c.

3279{
3281 if (PQstatus(st->con) == CONNECTION_BAD)
3282 return ESTATUS_CONN_ERROR;
3283
3284 if (sqlState != NULL)
3285 {
3286 if (strcmp(sqlState, ERRCODE_T_R_SERIALIZATION_FAILURE) == 0)
3288 else if (strcmp(sqlState, ERRCODE_T_R_DEADLOCK_DETECTED) == 0)
3290 }
3291
static void discardAvailableResults(CState *st)
Definition: pgbench.c:3249
#define ERRCODE_T_R_DEADLOCK_DETECTED
Definition: pgbench.c:78
#define ERRCODE_T_R_SERIALIZATION_FAILURE
Definition: pgbench.c:77

References CState::con, CONNECTION_BAD, discardAvailableResults(), ERRCODE_T_R_DEADLOCK_DETECTED, ERRCODE_T_R_SERIALIZATION_FAILURE, ESTATUS_CONN_ERROR, ESTATUS_DEADLOCK_ERROR, ESTATUS_OTHER_SQL_ERROR, ESTATUS_SERIALIZATION_ERROR, and PQstatus().

Referenced by readCommandResponse().

◆ GetTableInfo()

static void GetTableInfo ( PGconn con,
bool  scale_given 
)
static

Definition at line 5456 of file pgbench.c.

5458{
5459 PGresult *res;
5460
5461 /*
5462 * get the scaling factor that should be same as count(*) from
5463 * pgbench_branches if this is not a custom query
5464 */
5465 res = PQexec(con, "select count(*) from pgbench_branches");
5466 if (PQresultStatus(res) != PGRES_TUPLES_OK)
5467 {
5468 char *sqlState = PQresultErrorField(res, PG_DIAG_SQLSTATE);
5469
5470 pg_log_error("could not count number of branches: %s", PQerrorMessage(con));
5471
5472 if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) == 0)
5473 pg_log_error_hint("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".",
5474 PQdb(con));
5475
5476 exit(1);
5477 }
5478 scale = atoi(PQgetvalue(res, 0, 0));
5479 if (scale < 0)
5480 pg_fatal("invalid count(*) from pgbench_branches: \"%s\"",
5481 PQgetvalue(res, 0, 0));
5482 PQclear(res);
5483
5484 /* warn if we override user-given -s switch */
5485 if (scale_given)
5486 pg_log_warning("scale option ignored, using count from pgbench_branches table (%d)",
5487 scale);
5488
5489 /*
5490 * Get the partition information for the first "pgbench_accounts" table
5491 * found in search_path.
5492 *
5493 * The result is empty if no "pgbench_accounts" is found.
5494 *
5495 * Otherwise, it always returns one row even if the table is not
5496 * partitioned (in which case the partition strategy is NULL).
5497 *
5498 * The number of partitions can be 0 even for partitioned tables, if no
5499 * partition is attached.
5500 *
5501 * We assume no partitioning on any failure, so as to avoid failing on an
5502 * old version without "pg_partitioned_table".
5503 */
5504 res = PQexec(con,
5505 "select o.n, p.partstrat, pg_catalog.count(i.inhparent) "
5506 "from pg_catalog.pg_class as c "
5507 "join pg_catalog.pg_namespace as n on (n.oid = c.relnamespace) "
5508 "cross join lateral (select pg_catalog.array_position(pg_catalog.current_schemas(true), n.nspname)) as o(n) "
5509 "left join pg_catalog.pg_partitioned_table as p on (p.partrelid = c.oid) "
5510 "left join pg_catalog.pg_inherits as i on (c.oid = i.inhparent) "
5511 "where c.relname = 'pgbench_accounts' and o.n is not null "
5512 "group by 1, 2 "
5513 "order by 1 asc "
5514 "limit 1");
5515
5516 if (PQresultStatus(res) != PGRES_TUPLES_OK)
5517 {
5518 /* probably an older version, coldly assume no partitioning */
5520 partitions = 0;
5521 }
5522 else if (PQntuples(res) == 0)
5523 {
5524 /*
5525 * This case is unlikely as pgbench already found "pgbench_branches"
5526 * above to compute the scale.
5527 */
5528 pg_log_error("no pgbench_accounts table found in \"search_path\"");
5529 pg_log_error_hint("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".", PQdb(con));
5530 exit(1);
5531 }
5532 else /* PQntuples(res) == 1 */
5533 {
5534 /* normal case, extract partition information */
5535 if (PQgetisnull(res, 0, 1))
5537 else
5538 {
5539 char *ps = PQgetvalue(res, 0, 1);
5540
5541 /* column must be there */
5542 Assert(ps != NULL);
5543
5544 if (strcmp(ps, "r") == 0)
5546 else if (strcmp(ps, "h") == 0)
5548 else
5549 {
5550 /* possibly a newer version with new partition method */
5551 pg_fatal("unexpected partition method: \"%s\"", ps);
5552 }
5553 }
5554
5555 partitions = atoi(PQgetvalue(res, 0, 2));
5556 }
5557
5558 PQclear(res);
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:7538
#define PQresultErrorField
Definition: libpq-be-fe.h:249
#define PQgetisnull
Definition: libpq-be-fe.h:255
#define PQntuples
Definition: libpq-be-fe.h:251
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:79
#define pg_log_warning(...)
Definition: pgfnames.c:24
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:57

References Assert(), ERRCODE_UNDEFINED_TABLE, 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, and scale.

Referenced by main().

◆ getTransactionStatus()

static TStatus getTransactionStatus ( PGconn con)
static

Definition at line 3638 of file pgbench.c.

3640{
3641 PGTransactionStatusType tx_status;
3642
3643 tx_status = PQtransactionStatus(con);
3644 switch (tx_status)
3645 {
3646 case PQTRANS_IDLE:
3647 return TSTATUS_IDLE;
3648 case PQTRANS_INTRANS:
3649 case PQTRANS_INERROR:
3650 return TSTATUS_IN_BLOCK;
3651 case PQTRANS_UNKNOWN:
3652 /* PQTRANS_UNKNOWN is expected given a broken connection */
3653 if (PQstatus(con) == CONNECTION_BAD)
3654 return TSTATUS_CONN_ERROR;
3655 /* fall through */
3656 case PQTRANS_ACTIVE:
3657 default:
3658
3659 /*
3660 * We cannot find out whether we are in a transaction block or
3661 * not. Internal error which should never occur.
3662 */
3663 pg_log_error("unexpected transaction status %d", tx_status);
3664 return TSTATUS_OTHER_ERROR;
3665 }
3666
3667 /* not reached */
3668 Assert(false);
3669 return TSTATUS_OTHER_ERROR;
PGTransactionStatusType PQtransactionStatus(const PGconn *conn)
Definition: fe-connect.c:7649
PGTransactionStatusType
Definition: libpq-fe.h:146
@ PQTRANS_INTRANS
Definition: libpq-fe.h:149
@ PQTRANS_IDLE
Definition: libpq-fe.h:147
@ PQTRANS_ACTIVE
Definition: libpq-fe.h:148
@ PQTRANS_UNKNOWN
Definition: libpq-fe.h:151
@ PQTRANS_INERROR
Definition: libpq-fe.h:150

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

1672{
1673 Variable *var;
1674 char stringform[64];
1675
1676 var = lookupVariable(variables, name);
1677 if (var == NULL)
1678 return NULL; /* not found */
1679
1680 if (var->svalue)
1681 return var->svalue; /* we have it in string form */
1682
1683 /* We need to produce a string equivalent of the value */
1684 Assert(var->value.type != PGBT_NO_VALUE);
1685 if (var->value.type == PGBT_NULL)
1686 snprintf(stringform, sizeof(stringform), "NULL");
1687 else if (var->value.type == PGBT_BOOLEAN)
1688 snprintf(stringform, sizeof(stringform),
1689 "%s", var->value.u.bval ? "true" : "false");
1690 else if (var->value.type == PGBT_INT)
1691 snprintf(stringform, sizeof(stringform),
1692 INT64_FORMAT, var->value.u.ival);
1693 else if (var->value.type == PGBT_DOUBLE)
1694 snprintf(stringform, sizeof(stringform),
1695 "%.*g", DBL_DIG, var->value.u.dval);
1696 else /* internal error, unexpected type */
1697 Assert(0);
1698 var->svalue = pg_strdup(stringform);
1699 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:239
char * svalue
Definition: pgbench.c:326

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

1268{
1269 int64 n = max - min + 1;
1270
1271 /* abort if parameter is invalid */
1273
1274 return min - 1 + computeIterativeZipfian(state, n, s);
static int64 computeIterativeZipfian(pg_prng_state *state, int64 n, double s)
Definition: pgbench.c:1236

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

7891{
7892 timer_exceeded = true;

References timer_exceeded.

Referenced by setalarm().

◆ initAccount()

static void initAccount ( PQExpBufferData sql,
int64  curr 
)
static

Definition at line 5063 of file pgbench.c.

5065{
5066 /* "filler" column defaults to blank padded empty string */
5068 INT64_FORMAT "\t" INT64_FORMAT "\t0\t\n",
5069 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 5045 of file pgbench.c.

5047{
5048 /* "filler" column uses NULL */
5050 INT64_FORMAT "\t0\t\\N\n",
5051 curr + 1);

References INT64_FORMAT, and printfPQExpBuffer().

Referenced by initGenerateDataClientSide().

◆ initCreateFKeys()

static void initCreateFKeys ( PGconn con)
static

Definition at line 5325 of file pgbench.c.

5327{
5328 static const char *const DDLKEYs[] = {
5329 "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
5330 "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
5331 "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
5332 "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
5333 "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
5334 };
5335 int i;
5336
5337 fprintf(stderr, "creating foreign keys...\n");
5338 for (i = 0; i < lengthof(DDLKEYs); i++)
5339 {
5340 executeStatement(con, DDLKEYs[i]);
5341 }

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

Referenced by runInitSteps().

◆ initCreatePKeys()

static void initCreatePKeys ( PGconn con)
static

Definition at line 5287 of file pgbench.c.

5289{
5290 static const char *const DDLINDEXes[] = {
5291 "alter table pgbench_branches add primary key (bid)",
5292 "alter table pgbench_tellers add primary key (tid)",
5293 "alter table pgbench_accounts add primary key (aid)"
5294 };
5295 int i;
5296 PQExpBufferData query;
5297
5298 fprintf(stderr, "creating primary keys...\n");
5299 initPQExpBuffer(&query);
5300
5301 for (i = 0; i < lengthof(DDLINDEXes); i++)
5302 {
5303 resetPQExpBuffer(&query);
5304 appendPQExpBufferStr(&query, DDLINDEXes[i]);
5305
5306 if (index_tablespace != NULL)
5307 {
5308 char *escape_tablespace;
5309
5310 escape_tablespace = PQescapeIdentifier(con, index_tablespace,
5311 strlen(index_tablespace));
5312 appendPQExpBuffer(&query, " using index tablespace %s", escape_tablespace);
5313 PQfreemem(escape_tablespace);
5314 }
5315
5316 executeStatement(con, query.data);
5317 }
5318
5319 termPQExpBuffer(&query);
void PQfreemem(void *ptr)
Definition: fe-exec.c:4048
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:4425
static char * index_tablespace
Definition: pgbench.c:218
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 4940 of file pgbench.c.

4942{
4943 /*
4944 * Note: TPC-B requires at least 100 bytes per row, and the "filler"
4945 * fields in these table declarations were intended to comply with that.
4946 * The pgbench_accounts table complies with that because the "filler"
4947 * column is set to blank-padded empty string. But for all other tables
4948 * the columns default to NULL and so don't actually take any space. We
4949 * could fix that by giving them non-null default values. However, that
4950 * would completely break comparability of pgbench results with prior
4951 * versions. Since pgbench has never pretended to be fully TPC-B compliant
4952 * anyway, we stick with the historical behavior.
4953 */
4954 struct ddlinfo
4955 {
4956 const char *table; /* table name */
4957 const char *smcols; /* column decls if accountIDs are 32 bits */
4958 const char *bigcols; /* column decls if accountIDs are 64 bits */
4959 int declare_fillfactor;
4960 };
4961 static const struct ddlinfo DDLs[] = {
4962 {
4963 "pgbench_history",
4964 "tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)",
4965 "tid int,bid int,aid bigint,delta int,mtime timestamp,filler char(22)",
4966 0
4967 },
4968 {
4969 "pgbench_tellers",
4970 "tid int not null,bid int,tbalance int,filler char(84)",
4971 "tid int not null,bid int,tbalance int,filler char(84)",
4972 1
4973 },
4974 {
4975 "pgbench_accounts",
4976 "aid int not null,bid int,abalance int,filler char(84)",
4977 "aid bigint not null,bid int,abalance int,filler char(84)",
4978 1
4979 },
4980 {
4981 "pgbench_branches",
4982 "bid int not null,bbalance int,filler char(88)",
4983 "bid int not null,bbalance int,filler char(88)",
4984 1
4985 }
4986 };
4987 int i;
4988 PQExpBufferData query;
4989
4990 fprintf(stderr, "creating tables...\n");
4991
4992 initPQExpBuffer(&query);
4993
4994 for (i = 0; i < lengthof(DDLs); i++)
4995 {
4996 const struct ddlinfo *ddl = &DDLs[i];
4997
4998 /* Construct new create table statement. */
4999 printfPQExpBuffer(&query, "create%s table %s(%s)",
5000 (unlogged_tables && partition_method == PART_NONE) ? " unlogged" : "",
5001 ddl->table,
5002 (scale >= SCALE_32BIT_THRESHOLD) ? ddl->bigcols : ddl->smcols);
5003
5004 /* Partition pgbench_accounts table */
5005 if (partition_method != PART_NONE && strcmp(ddl->table, "pgbench_accounts") == 0)
5006 appendPQExpBuffer(&query,
5007 " partition by %s (aid)", PARTITION_METHOD[partition_method]);
5008 else if (ddl->declare_fillfactor)
5009 {
5010 /* fillfactor is only expected on actual tables */
5011 appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
5012 }
5013
5014 if (tablespace != NULL)
5015 {
5016 char *escape_tablespace;
5017
5018 escape_tablespace = PQescapeIdentifier(con, tablespace, strlen(tablespace));
5019 appendPQExpBuffer(&query, " tablespace %s", escape_tablespace);
5020 PQfreemem(escape_tablespace);
5021 }
5022
5023 executeStatement(con, query.data);
5024 }
5025
5026 termPQExpBuffer(&query);
5027
5029 createPartitions(con);
static void createPartitions(PGconn *con)
Definition: pgbench.c:4871
static const char *const PARTITION_METHOD[]
Definition: pgbench.c:235
#define SCALE_32BIT_THRESHOLD
Definition: pgbench.c:255
static char * tablespace
Definition: pgbench.c:217

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

Referenced by runInitSteps().

◆ initDropTables()

static void initDropTables ( PGconn con)
static

Definition at line 4849 of file pgbench.c.

4851{
4852 fprintf(stderr, "dropping old tables...\n");
4853
4854 /*
4855 * We drop all the tables in one command, so that whether there are
4856 * foreign key dependencies or not doesn't matter.
4857 */
4858 executeStatement(con, "drop table if exists "
4859 "pgbench_accounts, "
4860 "pgbench_branches, "
4861 "pgbench_history, "
4862 "pgbench_tellers");

References executeStatement(), and fprintf.

Referenced by runInitSteps().

◆ initGenerateDataClientSide()

static void initGenerateDataClientSide ( PGconn con)
static

Definition at line 5197 of file pgbench.c.

5199{
5200 fprintf(stderr, "generating data (client-side)...\n");
5201
5202 /*
5203 * we do all of this in one transaction to enable the backend's
5204 * data-loading optimizations
5205 */
5206 executeStatement(con, "begin");
5207
5208 /* truncate away any old data */
5209 initTruncateTables(con);
5210
5211 /*
5212 * fill branches, tellers, accounts in that order in case foreign keys
5213 * already exist
5214 */
5215 initPopulateTable(con, "pgbench_branches", nbranches, initBranch);
5216 initPopulateTable(con, "pgbench_tellers", ntellers, initTeller);
5217 initPopulateTable(con, "pgbench_accounts", naccounts, initAccount);
5218
5219 executeStatement(con, "commit");
static void initTeller(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:5054
static void initBranch(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:5045
#define ntellers
Definition: pgbench.c:245
static void initTruncateTables(PGconn *con)
Definition: pgbench.c:5035
static void initAccount(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:5063
#define nbranches
Definition: pgbench.c:244
static void initPopulateTable(PGconn *con, const char *table, int64 base, initRowMethod init_row)
Definition: pgbench.c:5072

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

5231{
5232 PQExpBufferData sql;
5233
5234 fprintf(stderr, "generating data (server-side)...\n");
5235
5236 /*
5237 * we do all of this in one transaction to enable the backend's
5238 * data-loading optimizations
5239 */
5240 executeStatement(con, "begin");
5241
5242 /* truncate away any old data */
5243 initTruncateTables(con);
5244
5245 initPQExpBuffer(&sql);
5246
5247 printfPQExpBuffer(&sql,
5248 "insert into pgbench_branches(bid,bbalance) "
5249 "select bid, 0 "
5250 "from generate_series(1, %d) as bid", nbranches * scale);
5251 executeStatement(con, sql.data);
5252
5253 printfPQExpBuffer(&sql,
5254 "insert into pgbench_tellers(tid,bid,tbalance) "
5255 "select tid, (tid - 1) / %d + 1, 0 "
5256 "from generate_series(1, %d) as tid", ntellers, ntellers * scale);
5257 executeStatement(con, sql.data);
5258
5259 printfPQExpBuffer(&sql,
5260 "insert into pgbench_accounts(aid,bid,abalance,filler) "
5261 "select aid, (aid - 1) / %d + 1, 0, '' "
5262 "from generate_series(1, " INT64_FORMAT ") as aid",
5264 executeStatement(con, sql.data);
5265
5266 termPQExpBuffer(&sql);
5267
5268 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 5072 of file pgbench.c.

5075{
5076 int n;
5077 int64 k;
5078 int chars = 0;
5079 int prev_chars = 0;
5080 PGresult *res;
5081 PQExpBufferData sql;
5082 char copy_statement[256];
5083 const char *copy_statement_fmt = "copy %s from stdin";
5084 int64 total = base * scale;
5085
5086 /* used to track elapsed time and estimate of the remaining time */
5088 int log_interval = 1;
5089
5090 /* Stay on the same line if reporting to a terminal */
5091 char eol = isatty(fileno(stderr)) ? '\r' : '\n';
5092
5093 initPQExpBuffer(&sql);
5094
5095 /* Use COPY with FREEZE on v14 and later for all ordinary tables */
5096 if ((PQserverVersion(con) >= 140000) &&
5097 get_table_relkind(con, table) == RELKIND_RELATION)
5098 copy_statement_fmt = "copy %s from stdin with (freeze on)";
5099
5100
5101 n = pg_snprintf(copy_statement, sizeof(copy_statement), copy_statement_fmt, table);
5102 if (n >= sizeof(copy_statement))
5103 pg_fatal("invalid buffer size: must be at least %d characters long", n);
5104 else if (n == -1)
5105 pg_fatal("invalid format string");
5106
5107 res = PQexec(con, copy_statement);
5108
5109 if (PQresultStatus(res) != PGRES_COPY_IN)
5110 pg_fatal("unexpected copy in result: %s", PQerrorMessage(con));
5111 PQclear(res);
5112
5113 start = pg_time_now();
5114
5115 for (k = 0; k < total; k++)
5116 {
5117 int64 j = k + 1;
5118
5119 init_row(&sql, k);
5120 if (PQputline(con, sql.data))
5121 pg_fatal("PQputline failed");
5122
5123 if (CancelRequested)
5124 break;
5125
5126 /*
5127 * If we want to stick with the original logging, print a message each
5128 * 100k inserted rows.
5129 */
5130 if ((!use_quiet) && (j % 100000 == 0))
5131 {
5132 double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
5133 double remaining_sec = ((double) total - j) * elapsed_sec / j;
5134
5135 chars = fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) of %s done (elapsed %.2f s, remaining %.2f s)",
5136 j, total,
5137 (int) ((j * 100) / total),
5138 table, elapsed_sec, remaining_sec);
5139
5140 /*
5141 * If the previous progress message is longer than the current
5142 * one, add spaces to the current line to fully overwrite any
5143 * remaining characters from the previous message.
5144 */
5145 if (prev_chars > chars)
5146 fprintf(stderr, "%*c", prev_chars - chars, ' ');
5147 fputc(eol, stderr);
5148 prev_chars = chars;
5149 }
5150 /* let's not call the timing for each row, but only each 100 rows */
5151 else if (use_quiet && (j % 100 == 0))
5152 {
5153 double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
5154 double remaining_sec = ((double) total - j) * elapsed_sec / j;
5155
5156 /* have we reached the next interval (or end)? */
5157 if ((j == total) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS))
5158 {
5159 chars = fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) of %s done (elapsed %.2f s, remaining %.2f s)",
5160 j, total,
5161 (int) ((j * 100) / total),
5162 table, elapsed_sec, remaining_sec);
5163
5164 /*
5165 * If the previous progress message is longer than the current
5166 * one, add spaces to the current line to fully overwrite any
5167 * remaining characters from the previous message.
5168 */
5169 if (prev_chars > chars)
5170 fprintf(stderr, "%*c", prev_chars - chars, ' ');
5171 fputc(eol, stderr);
5172 prev_chars = chars;
5173
5174 /* skip to the next interval */
5175 log_interval = (int) ceil(elapsed_sec / LOG_STEP_SECONDS);
5176 }
5177 }
5178 }
5179
5180 if (chars != 0 && eol != '\n')
5181 fprintf(stderr, "%*c\r", chars, ' '); /* Clear the current line */
5182
5183 if (PQputline(con, "\\.\n"))
5184 pg_fatal("very last PQputline failed");
5185 if (PQendcopy(con))
5186 pg_fatal("PQendcopy failed");
5187
5188 termPQExpBuffer(&sql);
volatile sig_atomic_t CancelRequested
Definition: cancel.c:59
int PQserverVersion(const PGconn *conn)
Definition: fe-connect.c:7694
int PQendcopy(PGconn *conn)
Definition: fe-exec.c:2965
int PQputline(PGconn *conn, const char *string)
Definition: fe-exec.c:2934
int j
Definition: isn.c:78
@ PGRES_COPY_IN
Definition: libpq-fe.h:132
static char get_table_relkind(PGconn *con, const char *table)
Definition: pgbench.c:860
#define LOG_STEP_SECONDS
Definition: pgbench.c:166
static bool use_quiet
Definition: pgbench.c:258
int int pg_snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static char chars[TZ_MAX_CHARS]
Definition: zic.c:401

References CancelRequested, chars, PQExpBufferData::data, fprintf, get_table_relkind(), initPQExpBuffer(), INT64_FORMAT, j, LOG_STEP_SECONDS, pg_fatal, pg_snprintf(), PG_TIME_GET_DOUBLE, pg_time_now(), PGRES_COPY_IN, PQclear, PQendcopy(), PQerrorMessage(), PQexec(), PQputline(), PQresultStatus, PQserverVersion(), scale, start, table, termPQExpBuffer(), and use_quiet.

Referenced by initGenerateDataClientSide().

◆ initRandomState()

static void initRandomState ( pg_prng_state state)
static

Definition at line 1123 of file pgbench.c.

1125{
uint64 pg_prng_uint64(pg_prng_state *state)
Definition: pg_prng.c:134
void pg_prng_seed(pg_prng_state *state, uint64 seed)
Definition: pg_prng.c:89
static pg_prng_state base_random_sequence
Definition: pgbench.c:485

References base_random_sequence, pg_prng_seed(), and pg_prng_uint64().

Referenced by main().

◆ initSimpleStats()

static void initSimpleStats ( SimpleStats ss)
static

Definition at line 1429 of file pgbench.c.

1431{
1432 memset(ss, 0, sizeof(SimpleStats));

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

◆ initStats()

◆ initTeller()

static void initTeller ( PQExpBufferData sql,
int64  curr 
)
static

Definition at line 5054 of file pgbench.c.

5056{
5057 /* "filler" column uses NULL */
5059 INT64_FORMAT "\t" INT64_FORMAT "\t0\t\\N\n",
5060 curr + 1, curr / ntellers + 1);

References INT64_FORMAT, ntellers, and printfPQExpBuffer().

Referenced by initGenerateDataClientSide().

◆ initTruncateTables()

static void initTruncateTables ( PGconn con)
static

Definition at line 5035 of file pgbench.c.

5037{
5038 executeStatement(con, "truncate table "
5039 "pgbench_accounts, "
5040 "pgbench_branches, "
5041 "pgbench_history, "
5042 "pgbench_tellers");

References executeStatement().

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

◆ initVacuum()

static void initVacuum ( PGconn con)
static

Definition at line 5274 of file pgbench.c.

5276{
5277 fprintf(stderr, "vacuuming...\n");
5278 executeStatement(con, "vacuum analyze pgbench_branches");
5279 executeStatement(con, "vacuum analyze pgbench_tellers");
5280 executeStatement(con, "vacuum analyze pgbench_accounts");
5281 executeStatement(con, "vacuum analyze pgbench_history");

References executeStatement(), and fprintf.

Referenced by runInitSteps().

◆ is_an_int()

static bool is_an_int ( const char *  str)
static

Definition at line 986 of file pgbench.c.

988{
989 const char *ptr = str;
990
991 /* skip leading spaces; cast is consistent with strtoint64 */
992 while (*ptr && isspace((unsigned char) *ptr))
993 ptr++;
994
995 /* skip sign */
996 if (*ptr == '+' || *ptr == '-')
997 ptr++;
998
999 /* at least one digit */
1000 if (*ptr && !isdigit((unsigned char) *ptr))
1001 return false;
1002
1003 /* eat all digits */
1004 while (*ptr && isdigit((unsigned char) *ptr))
1005 ptr++;
1006
1007 /* must have reached end of string */
1008 return *ptr == '\0';
const char * str

References str.

Referenced by makeVariableValue().

◆ isLazyFunc()

static bool isLazyFunc ( PgBenchFunction  func)
static

Definition at line 2164 of file pgbench.c.

2166{
2167 return func == PGBENCH_AND || func == PGBENCH_OR || func == PGBENCH_CASE;

References PGBENCH_AND, PGBENCH_CASE, and PGBENCH_OR.

Referenced by evalFunc(), and evalLazyFunc().

◆ listAvailableScripts()

static void listAvailableScripts ( void  )
static

Definition at line 6251 of file pgbench.c.

6253{
6254 int i;
6255
6256 fprintf(stderr, "Available builtin scripts:\n");
6257 for (i = 0; i < lengthof(builtin_script); i++)
6258 fprintf(stderr, " %13s: %s\n", builtin_script[i].name, builtin_script[i].desc);
6259 fprintf(stderr, "\n");

References builtin_script, fprintf, i, lengthof, and name.

Referenced by findBuiltin(), and main().

◆ lookupCreateVariable()

static Variable * lookupCreateVariable ( Variables variables,
const char *  context,
char *  name 
)
static

Definition at line 1831 of file pgbench.c.

1833{
1834 Variable *var;
1835
1836 var = lookupVariable(variables, name);
1837 if (var == NULL)
1838 {
1839 /*
1840 * Check for the name only when declaring a new variable to avoid
1841 * overhead.
1842 */
1844 {
1845 pg_log_error("%s: invalid variable name: \"%s\"", context, name);
1846 return NULL;
1847 }
1848
1849 /* Create variable at the end of the array */
1850 enlargeVariables(variables, 1);
1851
1852 var = &(variables->vars[variables->nvars]);
1853
1854 var->name = pg_strdup(name);
1855 var->svalue = NULL;
1856 /* caller is expected to initialize remaining fields */
1857
1858 variables->nvars++;
1859 /* we don't re-sort the array till we have to */
1860 variables->vars_sorted = false;
1861 }
1862
1863 return var;
static bool valid_variable_name(const char *name)
Definition: pgbench.c:1777
static void enlargeVariables(Variables *variables, int needed)
Definition: pgbench.c:1812
char * name
Definition: pgbench.c:325
bool vars_sorted
Definition: pgbench.c:345

References enlargeVariables(), lookupVariable(), name, Variable::name, Variables::nvars, pg_log_error, pg_strdup(), Variable::svalue, valid_variable_name(), Variables::vars, and Variables::vars_sorted.

Referenced by putVariable(), and putVariableValue().

◆ lookupVariable()

static Variable * lookupVariable ( Variables variables,
char *  name 
)
static

Definition at line 1643 of file pgbench.c.

1645{
1646 Variable key;
1647
1648 /* On some versions of Solaris, bsearch of zero items dumps core */
1649 if (variables->nvars <= 0)
1650 return NULL;
1651
1652 /* Sort if we have to */
1653 if (!variables->vars_sorted)
1654 {
1655 qsort(variables->vars, variables->nvars, sizeof(Variable),
1657 variables->vars_sorted = true;
1658 }
1659
1660 /* Now we can search */
1661 key.name = name;
1662 return (Variable *) bsearch(&key,
1663 variables->vars,
1664 variables->nvars,
1665 sizeof(Variable),
static int compareVariableNames(const void *v1, const void *v2)
Definition: pgbench.c:1635
#define qsort(a, b, c, d)
Definition: port.h:479

References compareVariableNames(), sort-test::key, name, Variables::nvars, qsort, Variables::vars, and Variables::vars_sorted.

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

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 6776 of file pgbench.c.

6778{
6779 static struct option long_options[] = {
6780 /* systematic long/short named options */
6781 {"builtin", required_argument, NULL, 'b'},
6782 {"client", required_argument, NULL, 'c'},
6783 {"connect", no_argument, NULL, 'C'},
6784 {"dbname", required_argument, NULL, 'd'},
6785 {"define", required_argument, NULL, 'D'},
6786 {"file", required_argument, NULL, 'f'},
6787 {"fillfactor", required_argument, NULL, 'F'},
6788 {"host", required_argument, NULL, 'h'},
6789 {"initialize", no_argument, NULL, 'i'},
6790 {"init-steps", required_argument, NULL, 'I'},
6791 {"jobs", required_argument, NULL, 'j'},
6792 {"log", no_argument, NULL, 'l'},
6793 {"latency-limit", required_argument, NULL, 'L'},
6794 {"no-vacuum", no_argument, NULL, 'n'},
6795 {"port", required_argument, NULL, 'p'},
6796 {"progress", required_argument, NULL, 'P'},
6797 {"protocol", required_argument, NULL, 'M'},
6798 {"quiet", no_argument, NULL, 'q'},
6799 {"report-per-command", no_argument, NULL, 'r'},
6800 {"rate", required_argument, NULL, 'R'},
6801 {"scale", required_argument, NULL, 's'},
6802 {"select-only", no_argument, NULL, 'S'},
6803 {"skip-some-updates", no_argument, NULL, 'N'},
6804 {"time", required_argument, NULL, 'T'},
6805 {"transactions", required_argument, NULL, 't'},
6806 {"username", required_argument, NULL, 'U'},
6807 {"vacuum-all", no_argument, NULL, 'v'},
6808 /* long-named only options */
6809 {"unlogged-tables", no_argument, NULL, 1},
6810 {"tablespace", required_argument, NULL, 2},
6811 {"index-tablespace", required_argument, NULL, 3},
6812 {"sampling-rate", required_argument, NULL, 4},
6813 {"aggregate-interval", required_argument, NULL, 5},
6814 {"progress-timestamp", no_argument, NULL, 6},
6815 {"log-prefix", required_argument, NULL, 7},
6816 {"foreign-keys", no_argument, NULL, 8},
6817 {"random-seed", required_argument, NULL, 9},
6818 {"show-script", required_argument, NULL, 10},
6819 {"partitions", required_argument, NULL, 11},
6820 {"partition-method", required_argument, NULL, 12},
6821 {"failures-detailed", no_argument, NULL, 13},
6822 {"max-tries", required_argument, NULL, 14},
6823 {"verbose-errors", no_argument, NULL, 15},
6824 {"exit-on-abort", no_argument, NULL, 16},
6825 {"debug", no_argument, NULL, 17},
6826 {"continue-on-error", no_argument, NULL, 18},
6827 {NULL, 0, NULL, 0}
6828 };
6829
6830 int c;
6831 bool is_init_mode = false; /* initialize mode? */
6832 char *initialize_steps = NULL;
6833 bool foreign_keys = false;
6834 bool is_no_vacuum = false;
6835 bool do_vacuum_accounts = false; /* vacuum accounts table? */
6836 int optindex;
6837 bool scale_given = false;
6838
6839 bool benchmarking_option_set = false;
6840 bool initialization_option_set = false;
6841 bool internal_script_used = false;
6842
6843 CState *state; /* status of clients */
6844 TState *threads; /* array of thread */
6845
6847 start_time, /* start up time */
6848 bench_start = 0, /* first recorded benchmarking time */
6849 conn_total_duration; /* cumulated connection time in
6850 * threads */
6851 int64 latency_late = 0;
6852 StatsData stats;
6853 int weight;
6854
6855 int i;
6856 int nclients_dealt;
6857
6858#ifdef HAVE_GETRLIMIT
6859 struct rlimit rlim;
6860#endif
6861
6862 PGconn *con;
6863 char *env;
6864
6865 int exit_code = 0;
6866 struct timeval tv;
6867
6868 /*
6869 * Record difference between Unix time and instr_time time. We'll use
6870 * this for logging and aggregation.
6871 */
6872 gettimeofday(&tv, NULL);
6873 epoch_shift = tv.tv_sec * INT64CONST(1000000) + tv.tv_usec - pg_time_now();
6874
6875 pg_logging_init(argv[0]);
6876 progname = get_progname(argv[0]);
6877
6878 if (argc > 1)
6879 {
6880 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
6881 {
6882 usage();
6883 exit(0);
6884 }
6885 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
6886 {
6887 puts("pgbench (PostgreSQL) " PG_VERSION);
6888 exit(0);
6889 }
6890 }
6891
6892 state = (CState *) pg_malloc0(sizeof(CState));
6893
6894 /* set random seed early, because it may be used while parsing scripts. */
6895 if (!set_random_seed(getenv("PGBENCH_RANDOM_SEED")))
6896 pg_fatal("error while setting random seed from PGBENCH_RANDOM_SEED environment variable");
6897
6898 while ((c = getopt_long(argc, argv, "b:c:Cd:D:f:F:h:iI:j:lL:M:nNp:P:qrR:s:St:T:U:v", long_options, &optindex)) != -1)
6899 {
6900 char *script;
6901
6902 switch (c)
6903 {
6904 case 'b':
6905 if (strcmp(optarg, "list") == 0)
6906 {
6908 exit(0);
6909 }
6910 weight = parseScriptWeight(optarg, &script);
6911 process_builtin(findBuiltin(script), weight);
6912 benchmarking_option_set = true;
6913 internal_script_used = true;
6914 break;
6915 case 'c':
6916 benchmarking_option_set = true;
6917 if (!option_parse_int(optarg, "-c/--clients", 1, INT_MAX,
6918 &nclients))
6919 {
6920 exit(1);
6921 }
6922#ifdef HAVE_GETRLIMIT
6923 if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
6924 pg_fatal("getrlimit failed: %m");
6925
6926 if (rlim.rlim_max < nclients + 3)
6927 {
6928 pg_log_error("need at least %d open files, but system limit is %ld",
6929 nclients + 3, (long) rlim.rlim_max);
6930 pg_log_error_hint("Reduce number of clients, or use limit/ulimit to increase the system limit.");
6931 exit(1);
6932 }
6933
6934 if (rlim.rlim_cur < nclients + 3)
6935 {
6936 rlim.rlim_cur = nclients + 3;
6937 if (setrlimit(RLIMIT_NOFILE, &rlim) == -1)
6938 {
6939 pg_log_error("need at least %d open files, but couldn't raise the limit: %m",
6940 nclients + 3);
6941 pg_log_error_hint("Reduce number of clients, or use limit/ulimit to increase the system limit.");
6942 exit(1);
6943 }
6944 }
6945#endif /* HAVE_GETRLIMIT */
6946 break;
6947 case 'C':
6948 benchmarking_option_set = true;
6949 is_connect = true;
6950 break;
6951 case 'd':
6953 break;
6954 case 'D':
6955 {
6956 char *p;
6957
6958 benchmarking_option_set = true;
6959
6960 if ((p = strchr(optarg, '=')) == NULL || p == optarg || *(p + 1) == '\0')
6961 pg_fatal("invalid variable definition: \"%s\"", optarg);
6962
6963 *p++ = '\0';
6964 if (!putVariable(&state[0].variables, "option", optarg, p))
6965 exit(1);
6966 }
6967 break;
6968 case 'f':
6969 weight = parseScriptWeight(optarg, &script);
6970 process_file(script, weight);
6971 benchmarking_option_set = true;
6972 break;
6973 case 'F':
6974 initialization_option_set = true;
6975 if (!option_parse_int(optarg, "-F/--fillfactor", 10, 100,
6976 &fillfactor))
6977 exit(1);
6978 break;
6979 case 'h':
6981 break;
6982 case 'i':
6983 is_init_mode = true;
6984 break;
6985 case 'I':
6986 pg_free(initialize_steps);
6987 initialize_steps = pg_strdup(optarg);
6988 checkInitSteps(initialize_steps);
6989 initialization_option_set = true;
6990 break;
6991 case 'j': /* jobs */
6992 benchmarking_option_set = true;
6993 if (!option_parse_int(optarg, "-j/--jobs", 1, INT_MAX,
6994 &nthreads))
6995 {
6996 exit(1);
6997 }
6998 break;
6999 case 'l':
7000 benchmarking_option_set = true;
7001 use_log = true;
7002 break;
7003 case 'L':
7004 {
7005 double limit_ms = atof(optarg);
7006
7007 if (limit_ms <= 0.0)
7008 pg_fatal("invalid latency limit: \"%s\"", optarg);
7009 benchmarking_option_set = true;
7010 latency_limit = (int64) (limit_ms * 1000);
7011 }
7012 break;
7013 case 'M':
7014 benchmarking_option_set = true;
7016 if (strcmp(optarg, QUERYMODE[querymode]) == 0)
7017 break;
7018 if (querymode >= NUM_QUERYMODE)
7019 pg_fatal("invalid query mode (-M): \"%s\"", optarg);
7020 break;
7021 case 'n':
7022 is_no_vacuum = true;
7023 break;
7024 case 'N':
7025 process_builtin(findBuiltin("simple-update"), 1);
7026 benchmarking_option_set = true;
7027 internal_script_used = true;
7028 break;
7029 case 'p':
7031 break;
7032 case 'P':
7033 benchmarking_option_set = true;
7034 if (!option_parse_int(optarg, "-P/--progress", 1, INT_MAX,
7035 &progress))
7036 exit(1);
7037 break;
7038 case 'q':
7039 initialization_option_set = true;
7040 use_quiet = true;
7041 break;
7042 case 'r':
7043 benchmarking_option_set = true;
7044 report_per_command = true;
7045 break;
7046 case 'R':
7047 {
7048 /* get a double from the beginning of option value */
7049 double throttle_value = atof(optarg);
7050
7051 benchmarking_option_set = true;
7052
7053 if (throttle_value <= 0.0)
7054 pg_fatal("invalid rate limit: \"%s\"", optarg);
7055 /* Invert rate limit into per-transaction delay in usec */
7056 throttle_delay = 1000000.0 / throttle_value;
7057 }
7058 break;
7059 case 's':
7060 scale_given = true;
7061 if (!option_parse_int(optarg, "-s/--scale", 1, INT_MAX,
7062 &scale))
7063 exit(1);
7064 break;
7065 case 'S':
7066 process_builtin(findBuiltin("select-only"), 1);
7067 benchmarking_option_set = true;
7068 internal_script_used = true;
7069 break;
7070 case 't':
7071 benchmarking_option_set = true;
7072 if (!option_parse_int(optarg, "-t/--transactions", 1, INT_MAX,
7073 &nxacts))
7074 exit(1);
7075 break;
7076 case 'T':
7077 benchmarking_option_set = true;
7078 if (!option_parse_int(optarg, "-T/--time", 1, INT_MAX,
7079 &duration))
7080 exit(1);
7081 break;
7082 case 'U':
7084 break;
7085 case 'v':
7086 benchmarking_option_set = true;
7087 do_vacuum_accounts = true;
7088 break;
7089 case 1: /* unlogged-tables */
7090 initialization_option_set = true;
7091 unlogged_tables = true;
7092 break;
7093 case 2: /* tablespace */
7094 initialization_option_set = true;
7096 break;
7097 case 3: /* index-tablespace */
7098 initialization_option_set = true;
7100 break;
7101 case 4: /* sampling-rate */
7102 benchmarking_option_set = true;
7103 sample_rate = atof(optarg);
7104 if (sample_rate <= 0.0 || sample_rate > 1.0)
7105 pg_fatal("invalid sampling rate: \"%s\"", optarg);
7106 break;
7107 case 5: /* aggregate-interval */
7108 benchmarking_option_set = true;
7109 if (!option_parse_int(optarg, "--aggregate-interval", 1, INT_MAX,
7110 &agg_interval))
7111 exit(1);
7112 break;
7113 case 6: /* progress-timestamp */
7114 progress_timestamp = true;
7115 benchmarking_option_set = true;
7116 break;
7117 case 7: /* log-prefix */
7118 benchmarking_option_set = true;
7120 break;
7121 case 8: /* foreign-keys */
7122 initialization_option_set = true;
7123 foreign_keys = true;
7124 break;
7125 case 9: /* random-seed */
7126 benchmarking_option_set = true;
7127 if (!set_random_seed(optarg))
7128 pg_fatal("error while setting random seed from --random-seed option");
7129 break;
7130 case 10: /* list */
7131 {
7132 const BuiltinScript *s = findBuiltin(optarg);
7133
7134 fprintf(stderr, "-- %s: %s\n%s\n", s->name, s->desc, s->script);
7135 exit(0);
7136 }
7137 break;
7138 case 11: /* partitions */
7139 initialization_option_set = true;
7140 if (!option_parse_int(optarg, "--partitions", 0, INT_MAX,
7141 &partitions))
7142 exit(1);
7143 break;
7144 case 12: /* partition-method */
7145 initialization_option_set = true;
7146 if (pg_strcasecmp(optarg, "range") == 0)
7148 else if (pg_strcasecmp(optarg, "hash") == 0)
7150 else
7151 pg_fatal("invalid partition method, expecting \"range\" or \"hash\", got: \"%s\"",
7152 optarg);
7153 break;
7154 case 13: /* failures-detailed */
7155 benchmarking_option_set = true;
7156 failures_detailed = true;
7157 break;
7158 case 14: /* max-tries */
7159 {
7160 int32 max_tries_arg = atoi(optarg);
7161
7162 if (max_tries_arg < 0)
7163 pg_fatal("invalid number of maximum tries: \"%s\"", optarg);
7164
7165 benchmarking_option_set = true;
7166 max_tries = (uint32) max_tries_arg;
7167 }
7168 break;
7169 case 15: /* verbose-errors */
7170 benchmarking_option_set = true;
7171 verbose_errors = true;
7172 break;
7173 case 16: /* exit-on-abort */
7174 benchmarking_option_set = true;
7175 exit_on_abort = true;
7176 break;
7177 case 17: /* debug */
7179 break;
7180 case 18: /* continue-on-error */
7181 benchmarking_option_set = true;
7182 continue_on_error = true;
7183 break;
7184 default:
7185 /* getopt_long already emitted a complaint */
7186 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
7187 exit(1);
7188 }
7189 }
7190
7191 /* set default script if none */
7192 if (num_scripts == 0 && !is_init_mode)
7193 {
7194 process_builtin(findBuiltin("tpcb-like"), 1);
7195 benchmarking_option_set = true;
7196 internal_script_used = true;
7197 }
7198
7199 /* complete SQL command initialization and compute total weight */
7200 for (i = 0; i < num_scripts; i++)
7201 {
7202 Command **commands = sql_script[i].commands;
7203
7204 for (int j = 0; commands[j] != NULL; j++)
7205 if (commands[j]->type == SQL_COMMAND)
7206 postprocess_sql_command(commands[j]);
7207
7208 /* cannot overflow: weight is 32b, total_weight 64b */
7210 }
7211
7212 if (total_weight == 0 && !is_init_mode)
7213 pg_fatal("total script weight must not be zero");
7214
7215 /* show per script stats if several scripts are used */
7216 if (num_scripts > 1)
7217 per_script_stats = true;
7218
7219 /*
7220 * Don't need more threads than there are clients. (This is not merely an
7221 * optimization; throttle_delay is calculated incorrectly below if some
7222 * threads have no clients assigned to them.)
7223 */
7224 if (nthreads > nclients)
7226
7227 /*
7228 * Convert throttle_delay to a per-thread delay time. Note that this
7229 * might be a fractional number of usec, but that's OK, since it's just
7230 * the center of a Poisson distribution of delays.
7231 */
7233
7234 if (dbName == NULL)
7235 {
7236 if (argc > optind)
7237 dbName = argv[optind++];
7238 else
7239 {
7240 if ((env = getenv("PGDATABASE")) != NULL && *env != '\0')
7241 dbName = env;
7242 else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
7243 dbName = env;
7244 else
7246 }
7247 }
7248
7249 if (optind < argc)
7250 {
7251 pg_log_error("too many command-line arguments (first is \"%s\")",
7252 argv[optind]);
7253 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
7254 exit(1);
7255 }
7256
7257 if (is_init_mode)
7258 {
7259 if (benchmarking_option_set)
7260 pg_fatal("some of the specified options cannot be used in initialization (-i) mode");
7261
7262 if (partitions == 0 && partition_method != PART_NONE)
7263 pg_fatal("--partition-method requires greater than zero --partitions");
7264
7265 /* set default method */
7268
7269 if (initialize_steps == NULL)
7270 initialize_steps = pg_strdup(DEFAULT_INIT_STEPS);
7271
7272 if (is_no_vacuum)
7273 {
7274 /* Remove any vacuum step in initialize_steps */
7275 char *p;
7276
7277 while ((p = strchr(initialize_steps, 'v')) != NULL)
7278 *p = ' ';
7279 }
7280
7281 if (foreign_keys)
7282 {
7283 /* Add 'f' to end of initialize_steps, if not already there */
7284 if (strchr(initialize_steps, 'f') == NULL)
7285 {
7286 initialize_steps = (char *)
7287 pg_realloc(initialize_steps,
7288 strlen(initialize_steps) + 2);
7289 strcat(initialize_steps, "f");
7290 }
7291 }
7292
7293 runInitSteps(initialize_steps);
7294 exit(0);
7295 }
7296 else
7297 {
7298 if (initialization_option_set)
7299 pg_fatal("some of the specified options cannot be used in benchmarking mode");
7300 }
7301
7302 if (nxacts > 0 && duration > 0)
7303 pg_fatal("specify either a number of transactions (-t) or a duration (-T), not both");
7304
7305 /* Use DEFAULT_NXACTS if neither nxacts nor duration is specified. */
7306 if (nxacts <= 0 && duration <= 0)
7308
7309 /* --sampling-rate may be used only with -l */
7310 if (sample_rate > 0.0 && !use_log)
7311 pg_fatal("log sampling (--sampling-rate) is allowed only when logging transactions (-l)");
7312
7313 /* --sampling-rate may not be used with --aggregate-interval */
7314 if (sample_rate > 0.0 && agg_interval > 0)
7315 pg_fatal("log sampling (--sampling-rate) and aggregation (--aggregate-interval) cannot be used at the same time");
7316
7317 if (agg_interval > 0 && !use_log)
7318 pg_fatal("log aggregation is allowed only when actually logging transactions");
7319
7320 if (!use_log && logfile_prefix)
7321 pg_fatal("log file prefix (--log-prefix) is allowed only when logging transactions (-l)");
7322
7323 if (duration > 0 && agg_interval > duration)
7324 pg_fatal("number of seconds for aggregation (%d) must not be higher than test duration (%d)", agg_interval, duration);
7325
7326 if (duration > 0 && agg_interval > 0 && duration % agg_interval != 0)
7327 pg_fatal("duration (%d) must be a multiple of aggregation interval (%d)", duration, agg_interval);
7328
7329 if (progress_timestamp && progress == 0)
7330 pg_fatal("--progress-timestamp is allowed only under --progress");
7331
7332 if (!max_tries)
7333 {
7334 if (!latency_limit && duration <= 0)
7335 pg_fatal("an unlimited number of transaction tries can only be used with --latency-limit or a duration (-T)");
7336 }
7337
7338 /*
7339 * save main process id in the global variable because process id will be
7340 * changed after fork.
7341 */
7342 main_pid = (int) getpid();
7343
7344 if (nclients > 1)
7345 {
7346 state = (CState *) pg_realloc(state, sizeof(CState) * nclients);
7347 memset(state + 1, 0, sizeof(CState) * (nclients - 1));
7348
7349 /* copy any -D switch values to all clients */
7350 for (i = 1; i < nclients; i++)
7351 {
7352 int j;
7353
7354 state[i].id = i;
7355 for (j = 0; j < state[0].variables.nvars; j++)
7356 {
7357 Variable *var = &state[0].variables.vars[j];
7358
7359 if (var->value.type != PGBT_NO_VALUE)
7360 {
7361 if (!putVariableValue(&state[i].variables, "startup",
7362 var->name, &var->value))
7363 exit(1);
7364 }
7365 else
7366 {
7367 if (!putVariable(&state[i].variables, "startup",
7368 var->name, var->svalue))
7369 exit(1);
7370 }
7371 }
7372 }
7373 }
7374
7375 /* other CState initializations */
7376 for (i = 0; i < nclients; i++)
7377 {
7378 state[i].cstack = conditional_stack_create();
7379 initRandomState(&state[i].cs_func_rs);
7380 }
7381
7382 /* opening connection... */
7383 con = doConnect();
7384 if (con == NULL)
7385 pg_fatal("could not create connection for setup");
7386
7387 /* report pgbench and server versions */
7388 printVersion(con);
7389
7390 pg_log_debug("pghost: %s pgport: %s nclients: %d %s: %d dbName: %s",
7391 PQhost(con), PQport(con), nclients,
7392 duration <= 0 ? "nxacts" : "duration",
7393 duration <= 0 ? nxacts : duration, PQdb(con));
7394
7395 if (internal_script_used)
7396 GetTableInfo(con, scale_given);
7397
7398 /*
7399 * :scale variables normally get -s or database scale, but don't override
7400 * an explicit -D switch
7401 */
7402 if (lookupVariable(&state[0].variables, "scale") == NULL)
7403 {
7404 for (i = 0; i < nclients; i++)
7405 {
7406 if (!putVariableInt(&state[i].variables, "startup", "scale", scale))
7407 exit(1);
7408 }
7409 }
7410
7411 /*
7412 * Define a :client_id variable that is unique per connection. But don't
7413 * override an explicit -D switch.
7414 */
7415 if (lookupVariable(&state[0].variables, "client_id") == NULL)
7416 {
7417 for (i = 0; i < nclients; i++)
7418 if (!putVariableInt(&state[i].variables, "startup", "client_id", i))
7419 exit(1);
7420 }
7421
7422 /* set default seed for hash functions */
7423 if (lookupVariable(&state[0].variables, "default_seed") == NULL)
7424 {
7426
7427 for (i = 0; i < nclients; i++)
7428 if (!putVariableInt(&state[i].variables, "startup", "default_seed",
7429 (int64) seed))
7430 exit(1);
7431 }
7432
7433 /* set random seed unless overwritten */
7434 if (lookupVariable(&state[0].variables, "random_seed") == NULL)
7435 {
7436 for (i = 0; i < nclients; i++)
7437 if (!putVariableInt(&state[i].variables, "startup", "random_seed",
7438 random_seed))
7439 exit(1);
7440 }
7441
7442 if (!is_no_vacuum)
7443 {
7444 fprintf(stderr, "starting vacuum...");
7445 tryExecuteStatement(con, "vacuum pgbench_branches");
7446 tryExecuteStatement(con, "vacuum pgbench_tellers");
7447 tryExecuteStatement(con, "truncate pgbench_history");
7448 fprintf(stderr, "end.\n");
7449
7450 if (do_vacuum_accounts)
7451 {
7452 fprintf(stderr, "starting vacuum pgbench_accounts...");
7453 tryExecuteStatement(con, "vacuum analyze pgbench_accounts");
7454 fprintf(stderr, "end.\n");
7455 }
7456 }
7457 PQfinish(con);
7458
7459 /* set up thread data structures */
7460 threads = (TState *) pg_malloc(sizeof(TState) * nthreads);
7461 nclients_dealt = 0;
7462
7463 for (i = 0; i < nthreads; i++)
7464 {
7465 TState *thread = &threads[i];
7466
7467 thread->tid = i;
7468 thread->state = &state[nclients_dealt];
7469 thread->nstate =
7470 (nclients - nclients_dealt + nthreads - i - 1) / (nthreads - i);
7471 initRandomState(&thread->ts_choose_rs);
7473 initRandomState(&thread->ts_sample_rs);
7474 thread->logfile = NULL; /* filled in later */
7475 thread->latency_late = 0;
7476 initStats(&thread->stats, 0);
7477
7478 nclients_dealt += thread->nstate;
7479 }
7480
7481 /* all clients must be assigned to a thread */
7482 Assert(nclients_dealt == nclients);
7483
7484 /* get start up time for the whole computation */
7486
7487 /* set alarm if duration is specified. */
7488 if (duration > 0)
7490
7492 if (errno != 0)
7493 pg_fatal("could not initialize barrier: %m");
7494
7495 /* start all threads but thread 0 which is executed directly later */
7496 for (i = 1; i < nthreads; i++)
7497 {
7498 TState *thread = &threads[i];
7499
7500 thread->create_time = pg_time_now();
7501 errno = THREAD_CREATE(&thread->thread, threadRun, thread);
7502
7503 if (errno != 0)
7504 pg_fatal("could not create thread: %m");
7505 }
7506
7507 /* compute when to stop */
7508 threads[0].create_time = pg_time_now();
7509 if (duration > 0)
7510 end_time = threads[0].create_time + (int64) 1000000 * duration;
7511
7512 /* run thread 0 directly */
7513 (void) threadRun(&threads[0]);
7514
7515 /* wait for other threads and accumulate results */
7516 initStats(&stats, 0);
7517 conn_total_duration = 0;
7518
7519 for (i = 0; i < nthreads; i++)
7520 {
7521 TState *thread = &threads[i];
7522
7523 if (i > 0)
7524 THREAD_JOIN(thread->thread);
7525
7526 for (int j = 0; j < thread->nstate; j++)
7527 if (thread->state[j].state != CSTATE_FINISHED)
7528 exit_code = 2;
7529
7530 /* aggregate thread level stats */
7531 mergeSimpleStats(&stats.latency, &thread->stats.latency);
7532 mergeSimpleStats(&stats.lag, &thread->stats.lag);
7533 stats.cnt += thread->stats.cnt;
7534 stats.skipped += thread->stats.skipped;
7535 stats.retries += thread->stats.retries;
7536 stats.retried += thread->stats.retried;
7538 stats.deadlock_failures += thread->stats.deadlock_failures;
7540 latency_late += thread->latency_late;
7541 conn_total_duration += thread->conn_duration;
7542
7543 /* first recorded benchmarking start time */
7544 if (bench_start == 0 || thread->bench_start < bench_start)
7545 bench_start = thread->bench_start;
7546 }
7547
7548 /*
7549 * All connections should be already closed in threadRun(), so this
7550 * disconnect_all() will be a no-op, but clean up the connections just to
7551 * be sure. We don't need to measure the disconnection delays here.
7552 */
7554
7555 /*
7556 * Beware that performance of short benchmarks with many threads and
7557 * possibly long transactions can be deceptive because threads do not
7558 * start and finish at the exact same time. The total duration computed
7559 * here encompasses all transactions so that tps shown is somehow slightly
7560 * underestimated.
7561 */
7562 printResults(&stats, pg_time_now() - bench_start, conn_total_duration,
7563 bench_start - start_time, latency_late);
7564
7566
7567 if (exit_code != 0)
7568 pg_log_error("Run was aborted; the above results are incomplete.");
7569
7570 return exit_code;
uint32_t uint32
Definition: c.h:542
char * PQport(const PGconn *conn)
Definition: fe-connect.c:7607
char * PQhost(const PGconn *conn)
Definition: fe-connect.c:7571
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:60
#define no_argument
Definition: getopt_long.h:25
#define required_argument
Definition: getopt_long.h:26
void pg_logging_increase_verbosity(void)
Definition: logging.c:185
void pg_logging_init(const char *argv0)
Definition: logging.c:83
bool option_parse_int(const char *optarg, const char *optname, int min_range, int max_range, int *result)
Definition: option_utils.c:50
static time_t start_time
Definition: pg_ctl.c:96
PGDLLIMPORT int optind
Definition: getopt.c:51
PGDLLIMPORT char * optarg
Definition: getopt.c:53
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)
Definition: pgbench.c:6497
static bool putVariableInt(Variables *variables, const char *context, char *name, int64 value)
Definition: pgbench.c:1910
static void GetTableInfo(PGconn *con, bool scale_given)
Definition: pgbench.c:5456
static void initRandomState(pg_prng_state *state)
Definition: pgbench.c:1123
static bool per_script_stats
Definition: pgbench.c:261
static THREAD_FUNC_RETURN_TYPE THREAD_FUNC_CC threadRun(void *arg)
Definition: pgbench.c:7573
static void setalarm(int seconds)
Definition: pgbench.c:7895
static int nthreads
Definition: pgbench.c:265
static bool exit_on_abort
Definition: pgbench.c:778
static bool putVariable(Variables *variables, const char *context, char *name, const char *value)
Definition: pgbench.c:1868
static int nclients
Definition: pgbench.c:264
static void printVersion(PGconn *con)
Definition: pgbench.c:6466
#define DEFAULT_NXACTS
Definition: pgbench.c:167
static void checkInitSteps(const char *initialize_steps)
Definition: pgbench.c:5351
static int progress
Definition: pgbench.c:262
static void postprocess_sql_command(Command *my_command)
Definition: pgbench.c:5746
static bool progress_timestamp
Definition: pgbench.c:263
static const char *const QUERYMODE[]
Definition: pgbench.c:722
static const BuiltinScript * findBuiltin(const char *name)
Definition: pgbench.c:6263
static void mergeSimpleStats(SimpleStats *acc, SimpleStats *ss)
Definition: pgbench.c:1453
#define THREAD_JOIN(handle)
Definition: pgbench.c:150
static char * logfile_prefix
Definition: pgbench.c:299
static bool set_random_seed(const char *seed)
Definition: pgbench.c:6734
static void runInitSteps(const char *initialize_steps)
Definition: pgbench.c:5371
static void process_builtin(const BuiltinScript *bi, int weight)
Definition: pgbench.c:6244
static int parseScriptWeight(const char *option, char **script)
Definition: pgbench.c:6299
static void tryExecuteStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1555
static THREAD_BARRIER_T barrier
Definition: pgbench.c:488
static void process_file(const char *filename, int weight)
Definition: pgbench.c:6218
static int main_pid
Definition: pgbench.c:270
#define THREAD_BARRIER_INIT(barrier, n)
Definition: pgbench.c:153
static void usage(void)
Definition: pgbench.c:904
static void disconnect_all(CState *state, int length)
Definition: pgbench.c:4837
#define DEFAULT_INIT_STEPS
Definition: pgbench.c:163
static int64 random_seed
Definition: pgbench.c:238
#define THREAD_CREATE(handle, function, arg)
Definition: pgbench.c:148
#define THREAD_BARRIER_DESTROY(barrier)
Definition: pgbench.c:156
const char * get_progname(const char *argv0)
Definition: path.c:652
char * c
const char * desc
Definition: pgbench.c:785
const char * name
Definition: pgbench.c:784
const char * script
Definition: pgbench.c:786
pg_time_usec_t create_time
Definition: pgbench.c:673
CState * state
Definition: pgbench.c:657
int tid
Definition: pgbench.c:655
int nstate
Definition: pgbench.c:658
StatsData stats
Definition: pgbench.c:679
THREAD_T thread
Definition: pgbench.c:656
pg_time_usec_t bench_start
Definition: pgbench.c:675
int64 latency_late
Definition: pgbench.c:680
const char * get_user_name_or_exit(const char *progname)
Definition: username.c:74
int gettimeofday(struct timeval *tp, void *tzp)

References agg_interval, Assert(), barrier, base_random_sequence, TState::bench_start, checkInitSteps(), StatsData::cnt, ParsedScript::commands, conditional_stack_create(), TState::conn_duration, continue_on_error, TState::create_time, CSTATE_FINISHED, dbName, StatsData::deadlock_failures, DEFAULT_INIT_STEPS, DEFAULT_NXACTS, BuiltinScript::desc, disconnect_all(), doConnect(), duration, end_time, epoch_shift, exit_on_abort, failures_detailed, fillfactor, findBuiltin(), fprintf, get_progname(), get_user_name_or_exit(), getopt_long(), GetTableInfo(), gettimeofday(), i, index_tablespace, initRandomState(), initStats(), INT64CONST, is_connect, j, StatsData::lag, StatsData::latency, TState::latency_late, latency_limit, listAvailableScripts(), TState::logfile, logfile_prefix, lookupVariable(), main_pid, max_tries, mergeSimpleStats(), Variable::name, BuiltinScript::name, nclients, no_argument, TState::nstate, nthreads, NUM_QUERYMODE, num_scripts, nxacts, optarg, optind, option_parse_int(), StatsData::other_sql_failures, parseScriptWeight(), PART_HASH, PART_NONE, PART_RANGE, partition_method, partitions, per_script_stats, pg_fatal, pg_free(), pg_log_debug, pg_log_error, pg_log_error_hint, pg_logging_increase_verbosity(), pg_logging_init(), pg_malloc(), pg_malloc0(), pg_prng_uint64(), pg_realloc(), pg_strcasecmp(), pg_strdup(), pg_time_now(), PGBT_NO_VALUE, pghost, pgport, postprocess_sql_command(), PQdb(), PQfinish(), PQhost(), PQport(), printResults(), printVersion(), process_builtin(), process_file(), progname, progress, progress_timestamp, putVariable(), putVariableInt(), putVariableValue(), querymode, QUERYMODE, random_seed, report_per_command, required_argument, StatsData::retried, StatsData::retries, runInitSteps(), sample_rate, scale, BuiltinScript::script, StatsData::serialization_failures, set_random_seed(), setalarm(), StatsData::skipped, SQL_COMMAND, sql_script, start_time, CState::state, TState::state, TState::stats, Variable::svalue, tablespace, TState::thread, THREAD_BARRIER_DESTROY, THREAD_BARRIER_INIT, THREAD_CREATE, THREAD_JOIN, threadRun(), throttle_delay, TState::tid, total_weight, tryExecuteStatement(), TState::ts_choose_rs, TState::ts_sample_rs, TState::ts_throttle_rs, type, PgBenchValue::type, unlogged_tables, usage(), use_log, use_quiet, username, Variable::value, verbose_errors, and ParsedScript::weight.

◆ makeVariableValue()

static bool makeVariableValue ( Variable var)
static

Definition at line 1703 of file pgbench.c.

1705{
1706 size_t slen;
1707
1708 if (var->value.type != PGBT_NO_VALUE)
1709 return true; /* no work */
1710
1711 slen = strlen(var->svalue);
1712
1713 if (slen == 0)
1714 /* what should it do on ""? */
1715 return false;
1716
1717 if (pg_strcasecmp(var->svalue, "null") == 0)
1718 {
1719 setNullValue(&var->value);
1720 }
1721
1722 /*
1723 * accept prefixes such as y, ye, n, no... but not for "o". 0/1 are
1724 * recognized later as an int, which is converted to bool if needed.
1725 */
1726 else if (pg_strncasecmp(var->svalue, "true", slen) == 0 ||
1727 pg_strncasecmp(var->svalue, "yes", slen) == 0 ||
1728 pg_strcasecmp(var->svalue, "on") == 0)
1729 {
1730 setBoolValue(&var->value, true);
1731 }
1732 else if (pg_strncasecmp(var->svalue, "false", slen) == 0 ||
1733 pg_strncasecmp(var->svalue, "no", slen) == 0 ||
1734 pg_strcasecmp(var->svalue, "off") == 0 ||
1735 pg_strcasecmp(var->svalue, "of") == 0)
1736 {
1737 setBoolValue(&var->value, false);
1738 }
1739 else if (is_an_int(var->svalue))
1740 {
1741 /* if it looks like an int, it must be an int without overflow */
1742 int64 iv;
1743
1744 if (!strtoint64(var->svalue, false, &iv))
1745 return false;
1746
1747 setIntValue(&var->value, iv);
1748 }
1749 else /* type should be double */
1750 {
1751 double dv;
1752
1753 if (!strtodouble(var->svalue, true, &dv))
1754 {
1755 pg_log_error("malformed variable \"%s\" value: \"%s\"",
1756 var->name, var->svalue);
1757 return false;
1758 }
1759 setDoubleValue(&var->value, dv);
1760 }
1761 return true;
bool strtodouble(const char *str, bool errorOK, double *dv)
Definition: pgbench.c:1094
bool strtoint64(const char *str, bool errorOK, int64 *result)
Definition: pgbench.c:1023
static bool is_an_int(const char *str)
Definition: pgbench.c:986
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
Definition: pgstrcasecmp.c:69

References is_an_int(), Variable::name, pg_log_error, pg_strcasecmp(), pg_strncasecmp(), PGBT_NO_VALUE, setBoolValue(), setDoubleValue(), setIntValue(), setNullValue(), strtodouble(), strtoint64(), Variable::svalue, PgBenchValue::type, and Variable::value.

Referenced by evaluateExpr().

◆ mergeSimpleStats()

static void mergeSimpleStats ( SimpleStats acc,
SimpleStats ss 
)
static

Definition at line 1453 of file pgbench.c.

1455{
1456 if (acc->count == 0 || ss->min < acc->min)
1457 acc->min = ss->min;
1458 if (acc->count == 0 || ss->max > acc->max)
1459 acc->max = ss->max;
1460 acc->count += ss->count;
1461 acc->sum += ss->sum;
1462 acc->sum2 += ss->sum2;

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

Referenced by main(), and printProgressReport().

◆ parseQuery()

static bool parseQuery ( Command cmd)
static

Definition at line 5565 of file pgbench.c.

5567{
5568 char *sql,
5569 *p;
5570
5571 cmd->argc = 1;
5572
5573 p = sql = pg_strdup(cmd->lines.data);
5574 while ((p = strchr(p, ':')) != NULL)
5575 {
5576 char var[13];
5577 char *name;
5578 int eaten;
5579
5580 name = parseVariable(p, &eaten);
5581 if (name == NULL)
5582 {
5583 while (*p == ':')
5584 {
5585 p++;
5586 }
5587 continue;
5588 }
5589
5590 /*
5591 * cmd->argv[0] is the SQL statement itself, so the max number of
5592 * arguments is one less than MAX_ARGS
5593 */
5594 if (cmd->argc >= MAX_ARGS)
5595 {
5596 pg_log_error("statement has too many arguments (maximum is %d): %s",
5597 MAX_ARGS - 1, cmd->lines.data);
5598 pg_free(name);
5599 return false;
5600 }
5601
5602 sprintf(var, "$%d", cmd->argc);
5603 p = replaceVariable(&sql, p, eaten, var);
5604
5605 cmd->argv[cmd->argc] = name;
5606 cmd->argc++;
5607 }
5608
5609 Assert(cmd->argv[0] == NULL);
5610 cmd->argv[0] = sql;
5611 return true;
#define MAX_ARGS
Definition: pgbench.c:693
#define sprintf
Definition: port.h:241

References Command::argc, Command::argv, Assert(), PQExpBufferData::data, Command::lines, MAX_ARGS, name, parseVariable(), pg_free(), pg_log_error, pg_strdup(), replaceVariable(), and sprintf.

Referenced by postprocess_sql_command().

◆ ParseScript()

static void ParseScript ( const char *  script,
const char *  desc,
int  weight 
)
static

Definition at line 6044 of file pgbench.c.

6046{
6048 PsqlScanState sstate;
6049 PQExpBufferData line_buf;
6050 int alloc_num;
6051 int index;
6052
6053#define COMMANDS_ALLOC_NUM 128
6054 alloc_num = COMMANDS_ALLOC_NUM;
6055
6056 /* Initialize all fields of ps */
6057 ps.desc = desc;
6058 ps.weight = weight;
6059 ps.commands = (Command **) pg_malloc(sizeof(Command *) * alloc_num);
6060 initStats(&ps.stats, 0);
6061
6062 /* Prepare to parse script */
6064
6065 /*
6066 * Ideally, we'd scan scripts using the encoding and stdstrings settings
6067 * we get from a DB connection. However, without major rearrangement of
6068 * pgbench's argument parsing, we can't have a DB connection at the time
6069 * we parse scripts. Using SQL_ASCII (encoding 0) should work well enough
6070 * with any backend-safe encoding, though conceivably we could be fooled
6071 * if a script file uses a client-only encoding. We also assume that
6072 * stdstrings should be true, which is a bit riskier.
6073 */
6074 psql_scan_setup(sstate, script, strlen(script), 0, true);
6075
6076 initPQExpBuffer(&line_buf);
6077
6078 index = 0;
6079
6080 for (;;)
6081 {
6082 PsqlScanResult sr;
6083 promptStatus_t prompt;
6084 Command *command = NULL;
6085
6086 resetPQExpBuffer(&line_buf);
6087
6088 sr = psql_scan(sstate, &line_buf, &prompt);
6089
6090 /* If we collected a new SQL command, process that */
6091 command = create_sql_command(&line_buf);
6092
6093 /* store new command */
6094 if (command)
6095 ps.commands[index++] = command;
6096
6097 /* If we reached a backslash, process that */
6098 if (sr == PSCAN_BACKSLASH)
6099 {
6100 int lineno;
6101 int start_offset;
6102
6103 /* Capture location of the backslash */
6104 psql_scan_get_location(sstate, &lineno, &start_offset);
6105 start_offset--;
6106
6107 command = process_backslash_command(sstate, desc,
6108 lineno, start_offset);
6109
6110 if (command)
6111 {
6112 /*
6113 * If this is gset or aset, merge into the preceding command.
6114 * (We don't use a command slot in this case).
6115 */
6116 if (command->meta == META_GSET || command->meta == META_ASET)
6117 {
6118 Command *cmd;
6119
6120 if (index == 0)
6121 syntax_error(desc, lineno, NULL, NULL,
6122 "\\gset must follow an SQL command",
6123 NULL, -1);
6124
6125 cmd = ps.commands[index - 1];
6126
6127 if (cmd->type != SQL_COMMAND ||
6128 cmd->varprefix != NULL)
6129 syntax_error(desc, lineno, NULL, NULL,
6130 "\\gset must follow an SQL command",
6131 cmd->first_line, -1);
6132
6133 /* get variable prefix */
6134 if (command->argc <= 1 || command->argv[1][0] == '\0')
6135 cmd->varprefix = pg_strdup("");
6136 else
6137 cmd->varprefix = pg_strdup(command->argv[1]);
6138
6139 /* update the sql command meta */
6140 cmd->meta = command->meta;
6141
6142 /* cleanup unused command */
6143 free_command(command);
6144
6145 continue;
6146 }
6147
6148 /* Attach any other backslash command as a new command */
6149 ps.commands[index++] = command;
6150 }
6151 }
6152
6153 /*
6154 * Since we used a command slot, allocate more if needed. Note we
6155 * always allocate one more in order to accommodate the NULL
6156 * terminator below.
6157 */
6158 if (index >= alloc_num)
6159 {
6160 alloc_num += COMMANDS_ALLOC_NUM;
6161 ps.commands = (Command **)
6162 pg_realloc(ps.commands, sizeof(Command *) * alloc_num);
6163 }
6164
6165 /* Done if we reached EOF */
6166 if (sr == PSCAN_INCOMPLETE || sr == PSCAN_EOL)
6167 break;
6168 }
6169
6170 ps.commands[index] = NULL;
6171
6172 addScript(&ps);
6173
6174 termPQExpBuffer(&line_buf);
6175 psql_scan_finish(sstate);
6176 psql_scan_destroy(sstate);
void syntax_error(const char *source, int lineno, const char *line, const char *command, const char *msg, const char *more, int column)
Definition: pgbench.c:5626
#define COMMANDS_ALLOC_NUM
static void free_command(Command *command)
Definition: pgbench.c:5726
static Command * create_sql_command(PQExpBuffer buf)
Definition: pgbench.c:5697
static Command * process_backslash_command(PsqlScanState sstate, const char *source, int lineno, int start_offset)
Definition: pgbench.c:5783
static void addScript(const ParsedScript *script)
Definition: pgbench.c:6336
static const PsqlScanCallbacks pgbench_callbacks
Definition: pgbench.c:855
PsqlScanResult
Definition: psqlscan.h:31
@ PSCAN_BACKSLASH
Definition: psqlscan.h:33
@ PSCAN_EOL
Definition: psqlscan.h:35
@ PSCAN_INCOMPLETE
Definition: psqlscan.h:34
enum _promptStatus promptStatus_t
void psql_scan_get_location(PsqlScanState state, int *lineno, int *offset)
Definition: psqlscan.l:1335
void psql_scan_destroy(PsqlScanState state)
Definition: psqlscan.l:1022
PsqlScanResult psql_scan(PsqlScanState state, PQExpBuffer query_buf, promptStatus_t *prompt)
Definition: psqlscan.l:1121
PsqlScanState psql_scan_create(const PsqlScanCallbacks *callbacks)
Definition: psqlscan.l:1001
void psql_scan_setup(PsqlScanState state, const char *line, int line_len, int encoding, bool std_strings)
Definition: psqlscan.l:1059
void psql_scan_finish(PsqlScanState state)
Definition: psqlscan.l:1248
Definition: type.h:96

References addScript(), Command::argc, Command::argv, COMMANDS_ALLOC_NUM, create_sql_command(), Command::first_line, free_command(), initPQExpBuffer(), initStats(), Command::meta, META_ASET, META_GSET, pg_malloc(), pg_realloc(), pg_strdup(), pgbench_callbacks, process_backslash_command(), ps, PSCAN_BACKSLASH, PSCAN_EOL, PSCAN_INCOMPLETE, psql_scan(), psql_scan_create(), psql_scan_destroy(), psql_scan_finish(), psql_scan_get_location(), psql_scan_setup(), resetPQExpBuffer(), SQL_COMMAND, syntax_error(), termPQExpBuffer(), Command::type, and Command::varprefix.

Referenced by process_builtin(), and process_file().

◆ parseScriptWeight()

static int parseScriptWeight ( const char *  option,
char **  script 
)
static

Definition at line 6299 of file pgbench.c.

6301{
6302 char *sep;
6303 int weight;
6304
6305 if ((sep = strrchr(option, WSEP)))
6306 {
6307 int namelen = sep - option;
6308 long wtmp;
6309 char *badp;
6310
6311 /* generate the script name */
6312 *script = pg_malloc(namelen + 1);
6313 strncpy(*script, option, namelen);
6314 (*script)[namelen] = '\0';
6315
6316 /* process digits of the weight spec */
6317 errno = 0;
6318 wtmp = strtol(sep + 1, &badp, 10);
6319 if (errno != 0 || badp == sep + 1 || *badp != '\0')
6320 pg_fatal("invalid weight specification: %s", sep);
6321 if (wtmp > INT_MAX || wtmp < 0)
6322 pg_fatal("weight specification out of range (0 .. %d): %lld",
6323 INT_MAX, (long long) wtmp);
6324 weight = wtmp;
6325 }
6326 else
6327 {
6328 *script = pg_strdup(option);
6329 weight = 1;
6330 }
6331
6332 return weight;
#define WSEP
Definition: pgbench.c:302

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

Referenced by main().

◆ parseVariable()

static char * parseVariable ( const char *  sql,
int *  eaten 
)
static

Definition at line 1928 of file pgbench.c.

1930{
1931 int i = 1; /* starting at 1 skips the colon */
1932 char *name;
1933
1934 /* keep this logic in sync with valid_variable_name() */
1935 if (IS_HIGHBIT_SET(sql[i]) ||
1936 strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1937 "_", sql[i]) != NULL)
1938 i++;
1939 else
1940 return NULL;
1941
1942 while (IS_HIGHBIT_SET(sql[i]) ||
1943 strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1944 "_0123456789", sql[i]) != NULL)
1945 i++;
1946
1947 name = pg_malloc(i);
1948 memcpy(name, &sql[1], i - 1);
1949 name[i - 1] = '\0';
1950
1951 *eaten = i;
1952 return name;
#define IS_HIGHBIT_SET(ch)
Definition: c.h:1158

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

Referenced by assignVariables(), and parseQuery().

◆ permute()

static int64 permute ( const int64  val,
const int64  isize,
const int64  seed 
)
static

Definition at line 1338 of file pgbench.c.

1340{
1341 /* using a high-end PRNG is probably overkill */
1343 uint64 size;
1344 uint64 v;
1345 int masklen;
1346 uint64 mask;
1347 int i;
1348
1349 if (isize < 2)
1350 return 0; /* nothing to permute */
1351
1352 /* Initialize prng state using the seed */
1353 pg_prng_seed(&state, (uint64) seed);
1354
1355 /* Computations are performed on unsigned values */
1356 size = (uint64) isize;
1357 v = (uint64) val % size;
1358
1359 /* Mask to work modulo largest power of 2 less than or equal to size */
1360 masklen = pg_leftmost_one_pos64(size);
1361 mask = (((uint64) 1) << masklen) - 1;
1362
1363 /*
1364 * Permute the input value by applying several rounds of pseudorandom
1365 * bijective transformations. The intention here is to distribute each
1366 * input uniformly randomly across the range, and separate adjacent inputs
1367 * approximately uniformly randomly from each other, leading to a fairly
1368 * random overall choice of permutation.
1369 *
1370 * To separate adjacent inputs, we multiply by a random number modulo
1371 * (mask + 1), which is a power of 2. For this to be a bijection, the
1372 * multiplier must be odd. Since this is known to lead to less randomness
1373 * in the lower bits, we also apply a rotation that shifts the topmost bit
1374 * into the least significant bit. In the special cases where size <= 3,
1375 * mask = 1 and each of these operations is actually a no-op, so we also
1376 * XOR the value with a different random number to inject additional
1377 * randomness. Since the size is generally not a power of 2, we apply
1378 * this bijection on overlapping upper and lower halves of the input.
1379 *
1380 * To distribute the inputs uniformly across the range, we then also apply
1381 * a random offset modulo the full range.
1382 *
1383 * Taken together, these operations resemble a modified linear
1384 * congruential generator, as is commonly used in pseudorandom number
1385 * generators. The number of rounds is fairly arbitrary, but six has been
1386 * found empirically to give a fairly good tradeoff between performance
1387 * and uniform randomness. For small sizes it selects each of the (size!)
1388 * possible permutations with roughly equal probability. For larger
1389 * sizes, not all permutations can be generated, but the intended random
1390 * spread is still produced.
1391 */
1392 for (i = 0; i < 6; i++)
1393 {
1394 uint64 m,
1395 r,
1396 t;
1397
1398 /* Random multiply (by an odd number), XOR and rotate of lower half */
1399 m = (pg_prng_uint64(&state) & mask) | 1;
1400 r = pg_prng_uint64(&state) & mask;
1401 if (v <= mask)
1402 {
1403 v = ((v * m) ^ r) & mask;
1404 v = ((v << 1) & mask) | (v >> (masklen - 1));
1405 }
1406
1407 /* Random multiply (by an odd number), XOR and rotate of upper half */
1408 m = (pg_prng_uint64(&state) & mask) | 1;
1409 r = pg_prng_uint64(&state) & mask;
1410 t = size - 1 - v;
1411 if (t <= mask)
1412 {
1413 t = ((t * m) ^ r) & mask;
1414 t = ((t << 1) & mask) | (t >> (masklen - 1));
1415 v = size - 1 - t;
1416 }
1417
1418 /* Random offset */
1419 r = pg_prng_uint64_range(&state, 0, size - 1);
1420 v = (v + r) % size;
1421 }
1422
1423 return (int64) v;
static int pg_leftmost_one_pos64(uint64 word)
Definition: pg_bitutils.h:72

References i, pg_leftmost_one_pos64(), pg_prng_seed(), pg_prng_uint64(), pg_prng_uint64_range(), and val.

Referenced by evalStandardFunc().

◆ pg_time_now()

static pg_time_usec_t pg_time_now ( void  )
inlinestatic

◆ pg_time_now_lazy()

static void pg_time_now_lazy ( pg_time_usec_t now)
inlinestatic

Definition at line 895 of file pgbench.c.

897{
898 if ((*now) == 0)
899 (*now) = pg_time_now();

References now(), and pg_time_now().

Referenced by advanceConnectionState(), doRetry(), executeMetaCommand(), printVerboseErrorMessages(), processXactStats(), and threadRun().

◆ postprocess_sql_command()

static void postprocess_sql_command ( Command my_command)
static

Definition at line 5746 of file pgbench.c.

5748{
5749 char buffer[128];
5750 static int prepnum = 0;
5751
5752 Assert(my_command->type == SQL_COMMAND);
5753
5754 /* Save the first line for error display. */
5755 strlcpy(buffer, my_command->lines.data, sizeof(buffer));
5756 buffer[strcspn(buffer, "\n\r")] = '\0';
5757 my_command->first_line = pg_strdup(buffer);
5758
5759 /* Parse query and generate prepared statement name, if necessary */
5760 switch (querymode)
5761 {
5762 case QUERY_SIMPLE:
5763 my_command->argv[0] = my_command->lines.data;
5764 my_command->argc++;
5765 break;
5766 case QUERY_PREPARED:
5767 my_command->prepname = psprintf("P_%d", prepnum++);
5768 /* fall through */
5769 case QUERY_EXTENDED:
5770 if (!parseQuery(my_command))
5771 exit(1);
5772 break;
5773 default:
5774 exit(1);
5775 }
static bool parseQuery(Command *cmd)
Definition: pgbench.c:5565
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43

References Command::argc, Command::argv, Assert(), PQExpBufferData::data, Command::first_line, Command::lines, parseQuery(), pg_strdup(), Command::prepname, psprintf(), QUERY_EXTENDED, QUERY_PREPARED, QUERY_SIMPLE, querymode, SQL_COMMAND, strlcpy(), and Command::type.

Referenced by main().

◆ prepareCommand()

static void prepareCommand ( CState st,
int  command_num 
)
static

Definition at line 3130 of file pgbench.c.

3132{
3133 Command *command = sql_script[st->use_file].commands[command_num];
3134
3135 /* No prepare for non-SQL commands */
3136 if (command->type != SQL_COMMAND)
3137 return;
3138
3139 if (!st->prepared)
3141
3142 if (!st->prepared[st->use_file][command_num])
3143 {
3144 PGresult *res;
3145
3146 pg_log_debug("client %d preparing %s", st->id, command->prepname);
3147 res = PQprepare(st->con, command->prepname,
3148 command->argv[0], command->argc - 1, NULL);
3149 if (PQresultStatus(res) != PGRES_COMMAND_OK)
3150 pg_log_error("%s", PQerrorMessage(st->con));
3151 PQclear(res);
3152 st->prepared[st->use_file][command_num] = true;
3153 }
PGresult * PQprepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes)
Definition: fe-exec.c:2322
static void allocCStatePrepared(CState *st)
Definition: pgbench.c:3110

References allocCStatePrepared(), Command::argc, Command::argv, ParsedScript::commands, CState::con, CState::id, pg_log_debug, pg_log_error, PGRES_COMMAND_OK, PQclear, PQerrorMessage(), PQprepare(), PQresultStatus, CState::prepared, Command::prepname, SQL_COMMAND, sql_script, Command::type, and CState::use_file.

Referenced by prepareCommandsInPipeline(), and sendCommand().

◆ prepareCommandsInPipeline()

static void prepareCommandsInPipeline ( CState st)
static

Definition at line 3163 of file pgbench.c.

3165{
3166 int j;
3167 Command **commands = sql_script[st->use_file].commands;
3168
3169 Assert(commands[st->command]->type == META_COMMAND &&
3170 commands[st->command]->meta == META_STARTPIPELINE);
3171
3172 if (!st->prepared)
3174
3175 /*
3176 * We set the 'prepared' flag on the \startpipeline itself to flag that we
3177 * don't need to do this next time without calling prepareCommand(), even
3178 * though we don't actually prepare this command.
3179 */
3180 if (st->prepared[st->use_file][st->command])
3181 return;
3182
3183 for (j = st->command + 1; commands[j] != NULL; j++)
3184 {
3185 if (commands[j]->type == META_COMMAND &&
3186 commands[j]->meta == META_ENDPIPELINE)
3187 break;
3188
3189 prepareCommand(st, j);
3190 }
3191
3192 st->prepared[st->use_file][st->command] = true;
static void prepareCommand(CState *st, int command_num)
Definition: pgbench.c:3130

References allocCStatePrepared(), Assert(), CState::command, ParsedScript::commands, j, Command::meta, META_COMMAND, META_ENDPIPELINE, META_STARTPIPELINE, prepareCommand(), CState::prepared, sql_script, type, Command::type, and CState::use_file.

Referenced by executeMetaCommand().

◆ printProgressReport()

static void printProgressReport ( TState threads,
int64  test_start,
pg_time_usec_t  now,
StatsData last,
int64 last_report 
)
static

Definition at line 6357 of file pgbench.c.

6360{
6361 /* generate and show report */
6362 pg_time_usec_t run = now - *last_report;
6363 int64 cnt,
6364 failures,
6365 retried;
6366 double tps,
6367 total_run,
6368 latency,
6369 sqlat,
6370 lag,
6371 stdev;
6372 char tbuf[315];
6373 StatsData cur;
6374
6375 /*
6376 * Add up the statistics of all threads.
6377 *
6378 * XXX: No locking. There is no guarantee that we get an atomic snapshot
6379 * of the transaction count and latencies, so these figures can well be
6380 * off by a small amount. The progress report's purpose is to give a
6381 * quick overview of how the test is going, so that shouldn't matter too
6382 * much. (If a read from a 64-bit integer is not atomic, you might get a
6383 * "torn" read and completely bogus latencies though!)
6384 */
6385 initStats(&cur, 0);
6386 for (int i = 0; i < nthreads; i++)
6387 {
6388 mergeSimpleStats(&cur.latency, &threads[i].stats.latency);
6389 mergeSimpleStats(&cur.lag, &threads[i].stats.lag);
6390 cur.cnt += threads[i].stats.cnt;
6391 cur.skipped += threads[i].stats.skipped;
6392 cur.retries += threads[i].stats.retries;
6393 cur.retried += threads[i].stats.retried;
6394 cur.serialization_failures +=
6396 cur.deadlock_failures += threads[i].stats.deadlock_failures;
6397 cur.other_sql_failures += threads[i].stats.other_sql_failures;
6398 }
6399
6400 /* we count only actually executed transactions */
6401 cnt = cur.cnt - last->cnt;
6402 total_run = (now - test_start) / 1000000.0;
6403 tps = 1000000.0 * cnt / run;
6404 if (cnt > 0)
6405 {
6406 latency = 0.001 * (cur.latency.sum - last->latency.sum) / cnt;
6407 sqlat = 1.0 * (cur.latency.sum2 - last->latency.sum2) / cnt;
6408 stdev = 0.001 * sqrt(sqlat - 1000000.0 * latency * latency);
6409 lag = 0.001 * (cur.lag.sum - last->lag.sum) / cnt;
6410 }
6411 else
6412 {
6413 latency = sqlat = stdev = lag = 0;
6414 }
6415 failures = getFailures(&cur) - getFailures(last);
6416 retried = cur.retried - last->retried;
6417
6419 {
6420 snprintf(tbuf, sizeof(tbuf), "%.3f s",
6422 }
6423 else
6424 {
6425 /* round seconds are expected, but the thread may be late */
6426 snprintf(tbuf, sizeof(tbuf), "%.1f s", total_run);
6427 }
6428
6429 fprintf(stderr,
6430 "progress: %s, %.1f tps, lat %.3f ms stddev %.3f, " INT64_FORMAT " failed",
6431 tbuf, tps, latency, stdev, failures);
6432
6433 if (throttle_delay)
6434 {
6435 fprintf(stderr, ", lag %.3f ms", lag);
6436 if (latency_limit)
6437 fprintf(stderr, ", " INT64_FORMAT " skipped",
6438 cur.skipped - last->skipped);
6439 }
6440
6441 /* it can be non-zero only if max_tries is not equal to one */
6442 if (max_tries != 1)
6443 fprintf(stderr,
6444 ", " INT64_FORMAT " retried, " INT64_FORMAT " retries",
6445 retried, cur.retries - last->retries);
6446 fprintf(stderr, "\n");
6447
6448 *last = cur;
6449 *last_report = now;
struct cursor * cur
Definition: ecpg.c:29
static int64 getFailures(const StatsData *stats)
Definition: pgbench.c:4630

References StatsData::cnt, cur, StatsData::deadlock_failures, epoch_shift, fprintf, getFailures(), i, initStats(), INT64_FORMAT, StatsData::lag, StatsData::latency, latency_limit, max_tries, mergeSimpleStats(), now(), nthreads, StatsData::other_sql_failures, PG_TIME_GET_DOUBLE, progress_timestamp, StatsData::retried, StatsData::retries, StatsData::serialization_failures, StatsData::skipped, snprintf, TState::stats, SimpleStats::sum, SimpleStats::sum2, and throttle_delay.

Referenced by threadRun().

◆ printResults()

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

Definition at line 6497 of file pgbench.c.

6503{
6504 /* tps is about actually executed transactions during benchmarking */
6505 int64 failures = getFailures(total);
6506 int64 total_cnt = total->cnt + total->skipped + failures;
6507 double bench_duration = PG_TIME_GET_DOUBLE(total_duration);
6508 double tps = total->cnt / bench_duration;
6509
6510 /* Report test parameters. */
6511 printf("transaction type: %s\n",
6512 num_scripts == 1 ? sql_script[0].desc : "multiple scripts");
6513 printf("scaling factor: %d\n", scale);
6514 /* only print partitioning information if some partitioning was detected */
6516 printf("partition method: %s\npartitions: %d\n",
6518 printf("query mode: %s\n", QUERYMODE[querymode]);
6519 printf("number of clients: %d\n", nclients);
6520 printf("number of threads: %d\n", nthreads);
6521
6522 if (max_tries)
6523 printf("maximum number of tries: %u\n", max_tries);
6524
6525 if (duration <= 0)
6526 {
6527 printf("number of transactions per client: %d\n", nxacts);
6528 printf("number of transactions actually processed: " INT64_FORMAT "/%d\n",
6529 total->cnt, nxacts * nclients);
6530 }
6531 else
6532 {
6533 printf("duration: %d s\n", duration);
6534 printf("number of transactions actually processed: " INT64_FORMAT "\n",
6535 total->cnt);
6536 }
6537
6538 /*
6539 * Remaining stats are nonsensical if we failed to execute any xacts due
6540 * to other than serialization or deadlock errors and --continue-on-error
6541 * is not set.
6542 */
6543 if (total_cnt <= 0)
6544 return;
6545
6546 printf("number of failed transactions: " INT64_FORMAT " (%.3f%%)\n",
6547 failures, 100.0 * failures / total_cnt);
6548
6550 {
6551 printf("number of serialization failures: " INT64_FORMAT " (%.3f%%)\n",
6553 100.0 * total->serialization_failures / total_cnt);
6554 printf("number of deadlock failures: " INT64_FORMAT " (%.3f%%)\n",
6555 total->deadlock_failures,
6556 100.0 * total->deadlock_failures / total_cnt);
6557 printf("number of other failures: " INT64_FORMAT " (%.3f%%)\n",
6558 total->other_sql_failures,
6559 100.0 * total->other_sql_failures / total_cnt);
6560 }
6561
6562 /* it can be non-zero only if max_tries is not equal to one */
6563 if (max_tries != 1)
6564 {
6565 printf("number of transactions retried: " INT64_FORMAT " (%.3f%%)\n",
6566 total->retried, 100.0 * total->retried / total_cnt);
6567 printf("total number of retries: " INT64_FORMAT "\n", total->retries);
6568 }
6569
6571 printf("number of transactions skipped: " INT64_FORMAT " (%.3f%%)\n",
6572 total->skipped, 100.0 * total->skipped / total_cnt);
6573
6574 if (latency_limit)
6575 printf("number of transactions above the %.1f ms latency limit: " INT64_FORMAT "/" INT64_FORMAT " (%.3f%%)\n",
6576 latency_limit / 1000.0, latency_late, total->cnt,
6577 (total->cnt > 0) ? 100.0 * latency_late / total->cnt : 0.0);
6578
6580 printSimpleStats("latency", &total->latency);
6581 else
6582 {
6583 /* no measurement, show average latency computed from run time */
6584 printf("latency average = %.3f ms%s\n",
6585 0.001 * total_duration * nclients / total_cnt,
6586 failures > 0 ? " (including failures)" : "");
6587 }
6588
6589 if (throttle_delay)
6590 {
6591 /*
6592 * Report average transaction lag under rate limit throttling. This
6593 * is the delay between scheduled and actual start times for the
6594 * transaction. The measured lag may be caused by thread/client load,
6595 * the database load, or the Poisson throttling process.
6596 */
6597 printf("rate limit schedule lag: avg %.3f (max %.3f) ms\n",
6598 0.001 * total->lag.sum / total->cnt, 0.001 * total->lag.max);
6599 }
6600
6601 /*
6602 * Under -C/--connect, each transaction incurs a significant connection
6603 * cost, it would not make much sense to ignore it in tps, and it would
6604 * not be tps anyway.
6605 *
6606 * Otherwise connections are made just once at the beginning of the run
6607 * and should not impact performance but for very short run, so they are
6608 * (right)fully ignored in tps.
6609 */
6610 if (is_connect)
6611 {
6612 printf("average connection time = %.3f ms\n", 0.001 * conn_total_duration / (total->cnt + failures));
6613 printf("tps = %f (including reconnection times)\n", tps);
6614 }
6615 else
6616 {
6617 printf("initial connection time = %.3f ms\n", 0.001 * conn_elapsed_duration);
6618 printf("tps = %f (without initial connection time)\n", tps);
6619 }
6620
6621 /* Report per-script/command statistics */
6623 {
6624 int i;
6625
6626 for (i = 0; i < num_scripts; i++)
6627 {
6628 if (per_script_stats)
6629 {
6630 StatsData *sstats = &sql_script[i].stats;
6631 int64 script_failures = getFailures(sstats);
6632 int64 script_total_cnt =
6633 sstats->cnt + sstats->skipped + script_failures;
6634
6635 printf("SQL script %d: %s\n"
6636 " - weight: %d (targets %.1f%% of total)\n"
6637 " - " INT64_FORMAT " transactions (%.1f%% of total)\n",
6638 i + 1, sql_script[i].desc,
6639 sql_script[i].weight,
6640 100.0 * sql_script[i].weight / total_weight,
6641 script_total_cnt,
6642 100.0 * script_total_cnt / total_cnt);
6643
6644 if (script_total_cnt > 0)
6645 {
6646 printf(" - number of transactions actually processed: " INT64_FORMAT " (tps = %f)\n",
6647 sstats->cnt, sstats->cnt / bench_duration);
6648
6649 printf(" - number of failed transactions: " INT64_FORMAT " (%.3f%%)\n",
6650 script_failures,
6651 100.0 * script_failures / script_total_cnt);
6652
6654 {
6655 printf(" - number of serialization failures: " INT64_FORMAT " (%.3f%%)\n",
6656 sstats->serialization_failures,
6657 (100.0 * sstats->serialization_failures /
6658 script_total_cnt));
6659 printf(" - number of deadlock failures: " INT64_FORMAT " (%.3f%%)\n",
6660 sstats->deadlock_failures,
6661 (100.0 * sstats->deadlock_failures /
6662 script_total_cnt));
6663 printf(" - number of other failures: " INT64_FORMAT " (%.3f%%)\n",
6664 sstats->other_sql_failures,
6665 (100.0 * sstats->other_sql_failures /
6666 script_total_cnt));
6667 }
6668
6669 /*
6670 * it can be non-zero only if max_tries is not equal to
6671 * one
6672 */
6673 if (max_tries != 1)
6674 {
6675 printf(" - number of transactions retried: " INT64_FORMAT " (%.3f%%)\n",
6676 sstats->retried,
6677 100.0 * sstats->retried / script_total_cnt);
6678 printf(" - total number of retries: " INT64_FORMAT "\n",
6679 sstats->retries);
6680 }
6681
6683 printf(" - number of transactions skipped: " INT64_FORMAT " (%.3f%%)\n",
6684 sstats->skipped,
6685 100.0 * sstats->skipped / script_total_cnt);
6686
6687 }
6688 printSimpleStats(" - latency", &sstats->latency);
6689 }
6690
6691 /*
6692 * Report per-command statistics: latencies, retries after errors,
6693 * failures (errors without retrying).
6694 */
6696 {
6697 Command **commands;
6698
6699 printf("%sstatement latencies in milliseconds%s:\n",
6700 per_script_stats ? " - " : "",
6701 (max_tries == 1 ?
6702 " and failures" :
6703 ", failures and retries"));
6704
6705 for (commands = sql_script[i].commands;
6706 *commands != NULL;
6707 commands++)
6708 {
6709 SimpleStats *cstats = &(*commands)->stats;
6710
6711 if (max_tries == 1)
6712 printf(" %11.3f %10" PRId64 " %s\n",
6713 (cstats->count > 0) ?
6714 1000.0 * cstats->sum / cstats->count : 0.0,
6715 (*commands)->failures,
6716 (*commands)->first_line);
6717 else
6718 printf(" %11.3f %10" PRId64 " %10" PRId64 " %s\n",
6719 (cstats->count > 0) ?
6720 1000.0 * cstats->sum / cstats->count : 0.0,
6721 (*commands)->failures,
6722 (*commands)->retries,
6723 (*commands)->first_line);
6724 }
6725 }
6726 }
6727 }
static void printSimpleStats(const char *prefix, SimpleStats *ss)
Definition: pgbench.c:6452
#define printf(...)
Definition: port.h:245
StatsData stats
Definition: pgbench.c:769

References StatsData::cnt, SimpleStats::count, StatsData::deadlock_failures, duration, failures_detailed, getFailures(), i, INT64_FORMAT, is_connect, StatsData::lag, StatsData::latency, latency_limit, SimpleStats::max, max_tries, nclients, nthreads, num_scripts, nxacts, StatsData::other_sql_failures, PART_NONE, partition_method, PARTITION_METHOD, partitions, per_script_stats, PG_TIME_GET_DOUBLE, printf, printSimpleStats(), progress, querymode, QUERYMODE, report_per_command, StatsData::retried, StatsData::retries, scale, StatsData::serialization_failures, StatsData::skipped, sql_script, ParsedScript::stats, SimpleStats::sum, throttle_delay, and total_weight.

Referenced by main().

◆ printSimpleStats()

static void printSimpleStats ( const char *  prefix,
SimpleStats ss 
)
static

Definition at line 6452 of file pgbench.c.

6454{
6455 if (ss->count > 0)
6456 {
6457 double latency = ss->sum / ss->count;
6458 double stddev = sqrt(ss->sum2 / ss->count - latency * latency);
6459
6460 printf("%s average = %.3f ms\n", prefix, 0.001 * latency);
6461 printf("%s stddev = %.3f ms\n", prefix, 0.001 * stddev);
6462 }

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

Referenced by printResults().

◆ printVerboseErrorMessages()

static void printVerboseErrorMessages ( CState st,
pg_time_usec_t now,
bool  is_retry 
)
static

Definition at line 3675 of file pgbench.c.

3677{
3678 static PQExpBuffer buf = NULL;
3679
3680 if (buf == NULL)
3682 else
3684
3685 printfPQExpBuffer(buf, "client %d ", st->id);
3686 appendPQExpBufferStr(buf, (is_retry ?
3687 "repeats the transaction after the error" :
3688 "ends the failed transaction"));
3689 appendPQExpBuffer(buf, " (try %u", st->tries);
3690
3691 /* Print max_tries if it is not unlimited. */
3692 if (max_tries)
3694
3695 /*
3696 * If the latency limit is used, print a percentage of the current
3697 * transaction latency from the latency limit.
3698 */
3699 if (latency_limit)
3700 {
3702 appendPQExpBuffer(buf, ", %.3f%% of the maximum time of tries was used",
3703 (100.0 * (*now - st->txn_scheduled) / latency_limit));
3704 }
3705 appendPQExpBufferStr(buf, ")\n");
3706
3707 pg_log_info("%s", buf->data);
PQExpBuffer createPQExpBuffer(void)
Definition: pqexpbuffer.c:72

References appendPQExpBuffer(), appendPQExpBufferStr(), buf, createPQExpBuffer(), CState::id, latency_limit, max_tries, now(), pg_log_info, pg_time_now_lazy(), printfPQExpBuffer(), resetPQExpBuffer(), CState::tries, and CState::txn_scheduled.

Referenced by advanceConnectionState().

◆ printVersion()

static void printVersion ( PGconn con)
static

Definition at line 6466 of file pgbench.c.

6468{
6469 int server_ver = PQserverVersion(con);
6470 int client_ver = PG_VERSION_NUM;
6471
6472 if (server_ver != client_ver)
6473 {
6474 const char *server_version;
6475 char sverbuf[32];
6476
6477 /* Try to get full text form, might include "devel" etc */
6478 server_version = PQparameterStatus(con, "server_version");
6479 /* Otherwise fall back on server_ver */
6480 if (!server_version)
6481 {
6482 formatPGVersionNumber(server_ver, true,
6483 sverbuf, sizeof(sverbuf));
6484 server_version = sverbuf;
6485 }
6486
6487 printf(_("%s (%s, server %s)\n"),
6488 "pgbench", PG_VERSION, server_version);
6489 }
6490 /* For version match, only print pgbench version */
6491 else
6492 printf("%s (%s)\n", "pgbench", PG_VERSION);
6493 fflush(stdout);
#define _(x)
Definition: elog.c:91
const char * PQparameterStatus(const PGconn *conn, const char *paramName)
Definition: fe-connect.c:7659
static int server_version
Definition: pg_dumpall.c:109
char * formatPGVersionNumber(int version_number, bool include_minor, char *buf, size_t buflen)
Definition: string_utils.c:313

References _, formatPGVersionNumber(), PQparameterStatus(), PQserverVersion(), printf, server_version, and generate_unaccent_rules::stdout.

Referenced by main().

◆ process_backslash_command()

static Command * process_backslash_command ( PsqlScanState  sstate,
const char *  source,
int  lineno,
int  start_offset 
)
static

Definition at line 5783 of file pgbench.c.

5786{
5787 Command *my_command;
5788 PQExpBufferData word_buf;
5789 int word_offset;
5790 int offsets[MAX_ARGS]; /* offsets of argument words */
5791 int j;
5792
5793 initPQExpBuffer(&word_buf);
5794
5795 /* Collect first word of command */
5796 if (!expr_lex_one_word(sstate, &word_buf, &word_offset))
5797 {
5798 termPQExpBuffer(&word_buf);
5799 return NULL;
5800 }
5801
5802 /* Allocate and initialize Command structure */
5803 my_command = (Command *) pg_malloc0(sizeof(Command));
5804 my_command->type = META_COMMAND;
5805 my_command->argc = 0;
5806 initSimpleStats(&my_command->stats);
5807
5808 /* Save first word (command name) */
5809 j = 0;
5810 offsets[j] = word_offset;
5811 my_command->argv[j++] = pg_strdup(word_buf.data);
5812 my_command->argc++;
5813
5814 /* ... and convert it to enum form */
5815 my_command->meta = getMetaCommand(my_command->argv[0]);
5816
5817 if (my_command->meta == META_SET ||
5818 my_command->meta == META_IF ||
5819 my_command->meta == META_ELIF)
5820 {
5821 yyscan_t yyscanner;
5822
5823 /* For \set, collect var name */
5824 if (my_command->meta == META_SET)
5825 {
5826 if (!expr_lex_one_word(sstate, &word_buf, &word_offset))
5827 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5828 "missing argument", NULL, -1);
5829
5830 offsets[j] = word_offset;
5831 my_command->argv[j++] = pg_strdup(word_buf.data);
5832 my_command->argc++;
5833 }
5834
5835 /* then for all parse the expression */
5836 yyscanner = expr_scanner_init(sstate, source, lineno, start_offset,
5837 my_command->argv[0]);
5838
5839 if (expr_yyparse(&my_command->expr, yyscanner) != 0)
5840 {
5841 /* dead code: exit done from syntax_error called by yyerror */
5842 exit(1);
5843 }
5844
5845 /* Save line, trimming any trailing newline */
5846 my_command->first_line =
5848 start_offset,
5849 true);
5850
5851 expr_scanner_finish(yyscanner);
5852
5853 termPQExpBuffer(&word_buf);
5854
5855 return my_command;
5856 }
5857
5858 /* For all other commands, collect remaining words. */
5859 while (expr_lex_one_word(sstate, &word_buf, &word_offset))
5860 {
5861 /*
5862 * my_command->argv[0] is the command itself, so the max number of
5863 * arguments is one less than MAX_ARGS
5864 */
5865 if (j >= MAX_ARGS)
5866 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5867 "too many arguments", NULL, -1);
5868
5869 offsets[j] = word_offset;
5870 my_command->argv[j++] = pg_strdup(word_buf.data);
5871 my_command->argc++;
5872 }
5873
5874 /* Save line, trimming any trailing newline */
5875 my_command->first_line =
5877 start_offset,
5878 true);
5879
5880 if (my_command->meta == META_SLEEP)
5881 {
5882 if (my_command->argc < 2)
5883 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5884 "missing argument", NULL, -1);
5885
5886 if (my_command->argc > 3)
5887 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5888 "too many arguments", NULL,
5889 offsets[3] - start_offset);
5890
5891 /*
5892 * Split argument into number and unit to allow "sleep 1ms" etc. We
5893 * don't have to terminate the number argument with null because it
5894 * will be parsed with atoi, which ignores trailing non-digit
5895 * characters.
5896 */
5897 if (my_command->argv[1][0] != ':')
5898 {
5899 char *c = my_command->argv[1];
5900 bool have_digit = false;
5901
5902 /* Skip sign */
5903 if (*c == '+' || *c == '-')
5904 c++;
5905
5906 /* Require at least one digit */
5907 if (*c && isdigit((unsigned char) *c))
5908 have_digit = true;
5909
5910 /* Eat all digits */
5911 while (*c && isdigit((unsigned char) *c))
5912 c++;
5913
5914 if (*c)
5915 {
5916 if (my_command->argc == 2 && have_digit)
5917 {
5918 my_command->argv[2] = c;
5919 offsets[2] = offsets[1] + (c - my_command->argv[1]);
5920 my_command->argc = 3;
5921 }
5922 else
5923 {
5924 /*
5925 * Raise an error if argument starts with non-digit
5926 * character (after sign).
5927 */
5928 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5929 "invalid sleep time, must be an integer",
5930 my_command->argv[1], offsets[1] - start_offset);
5931 }
5932 }
5933 }
5934
5935 if (my_command->argc == 3)
5936 {
5937 if (pg_strcasecmp(my_command->argv[2], "us") != 0 &&
5938 pg_strcasecmp(my_command->argv[2], "ms") != 0 &&
5939 pg_strcasecmp(my_command->argv[2], "s") != 0)
5940 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5941 "unrecognized time unit, must be us, ms or s",
5942 my_command->argv[2], offsets[2] - start_offset);
5943 }
5944 }
5945 else if (my_command->meta == META_SETSHELL)
5946 {
5947 if (my_command->argc < 3)
5948 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5949 "missing argument", NULL, -1);
5950 }
5951 else if (my_command->meta == META_SHELL)
5952 {
5953 if (my_command->argc < 2)
5954 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5955 "missing command", NULL, -1);
5956 }
5957 else if (my_command->meta == META_ELSE || my_command->meta == META_ENDIF ||
5958 my_command->meta == META_STARTPIPELINE ||
5959 my_command->meta == META_ENDPIPELINE ||
5960 my_command->meta == META_SYNCPIPELINE)
5961 {
5962 if (my_command->argc != 1)
5963 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5964 "unexpected argument", NULL, -1);
5965 }
5966 else if (my_command->meta == META_GSET || my_command->meta == META_ASET)
5967 {
5968 if (my_command->argc > 2)
5969 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5970 "too many arguments", NULL, -1);
5971 }
5972 else
5973 {
5974 /* my_command->meta == META_NONE */
5975 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5976 "invalid command", NULL, -1);
5977 }
5978
5979 termPQExpBuffer(&word_buf);
5980
5981 return my_command;
void * yyscan_t
Definition: cubedata.h:65
bool expr_lex_one_word(PsqlScanState state, PQExpBuffer word_buf, int *offset)
Definition: exprscan.l:318
char * expr_scanner_get_substring(PsqlScanState state, int start_offset, bool chomp)
Definition: exprscan.l:425
void expr_scanner_finish(yyscan_t yyscanner)
Definition: exprscan.l:402
yyscan_t expr_scanner_init(PsqlScanState state, const char *source, int lineno, int start_offset, const char *command)
Definition: exprscan.l:370
static rewind_source * source
Definition: pg_rewind.c:89
static MetaCommand getMetaCommand(const char *cmd)
Definition: pgbench.c:2914
int expr_yyparse(PgBenchExpr **expr_parse_result_p, yyscan_t yyscanner)

References Command::argc, Command::argv, PQExpBufferData::data, Command::expr, expr_lex_one_word(), expr_scanner_finish(), expr_scanner_get_substring(), expr_scanner_init(), expr_yyparse(), Command::first_line, getMetaCommand(), initPQExpBuffer(), initSimpleStats(), j, MAX_ARGS, Command::meta, META_ASET, META_COMMAND, META_ELIF, META_ELSE, META_ENDIF, META_ENDPIPELINE, META_GSET, META_IF, META_SET, META_SETSHELL, META_SHELL, META_SLEEP, META_STARTPIPELINE, META_SYNCPIPELINE, pg_malloc0(), pg_strcasecmp(), pg_strdup(), source, Command::stats, syntax_error(), termPQExpBuffer(), and Command::type.

Referenced by ParseScript().

◆ process_builtin()

static void process_builtin ( const BuiltinScript bi,
int  weight 
)
static

Definition at line 6244 of file pgbench.c.

6246{
6247 ParseScript(bi->script, bi->desc, weight);
static void ParseScript(const char *script, const char *desc, int weight)
Definition: pgbench.c:6044

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

Referenced by main().

◆ process_file()

static void process_file ( const char *  filename,
int  weight 
)
static

Definition at line 6218 of file pgbench.c.

6220{
6221 FILE *fd;
6222 char *buf;
6223
6224 /* Slurp the file contents into "buf" */
6225 if (strcmp(filename, "-") == 0)
6226 fd = stdin;
6227 else if ((fd = fopen(filename, "r")) == NULL)
6228 pg_fatal("could not open file \"%s\": %m", filename);
6229
6231
6232 if (ferror(fd))
6233 pg_fatal("could not read file \"%s\": %m", filename);
6234
6235 if (fd != stdin)
6236 fclose(fd);
6237
6238 ParseScript(buf, filename, weight);
6239
6240 free(buf);
static char * filename
Definition: pg_dumpall.c:120
static char * read_file_contents(FILE *fd)
Definition: pgbench.c:6185

References buf, fd(), filename, free, ParseScript(), pg_fatal, and read_file_contents().

Referenced by main(), and process_psqlrc_file().

◆ processXactStats()

static void processXactStats ( TState thread,
CState st,
pg_time_usec_t now,
bool  skipped,
StatsData agg 
)
static

Definition at line 4798 of file pgbench.c.

4801{
4802 double latency = 0.0,
4803 lag = 0.0;
4804 bool detailed = progress || throttle_delay || latency_limit ||
4806
4807 if (detailed && !skipped && st->estatus == ESTATUS_NO_ERROR)
4808 {
4810
4811 /* compute latency & lag */
4812 latency = (*now) - st->txn_scheduled;
4813 lag = st->txn_begin - st->txn_scheduled;
4814 }
4815
4816 /* keep detailed thread stats */
4817 accumStats(&thread->stats, skipped, latency, lag, st->estatus, st->tries);
4818
4819 /* count transactions over the latency limit, if needed */
4820 if (latency_limit && latency > latency_limit)
4821 thread->latency_late++;
4822
4823 /* client stat is just counting */
4824 st->cnt++;
4825
4826 if (use_log)
4827 doLog(thread, st, agg, skipped, latency, lag);
4828
4829 /* XXX could use a mutex here, but we choose not to */
4830 if (per_script_stats)
4831 accumStats(&sql_script[st->use_file].stats, skipped, latency, lag,
4832 st->estatus, st->tries);
static void doLog(TState *thread, CState *st, StatsData *agg, bool skipped, double latency, double lag)
Definition: pgbench.c:4675

References accumStats(), CState::cnt, doLog(), CState::estatus, ESTATUS_NO_ERROR, TState::latency_late, latency_limit, now(), per_script_stats, pg_time_now_lazy(), progress, sql_script, TState::stats, ParsedScript::stats, throttle_delay, CState::tries, CState::txn_begin, CState::txn_scheduled, CState::use_file, and use_log.

Referenced by advanceConnectionState().

◆ putVariable()

static bool putVariable ( Variables variables,
const char *  context,
char *  name,
const char *  value 
)
static

Definition at line 1868 of file pgbench.c.

1871{
1872 Variable *var;
1873 char *val;
1874
1875 var = lookupCreateVariable(variables, context, name);
1876 if (!var)
1877 return false;
1878
1879 /* dup then free, in case value is pointing at this variable */
1880 val = pg_strdup(value);
1881
1882 free(var->svalue);
1883 var->svalue = val;
1884 var->value.type = PGBT_NO_VALUE;
1885
1886 return true;
static struct @171 value
static Variable * lookupCreateVariable(Variables *variables, const char *context, char *name)
Definition: pgbench.c:1831

References free, lookupCreateVariable(), name, pg_strdup(), PGBT_NO_VALUE, Variable::svalue, PgBenchValue::type, val, Variable::value, and value.

Referenced by main(), and readCommandResponse().

◆ putVariableInt()

static bool putVariableInt ( Variables variables,
const char *  context,
char *  name,
int64  value 
)
static

Definition at line 1910 of file pgbench.c.

1913{
1915
1917 return putVariableValue(variables, context, name, &val);

References name, putVariableValue(), setIntValue(), val, and value.

Referenced by main(), and runShellCommand().

◆ putVariableValue()

static bool putVariableValue ( Variables variables,
const char *  context,
char *  name,
const PgBenchValue value 
)
static

Definition at line 1891 of file pgbench.c.

1894{
1895 Variable *var;
1896
1897 var = lookupCreateVariable(variables, context, name);
1898 if (!var)
1899 return false;
1900
1901 free(var->svalue);
1902 var->svalue = NULL;
1903 var->value = *value;
1904
1905 return true;

References free, lookupCreateVariable(), name, Variable::svalue, Variable::value, and value.

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

◆ read_file_contents()

static char * read_file_contents ( FILE *  fd)
static

Definition at line 6185 of file pgbench.c.

6187{
6188 char *buf;
6189 size_t buflen = BUFSIZ;
6190 size_t used = 0;
6191
6192 buf = (char *) pg_malloc(buflen);
6193
6194 for (;;)
6195 {
6196 size_t nread;
6197
6198 nread = fread(buf + used, 1, BUFSIZ, fd);
6199 used += nread;
6200 /* If fread() read less than requested, must be EOF or error */
6201 if (nread < BUFSIZ)
6202 break;
6203 /* Enlarge buf so we can read some more */
6204 buflen += BUFSIZ;
6205 buf = (char *) pg_realloc(buf, buflen);
6206 }
6207 /* There is surely room for a terminator */
6208 buf[used] = '\0';
6209
6210 return buf;

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

Referenced by process_file().

◆ readCommandResponse()

static bool readCommandResponse ( CState st,
MetaCommand  meta,
char *  varprefix 
)
static

Definition at line 3325 of file pgbench.c.

3327{
3328 PGresult *res;
3329 PGresult *next_res;
3330 int qrynum = 0;
3331
3332 /*
3333 * varprefix should be set only with \gset or \aset, and \endpipeline and
3334 * SQL commands do not need it.
3335 */
3336 Assert((meta == META_NONE && varprefix == NULL) ||
3337 ((meta == META_ENDPIPELINE) && varprefix == NULL) ||
3338 ((meta == META_GSET || meta == META_ASET) && varprefix != NULL));
3339
3340 res = PQgetResult(st->con);
3341
3342 while (res != NULL)
3343 {
3344 bool is_last;
3345
3346 /* peek at the next result to know whether the current is last */
3347 next_res = PQgetResult(st->con);
3348 is_last = (next_res == NULL);
3349
3350 switch (PQresultStatus(res))
3351 {
3352 case PGRES_COMMAND_OK: /* non-SELECT commands */
3353 case PGRES_EMPTY_QUERY: /* may be used for testing no-op overhead */
3354 if (is_last && meta == META_GSET)
3355 {
3356 pg_log_error("client %d script %d command %d query %d: expected one row, got %d",
3357 st->id, st->use_file, st->command, qrynum, 0);
3359 goto error;
3360 }
3361 break;
3362
3363 case PGRES_TUPLES_OK:
3364 if ((is_last && meta == META_GSET) || meta == META_ASET)
3365 {
3366 int ntuples = PQntuples(res);
3367
3368 if (meta == META_GSET && ntuples != 1)
3369 {
3370 /* under \gset, report the error */
3371 pg_log_error("client %d script %d command %d query %d: expected one row, got %d",
3372 st->id, st->use_file, st->command, qrynum, PQntuples(res));
3374 goto error;
3375 }
3376 else if (meta == META_ASET && ntuples <= 0)
3377 {
3378 /* coldly skip empty result under \aset */
3379 break;
3380 }
3381
3382 /* store results into variables */
3383 for (int fld = 0; fld < PQnfields(res); fld++)
3384 {
3385 char *varname = PQfname(res, fld);
3386
3387 /* allocate varname only if necessary, freed below */
3388 if (*varprefix != '\0')
3389 varname = psprintf("%s%s", varprefix, varname);
3390
3391 /* store last row result as a string */
3392 if (!putVariable(&st->variables, meta == META_ASET ? "aset" : "gset", varname,
3393 PQgetvalue(res, ntuples - 1, fld)))
3394 {
3395 /* internal error */
3396 pg_log_error("client %d script %d command %d query %d: error storing into variable %s",
3397 st->id, st->use_file, st->command, qrynum, varname);
3399 goto error;
3400 }
3401
3402 if (*varprefix != '\0')
3403 pg_free(varname);
3404 }
3405 }
3406 /* otherwise the result is simply thrown away by PQclear below */
3407 break;
3408
3410 pg_log_debug("client %d pipeline ending, ongoing syncs: %d",
3411 st->id, st->num_syncs);
3412 st->num_syncs--;
3413 if (st->num_syncs == 0 && PQexitPipelineMode(st->con) != 1)
3414 pg_log_error("client %d failed to exit pipeline mode: %s", st->id,
3416 break;
3417
3418 case PGRES_COPY_IN:
3419 case PGRES_COPY_OUT:
3420 case PGRES_COPY_BOTH:
3421 pg_log_error("COPY is not supported in pgbench, aborting");
3422
3423 /*
3424 * We need to exit the copy state. Otherwise, PQgetResult()
3425 * will always return an empty PGresult as an effect of
3426 * getCopyResult(), leading to an infinite loop in the error
3427 * cleanup done below.
3428 */
3429 PQendcopy(st->con);
3430 goto error;
3431
3433 case PGRES_FATAL_ERROR:
3437 {
3438 if (verbose_errors)
3440 goto error;
3441 }
3442 /* fall through */
3443
3444 default:
3445 /* anything else is unexpected */
3446 pg_log_error("client %d script %d aborted in command %d query %d: %s",
3447 st->id, st->use_file, st->command, qrynum,
3449 goto error;
3450 }
3451
3452 PQclear(res);
3453 qrynum++;
3454 res = next_res;
3455 }
3456
3457 if (qrynum == 0)
3458 {
3459 pg_log_error("client %d command %d: no results", st->id, st->command);
3460 return false;
3461 }
3462
3463 return true;
3464
3465error:
3466 PQclear(res);
3467 PQclear(next_res);
3469
3470 return false;
#define PQresultErrorMessage
#define PQnfields
Definition: libpq-be-fe.h:252
#define PQfname
Definition: libpq-be-fe.h:256
@ PGRES_COPY_BOTH
Definition: libpq-fe.h:137
@ PGRES_FATAL_ERROR
Definition: libpq-fe.h:136
@ PGRES_COPY_OUT
Definition: libpq-fe.h:131
@ PGRES_EMPTY_QUERY
Definition: libpq-fe.h:124
@ PGRES_NONFATAL_ERROR
Definition: libpq-fe.h:135
static void commandError(CState *st, const char *message)
Definition: pgbench.c:3072
static EStatus getSQLErrorStatus(CState *st, const char *sqlState)
Definition: pgbench.c:3277
static void error(void)
Definition: sql-dyntest.c:147

References Assert(), canContinueOnError(), canRetryError(), CState::command, commandError(), CState::con, discardAvailableResults(), error(), CState::estatus, ESTATUS_META_COMMAND_ERROR, getSQLErrorStatus(), CState::id, META_ASET, META_ENDPIPELINE, META_GSET, META_NONE, CState::num_syncs, PG_DIAG_SQLSTATE, pg_free(), pg_log_debug, pg_log_error, PGRES_COMMAND_OK, PGRES_COPY_BOTH, PGRES_COPY_IN, PGRES_COPY_OUT, PGRES_EMPTY_QUERY, PGRES_FATAL_ERROR, PGRES_NONFATAL_ERROR, PGRES_PIPELINE_SYNC, PGRES_TUPLES_OK, PQclear, PQendcopy(), PQexitPipelineMode(), PQfname, PQgetResult, PQgetvalue, PQnfields, PQntuples, PQresultErrorField, PQresultErrorMessage, PQresultStatus, psprintf(), putVariable(), CState::use_file, CState::variables, and verbose_errors.

Referenced by advanceConnectionState().

◆ replaceVariable()

static char * replaceVariable ( char **  sql,
char *  param,
int  len,
char *  value 
)
static

Definition at line 1955 of file pgbench.c.

1957{
1958 int valueln = strlen(value);
1959
1960 if (valueln > len)
1961 {
1962 size_t offset = param - *sql;
1963
1964 *sql = pg_realloc(*sql, strlen(*sql) - len + valueln + 1);
1965 param = *sql + offset;
1966 }
1967
1968 if (valueln != len)
1969 memmove(param + valueln, param + len, strlen(param + len) + 1);
1970 memcpy(param, value, valueln);
1971
1972 return param + valueln;

References len, pg_realloc(), and value.

Referenced by assignVariables(), and parseQuery().

◆ runInitSteps()

static void runInitSteps ( const char *  initialize_steps)
static

Definition at line 5371 of file pgbench.c.

5373{
5374 PQExpBufferData stats;
5375 PGconn *con;
5376 const char *step;
5377 double run_time = 0.0;
5378 bool first = true;
5379
5380 initPQExpBuffer(&stats);
5381
5382 if ((con = doConnect()) == NULL)
5383 pg_fatal("could not create connection for initialization");
5384
5386 SetCancelConn(con);
5387
5388 for (step = initialize_steps; *step != '\0'; step++)
5389 {
5390 char *op = NULL;
5392
5393 switch (*step)
5394 {
5395 case 'd':
5396 op = "drop tables";
5397 initDropTables(con);
5398 break;
5399 case 't':
5400 op = "create tables";
5401 initCreateTables(con);
5402 break;
5403 case 'g':
5404 op = "client-side generate";
5406 break;
5407 case 'G':
5408 op = "server-side generate";
5410 break;
5411 case 'v':
5412 op = "vacuum";
5413 initVacuum(con);
5414 break;
5415 case 'p':
5416 op = "primary keys";
5417 initCreatePKeys(con);
5418 break;
5419 case 'f':
5420 op = "foreign keys";
5421 initCreateFKeys(con);
5422 break;
5423 case ' ':
5424 break; /* ignore */
5425 default:
5426 pg_log_error("unrecognized initialization step \"%c\"", *step);
5427 PQfinish(con);
5428 exit(1);
5429 }
5430
5431 if (op != NULL)
5432 {
5433 double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
5434
5435 if (!first)
5436 appendPQExpBufferStr(&stats, ", ");
5437 else
5438 first = false;
5439
5440 appendPQExpBuffer(&stats, "%s %.2f s", op, elapsed_sec);
5441
5442 run_time += elapsed_sec;
5443 }
5444 }
5445
5446 fprintf(stderr, "done in %.2f s (%s).\n", run_time, stats.data);
5448 PQfinish(con);
5449 termPQExpBuffer(&stats);
void ResetCancelConn(void)
Definition: cancel.c:107
void SetCancelConn(PGconn *conn)
Definition: cancel.c:77
void setup_cancel_handler(void(*query_cancel_callback)(void))
Definition: cancel.c:183
static void initCreatePKeys(PGconn *con)
Definition: pgbench.c:5287
static void initDropTables(PGconn *con)
Definition: pgbench.c:4849
static void initGenerateDataServerSide(PGconn *con)
Definition: pgbench.c:5229
static void initCreateFKeys(PGconn *con)
Definition: pgbench.c:5325
static void initVacuum(PGconn *con)
Definition: pgbench.c:5274
static void initCreateTables(PGconn *con)
Definition: pgbench.c:4940
static void initGenerateDataClientSide(PGconn *con)
Definition: pgbench.c:5197

References appendPQExpBuffer(), appendPQExpBufferStr(), PQExpBufferData::data, doConnect(), fprintf, initCreateFKeys(), initCreatePKeys(), initCreateTables(), initDropTables(), initGenerateDataClientSide(), initGenerateDataServerSide(), initPQExpBuffer(), initVacuum(), pg_fatal, pg_log_error, PG_TIME_GET_DOUBLE, pg_time_now(), PQfinish(), ResetCancelConn(), SetCancelConn(), setup_cancel_handler(), start, and termPQExpBuffer().

Referenced by main().

◆ runShellCommand()

static bool runShellCommand ( Variables variables,
char *  variable,
char **  argv,
int  argc 
)
static

Definition at line 2956 of file pgbench.c.

2958{
2959 char command[SHELL_COMMAND_SIZE];
2960 int i,
2961 len = 0;
2962 FILE *fp;
2963 char res[64];
2964 char *endptr;
2965 int retval;
2966
2967 /*----------
2968 * Join arguments with whitespace separators. Arguments starting with
2969 * exactly one colon are treated as variables:
2970 * name - append a string "name"
2971 * :var - append a variable named 'var'
2972 * ::name - append a string ":name"
2973 *----------
2974 */
2975 for (i = 0; i < argc; i++)
2976 {
2977 char *arg;
2978 int arglen;
2979
2980 if (argv[i][0] != ':')
2981 {
2982 arg = argv[i]; /* a string literal */
2983 }
2984 else if (argv[i][1] == ':')
2985 {
2986 arg = argv[i] + 1; /* a string literal starting with colons */
2987 }
2988 else if ((arg = getVariable(variables, argv[i] + 1)) == NULL)
2989 {
2990 pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[i]);
2991 return false;
2992 }
2993
2994 arglen = strlen(arg);
2995 if (len + arglen + (i > 0 ? 1 : 0) >= SHELL_COMMAND_SIZE - 1)
2996 {
2997 pg_log_error("%s: shell command is too long", argv[0]);
2998 return false;
2999 }
3000
3001 if (i > 0)
3002 command[len++] = ' ';
3003 memcpy(command + len, arg, arglen);
3004 len += arglen;
3005 }
3006
3007 command[len] = '\0';
3008
3009 fflush(NULL); /* needed before either system() or popen() */
3010
3011 /* Fast path for non-assignment case */
3012 if (variable == NULL)
3013 {
3014 if (system(command))
3015 {
3016 if (!timer_exceeded)
3017 pg_log_error("%s: could not launch shell command", argv[0]);
3018 return false;
3019 }
3020 return true;
3021 }
3022
3023 /* Execute the command with pipe and read the standard output. */
3024 if ((fp = popen(command, "r")) == NULL)
3025 {
3026 pg_log_error("%s: could not launch shell command", argv[0]);
3027 return false;
3028 }
3029 if (fgets(res, sizeof(res), fp) == NULL)
3030 {
3031 if (!timer_exceeded)
3032 pg_log_error("%s: could not read result of shell command", argv[0]);
3033 (void) pclose(fp);
3034 return false;
3035 }
3036 if (pclose(fp) < 0)
3037 {
3038 pg_log_error("%s: could not run shell command: %m", argv[0]);
3039 return false;
3040 }
3041
3042 /* Check whether the result is an integer and assign it to the variable */
3043 retval = (int) strtol(res, &endptr, 10);
3044 while (*endptr != '\0' && isspace((unsigned char) *endptr))
3045 endptr++;
3046 if (*res == '\0' || *endptr != '\0')
3047 {
3048 pg_log_error("%s: shell command must return an integer (not \"%s\")", argv[0], res);
3049 return false;
3050 }
3051 if (!putVariableInt(variables, "setshell", variable, retval))
3052 return false;
3053
3054 pg_log_debug("%s: shell parameter name: \"%s\", value: \"%s\"", argv[0], argv[1], res);
3055
3056 return true;
void * arg
#define SHELL_COMMAND_SIZE
Definition: pgbench.c:349

References arg, getVariable(), i, len, pg_log_debug, pg_log_error, putVariableInt(), SHELL_COMMAND_SIZE, and timer_exceeded.

Referenced by executeMetaCommand().

◆ sendCommand()

static bool sendCommand ( CState st,
Command command 
)
static

Definition at line 3196 of file pgbench.c.

3198{
3199 int r;
3200
3201 if (querymode == QUERY_SIMPLE)
3202 {
3203 char *sql;
3204
3205 sql = pg_strdup(command->argv[0]);
3206 sql = assignVariables(&st->variables, sql);
3207
3208 pg_log_debug("client %d sending %s", st->id, sql);
3209 r = PQsendQuery(st->con, sql);
3210 free(sql);
3211 }
3212 else if (querymode == QUERY_EXTENDED)
3213 {
3214 const char *sql = command->argv[0];
3215 const char *params[MAX_ARGS];
3216
3217 getQueryParams(&st->variables, command, params);
3218
3219 pg_log_debug("client %d sending %s", st->id, sql);
3220 r = PQsendQueryParams(st->con, sql, command->argc - 1,
3221 NULL, params, NULL, NULL, 0);
3222 }
3223 else if (querymode == QUERY_PREPARED)
3224 {
3225 const char *params[MAX_ARGS];
3226
3227 prepareCommand(st, st->command);
3228 getQueryParams(&st->variables, command, params);
3229
3230 pg_log_debug("client %d sending %s", st->id, command->prepname);
3231 r = PQsendQueryPrepared(st->con, command->prepname, command->argc - 1,
3232 params, NULL, NULL, 0);
3233 }
3234 else /* unknown sql mode */
3235 r = 0;
3236
3237 if (r == 0)
3238 {
3239 pg_log_debug("client %d could not send %s", st->id, command->argv[0]);
3240 return false;
3241 }
3242 else
3243 return true;
int PQsendQueryParams(PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char *const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat)
Definition: fe-exec.c:1508
int PQsendQueryPrepared(PGconn *conn, const char *stmtName, int nParams, const char *const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat)
Definition: fe-exec.c:1649
static void getQueryParams(Variables *variables, const Command *command, const char **params)
Definition: pgbench.c:2011
static char * assignVariables(Variables *variables, char *sql)
Definition: pgbench.c:1975

References Command::argc, Command::argv, assignVariables(), CState::command, CState::con, free, getQueryParams(), CState::id, MAX_ARGS, pg_log_debug, pg_strdup(), PQsendQuery(), PQsendQueryParams(), PQsendQueryPrepared(), prepareCommand(), Command::prepname, QUERY_EXTENDED, QUERY_PREPARED, QUERY_SIMPLE, querymode, and CState::variables.

Referenced by advanceConnectionState().

◆ set_random_seed()

static bool set_random_seed ( const char *  seed)
static

Definition at line 6734 of file pgbench.c.

6736{
6737 uint64 iseed;
6738
6739 if (seed == NULL || strcmp(seed, "time") == 0)
6740 {
6741 /* rely on current time */
6742 iseed = pg_time_now();
6743 }
6744 else if (strcmp(seed, "rand") == 0)
6745 {
6746 /* use some "strong" random source */
6747 if (!pg_strong_random(&iseed, sizeof(iseed)))
6748 {
6749 pg_log_error("could not generate random seed");
6750 return false;
6751 }
6752 }
6753 else
6754 {
6755 char garbage;
6756
6757 if (sscanf(seed, "%" SCNu64 "%c", &iseed, &garbage) != 1)
6758 {
6759 pg_log_error("unrecognized random seed option \"%s\"", seed);
6760 pg_log_error_detail("Expecting an unsigned integer, \"time\" or \"rand\".");
6761 return false;
6762 }
6763 }
6764
6765 if (seed != NULL)
6766 pg_log_info("setting random seed to %" PRIu64, iseed);
6767
6768 random_seed = iseed;
6769
6770 /* Initialize base_random_sequence using seed */
6772
6773 return true;
bool pg_strong_random(void *buf, size_t len)

References base_random_sequence, pg_log_error, pg_log_error_detail, pg_log_info, pg_prng_seed(), pg_strong_random(), pg_time_now(), and random_seed.

Referenced by main().

◆ setalarm()

static void setalarm ( int  seconds)
static

Definition at line 7895 of file pgbench.c.

7897{
7899 alarm(seconds);
static void handle_sig_alarm(SIGNAL_ARGS)
Definition: pgbench.c:7889
#define pqsignal
Definition: port.h:531
#define SIGALRM
Definition: win32_port.h:164

References handle_sig_alarm(), pqsignal, and SIGALRM.

Referenced by main().

◆ setBoolValue()

static void setBoolValue ( PgBenchValue pv,
bool  bval 
)
static

Definition at line 2141 of file pgbench.c.

2143{
2144 pv->type = PGBT_BOOLEAN;
2145 pv->u.bval = bval;

References PgBenchValue::bval, PGBT_BOOLEAN, PgBenchValue::type, and PgBenchValue::u.

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

◆ setDoubleValue()

static void setDoubleValue ( PgBenchValue pv,
double  dval 
)
static

Definition at line 2157 of file pgbench.c.

2159{
2160 pv->type = PGBT_DOUBLE;
2161 pv->u.dval = dval;

References PgBenchValue::dval, PGBT_DOUBLE, PgBenchValue::type, and PgBenchValue::u.

Referenced by evalStandardFunc(), and makeVariableValue().

◆ setIntValue()

static void setIntValue ( PgBenchValue pv,
int64  ival 
)
static

Definition at line 2149 of file pgbench.c.

2151{
2152 pv->type = PGBT_INT;
2153 pv->u.ival = ival;

References PgBenchValue::ival, PGBT_INT, PgBenchValue::type, and PgBenchValue::u.

Referenced by evalStandardFunc(), makeVariableValue(), and putVariableInt().

◆ setNullValue()

static void setNullValue ( PgBenchValue pv)
static

Definition at line 2133 of file pgbench.c.

2135{
2136 pv->type = PGBT_NULL;
2137 pv->u.ival = 0;

References PgBenchValue::ival, PGBT_NULL, PgBenchValue::type, and PgBenchValue::u.

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

◆ skip_sql_comments()

static char * skip_sql_comments ( char *  sql_command)
static

Definition at line 5662 of file pgbench.c.

5664{
5665 char *p = sql_command;
5666
5667 /* Skip any leading whitespace, as well as "--" style comments */
5668 for (;;)
5669 {
5670 if (isspace((unsigned char) *p))
5671 p++;
5672 else if (strncmp(p, "--", 2) == 0)
5673 {
5674 p = strchr(p, '\n');
5675 if (p == NULL)
5676 return NULL;
5677 p++;
5678 }
5679 else
5680 break;
5681 }
5682
5683 /* NULL if there's nothing but whitespace and comments */
5684 if (*p == '\0')
5685 return NULL;
5686
5687 return p;

Referenced by create_sql_command().

◆ socket_has_input()

static bool socket_has_input ( socket_set sa,
int  fd,
int  idx 
)
static

Definition at line 8099 of file pgbench.c.

8101{
8102 return (FD_ISSET(fd, &sa->fds) != 0);

References fd().

Referenced by threadRun().

◆ strtodouble()

bool strtodouble ( const char *  str,
bool  errorOK,
double *  dv 
)

Definition at line 1094 of file pgbench.c.

1096{
1097 char *end;
1098
1099 errno = 0;
1100 *dv = strtod(str, &end);
1101
1102 if (unlikely(errno != 0))
1103 {
1104 if (!errorOK)
1105 pg_log_error("value \"%s\" is out of range for type double", str);
1106 return false;
1107 }
1108
1109 if (unlikely(end == str || *end != '\0'))
1110 {
1111 if (!errorOK)
1112 pg_log_error("invalid input syntax for type double: \"%s\"", str);
1113 return false;
1114 }
1115 return true;

References pg_log_error, str, and unlikely.

Referenced by makeVariableValue().

◆ strtoint64()

bool strtoint64 ( const char *  str,
bool  errorOK,
int64 result 
)

Definition at line 1023 of file pgbench.c.

1025{
1026 const char *ptr = str;
1027 int64 tmp = 0;
1028 bool neg = false;
1029
1030 /*
1031 * Do our own scan, rather than relying on sscanf which might be broken
1032 * for long long.
1033 *
1034 * As INT64_MIN can't be stored as a positive 64 bit integer, accumulate
1035 * value as a negative number.
1036 */
1037
1038 /* skip leading spaces */
1039 while (*ptr && isspace((unsigned char) *ptr))
1040 ptr++;
1041
1042 /* handle sign */
1043 if (*ptr == '-')
1044 {
1045 ptr++;
1046 neg = true;
1047 }
1048 else if (*ptr == '+')
1049 ptr++;
1050
1051 /* require at least one digit */
1052 if (unlikely(!isdigit((unsigned char) *ptr)))
1053 goto invalid_syntax;
1054
1055 /* process digits */
1056 while (*ptr && isdigit((unsigned char) *ptr))
1057 {
1058 int8 digit = (*ptr++ - '0');
1059
1060 if (unlikely(pg_mul_s64_overflow(tmp, 10, &tmp)) ||
1061 unlikely(pg_sub_s64_overflow(tmp, digit, &tmp)))
1062 goto out_of_range;
1063 }
1064
1065 /* allow trailing whitespace, but not other trailing chars */
1066 while (*ptr != '\0' && isspace((unsigned char) *ptr))
1067 ptr++;
1068
1069 if (unlikely(*ptr != '\0'))
1070 goto invalid_syntax;
1071
1072 if (!neg)
1073 {
1074 if (unlikely(tmp == PG_INT64_MIN))
1075 goto out_of_range;
1076 tmp = -tmp;
1077 }
1078
1079 *result = tmp;
1080 return true;
1081
1082out_of_range:
1083 if (!errorOK)
1084 pg_log_error("value \"%s\" is out of range for type bigint", str);
1085 return false;
1086
1087invalid_syntax:
1088 if (!errorOK)
1089 pg_log_error("invalid input syntax for type bigint: \"%s\"", str);
1090 return false;
int8_t int8
Definition: c.h:536

References PG_INT64_MIN, pg_log_error, pg_mul_s64_overflow(), pg_sub_s64_overflow(), str, and unlikely.

Referenced by makeVariableValue().

◆ syntax_error()

void syntax_error ( const char *  source,
int  lineno,
const char *  line,
const char *  command,
const char *  msg,
const char *  more,
int  column 
)

Definition at line 5626 of file pgbench.c.

5630{
5632
5634
5635 printfPQExpBuffer(&buf, "%s:%d: %s", source, lineno, msg);
5636 if (more != NULL)
5637 appendPQExpBuffer(&buf, " (%s)", more);
5638 if (column >= 0 && line == NULL)
5639 appendPQExpBuffer(&buf, " at column %d", column + 1);
5640 if (command != NULL)
5641 appendPQExpBuffer(&buf, " in command \"%s\"", command);
5642
5643 pg_log_error("%s", buf.data);
5644
5646
5647 if (line != NULL)
5648 {
5649 fprintf(stderr, "%s\n", line);
5650 if (column >= 0)
5651 fprintf(stderr, "%*c error found here\n", column + 1, '^');
5652 }
5653
5654 exit(1);

References appendPQExpBuffer(), buf, fprintf, initPQExpBuffer(), pg_log_error, printfPQExpBuffer(), source, and termPQExpBuffer().

Referenced by expr_yyerror_more(), ParseScript(), pg_lsn_in_safe(), process_backslash_command(), and string_to_uuid().

◆ threadRun()

static THREAD_FUNC_RETURN_TYPE THREAD_FUNC_CC threadRun ( void *  arg)
static

Definition at line 7573 of file pgbench.c.

7575{
7576 TState *thread = (TState *) arg;
7577 CState *state = thread->state;
7579 int nstate = thread->nstate;
7580 int remains = nstate; /* number of remaining clients */
7581 socket_set *sockets = alloc_socket_set(nstate);
7582 int64 thread_start,
7583 last_report,
7584 next_report;
7585 StatsData last,
7586 aggs;
7587
7588 /* open log file if requested */
7589 if (use_log)
7590 {
7591 char logpath[MAXPGPATH];
7592 char *prefix = logfile_prefix ? logfile_prefix : "pgbench_log";
7593
7594 if (thread->tid == 0)
7595 snprintf(logpath, sizeof(logpath), "%s.%d", prefix, main_pid);
7596 else
7597 snprintf(logpath, sizeof(logpath), "%s.%d.%d", prefix, main_pid, thread->tid);
7598
7599 thread->logfile = fopen(logpath, "w");
7600
7601 if (thread->logfile == NULL)
7602 pg_fatal("could not open logfile \"%s\": %m", logpath);
7603 }
7604
7605 /* explicitly initialize the state machines */
7606 for (int i = 0; i < nstate; i++)
7608
7609 /* READY */
7611
7612 thread_start = pg_time_now();
7613 thread->started_time = thread_start;
7614 thread->conn_duration = 0;
7615 last_report = thread_start;
7616 next_report = last_report + (int64) 1000000 * progress;
7617
7618 /* STEADY */
7619 if (!is_connect)
7620 {
7621 /* make connections to the database before starting */
7622 for (int i = 0; i < nstate; i++)
7623 {
7624 if ((state[i].con = doConnect()) == NULL)
7625 {
7626 /* coldly abort on initial connection failure */
7627 pg_fatal("could not create connection for client %d",
7628 state[i].id);
7629 }
7630 }
7631 }
7632
7633 /* GO */
7635
7636 start = pg_time_now();
7637 thread->bench_start = start;
7638 thread->throttle_trigger = start;
7639
7640 /*
7641 * The log format currently has Unix epoch timestamps with whole numbers
7642 * of seconds. Round the first aggregate's start time down to the nearest
7643 * Unix epoch second (the very first aggregate might really have started a
7644 * fraction of a second later, but later aggregates are measured from the
7645 * whole number time that is actually logged).
7646 */
7647 initStats(&aggs, (start + epoch_shift) / 1000000 * 1000000);
7648 last = aggs;
7649
7650 /* loop till all clients have terminated */
7651 while (remains > 0)
7652 {
7653 int nsocks; /* number of sockets to be waited for */
7654 pg_time_usec_t min_usec;
7655 pg_time_usec_t now = 0; /* set this only if needed */
7656
7657 /*
7658 * identify which client sockets should be checked for input, and
7659 * compute the nearest time (if any) at which we need to wake up.
7660 */
7661 clear_socket_set(sockets);
7662 nsocks = 0;
7663 min_usec = PG_INT64_MAX;
7664 for (int i = 0; i < nstate; i++)
7665 {
7666 CState *st = &state[i];
7667
7668 if (st->state == CSTATE_SLEEP || st->state == CSTATE_THROTTLE)
7669 {
7670 /* a nap from the script, or under throttling */
7671 pg_time_usec_t this_usec;
7672
7673 /* get current time if needed */
7675
7676 /* min_usec should be the minimum delay across all clients */
7677 this_usec = (st->state == CSTATE_SLEEP ?
7678 st->sleep_until : st->txn_scheduled) - now;
7679 if (min_usec > this_usec)
7680 min_usec = this_usec;
7681 }
7682 else if (st->state == CSTATE_WAIT_RESULT ||
7684 {
7685 /*
7686 * waiting for result from server - nothing to do unless the
7687 * socket is readable
7688 */
7689 int sock = PQsocket(st->con);
7690
7691 if (sock < 0)
7692 {
7693 pg_log_error("invalid socket: %s", PQerrorMessage(st->con));
7694 goto done;
7695 }
7696
7697 add_socket_to_set(sockets, sock, nsocks++);
7698 }
7699 else if (st->state != CSTATE_ABORTED &&
7700 st->state != CSTATE_FINISHED)
7701 {
7702 /*
7703 * This client thread is ready to do something, so we don't
7704 * want to wait. No need to examine additional clients.
7705 */
7706 min_usec = 0;
7707 break;
7708 }
7709 }
7710
7711 /* also wake up to print the next progress report on time */
7712 if (progress && min_usec > 0 && thread->tid == 0)
7713 {
7715
7716 if (now >= next_report)
7717 min_usec = 0;
7718 else if ((next_report - now) < min_usec)
7719 min_usec = next_report - now;
7720 }
7721
7722 /*
7723 * If no clients are ready to execute actions, sleep until we receive
7724 * data on some client socket or the timeout (if any) elapses.
7725 */
7726 if (min_usec > 0)
7727 {
7728 int rc = 0;
7729
7730 if (min_usec != PG_INT64_MAX)
7731 {
7732 if (nsocks > 0)
7733 {
7734 rc = wait_on_socket_set(sockets, min_usec);
7735 }
7736 else /* nothing active, simple sleep */
7737 {
7738 pg_usleep(min_usec);
7739 }
7740 }
7741 else /* no explicit delay, wait without timeout */
7742 {
7743 rc = wait_on_socket_set(sockets, 0);
7744 }
7745
7746 if (rc < 0)
7747 {
7748 if (errno == EINTR)
7749 {
7750 /* On EINTR, go back to top of loop */
7751 continue;
7752 }
7753 /* must be something wrong */
7754 pg_log_error("%s() failed: %m", SOCKET_WAIT_METHOD);
7755 goto done;
7756 }
7757 }
7758 else
7759 {
7760 /* min_usec <= 0, i.e. something needs to be executed now */
7761
7762 /* If we didn't wait, don't try to read any data */
7763 clear_socket_set(sockets);
7764 }
7765
7766 /* ok, advance the state machine of each connection */
7767 nsocks = 0;
7768 for (int i = 0; i < nstate; i++)
7769 {
7770 CState *st = &state[i];
7771
7772 if (st->state == CSTATE_WAIT_RESULT ||
7774 {
7775 /* don't call advanceConnectionState unless data is available */
7776 int sock = PQsocket(st->con);
7777
7778 if (sock < 0)
7779 {
7780 pg_log_error("invalid socket: %s", PQerrorMessage(st->con));
7781 goto done;
7782 }
7783
7784 if (!socket_has_input(sockets, sock, nsocks++))
7785 continue;
7786 }
7787 else if (st->state == CSTATE_FINISHED ||
7788 st->state == CSTATE_ABORTED)
7789 {
7790 /* this client is done, no need to consider it anymore */
7791 continue;
7792 }
7793
7794 advanceConnectionState(thread, st, &aggs);
7795
7796 /*
7797 * If --exit-on-abort is used, the program is going to exit when
7798 * any client is aborted.
7799 */
7800 if (exit_on_abort && st->state == CSTATE_ABORTED)
7801 goto done;
7802
7803 /*
7804 * If advanceConnectionState changed client to finished state,
7805 * that's one fewer client that remains.
7806 */
7807 else if (st->state == CSTATE_FINISHED ||
7808 st->state == CSTATE_ABORTED)
7809 remains--;
7810 }
7811
7812 /* progress report is made by thread 0 for all threads */
7813 if (progress && thread->tid == 0)
7814 {
7815 pg_time_usec_t now2 = pg_time_now();
7816
7817 if (now2 >= next_report)
7818 {
7819 /*
7820 * Horrible hack: this relies on the thread pointer we are
7821 * passed to be equivalent to threads[0], that is the first
7822 * entry of the threads array. That is why this MUST be done
7823 * by thread 0 and not any other.
7824 */
7825 printProgressReport(thread, thread_start, now2,
7826 &last, &last_report);
7827
7828 /*
7829 * Ensure that the next report is in the future, in case
7830 * pgbench/postgres got stuck somewhere.
7831 */
7832 do
7833 {
7834 next_report += (int64) 1000000 * progress;
7835 } while (now2 >= next_report);
7836 }
7837 }
7838 }
7839
7840done:
7841 if (exit_on_abort)
7842 {
7843 /*
7844 * Abort if any client is not finished, meaning some error occurred.
7845 */
7846 for (int i = 0; i < nstate; i++)
7847 {
7848 if (state[i].state != CSTATE_FINISHED)
7849 {
7850 pg_log_error("Run was aborted due to an error in thread %d",
7851 thread->tid);
7852 exit(2);
7853 }
7854 }
7855 }
7856
7857 disconnect_all(state, nstate);
7858
7859 if (thread->logfile)
7860 {
7861 if (agg_interval > 0)
7862 {
7863 /* log aggregated but not yet reported transactions */
7864 doLog(thread, state, &aggs, false, 0, 0);
7865 }
7866 fclose(thread->logfile);
7867 thread->logfile = NULL;
7868 }
7869 free_socket_set(sockets);
#define PG_INT64_MAX
Definition: c.h:601
int PQsocket(const PGconn *conn)
Definition: fe-connect.c:7730
#define MAXPGPATH
#define THREAD_BARRIER_WAIT(barrier)
Definition: pgbench.c:155
#define SOCKET_WAIT_METHOD
Definition: pgbench.c:107
static void free_socket_set(socket_set *sa)
Definition: pgbench.c:8044
static void clear_socket_set(socket_set *sa)
Definition: pgbench.c:8050
static void add_socket_to_set(socket_set *sa, int fd, int idx)
Definition: pgbench.c:8057
#define THREAD_FUNC_RETURN
Definition: pgbench.c:146
static void advanceConnectionState(TState *thread, CState *st, StatsData *agg)
Definition: pgbench.c:3713
static void printProgressReport(TState *threads, int64 test_start, pg_time_usec_t now, StatsData *last, int64 *last_report)
Definition: pgbench.c:6357
static bool socket_has_input(socket_set *sa, int fd, int idx)
Definition: pgbench.c:8099
static int wait_on_socket_set(socket_set *sa, int64 usecs)
Definition: pgbench.c:8082
static socket_set * alloc_socket_set(int count)
Definition: pgbench.c:8038
void pg_usleep(long microsec)
Definition: signal.c:53
pg_time_usec_t started_time
Definition: pgbench.c:674
#define EINTR
Definition: win32_port.h:364

References add_socket_to_set(), advanceConnectionState(), agg_interval, alloc_socket_set(), arg, barrier, TState::bench_start, clear_socket_set(), CState::con, TState::conn_duration, CSTATE_ABORTED, CSTATE_CHOOSE_SCRIPT, CSTATE_FINISHED, CSTATE_SLEEP, CSTATE_THROTTLE, CSTATE_WAIT_RESULT, CSTATE_WAIT_ROLLBACK_RESULT, disconnect_all(), doConnect(), doLog(), EINTR, epoch_shift, exit_on_abort, free_socket_set(), i, initStats(), is_connect, TState::logfile, logfile_prefix, main_pid, MAXPGPATH, now(), TState::nstate, pg_fatal, PG_INT64_MAX, pg_log_error, pg_time_now(), pg_time_now_lazy(), pg_usleep(), PQerrorMessage(), PQsocket(), printProgressReport(), progress, CState::sleep_until, snprintf, socket_has_input(), SOCKET_WAIT_METHOD, start, TState::started_time, CState::state, TState::state, THREAD_BARRIER_WAIT, THREAD_FUNC_RETURN, TState::throttle_trigger, TState::tid, CState::txn_scheduled, use_log, and wait_on_socket_set().

Referenced by main().

◆ tryExecuteStatement()

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

Definition at line 1555 of file pgbench.c.

1557{
1558 PGresult *res;
1559
1560 res = PQexec(con, sql);
1561 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1562 {
1563 pg_log_error("%s", PQerrorMessage(con));
1564 pg_log_error_detail("(ignoring this error and continuing anyway)");
1565 }
1566 PQclear(res);

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

Referenced by main().

◆ usage()

static void usage ( void  )
static

Definition at line 904 of file pgbench.c.

906{
907 printf("%s is a benchmarking tool for PostgreSQL.\n\n"
908 "Usage:\n"
909 " %s [OPTION]... [DBNAME]\n"
910 "\nInitialization options:\n"
911 " -i, --initialize invokes initialization mode\n"
912 " -I, --init-steps=[" ALL_INIT_STEPS "]+ (default \"" DEFAULT_INIT_STEPS "\")\n"
913 " run selected initialization steps, in the specified order\n"
914 " d: drop any existing pgbench tables\n"
915 " t: create the tables used by the standard pgbench scenario\n"
916 " g: generate data, client-side\n"
917 " G: generate data, server-side\n"
918 " v: invoke VACUUM on the standard tables\n"
919 " p: create primary key indexes on the standard tables\n"
920 " f: create foreign keys between the standard tables\n"
921 " -F, --fillfactor=NUM set fill factor\n"
922 " -n, --no-vacuum do not run VACUUM during initialization\n"
923 " -q, --quiet quiet logging (one message each 5 seconds)\n"
924 " -s, --scale=NUM scaling factor\n"
925 " --foreign-keys create foreign key constraints between tables\n"
926 " --index-tablespace=TABLESPACE\n"
927 " create indexes in the specified tablespace\n"
928 " --partition-method=(range|hash)\n"
929 " partition pgbench_accounts with this method (default: range)\n"
930 " --partitions=NUM partition pgbench_accounts into NUM parts (default: 0)\n"
931 " --tablespace=TABLESPACE create tables in the specified tablespace\n"
932 " --unlogged-tables create tables as unlogged tables\n"
933 "\nOptions to select what to run:\n"
934 " -b, --builtin=NAME[@W] add builtin script NAME weighted at W (default: 1)\n"
935 " (use \"-b list\" to list available scripts)\n"
936 " -f, --file=FILENAME[@W] add script FILENAME weighted at W (default: 1)\n"
937 " -N, --skip-some-updates skip updates of pgbench_tellers and pgbench_branches\n"
938 " (same as \"-b simple-update\")\n"
939 " -S, --select-only perform SELECT-only transactions\n"
940 " (same as \"-b select-only\")\n"
941 "\nBenchmarking options:\n"
942 " -c, --client=NUM number of concurrent database clients (default: 1)\n"
943 " -C, --connect establish new connection for each transaction\n"
944 " -D, --define=VARNAME=VALUE\n"
945 " define variable for use by custom script\n"
946 " -j, --jobs=NUM number of threads (default: 1)\n"
947 " -l, --log write transaction times to log file\n"
948 " -L, --latency-limit=NUM count transactions lasting more than NUM ms as late\n"
949 " -M, --protocol=simple|extended|prepared\n"
950 " protocol for submitting queries (default: simple)\n"
951 " -n, --no-vacuum do not run VACUUM before tests\n"
952 " -P, --progress=NUM show thread progress report every NUM seconds\n"
953 " -r, --report-per-command report latencies, failures, and retries per command\n"
954 " -R, --rate=NUM target rate in transactions per second\n"
955 " -s, --scale=NUM report this scale factor in output\n"
956 " -t, --transactions=NUM number of transactions each client runs (default: 10)\n"
957 " -T, --time=NUM duration of benchmark test in seconds\n"
958 " -v, --vacuum-all vacuum all four standard tables before tests\n"
959 " --aggregate-interval=NUM aggregate data over NUM seconds\n"
960 " --continue-on-error continue running after an SQL error\n"
961 " --exit-on-abort exit when any client is aborted\n"
962 " --failures-detailed report the failures grouped by basic types\n"
963 " --log-prefix=PREFIX prefix for transaction time log file\n"
964 " (default: \"pgbench_log\")\n"
965 " --max-tries=NUM max number of tries to run transaction (default: 1)\n"
966 " --progress-timestamp use Unix epoch timestamps for progress\n"
967 " --random-seed=SEED set random seed (\"time\", \"rand\", integer)\n"
968 " --sampling-rate=NUM fraction of transactions to log (e.g., 0.01 for 1%%)\n"
969 " --show-script=NAME show builtin script code, then exit\n"
970 " --verbose-errors print messages of all errors\n"
971 "\nCommon options:\n"
972 " --debug print debugging output\n"
973 " -d, --dbname=DBNAME database name to connect to\n"
974 " -h, --host=HOSTNAME database server host or socket directory\n"
975 " -p, --port=PORT database server port number\n"
976 " -U, --username=USERNAME connect as specified database user\n"
977 " -V, --version output version information, then exit\n"
978 " -?, --help show this help, then exit\n"
979 "\n"
980 "Report bugs to <%s>.\n"
981 "%s home page: <%s>\n",
982 progname, progname, PACKAGE_BUGREPORT, PACKAGE_NAME, PACKAGE_URL);

References ALL_INIT_STEPS, DEFAULT_INIT_STEPS, printf, and progname.

Referenced by main().

◆ valid_variable_name()

static bool valid_variable_name ( const char *  name)
static

Definition at line 1777 of file pgbench.c.

1779{
1780 const unsigned char *ptr = (const unsigned char *) name;
1781
1782 /* Mustn't be zero-length */
1783 if (*ptr == '\0')
1784 return false;
1785
1786 /* must not start with [0-9] */
1787 if (IS_HIGHBIT_SET(*ptr) ||
1788 strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1789 "_", *ptr) != NULL)
1790 ptr++;
1791 else
1792 return false;
1793
1794 /* remaining characters can include [0-9] */
1795 while (*ptr)
1796 {
1797 if (IS_HIGHBIT_SET(*ptr) ||
1798 strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1799 "_0123456789", *ptr) != NULL)
1800 ptr++;
1801 else
1802 return false;
1803 }
1804
1805 return true;

References IS_HIGHBIT_SET, and name.

Referenced by lookupCreateVariable().

◆ valueTruth()

static bool valueTruth ( PgBenchValue pval)
static

Definition at line 2063 of file pgbench.c.

2065{
2066 switch (pval->type)
2067 {
2068 case PGBT_NULL:
2069 return false;
2070 case PGBT_BOOLEAN:
2071 return pval->u.bval;
2072 case PGBT_INT:
2073 return pval->u.ival != 0;
2074 case PGBT_DOUBLE:
2075 return pval->u.dval != 0.0;
2076 default:
2077 /* internal error, unexpected type */
2078 Assert(0);
2079 return false;
2080 }

References Assert(), PgBenchValue::bval, PgBenchValue::dval, PgBenchValue::ival, PGBT_BOOLEAN, PGBT_DOUBLE, PGBT_INT, PGBT_NULL, PgBenchValue::type, and PgBenchValue::u.

Referenced by evalLazyFunc(), and executeMetaCommand().

◆ valueTypeName()

static char * valueTypeName ( PgBenchValue pval)
static

Definition at line 2021 of file pgbench.c.

2023{
2024 if (pval->type == PGBT_NO_VALUE)
2025 return "none";
2026 else if (pval->type == PGBT_NULL)
2027 return "null";
2028 else if (pval->type == PGBT_INT)
2029 return "int";
2030 else if (pval->type == PGBT_DOUBLE)
2031 return "double";
2032 else if (pval->type == PGBT_BOOLEAN)
2033 return "boolean";
2034 else
2035 {
2036 /* internal error, should never get there */
2037 Assert(false);
2038 return NULL;
2039 }

References Assert(), PGBT_BOOLEAN, PGBT_DOUBLE, PGBT_INT, PGBT_NO_VALUE, PGBT_NULL, and PgBenchValue::type.

Referenced by coerceToBool(), coerceToDouble(), and coerceToInt().

◆ wait_on_socket_set()

static int wait_on_socket_set ( socket_set sa,
int64  usecs 
)
static

Definition at line 8082 of file pgbench.c.

8084{
8085 if (usecs > 0)
8086 {
8087 struct timeval timeout;
8088
8089 timeout.tv_sec = usecs / 1000000;
8090 timeout.tv_usec = usecs % 1000000;
8091 return select(sa->maxfd + 1, &sa->fds, NULL, NULL, &timeout);
8092 }
8093 else
8094 {
8095 return select(sa->maxfd + 1, &sa->fds, NULL, NULL, NULL);
8096 }
#define select(n, r, w, e, timeout)
Definition: win32_port.h:503

References select.

Referenced by threadRun().

Variable Documentation

◆ agg_interval

int agg_interval
static

Definition at line 259 of file pgbench.c.

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

◆ barrier

◆ base_random_sequence

pg_prng_state base_random_sequence
static

Definition at line 485 of file pgbench.c.

Referenced by initRandomState(), main(), and set_random_seed().

◆ builtin_script

const BuiltinScript builtin_script[]
static

Definition at line 789 of file pgbench.c.

Referenced by findBuiltin(), and listAvailableScripts().

◆ continue_on_error

bool continue_on_error = false
static

Definition at line 779 of file pgbench.c.

Referenced by canContinueOnError(), and main().

◆ dbName

const char* dbName = NULL
static

Definition at line 298 of file pgbench.c.

Referenced by doConnect(), main(), pg_database_size_name(), and PQsetdbLogin().

◆ duration

int duration = 0
static

◆ end_time

◆ epoch_shift

pg_time_usec_t epoch_shift
static

Definition at line 456 of file pgbench.c.

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

◆ exit_on_abort

bool exit_on_abort = false
static

Definition at line 778 of file pgbench.c.

Referenced by main(), and threadRun().

◆ failures_detailed

bool failures_detailed = false
static

Definition at line 292 of file pgbench.c.

Referenced by doLog(), getResultString(), main(), and printResults().

◆ fillfactor

◆ index_tablespace

char* index_tablespace = NULL
static

Definition at line 218 of file pgbench.c.

Referenced by initCreatePKeys(), and main().

◆ is_connect

bool is_connect
static

Definition at line 266 of file pgbench.c.

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

◆ latency_limit

◆ logfile_prefix

char* logfile_prefix = NULL
static

Definition at line 299 of file pgbench.c.

Referenced by main(), and threadRun().

◆ main_pid

int main_pid
static

Definition at line 270 of file pgbench.c.

Referenced by main(), and threadRun().

◆ max_tries

uint32 max_tries = 1
static

◆ nclients

int nclients = 1
static

Definition at line 264 of file pgbench.c.

Referenced by main(), and printResults().

◆ nthreads

int nthreads = 1
static

Definition at line 265 of file pgbench.c.

Referenced by main(), printProgressReport(), and printResults().

◆ num_scripts

int num_scripts
static

Definition at line 773 of file pgbench.c.

Referenced by addScript(), allocCStatePrepared(), chooseScript(), main(), and printResults().

◆ nxacts

int nxacts = 0
static

Definition at line 174 of file pgbench.c.

Referenced by advanceConnectionState(), main(), and printResults().

◆ partition_method

partition_method_t partition_method = PART_NONE
static

Definition at line 234 of file pgbench.c.

Referenced by createPartitions(), GetTableInfo(), initCreateTables(), main(), and printResults().

◆ PARTITION_METHOD

const char* const PARTITION_METHOD[] = {"none", "range", "hash"}
static

Definition at line 235 of file pgbench.c.

Referenced by initCreateTables(), and printResults().

◆ partitions

int partitions = 0
static

◆ per_script_stats

bool per_script_stats = false
static

Definition at line 261 of file pgbench.c.

Referenced by main(), printResults(), and processXactStats().

◆ pgbench_callbacks

const PsqlScanCallbacks pgbench_callbacks
static
Initial value:
= {
NULL,
}

Definition at line 855 of file pgbench.c.

Referenced by ParseScript().

◆ pghost

const char* pghost = NULL
static

Definition at line 295 of file pgbench.c.

Referenced by ConnectDatabase(), doConnect(), initialize_environment(), main(), and PQsetdbLogin().

◆ pgport

const char* pgport = NULL
static

Definition at line 296 of file pgbench.c.

Referenced by ConnectDatabase(), doConnect(), initialize_environment(), main(), and PQsetdbLogin().

◆ progname

const char* progname
static

Definition at line 300 of file pgbench.c.

Referenced by doConnect(), main(), and usage().

◆ progress

◆ progress_timestamp

bool progress_timestamp = false
static

Definition at line 263 of file pgbench.c.

Referenced by main(), and printProgressReport().

◆ querymode

QueryMode querymode = QUERY_SIMPLE
static

◆ QUERYMODE

const char* const QUERYMODE[] = {"simple", "extended", "prepared"}
static

Definition at line 722 of file pgbench.c.

Referenced by main(), and printResults().

◆ random_seed

int64 random_seed = -1
static

Definition at line 238 of file pgbench.c.

Referenced by main(), and set_random_seed().

◆ report_per_command

bool report_per_command = false
static

Definition at line 267 of file pgbench.c.

Referenced by advanceConnectionState(), main(), and printResults().

◆ sample_rate

double sample_rate = 0.0
static

Definition at line 198 of file pgbench.c.

Referenced by doLog(), and main().

◆ scale

◆ sql_script

◆ tablespace

◆ throttle_delay

double throttle_delay = 0
static

◆ timer_exceeded

volatile sig_atomic_t timer_exceeded = false
static

Definition at line 304 of file pgbench.c.

Referenced by advanceConnectionState(), doRetry(), handle_sig_alarm(), and runShellCommand().

◆ total_weight

int64 total_weight = 0
static

Definition at line 774 of file pgbench.c.

Referenced by chooseScript(), main(), and printResults().

◆ unlogged_tables

bool unlogged_tables = false
static

Definition at line 193 of file pgbench.c.

Referenced by createPartitions(), initCreateTables(), and main().

◆ use_log

bool use_log
static

Definition at line 257 of file pgbench.c.

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

◆ use_quiet

bool use_quiet
static

Definition at line 258 of file pgbench.c.

Referenced by initPopulateTable(), and main().

◆ username

const char* username = NULL
static

Definition at line 297 of file pgbench.c.

Referenced by doConnect(), and main().

◆ verbose_errors

bool verbose_errors = false
static

Definition at line 776 of file pgbench.c.

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