Simplify creation of built-in functions with default arguments.

Up to now, to create such a function, one had to make a pg_proc.dat
entry and then overwrite it with a CREATE OR REPLACE command in
system_functions.sql.  That's error-prone (cf. bug #19409) and
results in leaving dead rows in the initial contents of pg_proc.

Manual maintenance of pg_node_tree strings seems entirely impractical,
and parsing expressions during bootstrap would be extremely difficult
as well.  But Andres Freund observed that all the current use-cases
are simple constants, and building a Const node is well within the
capabilities of bootstrap mode.  So this patch invents a special case:
if bootstrap mode is asked to ingest a non-null value for
pg_proc.proargdefaults (which would otherwise fail in
pg_node_tree_in), it parses the value as an array literal and then
feeds the element strings to the input functions for the corresponding
parameter types.  Then we can build a suitable pg_node_tree string
with just a few more lines of code.

This allows removing all the system_functions.sql entries that are
just there to set up default arguments, replacing them with
proargdefaults fields in pg_proc.dat entries.  The old technique
remains available in case someone needs a non-constant default.

The initial contents of pg_proc are demonstrably the same after
this patch, except that (1) json_strip_nulls and jsonb_strip_nulls
now have the correct provolatile setting, as per bug #19409;
(2) pg_terminate_backend, make_interval, and drandom_normal
now have defaults that don't include a type coercion, which is
how they should have been all along.

In passing, remove some unused entries from bootstrap.c's TypInfo[]
array.  I had to add some new ones because we'll now need an entry for
each default-possessing system function parameter, but we shouldn't
carry more than we need there; it's just a maintenance gotcha.

Bug: #19409
Reported-by: Lucio Chiessi <lucio.chiessi@trustly.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Author: Andrew Dunstan <andrew@dunslane.net>
Reviewed-by: Andres Freund <andres@anarazel.de>
Discussion: https://postgr.es/m/183292bb-4891-4c96-a3ca-e78b5e0e1358@dunslane.net
Discussion: https://postgr.es/m/19409-e16cd2605e59a4af@postgresql.org
This commit is contained in:
Tom Lane 2026-02-18 14:14:44 -05:00
parent d62dca3b29
commit 759b03b24c
7 changed files with 263 additions and 326 deletions

View file

@ -271,6 +271,21 @@
</para>
</listitem>
<listitem>
<para>
There is a special case for values of the
<structname>pg_proc</structname>.<structfield>proargdefaults</structfield>
field, which is of type <type>pg_node_tree</type>. The real
contents of that type are too complex for hand-written entries,
but what we need for <structfield>proargdefaults</structfield> is
typically just a list of Const nodes. Therefore, the bootstrap
backend will interpret a value given for that field according to
text array syntax, and then feed the array element values to the
datatype input routines for the corresponding input parameters' data
types, and finally build Const nodes from the datums.
</para>
</listitem>
<listitem>
<para>
Since hashes are unordered data structures, field order and line
@ -817,11 +832,11 @@ $ perl rewrite_dat_with_prokind.pl pg_proc.dat
The following column types are supported directly by
<filename>bootstrap.c</filename>: <type>bool</type>,
<type>bytea</type>, <type>char</type> (1 byte),
<type>name</type>, <type>int2</type>,
<type>int4</type>, <type>regproc</type>, <type>regclass</type>,
<type>regtype</type>, <type>text</type>,
<type>oid</type>, <type>tid</type>, <type>xid</type>,
<type>cid</type>, <type>int2vector</type>, <type>oidvector</type>,
<type>int2</type>, <type>int4</type>, <type>int8</type>,
<type>float4</type>, <type>float8</type>,
<type>name</type>, <type>regproc</type>, <type>text</type>,
<type>jsonb</type>, <type>oid</type>, <type>pg_node_tree</type>,
<type>int2vector</type>, <type>oidvector</type>,
<type>_int4</type> (array), <type>_text</type> (array),
<type>_oid</type> (array), <type>_char</type> (array),
<type>_aclitem</type> (array). Although it is possible to create
@ -884,7 +899,7 @@ $ perl rewrite_dat_with_prokind.pl pg_proc.dat
<varlistentry>
<term>
<literal>insert</literal> <literal>(</literal> <optional><replaceable class="parameter">oid_value</replaceable></optional> <replaceable class="parameter">value1</replaceable> <replaceable class="parameter">value2</replaceable> ... <literal>)</literal>
<literal>insert</literal> <literal>(</literal> <replaceable class="parameter">value1</replaceable> <replaceable class="parameter">value2</replaceable> ... <literal>)</literal>
</term>
<listitem>
@ -902,6 +917,13 @@ $ perl rewrite_dat_with_prokind.pl pg_proc.dat
(To include a single quote in a value, write it twice.
Escape-string-style backslash escapes are allowed in the string, too.)
</para>
<para>
In most cases a <replaceable class="parameter">value</replaceable>
string is simply fed to the datatype input routine for the column's
data type, after de-quoting if needed. However there are exceptions
for certain fields, as detailed previously.
</para>
</listitem>
</varlistentry>

View file

@ -26,6 +26,7 @@
#include "bootstrap/bootstrap.h"
#include "catalog/index.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "common/link-canary.h"
#include "miscadmin.h"
@ -46,6 +47,7 @@
static void CheckerModeMain(void);
static void bootstrap_signals(void);
static Form_pg_attribute AllocateAttribute(void);
static void InsertOneProargdefaultsValue(char *value);
static void populate_typ_list(void);
static Oid gettype(char *type);
static void cleanup(void);
@ -91,38 +93,28 @@ static const struct typinfo TypInfo[] = {
F_BYTEAIN, F_BYTEAOUT},
{"char", CHAROID, 0, 1, true, TYPALIGN_CHAR, TYPSTORAGE_PLAIN, InvalidOid,
F_CHARIN, F_CHAROUT},
{"cstring", CSTRINGOID, 0, -2, false, TYPALIGN_CHAR, TYPSTORAGE_PLAIN, InvalidOid,
F_CSTRING_IN, F_CSTRING_OUT},
{"int2", INT2OID, 0, 2, true, TYPALIGN_SHORT, TYPSTORAGE_PLAIN, InvalidOid,
F_INT2IN, F_INT2OUT},
{"int4", INT4OID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
F_INT4IN, F_INT4OUT},
{"int8", INT8OID, 0, 8, true, TYPALIGN_DOUBLE, TYPSTORAGE_PLAIN, InvalidOid,
F_INT8IN, F_INT8OUT},
{"float4", FLOAT4OID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
F_FLOAT4IN, F_FLOAT4OUT},
{"float8", FLOAT8OID, 0, 8, true, TYPALIGN_DOUBLE, TYPSTORAGE_PLAIN, InvalidOid,
F_FLOAT8IN, F_FLOAT8OUT},
{"name", NAMEOID, CHAROID, NAMEDATALEN, false, TYPALIGN_CHAR, TYPSTORAGE_PLAIN, C_COLLATION_OID,
F_NAMEIN, F_NAMEOUT},
{"regclass", REGCLASSOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
F_REGCLASSIN, F_REGCLASSOUT},
{"regproc", REGPROCOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
F_REGPROCIN, F_REGPROCOUT},
{"regtype", REGTYPEOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
F_REGTYPEIN, F_REGTYPEOUT},
{"regrole", REGROLEOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
F_REGROLEIN, F_REGROLEOUT},
{"regnamespace", REGNAMESPACEOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
F_REGNAMESPACEIN, F_REGNAMESPACEOUT},
{"regdatabase", REGDATABASEOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
F_REGDATABASEIN, F_REGDATABASEOUT},
{"text", TEXTOID, 0, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, DEFAULT_COLLATION_OID,
F_TEXTIN, F_TEXTOUT},
{"jsonb", JSONBOID, 0, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, InvalidOid,
F_JSONB_IN, F_JSONB_OUT},
{"oid", OIDOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
F_OIDIN, F_OIDOUT},
{"oid8", OID8OID, 0, 8, true, TYPALIGN_DOUBLE, TYPSTORAGE_PLAIN, InvalidOid,
F_OID8IN, F_OID8OUT},
{"tid", TIDOID, 0, 6, false, TYPALIGN_SHORT, TYPSTORAGE_PLAIN, InvalidOid,
F_TIDIN, F_TIDOUT},
{"xid", XIDOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
F_XIDIN, F_XIDOUT},
{"cid", CIDOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
F_CIDIN, F_CIDOUT},
{"pg_node_tree", PG_NODE_TREEOID, 0, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, DEFAULT_COLLATION_OID,
F_PG_NODE_TREE_IN, F_PG_NODE_TREE_OUT},
{"int2vector", INT2VECTOROID, INT2OID, -1, false, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
@ -660,6 +652,7 @@ InsertOneTuple(void)
void
InsertOneValue(char *value, int i)
{
Form_pg_attribute attr;
Oid typoid;
int16 typlen;
bool typbyval;
@ -668,19 +661,42 @@ InsertOneValue(char *value, int i)
Oid typioparam;
Oid typinput;
Oid typoutput;
Oid typcollation;
Assert(i >= 0 && i < MAXATTR);
elog(DEBUG4, "inserting column %d value \"%s\"", i, value);
typoid = TupleDescAttr(boot_reldesc->rd_att, i)->atttypid;
attr = TupleDescAttr(RelationGetDescr(boot_reldesc), i);
typoid = attr->atttypid;
boot_get_type_io_data(typoid,
&typlen, &typbyval, &typalign,
&typdelim, &typioparam,
&typinput, &typoutput);
&typinput, &typoutput,
&typcollation);
values[i] = OidInputFunctionCall(typinput, value, typioparam, -1);
/*
* pg_node_tree values can't be inserted normally (pg_node_tree_in would
* just error out), so provide special cases for such columns that we
* would like to fill during bootstrap.
*/
if (typoid == PG_NODE_TREEOID)
{
/* pg_proc.proargdefaults */
if (RelationGetRelid(boot_reldesc) == ProcedureRelationId &&
i == Anum_pg_proc_proargdefaults - 1)
InsertOneProargdefaultsValue(value);
else /* maybe other cases later */
elog(ERROR, "can't handle pg_node_tree input for %s.%s",
RelationGetRelationName(boot_reldesc),
NameStr(attr->attname));
}
else
{
/* Normal case */
values[i] = OidInputFunctionCall(typinput, value, typioparam, -1);
}
/*
* We use ereport not elog here so that parameters aren't evaluated unless
@ -691,6 +707,111 @@ InsertOneValue(char *value, int i)
OidOutputFunctionCall(typoutput, values[i]))));
}
/* ----------------
* InsertOneProargdefaultsValue
*
* In general, proargdefaults can be a list of any expressions, but
* for bootstrap we only support a list of Const nodes. The input
* has the form of a text array, and we feed non-null elements to the
* typinput functions for the appropriate parameters.
* ----------------
*/
static void
InsertOneProargdefaultsValue(char *value)
{
int pronargs;
oidvector *proargtypes;
Datum arrayval;
Datum *array_datums;
bool *array_nulls;
int array_count;
List *proargdefaults;
char *nodestring;
/* The pg_proc columns we need to use must have been filled already */
StaticAssertDecl(Anum_pg_proc_pronargs < Anum_pg_proc_proargdefaults,
"pronargs must come before proargdefaults");
StaticAssertDecl(Anum_pg_proc_pronargdefaults < Anum_pg_proc_proargdefaults,
"pronargdefaults must come before proargdefaults");
StaticAssertDecl(Anum_pg_proc_proargtypes < Anum_pg_proc_proargdefaults,
"proargtypes must come before proargdefaults");
if (Nulls[Anum_pg_proc_pronargs - 1])
elog(ERROR, "pronargs must not be null");
if (Nulls[Anum_pg_proc_proargtypes - 1])
elog(ERROR, "proargtypes must not be null");
pronargs = DatumGetInt16(values[Anum_pg_proc_pronargs - 1]);
proargtypes = DatumGetPointer(values[Anum_pg_proc_proargtypes - 1]);
Assert(pronargs == proargtypes->dim1);
/* Parse the input string as an array value, then deconstruct to Datums */
arrayval = OidFunctionCall3(F_ARRAY_IN,
CStringGetDatum(value),
ObjectIdGetDatum(CSTRINGOID),
Int32GetDatum(-1));
deconstruct_array_builtin(DatumGetArrayTypeP(arrayval), CSTRINGOID,
&array_datums, &array_nulls, &array_count);
/* The values should correspond to the last N argtypes */
if (array_count > pronargs)
elog(ERROR, "too many proargdefaults entries");
/* Build the List of Const nodes */
proargdefaults = NIL;
for (int i = 0; i < array_count; i++)
{
Oid argtype = proargtypes->values[pronargs - array_count + i];
int16 typlen;
bool typbyval;
char typalign;
char typdelim;
Oid typioparam;
Oid typinput;
Oid typoutput;
Oid typcollation;
Datum defval;
bool defnull;
Const *defConst;
boot_get_type_io_data(argtype,
&typlen, &typbyval, &typalign,
&typdelim, &typioparam,
&typinput, &typoutput,
&typcollation);
defnull = array_nulls[i];
if (defnull)
defval = (Datum) 0;
else
defval = OidInputFunctionCall(typinput,
DatumGetCString(array_datums[i]),
typioparam, -1);
defConst = makeConst(argtype,
-1, /* never any typmod */
typcollation,
typlen,
defval,
defnull,
typbyval);
proargdefaults = lappend(proargdefaults, defConst);
}
/*
* Flatten the List to a node-tree string, then convert to a text datum,
* which is the storage representation of pg_node_tree.
*/
nodestring = nodeToString(proargdefaults);
values[Anum_pg_proc_proargdefaults - 1] = CStringGetTextDatum(nodestring);
Nulls[Anum_pg_proc_proargdefaults - 1] = false;
/*
* Hack: fill in pronargdefaults with the right value. This is surely
* ugly, but it beats making the programmer do it.
*/
values[Anum_pg_proc_pronargdefaults - 1] = Int16GetDatum(array_count);
Nulls[Anum_pg_proc_pronargdefaults - 1] = false;
}
/* ----------------
* InsertOneNull
* ----------------
@ -831,10 +952,11 @@ gettype(char *type)
* boot_get_type_io_data
*
* Obtain type I/O information at bootstrap time. This intentionally has
* almost the same API as lsyscache.c's get_type_io_data, except that
* an API very close to that of lsyscache.c's get_type_io_data, except that
* we only support obtaining the typinput and typoutput routines, not
* the binary I/O routines. It is exported so that array_in and array_out
* can be made to work during early bootstrap.
* the binary I/O routines, and we also return the type's collation.
* This is exported so that array_in and array_out can be made to work
* during early bootstrap.
* ----------------
*/
void
@ -845,7 +967,8 @@ boot_get_type_io_data(Oid typid,
char *typdelim,
Oid *typioparam,
Oid *typinput,
Oid *typoutput)
Oid *typoutput,
Oid *typcollation)
{
if (Typ != NIL)
{
@ -876,6 +999,8 @@ boot_get_type_io_data(Oid typid,
*typinput = ap->am_typ.typinput;
*typoutput = ap->am_typ.typoutput;
*typcollation = ap->am_typ.typcollation;
}
else
{
@ -904,6 +1029,8 @@ boot_get_type_io_data(Oid typid,
*typinput = TypInfo[typeindex].inproc;
*typoutput = TypInfo[typeindex].outproc;
*typcollation = TypInfo[typeindex].collation;
}
}

View file

@ -7,7 +7,8 @@
*
* This file redefines certain built-in functions that are impractical
* to fully define in pg_proc.dat. In most cases that's because they use
* SQL-standard function bodies and/or default expressions. The node
* SQL-standard function bodies and/or default expressions. (But defaults
* that are just constants can be entered in pg_proc.dat.) The node
* tree representations of those are too unreadable, platform-dependent,
* and changeable to want to deal with them manually. Hence, we put stub
* definitions of such functions into pg_proc.dat and then replace them
@ -66,13 +67,6 @@ CREATE OR REPLACE FUNCTION bit_length(text)
IMMUTABLE PARALLEL SAFE STRICT COST 1
RETURN octet_length($1) * 8;
CREATE OR REPLACE FUNCTION
random_normal(mean float8 DEFAULT 0, stddev float8 DEFAULT 1)
RETURNS float8
LANGUAGE internal
VOLATILE PARALLEL RESTRICTED STRICT COST 1
AS 'drandom_normal';
CREATE OR REPLACE FUNCTION log(numeric)
RETURNS numeric
LANGUAGE sql
@ -383,279 +377,6 @@ BEGIN ATOMIC
SELECT * FROM ts_debug(get_current_ts_config(), $1);
END;
CREATE OR REPLACE FUNCTION
pg_backup_start(label text, fast boolean DEFAULT false)
RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_backup_start'
PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION pg_backup_stop (
wait_for_archive boolean DEFAULT true, OUT lsn pg_lsn,
OUT labelfile text, OUT spcmapfile text)
RETURNS record STRICT VOLATILE LANGUAGE internal as 'pg_backup_stop'
PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION
pg_promote(wait boolean DEFAULT true, wait_seconds integer DEFAULT 60)
RETURNS boolean STRICT VOLATILE LANGUAGE INTERNAL AS 'pg_promote'
PARALLEL SAFE;
CREATE OR REPLACE FUNCTION
pg_terminate_backend(pid integer, timeout int8 DEFAULT 0)
RETURNS boolean STRICT VOLATILE LANGUAGE INTERNAL AS 'pg_terminate_backend'
PARALLEL SAFE;
-- legacy definition for compatibility with 9.3
CREATE OR REPLACE FUNCTION
json_populate_record(base anyelement, from_json json, use_json_as_text boolean DEFAULT false)
RETURNS anyelement LANGUAGE internal STABLE AS 'json_populate_record' PARALLEL SAFE;
-- legacy definition for compatibility with 9.3
CREATE OR REPLACE FUNCTION
json_populate_recordset(base anyelement, from_json json, use_json_as_text boolean DEFAULT false)
RETURNS SETOF anyelement LANGUAGE internal STABLE ROWS 100 AS 'json_populate_recordset' PARALLEL SAFE;
CREATE OR REPLACE FUNCTION pg_logical_slot_get_changes(
IN slot_name name, IN upto_lsn pg_lsn, IN upto_nchanges int, VARIADIC options text[] DEFAULT '{}',
OUT lsn pg_lsn, OUT xid xid, OUT data text)
RETURNS SETOF RECORD
LANGUAGE INTERNAL
VOLATILE ROWS 1000 COST 1000
AS 'pg_logical_slot_get_changes';
CREATE OR REPLACE FUNCTION pg_logical_slot_peek_changes(
IN slot_name name, IN upto_lsn pg_lsn, IN upto_nchanges int, VARIADIC options text[] DEFAULT '{}',
OUT lsn pg_lsn, OUT xid xid, OUT data text)
RETURNS SETOF RECORD
LANGUAGE INTERNAL
VOLATILE ROWS 1000 COST 1000
AS 'pg_logical_slot_peek_changes';
CREATE OR REPLACE FUNCTION pg_logical_slot_get_binary_changes(
IN slot_name name, IN upto_lsn pg_lsn, IN upto_nchanges int, VARIADIC options text[] DEFAULT '{}',
OUT lsn pg_lsn, OUT xid xid, OUT data bytea)
RETURNS SETOF RECORD
LANGUAGE INTERNAL
VOLATILE ROWS 1000 COST 1000
AS 'pg_logical_slot_get_binary_changes';
CREATE OR REPLACE FUNCTION pg_logical_slot_peek_binary_changes(
IN slot_name name, IN upto_lsn pg_lsn, IN upto_nchanges int, VARIADIC options text[] DEFAULT '{}',
OUT lsn pg_lsn, OUT xid xid, OUT data bytea)
RETURNS SETOF RECORD
LANGUAGE INTERNAL
VOLATILE ROWS 1000 COST 1000
AS 'pg_logical_slot_peek_binary_changes';
CREATE OR REPLACE FUNCTION pg_logical_emit_message(
transactional boolean,
prefix text,
message text,
flush boolean DEFAULT false)
RETURNS pg_lsn
LANGUAGE INTERNAL
STRICT VOLATILE
AS 'pg_logical_emit_message_text';
CREATE OR REPLACE FUNCTION pg_logical_emit_message(
transactional boolean,
prefix text,
message bytea,
flush boolean DEFAULT false)
RETURNS pg_lsn
LANGUAGE INTERNAL
STRICT VOLATILE
AS 'pg_logical_emit_message_bytea';
CREATE OR REPLACE FUNCTION pg_create_physical_replication_slot(
IN slot_name name, IN immediately_reserve boolean DEFAULT false,
IN temporary boolean DEFAULT false,
OUT slot_name name, OUT lsn pg_lsn)
RETURNS RECORD
LANGUAGE INTERNAL
STRICT VOLATILE
AS 'pg_create_physical_replication_slot';
CREATE OR REPLACE FUNCTION pg_create_logical_replication_slot(
IN slot_name name, IN plugin name,
IN temporary boolean DEFAULT false,
IN twophase boolean DEFAULT false,
IN failover boolean DEFAULT false,
OUT slot_name name, OUT lsn pg_lsn)
RETURNS RECORD
LANGUAGE INTERNAL
STRICT VOLATILE
AS 'pg_create_logical_replication_slot';
CREATE OR REPLACE FUNCTION
make_interval(years int4 DEFAULT 0, months int4 DEFAULT 0, weeks int4 DEFAULT 0,
days int4 DEFAULT 0, hours int4 DEFAULT 0, mins int4 DEFAULT 0,
secs double precision DEFAULT 0.0)
RETURNS interval
LANGUAGE INTERNAL
STRICT IMMUTABLE PARALLEL SAFE
AS 'make_interval';
CREATE OR REPLACE FUNCTION
jsonb_set(jsonb_in jsonb, path text[] , replacement jsonb,
create_if_missing boolean DEFAULT true)
RETURNS jsonb
LANGUAGE INTERNAL
STRICT IMMUTABLE PARALLEL SAFE
AS 'jsonb_set';
CREATE OR REPLACE FUNCTION
jsonb_set_lax(jsonb_in jsonb, path text[] , replacement jsonb,
create_if_missing boolean DEFAULT true,
null_value_treatment text DEFAULT 'use_json_null')
RETURNS jsonb
LANGUAGE INTERNAL
CALLED ON NULL INPUT IMMUTABLE PARALLEL SAFE
AS 'jsonb_set_lax';
CREATE OR REPLACE FUNCTION
parse_ident(str text, strict boolean DEFAULT true)
RETURNS text[]
LANGUAGE INTERNAL
STRICT IMMUTABLE PARALLEL SAFE
AS 'parse_ident';
CREATE OR REPLACE FUNCTION
jsonb_insert(jsonb_in jsonb, path text[] , replacement jsonb,
insert_after boolean DEFAULT false)
RETURNS jsonb
LANGUAGE INTERNAL
STRICT IMMUTABLE PARALLEL SAFE
AS 'jsonb_insert';
CREATE OR REPLACE FUNCTION
jsonb_path_exists(target jsonb, path jsonpath, vars jsonb DEFAULT '{}',
silent boolean DEFAULT false)
RETURNS boolean
LANGUAGE INTERNAL
STRICT IMMUTABLE PARALLEL SAFE
AS 'jsonb_path_exists';
CREATE OR REPLACE FUNCTION
jsonb_path_match(target jsonb, path jsonpath, vars jsonb DEFAULT '{}',
silent boolean DEFAULT false)
RETURNS boolean
LANGUAGE INTERNAL
STRICT IMMUTABLE PARALLEL SAFE
AS 'jsonb_path_match';
CREATE OR REPLACE FUNCTION
jsonb_path_query(target jsonb, path jsonpath, vars jsonb DEFAULT '{}',
silent boolean DEFAULT false)
RETURNS SETOF jsonb
LANGUAGE INTERNAL
STRICT IMMUTABLE PARALLEL SAFE
AS 'jsonb_path_query';
CREATE OR REPLACE FUNCTION
jsonb_path_query_array(target jsonb, path jsonpath, vars jsonb DEFAULT '{}',
silent boolean DEFAULT false)
RETURNS jsonb
LANGUAGE INTERNAL
STRICT IMMUTABLE PARALLEL SAFE
AS 'jsonb_path_query_array';
CREATE OR REPLACE FUNCTION
jsonb_path_query_first(target jsonb, path jsonpath, vars jsonb DEFAULT '{}',
silent boolean DEFAULT false)
RETURNS jsonb
LANGUAGE INTERNAL
STRICT IMMUTABLE PARALLEL SAFE
AS 'jsonb_path_query_first';
CREATE OR REPLACE FUNCTION
jsonb_path_exists_tz(target jsonb, path jsonpath, vars jsonb DEFAULT '{}',
silent boolean DEFAULT false)
RETURNS boolean
LANGUAGE INTERNAL
STRICT STABLE PARALLEL SAFE
AS 'jsonb_path_exists_tz';
CREATE OR REPLACE FUNCTION
jsonb_path_match_tz(target jsonb, path jsonpath, vars jsonb DEFAULT '{}',
silent boolean DEFAULT false)
RETURNS boolean
LANGUAGE INTERNAL
STRICT STABLE PARALLEL SAFE
AS 'jsonb_path_match_tz';
CREATE OR REPLACE FUNCTION
jsonb_path_query_tz(target jsonb, path jsonpath, vars jsonb DEFAULT '{}',
silent boolean DEFAULT false)
RETURNS SETOF jsonb
LANGUAGE INTERNAL
STRICT STABLE PARALLEL SAFE
AS 'jsonb_path_query_tz';
CREATE OR REPLACE FUNCTION
jsonb_path_query_array_tz(target jsonb, path jsonpath, vars jsonb DEFAULT '{}',
silent boolean DEFAULT false)
RETURNS jsonb
LANGUAGE INTERNAL
STRICT STABLE PARALLEL SAFE
AS 'jsonb_path_query_array_tz';
CREATE OR REPLACE FUNCTION
jsonb_path_query_first_tz(target jsonb, path jsonpath, vars jsonb DEFAULT '{}',
silent boolean DEFAULT false)
RETURNS jsonb
LANGUAGE INTERNAL
STRICT STABLE PARALLEL SAFE
AS 'jsonb_path_query_first_tz';
CREATE OR REPLACE FUNCTION
jsonb_strip_nulls(target jsonb, strip_in_arrays boolean DEFAULT false)
RETURNS jsonb
LANGUAGE INTERNAL
STRICT STABLE PARALLEL SAFE
AS 'jsonb_strip_nulls';
CREATE OR REPLACE FUNCTION
json_strip_nulls(target json, strip_in_arrays boolean DEFAULT false)
RETURNS json
LANGUAGE INTERNAL
STRICT STABLE PARALLEL SAFE
AS 'json_strip_nulls';
-- default normalization form is NFC, per SQL standard
CREATE OR REPLACE FUNCTION
"normalize"(text, text DEFAULT 'NFC')
RETURNS text
LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_normalize_func';
CREATE OR REPLACE FUNCTION
is_normalized(text, text DEFAULT 'NFC')
RETURNS boolean
LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
CREATE OR REPLACE FUNCTION
pg_stat_reset_shared(target text DEFAULT NULL)
RETURNS void
LANGUAGE INTERNAL
CALLED ON NULL INPUT VOLATILE PARALLEL SAFE
AS 'pg_stat_reset_shared';
CREATE OR REPLACE FUNCTION
pg_stat_reset_slru(target text DEFAULT NULL)
RETURNS void
LANGUAGE INTERNAL
CALLED ON NULL INPUT VOLATILE PARALLEL SAFE
AS 'pg_stat_reset_slru';
CREATE OR REPLACE FUNCTION
pg_replication_origin_session_setup(node_name text, pid integer DEFAULT 0)
RETURNS void
LANGUAGE INTERNAL
STRICT VOLATILE PARALLEL UNSAFE
AS 'pg_replication_origin_session_setup';
--
-- The default permissions for functions mean that anyone can execute them.

View file

@ -2492,6 +2492,7 @@ get_type_io_data(Oid typid,
{
Oid typinput;
Oid typoutput;
Oid typcollation;
boot_get_type_io_data(typid,
typlen,
@ -2500,7 +2501,8 @@ get_type_io_data(Oid typid,
typdelim,
typioparam,
&typinput,
&typoutput);
&typoutput,
&typcollation);
switch (which_func)
{
case IOFunc_input:

View file

@ -53,7 +53,8 @@ extern void boot_get_type_io_data(Oid typid,
char *typdelim,
Oid *typioparam,
Oid *typinput,
Oid *typoutput);
Oid *typoutput,
Oid *typcollation);
union YYSTYPE;
typedef void *yyscan_t;

View file

@ -57,6 +57,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 202602121
#define CATALOG_VERSION_NO 202602181
#endif

View file

@ -3499,6 +3499,7 @@
{ oid => '6212', descr => 'random value from normal distribution',
proname => 'random_normal', provolatile => 'v', proparallel => 'r',
prorettype => 'float8', proargtypes => 'float8 float8',
proargnames => '{mean,stddev}', proargdefaults => '{0,1}',
prosrc => 'drandom_normal' },
{ oid => '6339', descr => 'random integer in range',
proname => 'random', provolatile => 'v', proparallel => 'r',
@ -6174,6 +6175,7 @@
descr => 'statistics: reset collected statistics shared across the cluster',
proname => 'pg_stat_reset_shared', proisstrict => 'f', provolatile => 'v',
prorettype => 'void', proargtypes => 'text',
proargnames => '{target}', proargdefaults => '{NULL}',
prosrc => 'pg_stat_reset_shared' },
{ oid => '3776',
descr => 'statistics: reset collected statistics for a single table or index in the current database or shared across all databases in the cluster',
@ -6193,6 +6195,7 @@
descr => 'statistics: reset collected statistics for a single SLRU',
proname => 'pg_stat_reset_slru', proisstrict => 'f', provolatile => 'v',
prorettype => 'void', proargtypes => 'text', proargnames => '{target}',
proargdefaults => '{NULL}',
prosrc => 'pg_stat_reset_slru' },
{ oid => '6170',
descr => 'statistics: reset collected statistics for a single replication slot',
@ -6728,20 +6731,24 @@
{ oid => '2096', descr => 'terminate a server process',
proname => 'pg_terminate_backend', provolatile => 'v', prorettype => 'bool',
proargtypes => 'int4 int8', proargnames => '{pid,timeout}',
proargdefaults => '{0}',
prosrc => 'pg_terminate_backend' },
{ oid => '2172', descr => 'prepare for taking an online backup',
proname => 'pg_backup_start', provolatile => 'v', proparallel => 'r',
prorettype => 'pg_lsn', proargtypes => 'text bool',
proargnames => '{label,fast}', proargdefaults => '{false}',
prosrc => 'pg_backup_start' },
{ oid => '2739', descr => 'finish taking an online backup',
proname => 'pg_backup_stop', provolatile => 'v', proparallel => 'r',
prorettype => 'record', proargtypes => 'bool',
proallargtypes => '{bool,pg_lsn,text,text}', proargmodes => '{i,o,o,o}',
proargnames => '{wait_for_archive,lsn,labelfile,spcmapfile}',
proargdefaults => '{true}',
prosrc => 'pg_backup_stop' },
{ oid => '3436', descr => 'promote standby server',
proname => 'pg_promote', provolatile => 'v', prorettype => 'bool',
proargtypes => 'bool int4', proargnames => '{wait,wait_seconds}',
proargdefaults => '{true,60}',
prosrc => 'pg_promote' },
{ oid => '2848', descr => 'switch to new wal file',
proname => 'pg_switch_wal', provolatile => 'v', prorettype => 'pg_lsn',
@ -7517,7 +7524,8 @@
{ oid => '1268',
descr => 'parse qualified identifier to array of identifiers',
proname => 'parse_ident', prorettype => '_text', proargtypes => 'text bool',
proargnames => '{str,strict}', prosrc => 'parse_ident' },
proargnames => '{str,strict}', proargdefaults => '{true}',
prosrc => 'parse_ident' },
{ oid => '2246', descr => '(internal)',
proname => 'fmgr_internal_validator', provolatile => 's',
@ -9423,7 +9431,9 @@
proargtypes => 'anyelement', prosrc => 'to_json' },
{ oid => '3261', descr => 'remove object fields with null values from json',
proname => 'json_strip_nulls', prorettype => 'json',
proargtypes => 'json bool', prosrc => 'json_strip_nulls' },
proargtypes => 'json bool',
proargnames => '{target,strip_in_arrays}', proargdefaults => '{false}',
prosrc => 'json_strip_nulls' },
{ oid => '3947',
proname => 'json_object_field', prorettype => 'json',
@ -9480,12 +9490,17 @@
{ oid => '3960', descr => 'get record fields from a json object',
proname => 'json_populate_record', proisstrict => 'f', provolatile => 's',
prorettype => 'anyelement', proargtypes => 'anyelement json bool',
proargnames => '{base,from_json,use_json_as_text}',
proargdefaults => '{false}',
prosrc => 'json_populate_record' },
{ oid => '3961',
descr => 'get set of records with fields from a json array of objects',
proname => 'json_populate_recordset', prorows => '100', proisstrict => 'f',
proretset => 't', provolatile => 's', prorettype => 'anyelement',
proargtypes => 'anyelement json bool', prosrc => 'json_populate_recordset' },
proargtypes => 'anyelement json bool',
proargnames => '{base,from_json,use_json_as_text}',
proargdefaults => '{false}',
prosrc => 'json_populate_recordset' },
{ oid => '3204', descr => 'get record fields from a json object',
proname => 'json_to_record', provolatile => 's', prorettype => 'record',
proargtypes => 'json', prosrc => 'json_to_record' },
@ -10364,7 +10379,9 @@
prosrc => 'jsonb_build_object_noargs' },
{ oid => '3262', descr => 'remove object fields with null values from jsonb',
proname => 'jsonb_strip_nulls', prorettype => 'jsonb',
proargtypes => 'jsonb bool', prosrc => 'jsonb_strip_nulls' },
proargtypes => 'jsonb bool',
proargnames => '{target,strip_in_arrays}', proargdefaults => '{false}',
prosrc => 'jsonb_strip_nulls' },
{ oid => '3478',
proname => 'jsonb_object_field', prorettype => 'jsonb',
@ -10538,16 +10555,25 @@
proargtypes => 'jsonb _text', prosrc => 'jsonb_delete_path' },
{ oid => '5054', descr => 'Set part of a jsonb, handle NULL value',
proname => 'jsonb_set_lax', proisstrict => 'f', prorettype => 'jsonb',
proargtypes => 'jsonb _text jsonb bool text', prosrc => 'jsonb_set_lax' },
proargtypes => 'jsonb _text jsonb bool text',
proargnames => '{jsonb_in,path,replacement,create_if_missing,null_value_treatment}',
proargdefaults => '{true,use_json_null}',
prosrc => 'jsonb_set_lax' },
{ oid => '3305', descr => 'Set part of a jsonb',
proname => 'jsonb_set', prorettype => 'jsonb',
proargtypes => 'jsonb _text jsonb bool', prosrc => 'jsonb_set' },
proargtypes => 'jsonb _text jsonb bool',
proargnames => '{jsonb_in,path,replacement,create_if_missing}',
proargdefaults => '{true}',
prosrc => 'jsonb_set' },
{ oid => '3306', descr => 'Indented text from jsonb',
proname => 'jsonb_pretty', prorettype => 'text', proargtypes => 'jsonb',
prosrc => 'jsonb_pretty' },
{ oid => '3579', descr => 'Insert value into a jsonb',
proname => 'jsonb_insert', prorettype => 'jsonb',
proargtypes => 'jsonb _text jsonb bool', prosrc => 'jsonb_insert' },
proargtypes => 'jsonb _text jsonb bool',
proargnames => '{jsonb_in,path,replacement,insert_after}',
proargdefaults => '{false}',
prosrc => 'jsonb_insert' },
# jsonpath
{ oid => '4001', descr => 'I/O',
@ -10565,42 +10591,66 @@
{ oid => '4005', descr => 'jsonpath exists test',
proname => 'jsonb_path_exists', prorettype => 'bool',
proargtypes => 'jsonb jsonpath jsonb bool', prosrc => 'jsonb_path_exists' },
proargtypes => 'jsonb jsonpath jsonb bool',
proargnames => '{target,path,vars,silent}',
proargdefaults => '{"{}",false}',
prosrc => 'jsonb_path_exists' },
{ oid => '4006', descr => 'jsonpath query',
proname => 'jsonb_path_query', prorows => '1000', proretset => 't',
prorettype => 'jsonb', proargtypes => 'jsonb jsonpath jsonb bool',
proargnames => '{target,path,vars,silent}',
proargdefaults => '{"{}",false}',
prosrc => 'jsonb_path_query' },
{ oid => '4007', descr => 'jsonpath query wrapped into array',
proname => 'jsonb_path_query_array', prorettype => 'jsonb',
proargtypes => 'jsonb jsonpath jsonb bool',
proargnames => '{target,path,vars,silent}',
proargdefaults => '{"{}",false}',
prosrc => 'jsonb_path_query_array' },
{ oid => '4008', descr => 'jsonpath query first item',
proname => 'jsonb_path_query_first', prorettype => 'jsonb',
proargtypes => 'jsonb jsonpath jsonb bool',
proargnames => '{target,path,vars,silent}',
proargdefaults => '{"{}",false}',
prosrc => 'jsonb_path_query_first' },
{ oid => '4009', descr => 'jsonpath match',
proname => 'jsonb_path_match', prorettype => 'bool',
proargtypes => 'jsonb jsonpath jsonb bool', prosrc => 'jsonb_path_match' },
proargtypes => 'jsonb jsonpath jsonb bool',
proargnames => '{target,path,vars,silent}',
proargdefaults => '{"{}",false}',
prosrc => 'jsonb_path_match' },
{ oid => '1177', descr => 'jsonpath exists test with timezone',
proname => 'jsonb_path_exists_tz', provolatile => 's', prorettype => 'bool',
proargtypes => 'jsonb jsonpath jsonb bool',
proargnames => '{target,path,vars,silent}',
proargdefaults => '{"{}",false}',
prosrc => 'jsonb_path_exists_tz' },
{ oid => '1179', descr => 'jsonpath query with timezone',
proname => 'jsonb_path_query_tz', prorows => '1000', proretset => 't',
provolatile => 's', prorettype => 'jsonb',
proargtypes => 'jsonb jsonpath jsonb bool', prosrc => 'jsonb_path_query_tz' },
proargtypes => 'jsonb jsonpath jsonb bool',
proargnames => '{target,path,vars,silent}',
proargdefaults => '{"{}",false}',
prosrc => 'jsonb_path_query_tz' },
{ oid => '1180', descr => 'jsonpath query wrapped into array with timezone',
proname => 'jsonb_path_query_array_tz', provolatile => 's',
prorettype => 'jsonb', proargtypes => 'jsonb jsonpath jsonb bool',
proargnames => '{target,path,vars,silent}',
proargdefaults => '{"{}",false}',
prosrc => 'jsonb_path_query_array_tz' },
{ oid => '2023', descr => 'jsonpath query first item with timezone',
proname => 'jsonb_path_query_first_tz', provolatile => 's',
prorettype => 'jsonb', proargtypes => 'jsonb jsonpath jsonb bool',
proargnames => '{target,path,vars,silent}',
proargdefaults => '{"{}",false}',
prosrc => 'jsonb_path_query_first_tz' },
{ oid => '2030', descr => 'jsonpath match with timezone',
proname => 'jsonb_path_match_tz', provolatile => 's', prorettype => 'bool',
proargtypes => 'jsonb jsonpath jsonb bool', prosrc => 'jsonb_path_match_tz' },
proargtypes => 'jsonb jsonpath jsonb bool',
proargnames => '{target,path,vars,silent}',
proargdefaults => '{"{}",false}',
prosrc => 'jsonb_path_match_tz' },
{ oid => '4010', descr => 'implementation of @? operator',
proname => 'jsonb_path_exists_opr', prorettype => 'bool',
@ -11411,6 +11461,7 @@
proname => 'make_interval', prorettype => 'interval',
proargtypes => 'int4 int4 int4 int4 int4 int4 float8',
proargnames => '{years,months,weeks,days,hours,mins,secs}',
proargdefaults => '{0,0,0,0,0,0,0.0}',
prosrc => 'make_interval' },
# spgist opclasses
@ -11511,6 +11562,7 @@
proallargtypes => '{name,bool,bool,name,pg_lsn}',
proargmodes => '{i,i,i,o,o}',
proargnames => '{slot_name,immediately_reserve,temporary,slot_name,lsn}',
proargdefaults => '{false,false}',
prosrc => 'pg_create_physical_replication_slot' },
{ oid => '4220',
descr => 'copy a physical replication slot, changing temporality',
@ -11546,6 +11598,7 @@
proallargtypes => '{name,name,bool,bool,bool,name,pg_lsn}',
proargmodes => '{i,i,i,i,i,o,o}',
proargnames => '{slot_name,plugin,temporary,twophase,failover,slot_name,lsn}',
proargdefaults => '{false,false,false}',
prosrc => 'pg_create_logical_replication_slot' },
{ oid => '4222',
descr => 'copy a logical replication slot, changing temporality and plugin',
@ -11578,6 +11631,7 @@
proallargtypes => '{name,pg_lsn,int4,_text,pg_lsn,xid,text}',
proargmodes => '{i,i,i,v,o,o,o}',
proargnames => '{slot_name,upto_lsn,upto_nchanges,options,lsn,xid,data}',
proargdefaults => '{"{}"}',
prosrc => 'pg_logical_slot_get_changes' },
{ oid => '3783', descr => 'get binary changes from replication slot',
proname => 'pg_logical_slot_get_binary_changes', procost => '1000',
@ -11587,6 +11641,7 @@
proallargtypes => '{name,pg_lsn,int4,_text,pg_lsn,xid,bytea}',
proargmodes => '{i,i,i,v,o,o,o}',
proargnames => '{slot_name,upto_lsn,upto_nchanges,options,lsn,xid,data}',
proargdefaults => '{"{}"}',
prosrc => 'pg_logical_slot_get_binary_changes' },
{ oid => '3784', descr => 'peek at changes from replication slot',
proname => 'pg_logical_slot_peek_changes', procost => '1000',
@ -11596,6 +11651,7 @@
proallargtypes => '{name,pg_lsn,int4,_text,pg_lsn,xid,text}',
proargmodes => '{i,i,i,v,o,o,o}',
proargnames => '{slot_name,upto_lsn,upto_nchanges,options,lsn,xid,data}',
proargdefaults => '{"{}"}',
prosrc => 'pg_logical_slot_peek_changes' },
{ oid => '3785', descr => 'peek at binary changes from replication slot',
proname => 'pg_logical_slot_peek_binary_changes', procost => '1000',
@ -11605,6 +11661,7 @@
proallargtypes => '{name,pg_lsn,int4,_text,pg_lsn,xid,bytea}',
proargmodes => '{i,i,i,v,o,o,o}',
proargnames => '{slot_name,upto_lsn,upto_nchanges,options,lsn,xid,data}',
proargdefaults => '{"{}"}',
prosrc => 'pg_logical_slot_peek_binary_changes' },
{ oid => '3878', descr => 'advance logical replication slot',
proname => 'pg_replication_slot_advance', provolatile => 'v',
@ -11615,10 +11672,14 @@
{ oid => '3577', descr => 'emit a textual logical decoding message',
proname => 'pg_logical_emit_message', provolatile => 'v', proparallel => 'u',
prorettype => 'pg_lsn', proargtypes => 'bool text text bool',
proargnames => '{transactional,prefix,message,flush}',
proargdefaults => '{false}',
prosrc => 'pg_logical_emit_message_text' },
{ oid => '3578', descr => 'emit a binary logical decoding message',
proname => 'pg_logical_emit_message', provolatile => 'v', proparallel => 'u',
prorettype => 'pg_lsn', proargtypes => 'bool text bytea bool',
proargnames => '{transactional,prefix,message,flush}',
proargdefaults => '{false}',
prosrc => 'pg_logical_emit_message_bytea' },
{ oid => '6344',
descr => 'sync replication slots from the primary to the standby',
@ -12268,6 +12329,7 @@
descr => 'configure session to maintain replication progress tracking for the passed in origin',
proname => 'pg_replication_origin_session_setup', provolatile => 'v',
proparallel => 'u', prorettype => 'void', proargtypes => 'text int4',
proargnames => '{node_name,pid}', proargdefaults => '{0}',
prosrc => 'pg_replication_origin_session_setup' },
{ oid => '6007', descr => 'teardown configured replication progress tracking',
@ -12518,10 +12580,12 @@
{ oid => '4350', descr => 'Unicode normalization',
proname => 'normalize', prorettype => 'text', proargtypes => 'text text',
proargdefaults => '{NFC}',
prosrc => 'unicode_normalize_func' },
{ oid => '4351', descr => 'check Unicode normalization',
proname => 'is_normalized', prorettype => 'bool', proargtypes => 'text text',
proargdefaults => '{NFC}',
prosrc => 'unicode_is_normalized' },
{ oid => '6198', descr => 'unescape Unicode characters',