PostgreSQL Source Code  git master
pgbench.c File Reference
#include "postgres_fe.h"
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <signal.h>
#include <time.h>
#include <sys/resource.h>
#include <sys/select.h>
#include "common/int.h"
#include "common/logging.h"
#include "common/pg_prng.h"
#include "common/string.h"
#include "common/username.h"
#include "fe_utils/cancel.h"
#include "fe_utils/conditional.h"
#include "fe_utils/option_utils.h"
#include "fe_utils/string_utils.h"
#include "getopt_long.h"
#include "libpq-fe.h"
#include "pgbench.h"
#include "port/pg_bitutils.h"
#include "portability/instr_time.h"
Include 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   void *
 
#define THREAD_FUNC_RETURN_TYPE   void *
 
#define THREAD_FUNC_RETURN   return NULL
 
#define THREAD_FUNC_CC
 
#define THREAD_BARRIER_T   int
 
#define THREAD_BARRIER_INIT(barrier, n)   (*(barrier) = 0)
 
#define THREAD_BARRIER_WAIT(barrier)
 
#define THREAD_BARRIER_DESTROY(barrier)
 
#define DEFAULT_INIT_STEPS   "dtgvp" /* default -I setting */
 
#define ALL_INIT_STEPS   "dtgGvpf" /* all possible steps */
 
#define LOG_STEP_SECONDS   5 /* seconds between log messages */
 
#define DEFAULT_NXACTS   10 /* default nxacts */
 
#define MIN_GAUSSIAN_PARAM   2.0 /* minimum parameter for gauss */
 
#define MIN_ZIPFIAN_PARAM   1.001 /* minimum parameter for zipfian */
 
#define MAX_ZIPFIAN_PARAM   1000.0 /* maximum parameter for zipfian */
 
#define nbranches
 
#define ntellers   10
 
#define naccounts   100000
 
#define SCALE_32BIT_THRESHOLD   20000
 
#define WSEP   '@' /* weight separator */
 
#define 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 MAX_PREPARE_NAME   32
 
#define COMMANDS_ALLOC_NUM   128
 

Typedefs

typedef struct socket_set socket_set
 
typedef struct SimpleStats SimpleStats
 
typedef int64 pg_time_usec_t
 
typedef struct StatsData StatsData
 
typedef 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
 

Enumerations

enum  partition_method_t { PART_NONE , PART_RANGE , PART_HASH }
 
enum  EStatus {
  ESTATUS_NO_ERROR = 0 , ESTATUS_META_COMMAND_ERROR , ESTATUS_SERIALIZATION_ERROR , ESTATUS_DEADLOCK_ERROR ,
  ESTATUS_OTHER_SQL_ERROR
}
 
enum  TStatus { TSTATUS_IDLE , TSTATUS_IN_BLOCK , TSTATUS_CONN_ERROR , TSTATUS_OTHER_ERROR }
 
enum  ConnectionStateEnum {
  CSTATE_CHOOSE_SCRIPT , CSTATE_START_TX , CSTATE_PREPARE_THROTTLE , CSTATE_THROTTLE ,
  CSTATE_START_COMMAND , CSTATE_WAIT_RESULT , CSTATE_SLEEP , CSTATE_END_COMMAND ,
  CSTATE_SKIP_COMMAND , CSTATE_ERROR , CSTATE_WAIT_ROLLBACK_RESULT , CSTATE_RETRY ,
  CSTATE_FAILURE , CSTATE_END_TX , CSTATE_ABORTED , CSTATE_FINISHED
}
 
enum  MetaCommand {
  META_NONE , META_SET , META_SETSHELL , META_SHELL ,
  META_SLEEP , META_GSET , META_ASET , META_IF ,
  META_ELIF , META_ELSE , META_ENDIF , META_STARTPIPELINE ,
  META_ENDPIPELINE
}
 
enum  QueryMode { QUERY_SIMPLE , QUERY_EXTENDED , QUERY_PREPARED , NUM_QUERYMODE }
 

Functions

static void setNullValue (PgBenchValue *pv)
 
static void setBoolValue (PgBenchValue *pv, bool bval)
 
static void setIntValue (PgBenchValue *pv, int64 ival)
 
static void setDoubleValue (PgBenchValue *pv, double dval)
 
static bool evaluateExpr (CState *st, PgBenchExpr *expr, PgBenchValue *retval)
 
static ConnectionStateEnum executeMetaCommand (CState *st, pg_time_usec_t *now)
 
static void doLog (TState *thread, CState *st, StatsData *agg, bool skipped, double latency, double lag)
 
static void processXactStats (TState *thread, CState *st, pg_time_usec_t *now, bool skipped, StatsData *agg)
 
static void addScript (const ParsedScript *script)
 
static THREAD_FUNC_RETURN_TYPE THREAD_FUNC_CC threadRun (void *arg)
 
static void finishCon (CState *st)
 
static void setalarm (int seconds)
 
static socket_setalloc_socket_set (int count)
 
static void free_socket_set (socket_set *sa)
 
static void clear_socket_set (socket_set *sa)
 
static void add_socket_to_set (socket_set *sa, int fd, int idx)
 
static int wait_on_socket_set (socket_set *sa, int64 usecs)
 
static bool socket_has_input (socket_set *sa, int fd, int idx)
 
static pg_time_usec_t pg_time_now (void)
 
static void pg_time_now_lazy (pg_time_usec_t *now)
 
static void usage (void)
 
static bool is_an_int (const char *str)
 
bool strtoint64 (const char *str, bool errorOK, int64 *result)
 
bool strtodouble (const char *str, bool errorOK, double *dv)
 
static void initRandomState (pg_prng_state *state)
 
static int64 getrand (pg_prng_state *state, int64 min, int64 max)
 
static int64 getExponentialRand (pg_prng_state *state, int64 min, int64 max, double parameter)
 
static int64 getGaussianRand (pg_prng_state *state, int64 min, int64 max, double parameter)
 
static int64 getPoissonRand (pg_prng_state *state, double center)
 
static int64 computeIterativeZipfian (pg_prng_state *state, int64 n, double s)
 
static int64 getZipfianRand (pg_prng_state *state, int64 min, int64 max, double s)
 
static int64 getHashFnv1a (int64 val, uint64 seed)
 
static int64 getHashMurmur2 (int64 val, uint64 seed)
 
static int64 permute (const int64 val, const int64 isize, const int64 seed)
 
static void initSimpleStats (SimpleStats *ss)
 
static void addToSimpleStats (SimpleStats *ss, double val)
 
static void mergeSimpleStats (SimpleStats *acc, SimpleStats *ss)
 
static void initStats (StatsData *sd, pg_time_usec_t start)
 
static void accumStats (StatsData *stats, bool skipped, double lat, double lag, EStatus estatus, int64 tries)
 
static void executeStatement (PGconn *con, const char *sql)
 
static void tryExecuteStatement (PGconn *con, const char *sql)
 
static PGconndoConnect (void)
 
static int compareVariableNames (const void *v1, const void *v2)
 
static VariablelookupVariable (Variables *variables, char *name)
 
static char * getVariable (Variables *variables, char *name)
 
static bool makeVariableValue (Variable *var)
 
static bool valid_variable_name (const char *name)
 
static void enlargeVariables (Variables *variables, int needed)
 
static VariablelookupCreateVariable (Variables *variables, const char *context, char *name)
 
static bool putVariable (Variables *variables, const char *context, char *name, const char *value)
 
static bool putVariableValue (Variables *variables, const char *context, char *name, const PgBenchValue *value)
 
static bool putVariableInt (Variables *variables, const char *context, char *name, int64 value)
 
static char * parseVariable (const char *sql, int *eaten)
 
static char * replaceVariable (char **sql, char *param, int len, char *value)
 
static char * assignVariables (Variables *variables, char *sql)
 
static void getQueryParams (Variables *variables, const Command *command, const char **params)
 
static char * valueTypeName (PgBenchValue *pval)
 
static bool coerceToBool (PgBenchValue *pval, bool *bval)
 
static bool valueTruth (PgBenchValue *pval)
 
static bool coerceToInt (PgBenchValue *pval, int64 *ival)
 
static bool coerceToDouble (PgBenchValue *pval, double *dval)
 
static bool isLazyFunc (PgBenchFunction func)
 
static bool evalLazyFunc (CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
 
static bool evalStandardFunc (CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
 
static bool evalFunc (CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
 
static MetaCommand getMetaCommand (const char *cmd)
 
static bool runShellCommand (Variables *variables, char *variable, char **argv, int argc)
 
static void preparedStatementName (char *buffer, int file, int state)
 
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 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 initGenerateDataClientSide (PGconn *con)
 
static void initGenerateDataServerSide (PGconn *con)
 
static void initVacuum (PGconn *con)
 
static void initCreatePKeys (PGconn *con)
 
static void initCreateFKeys (PGconn *con)
 
static void checkInitSteps (const char *initialize_steps)
 
static void runInitSteps (const char *initialize_steps)
 
static void GetTableInfo (PGconn *con, bool scale_given)
 
static bool parseQuery (Command *cmd)
 
void syntax_error (const char *source, int lineno, const char *line, const char *command, const char *msg, const char *more, int column)
 
static char * skip_sql_comments (char *sql_command)
 
static Commandcreate_sql_command (PQExpBuffer buf, const char *source)
 
static void free_command (Command *command)
 
static void postprocess_sql_command (Command *my_command)
 
static Commandprocess_backslash_command (PsqlScanState sstate, const char *source)
 
static void ConditionError (const char *desc, int cmdn, const char *msg)
 
static void CheckConditional (const ParsedScript *ps)
 
static void ParseScript (const char *script, const char *desc, int weight)
 
static char * read_file_contents (FILE *fd)
 
static void process_file (const char *filename, int weight)
 
static void process_builtin (const BuiltinScript *bi, int weight)
 
static void listAvailableScripts (void)
 
static const BuiltinScriptfindBuiltin (const char *name)
 
static int parseScriptWeight (const char *option, char **script)
 
static void printProgressReport (TState *threads, int64 test_start, pg_time_usec_t now, StatsData *last, int64 *last_report)
 
static void printSimpleStats (const char *prefix, SimpleStats *ss)
 
static void printVersion (PGconn *con)
 
static void printResults (StatsData *total, pg_time_usec_t total_duration, pg_time_usec_t conn_total_duration, pg_time_usec_t conn_elapsed_duration, int64 latency_late)
 
static bool set_random_seed (const char *seed)
 
int main (int argc, char **argv)
 
static void handle_sig_alarm (SIGNAL_ARGS)
 

Variables

int nxacts = 0
 
int duration = 0
 
int64 end_time = 0
 
int scale = 1
 
int fillfactor = 100
 
bool unlogged_tables = false
 
double sample_rate = 0.0
 
double throttle_delay = 0
 
int64 latency_limit = 0
 
char * tablespace = NULL
 
char * index_tablespace = NULL
 
static int partitions = 0
 
static partition_method_t partition_method = PART_NONE
 
static const char * PARTITION_METHOD [] = {"none", "range", "hash"}
 
int64 random_seed = -1
 
bool use_log
 
bool use_quiet
 
int agg_interval
 
bool per_script_stats = false
 
int progress = 0
 
bool progress_timestamp = false
 
int nclients = 1
 
int nthreads = 1
 
bool is_connect
 
bool report_per_command = false
 
int main_pid
 
uint32 max_tries = 1
 
bool failures_detailed = false
 
const char * pghost = NULL
 
const char * pgport = NULL
 
const char * username = NULL
 
const char * dbName = NULL
 
char * logfile_prefix = NULL
 
const char * progname
 
volatile sig_atomic_t timer_exceeded = false
 
pg_time_usec_t epoch_shift
 
static pg_prng_state base_random_sequence
 
static THREAD_BARRIER_T barrier
 
static QueryMode querymode = QUERY_SIMPLE
 
static const char * 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 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 172 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 171 of file pgbench.c.

◆ DEFAULT_NXACTS

#define DEFAULT_NXACTS   10 /* default nxacts */

Definition at line 175 of file pgbench.c.

◆ ERRCODE_T_R_DEADLOCK_DETECTED

#define ERRCODE_T_R_DEADLOCK_DETECTED   "40P01"

Definition at line 76 of file pgbench.c.

◆ ERRCODE_T_R_SERIALIZATION_FAILURE

#define ERRCODE_T_R_SERIALIZATION_FAILURE   "40001"

Definition at line 75 of file pgbench.c.

◆ ERRCODE_UNDEFINED_TABLE

#define ERRCODE_UNDEFINED_TABLE   "42P01"

Definition at line 77 of file pgbench.c.

◆ FNV_OFFSET_BASIS

#define FNV_OFFSET_BASIS   UINT64CONST(0xcbf29ce484222325)

Definition at line 83 of file pgbench.c.

◆ FNV_PRIME

#define FNV_PRIME   UINT64CONST(0x100000001b3)

Definition at line 82 of file pgbench.c.

◆ LOG_STEP_SECONDS

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

Definition at line 174 of file pgbench.c.

◆ M_PI

#define M_PI   3.14159265358979323846

Definition at line 72 of file pgbench.c.

◆ MAX_ARGS

#define MAX_ARGS   256

Definition at line 691 of file pgbench.c.

◆ MAX_FARGS

#define MAX_FARGS   16

Definition at line 2250 of file pgbench.c.

◆ MAX_PREPARE_NAME

#define MAX_PREPARE_NAME   32

Definition at line 3025 of file pgbench.c.

◆ MAX_SCRIPTS

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

Definition at line 355 of file pgbench.c.

◆ MAX_ZIPFIAN_PARAM

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

Definition at line 180 of file pgbench.c.

◆ META_COMMAND

#define META_COMMAND   2

Definition at line 685 of file pgbench.c.

◆ MIN_GAUSSIAN_PARAM

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

Definition at line 177 of file pgbench.c.

◆ MIN_ZIPFIAN_PARAM

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

Definition at line 179 of file pgbench.c.

◆ MM2_MUL

#define MM2_MUL   UINT64CONST(0xc6a4a7935bd1e995)

Definition at line 84 of file pgbench.c.

◆ MM2_MUL_TIMES_8

#define MM2_MUL_TIMES_8   UINT64CONST(0x35253c9ade8f4ca8)

Definition at line 85 of file pgbench.c.

◆ MM2_ROT

#define MM2_ROT   47

Definition at line 86 of file pgbench.c.

◆ naccounts

#define naccounts   100000

Definition at line 254 of file pgbench.c.

◆ nbranches

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

Definition at line 252 of file pgbench.c.

◆ ntellers

#define ntellers   10

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

◆ SHELL_COMMAND_SIZE

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

Definition at line 356 of file pgbench.c.

◆ SOCKET_WAIT_METHOD

#define SOCKET_WAIT_METHOD   "select"

Definition at line 105 of file pgbench.c.

◆ SQL_COMMAND

#define SQL_COMMAND   1

Definition at line 684 of file pgbench.c.

◆ THREAD_BARRIER_DESTROY

#define THREAD_BARRIER_DESTROY (   barrier)

Definition at line 164 of file pgbench.c.

◆ THREAD_BARRIER_INIT

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

Definition at line 162 of file pgbench.c.

◆ THREAD_BARRIER_T

#define THREAD_BARRIER_T   int

Definition at line 161 of file pgbench.c.

◆ THREAD_BARRIER_WAIT

#define THREAD_BARRIER_WAIT (   barrier)

Definition at line 163 of file pgbench.c.

◆ THREAD_FUNC_CC

#define THREAD_FUNC_CC

Definition at line 160 of file pgbench.c.

◆ THREAD_FUNC_RETURN

#define THREAD_FUNC_RETURN   return NULL

Definition at line 159 of file pgbench.c.

◆ THREAD_FUNC_RETURN_TYPE

#define THREAD_FUNC_RETURN_TYPE   void *

Definition at line 158 of file pgbench.c.

◆ THREAD_T

#define THREAD_T   void *

Definition at line 157 of file pgbench.c.

◆ VARIABLES_ALLOC_MARGIN

#define VARIABLES_ALLOC_MARGIN   8

Definition at line 318 of file pgbench.c.

◆ WSEP

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

Definition at line 310 of file pgbench.c.

Typedef Documentation

◆ BuiltinScript

typedef struct BuiltinScript BuiltinScript

◆ Command

typedef struct Command Command

◆ EStatus

typedef enum EStatus EStatus

◆ MetaCommand

typedef enum MetaCommand MetaCommand

◆ ParsedScript

typedef struct ParsedScript ParsedScript

◆ pg_time_usec_t

typedef int64 pg_time_usec_t

Definition at line 378 of file pgbench.c.

◆ QueryMode

typedef enum QueryMode QueryMode

◆ SimpleStats

typedef struct SimpleStats SimpleStats

◆ socket_set

typedef struct socket_set socket_set

◆ StatsData

typedef struct StatsData StatsData

◆ TStatus

typedef enum TStatus TStatus

Enumeration Type Documentation

◆ ConnectionStateEnum

Enumerator
CSTATE_CHOOSE_SCRIPT 
CSTATE_START_TX 
CSTATE_PREPARE_THROTTLE 
CSTATE_THROTTLE 
CSTATE_START_COMMAND 
CSTATE_WAIT_RESULT 
CSTATE_SLEEP 
CSTATE_END_COMMAND 
CSTATE_SKIP_COMMAND 
CSTATE_ERROR 
CSTATE_WAIT_ROLLBACK_RESULT 
CSTATE_RETRY 
CSTATE_FAILURE 
CSTATE_END_TX 
CSTATE_ABORTED 
CSTATE_FINISHED 

Definition at line 493 of file pgbench.c.

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

◆ EStatus

enum EStatus
Enumerator
ESTATUS_NO_ERROR 
ESTATUS_META_COMMAND_ERROR 
ESTATUS_SERIALIZATION_ERROR 
ESTATUS_DEADLOCK_ERROR 
ESTATUS_OTHER_SQL_ERROR 

Definition at line 462 of file pgbench.c.

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

◆ MetaCommand

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

Definition at line 693 of file pgbench.c.

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

◆ partition_method_t

Enumerator
PART_NONE 
PART_RANGE 
PART_HASH 

Definition at line 235 of file pgbench.c.

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

◆ QueryMode

enum QueryMode
Enumerator
QUERY_SIMPLE 
QUERY_EXTENDED 
QUERY_PREPARED 
NUM_QUERYMODE 

Definition at line 710 of file pgbench.c.

712 {
713  QUERY_SIMPLE, /* simple query */
714  QUERY_EXTENDED, /* extended query */
715  QUERY_PREPARED, /* extended query with prepared statements */
@ QUERY_PREPARED
Definition: pgbench.c:714
@ NUM_QUERYMODE
Definition: pgbench.c:715
@ QUERY_SIMPLE
Definition: pgbench.c:712
@ QUERY_EXTENDED
Definition: pgbench.c:713

◆ TStatus

enum TStatus
Enumerator
TSTATUS_IDLE 
TSTATUS_IN_BLOCK 
TSTATUS_CONN_ERROR 
TSTATUS_OTHER_ERROR 

Definition at line 476 of file pgbench.c.

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

Function Documentation

◆ accumStats()

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

Definition at line 1459 of file pgbench.c.

1462 {
1463  /* Record the skipped transaction */
1464  if (skipped)
1465  {
1466  /* no latency to record on skipped transactions */
1467  stats->skipped++;
1468  return;
1469  }
1470 
1471  /*
1472  * Record the number of retries regardless of whether the transaction was
1473  * successful or failed.
1474  */
1475  if (tries > 1)
1476  {
1477  stats->retries += (tries - 1);
1478  stats->retried++;
1479  }
1480 
1481  switch (estatus)
1482  {
1483  /* Record the successful transaction */
1484  case ESTATUS_NO_ERROR:
1485  stats->cnt++;
1486 
1487  addToSimpleStats(&stats->latency, lat);
1488 
1489  /* and possibly the same for schedule lag */
1490  if (throttle_delay)
1491  addToSimpleStats(&stats->lag, lag);
1492  break;
1493 
1494  /* Record the failed transaction */
1496  stats->serialization_failures++;
1497  break;
1499  stats->deadlock_failures++;
1500  break;
1501  default:
1502  /* internal error which should never occur */
1503  pg_fatal("unexpected error status: %d", estatus);
1504  }
#define pg_fatal(...)
double throttle_delay
Definition: pgbench.c:212
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:1411
int64 serialization_failures
Definition: pgbench.c:443
int64 cnt
Definition: pgbench.c:433
int64 retried
Definition: pgbench.c:439
int64 deadlock_failures
Definition: pgbench.c:446
int64 skipped
Definition: pgbench.c:435
SimpleStats lag
Definition: pgbench.c:450
int64 retries
Definition: pgbench.c:437
SimpleStats latency
Definition: pgbench.c:449

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

7737 {
7738  if (fd < 0 || fd >= FD_SETSIZE)
7739  {
7740  /*
7741  * Doing a hard exit here is a bit grotty, but it doesn't seem worth
7742  * complicating the API to make it less grotty.
7743  */
7744  pg_fatal("too many client connections for select()");
7745  }
7746  FD_SET(fd, &sa->fds);
7747  if (fd > sa->maxfd)
7748  sa->maxfd = fd;
static int fd(const char *x, int i)
Definition: preproc-init.c:105

References fd(), and pg_fatal.

Referenced by threadRun().

◆ addScript()

static void addScript ( const ParsedScript script)
static

Definition at line 6075 of file pgbench.c.

6077 {
6078  if (script->commands == NULL || script->commands[0] == NULL)
6079  pg_fatal("empty command list for script \"%s\"", script->desc);
6080 
6081  if (num_scripts >= MAX_SCRIPTS)
6082  pg_fatal("at most %d SQL scripts are allowed", MAX_SCRIPTS);
6083 
6084  CheckConditional(script);
6085 
6086  sql_script[num_scripts] = *script;
6087  num_scripts++;
static void CheckConditional(const ParsedScript *ps)
Definition: pgbench.c:5737
#define MAX_SCRIPTS
Definition: pgbench.c:355
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:767
static int num_scripts
Definition: pgbench.c:768
const char * desc
Definition: pgbench.c:761
Command ** commands
Definition: pgbench.c:763

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

1413 {
1414  if (ss->count == 0 || val < ss->min)
1415  ss->min = val;
1416  if (ss->count == 0 || val > ss->max)
1417  ss->max = val;
1418  ss->count++;
1419  ss->sum += val;
1420  ss->sum2 += val * val;
long val
Definition: informix.c:664
int64 count
Definition: pgbench.c:366
double sum
Definition: pgbench.c:369
double min
Definition: pgbench.c:367
double max
Definition: pgbench.c:368
double sum2
Definition: pgbench.c:370

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

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

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_log_debug, pg_log_error, PG_TIME_GET_DOUBLE, pg_time_now(), pg_time_now_lazy(), PGRES_COMMAND_OK, PQ_PIPELINE_OFF, PQ_PIPELINE_ON, PQclear(), PQconsumeInput(), PQerrorMessage(), PQgetResult(), PQisBusy(), PQpipelineStatus(), PQresultStatus(), PQsendQuery(), CState::prepared, printVerboseErrorMessages(), processXactStats(), CState::random_state, readCommandResponse(), report_per_command, res, Command::retries, sendCommand(), SQL_COMMAND, sql_script, CState::state, Command::stats, CState::stmt_begin, throttle_delay, TState::throttle_trigger, timer_exceeded, CState::tries, TState::ts_throttle_rs, TSTATUS_CONN_ERROR, TSTATUS_IDLE, TSTATUS_IN_BLOCK, CState::txn_begin, CState::txn_scheduled, Command::type, CState::use_file, Command::varprefix, and verbose_errors.

Referenced by threadRun().

◆ alloc_socket_set()

static socket_set * alloc_socket_set ( int  count)
static

Definition at line 7716 of file pgbench.c.

7718 {
7719  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().

◆ assignVariables()

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

Definition at line 1944 of file pgbench.c.

1946 {
1947  char *p,
1948  *name,
1949  *val;
1950 
1951  p = sql;
1952  while ((p = strchr(p, ':')) != NULL)
1953  {
1954  int eaten;
1955 
1956  name = parseVariable(p, &eaten);
1957  if (name == NULL)
1958  {
1959  while (*p == ':')
1960  {
1961  p++;
1962  }
1963  continue;
1964  }
1965 
1966  val = getVariable(variables, name);
1967  free(name);
1968  if (val == NULL)
1969  {
1970  p++;
1971  continue;
1972  }
1973 
1974  p = replaceVariable(&sql, p, eaten, val);
1975  }
1976 
1977  return sql;
const char * name
Definition: encode.c:561
#define free(a)
Definition: header.h:65
static char * getVariable(Variables *variables, char *name)
Definition: pgbench.c:1639
static char * parseVariable(const char *sql, int *eaten)
Definition: pgbench.c:1897
static char * replaceVariable(char **sql, char *param, int len, char *value)
Definition: pgbench.c:1924

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

Referenced by sendCommand().

◆ canRetryError()

static bool canRetryError ( EStatus  estatus)
static

Definition at line 3180 of file pgbench.c.

3182 {
3183  return (estatus == ESTATUS_SERIALIZATION_ERROR ||
3184  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 5737 of file pgbench.c.

5739 {
5740  /* statically check conditional structure */
5742  int i;
5743 
5744  for (i = 0; ps->commands[i] != NULL; i++)
5745  {
5746  Command *cmd = ps->commands[i];
5747 
5748  if (cmd->type == META_COMMAND)
5749  {
5750  switch (cmd->meta)
5751  {
5752  case META_IF:
5754  break;
5755  case META_ELIF:
5756  if (conditional_stack_empty(cs))
5757  ConditionError(ps->desc, i + 1, "\\elif without matching \\if");
5759  ConditionError(ps->desc, i + 1, "\\elif after \\else");
5760  break;
5761  case META_ELSE:
5762  if (conditional_stack_empty(cs))
5763  ConditionError(ps->desc, i + 1, "\\else without matching \\if");
5765  ConditionError(ps->desc, i + 1, "\\else after \\else");
5767  break;
5768  case META_ENDIF:
5769  if (!conditional_stack_pop(cs))
5770  ConditionError(ps->desc, i + 1, "\\endif without matching \\if");
5771  break;
5772  default:
5773  /* ignore anything else... */
5774  break;
5775  }
5776  }
5777  }
5778  if (!conditional_stack_empty(cs))
5779  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
int i
Definition: isn.c:73
static void ConditionError(const char *desc, int cmdn, const char *msg)
Definition: pgbench.c:5727

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

Referenced by addScript().

◆ checkInitSteps()

static void checkInitSteps ( const char *  initialize_steps)
static

Definition at line 5090 of file pgbench.c.

5092 {
5093  if (initialize_steps[0] == '\0')
5094  pg_fatal("no initialization steps specified");
5095 
5096  for (const char *step = initialize_steps; *step != '\0'; step++)
5097  {
5098  if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
5099  {
5100  pg_log_error("unrecognized initialization step \"%c\"", *step);
5101  pg_log_error_detail("Allowed step characters are: \"" ALL_INIT_STEPS "\".");
5102  exit(1);
5103  }
5104  }
exit(1)
#define pg_log_error_detail(...)
Definition: logging.h:109
#define ALL_INIT_STEPS
Definition: pgbench.c:172

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

Referenced by main().

◆ chooseScript()

static int chooseScript ( TState thread)
static

Definition at line 3055 of file pgbench.c.

3057 {
3058  int i = 0;
3059  int64 w;
3060 
3061  if (num_scripts == 1)
3062  return 0;
3063 
3064  w = getrand(&thread->ts_choose_rs, 0, total_weight - 1);
3065  do
3066  {
3067  w -= sql_script[i++].weight;
3068  } while (w >= 0);
3069 
3070  return i - 1;
static int64 total_weight
Definition: pgbench.c:769
static int64 getrand(pg_prng_state *state, int64 min, int64 max)
Definition: pgbench.c:1092
int weight
Definition: pgbench.c:762
pg_prng_state ts_choose_rs
Definition: pgbench.c:663

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

7730 {
7731  FD_ZERO(&sa->fds);
7732  sa->maxfd = -1;

Referenced by threadRun().

◆ coerceToBool()

static bool coerceToBool ( PgBenchValue pval,
bool bval 
)
static

Definition at line 2012 of file pgbench.c.

2014 {
2015  if (pval->type == PGBT_BOOLEAN)
2016  {
2017  *bval = pval->u.bval;
2018  return true;
2019  }
2020  else /* NULL, INT or DOUBLE */
2021  {
2022  pg_log_error("cannot coerce %s to boolean", valueTypeName(pval));
2023  *bval = false; /* suppress uninitialized-variable warnings */
2024  return false;
2025  }
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1990
@ PGBT_BOOLEAN
Definition: pgbench.h:40
PgBenchValueType type
Definition: pgbench.h:46
bool bval
Definition: pgbench.h:51
union PgBenchValue::@32 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 2081 of file pgbench.c.

2083 {
2084  if (pval->type == PGBT_DOUBLE)
2085  {
2086  *dval = pval->u.dval;
2087  return true;
2088  }
2089  else if (pval->type == PGBT_INT)
2090  {
2091  *dval = (double) pval->u.ival;
2092  return true;
2093  }
2094  else /* BOOLEAN or NULL */
2095  {
2096  pg_log_error("cannot coerce %s to double", valueTypeName(pval));
2097  return false;
2098  }
@ 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 2053 of file pgbench.c.

2055 {
2056  if (pval->type == PGBT_INT)
2057  {
2058  *ival = pval->u.ival;
2059  return true;
2060  }
2061  else if (pval->type == PGBT_DOUBLE)
2062  {
2063  double dval = rint(pval->u.dval);
2064 
2065  if (isnan(dval) || !FLOAT8_FITS_IN_INT64(dval))
2066  {
2067  pg_log_error("double to int overflow for %f", dval);
2068  return false;
2069  }
2070  *ival = (int64) dval;
2071  return true;
2072  }
2073  else /* BOOLEAN or NULL */
2074  {
2075  pg_log_error("cannot coerce %s to int", valueTypeName(pval));
2076  return false;
2077  }
#define FLOAT8_FITS_IN_INT64(num)
Definition: c.h:1049

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

3048 {
3050  pg_log_info("client %d got an error in command %d (SQL) of script %d; %s",
3051  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 3036 of file pgbench.c.

3038 {
3039  pg_log_error("client %d aborted in command %d (%s) of script %d; %s",
3040  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 1604 of file pgbench.c.

1606 {
1607  return strcmp(((const Variable *) v1)->name,
1608  ((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 1209 of file pgbench.c.

1211 {
1212  double b = pow(2.0, s - 1.0);
1213  double x,
1214  t,
1215  u,
1216  v;
1217 
1218  /* Ensure n is sane */
1219  if (n <= 1)
1220  return 1;
1221 
1222  while (true)
1223  {
1224  /* random variates */
1225  u = pg_prng_double(state);
1226  v = pg_prng_double(state);
1227 
1228  x = floor(pow(u, -1.0 / (s - 1.0)));
1229 
1230  t = pow(1.0 + 1.0 / x, s - 1.0);
1231  /* reject if too large or out of bound */
1232  if (v * x * (t - 1.0) / (b - 1.0) <= t / b && x <= n)
1233  break;
1234  }
1235  return (int64) x;
int b
Definition: isn.c:70
int x
Definition: isn.c:71
double pg_prng_double(pg_prng_state *state)
Definition: pg_prng.c:226
Definition: regguts.h:318

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

5729 {
5730  pg_fatal("condition error in script \"%s\" command %d: %s",
5731  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 5436 of file pgbench.c.

5438 {
5439  Command *my_command;
5440  char *p = skip_sql_comments(buf->data);
5441 
5442  if (p == NULL)
5443  return NULL;
5444 
5445  /* Allocate and initialize Command structure */
5446  my_command = (Command *) pg_malloc(sizeof(Command));
5447  initPQExpBuffer(&my_command->lines);
5448  appendPQExpBufferStr(&my_command->lines, p);
5449  my_command->first_line = NULL; /* this is set later */
5450  my_command->type = SQL_COMMAND;
5451  my_command->meta = META_NONE;
5452  my_command->argc = 0;
5453  my_command->retries = 0;
5454  my_command->failures = 0;
5455  memset(my_command->argv, 0, sizeof(my_command->argv));
5456  my_command->varprefix = NULL; /* allocated later, if needed */
5457  my_command->expr = NULL;
5458  initSimpleStats(&my_command->stats);
5459 
5460  return my_command;
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
static char * buf
Definition: pg_test_fsync.c:67
static char * skip_sql_comments(char *sql_command)
Definition: pgbench.c:5401
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1402
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:90
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367
PQExpBufferData lines
Definition: pgbench.c:746
PgBenchExpr * expr
Definition: pgbench.c:753
char * argv[MAX_ARGS]
Definition: pgbench.c:751
char * first_line
Definition: pgbench.c:747
int argc
Definition: pgbench.c:750

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

4657 {
4658  PQExpBufferData query;
4659 
4660  /* we must have to create some partitions */
4661  Assert(partitions > 0);
4662 
4663  fprintf(stderr, "creating %d partitions...\n", partitions);
4664 
4665  initPQExpBuffer(&query);
4666 
4667  for (int p = 1; p <= partitions; p++)
4668  {
4670  {
4671  int64 part_size = (naccounts * (int64) scale + partitions - 1) / partitions;
4672 
4673  printfPQExpBuffer(&query,
4674  "create%s table pgbench_accounts_%d\n"
4675  " partition of pgbench_accounts\n"
4676  " for values from (",
4677  unlogged_tables ? " unlogged" : "", p);
4678 
4679  /*
4680  * For RANGE, we use open-ended partitions at the beginning and
4681  * end to allow any valid value for the primary key. Although the
4682  * actual minimum and maximum values can be derived from the
4683  * scale, it is more generic and the performance is better.
4684  */
4685  if (p == 1)
4686  appendPQExpBufferStr(&query, "minvalue");
4687  else
4688  appendPQExpBuffer(&query, INT64_FORMAT, (p - 1) * part_size + 1);
4689 
4690  appendPQExpBufferStr(&query, ") to (");
4691 
4692  if (p < partitions)
4693  appendPQExpBuffer(&query, INT64_FORMAT, p * part_size + 1);
4694  else
4695  appendPQExpBufferStr(&query, "maxvalue");
4696 
4697  appendPQExpBufferChar(&query, ')');
4698  }
4699  else if (partition_method == PART_HASH)
4700  printfPQExpBuffer(&query,
4701  "create%s table pgbench_accounts_%d\n"
4702  " partition of pgbench_accounts\n"
4703  " for values with (modulus %d, remainder %d)",
4704  unlogged_tables ? " unlogged" : "", p,
4705  partitions, p - 1);
4706  else /* cannot get there */
4707  Assert(0);
4708 
4709  /*
4710  * Per ddlinfo in initCreateTables, fillfactor is needed on table
4711  * pgbench_accounts.
4712  */
4713  appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4714 
4715  executeStatement(con, query.data);
4716  }
4717 
4718  termPQExpBuffer(&query);
#define INT64_FORMAT
Definition: c.h:484
int scale
Definition: pgbench.c:190
static int partitions
Definition: pgbench.c:232
int fillfactor
Definition: pgbench.c:196
static partition_method_t partition_method
Definition: pgbench.c:242
bool unlogged_tables
Definition: pgbench.c:201
#define naccounts
Definition: pgbench.c:254
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1508
#define fprintf
Definition: port.h:242
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:235
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:265
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:378
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:129

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

Referenced by initCreateTables().

◆ discardUntilSync()

static int discardUntilSync ( CState st)
static

Definition at line 3427 of file pgbench.c.

3429 {
3430  /* send a sync */
3431  if (!PQpipelineSync(st->con))
3432  {
3433  pg_log_error("client %d aborted: failed to send a pipeline sync",
3434  st->id);
3435  return 0;
3436  }
3437 
3438  /* receive PGRES_PIPELINE_SYNC and null following it */
3439  for (;;)
3440  {
3441  PGresult *res = PQgetResult(st->con);
3442 
3444  {
3445  PQclear(res);
3446  res = PQgetResult(st->con);
3447  Assert(res == NULL);
3448  break;
3449  }
3450  PQclear(res);
3451  }
3452 
3453  /* exit pipeline */
3454  if (PQexitPipelineMode(st->con) != 1)
3455  {
3456  pg_log_error("client %d aborted: failed to exit pipeline mode for rolling back the failed transaction",
3457  st->id);
3458  return 0;
3459  }
3460  return 1;
int PQexitPipelineMode(PGconn *conn)
Definition: fe-exec.c:2955
int PQpipelineSync(PGconn *conn)
Definition: fe-exec.c:3141
@ PGRES_PIPELINE_SYNC
Definition: libpq-fe.h:111

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

Referenced by advanceConnectionState().

◆ disconnect_all()

static void disconnect_all ( CState state,
int  length 
)
static

Definition at line 4621 of file pgbench.c.

4623 {
4624  int i;
4625 
4626  for (i = 0; i < length; i++)
4627  finishCon(&state[i]);

References finishCon(), and i.

Referenced by main(), and threadRun().

◆ doConnect()

static PGconn* doConnect ( void  )
static

Definition at line 1539 of file pgbench.c.

1541 {
1542  PGconn *conn;
1543  bool new_pass;
1544  static char *password = NULL;
1545 
1546  /*
1547  * Start the connection. Loop until we have a password if requested by
1548  * backend.
1549  */
1550  do
1551  {
1552 #define PARAMS_ARRAY_SIZE 7
1553 
1554  const char *keywords[PARAMS_ARRAY_SIZE];
1555  const char *values[PARAMS_ARRAY_SIZE];
1556 
1557  keywords[0] = "host";
1558  values[0] = pghost;
1559  keywords[1] = "port";
1560  values[1] = pgport;
1561  keywords[2] = "user";
1562  values[2] = username;
1563  keywords[3] = "password";
1564  values[3] = password;
1565  keywords[4] = "dbname";
1566  values[4] = dbName;
1567  keywords[5] = "fallback_application_name";
1568  values[5] = progname;
1569  keywords[6] = NULL;
1570  values[6] = NULL;
1571 
1572  new_pass = false;
1573 
1574  conn = PQconnectdbParams(keywords, values, true);
1575 
1576  if (!conn)
1577  {
1578  pg_log_error("connection to database \"%s\" failed", dbName);
1579  return NULL;
1580  }
1581 
1582  if (PQstatus(conn) == CONNECTION_BAD &&
1584  !password)
1585  {
1586  PQfinish(conn);
1587  password = simple_prompt("Password: ", false);
1588  new_pass = true;
1589  }
1590  } while (new_pass);
1591 
1592  /* check to see that the backend connection was successfully made */
1593  if (PQstatus(conn) == CONNECTION_BAD)
1594  {
1596  PQfinish(conn);
1597  return NULL;
1598  }
1599 
1600  return conn;
static Datum values[MAXATTR]
Definition: bootstrap.c:156
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:652
int PQconnectionNeedsPassword(const PGconn *conn)
Definition: fe-connect.c:6794
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:6690
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4130
@ CONNECTION_BAD
Definition: libpq-fe.h:61
#define PARAMS_ARRAY_SIZE
const char * pghost
Definition: pgbench.c:303
const char * username
Definition: pgbench.c:305
const char * progname
Definition: pgbench.c:308
const char * pgport
Definition: pgbench.c:304
const char * dbName
Definition: pgbench.c:306
char * simple_prompt(const char *prompt, bool echo)
Definition: sprompt.c:38
static char * password
Definition: streamutil.c:53
PGconn * conn
Definition: streamutil.c:54

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

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

◆ doLog()

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

Definition at line 4462 of file pgbench.c.

4465 {
4466  FILE *logfile = thread->logfile;
4468 
4469  Assert(use_log);
4470 
4471  /*
4472  * Skip the log entry if sampling is enabled and this row doesn't belong
4473  * to the random sample.
4474  */
4475  if (sample_rate != 0.0 &&
4477  return;
4478 
4479  /* should we aggregate the results or not? */
4480  if (agg_interval > 0)
4481  {
4483 
4484  /*
4485  * Loop until we reach the interval of the current moment, and print
4486  * any empty intervals in between (this may happen with very low tps,
4487  * e.g. --rate=0.1).
4488  */
4489 
4490  while ((next = agg->start_time + agg_interval * INT64CONST(1000000)) <= now)
4491  {
4492  double lag_sum = 0.0;
4493  double lag_sum2 = 0.0;
4494  double lag_min = 0.0;
4495  double lag_max = 0.0;
4496  int64 skipped = 0;
4497  int64 serialization_failures = 0;
4498  int64 deadlock_failures = 0;
4499  int64 retried = 0;
4500  int64 retries = 0;
4501 
4502  /* print aggregated report to logfile */
4503  fprintf(logfile, INT64_FORMAT " " INT64_FORMAT " %.0f %.0f %.0f %.0f",
4504  agg->start_time / 1000000, /* seconds since Unix epoch */
4505  agg->cnt,
4506  agg->latency.sum,
4507  agg->latency.sum2,
4508  agg->latency.min,
4509  agg->latency.max);
4510 
4511  if (throttle_delay)
4512  {
4513  lag_sum = agg->lag.sum;
4514  lag_sum2 = agg->lag.sum2;
4515  lag_min = agg->lag.min;
4516  lag_max = agg->lag.max;
4517  }
4518  fprintf(logfile, " %.0f %.0f %.0f %.0f",
4519  lag_sum,
4520  lag_sum2,
4521  lag_min,
4522  lag_max);
4523 
4524  if (latency_limit)
4525  skipped = agg->skipped;
4526  fprintf(logfile, " " INT64_FORMAT, skipped);
4527 
4528  if (max_tries != 1)
4529  {
4530  retried = agg->retried;
4531  retries = agg->retries;
4532  }
4533  fprintf(logfile, " " INT64_FORMAT " " INT64_FORMAT, retried, retries);
4534 
4535  if (failures_detailed)
4536  {
4537  serialization_failures = agg->serialization_failures;
4538  deadlock_failures = agg->deadlock_failures;
4539  }
4541  serialization_failures,
4542  deadlock_failures);
4543 
4544  fputc('\n', logfile);
4545 
4546  /* reset data and move to next interval */
4547  initStats(agg, next);
4548  }
4549 
4550  /* accumulate the current transaction */
4551  accumStats(agg, skipped, latency, lag, st->estatus, st->tries);
4552  }
4553  else
4554  {
4555  /* no, print raw transactions */
4556  if (!skipped && st->estatus == ESTATUS_NO_ERROR)
4557  fprintf(logfile, "%d " INT64_FORMAT " %.0f %d " INT64_FORMAT " "
4558  INT64_FORMAT,
4559  st->id, st->cnt, latency, st->use_file,
4560  now / 1000000, now % 1000000);
4561  else
4562  fprintf(logfile, "%d " INT64_FORMAT " %s %d " INT64_FORMAT " "
4563  INT64_FORMAT,
4564  st->id, st->cnt, getResultString(skipped, st->estatus),
4565  st->use_file, now / 1000000, now % 1000000);
4566 
4567  if (throttle_delay)
4568  fprintf(logfile, " %.0f", lag);
4569  if (max_tries != 1)
4570  fprintf(logfile, " %u", st->tries - 1);
4571  fputc('\n', logfile);
4572  }
static int32 next
Definition: blutils.c:219
static FILE * logfile
Definition: pg_regress.c:100
static void accumStats(StatsData *stats, bool skipped, double lat, double lag, EStatus estatus, int64 tries)
Definition: pgbench.c:1459
uint32 max_tries
Definition: pgbench.c:298
bool use_log
Definition: pgbench.c:265
int agg_interval
Definition: pgbench.c:267
static const char * getResultString(bool skipped, EStatus estatus)
Definition: pgbench.c:4431
static void initStats(StatsData *sd, pg_time_usec_t start)
Definition: pgbench.c:1442
double sample_rate
Definition: pgbench.c:206
bool failures_detailed
Definition: pgbench.c:300
pg_time_usec_t epoch_shift
Definition: pgbench.c:457
pg_time_usec_t start_time
Definition: pgbench.c:386
FILE * logfile
Definition: pgbench.c:668
pg_prng_state ts_sample_rs
Definition: pgbench.c:665

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

Referenced by processXactStats(), and threadRun().

◆ doRetry()

static bool doRetry ( CState st,
pg_time_usec_t now 
)
static

Definition at line 3381 of file pgbench.c.

3383 {
3385 
3386  /* We can only retry serialization or deadlock errors. */
3387  if (!canRetryError(st->estatus))
3388  return false;
3389 
3390  /*
3391  * We must have at least one option to limit the retrying of transactions
3392  * that got an error.
3393  */
3395 
3396  /*
3397  * We cannot retry the error if we have reached the maximum number of
3398  * tries.
3399  */
3400  if (max_tries && st->tries >= max_tries)
3401  return false;
3402 
3403  /*
3404  * We cannot retry the error if we spent too much time on this
3405  * transaction.
3406  */
3407  if (latency_limit)
3408  {
3410  if (*now - st->txn_scheduled > latency_limit)
3411  return false;
3412  }
3413 
3414  /*
3415  * We cannot retry the error if the benchmark duration is over.
3416  */
3417  if (timer_exceeded)
3418  return false;
3419 
3420  /* OK */
3421  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 1781 of file pgbench.c.

1783 {
1784  /* total number of variables required now */
1785  needed += variables->nvars;
1786 
1787  if (variables->max_vars < needed)
1788  {
1789  variables->max_vars = needed + VARIABLES_ALLOC_MARGIN;
1790  variables->vars = (Variable *)
1791  pg_realloc(variables->vars, variables->max_vars * sizeof(Variable));
1792  }
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
#define VARIABLES_ALLOC_MARGIN
Definition: pgbench.c:318
Variable * vars
Definition: pgbench.c:342
int nvars
Definition: pgbench.c:343
int max_vars
Definition: pgbench.c:350

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

2827 {
2828  if (isLazyFunc(func))
2829  return evalLazyFunc(st, func, args, retval);
2830  else
2831  return evalStandardFunc(st, func, args, retval);
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:2133
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2140
static bool evalStandardFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2257

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

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

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

Referenced by evalFunc().

◆ evalStandardFunc()

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

Definition at line 2257 of file pgbench.c.

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

References generate_unaccent_rules::args, Assert(), b, PgBenchValue::bval, coerceToBool(), coerceToDouble(), coerceToInt(), CState::command, CState::cs_func_rs, PgBenchValue::dval, evaluateExpr(), PgBenchExprLink::expr, fprintf, getExponentialRand(), getGaussianRand(), getHashFnv1a(), getHashMurmur2(), getrand(), getZipfianRand(), i, INT64_FORMAT, PgBenchValue::ival, M_PI, Max, MAX_FARGS, MAX_ZIPFIAN_PARAM, Min, MIN_GAUSSIAN_PARAM, MIN_ZIPFIAN_PARAM, PgBenchExprLink::next, permute(), pg_add_s64_overflow(), PG_INT64_MIN, pg_log_error, pg_mul_s64_overflow(), pg_sub_s64_overflow(), PGBENCH_ABS, PGBENCH_ADD, PGBENCH_BITAND, PGBENCH_BITOR, PGBENCH_BITXOR, PGBENCH_DEBUG, PGBENCH_DIV, PGBENCH_DOUBLE, PGBENCH_EQ, PGBENCH_EXP, PGBENCH_GREATEST, PGBENCH_HASH_FNV1A, PGBENCH_HASH_MURMUR2, PGBENCH_INT, PGBENCH_IS, PGBENCH_LE, PGBENCH_LEAST, PGBENCH_LN, PGBENCH_LSHIFT, PGBENCH_LT, PGBENCH_MOD, PGBENCH_MUL, PGBENCH_NE, PGBENCH_NOT, PGBENCH_PERMUTE, PGBENCH_PI, PGBENCH_POW, PGBENCH_RANDOM, PGBENCH_RANDOM_EXPONENTIAL, PGBENCH_RANDOM_GAUSSIAN, PGBENCH_RANDOM_ZIPFIAN, PGBENCH_RSHIFT, PGBENCH_SQRT, PGBENCH_SUB, PGBT_BOOLEAN, PGBT_DOUBLE, PGBT_INT, PGBT_NULL, res, setBoolValue(), setDoubleValue(), setIntValue(), setNullValue(), generate_unaccent_rules::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 2840 of file pgbench.c.

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

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

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

◆ evaluateSleep()

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

Definition at line 3336 of file pgbench.c.

3338 {
3339  char *var;
3340  int usec;
3341 
3342  if (*argv[1] == ':')
3343  {
3344  if ((var = getVariable(variables, argv[1] + 1)) == NULL)
3345  {
3346  pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[1] + 1);
3347  return false;
3348  }
3349 
3350  usec = atoi(var);
3351 
3352  /* Raise an error if the value of a variable is not a number */
3353  if (usec == 0 && !isdigit((unsigned char) *var))
3354  {
3355  pg_log_error("%s: invalid sleep time \"%s\" for variable \"%s\"",
3356  argv[0], var, argv[1] + 1);
3357  return false;
3358  }
3359  }
3360  else
3361  usec = atoi(argv[1]);
3362 
3363  if (argc > 2)
3364  {
3365  if (pg_strcasecmp(argv[2], "ms") == 0)
3366  usec *= 1000;
3367  else if (pg_strcasecmp(argv[2], "s") == 0)
3368  usec *= 1000000;
3369  }
3370  else
3371  usec *= 1000000;
3372 
3373  *usecs = usec;
3374  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 4226 of file pgbench.c.

4228 {
4229  Command *command = sql_script[st->use_file].commands[st->command];
4230  int argc;
4231  char **argv;
4232 
4233  Assert(command != NULL && command->type == META_COMMAND);
4234 
4235  argc = command->argc;
4236  argv = command->argv;
4237 
4239  {
4241 
4242  initPQExpBuffer(&buf);
4243 
4244  printfPQExpBuffer(&buf, "client %d executing \\%s", st->id, argv[0]);
4245  for (int i = 1; i < argc; i++)
4246  appendPQExpBuffer(&buf, " %s", argv[i]);
4247 
4248  pg_log_debug("%s", buf.data);
4249 
4250  termPQExpBuffer(&buf);
4251  }
4252 
4253  if (command->meta == META_SLEEP)
4254  {
4255  int usec;
4256 
4257  /*
4258  * A \sleep doesn't execute anything, we just get the delay from the
4259  * argument, and enter the CSTATE_SLEEP state. (The per-command
4260  * latency will be recorded in CSTATE_SLEEP state, not here, after the
4261  * delay has elapsed.)
4262  */
4263  if (!evaluateSleep(&st->variables, argc, argv, &usec))
4264  {
4265  commandFailed(st, "sleep", "execution of meta-command failed");
4266  return CSTATE_ABORTED;
4267  }
4268 
4270  st->sleep_until = (*now) + usec;
4271  return CSTATE_SLEEP;
4272  }
4273  else if (command->meta == META_SET)
4274  {
4275  PgBenchExpr *expr = command->expr;
4276  PgBenchValue result;
4277 
4278  if (!evaluateExpr(st, expr, &result))
4279  {
4280  commandFailed(st, argv[0], "evaluation of meta-command failed");
4281  return CSTATE_ABORTED;
4282  }
4283 
4284  if (!putVariableValue(&st->variables, argv[0], argv[1], &result))
4285  {
4286  commandFailed(st, "set", "assignment of meta-command failed");
4287  return CSTATE_ABORTED;
4288  }
4289  }
4290  else if (command->meta == META_IF)
4291  {
4292  /* backslash commands with an expression to evaluate */
4293  PgBenchExpr *expr = command->expr;
4294  PgBenchValue result;
4295  bool cond;
4296 
4297  if (!evaluateExpr(st, expr, &result))
4298  {
4299  commandFailed(st, argv[0], "evaluation of meta-command failed");
4300  return CSTATE_ABORTED;
4301  }
4302 
4303  cond = valueTruth(&result);
4305  }
4306  else if (command->meta == META_ELIF)
4307  {
4308  /* backslash commands with an expression to evaluate */
4309  PgBenchExpr *expr = command->expr;
4310  PgBenchValue result;
4311  bool cond;
4312 
4314  {
4315  /* elif after executed block, skip eval and wait for endif. */
4317  return CSTATE_END_COMMAND;
4318  }
4319 
4320  if (!evaluateExpr(st, expr, &result))
4321  {
4322  commandFailed(st, argv[0], "evaluation of meta-command failed");
4323  return CSTATE_ABORTED;
4324  }
4325 
4326  cond = valueTruth(&result);
4329  }
4330  else if (command->meta == META_ELSE)
4331  {
4332  switch (conditional_stack_peek(st->cstack))
4333  {
4334  case IFSTATE_TRUE:
4336  break;
4337  case IFSTATE_FALSE: /* inconsistent if active */
4338  case IFSTATE_IGNORED: /* inconsistent if active */
4339  case IFSTATE_NONE: /* else without if */
4340  case IFSTATE_ELSE_TRUE: /* else after else */
4341  case IFSTATE_ELSE_FALSE: /* else after else */
4342  default:
4343  /* dead code if conditional check is ok */
4344  Assert(false);
4345  }
4346  }
4347  else if (command->meta == META_ENDIF)
4348  {
4351  }
4352  else if (command->meta == META_SETSHELL)
4353  {
4354  if (!runShellCommand(&st->variables, argv[1], argv + 2, argc - 2))
4355  {
4356  commandFailed(st, "setshell", "execution of meta-command failed");
4357  return CSTATE_ABORTED;
4358  }
4359  }
4360  else if (command->meta == META_SHELL)
4361  {
4362  if (!runShellCommand(&st->variables, NULL, argv + 1, argc - 1))
4363  {
4364  commandFailed(st, "shell", "execution of meta-command failed");
4365  return CSTATE_ABORTED;
4366  }
4367  }
4368  else if (command->meta == META_STARTPIPELINE)
4369  {
4370  /*
4371  * In pipeline mode, we use a workflow based on libpq pipeline
4372  * functions.
4373  */
4374  if (querymode == QUERY_SIMPLE)
4375  {
4376  commandFailed(st, "startpipeline", "cannot use pipeline mode with the simple query protocol");
4377  return CSTATE_ABORTED;
4378  }
4379 
4380  if (PQpipelineStatus(st->con) != PQ_PIPELINE_OFF)
4381  {
4382  commandFailed(st, "startpipeline", "already in pipeline mode");
4383  return CSTATE_ABORTED;
4384  }
4385  if (PQenterPipelineMode(st->con) == 0)
4386  {
4387  commandFailed(st, "startpipeline", "failed to enter pipeline mode");
4388  return CSTATE_ABORTED;
4389  }
4390  }
4391  else if (command->meta == META_ENDPIPELINE)
4392  {
4393  if (PQpipelineStatus(st->con) != PQ_PIPELINE_ON)
4394  {
4395  commandFailed(st, "endpipeline", "not in pipeline mode");
4396  return CSTATE_ABORTED;
4397  }
4398  if (!PQpipelineSync(st->con))
4399  {
4400  commandFailed(st, "endpipeline", "failed to send a pipeline sync");
4401  return CSTATE_ABORTED;
4402  }
4403  /* Now wait for the PGRES_PIPELINE_SYNC and exit pipeline mode there */
4404  /* collect pending results before getting out of pipeline mode */
4405  return CSTATE_WAIT_RESULT;
4406  }
4407 
4408  /*
4409  * executing the expression or shell command might have taken a
4410  * non-negligible amount of time, so reset 'now'
4411  */
4412  *now = 0;
4413 
4414  return CSTATE_END_COMMAND;
int PQenterPipelineMode(PGconn *conn)
Definition: fe-exec.c:2924
enum pg_log_level __pg_log_level
Definition: logging.c:21
@ PG_LOG_DEBUG
Definition: logging.h:26
static QueryMode querymode
Definition: pgbench.c:718
static bool runShellCommand(Variables *variables, char *variable, char **argv, int argc)
Definition: pgbench.c:2923
static bool evaluateSleep(Variables *variables, int argc, char **argv, int *usecs)
Definition: pgbench.c:3336
static bool putVariableValue(Variables *variables, const char *context, char *name, const PgBenchValue *value)
Definition: pgbench.c:1860
pg_time_usec_t sleep_until
Definition: pgbench.c:625

References __pg_log_level, appendPQExpBuffer(), Command::argc, Command::argv, Assert(), buf, CState::command, commandFailed(), ParsedScript::commands, CState::con, conditional_stack_empty(), conditional_stack_peek(), conditional_stack_poke(), conditional_stack_pop(), conditional_stack_push(), CState::cstack, CSTATE_ABORTED, CSTATE_END_COMMAND, CSTATE_SLEEP, CSTATE_WAIT_RESULT, evaluateExpr(), evaluateSleep(), Command::expr, i, CState::id, IFSTATE_ELSE_FALSE, IFSTATE_ELSE_TRUE, IFSTATE_FALSE, IFSTATE_IGNORED, IFSTATE_NONE, IFSTATE_TRUE, initPQExpBuffer(), Command::meta, META_COMMAND, META_ELIF, META_ELSE, META_ENDIF, META_ENDPIPELINE, META_IF, META_SET, META_SETSHELL, META_SHELL, META_SLEEP, META_STARTPIPELINE, now(), PG_LOG_DEBUG, pg_log_debug, pg_time_now_lazy(), PQ_PIPELINE_OFF, PQ_PIPELINE_ON, PQenterPipelineMode(), PQpipelineStatus(), PQpipelineSync(), printfPQExpBuffer(), putVariableValue(), 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 1508 of file pgbench.c.

1510 {
1511  PGresult *res;
1512 
1513  res = PQexec(con, sql);
1515  {
1516  pg_log_error("query failed: %s", PQerrorMessage(con));
1517  pg_log_error_detail("Query was: %s", sql);
1518  exit(1);
1519  }
1520  PQclear(res);
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2225

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

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

◆ findBuiltin()

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

Definition at line 6002 of file pgbench.c.

6004 {
6005  int i,
6006  found = 0,
6007  len = strlen(name);
6008  const BuiltinScript *result = NULL;
6009 
6010  for (i = 0; i < lengthof(builtin_script); i++)
6011  {
6012  if (strncmp(builtin_script[i].name, name, len) == 0)
6013  {
6014  result = &builtin_script[i];
6015  found++;
6016  }
6017  }
6018 
6019  /* ok, unambiguous result */
6020  if (found == 1)
6021  return result;
6022 
6023  /* error cases */
6024  if (found == 0)
6025  pg_log_error("no builtin script found for name \"%s\"", name);
6026  else /* found > 1 */
6027  pg_log_error("ambiguous builtin name: %d builtin scripts found for prefix \"%s\"", found, name);
6028 
6030  exit(1);
#define lengthof(array)
Definition: c.h:724
const void size_t len
static void listAvailableScripts(void)
Definition: pgbench.c:5990
static const BuiltinScript builtin_script[]
Definition: pgbench.c:781

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

Referenced by main().

◆ finishCon()

static void finishCon ( CState st)
static

Definition at line 7551 of file pgbench.c.

7553 {
7554  if (st->con != NULL)
7555  {
7556  PQfinish(st->con);
7557  st->con = NULL;
7558  }

References CState::con, and PQfinish().

Referenced by advanceConnectionState(), and disconnect_all().

◆ free_command()

static void free_command ( Command command)
static

Definition at line 5464 of file pgbench.c.

5466 {
5467  termPQExpBuffer(&command->lines);
5468  pg_free(command->first_line);
5469  for (int i = 0; i < command->argc; i++)
5470  pg_free(command->argv[i]);
5471  pg_free(command->varprefix);
5472 
5473  /*
5474  * It should also free expr recursively, but this is currently not needed
5475  * as only gset commands (which do not have an expression) are freed.
5476  */
5477  pg_free(command);
void pg_free(void *ptr)
Definition: fe_memutils.c:105

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

7724 {
7725  pg_free(sa);

References pg_free().

Referenced by threadRun().

◆ getExponentialRand()

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

Definition at line 1103 of file pgbench.c.

1106 {
1107  double cut,
1108  uniform,
1109  rand;
1110 
1111  /* abort if wrong parameter, but must really be checked beforehand */
1112  Assert(parameter > 0.0);
1113  cut = exp(-parameter);
1114  /* pg_prng_double value in [0, 1), uniform in (0, 1] */
1115  uniform = 1.0 - pg_prng_double(state);
1116 
1117  /*
1118  * inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
1119  */
1120  Assert((1.0 - cut) != 0.0);
1121  rand = -log(cut + (1.0 - cut) * uniform) / parameter;
1122  /* return int64 random number within between min and max */
1123  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 4420 of file pgbench.c.

4422 {
4423  return (stats->serialization_failures +
4424  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 1127 of file pgbench.c.

1130 {
1131  double stdev;
1132  double rand;
1133 
1134  /* abort if parameter is too low, but must really be checked beforehand */
1135  Assert(parameter >= MIN_GAUSSIAN_PARAM);
1136 
1137  /*
1138  * Get user specified random number from this loop, with -parameter <
1139  * stdev <= parameter
1140  *
1141  * This loop is executed until the number is in the expected range.
1142  *
1143  * As the minimum parameter is 2.0, the probability of looping is low:
1144  * sqrt(-2 ln(r)) <= 2 => r >= e^{-2} ~ 0.135, then when taking the
1145  * average sinus multiplier as 2/pi, we have a 8.6% looping probability in
1146  * the worst case. For a parameter value of 5.0, the looping probability
1147  * is about e^{-5} * 2 / pi ~ 0.43%.
1148  */
1149  do
1150  {
1151  /*
1152  * pg_prng_double generates [0, 1), but for the basic version of the
1153  * Box-Muller transform the two uniformly distributed random numbers
1154  * are expected to be in (0, 1] (see
1155  * https://en.wikipedia.org/wiki/Box-Muller_transform)
1156  */
1157  double rand1 = 1.0 - pg_prng_double(state);
1158  double rand2 = 1.0 - pg_prng_double(state);
1159 
1160  /* Box-Muller basic form transform */
1161  double var_sqrt = sqrt(-2.0 * log(rand1));
1162 
1163  stdev = var_sqrt * sin(2.0 * M_PI * rand2);
1164 
1165  /*
1166  * we may try with cos, but there may be a bias induced if the
1167  * previous value fails the test. To be on the safe side, let us try
1168  * over.
1169  */
1170  }
1171  while (stdev < -parameter || stdev >= parameter);
1172 
1173  /* stdev is in [-parameter, parameter), normalization to [0,1) */
1174  rand = (stdev + parameter) / (parameter * 2.0);
1175 
1176  /* return int64 random number within between min and max */
1177  return min + (int64) ((max - min + 1) * rand);

References Assert(), M_PI, MIN_GAUSSIAN_PARAM, and pg_prng_double().

Referenced by evalStandardFunc().

◆ getHashFnv1a()

static int64 getHashFnv1a ( int64  val,
uint64  seed 
)
static

Definition at line 1253 of file pgbench.c.

1255 {
1256  int64 result;
1257  int i;
1258 
1259  result = FNV_OFFSET_BASIS ^ seed;
1260  for (i = 0; i < 8; ++i)
1261  {
1262  int32 octet = val & 0xff;
1263 
1264  val = val >> 8;
1265  result = result ^ octet;
1266  result = result * FNV_PRIME;
1267  }
1268 
1269  return result;
signed int int32
Definition: c.h:430
#define FNV_OFFSET_BASIS
Definition: pgbench.c:83
#define FNV_PRIME
Definition: pgbench.c:82

References FNV_OFFSET_BASIS, FNV_PRIME, i, and val.

Referenced by evalStandardFunc().

◆ getHashMurmur2()

static int64 getHashMurmur2 ( int64  val,
uint64  seed 
)
static

Definition at line 1278 of file pgbench.c.

1280 {
1281  uint64 result = seed ^ MM2_MUL_TIMES_8; /* sizeof(int64) */
1282  uint64 k = (uint64) val;
1283 
1284  k *= MM2_MUL;
1285  k ^= k >> MM2_ROT;
1286  k *= MM2_MUL;
1287 
1288  result ^= k;
1289  result *= MM2_MUL;
1290 
1291  result ^= result >> MM2_ROT;
1292  result *= MM2_MUL;
1293  result ^= result >> MM2_ROT;
1294 
1295  return (int64) result;
#define MM2_MUL_TIMES_8
Definition: pgbench.c:85
#define MM2_ROT
Definition: pgbench.c:86
#define MM2_MUL
Definition: pgbench.c:84

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

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

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

Referenced by process_backslash_command().

◆ getPoissonRand()

static int64 getPoissonRand ( pg_prng_state state,
double  center 
)
static

Definition at line 1187 of file pgbench.c.

1189 {
1190  /*
1191  * Use inverse transform sampling to generate a value > 0, such that the
1192  * expected (i.e. average) value is the given argument.
1193  */
1194  double uniform;
1195 
1196  /* pg_prng_double value in [0, 1), uniform in (0, 1] */
1197  uniform = 1.0 - pg_prng_double(state);
1198 
1199  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 1980 of file pgbench.c.

1983 {
1984  int i;
1985 
1986  for (i = 0; i < command->argc - 1; i++)
1987  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 1092 of file pgbench.c.

1094 {
1095  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:138

References pg_prng_uint64_range().

Referenced by chooseScript(), and evalStandardFunc().

◆ getResultString()

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

Definition at line 4431 of file pgbench.c.

4433 {
4434  if (skipped)
4435  return "skipped";
4436  else if (failures_detailed)
4437  {
4438  switch (estatus)
4439  {
4441  return "serialization";
4443  return "deadlock";
4444  default:
4445  /* internal error which should never occur */
4446  pg_fatal("unexpected error status: %d", estatus);
4447  }
4448  }
4449  else
4450  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 3163 of file pgbench.c.

3165 {
3166  if (sqlState != NULL)
3167  {
3168  if (strcmp(sqlState, ERRCODE_T_R_SERIALIZATION_FAILURE) == 0)
3170  else if (strcmp(sqlState, ERRCODE_T_R_DEADLOCK_DETECTED) == 0)
3171  return ESTATUS_DEADLOCK_ERROR;
3172  }
3173 
3174  return ESTATUS_OTHER_SQL_ERROR;
#define ERRCODE_T_R_DEADLOCK_DETECTED
Definition: pgbench.c:76
#define ERRCODE_T_R_SERIALIZATION_FAILURE
Definition: pgbench.c:75

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

5197 {
5198  PGresult *res;
5199 
5200  /*
5201  * get the scaling factor that should be same as count(*) from
5202  * pgbench_branches if this is not a custom query
5203  */
5204  res = PQexec(con, "select count(*) from pgbench_branches");
5206  {
5207  char *sqlState = PQresultErrorField(res, PG_DIAG_SQLSTATE);
5208 
5209  pg_log_error("could not count number of branches: %s", PQerrorMessage(con));
5210 
5211  if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) == 0)
5212  pg_log_error_hint("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".",
5213  PQdb(con));
5214 
5215  exit(1);
5216  }
5217  scale = atoi(PQgetvalue(res, 0, 0));
5218  if (scale < 0)
5219  pg_fatal("invalid count(*) from pgbench_branches: \"%s\"",
5220  PQgetvalue(res, 0, 0));
5221  PQclear(res);
5222 
5223  /* warn if we override user-given -s switch */
5224  if (scale_given)
5225  pg_log_warning("scale option ignored, using count from pgbench_branches table (%d)",
5226  scale);
5227 
5228  /*
5229  * Get the partition information for the first "pgbench_accounts" table
5230  * found in search_path.
5231  *
5232  * The result is empty if no "pgbench_accounts" is found.
5233  *
5234  * Otherwise, it always returns one row even if the table is not
5235  * partitioned (in which case the partition strategy is NULL).
5236  *
5237  * The number of partitions can be 0 even for partitioned tables, if no
5238  * partition is attached.
5239  *
5240  * We assume no partitioning on any failure, so as to avoid failing on an
5241  * old version without "pg_partitioned_table".
5242  */
5243  res = PQexec(con,
5244  "select o.n, p.partstrat, pg_catalog.count(i.inhparent) "
5245  "from pg_catalog.pg_class as c "
5246  "join pg_catalog.pg_namespace as n on (n.oid = c.relnamespace) "
5247  "cross join lateral (select pg_catalog.array_position(pg_catalog.current_schemas(true), n.nspname)) as o(n) "
5248  "left join pg_catalog.pg_partitioned_table as p on (p.partrelid = c.oid) "
5249  "left join pg_catalog.pg_inherits as i on (c.oid = i.inhparent) "
5250  "where c.relname = 'pgbench_accounts' and o.n is not null "
5251  "group by 1, 2 "
5252  "order by 1 asc "
5253  "limit 1");
5254 
5256  {
5257  /* probably an older version, coldly assume no partitioning */
5259  partitions = 0;
5260  }
5261  else if (PQntuples(res) == 0)
5262  {
5263  /*
5264  * This case is unlikely as pgbench already found "pgbench_branches"
5265  * above to compute the scale.
5266  */
5267  pg_log_error("no pgbench_accounts table found in search_path");
5268  pg_log_error_hint("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".", PQdb(con));
5269  exit(1);
5270  }
5271  else /* PQntupes(res) == 1 */
5272  {
5273  /* normal case, extract partition information */
5274  if (PQgetisnull(res, 0, 1))
5276  else
5277  {
5278  char *ps = PQgetvalue(res, 0, 1);
5279 
5280  /* column must be there */
5281  Assert(ps != NULL);
5282 
5283  if (strcmp(ps, "r") == 0)
5285  else if (strcmp(ps, "h") == 0)
5287  else
5288  {
5289  /* possibly a newer version with new partition method */
5290  pg_fatal("unexpected partition method: \"%s\"", ps);
5291  }
5292  }
5293 
5294  partitions = atoi(PQgetvalue(res, 0, 2));
5295  }
5296 
5297  PQclear(res);
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:6589
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3310
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3705
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3730
char * PQresultErrorField(const PGresult *res, int fieldcode)
Definition: fe-exec.c:3295
@ PGRES_TUPLES_OK
Definition: libpq-fe.h:100
#define pg_log_error_hint(...)
Definition: logging.h:112
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:77
#define pg_log_warning(...)
Definition: pgfnames.c:24
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:56

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

Referenced by main().

◆ getTransactionStatus()

static TStatus getTransactionStatus ( PGconn con)
static

Definition at line 3467 of file pgbench.c.

3469 {
3470  PGTransactionStatusType tx_status;
3471 
3472  tx_status = PQtransactionStatus(con);
3473  switch (tx_status)
3474  {
3475  case PQTRANS_IDLE:
3476  return TSTATUS_IDLE;
3477  case PQTRANS_INTRANS:
3478  case PQTRANS_INERROR:
3479  return TSTATUS_IN_BLOCK;
3480  case PQTRANS_UNKNOWN:
3481  /* PQTRANS_UNKNOWN is expected given a broken connection */
3482  if (PQstatus(con) == CONNECTION_BAD)
3483  return TSTATUS_CONN_ERROR;
3484  /* fall through */
3485  case PQTRANS_ACTIVE:
3486  default:
3487 
3488  /*
3489  * We cannot find out whether we are in a transaction block or
3490  * not. Internal error which should never occur.
3491  */
3492  pg_log_error("unexpected transaction status %d", tx_status);
3493  return TSTATUS_OTHER_ERROR;
3494  }
3495 
3496  /* not reached */
3497  Assert(false);
3498  return TSTATUS_OTHER_ERROR;
PGTransactionStatusType PQtransactionStatus(const PGconn *conn)
Definition: fe-connect.c:6698
PGTransactionStatusType
Definition: libpq-fe.h:117
@ PQTRANS_INTRANS
Definition: libpq-fe.h:120
@ PQTRANS_IDLE
Definition: libpq-fe.h:118
@ PQTRANS_ACTIVE
Definition: libpq-fe.h:119
@ PQTRANS_UNKNOWN
Definition: libpq-fe.h:122
@ PQTRANS_INERROR
Definition: libpq-fe.h:121

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

Referenced by advanceConnectionState().

◆ getVariable()

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

Definition at line 1639 of file pgbench.c.

1641 {
1642  Variable *var;
1643  char stringform[64];
1644 
1645  var = lookupVariable(variables, name);
1646  if (var == NULL)
1647  return NULL; /* not found */
1648 
1649  if (var->svalue)
1650  return var->svalue; /* we have it in string form */
1651 
1652  /* We need to produce a string equivalent of the value */
1653  Assert(var->value.type != PGBT_NO_VALUE);
1654  if (var->value.type == PGBT_NULL)
1655  snprintf(stringform, sizeof(stringform), "NULL");
1656  else if (var->value.type == PGBT_BOOLEAN)
1657  snprintf(stringform, sizeof(stringform),
1658  "%s", var->value.u.bval ? "true" : "false");
1659  else if (var->value.type == PGBT_INT)
1660  snprintf(stringform, sizeof(stringform),
1661  INT64_FORMAT, var->value.u.ival);
1662  else if (var->value.type == PGBT_DOUBLE)
1663  snprintf(stringform, sizeof(stringform),
1664  "%.*g", DBL_DIG, var->value.u.dval);
1665  else /* internal error, unexpected type */
1666  Assert(0);
1667  var->svalue = pg_strdup(stringform);
1668  return var->svalue;
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
@ PGBT_NO_VALUE
Definition: pgbench.h:36
#define snprintf
Definition: port.h:238
char * svalue
Definition: pgbench.c:333

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

1241 {
1242  int64 n = max - min + 1;
1243 
1244  /* abort if parameter is invalid */
1246 
1247  return min - 1 + computeIterativeZipfian(state, n, s);
static int64 computeIterativeZipfian(pg_prng_state *state, int64 n, double s)
Definition: pgbench.c:1209

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

7569 {
7570  timer_exceeded = true;

References timer_exceeded.

Referenced by setalarm().

◆ initCreateFKeys()

static void initCreateFKeys ( PGconn con)
static

Definition at line 5064 of file pgbench.c.

5066 {
5067  static const char *const DDLKEYs[] = {
5068  "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
5069  "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
5070  "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
5071  "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
5072  "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
5073  };
5074  int i;
5075 
5076  fprintf(stderr, "creating foreign keys...\n");
5077  for (i = 0; i < lengthof(DDLKEYs); i++)
5078  {
5079  executeStatement(con, DDLKEYs[i]);
5080  }

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

Referenced by runInitSteps().

◆ initCreatePKeys()

static void initCreatePKeys ( PGconn con)
static

Definition at line 5026 of file pgbench.c.

5028 {
5029  static const char *const DDLINDEXes[] = {
5030  "alter table pgbench_branches add primary key (bid)",
5031  "alter table pgbench_tellers add primary key (tid)",
5032  "alter table pgbench_accounts add primary key (aid)"
5033  };
5034  int i;
5035  PQExpBufferData query;
5036 
5037  fprintf(stderr, "creating primary keys...\n");
5038  initPQExpBuffer(&query);
5039 
5040  for (i = 0; i < lengthof(DDLINDEXes); i++)
5041  {
5042  resetPQExpBuffer(&query);
5043  appendPQExpBufferStr(&query, DDLINDEXes[i]);
5044 
5045  if (index_tablespace != NULL)
5046  {
5047  char *escape_tablespace;
5048 
5049  escape_tablespace = PQescapeIdentifier(con, index_tablespace,
5050  strlen(index_tablespace));
5051  appendPQExpBuffer(&query, " using index tablespace %s", escape_tablespace);
5052  PQfreemem(escape_tablespace);
5053  }
5054 
5055  executeStatement(con, query.data);
5056  }
5057 
5058  termPQExpBuffer(&query);
void PQfreemem(void *ptr)
Definition: fe-exec.c:3865
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:4143
char * index_tablespace
Definition: pgbench.c:226
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 4724 of file pgbench.c.

4726 {
4727  /*
4728  * Note: TPC-B requires at least 100 bytes per row, and the "filler"
4729  * fields in these table declarations were intended to comply with that.
4730  * The pgbench_accounts table complies with that because the "filler"
4731  * column is set to blank-padded empty string. But for all other tables
4732  * the columns default to NULL and so don't actually take any space. We
4733  * could fix that by giving them non-null default values. However, that
4734  * would completely break comparability of pgbench results with prior
4735  * versions. Since pgbench has never pretended to be fully TPC-B compliant
4736  * anyway, we stick with the historical behavior.
4737  */
4738  struct ddlinfo
4739  {
4740  const char *table; /* table name */
4741  const char *smcols; /* column decls if accountIDs are 32 bits */
4742  const char *bigcols; /* column decls if accountIDs are 64 bits */
4743  int declare_fillfactor;
4744  };
4745  static const struct ddlinfo DDLs[] = {
4746  {
4747  "pgbench_history",
4748  "tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)",
4749  "tid int,bid int,aid bigint,delta int,mtime timestamp,filler char(22)",
4750  0
4751  },
4752  {
4753  "pgbench_tellers",
4754  "tid int not null,bid int,tbalance int,filler char(84)",
4755  "tid int not null,bid int,tbalance int,filler char(84)",
4756  1
4757  },
4758  {
4759  "pgbench_accounts",
4760  "aid int not null,bid int,abalance int,filler char(84)",
4761  "aid bigint not null,bid int,abalance int,filler char(84)",
4762  1
4763  },
4764  {
4765  "pgbench_branches",
4766  "bid int not null,bbalance int,filler char(88)",
4767  "bid int not null,bbalance int,filler char(88)",
4768  1
4769  }
4770  };
4771  int i;
4772  PQExpBufferData query;
4773 
4774  fprintf(stderr, "creating tables...\n");
4775 
4776  initPQExpBuffer(&query);
4777 
4778  for (i = 0; i < lengthof(DDLs); i++)
4779  {
4780  const struct ddlinfo *ddl = &DDLs[i];
4781 
4782  /* Construct new create table statement. */
4783  printfPQExpBuffer(&query, "create%s table %s(%s)",
4784  unlogged_tables ? " unlogged" : "",
4785  ddl->table,
4786  (scale >= SCALE_32BIT_THRESHOLD) ? ddl->bigcols : ddl->smcols);
4787 
4788  /* Partition pgbench_accounts table */
4789  if (partition_method != PART_NONE && strcmp(ddl->table, "pgbench_accounts") == 0)
4790  appendPQExpBuffer(&query,
4791  " partition by %s (aid)", PARTITION_METHOD[partition_method]);
4792  else if (ddl->declare_fillfactor)
4793  {
4794  /* fillfactor is only expected on actual tables */
4795  appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4796  }
4797 
4798  if (tablespace != NULL)
4799  {
4800  char *escape_tablespace;
4801 
4802  escape_tablespace = PQescapeIdentifier(con, tablespace, strlen(tablespace));
4803  appendPQExpBuffer(&query, " tablespace %s", escape_tablespace);
4804  PQfreemem(escape_tablespace);
4805  }
4806 
4807  executeStatement(con, query.data);
4808  }
4809 
4810  termPQExpBuffer(&query);
4811 
4812  if (partition_method != PART_NONE)
4813  createPartitions(con);
static void createPartitions(PGconn *con)
Definition: pgbench.c:4655
static const char * PARTITION_METHOD[]
Definition: pgbench.c:243
#define SCALE_32BIT_THRESHOLD
Definition: pgbench.c:263
char * tablespace
Definition: pgbench.c:225

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

Referenced by runInitSteps().

◆ initDropTables()

static void initDropTables ( PGconn con)
static

Definition at line 4633 of file pgbench.c.

4635 {
4636  fprintf(stderr, "dropping old tables...\n");
4637 
4638  /*
4639  * We drop all the tables in one command, so that whether there are
4640  * foreign key dependencies or not doesn't matter.
4641  */
4642  executeStatement(con, "drop table if exists "
4643  "pgbench_accounts, "
4644  "pgbench_branches, "
4645  "pgbench_history, "
4646  "pgbench_tellers");

References executeStatement(), and fprintf.

Referenced by runInitSteps().

◆ initGenerateDataClientSide()

static void initGenerateDataClientSide ( PGconn con)
static

Definition at line 4832 of file pgbench.c.

4834 {
4835  PQExpBufferData sql;
4836  PGresult *res;
4837  int i;
4838  int64 k;
4839  char *copy_statement;
4840 
4841  /* used to track elapsed time and estimate of the remaining time */
4842  pg_time_usec_t start;
4843  int log_interval = 1;
4844 
4845  /* Stay on the same line if reporting to a terminal */
4846  char eol = isatty(fileno(stderr)) ? '\r' : '\n';
4847 
4848  fprintf(stderr, "generating data (client-side)...\n");
4849 
4850  /*
4851  * we do all of this in one transaction to enable the backend's
4852  * data-loading optimizations
4853  */
4854  executeStatement(con, "begin");
4855 
4856  /* truncate away any old data */
4857  initTruncateTables(con);
4858 
4859  initPQExpBuffer(&sql);
4860 
4861  /*
4862  * fill branches, tellers, accounts in that order in case foreign keys
4863  * already exist
4864  */
4865  for (i = 0; i < nbranches * scale; i++)
4866  {
4867  /* "filler" column defaults to NULL */
4868  printfPQExpBuffer(&sql,
4869  "insert into pgbench_branches(bid,bbalance) values(%d,0)",
4870  i + 1);
4871  executeStatement(con, sql.data);
4872  }
4873 
4874  for (i = 0; i < ntellers * scale; i++)
4875  {
4876  /* "filler" column defaults to NULL */
4877  printfPQExpBuffer(&sql,
4878  "insert into pgbench_tellers(tid,bid,tbalance) values (%d,%d,0)",
4879  i + 1, i / ntellers + 1);
4880  executeStatement(con, sql.data);
4881  }
4882 
4883  /*
4884  * accounts is big enough to be worth using COPY and tracking runtime
4885  */
4886 
4887  /* use COPY with FREEZE on v14 and later without partitioning */
4888  if (partitions == 0 && PQserverVersion(con) >= 140000)
4889  copy_statement = "copy pgbench_accounts from stdin with (freeze on)";
4890  else
4891  copy_statement = "copy pgbench_accounts from stdin";
4892 
4893  res = PQexec(con, copy_statement);
4894 
4896  pg_fatal("unexpected copy in result: %s", PQerrorMessage(con));
4897  PQclear(res);
4898 
4899  start = pg_time_now();
4900 
4901  for (k = 0; k < (int64) naccounts * scale; k++)
4902  {
4903  int64 j = k + 1;
4904 
4905  /* "filler" column defaults to blank padded empty string */
4906  printfPQExpBuffer(&sql,
4907  INT64_FORMAT "\t" INT64_FORMAT "\t%d\t\n",
4908  j, k / naccounts + 1, 0);
4909  if (PQputline(con, sql.data))
4910  pg_fatal("PQputline failed");
4911 
4912  if (CancelRequested)
4913  break;
4914 
4915  /*
4916  * If we want to stick with the original logging, print a message each
4917  * 100k inserted rows.
4918  */
4919  if ((!use_quiet) && (j % 100000 == 0))
4920  {
4921  double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
4922  double remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
4923 
4924  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c",
4925  j, (int64) naccounts * scale,
4926  (int) (((int64) j * 100) / (naccounts * (int64) scale)),
4927  elapsed_sec, remaining_sec, eol);
4928  }
4929  /* let's not call the timing for each row, but only each 100 rows */
4930  else if (use_quiet && (j % 100 == 0))
4931  {
4932  double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
4933  double remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
4934 
4935  /* have we reached the next interval (or end)? */
4936  if ((j == scale * naccounts) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS))
4937  {
4938  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c",
4939  j, (int64) naccounts * scale,
4940  (int) (((int64) j * 100) / (naccounts * (int64) scale)), elapsed_sec, remaining_sec, eol);
4941 
4942  /* skip to the next interval */
4943  log_interval = (int) ceil(elapsed_sec / LOG_STEP_SECONDS);
4944  }
4945  }
4946  }
4947 
4948  if (eol != '\n')
4949  fputc('\n', stderr); /* Need to move to next line */
4950 
4951  if (PQputline(con, "\\.\n"))
4952  pg_fatal("very last PQputline failed");
4953  if (PQendcopy(con))
4954  pg_fatal("PQendcopy failed");
4955 
4956  termPQExpBuffer(&sql);
4957 
4958  executeStatement(con, "commit");
volatile sig_atomic_t CancelRequested
Definition: cancel.c:59
int PQserverVersion(const PGconn *conn)
Definition: fe-connect.c:6733
int PQendcopy(PGconn *conn)
Definition: fe-exec.c:2831
int PQputline(PGconn *conn, const char *string)
Definition: fe-exec.c:2800
int j
Definition: isn.c:74
@ PGRES_COPY_IN
Definition: libpq-fe.h:104
#define ntellers
Definition: pgbench.c:253
static void initTruncateTables(PGconn *con)
Definition: pgbench.c:4819
#define LOG_STEP_SECONDS
Definition: pgbench.c:174
#define nbranches
Definition: pgbench.c:252
bool use_quiet
Definition: pgbench.c:266

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

Referenced by runInitSteps().

◆ initGenerateDataServerSide()

static void initGenerateDataServerSide ( PGconn con)
static

Definition at line 4968 of file pgbench.c.

4970 {
4971  PQExpBufferData sql;
4972 
4973  fprintf(stderr, "generating data (server-side)...\n");
4974 
4975  /*
4976  * we do all of this in one transaction to enable the backend's
4977  * data-loading optimizations
4978  */
4979  executeStatement(con, "begin");
4980 
4981  /* truncate away any old data */
4982  initTruncateTables(con);
4983 
4984  initPQExpBuffer(&sql);
4985 
4986  printfPQExpBuffer(&sql,
4987  "insert into pgbench_branches(bid,bbalance) "
4988  "select bid, 0 "
4989  "from generate_series(1, %d) as bid", nbranches * scale);
4990  executeStatement(con, sql.data);
4991 
4992  printfPQExpBuffer(&sql,
4993  "insert into pgbench_tellers(tid,bid,tbalance) "
4994  "select tid, (tid - 1) / %d + 1, 0 "
4995  "from generate_series(1, %d) as tid", ntellers, ntellers * scale);
4996  executeStatement(con, sql.data);
4997 
4998  printfPQExpBuffer(&sql,
4999  "insert into pgbench_accounts(aid,bid,abalance,filler) "
5000  "select aid, (aid - 1) / %d + 1, 0, '' "
5001  "from generate_series(1, " INT64_FORMAT ") as aid",
5002  naccounts, (int64) naccounts * scale);
5003  executeStatement(con, sql.data);
5004 
5005  termPQExpBuffer(&sql);
5006 
5007  executeStatement(con, "commit");

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

Referenced by runInitSteps().

◆ initRandomState()

static void initRandomState ( pg_prng_state state)
static

Definition at line 1078 of file pgbench.c.