mirror of
https://github.com/postgres/postgres.git
synced 2025-07-29 00:03:13 -04:00
Compare commits
8 Commits
30b4955a46
...
9886744a36
Author | SHA1 | Date | |
---|---|---|---|
|
9886744a36 | ||
|
f896057e46 | ||
|
d97ef756af | ||
|
5b1b9bce84 | ||
|
a7be2a6c26 | ||
|
d596736a49 | ||
|
028b15405b | ||
|
8c441c0827 |
@ -4179,7 +4179,7 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows
|
|||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="guc-wal-summary-keep-time" xreflabel="wal_summary_keep_time">
|
<varlistentry id="guc-wal-summary-keep-time" xreflabel="wal_summary_keep_time">
|
||||||
<term><varname>wal_summary_keep_time</varname> (<type>boolean</type>)
|
<term><varname>wal_summary_keep_time</varname> (<type>integer</type>)
|
||||||
<indexterm>
|
<indexterm>
|
||||||
<primary><varname>wal_summary_keep_time</varname> configuration parameter</primary>
|
<primary><varname>wal_summary_keep_time</varname> configuration parameter</primary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
@ -4198,6 +4198,7 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows
|
|||||||
know will not be required for future incremental backups.
|
know will not be required for future incremental backups.
|
||||||
This parameter can only be set in the
|
This parameter can only be set in the
|
||||||
<filename>postgresql.conf</filename> file or on the server command line.
|
<filename>postgresql.conf</filename> file or on the server command line.
|
||||||
|
If this value is specified without units, it is taken as minutes.
|
||||||
The default is 10 days. If <literal>summarize_wal = off</literal>,
|
The default is 10 days. If <literal>summarize_wal = off</literal>,
|
||||||
existing WAL summaries will not be removed regardless of the value of
|
existing WAL summaries will not be removed regardless of the value of
|
||||||
this parameter, because the WAL summarizer will not run.
|
this parameter, because the WAL summarizer will not run.
|
||||||
|
@ -26480,6 +26480,86 @@ SELECT collation for ('foo' COLLATE "de_DE");
|
|||||||
|
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="functions-info-wal-summary">
|
||||||
|
<title>WAL Summarization Information Functions</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The functions shown in <xref linkend="functions-wal-summary"/>
|
||||||
|
print information about the status of WAL summarization.
|
||||||
|
See <xref linkend="guc-summarize-wal" />.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<table id="functions-wal-summary">
|
||||||
|
<title>WAL Summarization Information Functions</title>
|
||||||
|
<tgroup cols="1">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry role="func_table_entry"><para role="func_signature">
|
||||||
|
Function
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Description
|
||||||
|
</para></entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry role="func_table_entry"><para role="func_signature">
|
||||||
|
<indexterm>
|
||||||
|
<primary>pg_available_wal_summaries</primary>
|
||||||
|
</indexterm>
|
||||||
|
<function>pg_available_wal_summaries</function> ()
|
||||||
|
<returnvalue>setof record</returnvalue>
|
||||||
|
( <parameter>tli</parameter> <type>bigint</type>,
|
||||||
|
<parameter>start_lsn</parameter> <type>pg_lsn</type>,
|
||||||
|
<parameter>end_lsn</parameter> <type>pg_lsn</type> )
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Returns information about the WAL summary files present in the
|
||||||
|
data directory, under <literal>pg_wal/summaries</literal>.
|
||||||
|
One row will be returned per WAL summary file. Each file summarizes
|
||||||
|
WAL on the indicated TLI within the indicated LSN range. This function
|
||||||
|
might be useful to determine whether enough WAL summaries are present
|
||||||
|
on the server to take an incremental backup based on some prior
|
||||||
|
backup whose start LSN is known.
|
||||||
|
</para></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry role="func_table_entry"><para role="func_signature">
|
||||||
|
<indexterm>
|
||||||
|
<primary>pg_wal_summary_contents</primary>
|
||||||
|
</indexterm>
|
||||||
|
<function>pg_wal_summary_contents</function> ( <parameter>tli</parameter> <type>bigint</type>, <parameter>start_lsn</parameter> <type>pg_lsn</type>, <parameter>end_lsn</parameter> <type>pg_lsn</type> )
|
||||||
|
<returnvalue>setof record</returnvalue>
|
||||||
|
( <parameter>relfilenode</parameter> <type>oid</type>,
|
||||||
|
<parameter>reltablespace</parameter> <type>oid</type>,
|
||||||
|
<parameter>reldatabase</parameter> <type>oid</type>,
|
||||||
|
<parameter>relforknumber</parameter> <type>smallint</type>,
|
||||||
|
<parameter>relblocknumber</parameter> <type>bigint</type>,
|
||||||
|
<parameter>is_limit_block</parameter> <type>boolean</type> )
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Returns one information about the contents of a single WAL summary file
|
||||||
|
identified by TLI and starting and ending LSNs. Each row with
|
||||||
|
<literal>is_limit_block</literal> false indicates that the block
|
||||||
|
identified by the remaining output columns was modified by at least
|
||||||
|
one WAL record within the range of records summarized by this file.
|
||||||
|
Each row with <literal>is_limit_block</literal> true indicates either
|
||||||
|
that (a) the relation fork was truncated to the length given by
|
||||||
|
<literal>relblocknumber</literal> within the relevant range of WAL
|
||||||
|
records or (b) that the relation fork was created or dropped within
|
||||||
|
the relevant range of WAL records; in such cases,
|
||||||
|
<literal>relblocknumber</literal> will be zero.
|
||||||
|
</para></entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</sect2>
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="functions-admin">
|
<sect1 id="functions-admin">
|
||||||
|
@ -697,8 +697,8 @@
|
|||||||
<para>
|
<para>
|
||||||
An encoding of some character repertoire. Most older character
|
An encoding of some character repertoire. Most older character
|
||||||
repertoires only use one encoding form, and so there are no
|
repertoires only use one encoding form, and so there are no
|
||||||
separate names for them (e.g., <literal>LATIN1</literal> is an
|
separate names for them (e.g., <literal>LATIN2</literal> is an
|
||||||
encoding form applicable to the <literal>LATIN1</literal>
|
encoding form applicable to the <literal>LATIN2</literal>
|
||||||
repertoire). But for example Unicode has the encoding forms
|
repertoire). But for example Unicode has the encoding forms
|
||||||
<literal>UTF8</literal>, <literal>UTF16</literal>, etc. (not
|
<literal>UTF8</literal>, <literal>UTF16</literal>, etc. (not
|
||||||
all supported by PostgreSQL). Encoding forms are not exposed
|
all supported by PostgreSQL). Encoding forms are not exposed
|
||||||
|
@ -7116,6 +7116,45 @@ char *PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user,
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="libpq-PQchangePassword">
|
||||||
|
<term><function>PQchangePassword</function><indexterm><primary>PQchangePassword</primary></indexterm></term>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Changes a <productname>PostgreSQL</productname> password.
|
||||||
|
<synopsis>
|
||||||
|
PGresult *PQchangePassword(PGconn *conn, const char *user, const char *passwd);
|
||||||
|
</synopsis>
|
||||||
|
This function uses <function>PQencryptPasswordConn</function>
|
||||||
|
to build and execute the command <literal>ALTER USER ... PASSWORD
|
||||||
|
'...'</literal>, thereby changing the user's password. It exists for
|
||||||
|
the same reason as <function>PQencryptPasswordConn</function>, but
|
||||||
|
is more convenient as it both builds and runs the command for you.
|
||||||
|
<xref linkend="libpq-PQencryptPasswordConn"/> is passed a
|
||||||
|
<symbol>NULL</symbol> for the algorithm argument, hence encryption is
|
||||||
|
done according to the server's <xref linkend="guc-password-encryption"/>
|
||||||
|
setting.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The <parameter>user</parameter> and <parameter>passwd</parameter> arguments
|
||||||
|
are the SQL name of the target user, and the new cleartext password.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Returns a <structname>PGresult</structname> pointer representing
|
||||||
|
the result of the <literal>ALTER USER</literal> command, or
|
||||||
|
a null pointer if the routine failed before issuing any command.
|
||||||
|
The <xref linkend="libpq-PQresultStatus"/> function should be called
|
||||||
|
to check the return value for any errors (including the value of a null
|
||||||
|
pointer, in which case it will return
|
||||||
|
<symbol>PGRES_FATAL_ERROR</symbol>). Use
|
||||||
|
<xref linkend="libpq-PQerrorMessage"/> to get more information about
|
||||||
|
such errors.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="libpq-PQencryptPassword">
|
<varlistentry id="libpq-PQencryptPassword">
|
||||||
<term><function>PQencryptPassword</function><indexterm><primary>PQencryptPassword</primary></indexterm></term>
|
<term><function>PQencryptPassword</function><indexterm><primary>PQencryptPassword</primary></indexterm></term>
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ $(top_builddir)/src/port/libpgport_srv.a: | submake-libpgport
|
|||||||
parser/gram.h: parser/gram.y
|
parser/gram.h: parser/gram.y
|
||||||
$(MAKE) -C parser gram.h
|
$(MAKE) -C parser gram.h
|
||||||
|
|
||||||
storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl storage/lmgr/lwlocknames.txt
|
storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl storage/lmgr/lwlocknames.txt utils/activity/wait_event_names.txt
|
||||||
$(MAKE) -C storage/lmgr lwlocknames.h lwlocknames.c
|
$(MAKE) -C storage/lmgr lwlocknames.h lwlocknames.c
|
||||||
|
|
||||||
utils/activity/wait_event_types.h: utils/activity/generate-wait_event_types.pl utils/activity/wait_event_names.txt
|
utils/activity/wait_event_types.h: utils/activity/generate-wait_event_types.pl utils/activity/wait_event_names.txt
|
||||||
|
@ -1900,8 +1900,10 @@ remove_self_join_rel(PlannerInfo *root, PlanRowMark *kmark, PlanRowMark *rmark,
|
|||||||
/* Replace varno in all the query structures */
|
/* Replace varno in all the query structures */
|
||||||
query_tree_walker(root->parse, replace_varno_walker, &ctx,
|
query_tree_walker(root->parse, replace_varno_walker, &ctx,
|
||||||
QTW_EXAMINE_SORTGROUP);
|
QTW_EXAMINE_SORTGROUP);
|
||||||
if (root->parse->resultRelation == toRemove->relid)
|
|
||||||
root->parse->resultRelation = toKeep->relid;
|
/* See remove_self_joins_one_group() */
|
||||||
|
Assert(root->parse->resultRelation != toRemove->relid);
|
||||||
|
Assert(root->parse->resultRelation != toKeep->relid);
|
||||||
|
|
||||||
/* Replace links in the planner info */
|
/* Replace links in the planner info */
|
||||||
remove_rel_from_query(root, toRemove, toKeep->relid, NULL, NULL);
|
remove_rel_from_query(root, toRemove, toKeep->relid, NULL, NULL);
|
||||||
@ -2086,6 +2088,14 @@ remove_self_joins_one_group(PlannerInfo *root, Relids relids)
|
|||||||
{
|
{
|
||||||
RelOptInfo *inner = root->simple_rel_array[r];
|
RelOptInfo *inner = root->simple_rel_array[r];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't accept result relation as either source or target relation
|
||||||
|
* of SJE, because result relation has different behavior in
|
||||||
|
* EvalPlanQual() and RETURNING clause.
|
||||||
|
*/
|
||||||
|
if (root->parse->resultRelation == r)
|
||||||
|
continue;
|
||||||
|
|
||||||
k = r;
|
k = r;
|
||||||
|
|
||||||
while ((k = bms_next_member(relids, k)) > 0)
|
while ((k = bms_next_member(relids, k)) > 0)
|
||||||
@ -2101,6 +2111,9 @@ remove_self_joins_one_group(PlannerInfo *root, Relids relids)
|
|||||||
PlanRowMark *imark = NULL;
|
PlanRowMark *imark = NULL;
|
||||||
List *uclauses = NIL;
|
List *uclauses = NIL;
|
||||||
|
|
||||||
|
if (root->parse->resultRelation == k)
|
||||||
|
continue;
|
||||||
|
|
||||||
/* A sanity check: the relations have the same Oid. */
|
/* A sanity check: the relations have the same Oid. */
|
||||||
Assert(root->simple_rte_array[k]->relid ==
|
Assert(root->simple_rte_array[k]->relid ==
|
||||||
root->simple_rte_array[r]->relid);
|
root->simple_rte_array[r]->relid);
|
||||||
|
@ -39,8 +39,8 @@ s_lock_test: s_lock.c $(top_builddir)/src/common/libpgcommon.a $(top_builddir)/s
|
|||||||
lwlocknames.c: lwlocknames.h
|
lwlocknames.c: lwlocknames.h
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
lwlocknames.h: $(top_srcdir)/src/backend/storage/lmgr/lwlocknames.txt generate-lwlocknames.pl
|
lwlocknames.h: $(top_srcdir)/src/backend/storage/lmgr/lwlocknames.txt $(top_srcdir)/src/backend/utils/activity/wait_event_names.txt generate-lwlocknames.pl
|
||||||
$(PERL) $(srcdir)/generate-lwlocknames.pl $<
|
$(PERL) $(srcdir)/generate-lwlocknames.pl $^
|
||||||
|
|
||||||
check: s_lock_test
|
check: s_lock_test
|
||||||
./s_lock_test
|
./s_lock_test
|
||||||
|
@ -15,6 +15,7 @@ my $continue = "\n";
|
|||||||
GetOptions('outdir:s' => \$output_path);
|
GetOptions('outdir:s' => \$output_path);
|
||||||
|
|
||||||
open my $lwlocknames, '<', $ARGV[0] or die;
|
open my $lwlocknames, '<', $ARGV[0] or die;
|
||||||
|
open my $wait_event_names, '<', $ARGV[1] or die;
|
||||||
|
|
||||||
# Include PID in suffix in case parallel make runs this multiple times.
|
# Include PID in suffix in case parallel make runs this multiple times.
|
||||||
my $htmp = "$output_path/lwlocknames.h.tmp$$";
|
my $htmp = "$output_path/lwlocknames.h.tmp$$";
|
||||||
@ -30,6 +31,40 @@ print $c $autogen, "\n";
|
|||||||
|
|
||||||
print $c "const char *const IndividualLWLockNames[] = {";
|
print $c "const char *const IndividualLWLockNames[] = {";
|
||||||
|
|
||||||
|
#
|
||||||
|
# First, record the predefined LWLocks listed in wait_event_names.txt. We'll
|
||||||
|
# cross-check those with the ones in lwlocknames.txt.
|
||||||
|
#
|
||||||
|
my @wait_event_lwlocks;
|
||||||
|
my $record_lwlocks = 0;
|
||||||
|
|
||||||
|
while (<$wait_event_names>)
|
||||||
|
{
|
||||||
|
chomp;
|
||||||
|
|
||||||
|
# Check for end marker.
|
||||||
|
last if /^# END OF PREDEFINED LWLOCKS/;
|
||||||
|
|
||||||
|
# Skip comments and empty lines.
|
||||||
|
next if /^#/;
|
||||||
|
next if /^\s*$/;
|
||||||
|
|
||||||
|
# Start recording LWLocks when we find the WaitEventLWLock section.
|
||||||
|
if (/^Section: ClassName - WaitEventLWLock$/)
|
||||||
|
{
|
||||||
|
$record_lwlocks = 1;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Go to the next line if we are not yet recording LWLocks.
|
||||||
|
next if not $record_lwlocks;
|
||||||
|
|
||||||
|
# Record the LWLock.
|
||||||
|
(my $waiteventname, my $waitevendocsentence) = split(/\t/, $_);
|
||||||
|
push(@wait_event_lwlocks, $waiteventname . "Lock");
|
||||||
|
}
|
||||||
|
|
||||||
|
my $i = 0;
|
||||||
while (<$lwlocknames>)
|
while (<$lwlocknames>)
|
||||||
{
|
{
|
||||||
chomp;
|
chomp;
|
||||||
@ -50,6 +85,15 @@ while (<$lwlocknames>)
|
|||||||
die "lwlocknames.txt not in order" if $lockidx < $lastlockidx;
|
die "lwlocknames.txt not in order" if $lockidx < $lastlockidx;
|
||||||
die "lwlocknames.txt has duplicates" if $lockidx == $lastlockidx;
|
die "lwlocknames.txt has duplicates" if $lockidx == $lastlockidx;
|
||||||
|
|
||||||
|
die "$lockname defined in lwlocknames.txt but missing from "
|
||||||
|
. "wait_event_names.txt"
|
||||||
|
if $i >= scalar @wait_event_lwlocks;
|
||||||
|
die "lists of predefined LWLocks do not match (first mismatch at "
|
||||||
|
. "$wait_event_lwlocks[$i] in wait_event_names.txt and $lockname in "
|
||||||
|
. "lwlocknames.txt)"
|
||||||
|
if $wait_event_lwlocks[$i] ne $lockname;
|
||||||
|
$i++;
|
||||||
|
|
||||||
while ($lastlockidx < $lockidx - 1)
|
while ($lastlockidx < $lockidx - 1)
|
||||||
{
|
{
|
||||||
++$lastlockidx;
|
++$lastlockidx;
|
||||||
@ -63,6 +107,11 @@ while (<$lwlocknames>)
|
|||||||
print $h "#define $lockname (&MainLWLockArray[$lockidx].lock)\n";
|
print $h "#define $lockname (&MainLWLockArray[$lockidx].lock)\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
die
|
||||||
|
"$wait_event_lwlocks[$i] defined in wait_event_names.txt but missing from "
|
||||||
|
. "lwlocknames.txt"
|
||||||
|
if $i < scalar @wait_event_lwlocks;
|
||||||
|
|
||||||
printf $c "\n};\n";
|
printf $c "\n};\n";
|
||||||
print $h "\n";
|
print $h "\n";
|
||||||
printf $h "#define NUM_INDIVIDUAL_LWLOCKS %s\n", $lastlockidx + 1;
|
printf $h "#define NUM_INDIVIDUAL_LWLOCKS %s\n", $lastlockidx + 1;
|
||||||
|
@ -276,6 +276,10 @@ Extension "Waiting in an extension."
|
|||||||
# This class of wait events has its own set of C structure, so these are
|
# This class of wait events has its own set of C structure, so these are
|
||||||
# only used for the documentation.
|
# only used for the documentation.
|
||||||
#
|
#
|
||||||
|
# NB: Predefined LWLocks (i.e., those declared in lwlocknames.txt) must be
|
||||||
|
# listed in the top section of locks and must be listed in the same order as in
|
||||||
|
# lwlocknames.txt.
|
||||||
|
#
|
||||||
|
|
||||||
Section: ClassName - WaitEventLWLock
|
Section: ClassName - WaitEventLWLock
|
||||||
|
|
||||||
@ -326,6 +330,14 @@ NotifyQueueTail "Waiting to update limit on <command>NOTIFY</command> message st
|
|||||||
WaitEventExtension "Waiting to read or update custom wait events information for extensions."
|
WaitEventExtension "Waiting to read or update custom wait events information for extensions."
|
||||||
WALSummarizer "Waiting to read or update WAL summarization state."
|
WALSummarizer "Waiting to read or update WAL summarization state."
|
||||||
|
|
||||||
|
#
|
||||||
|
# END OF PREDEFINED LWLOCKS (DO NOT CHANGE THIS LINE)
|
||||||
|
#
|
||||||
|
# Predefined LWLocks (i.e., those declared in lwlocknames.txt) must be listed
|
||||||
|
# in the section above and must be listed in the same order as in
|
||||||
|
# lwlocknames.txt. Other LWLocks must be listed in the section below.
|
||||||
|
#
|
||||||
|
|
||||||
XactBuffer "Waiting for I/O on a transaction status SLRU buffer."
|
XactBuffer "Waiting for I/O on a transaction status SLRU buffer."
|
||||||
CommitTsBuffer "Waiting for I/O on a commit timestamp SLRU buffer."
|
CommitTsBuffer "Waiting for I/O on a commit timestamp SLRU buffer."
|
||||||
SubtransBuffer "Waiting for I/O on a sub-transaction SLRU buffer."
|
SubtransBuffer "Waiting for I/O on a sub-transaction SLRU buffer."
|
||||||
|
@ -552,11 +552,11 @@ start_postmaster(void)
|
|||||||
else
|
else
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
cmd = psprintf("\"%s\" /C \"\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1\"",
|
cmd = psprintf("\"%s\" /D /C \"\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1\"",
|
||||||
comspec, exec_path, pgdata_opt, post_opts, DEVNULL, log_file);
|
comspec, exec_path, pgdata_opt, post_opts, DEVNULL, log_file);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
cmd = psprintf("\"%s\" /C \"\"%s\" %s%s < \"%s\" 2>&1\"",
|
cmd = psprintf("\"%s\" /D /C \"\"%s\" %s%s < \"%s\" 2>&1\"",
|
||||||
comspec, exec_path, pgdata_opt, post_opts, DEVNULL);
|
comspec, exec_path, pgdata_opt, post_opts, DEVNULL);
|
||||||
|
|
||||||
if (!CreateRestrictedProcess(cmd, &pi, false))
|
if (!CreateRestrictedProcess(cmd, &pi, false))
|
||||||
|
@ -2158,29 +2158,15 @@ exec_command_password(PsqlScanState scan_state, bool active_branch)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *encrypted_password;
|
PGresult *res = PQchangePassword(pset.db, user, pw1);
|
||||||
|
|
||||||
encrypted_password = PQencryptPasswordConn(pset.db, pw1, user, NULL);
|
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||||
|
|
||||||
if (!encrypted_password)
|
|
||||||
{
|
{
|
||||||
pg_log_info("%s", PQerrorMessage(pset.db));
|
pg_log_info("%s", PQerrorMessage(pset.db));
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
PGresult *res;
|
|
||||||
|
|
||||||
printfPQExpBuffer(&buf, "ALTER USER %s PASSWORD ",
|
PQclear(res);
|
||||||
fmtId(user));
|
|
||||||
appendStringLiteralConn(&buf, encrypted_password, pset.db);
|
|
||||||
res = PSQLexec(buf.data);
|
|
||||||
if (!res)
|
|
||||||
success = false;
|
|
||||||
else
|
|
||||||
PQclear(res);
|
|
||||||
PQfreemem(encrypted_password);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(user);
|
free(user);
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
# Copyright (c) 2022-2024, PostgreSQL Global Development Group
|
# Copyright (c) 2022-2024, PostgreSQL Global Development Group
|
||||||
|
|
||||||
lwlocknames = custom_target('lwlocknames',
|
lwlocknames = custom_target('lwlocknames',
|
||||||
input: files('../../backend/storage/lmgr/lwlocknames.txt'),
|
input: files(
|
||||||
|
'../../backend/storage/lmgr/lwlocknames.txt',
|
||||||
|
'../../backend/utils/activity/wait_event_names.txt'),
|
||||||
output: ['lwlocknames.h', 'lwlocknames.c'],
|
output: ['lwlocknames.h', 'lwlocknames.c'],
|
||||||
command: [
|
command: [
|
||||||
perl, files('../../backend/storage/lmgr/generate-lwlocknames.pl'),
|
perl, files('../../backend/storage/lmgr/generate-lwlocknames.pl'),
|
||||||
|
@ -191,3 +191,4 @@ PQclosePrepared 188
|
|||||||
PQclosePortal 189
|
PQclosePortal 189
|
||||||
PQsendClosePrepared 190
|
PQsendClosePrepared 190
|
||||||
PQsendClosePortal 191
|
PQsendClosePortal 191
|
||||||
|
PQchangePassword 192
|
||||||
|
@ -1372,3 +1372,84 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user,
|
|||||||
|
|
||||||
return crypt_pwd;
|
return crypt_pwd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PQchangePassword -- exported routine to change a password
|
||||||
|
*
|
||||||
|
* This is intended to be used by client applications that wish to
|
||||||
|
* change the password for a user. The password is not sent in
|
||||||
|
* cleartext because it is encrypted on the client side. This is
|
||||||
|
* good because it ensures the cleartext password is never known by
|
||||||
|
* the server, and therefore won't end up in logs, pg_stat displays,
|
||||||
|
* etc. The password encryption is performed by PQencryptPasswordConn(),
|
||||||
|
* which is passed a NULL for the algorithm argument. Hence encryption
|
||||||
|
* is done according to the server's password_encryption
|
||||||
|
* setting. We export the function so that clients won't be dependent
|
||||||
|
* on the implementation specific details with respect to how the
|
||||||
|
* server changes passwords.
|
||||||
|
*
|
||||||
|
* Arguments are a connection object, the SQL name of the target user,
|
||||||
|
* and the cleartext password.
|
||||||
|
*
|
||||||
|
* Return value is the PGresult of the executed ALTER USER statement
|
||||||
|
* or NULL if we never get there. The caller is responsible to PQclear()
|
||||||
|
* the returned PGresult.
|
||||||
|
*
|
||||||
|
* PQresultStatus() should be called to check the return value for errors,
|
||||||
|
* and PQerrorMessage() used to get more information about such errors.
|
||||||
|
*/
|
||||||
|
PGresult *
|
||||||
|
PQchangePassword(PGconn *conn, const char *user, const char *passwd)
|
||||||
|
{
|
||||||
|
char *encrypted_password = PQencryptPasswordConn(conn, passwd,
|
||||||
|
user, NULL);
|
||||||
|
|
||||||
|
if (!encrypted_password)
|
||||||
|
{
|
||||||
|
/* PQencryptPasswordConn() already registered the error */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char *fmtpw = PQescapeLiteral(conn, encrypted_password,
|
||||||
|
strlen(encrypted_password));
|
||||||
|
|
||||||
|
/* no longer needed, so clean up now */
|
||||||
|
PQfreemem(encrypted_password);
|
||||||
|
|
||||||
|
if (!fmtpw)
|
||||||
|
{
|
||||||
|
/* PQescapeLiteral() already registered the error */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char *fmtuser = PQescapeIdentifier(conn, user, strlen(user));
|
||||||
|
|
||||||
|
if (!fmtuser)
|
||||||
|
{
|
||||||
|
/* PQescapeIdentifier() already registered the error */
|
||||||
|
PQfreemem(fmtpw);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PQExpBufferData buf;
|
||||||
|
PGresult *res;
|
||||||
|
|
||||||
|
initPQExpBuffer(&buf);
|
||||||
|
printfPQExpBuffer(&buf, "ALTER USER %s PASSWORD %s",
|
||||||
|
fmtuser, fmtpw);
|
||||||
|
|
||||||
|
res = PQexec(conn, buf.data);
|
||||||
|
|
||||||
|
/* clean up */
|
||||||
|
termPQExpBuffer(&buf);
|
||||||
|
PQfreemem(fmtuser);
|
||||||
|
PQfreemem(fmtpw);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -659,6 +659,7 @@ extern int PQenv2encoding(void);
|
|||||||
|
|
||||||
extern char *PQencryptPassword(const char *passwd, const char *user);
|
extern char *PQencryptPassword(const char *passwd, const char *user);
|
||||||
extern char *PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, const char *algorithm);
|
extern char *PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, const char *algorithm);
|
||||||
|
extern PGresult *PQchangePassword(PGconn *conn, const char *user, const char *passwd);
|
||||||
|
|
||||||
/* === in encnames.c === */
|
/* === in encnames.c === */
|
||||||
|
|
||||||
|
@ -6868,18 +6868,58 @@ select * from emp1 t1
|
|||||||
-> Seq Scan on emp1 t3
|
-> Seq Scan on emp1 t3
|
||||||
(6 rows)
|
(6 rows)
|
||||||
|
|
||||||
-- Check that SJE replaces target relation correctly
|
-- Check that SJE doesn't replace the target relation
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
WITH t1 AS (SELECT * FROM emp1)
|
WITH t1 AS (SELECT * FROM emp1)
|
||||||
UPDATE emp1 SET code = t1.code + 1 FROM t1
|
UPDATE emp1 SET code = t1.code + 1 FROM t1
|
||||||
WHERE t1.id = emp1.id RETURNING emp1.id, emp1.code;
|
WHERE t1.id = emp1.id RETURNING emp1.id, emp1.code, t1.code;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
----------------------------------
|
-------------------------------------------------------
|
||||||
Update on emp1
|
Update on emp1
|
||||||
-> Seq Scan on emp1
|
-> Nested Loop
|
||||||
Filter: (id IS NOT NULL)
|
-> Seq Scan on emp1
|
||||||
(3 rows)
|
-> Index Scan using emp1_pkey on emp1 emp1_1
|
||||||
|
Index Cond: (id = emp1.id)
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
INSERT INTO emp1 VALUES (1, 1), (2, 1);
|
||||||
|
WITH t1 AS (SELECT * FROM emp1)
|
||||||
|
UPDATE emp1 SET code = t1.code + 1 FROM t1
|
||||||
|
WHERE t1.id = emp1.id RETURNING emp1.id, emp1.code, t1.code;
|
||||||
|
id | code | code
|
||||||
|
----+------+------
|
||||||
|
1 | 2 | 1
|
||||||
|
2 | 2 | 1
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
TRUNCATE emp1;
|
||||||
|
EXPLAIN (COSTS OFF)
|
||||||
|
UPDATE sj sq SET b = 1 FROM sj as sz WHERE sq.a = sz.a;
|
||||||
|
QUERY PLAN
|
||||||
|
-------------------------------------
|
||||||
|
Update on sj sq
|
||||||
|
-> Nested Loop
|
||||||
|
Join Filter: (sq.a = sz.a)
|
||||||
|
-> Seq Scan on sj sq
|
||||||
|
-> Materialize
|
||||||
|
-> Seq Scan on sj sz
|
||||||
|
(6 rows)
|
||||||
|
|
||||||
|
CREATE RULE sj_del_rule AS ON DELETE TO sj
|
||||||
|
DO INSTEAD
|
||||||
|
UPDATE sj SET a = 1 WHERE a = old.a;
|
||||||
|
EXPLAIN (COSTS OFF) DELETE FROM sj;
|
||||||
|
QUERY PLAN
|
||||||
|
--------------------------------------
|
||||||
|
Update on sj sj_1
|
||||||
|
-> Nested Loop
|
||||||
|
Join Filter: (sj.a = sj_1.a)
|
||||||
|
-> Seq Scan on sj sj_1
|
||||||
|
-> Materialize
|
||||||
|
-> Seq Scan on sj
|
||||||
|
(6 rows)
|
||||||
|
|
||||||
|
DROP RULE sj_del_rule ON sj CASCADE;
|
||||||
-- Check that SJE does not mistakenly omit qual clauses (bug #18187)
|
-- Check that SJE does not mistakenly omit qual clauses (bug #18187)
|
||||||
insert into emp1 values (1, 1);
|
insert into emp1 values (1, 1);
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
@ -7076,7 +7116,6 @@ ON sj_t1.id = _t2t3t4.id;
|
|||||||
--
|
--
|
||||||
-- Test RowMarks-related code
|
-- Test RowMarks-related code
|
||||||
--
|
--
|
||||||
-- TODO: Why this select returns two copies of ctid field? Should we fix it?
|
|
||||||
EXPLAIN (COSTS OFF) -- Both sides have explicit LockRows marks
|
EXPLAIN (COSTS OFF) -- Both sides have explicit LockRows marks
|
||||||
SELECT a1.a FROM sj a1,sj a2 WHERE (a1.a=a2.a) FOR UPDATE;
|
SELECT a1.a FROM sj a1,sj a2 WHERE (a1.a=a2.a) FOR UPDATE;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
@ -7086,27 +7125,6 @@ SELECT a1.a FROM sj a1,sj a2 WHERE (a1.a=a2.a) FOR UPDATE;
|
|||||||
Filter: (a IS NOT NULL)
|
Filter: (a IS NOT NULL)
|
||||||
(3 rows)
|
(3 rows)
|
||||||
|
|
||||||
EXPLAIN (COSTS OFF) -- A RowMark exists for the table being kept
|
|
||||||
UPDATE sj sq SET b = 1 FROM sj as sz WHERE sq.a = sz.a;
|
|
||||||
QUERY PLAN
|
|
||||||
---------------------------------
|
|
||||||
Update on sj sz
|
|
||||||
-> Seq Scan on sj sz
|
|
||||||
Filter: (a IS NOT NULL)
|
|
||||||
(3 rows)
|
|
||||||
|
|
||||||
CREATE RULE sj_del_rule AS ON DELETE TO sj
|
|
||||||
DO INSTEAD
|
|
||||||
UPDATE sj SET a = 1 WHERE a = old.a;
|
|
||||||
EXPLAIN (COSTS OFF) DELETE FROM sj; -- A RowMark exists for the table being dropped
|
|
||||||
QUERY PLAN
|
|
||||||
---------------------------------
|
|
||||||
Update on sj
|
|
||||||
-> Seq Scan on sj
|
|
||||||
Filter: (a IS NOT NULL)
|
|
||||||
(3 rows)
|
|
||||||
|
|
||||||
DROP RULE sj_del_rule ON sj CASCADE;
|
|
||||||
reset enable_hashjoin;
|
reset enable_hashjoin;
|
||||||
reset enable_mergejoin;
|
reset enable_mergejoin;
|
||||||
--
|
--
|
||||||
|
@ -2499,13 +2499,16 @@ SELECT * FROM rw_view1;
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
EXPLAIN (costs off) DELETE FROM rw_view1 WHERE id = 1 AND snoop(data);
|
EXPLAIN (costs off) DELETE FROM rw_view1 WHERE id = 1 AND snoop(data);
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
Update on base_tbl
|
Update on base_tbl base_tbl_1
|
||||||
-> Index Scan using base_tbl_pkey on base_tbl
|
-> Nested Loop
|
||||||
Index Cond: (id = 1)
|
-> Index Scan using base_tbl_pkey on base_tbl base_tbl_1
|
||||||
Filter: ((NOT deleted) AND snoop(data))
|
Index Cond: (id = 1)
|
||||||
(4 rows)
|
-> Index Scan using base_tbl_pkey on base_tbl
|
||||||
|
Index Cond: (id = 1)
|
||||||
|
Filter: ((NOT deleted) AND snoop(data))
|
||||||
|
(7 rows)
|
||||||
|
|
||||||
DELETE FROM rw_view1 WHERE id = 1 AND snoop(data);
|
DELETE FROM rw_view1 WHERE id = 1 AND snoop(data);
|
||||||
NOTICE: snooped value: Row 1
|
NOTICE: snooped value: Row 1
|
||||||
|
@ -2616,11 +2616,25 @@ select * from emp1 t1
|
|||||||
inner join emp1 t2 on t1.id = t2.id
|
inner join emp1 t2 on t1.id = t2.id
|
||||||
left join emp1 t3 on t1.id > 1 and t1.id < 2;
|
left join emp1 t3 on t1.id > 1 and t1.id < 2;
|
||||||
|
|
||||||
-- Check that SJE replaces target relation correctly
|
-- Check that SJE doesn't replace the target relation
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
WITH t1 AS (SELECT * FROM emp1)
|
WITH t1 AS (SELECT * FROM emp1)
|
||||||
UPDATE emp1 SET code = t1.code + 1 FROM t1
|
UPDATE emp1 SET code = t1.code + 1 FROM t1
|
||||||
WHERE t1.id = emp1.id RETURNING emp1.id, emp1.code;
|
WHERE t1.id = emp1.id RETURNING emp1.id, emp1.code, t1.code;
|
||||||
|
INSERT INTO emp1 VALUES (1, 1), (2, 1);
|
||||||
|
WITH t1 AS (SELECT * FROM emp1)
|
||||||
|
UPDATE emp1 SET code = t1.code + 1 FROM t1
|
||||||
|
WHERE t1.id = emp1.id RETURNING emp1.id, emp1.code, t1.code;
|
||||||
|
TRUNCATE emp1;
|
||||||
|
|
||||||
|
EXPLAIN (COSTS OFF)
|
||||||
|
UPDATE sj sq SET b = 1 FROM sj as sz WHERE sq.a = sz.a;
|
||||||
|
|
||||||
|
CREATE RULE sj_del_rule AS ON DELETE TO sj
|
||||||
|
DO INSTEAD
|
||||||
|
UPDATE sj SET a = 1 WHERE a = old.a;
|
||||||
|
EXPLAIN (COSTS OFF) DELETE FROM sj;
|
||||||
|
DROP RULE sj_del_rule ON sj CASCADE;
|
||||||
|
|
||||||
-- Check that SJE does not mistakenly omit qual clauses (bug #18187)
|
-- Check that SJE does not mistakenly omit qual clauses (bug #18187)
|
||||||
insert into emp1 values (1, 1);
|
insert into emp1 values (1, 1);
|
||||||
@ -2729,19 +2743,9 @@ ON sj_t1.id = _t2t3t4.id;
|
|||||||
-- Test RowMarks-related code
|
-- Test RowMarks-related code
|
||||||
--
|
--
|
||||||
|
|
||||||
-- TODO: Why this select returns two copies of ctid field? Should we fix it?
|
|
||||||
EXPLAIN (COSTS OFF) -- Both sides have explicit LockRows marks
|
EXPLAIN (COSTS OFF) -- Both sides have explicit LockRows marks
|
||||||
SELECT a1.a FROM sj a1,sj a2 WHERE (a1.a=a2.a) FOR UPDATE;
|
SELECT a1.a FROM sj a1,sj a2 WHERE (a1.a=a2.a) FOR UPDATE;
|
||||||
|
|
||||||
EXPLAIN (COSTS OFF) -- A RowMark exists for the table being kept
|
|
||||||
UPDATE sj sq SET b = 1 FROM sj as sz WHERE sq.a = sz.a;
|
|
||||||
|
|
||||||
CREATE RULE sj_del_rule AS ON DELETE TO sj
|
|
||||||
DO INSTEAD
|
|
||||||
UPDATE sj SET a = 1 WHERE a = old.a;
|
|
||||||
EXPLAIN (COSTS OFF) DELETE FROM sj; -- A RowMark exists for the table being dropped
|
|
||||||
DROP RULE sj_del_rule ON sj CASCADE;
|
|
||||||
|
|
||||||
reset enable_hashjoin;
|
reset enable_hashjoin;
|
||||||
reset enable_mergejoin;
|
reset enable_mergejoin;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user