Compare commits

..

No commits in common. "e83aa9f92fdd88c2912cc43a61fd9f59f4c8f4d3" and "3650e7a3933166b40f7f9043bd91f45d3467c74d" have entirely different histories.

12 changed files with 115 additions and 295 deletions

View File

@ -15,8 +15,6 @@
# 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
@ -27,6 +25,8 @@ 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 targets-meson.sgml wait_event_types.sgml keywords-table.sgml wait_event_types.sgml
ALLSGML := $(wildcard $(srcdir)/*.sgml $(srcdir)/ref/*.sgml) $(GENERATED_SGML) ALLSGML := $(wildcard $(srcdir)/*.sgml $(srcdir)/ref/*.sgml) $(GENERATED_SGML)
@ -110,9 +110,6 @@ 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.
## ##

View File

@ -7510,12 +7510,11 @@ log_line_prefix = '%m [%p] %q%u@%d/%a '
</term> </term>
<listitem> <listitem>
<para> <para>
Causes each replication command and <literal>walsender</literal> Causes each replication command to be logged in the server log.
process's replication slot acquisition/release to be logged in the See <xref linkend="protocol-replication"/> for more information about
server log. See <xref linkend="protocol-replication"/> for more replication command. The default value is <literal>off</literal>.
information about replication command. The default value is Only superusers and users with the appropriate <literal>SET</literal>
<literal>off</literal>. Only superusers and users with the appropriate privilege can change this setting.
<literal>SET</literal> privilege can change this setting.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@ -434,19 +434,20 @@ LOGLEVEL=-Dorg.apache.commons.logging.simplelog.defaultlog=WARN
<title>Building the Documentation with Meson</title> <title>Building the Documentation with Meson</title>
<para> <para>
To build the documentation using Meson, change to the Two options are provided for building the documentation using Meson.
<filename>build</filename> directory before running one of these commands, Change to the <filename>build</filename> directory before running
or add <option>-C build</option> to the command. one of these commands, 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 html</userinput> <prompt>build$ </prompt><userinput>ninja docs</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>

View File

@ -38,7 +38,6 @@
<!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">

View File

@ -1,63 +0,0 @@
#!/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;

View File

@ -3200,21 +3200,6 @@ 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">

View File

@ -71,15 +71,6 @@ 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()
@ -151,8 +142,7 @@ 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('html', html) alias_target('install-doc-html', install_doc_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
@ -241,12 +231,11 @@ 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('man', man) alias_target('install-doc-man', install_doc_man)
alias_target('install-man', install_doc_man)
# built and installed as part of the the docs target # even though we don't want to build man pages as part of 'docs', we do want
# to install them as part of install-docs
installdocs += install_doc_man installdocs += install_doc_man
docs += man
endif endif

View File

@ -1,43 +0,0 @@
# 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

View File

@ -3331,17 +3331,8 @@ 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'),
]
)
############################################################### ###############################################################

View File

@ -235,10 +235,6 @@ 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.
@ -283,36 +279,40 @@ spcachekey_equal(SearchPathCacheKey a, SearchPathCacheKey b)
static nsphash_hash * SearchPathCache = NULL; static nsphash_hash * SearchPathCache = NULL;
/* /*
* Create or reset search_path cache as necessary. * Create search path cache.
*/ */
static void static void
spcache_init(void) spcache_init(void)
{ {
Assert(SearchPathCacheContext); Assert(SearchPathCacheContext);
if (SearchPathCache && searchPathCacheValid && if (SearchPathCache)
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;
} }
/* /*
* Look up entry in search path cache without inserting. Returns NULL if not * Reset and reinitialize search path cache.
* present.
*/ */
static SearchPathCacheEntry * static void
spcache_lookup(const char *searchPath, Oid roleid) spcache_reset(void)
{ {
SearchPathCacheKey cachekey = { Assert(SearchPathCacheContext);
.searchPath = searchPath, Assert(SearchPathCache);
.roleid = roleid
};
return nsphash_lookup(SearchPathCache, cachekey); MemoryContextReset(SearchPathCacheContext);
SearchPathCache = NULL;
spcache_init();
}
static uint32
spcache_members(void)
{
return SearchPathCache->members;
} }
/* /*
@ -325,25 +325,27 @@ 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
}; };
/* /*
* searchPath is not saved in SearchPathCacheContext. First perform a * If a new entry is created, we must ensure that it's properly
* lookup, and copy searchPath only if we need to create a new entry. * initialized. Set the cache invalid temporarily, so that if the
* MemoryContextStrdup() below raises an OOM, the cache will be reset on
* the next use, clearing the uninitialized entry.
*/ */
entry = nsphash_lookup(SearchPathCache, cachekey); searchPathCacheValid = false;
if (!entry)
{
bool found;
cachekey.searchPath = MemoryContextStrdup(SearchPathCacheContext, searchPath);
entry = nsphash_insert(SearchPathCache, cachekey, &found); entry = nsphash_insert(SearchPathCache, cachekey, &found);
Assert(!found);
/* ensure that key is initialized and the rest is zeroed */
if (!found)
{
entry->key.searchPath = MemoryContextStrdup(SearchPathCacheContext, searchPath);
entry->key.roleid = roleid;
entry->oidlist = NIL; entry->oidlist = NIL;
entry->finalPath = NIL; entry->finalPath = NIL;
entry->firstNS = InvalidOid; entry->firstNS = InvalidOid;
@ -352,6 +354,7 @@ 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;
} }
@ -4180,15 +4183,31 @@ 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) cachedNamespacePath(const char *searchPath, Oid roleid, List *prevPath,
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);
/* /*
@ -4213,22 +4232,38 @@ cachedNamespacePath(const char *searchPath, Oid roleid)
if (entry->finalPath == NIL || object_access_hook || if (entry->finalPath == NIL || object_access_hook ||
entry->forceRecompute) entry->forceRecompute)
{ {
list_free(entry->finalPath); /*
entry->finalPath = NIL; * Do not free the stale value of entry->finalPath until we've
* 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);
entry->finalPath = finalNamespacePath(entry->oidlist, 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 is set when finalPath is calculated, the * If an object_access_hook 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;
} }
@ -4240,6 +4275,7 @@ static void
recomputeNamespacePath(void) recomputeNamespacePath(void)
{ {
Oid roleid = GetUserId(); Oid roleid = GetUserId();
bool newPathEqual;
bool pathChanged; bool pathChanged;
const SearchPathCacheEntry *entry; const SearchPathCacheEntry *entry;
@ -4247,32 +4283,24 @@ recomputeNamespacePath(void)
if (baseSearchPathValid && namespaceUser == roleid) if (baseSearchPathValid && namespaceUser == roleid)
return; return;
entry = cachedNamespacePath(namespace_search_path, roleid); entry = cachedNamespacePath(namespace_search_path, roleid, baseSearchPath,
&newPathEqual);
if (baseCreationNamespace == entry->firstNS && if (baseCreationNamespace == entry->firstNS &&
baseTempCreationPending == entry->temp_missing && baseTempCreationPending == entry->temp_missing &&
equal(entry->finalPath, baseSearchPath)) newPathEqual)
{ {
pathChanged = false; pathChanged = false;
} }
else else
{ {
MemoryContext oldcxt;
List *newpath;
pathChanged = true; pathChanged = true;
}
/* Must save OID list in permanent storage. */
oldcxt = MemoryContextSwitchTo(TopMemoryContext);
newpath = list_copy(entry->finalPath);
MemoryContextSwitchTo(oldcxt);
/* Now safe to assign to state variables. */ /* Now safe to assign to state variables. */
list_free(baseSearchPath); baseSearchPath = entry->finalPath;
baseSearchPath = newpath;
baseCreationNamespace = entry->firstNS; baseCreationNamespace = entry->firstNS;
baseTempCreationPending = entry->temp_missing; baseTempCreationPending = entry->temp_missing;
}
/* Mark the path valid. */ /* Mark the path valid. */
baseSearchPathValid = true; baseSearchPathValid = true;
@ -4597,40 +4625,11 @@ 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 */
* We used to try to check that the named schemas exist, but there are rawname = pstrdup(*newval);
* 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))
@ -4653,10 +4652,6 @@ 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;
} }

View File

@ -537,16 +537,6 @@ 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)));
}
} }
/* /*
@ -559,17 +549,9 @@ 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)
{ {
/* /*
@ -614,18 +596,6 @@ 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);
}
} }
/* /*

View File

@ -1061,25 +1061,9 @@ 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();
/* /*
@ -1092,6 +1076,12 @@ 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
@ -1185,6 +1175,16 @@ 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));