Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

PostgreSQL Source Code git master
pgbench.c File Reference
#include "postgres_fe.h"
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <signal.h>
#include <time.h>
#include <sys/resource.h>
#include <sys/select.h>
#include "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_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 EStatus getSQLErrorStatus (const char *sqlState)
 
static bool canRetryError (EStatus estatus)
 
static bool readCommandResponse (CState *st, MetaCommand meta, char *varprefix)
 
static bool evaluateSleep (Variables *variables, int argc, char **argv, int *usecs)
 
static bool doRetry (CState *st, pg_time_usec_t *now)
 
static int discardUntilSync (CState *st)
 
static TStatus getTransactionStatus (PGconn *con)
 
static void printVerboseErrorMessages (CState *st, pg_time_usec_t *now, bool is_retry)
 
static void advanceConnectionState (TState *thread, CState *st, StatsData *agg)
 
static int64 getFailures (const StatsData *stats)
 
static const char * getResultString (bool skipped, EStatus estatus)
 
static void disconnect_all (CState *state, int length)
 
static void initDropTables (PGconn *con)
 
static void createPartitions (PGconn *con)
 
static void initCreateTables (PGconn *con)
 
static void initTruncateTables (PGconn *con)
 
static void initBranch (PQExpBufferData *sql, int64 curr)
 
static void initTeller (PQExpBufferData *sql, int64 curr)
 
static void initAccount (PQExpBufferData *sql, int64 curr)
 
static void initPopulateTable (PGconn *con, const char *table, int64 base, initRowMethod init_row)
 
static void initGenerateDataClientSide (PGconn *con)
 
static void initGenerateDataServerSide (PGconn *con)
 
static void initVacuum (PGconn *con)
 
static void initCreatePKeys (PGconn *con)
 
static void initCreateFKeys (PGconn *con)
 
static void checkInitSteps (const char *initialize_steps)
 
static void runInitSteps (const char *initialize_steps)
 
static void GetTableInfo (PGconn *con, bool scale_given)
 
static bool parseQuery (Command *cmd)
 
void syntax_error (const char *source, int lineno, const char *line, const char *command, const char *msg, const char *more, int column)
 
static char * skip_sql_comments (char *sql_command)
 
static Commandcreate_sql_command (PQExpBuffer buf)
 
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 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 686 of file pgbench.c.

◆ MAX_FARGS

#define MAX_FARGS   16

Definition at line 2268 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 680 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 893 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 679 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 844 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 486 of file pgbench.c.

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

◆ EStatus

enum EStatus
Enumerator
ESTATUS_NO_ERROR 
ESTATUS_META_COMMAND_ERROR 
ESTATUS_SERIALIZATION_ERROR 
ESTATUS_DEADLOCK_ERROR 
ESTATUS_OTHER_SQL_ERROR 

Definition at line 455 of file pgbench.c.

457{
460
461 /* SQL errors */
@ ESTATUS_DEADLOCK_ERROR
Definition: pgbench.c:462
@ ESTATUS_META_COMMAND_ERROR
Definition: pgbench.c:458
@ ESTATUS_OTHER_SQL_ERROR
Definition: pgbench.c:463
@ ESTATUS_NO_ERROR
Definition: pgbench.c:457
@ ESTATUS_SERIALIZATION_ERROR
Definition: pgbench.c:461

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

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

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

708{
709 QUERY_SIMPLE, /* simple query */
710 QUERY_EXTENDED, /* extended query */
711 QUERY_PREPARED, /* extended query with prepared statements */
@ QUERY_PREPARED
Definition: pgbench.c:710
@ NUM_QUERYMODE
Definition: pgbench.c:711
@ QUERY_SIMPLE
Definition: pgbench.c:708
@ QUERY_EXTENDED
Definition: pgbench.c:709

◆ TStatus

enum TStatus
Enumerator
TSTATUS_IDLE 
TSTATUS_IN_BLOCK 
TSTATUS_CONN_ERROR 
TSTATUS_OTHER_ERROR 

Definition at line 469 of file pgbench.c.

471{
@ TSTATUS_CONN_ERROR
Definition: pgbench.c:473
@ TSTATUS_IDLE
Definition: pgbench.c:471
@ TSTATUS_IN_BLOCK
Definition: pgbench.c:472
@ TSTATUS_OTHER_ERROR
Definition: pgbench.c:474

Function Documentation

◆ accumStats()

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

Definition at line 1477 of file pgbench.c.

1480{
1481 /* Record the skipped transaction */
1482 if (skipped)
1483 {
1484 /* no latency to record on skipped transactions */
1485 stats->skipped++;
1486 return;
1487 }
1488
1489 /*
1490 * Record the number of retries regardless of whether the transaction was
1491 * successful or failed.
1492 */
1493 if (tries > 1)
1494 {
1495 stats->retries += (tries - 1);
1496 stats->retried++;
1497 }
1498
1499 switch (estatus)
1500 {
1501 /* Record the successful transaction */
1502 case ESTATUS_NO_ERROR:
1503 stats->cnt++;
1504
1505 addToSimpleStats(&stats->latency, lat);
1506
1507 /* and possibly the same for schedule lag */
1508 if (throttle_delay)
1509 addToSimpleStats(&stats->lag, lag);
1510 break;
1511
1512 /* Record the failed transaction */
1514 stats->serialization_failures++;
1515 break;
1517 stats->deadlock_failures++;
1518 break;
1519 default:
1520 /* internal error which should never occur */
1521 pg_fatal("unexpected error status: %d", estatus);
1522 }
#define pg_fatal(...)
static double throttle_delay
Definition: pgbench.c:204
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:1429
int64 serialization_failures
Definition: pgbench.c:436
int64 cnt
Definition: pgbench.c:426
int64 retried
Definition: pgbench.c:432
int64 deadlock_failures
Definition: pgbench.c:439
int64 skipped
Definition: pgbench.c:428
SimpleStats lag
Definition: pgbench.c:443
int64 retries
Definition: pgbench.c:430
SimpleStats latency
Definition: pgbench.c:442

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

Referenced by doLog(), and processXactStats().

◆ add_socket_to_set()

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

Definition at line 7967 of file pgbench.c.

7969{
7970 /* See connect_slot() for background on this code. */
7971#ifdef WIN32
7972 if (sa->fds.fd_count + 1 >= FD_SETSIZE)
7973 {
7974 pg_log_error("too many concurrent database clients for this platform: %d",
7975 sa->fds.fd_count + 1);
7976 exit(1);
7977 }
7978#else
7979 if (fd < 0 || fd >= FD_SETSIZE)
7980 {
7981 pg_log_error("socket file descriptor out of range for select(): %d",
7982 fd);
7983 pg_log_error_hint("Try fewer concurrent database clients.");
7984 exit(1);
7985 }
7986#endif
7987 FD_SET(fd, &sa->fds);
7988 if (fd > sa->maxfd)
7989 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 6261 of file pgbench.c.

6263{
6264 if (script->commands == NULL || script->commands[0] == NULL)
6265 pg_fatal("empty command list for script \"%s\"", script->desc);
6266
6267 if (num_scripts >= MAX_SCRIPTS)
6268 pg_fatal("at most %d SQL scripts are allowed", MAX_SCRIPTS);
6269
6270 CheckConditional(script);
6271
6272 sql_script[num_scripts] = *script;
6273 num_scripts++;
static void CheckConditional(const ParsedScript *ps)
Definition: pgbench.c:5919
#define MAX_SCRIPTS
Definition: pgbench.c:348
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:765
static int num_scripts
Definition: pgbench.c:766
const char * desc
Definition: pgbench.c:759
Command ** commands
Definition: pgbench.c:761

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

1431{
1432 if (ss->count == 0 || val < ss->min)
1433 ss->min = val;
1434 if (ss->count == 0 || val > ss->max)
1435 ss->max = val;
1436 ss->count++;
1437 ss->sum += val;
1438 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 3644 of file pgbench.c.

3646{
3647
3648 /*
3649 * gettimeofday() isn't free, so we get the current timestamp lazily the
3650 * first time it's needed, and reuse the same value throughout this
3651 * function after that. This also ensures that e.g. the calculated
3652 * latency reported in the log file and in the totals are the same. Zero
3653 * means "not set yet". Reset "now" when we execute shell commands or
3654 * expressions, which might take a non-negligible amount of time, though.
3655 */
3656 pg_time_usec_t now = 0;
3657
3658 /*
3659 * Loop in the state machine, until we have to wait for a result from the
3660 * server or have to sleep for throttling or \sleep.
3661 *
3662 * Note: In the switch-statement below, 'break' will loop back here,
3663 * meaning "continue in the state machine". Return is used to return to
3664 * the caller, giving the thread the opportunity to advance another
3665 * client.
3666 */
3667 for (;;)
3668 {
3669 Command *command;
3670
3671 switch (st->state)
3672 {
3673 /* Select transaction (script) to run. */
3675 st->use_file = chooseScript(thread);
3677
3678 /* reset transaction variables to default values */
3680 st->tries = 1;
3681
3682 pg_log_debug("client %d executing script \"%s\"",
3683 st->id, sql_script[st->use_file].desc);
3684
3685 /*
3686 * If time is over, we're done; otherwise, get ready to start
3687 * a new transaction, or to get throttled if that's requested.
3688 */
3691 break;
3692
3693 /* Start new transaction (script) */
3694 case CSTATE_START_TX:
3696
3697 /* establish connection if needed, i.e. under --connect */
3698 if (st->con == NULL)
3699 {
3701
3702 if ((st->con = doConnect()) == NULL)
3703 {
3704 /*
3705 * as the bench is already running, we do not abort
3706 * the process
3707 */
3708 pg_log_error("client %d aborted while establishing connection", st->id);
3709 st->state = CSTATE_ABORTED;
3710 break;
3711 }
3712
3713 /* reset now after connection */
3714 now = pg_time_now();
3715
3716 thread->conn_duration += now - start;
3717
3718 /* Reset session-local state */
3719 pg_free(st->prepared);
3720 st->prepared = NULL;
3721 }
3722
3723 /*
3724 * It is the first try to run this transaction. Remember the
3725 * random state: maybe it will get an error and we will need
3726 * to run it again.
3727 */
3728 st->random_state = st->cs_func_rs;
3729
3730 /* record transaction start time */
3731 st->txn_begin = now;
3732
3733 /*
3734 * When not throttling, this is also the transaction's
3735 * scheduled start time.
3736 */
3737 if (!throttle_delay)
3738 st->txn_scheduled = now;
3739
3740 /* Begin with the first command */
3742 st->command = 0;
3743 break;
3744
3745 /*
3746 * Handle throttling once per transaction by sleeping.
3747 */
3749
3750 /*
3751 * Generate a delay such that the series of delays will
3752 * approximate a Poisson distribution centered on the
3753 * throttle_delay time.
3754 *
3755 * If transactions are too slow or a given wait is shorter
3756 * than a transaction, the next transaction will start right
3757 * away.
3758 */
3760
3761 thread->throttle_trigger +=
3763 st->txn_scheduled = thread->throttle_trigger;
3764
3765 /*
3766 * If --latency-limit is used, and this slot is already late
3767 * so that the transaction will miss the latency limit even if
3768 * it completed immediately, skip this time slot and loop to
3769 * reschedule.
3770 */
3771 if (latency_limit)
3772 {
3774
3775 if (thread->throttle_trigger < now - latency_limit)
3776 {
3777 processXactStats(thread, st, &now, true, agg);
3778
3779 /*
3780 * Finish client if -T or -t was exceeded.
3781 *
3782 * Stop counting skipped transactions under -T as soon
3783 * as the timer is exceeded. Because otherwise it can
3784 * take a very long time to count all of them
3785 * especially when quite a lot of them happen with
3786 * unrealistically high rate setting in -R, which
3787 * would prevent pgbench from ending immediately.
3788 * Because of this behavior, note that there is no
3789 * guarantee that all skipped transactions are counted
3790 * under -T though there is under -t. This is OK in
3791 * practice because it's very unlikely to happen with
3792 * realistic setting.
3793 */
3794 if (timer_exceeded || (nxacts > 0 && st->cnt >= nxacts))
3795 st->state = CSTATE_FINISHED;
3796
3797 /* Go back to top of loop with CSTATE_PREPARE_THROTTLE */
3798 break;
3799 }
3800 }
3801
3802 /*
3803 * stop client if next transaction is beyond pgbench end of
3804 * execution; otherwise, throttle it.
3805 */
3806 st->state = end_time > 0 && st->txn_scheduled > end_time ?
3808 break;
3809
3810 /*
3811 * Wait until it's time to start next transaction.
3812 */
3813 case CSTATE_THROTTLE:
3815
3816 if (now < st->txn_scheduled)
3817 return; /* still sleeping, nothing to do here */
3818
3819 /* done sleeping, but don't start transaction if we're done */
3821 break;
3822
3823 /*
3824 * Send a command to server (or execute a meta-command)
3825 */
3827 command = sql_script[st->use_file].commands[st->command];
3828
3829 /*
3830 * Transition to script end processing if done, but close up
3831 * shop if a pipeline is open at this point.
3832 */
3833 if (command == NULL)
3834 {
3836 st->state = CSTATE_END_TX;
3837 else
3838 {
3839 pg_log_error("client %d aborted: end of script reached with pipeline open",
3840 st->id);
3841 st->state = CSTATE_ABORTED;
3842 }
3843
3844 break;
3845 }
3846
3847 /* record begin time of next command, and initiate it */
3849 {
3851 st->stmt_begin = now;
3852 }
3853
3854 /* Execute the command */
3855 if (command->type == SQL_COMMAND)
3856 {
3857 /* disallow \aset and \gset in pipeline mode */
3859 {
3860 if (command->meta == META_GSET)
3861 {
3862 commandFailed(st, "gset", "\\gset is not allowed in pipeline mode");
3863 st->state = CSTATE_ABORTED;
3864 break;
3865 }
3866 else if (command->meta == META_ASET)
3867 {
3868 commandFailed(st, "aset", "\\aset is not allowed in pipeline mode");
3869 st->state = CSTATE_ABORTED;
3870 break;
3871 }
3872 }
3873
3874 if (!sendCommand(st, command))
3875 {
3876 commandFailed(st, "SQL", "SQL command send failed");
3877 st->state = CSTATE_ABORTED;
3878 }
3879 else
3880 {
3881 /* Wait for results, unless in pipeline mode */
3884 else
3886 }
3887 }
3888 else if (command->type == META_COMMAND)
3889 {
3890 /*-----
3891 * Possible state changes when executing meta commands:
3892 * - on errors CSTATE_ABORTED
3893 * - on sleep CSTATE_SLEEP
3894 * - else CSTATE_END_COMMAND
3895 */
3896 st->state = executeMetaCommand(st, &now);
3897 if (st->state == CSTATE_ABORTED)
3899 }
3900
3901 /*
3902 * We're now waiting for an SQL command to complete, or
3903 * finished processing a metacommand, or need to sleep, or
3904 * something bad happened.
3905 */
3907 st->state == CSTATE_END_COMMAND ||
3908 st->state == CSTATE_SLEEP ||
3909 st->state == CSTATE_ABORTED);
3910 break;
3911
3912 /*
3913 * non executed conditional branch
3914 */
3917 /* quickly skip commands until something to do... */
3918 while (true)
3919 {
3920 command = sql_script[st->use_file].commands[st->command];
3921
3922 /* cannot reach end of script in that state */
3923 Assert(command != NULL);
3924
3925 /*
3926 * if this is conditional related, update conditional
3927 * state
3928 */
3929 if (command->type == META_COMMAND &&
3930 (command->meta == META_IF ||
3931 command->meta == META_ELIF ||
3932 command->meta == META_ELSE ||
3933 command->meta == META_ENDIF))
3934 {
3935 switch (conditional_stack_peek(st->cstack))
3936 {
3937 case IFSTATE_FALSE:
3938 if (command->meta == META_IF)
3939 {
3940 /* nested if in skipped branch - ignore */
3943 st->command++;
3944 }
3945 else if (command->meta == META_ELIF)
3946 {
3947 /* we must evaluate the condition */
3949 }
3950 else if (command->meta == META_ELSE)
3951 {
3952 /* we must execute next command */
3956 st->command++;
3957 }
3958 else if (command->meta == META_ENDIF)
3959 {
3962 if (conditional_active(st->cstack))
3964 /* else state remains CSTATE_SKIP_COMMAND */
3965 st->command++;
3966 }
3967 break;
3968
3969 case IFSTATE_IGNORED:
3970 case IFSTATE_ELSE_FALSE:
3971 if (command->meta == META_IF)
3974 else if (command->meta == META_ENDIF)
3975 {
3978 if (conditional_active(st->cstack))
3980 }
3981 /* could detect "else" & "elif" after "else" */
3982 st->command++;
3983 break;
3984
3985 case IFSTATE_NONE:
3986 case IFSTATE_TRUE:
3987 case IFSTATE_ELSE_TRUE:
3988 default:
3989
3990 /*
3991 * inconsistent if inactive, unreachable dead
3992 * code
3993 */
3994 Assert(false);
3995 }
3996 }
3997 else
3998 {
3999 /* skip and consider next */
4000 st->command++;
4001 }
4002
4003 if (st->state != CSTATE_SKIP_COMMAND)
4004 /* out of quick skip command loop */
4005 break;
4006 }
4007 break;
4008
4009 /*
4010 * Wait for the current SQL command to complete
4011 */
4012 case CSTATE_WAIT_RESULT:
4013 pg_log_debug("client %d receiving", st->id);
4014
4015 /*
4016 * Only check for new network data if we processed all data
4017 * fetched prior. Otherwise we end up doing a syscall for each
4018 * individual pipelined query, which has a measurable
4019 * performance impact.
4020 */
4021 if (PQisBusy(st->con) && !PQconsumeInput(st->con))
4022 {
4023 /* there's something wrong */
4024 commandFailed(st, "SQL", "perhaps the backend died while processing");
4025 st->state = CSTATE_ABORTED;
4026 break;
4027 }
4028 if (PQisBusy(st->con))
4029 return; /* don't have the whole result yet */
4030
4031 /* store or discard the query results */
4032 if (readCommandResponse(st,
4035 {
4036 /*
4037 * outside of pipeline mode: stop reading results.
4038 * pipeline mode: continue reading results until an
4039 * end-of-pipeline response.
4040 */
4043 }
4044 else if (canRetryError(st->estatus))
4045 st->state = CSTATE_ERROR;
4046 else
4047 st->state = CSTATE_ABORTED;
4048 break;
4049
4050 /*
4051 * Wait until sleep is done. This state is entered after a
4052 * \sleep metacommand. The behavior is similar to
4053 * CSTATE_THROTTLE, but proceeds to CSTATE_START_COMMAND
4054 * instead of CSTATE_START_TX.
4055 */
4056 case CSTATE_SLEEP:
4058 if (now < st->sleep_until)
4059 return; /* still sleeping, nothing to do here */
4060 /* Else done sleeping. */
4062 break;
4063
4064 /*
4065 * End of command: record stats and proceed to next command.
4066 */
4067 case CSTATE_END_COMMAND:
4068
4069 /*
4070 * command completed: accumulate per-command execution times
4071 * in thread-local data structure, if per-command latencies
4072 * are requested.
4073 */
4075 {
4077
4078 command = sql_script[st->use_file].commands[st->command];
4079 /* XXX could use a mutex here, but we choose not to */
4080 addToSimpleStats(&command->stats,
4082 }
4083
4084 /* Go ahead with next command, to be executed or skipped */
4085 st->command++;
4086 st->state = conditional_active(st->cstack) ?
4088 break;
4089
4090 /*
4091 * Clean up after an error.
4092 */
4093 case CSTATE_ERROR:
4094 {
4095 TStatus tstatus;
4096
4098
4099 /* Clear the conditional stack */
4101
4102 /* Read and discard until a sync point in pipeline mode */
4104 {
4105 if (!discardUntilSync(st))
4106 {
4107 st->state = CSTATE_ABORTED;
4108 break;
4109 }
4110 }
4111
4112 /*
4113 * Check if we have a (failed) transaction block or not,
4114 * and roll it back if any.
4115 */
4116 tstatus = getTransactionStatus(st->con);
4117 if (tstatus == TSTATUS_IN_BLOCK)
4118 {
4119 /* Try to rollback a (failed) transaction block. */
4120 if (!PQsendQuery(st->con, "ROLLBACK"))
4121 {
4122 pg_log_error("client %d aborted: failed to send sql command for rolling back the failed transaction",
4123 st->id);
4124 st->state = CSTATE_ABORTED;
4125 }
4126 else
4128 }
4129 else if (tstatus == TSTATUS_IDLE)
4130 {
4131 /*
4132 * If time is over, we're done; otherwise, check if we
4133 * can retry the error.
4134 */
4137 }
4138 else
4139 {
4140 if (tstatus == TSTATUS_CONN_ERROR)
4141 pg_log_error("perhaps the backend died while processing");
4142
4143 pg_log_error("client %d aborted while receiving the transaction status", st->id);
4144 st->state = CSTATE_ABORTED;
4145 }
4146 break;
4147 }
4148
4149 /*
4150 * Wait for the rollback command to complete
4151 */
4153 {
4154 PGresult *res;
4155
4156 pg_log_debug("client %d receiving", st->id);
4157 if (!PQconsumeInput(st->con))
4158 {
4159 pg_log_error("client %d aborted while rolling back the transaction after an error; perhaps the backend died while processing",
4160 st->id);
4161 st->state = CSTATE_ABORTED;
4162 break;
4163 }
4164 if (PQisBusy(st->con))
4165 return; /* don't have the whole result yet */
4166
4167 /*
4168 * Read and discard the query result;
4169 */
4170 res = PQgetResult(st->con);
4171 switch (PQresultStatus(res))
4172 {
4173 case PGRES_COMMAND_OK:
4174 /* OK */
4175 PQclear(res);
4176 /* null must be returned */
4177 res = PQgetResult(st->con);
4178 Assert(res == NULL);
4179
4180 /*
4181 * If time is over, we're done; otherwise, check
4182 * if we can retry the error.
4183 */
4186 break;
4187 default:
4188 pg_log_error("client %d aborted while rolling back the transaction after an error; %s",
4189 st->id, PQerrorMessage(st->con));
4190 PQclear(res);
4191 st->state = CSTATE_ABORTED;
4192 break;
4193 }
4194 break;
4195 }
4196
4197 /*
4198 * Retry the transaction after an error.
4199 */
4200 case CSTATE_RETRY:
4201 command = sql_script[st->use_file].commands[st->command];
4202
4203 /*
4204 * Inform that the transaction will be retried after the
4205 * error.
4206 */
4207 if (verbose_errors)
4208 printVerboseErrorMessages(st, &now, true);
4209
4210 /* Count tries and retries */
4211 st->tries++;
4212 command->retries++;
4213
4214 /*
4215 * Reset the random state as they were at the beginning of the
4216 * transaction.
4217 */
4218 st->cs_func_rs = st->random_state;
4219
4220 /* Process the first transaction command. */
4221 st->command = 0;
4224 break;
4225
4226 /*
4227 * Record a failed transaction.
4228 */
4229 case CSTATE_FAILURE:
4230 command = sql_script[st->use_file].commands[st->command];
4231
4232 /* Accumulate the failure. */
4233 command->failures++;
4234
4235 /*
4236 * Inform that the failed transaction will not be retried.
4237 */
4238 if (verbose_errors)
4239 printVerboseErrorMessages(st, &now, false);
4240
4241 /* End the failed transaction. */
4242 st->state = CSTATE_END_TX;
4243 break;
4244
4245 /*
4246 * End of transaction (end of script, really).
4247 */
4248 case CSTATE_END_TX:
4249 {
4250 TStatus tstatus;
4251
4252 /* transaction finished: calculate latency and do log */
4253 processXactStats(thread, st, &now, false, agg);
4254
4255 /*
4256 * missing \endif... cannot happen if CheckConditional was
4257 * okay
4258 */
4260
4261 /*
4262 * We must complete all the transaction blocks that were
4263 * started in this script.
4264 */
4265 tstatus = getTransactionStatus(st->con);
4266 if (tstatus == TSTATUS_IN_BLOCK)
4267 {
4268 pg_log_error("client %d aborted: end of script reached without completing the last transaction",
4269 st->id);
4270 st->state = CSTATE_ABORTED;
4271 break;
4272 }
4273 else if (tstatus != TSTATUS_IDLE)
4274 {
4275 if (tstatus == TSTATUS_CONN_ERROR)
4276 pg_log_error("perhaps the backend died while processing");
4277
4278 pg_log_error("client %d aborted while receiving the transaction status", st->id);
4279 st->state = CSTATE_ABORTED;
4280 break;
4281 }
4282
4283 if (is_connect)
4284 {
4286
4288 finishCon(st);
4289 now = pg_time_now();
4290 thread->conn_duration += now - start;
4291 }
4292
4293 if ((st->cnt >= nxacts && duration <= 0) || timer_exceeded)
4294 {
4295 /* script completed */
4296 st->state = CSTATE_FINISHED;
4297 break;
4298 }
4299
4300 /* next transaction (script) */
4302
4303 /*
4304 * Ensure that we always return on this point, so as to
4305 * avoid an infinite loop if the script only contains meta
4306 * commands.
4307 */
4308 return;
4309 }
4310
4311 /*
4312 * Final states. Close the connection if it's still open.
4313 */
4314 case CSTATE_ABORTED:
4315 case CSTATE_FINISHED:
4316
4317 /*
4318 * Don't measure the disconnection delays here even if in
4319 * CSTATE_FINISHED and -C/--connect option is specified.
4320 * Because in this case all the connections that this thread
4321 * established are closed at the end of transactions and the
4322 * disconnection delays should have already been measured at
4323 * that moment.
4324 *
4325 * In CSTATE_ABORTED state, the measurement is no longer
4326 * necessary because we cannot report complete results anyways
4327 * in this case.
4328 */
4329 finishCon(st);
4330 return;
4331 }
4332 }
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:7723
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:7679
int PQconsumeInput(PGconn *conn)
Definition: fe-exec.c:1995
int PQsendQuery(PGconn *conn, const char *query)
Definition: fe-exec.c:1427
int PQisBusy(PGconn *conn)
Definition: fe-exec.c:2042
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:877
static void printVerboseErrorMessages(CState *st, pg_time_usec_t *now, bool is_retry)
Definition: pgbench.c:3606
static int64 latency_limit
Definition: pgbench.c:212
static TStatus getTransactionStatus(PGconn *con)
Definition: pgbench.c:3569
static int64 end_time
Definition: pgbench.c:176
static bool doRetry(CState *st, pg_time_usec_t *now)
Definition: pgbench.c:3470
static bool sendCommand(CState *st, Command *command)
Definition: pgbench.c:3183
TStatus
Definition: pgbench.c:470
static void finishCon(CState *st)
Definition: pgbench.c:7783
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:893
static int discardUntilSync(CState *st)
Definition: pgbench.c:3516
static ConnectionStateEnum executeMetaCommand(CState *st, pg_time_usec_t *now)
Definition: pgbench.c:4342
static bool canRetryError(EStatus estatus)
Definition: pgbench.c:3253
static void commandFailed(CState *st, const char *cmd, const char *message)
Definition: pgbench.c:3049
static int chooseScript(TState *thread)
Definition: pgbench.c:3075
#define SQL_COMMAND
Definition: pgbench.c:679
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:4723
static int duration
Definition: pgbench.c:175
static PGconn * doConnect(void)
Definition: pgbench.c:1557
static void pg_time_now_lazy(pg_time_usec_t *now)
Definition: pgbench.c:887
static bool verbose_errors
Definition: pgbench.c:769
static int64 getPoissonRand(pg_prng_state *state, double center)
Definition: pgbench.c:1205
#define META_COMMAND
Definition: pgbench.c:680
static bool readCommandResponse(CState *st, MetaCommand meta, char *varprefix)
Definition: pgbench.c:3269
int64 cnt
Definition: pgbench.c:638
int id
Definition: pgbench.c:600
pg_time_usec_t txn_scheduled
Definition: pgbench.c:618
pg_time_usec_t stmt_begin
Definition: pgbench.c:621
int command
Definition: pgbench.c:611
int use_file
Definition: pgbench.c:610
ConditionalStack cstack
Definition: pgbench.c:602
pg_prng_state random_state
Definition: pgbench.c:633
pg_time_usec_t txn_begin
Definition: pgbench.c:620
EStatus estatus
Definition: pgbench.c:630
PGconn * con
Definition: pgbench.c:599
pg_prng_state cs_func_rs
Definition: pgbench.c:608
uint32 tries
Definition: pgbench.c:634
bool ** prepared
Definition: pgbench.c:624
ConnectionStateEnum state
Definition: pgbench.c:601
int64 retries
Definition: pgbench.c:753
char * varprefix
Definition: pgbench.c:750
int type
Definition: pgbench.c:745
MetaCommand meta
Definition: pgbench.c:746
SimpleStats stats
Definition: pgbench.c:752
int64 failures
Definition: pgbench.c:754
int64 throttle_trigger
Definition: pgbench.c:662
pg_prng_state ts_throttle_rs
Definition: pgbench.c:659
pg_time_usec_t conn_duration
Definition: pgbench.c:669

References addToSimpleStats(), Assert(), canRetryError(), chooseScript(), CState::cnt, CState::command, commandFailed(), ParsedScript::commands, CState::con, conditional_active(), conditional_stack_empty(), conditional_stack_peek(), conditional_stack_poke(), conditional_stack_pop(), conditional_stack_push(), conditional_stack_reset(), TState::conn_duration, CState::cs_func_rs, CState::cstack, CSTATE_ABORTED, CSTATE_CHOOSE_SCRIPT, CSTATE_END_COMMAND, CSTATE_END_TX, CSTATE_ERROR, CSTATE_FAILURE, CSTATE_FINISHED, CSTATE_PREPARE_THROTTLE, CSTATE_RETRY, CSTATE_SKIP_COMMAND, CSTATE_SLEEP, CSTATE_START_COMMAND, CSTATE_START_TX, CSTATE_THROTTLE, CSTATE_WAIT_RESULT, CSTATE_WAIT_ROLLBACK_RESULT, ParsedScript::desc, discardUntilSync(), doConnect(), doRetry(), duration, end_time, CState::estatus, ESTATUS_META_COMMAND_ERROR, ESTATUS_NO_ERROR, executeMetaCommand(), Command::failures, finishCon(), getPoissonRand(), getTransactionStatus(), CState::id, IFSTATE_ELSE_FALSE, IFSTATE_ELSE_TRUE, IFSTATE_FALSE, IFSTATE_IGNORED, IFSTATE_NONE, IFSTATE_TRUE, is_connect, latency_limit, Command::meta, META_ASET, META_COMMAND, META_ELIF, META_ELSE, META_ENDIF, META_GSET, META_IF, now(), nxacts, pg_free(), pg_log_debug, pg_log_error, PG_TIME_GET_DOUBLE, pg_time_now(), pg_time_now_lazy(), PGRES_COMMAND_OK, PQ_PIPELINE_OFF, PQ_PIPELINE_ON, PQclear, PQconsumeInput(), PQerrorMessage(), PQgetResult, PQisBusy(), PQpipelineStatus(), PQresultStatus, PQsendQuery(), CState::prepared, printVerboseErrorMessages(), processXactStats(), CState::random_state, readCommandResponse(), report_per_command, 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 7948 of file pgbench.c.

7950{
7951 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 3097 of file pgbench.c.

3099{
3100 Assert(st->prepared == NULL);
3101
3102 st->prepared = pg_malloc(sizeof(bool *) * num_scripts);
3103 for (int i = 0; i < num_scripts; i++)
3104 {
3105 ParsedScript *script = &sql_script[i];
3106 int numcmds;
3107
3108 for (numcmds = 0; script->commands[numcmds] != NULL; numcmds++)
3109 ;
3110 st->prepared[i] = pg_malloc0(sizeof(bool) * numcmds);
3111 }
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 1962 of file pgbench.c.

1964{
1965 char *p,
1966 *name,
1967 *val;
1968
1969 p = sql;
1970 while ((p = strchr(p, ':')) != NULL)
1971 {
1972 int eaten;
1973
1974 name = parseVariable(p, &eaten);
1975 if (name == NULL)
1976 {
1977 while (*p == ':')
1978 {
1979 p++;
1980 }
1981 continue;
1982 }
1983
1984 val = getVariable(variables, name);
1985 free(name);
1986 if (val == NULL)
1987 {
1988 p++;
1989 continue;
1990 }
1991
1992 p = replaceVariable(&sql, p, eaten, val);
1993 }
1994
1995 return sql;
#define free(a)
Definition: header.h:65
static char * parseVariable(const char *sql, int *eaten)
Definition: pgbench.c:1915
static char * getVariable(Variables *variables, char *name)
Definition: pgbench.c:1657
static char * replaceVariable(char **sql, char *param, int len, char *value)
Definition: pgbench.c:1942
const char * name

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

Referenced by sendCommand().

◆ canRetryError()

static bool canRetryError ( EStatus  estatus)
static

Definition at line 3253 of file pgbench.c.

3255{
3256 return (estatus == ESTATUS_SERIALIZATION_ERROR ||
3257 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 5919 of file pgbench.c.

5921{
5922 /* statically check conditional structure */
5924 int i;
5925
5926 for (i = 0; ps->commands[i] != NULL; i++)
5927 {
5928 Command *cmd = ps->commands[i];
5929
5930 if (cmd->type == META_COMMAND)
5931 {
5932 switch (cmd->meta)
5933 {
5934 case META_IF:
5936 break;
5937 case META_ELIF:
5939 ConditionError(ps->desc, i + 1, "\\elif without matching \\if");
5941 ConditionError(ps->desc, i + 1, "\\elif after \\else");
5942 break;
5943 case META_ELSE:
5945 ConditionError(ps->desc, i + 1, "\\else without matching \\if");
5947 ConditionError(ps->desc, i + 1, "\\else after \\else");
5949 break;
5950 case META_ENDIF:
5951 if (!conditional_stack_pop(cs))
5952 ConditionError(ps->desc, i + 1, "\\endif without matching \\if");
5953 break;
5954 default:
5955 /* ignore anything else... */
5956 break;
5957 }
5958 }
5959 }
5960 if (!conditional_stack_empty(cs))
5961 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:5909

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

5278{
5279 if (initialize_steps[0] == '\0')
5280 pg_fatal("no initialization steps specified");
5281
5282 for (const char *step = initialize_steps; *step != '\0'; step++)
5283 {
5284 if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
5285 {
5286 pg_log_error("unrecognized initialization step \"%c\"", *step);
5287 pg_log_error_detail("Allowed step characters are: \"" ALL_INIT_STEPS "\".");
5288 exit(1);
5289 }
5290 }
#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 3075 of file pgbench.c.

3077{
3078 int i = 0;
3079 int64 w;
3080
3081 if (num_scripts == 1)
3082 return 0;
3083
3084 w = getrand(&thread->ts_choose_rs, 0, total_weight - 1);
3085 do
3086 {
3087 w -= sql_script[i++].weight;
3088 } while (w >= 0);
3089
3090 return i - 1;
int64_t int64
Definition: c.h:535
static int64 total_weight
Definition: pgbench.c:767
static int64 getrand(pg_prng_state *state, int64 min, int64 max)
Definition: pgbench.c:1128
int weight
Definition: pgbench.c:760
pg_prng_state ts_choose_rs
Definition: pgbench.c:658

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

7962{
7963 FD_ZERO(&sa->fds);
7964 sa->maxfd = -1;

Referenced by threadRun().

◆ coerceToBool()

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

Definition at line 2030 of file pgbench.c.

2032{
2033 if (pval->type == PGBT_BOOLEAN)
2034 {
2035 *bval = pval->u.bval;
2036 return true;
2037 }
2038 else /* NULL, INT or DOUBLE */
2039 {
2040 pg_log_error("cannot coerce %s to boolean", valueTypeName(pval));
2041 *bval = false; /* suppress uninitialized-variable warnings */
2042 return false;
2043 }
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:2008
@ 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 2099 of file pgbench.c.

2101{
2102 if (pval->type == PGBT_DOUBLE)
2103 {
2104 *dval = pval->u.dval;
2105 return true;
2106 }
2107 else if (pval->type == PGBT_INT)
2108 {
2109 *dval = (double) pval->u.ival;
2110 return true;
2111 }
2112 else /* BOOLEAN or NULL */
2113 {
2114 pg_log_error("cannot coerce %s to double", valueTypeName(pval));
2115 return false;
2116 }
@ 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 2071 of file pgbench.c.

2073{
2074 if (pval->type == PGBT_INT)
2075 {
2076 *ival = pval->u.ival;
2077 return true;
2078 }
2079 else if (pval->type == PGBT_DOUBLE)
2080 {
2081 double dval = rint(pval->u.dval);
2082
2083 if (isnan(dval) || !FLOAT8_FITS_IN_INT64(dval))
2084 {
2085 pg_log_error("double to int overflow for %f", dval);
2086 return false;
2087 }
2088 *ival = (int64) dval;
2089 return true;
2090 }
2091 else /* BOOLEAN or NULL */
2092 {
2093 pg_log_error("cannot coerce %s to int", valueTypeName(pval));
2094 return false;
2095 }
#define FLOAT8_FITS_IN_INT64(num)
Definition: c.h:1091

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

3061{
3062 /*
3063 * Errors should only be detected during an SQL command or the
3064 * \endpipeline meta command. Any other case triggers an assertion
3065 * failure.
3066 */
3069
3070 pg_log_info("client %d got an error in command %d (SQL) of script %d; %s",
3071 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 3049 of file pgbench.c.

3051{
3052 pg_log_error("client %d aborted in command %d (%s) of script %d; %s",
3053 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 1622 of file pgbench.c.

1624{
1625 return strcmp(((const Variable *) v1)->name,
1626 ((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 1227 of file pgbench.c.

1229{
1230 double b = pow(2.0, s - 1.0);
1231 double x,
1232 t,
1233 u,
1234 v;
1235
1236 /* Ensure n is sane */
1237 if (n <= 1)
1238 return 1;
1239
1240 while (true)
1241 {
1242 /* random variates */
1243 u = pg_prng_double(state);
1244 v = pg_prng_double(state);
1245
1246 x = floor(pow(u, -1.0 / (s - 1.0)));
1247
1248 t = pow(1.0 + 1.0 / x, s - 1.0);
1249 /* reject if too large or out of bound */
1250 if (v * x * (t - 1.0) / (b - 1.0) <= t / b && x <= n)
1251 break;
1252 }
1253 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 5909 of file pgbench.c.

5911{
5912 pg_fatal("condition error in script \"%s\" command %d: %s",
5913 desc, cmdn, msg);

References pg_fatal.

Referenced by CheckConditional().

◆ create_sql_command()

static Command * create_sql_command ( PQExpBuffer  buf)
static

Definition at line 5622 of file pgbench.c.

5624{
5625 Command *my_command;
5626 char *p = skip_sql_comments(buf->data);
5627
5628 if (p == NULL)
5629 return NULL;
5630
5631 /* Allocate and initialize Command structure */
5632 my_command = (Command *) pg_malloc(sizeof(Command));
5633 initPQExpBuffer(&my_command->lines);
5634 appendPQExpBufferStr(&my_command->lines, p);
5635 my_command->first_line = NULL; /* this is set later */
5636 my_command->type = SQL_COMMAND;
5637 my_command->meta = META_NONE;
5638 my_command->argc = 0;
5639 my_command->retries = 0;
5640 my_command->failures = 0;
5641 memset(my_command->argv, 0, sizeof(my_command->argv));
5642 my_command->varprefix = NULL; /* allocated later, if needed */
5643 my_command->expr = NULL;
5644 initSimpleStats(&my_command->stats);
5645 my_command->prepname = NULL; /* set later, if needed */
5646
5647 return my_command;
static char * buf
Definition: pg_test_fsync.c:72
static char * skip_sql_comments(char *sql_command)
Definition: pgbench.c:5587
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1420
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:90
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367
PQExpBufferData lines
Definition: pgbench.c:743
PgBenchExpr * expr
Definition: pgbench.c:751
char * argv[MAX_ARGS]
Definition: pgbench.c:748
char * first_line
Definition: pgbench.c:744
int argc
Definition: pgbench.c:747
char * prepname
Definition: pgbench.c:749

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

4798{
4799 PQExpBufferData query;
4800
4801 /* we must have to create some partitions */
4802 Assert(partitions > 0);
4803
4804 fprintf(stderr, "creating %d partitions...\n", partitions);
4805
4806 initPQExpBuffer(&query);
4807
4808 for (int p = 1; p <= partitions; p++)
4809 {
4811 {
4812 int64 part_size = (naccounts * (int64) scale + partitions - 1) / partitions;
4813
4814 printfPQExpBuffer(&query,
4815 "create%s table pgbench_accounts_%d\n"
4816 " partition of pgbench_accounts\n"
4817 " for values from (",
4818 unlogged_tables ? " unlogged" : "", p);
4819
4820 /*
4821 * For RANGE, we use open-ended partitions at the beginning and
4822 * end to allow any valid value for the primary key. Although the
4823 * actual minimum and maximum values can be derived from the
4824 * scale, it is more generic and the performance is better.
4825 */
4826 if (p == 1)
4827 appendPQExpBufferStr(&query, "minvalue");
4828 else
4829 appendPQExpBuffer(&query, INT64_FORMAT, (p - 1) * part_size + 1);
4830
4831 appendPQExpBufferStr(&query, ") to (");
4832
4833 if (p < partitions)
4834 appendPQExpBuffer(&query, INT64_FORMAT, p * part_size + 1);
4835 else
4836 appendPQExpBufferStr(&query, "maxvalue");
4837
4838 appendPQExpBufferChar(&query, ')');
4839 }
4840 else if (partition_method == PART_HASH)
4841 printfPQExpBuffer(&query,
4842 "create%s table pgbench_accounts_%d\n"
4843 " partition of pgbench_accounts\n"
4844 " for values with (modulus %d, remainder %d)",
4845 unlogged_tables ? " unlogged" : "", p,
4846 partitions, p - 1);
4847 else /* cannot get there */
4848 Assert(0);
4849
4850 /*
4851 * Per ddlinfo in initCreateTables, fillfactor is needed on table
4852 * pgbench_accounts.
4853 */
4854 appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4855
4856 executeStatement(con, query.data);
4857 }
4858
4859 termPQExpBuffer(&query);
#define INT64_FORMAT
Definition: c.h:556
#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:1526
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:235
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:265
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:378
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:129

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

Referenced by initCreateTables().

◆ discardUntilSync()

static int discardUntilSync ( CState st)
static

Definition at line 3516 of file pgbench.c.

3518{
3519 bool received_sync = false;
3520
3521 /* send a sync */
3522 if (!PQpipelineSync(st->con))
3523 {
3524 pg_log_error("client %d aborted: failed to send a pipeline sync",
3525 st->id);
3526 return 0;
3527 }
3528
3529 /* receive PGRES_PIPELINE_SYNC and null following it */
3530 for (;;)
3531 {
3532 PGresult *res = PQgetResult(st->con);
3533
3535 received_sync = true;
3536 else if (received_sync)
3537 {
3538 /*
3539 * PGRES_PIPELINE_SYNC must be followed by another
3540 * PGRES_PIPELINE_SYNC or NULL; otherwise, assert failure.
3541 */
3542 Assert(res == NULL);
3543
3544 /*
3545 * Reset ongoing sync count to 0 since all PGRES_PIPELINE_SYNC
3546 * results have been discarded.
3547 */
3548 st->num_syncs = 0;
3549 PQclear(res);
3550 break;
3551 }
3552 PQclear(res);
3553 }
3554
3555 /* exit pipeline */
3556 if (PQexitPipelineMode(st->con) != 1)
3557 {
3558 pg_log_error("client %d aborted: failed to exit pipeline mode for rolling back the failed transaction",
3559 st->id);
3560 return 0;
3561 }
3562 return 1;
int PQexitPipelineMode(PGconn *conn)
Definition: fe-exec.c:3084
int PQpipelineSync(PGconn *conn)
Definition: fe-exec.c:3283
@ PGRES_PIPELINE_SYNC
Definition: libpq-fe.h:139
int num_syncs
Definition: pgbench.c:612

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

Referenced by advanceConnectionState().

◆ disconnect_all()

static void disconnect_all ( CState state,
int  length 
)
static

Definition at line 4762 of file pgbench.c.

4764{
4765 int i;
4766
4767 for (i = 0; i < length; i++)
4768 finishCon(&state[i]);

References finishCon(), and i.

Referenced by main(), and threadRun().

◆ doConnect()

static PGconn * doConnect ( void  )
static

Definition at line 1557 of file pgbench.c.

1559{
1560 PGconn *conn;
1561 bool new_pass;
1562 static char *password = NULL;
1563
1564 /*
1565 * Start the connection. Loop until we have a password if requested by
1566 * backend.
1567 */
1568 do
1569 {
1570#define PARAMS_ARRAY_SIZE 7
1571
1572 const char *keywords[PARAMS_ARRAY_SIZE];
1573 const char *values[PARAMS_ARRAY_SIZE];
1574
1575 keywords[0] = "host";
1576 values[0] = pghost;
1577 keywords[1] = "port";
1578 values[1] = pgport;
1579 keywords[2] = "user";
1580 values[2] = username;
1581 keywords[3] = "password";
1582 values[3] = password;
1583 keywords[4] = "dbname";
1584 values[4] = dbName;
1585 keywords[5] = "fallback_application_name";
1586 values[5] = progname;
1587 keywords[6] = NULL;
1588 values[6] = NULL;
1589
1590 new_pass = false;
1591
1593
1594 if (!conn)
1595 {
1596 pg_log_error("connection to database \"%s\" failed", dbName);
1597 return NULL;
1598 }
1599
1600 if (PQstatus(conn) == CONNECTION_BAD &&
1602 !password)
1603 {
1604 PQfinish(conn);
1605 password = simple_prompt("Password: ", false);
1606 new_pass = true;
1607 }
1608 } while (new_pass);
1609
1610 /* check to see that the backend connection was successfully made */
1612 {
1614 PQfinish(conn);
1615 return NULL;
1616 }
1617
1618 return conn;
static Datum values[MAXATTR]
Definition: bootstrap.c:153
int PQconnectionNeedsPassword(const PGconn *conn)
Definition: fe-connect.c:7732
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:7616
void PQfinish(PGconn *conn)
Definition: fe-connect.c:5305
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:768
static const JsonPathKeyword keywords[]
@ CONNECTION_BAD
Definition: libpq-fe.h:85
#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 4603 of file pgbench.c.

4606{
4607 FILE *logfile = thread->logfile;
4609
4610 Assert(use_log);
4611
4612 /*
4613 * Skip the log entry if sampling is enabled and this row doesn't belong
4614 * to the random sample.
4615 */
4616 if (sample_rate != 0.0 &&
4618 return;
4619
4620 /* should we aggregate the results or not? */
4621 if (agg_interval > 0)
4622 {
4624
4625 /*
4626 * Loop until we reach the interval of the current moment, and print
4627 * any empty intervals in between (this may happen with very low tps,
4628 * e.g. --rate=0.1).
4629 */
4630
4631 while ((next = agg->start_time + agg_interval * INT64CONST(1000000)) <= now)
4632 {
4633 double lag_sum = 0.0;
4634 double lag_sum2 = 0.0;
4635 double lag_min = 0.0;
4636 double lag_max = 0.0;
4637 int64 skipped = 0;
4638 int64 serialization_failures = 0;
4639 int64 deadlock_failures = 0;
4640 int64 retried = 0;
4641 int64 retries = 0;
4642
4643 /* print aggregated report to logfile */
4644 fprintf(logfile, INT64_FORMAT " " INT64_FORMAT " %.0f %.0f %.0f %.0f",
4645 agg->start_time / 1000000, /* seconds since Unix epoch */
4646 agg->cnt,
4647 agg->latency.sum,
4648 agg->latency.sum2,
4649 agg->latency.min,
4650 agg->latency.max);
4651
4652 if (throttle_delay)
4653 {
4654 lag_sum = agg->lag.sum;
4655 lag_sum2 = agg->lag.sum2;
4656 lag_min = agg->lag.min;
4657 lag_max = agg->lag.max;
4658 }
4659 fprintf(logfile, " %.0f %.0f %.0f %.0f",
4660 lag_sum,
4661 lag_sum2,
4662 lag_min,
4663 lag_max);
4664
4665 if (latency_limit)
4666 skipped = agg->skipped;
4667 fprintf(logfile, " " INT64_FORMAT, skipped);
4668
4669 if (max_tries != 1)
4670 {
4671 retried = agg->retried;
4672 retries = agg->retries;
4673 }
4674 fprintf(logfile, " " INT64_FORMAT " " INT64_FORMAT, retried, retries);
4675
4677 {
4678 serialization_failures = agg->serialization_failures;
4679 deadlock_failures = agg->deadlock_failures;
4680 }
4682 serialization_failures,
4683 deadlock_failures);
4684
4685 fputc('\n', logfile);
4686
4687 /* reset data and move to next interval */
4688 initStats(agg, next);
4689 }
4690
4691 /* accumulate the current transaction */
4692 accumStats(agg, skipped, latency, lag, st->estatus, st->tries);
4693 }
4694 else
4695 {
4696 /* no, print raw transactions */
4697 if (!skipped && st->estatus == ESTATUS_NO_ERROR)
4698 fprintf(logfile, "%d " INT64_FORMAT " %.0f %d " INT64_FORMAT " "
4700 st->id, st->cnt, latency, st->use_file,
4701 now / 1000000, now % 1000000);
4702 else
4703 fprintf(logfile, "%d " INT64_FORMAT " %s %d " INT64_FORMAT " "
4705 st->id, st->cnt, getResultString(skipped, st->estatus),
4706 st->use_file, now / 1000000, now % 1000000);
4707
4708 if (throttle_delay)
4709 fprintf(logfile, " %.0f", lag);
4710 if (max_tries != 1)
4711 fprintf(logfile, " %u", st->tries - 1);
4712 fputc('\n', logfile);
4713 }
static int32 next
Definition: blutils.c:224
#define INT64CONST(x)
Definition: c.h:552
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:1477
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:1460
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:450
static const char * getResultString(bool skipped, EStatus estatus)
Definition: pgbench.c:4572
pg_time_usec_t start_time
Definition: pgbench.c:379
FILE * logfile
Definition: pgbench.c:663
pg_prng_state ts_sample_rs
Definition: pgbench.c:660

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(), 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 3470 of file pgbench.c.

3472{
3474
3475 /* We can only retry serialization or deadlock errors. */
3476 if (!canRetryError(st->estatus))
3477 return false;
3478
3479 /*
3480 * We must have at least one option to limit the retrying of transactions
3481 * that got an error.
3482 */
3484
3485 /*
3486 * We cannot retry the error if we have reached the maximum number of
3487 * tries.
3488 */
3489 if (max_tries && st->tries >= max_tries)
3490 return false;
3491
3492 /*
3493 * We cannot retry the error if we spent too much time on this
3494 * transaction.
3495 */
3496 if (latency_limit)
3497 {
3499 if (*now - st->txn_scheduled > latency_limit)
3500 return false;
3501 }
3502
3503 /*
3504 * We cannot retry the error if the benchmark duration is over.
3505 */
3506 if (timer_exceeded)
3507 return false;
3508
3509 /* OK */
3510 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 1799 of file pgbench.c.

1801{
1802 /* total number of variables required now */
1803 needed += variables->nvars;
1804
1805 if (variables->max_vars < needed)
1806 {
1807 variables->max_vars = needed + VARIABLES_ALLOC_MARGIN;
1808 variables->vars = (Variable *)
1809 pg_realloc(variables->vars, variables->max_vars * sizeof(Variable));
1810 }
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 2842 of file pgbench.c.

2845{
2846 if (isLazyFunc(func))
2847 return evalLazyFunc(st, func, args, retval);
2848 else
2849 return evalStandardFunc(st, func, args, retval);
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:2151
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2158
static bool evalStandardFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2275

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

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

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

2860{
2861 switch (expr->etype)
2862 {
2863 case ENODE_CONSTANT:
2864 {
2865 *retval = expr->u.constant;
2866 return true;
2867 }
2868
2869 case ENODE_VARIABLE:
2870 {
2871 Variable *var;
2872
2873 if ((var = lookupVariable(&st->variables, expr->u.variable.varname)) == NULL)
2874 {
2875 pg_log_error("undefined variable \"%s\"", expr->u.variable.varname);
2876 return false;
2877 }
2878
2879 if (!makeVariableValue(var))
2880 return false;
2881
2882 *retval = var->value;
2883 return true;
2884 }
2885
2886 case ENODE_FUNCTION:
2887 return evalFunc(st,
2888 expr->u.function.function,
2889 expr->u.function.args,
2890 retval);
2891
2892 default:
2893 /* internal error which should never occur */
2894 pg_fatal("unexpected enode type in evaluation: %d", expr->etype);
2895 }
static bool evalFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2842
static bool makeVariableValue(Variable *var)
Definition: pgbench.c:1690
static Variable * lookupVariable(Variables *variables, char *name)
Definition: pgbench.c:1630
@ ENODE_VARIABLE
Definition: pgbench.h:60
@ ENODE_CONSTANT
Definition: pgbench.h:59
@ ENODE_FUNCTION
Definition: pgbench.h:61
Variables variables
Definition: pgbench.c:615
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 3425 of file pgbench.c.

3427{
3428 char *var;
3429 int usec;
3430
3431 if (*argv[1] == ':')
3432 {
3433 if ((var = getVariable(variables, argv[1] + 1)) == NULL)
3434 {
3435 pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[1] + 1);
3436 return false;
3437 }
3438
3439 usec = atoi(var);
3440
3441 /* Raise an error if the value of a variable is not a number */
3442 if (usec == 0 && !isdigit((unsigned char) *var))
3443 {
3444 pg_log_error("%s: invalid sleep time \"%s\" for variable \"%s\"",
3445 argv[0], var, argv[1] + 1);
3446 return false;
3447 }
3448 }
3449 else
3450 usec = atoi(argv[1]);
3451
3452 if (argc > 2)
3453 {
3454 if (pg_strcasecmp(argv[2], "ms") == 0)
3455 usec *= 1000;
3456 else if (pg_strcasecmp(argv[2], "s") == 0)
3457 usec *= 1000000;
3458 }
3459 else
3460 usec *= 1000000;
3461
3462 *usecs = usec;
3463 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 4342 of file pgbench.c.

4344{
4345 Command *command = sql_script[st->use_file].commands[st->command];
4346 int argc;
4347 char **argv;
4348
4349 Assert(command != NULL && command->type == META_COMMAND);
4350
4351 argc = command->argc;
4352 argv = command->argv;
4353
4355 {
4357
4359
4360 printfPQExpBuffer(&buf, "client %d executing \\%s", st->id, argv[0]);
4361 for (int i = 1; i < argc; i++)
4362 appendPQExpBuffer(&buf, " %s", argv[i]);
4363
4364 pg_log_debug("%s", buf.data);
4365
4367 }
4368
4369 if (command->meta == META_SLEEP)
4370 {
4371 int usec;
4372
4373 /*
4374 * A \sleep doesn't execute anything, we just get the delay from the
4375 * argument, and enter the CSTATE_SLEEP state. (The per-command
4376 * latency will be recorded in CSTATE_SLEEP state, not here, after the
4377 * delay has elapsed.)
4378 */
4379 if (!evaluateSleep(&st->variables, argc, argv, &usec))
4380 {
4381 commandFailed(st, "sleep", "execution of meta-command failed");
4382 return CSTATE_ABORTED;
4383 }
4384
4386 st->sleep_until = (*now) + usec;
4387 return CSTATE_SLEEP;
4388 }
4389 else if (command->meta == META_SET)
4390 {
4391 PgBenchExpr *expr = command->expr;
4392 PgBenchValue result;
4393
4394 if (!evaluateExpr(st, expr, &result))
4395 {
4396 commandFailed(st, argv[0], "evaluation of meta-command failed");
4397 return CSTATE_ABORTED;
4398 }
4399
4400 if (!putVariableValue(&st->variables, argv[0], argv[1], &result))
4401 {
4402 commandFailed(st, "set", "assignment of meta-command failed");
4403 return CSTATE_ABORTED;
4404 }
4405 }
4406 else if (command->meta == META_IF)
4407 {
4408 /* backslash commands with an expression to evaluate */
4409 PgBenchExpr *expr = command->expr;
4410 PgBenchValue result;
4411 bool cond;
4412
4413 if (!evaluateExpr(st, expr, &result))
4414 {
4415 commandFailed(st, argv[0], "evaluation of meta-command failed");
4416 return CSTATE_ABORTED;
4417 }
4418
4419 cond = valueTruth(&result);
4421 }
4422 else if (command->meta == META_ELIF)
4423 {
4424 /* backslash commands with an expression to evaluate */
4425 PgBenchExpr *expr = command->expr;
4426 PgBenchValue result;
4427 bool cond;
4428
4430 {
4431 /* elif after executed block, skip eval and wait for endif. */
4433 return CSTATE_END_COMMAND;
4434 }
4435
4436 if (!evaluateExpr(st, expr, &result))
4437 {
4438 commandFailed(st, argv[0], "evaluation of meta-command failed");
4439 return CSTATE_ABORTED;
4440 }
4441
4442 cond = valueTruth(&result);
4445 }
4446 else if (command->meta == META_ELSE)
4447 {
4448 switch (conditional_stack_peek(st->cstack))
4449 {
4450 case IFSTATE_TRUE:
4452 break;
4453 case IFSTATE_FALSE: /* inconsistent if active */
4454 case IFSTATE_IGNORED: /* inconsistent if active */
4455 case IFSTATE_NONE: /* else without if */
4456 case IFSTATE_ELSE_TRUE: /* else after else */
4457 case IFSTATE_ELSE_FALSE: /* else after else */
4458 default:
4459 /* dead code if conditional check is ok */
4460 Assert(false);
4461 }
4462 }
4463 else if (command->meta == META_ENDIF)
4464 {
4467 }
4468 else if (command->meta == META_SETSHELL)
4469 {
4470 if (!runShellCommand(&st->variables, argv[1], argv + 2, argc - 2))
4471 {
4472 commandFailed(st, "setshell", "execution of meta-command failed");
4473 return CSTATE_ABORTED;
4474 }
4475 }
4476 else if (command->meta == META_SHELL)
4477 {
4478 if (!runShellCommand(&st->variables, NULL, argv + 1, argc - 1))
4479 {
4480 commandFailed(st, "shell", "execution of meta-command failed");
4481 return CSTATE_ABORTED;
4482 }
4483 }
4484 else if (command->meta == META_STARTPIPELINE)
4485 {
4486 /*
4487 * In pipeline mode, we use a workflow based on libpq pipeline
4488 * functions.
4489 */
4490 if (querymode == QUERY_SIMPLE)
4491 {
4492 commandFailed(st, "startpipeline", "cannot use pipeline mode with the simple query protocol");
4493 return CSTATE_ABORTED;
4494 }
4495
4496 /*
4497 * If we're in prepared-query mode, we need to prepare all the
4498 * commands that are inside the pipeline before we actually start the
4499 * pipeline itself. This solves the problem that running BEGIN
4500 * ISOLATION LEVEL SERIALIZABLE in a pipeline would fail due to a
4501 * snapshot having been acquired by the prepare within the pipeline.
4502 */
4505
4507 {
4508 commandFailed(st, "startpipeline", "already in pipeline mode");
4509 return CSTATE_ABORTED;
4510 }
4511 if (PQenterPipelineMode(st->con) == 0)
4512 {
4513 commandFailed(st, "startpipeline", "failed to enter pipeline mode");
4514 return CSTATE_ABORTED;
4515 }
4516 }
4517 else if (command->meta == META_SYNCPIPELINE)
4518 {
4520 {
4521 commandFailed(st, "syncpipeline", "not in pipeline mode");
4522 return CSTATE_ABORTED;
4523 }
4524 if (PQsendPipelineSync(st->con) == 0)
4525 {
4526 commandFailed(st, "syncpipeline", "failed to send a pipeline sync");
4527 return CSTATE_ABORTED;
4528 }
4529 st->num_syncs++;
4530 }
4531 else if (command->meta == META_ENDPIPELINE)
4532 {
4534 {
4535 commandFailed(st, "endpipeline", "not in pipeline mode");
4536 return CSTATE_ABORTED;
4537 }
4538 if (!PQpipelineSync(st->con))
4539 {
4540 commandFailed(st, "endpipeline", "failed to send a pipeline sync");
4541 return CSTATE_ABORTED;
4542 }
4543 st->num_syncs++;
4544 /* Now wait for the PGRES_PIPELINE_SYNC and exit pipeline mode there */
4545 /* collect pending results before getting out of pipeline mode */
4546 return CSTATE_WAIT_RESULT;
4547 }
4548
4549 /*
4550 * executing the expression or shell command might have taken a
4551 * non-negligible amount of time, so reset 'now'
4552 */
4553 *now = 0;
4554
4555 return CSTATE_END_COMMAND;
int PQenterPipelineMode(PGconn *conn)
Definition: fe-exec.c:3053
int PQsendPipelineSync(PGconn *conn)
Definition: fe-exec.c:3293
enum pg_log_level __pg_log_level
Definition: logging.c:21
@ PG_LOG_DEBUG
Definition: logging.h:26
static QueryMode querymode
Definition: pgbench.c:714
static void prepareCommandsInPipeline(CState *st)
Definition: pgbench.c:3150
static bool runShellCommand(Variables *variables, char *variable, char **argv, int argc)
Definition: pgbench.c:2943
static bool evaluateSleep(Variables *variables, int argc, char **argv, int *usecs)
Definition: pgbench.c:3425
static bool putVariableValue(Variables *variables, const char *context, char *name, const PgBenchValue *value)
Definition: pgbench.c:1878
pg_time_usec_t sleep_until
Definition: pgbench.c:619

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

1528{
1529 PGresult *res;
1530
1531 res = PQexec(con, sql);
1532 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1533 {
1534 pg_log_error("query failed: %s", PQerrorMessage(con));
1535 pg_log_error_detail("Query was: %s", sql);
1536 exit(1);
1537 }
1538 PQclear(res);
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2273

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

6190{
6191 int i,
6192 found = 0,
6193 len = strlen(name);
6194 const BuiltinScript *result = NULL;
6195
6196 for (i = 0; i < lengthof(builtin_script); i++)
6197 {
6198 if (strncmp(builtin_script[i].name, name, len) == 0)
6199 {
6200 result = &builtin_script[i];
6201 found++;
6202 }
6203 }
6204
6205 /* ok, unambiguous result */
6206 if (found == 1)
6207 return result;
6208
6209 /* error cases */
6210 if (found == 0)
6211 pg_log_error("no builtin script found for name \"%s\"", name);
6212 else /* found > 1 */
6213 pg_log_error("ambiguous builtin name: %d builtin scripts found for prefix \"%s\"", found, name);
6214
6216 exit(1);
#define lengthof(array)
Definition: c.h:787
const void size_t len
static void listAvailableScripts(void)
Definition: pgbench.c:6176
static const BuiltinScript builtin_script[]
Definition: pgbench.c:781

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

7785{
7786 if (st->con != NULL)
7787 {
7788 PQfinish(st->con);
7789 st->con = NULL;
7790 }

References CState::con, and PQfinish().

Referenced by advanceConnectionState(), and disconnect_all().

◆ free_command()

static void free_command ( Command command)
static

Definition at line 5651 of file pgbench.c.

5653{
5654 termPQExpBuffer(&command->lines);
5655 pg_free(command->first_line);
5656 for (int i = 0; i < command->argc; i++)
5657 pg_free(command->argv[i]);
5658 pg_free(command->varprefix);
5659
5660 /*
5661 * It should also free expr recursively, but this is currently not needed
5662 * as only gset commands (which do not have an expression) are freed.
5663 */
5664 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 7954 of file pgbench.c.

7956{
7957 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 852 of file pgbench.c.

854{
855 PGresult *res;
856 char *val;
857 char relkind;
858 const char *params[1] = {table};
859 const char *sql =
860 "SELECT relkind FROM pg_catalog.pg_class WHERE oid=$1::pg_catalog.regclass";
861
862 res = PQexecParams(con, sql, 1, NULL, params, NULL, NULL, 0);
864 {
865 pg_log_error("query failed: %s", PQerrorMessage(con));
866 pg_log_error_detail("Query was: %s", sql);
867 exit(1);
868 }
869 val = PQgetvalue(res, 0, 0);
870 Assert(strlen(val) == 1);
871 relkind = val[0];
872 PQclear(res);
873
874 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:2287
#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 1139 of file pgbench.c.

1142{
1143 double cut,
1144 uniform,
1145 rand;
1146
1147 /* abort if wrong parameter, but must really be checked beforehand */
1148 Assert(parameter > 0.0);
1149 cut = exp(-parameter);
1150 /* pg_prng_double value in [0, 1), uniform in (0, 1] */
1151 uniform = 1.0 - pg_prng_double(state);
1152
1153 /*
1154 * inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
1155 */
1156 Assert((1.0 - cut) != 0.0);
1157 rand = -log(cut + (1.0 - cut) * uniform) / parameter;
1158 /* return int64 random number within between min and max */
1159 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 4561 of file pgbench.c.

4563{
4564 return (stats->serialization_failures +
4565 stats->deadlock_failures);

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

Referenced by printProgressReport(), and printResults().

◆ getGaussianRand()

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

Definition at line 1163 of file pgbench.c.

1166{
1167 double stdev;
1168 double rand;
1169
1170 /* abort if parameter is too low, but must really be checked beforehand */
1171 Assert(parameter >= MIN_GAUSSIAN_PARAM);
1172
1173 /*
1174 * Get normally-distributed random number in the range -parameter <= stdev
1175 * < parameter.
1176 *
1177 * This loop is executed until the number is in the expected range.
1178 *
1179 * As the minimum parameter is 2.0, the probability of looping is low:
1180 * sqrt(-2 ln(r)) <= 2 => r >= e^{-2} ~ 0.135, then when taking the
1181 * average sinus multiplier as 2/pi, we have a 8.6% looping probability in
1182 * the worst case. For a parameter value of 5.0, the looping probability
1183 * is about e^{-5} * 2 / pi ~ 0.43%.
1184 */
1185 do
1186 {
1188 }
1189 while (stdev < -parameter || stdev >= parameter);
1190
1191 /* stdev is in [-parameter, parameter), normalization to [0,1) */
1192 rand = (stdev + parameter) / (parameter * 2.0);
1193
1194 /* return int64 random number within between min and max */
1195 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 1271 of file pgbench.c.

1273{
1274 int64 result;
1275 int i;
1276
1277 result = FNV_OFFSET_BASIS ^ seed;
1278 for (i = 0; i < 8; ++i)
1279 {
1280 int32 octet = val & 0xff;
1281
1282 val = val >> 8;
1283 result = result ^ octet;
1284 result = result * FNV_PRIME;
1285 }
1286
1287 return result;
int32_t int32
Definition: c.h:534
#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 1296 of file pgbench.c.

1298{
1299 uint64 result = seed ^ MM2_MUL_TIMES_8; /* sizeof(int64) */
1300 uint64 k = (uint64) val;
1301
1302 k *= MM2_MUL;
1303 k ^= k >> MM2_ROT;
1304 k *= MM2_MUL;
1305
1306 result ^= k;
1307 result *= MM2_MUL;
1308
1309 result ^= result >> MM2_ROT;
1310 result *= MM2_MUL;
1311 result ^= result >> MM2_ROT;
1312
1313 return (int64) result;
uint64_t uint64
Definition: c.h:539
#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 2901 of file pgbench.c.

2903{
2904 MetaCommand mc;
2905
2906 if (cmd == NULL)
2907 mc = META_NONE;
2908 else if (pg_strcasecmp(cmd, "set") == 0)
2909 mc = META_SET;
2910 else if (pg_strcasecmp(cmd, "setshell") == 0)
2911 mc = META_SETSHELL;
2912 else if (pg_strcasecmp(cmd, "shell") == 0)
2913 mc = META_SHELL;
2914 else if (pg_strcasecmp(cmd, "sleep") == 0)
2915 mc = META_SLEEP;
2916 else if (pg_strcasecmp(cmd, "if") == 0)
2917 mc = META_IF;
2918 else if (pg_strcasecmp(cmd, "elif") == 0)
2919 mc = META_ELIF;
2920 else if (pg_strcasecmp(cmd, "else") == 0)
2921 mc = META_ELSE;
2922 else if (pg_strcasecmp(cmd, "endif") == 0)
2923 mc = META_ENDIF;
2924 else if (pg_strcasecmp(cmd, "gset") == 0)
2925 mc = META_GSET;
2926 else if (pg_strcasecmp(cmd, "aset") == 0)
2927 mc = META_ASET;
2928 else if (pg_strcasecmp(cmd, "startpipeline") == 0)
2929 mc = META_STARTPIPELINE;
2930 else if (pg_strcasecmp(cmd, "syncpipeline") == 0)
2931 mc = META_SYNCPIPELINE;
2932 else if (pg_strcasecmp(cmd, "endpipeline") == 0)
2933 mc = META_ENDPIPELINE;
2934 else
2935 mc = META_NONE;
2936 return mc;
MetaCommand
Definition: pgbench.c:689

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

1207{
1208 /*
1209 * Use inverse transform sampling to generate a value > 0, such that the
1210 * expected (i.e. average) value is the given argument.
1211 */
1212 double uniform;
1213
1214 /* pg_prng_double value in [0, 1), uniform in (0, 1] */
1215 uniform = 1.0 - pg_prng_double(state);
1216
1217 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 1998 of file pgbench.c.

2001{
2002 int i;
2003
2004 for (i = 0; i < command->argc - 1; i++)
2005 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 1128 of file pgbench.c.

1130{
1131 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 4572 of file pgbench.c.

4574{
4575 if (skipped)
4576 return "skipped";
4577 else if (failures_detailed)
4578 {
4579 switch (estatus)
4580 {
4582 return "serialization";
4584 return "deadlock";
4585 default:
4586 /* internal error which should never occur */
4587 pg_fatal("unexpected error status: %d", estatus);
4588 }
4589 }
4590 else
4591 return "failed";

References ESTATUS_DEADLOCK_ERROR, ESTATUS_SERIALIZATION_ERROR, failures_detailed, and pg_fatal.

Referenced by doLog().

◆ getSQLErrorStatus()

static EStatus getSQLErrorStatus ( const char *  sqlState)
static

Definition at line 3236 of file pgbench.c.

3238{
3239 if (sqlState != NULL)
3240 {
3241 if (strcmp(sqlState, ERRCODE_T_R_SERIALIZATION_FAILURE) == 0)
3243 else if (strcmp(sqlState, ERRCODE_T_R_DEADLOCK_DETECTED) == 0)
3245 }
3246
#define ERRCODE_T_R_DEADLOCK_DETECTED
Definition: pgbench.c:78
#define ERRCODE_T_R_SERIALIZATION_FAILURE
Definition: pgbench.c:77

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

Referenced by readCommandResponse().

◆ GetTableInfo()

static void GetTableInfo ( PGconn con,
bool  scale_given 
)
static

Definition at line 5381 of file pgbench.c.

5383{
5384 PGresult *res;
5385
5386 /*
5387 * get the scaling factor that should be same as count(*) from
5388 * pgbench_branches if this is not a custom query
5389 */
5390 res = PQexec(con, "select count(*) from pgbench_branches");
5391 if (PQresultStatus(res) != PGRES_TUPLES_OK)
5392 {
5393 char *sqlState = PQresultErrorField(res, PG_DIAG_SQLSTATE);
5394
5395 pg_log_error("could not count number of branches: %s", PQerrorMessage(con));
5396
5397 if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) == 0)
5398 pg_log_error_hint("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".",
5399 PQdb(con));
5400
5401 exit(1);
5402 }
5403 scale = atoi(PQgetvalue(res, 0, 0));
5404 if (scale < 0)
5405 pg_fatal("invalid count(*) from pgbench_branches: \"%s\"",
5406 PQgetvalue(res, 0, 0));
5407 PQclear(res);
5408
5409 /* warn if we override user-given -s switch */
5410 if (scale_given)
5411 pg_log_warning("scale option ignored, using count from pgbench_branches table (%d)",
5412 scale);
5413
5414 /*
5415 * Get the partition information for the first "pgbench_accounts" table
5416 * found in search_path.
5417 *
5418 * The result is empty if no "pgbench_accounts" is found.
5419 *
5420 * Otherwise, it always returns one row even if the table is not
5421 * partitioned (in which case the partition strategy is NULL).
5422 *
5423 * The number of partitions can be 0 even for partitioned tables, if no
5424 * partition is attached.
5425 *
5426 * We assume no partitioning on any failure, so as to avoid failing on an
5427 * old version without "pg_partitioned_table".
5428 */
5429 res = PQexec(con,
5430 "select o.n, p.partstrat, pg_catalog.count(i.inhparent) "
5431 "from pg_catalog.pg_class as c "
5432 "join pg_catalog.pg_namespace as n on (n.oid = c.relnamespace) "
5433 "cross join lateral (select pg_catalog.array_position(pg_catalog.current_schemas(true), n.nspname)) as o(n) "
5434 "left join pg_catalog.pg_partitioned_table as p on (p.partrelid = c.oid) "
5435 "left join pg_catalog.pg_inherits as i on (c.oid = i.inhparent) "
5436 "where c.relname = 'pgbench_accounts' and o.n is not null "
5437 "group by 1, 2 "
5438 "order by 1 asc "
5439 "limit 1");
5440
5441 if (PQresultStatus(res) != PGRES_TUPLES_OK)
5442 {
5443 /* probably an older version, coldly assume no partitioning */
5445 partitions = 0;
5446 }
5447 else if (PQntuples(res) == 0)
5448 {
5449 /*
5450 * This case is unlikely as pgbench already found "pgbench_branches"
5451 * above to compute the scale.
5452 */
5453 pg_log_error("no pgbench_accounts table found in \"search_path\"");
5454 pg_log_error_hint("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".", PQdb(con));
5455 exit(1);
5456 }
5457 else /* PQntuples(res) == 1 */
5458 {
5459 /* normal case, extract partition information */
5460 if (PQgetisnull(res, 0, 1))
5462 else
5463 {
5464 char *ps = PQgetvalue(res, 0, 1);
5465
5466 /* column must be there */
5467 Assert(ps != NULL);
5468
5469 if (strcmp(ps, "r") == 0)
5471 else if (strcmp(ps, "h") == 0)
5473 else
5474 {
5475 /* possibly a newer version with new partition method */
5476 pg_fatal("unexpected partition method: \"%s\"", ps);
5477 }
5478 }
5479
5480 partitions = atoi(PQgetvalue(res, 0, 2));
5481 }
5482
5483 PQclear(res);
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:7513
#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 3569 of file pgbench.c.

3571{
3572 PGTransactionStatusType tx_status;
3573
3574 tx_status = PQtransactionStatus(con);
3575 switch (tx_status)
3576 {
3577 case PQTRANS_IDLE:
3578 return TSTATUS_IDLE;
3579 case PQTRANS_INTRANS:
3580 case PQTRANS_INERROR:
3581 return TSTATUS_IN_BLOCK;
3582 case PQTRANS_UNKNOWN:
3583 /* PQTRANS_UNKNOWN is expected given a broken connection */
3584 if (PQstatus(con) == CONNECTION_BAD)
3585 return TSTATUS_CONN_ERROR;
3586 /* fall through */
3587 case PQTRANS_ACTIVE:
3588 default:
3589
3590 /*
3591 * We cannot find out whether we are in a transaction block or
3592 * not. Internal error which should never occur.
3593 */
3594 pg_log_error("unexpected transaction status %d", tx_status);
3595 return TSTATUS_OTHER_ERROR;
3596 }
3597
3598 /* not reached */
3599 Assert(false);
3600 return TSTATUS_OTHER_ERROR;
PGTransactionStatusType PQtransactionStatus(const PGconn *conn)
Definition: fe-connect.c:7624
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 1657 of file pgbench.c.

1659{
1660 Variable *var;
1661 char stringform[64];
1662
1663 var = lookupVariable(variables, name);
1664 if (var == NULL)
1665 return NULL; /* not found */
1666
1667 if (var->svalue)
1668 return var->svalue; /* we have it in string form */
1669
1670 /* We need to produce a string equivalent of the value */
1671 Assert(var->value.type != PGBT_NO_VALUE);
1672 if (var->value.type == PGBT_NULL)
1673 snprintf(stringform, sizeof(stringform), "NULL");
1674 else if (var->value.type == PGBT_BOOLEAN)
1675 snprintf(stringform, sizeof(stringform),
1676 "%s", var->value.u.bval ? "true" : "false");
1677 else if (var->value.type == PGBT_INT)
1678 snprintf(stringform, sizeof(stringform),
1679 INT64_FORMAT, var->value.u.ival);
1680 else if (var->value.type == PGBT_DOUBLE)
1681 snprintf(stringform, sizeof(stringform),
1682 "%.*g", DBL_DIG, var->value.u.dval);
1683 else /* internal error, unexpected type */
1684 Assert(0);
1685 var->svalue = pg_strdup(stringform);
1686 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 1257 of file pgbench.c.

1259{
1260 int64 n = max - min + 1;
1261
1262 /* abort if parameter is invalid */
1264
1265 return min - 1 + computeIterativeZipfian(state, n, s);
static int64 computeIterativeZipfian(pg_prng_state *state, int64 n, double s)
Definition: pgbench.c:1227

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

7801{
7802 timer_exceeded = true;

References timer_exceeded.

Referenced by setalarm().

◆ initAccount()

static void initAccount ( PQExpBufferData sql,
int64  curr 
)
static

Definition at line 4988 of file pgbench.c.

4990{
4991 /* "filler" column defaults to blank padded empty string */
4993 INT64_FORMAT "\t" INT64_FORMAT "\t0\t\n",
4994 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 4970 of file pgbench.c.

4972{
4973 /* "filler" column uses NULL */
4975 INT64_FORMAT "\t0\t\\N\n",
4976 curr + 1);

References INT64_FORMAT, and printfPQExpBuffer().

Referenced by initGenerateDataClientSide().

◆ initCreateFKeys()

static void initCreateFKeys ( PGconn con)
static

Definition at line 5250 of file pgbench.c.

5252{
5253 static const char *const DDLKEYs[] = {
5254 "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
5255 "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
5256 "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
5257 "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
5258 "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
5259 };
5260 int i;
5261
5262 fprintf(stderr, "creating foreign keys...\n");
5263 for (i = 0; i < lengthof(DDLKEYs); i++)
5264 {
5265 executeStatement(con, DDLKEYs[i]);
5266 }

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

Referenced by runInitSteps().

◆ initCreatePKeys()

static void initCreatePKeys ( PGconn con)
static

Definition at line 5212 of file pgbench.c.

5214{
5215 static const char *const DDLINDEXes[] = {
5216 "alter table pgbench_branches add primary key (bid)",
5217 "alter table pgbench_tellers add primary key (tid)",
5218 "alter table pgbench_accounts add primary key (aid)"
5219 };
5220 int i;
5221 PQExpBufferData query;
5222
5223 fprintf(stderr, "creating primary keys...\n");
5224 initPQExpBuffer(&query);
5225
5226 for (i = 0; i < lengthof(DDLINDEXes); i++)
5227 {
5228 resetPQExpBuffer(&query);
5229 appendPQExpBufferStr(&query, DDLINDEXes[i]);
5230
5231 if (index_tablespace != NULL)
5232 {
5233 char *escape_tablespace;
5234
5235 escape_tablespace = PQescapeIdentifier(con, index_tablespace,
5236 strlen(index_tablespace));
5237 appendPQExpBuffer(&query, " using index tablespace %s", escape_tablespace);
5238 PQfreemem(escape_tablespace);
5239 }
5240
5241 executeStatement(con, query.data);
5242 }
5243
5244 termPQExpBuffer(&query);
void PQfreemem(void *ptr)
Definition: fe-exec.c:4043
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:4382
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 4865 of file pgbench.c.

4867{
4868 /*
4869 * Note: TPC-B requires at least 100 bytes per row, and the "filler"
4870 * fields in these table declarations were intended to comply with that.
4871 * The pgbench_accounts table complies with that because the "filler"
4872 * column is set to blank-padded empty string. But for all other tables
4873 * the columns default to NULL and so don't actually take any space. We
4874 * could fix that by giving them non-null default values. However, that
4875 * would completely break comparability of pgbench results with prior
4876 * versions. Since pgbench has never pretended to be fully TPC-B compliant
4877 * anyway, we stick with the historical behavior.
4878 */
4879 struct ddlinfo
4880 {
4881 const char *table; /* table name */
4882 const char *smcols; /* column decls if accountIDs are 32 bits */
4883 const char *bigcols; /* column decls if accountIDs are 64 bits */
4884 int declare_fillfactor;
4885 };
4886 static const struct ddlinfo DDLs[] = {
4887 {
4888 "pgbench_history",
4889 "tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)",
4890 "tid int,bid int,aid bigint,delta int,mtime timestamp,filler char(22)",
4891 0
4892 },
4893 {
4894 "pgbench_tellers",
4895 "tid int not null,bid int,tbalance int,filler char(84)",
4896 "tid int not null,bid int,tbalance int,filler char(84)",
4897 1
4898 },
4899 {
4900 "pgbench_accounts",
4901 "aid int not null,bid int,abalance int,filler char(84)",
4902 "aid bigint not null,bid int,abalance int,filler char(84)",
4903 1
4904 },
4905 {
4906 "pgbench_branches",
4907 "bid int not null,bbalance int,filler char(88)",
4908 "bid int not null,bbalance int,filler char(88)",
4909 1
4910 }
4911 };
4912 int i;
4913 PQExpBufferData query;
4914
4915 fprintf(stderr, "creating tables...\n");
4916
4917 initPQExpBuffer(&query);
4918
4919 for (i = 0; i < lengthof(DDLs); i++)
4920 {
4921 const struct ddlinfo *ddl = &DDLs[i];
4922
4923 /* Construct new create table statement. */
4924 printfPQExpBuffer(&query, "create%s table %s(%s)",
4925 (unlogged_tables && partition_method == PART_NONE) ? " unlogged" : "",
4926 ddl->table,
4927 (scale >= SCALE_32BIT_THRESHOLD) ? ddl->bigcols : ddl->smcols);
4928
4929 /* Partition pgbench_accounts table */
4930 if (partition_method != PART_NONE && strcmp(ddl->table, "pgbench_accounts") == 0)
4931 appendPQExpBuffer(&query,
4932 " partition by %s (aid)", PARTITION_METHOD[partition_method]);
4933 else if (ddl->declare_fillfactor)
4934 {
4935 /* fillfactor is only expected on actual tables */
4936 appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4937 }
4938
4939 if (tablespace != NULL)
4940 {
4941 char *escape_tablespace;
4942
4943 escape_tablespace = PQescapeIdentifier(con, tablespace, strlen(tablespace));
4944 appendPQExpBuffer(&query, " tablespace %s", escape_tablespace);
4945 PQfreemem(escape_tablespace);
4946 }
4947
4948 executeStatement(con, query.data);
4949 }
4950
4951 termPQExpBuffer(&query);
4952
4954 createPartitions(con);
static void createPartitions(PGconn *con)
Definition: pgbench.c:4796
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 4774 of file pgbench.c.

4776{
4777 fprintf(stderr, "dropping old tables...\n");
4778
4779 /*
4780 * We drop all the tables in one command, so that whether there are
4781 * foreign key dependencies or not doesn't matter.
4782 */
4783 executeStatement(con, "drop table if exists "
4784 "pgbench_accounts, "
4785 "pgbench_branches, "
4786 "pgbench_history, "
4787 "pgbench_tellers");

References executeStatement(), and fprintf.

Referenced by runInitSteps().

◆ initGenerateDataClientSide()

static void initGenerateDataClientSide ( PGconn con)
static

Definition at line 5122 of file pgbench.c.

5124{
5125 fprintf(stderr, "generating data (client-side)...\n");
5126
5127 /*
5128 * we do all of this in one transaction to enable the backend's
5129 * data-loading optimizations
5130 */
5131 executeStatement(con, "begin");
5132
5133 /* truncate away any old data */
5134 initTruncateTables(con);
5135
5136 /*
5137 * fill branches, tellers, accounts in that order in case foreign keys
5138 * already exist
5139 */
5140 initPopulateTable(con, "pgbench_branches", nbranches, initBranch);
5141 initPopulateTable(con, "pgbench_tellers", ntellers, initTeller);
5142 initPopulateTable(con, "pgbench_accounts", naccounts, initAccount);
5143
5144 executeStatement(con, "commit");
static void initTeller(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:4979
static void initBranch(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:4970
#define ntellers
Definition: pgbench.c:245
static void initTruncateTables(PGconn *con)
Definition: pgbench.c:4960
static void initAccount(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:4988
#define nbranches
Definition: pgbench.c:244
static void initPopulateTable(PGconn *con, const char *table, int64 base, initRowMethod init_row)
Definition: pgbench.c:4997

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

5156{
5157 PQExpBufferData sql;
5158
5159 fprintf(stderr, "generating data (server-side)...\n");
5160
5161 /*
5162 * we do all of this in one transaction to enable the backend's
5163 * data-loading optimizations
5164 */
5165 executeStatement(con, "begin");
5166
5167 /* truncate away any old data */
5168 initTruncateTables(con);
5169
5170 initPQExpBuffer(&sql);
5171
5172 printfPQExpBuffer(&sql,
5173 "insert into pgbench_branches(bid,bbalance) "
5174 "select bid, 0 "
5175 "from generate_series(1, %d) as bid", nbranches * scale);
5176 executeStatement(con, sql.data);
5177
5178 printfPQExpBuffer(&sql,
5179 "insert into pgbench_tellers(tid,bid,tbalance) "
5180 "select tid, (tid - 1) / %d + 1, 0 "
5181 "from generate_series(1, %d) as tid", ntellers, ntellers * scale);
5182 executeStatement(con, sql.data);
5183
5184 printfPQExpBuffer(&sql,
5185 "insert into pgbench_accounts(aid,bid,abalance,filler) "
5186 "select aid, (aid - 1) / %d + 1, 0, '' "
5187 "from generate_series(1, " INT64_FORMAT ") as aid",
5189 executeStatement(con, sql.data);
5190
5191 termPQExpBuffer(&sql);
5192
5193 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 4997 of file pgbench.c.

5000{
5001 int n;
5002 int64 k;
5003 int chars = 0;
5004 int prev_chars = 0;
5005 PGresult *res;
5006 PQExpBufferData sql;
5007 char copy_statement[256];
5008 const char *copy_statement_fmt = "copy %s from stdin";
5009 int64 total = base * scale;
5010
5011 /* used to track elapsed time and estimate of the remaining time */
5013 int log_interval = 1;
5014
5015 /* Stay on the same line if reporting to a terminal */
5016 char eol = isatty(fileno(stderr)) ? '\r' : '\n';
5017
5018 initPQExpBuffer(&sql);
5019
5020 /* Use COPY with FREEZE on v14 and later for all ordinary tables */
5021 if ((PQserverVersion(con) >= 140000) &&
5022 get_table_relkind(con, table) == RELKIND_RELATION)
5023 copy_statement_fmt = "copy %s from stdin with (freeze on)";
5024
5025
5026 n = pg_snprintf(copy_statement, sizeof(copy_statement), copy_statement_fmt, table);
5027 if (n >= sizeof(copy_statement))
5028 pg_fatal("invalid buffer size: must be at least %d characters long", n);
5029 else if (n == -1)
5030 pg_fatal("invalid format string");
5031
5032 res = PQexec(con, copy_statement);
5033
5034 if (PQresultStatus(res) != PGRES_COPY_IN)
5035 pg_fatal("unexpected copy in result: %s", PQerrorMessage(con));
5036 PQclear(res);
5037
5038 start = pg_time_now();
5039
5040 for (k = 0; k < total; k++)
5041 {
5042 int64 j = k + 1;
5043
5044 init_row(&sql, k);
5045 if (PQputline(con, sql.data))
5046 pg_fatal("PQputline failed");
5047
5048 if (CancelRequested)
5049 break;
5050
5051 /*
5052 * If we want to stick with the original logging, print a message each
5053 * 100k inserted rows.
5054 */
5055 if ((!use_quiet) && (j % 100000 == 0))
5056 {
5057 double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
5058 double remaining_sec = ((double) total - j) * elapsed_sec / j;
5059
5060 chars = fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) of %s done (elapsed %.2f s, remaining %.2f s)",
5061 j, total,
5062 (int) ((j * 100) / total),
5063 table, elapsed_sec, remaining_sec);
5064
5065 /*
5066 * If the previous progress message is longer than the current
5067 * one, add spaces to the current line to fully overwrite any
5068 * remaining characters from the previous message.
5069 */
5070 if (prev_chars > chars)
5071 fprintf(stderr, "%*c", prev_chars - chars, ' ');
5072 fputc(eol, stderr);
5073 prev_chars = chars;
5074 }
5075 /* let's not call the timing for each row, but only each 100 rows */
5076 else if (use_quiet && (j % 100 == 0))
5077 {
5078 double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
5079 double remaining_sec = ((double) total - j) * elapsed_sec / j;
5080
5081 /* have we reached the next interval (or end)? */
5082 if ((j == total) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS))
5083 {
5084 chars = fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) of %s done (elapsed %.2f s, remaining %.2f s)",
5085 j, total,
5086 (int) ((j * 100) / total),
5087 table, elapsed_sec, remaining_sec);
5088
5089 /*
5090 * If the previous progress message is longer than the current
5091 * one, add spaces to the current line to fully overwrite any
5092 * remaining characters from the previous message.
5093 */
5094 if (prev_chars > chars)
5095 fprintf(stderr, "%*c", prev_chars - chars, ' ');
5096 fputc(eol, stderr);
5097 prev_chars = chars;
5098
5099 /* skip to the next interval */
5100 log_interval = (int) ceil(elapsed_sec / LOG_STEP_SECONDS);
5101 }
5102 }
5103 }
5104
5105 if (chars != 0 && eol != '\n')
5106 fprintf(stderr, "%*c\r", chars, ' '); /* Clear the current line */
5107
5108 if (PQputline(con, "\\.\n"))
5109 pg_fatal("very last PQputline failed");
5110 if (PQendcopy(con))
5111 pg_fatal("PQendcopy failed");
5112
5113 termPQExpBuffer(&sql);
volatile sig_atomic_t CancelRequested
Definition: cancel.c:59
int PQserverVersion(const PGconn *conn)
Definition: fe-connect.c:7669
int PQendcopy(PGconn *conn)
Definition: fe-exec.c:2960
int PQputline(PGconn *conn, const char *string)
Definition: fe-exec.c:2929
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:852
#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 1114 of file pgbench.c.

1116{
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:478

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

Referenced by main().

◆ initSimpleStats()

static void initSimpleStats ( SimpleStats ss)
static

Definition at line 1420 of file pgbench.c.

1422{
1423 memset(ss, 0, sizeof(SimpleStats));

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

◆ initStats()

static void initStats ( StatsData sd,
pg_time_usec_t  start 
)
static

◆ initTeller()

static void initTeller ( PQExpBufferData sql,
int64  curr 
)
static

Definition at line 4979 of file pgbench.c.

4981{
4982 /* "filler" column uses NULL */
4984 INT64_FORMAT "\t" INT64_FORMAT "\t0\t\\N\n",
4985 curr + 1, curr / ntellers + 1);

References INT64_FORMAT, ntellers, and printfPQExpBuffer().

Referenced by initGenerateDataClientSide().

◆ initTruncateTables()

static void initTruncateTables ( PGconn con)
static

Definition at line 4960 of file pgbench.c.

4962{
4963 executeStatement(con, "truncate table "
4964 "pgbench_accounts, "
4965 "pgbench_branches, "
4966 "pgbench_history, "
4967 "pgbench_tellers");

References executeStatement().

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

◆ initVacuum()

static void initVacuum ( PGconn con)
static

Definition at line 5199 of file pgbench.c.

5201{
5202 fprintf(stderr, "vacuuming...\n");
5203 executeStatement(con, "vacuum analyze pgbench_branches");
5204 executeStatement(con, "vacuum analyze pgbench_tellers");
5205 executeStatement(con, "vacuum analyze pgbench_accounts");
5206 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 977 of file pgbench.c.

979{
980 const char *ptr = str;
981
982 /* skip leading spaces; cast is consistent with strtoint64 */
983 while (*ptr && isspace((unsigned char) *ptr))
984 ptr++;
985
986 /* skip sign */
987 if (*ptr == '+' || *ptr == '-')
988 ptr++;
989
990 /* at least one digit */
991 if (*ptr && !isdigit((unsigned char) *ptr))
992 return false;
993
994 /* eat all digits */
995 while (*ptr && isdigit((unsigned char) *ptr))
996 ptr++;
997
998 /* must have reached end of string */
999 return *ptr == '\0';
const char * str

References str.

Referenced by makeVariableValue().

◆ isLazyFunc()

static bool isLazyFunc ( PgBenchFunction  func)
static

Definition at line 2151 of file pgbench.c.

2153{
2154 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 6176 of file pgbench.c.

6178{
6179 int i;
6180
6181 fprintf(stderr, "Available builtin scripts:\n");
6182 for (i = 0; i < lengthof(builtin_script); i++)
6183 fprintf(stderr, " %13s: %s\n", builtin_script[i].name, builtin_script[i].desc);
6184 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 1818 of file pgbench.c.

1820{
1821 Variable *var;
1822
1823 var = lookupVariable(variables, name);
1824 if (var == NULL)
1825 {
1826 /*
1827 * Check for the name only when declaring a new variable to avoid
1828 * overhead.
1829 */
1831 {
1832 pg_log_error("%s: invalid variable name: \"%s\"", context, name);
1833 return NULL;
1834 }
1835
1836 /* Create variable at the end of the array */
1837 enlargeVariables(variables, 1);
1838
1839 var = &(variables->vars[variables->nvars]);
1840
1841 var->name = pg_strdup(name);
1842 var->svalue = NULL;
1843 /* caller is expected to initialize remaining fields */
1844
1845 variables->nvars++;
1846 /* we don't re-sort the array till we have to */
1847 variables->vars_sorted = false;
1848 }
1849
1850 return var;
static bool valid_variable_name(const char *name)
Definition: pgbench.c:1764
static void enlargeVariables(Variables *variables, int needed)
Definition: pgbench.c:1799
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 1630 of file pgbench.c.

1632{
1633 Variable key;
1634
1635 /* On some versions of Solaris, bsearch of zero items dumps core */
1636 if (variables->nvars <= 0)
1637 return NULL;
1638
1639 /* Sort if we have to */
1640 if (!variables->vars_sorted)
1641 {
1642 qsort(variables->vars, variables->nvars, sizeof(Variable),
1644 variables->vars_sorted = true;
1645 }
1646
1647 /* Now we can search */
1648 key.name = name;
1649 return (Variable *) bsearch(&key,
1650 variables->vars,
1651 variables->nvars,
1652 sizeof(Variable),
static int compareVariableNames(const void *v1, const void *v2)
Definition: pgbench.c:1622
#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 6692 of file pgbench.c.

6694{
6695 static struct option long_options[] = {
6696 /* systematic long/short named options */
6697 {"builtin", required_argument, NULL, 'b'},
6698 {"client", required_argument, NULL, 'c'},
6699 {"connect", no_argument, NULL, 'C'},
6700 {"dbname", required_argument, NULL, 'd'},
6701 {"define", required_argument, NULL, 'D'},
6702 {"file", required_argument, NULL, 'f'},
6703 {"fillfactor", required_argument, NULL, 'F'},
6704 {"host", required_argument, NULL, 'h'},
6705 {"initialize", no_argument, NULL, 'i'},
6706 {"init-steps", required_argument, NULL, 'I'},
6707 {"jobs", required_argument, NULL, 'j'},
6708 {"log", no_argument, NULL, 'l'},
6709 {"latency-limit", required_argument, NULL, 'L'},
6710 {"no-vacuum", no_argument, NULL, 'n'},
6711 {"port", required_argument, NULL, 'p'},
6712 {"progress", required_argument, NULL, 'P'},
6713 {"protocol", required_argument, NULL, 'M'},
6714 {"quiet", no_argument, NULL, 'q'},
6715 {"report-per-command", no_argument, NULL, 'r'},
6716 {"rate", required_argument, NULL, 'R'},
6717 {"scale", required_argument, NULL, 's'},
6718 {"select-only", no_argument, NULL, 'S'},
6719 {"skip-some-updates", no_argument, NULL, 'N'},
6720 {"time", required_argument, NULL, 'T'},
6721 {"transactions", required_argument, NULL, 't'},
6722 {"username", required_argument, NULL, 'U'},
6723 {"vacuum-all", no_argument, NULL, 'v'},
6724 /* long-named only options */
6725 {"unlogged-tables", no_argument, NULL, 1},
6726 {"tablespace", required_argument, NULL, 2},
6727 {"index-tablespace", required_argument, NULL, 3},
6728 {"sampling-rate", required_argument, NULL, 4},
6729 {"aggregate-interval", required_argument, NULL, 5},
6730 {"progress-timestamp", no_argument, NULL, 6},
6731 {"log-prefix", required_argument, NULL, 7},
6732 {"foreign-keys", no_argument, NULL, 8},
6733 {"random-seed", required_argument, NULL, 9},
6734 {"show-script", required_argument, NULL, 10},
6735 {"partitions", required_argument, NULL, 11},
6736 {"partition-method", required_argument, NULL, 12},
6737 {"failures-detailed", no_argument, NULL, 13},
6738 {"max-tries", required_argument, NULL, 14},
6739 {"verbose-errors", no_argument, NULL, 15},
6740 {"exit-on-abort", no_argument, NULL, 16},
6741 {"debug", no_argument, NULL, 17},
6742 {NULL, 0, NULL, 0}
6743 };
6744
6745 int c;
6746 bool is_init_mode = false; /* initialize mode? */
6747 char *initialize_steps = NULL;
6748 bool foreign_keys = false;
6749 bool is_no_vacuum = false;
6750 bool do_vacuum_accounts = false; /* vacuum accounts table? */
6751 int optindex;
6752 bool scale_given = false;
6753
6754 bool benchmarking_option_set = false;
6755 bool initialization_option_set = false;
6756 bool internal_script_used = false;
6757
6758 CState *state; /* status of clients */
6759 TState *threads; /* array of thread */
6760
6762 start_time, /* start up time */
6763 bench_start = 0, /* first recorded benchmarking time */
6764 conn_total_duration; /* cumulated connection time in
6765 * threads */
6766 int64 latency_late = 0;
6767 StatsData stats;
6768 int weight;
6769
6770 int i;
6771 int nclients_dealt;
6772
6773#ifdef HAVE_GETRLIMIT
6774 struct rlimit rlim;
6775#endif
6776
6777 PGconn *con;
6778 char *env;
6779
6780 int exit_code = 0;
6781 struct timeval tv;
6782
6783 /*
6784 * Record difference between Unix time and instr_time time. We'll use
6785 * this for logging and aggregation.
6786 */
6787 gettimeofday(&tv, NULL);
6788 epoch_shift = tv.tv_sec * INT64CONST(1000000) + tv.tv_usec - pg_time_now();
6789
6790 pg_logging_init(argv[0]);
6791 progname = get_progname(argv[0]);
6792
6793 if (argc > 1)
6794 {
6795 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
6796 {
6797 usage();
6798 exit(0);
6799 }
6800 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
6801 {
6802 puts("pgbench (PostgreSQL) " PG_VERSION);
6803 exit(0);
6804 }
6805 }
6806
6807 state = (CState *) pg_malloc0(sizeof(CState));
6808
6809 /* set random seed early, because it may be used while parsing scripts. */
6810 if (!set_random_seed(getenv("PGBENCH_RANDOM_SEED")))
6811 pg_fatal("error while setting random seed from PGBENCH_RANDOM_SEED environment variable");
6812
6813 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)
6814 {
6815 char *script;
6816
6817 switch (c)
6818 {
6819 case 'b':
6820 if (strcmp(optarg, "list") == 0)
6821 {
6823 exit(0);
6824 }
6825 weight = parseScriptWeight(optarg, &script);
6826 process_builtin(findBuiltin(script), weight);
6827 benchmarking_option_set = true;
6828 internal_script_used = true;
6829 break;
6830 case 'c':
6831 benchmarking_option_set = true;
6832 if (!option_parse_int(optarg, "-c/--clients", 1, INT_MAX,
6833 &nclients))
6834 {
6835 exit(1);
6836 }
6837#ifdef HAVE_GETRLIMIT
6838 if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
6839 pg_fatal("getrlimit failed: %m");
6840
6841 if (rlim.rlim_max < nclients + 3)
6842 {
6843 pg_log_error("need at least %d open files, but system limit is %ld",
6844 nclients + 3, (long) rlim.rlim_max);
6845 pg_log_error_hint("Reduce number of clients, or use limit/ulimit to increase the system limit.");
6846 exit(1);
6847 }
6848
6849 if (rlim.rlim_cur < nclients + 3)
6850 {
6851 rlim.rlim_cur = nclients + 3;
6852 if (setrlimit(RLIMIT_NOFILE, &rlim) == -1)
6853 {
6854 pg_log_error("need at least %d open files, but couldn't raise the limit: %m",
6855 nclients + 3);
6856 pg_log_error_hint("Reduce number of clients, or use limit/ulimit to increase the system limit.");
6857 exit(1);
6858 }
6859 }
6860#endif /* HAVE_GETRLIMIT */
6861 break;
6862 case 'C':
6863 benchmarking_option_set = true;
6864 is_connect = true;
6865 break;
6866 case 'd':
6868 break;
6869 case 'D':
6870 {
6871 char *p;
6872
6873 benchmarking_option_set = true;
6874
6875 if ((p = strchr(optarg, '=')) == NULL || p == optarg || *(p + 1) == '\0')
6876 pg_fatal("invalid variable definition: \"%s\"", optarg);
6877
6878 *p++ = '\0';
6879 if (!putVariable(&state[0].variables, "option", optarg, p))
6880 exit(1);
6881 }
6882 break;
6883 case 'f':
6884 weight = parseScriptWeight(optarg, &script);
6885 process_file(script, weight);
6886 benchmarking_option_set = true;
6887 break;
6888 case 'F':
6889 initialization_option_set = true;
6890 if (!option_parse_int(optarg, "-F/--fillfactor", 10, 100,
6891 &fillfactor))
6892 exit(1);
6893 break;
6894 case 'h':
6896 break;
6897 case 'i':
6898 is_init_mode = true;
6899 break;
6900 case 'I':
6901 pg_free(initialize_steps);
6902 initialize_steps = pg_strdup(optarg);
6903 checkInitSteps(initialize_steps);
6904 initialization_option_set = true;
6905 break;
6906 case 'j': /* jobs */
6907 benchmarking_option_set = true;
6908 if (!option_parse_int(optarg, "-j/--jobs", 1, INT_MAX,
6909 &nthreads))
6910 {
6911 exit(1);
6912 }
6913 break;
6914 case 'l':
6915 benchmarking_option_set = true;
6916 use_log = true;
6917 break;
6918 case 'L':
6919 {
6920 double limit_ms = atof(optarg);
6921
6922 if (limit_ms <= 0.0)
6923 pg_fatal("invalid latency limit: \"%s\"", optarg);
6924 benchmarking_option_set = true;
6925 latency_limit = (int64) (limit_ms * 1000);
6926 }
6927 break;
6928 case 'M':
6929 benchmarking_option_set = true;
6931 if (strcmp(optarg, QUERYMODE[querymode]) == 0)
6932 break;
6933 if (querymode >= NUM_QUERYMODE)
6934 pg_fatal("invalid query mode (-M): \"%s\"", optarg);
6935 break;
6936 case 'n':
6937 is_no_vacuum = true;
6938 break;
6939 case 'N':
6940 process_builtin(findBuiltin("simple-update"), 1);
6941 benchmarking_option_set = true;
6942 internal_script_used = true;
6943 break;
6944 case 'p':
6946 break;
6947 case 'P':
6948 benchmarking_option_set = true;
6949 if (!option_parse_int(optarg, "-P/--progress", 1, INT_MAX,
6950 &progress))
6951 exit(1);
6952 break;
6953 case 'q':
6954 initialization_option_set = true;
6955 use_quiet = true;
6956 break;
6957 case 'r':
6958 benchmarking_option_set = true;
6959 report_per_command = true;
6960 break;
6961 case 'R':
6962 {
6963 /* get a double from the beginning of option value */
6964 double throttle_value = atof(optarg);
6965
6966 benchmarking_option_set = true;
6967
6968 if (throttle_value <= 0.0)
6969 pg_fatal("invalid rate limit: \"%s\"", optarg);
6970 /* Invert rate limit into per-transaction delay in usec */
6971 throttle_delay = 1000000.0 / throttle_value;
6972 }
6973 break;
6974 case 's':
6975 scale_given = true;
6976 if (!option_parse_int(optarg, "-s/--scale", 1, INT_MAX,
6977 &scale))
6978 exit(1);
6979 break;
6980 case 'S':
6981 process_builtin(findBuiltin("select-only"), 1);
6982 benchmarking_option_set = true;
6983 internal_script_used = true;
6984 break;
6985 case 't':
6986 benchmarking_option_set = true;
6987 if (!option_parse_int(optarg, "-t/--transactions", 1, INT_MAX,
6988 &nxacts))
6989 exit(1);
6990 break;
6991 case 'T':
6992 benchmarking_option_set = true;
6993 if (!option_parse_int(optarg, "-T/--time", 1, INT_MAX,
6994 &duration))
6995 exit(1);
6996 break;
6997 case 'U':
6999 break;
7000 case 'v':
7001 benchmarking_option_set = true;
7002 do_vacuum_accounts = true;
7003 break;
7004 case 1: /* unlogged-tables */
7005 initialization_option_set = true;
7006 unlogged_tables = true;
7007 break;
7008 case 2: /* tablespace */
7009 initialization_option_set = true;
7011 break;
7012 case 3: /* index-tablespace */
7013 initialization_option_set = true;
7015 break;
7016 case 4: /* sampling-rate */
7017 benchmarking_option_set = true;
7018 sample_rate = atof(optarg);
7019 if (sample_rate <= 0.0 || sample_rate > 1.0)
7020 pg_fatal("invalid sampling rate: \"%s\"", optarg);
7021 break;
7022 case 5: /* aggregate-interval */
7023 benchmarking_option_set = true;
7024 if (!option_parse_int(optarg, "--aggregate-interval", 1, INT_MAX,
7025 &agg_interval))
7026 exit(1);
7027 break;
7028 case 6: /* progress-timestamp */
7029 progress_timestamp = true;
7030 benchmarking_option_set = true;
7031 break;
7032 case 7: /* log-prefix */
7033 benchmarking_option_set = true;
7035 break;
7036 case 8: /* foreign-keys */
7037 initialization_option_set = true;
7038 foreign_keys = true;
7039 break;
7040 case 9: /* random-seed */
7041 benchmarking_option_set = true;
7042 if (!set_random_seed(optarg))
7043 pg_fatal("error while setting random seed from --random-seed option");
7044 break;
7045 case 10: /* list */
7046 {
7047 const BuiltinScript *s = findBuiltin(optarg);
7048
7049 fprintf(stderr, "-- %s: %s\n%s\n", s->name, s->desc, s->script);
7050 exit(0);
7051 }
7052 break;
7053 case 11: /* partitions */
7054 initialization_option_set = true;
7055 if (!option_parse_int(optarg, "--partitions", 0, INT_MAX,
7056 &partitions))
7057 exit(1);
7058 break;
7059 case 12: /* partition-method */
7060 initialization_option_set = true;
7061 if (pg_strcasecmp(optarg, "range") == 0)
7063 else if (pg_strcasecmp(optarg, "hash") == 0)
7065 else
7066 pg_fatal("invalid partition method, expecting \"range\" or \"hash\", got: \"%s\"",
7067 optarg);
7068 break;
7069 case 13: /* failures-detailed */
7070 benchmarking_option_set = true;
7071 failures_detailed = true;
7072 break;
7073 case 14: /* max-tries */
7074 {
7075 int32 max_tries_arg = atoi(optarg);
7076
7077 if (max_tries_arg < 0)
7078 pg_fatal("invalid number of maximum tries: \"%s\"", optarg);
7079
7080 benchmarking_option_set = true;
7081 max_tries = (uint32) max_tries_arg;
7082 }
7083 break;
7084 case 15: /* verbose-errors */
7085 benchmarking_option_set = true;
7086 verbose_errors = true;
7087 break;
7088 case 16: /* exit-on-abort */
7089 benchmarking_option_set = true;
7090 exit_on_abort = true;
7091 break;
7092 case 17: /* debug */
7094 break;
7095 default:
7096 /* getopt_long already emitted a complaint */
7097 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
7098 exit(1);
7099 }
7100 }
7101
7102 /* set default script if none */
7103 if (num_scripts == 0 && !is_init_mode)
7104 {
7105 process_builtin(findBuiltin("tpcb-like"), 1);
7106 benchmarking_option_set = true;
7107 internal_script_used = true;
7108 }
7109
7110 /* complete SQL command initialization and compute total weight */
7111 for (i = 0; i < num_scripts; i++)
7112 {
7113 Command **commands = sql_script[i].commands;
7114
7115 for (int j = 0; commands[j] != NULL; j++)
7116 if (commands[j]->type == SQL_COMMAND)
7117 postprocess_sql_command(commands[j]);
7118
7119 /* cannot overflow: weight is 32b, total_weight 64b */
7121 }
7122
7123 if (total_weight == 0 && !is_init_mode)
7124 pg_fatal("total script weight must not be zero");
7125
7126 /* show per script stats if several scripts are used */
7127 if (num_scripts > 1)
7128 per_script_stats = true;
7129
7130 /*
7131 * Don't need more threads than there are clients. (This is not merely an
7132 * optimization; throttle_delay is calculated incorrectly below if some
7133 * threads have no clients assigned to them.)
7134 */
7135 if (nthreads > nclients)
7137
7138 /*
7139 * Convert throttle_delay to a per-thread delay time. Note that this
7140 * might be a fractional number of usec, but that's OK, since it's just
7141 * the center of a Poisson distribution of delays.
7142 */
7144
7145 if (dbName == NULL)
7146 {
7147 if (argc > optind)
7148 dbName = argv[optind++];
7149 else
7150 {
7151 if ((env = getenv("PGDATABASE")) != NULL && *env != '\0')
7152 dbName = env;
7153 else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
7154 dbName = env;
7155 else
7157 }
7158 }
7159
7160 if (optind < argc)
7161 {
7162 pg_log_error("too many command-line arguments (first is \"%s\")",
7163 argv[optind]);
7164 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
7165 exit(1);
7166 }
7167
7168 if (is_init_mode)
7169 {
7170 if (benchmarking_option_set)
7171 pg_fatal("some of the specified options cannot be used in initialization (-i) mode");
7172
7173 if (partitions == 0 && partition_method != PART_NONE)
7174 pg_fatal("--partition-method requires greater than zero --partitions");
7175
7176 /* set default method */
7179
7180 if (initialize_steps == NULL)
7181 initialize_steps = pg_strdup(DEFAULT_INIT_STEPS);
7182
7183 if (is_no_vacuum)
7184 {
7185 /* Remove any vacuum step in initialize_steps */
7186 char *p;
7187
7188 while ((p = strchr(initialize_steps, 'v')) != NULL)
7189 *p = ' ';
7190 }
7191
7192 if (foreign_keys)
7193 {
7194 /* Add 'f' to end of initialize_steps, if not already there */
7195 if (strchr(initialize_steps, 'f') == NULL)
7196 {
7197 initialize_steps = (char *)
7198 pg_realloc(initialize_steps,
7199 strlen(initialize_steps) + 2);
7200 strcat(initialize_steps, "f");
7201 }
7202 }
7203
7204 runInitSteps(initialize_steps);
7205 exit(0);
7206 }
7207 else
7208 {
7209 if (initialization_option_set)
7210 pg_fatal("some of the specified options cannot be used in benchmarking mode");
7211 }
7212
7213 if (nxacts > 0 && duration > 0)
7214 pg_fatal("specify either a number of transactions (-t) or a duration (-T), not both");
7215
7216 /* Use DEFAULT_NXACTS if neither nxacts nor duration is specified. */
7217 if (nxacts <= 0 && duration <= 0)
7219
7220 /* --sampling-rate may be used only with -l */
7221 if (sample_rate > 0.0 && !use_log)
7222 pg_fatal("log sampling (--sampling-rate) is allowed only when logging transactions (-l)");
7223
7224 /* --sampling-rate may not be used with --aggregate-interval */
7225 if (sample_rate > 0.0 && agg_interval > 0)
7226 pg_fatal("log sampling (--sampling-rate) and aggregation (--aggregate-interval) cannot be used at the same time");
7227
7228 if (agg_interval > 0 && !use_log)
7229 pg_fatal("log aggregation is allowed only when actually logging transactions");
7230
7231 if (!use_log && logfile_prefix)
7232 pg_fatal("log file prefix (--log-prefix) is allowed only when logging transactions (-l)");
7233
7234 if (duration > 0 && agg_interval > duration)
7235 pg_fatal("number of seconds for aggregation (%d) must not be higher than test duration (%d)", agg_interval, duration);
7236
7237 if (duration > 0 && agg_interval > 0 && duration % agg_interval != 0)
7238 pg_fatal("duration (%d) must be a multiple of aggregation interval (%d)", duration, agg_interval);
7239
7240 if (progress_timestamp && progress == 0)
7241 pg_fatal("--progress-timestamp is allowed only under --progress");
7242
7243 if (!max_tries)
7244 {
7245 if (!latency_limit && duration <= 0)
7246 pg_fatal("an unlimited number of transaction tries can only be used with --latency-limit or a duration (-T)");
7247 }
7248
7249 /*
7250 * save main process id in the global variable because process id will be
7251 * changed after fork.
7252 */
7253 main_pid = (int) getpid();
7254
7255 if (nclients > 1)
7256 {
7257 state = (CState *) pg_realloc(state, sizeof(CState) * nclients);
7258 memset(state + 1, 0, sizeof(CState) * (nclients - 1));
7259
7260 /* copy any -D switch values to all clients */
7261 for (i = 1; i < nclients; i++)
7262 {
7263 int j;
7264
7265 state[i].id = i;
7266 for (j = 0; j < state[0].variables.nvars; j++)
7267 {
7268 Variable *var = &state[0].variables.vars[j];
7269
7270 if (var->value.type != PGBT_NO_VALUE)
7271 {
7272 if (!putVariableValue(&state[i].variables, "startup",
7273 var->name, &var->value))
7274 exit(1);
7275 }
7276 else
7277 {
7278 if (!putVariable(&state[i].variables, "startup",
7279 var->name, var->svalue))
7280 exit(1);
7281 }
7282 }
7283 }
7284 }
7285
7286 /* other CState initializations */
7287 for (i = 0; i < nclients; i++)
7288 {
7289 state[i].cstack = conditional_stack_create();
7290 initRandomState(&state[i].cs_func_rs);
7291 }
7292
7293 /* opening connection... */
7294 con = doConnect();
7295 if (con == NULL)
7296 pg_fatal("could not create connection for setup");
7297
7298 /* report pgbench and server versions */
7299 printVersion(con);
7300
7301 pg_log_debug("pghost: %s pgport: %s nclients: %d %s: %d dbName: %s",
7302 PQhost(con), PQport(con), nclients,
7303 duration <= 0 ? "nxacts" : "duration",
7304 duration <= 0 ? nxacts : duration, PQdb(con));
7305
7306 if (internal_script_used)
7307 GetTableInfo(con, scale_given);
7308
7309 /*
7310 * :scale variables normally get -s or database scale, but don't override
7311 * an explicit -D switch
7312 */
7313 if (lookupVariable(&state[0].variables, "scale") == NULL)
7314 {
7315 for (i = 0; i < nclients; i++)
7316 {
7317 if (!putVariableInt(&state[i].variables, "startup", "scale", scale))
7318 exit(1);
7319 }
7320 }
7321
7322 /*
7323 * Define a :client_id variable that is unique per connection. But don't
7324 * override an explicit -D switch.
7325 */
7326 if (lookupVariable(&state[0].variables, "client_id") == NULL)
7327 {
7328 for (i = 0; i < nclients; i++)
7329 if (!putVariableInt(&state[i].variables, "startup", "client_id", i))
7330 exit(1);
7331 }
7332
7333 /* set default seed for hash functions */
7334 if (lookupVariable(&state[0].variables, "default_seed") == NULL)
7335 {
7337
7338 for (i = 0; i < nclients; i++)
7339 if (!putVariableInt(&state[i].variables, "startup", "default_seed",
7340 (int64) seed))
7341 exit(1);
7342 }
7343
7344 /* set random seed unless overwritten */
7345 if (lookupVariable(&state[0].variables, "random_seed") == NULL)
7346 {
7347 for (i = 0; i < nclients; i++)
7348 if (!putVariableInt(&state[i].variables, "startup", "random_seed",
7349 random_seed))
7350 exit(1);
7351 }
7352
7353 if (!is_no_vacuum)
7354 {
7355 fprintf(stderr, "starting vacuum...");
7356 tryExecuteStatement(con, "vacuum pgbench_branches");
7357 tryExecuteStatement(con, "vacuum pgbench_tellers");
7358 tryExecuteStatement(con, "truncate pgbench_history");
7359 fprintf(stderr, "end.\n");
7360
7361 if (do_vacuum_accounts)
7362 {
7363 fprintf(stderr, "starting vacuum pgbench_accounts...");
7364 tryExecuteStatement(con, "vacuum analyze pgbench_accounts");
7365 fprintf(stderr, "end.\n");
7366 }
7367 }
7368 PQfinish(con);
7369
7370 /* set up thread data structures */
7371 threads = (TState *) pg_malloc(sizeof(TState) * nthreads);
7372 nclients_dealt = 0;
7373
7374 for (i = 0; i < nthreads; i++)
7375 {
7376 TState *thread = &threads[i];
7377
7378 thread->tid = i;
7379 thread->state = &state[nclients_dealt];
7380 thread->nstate =
7381 (nclients - nclients_dealt + nthreads - i - 1) / (nthreads - i);
7382 initRandomState(&thread->ts_choose_rs);
7384 initRandomState(&thread->ts_sample_rs);
7385 thread->logfile = NULL; /* filled in later */
7386 thread->latency_late = 0;
7387 initStats(&thread->stats, 0);
7388
7389 nclients_dealt += thread->nstate;
7390 }
7391
7392 /* all clients must be assigned to a thread */
7393 Assert(nclients_dealt == nclients);
7394
7395 /* get start up time for the whole computation */
7397
7398 /* set alarm if duration is specified. */
7399 if (duration > 0)
7401
7403 if (errno != 0)
7404 pg_fatal("could not initialize barrier: %m");
7405
7406 /* start all threads but thread 0 which is executed directly later */
7407 for (i = 1; i < nthreads; i++)
7408 {
7409 TState *thread = &threads[i];
7410
7411 thread->create_time = pg_time_now();
7412 errno = THREAD_CREATE(&thread->thread, threadRun, thread);
7413
7414 if (errno != 0)
7415 pg_fatal("could not create thread: %m");
7416 }
7417
7418 /* compute when to stop */
7419 threads[0].create_time = pg_time_now();
7420 if (duration > 0)
7421 end_time = threads[0].create_time + (int64) 1000000 * duration;
7422
7423 /* run thread 0 directly */
7424 (void) threadRun(&threads[0]);
7425
7426 /* wait for other threads and accumulate results */
7427 initStats(&stats, 0);
7428 conn_total_duration = 0;
7429
7430 for (i = 0; i < nthreads; i++)
7431 {
7432 TState *thread = &threads[i];
7433
7434 if (i > 0)
7435 THREAD_JOIN(thread->thread);
7436
7437 for (int j = 0; j < thread->nstate; j++)
7438 if (thread->state[j].state != CSTATE_FINISHED)
7439 exit_code = 2;
7440
7441 /* aggregate thread level stats */
7442 mergeSimpleStats(&stats.latency, &thread->stats.latency);
7443 mergeSimpleStats(&stats.lag, &thread->stats.lag);
7444 stats.cnt += thread->stats.cnt;
7445 stats.skipped += thread->stats.skipped;
7446 stats.retries += thread->stats.retries;
7447 stats.retried += thread->stats.retried;
7449 stats.deadlock_failures += thread->stats.deadlock_failures;
7450 latency_late += thread->latency_late;
7451 conn_total_duration += thread->conn_duration;
7452
7453 /* first recorded benchmarking start time */
7454 if (bench_start == 0 || thread->bench_start < bench_start)
7455 bench_start = thread->bench_start;
7456 }
7457
7458 /*
7459 * All connections should be already closed in threadRun(), so this
7460 * disconnect_all() will be a no-op, but clean up the connections just to
7461 * be sure. We don't need to measure the disconnection delays here.
7462 */
7464
7465 /*
7466 * Beware that performance of short benchmarks with many threads and
7467 * possibly long transactions can be deceptive because threads do not
7468 * start and finish at the exact same time. The total duration computed
7469 * here encompasses all transactions so that tps shown is somehow slightly
7470 * underestimated.
7471 */
7472 printResults(&stats, pg_time_now() - bench_start, conn_total_duration,
7473 bench_start - start_time, latency_late);
7474
7476
7477 if (exit_code != 0)
7478 pg_log_error("Run was aborted; the above results are incomplete.");
7479
7480 return exit_code;
uint32_t uint32
Definition: c.h:538
char * PQport(const PGconn *conn)
Definition: fe-connect.c:7582
char * PQhost(const PGconn *conn)
Definition: fe-connect.c:7546
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:95
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:6421
static bool putVariableInt(Variables *variables, const char *context, char *name, int64 value)
Definition: pgbench.c:1897
static void GetTableInfo(PGconn *con, bool scale_given)
Definition: pgbench.c:5381
static void initRandomState(pg_prng_state *state)
Definition: pgbench.c:1114
static bool per_script_stats
Definition: pgbench.c:261
static THREAD_FUNC_RETURN_TYPE THREAD_FUNC_CC threadRun(void *arg)
Definition: pgbench.c:7483
static void setalarm(int seconds)
Definition: pgbench.c:7805
static int nthreads
Definition: pgbench.c:265
static bool exit_on_abort
Definition: pgbench.c:771
static bool putVariable(Variables *variables, const char *context, char *name, const char *value)
Definition: pgbench.c:1855
static int nclients
Definition: pgbench.c:264
static void printVersion(PGconn *con)
Definition: pgbench.c:6390
#define DEFAULT_NXACTS
Definition: pgbench.c:167
static void checkInitSteps(const char *initialize_steps)
Definition: pgbench.c:5276
static int progress
Definition: pgbench.c:262
static void postprocess_sql_command(Command *my_command)
Definition: pgbench.c:5671
static bool progress_timestamp
Definition: pgbench.c:263
static const char *const QUERYMODE[]
Definition: pgbench.c:715
static const BuiltinScript * findBuiltin(const char *name)
Definition: pgbench.c:6188
static void mergeSimpleStats(SimpleStats *acc, SimpleStats *ss)
Definition: pgbench.c:1444
#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:6650
static void runInitSteps(const char *initialize_steps)
Definition: pgbench.c:5296
static void process_builtin(const BuiltinScript *bi, int weight)
Definition: pgbench.c:6169
static int parseScriptWeight(const char *option, char **script)
Definition: pgbench.c:6224
static void tryExecuteStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1542
static THREAD_BARRIER_T barrier
Definition: pgbench.c:481
static void process_file(const char *filename, int weight)
Definition: pgbench.c:6143
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:896
static void disconnect_all(CState *state, int length)
Definition: pgbench.c:4762
#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:777
const char * name
Definition: pgbench.c:776
const char * script
Definition: pgbench.c:778
pg_time_usec_t create_time
Definition: pgbench.c:666
CState * state
Definition: pgbench.c:650
int tid
Definition: pgbench.c:648
int nstate
Definition: pgbench.c:651
StatsData stats
Definition: pgbench.c:672
THREAD_T thread
Definition: pgbench.c:649
pg_time_usec_t bench_start
Definition: pgbench.c:668
int64 latency_late
Definition: pgbench.c:673
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, 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(), 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 1690 of file pgbench.c.

1692{
1693 size_t slen;
1694
1695 if (var->value.type != PGBT_NO_VALUE)
1696 return true; /* no work */
1697
1698 slen = strlen(var->svalue);
1699
1700 if (slen == 0)
1701 /* what should it do on ""? */
1702 return false;
1703
1704 if (pg_strcasecmp(var->svalue, "null") == 0)
1705 {
1706 setNullValue(&var->value);
1707 }
1708
1709 /*
1710 * accept prefixes such as y, ye, n, no... but not for "o". 0/1 are
1711 * recognized later as an int, which is converted to bool if needed.
1712 */
1713 else if (pg_strncasecmp(var->svalue, "true", slen) == 0 ||
1714 pg_strncasecmp(var->svalue, "yes", slen) == 0 ||
1715 pg_strcasecmp(var->svalue, "on") == 0)
1716 {
1717 setBoolValue(&var->value, true);
1718 }
1719 else if (pg_strncasecmp(var->svalue, "false", slen) == 0 ||
1720 pg_strncasecmp(var->svalue, "no", slen) == 0 ||
1721 pg_strcasecmp(var->svalue, "off") == 0 ||
1722 pg_strcasecmp(var->svalue, "of") == 0)
1723 {
1724 setBoolValue(&var->value, false);
1725 }
1726 else if (is_an_int(var->svalue))
1727 {
1728 /* if it looks like an int, it must be an int without overflow */
1729 int64 iv;
1730
1731 if (!strtoint64(var->svalue, false, &iv))
1732 return false;
1733
1734 setIntValue(&var->value, iv);
1735 }
1736 else /* type should be double */
1737 {
1738 double dv;
1739
1740 if (!strtodouble(var->svalue, true, &dv))
1741 {
1742 pg_log_error("malformed variable \"%s\" value: \"%s\"",
1743 var->name, var->svalue);
1744 return false;
1745 }
1746 setDoubleValue(&var->value, dv);
1747 }
1748 return true;
bool strtodouble(const char *str, bool errorOK, double *dv)
Definition: pgbench.c:1085
bool strtoint64(const char *str, bool errorOK, int64 *result)
Definition: pgbench.c:1014
static bool is_an_int(const char *str)
Definition: pgbench.c:977
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 1444 of file pgbench.c.

1446{
1447 if (acc->count == 0 || ss->min < acc->min)
1448 acc->min = ss->min;
1449 if (acc->count == 0 || ss->max > acc->max)
1450 acc->max = ss->max;
1451 acc->count += ss->count;
1452 acc->sum += ss->sum;
1453 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 5490 of file pgbench.c.

5492{
5493 char *sql,
5494 *p;
5495
5496 cmd->argc = 1;
5497
5498 p = sql = pg_strdup(cmd->lines.data);
5499 while ((p = strchr(p, ':')) != NULL)
5500 {
5501 char var[13];
5502 char *name;
5503 int eaten;
5504
5505 name = parseVariable(p, &eaten);
5506 if (name == NULL)
5507 {
5508 while (*p == ':')
5509 {
5510 p++;
5511 }
5512 continue;
5513 }
5514
5515 /*
5516 * cmd->argv[0] is the SQL statement itself, so the max number of
5517 * arguments is one less than MAX_ARGS
5518 */
5519 if (cmd->argc >= MAX_ARGS)
5520 {
5521 pg_log_error("statement has too many arguments (maximum is %d): %s",
5522 MAX_ARGS - 1, cmd->lines.data);
5523 pg_free(name);
5524 return false;
5525 }
5526
5527 sprintf(var, "$%d", cmd->argc);
5528 p = replaceVariable(&sql, p, eaten, var);
5529
5530 cmd->argv[cmd->argc] = name;
5531 cmd->argc++;
5532 }
5533
5534 Assert(cmd->argv[0] == NULL);
5535 cmd->argv[0] = sql;
5536 return true;
#define MAX_ARGS
Definition: pgbench.c:686
#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 5969 of file pgbench.c.

5971{
5973 PsqlScanState sstate;
5974 PQExpBufferData line_buf;
5975 int alloc_num;
5976 int index;
5977
5978#define COMMANDS_ALLOC_NUM 128
5979 alloc_num = COMMANDS_ALLOC_NUM;
5980
5981 /* Initialize all fields of ps */
5982 ps.desc = desc;
5983 ps.weight = weight;
5984 ps.commands = (Command **) pg_malloc(sizeof(Command *) * alloc_num);
5985 initStats(&ps.stats, 0);
5986
5987 /* Prepare to parse script */
5989
5990 /*
5991 * Ideally, we'd scan scripts using the encoding and stdstrings settings
5992 * we get from a DB connection. However, without major rearrangement of
5993 * pgbench's argument parsing, we can't have a DB connection at the time
5994 * we parse scripts. Using SQL_ASCII (encoding 0) should work well enough
5995 * with any backend-safe encoding, though conceivably we could be fooled
5996 * if a script file uses a client-only encoding. We also assume that
5997 * stdstrings should be true, which is a bit riskier.
5998 */
5999 psql_scan_setup(sstate, script, strlen(script), 0, true);
6000
6001 initPQExpBuffer(&line_buf);
6002
6003 index = 0;
6004
6005 for (;;)
6006 {
6007 PsqlScanResult sr;
6008 promptStatus_t prompt;
6009 Command *command = NULL;
6010
6011 resetPQExpBuffer(&line_buf);
6012
6013 sr = psql_scan(sstate, &line_buf, &prompt);
6014
6015 /* If we collected a new SQL command, process that */
6016 command = create_sql_command(&line_buf);
6017
6018 /* store new command */
6019 if (command)
6020 ps.commands[index++] = command;
6021
6022 /* If we reached a backslash, process that */
6023 if (sr == PSCAN_BACKSLASH)
6024 {
6025 int lineno;
6026 int start_offset;
6027
6028 /* Capture location of the backslash */
6029 psql_scan_get_location(sstate, &lineno, &start_offset);
6030 start_offset--;
6031
6032 command = process_backslash_command(sstate, desc,
6033 lineno, start_offset);
6034
6035 if (command)
6036 {
6037 /*
6038 * If this is gset or aset, merge into the preceding command.
6039 * (We don't use a command slot in this case).
6040 */
6041 if (command->meta == META_GSET || command->meta == META_ASET)
6042 {
6043 Command *cmd;
6044
6045 if (index == 0)
6046 syntax_error(desc, lineno, NULL, NULL,
6047 "\\gset must follow an SQL command",
6048 NULL, -1);
6049
6050 cmd = ps.commands[index - 1];
6051
6052 if (cmd->type != SQL_COMMAND ||
6053 cmd->varprefix != NULL)
6054 syntax_error(desc, lineno, NULL, NULL,
6055 "\\gset must follow an SQL command",
6056 cmd->first_line, -1);
6057
6058 /* get variable prefix */
6059 if (command->argc <= 1 || command->argv[1][0] == '\0')
6060 cmd->varprefix = pg_strdup("");
6061 else
6062 cmd->varprefix = pg_strdup(command->argv[1]);
6063
6064 /* update the sql command meta */
6065 cmd->meta = command->meta;
6066
6067 /* cleanup unused command */
6068 free_command(command);
6069
6070 continue;
6071 }
6072
6073 /* Attach any other backslash command as a new command */
6074 ps.commands[index++] = command;
6075 }
6076 }
6077
6078 /*
6079 * Since we used a command slot, allocate more if needed. Note we
6080 * always allocate one more in order to accommodate the NULL
6081 * terminator below.
6082 */
6083 if (index >= alloc_num)
6084 {
6085 alloc_num += COMMANDS_ALLOC_NUM;
6086 ps.commands = (Command **)
6087 pg_realloc(ps.commands, sizeof(Command *) * alloc_num);
6088 }
6089
6090 /* Done if we reached EOF */
6091 if (sr == PSCAN_INCOMPLETE || sr == PSCAN_EOL)
6092 break;
6093 }
6094
6095 ps.commands[index] = NULL;
6096
6097 addScript(&ps);
6098
6099 termPQExpBuffer(&line_buf);
6100 psql_scan_finish(sstate);
6101 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:5551
#define COMMANDS_ALLOC_NUM
static void free_command(Command *command)
Definition: pgbench.c:5651
static Command * create_sql_command(PQExpBuffer buf)
Definition: pgbench.c:5622
static Command * process_backslash_command(PsqlScanState sstate, const char *source, int lineno, int start_offset)
Definition: pgbench.c:5708
static void addScript(const ParsedScript *script)
Definition: pgbench.c:6261
static const PsqlScanCallbacks pgbench_callbacks
Definition: pgbench.c:847
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 6224 of file pgbench.c.

6226{
6227 char *sep;
6228 int weight;
6229
6230 if ((sep = strrchr(option, WSEP)))
6231 {
6232 int namelen = sep - option;
6233 long wtmp;
6234 char *badp;
6235
6236 /* generate the script name */
6237 *script = pg_malloc(namelen + 1);
6238 strncpy(*script, option, namelen);
6239 (*script)[namelen] = '\0';
6240
6241 /* process digits of the weight spec */
6242 errno = 0;
6243 wtmp = strtol(sep + 1, &badp, 10);
6244 if (errno != 0 || badp == sep + 1 || *badp != '\0')
6245 pg_fatal("invalid weight specification: %s", sep);
6246 if (wtmp > INT_MAX || wtmp < 0)
6247 pg_fatal("weight specification out of range (0 .. %d): %lld",
6248 INT_MAX, (long long) wtmp);
6249 weight = wtmp;
6250 }
6251 else
6252 {
6253 *script = pg_strdup(option);
6254 weight = 1;
6255 }
6256
6257 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 1915 of file pgbench.c.

1917{
1918 int i = 1; /* starting at 1 skips the colon */
1919 char *name;
1920
1921 /* keep this logic in sync with valid_variable_name() */
1922 if (IS_HIGHBIT_SET(sql[i]) ||
1923 strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1924 "_", sql[i]) != NULL)
1925 i++;
1926 else
1927 return NULL;
1928
1929 while (IS_HIGHBIT_SET(sql[i]) ||
1930 strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1931 "_0123456789", sql[i]) != NULL)
1932 i++;
1933
1934 name = pg_malloc(i);
1935 memcpy(name, &sql[1], i - 1);
1936 name[i - 1] = '\0';
1937
1938 *eaten = i;
1939 return name;
#define IS_HIGHBIT_SET(ch)
Definition: c.h:1154

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

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

889{
890 if ((*now) == 0)
891 (*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 5671 of file pgbench.c.

5673{
5674 char buffer[128];
5675 static int prepnum = 0;
5676
5677 Assert(my_command->type == SQL_COMMAND);
5678
5679 /* Save the first line for error display. */
5680 strlcpy(buffer, my_command->lines.data, sizeof(buffer));
5681 buffer[strcspn(buffer, "\n\r")] = '\0';
5682 my_command->first_line = pg_strdup(buffer);
5683
5684 /* Parse query and generate prepared statement name, if necessary */
5685 switch (querymode)
5686 {
5687 case QUERY_SIMPLE:
5688 my_command->argv[0] = my_command->lines.data;
5689 my_command->argc++;
5690 break;
5691 case QUERY_PREPARED:
5692 my_command->prepname = psprintf("P_%d", prepnum++);
5693 /* fall through */
5694 case QUERY_EXTENDED:
5695 if (!parseQuery(my_command))
5696 exit(1);
5697 break;
5698 default:
5699 exit(1);
5700 }
static bool parseQuery(Command *cmd)
Definition: pgbench.c:5490
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 3117 of file pgbench.c.

3119{
3120 Command *command = sql_script[st->use_file].commands[command_num];
3121
3122 /* No prepare for non-SQL commands */
3123 if (command->type != SQL_COMMAND)
3124 return;
3125
3126 if (!st->prepared)
3128
3129 if (!st->prepared[st->use_file][command_num])
3130 {
3131 PGresult *res;
3132
3133 pg_log_debug("client %d preparing %s", st->id, command->prepname);
3134 res = PQprepare(st->con, command->prepname,
3135 command->argv[0], command->argc - 1, NULL);
3136 if (PQresultStatus(res) != PGRES_COMMAND_OK)
3137 pg_log_error("%s", PQerrorMessage(st->con));
3138 PQclear(res);
3139 st->prepared[st->use_file][command_num] = true;
3140 }
PGresult * PQprepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes)
Definition: fe-exec.c:2317
static void allocCStatePrepared(CState *st)
Definition: pgbench.c:3097

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

3152{
3153 int j;
3154 Command **commands = sql_script[st->use_file].commands;
3155
3156 Assert(commands[st->command]->type == META_COMMAND &&
3157 commands[st->command]->meta == META_STARTPIPELINE);
3158
3159 if (!st->prepared)
3161
3162 /*
3163 * We set the 'prepared' flag on the \startpipeline itself to flag that we
3164 * don't need to do this next time without calling prepareCommand(), even
3165 * though we don't actually prepare this command.
3166 */
3167 if (st->prepared[st->use_file][st->command])
3168 return;
3169
3170 for (j = st->command + 1; commands[j] != NULL; j++)
3171 {
3172 if (commands[j]->type == META_COMMAND &&
3173 commands[j]->meta == META_ENDPIPELINE)
3174 break;
3175
3176 prepareCommand(st, j);
3177 }
3178
3179 st->prepared[st->use_file][st->command] = true;
static void prepareCommand(CState *st, int command_num)
Definition: pgbench.c:3117

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

6285{
6286 /* generate and show report */
6287 pg_time_usec_t run = now - *last_report;
6288 int64 cnt,
6289 failures,
6290 retried;
6291 double tps,
6292 total_run,
6293 latency,
6294 sqlat,
6295 lag,
6296 stdev;
6297 char tbuf[315];
6298 StatsData cur;
6299
6300 /*
6301 * Add up the statistics of all threads.
6302 *
6303 * XXX: No locking. There is no guarantee that we get an atomic snapshot
6304 * of the transaction count and latencies, so these figures can well be
6305 * off by a small amount. The progress report's purpose is to give a
6306 * quick overview of how the test is going, so that shouldn't matter too
6307 * much. (If a read from a 64-bit integer is not atomic, you might get a
6308 * "torn" read and completely bogus latencies though!)
6309 */
6310 initStats(&cur, 0);
6311 for (int i = 0; i < nthreads; i++)
6312 {
6313 mergeSimpleStats(&cur.latency, &threads[i].stats.latency);
6314 mergeSimpleStats(&cur.lag, &threads[i].stats.lag);
6315 cur.cnt += threads[i].stats.cnt;
6316 cur.skipped += threads[i].stats.skipped;
6317 cur.retries += threads[i].stats.retries;
6318 cur.retried += threads[i].stats.retried;
6319 cur.serialization_failures +=
6321 cur.deadlock_failures += threads[i].stats.deadlock_failures;
6322 }
6323
6324 /* we count only actually executed transactions */
6325 cnt = cur.cnt - last->cnt;
6326 total_run = (now - test_start) / 1000000.0;
6327 tps = 1000000.0 * cnt / run;
6328 if (cnt > 0)
6329 {
6330 latency = 0.001 * (cur.latency.sum - last->latency.sum) / cnt;
6331 sqlat = 1.0 * (cur.latency.sum2 - last->latency.sum2) / cnt;
6332 stdev = 0.001 * sqrt(sqlat - 1000000.0 * latency * latency);
6333 lag = 0.001 * (cur.lag.sum - last->lag.sum) / cnt;
6334 }
6335 else
6336 {
6337 latency = sqlat = stdev = lag = 0;
6338 }
6339 failures = getFailures(&cur) - getFailures(last);
6340 retried = cur.retried - last->retried;
6341
6343 {
6344 snprintf(tbuf, sizeof(tbuf), "%.3f s",
6346 }
6347 else
6348 {
6349 /* round seconds are expected, but the thread may be late */
6350 snprintf(tbuf, sizeof(tbuf), "%.1f s", total_run);
6351 }
6352
6353 fprintf(stderr,
6354 "progress: %s, %.1f tps, lat %.3f ms stddev %.3f, " INT64_FORMAT " failed",
6355 tbuf, tps, latency, stdev, failures);
6356
6357 if (throttle_delay)
6358 {
6359 fprintf(stderr, ", lag %.3f ms", lag);
6360 if (latency_limit)
6361 fprintf(stderr, ", " INT64_FORMAT " skipped",
6362 cur.skipped - last->skipped);
6363 }
6364
6365 /* it can be non-zero only if max_tries is not equal to one */
6366 if (max_tries != 1)
6367 fprintf(stderr,
6368 ", " INT64_FORMAT " retried, " INT64_FORMAT " retries",
6369 retried, cur.retries - last->retries);
6370 fprintf(stderr, "\n");
6371
6372 *last = cur;
6373 *last_report = now;
struct cursor * cur
Definition: ecpg.c:29
static int64 getFailures(const StatsData *stats)
Definition: pgbench.c:4561

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

6427{
6428 /* tps is about actually executed transactions during benchmarking */
6429 int64 failures = getFailures(total);
6430 int64 total_cnt = total->cnt + total->skipped + failures;
6431 double bench_duration = PG_TIME_GET_DOUBLE(total_duration);
6432 double tps = total->cnt / bench_duration;
6433
6434 /* Report test parameters. */
6435 printf("transaction type: %s\n",
6436 num_scripts == 1 ? sql_script[0].desc : "multiple scripts");
6437 printf("scaling factor: %d\n", scale);
6438 /* only print partitioning information if some partitioning was detected */
6440 printf("partition method: %s\npartitions: %d\n",
6442 printf("query mode: %s\n", QUERYMODE[querymode]);
6443 printf("number of clients: %d\n", nclients);
6444 printf("number of threads: %d\n", nthreads);
6445
6446 if (max_tries)
6447 printf("maximum number of tries: %u\n", max_tries);
6448
6449 if (duration <= 0)
6450 {
6451 printf("number of transactions per client: %d\n", nxacts);
6452 printf("number of transactions actually processed: " INT64_FORMAT "/%d\n",
6453 total->cnt, nxacts * nclients);
6454 }
6455 else
6456 {
6457 printf("duration: %d s\n", duration);
6458 printf("number of transactions actually processed: " INT64_FORMAT "\n",
6459 total->cnt);
6460 }
6461
6462 /*
6463 * Remaining stats are nonsensical if we failed to execute any xacts due
6464 * to others than serialization or deadlock errors
6465 */
6466 if (total_cnt <= 0)
6467 return;
6468
6469 printf("number of failed transactions: " INT64_FORMAT " (%.3f%%)\n",
6470 failures, 100.0 * failures / total_cnt);
6471
6473 {
6474 printf("number of serialization failures: " INT64_FORMAT " (%.3f%%)\n",
6476 100.0 * total->serialization_failures / total_cnt);
6477 printf("number of deadlock failures: " INT64_FORMAT " (%.3f%%)\n",
6478 total->deadlock_failures,
6479 100.0 * total->deadlock_failures / total_cnt);
6480 }
6481
6482 /* it can be non-zero only if max_tries is not equal to one */
6483 if (max_tries != 1)
6484 {
6485 printf("number of transactions retried: " INT64_FORMAT " (%.3f%%)\n",
6486 total->retried, 100.0 * total->retried / total_cnt);
6487 printf("total number of retries: " INT64_FORMAT "\n", total->retries);
6488 }
6489
6491 printf("number of transactions skipped: " INT64_FORMAT " (%.3f%%)\n",
6492 total->skipped, 100.0 * total->skipped / total_cnt);
6493
6494 if (latency_limit)
6495 printf("number of transactions above the %.1f ms latency limit: " INT64_FORMAT "/" INT64_FORMAT " (%.3f%%)\n",
6496 latency_limit / 1000.0, latency_late, total->cnt,
6497 (total->cnt > 0) ? 100.0 * latency_late / total->cnt : 0.0);
6498
6500 printSimpleStats("latency", &total->latency);
6501 else
6502 {
6503 /* no measurement, show average latency computed from run time */
6504 printf("latency average = %.3f ms%s\n",
6505 0.001 * total_duration * nclients / total_cnt,
6506 failures > 0 ? " (including failures)" : "");
6507 }
6508
6509 if (throttle_delay)
6510 {
6511 /*
6512 * Report average transaction lag under rate limit throttling. This
6513 * is the delay between scheduled and actual start times for the
6514 * transaction. The measured lag may be caused by thread/client load,
6515 * the database load, or the Poisson throttling process.
6516 */
6517 printf("rate limit schedule lag: avg %.3f (max %.3f) ms\n",
6518 0.001 * total->lag.sum / total->cnt, 0.001 * total->lag.max);
6519 }
6520
6521 /*
6522 * Under -C/--connect, each transaction incurs a significant connection
6523 * cost, it would not make much sense to ignore it in tps, and it would
6524 * not be tps anyway.
6525 *
6526 * Otherwise connections are made just once at the beginning of the run
6527 * and should not impact performance but for very short run, so they are
6528 * (right)fully ignored in tps.
6529 */
6530 if (is_connect)
6531 {
6532 printf("average connection time = %.3f ms\n", 0.001 * conn_total_duration / (total->cnt + failures));
6533 printf("tps = %f (including reconnection times)\n", tps);
6534 }
6535 else
6536 {
6537 printf("initial connection time = %.3f ms\n", 0.001 * conn_elapsed_duration);
6538 printf("tps = %f (without initial connection time)\n", tps);
6539 }
6540
6541 /* Report per-script/command statistics */
6543 {
6544 int i;
6545
6546 for (i = 0; i < num_scripts; i++)
6547 {
6548 if (per_script_stats)
6549 {
6550 StatsData *sstats = &sql_script[i].stats;
6551 int64 script_failures = getFailures(sstats);
6552 int64 script_total_cnt =
6553 sstats->cnt + sstats->skipped + script_failures;
6554
6555 printf("SQL script %d: %s\n"
6556 " - weight: %d (targets %.1f%% of total)\n"
6557 " - " INT64_FORMAT " transactions (%.1f%% of total)\n",
6558 i + 1, sql_script[i].desc,
6559 sql_script[i].weight,
6560 100.0 * sql_script[i].weight / total_weight,
6561 script_total_cnt,
6562 100.0 * script_total_cnt / total_cnt);
6563
6564 if (script_total_cnt > 0)
6565 {
6566 printf(" - number of transactions actually processed: " INT64_FORMAT " (tps = %f)\n",
6567 sstats->cnt, sstats->cnt / bench_duration);
6568
6569 printf(" - number of failed transactions: " INT64_FORMAT " (%.3f%%)\n",
6570 script_failures,
6571 100.0 * script_failures / script_total_cnt);
6572
6574 {
6575 printf(" - number of serialization failures: " INT64_FORMAT " (%.3f%%)\n",
6576 sstats->serialization_failures,
6577 (100.0 * sstats->serialization_failures /
6578 script_total_cnt));
6579 printf(" - number of deadlock failures: " INT64_FORMAT " (%.3f%%)\n",
6580 sstats->deadlock_failures,
6581 (100.0 * sstats->deadlock_failures /
6582 script_total_cnt));
6583 }
6584
6585 /*
6586 * it can be non-zero only if max_tries is not equal to
6587 * one
6588 */
6589 if (max_tries != 1)
6590 {
6591 printf(" - number of transactions retried: " INT64_FORMAT " (%.3f%%)\n",
6592 sstats->retried,
6593 100.0 * sstats->retried / script_total_cnt);
6594 printf(" - total number of retries: " INT64_FORMAT "\n",
6595 sstats->retries);
6596 }
6597
6599 printf(" - number of transactions skipped: " INT64_FORMAT " (%.3f%%)\n",
6600 sstats->skipped,
6601 100.0 * sstats->skipped / script_total_cnt);
6602
6603 }
6604 printSimpleStats(" - latency", &sstats->latency);
6605 }
6606
6607 /*
6608 * Report per-command statistics: latencies, retries after errors,
6609 * failures (errors without retrying).
6610 */
6612 {
6613 Command **commands;
6614
6615 printf("%sstatement latencies in milliseconds%s:\n",
6616 per_script_stats ? " - " : "",
6617 (max_tries == 1 ?
6618 " and failures" :
6619 ", failures and retries"));
6620
6621 for (commands = sql_script[i].commands;
6622 *commands != NULL;
6623 commands++)
6624 {
6625 SimpleStats *cstats = &(*commands)->stats;
6626
6627 if (max_tries == 1)
6628 printf(" %11.3f %10" PRId64 " %s\n",
6629 (cstats->count > 0) ?
6630 1000.0 * cstats->sum / cstats->count : 0.0,
6631 (*commands)->failures,
6632 (*commands)->first_line);
6633 else
6634 printf(" %11.3f %10" PRId64 " %10" PRId64 " %s\n",
6635 (cstats->count > 0) ?
6636 1000.0 * cstats->sum / cstats->count : 0.0,
6637 (*commands)->failures,
6638 (*commands)->retries,
6639 (*commands)->first_line);
6640 }
6641 }
6642 }
6643 }
static void printSimpleStats(const char *prefix, SimpleStats *ss)
Definition: pgbench.c:6376
#define printf(...)
Definition: port.h:245
StatsData stats
Definition: pgbench.c:762

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

6378{
6379 if (ss->count > 0)
6380 {
6381 double latency = ss->sum / ss->count;
6382 double stddev = sqrt(ss->sum2 / ss->count - latency * latency);
6383
6384 printf("%s average = %.3f ms\n", prefix, 0.001 * latency);
6385 printf("%s stddev = %.3f ms\n", prefix, 0.001 * stddev);
6386 }

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

3608{
3609 static PQExpBuffer buf = NULL;
3610
3611 if (buf == NULL)
3613 else
3615
3616 printfPQExpBuffer(buf, "client %d ", st->id);
3617 appendPQExpBufferStr(buf, (is_retry ?
3618 "repeats the transaction after the error" :
3619 "ends the failed transaction"));
3620 appendPQExpBuffer(buf, " (try %u", st->tries);
3621
3622 /* Print max_tries if it is not unlimited. */
3623 if (max_tries)
3625
3626 /*
3627 * If the latency limit is used, print a percentage of the current
3628 * transaction latency from the latency limit.
3629 */
3630 if (latency_limit)
3631 {
3633 appendPQExpBuffer(buf, ", %.3f%% of the maximum time of tries was used",
3634 (100.0 * (*now - st->txn_scheduled) / latency_limit));
3635 }
3636 appendPQExpBufferStr(buf, ")\n");
3637
3638 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 6390 of file pgbench.c.

6392{
6393 int server_ver = PQserverVersion(con);
6394 int client_ver = PG_VERSION_NUM;
6395
6396 if (server_ver != client_ver)
6397 {
6398 const char *server_version;
6399 char sverbuf[32];
6400
6401 /* Try to get full text form, might include "devel" etc */
6402 server_version = PQparameterStatus(con, "server_version");
6403 /* Otherwise fall back on server_ver */
6404 if (!server_version)
6405 {
6406 formatPGVersionNumber(server_ver, true,
6407 sverbuf, sizeof(sverbuf));
6408 server_version = sverbuf;
6409 }
6410
6411 printf(_("%s (%s, server %s)\n"),
6412 "pgbench", PG_VERSION, server_version);
6413 }
6414 /* For version match, only print pgbench version */
6415 else
6416 printf("%s (%s)\n", "pgbench", PG_VERSION);
6417 fflush(stdout);
#define _(x)
Definition: elog.c:91
const char * PQparameterStatus(const PGconn *conn, const char *paramName)
Definition: fe-connect.c:7634
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 5708 of file pgbench.c.

5711{
5712 Command *my_command;
5713 PQExpBufferData word_buf;
5714 int word_offset;
5715 int offsets[MAX_ARGS]; /* offsets of argument words */
5716 int j;
5717
5718 initPQExpBuffer(&word_buf);
5719
5720 /* Collect first word of command */
5721 if (!expr_lex_one_word(sstate, &word_buf, &word_offset))
5722 {
5723 termPQExpBuffer(&word_buf);
5724 return NULL;
5725 }
5726
5727 /* Allocate and initialize Command structure */
5728 my_command = (Command *) pg_malloc0(sizeof(Command));
5729 my_command->type = META_COMMAND;
5730 my_command->argc = 0;
5731 initSimpleStats(&my_command->stats);
5732
5733 /* Save first word (command name) */
5734 j = 0;
5735 offsets[j] = word_offset;
5736 my_command->argv[j++] = pg_strdup(word_buf.data);
5737 my_command->argc++;
5738
5739 /* ... and convert it to enum form */
5740 my_command->meta = getMetaCommand(my_command->argv[0]);
5741
5742 if (my_command->meta == META_SET ||
5743 my_command->meta == META_IF ||
5744 my_command->meta == META_ELIF)
5745 {
5746 yyscan_t yyscanner;
5747
5748 /* For \set, collect var name */
5749 if (my_command->meta == META_SET)
5750 {
5751 if (!expr_lex_one_word(sstate, &word_buf, &word_offset))
5752 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5753 "missing argument", NULL, -1);
5754
5755 offsets[j] = word_offset;
5756 my_command->argv[j++] = pg_strdup(word_buf.data);
5757 my_command->argc++;
5758 }
5759
5760 /* then for all parse the expression */
5761 yyscanner = expr_scanner_init(sstate, source, lineno, start_offset,
5762 my_command->argv[0]);
5763
5764 if (expr_yyparse(&my_command->expr, yyscanner) != 0)
5765 {
5766 /* dead code: exit done from syntax_error called by yyerror */
5767 exit(1);
5768 }
5769
5770 /* Save line, trimming any trailing newline */
5771 my_command->first_line =
5773 start_offset,
5774 true);
5775
5776 expr_scanner_finish(yyscanner);
5777
5778 termPQExpBuffer(&word_buf);
5779
5780 return my_command;
5781 }
5782
5783 /* For all other commands, collect remaining words. */
5784 while (expr_lex_one_word(sstate, &word_buf, &word_offset))
5785 {
5786 /*
5787 * my_command->argv[0] is the command itself, so the max number of
5788 * arguments is one less than MAX_ARGS
5789 */
5790 if (j >= MAX_ARGS)
5791 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5792 "too many arguments", NULL, -1);
5793
5794 offsets[j] = word_offset;
5795 my_command->argv[j++] = pg_strdup(word_buf.data);
5796 my_command->argc++;
5797 }
5798
5799 /* Save line, trimming any trailing newline */
5800 my_command->first_line =
5802 start_offset,
5803 true);
5804
5805 if (my_command->meta == META_SLEEP)
5806 {
5807 if (my_command->argc < 2)
5808 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5809 "missing argument", NULL, -1);
5810
5811 if (my_command->argc > 3)
5812 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5813 "too many arguments", NULL,
5814 offsets[3] - start_offset);
5815
5816 /*
5817 * Split argument into number and unit to allow "sleep 1ms" etc. We
5818 * don't have to terminate the number argument with null because it
5819 * will be parsed with atoi, which ignores trailing non-digit
5820 * characters.
5821 */
5822 if (my_command->argv[1][0] != ':')
5823 {
5824 char *c = my_command->argv[1];
5825 bool have_digit = false;
5826
5827 /* Skip sign */
5828 if (*c == '+' || *c == '-')
5829 c++;
5830
5831 /* Require at least one digit */
5832 if (*c && isdigit((unsigned char) *c))
5833 have_digit = true;
5834
5835 /* Eat all digits */
5836 while (*c && isdigit((unsigned char) *c))
5837 c++;
5838
5839 if (*c)
5840 {
5841 if (my_command->argc == 2 && have_digit)
5842 {
5843 my_command->argv[2] = c;
5844 offsets[2] = offsets[1] + (c - my_command->argv[1]);
5845 my_command->argc = 3;
5846 }
5847 else
5848 {
5849 /*
5850 * Raise an error if argument starts with non-digit
5851 * character (after sign).
5852 */
5853 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5854 "invalid sleep time, must be an integer",
5855 my_command->argv[1], offsets[1] - start_offset);
5856 }
5857 }
5858 }
5859
5860 if (my_command->argc == 3)
5861 {
5862 if (pg_strcasecmp(my_command->argv[2], "us") != 0 &&
5863 pg_strcasecmp(my_command->argv[2], "ms") != 0 &&
5864 pg_strcasecmp(my_command->argv[2], "s") != 0)
5865 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5866 "unrecognized time unit, must be us, ms or s",
5867 my_command->argv[2], offsets[2] - start_offset);
5868 }
5869 }
5870 else if (my_command->meta == META_SETSHELL)
5871 {
5872 if (my_command->argc < 3)
5873 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5874 "missing argument", NULL, -1);
5875 }
5876 else if (my_command->meta == META_SHELL)
5877 {
5878 if (my_command->argc < 2)
5879 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5880 "missing command", NULL, -1);
5881 }
5882 else if (my_command->meta == META_ELSE || my_command->meta == META_ENDIF ||
5883 my_command->meta == META_STARTPIPELINE ||
5884 my_command->meta == META_ENDPIPELINE ||
5885 my_command->meta == META_SYNCPIPELINE)
5886 {
5887 if (my_command->argc != 1)
5888 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5889 "unexpected argument", NULL, -1);
5890 }
5891 else if (my_command->meta == META_GSET || my_command->meta == META_ASET)
5892 {
5893 if (my_command->argc > 2)
5894 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5895 "too many arguments", NULL, -1);
5896 }
5897 else
5898 {
5899 /* my_command->meta == META_NONE */
5900 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5901 "invalid command", NULL, -1);
5902 }
5903
5904 termPQExpBuffer(&word_buf);
5905
5906 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:2901
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 6169 of file pgbench.c.

6171{
6172 ParseScript(bi->script, bi->desc, weight);
static void ParseScript(const char *script, const char *desc, int weight)
Definition: pgbench.c:5969

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

6145{
6146 FILE *fd;
6147 char *buf;
6148
6149 /* Slurp the file contents into "buf" */
6150 if (strcmp(filename, "-") == 0)
6151 fd = stdin;
6152 else if ((fd = fopen(filename, "r")) == NULL)
6153 pg_fatal("could not open file \"%s\": %m", filename);
6154
6156
6157 if (ferror(fd))
6158 pg_fatal("could not read file \"%s\": %m", filename);
6159
6160 if (fd != stdin)
6161 fclose(fd);
6162
6163 ParseScript(buf, filename, weight);
6164
6165 free(buf);
static char * filename
Definition: pg_dumpall.c:120
static char * read_file_contents(FILE *fd)
Definition: pgbench.c:6110

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

4726{
4727 double latency = 0.0,
4728 lag = 0.0;
4729 bool detailed = progress || throttle_delay || latency_limit ||
4731
4732 if (detailed && !skipped && st->estatus == ESTATUS_NO_ERROR)
4733 {
4735
4736 /* compute latency & lag */
4737 latency = (*now) - st->txn_scheduled;
4738 lag = st->txn_begin - st->txn_scheduled;
4739 }
4740
4741 /* keep detailed thread stats */
4742 accumStats(&thread->stats, skipped, latency, lag, st->estatus, st->tries);
4743
4744 /* count transactions over the latency limit, if needed */
4745 if (latency_limit && latency > latency_limit)
4746 thread->latency_late++;
4747
4748 /* client stat is just counting */
4749 st->cnt++;
4750
4751 if (use_log)
4752 doLog(thread, st, agg, skipped, latency, lag);
4753
4754 /* XXX could use a mutex here, but we choose not to */
4755 if (per_script_stats)
4756 accumStats(&sql_script[st->use_file].stats, skipped, latency, lag,
4757 st->estatus, st->tries);
static void doLog(TState *thread, CState *st, StatsData *agg, bool skipped, double latency, double lag)
Definition: pgbench.c:4603

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

1858{
1859 Variable *var;
1860 char *val;
1861
1862 var = lookupCreateVariable(variables, context, name);
1863 if (!var)
1864 return false;
1865
1866 /* dup then free, in case value is pointing at this variable */
1867 val = pg_strdup(value);
1868
1869 free(var->svalue);
1870 var->svalue = val;
1871 var->value.type = PGBT_NO_VALUE;
1872
1873 return true;
static struct @169 value
static Variable * lookupCreateVariable(Variables *variables, const char *context, char *name)
Definition: pgbench.c:1818

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

1900{
1902
1904 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 1878 of file pgbench.c.

1881{
1882 Variable *var;
1883
1884 var = lookupCreateVariable(variables, context, name);
1885 if (!var)
1886 return false;
1887
1888 free(var->svalue);
1889 var->svalue = NULL;
1890 var->value = *value;
1891
1892 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 6110 of file pgbench.c.

6112{
6113 char *buf;
6114 size_t buflen = BUFSIZ;
6115 size_t used = 0;
6116
6117 buf = (char *) pg_malloc(buflen);
6118
6119 for (;;)
6120 {
6121 size_t nread;
6122
6123 nread = fread(buf + used, 1, BUFSIZ, fd);
6124 used += nread;
6125 /* If fread() read less than requested, must be EOF or error */
6126 if (nread < BUFSIZ)
6127 break;
6128 /* Enlarge buf so we can read some more */
6129 buflen += BUFSIZ;
6130 buf = (char *) pg_realloc(buf, buflen);
6131 }
6132 /* There is surely room for a terminator */
6133 buf[used] = '\0';
6134
6135 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 3269 of file pgbench.c.

3271{
3272 PGresult *res;
3273 PGresult *next_res;
3274 int qrynum = 0;
3275
3276 /*
3277 * varprefix should be set only with \gset or \aset, and \endpipeline and
3278 * SQL commands do not need it.
3279 */
3280 Assert((meta == META_NONE && varprefix == NULL) ||
3281 ((meta == META_ENDPIPELINE) && varprefix == NULL) ||
3282 ((meta == META_GSET || meta == META_ASET) && varprefix != NULL));
3283
3284 res = PQgetResult(st->con);
3285
3286 while (res != NULL)
3287 {
3288 bool is_last;
3289
3290 /* peek at the next result to know whether the current is last */
3291 next_res = PQgetResult(st->con);
3292 is_last = (next_res == NULL);
3293
3294 switch (PQresultStatus(res))
3295 {
3296 case PGRES_COMMAND_OK: /* non-SELECT commands */
3297 case PGRES_EMPTY_QUERY: /* may be used for testing no-op overhead */
3298 if (is_last && meta == META_GSET)
3299 {
3300 pg_log_error("client %d script %d command %d query %d: expected one row, got %d",
3301 st->id, st->use_file, st->command, qrynum, 0);
3303 goto error;
3304 }
3305 break;
3306
3307 case PGRES_TUPLES_OK:
3308 if ((is_last && meta == META_GSET) || meta == META_ASET)
3309 {
3310 int ntuples = PQntuples(res);
3311
3312 if (meta == META_GSET && ntuples != 1)
3313 {
3314 /* under \gset, report the error */
3315 pg_log_error("client %d script %d command %d query %d: expected one row, got %d",
3316 st->id, st->use_file, st->command, qrynum, PQntuples(res));
3318 goto error;
3319 }
3320 else if (meta == META_ASET && ntuples <= 0)
3321 {
3322 /* coldly skip empty result under \aset */
3323 break;
3324 }
3325
3326 /* store results into variables */
3327 for (int fld = 0; fld < PQnfields(res); fld++)
3328 {
3329 char *varname = PQfname(res, fld);
3330
3331 /* allocate varname only if necessary, freed below */
3332 if (*varprefix != '\0')
3333 varname = psprintf("%s%s", varprefix, varname);
3334
3335 /* store last row result as a string */
3336 if (!putVariable(&st->variables, meta == META_ASET ? "aset" : "gset", varname,
3337 PQgetvalue(res, ntuples - 1, fld)))
3338 {
3339 /* internal error */
3340 pg_log_error("client %d script %d command %d query %d: error storing into variable %s",
3341 st->id, st->use_file, st->command, qrynum, varname);
3343 goto error;
3344 }
3345
3346 if (*varprefix != '\0')
3347 pg_free(varname);
3348 }
3349 }
3350 /* otherwise the result is simply thrown away by PQclear below */
3351 break;
3352
3354 pg_log_debug("client %d pipeline ending, ongoing syncs: %d",
3355 st->id, st->num_syncs);
3356 st->num_syncs--;
3357 if (st->num_syncs == 0 && PQexitPipelineMode(st->con) != 1)
3358 pg_log_error("client %d failed to exit pipeline mode: %s", st->id,
3360 break;
3361
3362 case PGRES_COPY_IN:
3363 case PGRES_COPY_OUT:
3364 case PGRES_COPY_BOTH:
3365 pg_log_error("COPY is not supported in pgbench, aborting");
3366
3367 /*
3368 * We need to exit the copy state. Otherwise, PQgetResult()
3369 * will always return an empty PGresult as an effect of
3370 * getCopyResult(), leading to an infinite loop in the error
3371 * cleanup done below.
3372 */
3373 PQendcopy(st->con);
3374 goto error;
3375
3377 case PGRES_FATAL_ERROR:
3380 if (canRetryError(st->estatus))
3381 {
3382 if (verbose_errors)
3384 goto error;
3385 }
3386 /* fall through */
3387
3388 default:
3389 /* anything else is unexpected */
3390 pg_log_error("client %d script %d aborted in command %d query %d: %s",
3391 st->id, st->use_file, st->command, qrynum,
3393 goto error;
3394 }
3395
3396 PQclear(res);
3397 qrynum++;
3398 res = next_res;
3399 }
3400
3401 if (qrynum == 0)
3402 {
3403 pg_log_error("client %d command %d: no results", st->id, st->command);
3404 return false;
3405 }
3406
3407 return true;
3408
3409error:
3410 PQclear(res);
3411 PQclear(next_res);
3412 do
3413 {
3414 res = PQgetResult(st->con);
3415 PQclear(res);
3416 } while (res);
3417
3418 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 EStatus getSQLErrorStatus(const char *sqlState)
Definition: pgbench.c:3236
static void commandError(CState *st, const char *message)
Definition: pgbench.c:3059
static void error(void)
Definition: sql-dyntest.c:147

References Assert(), canRetryError(), CState::command, commandError(), CState::con, 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 1942 of file pgbench.c.

1944{
1945 int valueln = strlen(value);
1946
1947 if (valueln > len)
1948 {
1949 size_t offset = param - *sql;
1950
1951 *sql = pg_realloc(*sql, strlen(*sql) - len + valueln + 1);
1952 param = *sql + offset;
1953 }
1954
1955 if (valueln != len)
1956 memmove(param + valueln, param + len, strlen(param + len) + 1);
1957 memcpy(param, value, valueln);
1958
1959 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 5296 of file pgbench.c.

5298{
5299 PQExpBufferData stats;
5300 PGconn *con;
5301 const char *step;
5302 double run_time = 0.0;
5303 bool first = true;
5304
5305 initPQExpBuffer(&stats);
5306
5307 if ((con = doConnect()) == NULL)
5308 pg_fatal("could not create connection for initialization");
5309
5311 SetCancelConn(con);
5312
5313 for (step = initialize_steps; *step != '\0'; step++)
5314 {
5315 char *op = NULL;
5317
5318 switch (*step)
5319 {
5320 case 'd':
5321 op = "drop tables";
5322 initDropTables(con);
5323 break;
5324 case 't':
5325 op = "create tables";
5326 initCreateTables(con);
5327 break;
5328 case 'g':
5329 op = "client-side generate";
5331 break;
5332 case 'G':
5333 op = "server-side generate";
5335 break;
5336 case 'v':
5337 op = "vacuum";
5338 initVacuum(con);
5339 break;
5340 case 'p':
5341 op = "primary keys";
5342 initCreatePKeys(con);
5343 break;
5344 case 'f':
5345 op = "foreign keys";
5346 initCreateFKeys(con);
5347 break;
5348 case ' ':
5349 break; /* ignore */
5350 default:
5351 pg_log_error("unrecognized initialization step \"%c\"", *step);
5352 PQfinish(con);
5353 exit(1);
5354 }
5355
5356 if (op != NULL)
5357 {
5358 double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
5359
5360 if (!first)
5361 appendPQExpBufferStr(&stats, ", ");
5362 else
5363 first = false;
5364
5365 appendPQExpBuffer(&stats, "%s %.2f s", op, elapsed_sec);
5366
5367 run_time += elapsed_sec;
5368 }
5369 }
5370
5371 fprintf(stderr, "done in %.2f s (%s).\n", run_time, stats.data);
5373 PQfinish(con);
5374 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:5212
static void initDropTables(PGconn *con)
Definition: pgbench.c:4774
static void initGenerateDataServerSide(PGconn *con)
Definition: pgbench.c:5154
static void initCreateFKeys(PGconn *con)
Definition: pgbench.c:5250
static void initVacuum(PGconn *con)
Definition: pgbench.c:5199
static void initCreateTables(PGconn *con)
Definition: pgbench.c:4865
static void initGenerateDataClientSide(PGconn *con)
Definition: pgbench.c:5122

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

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

3185{
3186 int r;
3187
3188 if (querymode == QUERY_SIMPLE)
3189 {
3190 char *sql;
3191
3192 sql = pg_strdup(command->argv[0]);
3193 sql = assignVariables(&st->variables, sql);
3194
3195 pg_log_debug("client %d sending %s", st->id, sql);
3196 r = PQsendQuery(st->con, sql);
3197 free(sql);
3198 }
3199 else if (querymode == QUERY_EXTENDED)
3200 {
3201 const char *sql = command->argv[0];
3202 const char *params[MAX_ARGS];
3203
3204 getQueryParams(&st->variables, command, params);
3205
3206 pg_log_debug("client %d sending %s", st->id, sql);
3207 r = PQsendQueryParams(st->con, sql, command->argc - 1,
3208 NULL, params, NULL, NULL, 0);
3209 }
3210 else if (querymode == QUERY_PREPARED)
3211 {
3212 const char *params[MAX_ARGS];
3213
3214 prepareCommand(st, st->command);
3215 getQueryParams(&st->variables, command, params);
3216
3217 pg_log_debug("client %d sending %s", st->id, command->prepname);
3218 r = PQsendQueryPrepared(st->con, command->prepname, command->argc - 1,
3219 params, NULL, NULL, 0);
3220 }
3221 else /* unknown sql mode */
3222 r = 0;
3223
3224 if (r == 0)
3225 {
3226 pg_log_debug("client %d could not send %s", st->id, command->argv[0]);
3227 return false;
3228 }
3229 else
3230 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:1503
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:1644
static void getQueryParams(Variables *variables, const Command *command, const char **params)
Definition: pgbench.c:1998
static char * assignVariables(Variables *variables, char *sql)
Definition: pgbench.c:1962

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

6652{
6653 uint64 iseed;
6654
6655 if (seed == NULL || strcmp(seed, "time") == 0)
6656 {
6657 /* rely on current time */
6658 iseed = pg_time_now();
6659 }
6660 else if (strcmp(seed, "rand") == 0)
6661 {
6662 /* use some "strong" random source */
6663 if (!pg_strong_random(&iseed, sizeof(iseed)))
6664 {
6665 pg_log_error("could not generate random seed");
6666 return false;
6667 }
6668 }
6669 else
6670 {
6671 char garbage;
6672
6673 if (sscanf(seed, "%" SCNu64 "%c", &iseed, &garbage) != 1)
6674 {
6675 pg_log_error("unrecognized random seed option \"%s\"", seed);
6676 pg_log_error_detail("Expecting an unsigned integer, \"time\" or \"rand\".");
6677 return false;
6678 }
6679 }
6680
6681 if (seed != NULL)
6682 pg_log_info("setting random seed to %" PRIu64, iseed);
6683
6684 random_seed = iseed;
6685
6686 /* Initialize base_random_sequence using seed */
6688
6689 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 7805 of file pgbench.c.

7807{
7809 alarm(seconds);
static void handle_sig_alarm(SIGNAL_ARGS)
Definition: pgbench.c:7799
#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 2128 of file pgbench.c.

2130{
2131 pv->type = PGBT_BOOLEAN;
2132 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 2144 of file pgbench.c.

2146{
2147 pv->type = PGBT_DOUBLE;
2148 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 2136 of file pgbench.c.

2138{
2139 pv->type = PGBT_INT;
2140 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 2120 of file pgbench.c.

2122{
2123 pv->type = PGBT_NULL;
2124 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 5587 of file pgbench.c.

5589{
5590 char *p = sql_command;
5591
5592 /* Skip any leading whitespace, as well as "--" style comments */
5593 for (;;)
5594 {
5595 if (isspace((unsigned char) *p))
5596 p++;
5597 else if (strncmp(p, "--", 2) == 0)
5598 {
5599 p = strchr(p, '\n');
5600 if (p == NULL)
5601 return NULL;
5602 p++;
5603 }
5604 else
5605 break;
5606 }
5607
5608 /* NULL if there's nothing but whitespace and comments */
5609 if (*p == '\0')
5610 return NULL;
5611
5612 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 8009 of file pgbench.c.

8011{
8012 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 1085 of file pgbench.c.

1087{
1088 char *end;
1089
1090 errno = 0;
1091 *dv = strtod(str, &end);
1092
1093 if (unlikely(errno != 0))
1094 {
1095 if (!errorOK)
1096 pg_log_error("value \"%s\" is out of range for type double", str);
1097 return false;
1098 }
1099
1100 if (unlikely(end == str || *end != '\0'))
1101 {
1102 if (!errorOK)
1103 pg_log_error("invalid input syntax for type double: \"%s\"", str);
1104 return false;
1105 }
1106 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 1014 of file pgbench.c.

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

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

5555{
5557
5559
5560 printfPQExpBuffer(&buf, "%s:%d: %s", source, lineno, msg);
5561 if (more != NULL)
5562 appendPQExpBuffer(&buf, " (%s)", more);
5563 if (column >= 0 && line == NULL)
5564 appendPQExpBuffer(&buf, " at column %d", column + 1);
5565 if (command != NULL)
5566 appendPQExpBuffer(&buf, " in command \"%s\"", command);
5567
5568 pg_log_error("%s", buf.data);
5569
5571
5572 if (line != NULL)
5573 {
5574 fprintf(stderr, "%s\n", line);
5575 if (column >= 0)
5576 fprintf(stderr, "%*c error found here\n", column + 1, '^');
5577 }
5578
5579 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 7483 of file pgbench.c.

7485{
7486 TState *thread = (TState *) arg;
7487 CState *state = thread->state;
7489 int nstate = thread->nstate;
7490 int remains = nstate; /* number of remaining clients */
7491 socket_set *sockets = alloc_socket_set(nstate);
7492 int64 thread_start,
7493 last_report,
7494 next_report;
7495 StatsData last,
7496 aggs;
7497
7498 /* open log file if requested */
7499 if (use_log)
7500 {
7501 char logpath[MAXPGPATH];
7502 char *prefix = logfile_prefix ? logfile_prefix : "pgbench_log";
7503
7504 if (thread->tid == 0)
7505 snprintf(logpath, sizeof(logpath), "%s.%d", prefix, main_pid);
7506 else
7507 snprintf(logpath, sizeof(logpath), "%s.%d.%d", prefix, main_pid, thread->tid);
7508
7509 thread->logfile = fopen(logpath, "w");
7510
7511 if (thread->logfile == NULL)
7512 pg_fatal("could not open logfile \"%s\": %m", logpath);
7513 }
7514
7515 /* explicitly initialize the state machines */
7516 for (int i = 0; i < nstate; i++)
7518
7519 /* READY */
7521
7522 thread_start = pg_time_now();
7523 thread->started_time = thread_start;
7524 thread->conn_duration = 0;
7525 last_report = thread_start;
7526 next_report = last_report + (int64) 1000000 * progress;
7527
7528 /* STEADY */
7529 if (!is_connect)
7530 {
7531 /* make connections to the database before starting */
7532 for (int i = 0; i < nstate; i++)
7533 {
7534 if ((state[i].con = doConnect()) == NULL)
7535 {
7536 /* coldly abort on initial connection failure */
7537 pg_fatal("could not create connection for client %d",
7538 state[i].id);
7539 }
7540 }
7541 }
7542
7543 /* GO */
7545
7546 start = pg_time_now();
7547 thread->bench_start = start;
7548 thread->throttle_trigger = start;
7549
7550 /*
7551 * The log format currently has Unix epoch timestamps with whole numbers
7552 * of seconds. Round the first aggregate's start time down to the nearest
7553 * Unix epoch second (the very first aggregate might really have started a
7554 * fraction of a second later, but later aggregates are measured from the
7555 * whole number time that is actually logged).
7556 */
7557 initStats(&aggs, (start + epoch_shift) / 1000000 * 1000000);
7558 last = aggs;
7559
7560 /* loop till all clients have terminated */
7561 while (remains > 0)
7562 {
7563 int nsocks; /* number of sockets to be waited for */
7564 pg_time_usec_t min_usec;
7565 pg_time_usec_t now = 0; /* set this only if needed */
7566
7567 /*
7568 * identify which client sockets should be checked for input, and
7569 * compute the nearest time (if any) at which we need to wake up.
7570 */
7571 clear_socket_set(sockets);
7572 nsocks = 0;
7573 min_usec = PG_INT64_MAX;
7574 for (int i = 0; i < nstate; i++)
7575 {
7576 CState *st = &state[i];
7577
7578 if (st->state == CSTATE_SLEEP || st->state == CSTATE_THROTTLE)
7579 {
7580 /* a nap from the script, or under throttling */
7581 pg_time_usec_t this_usec;
7582
7583 /* get current time if needed */
7585
7586 /* min_usec should be the minimum delay across all clients */
7587 this_usec = (st->state == CSTATE_SLEEP ?
7588 st->sleep_until : st->txn_scheduled) - now;
7589 if (min_usec > this_usec)
7590 min_usec = this_usec;
7591 }
7592 else if (st->state == CSTATE_WAIT_RESULT ||
7594 {
7595 /*
7596 * waiting for result from server - nothing to do unless the
7597 * socket is readable
7598 */
7599 int sock = PQsocket(st->con);
7600
7601 if (sock < 0)
7602 {
7603 pg_log_error("invalid socket: %s", PQerrorMessage(st->con));
7604 goto done;
7605 }
7606
7607 add_socket_to_set(sockets, sock, nsocks++);
7608 }
7609 else if (st->state != CSTATE_ABORTED &&
7610 st->state != CSTATE_FINISHED)
7611 {
7612 /*
7613 * This client thread is ready to do something, so we don't
7614 * want to wait. No need to examine additional clients.
7615 */
7616 min_usec = 0;
7617 break;
7618 }
7619 }
7620
7621 /* also wake up to print the next progress report on time */
7622 if (progress && min_usec > 0 && thread->tid == 0)
7623 {
7625
7626 if (now >= next_report)
7627 min_usec = 0;
7628 else if ((next_report - now) < min_usec)
7629 min_usec = next_report - now;
7630 }
7631
7632 /*
7633 * If no clients are ready to execute actions, sleep until we receive
7634 * data on some client socket or the timeout (if any) elapses.
7635 */
7636 if (min_usec > 0)
7637 {
7638 int rc = 0;
7639
7640 if (min_usec != PG_INT64_MAX)
7641 {
7642 if (nsocks > 0)
7643 {
7644 rc = wait_on_socket_set(sockets, min_usec);
7645 }
7646 else /* nothing active, simple sleep */
7647 {
7648 pg_usleep(min_usec);
7649 }
7650 }
7651 else /* no explicit delay, wait without timeout */
7652 {
7653 rc = wait_on_socket_set(sockets, 0);
7654 }
7655
7656 if (rc < 0)
7657 {
7658 if (errno == EINTR)
7659 {
7660 /* On EINTR, go back to top of loop */
7661 continue;
7662 }
7663 /* must be something wrong */
7664 pg_log_error("%s() failed: %m", SOCKET_WAIT_METHOD);
7665 goto done;
7666 }
7667 }
7668 else
7669 {
7670 /* min_usec <= 0, i.e. something needs to be executed now */
7671
7672 /* If we didn't wait, don't try to read any data */
7673 clear_socket_set(sockets);
7674 }
7675
7676 /* ok, advance the state machine of each connection */
7677 nsocks = 0;
7678 for (int i = 0; i < nstate; i++)
7679 {
7680 CState *st = &state[i];
7681
7682 if (st->state == CSTATE_WAIT_RESULT ||
7684 {
7685 /* don't call advanceConnectionState unless data is available */
7686 int sock = PQsocket(st->con);
7687
7688 if (sock < 0)
7689 {
7690 pg_log_error("invalid socket: %s", PQerrorMessage(st->con));
7691 goto done;
7692 }
7693
7694 if (!socket_has_input(sockets, sock, nsocks++))
7695 continue;
7696 }
7697 else if (st->state == CSTATE_FINISHED ||
7698 st->state == CSTATE_ABORTED)
7699 {
7700 /* this client is done, no need to consider it anymore */
7701 continue;
7702 }
7703
7704 advanceConnectionState(thread, st, &aggs);
7705
7706 /*
7707 * If --exit-on-abort is used, the program is going to exit when
7708 * any client is aborted.
7709 */
7710 if (exit_on_abort && st->state == CSTATE_ABORTED)
7711 goto done;
7712
7713 /*
7714 * If advanceConnectionState changed client to finished state,
7715 * that's one fewer client that remains.
7716 */
7717 else if (st->state == CSTATE_FINISHED ||
7718 st->state == CSTATE_ABORTED)
7719 remains--;
7720 }
7721
7722 /* progress report is made by thread 0 for all threads */
7723 if (progress && thread->tid == 0)
7724 {
7725 pg_time_usec_t now2 = pg_time_now();
7726
7727 if (now2 >= next_report)
7728 {
7729 /*
7730 * Horrible hack: this relies on the thread pointer we are
7731 * passed to be equivalent to threads[0], that is the first
7732 * entry of the threads array. That is why this MUST be done
7733 * by thread 0 and not any other.
7734 */
7735 printProgressReport(thread, thread_start, now2,
7736 &last, &last_report);
7737
7738 /*
7739 * Ensure that the next report is in the future, in case
7740 * pgbench/postgres got stuck somewhere.
7741 */
7742 do
7743 {
7744 next_report += (int64) 1000000 * progress;
7745 } while (now2 >= next_report);
7746 }
7747 }
7748 }
7749
7750done:
7751 if (exit_on_abort)
7752 {
7753 /*
7754 * Abort if any client is not finished, meaning some error occurred.
7755 */
7756 for (int i = 0; i < nstate; i++)
7757 {
7758 if (state[i].state != CSTATE_FINISHED)
7759 {
7760 pg_log_error("Run was aborted due to an error in thread %d",
7761 thread->tid);
7762 exit(2);
7763 }
7764 }
7765 }
7766
7767 disconnect_all(state, nstate);
7768
7769 if (thread->logfile)
7770 {
7771 if (agg_interval > 0)
7772 {
7773 /* log aggregated but not yet reported transactions */
7774 doLog(thread, state, &aggs, false, 0, 0);
7775 }
7776 fclose(thread->logfile);
7777 thread->logfile = NULL;
7778 }
7779 free_socket_set(sockets);
#define PG_INT64_MAX
Definition: c.h:597
int PQsocket(const PGconn *conn)
Definition: fe-connect.c:7705
#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:7954
static void clear_socket_set(socket_set *sa)
Definition: pgbench.c:7960
static void add_socket_to_set(socket_set *sa, int fd, int idx)
Definition: pgbench.c:7967
#define THREAD_FUNC_RETURN
Definition: pgbench.c:146
static void advanceConnectionState(TState *thread, CState *st, StatsData *agg)
Definition: pgbench.c:3644
static void printProgressReport(TState *threads, int64 test_start, pg_time_usec_t now, StatsData *last, int64 *last_report)
Definition: pgbench.c:6282
static bool socket_has_input(socket_set *sa, int fd, int idx)
Definition: pgbench.c:8009
static int wait_on_socket_set(socket_set *sa, int64 usecs)
Definition: pgbench.c:7992
static socket_set * alloc_socket_set(int count)
Definition: pgbench.c:7948
void pg_usleep(long microsec)
Definition: signal.c:53
pg_time_usec_t started_time
Definition: pgbench.c:667
#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 1542 of file pgbench.c.

1544{
1545 PGresult *res;
1546
1547 res = PQexec(con, sql);
1548 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1549 {
1550 pg_log_error("%s", PQerrorMessage(con));
1551 pg_log_error_detail("(ignoring this error and continuing anyway)");
1552 }
1553 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 896 of file pgbench.c.

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

1766{
1767 const unsigned char *ptr = (const unsigned char *) name;
1768
1769 /* Mustn't be zero-length */
1770 if (*ptr == '\0')
1771 return false;
1772
1773 /* must not start with [0-9] */
1774 if (IS_HIGHBIT_SET(*ptr) ||
1775 strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1776 "_", *ptr) != NULL)
1777 ptr++;
1778 else
1779 return false;
1780
1781 /* remaining characters can include [0-9] */
1782 while (*ptr)
1783 {
1784 if (IS_HIGHBIT_SET(*ptr) ||
1785 strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1786 "_0123456789", *ptr) != NULL)
1787 ptr++;
1788 else
1789 return false;
1790 }
1791
1792 return true;

References IS_HIGHBIT_SET, and name.

Referenced by lookupCreateVariable().

◆ valueTruth()

static bool valueTruth ( PgBenchValue pval)
static

Definition at line 2050 of file pgbench.c.

2052{
2053 switch (pval->type)
2054 {
2055 case PGBT_NULL:
2056 return false;
2057 case PGBT_BOOLEAN:
2058 return pval->u.bval;
2059 case PGBT_INT:
2060 return pval->u.ival != 0;
2061 case PGBT_DOUBLE:
2062 return pval->u.dval != 0.0;
2063 default:
2064 /* internal error, unexpected type */
2065 Assert(0);
2066 return false;
2067 }

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

2010{
2011 if (pval->type == PGBT_NO_VALUE)
2012 return "none";
2013 else if (pval->type == PGBT_NULL)
2014 return "null";
2015 else if (pval->type == PGBT_INT)
2016 return "int";
2017 else if (pval->type == PGBT_DOUBLE)
2018 return "double";
2019 else if (pval->type == PGBT_BOOLEAN)
2020 return "boolean";
2021 else
2022 {
2023 /* internal error, should never get there */
2024 Assert(false);
2025 return NULL;
2026 }

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

7994{
7995 if (usecs > 0)
7996 {
7997 struct timeval timeout;
7998
7999 timeout.tv_sec = usecs / 1000000;
8000 timeout.tv_usec = usecs % 1000000;
8001 return select(sa->maxfd + 1, &sa->fds, NULL, NULL, &timeout);
8002 }
8003 else
8004 {
8005 return select(sa->maxfd + 1, &sa->fds, NULL, NULL, NULL);
8006 }
#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 478 of file pgbench.c.

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

◆ builtin_script

const BuiltinScript builtin_script[]
static

Definition at line 781 of file pgbench.c.

Referenced by findBuiltin(), and listAvailableScripts().

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

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

◆ exit_on_abort

bool exit_on_abort = false
static

Definition at line 771 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 766 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 847 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 715 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 767 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 769 of file pgbench.c.

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