diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml
index 0c60077e1f..2c0827a440 100644
--- a/doc/src/sgml/ref/pgbench.sgml
+++ b/doc/src/sgml/ref/pgbench.sgml
@@ -326,13 +326,25 @@ pgbench optionsd
+
+
+
+
+ Create extra indexes on the standard tables for referenced FK columns.
+ (This option adds the i step to the initialization
+ step sequence, if it is not already present.)
+
+
+
+
Create foreign key constraints between the standard tables.
(This option adds the f step to the initialization
- step sequence, if it is not already present.)
+ step sequence, if it is not already present.) Also implies
+ .
@@ -410,7 +422,7 @@ pgbench optionsd
Add the specified built-in script to the list of scripts to be executed.
- Available built-in scripts are: tpcb-like,
+ Available built-in scripts are: tpcb-like, insert-only,
simple-update and select-only.
Unambiguous prefixes of built-in names are accepted.
With the special name list, show the list of built-in scripts
@@ -489,6 +501,16 @@ pgbench optionsd
+
+
+
+
+ Run built-in insert-only script.
+ Shorthand for .
+
+
+
+
threadsthreads
@@ -986,6 +1008,11 @@ pgbench optionsd
If you select the select-only built-in (also ),
only the SELECT is issued.
+
+
+ If you select the insert-only built-in,
+ only the INSERT is issued.
+
diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index 4aeccd93af..cb30082c58 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -85,6 +85,12 @@
#define MM2_MUL_TIMES_8 UINT64CONST(0x35253c9ade8f4ca8)
#define MM2_ROT 47
+/* Filler strings of indicated lenghts */
+#define FILLER_ACCOUNTS_PADDING "123456789012345678901234567890123456789012345678901234567890123456789012345678901234"
+#define FILLER_BRANCHES_PADDING "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678"
+#define FILLER_HISTORY_PADDING "1234567890123456789012"
+#define FILLER_TELLERS_PADDING "123456789012345678901234567890123456789012345678901234567890123456789012345678901234"
+
/*
* Multi-platform socket set implementations
*/
@@ -616,7 +622,7 @@ static const BuiltinScript builtin_script[] =
"SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
"UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;\n"
"UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;\n"
- "INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n"
+ "INSERT INTO pgbench_history (tid, bid, aid, delta, mtime, filler) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP, " FILLER_HISTORY_PADDING ");\n"
"END;\n"
},
{
@@ -629,7 +635,7 @@ static const BuiltinScript builtin_script[] =
"BEGIN;\n"
"UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;\n"
"SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
- "INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n"
+ "INSERT INTO pgbench_history (tid, bid, aid, delta, mtime, filler) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP, " FILLER_HISTORY_PADDING ");\n"
"END;\n"
},
{
@@ -637,6 +643,15 @@ static const BuiltinScript builtin_script[] =
"",
"\\set aid random(1, " CppAsString2(naccounts) " * :scale)\n"
"SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
+ },
+ {
+ "insert-only",
+ "",
+ "\\set aid random(1, " CppAsString2(naccounts) " * :scale)\n"
+ "\\set bid random(1, " CppAsString2(nbranches) " * :scale)\n"
+ "\\set tid random(1, " CppAsString2(ntellers) " * :scale)\n"
+ "\\set delta random(-5000, 5000)\n"
+ "INSERT INTO pgbench_history (tid, bid, aid, delta, mtime, filler) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP, " FILLER_HISTORY_PADDING ");\n"
}
};
@@ -703,6 +718,7 @@ usage(void)
" -n, --no-vacuum do not run VACUUM during initialization\n"
" -q, --quiet quiet logging (one message each 5 seconds)\n"
" -s, --scale=NUM scaling factor\n"
+ " --extra-indexes create additional indexes on the tables\n"
" --foreign-keys create foreign key constraints between tables\n"
" --index-tablespace=TABLESPACE\n"
" create indexes in the specified tablespace\n"
@@ -719,6 +735,8 @@ usage(void)
" (same as \"-b simple-update\")\n"
" -S, --select-only perform SELECT-only transactions\n"
" (same as \"-b select-only\")\n"
+ " --insert-only perform INSERT-only transactions\n"
+ " (same as \"-b insert-only\")\n"
"\nBenchmarking options:\n"
" -c, --client=NUM number of concurrent database clients (default: 1)\n"
" -C, --connect establish new connection for each transaction\n"
@@ -4009,14 +4027,12 @@ initCreateTables(PGconn *con)
{
/*
* Note: TPC-B requires at least 100 bytes per row, and the "filler"
- * fields in these table declarations were intended to comply with that.
- * The pgbench_accounts table complies with that because the "filler"
- * column is set to blank-padded empty string. But for all other tables
- * the columns default to NULL and so don't actually take any space. We
- * could fix that by giving them non-null default values. However, that
- * would completely break comparability of pgbench results with prior
- * versions. Since pgbench has never pretended to be fully TPC-B compliant
- * anyway, we stick with the historical behavior.
+ * fields in these table declarations comply with that. This does change
+ * how "pgbench" has traditionally handled this, which in versions prior
+ * to 15 used NULL values for this field for every table but the accounts
+ * table. It was determined that having this timing data be comparable to
+ * other benchmarking tools was more important than compatibility with
+ * previous runs of pgbench.
*/
struct ddlinfo
{
@@ -4146,18 +4162,16 @@ initGenerateDataClientSide(PGconn *con)
*/
for (i = 0; i < nbranches * scale; i++)
{
- /* "filler" column defaults to NULL */
printfPQExpBuffer(&sql,
- "insert into pgbench_branches(bid,bbalance) values(%d,0)",
+ "insert into pgbench_branches(bid,bbalance,filler) values(%d,0,'" FILLER_BRANCHES_PADDING "')",
i + 1);
executeStatement(con, sql.data);
}
for (i = 0; i < ntellers * scale; i++)
{
- /* "filler" column defaults to NULL */
printfPQExpBuffer(&sql,
- "insert into pgbench_tellers(tid,bid,tbalance) values (%d,%d,0)",
+ "insert into pgbench_tellers(tid,bid,tbalance,filler) values (%d,%d,0,'" FILLER_TELLERS_PADDING "')",
i + 1, i / ntellers + 1);
executeStatement(con, sql.data);
}
@@ -4181,7 +4195,7 @@ initGenerateDataClientSide(PGconn *con)
/* "filler" column defaults to blank padded empty string */
printfPQExpBuffer(&sql,
- INT64_FORMAT "\t" INT64_FORMAT "\t%d\t\n",
+ INT64_FORMAT "\t" INT64_FORMAT "\t%d\t" FILLER_ACCOUNTS_PADDING "\n",
j, k / naccounts + 1, 0);
if (PQputline(con, sql.data))
{
@@ -4248,8 +4262,8 @@ initGenerateDataClientSide(PGconn *con)
* Fill the standard tables with some data generated on the server
*
* As already the case with the client-side data generation, the filler
- * column defaults to NULL in pgbench_branches and pgbench_tellers,
- * and is a blank-padded string in pgbench_accounts.
+ * columns default to blank-padded strings, so bring the record size up to
+ * 100.
*/
static void
initGenerateDataServerSide(PGconn *con)
@@ -4270,20 +4284,20 @@ initGenerateDataServerSide(PGconn *con)
initPQExpBuffer(&sql);
printfPQExpBuffer(&sql,
- "insert into pgbench_branches(bid,bbalance) "
- "select bid, 0 "
+ "insert into pgbench_branches(bid,bbalance,filler) "
+ "select bid, 0, '" FILLER_BRANCHES_PADDING "' "
"from generate_series(1, %d) as bid", nbranches * scale);
executeStatement(con, sql.data);
printfPQExpBuffer(&sql,
- "insert into pgbench_tellers(tid,bid,tbalance) "
- "select tid, (tid - 1) / %d + 1, 0 "
+ "insert into pgbench_tellers(tid,bid,tbalance,filler) "
+ "select tid, (tid - 1) / %d + 1, 0, '" FILLER_TELLERS_PADDING "' "
"from generate_series(1, %d) as tid", ntellers, ntellers * scale);
executeStatement(con, sql.data);
printfPQExpBuffer(&sql,
"insert into pgbench_accounts(aid,bid,abalance,filler) "
- "select aid, (aid - 1) / %d + 1, 0, '' "
+ "select aid, (aid - 1) / %d + 1, 0, '" FILLER_ACCOUNTS_PADDING "' "
"from generate_series(1, " INT64_FORMAT ") as aid",
naccounts, (int64) naccounts * scale);
executeStatement(con, sql.data);
@@ -4366,6 +4380,28 @@ initCreateFKeys(PGconn *con)
}
}
+/*
+ * Create extra indexes on the standard tables
+ */
+static void
+initCreateExtraIndexes(PGconn *con)
+{
+ static const char *const DDLKEYs[] = {
+ "create index pgbench_tellers_bid_idx on pgbench_tellers (bid)",
+ "create index pgbench_accounts_bid_idx on pgbench_accounts (bid)",
+ "create index pgbench_history_aid_idx on pgbench_history (aid)",
+ "create index pgbench_history_bid_idx on pgbench_history (bid)",
+ "create index pgbench_history_tid_idx on pgbench_history (tid)"
+ };
+ int i;
+
+ fprintf(stderr, "creating extra indexes...\n");
+ for (i = 0; i < lengthof(DDLKEYs); i++)
+ {
+ executeStatement(con, DDLKEYs[i]);
+ }
+}
+
/*
* Validate an initialization-steps string
*
@@ -4448,6 +4484,10 @@ runInitSteps(const char *initialize_steps)
op = "foreign keys";
initCreateFKeys(con);
break;
+ case 'i':
+ op = "extra indexes";
+ initCreateExtraIndexes(con);
+ break;
case ' ':
break; /* ignore */
default:
@@ -5769,6 +5809,8 @@ main(int argc, char **argv)
{"show-script", required_argument, NULL, 10},
{"partitions", required_argument, NULL, 11},
{"partition-method", required_argument, NULL, 12},
+ {"insert-only", no_argument, NULL, 13},
+ {"extra-indexes", no_argument, NULL, 14},
{NULL, 0, NULL, 0}
};
@@ -5776,6 +5818,7 @@ main(int argc, char **argv)
bool is_init_mode = false; /* initialize mode? */
char *initialize_steps = NULL;
bool foreign_keys = false;
+ bool extra_indexes = false;
bool is_no_vacuum = false;
bool do_vacuum_accounts = false; /* vacuum accounts table? */
int optindex;
@@ -6137,6 +6180,15 @@ main(int argc, char **argv)
exit(1);
}
break;
+ case 13: /* insert-only */
+ process_builtin(findBuiltin("insert-only"), 1);
+ benchmarking_option_set = true;
+ internal_script_used = true;
+ break;
+ case 14: /* indexes */
+ initialization_option_set = true;
+ extra_indexes = true;
+ break;
default:
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit(1);
@@ -6252,6 +6304,19 @@ main(int argc, char **argv)
}
}
+ /* foreign_keys always implies extra_indexes */
+ if (extra_indexes || foreign_keys)
+ {
+ /* Add 'i' to end of initialize_steps, if not already there */
+ if (strchr(initialize_steps, 'i') == NULL)
+ {
+ initialize_steps = (char *)
+ pg_realloc(initialize_steps,
+ strlen(initialize_steps) + 2);
+ strcat(initialize_steps, "i");
+ }
+ }
+
runInitSteps(initialize_steps);
exit(0);
}
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index c2a35a488a..e8cd07e9c9 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -102,15 +102,13 @@ all: all-lib check-libpq-refs
include $(top_srcdir)/src/Makefile.shlib
backend_src = $(top_srcdir)/src/backend
-# Check for functions that libpq must not call, currently just exit().
-# (Ideally we'd reject abort() too, but there are various scenarios where
-# build toolchains silently insert abort() calls, e.g. when profiling.)
-# If nm doesn't exist or doesn't work on shlibs, this test will do nothing,
-# which is fine. The exclusion of __cxa_atexit is necessary on OpenBSD,
-# which seems to insert references to that even in pure C code.
+# Check for functions that libpq must not call, currently abort() and exit().
+# If nm doesn't exist or doesn't work on shlibs, this test will silently
+# do nothing, which is fine. The exclusion of _eprintf.o is to prevent
+# complaining about infrastructure on ancient macOS releases.
.PHONY: check-libpq-refs
check-libpq-refs: $(shlib)
- ! nm -A -g -u $< 2>/dev/null | grep -v __cxa_atexit | grep exit
+ ! nm -A -g -u $< 2>/dev/null | grep -v '_eprintf\.o:' | grep -e abort -e exit
# Make dependencies on pg_config_paths.h visible in all builds.
fe-connect.o: fe-connect.c $(top_builddir)/src/port/pg_config_paths.h