PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
pgbench.c File Reference
#include "postgres_fe.h"
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <signal.h>
#include <time.h>
#include <sys/resource.h>
#include <sys/select.h>
#include "catalog/pg_class_d.h"
#include "common/int.h"
#include "common/logging.h"
#include "common/pg_prng.h"
#include "common/string.h"
#include "common/username.h"
#include "fe_utils/cancel.h"
#include "fe_utils/conditional.h"
#include "fe_utils/option_utils.h"
#include "fe_utils/string_utils.h"
#include "getopt_long.h"
#include "libpq-fe.h"
#include "pgbench.h"
#include "port/pg_bitutils.h"
#include "portability/instr_time.h"
#include "port/pg_pthread.h"
Include dependency graph for pgbench.c:

Go to the source code of this file.

Data Structures

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

Macros

#define POLL_USING_SELECT
 
#define M_PI   3.14159265358979323846
 
#define ERRCODE_T_R_SERIALIZATION_FAILURE   "40001"
 
#define ERRCODE_T_R_DEADLOCK_DETECTED   "40P01"
 
#define ERRCODE_UNDEFINED_TABLE   "42P01"
 
#define FNV_PRIME   UINT64CONST(0x100000001b3)
 
#define FNV_OFFSET_BASIS   UINT64CONST(0xcbf29ce484222325)
 
#define MM2_MUL   UINT64CONST(0xc6a4a7935bd1e995)
 
#define MM2_MUL_TIMES_8   UINT64CONST(0x35253c9ade8f4ca8)
 
#define MM2_ROT   47
 
#define SOCKET_WAIT_METHOD   "select"
 
#define THREAD_T   pthread_t
 
#define THREAD_FUNC_RETURN_TYPE   void *
 
#define THREAD_FUNC_RETURN   return NULL
 
#define THREAD_FUNC_CC
 
#define THREAD_CREATE(handle, function, arg)    pthread_create((handle), NULL, (function), (arg))
 
#define THREAD_JOIN(handle)    pthread_join((handle), NULL)
 
#define THREAD_BARRIER_T   pthread_barrier_t
 
#define THREAD_BARRIER_INIT(barrier, n)    pthread_barrier_init((barrier), NULL, (n))
 
#define THREAD_BARRIER_WAIT(barrier)   pthread_barrier_wait((barrier))
 
#define THREAD_BARRIER_DESTROY(barrier)   pthread_barrier_destroy((barrier))
 
#define DEFAULT_INIT_STEPS   "dtgvp" /* default -I setting */
 
#define ALL_INIT_STEPS   "dtgGvpf" /* all possible steps */
 
#define LOG_STEP_SECONDS   5 /* seconds between log messages */
 
#define DEFAULT_NXACTS   10 /* default nxacts */
 
#define MIN_GAUSSIAN_PARAM   2.0 /* minimum parameter for gauss */
 
#define MIN_ZIPFIAN_PARAM   1.001 /* minimum parameter for zipfian */
 
#define MAX_ZIPFIAN_PARAM   1000.0 /* maximum parameter for zipfian */
 
#define nbranches
 
#define ntellers   10
 
#define naccounts   100000
 
#define SCALE_32BIT_THRESHOLD   20000
 
#define WSEP   '@' /* weight separator */
 
#define VARIABLES_ALLOC_MARGIN   8
 
#define MAX_SCRIPTS   128 /* max number of SQL scripts allowed */
 
#define SHELL_COMMAND_SIZE   256 /* maximum size allowed for shell command */
 
#define SQL_COMMAND   1
 
#define META_COMMAND   2
 
#define MAX_ARGS   256
 
#define PG_TIME_GET_DOUBLE(t)   (0.000001 * (t))
 
#define PARAMS_ARRAY_SIZE   7
 
#define MAX_FARGS   16
 
#define COMMANDS_ALLOC_NUM   128
 

Typedefs

typedef struct socket_set socket_set
 
typedef struct SimpleStats SimpleStats
 
typedef int64 pg_time_usec_t
 
typedef struct StatsData StatsData
 
typedef enum EStatus EStatus
 
typedef enum TStatus TStatus
 
typedef enum MetaCommand MetaCommand
 
typedef enum QueryMode QueryMode
 
typedef struct Command Command
 
typedef struct ParsedScript ParsedScript
 
typedef struct BuiltinScript BuiltinScript
 
typedef void(* initRowMethod) (PQExpBufferData *sql, int64 curr)
 

Enumerations

enum  partition_method_t { PART_NONE , PART_RANGE , PART_HASH }
 
enum  EStatus {
  ESTATUS_NO_ERROR = 0 , ESTATUS_META_COMMAND_ERROR , ESTATUS_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, const char *source)
 
static void free_command (Command *command)
 
static void postprocess_sql_command (Command *my_command)
 
static Commandprocess_backslash_command (PsqlScanState sstate, const char *source, 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 7933 of file pgbench.c.

7935{
7936 /* See connect_slot() for background on this code. */
7937#ifdef WIN32
7938 if (sa->fds.fd_count + 1 >= FD_SETSIZE)
7939 {
7940 pg_log_error("too many concurrent database clients for this platform: %d",
7941 sa->fds.fd_count + 1);
7942 exit(1);
7943 }
7944#else
7945 if (fd < 0 || fd >= FD_SETSIZE)
7946 {
7947 pg_log_error("socket file descriptor out of range for select(): %d",
7948 fd);
7949 pg_log_error_hint("Try fewer concurrent database clients.");
7950 exit(1);
7951 }
7952#endif
7953 FD_SET(fd, &sa->fds);
7954 if (fd > sa->maxfd)
7955 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 6227 of file pgbench.c.

6229{
6230 if (script->commands == NULL || script->commands[0] == NULL)
6231 pg_fatal("empty command list for script \"%s\"", script->desc);
6232
6233 if (num_scripts >= MAX_SCRIPTS)
6234 pg_fatal("at most %d SQL scripts are allowed", MAX_SCRIPTS);
6235
6236 CheckConditional(script);
6237
6238 sql_script[num_scripts] = *script;
6239 num_scripts++;
static void CheckConditional(const ParsedScript *ps)
Definition: pgbench.c:5885
#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 3610 of file pgbench.c.

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

7916{
7917 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 3090 of file pgbench.c.

3092{
3093 Assert(st->prepared == NULL);
3094
3095 st->prepared = pg_malloc(sizeof(bool *) * num_scripts);
3096 for (int i = 0; i < num_scripts; i++)
3097 {
3098 ParsedScript *script = &sql_script[i];
3099 int numcmds;
3100
3101 for (numcmds = 0; script->commands[numcmds] != NULL; numcmds++)
3102 ;
3103 st->prepared[i] = pg_malloc0(sizeof(bool) * numcmds);
3104 }
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 3246 of file pgbench.c.

3248{
3249 return (estatus == ESTATUS_SERIALIZATION_ERROR ||
3250 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 5885 of file pgbench.c.

5887{
5888 /* statically check conditional structure */
5890 int i;
5891
5892 for (i = 0; ps->commands[i] != NULL; i++)
5893 {
5894 Command *cmd = ps->commands[i];
5895
5896 if (cmd->type == META_COMMAND)
5897 {
5898 switch (cmd->meta)
5899 {
5900 case META_IF:
5902 break;
5903 case META_ELIF:
5905 ConditionError(ps->desc, i + 1, "\\elif without matching \\if");
5907 ConditionError(ps->desc, i + 1, "\\elif after \\else");
5908 break;
5909 case META_ELSE:
5911 ConditionError(ps->desc, i + 1, "\\else without matching \\if");
5913 ConditionError(ps->desc, i + 1, "\\else after \\else");
5915 break;
5916 case META_ENDIF:
5917 if (!conditional_stack_pop(cs))
5918 ConditionError(ps->desc, i + 1, "\\endif without matching \\if");
5919 break;
5920 default:
5921 /* ignore anything else... */
5922 break;
5923 }
5924 }
5925 }
5926 if (!conditional_stack_empty(cs))
5927 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:5875

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

5244{
5245 if (initialize_steps[0] == '\0')
5246 pg_fatal("no initialization steps specified");
5247
5248 for (const char *step = initialize_steps; *step != '\0'; step++)
5249 {
5250 if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
5251 {
5252 pg_log_error("unrecognized initialization step \"%c\"", *step);
5253 pg_log_error_detail("Allowed step characters are: \"" ALL_INIT_STEPS "\".");
5254 exit(1);
5255 }
5256 }
#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 3068 of file pgbench.c.

3070{
3071 int i = 0;
3072 int64 w;
3073
3074 if (num_scripts == 1)
3075 return 0;
3076
3077 w = getrand(&thread->ts_choose_rs, 0, total_weight - 1);
3078 do
3079 {
3080 w -= sql_script[i++].weight;
3081 } while (w >= 0);
3082
3083 return i - 1;
int64_t int64
Definition: c.h:499
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 7926 of file pgbench.c.

7928{
7929 FD_ZERO(&sa->fds);
7930 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::@35 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:1063

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{
3063 pg_log_info("client %d got an error in command %d (SQL) of script %d; %s",
3064 st->id, st->command, st->use_file, message);
#define pg_log_info(...)
Definition: logging.h:124

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

Referenced by readCommandResponse().

◆ commandFailed()

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

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

5877{
5878 pg_fatal("condition error in script \"%s\" command %d: %s",
5879 desc, cmdn, msg);

References pg_fatal.

Referenced by CheckConditional().

◆ create_sql_command()

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

Definition at line 5588 of file pgbench.c.

5590{
5591 Command *my_command;
5592 char *p = skip_sql_comments(buf->data);
5593
5594 if (p == NULL)
5595 return NULL;
5596
5597 /* Allocate and initialize Command structure */
5598 my_command = (Command *) pg_malloc(sizeof(Command));
5599 initPQExpBuffer(&my_command->lines);
5600 appendPQExpBufferStr(&my_command->lines, p);
5601 my_command->first_line = NULL; /* this is set later */
5602 my_command->type = SQL_COMMAND;
5603 my_command->meta = META_NONE;
5604 my_command->argc = 0;
5605 my_command->retries = 0;
5606 my_command->failures = 0;
5607 memset(my_command->argv, 0, sizeof(my_command->argv));
5608 my_command->varprefix = NULL; /* allocated later, if needed */
5609 my_command->expr = NULL;
5610 initSimpleStats(&my_command->stats);
5611 my_command->prepname = NULL; /* set later, if needed */
5612
5613 return my_command;
static char * buf
Definition: pg_test_fsync.c:72
static char * skip_sql_comments(char *sql_command)
Definition: pgbench.c:5553
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 4762 of file pgbench.c.

4764{
4765 PQExpBufferData query;
4766
4767 /* we must have to create some partitions */
4768 Assert(partitions > 0);
4769
4770 fprintf(stderr, "creating %d partitions...\n", partitions);
4771
4772 initPQExpBuffer(&query);
4773
4774 for (int p = 1; p <= partitions; p++)
4775 {
4777 {
4778 int64 part_size = (naccounts * (int64) scale + partitions - 1) / partitions;
4779
4780 printfPQExpBuffer(&query,
4781 "create%s table pgbench_accounts_%d\n"
4782 " partition of pgbench_accounts\n"
4783 " for values from (",
4784 unlogged_tables ? " unlogged" : "", p);
4785
4786 /*
4787 * For RANGE, we use open-ended partitions at the beginning and
4788 * end to allow any valid value for the primary key. Although the
4789 * actual minimum and maximum values can be derived from the
4790 * scale, it is more generic and the performance is better.
4791 */
4792 if (p == 1)
4793 appendPQExpBufferStr(&query, "minvalue");
4794 else
4795 appendPQExpBuffer(&query, INT64_FORMAT, (p - 1) * part_size + 1);
4796
4797 appendPQExpBufferStr(&query, ") to (");
4798
4799 if (p < partitions)
4800 appendPQExpBuffer(&query, INT64_FORMAT, p * part_size + 1);
4801 else
4802 appendPQExpBufferStr(&query, "maxvalue");
4803
4804 appendPQExpBufferChar(&query, ')');
4805 }
4806 else if (partition_method == PART_HASH)
4807 printfPQExpBuffer(&query,
4808 "create%s table pgbench_accounts_%d\n"
4809 " partition of pgbench_accounts\n"
4810 " for values with (modulus %d, remainder %d)",
4811 unlogged_tables ? " unlogged" : "", p,
4812 partitions, p - 1);
4813 else /* cannot get there */
4814 Assert(0);
4815
4816 /*
4817 * Per ddlinfo in initCreateTables, fillfactor is needed on table
4818 * pgbench_accounts.
4819 */
4820 appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4821
4822 executeStatement(con, query.data);
4823 }
4824
4825 termPQExpBuffer(&query);
#define INT64_FORMAT
Definition: c.h:520
#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 3495 of file pgbench.c.

3497{
3498 /* send a sync */
3499 if (!PQpipelineSync(st->con))
3500 {
3501 pg_log_error("client %d aborted: failed to send a pipeline sync",
3502 st->id);
3503 return 0;
3504 }
3505
3506 /* receive PGRES_PIPELINE_SYNC and null following it */
3507 for (;;)
3508 {
3509 PGresult *res = PQgetResult(st->con);
3510
3512 {
3513 PQclear(res);
3514 res = PQgetResult(st->con);
3515 Assert(res == NULL);
3516 break;
3517 }
3518 PQclear(res);
3519 }
3520
3521 /* exit pipeline */
3522 if (PQexitPipelineMode(st->con) != 1)
3523 {
3524 pg_log_error("client %d aborted: failed to exit pipeline mode for rolling back the failed transaction",
3525 st->id);
3526 return 0;
3527 }
3528 return 1;
int PQexitPipelineMode(PGconn *conn)
Definition: fe-exec.c:3073
int PQpipelineSync(PGconn *conn)
Definition: fe-exec.c:3272
@ PGRES_PIPELINE_SYNC
Definition: libpq-fe.h:139

References Assert(), CState::con, CState::id, 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 4728 of file pgbench.c.

4730{
4731 int i;
4732
4733 for (i = 0; i < length; i++)
4734 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:151
int PQconnectionNeedsPassword(const PGconn *conn)
Definition: fe-connect.c:7672
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:7556
void PQfinish(PGconn *conn)
Definition: fe-connect.c:5290
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:758
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 4569 of file pgbench.c.

4572{
4573 FILE *logfile = thread->logfile;
4575
4576 Assert(use_log);
4577
4578 /*
4579 * Skip the log entry if sampling is enabled and this row doesn't belong
4580 * to the random sample.
4581 */
4582 if (sample_rate != 0.0 &&
4584 return;
4585
4586 /* should we aggregate the results or not? */
4587 if (agg_interval > 0)
4588 {
4590
4591 /*
4592 * Loop until we reach the interval of the current moment, and print
4593 * any empty intervals in between (this may happen with very low tps,
4594 * e.g. --rate=0.1).
4595 */
4596
4597 while ((next = agg->start_time + agg_interval * INT64CONST(1000000)) <= now)
4598 {
4599 double lag_sum = 0.0;
4600 double lag_sum2 = 0.0;
4601 double lag_min = 0.0;
4602 double lag_max = 0.0;
4603 int64 skipped = 0;
4604 int64 serialization_failures = 0;
4605 int64 deadlock_failures = 0;
4606 int64 retried = 0;
4607 int64 retries = 0;
4608
4609 /* print aggregated report to logfile */
4610 fprintf(logfile, INT64_FORMAT " " INT64_FORMAT " %.0f %.0f %.0f %.0f",
4611 agg->start_time / 1000000, /* seconds since Unix epoch */
4612 agg->cnt,
4613 agg->latency.sum,
4614 agg->latency.sum2,
4615 agg->latency.min,
4616 agg->latency.max);
4617
4618 if (throttle_delay)
4619 {
4620 lag_sum = agg->lag.sum;
4621 lag_sum2 = agg->lag.sum2;
4622 lag_min = agg->lag.min;
4623 lag_max = agg->lag.max;
4624 }
4625 fprintf(logfile, " %.0f %.0f %.0f %.0f",
4626 lag_sum,
4627 lag_sum2,
4628 lag_min,
4629 lag_max);
4630
4631 if (latency_limit)
4632 skipped = agg->skipped;
4633 fprintf(logfile, " " INT64_FORMAT, skipped);
4634
4635 if (max_tries != 1)
4636 {
4637 retried = agg->retried;
4638 retries = agg->retries;
4639 }
4640 fprintf(logfile, " " INT64_FORMAT " " INT64_FORMAT, retried, retries);
4641
4643 {
4644 serialization_failures = agg->serialization_failures;
4645 deadlock_failures = agg->deadlock_failures;
4646 }
4648 serialization_failures,
4649 deadlock_failures);
4650
4651 fputc('\n', logfile);
4652
4653 /* reset data and move to next interval */
4654 initStats(agg, next);
4655 }
4656
4657 /* accumulate the current transaction */
4658 accumStats(agg, skipped, latency, lag, st->estatus, st->tries);
4659 }
4660 else
4661 {
4662 /* no, print raw transactions */
4663 if (!skipped && st->estatus == ESTATUS_NO_ERROR)
4664 fprintf(logfile, "%d " INT64_FORMAT " %.0f %d " INT64_FORMAT " "
4666 st->id, st->cnt, latency, st->use_file,
4667 now / 1000000, now % 1000000);
4668 else
4669 fprintf(logfile, "%d " INT64_FORMAT " %s %d " INT64_FORMAT " "
4671 st->id, st->cnt, getResultString(skipped, st->estatus),
4672 st->use_file, now / 1000000, now % 1000000);
4673
4674 if (throttle_delay)
4675 fprintf(logfile, " %.0f", lag);
4676 if (max_tries != 1)
4677 fprintf(logfile, " %u", st->tries - 1);
4678 fputc('\n', logfile);
4679 }
static int32 next
Definition: blutils.c:224
#define INT64CONST(x)
Definition: c.h:516
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:4538
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 3449 of file pgbench.c.

3451{
3453
3454 /* We can only retry serialization or deadlock errors. */
3455 if (!canRetryError(st->estatus))
3456 return false;
3457
3458 /*
3459 * We must have at least one option to limit the retrying of transactions
3460 * that got an error.
3461 */
3463
3464 /*
3465 * We cannot retry the error if we have reached the maximum number of
3466 * tries.
3467 */
3468 if (max_tries && st->tries >= max_tries)
3469 return false;
3470
3471 /*
3472 * We cannot retry the error if we spent too much time on this
3473 * transaction.
3474 */
3475 if (latency_limit)
3476 {
3478 if (*now - st->txn_scheduled > latency_limit)
3479 return false;
3480 }
3481
3482 /*
3483 * We cannot retry the error if the benchmark duration is over.
3484 */
3485 if (timer_exceeded)
3486 return false;
3487
3488 /* OK */
3489 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:975
#define Max(x, y)
Definition: c.h:969
#define PG_INT64_MIN
Definition: c.h:562
#define unlikely(x)
Definition: c.h:347
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
PgBenchValue constant
Definition: pgbench.h:115
char * varname
Definition: pgbench.h:118
PgBenchFunction function
Definition: pgbench.h:122
PgBenchExprType etype
Definition: pgbench.h:112
struct PgBenchExpr::@36::@37 variable
union PgBenchExpr::@36 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 3404 of file pgbench.c.

3406{
3407 char *var;
3408 int usec;
3409
3410 if (*argv[1] == ':')
3411 {
3412 if ((var = getVariable(variables, argv[1] + 1)) == NULL)
3413 {
3414 pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[1] + 1);
3415 return false;
3416 }
3417
3418 usec = atoi(var);
3419
3420 /* Raise an error if the value of a variable is not a number */
3421 if (usec == 0 && !isdigit((unsigned char) *var))
3422 {
3423 pg_log_error("%s: invalid sleep time \"%s\" for variable \"%s\"",
3424 argv[0], var, argv[1] + 1);
3425 return false;
3426 }
3427 }
3428 else
3429 usec = atoi(argv[1]);
3430
3431 if (argc > 2)
3432 {
3433 if (pg_strcasecmp(argv[2], "ms") == 0)
3434 usec *= 1000;
3435 else if (pg_strcasecmp(argv[2], "s") == 0)
3436 usec *= 1000000;
3437 }
3438 else
3439 usec *= 1000000;
3440
3441 *usecs = usec;
3442 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 4308 of file pgbench.c.

4310{
4311 Command *command = sql_script[st->use_file].commands[st->command];
4312 int argc;
4313 char **argv;
4314
4315 Assert(command != NULL && command->type == META_COMMAND);
4316
4317 argc = command->argc;
4318 argv = command->argv;
4319
4321 {
4323
4325
4326 printfPQExpBuffer(&buf, "client %d executing \\%s", st->id, argv[0]);
4327 for (int i = 1; i < argc; i++)
4328 appendPQExpBuffer(&buf, " %s", argv[i]);
4329
4330 pg_log_debug("%s", buf.data);
4331
4333 }
4334
4335 if (command->meta == META_SLEEP)
4336 {
4337 int usec;
4338
4339 /*
4340 * A \sleep doesn't execute anything, we just get the delay from the
4341 * argument, and enter the CSTATE_SLEEP state. (The per-command
4342 * latency will be recorded in CSTATE_SLEEP state, not here, after the
4343 * delay has elapsed.)
4344 */
4345 if (!evaluateSleep(&st->variables, argc, argv, &usec))
4346 {
4347 commandFailed(st, "sleep", "execution of meta-command failed");
4348 return CSTATE_ABORTED;
4349 }
4350
4352 st->sleep_until = (*now) + usec;
4353 return CSTATE_SLEEP;
4354 }
4355 else if (command->meta == META_SET)
4356 {
4357 PgBenchExpr *expr = command->expr;
4358 PgBenchValue result;
4359
4360 if (!evaluateExpr(st, expr, &result))
4361 {
4362 commandFailed(st, argv[0], "evaluation of meta-command failed");
4363 return CSTATE_ABORTED;
4364 }
4365
4366 if (!putVariableValue(&st->variables, argv[0], argv[1], &result))
4367 {
4368 commandFailed(st, "set", "assignment of meta-command failed");
4369 return CSTATE_ABORTED;
4370 }
4371 }
4372 else if (command->meta == META_IF)
4373 {
4374 /* backslash commands with an expression to evaluate */
4375 PgBenchExpr *expr = command->expr;
4376 PgBenchValue result;
4377 bool cond;
4378
4379 if (!evaluateExpr(st, expr, &result))
4380 {
4381 commandFailed(st, argv[0], "evaluation of meta-command failed");
4382 return CSTATE_ABORTED;
4383 }
4384
4385 cond = valueTruth(&result);
4387 }
4388 else if (command->meta == META_ELIF)
4389 {
4390 /* backslash commands with an expression to evaluate */
4391 PgBenchExpr *expr = command->expr;
4392 PgBenchValue result;
4393 bool cond;
4394
4396 {
4397 /* elif after executed block, skip eval and wait for endif. */
4399 return CSTATE_END_COMMAND;
4400 }
4401
4402 if (!evaluateExpr(st, expr, &result))
4403 {
4404 commandFailed(st, argv[0], "evaluation of meta-command failed");
4405 return CSTATE_ABORTED;
4406 }
4407
4408 cond = valueTruth(&result);
4411 }
4412 else if (command->meta == META_ELSE)
4413 {
4414 switch (conditional_stack_peek(st->cstack))
4415 {
4416 case IFSTATE_TRUE:
4418 break;
4419 case IFSTATE_FALSE: /* inconsistent if active */
4420 case IFSTATE_IGNORED: /* inconsistent if active */
4421 case IFSTATE_NONE: /* else without if */
4422 case IFSTATE_ELSE_TRUE: /* else after else */
4423 case IFSTATE_ELSE_FALSE: /* else after else */
4424 default:
4425 /* dead code if conditional check is ok */
4426 Assert(false);
4427 }
4428 }
4429 else if (command->meta == META_ENDIF)
4430 {
4433 }
4434 else if (command->meta == META_SETSHELL)
4435 {
4436 if (!runShellCommand(&st->variables, argv[1], argv + 2, argc - 2))
4437 {
4438 commandFailed(st, "setshell", "execution of meta-command failed");
4439 return CSTATE_ABORTED;
4440 }
4441 }
4442 else if (command->meta == META_SHELL)
4443 {
4444 if (!runShellCommand(&st->variables, NULL, argv + 1, argc - 1))
4445 {
4446 commandFailed(st, "shell", "execution of meta-command failed");
4447 return CSTATE_ABORTED;
4448 }
4449 }
4450 else if (command->meta == META_STARTPIPELINE)
4451 {
4452 /*
4453 * In pipeline mode, we use a workflow based on libpq pipeline
4454 * functions.
4455 */
4456 if (querymode == QUERY_SIMPLE)
4457 {
4458 commandFailed(st, "startpipeline", "cannot use pipeline mode with the simple query protocol");
4459 return CSTATE_ABORTED;
4460 }
4461
4462 /*
4463 * If we're in prepared-query mode, we need to prepare all the
4464 * commands that are inside the pipeline before we actually start the
4465 * pipeline itself. This solves the problem that running BEGIN
4466 * ISOLATION LEVEL SERIALIZABLE in a pipeline would fail due to a
4467 * snapshot having been acquired by the prepare within the pipeline.
4468 */
4471
4473 {
4474 commandFailed(st, "startpipeline", "already in pipeline mode");
4475 return CSTATE_ABORTED;
4476 }
4477 if (PQenterPipelineMode(st->con) == 0)
4478 {
4479 commandFailed(st, "startpipeline", "failed to enter pipeline mode");
4480 return CSTATE_ABORTED;
4481 }
4482 }
4483 else if (command->meta == META_SYNCPIPELINE)
4484 {
4486 {
4487 commandFailed(st, "syncpipeline", "not in pipeline mode");
4488 return CSTATE_ABORTED;
4489 }
4490 if (PQsendPipelineSync(st->con) == 0)
4491 {
4492 commandFailed(st, "syncpipeline", "failed to send a pipeline sync");
4493 return CSTATE_ABORTED;
4494 }
4495 st->num_syncs++;
4496 }
4497 else if (command->meta == META_ENDPIPELINE)
4498 {
4500 {
4501 commandFailed(st, "endpipeline", "not in pipeline mode");
4502 return CSTATE_ABORTED;
4503 }
4504 if (!PQpipelineSync(st->con))
4505 {
4506 commandFailed(st, "endpipeline", "failed to send a pipeline sync");
4507 return CSTATE_ABORTED;
4508 }
4509 st->num_syncs++;
4510 /* Now wait for the PGRES_PIPELINE_SYNC and exit pipeline mode there */
4511 /* collect pending results before getting out of pipeline mode */
4512 return CSTATE_WAIT_RESULT;
4513 }
4514
4515 /*
4516 * executing the expression or shell command might have taken a
4517 * non-negligible amount of time, so reset 'now'
4518 */
4519 *now = 0;
4520
4521 return CSTATE_END_COMMAND;
int PQenterPipelineMode(PGconn *conn)
Definition: fe-exec.c:3042
int PQsendPipelineSync(PGconn *conn)
Definition: fe-exec.c:3282
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:3143
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:3404
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
int num_syncs
Definition: pgbench.c:612

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:2262

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

6156{
6157 int i,
6158 found = 0,
6159 len = strlen(name);
6160 const BuiltinScript *result = NULL;
6161
6162 for (i = 0; i < lengthof(builtin_script); i++)
6163 {
6164 if (strncmp(builtin_script[i].name, name, len) == 0)
6165 {
6166 result = &builtin_script[i];
6167 found++;
6168 }
6169 }
6170
6171 /* ok, unambiguous result */
6172 if (found == 1)
6173 return result;
6174
6175 /* error cases */
6176 if (found == 0)
6177 pg_log_error("no builtin script found for name \"%s\"", name);
6178 else /* found > 1 */
6179 pg_log_error("ambiguous builtin name: %d builtin scripts found for prefix \"%s\"", found, name);
6180
6182 exit(1);
#define lengthof(array)
Definition: c.h:759
const void size_t len
static void listAvailableScripts(void)
Definition: pgbench.c:6142
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 7749 of file pgbench.c.

7751{
7752 if (st->con != NULL)
7753 {
7754 PQfinish(st->con);
7755 st->con = NULL;
7756 }

References CState::con, and PQfinish().

Referenced by advanceConnectionState(), and disconnect_all().

◆ free_command()

static void free_command ( Command command)
static

Definition at line 5617 of file pgbench.c.

5619{
5620 termPQExpBuffer(&command->lines);
5621 pg_free(command->first_line);
5622 for (int i = 0; i < command->argc; i++)
5623 pg_free(command->argv[i]);
5624 pg_free(command->varprefix);
5625
5626 /*
5627 * It should also free expr recursively, but this is currently not needed
5628 * as only gset commands (which do not have an expression) are freed.
5629 */
5630 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 7920 of file pgbench.c.

7922{
7923 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:2276
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3876
@ 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 4527 of file pgbench.c.

4529{
4530 return (stats->serialization_failures +
4531 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:498
#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:503
#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 4538 of file pgbench.c.

4540{
4541 if (skipped)
4542 return "skipped";
4543 else if (failures_detailed)
4544 {
4545 switch (estatus)
4546 {
4548 return "serialization";
4550 return "deadlock";
4551 default:
4552 /* internal error which should never occur */
4553 pg_fatal("unexpected error status: %d", estatus);
4554 }
4555 }
4556 else
4557 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 3229 of file pgbench.c.

3231{
3232 if (sqlState != NULL)
3233 {
3234 if (strcmp(sqlState, ERRCODE_T_R_SERIALIZATION_FAILURE) == 0)
3236 else if (strcmp(sqlState, ERRCODE_T_R_DEADLOCK_DETECTED) == 0)
3238 }
3239
#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 5347 of file pgbench.c.

5349{
5350 PGresult *res;
5351
5352 /*
5353 * get the scaling factor that should be same as count(*) from
5354 * pgbench_branches if this is not a custom query
5355 */
5356 res = PQexec(con, "select count(*) from pgbench_branches");
5357 if (PQresultStatus(res) != PGRES_TUPLES_OK)
5358 {
5359 char *sqlState = PQresultErrorField(res, PG_DIAG_SQLSTATE);
5360
5361 pg_log_error("could not count number of branches: %s", PQerrorMessage(con));
5362
5363 if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) == 0)
5364 pg_log_error_hint("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".",
5365 PQdb(con));
5366
5367 exit(1);
5368 }
5369 scale = atoi(PQgetvalue(res, 0, 0));
5370 if (scale < 0)
5371 pg_fatal("invalid count(*) from pgbench_branches: \"%s\"",
5372 PQgetvalue(res, 0, 0));
5373 PQclear(res);
5374
5375 /* warn if we override user-given -s switch */
5376 if (scale_given)
5377 pg_log_warning("scale option ignored, using count from pgbench_branches table (%d)",
5378 scale);
5379
5380 /*
5381 * Get the partition information for the first "pgbench_accounts" table
5382 * found in search_path.
5383 *
5384 * The result is empty if no "pgbench_accounts" is found.
5385 *
5386 * Otherwise, it always returns one row even if the table is not
5387 * partitioned (in which case the partition strategy is NULL).
5388 *
5389 * The number of partitions can be 0 even for partitioned tables, if no
5390 * partition is attached.
5391 *
5392 * We assume no partitioning on any failure, so as to avoid failing on an
5393 * old version without "pg_partitioned_table".
5394 */
5395 res = PQexec(con,
5396 "select o.n, p.partstrat, pg_catalog.count(i.inhparent) "
5397 "from pg_catalog.pg_class as c "
5398 "join pg_catalog.pg_namespace as n on (n.oid = c.relnamespace) "
5399 "cross join lateral (select pg_catalog.array_position(pg_catalog.current_schemas(true), n.nspname)) as o(n) "
5400 "left join pg_catalog.pg_partitioned_table as p on (p.partrelid = c.oid) "
5401 "left join pg_catalog.pg_inherits as i on (c.oid = i.inhparent) "
5402 "where c.relname = 'pgbench_accounts' and o.n is not null "
5403 "group by 1, 2 "
5404 "order by 1 asc "
5405 "limit 1");
5406
5407 if (PQresultStatus(res) != PGRES_TUPLES_OK)
5408 {
5409 /* probably an older version, coldly assume no partitioning */
5411 partitions = 0;
5412 }
5413 else if (PQntuples(res) == 0)
5414 {
5415 /*
5416 * This case is unlikely as pgbench already found "pgbench_branches"
5417 * above to compute the scale.
5418 */
5419 pg_log_error("no pgbench_accounts table found in \"search_path\"");
5420 pg_log_error_hint("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".", PQdb(con));
5421 exit(1);
5422 }
5423 else /* PQntuples(res) == 1 */
5424 {
5425 /* normal case, extract partition information */
5426 if (PQgetisnull(res, 0, 1))
5428 else
5429 {
5430 char *ps = PQgetvalue(res, 0, 1);
5431
5432 /* column must be there */
5433 Assert(ps != NULL);
5434
5435 if (strcmp(ps, "r") == 0)
5437 else if (strcmp(ps, "h") == 0)
5439 else
5440 {
5441 /* possibly a newer version with new partition method */
5442 pg_fatal("unexpected partition method: \"%s\"", ps);
5443 }
5444 }
5445
5446 partitions = atoi(PQgetvalue(res, 0, 2));
5447 }
5448
5449 PQclear(res);
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:7447
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3481
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3901
char * PQresultErrorField(const PGresult *res, int fieldcode)
Definition: fe-exec.c:3466
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:79
#define pg_log_warning(...)
Definition: pgfnames.c:24
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:52

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

3537{
3538 PGTransactionStatusType tx_status;
3539
3540 tx_status = PQtransactionStatus(con);
3541 switch (tx_status)
3542 {
3543 case PQTRANS_IDLE:
3544 return TSTATUS_IDLE;
3545 case PQTRANS_INTRANS:
3546 case PQTRANS_INERROR:
3547 return TSTATUS_IN_BLOCK;
3548 case PQTRANS_UNKNOWN:
3549 /* PQTRANS_UNKNOWN is expected given a broken connection */
3550 if (PQstatus(con) == CONNECTION_BAD)
3551 return TSTATUS_CONN_ERROR;
3552 /* fall through */
3553 case PQTRANS_ACTIVE:
3554 default:
3555
3556 /*
3557 * We cannot find out whether we are in a transaction block or
3558 * not. Internal error which should never occur.
3559 */
3560 pg_log_error("unexpected transaction status %d", tx_status);
3561 return TSTATUS_OTHER_ERROR;
3562 }
3563
3564 /* not reached */
3565 Assert(false);
3566 return TSTATUS_OTHER_ERROR;
PGTransactionStatusType PQtransactionStatus(const PGconn *conn)
Definition: fe-connect.c:7564
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 7765 of file pgbench.c.

7767{
7768 timer_exceeded = true;

References timer_exceeded.

Referenced by setalarm().

◆ initAccount()

static void initAccount ( PQExpBufferData sql,
int64  curr 
)
static

Definition at line 4954 of file pgbench.c.

4956{
4957 /* "filler" column defaults to blank padded empty string */
4959 INT64_FORMAT "\t" INT64_FORMAT "\t0\t\n",
4960 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 4936 of file pgbench.c.

4938{
4939 /* "filler" column uses NULL */
4941 INT64_FORMAT "\t0\t\\N\n",
4942 curr + 1);

References INT64_FORMAT, and printfPQExpBuffer().

Referenced by initGenerateDataClientSide().

◆ initCreateFKeys()

static void initCreateFKeys ( PGconn con)
static

Definition at line 5216 of file pgbench.c.

5218{
5219 static const char *const DDLKEYs[] = {
5220 "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
5221 "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
5222 "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
5223 "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
5224 "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
5225 };
5226 int i;
5227
5228 fprintf(stderr, "creating foreign keys...\n");
5229 for (i = 0; i < lengthof(DDLKEYs); i++)
5230 {
5231 executeStatement(con, DDLKEYs[i]);
5232 }

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

Referenced by runInitSteps().

◆ initCreatePKeys()

static void initCreatePKeys ( PGconn con)
static

Definition at line 5178 of file pgbench.c.

5180{
5181 static const char *const DDLINDEXes[] = {
5182 "alter table pgbench_branches add primary key (bid)",
5183 "alter table pgbench_tellers add primary key (tid)",
5184 "alter table pgbench_accounts add primary key (aid)"
5185 };
5186 int i;
5187 PQExpBufferData query;
5188
5189 fprintf(stderr, "creating primary keys...\n");
5190 initPQExpBuffer(&query);
5191
5192 for (i = 0; i < lengthof(DDLINDEXes); i++)
5193 {
5194 resetPQExpBuffer(&query);
5195 appendPQExpBufferStr(&query, DDLINDEXes[i]);
5196
5197 if (index_tablespace != NULL)
5198 {
5199 char *escape_tablespace;
5200
5201 escape_tablespace = PQescapeIdentifier(con, index_tablespace,
5202 strlen(index_tablespace));
5203 appendPQExpBuffer(&query, " using index tablespace %s", escape_tablespace);
5204 PQfreemem(escape_tablespace);
5205 }
5206
5207 executeStatement(con, query.data);
5208 }
5209
5210 termPQExpBuffer(&query);
void PQfreemem(void *ptr)
Definition: fe-exec.c:4032
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:4369
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 4831 of file pgbench.c.

4833{
4834 /*
4835 * Note: TPC-B requires at least 100 bytes per row, and the "filler"
4836 * fields in these table declarations were intended to comply with that.
4837 * The pgbench_accounts table complies with that because the "filler"
4838 * column is set to blank-padded empty string. But for all other tables
4839 * the columns default to NULL and so don't actually take any space. We
4840 * could fix that by giving them non-null default values. However, that
4841 * would completely break comparability of pgbench results with prior
4842 * versions. Since pgbench has never pretended to be fully TPC-B compliant
4843 * anyway, we stick with the historical behavior.
4844 */
4845 struct ddlinfo
4846 {
4847 const char *table; /* table name */
4848 const char *smcols; /* column decls if accountIDs are 32 bits */
4849 const char *bigcols; /* column decls if accountIDs are 64 bits */
4850 int declare_fillfactor;
4851 };
4852 static const struct ddlinfo DDLs[] = {
4853 {
4854 "pgbench_history",
4855 "tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)",
4856 "tid int,bid int,aid bigint,delta int,mtime timestamp,filler char(22)",
4857 0
4858 },
4859 {
4860 "pgbench_tellers",
4861 "tid int not null,bid int,tbalance int,filler char(84)",
4862 "tid int not null,bid int,tbalance int,filler char(84)",
4863 1
4864 },
4865 {
4866 "pgbench_accounts",
4867 "aid int not null,bid int,abalance int,filler char(84)",
4868 "aid bigint not null,bid int,abalance int,filler char(84)",
4869 1
4870 },
4871 {
4872 "pgbench_branches",
4873 "bid int not null,bbalance int,filler char(88)",
4874 "bid int not null,bbalance int,filler char(88)",
4875 1
4876 }
4877 };
4878 int i;
4879 PQExpBufferData query;
4880
4881 fprintf(stderr, "creating tables...\n");
4882
4883 initPQExpBuffer(&query);
4884
4885 for (i = 0; i < lengthof(DDLs); i++)
4886 {
4887 const struct ddlinfo *ddl = &DDLs[i];
4888
4889 /* Construct new create table statement. */
4890 printfPQExpBuffer(&query, "create%s table %s(%s)",
4891 (unlogged_tables && partition_method == PART_NONE) ? " unlogged" : "",
4892 ddl->table,
4893 (scale >= SCALE_32BIT_THRESHOLD) ? ddl->bigcols : ddl->smcols);
4894
4895 /* Partition pgbench_accounts table */
4896 if (partition_method != PART_NONE && strcmp(ddl->table, "pgbench_accounts") == 0)
4897 appendPQExpBuffer(&query,
4898 " partition by %s (aid)", PARTITION_METHOD[partition_method]);
4899 else if (ddl->declare_fillfactor)
4900 {
4901 /* fillfactor is only expected on actual tables */
4902 appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4903 }
4904
4905 if (tablespace != NULL)
4906 {
4907 char *escape_tablespace;
4908
4909 escape_tablespace = PQescapeIdentifier(con, tablespace, strlen(tablespace));
4910 appendPQExpBuffer(&query, " tablespace %s", escape_tablespace);
4911 PQfreemem(escape_tablespace);
4912 }
4913
4914 executeStatement(con, query.data);
4915 }
4916
4917 termPQExpBuffer(&query);
4918
4920 createPartitions(con);
static void createPartitions(PGconn *con)
Definition: pgbench.c:4762
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 4740 of file pgbench.c.

4742{
4743 fprintf(stderr, "dropping old tables...\n");
4744
4745 /*
4746 * We drop all the tables in one command, so that whether there are
4747 * foreign key dependencies or not doesn't matter.
4748 */
4749 executeStatement(con, "drop table if exists "
4750 "pgbench_accounts, "
4751 "pgbench_branches, "
4752 "pgbench_history, "
4753 "pgbench_tellers");

References executeStatement(), and fprintf.

Referenced by runInitSteps().

◆ initGenerateDataClientSide()

static void initGenerateDataClientSide ( PGconn con)
static

Definition at line 5088 of file pgbench.c.

5090{
5091 fprintf(stderr, "generating data (client-side)...\n");
5092
5093 /*
5094 * we do all of this in one transaction to enable the backend's
5095 * data-loading optimizations
5096 */
5097 executeStatement(con, "begin");
5098
5099 /* truncate away any old data */
5100 initTruncateTables(con);
5101
5102 /*
5103 * fill branches, tellers, accounts in that order in case foreign keys
5104 * already exist
5105 */
5106 initPopulateTable(con, "pgbench_branches", nbranches, initBranch);
5107 initPopulateTable(con, "pgbench_tellers", ntellers, initTeller);
5108 initPopulateTable(con, "pgbench_accounts", naccounts, initAccount);
5109
5110 executeStatement(con, "commit");
static void initTeller(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:4945
static void initBranch(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:4936
#define ntellers
Definition: pgbench.c:245
static void initTruncateTables(PGconn *con)
Definition: pgbench.c:4926
static void initAccount(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:4954
#define nbranches
Definition: pgbench.c:244
static void initPopulateTable(PGconn *con, const char *table, int64 base, initRowMethod init_row)
Definition: pgbench.c:4963

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

5122{
5123 PQExpBufferData sql;
5124
5125 fprintf(stderr, "generating data (server-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 initPQExpBuffer(&sql);
5137
5138 printfPQExpBuffer(&sql,
5139 "insert into pgbench_branches(bid,bbalance) "
5140 "select bid, 0 "
5141 "from generate_series(1, %d) as bid", nbranches * scale);
5142 executeStatement(con, sql.data);
5143
5144 printfPQExpBuffer(&sql,
5145 "insert into pgbench_tellers(tid,bid,tbalance) "
5146 "select tid, (tid - 1) / %d + 1, 0 "
5147 "from generate_series(1, %d) as tid", ntellers, ntellers * scale);
5148 executeStatement(con, sql.data);
5149
5150 printfPQExpBuffer(&sql,
5151 "insert into pgbench_accounts(aid,bid,abalance,filler) "
5152 "select aid, (aid - 1) / %d + 1, 0, '' "
5153 "from generate_series(1, " INT64_FORMAT ") as aid",
5155 executeStatement(con, sql.data);
5156
5157 termPQExpBuffer(&sql);
5158
5159 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 4963 of file pgbench.c.

4966{
4967 int n;
4968 int64 k;
4969 int chars = 0;
4970 int prev_chars = 0;
4971 PGresult *res;
4972 PQExpBufferData sql;
4973 char copy_statement[256];
4974 const char *copy_statement_fmt = "copy %s from stdin";
4975 int64 total = base * scale;
4976
4977 /* used to track elapsed time and estimate of the remaining time */
4979 int log_interval = 1;
4980
4981 /* Stay on the same line if reporting to a terminal */
4982 char eol = isatty(fileno(stderr)) ? '\r' : '\n';
4983
4984 initPQExpBuffer(&sql);
4985
4986 /* Use COPY with FREEZE on v14 and later for all ordinary tables */
4987 if ((PQserverVersion(con) >= 140000) &&
4988 get_table_relkind(con, table) == RELKIND_RELATION)
4989 copy_statement_fmt = "copy %s from stdin with (freeze on)";
4990
4991
4992 n = pg_snprintf(copy_statement, sizeof(copy_statement), copy_statement_fmt, table);
4993 if (n >= sizeof(copy_statement))
4994 pg_fatal("invalid buffer size: must be at least %d characters long", n);
4995 else if (n == -1)
4996 pg_fatal("invalid format string");
4997
4998 res = PQexec(con, copy_statement);
4999
5000 if (PQresultStatus(res) != PGRES_COPY_IN)
5001 pg_fatal("unexpected copy in result: %s", PQerrorMessage(con));
5002 PQclear(res);
5003
5004 start = pg_time_now();
5005
5006 for (k = 0; k < total; k++)
5007 {
5008 int64 j = k + 1;
5009
5010 init_row(&sql, k);
5011 if (PQputline(con, sql.data))
5012 pg_fatal("PQputline failed");
5013
5014 if (CancelRequested)
5015 break;
5016
5017 /*
5018 * If we want to stick with the original logging, print a message each
5019 * 100k inserted rows.
5020 */
5021 if ((!use_quiet) && (j % 100000 == 0))
5022 {
5023 double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
5024 double remaining_sec = ((double) total - j) * elapsed_sec / j;
5025
5026 chars = fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) of %s done (elapsed %.2f s, remaining %.2f s)",
5027 j, total,
5028 (int) ((j * 100) / total),
5029 table, elapsed_sec, remaining_sec);
5030
5031 /*
5032 * If the previous progress message is longer than the current
5033 * one, add spaces to the current line to fully overwrite any
5034 * remaining characters from the previous message.
5035 */
5036 if (prev_chars > chars)
5037 fprintf(stderr, "%*c", prev_chars - chars, ' ');
5038 fputc(eol, stderr);
5039 prev_chars = chars;
5040 }
5041 /* let's not call the timing for each row, but only each 100 rows */
5042 else if (use_quiet && (j % 100 == 0))
5043 {
5044 double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
5045 double remaining_sec = ((double) total - j) * elapsed_sec / j;
5046
5047 /* have we reached the next interval (or end)? */
5048 if ((j == total) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS))
5049 {
5050 chars = fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) of %s done (elapsed %.2f s, remaining %.2f s)",
5051 j, total,
5052 (int) ((j * 100) / total),
5053 table, elapsed_sec, remaining_sec);
5054
5055 /*
5056 * If the previous progress message is longer than the current
5057 * one, add spaces to the current line to fully overwrite any
5058 * remaining characters from the previous message.
5059 */
5060 if (prev_chars > chars)
5061 fprintf(stderr, "%*c", prev_chars - chars, ' ');
5062 fputc(eol, stderr);
5063 prev_chars = chars;
5064
5065 /* skip to the next interval */
5066 log_interval = (int) ceil(elapsed_sec / LOG_STEP_SECONDS);
5067 }
5068 }
5069 }
5070
5071 if (chars != 0 && eol != '\n')
5072 fprintf(stderr, "%*c\r", chars, ' '); /* Clear the current line */
5073
5074 if (PQputline(con, "\\.\n"))
5075 pg_fatal("very last PQputline failed");
5076 if (PQendcopy(con))
5077 pg_fatal("PQendcopy failed");
5078
5079 termPQExpBuffer(&sql);
volatile sig_atomic_t CancelRequested
Definition: cancel.c:59
int PQserverVersion(const PGconn *conn)
Definition: fe-connect.c:7609
int PQendcopy(PGconn *conn)
Definition: fe-exec.c:2949
int PQputline(PGconn *conn, const char *string)
Definition: fe-exec.c:2918
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 4945 of file pgbench.c.

4947{
4948 /* "filler" column uses NULL */
4950 INT64_FORMAT "\t" INT64_FORMAT "\t0\t\\N\n",
4951 curr + 1, curr / ntellers + 1);

References INT64_FORMAT, ntellers, and printfPQExpBuffer().

Referenced by initGenerateDataClientSide().

◆ initTruncateTables()

static void initTruncateTables ( PGconn con)
static

Definition at line 4926 of file pgbench.c.

4928{
4929 executeStatement(con, "truncate table "
4930 "pgbench_accounts, "
4931 "pgbench_branches, "
4932 "pgbench_history, "
4933 "pgbench_tellers");

References executeStatement().

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

◆ initVacuum()

static void initVacuum ( PGconn con)
static

Definition at line 5165 of file pgbench.c.

5167{
5168 fprintf(stderr, "vacuuming...\n");
5169 executeStatement(con, "vacuum analyze pgbench_branches");
5170 executeStatement(con, "vacuum analyze pgbench_tellers");
5171 executeStatement(con, "vacuum analyze pgbench_accounts");
5172 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 6142 of file pgbench.c.

6144{
6145 int i;
6146
6147 fprintf(stderr, "Available builtin scripts:\n");
6148 for (i = 0; i < lengthof(builtin_script); i++)
6149 fprintf(stderr, " %13s: %s\n", builtin_script[i].name, builtin_script[i].desc);
6150 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 6658 of file pgbench.c.

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

5458{
5459 char *sql,
5460 *p;
5461
5462 cmd->argc = 1;
5463
5464 p = sql = pg_strdup(cmd->lines.data);
5465 while ((p = strchr(p, ':')) != NULL)
5466 {
5467 char var[13];
5468 char *name;
5469 int eaten;
5470
5471 name = parseVariable(p, &eaten);
5472 if (name == NULL)
5473 {
5474 while (*p == ':')
5475 {
5476 p++;
5477 }
5478 continue;
5479 }
5480
5481 /*
5482 * cmd->argv[0] is the SQL statement itself, so the max number of
5483 * arguments is one less than MAX_ARGS
5484 */
5485 if (cmd->argc >= MAX_ARGS)
5486 {
5487 pg_log_error("statement has too many arguments (maximum is %d): %s",
5488 MAX_ARGS - 1, cmd->lines.data);
5489 pg_free(name);
5490 return false;
5491 }
5492
5493 sprintf(var, "$%d", cmd->argc);
5494 p = replaceVariable(&sql, p, eaten, var);
5495
5496 cmd->argv[cmd->argc] = name;
5497 cmd->argc++;
5498 }
5499
5500 Assert(cmd->argv[0] == NULL);
5501 cmd->argv[0] = sql;
5502 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 5935 of file pgbench.c.

5937{
5939 PsqlScanState sstate;
5940 PQExpBufferData line_buf;
5941 int alloc_num;
5942 int index;
5943
5944#define COMMANDS_ALLOC_NUM 128
5945 alloc_num = COMMANDS_ALLOC_NUM;
5946
5947 /* Initialize all fields of ps */
5948 ps.desc = desc;
5949 ps.weight = weight;
5950 ps.commands = (Command **) pg_malloc(sizeof(Command *) * alloc_num);
5951 initStats(&ps.stats, 0);
5952
5953 /* Prepare to parse script */
5955
5956 /*
5957 * Ideally, we'd scan scripts using the encoding and stdstrings settings
5958 * we get from a DB connection. However, without major rearrangement of
5959 * pgbench's argument parsing, we can't have a DB connection at the time
5960 * we parse scripts. Using SQL_ASCII (encoding 0) should work well enough
5961 * with any backend-safe encoding, though conceivably we could be fooled
5962 * if a script file uses a client-only encoding. We also assume that
5963 * stdstrings should be true, which is a bit riskier.
5964 */
5965 psql_scan_setup(sstate, script, strlen(script), 0, true);
5966
5967 initPQExpBuffer(&line_buf);
5968
5969 index = 0;
5970
5971 for (;;)
5972 {
5973 PsqlScanResult sr;
5974 promptStatus_t prompt;
5975 Command *command = NULL;
5976
5977 resetPQExpBuffer(&line_buf);
5978
5979 sr = psql_scan(sstate, &line_buf, &prompt);
5980
5981 /* If we collected a new SQL command, process that */
5982 command = create_sql_command(&line_buf, desc);
5983
5984 /* store new command */
5985 if (command)
5986 ps.commands[index++] = command;
5987
5988 /* If we reached a backslash, process that */
5989 if (sr == PSCAN_BACKSLASH)
5990 {
5991 int lineno;
5992 int start_offset;
5993
5994 /* Capture location of the backslash */
5995 psql_scan_get_location(sstate, &lineno, &start_offset);
5996 start_offset--;
5997
5998 command = process_backslash_command(sstate, desc,
5999 lineno, start_offset);
6000
6001 if (command)
6002 {
6003 /*
6004 * If this is gset or aset, merge into the preceding command.
6005 * (We don't use a command slot in this case).
6006 */
6007 if (command->meta == META_GSET || command->meta == META_ASET)
6008 {
6009 Command *cmd;
6010
6011 if (index == 0)
6012 syntax_error(desc, lineno, NULL, NULL,
6013 "\\gset must follow an SQL command",
6014 NULL, -1);
6015
6016 cmd = ps.commands[index - 1];
6017
6018 if (cmd->type != SQL_COMMAND ||
6019 cmd->varprefix != NULL)
6020 syntax_error(desc, lineno, NULL, NULL,
6021 "\\gset must follow an SQL command",
6022 cmd->first_line, -1);
6023
6024 /* get variable prefix */
6025 if (command->argc <= 1 || command->argv[1][0] == '\0')
6026 cmd->varprefix = pg_strdup("");
6027 else
6028 cmd->varprefix = pg_strdup(command->argv[1]);
6029
6030 /* update the sql command meta */
6031 cmd->meta = command->meta;
6032
6033 /* cleanup unused command */
6034 free_command(command);
6035
6036 continue;
6037 }
6038
6039 /* Attach any other backslash command as a new command */
6040 ps.commands[index++] = command;
6041 }
6042 }
6043
6044 /*
6045 * Since we used a command slot, allocate more if needed. Note we
6046 * always allocate one more in order to accommodate the NULL
6047 * terminator below.
6048 */
6049 if (index >= alloc_num)
6050 {
6051 alloc_num += COMMANDS_ALLOC_NUM;
6052 ps.commands = (Command **)
6053 pg_realloc(ps.commands, sizeof(Command *) * alloc_num);
6054 }
6055
6056 /* Done if we reached EOF */
6057 if (sr == PSCAN_INCOMPLETE || sr == PSCAN_EOL)
6058 break;
6059 }
6060
6061 ps.commands[index] = NULL;
6062
6063 addScript(&ps);
6064
6065 termPQExpBuffer(&line_buf);
6066 psql_scan_finish(sstate);
6067 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:5517
static Command * create_sql_command(PQExpBuffer buf, const char *source)
Definition: pgbench.c:5588
#define COMMANDS_ALLOC_NUM
static void free_command(Command *command)
Definition: pgbench.c:5617
static Command * process_backslash_command(PsqlScanState sstate, const char *source, int lineno, int start_offset)
Definition: pgbench.c:5674
static void addScript(const ParsedScript *script)
Definition: pgbench.c:6227
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 6190 of file pgbench.c.

6192{
6193 char *sep;
6194 int weight;
6195
6196 if ((sep = strrchr(option, WSEP)))
6197 {
6198 int namelen = sep - option;
6199 long wtmp;
6200 char *badp;
6201
6202 /* generate the script name */
6203 *script = pg_malloc(namelen + 1);
6204 strncpy(*script, option, namelen);
6205 (*script)[namelen] = '\0';
6206
6207 /* process digits of the weight spec */
6208 errno = 0;
6209 wtmp = strtol(sep + 1, &badp, 10);
6210 if (errno != 0 || badp == sep + 1 || *badp != '\0')
6211 pg_fatal("invalid weight specification: %s", sep);
6212 if (wtmp > INT_MAX || wtmp < 0)
6213 pg_fatal("weight specification out of range (0 .. %d): %lld",
6214 INT_MAX, (long long) wtmp);
6215 weight = wtmp;
6216 }
6217 else
6218 {
6219 *script = pg_strdup(option);
6220 weight = 1;
6221 }
6222
6223 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:1126

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

5639{
5640 char buffer[128];
5641 static int prepnum = 0;
5642
5643 Assert(my_command->type == SQL_COMMAND);
5644
5645 /* Save the first line for error display. */
5646 strlcpy(buffer, my_command->lines.data, sizeof(buffer));
5647 buffer[strcspn(buffer, "\n\r")] = '\0';
5648 my_command->first_line = pg_strdup(buffer);
5649
5650 /* Parse query and generate prepared statement name, if necessary */
5651 switch (querymode)
5652 {
5653 case QUERY_SIMPLE:
5654 my_command->argv[0] = my_command->lines.data;
5655 my_command->argc++;
5656 break;
5657 case QUERY_PREPARED:
5658 my_command->prepname = psprintf("P_%d", prepnum++);
5659 /* fall through */
5660 case QUERY_EXTENDED:
5661 if (!parseQuery(my_command))
5662 exit(1);
5663 break;
5664 default:
5665 exit(1);
5666 }
static bool parseQuery(Command *cmd)
Definition: pgbench.c:5456
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 3110 of file pgbench.c.

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

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

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

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

6251{
6252 /* generate and show report */
6253 pg_time_usec_t run = now - *last_report;
6254 int64 cnt,
6255 failures,
6256 retried;
6257 double tps,
6258 total_run,
6259 latency,
6260 sqlat,
6261 lag,
6262 stdev;
6263 char tbuf[315];
6264 StatsData cur;
6265
6266 /*
6267 * Add up the statistics of all threads.
6268 *
6269 * XXX: No locking. There is no guarantee that we get an atomic snapshot
6270 * of the transaction count and latencies, so these figures can well be
6271 * off by a small amount. The progress report's purpose is to give a
6272 * quick overview of how the test is going, so that shouldn't matter too
6273 * much. (If a read from a 64-bit integer is not atomic, you might get a
6274 * "torn" read and completely bogus latencies though!)
6275 */
6276 initStats(&cur, 0);
6277 for (int i = 0; i < nthreads; i++)
6278 {
6279 mergeSimpleStats(&cur.latency, &threads[i].stats.latency);
6280 mergeSimpleStats(&cur.lag, &threads[i].stats.lag);
6281 cur.cnt += threads[i].stats.cnt;
6282 cur.skipped += threads[i].stats.skipped;
6283 cur.retries += threads[i].stats.retries;
6284 cur.retried += threads[i].stats.retried;
6285 cur.serialization_failures +=
6287 cur.deadlock_failures += threads[i].stats.deadlock_failures;
6288 }
6289
6290 /* we count only actually executed transactions */
6291 cnt = cur.cnt - last->cnt;
6292 total_run = (now - test_start) / 1000000.0;
6293 tps = 1000000.0 * cnt / run;
6294 if (cnt > 0)
6295 {
6296 latency = 0.001 * (cur.latency.sum - last->latency.sum) / cnt;
6297 sqlat = 1.0 * (cur.latency.sum2 - last->latency.sum2) / cnt;
6298 stdev = 0.001 * sqrt(sqlat - 1000000.0 * latency * latency);
6299 lag = 0.001 * (cur.lag.sum - last->lag.sum) / cnt;
6300 }
6301 else
6302 {
6303 latency = sqlat = stdev = lag = 0;
6304 }
6305 failures = getFailures(&cur) - getFailures(last);
6306 retried = cur.retried - last->retried;
6307
6309 {
6310 snprintf(tbuf, sizeof(tbuf), "%.3f s",
6312 }
6313 else
6314 {
6315 /* round seconds are expected, but the thread may be late */
6316 snprintf(tbuf, sizeof(tbuf), "%.1f s", total_run);
6317 }
6318
6319 fprintf(stderr,
6320 "progress: %s, %.1f tps, lat %.3f ms stddev %.3f, " INT64_FORMAT " failed",
6321 tbuf, tps, latency, stdev, failures);
6322
6323 if (throttle_delay)
6324 {
6325 fprintf(stderr, ", lag %.3f ms", lag);
6326 if (latency_limit)
6327 fprintf(stderr, ", " INT64_FORMAT " skipped",
6328 cur.skipped - last->skipped);
6329 }
6330
6331 /* it can be non-zero only if max_tries is not equal to one */
6332 if (max_tries != 1)
6333 fprintf(stderr,
6334 ", " INT64_FORMAT " retried, " INT64_FORMAT " retries",
6335 retried, cur.retries - last->retries);
6336 fprintf(stderr, "\n");
6337
6338 *last = cur;
6339 *last_report = now;
struct cursor * cur
Definition: ecpg.c:29
static int64 getFailures(const StatsData *stats)
Definition: pgbench.c:4527

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

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

6344{
6345 if (ss->count > 0)
6346 {
6347 double latency = ss->sum / ss->count;
6348 double stddev = sqrt(ss->sum2 / ss->count - latency * latency);
6349
6350 printf("%s average = %.3f ms\n", prefix, 0.001 * latency);
6351 printf("%s stddev = %.3f ms\n", prefix, 0.001 * stddev);
6352 }

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

3574{
3575 static PQExpBuffer buf = NULL;
3576
3577 if (buf == NULL)
3579 else
3581
3582 printfPQExpBuffer(buf, "client %d ", st->id);
3583 appendPQExpBufferStr(buf, (is_retry ?
3584 "repeats the transaction after the error" :
3585 "ends the failed transaction"));
3586 appendPQExpBuffer(buf, " (try %u", st->tries);
3587
3588 /* Print max_tries if it is not unlimited. */
3589 if (max_tries)
3591
3592 /*
3593 * If the latency limit is used, print a percentage of the current
3594 * transaction latency from the latency limit.
3595 */
3596 if (latency_limit)
3597 {
3599 appendPQExpBuffer(buf, ", %.3f%% of the maximum time of tries was used",
3600 (100.0 * (*now - st->txn_scheduled) / latency_limit));
3601 }
3602 appendPQExpBufferStr(buf, ")\n");
3603
3604 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 6356 of file pgbench.c.

6358{
6359 int server_ver = PQserverVersion(con);
6360 int client_ver = PG_VERSION_NUM;
6361
6362 if (server_ver != client_ver)
6363 {
6364 const char *server_version;
6365 char sverbuf[32];
6366
6367 /* Try to get full text form, might include "devel" etc */
6368 server_version = PQparameterStatus(con, "server_version");
6369 /* Otherwise fall back on server_ver */
6370 if (!server_version)
6371 {
6372 formatPGVersionNumber(server_ver, true,
6373 sverbuf, sizeof(sverbuf));
6374 server_version = sverbuf;
6375 }
6376
6377 printf(_("%s (%s, server %s)\n"),
6378 "pgbench", PG_VERSION, server_version);
6379 }
6380 /* For version match, only print pgbench version */
6381 else
6382 printf("%s (%s)\n", "pgbench", PG_VERSION);
6383 fflush(stdout);
#define _(x)
Definition: elog.c:91
const char * PQparameterStatus(const PGconn *conn, const char *paramName)
Definition: fe-connect.c:7574
static int server_version
Definition: pg_dumpall.c:113
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 5674 of file pgbench.c.

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

6137{
6138 ParseScript(bi->script, bi->desc, weight);
static void ParseScript(const char *script, const char *desc, int weight)
Definition: pgbench.c:5935

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

6111{
6112 FILE *fd;
6113 char *buf;
6114
6115 /* Slurp the file contents into "buf" */
6116 if (strcmp(filename, "-") == 0)
6117 fd = stdin;
6118 else if ((fd = fopen(filename, "r")) == NULL)
6119 pg_fatal("could not open file \"%s\": %m", filename);
6120
6122
6123 if (ferror(fd))
6124 pg_fatal("could not read file \"%s\": %m", filename);
6125
6126 if (fd != stdin)
6127 fclose(fd);
6128
6129 ParseScript(buf, filename, weight);
6130
6131 free(buf);
static char * filename
Definition: pg_dumpall.c:123
static char * read_file_contents(FILE *fd)
Definition: pgbench.c:6076

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

4692{
4693 double latency = 0.0,
4694 lag = 0.0;
4695 bool detailed = progress || throttle_delay || latency_limit ||
4697
4698 if (detailed && !skipped && st->estatus == ESTATUS_NO_ERROR)
4699 {
4701
4702 /* compute latency & lag */
4703 latency = (*now) - st->txn_scheduled;
4704 lag = st->txn_begin - st->txn_scheduled;
4705 }
4706
4707 /* keep detailed thread stats */
4708 accumStats(&thread->stats, skipped, latency, lag, st->estatus, st->tries);
4709
4710 /* count transactions over the latency limit, if needed */
4711 if (latency_limit && latency > latency_limit)
4712 thread->latency_late++;
4713
4714 /* client stat is just counting */
4715 st->cnt++;
4716
4717 if (use_log)
4718 doLog(thread, st, agg, skipped, latency, lag);
4719
4720 /* XXX could use a mutex here, but we choose not to */
4721 if (per_script_stats)
4722 accumStats(&sql_script[st->use_file].stats, skipped, latency, lag,
4723 st->estatus, st->tries);
static void doLog(TState *thread, CState *st, StatsData *agg, bool skipped, double latency, double lag)
Definition: pgbench.c:4569

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 @165 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 6076 of file pgbench.c.

6078{
6079 char *buf;
6080 size_t buflen = BUFSIZ;
6081 size_t used = 0;
6082
6083 buf = (char *) pg_malloc(buflen);
6084
6085 for (;;)
6086 {
6087 size_t nread;
6088
6089 nread = fread(buf + used, 1, BUFSIZ, fd);
6090 used += nread;
6091 /* If fread() read less than requested, must be EOF or error */
6092 if (nread < BUFSIZ)
6093 break;
6094 /* Enlarge buf so we can read some more */
6095 buflen += BUFSIZ;
6096 buf = (char *) pg_realloc(buf, buflen);
6097 }
6098 /* There is surely room for a terminator */
6099 buf[used] = '\0';
6100
6101 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 3262 of file pgbench.c.

3264{
3265 PGresult *res;
3266 PGresult *next_res;
3267 int qrynum = 0;
3268
3269 /*
3270 * varprefix should be set only with \gset or \aset, and \endpipeline and
3271 * SQL commands do not need it.
3272 */
3273 Assert((meta == META_NONE && varprefix == NULL) ||
3274 ((meta == META_ENDPIPELINE) && varprefix == NULL) ||
3275 ((meta == META_GSET || meta == META_ASET) && varprefix != NULL));
3276
3277 res = PQgetResult(st->con);
3278
3279 while (res != NULL)
3280 {
3281 bool is_last;
3282
3283 /* peek at the next result to know whether the current is last */
3284 next_res = PQgetResult(st->con);
3285 is_last = (next_res == NULL);
3286
3287 switch (PQresultStatus(res))
3288 {
3289 case PGRES_COMMAND_OK: /* non-SELECT commands */
3290 case PGRES_EMPTY_QUERY: /* may be used for testing no-op overhead */
3291 if (is_last && meta == META_GSET)
3292 {
3293 pg_log_error("client %d script %d command %d query %d: expected one row, got %d",
3294 st->id, st->use_file, st->command, qrynum, 0);
3296 goto error;
3297 }
3298 break;
3299
3300 case PGRES_TUPLES_OK:
3301 if ((is_last && meta == META_GSET) || meta == META_ASET)
3302 {
3303 int ntuples = PQntuples(res);
3304
3305 if (meta == META_GSET && ntuples != 1)
3306 {
3307 /* under \gset, report the error */
3308 pg_log_error("client %d script %d command %d query %d: expected one row, got %d",
3309 st->id, st->use_file, st->command, qrynum, PQntuples(res));
3311 goto error;
3312 }
3313 else if (meta == META_ASET && ntuples <= 0)
3314 {
3315 /* coldly skip empty result under \aset */
3316 break;
3317 }
3318
3319 /* store results into variables */
3320 for (int fld = 0; fld < PQnfields(res); fld++)
3321 {
3322 char *varname = PQfname(res, fld);
3323
3324 /* allocate varname only if necessary, freed below */
3325 if (*varprefix != '\0')
3326 varname = psprintf("%s%s", varprefix, varname);
3327
3328 /* store last row result as a string */
3329 if (!putVariable(&st->variables, meta == META_ASET ? "aset" : "gset", varname,
3330 PQgetvalue(res, ntuples - 1, fld)))
3331 {
3332 /* internal error */
3333 pg_log_error("client %d script %d command %d query %d: error storing into variable %s",
3334 st->id, st->use_file, st->command, qrynum, varname);
3336 goto error;
3337 }
3338
3339 if (*varprefix != '\0')
3340 pg_free(varname);
3341 }
3342 }
3343 /* otherwise the result is simply thrown away by PQclear below */
3344 break;
3345
3347 pg_log_debug("client %d pipeline ending, ongoing syncs: %d",
3348 st->id, st->num_syncs);
3349 st->num_syncs--;
3350 if (st->num_syncs == 0 && PQexitPipelineMode(st->con) != 1)
3351 pg_log_error("client %d failed to exit pipeline mode: %s", st->id,
3352 PQerrorMessage(st->con));
3353 break;
3354
3356 case PGRES_FATAL_ERROR:
3359 if (canRetryError(st->estatus))
3360 {
3361 if (verbose_errors)
3363 goto error;
3364 }
3365 /* fall through */
3366
3367 default:
3368 /* anything else is unexpected */
3369 pg_log_error("client %d script %d aborted in command %d query %d: %s",
3370 st->id, st->use_file, st->command, qrynum,
3371 PQerrorMessage(st->con));
3372 goto error;
3373 }
3374
3375 PQclear(res);
3376 qrynum++;
3377 res = next_res;
3378 }
3379
3380 if (qrynum == 0)
3381 {
3382 pg_log_error("client %d command %d: no results", st->id, st->command);
3383 return false;
3384 }
3385
3386 return true;
3387
3388error:
3389 PQclear(res);
3390 PQclear(next_res);
3391 do
3392 {
3393 res = PQgetResult(st->con);
3394 PQclear(res);
3395 } while (res);
3396
3397 return false;
char * PQfname(const PGresult *res, int field_num)
Definition: fe-exec.c:3567
int PQnfields(const PGresult *res)
Definition: fe-exec.c:3489
@ PGRES_FATAL_ERROR
Definition: libpq-fe.h:136
@ 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:3229
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_EMPTY_QUERY, PGRES_FATAL_ERROR, PGRES_NONFATAL_ERROR, PGRES_PIPELINE_SYNC, PGRES_TUPLES_OK, PQclear(), PQerrorMessage(), PQexitPipelineMode(), PQfname(), PQgetResult(), PQgetvalue(), PQnfields(), PQntuples(), PQresultErrorField(), 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 5262 of file pgbench.c.

5264{
5265 PQExpBufferData stats;
5266 PGconn *con;
5267 const char *step;
5268 double run_time = 0.0;
5269 bool first = true;
5270
5271 initPQExpBuffer(&stats);
5272
5273 if ((con = doConnect()) == NULL)
5274 pg_fatal("could not create connection for initialization");
5275
5277 SetCancelConn(con);
5278
5279 for (step = initialize_steps; *step != '\0'; step++)
5280 {
5281 char *op = NULL;
5283
5284 switch (*step)
5285 {
5286 case 'd':
5287 op = "drop tables";
5288 initDropTables(con);
5289 break;
5290 case 't':
5291 op = "create tables";
5292 initCreateTables(con);
5293 break;
5294 case 'g':
5295 op = "client-side generate";
5297 break;
5298 case 'G':
5299 op = "server-side generate";
5301 break;
5302 case 'v':
5303 op = "vacuum";
5304 initVacuum(con);
5305 break;
5306 case 'p':
5307 op = "primary keys";
5308 initCreatePKeys(con);
5309 break;
5310 case 'f':
5311 op = "foreign keys";
5312 initCreateFKeys(con);
5313 break;
5314 case ' ':
5315 break; /* ignore */
5316 default:
5317 pg_log_error("unrecognized initialization step \"%c\"", *step);
5318 PQfinish(con);
5319 exit(1);
5320 }
5321
5322 if (op != NULL)
5323 {
5324 double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
5325
5326 if (!first)
5327 appendPQExpBufferStr(&stats, ", ");
5328 else
5329 first = false;
5330
5331 appendPQExpBuffer(&stats, "%s %.2f s", op, elapsed_sec);
5332
5333 run_time += elapsed_sec;
5334 }
5335 }
5336
5337 fprintf(stderr, "done in %.2f s (%s).\n", run_time, stats.data);
5339 PQfinish(con);
5340 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:5178
static void initDropTables(PGconn *con)
Definition: pgbench.c:4740
static void initGenerateDataServerSide(PGconn *con)
Definition: pgbench.c:5120
static void initCreateFKeys(PGconn *con)
Definition: pgbench.c:5216
static void initVacuum(PGconn *con)
Definition: pgbench.c:5165
static void initCreateTables(PGconn *con)
Definition: pgbench.c:4831
static void initGenerateDataClientSide(PGconn *con)
Definition: pgbench.c:5088

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

3178{
3179 int r;
3180
3181 if (querymode == QUERY_SIMPLE)
3182 {
3183 char *sql;
3184
3185 sql = pg_strdup(command->argv[0]);
3186 sql = assignVariables(&st->variables, sql);
3187
3188 pg_log_debug("client %d sending %s", st->id, sql);
3189 r = PQsendQuery(st->con, sql);
3190 free(sql);
3191 }
3192 else if (querymode == QUERY_EXTENDED)
3193 {
3194 const char *sql = command->argv[0];
3195 const char *params[MAX_ARGS];
3196
3197 getQueryParams(&st->variables, command, params);
3198
3199 pg_log_debug("client %d sending %s", st->id, sql);
3200 r = PQsendQueryParams(st->con, sql, command->argc - 1,
3201 NULL, params, NULL, NULL, 0);
3202 }
3203 else if (querymode == QUERY_PREPARED)
3204 {
3205 const char *params[MAX_ARGS];
3206
3207 prepareCommand(st, st->command);
3208 getQueryParams(&st->variables, command, params);
3209
3210 pg_log_debug("client %d sending %s", st->id, command->prepname);
3211 r = PQsendQueryPrepared(st->con, command->prepname, command->argc - 1,
3212 params, NULL, NULL, 0);
3213 }
3214 else /* unknown sql mode */
3215 r = 0;
3216
3217 if (r == 0)
3218 {
3219 pg_log_debug("client %d could not send %s", st->id, command->argv[0]);
3220 return false;
3221 }
3222 else
3223 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:1492
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:1633
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 6616 of file pgbench.c.

6618{
6619 uint64 iseed;
6620
6621 if (seed == NULL || strcmp(seed, "time") == 0)
6622 {
6623 /* rely on current time */
6624 iseed = pg_time_now();
6625 }
6626 else if (strcmp(seed, "rand") == 0)
6627 {
6628 /* use some "strong" random source */
6629 if (!pg_strong_random(&iseed, sizeof(iseed)))
6630 {
6631 pg_log_error("could not generate random seed");
6632 return false;
6633 }
6634 }
6635 else
6636 {
6637 char garbage;
6638
6639 if (sscanf(seed, "%" SCNu64 "%c", &iseed, &garbage) != 1)
6640 {
6641 pg_log_error("unrecognized random seed option \"%s\"", seed);
6642 pg_log_error_detail("Expecting an unsigned integer, \"time\" or \"rand\".");
6643 return false;
6644 }
6645 }
6646
6647 if (seed != NULL)
6648 pg_log_info("setting random seed to %" PRIu64, iseed);
6649
6650 random_seed = iseed;
6651
6652 /* Initialize base_random_sequence using seed */
6654
6655 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 7771 of file pgbench.c.

7773{
7775 alarm(seconds);
static void handle_sig_alarm(SIGNAL_ARGS)
Definition: pgbench.c:7765
#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 5553 of file pgbench.c.

5555{
5556 char *p = sql_command;
5557
5558 /* Skip any leading whitespace, as well as "--" style comments */
5559 for (;;)
5560 {
5561 if (isspace((unsigned char) *p))
5562 p++;
5563 else if (strncmp(p, "--", 2) == 0)
5564 {
5565 p = strchr(p, '\n');
5566 if (p == NULL)
5567 return NULL;
5568 p++;
5569 }
5570 else
5571 break;
5572 }
5573
5574 /* NULL if there's nothing but whitespace and comments */
5575 if (*p == '\0')
5576 return NULL;
5577
5578 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 7975 of file pgbench.c.

7977{
7978 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:496

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

5521{
5523
5525
5526 printfPQExpBuffer(&buf, "%s:%d: %s", source, lineno, msg);
5527 if (more != NULL)
5528 appendPQExpBuffer(&buf, " (%s)", more);
5529 if (column >= 0 && line == NULL)
5530 appendPQExpBuffer(&buf, " at column %d", column + 1);
5531 if (command != NULL)
5532 appendPQExpBuffer(&buf, " in command \"%s\"", command);
5533
5534 pg_log_error("%s", buf.data);
5535
5537
5538 if (line != NULL)
5539 {
5540 fprintf(stderr, "%s\n", line);
5541 if (column >= 0)
5542 fprintf(stderr, "%*c error found here\n", column + 1, '^');
5543 }
5544
5545 exit(1);

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

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

◆ threadRun()

static THREAD_FUNC_RETURN_TYPE THREAD_FUNC_CC threadRun ( void *  arg)
static

Definition at line 7449 of file pgbench.c.

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

7960{
7961 if (usecs > 0)
7962 {
7963 struct timeval timeout;
7964
7965 timeout.tv_sec = usecs / 1000000;
7966 timeout.tv_usec = usecs % 1000000;
7967 return select(sa->maxfd + 1, &sa->fds, NULL, NULL, &timeout);
7968 }
7969 else
7970 {
7971 return select(sa->maxfd + 1, &sa->fds, NULL, NULL, NULL);
7972 }
#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().