diff -cpr head/contrib/pgbench/README.pgbench pgbench_querymode/contrib/pgbench/README.pgbench *** head/contrib/pgbench/README.pgbench Wed Oct 17 15:19:18 2007 --- pgbench_querymode/contrib/pgbench/README.pgbench Wed Oct 17 15:20:08 2007 *************** o options *** 163,168 **** --- 163,176 ---- 0 201 2513 0 1175850569 608 0 202 2038 0 1175850569 2663 + -M querymode + + Choose the query mode from the follows: + simple: using simple query protocol. + extended: using extended protocol. + prepared: using extended protocol with prepared statements. + default is simple. + -F fillfactor Create tables(accounts, tellers and branches) with the given diff -cpr head/contrib/pgbench/pgbench.c pgbench_querymode/contrib/pgbench/pgbench.c *** head/contrib/pgbench/pgbench.c Wed Oct 17 15:19:18 2007 --- pgbench_querymode/contrib/pgbench/pgbench.c Wed Oct 17 14:53:44 2007 *************** typedef struct *** 102,107 **** --- 102,109 ---- char *value; /* its value */ } Variable; + #define MAX_FILES 128 /* max number of SQL script files allowed */ + /* * structures used in custom query mode */ *************** typedef struct *** 121,126 **** --- 123,129 ---- int nvariables; struct timeval txn_begin; /* used for measuring latencies */ int use_file; /* index in sql_files for this client */ + bool prepared[MAX_FILES]; } CState; /* *************** typedef struct *** 130,135 **** --- 133,149 ---- #define META_COMMAND 2 #define MAX_ARGS 10 + typedef enum QueryMode + { + QUERY_SIMPLE, /* simple query */ + QUERY_EXTENDED, /* extended query */ + QUERY_PREPARED, /* extended query with prepared statements */ + NUM_SQLMODE + } QueryMode; + + static QueryMode querymode = QUERY_SIMPLE; + static const char *QUERYMODE[] = { "simple", "extended", "prepared" }; + typedef struct { int type; /* command type (SQL_COMMAND or META_COMMAND) */ *************** typedef struct *** 137,144 **** char *argv[MAX_ARGS]; /* command list */ } Command; - #define MAX_FILES 128 /* max number of SQL script files allowed */ - Command **sql_files[MAX_FILES]; /* SQL script files */ int num_files; /* its number */ --- 151,156 ---- *************** static char *select_only = { *** 186,192 **** static void usage(void) { ! fprintf(stderr, "usage: pgbench [-h hostname][-p port][-c nclients][-t ntransactions][-s scaling_factor][-D varname=value][-n][-C][-v][-S][-N][-f filename][-l][-U login][-P password][-d][dbname]\n"); fprintf(stderr, "(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor] [-F fillfactor] [-U login][-P password][-d][dbname]\n"); } --- 198,204 ---- static void usage(void) { ! fprintf(stderr, "usage: pgbench [-h hostname][-p port][-c nclients][-t ntransactions][-s scaling_factor][-D varname=value][-n][-C][-v][-S][-N][-f filename][-M querymode][-l][-U login][-P password][-d][dbname]\n"); fprintf(stderr, "(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor] [-F fillfactor] [-U login][-P password][-d][dbname]\n"); } *************** assignVariables(CState * st, char *sql) *** 439,444 **** --- 451,472 ---- } static void + getQueryParams(CState *st, const Command *command, const char **params) + { + int i; + + for (i = 0; i < command->argc - 1; i++) + params[i] = getVariable(st, command->argv[i+1]); + } + + #define MAX_PREPARE_NAME 32 + static void + preparedStatementName(char *buffer, int file, int state) + { + sprintf(buffer, "P%d_%d", file, state); + } + + static void doCustom(CState * state, int n, int debug) { PGresult *res; *************** top: *** 557,585 **** if (commands[st->state]->type == SQL_COMMAND) { ! char *sql; ! if ((sql = strdup(commands[st->state]->argv[0])) == NULL ! || (sql = assignVariables(st, sql)) == NULL) { ! fprintf(stderr, "out of memory\n"); ! st->ecnt++; ! return; } ! if (debug) ! fprintf(stderr, "client %d sending %s\n", n, sql); ! if (PQsendQuery(st->con, sql) == 0) { if (debug) ! fprintf(stderr, "PQsendQuery(%s)failed\n", sql); st->ecnt++; } else - { st->listen = 1; /* flags that should be listened */ - } - free(sql); } else if (commands[st->state]->type == META_COMMAND) { --- 585,667 ---- if (commands[st->state]->type == SQL_COMMAND) { ! const Command *command = commands[st->state]; ! int r; ! if (querymode == QUERY_SIMPLE) { ! char *sql; ! ! if ((sql = strdup(command->argv[0])) == NULL ! || (sql = assignVariables(st, sql)) == NULL) ! { ! fprintf(stderr, "out of memory\n"); ! st->ecnt++; ! return; ! } ! ! if (debug) ! fprintf(stderr, "client %d sending %s\n", n, sql); ! r = PQsendQuery(st->con, sql); ! free(sql); } + else if (querymode == QUERY_EXTENDED) + { + const char *sql = command->argv[0]; + const char *params[MAX_ARGS]; ! getQueryParams(st, command, params); ! ! if (debug) ! fprintf(stderr, "client %d sending %s\n", n, sql); ! r = PQsendQueryParams(st->con, sql, command->argc - 1, ! NULL, params, NULL, NULL, 0); ! } ! else if (querymode == QUERY_PREPARED) { + char name[MAX_PREPARE_NAME]; + const char *params[MAX_ARGS]; + + if (!st->prepared[st->use_file]) + { + int j; + + for (j = 0; commands[j] != NULL; j++) + { + PGresult *res; + char name[MAX_PREPARE_NAME]; + + if (commands[j]->type != SQL_COMMAND) + continue; + preparedStatementName(name, st->use_file, j); + res = PQprepare(st->con, name, + commands[j]->argv[0], commands[j]->argc - 1, NULL); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + fprintf(stderr, "%s", PQerrorMessage(st->con)); + PQclear(res); + } + st->prepared[st->use_file] = true; + } + + getQueryParams(st, command, params); + preparedStatementName(name, st->use_file, st->state); + if (debug) ! fprintf(stderr, "client %d sending %s\n", n, name); ! r = PQsendQueryPrepared(st->con, name, command->argc - 1, ! params, NULL, NULL, 0); ! } ! else /* unknown sql mode */ ! r = 0; ! ! if (r == 0) ! { ! if (debug) ! fprintf(stderr, "client %d cannot send %s\n", n, command->argv[0]); st->ecnt++; } else st->listen = 1; /* flags that should be listened */ } else if (commands[st->state]->type == META_COMMAND) { *************** init(void) *** 902,907 **** --- 984,1046 ---- PQfinish(con); } + /* + * Parse the raw sql and replace :param to $n. + */ + static bool + parseQuery(Command *cmd, const char *raw_sql) + { + int i, + j; + char *sql, + *p, + *name; + + sql = strdup(raw_sql); + if (sql == NULL) + return false; + cmd->argc = 1; + + i = 0; + while ((p = strchr(&sql[i], ':')) != NULL) + { + char param[12]; + int paramln; + + if (cmd->argc > MAX_ARGS) + { + fprintf(stderr, "too many args: %s\n", raw_sql); + return false; + } + + i = j = p - sql; + do + { + i++; + } while (isalnum((unsigned char) sql[i]) || sql[i] == '_'); + if (i == j + 1) + continue; + + name = malloc(i - j); + if (name == NULL) + return false; + memcpy(name, &sql[j + 1], i - (j + 1)); + name[i - (j + 1)] = '\0'; + + paramln = sprintf(param, "$%d", cmd->argc); + if (paramln != i - j) + memmove(&sql[j + paramln], &sql[i], strlen(&sql[i]) + 1); + strncpy(&sql[j], param, paramln); + cmd->argv[cmd->argc] = name; + cmd->argc++; + + i = j + paramln; + } + + cmd->argv[0] = sql; + return true; + } + static Command * process_commands(char *buf) { *************** process_commands(char *buf) *** 1008,1017 **** { my_commands->type = SQL_COMMAND; ! if ((my_commands->argv[0] = strdup(p)) == NULL) ! return NULL; ! ! my_commands->argc++; } return my_commands; --- 1147,1167 ---- { my_commands->type = SQL_COMMAND; ! switch (querymode) ! { ! case QUERY_SIMPLE: ! if ((my_commands->argv[0] = strdup(p)) == NULL) ! return NULL; ! my_commands->argc++; ! break; ! case QUERY_EXTENDED: ! case QUERY_PREPARED: ! if (!parseQuery(my_commands, p)) ! return NULL; ! break; ! default: ! return NULL; ! } } return my_commands; *************** printResults( *** 1188,1193 **** --- 1338,1344 ---- printf("transaction type: %s\n", s); printf("scaling factor: %d\n", scale); + printf("query mode: %s\n", QUERYMODE[querymode]); printf("number of clients: %d\n", nclients); printf("number of transactions per client: %d\n", nxacts); printf("number of transactions actually processed: %d/%d\n", normal_xacts, nxacts * nclients); *************** main(int argc, char **argv) *** 1255,1261 **** memset(state, 0, sizeof(*state)); ! while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:U:P:CNSlf:D:F:")) != -1) { switch (c) { --- 1406,1412 ---- memset(state, 0, sizeof(*state)); ! while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:U:P:CNSlf:D:F:M:")) != -1) { switch (c) { *************** main(int argc, char **argv) *** 1365,1370 **** --- 1516,1531 ---- if ((fillfactor < 10) || (fillfactor > 100)) { fprintf(stderr, "invalid fillfactor: %d\n", fillfactor); + exit(1); + } + break; + case 'M': + for (querymode = 0; querymode < NUM_SQLMODE; querymode++) + if (strcmp(optarg, QUERYMODE[querymode]) == 0) + break; + if (querymode >= NUM_SQLMODE) + { + fprintf(stderr, "invalid querymode: %s\n", optarg); exit(1); } break;