mirror of
https://github.com/postgres/postgres.git
synced 2025-07-25 00:01:36 -04:00
Compare commits
8 Commits
3650e7a393
...
e83aa9f92f
Author | SHA1 | Date | |
---|---|---|---|
|
e83aa9f92f | ||
|
7c3fb505b1 | ||
|
07cb29737a | ||
|
6614cfb43c | ||
|
9e5b2a091f | ||
|
ddcab2a032 | ||
|
ad57c2a7c5 | ||
|
8efa301532 |
@ -15,6 +15,8 @@
|
|||||||
# Make "html" the default target, since that is what most people tend
|
# Make "html" the default target, since that is what most people tend
|
||||||
# to want to use.
|
# to want to use.
|
||||||
html:
|
html:
|
||||||
|
# Note that all is *not* the default target in this directory
|
||||||
|
all: html man
|
||||||
|
|
||||||
# We don't need the tree-wide headers or install support here.
|
# We don't need the tree-wide headers or install support here.
|
||||||
NO_GENERATED_HEADERS=yes
|
NO_GENERATED_HEADERS=yes
|
||||||
@ -25,8 +27,6 @@ top_builddir = ../../..
|
|||||||
include $(top_builddir)/src/Makefile.global
|
include $(top_builddir)/src/Makefile.global
|
||||||
|
|
||||||
|
|
||||||
all: html man
|
|
||||||
|
|
||||||
|
|
||||||
ifndef DBTOEPUB
|
ifndef DBTOEPUB
|
||||||
DBTOEPUB = $(missing) dbtoepub
|
DBTOEPUB = $(missing) dbtoepub
|
||||||
@ -55,7 +55,7 @@ override XSLTPROCFLAGS += --stringparam pg.version '$(VERSION)'
|
|||||||
|
|
||||||
GENERATED_SGML = version.sgml \
|
GENERATED_SGML = version.sgml \
|
||||||
features-supported.sgml features-unsupported.sgml errcodes-table.sgml \
|
features-supported.sgml features-unsupported.sgml errcodes-table.sgml \
|
||||||
keywords-table.sgml wait_event_types.sgml
|
keywords-table.sgml targets-meson.sgml wait_event_types.sgml
|
||||||
|
|
||||||
ALLSGML := $(wildcard $(srcdir)/*.sgml $(srcdir)/ref/*.sgml) $(GENERATED_SGML)
|
ALLSGML := $(wildcard $(srcdir)/*.sgml $(srcdir)/ref/*.sgml) $(GENERATED_SGML)
|
||||||
|
|
||||||
@ -110,6 +110,9 @@ keywords-table.sgml: $(top_srcdir)/src/include/parser/kwlist.h $(wildcard $(srcd
|
|||||||
wait_event_types.sgml: $(top_srcdir)/src/backend/utils/activity/wait_event_names.txt $(top_srcdir)/src/backend/utils/activity/generate-wait_event_types.pl
|
wait_event_types.sgml: $(top_srcdir)/src/backend/utils/activity/wait_event_names.txt $(top_srcdir)/src/backend/utils/activity/generate-wait_event_types.pl
|
||||||
$(PERL) $(top_srcdir)/src/backend/utils/activity/generate-wait_event_types.pl --docs $<
|
$(PERL) $(top_srcdir)/src/backend/utils/activity/generate-wait_event_types.pl --docs $<
|
||||||
|
|
||||||
|
targets-meson.sgml: targets-meson.txt $(srcdir)/generate-targets-meson.pl
|
||||||
|
$(PERL) $(srcdir)/generate-targets-meson.pl $^ > $@
|
||||||
|
|
||||||
##
|
##
|
||||||
## Generation of some text files.
|
## Generation of some text files.
|
||||||
##
|
##
|
||||||
|
@ -7510,11 +7510,12 @@ log_line_prefix = '%m [%p] %q%u@%d/%a '
|
|||||||
</term>
|
</term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Causes each replication command to be logged in the server log.
|
Causes each replication command and <literal>walsender</literal>
|
||||||
See <xref linkend="protocol-replication"/> for more information about
|
process's replication slot acquisition/release to be logged in the
|
||||||
replication command. The default value is <literal>off</literal>.
|
server log. See <xref linkend="protocol-replication"/> for more
|
||||||
Only superusers and users with the appropriate <literal>SET</literal>
|
information about replication command. The default value is
|
||||||
privilege can change this setting.
|
<literal>off</literal>. Only superusers and users with the appropriate
|
||||||
|
<literal>SET</literal> privilege can change this setting.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
@ -434,20 +434,19 @@ LOGLEVEL=-Dorg.apache.commons.logging.simplelog.defaultlog=WARN
|
|||||||
<title>Building the Documentation with Meson</title>
|
<title>Building the Documentation with Meson</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Two options are provided for building the documentation using Meson.
|
To build the documentation using Meson, change to the
|
||||||
Change to the <filename>build</filename> directory before running
|
<filename>build</filename> directory before running one of these commands,
|
||||||
one of these commands, or add <option>-C build</option> to the command.
|
or add <option>-C build</option> to the command.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
To build just the <acronym>HTML</acronym> version of the documentation:
|
To build just the <acronym>HTML</acronym> version of the documentation:
|
||||||
<screen>
|
<screen>
|
||||||
<prompt>build$ </prompt><userinput>ninja docs</userinput>
|
<prompt>build$ </prompt><userinput>ninja html</userinput>
|
||||||
</screen>
|
|
||||||
To build all forms of the documentation:
|
|
||||||
<screen>
|
|
||||||
<prompt>build$ </prompt><userinput>ninja alldocs</userinput>
|
|
||||||
</screen>
|
</screen>
|
||||||
|
For a list of other documentation targets see
|
||||||
|
<xref linkend="targets-meson-documentation"/>.
|
||||||
|
|
||||||
The output appears in the
|
The output appears in the
|
||||||
subdirectory <filename>build/doc/src/sgml</filename>.
|
subdirectory <filename>build/doc/src/sgml</filename>.
|
||||||
</para>
|
</para>
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
<!ENTITY high-availability SYSTEM "high-availability.sgml">
|
<!ENTITY high-availability SYSTEM "high-availability.sgml">
|
||||||
<!ENTITY installbin SYSTEM "install-binaries.sgml">
|
<!ENTITY installbin SYSTEM "install-binaries.sgml">
|
||||||
<!ENTITY installation SYSTEM "installation.sgml">
|
<!ENTITY installation SYSTEM "installation.sgml">
|
||||||
|
<!ENTITY targets-meson SYSTEM "targets-meson.sgml">
|
||||||
<!ENTITY installw SYSTEM "install-windows.sgml">
|
<!ENTITY installw SYSTEM "install-windows.sgml">
|
||||||
<!ENTITY maintenance SYSTEM "maintenance.sgml">
|
<!ENTITY maintenance SYSTEM "maintenance.sgml">
|
||||||
<!ENTITY manage-ag SYSTEM "manage-ag.sgml">
|
<!ENTITY manage-ag SYSTEM "manage-ag.sgml">
|
||||||
|
63
doc/src/sgml/generate-targets-meson.pl
Normal file
63
doc/src/sgml/generate-targets-meson.pl
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
#
|
||||||
|
# Generate the targets-meson.sgml file from targets-meson.txt
|
||||||
|
# Copyright (c) 2000-2023, PostgreSQL Global Development Group
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
my $targets_meson_file = $ARGV[0];
|
||||||
|
open my $targets_meson, '<', $targets_meson_file or die;
|
||||||
|
|
||||||
|
print
|
||||||
|
"<!-- autogenerated from doc/src/sgml/targets-meson.txt, do not edit -->\n";
|
||||||
|
|
||||||
|
# Find the start of each group of targets
|
||||||
|
while (<$targets_meson>)
|
||||||
|
{
|
||||||
|
next if /^#/;
|
||||||
|
|
||||||
|
if (/^(.*) Targets:$/)
|
||||||
|
{
|
||||||
|
my $targets = $1;
|
||||||
|
my $targets_id = lc $targets;
|
||||||
|
|
||||||
|
print qq(
|
||||||
|
<sect3 id="targets-meson-$targets_id">
|
||||||
|
<title>$targets Targets</title>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
);
|
||||||
|
|
||||||
|
# Each target in the group
|
||||||
|
while (<$targets_meson>)
|
||||||
|
{
|
||||||
|
next if /^#/;
|
||||||
|
last if !/^\s+([^ ]+)\s+(.+)/;
|
||||||
|
|
||||||
|
my $target = $1;
|
||||||
|
my $desc = $2;
|
||||||
|
my $target_id = $1;
|
||||||
|
|
||||||
|
$target_id =~ s/\//-/g;
|
||||||
|
|
||||||
|
print qq(
|
||||||
|
<varlistentry id="meson-target-${target_id}">
|
||||||
|
<term><option>${target}</option></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
${desc}
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
print qq(
|
||||||
|
</variablelist>
|
||||||
|
</sect3>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close $targets_meson;
|
@ -3200,6 +3200,21 @@ ninja install
|
|||||||
</variablelist>
|
</variablelist>
|
||||||
</sect3>
|
</sect3>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="targets-meson">
|
||||||
|
<title><literal>meson</literal> Build Targets</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Individual build targets can be built using <command>ninja</command> <replaceable>target</replaceable>.
|
||||||
|
|
||||||
|
When no target is specified, everything except documentation is
|
||||||
|
built. Individual build products can be built using the path/filename as
|
||||||
|
<replaceable>target</replaceable>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
&targets-meson;
|
||||||
|
</sect2>
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="install-post">
|
<sect1 id="install-post">
|
||||||
|
@ -71,6 +71,15 @@ doc_generated += custom_target('keywords-table.sgml',
|
|||||||
capture: true,
|
capture: true,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
doc_generated += custom_target('targets-meson.sgml',
|
||||||
|
input: files('targets-meson.txt'),
|
||||||
|
output: 'targets-meson.sgml',
|
||||||
|
command: [perl, files('generate-targets-meson.pl'), '@INPUT@'],
|
||||||
|
build_by_default: false,
|
||||||
|
install: false,
|
||||||
|
capture: true,
|
||||||
|
)
|
||||||
|
|
||||||
# For everything else we need at least xmllint
|
# For everything else we need at least xmllint
|
||||||
if not xmllint_bin.found()
|
if not xmllint_bin.found()
|
||||||
subdir_done()
|
subdir_done()
|
||||||
@ -142,7 +151,8 @@ if docs_dep.found()
|
|||||||
'--install-dir-contents', dir_doc_html, html],
|
'--install-dir-contents', dir_doc_html, html],
|
||||||
build_always_stale: true, build_by_default: false,
|
build_always_stale: true, build_by_default: false,
|
||||||
)
|
)
|
||||||
alias_target('install-doc-html', install_doc_html)
|
alias_target('html', html)
|
||||||
|
alias_target('install-html', install_doc_html)
|
||||||
|
|
||||||
# build and install multi-page html docs as part of docs target
|
# build and install multi-page html docs as part of docs target
|
||||||
docs += html
|
docs += html
|
||||||
@ -231,11 +241,12 @@ if docs_dep.found()
|
|||||||
'--install-dirs', dir_man, '@INPUT@'],
|
'--install-dirs', dir_man, '@INPUT@'],
|
||||||
build_always_stale: true, build_by_default: false,
|
build_always_stale: true, build_by_default: false,
|
||||||
)
|
)
|
||||||
alias_target('install-doc-man', install_doc_man)
|
alias_target('man', man)
|
||||||
|
alias_target('install-man', install_doc_man)
|
||||||
|
|
||||||
# even though we don't want to build man pages as part of 'docs', we do want
|
# built and installed as part of the the docs target
|
||||||
# to install them as part of install-docs
|
|
||||||
installdocs += install_doc_man
|
installdocs += install_doc_man
|
||||||
|
docs += man
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
43
doc/src/sgml/targets-meson.txt
Normal file
43
doc/src/sgml/targets-meson.txt
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# Copyright (c) 2023, PostgreSQL Global Development Group
|
||||||
|
#
|
||||||
|
# Description of important meson targets, used for the 'help' target and
|
||||||
|
# installation.sgml (via generate-targets-meson.pl). Right now the parsers are
|
||||||
|
# extremely simple. Both parsers ignore comments. The help target prints
|
||||||
|
# everything else. For xml everything without a leading newline is a group,
|
||||||
|
# remaining lines are target separated by whitespace from their description
|
||||||
|
#
|
||||||
|
Code Targets:
|
||||||
|
all Build everything other than documentation
|
||||||
|
backend Build backend and related modules
|
||||||
|
bin Build frontend binaries
|
||||||
|
contrib Build contrib modules
|
||||||
|
pl Build procedual languages
|
||||||
|
|
||||||
|
Developer Targets:
|
||||||
|
reformat-dat-files Rewrite catalog data files into standard format
|
||||||
|
expand-dat-files Expand all data files to include defaults
|
||||||
|
update-unicode Update unicode data to new version
|
||||||
|
|
||||||
|
Documentation Targets:
|
||||||
|
html Build documentation in multi-page HTML format
|
||||||
|
man Build documentation in man page format
|
||||||
|
docs Build documentation in multi-page HTML and man page format
|
||||||
|
doc/src/sgml/postgres-A4.pdf Build documentation in PDF format, with A4 pages
|
||||||
|
doc/src/sgml/postgres-US.pdf Build documentation in PDF format, with US letter pages
|
||||||
|
doc/src/sgml/postgres.html Build documentation in single-page HTML format
|
||||||
|
alldocs Build documentation in all supported formats
|
||||||
|
|
||||||
|
Installation Targets:
|
||||||
|
install Install postgres, excluding documentation
|
||||||
|
install-docs Install documentation in multi-page HTML and man page formats
|
||||||
|
install-html Install documentation in multi-page HTML format
|
||||||
|
install-man Install documentation in man page format
|
||||||
|
install-quiet Like "install", but installed files are not displayed
|
||||||
|
install-world Install postgres, including multi-page HTML and man page documentation
|
||||||
|
uninstall Remove installed files
|
||||||
|
|
||||||
|
Other Targets:
|
||||||
|
clean Remove all build products
|
||||||
|
test Run all enabled tests (including contrib)
|
||||||
|
world Build everything, including documentation
|
||||||
|
help List important targets
|
@ -3331,8 +3331,17 @@ alias_target('bin', bin_targets + [libpq_st])
|
|||||||
alias_target('pl', pl_targets)
|
alias_target('pl', pl_targets)
|
||||||
alias_target('contrib', contrib_targets)
|
alias_target('contrib', contrib_targets)
|
||||||
alias_target('testprep', testprep_targets)
|
alias_target('testprep', testprep_targets)
|
||||||
|
|
||||||
|
alias_target('world', all_built, docs)
|
||||||
alias_target('install-world', install_quiet, installdocs)
|
alias_target('install-world', install_quiet, installdocs)
|
||||||
|
|
||||||
|
run_target('help',
|
||||||
|
command: [
|
||||||
|
perl, '-ne', 'next if /^#/; print',
|
||||||
|
files('doc/src/sgml/targets-meson.txt'),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
###############################################################
|
###############################################################
|
||||||
|
@ -235,6 +235,10 @@ static bool MatchNamedCall(HeapTuple proctup, int nargs, List *argnames,
|
|||||||
* when a function has search_path set in proconfig. Add a search path cache
|
* when a function has search_path set in proconfig. Add a search path cache
|
||||||
* that can be used by recomputeNamespacePath().
|
* that can be used by recomputeNamespacePath().
|
||||||
*
|
*
|
||||||
|
* The cache is also used to remember already-validated strings in
|
||||||
|
* check_search_path() to avoid the need to call SplitIdentifierString()
|
||||||
|
* repeatedly.
|
||||||
|
*
|
||||||
* The search path cache is based on a wrapper around a simplehash hash table
|
* The search path cache is based on a wrapper around a simplehash hash table
|
||||||
* (nsphash, defined below). The spcache wrapper deals with OOM while trying
|
* (nsphash, defined below). The spcache wrapper deals with OOM while trying
|
||||||
* to initialize a key, and also offers a more convenient API.
|
* to initialize a key, and also offers a more convenient API.
|
||||||
@ -279,40 +283,36 @@ spcachekey_equal(SearchPathCacheKey a, SearchPathCacheKey b)
|
|||||||
static nsphash_hash * SearchPathCache = NULL;
|
static nsphash_hash * SearchPathCache = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create search path cache.
|
* Create or reset search_path cache as necessary.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
spcache_init(void)
|
spcache_init(void)
|
||||||
{
|
{
|
||||||
Assert(SearchPathCacheContext);
|
Assert(SearchPathCacheContext);
|
||||||
|
|
||||||
if (SearchPathCache)
|
if (SearchPathCache && searchPathCacheValid &&
|
||||||
|
SearchPathCache->members < SPCACHE_RESET_THRESHOLD)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
MemoryContextReset(SearchPathCacheContext);
|
||||||
/* arbitrary initial starting size of 16 elements */
|
/* arbitrary initial starting size of 16 elements */
|
||||||
SearchPathCache = nsphash_create(SearchPathCacheContext, 16, NULL);
|
SearchPathCache = nsphash_create(SearchPathCacheContext, 16, NULL);
|
||||||
searchPathCacheValid = true;
|
searchPathCacheValid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reset and reinitialize search path cache.
|
* Look up entry in search path cache without inserting. Returns NULL if not
|
||||||
|
* present.
|
||||||
*/
|
*/
|
||||||
static void
|
static SearchPathCacheEntry *
|
||||||
spcache_reset(void)
|
spcache_lookup(const char *searchPath, Oid roleid)
|
||||||
{
|
{
|
||||||
Assert(SearchPathCacheContext);
|
SearchPathCacheKey cachekey = {
|
||||||
Assert(SearchPathCache);
|
.searchPath = searchPath,
|
||||||
|
.roleid = roleid
|
||||||
|
};
|
||||||
|
|
||||||
MemoryContextReset(SearchPathCacheContext);
|
return nsphash_lookup(SearchPathCache, cachekey);
|
||||||
SearchPathCache = NULL;
|
|
||||||
|
|
||||||
spcache_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32
|
|
||||||
spcache_members(void)
|
|
||||||
{
|
|
||||||
return SearchPathCache->members;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -325,27 +325,25 @@ static SearchPathCacheEntry *
|
|||||||
spcache_insert(const char *searchPath, Oid roleid)
|
spcache_insert(const char *searchPath, Oid roleid)
|
||||||
{
|
{
|
||||||
SearchPathCacheEntry *entry;
|
SearchPathCacheEntry *entry;
|
||||||
bool found;
|
|
||||||
SearchPathCacheKey cachekey = {
|
SearchPathCacheKey cachekey = {
|
||||||
.searchPath = searchPath,
|
.searchPath = searchPath,
|
||||||
.roleid = roleid
|
.roleid = roleid
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If a new entry is created, we must ensure that it's properly
|
* searchPath is not saved in SearchPathCacheContext. First perform a
|
||||||
* initialized. Set the cache invalid temporarily, so that if the
|
* lookup, and copy searchPath only if we need to create a new entry.
|
||||||
* MemoryContextStrdup() below raises an OOM, the cache will be reset on
|
|
||||||
* the next use, clearing the uninitialized entry.
|
|
||||||
*/
|
*/
|
||||||
searchPathCacheValid = false;
|
entry = nsphash_lookup(SearchPathCache, cachekey);
|
||||||
|
|
||||||
entry = nsphash_insert(SearchPathCache, cachekey, &found);
|
if (!entry)
|
||||||
|
|
||||||
/* ensure that key is initialized and the rest is zeroed */
|
|
||||||
if (!found)
|
|
||||||
{
|
{
|
||||||
entry->key.searchPath = MemoryContextStrdup(SearchPathCacheContext, searchPath);
|
bool found;
|
||||||
entry->key.roleid = roleid;
|
|
||||||
|
cachekey.searchPath = MemoryContextStrdup(SearchPathCacheContext, searchPath);
|
||||||
|
entry = nsphash_insert(SearchPathCache, cachekey, &found);
|
||||||
|
Assert(!found);
|
||||||
|
|
||||||
entry->oidlist = NIL;
|
entry->oidlist = NIL;
|
||||||
entry->finalPath = NIL;
|
entry->finalPath = NIL;
|
||||||
entry->firstNS = InvalidOid;
|
entry->firstNS = InvalidOid;
|
||||||
@ -354,7 +352,6 @@ spcache_insert(const char *searchPath, Oid roleid)
|
|||||||
/* do not touch entry->status, used by simplehash */
|
/* do not touch entry->status, used by simplehash */
|
||||||
}
|
}
|
||||||
|
|
||||||
searchPathCacheValid = true;
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4183,31 +4180,15 @@ finalNamespacePath(List *oidlist, Oid *firstNS)
|
|||||||
/*
|
/*
|
||||||
* Retrieve search path information from the cache; or if not there, fill
|
* Retrieve search path information from the cache; or if not there, fill
|
||||||
* it. The returned entry is valid only until the next call to this function.
|
* it. The returned entry is valid only until the next call to this function.
|
||||||
*
|
|
||||||
* We also determine if the newly-computed finalPath is the same as the
|
|
||||||
* prevPath passed by the caller (i.e. a no-op or a real change?). It's more
|
|
||||||
* efficient to check for a change in this function than the caller, because
|
|
||||||
* we can avoid unnecessary temporary copies of the previous path.
|
|
||||||
*/
|
*/
|
||||||
static const SearchPathCacheEntry *
|
static const SearchPathCacheEntry *
|
||||||
cachedNamespacePath(const char *searchPath, Oid roleid, List *prevPath,
|
cachedNamespacePath(const char *searchPath, Oid roleid)
|
||||||
bool *same)
|
|
||||||
{
|
{
|
||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
SearchPathCacheEntry *entry;
|
SearchPathCacheEntry *entry;
|
||||||
List *prevPathCopy = NIL;
|
|
||||||
|
|
||||||
spcache_init();
|
spcache_init();
|
||||||
|
|
||||||
/* invalidate cache if necessary */
|
|
||||||
if (!searchPathCacheValid || spcache_members() >= SPCACHE_RESET_THRESHOLD)
|
|
||||||
{
|
|
||||||
/* prevPath will be destroyed; make temp copy for later comparison */
|
|
||||||
prevPathCopy = list_copy(prevPath);
|
|
||||||
prevPath = prevPathCopy;
|
|
||||||
spcache_reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
entry = spcache_insert(searchPath, roleid);
|
entry = spcache_insert(searchPath, roleid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4232,38 +4213,22 @@ cachedNamespacePath(const char *searchPath, Oid roleid, List *prevPath,
|
|||||||
if (entry->finalPath == NIL || object_access_hook ||
|
if (entry->finalPath == NIL || object_access_hook ||
|
||||||
entry->forceRecompute)
|
entry->forceRecompute)
|
||||||
{
|
{
|
||||||
/*
|
list_free(entry->finalPath);
|
||||||
* Do not free the stale value of entry->finalPath until we've
|
entry->finalPath = NIL;
|
||||||
* performed the comparison, in case it's aliased by prevPath (which
|
|
||||||
* can only happen when recomputing due to an object_access_hook).
|
|
||||||
*/
|
|
||||||
List *finalPath;
|
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo(SearchPathCacheContext);
|
oldcxt = MemoryContextSwitchTo(SearchPathCacheContext);
|
||||||
finalPath = finalNamespacePath(entry->oidlist,
|
entry->finalPath = finalNamespacePath(entry->oidlist,
|
||||||
&entry->firstNS);
|
&entry->firstNS);
|
||||||
MemoryContextSwitchTo(oldcxt);
|
MemoryContextSwitchTo(oldcxt);
|
||||||
|
|
||||||
*same = equal(prevPath, finalPath);
|
|
||||||
|
|
||||||
list_free(entry->finalPath);
|
|
||||||
entry->finalPath = finalPath;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If an object_access_hook set when finalPath is calculated, the
|
* If an object_access_hook is set when finalPath is calculated, the
|
||||||
* result may be affected by the hook. Force recomputation of
|
* result may be affected by the hook. Force recomputation of
|
||||||
* finalPath the next time this cache entry is used, even if the
|
* finalPath the next time this cache entry is used, even if the
|
||||||
* object_access_hook is not set at that time.
|
* object_access_hook is not set at that time.
|
||||||
*/
|
*/
|
||||||
entry->forceRecompute = object_access_hook ? true : false;
|
entry->forceRecompute = object_access_hook ? true : false;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
/* use cached version of finalPath */
|
|
||||||
*same = equal(prevPath, entry->finalPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
list_free(prevPathCopy);
|
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
@ -4275,7 +4240,6 @@ static void
|
|||||||
recomputeNamespacePath(void)
|
recomputeNamespacePath(void)
|
||||||
{
|
{
|
||||||
Oid roleid = GetUserId();
|
Oid roleid = GetUserId();
|
||||||
bool newPathEqual;
|
|
||||||
bool pathChanged;
|
bool pathChanged;
|
||||||
const SearchPathCacheEntry *entry;
|
const SearchPathCacheEntry *entry;
|
||||||
|
|
||||||
@ -4283,24 +4247,32 @@ recomputeNamespacePath(void)
|
|||||||
if (baseSearchPathValid && namespaceUser == roleid)
|
if (baseSearchPathValid && namespaceUser == roleid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
entry = cachedNamespacePath(namespace_search_path, roleid, baseSearchPath,
|
entry = cachedNamespacePath(namespace_search_path, roleid);
|
||||||
&newPathEqual);
|
|
||||||
|
|
||||||
if (baseCreationNamespace == entry->firstNS &&
|
if (baseCreationNamespace == entry->firstNS &&
|
||||||
baseTempCreationPending == entry->temp_missing &&
|
baseTempCreationPending == entry->temp_missing &&
|
||||||
newPathEqual)
|
equal(entry->finalPath, baseSearchPath))
|
||||||
{
|
{
|
||||||
pathChanged = false;
|
pathChanged = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pathChanged = true;
|
MemoryContext oldcxt;
|
||||||
}
|
List *newpath;
|
||||||
|
|
||||||
/* Now safe to assign to state variables. */
|
pathChanged = true;
|
||||||
baseSearchPath = entry->finalPath;
|
|
||||||
baseCreationNamespace = entry->firstNS;
|
/* Must save OID list in permanent storage. */
|
||||||
baseTempCreationPending = entry->temp_missing;
|
oldcxt = MemoryContextSwitchTo(TopMemoryContext);
|
||||||
|
newpath = list_copy(entry->finalPath);
|
||||||
|
MemoryContextSwitchTo(oldcxt);
|
||||||
|
|
||||||
|
/* Now safe to assign to state variables. */
|
||||||
|
list_free(baseSearchPath);
|
||||||
|
baseSearchPath = newpath;
|
||||||
|
baseCreationNamespace = entry->firstNS;
|
||||||
|
baseTempCreationPending = entry->temp_missing;
|
||||||
|
}
|
||||||
|
|
||||||
/* Mark the path valid. */
|
/* Mark the path valid. */
|
||||||
baseSearchPathValid = true;
|
baseSearchPathValid = true;
|
||||||
@ -4625,11 +4597,40 @@ ResetTempTableNamespace(void)
|
|||||||
bool
|
bool
|
||||||
check_search_path(char **newval, void **extra, GucSource source)
|
check_search_path(char **newval, void **extra, GucSource source)
|
||||||
{
|
{
|
||||||
|
Oid roleid = InvalidOid;
|
||||||
|
const char *searchPath = *newval;
|
||||||
char *rawname;
|
char *rawname;
|
||||||
List *namelist;
|
List *namelist;
|
||||||
|
bool use_cache = (SearchPathCacheContext != NULL);
|
||||||
|
|
||||||
/* Need a modifiable copy of string */
|
/*
|
||||||
rawname = pstrdup(*newval);
|
* We used to try to check that the named schemas exist, but there are
|
||||||
|
* many valid use-cases for having search_path settings that include
|
||||||
|
* schemas that don't exist; and often, we are not inside a transaction
|
||||||
|
* here and so can't consult the system catalogs anyway. So now, the only
|
||||||
|
* requirement is syntactic validity of the identifier list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checking only the syntactic validity also allows us to use the search
|
||||||
|
* path cache (if available) to avoid calling SplitIdentifierString() on
|
||||||
|
* the same string repeatedly.
|
||||||
|
*/
|
||||||
|
if (use_cache)
|
||||||
|
{
|
||||||
|
spcache_init();
|
||||||
|
|
||||||
|
roleid = GetUserId();
|
||||||
|
|
||||||
|
if (spcache_lookup(searchPath, roleid) != NULL)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure validity check succeeds before creating cache entry.
|
||||||
|
*/
|
||||||
|
|
||||||
|
rawname = pstrdup(searchPath); /* need a modifiable copy */
|
||||||
|
|
||||||
/* Parse string into list of identifiers */
|
/* Parse string into list of identifiers */
|
||||||
if (!SplitIdentifierString(rawname, ',', &namelist))
|
if (!SplitIdentifierString(rawname, ',', &namelist))
|
||||||
@ -4652,6 +4653,10 @@ check_search_path(char **newval, void **extra, GucSource source)
|
|||||||
pfree(rawname);
|
pfree(rawname);
|
||||||
list_free(namelist);
|
list_free(namelist);
|
||||||
|
|
||||||
|
/* create empty cache entry */
|
||||||
|
if (use_cache)
|
||||||
|
(void) spcache_insert(searchPath, roleid);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -537,6 +537,16 @@ retry:
|
|||||||
*/
|
*/
|
||||||
if (SlotIsLogical(s))
|
if (SlotIsLogical(s))
|
||||||
pgstat_acquire_replslot(s);
|
pgstat_acquire_replslot(s);
|
||||||
|
|
||||||
|
if (am_walsender)
|
||||||
|
{
|
||||||
|
ereport(log_replication_commands ? LOG : DEBUG1,
|
||||||
|
SlotIsLogical(s)
|
||||||
|
? errmsg("acquired logical replication slot \"%s\"",
|
||||||
|
NameStr(s->data.name))
|
||||||
|
: errmsg("acquired physical replication slot \"%s\"",
|
||||||
|
NameStr(s->data.name)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -549,9 +559,17 @@ void
|
|||||||
ReplicationSlotRelease(void)
|
ReplicationSlotRelease(void)
|
||||||
{
|
{
|
||||||
ReplicationSlot *slot = MyReplicationSlot;
|
ReplicationSlot *slot = MyReplicationSlot;
|
||||||
|
char *slotname = NULL; /* keep compiler quiet */
|
||||||
|
bool is_logical = false; /* keep compiler quiet */
|
||||||
|
|
||||||
Assert(slot != NULL && slot->active_pid != 0);
|
Assert(slot != NULL && slot->active_pid != 0);
|
||||||
|
|
||||||
|
if (am_walsender)
|
||||||
|
{
|
||||||
|
slotname = pstrdup(NameStr(slot->data.name));
|
||||||
|
is_logical = SlotIsLogical(slot);
|
||||||
|
}
|
||||||
|
|
||||||
if (slot->data.persistency == RS_EPHEMERAL)
|
if (slot->data.persistency == RS_EPHEMERAL)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -596,6 +614,18 @@ ReplicationSlotRelease(void)
|
|||||||
MyProc->statusFlags &= ~PROC_IN_LOGICAL_DECODING;
|
MyProc->statusFlags &= ~PROC_IN_LOGICAL_DECODING;
|
||||||
ProcGlobal->statusFlags[MyProc->pgxactoff] = MyProc->statusFlags;
|
ProcGlobal->statusFlags[MyProc->pgxactoff] = MyProc->statusFlags;
|
||||||
LWLockRelease(ProcArrayLock);
|
LWLockRelease(ProcArrayLock);
|
||||||
|
|
||||||
|
if (am_walsender)
|
||||||
|
{
|
||||||
|
ereport(log_replication_commands ? LOG : DEBUG1,
|
||||||
|
is_logical
|
||||||
|
? errmsg("released logical replication slot \"%s\"",
|
||||||
|
slotname)
|
||||||
|
: errmsg("released physical replication slot \"%s\"",
|
||||||
|
slotname));
|
||||||
|
|
||||||
|
pfree(slotname);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1061,9 +1061,25 @@ CreateReplicationSlot(CreateReplicationSlotCmd *cmd)
|
|||||||
ReplicationSlotCreate(cmd->slotname, false,
|
ReplicationSlotCreate(cmd->slotname, false,
|
||||||
cmd->temporary ? RS_TEMPORARY : RS_PERSISTENT,
|
cmd->temporary ? RS_TEMPORARY : RS_PERSISTENT,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
|
if (reserve_wal)
|
||||||
|
{
|
||||||
|
ReplicationSlotReserveWal();
|
||||||
|
|
||||||
|
ReplicationSlotMarkDirty();
|
||||||
|
|
||||||
|
/* Write this slot to disk if it's a permanent one. */
|
||||||
|
if (!cmd->temporary)
|
||||||
|
ReplicationSlotSave();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
LogicalDecodingContext *ctx;
|
||||||
|
bool need_full_snapshot = false;
|
||||||
|
|
||||||
|
Assert(cmd->kind == REPLICATION_KIND_LOGICAL);
|
||||||
|
|
||||||
CheckLogicalDecodingRequirements();
|
CheckLogicalDecodingRequirements();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1076,12 +1092,6 @@ CreateReplicationSlot(CreateReplicationSlotCmd *cmd)
|
|||||||
ReplicationSlotCreate(cmd->slotname, true,
|
ReplicationSlotCreate(cmd->slotname, true,
|
||||||
cmd->temporary ? RS_TEMPORARY : RS_EPHEMERAL,
|
cmd->temporary ? RS_TEMPORARY : RS_EPHEMERAL,
|
||||||
two_phase);
|
two_phase);
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd->kind == REPLICATION_KIND_LOGICAL)
|
|
||||||
{
|
|
||||||
LogicalDecodingContext *ctx;
|
|
||||||
bool need_full_snapshot = false;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do options check early so that we can bail before calling the
|
* Do options check early so that we can bail before calling the
|
||||||
@ -1175,16 +1185,6 @@ CreateReplicationSlot(CreateReplicationSlotCmd *cmd)
|
|||||||
if (!cmd->temporary)
|
if (!cmd->temporary)
|
||||||
ReplicationSlotPersist();
|
ReplicationSlotPersist();
|
||||||
}
|
}
|
||||||
else if (cmd->kind == REPLICATION_KIND_PHYSICAL && reserve_wal)
|
|
||||||
{
|
|
||||||
ReplicationSlotReserveWal();
|
|
||||||
|
|
||||||
ReplicationSlotMarkDirty();
|
|
||||||
|
|
||||||
/* Write this slot to disk if it's a permanent one. */
|
|
||||||
if (!cmd->temporary)
|
|
||||||
ReplicationSlotSave();
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(xloc, sizeof(xloc), "%X/%X",
|
snprintf(xloc, sizeof(xloc), "%X/%X",
|
||||||
LSN_FORMAT_ARGS(MyReplicationSlot->data.confirmed_flush));
|
LSN_FORMAT_ARGS(MyReplicationSlot->data.confirmed_flush));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user