aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/amcheck/expected/check_btree.out8
-rw-r--r--contrib/amcheck/sql/check_btree.sql7
-rw-r--r--contrib/amcheck/verify_common.c24
-rw-r--r--contrib/amcheck/verify_common.h2
-rw-r--r--doc/src/sgml/client-auth.sgml16
-rw-r--r--doc/src/sgml/func.sgml6
-rw-r--r--doc/src/sgml/libpq.sgml24
-rw-r--r--doc/src/sgml/monitoring.sgml4
-rw-r--r--doc/src/sgml/protocol.sgml26
-rw-r--r--doc/src/sgml/ref/psql-ref.sgml9
-rw-r--r--src/backend/access/common/toast_compression.c14
-rw-r--r--src/backend/access/transam/xlog.c17
-rw-r--r--src/backend/catalog/index.c8
-rw-r--r--src/backend/libpq/hba.c38
-rw-r--r--src/backend/libpq/pg_ident.conf.sample26
-rw-r--r--src/backend/replication/pgoutput/pgoutput.c2
-rw-r--r--src/backend/storage/aio/method_worker.c6
-rw-r--r--src/backend/storage/ipc/procarray.c52
-rw-r--r--src/backend/utils/adt/jsonb_util.c43
-rw-r--r--src/backend/utils/adt/timestamp.c20
-rw-r--r--src/bin/psql/command.c7
-rw-r--r--src/bin/psql/tab-complete.in.c12
-rw-r--r--src/include/storage/procarray.h1
-rw-r--r--src/interfaces/libpq/fe-connect.c54
-rw-r--r--src/interfaces/libpq/libpq-int.h2
-rw-r--r--src/interfaces/libpq/t/006_service.pl79
-rw-r--r--src/test/authentication/t/003_peer.pl18
27 files changed, 337 insertions, 188 deletions
diff --git a/contrib/amcheck/expected/check_btree.out b/contrib/amcheck/expected/check_btree.out
index c6f4b16c556..6558f2c5a4f 100644
--- a/contrib/amcheck/expected/check_btree.out
+++ b/contrib/amcheck/expected/check_btree.out
@@ -60,6 +60,14 @@ SELECT bt_index_parent_check('bttest_a_brin_idx');
ERROR: expected "btree" index as targets for verification
DETAIL: Relation "bttest_a_brin_idx" is a brin index.
ROLLBACK;
+-- verify partitioned indexes are rejected (error)
+BEGIN;
+CREATE TABLE bttest_partitioned (a int, b int) PARTITION BY list (a);
+CREATE INDEX bttest_btree_partitioned_idx ON bttest_partitioned USING btree (b);
+SELECT bt_index_parent_check('bttest_btree_partitioned_idx');
+ERROR: expected index as targets for verification
+DETAIL: This operation is not supported for partitioned indexes.
+ROLLBACK;
-- normal check outside of xact
SELECT bt_index_check('bttest_a_idx');
bt_index_check
diff --git a/contrib/amcheck/sql/check_btree.sql b/contrib/amcheck/sql/check_btree.sql
index 0793dbfeebd..171f7f691ec 100644
--- a/contrib/amcheck/sql/check_btree.sql
+++ b/contrib/amcheck/sql/check_btree.sql
@@ -52,6 +52,13 @@ CREATE INDEX bttest_a_brin_idx ON bttest_a USING brin(id);
SELECT bt_index_parent_check('bttest_a_brin_idx');
ROLLBACK;
+-- verify partitioned indexes are rejected (error)
+BEGIN;
+CREATE TABLE bttest_partitioned (a int, b int) PARTITION BY list (a);
+CREATE INDEX bttest_btree_partitioned_idx ON bttest_partitioned USING btree (b);
+SELECT bt_index_parent_check('bttest_btree_partitioned_idx');
+ROLLBACK;
+
-- normal check outside of xact
SELECT bt_index_check('bttest_a_idx');
-- more expansive tests
diff --git a/contrib/amcheck/verify_common.c b/contrib/amcheck/verify_common.c
index d095e62ce55..a31ce06ed99 100644
--- a/contrib/amcheck/verify_common.c
+++ b/contrib/amcheck/verify_common.c
@@ -18,11 +18,13 @@
#include "verify_common.h"
#include "catalog/index.h"
#include "catalog/pg_am.h"
+#include "commands/defrem.h"
#include "commands/tablecmds.h"
#include "utils/guc.h"
#include "utils/syscache.h"
static bool amcheck_index_mainfork_expected(Relation rel);
+static bool index_checkable(Relation rel, Oid am_id);
/*
@@ -155,23 +157,21 @@ amcheck_lock_relation_and_check(Oid indrelid,
* callable by non-superusers. If granted, it's useful to be able to check a
* whole cluster.
*/
-bool
+static bool
index_checkable(Relation rel, Oid am_id)
{
- if (rel->rd_rel->relkind != RELKIND_INDEX ||
- rel->rd_rel->relam != am_id)
- {
- HeapTuple amtup;
- HeapTuple amtuprel;
+ if (rel->rd_rel->relkind != RELKIND_INDEX)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("expected index as targets for verification"),
+ errdetail_relkind_not_supported(rel->rd_rel->relkind)));
- amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(am_id));
- amtuprel = SearchSysCache1(AMOID, ObjectIdGetDatum(rel->rd_rel->relam));
+ if (rel->rd_rel->relam != am_id)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("expected \"%s\" index as targets for verification", NameStr(((Form_pg_am) GETSTRUCT(amtup))->amname)),
+ errmsg("expected \"%s\" index as targets for verification", get_am_name(am_id)),
errdetail("Relation \"%s\" is a %s index.",
- RelationGetRelationName(rel), NameStr(((Form_pg_am) GETSTRUCT(amtuprel))->amname))));
- }
+ RelationGetRelationName(rel), get_am_name(rel->rd_rel->relam))));
if (RELATION_IS_OTHER_TEMP(rel))
ereport(ERROR,
@@ -182,7 +182,7 @@ index_checkable(Relation rel, Oid am_id)
if (!rel->rd_index->indisvalid)
ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("cannot check index \"%s\"",
RelationGetRelationName(rel)),
errdetail("Index is not valid.")));
diff --git a/contrib/amcheck/verify_common.h b/contrib/amcheck/verify_common.h
index 42ef9c20fe2..3f4c57f963d 100644
--- a/contrib/amcheck/verify_common.h
+++ b/contrib/amcheck/verify_common.h
@@ -26,5 +26,3 @@ extern void amcheck_lock_relation_and_check(Oid indrelid,
Oid am_id,
IndexDoCheckCallback check,
LOCKMODE lockmode, void *state);
-
-extern bool index_checkable(Relation rel, Oid am_id);
diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index 832b616a7bb..51b95ed04f3 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -1003,8 +1003,9 @@ local db1,db2,@demodbs all md5
the remainder of the field is treated as a regular expression.
(See <xref linkend="posix-syntax-details"/> for details of
<productname>PostgreSQL</productname>'s regular expression syntax.) The regular
- expression can include a single capture, or parenthesized subexpression,
- which can then be referenced in the <replaceable>database-username</replaceable>
+ expression can include a single capture, or parenthesized subexpression.
+ The portion of the system user name that matched the capture can then
+ be referenced in the <replaceable>database-username</replaceable>
field as <literal>\1</literal> (backslash-one). This allows the mapping of
multiple user names in a single line, which is particularly useful for
simple syntax substitutions. For example, these entries
@@ -1022,12 +1023,11 @@ mymap /^(.*)@otherdomain\.com$ guest
<para>
If the <replaceable>database-username</replaceable> field starts with
a slash (<literal>/</literal>), the remainder of the field is treated
- as a regular expression (see <xref linkend="posix-syntax-details"/>
- for details of <productname>PostgreSQL</productname>'s regular
- expression syntax). It is not possible to use <literal>\1</literal>
- to use a capture from regular expression on
- <replaceable>system-username</replaceable> for a regular expression
- on <replaceable>database-username</replaceable>.
+ as a regular expression.
+ When the <replaceable>database-username</replaceable> field is a regular
+ expression, it is not possible to use <literal>\1</literal> within it to
+ refer to a capture from the <replaceable>system-username</replaceable>
+ field.
</para>
<tip>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 6b327d4fd81..f5a0e0954a1 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -11247,10 +11247,10 @@ now()
statement (more specifically, the time of receipt of the latest command
message from the client).
<function>statement_timestamp()</function> and <function>transaction_timestamp()</function>
- return the same value during the first command of a transaction, but might
- differ during subsequent commands.
+ return the same value during the first statement of a transaction, but might
+ differ during subsequent statements.
<function>clock_timestamp()</function> returns the actual current time, and
- therefore its value changes even within a single SQL command.
+ therefore its value changes even within a single SQL statement.
<function>timeofday()</function> is a historical
<productname>PostgreSQL</productname> function. Like
<function>clock_timestamp()</function>, it returns the actual current time,
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index b2c2cf9eac8..5bf59a19855 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -2320,6 +2320,19 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
</listitem>
</varlistentry>
+ <varlistentry id="libpq-connect-servicefile" xreflabel="servicefile">
+ <term><literal>servicefile</literal></term>
+ <listitem>
+ <para>
+ This option specifies the name of the per-user connection service file
+ (see <xref linkend="libpq-pgservice"/>).
+ Defaults to <filename>~/.pg_service.conf</filename>, or
+ <filename>%APPDATA%\postgresql\.pg_service.conf</filename> on
+ Microsoft Windows.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="libpq-connect-target-session-attrs" xreflabel="target_session_attrs">
<term><literal>target_session_attrs</literal></term>
<listitem>
@@ -9140,12 +9153,8 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
<indexterm>
<primary><envar>PGSERVICEFILE</envar></primary>
</indexterm>
- <envar>PGSERVICEFILE</envar> specifies the name of the per-user
- connection service file
- (see <xref linkend="libpq-pgservice"/>).
- Defaults to <filename>~/.pg_service.conf</filename>, or
- <filename>%APPDATA%\postgresql\.pg_service.conf</filename> on
- Microsoft Windows.
+ <envar>PGSERVICEFILE</envar> behaves the same as the
+ <xref linkend="libpq-connect-servicefile"/> connection parameter.
</para>
</listitem>
@@ -9576,7 +9585,8 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
On Microsoft Windows, it is named
<filename>%APPDATA%\postgresql\.pg_service.conf</filename> (where
<filename>%APPDATA%</filename> refers to the Application Data subdirectory
- in the user's profile). A different file name can be specified by
+ in the user's profile). A different file name can be specified using the
+ <literal>servicefile</literal> key word in a libpq connection string or by
setting the environment variable <envar>PGSERVICEFILE</envar>.
The system-wide file is named <filename>pg_service.conf</filename>.
By default it is sought in the <filename>etc</filename> directory
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 4265a22d4de..823afe1b30b 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -3980,6 +3980,7 @@ description | Waiting for a newly initialized WAL file to reach durable storage
</para>
<para>
Estimated number of rows inserted since this table was last vacuumed
+ (not counting <command>VACUUM FULL</command>)
</para></entry>
</row>
@@ -4066,7 +4067,8 @@ description | Waiting for a newly initialized WAL file to reach durable storage
<structfield>total_vacuum_time</structfield> <type>double precision</type>
</para>
<para>
- Total time this table has been manually vacuumed, in milliseconds.
+ Total time this table has been manually vacuumed, in milliseconds
+ (not counting <command>VACUUM FULL</command>).
(This includes the time spent sleeping due to cost-based delays.)
</para></entry>
</row>
diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index 4cfd9767f7c..e74b5be1eff 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -886,6 +886,16 @@ SELCT 1/0;<!-- this typo is intentional -->
Errors detected at semantic analysis or later, such as a misspelled
table or column name, do not have this effect.
</para>
+
+ <para>
+ Lastly, note that all the statements within the Query message will
+ observe the same value of <function>statement_timestamp()</function>,
+ since that timestamp is updated only upon receipt of the Query
+ message. This will result in them all observing the same
+ value of <function>transaction_timestamp()</function> as well,
+ except in cases where the query string ends a previously-started
+ transaction and begins a new one.
+ </para>
</sect3>
</sect2>
@@ -3482,6 +3492,7 @@ psql "dbname=postgres replication=database" -c "IDENTIFY_SYSTEM;"
<para>
Boolean option to use binary transfer mode. Binary mode is faster
than the text mode but slightly less robust.
+ The default is <literal>off</literal>.
</para>
</listitem>
</varlistentry>
@@ -3494,6 +3505,7 @@ psql "dbname=postgres replication=database" -c "IDENTIFY_SYSTEM;"
<para>
Boolean option to enable sending the messages that are written
by <function>pg_logical_emit_message</function>.
+ The default is <literal>off</literal>.
</para>
</listitem>
</varlistentry>
@@ -3504,11 +3516,13 @@ psql "dbname=postgres replication=database" -c "IDENTIFY_SYSTEM;"
</term>
<listitem>
<para>
- Boolean option to enable streaming of in-progress transactions.
- It accepts an additional value "parallel" to enable sending extra
- information with some messages to be used for parallelisation.
- Minimum protocol version 2 is required to turn it on. Minimum protocol
- version 4 is required for the "parallel" option.
+ Option to enable streaming of in-progress transactions. Valid values are
+ <literal>off</literal> (the default), <literal>on</literal> and
+ <literal>parallel</literal>. The setting <literal>parallel</literal>
+ enables sending extra information with some messages to be used for
+ parallelization. Minimum protocol version 2 is required to turn it
+ <literal>on</literal>. Minimum protocol version 4 is required for the
+ <literal>parallel</literal> value.
</para>
</listitem>
</varlistentry>
@@ -3521,6 +3535,7 @@ psql "dbname=postgres replication=database" -c "IDENTIFY_SYSTEM;"
<para>
Boolean option to enable two-phase transactions. Minimum protocol
version 3 is required to turn it on.
+ The default is <literal>off</literal>.
</para>
</listitem>
</varlistentry>
@@ -3537,6 +3552,7 @@ psql "dbname=postgres replication=database" -c "IDENTIFY_SYSTEM;"
to send the changes regardless of their origin. This can be used
to avoid loops (infinite replication of the same data) among
replication nodes.
+ The default is <literal>any</literal>.
</para>
</listitem>
</varlistentry>
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 95f4cac2467..4f7b11175c6 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -4623,6 +4623,15 @@ bar
</listitem>
</varlistentry>
+ <varlistentry id="app-psql-variables-servicefile">
+ <term><varname>SERVICEFILE</varname></term>
+ <listitem>
+ <para>
+ The service file name, if applicable.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="app-psql-variables-shell-error">
<term><varname>SHELL_ERROR</varname></term>
<listitem>
diff --git a/src/backend/access/common/toast_compression.c b/src/backend/access/common/toast_compression.c
index 21f2f4af97e..926f1e4008a 100644
--- a/src/backend/access/common/toast_compression.c
+++ b/src/backend/access/common/toast_compression.c
@@ -25,11 +25,11 @@
/* GUC */
int default_toast_compression = TOAST_PGLZ_COMPRESSION;
-#define NO_LZ4_SUPPORT() \
+#define NO_COMPRESSION_SUPPORT(method) \
ereport(ERROR, \
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \
- errmsg("compression method lz4 not supported"), \
- errdetail("This functionality requires the server to be built with lz4 support.")))
+ errmsg("compression method %s not supported", method), \
+ errdetail("This functionality requires the server to be built with %s support.", method)))
/*
* Compress a varlena using PGLZ.
@@ -139,7 +139,7 @@ struct varlena *
lz4_compress_datum(const struct varlena *value)
{
#ifndef USE_LZ4
- NO_LZ4_SUPPORT();
+ NO_COMPRESSION_SUPPORT("lz4");
return NULL; /* keep compiler quiet */
#else
int32 valsize;
@@ -182,7 +182,7 @@ struct varlena *
lz4_decompress_datum(const struct varlena *value)
{
#ifndef USE_LZ4
- NO_LZ4_SUPPORT();
+ NO_COMPRESSION_SUPPORT("lz4");
return NULL; /* keep compiler quiet */
#else
int32 rawsize;
@@ -215,7 +215,7 @@ struct varlena *
lz4_decompress_datum_slice(const struct varlena *value, int32 slicelength)
{
#ifndef USE_LZ4
- NO_LZ4_SUPPORT();
+ NO_COMPRESSION_SUPPORT("lz4");
return NULL; /* keep compiler quiet */
#else
int32 rawsize;
@@ -289,7 +289,7 @@ CompressionNameToMethod(const char *compression)
else if (strcmp(compression, "lz4") == 0)
{
#ifndef USE_LZ4
- NO_LZ4_SUPPORT();
+ NO_COMPRESSION_SUPPORT("lz4");
#endif
return TOAST_LZ4_COMPRESSION;
}
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 88fb9b45b2a..8e7827c6ed9 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -449,7 +449,6 @@ typedef struct XLogCtlData
/* Protected by info_lck: */
XLogwrtRqst LogwrtRqst;
XLogRecPtr RedoRecPtr; /* a recent copy of Insert->RedoRecPtr */
- FullTransactionId ckptFullXid; /* nextXid of latest checkpoint */
XLogRecPtr asyncXactLSN; /* LSN of newest async commit/abort */
XLogRecPtr replicationSlotMinLSN; /* oldest LSN needed by any slot */
@@ -5744,7 +5743,6 @@ StartupXLOG(void)
SetMultiXactIdLimit(checkPoint.oldestMulti, checkPoint.oldestMultiDB, true);
SetCommitTsLimit(checkPoint.oldestCommitTsXid,
checkPoint.newestCommitTsXid);
- XLogCtl->ckptFullXid = checkPoint.nextXid;
/*
* Clear out any old relcache cache files. This is *necessary* if we do
@@ -7437,11 +7435,6 @@ CreateCheckPoint(int flags)
UpdateControlFile();
LWLockRelease(ControlFileLock);
- /* Update shared-memory copy of checkpoint XID/epoch */
- SpinLockAcquire(&XLogCtl->info_lck);
- XLogCtl->ckptFullXid = checkPoint.nextXid;
- SpinLockRelease(&XLogCtl->info_lck);
-
/*
* We are now done with critical updates; no need for system panic if we
* have trouble while fooling with old log segments.
@@ -8516,11 +8509,6 @@ xlog_redo(XLogReaderState *record)
ControlFile->checkPointCopy.nextXid = checkPoint.nextXid;
LWLockRelease(ControlFileLock);
- /* Update shared-memory copy of checkpoint XID/epoch */
- SpinLockAcquire(&XLogCtl->info_lck);
- XLogCtl->ckptFullXid = checkPoint.nextXid;
- SpinLockRelease(&XLogCtl->info_lck);
-
/*
* We should've already switched to the new TLI before replaying this
* record.
@@ -8577,11 +8565,6 @@ xlog_redo(XLogReaderState *record)
ControlFile->checkPointCopy.nextXid = checkPoint.nextXid;
LWLockRelease(ControlFileLock);
- /* Update shared-memory copy of checkpoint XID/epoch */
- SpinLockAcquire(&XLogCtl->info_lck);
- XLogCtl->ckptFullXid = checkPoint.nextXid;
- SpinLockRelease(&XLogCtl->info_lck);
-
/* TLI should not change in an on-line checkpoint */
(void) GetCurrentReplayRecPtr(&replayTLI);
if (checkPoint.ThisTimeLineID != replayTLI)
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index aa216683b74..c4029a4f3d3 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -800,11 +800,11 @@ index_create(Relation heapRelation,
errmsg("user-defined indexes on system catalog tables are not supported")));
/*
- * Btree text_pattern_ops uses text_eq as the equality operator, which is
- * fine as long as the collation is deterministic; text_eq then reduces to
+ * Btree text_pattern_ops uses texteq as the equality operator, which is
+ * fine as long as the collation is deterministic; texteq then reduces to
* bitwise equality and so it is semantically compatible with the other
* operators and functions in that opclass. But with a nondeterministic
- * collation, text_eq could yield results that are incompatible with the
+ * collation, texteq could yield results that are incompatible with the
* actual behavior of the index (which is determined by the opclass's
* comparison function). We prevent such problems by refusing creation of
* an index with that opclass and a nondeterministic collation.
@@ -814,7 +814,7 @@ index_create(Relation heapRelation,
* opclasses as incompatible with nondeterminism; but for now, this small
* hack suffices.
*
- * Another solution is to use a special operator, not text_eq, as the
+ * Another solution is to use a special operator, not texteq, as the
* equality opclass member; but that is undesirable because it would
* prevent index usage in many queries that work fine today.
*/
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 332fad27835..fecee8224d0 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -2873,8 +2873,11 @@ check_ident_usermap(IdentLine *identLine, const char *usermap_name,
!token_has_regexp(identLine->pg_user) &&
(ofs = strstr(identLine->pg_user->string, "\\1")) != NULL)
{
+ const char *repl_str;
+ size_t repl_len;
+ char *old_pg_user;
char *expanded_pg_user;
- int offset;
+ size_t offset;
/* substitution of the first argument requested */
if (matches[1].rm_so < 0)
@@ -2886,18 +2889,33 @@ check_ident_usermap(IdentLine *identLine, const char *usermap_name,
*error_p = true;
return;
}
+ repl_str = system_user + matches[1].rm_so;
+ repl_len = matches[1].rm_eo - matches[1].rm_so;
/*
- * length: original length minus length of \1 plus length of match
- * plus null terminator
+ * It's allowed to have more than one \1 in the string, and we'll
+ * replace them all. But that's pretty unusual so we optimize on
+ * the assumption of only one occurrence, which motivates doing
+ * repeated replacements instead of making two passes over the
+ * string to determine the final length right away.
*/
- expanded_pg_user = palloc0(strlen(identLine->pg_user->string) - 2 + (matches[1].rm_eo - matches[1].rm_so) + 1);
- offset = ofs - identLine->pg_user->string;
- memcpy(expanded_pg_user, identLine->pg_user->string, offset);
- memcpy(expanded_pg_user + offset,
- system_user + matches[1].rm_so,
- matches[1].rm_eo - matches[1].rm_so);
- strcat(expanded_pg_user, ofs + 2);
+ old_pg_user = identLine->pg_user->string;
+ do
+ {
+ /*
+ * length: current length minus length of \1 plus length of
+ * replacement plus null terminator
+ */
+ expanded_pg_user = palloc(strlen(old_pg_user) - 2 + repl_len + 1);
+ /* ofs points into the old_pg_user string at this point */
+ offset = ofs - old_pg_user;
+ memcpy(expanded_pg_user, old_pg_user, offset);
+ memcpy(expanded_pg_user + offset, repl_str, repl_len);
+ strcpy(expanded_pg_user + offset + repl_len, ofs + 2);
+ if (old_pg_user != identLine->pg_user->string)
+ pfree(old_pg_user);
+ old_pg_user = expanded_pg_user;
+ } while ((ofs = strstr(old_pg_user + offset + repl_len, "\\1")) != NULL);
/*
* Mark the token as quoted, so it will only be compared literally
diff --git a/src/backend/libpq/pg_ident.conf.sample b/src/backend/libpq/pg_ident.conf.sample
index f5225f26cdf..8ee6c0ba315 100644
--- a/src/backend/libpq/pg_ident.conf.sample
+++ b/src/backend/libpq/pg_ident.conf.sample
@@ -13,25 +13,25 @@
# user names to their corresponding PostgreSQL user names. Records
# are of the form:
#
-# MAPNAME SYSTEM-USERNAME PG-USERNAME
+# MAPNAME SYSTEM-USERNAME DATABASE-USERNAME
#
# (The uppercase quantities must be replaced by actual values.)
#
# MAPNAME is the (otherwise freely chosen) map name that was used in
# pg_hba.conf. SYSTEM-USERNAME is the detected user name of the
-# client. PG-USERNAME is the requested PostgreSQL user name. The
-# existence of a record specifies that SYSTEM-USERNAME may connect as
-# PG-USERNAME.
+# client. DATABASE-USERNAME is the requested PostgreSQL user name.
+# The existence of a record specifies that SYSTEM-USERNAME may connect
+# as DATABASE-USERNAME.
#
-# If SYSTEM-USERNAME starts with a slash (/), it will be treated as a
-# regular expression. Optionally this can contain a capture (a
-# parenthesized subexpression). The substring matching the capture
-# will be substituted for \1 (backslash-one) if present in
-# PG-USERNAME.
+# If SYSTEM-USERNAME starts with a slash (/), the rest of it will be
+# treated as a regular expression. Optionally this can contain a capture
+# (a parenthesized subexpression). The substring matching the capture
+# will be substituted for \1 (backslash-one) if that appears in
+# DATABASE-USERNAME.
#
-# PG-USERNAME can be "all", a user name, a group name prefixed with "+", or
-# a regular expression (if it starts with a slash (/)). If it is a regular
-# expression, the substring matching with \1 has no effect.
+# DATABASE-USERNAME can be "all", a user name, a group name prefixed with "+",
+# or a regular expression (if it starts with a slash (/)). If it is a regular
+# expression, no substitution for \1 will occur.
#
# Multiple maps may be specified in this file and used by pg_hba.conf.
#
@@ -69,4 +69,4 @@
# Put your actual configuration here
# ----------------------------------
-# MAPNAME SYSTEM-USERNAME PG-USERNAME
+# MAPNAME SYSTEM-USERNAME DATABASE-USERNAME
diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c
index 082b4d9d327..f4c977262c5 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -297,10 +297,12 @@ parse_output_parameters(List *options, PGOutputData *data)
bool two_phase_option_given = false;
bool origin_option_given = false;
+ /* Initialize optional parameters to defaults */
data->binary = false;
data->streaming = LOGICALREP_STREAM_OFF;
data->messages = false;
data->two_phase = false;
+ data->publish_no_origin = false;
foreach(lc, options)
{
diff --git a/src/backend/storage/aio/method_worker.c b/src/backend/storage/aio/method_worker.c
index 1ce1bcd57a0..bf8f77e6ff6 100644
--- a/src/backend/storage/aio/method_worker.c
+++ b/src/backend/storage/aio/method_worker.c
@@ -575,6 +575,12 @@ IoWorkerMain(const void *startup_data, size_t startup_data_len)
}
CHECK_FOR_INTERRUPTS();
+
+ if (ConfigReloadPending)
+ {
+ ConfigReloadPending = false;
+ ProcessConfigFile(PGC_SIGHUP);
+ }
}
error_context_stack = errcallback.previous;
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index e5b945a9ee3..2418967def6 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -1622,58 +1622,6 @@ TransactionIdIsInProgress(TransactionId xid)
return false;
}
-/*
- * TransactionIdIsActive -- is xid the top-level XID of an active backend?
- *
- * This differs from TransactionIdIsInProgress in that it ignores prepared
- * transactions, as well as transactions running on the primary if we're in
- * hot standby. Also, we ignore subtransactions since that's not needed
- * for current uses.
- */
-bool
-TransactionIdIsActive(TransactionId xid)
-{
- bool result = false;
- ProcArrayStruct *arrayP = procArray;
- TransactionId *other_xids = ProcGlobal->xids;
- int i;
-
- /*
- * Don't bother checking a transaction older than RecentXmin; it could not
- * possibly still be running.
- */
- if (TransactionIdPrecedes(xid, RecentXmin))
- return false;
-
- LWLockAcquire(ProcArrayLock, LW_SHARED);
-
- for (i = 0; i < arrayP->numProcs; i++)
- {
- int pgprocno = arrayP->pgprocnos[i];
- PGPROC *proc = &allProcs[pgprocno];
- TransactionId pxid;
-
- /* Fetch xid just once - see GetNewTransactionId */
- pxid = UINT32_ACCESS_ONCE(other_xids[i]);
-
- if (!TransactionIdIsValid(pxid))
- continue;
-
- if (proc->pid == 0)
- continue; /* ignore prepared transactions */
-
- if (TransactionIdEquals(pxid, xid))
- {
- result = true;
- break;
- }
- }
-
- LWLockRelease(ProcArrayLock);
-
- return result;
-}
-
/*
* Determine XID horizons.
diff --git a/src/backend/utils/adt/jsonb_util.c b/src/backend/utils/adt/jsonb_util.c
index c8b6c15e059..82b807d067a 100644
--- a/src/backend/utils/adt/jsonb_util.c
+++ b/src/backend/utils/adt/jsonb_util.c
@@ -277,22 +277,16 @@ compareJsonbContainers(JsonbContainer *a, JsonbContainer *b)
else
{
/*
- * It's safe to assume that the types differed, and that the va
- * and vb values passed were set.
- *
- * If the two values were of the same container type, then there'd
- * have been a chance to observe the variation in the number of
- * elements/pairs (when processing WJB_BEGIN_OBJECT, say). They're
- * either two heterogeneously-typed containers, or a container and
- * some scalar type.
- *
- * We don't have to consider the WJB_END_ARRAY and WJB_END_OBJECT
- * cases here, because we would have seen the corresponding
- * WJB_BEGIN_ARRAY and WJB_BEGIN_OBJECT tokens first, and
- * concluded that they don't match.
+ * It's not possible for one iterator to report end of array or
+ * object while the other one reports something else, because we
+ * would have detected a length mismatch when we processed the
+ * container-start tokens above. Likewise we can't see WJB_DONE
+ * from one but not the other. So we have two different-type
+ * containers, or a container and some scalar type, or two
+ * different scalar types. Sort on the basis of the type code.
*/
- Assert(ra != WJB_END_ARRAY && ra != WJB_END_OBJECT);
- Assert(rb != WJB_END_ARRAY && rb != WJB_END_OBJECT);
+ Assert(ra != WJB_DONE && ra != WJB_END_ARRAY && ra != WJB_END_OBJECT);
+ Assert(rb != WJB_DONE && rb != WJB_END_ARRAY && rb != WJB_END_OBJECT);
Assert(va.type != vb.type);
Assert(va.type != jbvBinary);
@@ -852,15 +846,20 @@ JsonbIteratorInit(JsonbContainer *container)
* It is our job to expand the jbvBinary representation without bothering them
* with it. However, clients should not take it upon themselves to touch array
* or Object element/pair buffers, since their element/pair pointers are
- * garbage. Also, *val will not be set when returning WJB_END_ARRAY or
- * WJB_END_OBJECT, on the assumption that it's only useful to access values
- * when recursing in.
+ * garbage.
+ *
+ * *val is not meaningful when the result is WJB_DONE, WJB_END_ARRAY or
+ * WJB_END_OBJECT. However, we set val->type = jbvNull in those cases,
+ * so that callers may assume that val->type is always well-defined.
*/
JsonbIteratorToken
JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested)
{
if (*it == NULL)
+ {
+ val->type = jbvNull;
return WJB_DONE;
+ }
/*
* When stepping into a nested container, we jump back here to start
@@ -898,6 +897,7 @@ recurse:
* nesting).
*/
*it = freeAndGetParent(*it);
+ val->type = jbvNull;
return WJB_END_ARRAY;
}
@@ -951,6 +951,7 @@ recurse:
* of nesting).
*/
*it = freeAndGetParent(*it);
+ val->type = jbvNull;
return WJB_END_OBJECT;
}
else
@@ -995,8 +996,10 @@ recurse:
return WJB_VALUE;
}
- elog(ERROR, "invalid iterator state");
- return -1;
+ elog(ERROR, "invalid jsonb iterator state");
+ /* satisfy compilers that don't know that elog(ERROR) doesn't return */
+ val->type = jbvNull;
+ return WJB_DONE;
}
/*
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 0a5848a4ab2..25cff56c3d0 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -5312,10 +5312,10 @@ isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday)
int
date2isoweek(int year, int mon, int mday)
{
- float8 result;
int day0,
day4,
- dayn;
+ dayn,
+ week;
/* current day */
dayn = date2j(year, mon, mday);
@@ -5338,13 +5338,13 @@ date2isoweek(int year, int mon, int mday)
day0 = j2day(day4 - 1);
}
- result = (dayn - (day4 - day0)) / 7 + 1;
+ week = (dayn - (day4 - day0)) / 7 + 1;
/*
* Sometimes the last few days in a year will fall into the first week of
* the next year, so check for this.
*/
- if (result >= 52)
+ if (week >= 52)
{
day4 = date2j(year + 1, 1, 4);
@@ -5352,10 +5352,10 @@ date2isoweek(int year, int mon, int mday)
day0 = j2day(day4 - 1);
if (dayn >= day4 - day0)
- result = (dayn - (day4 - day0)) / 7 + 1;
+ week = (dayn - (day4 - day0)) / 7 + 1;
}
- return (int) result;
+ return week;
}
@@ -5367,10 +5367,10 @@ date2isoweek(int year, int mon, int mday)
int
date2isoyear(int year, int mon, int mday)
{
- float8 result;
int day0,
day4,
- dayn;
+ dayn,
+ week;
/* current day */
dayn = date2j(year, mon, mday);
@@ -5395,13 +5395,13 @@ date2isoyear(int year, int mon, int mday)
year--;
}
- result = (dayn - (day4 - day0)) / 7 + 1;
+ week = (dayn - (day4 - day0)) / 7 + 1;
/*
* Sometimes the last few days in a year will fall into the first week of
* the next year, so check for this.
*/
- if (result >= 52)
+ if (week >= 52)
{
day4 = date2j(year + 1, 1, 4);
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 0a55901b14e..0e00d73487c 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -4481,6 +4481,7 @@ SyncVariables(void)
char vbuf[32];
const char *server_version;
char *service_name;
+ char *service_file;
/* get stuff from connection */
pset.encoding = PQclientEncoding(pset.db);
@@ -4500,6 +4501,11 @@ SyncVariables(void)
if (service_name)
pg_free(service_name);
+ service_file = get_conninfo_value("servicefile");
+ SetVariable(pset.vars, "SERVICEFILE", service_file);
+ if (service_file)
+ pg_free(service_file);
+
/* this bit should match connection_warnings(): */
/* Try to get full text form of version, might include "devel" etc */
server_version = PQparameterStatus(pset.db, "server_version");
@@ -4529,6 +4535,7 @@ UnsyncVariables(void)
{
SetVariable(pset.vars, "DBNAME", NULL);
SetVariable(pset.vars, "SERVICE", NULL);
+ SetVariable(pset.vars, "SERVICEFILE", NULL);
SetVariable(pset.vars, "USER", NULL);
SetVariable(pset.vars, "HOST", NULL);
SetVariable(pset.vars, "PORT", NULL);
diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c
index 6872653c6c8..37524364290 100644
--- a/src/bin/psql/tab-complete.in.c
+++ b/src/bin/psql/tab-complete.in.c
@@ -4619,10 +4619,14 @@ match_previous_words(int pattern_id,
else if (Matches("ALTER", "DEFAULT", "PRIVILEGES", MatchAnyN, "TO", MatchAny))
COMPLETE_WITH("WITH GRANT OPTION");
/* Complete "GRANT/REVOKE ... ON * *" with TO/FROM */
- else if (Matches("GRANT", MatchAnyN, "ON", MatchAny, MatchAny))
- COMPLETE_WITH("TO");
- else if (Matches("REVOKE", MatchAnyN, "ON", MatchAny, MatchAny))
- COMPLETE_WITH("FROM");
+ else if (Matches("GRANT|REVOKE", MatchAnyN, "ON", MatchAny, MatchAny) &&
+ !TailMatches("FOREIGN", "SERVER") && !TailMatches("LARGE", "OBJECT"))
+ {
+ if (Matches("GRANT", MatchAnyN, "ON", MatchAny, MatchAny))
+ COMPLETE_WITH("TO");
+ else
+ COMPLETE_WITH("FROM");
+ }
/* Complete "GRANT/REVOKE * ON ALL * IN SCHEMA *" with TO/FROM */
else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "ALL", MatchAny, "IN", "SCHEMA", MatchAny) ||
diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h
index ef0b733ebe8..e4877d88e8f 100644
--- a/src/include/storage/procarray.h
+++ b/src/include/storage/procarray.h
@@ -53,7 +53,6 @@ extern bool ProcArrayInstallRestoredXmin(TransactionId xmin, PGPROC *proc);
extern RunningTransactions GetRunningTransactionData(void);
extern bool TransactionIdIsInProgress(TransactionId xid);
-extern bool TransactionIdIsActive(TransactionId xid);
extern TransactionId GetOldestNonRemovableTransactionId(Relation rel);
extern TransactionId GetOldestTransactionIdConsideredRunning(void);
extern TransactionId GetOldestActiveTransactionId(void);
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 09eb79812ac..2a2b10d5a29 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -201,6 +201,10 @@ static const internalPQconninfoOption PQconninfoOptions[] = {
"Database-Service", "", 20,
offsetof(struct pg_conn, pgservice)},
+ {"servicefile", "PGSERVICEFILE", NULL, NULL,
+ "Database-Service-File", "", 64,
+ offsetof(struct pg_conn, pgservicefile)},
+
{"user", "PGUSER", NULL, NULL,
"Database-User", "", 20,
offsetof(struct pg_conn, pguser)},
@@ -5062,6 +5066,7 @@ freePGconn(PGconn *conn)
free(conn->dbName);
free(conn->replication);
free(conn->pgservice);
+ free(conn->pgservicefile);
free(conn->pguser);
if (conn->pgpass)
{
@@ -5914,6 +5919,7 @@ static int
parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage)
{
const char *service = conninfo_getval(options, "service");
+ const char *service_fname = conninfo_getval(options, "servicefile");
char serviceFile[MAXPGPATH];
char *env;
bool group_found = false;
@@ -5933,10 +5939,13 @@ parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage)
return 0;
/*
- * Try PGSERVICEFILE if specified, else try ~/.pg_service.conf (if that
- * exists).
+ * First, try the "servicefile" option in connection string. Then, try
+ * the PGSERVICEFILE environment variable. Finally, check
+ * ~/.pg_service.conf (if that exists).
*/
- if ((env = getenv("PGSERVICEFILE")) != NULL)
+ if (service_fname != NULL)
+ strlcpy(serviceFile, service_fname, sizeof(serviceFile));
+ else if ((env = getenv("PGSERVICEFILE")) != NULL)
strlcpy(serviceFile, env, sizeof(serviceFile));
else
{
@@ -6092,7 +6101,17 @@ parseServiceFile(const char *serviceFile,
if (strcmp(key, "service") == 0)
{
libpq_append_error(errorMessage,
- "nested service specifications not supported in service file \"%s\", line %d",
+ "nested \"service\" specifications not supported in service file \"%s\", line %d",
+ serviceFile,
+ linenr);
+ result = 3;
+ goto exit;
+ }
+
+ if (strcmp(key, "servicefile") == 0)
+ {
+ libpq_append_error(errorMessage,
+ "nested \"servicefile\" specifications not supported in service file \"%s\", line %d",
serviceFile,
linenr);
result = 3;
@@ -6135,6 +6154,33 @@ parseServiceFile(const char *serviceFile,
}
exit:
+
+ /*
+ * If a service has been successfully found, set the "servicefile" option
+ * if not already set. This matters when we use a default service file or
+ * PGSERVICEFILE, where we want to be able track the value.
+ */
+ if (*group_found && result == 0)
+ {
+ for (i = 0; options[i].keyword; i++)
+ {
+ if (strcmp(options[i].keyword, "servicefile") != 0)
+ continue;
+
+ /* If value is already set, nothing to do */
+ if (options[i].val != NULL)
+ break;
+
+ options[i].val = strdup(serviceFile);
+ if (options[i].val == NULL)
+ {
+ libpq_append_error(errorMessage, "out of memory");
+ result = 3;
+ }
+ break;
+ }
+ }
+
fclose(f);
return result;
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index a6cfd7f5c9d..70c28f2ffca 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -389,6 +389,8 @@ struct pg_conn
char *dbName; /* database name */
char *replication; /* connect as the replication standby? */
char *pgservice; /* Postgres service, if any */
+ char *pgservicefile; /* path to a service file containing
+ * service(s) */
char *pguser; /* Postgres username and password, if any */
char *pgpass;
char *pgpassfile; /* path to a file containing password(s) */
diff --git a/src/interfaces/libpq/t/006_service.pl b/src/interfaces/libpq/t/006_service.pl
index d896558a6cc..797e6232b8f 100644
--- a/src/interfaces/libpq/t/006_service.pl
+++ b/src/interfaces/libpq/t/006_service.pl
@@ -53,6 +53,13 @@ copy($srvfile_valid, $srvfile_nested)
or die "Could not copy $srvfile_valid to $srvfile_nested: $!";
append_to_file($srvfile_nested, 'service=invalid_srv' . $newline);
+# Service file with nested "servicefile" defined.
+my $srvfile_nested_2 = "$td/pg_service_nested_2.conf";
+copy($srvfile_valid, $srvfile_nested_2)
+ or die "Could not copy $srvfile_valid to $srvfile_nested_2: $!";
+append_to_file($srvfile_nested_2,
+ 'servicefile=' . $srvfile_default . $newline);
+
# Set the fallback directory lookup of the service file to the temporary
# directory of this test. PGSYSCONFDIR is used if the service file
# defined in PGSERVICEFILE cannot be found, or when a service file is
@@ -158,9 +165,77 @@ local $ENV{PGSERVICEFILE} = "$srvfile_empty";
$dummy_node->connect_fails(
'service=my_srv',
- 'connection with nested service file',
+ 'connection with "service" in nested service file',
+ expected_stderr =>
+ qr/nested "service" specifications not supported in service file/);
+
+ local $ENV{PGSERVICEFILE} = $srvfile_nested_2;
+
+ $dummy_node->connect_fails(
+ 'service=my_srv',
+ 'connection with "servicefile" in nested service file',
expected_stderr =>
- qr/nested service specifications not supported in service file/);
+ qr/nested "servicefile" specifications not supported in service file/
+ );
+}
+
+# Properly escape backslashes in the path, to ensure the generation of
+# correct connection strings.
+my $srvfile_win_cared = $srvfile_valid;
+$srvfile_win_cared =~ s/\\/\\\\/g;
+
+# Checks that the "servicefile" option works as expected
+{
+ $dummy_node->connect_ok(
+ q{service=my_srv servicefile='} . $srvfile_win_cared . q{'},
+ 'connection with valid servicefile in connection string',
+ sql => "SELECT 'connect3_1'",
+ expected_stdout => qr/connect3_1/);
+
+ # Encode slashes and backslash
+ my $encoded_srvfile = $srvfile_valid =~ s{([\\/])}{
+ $1 eq '/' ? '%2F' : '%5C'
+ }ger;
+
+ # Additionally encode a colon in servicefile path of Windows
+ $encoded_srvfile =~ s/:/%3A/g;
+
+ $dummy_node->connect_ok(
+ 'postgresql:///?service=my_srv&servicefile=' . $encoded_srvfile,
+ 'connection with valid servicefile in URI',
+ sql => "SELECT 'connect3_2'",
+ expected_stdout => qr/connect3_2/);
+
+ local $ENV{PGSERVICE} = 'my_srv';
+ $dummy_node->connect_ok(
+ q{servicefile='} . $srvfile_win_cared . q{'},
+ 'connection with PGSERVICE and servicefile in connection string',
+ sql => "SELECT 'connect3_3'",
+ expected_stdout => qr/connect3_3/);
+
+ $dummy_node->connect_ok(
+ 'postgresql://?servicefile=' . $encoded_srvfile,
+ 'connection with PGSERVICE and servicefile in URI',
+ sql => "SELECT 'connect3_4'",
+ expected_stdout => qr/connect3_4/);
+}
+
+# Check that the "servicefile" option takes priority over the PGSERVICEFILE
+# environment variable.
+{
+ local $ENV{PGSERVICEFILE} = 'non-existent-file.conf';
+
+ $dummy_node->connect_fails(
+ 'service=my_srv',
+ 'connection with invalid PGSERVICEFILE',
+ expected_stderr =>
+ qr/service file "non-existent-file\.conf" not found/);
+
+ $dummy_node->connect_ok(
+ q{service=my_srv servicefile='} . $srvfile_win_cared . q{'},
+ 'connection with both servicefile and PGSERVICEFILE',
+ sql => "SELECT 'connect4_1'",
+ expected_stdout => qr/connect4_1/);
}
$node->teardown_node;
diff --git a/src/test/authentication/t/003_peer.pl b/src/test/authentication/t/003_peer.pl
index f2320b62c87..c751fbdbaa5 100644
--- a/src/test/authentication/t/003_peer.pl
+++ b/src/test/authentication/t/003_peer.pl
@@ -171,7 +171,8 @@ test_role(
# Test with regular expression in user name map.
# Extract the last 3 characters from the system_user
-# or the entire system_user (if its length is <= -3).
+# or the entire system_user name (if its length is <= 3).
+# We trust this will not include any regex metacharacters.
my $regex_test_string = substr($system_user, -3);
# Success as the system user regular expression matches.
@@ -210,12 +211,17 @@ test_role(
log_like =>
[qr/connection authenticated: identity="$system_user" method=peer/]);
+# Create target role for \1 tests.
+my $mapped_name = "test${regex_test_string}map${regex_test_string}user";
+$node->safe_psql('postgres', "CREATE ROLE $mapped_name LOGIN");
+
# Success as the regular expression matches and \1 is replaced in the given
# subexpression.
-reset_pg_ident($node, 'mypeermap', qq{/^$system_user(.*)\$}, 'test\1mapuser');
+reset_pg_ident($node, 'mypeermap', qq{/^.*($regex_test_string)\$},
+ 'test\1map\1user');
test_role(
$node,
- qq{testmapuser},
+ $mapped_name,
'peer',
0,
'with regular expression in user name map with \1 replaced',
@@ -224,11 +230,11 @@ test_role(
# Success as the regular expression matches and \1 is replaced in the given
# subexpression, even if quoted.
-reset_pg_ident($node, 'mypeermap', qq{/^$system_user(.*)\$},
- '"test\1mapuser"');
+reset_pg_ident($node, 'mypeermap', qq{/^.*($regex_test_string)\$},
+ '"test\1map\1user"');
test_role(
$node,
- qq{testmapuser},
+ $mapped_name,
'peer',
0,
'with regular expression in user name map with quoted \1 replaced',