agora inbox for pgsql-hackers@postgresql.orghelp / color / mirror / Atom feed
[PATCH v2] Generate bootstrap entries for array types 2+ messages / 2 participants [nested] [flat]
* [PATCH v2] Generate bootstrap entries for array types @ 2018-09-20 11:43 Dagfinn Ilmari Mannsåker <ilmari@ilmari.org> 0 siblings, 0 replies; 2+ messages in thread From: Dagfinn Ilmari Mannsåker @ 2018-09-20 11:43 UTC (permalink / raw) Add a new metadata field called 'array_type_oid', which instructs Catalog::ParseData to generate an array type from the given element type. This allows most array type entries to be deleted from pg_type.dat. The lone exception is _record, since it's a pseudotype. --- src/backend/catalog/Catalog.pm | 57 +++ src/backend/catalog/genbki.pl | 3 +- src/include/catalog/genbki.h | 2 + src/include/catalog/pg_type.dat | 471 ++++------------------- src/include/catalog/pg_type.h | 24 +- src/include/catalog/reformat_dat_file.pl | 2 +- 6 files changed, 154 insertions(+), 405 deletions(-) diff --git a/src/backend/catalog/Catalog.pm b/src/backend/catalog/Catalog.pm index ae5b499b6a..12b142928a 100644 --- a/src/backend/catalog/Catalog.pm +++ b/src/backend/catalog/Catalog.pm @@ -191,6 +191,10 @@ sub ParseHeader { $column{default} = $1; } + elsif ($attopt =~ /BKI_ARRAY_TYPE\(['"]?([^'"]+)['"]?\)/) + { + $column{array} = $1; + } elsif ($attopt =~ /BKI_LOOKUP\((\w+)\)/) { $column{lookup} = $1; @@ -290,6 +294,10 @@ sub ParseData } } close $ifd; + + # Generate array types unless we're just reformatting the file + Catalog::GenArrayTypes($schema, $data) + if $catname eq 'pg_type' and !$preserve_formatting; return $data; } @@ -448,6 +456,8 @@ sub FindAllOidsFromHeaders foreach my $row (@$catdata) { push @oids, $row->{oid} if defined $row->{oid}; + push @oids, $row->{array_type_oid} + if defined $row->{array_type_oid}; } } @@ -464,4 +474,51 @@ sub FindAllOidsFromHeaders return \@oids; } +# If the type specifies an array type OID, generate an entry for the array +# type using values from the element type, plus some values that are needed +# for all array types. +sub GenArrayTypes +{ + my $pgtype_schema = shift; + my $types = shift; + my @array_types; + + foreach my $elem_type (@$types) + { + next if !exists $elem_type->{array_type_oid}; + my %array_type; + + # Specific values derived from the element type. + $array_type{oid} = $elem_type->{array_type_oid}; + $array_type{typname} = '_' . $elem_type->{typname}; + $array_type{typelem} = $elem_type->{typname}; + + # Arrays require INT alignment, unless the element type requires + # DOUBLE alignment. + $array_type{typalign} = $elem_type->{typalign} eq 'd' ? 'd' : 'i'; + + # Fill in the rest of the values. + foreach my $column (@$pgtype_schema) + { + my $attname = $column->{name}; + + # Skip if we already set it above. + next if defined $array_type{$attname}; + + # If we have a value needed for all arrays, use it, otherwise + # copy the value from the element type. + if (defined $column->{array}) + { + $array_type{$attname} = $column->{array}; + } + else + { + $array_type{$attname} = $elem_type->{$attname}; + } + } + push @array_types, \%array_type; + } + push @$types, @array_types; +} + 1; diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl index 9be51d28b0..053d1ee00d 100644 --- a/src/backend/catalog/genbki.pl +++ b/src/backend/catalog/genbki.pl @@ -395,7 +395,8 @@ EOM if $key eq "oid" || $key eq "oid_symbol" || $key eq "descr" - || $key eq "line_number"; + || $key eq "line_number" + || $key eq "array_type_oid"; die sprintf "unrecognized field name \"%s\" in %s.dat line %s\n", $key, $catname, $bki_values{line_number} if (!exists($attnames{$key})); diff --git a/src/include/catalog/genbki.h b/src/include/catalog/genbki.h index b1e2cbdb62..a5fc03f3f4 100644 --- a/src/include/catalog/genbki.h +++ b/src/include/catalog/genbki.h @@ -34,6 +34,8 @@ #define BKI_FORCE_NOT_NULL /* Specifies a default value for a catalog field */ #define BKI_DEFAULT(value) +/* Specifies a value needed for array types */ +#define BKI_ARRAY_TYPE(value) /* Indicates how to perform name lookups for an OID or OID-array field */ #define BKI_LOOKUP(catalog) diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat index 48e01cd694..785e8f43ad 100644 --- a/src/include/catalog/pg_type.dat +++ b/src/include/catalog/pg_type.dat @@ -15,6 +15,12 @@ # For types used in the system catalogs, make sure the values here match # TypInfo[] in bootstrap.c. +# To create an array type, add 'array_type_oid => 'nnnn' to the element +# type, which will instruct genbki.pl to generate a BKI entry for it. +# The values used can be found in pg_type.h. If you want to add an array +# type that needs any values different from normal array types, it will +# need its own entry in this file, e.g. _record. + # OID symbol macro names for pg_type OIDs are generated by genbki.pl # according to the following rule, so you don't need to specify them # here: @@ -31,69 +37,81 @@ # OIDS 1 - 99 { oid => '16', descr => 'boolean, \'true\'/\'false\'', + array_type_oid => '1000', typname => 'bool', typlen => '1', typbyval => 't', typcategory => 'B', typispreferred => 't', typarray => '_bool', typinput => 'boolin', typoutput => 'boolout', typreceive => 'boolrecv', typsend => 'boolsend', typalign => 'c' }, { oid => '17', descr => 'variable-length string, binary values escaped', + array_type_oid => '1001', typname => 'bytea', typlen => '-1', typbyval => 'f', typcategory => 'U', typarray => '_bytea', typinput => 'byteain', typoutput => 'byteaout', typreceive => 'bytearecv', typsend => 'byteasend', typalign => 'i', typstorage => 'x' }, -{ oid => '18', descr => 'single character', +{ oid => '18', descr => 'single character', array_type_oid => '1002', typname => 'char', typlen => '1', typbyval => 't', typcategory => 'S', typarray => '_char', typinput => 'charin', typoutput => 'charout', typreceive => 'charrecv', typsend => 'charsend', typalign => 'c' }, { oid => '19', descr => '63-byte type for storing system identifiers', + array_type_oid => '1003', typname => 'name', typlen => 'NAMEDATALEN', typbyval => 'f', typcategory => 'S', typelem => 'char', typarray => '_name', typinput => 'namein', typoutput => 'nameout', typreceive => 'namerecv', typsend => 'namesend', typalign => 'c' }, { oid => '20', descr => '~18 digit integer, 8-byte storage', + array_type_oid => '1016', typname => 'int8', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', typcategory => 'N', typarray => '_int8', typinput => 'int8in', typoutput => 'int8out', typreceive => 'int8recv', typsend => 'int8send', typalign => 'd' }, { oid => '21', descr => '-32 thousand to 32 thousand, 2-byte storage', + array_type_oid => '1005', typname => 'int2', typlen => '2', typbyval => 't', typcategory => 'N', typarray => '_int2', typinput => 'int2in', typoutput => 'int2out', typreceive => 'int2recv', typsend => 'int2send', typalign => 's' }, { oid => '22', descr => 'array of int2, used in system tables', + array_type_oid => '1006', typname => 'int2vector', typlen => '-1', typbyval => 'f', typcategory => 'A', typelem => 'int2', typarray => '_int2vector', typinput => 'int2vectorin', typoutput => 'int2vectorout', typreceive => 'int2vectorrecv', typsend => 'int2vectorsend', typalign => 'i' }, { oid => '23', descr => '-2 billion to 2 billion integer, 4-byte storage', + array_type_oid => '1007', typname => 'int4', typlen => '4', typbyval => 't', typcategory => 'N', typarray => '_int4', typinput => 'int4in', typoutput => 'int4out', typreceive => 'int4recv', typsend => 'int4send', typalign => 'i' }, -{ oid => '24', descr => 'registered procedure', +{ oid => '24', descr => 'registered procedure', array_type_oid => '1008', typname => 'regproc', typlen => '4', typbyval => 't', typcategory => 'N', typarray => '_regproc', typinput => 'regprocin', typoutput => 'regprocout', typreceive => 'regprocrecv', typsend => 'regprocsend', typalign => 'i' }, { oid => '25', descr => 'variable-length string, no limit specified', + array_type_oid => '1009', typname => 'text', typlen => '-1', typbyval => 'f', typcategory => 'S', typispreferred => 't', typarray => '_text', typinput => 'textin', typoutput => 'textout', typreceive => 'textrecv', typsend => 'textsend', typalign => 'i', typstorage => 'x', typcollation => '100' }, { oid => '26', descr => 'object identifier(oid), maximum 4 billion', + array_type_oid => '1028', typname => 'oid', typlen => '4', typbyval => 't', typcategory => 'N', typispreferred => 't', typarray => '_oid', typinput => 'oidin', typoutput => 'oidout', typreceive => 'oidrecv', typsend => 'oidsend', typalign => 'i' }, { oid => '27', descr => '(block, offset), physical location of tuple', + array_type_oid => '1010', typname => 'tid', typlen => '6', typbyval => 'f', typcategory => 'U', typarray => '_tid', typinput => 'tidin', typoutput => 'tidout', typreceive => 'tidrecv', typsend => 'tidsend', typalign => 's' }, -{ oid => '28', descr => 'transaction id', +{ oid => '28', descr => 'transaction id', array_type_oid => '1011', typname => 'xid', typlen => '4', typbyval => 't', typcategory => 'U', typarray => '_xid', typinput => 'xidin', typoutput => 'xidout', typreceive => 'xidrecv', typsend => 'xidsend', typalign => 'i' }, { oid => '29', descr => 'command identifier type, sequence in transaction id', + array_type_oid => '1012', typname => 'cid', typlen => '4', typbyval => 't', typcategory => 'U', typarray => '_cid', typinput => 'cidin', typoutput => 'cidout', typreceive => 'cidrecv', typsend => 'cidsend', typalign => 'i' }, { oid => '30', descr => 'array of oids, used in system tables', + array_type_oid => '1013', typname => 'oidvector', typlen => '-1', typbyval => 'f', typcategory => 'A', typelem => 'oid', typarray => '_oidvector', typinput => 'oidvectorin', typoutput => 'oidvectorout', typreceive => 'oidvectorrecv', @@ -124,26 +142,16 @@ # OIDS 100 - 199 -{ oid => '114', +{ oid => '114', array_type_oid => '199', typname => 'json', typlen => '-1', typbyval => 'f', typcategory => 'U', typarray => '_json', typinput => 'json_in', typoutput => 'json_out', typreceive => 'json_recv', typsend => 'json_send', typalign => 'i', typstorage => 'x' }, -{ oid => '142', descr => 'XML content', +{ oid => '142', descr => 'XML content', array_type_oid => '143', typname => 'xml', typlen => '-1', typbyval => 'f', typcategory => 'U', typarray => '_xml', typinput => 'xml_in', typoutput => 'xml_out', typreceive => 'xml_recv', typsend => 'xml_send', typalign => 'i', typstorage => 'x' }, -{ oid => '143', - typname => '_xml', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'xml', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '199', - typname => '_json', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'json', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, { oid => '194', oid_symbol => 'PGNODETREEOID', descr => 'string representing an internal node tree', typname => 'pg_node_tree', typlen => '-1', typbyval => 'f', @@ -182,66 +190,71 @@ # OIDS 600 - 699 { oid => '600', descr => 'geometric point \'(x, y)\'', + array_type_oid => '1017', typname => 'point', typlen => '16', typbyval => 'f', typcategory => 'G', typelem => 'float8', typarray => '_point', typinput => 'point_in', typoutput => 'point_out', typreceive => 'point_recv', typsend => 'point_send', typalign => 'd' }, { oid => '601', descr => 'geometric line segment \'(pt1,pt2)\'', + array_type_oid => '1018', typname => 'lseg', typlen => '32', typbyval => 'f', typcategory => 'G', typelem => 'point', typarray => '_lseg', typinput => 'lseg_in', typoutput => 'lseg_out', typreceive => 'lseg_recv', typsend => 'lseg_send', typalign => 'd' }, { oid => '602', descr => 'geometric path \'(pt1,...)\'', + array_type_oid => '1019', typname => 'path', typlen => '-1', typbyval => 'f', typcategory => 'G', typarray => '_path', typinput => 'path_in', typoutput => 'path_out', typreceive => 'path_recv', typsend => 'path_send', typalign => 'd', typstorage => 'x' }, { oid => '603', descr => 'geometric box \'(lower left,upper right)\'', + array_type_oid => '1020', typname => 'box', typlen => '32', typbyval => 'f', typcategory => 'G', typdelim => ';', typelem => 'point', typarray => '_box', typinput => 'box_in', typoutput => 'box_out', typreceive => 'box_recv', typsend => 'box_send', typalign => 'd' }, { oid => '604', descr => 'geometric polygon \'(pt1,...)\'', + array_type_oid => '1027', typname => 'polygon', typlen => '-1', typbyval => 'f', typcategory => 'G', typarray => '_polygon', typinput => 'poly_in', typoutput => 'poly_out', typreceive => 'poly_recv', typsend => 'poly_send', typalign => 'd', typstorage => 'x' }, -{ oid => '628', descr => 'geometric line', +{ oid => '628', descr => 'geometric line', array_type_oid => '629', typname => 'line', typlen => '24', typbyval => 'f', typcategory => 'G', typelem => 'float8', typarray => '_line', typinput => 'line_in', typoutput => 'line_out', typreceive => 'line_recv', typsend => 'line_send', typalign => 'd' }, -{ oid => '629', - typname => '_line', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'line', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, # OIDS 700 - 799 { oid => '700', descr => 'single-precision floating point number, 4-byte storage', + array_type_oid => '1021', typname => 'float4', typlen => '4', typbyval => 'FLOAT4PASSBYVAL', typcategory => 'N', typarray => '_float4', typinput => 'float4in', typoutput => 'float4out', typreceive => 'float4recv', typsend => 'float4send', typalign => 'i' }, { oid => '701', descr => 'double-precision floating point number, 8-byte storage', + array_type_oid => '1022', typname => 'float8', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', typcategory => 'N', typispreferred => 't', typarray => '_float8', typinput => 'float8in', typoutput => 'float8out', typreceive => 'float8recv', typsend => 'float8send', typalign => 'd' }, { oid => '702', descr => 'absolute, limited-range date and time (Unix system time)', + array_type_oid => '1023', typname => 'abstime', typlen => '4', typbyval => 't', typcategory => 'D', typarray => '_abstime', typinput => 'abstimein', typoutput => 'abstimeout', typreceive => 'abstimerecv', typsend => 'abstimesend', typalign => 'i' }, { oid => '703', descr => 'relative, limited-range time interval (Unix delta time)', + array_type_oid => '1024', typname => 'reltime', typlen => '4', typbyval => 't', typcategory => 'T', typarray => '_reltime', typinput => 'reltimein', typoutput => 'reltimeout', typreceive => 'reltimerecv', typsend => 'reltimesend', typalign => 'i' }, { oid => '704', descr => '(abstime,abstime), time interval', + array_type_oid => '1025', typname => 'tinterval', typlen => '12', typbyval => 'f', typcategory => 'T', typarray => '_tinterval', typinput => 'tintervalin', typoutput => 'tintervalout', typreceive => 'tintervalrecv', @@ -251,43 +264,38 @@ typcategory => 'X', typinput => 'unknownin', typoutput => 'unknownout', typreceive => 'unknownrecv', typsend => 'unknownsend', typalign => 'c' }, { oid => '718', descr => 'geometric circle \'(center,radius)\'', + array_type_oid => '719', typname => 'circle', typlen => '24', typbyval => 'f', typcategory => 'G', typarray => '_circle', typinput => 'circle_in', typoutput => 'circle_out', typreceive => 'circle_recv', typsend => 'circle_send', typalign => 'd' }, -{ oid => '719', - typname => '_circle', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'circle', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, -{ oid => '790', oid_symbol => 'CASHOID', - descr => 'monetary amounts, $d,ddd.cc', +{ oid => '790', oid_symbol => 'CASHOID', descr => 'monetary amounts, $d,ddd.cc', + array_type_oid => '791', typname => 'money', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', typcategory => 'N', typarray => '_money', typinput => 'cash_in', typoutput => 'cash_out', typreceive => 'cash_recv', typsend => 'cash_send', typalign => 'd' }, -{ oid => '791', - typname => '_money', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'money', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, # OIDS 800 - 899 { oid => '829', descr => 'XX:XX:XX:XX:XX:XX, MAC address', + array_type_oid => '1040', typname => 'macaddr', typlen => '6', typbyval => 'f', typcategory => 'U', typarray => '_macaddr', typinput => 'macaddr_in', typoutput => 'macaddr_out', typreceive => 'macaddr_recv', typsend => 'macaddr_send', typalign => 'i' }, { oid => '869', descr => 'IP address/netmask, host address, netmask optional', + array_type_oid => '1041', typname => 'inet', typlen => '-1', typbyval => 'f', typcategory => 'I', typispreferred => 't', typarray => '_inet', typinput => 'inet_in', typoutput => 'inet_out', typreceive => 'inet_recv', typsend => 'inet_send', typalign => 'i', typstorage => 'm' }, { oid => '650', descr => 'network IP address/netmask, network address', + array_type_oid => '651', typname => 'cidr', typlen => '-1', typbyval => 'f', typcategory => 'I', typarray => '_cidr', typinput => 'cidr_in', typoutput => 'cidr_out', typreceive => 'cidr_recv', typsend => 'cidr_send', typalign => 'i', typstorage => 'm' }, { oid => '774', descr => 'XX:XX:XX:XX:XX:XX:XX:XX, MAC address', + array_type_oid => '775', typname => 'macaddr8', typlen => '8', typbyval => 'f', typcategory => 'U', typarray => '_macaddr8', typinput => 'macaddr8_in', typoutput => 'macaddr8_out', typreceive => 'macaddr8_recv', @@ -295,182 +303,13 @@ # OIDS 1000 - 1099 -{ oid => '1000', - typname => '_bool', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'bool', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1001', - typname => '_bytea', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'bytea', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1002', - typname => '_char', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'char', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1003', - typname => '_name', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'name', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1005', - typname => '_int2', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'int2', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1006', - typname => '_int2vector', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'int2vector', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1007', - typname => '_int4', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'int4', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1008', - typname => '_regproc', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'regproc', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1009', - typname => '_text', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'text', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x', - typcollation => '100' }, -{ oid => '1028', - typname => '_oid', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'oid', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1010', - typname => '_tid', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'tid', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1011', - typname => '_xid', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'xid', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1012', - typname => '_cid', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'cid', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1013', - typname => '_oidvector', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'oidvector', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1014', - typname => '_bpchar', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'bpchar', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typmodin => 'bpchartypmodin', typmodout => 'bpchartypmodout', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x', - typcollation => '100' }, -{ oid => '1015', - typname => '_varchar', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'varchar', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typmodin => 'varchartypmodin', typmodout => 'varchartypmodout', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x', - typcollation => '100' }, -{ oid => '1016', - typname => '_int8', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'int8', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, -{ oid => '1017', - typname => '_point', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'point', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, -{ oid => '1018', - typname => '_lseg', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'lseg', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, -{ oid => '1019', - typname => '_path', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'path', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, -{ oid => '1020', - typname => '_box', typlen => '-1', typbyval => 'f', typcategory => 'A', - typdelim => ';', typelem => 'box', typinput => 'array_in', - typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, -{ oid => '1021', - typname => '_float4', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'float4', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1022', - typname => '_float8', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'float8', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, -{ oid => '1023', - typname => '_abstime', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'abstime', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1024', - typname => '_reltime', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'reltime', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1025', - typname => '_tinterval', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'tinterval', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1027', - typname => '_polygon', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'polygon', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, -{ oid => '1033', descr => 'access control list', +{ oid => '1033', descr => 'access control list', array_type_oid => '1034', typname => 'aclitem', typlen => '12', typbyval => 'f', typcategory => 'U', typarray => '_aclitem', typinput => 'aclitemin', typoutput => 'aclitemout', typreceive => '-', typsend => '-', typalign => 'i' }, -{ oid => '1034', - typname => '_aclitem', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'aclitem', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1040', - typname => '_macaddr', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'macaddr', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '775', - typname => '_macaddr8', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'macaddr8', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1041', - typname => '_inet', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'inet', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '651', - typname => '_cidr', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'cidr', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1263', - typname => '_cstring', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'cstring', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, { oid => '1042', descr => 'char(length), blank-padded string, fixed storage length', + array_type_oid => '1014', typname => 'bpchar', typlen => '-1', typbyval => 'f', typcategory => 'S', typarray => '_bpchar', typinput => 'bpcharin', typoutput => 'bpcharout', typreceive => 'bpcharrecv', typsend => 'bpcharsend', @@ -478,16 +317,17 @@ typstorage => 'x', typcollation => '100' }, { oid => '1043', descr => 'varchar(length), non-blank-padded string, variable storage length', + array_type_oid => '1015', typname => 'varchar', typlen => '-1', typbyval => 'f', typcategory => 'S', typarray => '_varchar', typinput => 'varcharin', typoutput => 'varcharout', typreceive => 'varcharrecv', typsend => 'varcharsend', typmodin => 'varchartypmodin', typmodout => 'varchartypmodout', typalign => 'i', typstorage => 'x', typcollation => '100' }, -{ oid => '1082', descr => 'date', +{ oid => '1082', descr => 'date', array_type_oid => '1182', typname => 'date', typlen => '4', typbyval => 't', typcategory => 'D', typarray => '_date', typinput => 'date_in', typoutput => 'date_out', typreceive => 'date_recv', typsend => 'date_send', typalign => 'i' }, -{ oid => '1083', descr => 'time of day', +{ oid => '1083', descr => 'time of day', array_type_oid => '1183', typname => 'time', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', typcategory => 'D', typarray => '_time', typinput => 'time_in', typoutput => 'time_out', typreceive => 'time_recv', typsend => 'time_send', @@ -495,106 +335,58 @@ # OIDS 1100 - 1199 -{ oid => '1114', descr => 'date and time', +{ oid => '1114', descr => 'date and time', array_type_oid => '1115', typname => 'timestamp', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', typcategory => 'D', typarray => '_timestamp', typinput => 'timestamp_in', typoutput => 'timestamp_out', typreceive => 'timestamp_recv', typsend => 'timestamp_send', typmodin => 'timestamptypmodin', typmodout => 'timestamptypmodout', typalign => 'd' }, -{ oid => '1115', - typname => '_timestamp', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'timestamp', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typmodin => 'timestamptypmodin', typmodout => 'timestamptypmodout', - typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, -{ oid => '1182', - typname => '_date', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'date', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '1183', - typname => '_time', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'time', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typmodin => 'timetypmodin', typmodout => 'timetypmodout', - typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, { oid => '1184', descr => 'date and time with time zone', + array_type_oid => '1185', typname => 'timestamptz', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', typcategory => 'D', typispreferred => 't', typarray => '_timestamptz', typinput => 'timestamptz_in', typoutput => 'timestamptz_out', typreceive => 'timestamptz_recv', typsend => 'timestamptz_send', typmodin => 'timestamptztypmodin', typmodout => 'timestamptztypmodout', typalign => 'd' }, -{ oid => '1185', - typname => '_timestamptz', typlen => '-1', typbyval => 'f', - typcategory => 'A', typelem => 'timestamptz', typinput => 'array_in', - typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send', - typmodin => 'timestamptztypmodin', typmodout => 'timestamptztypmodout', - typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, { oid => '1186', descr => '@ <number> <units>, time interval', + array_type_oid => '1187', typname => 'interval', typlen => '16', typbyval => 'f', typcategory => 'T', typispreferred => 't', typarray => '_interval', typinput => 'interval_in', typoutput => 'interval_out', typreceive => 'interval_recv', typsend => 'interval_send', typmodin => 'intervaltypmodin', typmodout => 'intervaltypmodout', typalign => 'd' }, -{ oid => '1187', - typname => '_interval', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'interval', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typmodin => 'intervaltypmodin', typmodout => 'intervaltypmodout', - typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, # OIDS 1200 - 1299 -{ oid => '1231', - typname => '_numeric', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'numeric', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typmodin => 'numerictypmodin', typmodout => 'numerictypmodout', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, { oid => '1266', descr => 'time of day with time zone', + array_type_oid => '1270', typname => 'timetz', typlen => '12', typbyval => 'f', typcategory => 'D', typarray => '_timetz', typinput => 'timetz_in', typoutput => 'timetz_out', typreceive => 'timetz_recv', typsend => 'timetz_send', typmodin => 'timetztypmodin', typmodout => 'timetztypmodout', typalign => 'd' }, -{ oid => '1270', - typname => '_timetz', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'timetz', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typmodin => 'timetztypmodin', typmodout => 'timetztypmodout', - typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, # OIDS 1500 - 1599 -{ oid => '1560', descr => 'fixed-length bit string', +{ oid => '1560', descr => 'fixed-length bit string', array_type_oid => '1561', typname => 'bit', typlen => '-1', typbyval => 'f', typcategory => 'V', typarray => '_bit', typinput => 'bit_in', typoutput => 'bit_out', typreceive => 'bit_recv', typsend => 'bit_send', typmodin => 'bittypmodin', typmodout => 'bittypmodout', typalign => 'i', typstorage => 'x' }, -{ oid => '1561', - typname => '_bit', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'bit', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typmodin => 'bittypmodin', typmodout => 'bittypmodout', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, { oid => '1562', descr => 'variable-length bit string', + array_type_oid => '1563', typname => 'varbit', typlen => '-1', typbyval => 'f', typcategory => 'V', typispreferred => 't', typarray => '_varbit', typinput => 'varbit_in', typoutput => 'varbit_out', typreceive => 'varbit_recv', typsend => 'varbit_send', typmodin => 'varbittypmodin', typmodout => 'varbittypmodout', typalign => 'i', typstorage => 'x' }, -{ oid => '1563', - typname => '_varbit', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'varbit', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typmodin => 'varbittypmodin', typmodout => 'varbittypmodout', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, # OIDS 1700 - 1799 { oid => '1700', descr => 'numeric(precision, decimal), arbitrary precision number', + array_type_oid => '1231', typname => 'numeric', typlen => '-1', typbyval => 'f', typcategory => 'N', typarray => '_numeric', typinput => 'numeric_in', typoutput => 'numeric_out', typreceive => 'numeric_recv', typsend => 'numeric_send', @@ -602,6 +394,7 @@ typalign => 'i', typstorage => 'm' }, { oid => '1790', descr => 'reference to cursor (portal name)', + array_type_oid => '2201', typname => 'refcursor', typlen => '-1', typbyval => 'f', typcategory => 'U', typarray => '_refcursor', typinput => 'textin', typoutput => 'textout', typreceive => 'textrecv', typsend => 'textsend', typalign => 'i', @@ -609,241 +402,134 @@ # OIDS 2200 - 2299 -{ oid => '2201', - typname => '_refcursor', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'refcursor', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, - { oid => '2202', descr => 'registered procedure (with args)', + array_type_oid => '2207', typname => 'regprocedure', typlen => '4', typbyval => 't', typcategory => 'N', typarray => '_regprocedure', typinput => 'regprocedurein', typoutput => 'regprocedureout', typreceive => 'regprocedurerecv', typsend => 'regproceduresend', typalign => 'i' }, -{ oid => '2203', descr => 'registered operator', +{ oid => '2203', descr => 'registered operator', array_type_oid => '2208', typname => 'regoper', typlen => '4', typbyval => 't', typcategory => 'N', typarray => '_regoper', typinput => 'regoperin', typoutput => 'regoperout', typreceive => 'regoperrecv', typsend => 'regopersend', typalign => 'i' }, { oid => '2204', descr => 'registered operator (with args)', + array_type_oid => '2209', typname => 'regoperator', typlen => '4', typbyval => 't', typcategory => 'N', typarray => '_regoperator', typinput => 'regoperatorin', typoutput => 'regoperatorout', typreceive => 'regoperatorrecv', typsend => 'regoperatorsend', typalign => 'i' }, -{ oid => '2205', descr => 'registered class', +{ oid => '2205', descr => 'registered class', array_type_oid => '2210', typname => 'regclass', typlen => '4', typbyval => 't', typcategory => 'N', typarray => '_regclass', typinput => 'regclassin', typoutput => 'regclassout', typreceive => 'regclassrecv', typsend => 'regclasssend', typalign => 'i' }, -{ oid => '2206', descr => 'registered type', +{ oid => '2206', descr => 'registered type', array_type_oid => '2211', typname => 'regtype', typlen => '4', typbyval => 't', typcategory => 'N', typarray => '_regtype', typinput => 'regtypein', typoutput => 'regtypeout', typreceive => 'regtyperecv', typsend => 'regtypesend', typalign => 'i' }, -{ oid => '4096', descr => 'registered role', +{ oid => '4096', descr => 'registered role', array_type_oid => '4097', typname => 'regrole', typlen => '4', typbyval => 't', typcategory => 'N', typarray => '_regrole', typinput => 'regrolein', typoutput => 'regroleout', typreceive => 'regrolerecv', typsend => 'regrolesend', typalign => 'i' }, -{ oid => '4089', descr => 'registered namespace', +{ oid => '4089', descr => 'registered namespace', array_type_oid => '4090', typname => 'regnamespace', typlen => '4', typbyval => 't', typcategory => 'N', typarray => '_regnamespace', typinput => 'regnamespacein', typoutput => 'regnamespaceout', typreceive => 'regnamespacerecv', typsend => 'regnamespacesend', typalign => 'i' }, -{ oid => '2207', - typname => '_regprocedure', typlen => '-1', typbyval => 'f', - typcategory => 'A', typelem => 'regprocedure', typinput => 'array_in', - typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '2208', - typname => '_regoper', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'regoper', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '2209', - typname => '_regoperator', typlen => '-1', typbyval => 'f', - typcategory => 'A', typelem => 'regoperator', typinput => 'array_in', - typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '2210', - typname => '_regclass', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'regclass', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '2211', - typname => '_regtype', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'regtype', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '4097', - typname => '_regrole', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'regrole', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '4090', - typname => '_regnamespace', typlen => '-1', typbyval => 'f', - typcategory => 'A', typelem => 'regnamespace', typinput => 'array_in', - typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, # uuid -{ oid => '2950', descr => 'UUID datatype', +{ oid => '2950', descr => 'UUID datatype', array_type_oid => '2951', typname => 'uuid', typlen => '16', typbyval => 'f', typcategory => 'U', typarray => '_uuid', typinput => 'uuid_in', typoutput => 'uuid_out', typreceive => 'uuid_recv', typsend => 'uuid_send', typalign => 'c' }, -{ oid => '2951', - typname => '_uuid', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'uuid', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, # pg_lsn { oid => '3220', oid_symbol => 'LSNOID', descr => 'PostgreSQL LSN datatype', + array_type_oid => '3221', typname => 'pg_lsn', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', typcategory => 'U', typarray => '_pg_lsn', typinput => 'pg_lsn_in', typoutput => 'pg_lsn_out', typreceive => 'pg_lsn_recv', typsend => 'pg_lsn_send', typalign => 'd' }, -{ oid => '3221', - typname => '_pg_lsn', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'pg_lsn', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, # text search { oid => '3614', descr => 'text representation for text search', + array_type_oid => '3643', typname => 'tsvector', typlen => '-1', typbyval => 'f', typcategory => 'U', typarray => '_tsvector', typinput => 'tsvectorin', typoutput => 'tsvectorout', typreceive => 'tsvectorrecv', typsend => 'tsvectorsend', typanalyze => 'ts_typanalyze', typalign => 'i', typstorage => 'x' }, { oid => '3642', descr => 'GiST index internal text representation for text search', + array_type_oid => '3644', typname => 'gtsvector', typlen => '-1', typbyval => 'f', typcategory => 'U', typarray => '_gtsvector', typinput => 'gtsvectorin', typoutput => 'gtsvectorout', typreceive => '-', typsend => '-', typalign => 'i' }, { oid => '3615', descr => 'query representation for text search', + array_type_oid => '3645', typname => 'tsquery', typlen => '-1', typbyval => 'f', typcategory => 'U', typarray => '_tsquery', typinput => 'tsqueryin', typoutput => 'tsqueryout', typreceive => 'tsqueryrecv', typsend => 'tsquerysend', typalign => 'i' }, { oid => '3734', descr => 'registered text search configuration', + array_type_oid => '3735', typname => 'regconfig', typlen => '4', typbyval => 't', typcategory => 'N', typarray => '_regconfig', typinput => 'regconfigin', typoutput => 'regconfigout', typreceive => 'regconfigrecv', typsend => 'regconfigsend', typalign => 'i' }, { oid => '3769', descr => 'registered text search dictionary', + array_type_oid => '3770', typname => 'regdictionary', typlen => '4', typbyval => 't', typcategory => 'N', typarray => '_regdictionary', typinput => 'regdictionaryin', typoutput => 'regdictionaryout', typreceive => 'regdictionaryrecv', typsend => 'regdictionarysend', typalign => 'i' }, -{ oid => '3643', - typname => '_tsvector', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'tsvector', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '3644', - typname => '_gtsvector', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'gtsvector', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '3645', - typname => '_tsquery', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'tsquery', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '3735', - typname => '_regconfig', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'regconfig', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '3770', - typname => '_regdictionary', typlen => '-1', typbyval => 'f', - typcategory => 'A', typelem => 'regdictionary', typinput => 'array_in', - typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, - # jsonb -{ oid => '3802', descr => 'Binary JSON', +{ oid => '3802', descr => 'Binary JSON', array_type_oid => '3807', typname => 'jsonb', typlen => '-1', typbyval => 'f', typcategory => 'U', typarray => '_jsonb', typinput => 'jsonb_in', typoutput => 'jsonb_out', typreceive => 'jsonb_recv', typsend => 'jsonb_send', typalign => 'i', typstorage => 'x' }, -{ oid => '3807', - typname => '_jsonb', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'jsonb', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '2970', descr => 'txid snapshot', +{ oid => '2970', descr => 'txid snapshot', array_type_oid => '2949', typname => 'txid_snapshot', typlen => '-1', typbyval => 'f', typcategory => 'U', typarray => '_txid_snapshot', typinput => 'txid_snapshot_in', typoutput => 'txid_snapshot_out', typreceive => 'txid_snapshot_recv', typsend => 'txid_snapshot_send', typalign => 'd', typstorage => 'x' }, -{ oid => '2949', - typname => '_txid_snapshot', typlen => '-1', typbyval => 'f', - typcategory => 'A', typelem => 'txid_snapshot', typinput => 'array_in', - typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, # range types -{ oid => '3904', descr => 'range of integers', +{ oid => '3904', descr => 'range of integers', array_type_oid => '3905', typname => 'int4range', typlen => '-1', typbyval => 'f', typtype => 'r', typcategory => 'R', typarray => '_int4range', typinput => 'range_in', typoutput => 'range_out', typreceive => 'range_recv', typsend => 'range_send', typanalyze => 'range_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '3905', - typname => '_int4range', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'int4range', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '3906', descr => 'range of numerics', +{ oid => '3906', descr => 'range of numerics', array_type_oid => '3907', typname => 'numrange', typlen => '-1', typbyval => 'f', typtype => 'r', typcategory => 'R', typarray => '_numrange', typinput => 'range_in', typoutput => 'range_out', typreceive => 'range_recv', typsend => 'range_send', typanalyze => 'range_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '3907', - typname => '_numrange', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'numrange', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, { oid => '3908', descr => 'range of timestamps without time zone', + array_type_oid => '3909', typname => 'tsrange', typlen => '-1', typbyval => 'f', typtype => 'r', typcategory => 'R', typarray => '_tsrange', typinput => 'range_in', typoutput => 'range_out', typreceive => 'range_recv', typsend => 'range_send', typanalyze => 'range_typanalyze', typalign => 'd', typstorage => 'x' }, -{ oid => '3909', - typname => '_tsrange', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'tsrange', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, { oid => '3910', descr => 'range of timestamps with time zone', + array_type_oid => '3911', typname => 'tstzrange', typlen => '-1', typbyval => 'f', typtype => 'r', typcategory => 'R', typarray => '_tstzrange', typinput => 'range_in', typoutput => 'range_out', typreceive => 'range_recv', typsend => 'range_send', typanalyze => 'range_typanalyze', typalign => 'd', typstorage => 'x' }, -{ oid => '3911', - typname => '_tstzrange', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'tstzrange', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, -{ oid => '3912', descr => 'range of dates', +{ oid => '3912', descr => 'range of dates', array_type_oid => '3913', typname => 'daterange', typlen => '-1', typbyval => 'f', typtype => 'r', typcategory => 'R', typarray => '_daterange', typinput => 'range_in', typoutput => 'range_out', typreceive => 'range_recv', typsend => 'range_send', typanalyze => 'range_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '3913', - typname => '_daterange', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'daterange', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'i', typstorage => 'x' }, -{ oid => '3926', descr => 'range of bigints', +{ oid => '3926', descr => 'range of bigints', array_type_oid => '3927', typname => 'int8range', typlen => '-1', typbyval => 'f', typtype => 'r', typcategory => 'R', typarray => '_int8range', typinput => 'range_in', typoutput => 'range_out', typreceive => 'range_recv', typsend => 'range_send', typanalyze => 'range_typanalyze', typalign => 'd', typstorage => 'x' }, -{ oid => '3927', - typname => '_int8range', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'int8range', typinput => 'array_in', typoutput => 'array_out', - typreceive => 'array_recv', typsend => 'array_send', - typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, # pseudo-types # types with typtype='p' represent various special cases in the type system. @@ -859,12 +545,15 @@ typcategory => 'P', typarray => '_record', typinput => 'record_in', typoutput => 'record_out', typreceive => 'record_recv', typsend => 'record_send', typalign => 'd', typstorage => 'x' }, + +# Arrays of records have typcategory P, so they can't be generated. { oid => '2287', typname => '_record', typlen => '-1', typbyval => 'f', typtype => 'p', typcategory => 'P', typelem => 'record', typinput => 'array_in', typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send', typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, -{ oid => '2275', + +{ oid => '2275', array_type_oid => '1263', typname => 'cstring', typlen => '-2', typbyval => 'f', typtype => 'p', typcategory => 'P', typarray => '_cstring', typinput => 'cstring_in', typoutput => 'cstring_out', typreceive => 'cstring_recv', diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 1e9cea70e2..a345044bbf 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -52,7 +52,7 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati * "varlena" type (one that has a length word), -2 to indicate a * null-terminated C string. */ - int16 typlen; + int16 typlen BKI_ARRAY_TYPE(-1); /* * typbyval determines whether internal Postgres routines pass a value of @@ -62,7 +62,7 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati * typbyval can be false even if the length would allow pass-by-value; for * example, type macaddr8 is pass-by-ref even when Datum is 8 bytes. */ - bool typbyval; + bool typbyval BKI_ARRAY_TYPE(f); /* * typtype is 'b' for a base type, 'c' for a composite type (e.g., a @@ -71,7 +71,7 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati * * If typtype is 'c', typrelid is the OID of the class' entry in pg_class. */ - char typtype BKI_DEFAULT(b); + char typtype BKI_DEFAULT(b) BKI_ARRAY_TYPE(b); /* * typcategory and typispreferred help the parser distinguish preferred @@ -81,10 +81,10 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati */ /* arbitrary type classification */ - char typcategory; + char typcategory BKI_ARRAY_TYPE(A); /* is type "preferred" within its category? */ - bool typispreferred BKI_DEFAULT(f); + bool typispreferred BKI_DEFAULT(f) BKI_ARRAY_TYPE(f); /* * If typisdefined is false, the entry is only a placeholder (forward @@ -116,19 +116,19 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati * If there is a "true" array type having this type as element type, * typarray links to it. Zero if no associated "true" array type. */ - Oid typarray BKI_DEFAULT(0) BKI_LOOKUP(pg_type); + Oid typarray BKI_DEFAULT(0) BKI_ARRAY_TYPE(0) BKI_LOOKUP(pg_type); /* * I/O conversion procedures for the datatype. */ /* text format (required) */ - regproc typinput BKI_LOOKUP(pg_proc); - regproc typoutput BKI_LOOKUP(pg_proc); + regproc typinput BKI_ARRAY_TYPE(array_in) BKI_LOOKUP(pg_proc); + regproc typoutput BKI_ARRAY_TYPE(array_out) BKI_LOOKUP(pg_proc); /* binary format (optional) */ - regproc typreceive BKI_LOOKUP(pg_proc); - regproc typsend BKI_LOOKUP(pg_proc); + regproc typreceive BKI_ARRAY_TYPE(array_recv) BKI_LOOKUP(pg_proc); + regproc typsend BKI_ARRAY_TYPE(array_send) BKI_LOOKUP(pg_proc); /* * I/O functions for optional type modifiers. @@ -139,7 +139,7 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati /* * Custom ANALYZE procedure for the datatype (0 selects the default). */ - regproc typanalyze BKI_DEFAULT(-) BKI_LOOKUP(pg_proc); + regproc typanalyze BKI_DEFAULT(-) BKI_ARRAY_TYPE(array_typanalyze) BKI_LOOKUP(pg_proc); /* ---------------- * typalign is the alignment required when storing a value of this @@ -177,7 +177,7 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati * 'm' MAIN like 'x' but try to keep in main tuple * ---------------- */ - char typstorage BKI_DEFAULT(p); + char typstorage BKI_DEFAULT(p) BKI_ARRAY_TYPE(x); /* * This flag represents a "NOT NULL" constraint against this datatype. diff --git a/src/include/catalog/reformat_dat_file.pl b/src/include/catalog/reformat_dat_file.pl index 687aca0b16..24d9d18637 100755 --- a/src/include/catalog/reformat_dat_file.pl +++ b/src/include/catalog/reformat_dat_file.pl @@ -63,7 +63,7 @@ if ($output_path ne '' && substr($output_path, -1) ne '/') } # Metadata of a catalog entry -my @METADATA = ('oid', 'oid_symbol', 'descr'); +my @METADATA = ('oid', 'oid_symbol', 'descr', 'array_type_oid'); # Read all the input files into internal data structures. # We pass data file names as arguments and then look for matching -- 2.18.0 --=-=-=-- ^ permalink raw reply [nested|flat] 2+ messages in thread
* [PATCH v56 1/3] Allow logical replication snapshots to be database-specific @ 2026-04-06 22:07 Álvaro Herrera <alvherre@kurilemu.de> 0 siblings, 0 replies; 2+ messages in thread From: Álvaro Herrera @ 2026-04-06 22:07 UTC (permalink / raw) By default, the logical decoding assumes access to shared catalogs, so the snapshot builder needs to consider cluster-wide XIDs during startup. That in turn means that, if any transaction is already running (and has XID assigned), the snapshot builder needs to wait for its completion, as it does not know if that transaction performed catalog changes earlier. A possible problem with this concept is that if REPACK (CONCURRENTLY) is running in some database, backends running the same command in other databases get stuck until the first one has committed. Thus only a single backend in the cluster can run REPACK (CONCURRENTLY) at any time. Likewise, REPACK (CONCURRENTLY) can block walsenders starting on behalf of subscriptions throughout the cluster. This patch adds a new option to logical replication output plugin, to declare that it does not use shared catalogs (i.e. catalogs that can be changed by transactions running in other databases in the cluster). In that case, no snapshot the backend will use during the decoding needs to contain information about transactions running in other databases. Thus the snapshot builder only needs to wait for completion of transactions in the current database. Currently we only use this option in the REPACK background worker. It could possibly be used in the plugin for logical replication too, however that would need thorough analysis of that plugin. Bump WAL version number, due to a new field in xl_running_xacts. Author: Antonin Houska <ah@cybertec.at> Reviewed-by: Álvaro Herrera <alvherre@kurilemu.de> Discussion: https://postgr.es/m/90475.1775218118@localhost --- contrib/pg_visibility/pg_visibility.c | 4 +- doc/src/sgml/logicaldecoding.sgml | 4 ++ src/backend/access/index/genam.c | 8 +++ src/backend/access/rmgrdesc/standbydesc.c | 2 + src/backend/access/transam/xlog.c | 2 +- src/backend/access/transam/xlogfuncs.c | 2 +- src/backend/postmaster/bgwriter.c | 2 +- src/backend/replication/logical/decode.c | 17 +++++- src/backend/replication/logical/logical.c | 3 + src/backend/replication/logical/snapbuild.c | 63 ++++++++++++++++++++- src/backend/replication/pgrepack/pgrepack.c | 7 +++ src/backend/replication/slot.c | 2 +- src/backend/storage/ipc/procarray.c | 23 +++++++- src/backend/storage/ipc/standby.c | 24 +++++++- src/include/access/genam.h | 1 + src/include/access/xlog_internal.h | 2 +- src/include/miscadmin.h | 9 +++ src/include/replication/output_plugin.h | 1 + src/include/replication/snapbuild.h | 3 +- src/include/storage/procarray.h | 2 +- src/include/storage/standby.h | 3 +- src/include/storage/standbydefs.h | 1 + 22 files changed, 167 insertions(+), 18 deletions(-) diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c index dfab0b64cf5..d564bd2a00c 100644 --- a/contrib/pg_visibility/pg_visibility.c +++ b/contrib/pg_visibility/pg_visibility.c @@ -621,7 +621,7 @@ GetStrictOldestNonRemovableTransactionId(Relation rel) else if (rel == NULL || rel->rd_rel->relisshared) { /* Shared relation: take into account all running xids */ - runningTransactions = GetRunningTransactionData(); + runningTransactions = GetRunningTransactionData(InvalidOid); LWLockRelease(ProcArrayLock); LWLockRelease(XidGenLock); return runningTransactions->oldestRunningXid; @@ -632,7 +632,7 @@ GetStrictOldestNonRemovableTransactionId(Relation rel) * Normal relation: take into account xids running within the current * database */ - runningTransactions = GetRunningTransactionData(); + runningTransactions = GetRunningTransactionData(InvalidOid); LWLockRelease(ProcArrayLock); LWLockRelease(XidGenLock); return runningTransactions->oldestDatabaseRunningXid; diff --git a/doc/src/sgml/logicaldecoding.sgml b/doc/src/sgml/logicaldecoding.sgml index 6dc49108997..9b1d68d0de6 100644 --- a/doc/src/sgml/logicaldecoding.sgml +++ b/doc/src/sgml/logicaldecoding.sgml @@ -959,6 +959,7 @@ typedef struct OutputPluginOptions { OutputPluginOutputType output_type; bool receive_rewrites; + bool need_shared_catalogs; } OutputPluginOptions; </programlisting> <literal>output_type</literal> has to either be set to @@ -969,6 +970,9 @@ typedef struct OutputPluginOptions also be called for changes made by heap rewrites during certain DDL operations. These are of interest to plugins that handle DDL replication, but they require special handling. + <literal>need_shared_catalogs</literal> can be set to false if you are + certain the plugin functions do not access shared system catalogs. + Doing so can speed up creation of replication slots that use this plugin. </para> <para> diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c index 1408989c568..97d44b84622 100644 --- a/src/backend/access/index/genam.c +++ b/src/backend/access/index/genam.c @@ -394,6 +394,14 @@ systable_beginscan(Relation heapRelation, SysScanDesc sysscan; Relation irel; + /* + * If this backend promised that it won't access shared catalogs during + * logical decoding, this it the right place to verify. + */ + Assert(!HistoricSnapshotActive() || + accessSharedCatalogsInDecoding || + !heapRelation->rd_rel->relisshared); + if (indexOK && !IgnoreSystemIndexes && !ReindexIsProcessingIndex(indexId)) diff --git a/src/backend/access/rmgrdesc/standbydesc.c b/src/backend/access/rmgrdesc/standbydesc.c index 0a291354ae2..685d1bdb024 100644 --- a/src/backend/access/rmgrdesc/standbydesc.c +++ b/src/backend/access/rmgrdesc/standbydesc.c @@ -41,6 +41,8 @@ standby_desc_running_xacts(StringInfo buf, xl_running_xacts *xlrec) for (i = 0; i < xlrec->subxcnt; i++) appendStringInfo(buf, " %u", xlrec->xids[xlrec->xcnt + i]); } + + appendStringInfo(buf, "; dbid: %u", xlrec->dbid); } void diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index b82af9a85c0..3f08a832ca6 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -7735,7 +7735,7 @@ CreateCheckPoint(int flags) * recovery we don't need to write running xact data. */ if (!shutdown && XLogStandbyInfoActive()) - LogStandbySnapshot(); + LogStandbySnapshot(InvalidOid); START_CRIT_SECTION(); diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c index 65bbaeda59c..0f5979691e6 100644 --- a/src/backend/access/transam/xlogfuncs.c +++ b/src/backend/access/transam/xlogfuncs.c @@ -245,7 +245,7 @@ pg_log_standby_snapshot(PG_FUNCTION_ARGS) (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("pg_log_standby_snapshot() can only be used if \"wal_level\" >= \"replica\""))); - recptr = LogStandbySnapshot(); + recptr = LogStandbySnapshot(InvalidOid); /* * As a convenience, return the WAL location of the last inserted record diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c index 1d8947774a9..a30de4262eb 100644 --- a/src/backend/postmaster/bgwriter.c +++ b/src/backend/postmaster/bgwriter.c @@ -289,7 +289,7 @@ BackgroundWriterMain(const void *startup_data, size_t startup_data_len) if (now >= timeout && last_snapshot_lsn <= GetLastImportantRecPtr()) { - last_snapshot_lsn = LogStandbySnapshot(); + last_snapshot_lsn = LogStandbySnapshot(InvalidOid); last_snapshot_ts = now; } } diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c index c9fea8cad28..38c5a4f5540 100644 --- a/src/backend/replication/logical/decode.c +++ b/src/backend/replication/logical/decode.c @@ -382,7 +382,16 @@ standby_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) { xl_running_xacts *running = (xl_running_xacts *) XLogRecGetData(r); - SnapBuildProcessRunningXacts(builder, buf->origptr, running); + /* + * Update this decoder's idea of transactions currently + * running. In doing so we will determine whether we have + * reached consistent status. + * + * If the output plugin doesn't need access to shared + * catalogs, we can ignore transactions in other databases. + */ + SnapBuildProcessRunningXacts(builder, buf->origptr, running, + !ctx->options.need_shared_catalogs); /* * Abort all transactions that we keep track of, that are @@ -392,8 +401,12 @@ standby_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) * all running transactions which includes prepared ones, * while shutdown checkpoints just know that no non-prepared * transactions are in progress. + * + * The database-specific records might work here too, but it's + * not their purpose. */ - ReorderBufferAbortOld(ctx->reorder, running->oldestRunningXid); + if (!OidIsValid(running->dbid)) + ReorderBufferAbortOld(ctx->reorder, running->oldestRunningXid); } break; case XLOG_STANDBY_LOCK: diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c index f20d0c542f3..8ceaf64d164 100644 --- a/src/backend/replication/logical/logical.c +++ b/src/backend/replication/logical/logical.c @@ -285,6 +285,9 @@ StartupDecodingContext(List *output_plugin_options, ctx->write = do_write; ctx->update_progress = update_progress; + /* Assume shared catalog access. The startup callback can change it. */ + ctx->options.need_shared_catalogs = true; + ctx->output_plugin_options = output_plugin_options; ctx->fast_forward = fast_forward; diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c index b4269a3b102..ffb4ab2cf2a 100644 --- a/src/backend/replication/logical/snapbuild.c +++ b/src/backend/replication/logical/snapbuild.c @@ -154,6 +154,14 @@ static ResourceOwner SavedResourceOwnerDuringExport = NULL; static bool ExportInProgress = false; +/* + * If a backend is going to do logical decoding and the output plugin does + * not need to access shared catalogs, setting this variable to false can make + * the decoding startup faster. In particular, the backend will not need to + * wait for completion of already running transactions in other databases. + */ +bool accessSharedCatalogsInDecoding = true; + /* ->committed and ->catchange manipulation */ static void SnapBuildPurgeOlderTxn(SnapBuild *builder); @@ -170,7 +178,8 @@ static inline bool SnapBuildXidHasCatalogChanges(SnapBuild *builder, Transaction uint32 xinfo); /* xlog reading helper functions for SnapBuildProcessRunningXacts */ -static bool SnapBuildFindSnapshot(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *running); +static bool SnapBuildFindSnapshot(SnapBuild *builder, XLogRecPtr lsn, + xl_running_xacts *running); static void SnapBuildWaitSnapshot(xl_running_xacts *running, TransactionId cutoff); /* serialization functions */ @@ -226,6 +235,9 @@ AllocateSnapshotBuilder(ReorderBuffer *reorder, MemoryContextSwitchTo(oldcontext); + /* The default is that shared catalog are used. */ + accessSharedCatalogsInDecoding = true; + return builder; } @@ -244,6 +256,9 @@ FreeSnapshotBuilder(SnapBuild *builder) builder->snapshot = NULL; } + /* The default is that shared catalog are used. */ + accessSharedCatalogsInDecoding = true; + /* other resources are deallocated via memory context reset */ MemoryContextDelete(context); } @@ -1136,7 +1151,8 @@ SnapBuildXidHasCatalogChanges(SnapBuild *builder, TransactionId xid, * anymore. */ void -SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *running) +SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *running, + bool db_specific) { ReorderBufferTXN *txn; TransactionId xmin; @@ -1148,6 +1164,33 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact */ if (builder->state < SNAPBUILD_CONSISTENT) { + /* + * To reduce the potential for unnecessarily waiting for completion of + * unrelated transactions, the caller can declare that only + * transactions of the current database are relevant at this stage. + */ + if (db_specific) + { + /* + * If we must only keep track of transactions running in the + * current database, we need transaction info from exactly that + * database. + */ + if (running->dbid != MyDatabaseId) + { + LogStandbySnapshot(MyDatabaseId); + + return; + } + + /* + * We'd better be able to check during scan if the plugin does not + * lie. + */ + if (accessSharedCatalogsInDecoding) + accessSharedCatalogsInDecoding = false; + } + /* returns false if there's no point in performing cleanup just yet */ if (!SnapBuildFindSnapshot(builder, lsn, running)) return; @@ -1155,6 +1198,16 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact else SnapBuildSerialize(builder, lsn); + /* + * Database specific transaction info may exist to reach CONSISTENT state + * faster, however the code below makes no use of it. Moreover, such + * record might cause problems because the following normal (cluster-wide) + * record can have lower value of oldestRunningXid. In that case, let's + * wait with the cleanup for the next regular cluster-wide record. + */ + if (OidIsValid(running->dbid)) + return; + /* * Update range of interesting xids based on the running xacts * information. We don't increase ->xmax using it, because once we are in @@ -1465,7 +1518,11 @@ SnapBuildWaitSnapshot(xl_running_xacts *running, TransactionId cutoff) */ if (!RecoveryInProgress()) { - LogStandbySnapshot(); + /* + * If the last transaction info was about specific database, so needs + * to be the next one - at least until we're in the CONSISTENT state. + */ + LogStandbySnapshot(running->dbid); } } diff --git a/src/backend/replication/pgrepack/pgrepack.c b/src/backend/replication/pgrepack/pgrepack.c index 457b6518a8e..4da66aa0f44 100644 --- a/src/backend/replication/pgrepack/pgrepack.c +++ b/src/backend/replication/pgrepack/pgrepack.c @@ -52,6 +52,13 @@ repack_startup(LogicalDecodingContext *ctx, OutputPluginOptions *opt, /* Probably unnecessary, as we don't use the SQL interface ... */ opt->output_type = OUTPUT_PLUGIN_BINARY_OUTPUT; + /* + * REPACK doesn't need access to shared catalogs, so we can speed up the + * historic snapshot creation by setting this flag. We'll only have to + * wait for transactions in our database. + */ + opt->need_shared_catalogs = false; + if (ctx->output_plugin_options != NIL) { ereport(ERROR, diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c index 21a213a0ebf..a1f37e59dbc 100644 --- a/src/backend/replication/slot.c +++ b/src/backend/replication/slot.c @@ -1756,7 +1756,7 @@ ReplicationSlotReserveWal(void) XLogRecPtr flushptr; /* make sure we have enough information to start */ - flushptr = LogStandbySnapshot(); + flushptr = LogStandbySnapshot(InvalidOid); /* and make sure it's fsynced to disk */ XLogFlush(flushptr); diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index f540bb6b23f..9299bcebbda 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -2623,9 +2623,11 @@ ProcArrayInstallRestoredXmin(TransactionId xmin, PGPROC *proc) * * Note that if any transaction has overflowed its cached subtransactions * then there is no real need include any subtransactions. + * + * If 'dbid' is valid, only gather transactions running in that database. */ RunningTransactions -GetRunningTransactionData(void) +GetRunningTransactionData(Oid dbid) { /* result workspace */ static RunningTransactionsData CurrentRunningXactsData; @@ -2700,6 +2702,18 @@ GetRunningTransactionData(void) if (!TransactionIdIsValid(xid)) continue; + /* + * Filter by database OID if requested. + */ + if (OidIsValid(dbid)) + { + int pgprocno = arrayP->pgprocnos[index]; + PGPROC *proc = &allProcs[pgprocno]; + + if (proc->databaseId != dbid) + continue; + } + /* * Be careful not to exclude any xids before calculating the values of * oldestRunningXid and suboverflowed, since these are used to clean @@ -2750,6 +2764,12 @@ GetRunningTransactionData(void) PGPROC *proc = &allProcs[pgprocno]; int nsubxids; + /* + * Filter by database OID if requested. + */ + if (OidIsValid(dbid) && proc->databaseId != dbid) + continue; + /* * Save subtransaction XIDs. Other backends can't add or remove * entries while we're holding XidGenLock. @@ -2783,6 +2803,7 @@ GetRunningTransactionData(void) * increases if slots do. */ + CurrentRunningXacts->dbid = dbid; CurrentRunningXacts->xcnt = count - subcount; CurrentRunningXacts->subxcnt = subcount; CurrentRunningXacts->subxid_status = suboverflowed ? SUBXIDS_IN_SUBTRANS : SUBXIDS_IN_ARRAY; diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c index de9092fdf5b..29af7733948 100644 --- a/src/backend/storage/ipc/standby.c +++ b/src/backend/storage/ipc/standby.c @@ -1188,6 +1188,14 @@ standby_redo(XLogReaderState *record) xl_running_xacts *xlrec = (xl_running_xacts *) XLogRecGetData(record); RunningTransactionsData running; + /* + * Records issued for specific database are not suitable for physical + * replication because that affects the whole cluster. In particular, + * the list of XID is probably incomplete here. + */ + if (OidIsValid(xlrec->dbid)) + return; + running.xcnt = xlrec->xcnt; running.subxcnt = xlrec->subxcnt; running.subxid_status = xlrec->subxid_overflow ? SUBXIDS_MISSING : SUBXIDS_IN_ARRAY; @@ -1277,11 +1285,22 @@ standby_redo(XLogReaderState *record) * as there's no independent knob to just enable logical decoding. For * details of how this is used, check snapbuild.c's introductory comment. * + * If 'dbid' is valid, only gather transactions running in that + * database. snapbuild.c can use such running xacts information for faster + * startup, but it still needs normal (cluster-wide) during the actual + * decoding - see standby_decode() and SnapBuildProcessRunningXacts() for + * details. Other processes (e.g. checkpointer) issue the cluster-wide records + * whether logical decoding is active or not. + * + * Please be careful about using this argument for other purposes. In + * particular, physical replication *must* ignore the database-specific + * records, exactly because they do not cover the whole cluster - see + * standby_redo(). * * Returns the RecPtr of the last inserted record. */ XLogRecPtr -LogStandbySnapshot(void) +LogStandbySnapshot(Oid dbid) { XLogRecPtr recptr; RunningTransactions running; @@ -1314,7 +1333,7 @@ LogStandbySnapshot(void) * Log details of all in-progress transactions. This should be the last * record we write, because standby will open up when it sees this. */ - running = GetRunningTransactionData(); + running = GetRunningTransactionData(dbid); /* * GetRunningTransactionData() acquired ProcArrayLock, we must release it. @@ -1358,6 +1377,7 @@ LogCurrentRunningXacts(RunningTransactions CurrRunningXacts) xl_running_xacts xlrec; XLogRecPtr recptr; + xlrec.dbid = CurrRunningXacts->dbid; xlrec.xcnt = CurrRunningXacts->xcnt; xlrec.subxcnt = CurrRunningXacts->subxcnt; xlrec.subxid_overflow = (CurrRunningXacts->subxid_status != SUBXIDS_IN_ARRAY); diff --git a/src/include/access/genam.h b/src/include/access/genam.h index b69320a7fc8..de55821e414 100644 --- a/src/include/access/genam.h +++ b/src/include/access/genam.h @@ -136,6 +136,7 @@ typedef struct IndexOrderByDistance bool isnull; } IndexOrderByDistance; + /* * generalized index_ interface routines (in indexam.c) */ diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h index 10c18d39ff8..13ae3ad4fbb 100644 --- a/src/include/access/xlog_internal.h +++ b/src/include/access/xlog_internal.h @@ -32,7 +32,7 @@ /* * Each page of XLOG file has a header like this: */ -#define XLOG_PAGE_MAGIC 0xD11E /* can be used as WAL version indicator */ +#define XLOG_PAGE_MAGIC 0xD11F /* can be used as WAL version indicator */ typedef struct XLogPageHeaderData { diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 2e10e3c814d..93b7816c09c 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -310,6 +310,15 @@ extern void PreventCommandIfReadOnly(const char *cmdname); extern void PreventCommandIfParallelMode(const char *cmdname); extern void PreventCommandDuringRecovery(const char *cmdname); +/* in replication/snapbuild.c */ + +/* + * Keep track of whether logical decoding in this backend promised not to + * access shared catalogs, as a safety check. This is checked by genam.c when + * a catalog scan takes place to verify that no shared catalogs are accessed. + */ +extern bool accessSharedCatalogsInDecoding; + /***************************************************************************** * pdir.h -- * * POSTGRES directory path definitions. * diff --git a/src/include/replication/output_plugin.h b/src/include/replication/output_plugin.h index 842fcde67f9..917f3cff232 100644 --- a/src/include/replication/output_plugin.h +++ b/src/include/replication/output_plugin.h @@ -27,6 +27,7 @@ typedef struct OutputPluginOptions { OutputPluginOutputType output_type; bool receive_rewrites; + bool need_shared_catalogs; } OutputPluginOptions; /* diff --git a/src/include/replication/snapbuild.h b/src/include/replication/snapbuild.h index a22a83a2f23..d02530a912a 100644 --- a/src/include/replication/snapbuild.h +++ b/src/include/replication/snapbuild.h @@ -92,7 +92,8 @@ extern void SnapBuildProcessNewCid(SnapBuild *builder, TransactionId xid, XLogRecPtr lsn, xl_heap_new_cid *xlrec); extern void SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, - xl_running_xacts *running); + xl_running_xacts *running, + bool db_specific); extern void SnapBuildSerializationPoint(SnapBuild *builder, XLogRecPtr lsn); extern bool SnapBuildSnapshotExists(XLogRecPtr lsn); diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h index d718a5b542f..ec89c448220 100644 --- a/src/include/storage/procarray.h +++ b/src/include/storage/procarray.h @@ -47,7 +47,7 @@ extern bool ProcArrayInstallImportedXmin(TransactionId xmin, VirtualTransactionId *sourcevxid); extern bool ProcArrayInstallRestoredXmin(TransactionId xmin, PGPROC *proc); -extern RunningTransactions GetRunningTransactionData(void); +extern RunningTransactions GetRunningTransactionData(Oid dbid); extern bool TransactionIdIsInProgress(TransactionId xid); extern TransactionId GetOldestNonRemovableTransactionId(Relation rel); diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h index 6a314c693cd..8715c08e94f 100644 --- a/src/include/storage/standby.h +++ b/src/include/storage/standby.h @@ -126,6 +126,7 @@ typedef enum typedef struct RunningTransactionsData { + Oid dbid; /* only track xacts in this database */ int xcnt; /* # of xact ids in xids[] */ int subxcnt; /* # of subxact ids in xids[] */ subxids_array_status subxid_status; @@ -143,7 +144,7 @@ typedef RunningTransactionsData *RunningTransactions; extern void LogAccessExclusiveLock(Oid dbOid, Oid relOid); extern void LogAccessExclusiveLockPrepare(void); -extern XLogRecPtr LogStandbySnapshot(void); +extern XLogRecPtr LogStandbySnapshot(Oid dbid); extern void LogStandbyInvalidations(int nmsgs, SharedInvalidationMessage *msgs, bool relcacheInitFileInval); diff --git a/src/include/storage/standbydefs.h b/src/include/storage/standbydefs.h index 231d251fd51..e75b7078766 100644 --- a/src/include/storage/standbydefs.h +++ b/src/include/storage/standbydefs.h @@ -46,6 +46,7 @@ typedef struct xl_standby_locks */ typedef struct xl_running_xacts { + Oid dbid; /* only track xacts in this database */ int xcnt; /* # of xact ids in xids[] */ int subxcnt; /* # of subxact ids in xids[] */ bool subxid_overflow; /* snapshot overflowed, subxids missing */ -- 2.47.3 --qs77q6fpwolne4ds Content-Type: text/x-diff; charset=utf-8 Content-Disposition: attachment; filename="v56-0002-Reserve-replication-slots-specifically-for-REPAC.patch" ^ permalink raw reply [nested|flat] 2+ messages in thread
end of thread, other threads:[~2026-04-06 22:07 UTC | newest] Thread overview: 2+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2018-09-20 11:43 [PATCH v2] Generate bootstrap entries for array types Dagfinn Ilmari Mannsåker <ilmari@ilmari.org> 2026-04-06 22:07 [PATCH v56 1/3] Allow logical replication snapshots to be database-specific Álvaro Herrera <alvherre@kurilemu.de>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox