diff options
Diffstat (limited to 'src/backend/catalog')
103 files changed, 61565 insertions, 0 deletions
diff --git a/src/backend/catalog/.gitignore b/src/backend/catalog/.gitignore new file mode 100644 index 0000000..11e2e52 --- /dev/null +++ b/src/backend/catalog/.gitignore @@ -0,0 +1,4 @@ +/postgres.bki +/schemapg.h +/pg_*_d.h +/bki-stamp diff --git a/src/backend/catalog/Catalog.pm b/src/backend/catalog/Catalog.pm new file mode 100644 index 0000000..dd39a08 --- /dev/null +++ b/src/backend/catalog/Catalog.pm @@ -0,0 +1,540 @@ +#---------------------------------------------------------------------- +# +# Catalog.pm +# Perl module that extracts info from catalog files into Perl +# data structures +# +# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/backend/catalog/Catalog.pm +# +#---------------------------------------------------------------------- + +package Catalog; + +use strict; +use warnings; + +use File::Compare; + + +# Parses a catalog header file into a data structure describing the schema +# of the catalog. +sub ParseHeader +{ + my $input_file = shift; + + # There are a few types which are given one name in the C source, but a + # different name at the SQL level. These are enumerated here. + my %RENAME_ATTTYPE = ( + 'int16' => 'int2', + 'int32' => 'int4', + 'int64' => 'int8', + 'Oid' => 'oid', + 'NameData' => 'name', + 'TransactionId' => 'xid', + 'XLogRecPtr' => 'pg_lsn'); + + my %catalog; + my $declaring_attributes = 0; + my $is_varlen = 0; + my $is_client_code = 0; + + $catalog{columns} = []; + $catalog{toasting} = []; + $catalog{indexing} = []; + $catalog{client_code} = []; + + open(my $ifh, '<', $input_file) || die "$input_file: $!"; + + # Scan the input file. + while (<$ifh>) + { + + # Set appropriate flag when we're in certain code sections. + if (/^#/) + { + $is_varlen = 1 if /^#ifdef\s+CATALOG_VARLEN/; + if (/^#ifdef\s+EXPOSE_TO_CLIENT_CODE/) + { + $is_client_code = 1; + next; + } + next if !$is_client_code; + } + + if (!$is_client_code) + { + # Strip C-style comments. + s;/\*(.|\n)*\*/;;g; + if (m;/\*;) + { + + # handle multi-line comments properly. + my $next_line = <$ifh>; + die "$input_file: ends within C-style comment\n" + if !defined $next_line; + $_ .= $next_line; + redo; + } + + # Strip useless whitespace and trailing semicolons. + chomp; + s/^\s+//; + s/;\s*$//; + s/\s+/ /g; + } + + # Push the data into the appropriate data structure. + # Caution: when adding new recognized OID-defining macros, + # also update src/include/catalog/renumber_oids.pl. + if (/^DECLARE_TOAST\(\s*(\w+),\s*(\d+),\s*(\d+)\)/) + { + push @{ $catalog{toasting} }, + { parent_table => $1, toast_oid => $2, toast_index_oid => $3 }; + } + elsif (/^DECLARE_(UNIQUE_)?INDEX\(\s*(\w+),\s*(\d+),\s*(.+)\)/) + { + push @{ $catalog{indexing} }, + { + is_unique => $1 ? 1 : 0, + index_name => $2, + index_oid => $3, + index_decl => $4 + }; + } + elsif (/^CATALOG\((\w+),(\d+),(\w+)\)/) + { + $catalog{catname} = $1; + $catalog{relation_oid} = $2; + $catalog{relation_oid_macro} = $3; + + $catalog{bootstrap} = /BKI_BOOTSTRAP/ ? ' bootstrap' : ''; + $catalog{shared_relation} = + /BKI_SHARED_RELATION/ ? ' shared_relation' : ''; + if (/BKI_ROWTYPE_OID\((\d+),(\w+)\)/) + { + $catalog{rowtype_oid} = $1; + $catalog{rowtype_oid_clause} = " rowtype_oid $1"; + $catalog{rowtype_oid_macro} = $2; + } + else + { + $catalog{rowtype_oid} = ''; + $catalog{rowtype_oid_clause} = ''; + $catalog{rowtype_oid_macro} = ''; + } + $catalog{schema_macro} = /BKI_SCHEMA_MACRO/ ? 1 : 0; + $declaring_attributes = 1; + } + elsif ($is_client_code) + { + if (/^#endif/) + { + $is_client_code = 0; + } + else + { + push @{ $catalog{client_code} }, $_; + } + } + elsif ($declaring_attributes) + { + next if (/^{|^$/); + if (/^}/) + { + $declaring_attributes = 0; + } + else + { + my %column; + my @attopts = split /\s+/, $_; + my $atttype = shift @attopts; + my $attname = shift @attopts; + die "parse error ($input_file)" + unless ($attname and $atttype); + + if (exists $RENAME_ATTTYPE{$atttype}) + { + $atttype = $RENAME_ATTTYPE{$atttype}; + } + + # If the C name ends with '[]' or '[digits]', we have + # an array type, so we discard that from the name and + # prepend '_' to the type. + if ($attname =~ /(\w+)\[\d*\]/) + { + $attname = $1; + $atttype = '_' . $atttype; + } + + $column{type} = $atttype; + $column{name} = $attname; + $column{is_varlen} = 1 if $is_varlen; + + foreach my $attopt (@attopts) + { + if ($attopt eq 'BKI_FORCE_NULL') + { + $column{forcenull} = 1; + } + elsif ($attopt eq 'BKI_FORCE_NOT_NULL') + { + $column{forcenotnull} = 1; + } + + # We use quotes for values like \0 and \054, to + # make sure all compilers and syntax highlighters + # can recognize them properly. + elsif ($attopt =~ /BKI_DEFAULT\(['"]?([^'"]+)['"]?\)/) + { + $column{default} = $1; + } + elsif ( + $attopt =~ /BKI_ARRAY_DEFAULT\(['"]?([^'"]+)['"]?\)/) + { + $column{array_default} = $1; + } + elsif ($attopt =~ /BKI_LOOKUP\((\w+)\)/) + { + $column{lookup} = $1; + } + else + { + die + "unknown or misformatted column option $attopt on column $attname"; + } + + if ($column{forcenull} and $column{forcenotnull}) + { + die "$attname is forced both null and not null"; + } + } + push @{ $catalog{columns} }, \%column; + } + } + } + close $ifh; + return \%catalog; +} + +# Parses a file containing Perl data structure literals, returning live data. +# +# The parameter $preserve_formatting needs to be set for callers that want +# to work with non-data lines in the data files, such as comments and blank +# lines. If a caller just wants to consume the data, leave it unset. +sub ParseData +{ + my ($input_file, $schema, $preserve_formatting) = @_; + + open(my $ifd, '<', $input_file) || die "$input_file: $!"; + $input_file =~ /(\w+)\.dat$/ + or die "Input file $input_file needs to be a .dat file.\n"; + my $catname = $1; + my $data = []; + + # Scan the input file. + while (<$ifd>) + { + my $hash_ref; + + if (/{/) + { + # Capture the hash ref + # NB: Assumes that the next hash ref can't start on the + # same line where the present one ended. + # Not foolproof, but we shouldn't need a full parser, + # since we expect relatively well-behaved input. + + # Quick hack to detect when we have a full hash ref to + # parse. We can't just use a regex because of values in + # pg_aggregate and pg_proc like '{0,0}'. This will need + # work if we ever need to allow unbalanced braces within + # a field value. + my $lcnt = tr/{//; + my $rcnt = tr/}//; + + if ($lcnt == $rcnt) + { + # We're treating the input line as a piece of Perl, so we + # need to use string eval here. Tell perlcritic we know what + # we're doing. + eval '$hash_ref = ' . $_; ## no critic (ProhibitStringyEval) + if (!ref $hash_ref) + { + die "$input_file: error parsing line $.:\n$_\n"; + } + + # Annotate each hash with the source line number. + $hash_ref->{line_number} = $.; + + # Expand tuples to their full representation. + AddDefaultValues($hash_ref, $schema, $catname); + } + else + { + my $next_line = <$ifd>; + die "$input_file: file ends within Perl hash\n" + if !defined $next_line; + $_ .= $next_line; + redo; + } + } + + # If we found a hash reference, keep it, unless it is marked as + # autogenerated; in that case it'd duplicate an entry we'll + # autogenerate below. (This makes it safe for reformat_dat_file.pl + # with --full-tuples to print autogenerated entries, which seems like + # useful behavior for debugging.) + # + # Only keep non-data strings if we are told to preserve formatting. + if (defined $hash_ref) + { + push @$data, $hash_ref if !$hash_ref->{autogenerated}; + } + elsif ($preserve_formatting) + { + push @$data, $_; + } + } + close $ifd; + + # If this is pg_type, auto-generate array types too. + GenerateArrayTypes($schema, $data) if $catname eq 'pg_type'; + + return $data; +} + +# Fill in default values of a record using the given schema. +# It's the caller's responsibility to specify other values beforehand. +sub AddDefaultValues +{ + my ($row, $schema, $catname) = @_; + my @missing_fields; + + # Compute special-case column values. + # Note: If you add new cases here, you must also teach + # strip_default_values() in include/catalog/reformat_dat_file.pl + # to delete them. + if ($catname eq 'pg_proc') + { + # pg_proc.pronargs can be derived from proargtypes. + if (defined $row->{proargtypes}) + { + my @proargtypes = split /\s+/, $row->{proargtypes}; + $row->{pronargs} = scalar(@proargtypes); + } + } + + # Now fill in defaults, and note any columns that remain undefined. + foreach my $column (@$schema) + { + my $attname = $column->{name}; + + # No work if field already has a value. + next if defined $row->{$attname}; + + # Ignore 'oid' columns, they're handled elsewhere. + next if $attname eq 'oid'; + + # If column has a default value, fill that in. + if (defined $column->{default}) + { + $row->{$attname} = $column->{default}; + next; + } + + # Failed to find a value for this field. + push @missing_fields, $attname; + } + + # Failure to provide all columns is a hard error. + if (@missing_fields) + { + die sprintf "missing values for field(s) %s in %s.dat line %s\n", + join(', ', @missing_fields), $catname, $row->{line_number}; + } +} + +# If a pg_type entry has an array_type_oid metadata field, +# auto-generate an entry for its array type. +sub GenerateArrayTypes +{ + my $pgtype_schema = shift; + my $types = shift; + my @array_types; + + foreach my $elem_type (@$types) + { + next if !(ref $elem_type eq 'HASH'); + next if !defined($elem_type->{array_type_oid}); + + my %array_type; + + # Set up metadata fields for array type. + $array_type{oid} = $elem_type->{array_type_oid}; + $array_type{autogenerated} = 1; + $array_type{line_number} = $elem_type->{line_number}; + + # Set up column values derived from the element type. + $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 array entry's fields. + foreach my $column (@$pgtype_schema) + { + my $attname = $column->{name}; + + # Skip if we already set it above. + next if defined $array_type{$attname}; + + # Apply the BKI_ARRAY_DEFAULT setting if there is one, + # otherwise copy the field from the element type. + if (defined $column->{array_default}) + { + $array_type{$attname} = $column->{array_default}; + } + else + { + $array_type{$attname} = $elem_type->{$attname}; + } + } + + # Lastly, cross-link the array to the element type. + $elem_type->{typarray} = $array_type{typname}; + + push @array_types, \%array_type; + } + + push @$types, @array_types; + + return; +} + +# Rename temporary files to final names. +# Call this function with the final file name and the .tmp extension. +# +# If the final file already exists and has identical contents, don't +# overwrite it; this behavior avoids unnecessary recompiles due to +# updating the mod date on unchanged header files. +# +# Note: recommended extension is ".tmp$$", so that parallel make steps +# can't use the same temp files. +sub RenameTempFile +{ + my $final_name = shift; + my $extension = shift; + my $temp_name = $final_name . $extension; + + if (-f $final_name + && compare($temp_name, $final_name) == 0) + { + unlink($temp_name) || die "unlink: $temp_name: $!"; + } + else + { + rename($temp_name, $final_name) || die "rename: $temp_name: $!"; + } + return; +} + +# Find a symbol defined in a particular header file and extract the value. +# include_path should be the path to src/include/. +sub FindDefinedSymbol +{ + my ($catalog_header, $include_path, $symbol) = @_; + my $value; + + # Make sure include path ends in a slash. + if (substr($include_path, -1) ne '/') + { + $include_path .= '/'; + } + my $file = $include_path . $catalog_header; + open(my $find_defined_symbol, '<', $file) || die "$file: $!"; + while (<$find_defined_symbol>) + { + if (/^#define\s+\Q$symbol\E\s+(\S+)/) + { + $value = $1; + last; + } + } + close $find_defined_symbol; + return $value if defined $value; + die "$file: no definition found for $symbol\n"; +} + +# Similar to FindDefinedSymbol, but looks in the bootstrap metadata. +sub FindDefinedSymbolFromData +{ + my ($data, $symbol) = @_; + foreach my $row (@{$data}) + { + if ($row->{oid_symbol} eq $symbol) + { + return $row->{oid}; + } + } + die "no definition found for $symbol\n"; +} + +# Extract an array of all the OIDs assigned in the specified catalog headers +# and their associated data files (if any). +# Caution: genbki.pl contains equivalent logic; change it too if you need to +# touch this. +sub FindAllOidsFromHeaders +{ + my @input_files = @_; + + my @oids = (); + + foreach my $header (@input_files) + { + $header =~ /(.+)\.h$/ + or die "Input files need to be header files.\n"; + my $datfile = "$1.dat"; + + my $catalog = Catalog::ParseHeader($header); + + # We ignore the pg_class OID and rowtype OID of bootstrap catalogs, + # as those are expected to appear in the initial data for pg_class + # and pg_type. For regular catalogs, include these OIDs. + if (!$catalog->{bootstrap}) + { + push @oids, $catalog->{relation_oid} + if ($catalog->{relation_oid}); + push @oids, $catalog->{rowtype_oid} if ($catalog->{rowtype_oid}); + } + + # Not all catalogs have a data file. + if (-e $datfile) + { + my $catdata = + Catalog::ParseData($datfile, $catalog->{columns}, 0); + + foreach my $row (@$catdata) + { + push @oids, $row->{oid} if defined $row->{oid}; + } + } + + foreach my $toast (@{ $catalog->{toasting} }) + { + push @oids, $toast->{toast_oid}, $toast->{toast_index_oid}; + } + foreach my $index (@{ $catalog->{indexing} }) + { + push @oids, $index->{index_oid}; + } + } + + return \@oids; +} + +1; diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile new file mode 100644 index 0000000..9499bb3 --- /dev/null +++ b/src/backend/catalog/Makefile @@ -0,0 +1,145 @@ +#------------------------------------------------------------------------- +# +# Makefile for backend/catalog +# +# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/backend/catalog/Makefile +# +#------------------------------------------------------------------------- + +subdir = src/backend/catalog +top_builddir = ../../.. +include $(top_builddir)/src/Makefile.global + +OBJS = \ + aclchk.o \ + catalog.o \ + dependency.o \ + heap.o \ + index.o \ + indexing.o \ + namespace.o \ + objectaccess.o \ + objectaddress.o \ + partition.o \ + pg_aggregate.o \ + pg_cast.o \ + pg_collation.o \ + pg_constraint.o \ + pg_conversion.o \ + pg_db_role_setting.o \ + pg_depend.o \ + pg_enum.o \ + pg_inherits.o \ + pg_largeobject.o \ + pg_namespace.o \ + pg_operator.o \ + pg_proc.o \ + pg_publication.o \ + pg_range.o \ + pg_shdepend.o \ + pg_subscription.o \ + pg_type.o \ + storage.o \ + toasting.o + +include $(top_srcdir)/src/backend/common.mk + +# Note: the order of this list determines the order in which the catalog +# header files are assembled into postgres.bki. BKI_BOOTSTRAP catalogs +# must appear first, and there are reputedly other, undocumented ordering +# dependencies. +CATALOG_HEADERS := \ + pg_proc.h pg_type.h pg_attribute.h pg_class.h \ + pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.h \ + pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \ + pg_language.h pg_largeobject_metadata.h pg_largeobject.h pg_aggregate.h \ + pg_statistic_ext.h pg_statistic_ext_data.h \ + pg_statistic.h pg_rewrite.h pg_trigger.h pg_event_trigger.h pg_description.h \ + pg_cast.h pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \ + pg_database.h pg_db_role_setting.h pg_tablespace.h \ + pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \ + pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \ + pg_ts_parser.h pg_ts_template.h pg_extension.h \ + pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \ + pg_foreign_table.h pg_policy.h pg_replication_origin.h \ + pg_default_acl.h pg_init_privs.h pg_seclabel.h pg_shseclabel.h \ + pg_collation.h pg_partitioned_table.h pg_range.h pg_transform.h \ + pg_sequence.h pg_publication.h pg_publication_rel.h pg_subscription.h \ + pg_subscription_rel.h + +GENERATED_HEADERS := $(CATALOG_HEADERS:%.h=%_d.h) schemapg.h + +# In the list of headers used to assemble postgres.bki, indexing.h needs +# be last, and toasting.h just before it. This ensures we don't try to +# create indexes or toast tables before their catalogs exist. +POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/,\ + $(CATALOG_HEADERS) toasting.h indexing.h \ + ) + +# The .dat files we need can just be listed alphabetically. +POSTGRES_BKI_DATA = $(addprefix $(top_srcdir)/src/include/catalog/,\ + pg_aggregate.dat pg_am.dat pg_amop.dat pg_amproc.dat pg_authid.dat \ + pg_cast.dat pg_class.dat pg_collation.dat pg_conversion.dat \ + pg_database.dat pg_language.dat \ + pg_namespace.dat pg_opclass.dat pg_operator.dat pg_opfamily.dat \ + pg_proc.dat pg_range.dat pg_tablespace.dat \ + pg_ts_config.dat pg_ts_config_map.dat pg_ts_dict.dat pg_ts_parser.dat \ + pg_ts_template.dat pg_type.dat \ + ) + +all: distprep generated-header-symlinks + +distprep: bki-stamp + +.PHONY: generated-header-symlinks + +generated-header-symlinks: $(top_builddir)/src/include/catalog/header-stamp + +# bki-stamp records the last time we ran genbki.pl. We don't rely on +# the timestamps of the individual output files, because the Perl script +# won't update them if they didn't change (to avoid unnecessary recompiles). +# Technically, this should depend on Makefile.global which supplies +# $(MAJORVERSION); but then genbki.pl would need to be re-run after every +# configure run, even in distribution tarballs. So depending on configure.in +# instead is cheating a bit, but it will achieve the goal of updating the +# version number when it changes. +bki-stamp: genbki.pl Catalog.pm $(POSTGRES_BKI_SRCS) $(POSTGRES_BKI_DATA) $(top_srcdir)/configure.in + $(PERL) $< --include-path=$(top_srcdir)/src/include/ \ + --set-version=$(MAJORVERSION) $(POSTGRES_BKI_SRCS) + touch $@ + +# The generated headers must all be symlinked into builddir/src/include/, +# using absolute links for the reasons explained in src/backend/Makefile. +# We use header-stamp to record that we've done this because the symlinks +# themselves may appear older than bki-stamp. +$(top_builddir)/src/include/catalog/header-stamp: bki-stamp + prereqdir=`cd '$(dir $<)' >/dev/null && pwd` && \ + cd '$(dir $@)' && for file in $(GENERATED_HEADERS); do \ + rm -f $$file && $(LN_S) "$$prereqdir/$$file" . ; \ + done + touch $@ + +# Note: installation of generated headers is handled elsewhere +.PHONY: install-data +install-data: bki-stamp installdirs + $(INSTALL_DATA) $(call vpathsearch,postgres.bki) '$(DESTDIR)$(datadir)/postgres.bki' + $(INSTALL_DATA) $(srcdir)/system_views.sql '$(DESTDIR)$(datadir)/system_views.sql' + $(INSTALL_DATA) $(srcdir)/information_schema.sql '$(DESTDIR)$(datadir)/information_schema.sql' + $(INSTALL_DATA) $(srcdir)/sql_features.txt '$(DESTDIR)$(datadir)/sql_features.txt' + +installdirs: + $(MKDIR_P) '$(DESTDIR)$(datadir)' + +.PHONY: uninstall-data +uninstall-data: + rm -f $(addprefix '$(DESTDIR)$(datadir)'/, postgres.bki system_views.sql information_schema.sql sql_features.txt) + +# postgres.bki and the generated headers are in the distribution tarball, +# so they are not cleaned here. +clean: + +maintainer-clean: clean + rm -f bki-stamp postgres.bki $(GENERATED_HEADERS) diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c new file mode 100644 index 0000000..4f1e8a4 --- /dev/null +++ b/src/backend/catalog/aclchk.c @@ -0,0 +1,6037 @@ +/*------------------------------------------------------------------------- + * + * aclchk.c + * Routines to check access control permissions. + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/aclchk.c + * + * NOTES + * See acl.h. + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/genam.h" +#include "access/heapam.h" +#include "access/htup_details.h" +#include "access/sysattr.h" +#include "access/tableam.h" +#include "access/xact.h" +#include "catalog/binary_upgrade.h" +#include "catalog/catalog.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/objectaccess.h" +#include "catalog/pg_aggregate.h" +#include "catalog/pg_am.h" +#include "catalog/pg_authid.h" +#include "catalog/pg_cast.h" +#include "catalog/pg_collation.h" +#include "catalog/pg_conversion.h" +#include "catalog/pg_database.h" +#include "catalog/pg_default_acl.h" +#include "catalog/pg_event_trigger.h" +#include "catalog/pg_extension.h" +#include "catalog/pg_foreign_data_wrapper.h" +#include "catalog/pg_foreign_server.h" +#include "catalog/pg_init_privs.h" +#include "catalog/pg_language.h" +#include "catalog/pg_largeobject.h" +#include "catalog/pg_largeobject_metadata.h" +#include "catalog/pg_namespace.h" +#include "catalog/pg_opclass.h" +#include "catalog/pg_operator.h" +#include "catalog/pg_opfamily.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_statistic_ext.h" +#include "catalog/pg_subscription.h" +#include "catalog/pg_tablespace.h" +#include "catalog/pg_transform.h" +#include "catalog/pg_ts_config.h" +#include "catalog/pg_ts_dict.h" +#include "catalog/pg_ts_parser.h" +#include "catalog/pg_ts_template.h" +#include "catalog/pg_type.h" +#include "commands/dbcommands.h" +#include "commands/event_trigger.h" +#include "commands/extension.h" +#include "commands/proclang.h" +#include "commands/tablespace.h" +#include "foreign/foreign.h" +#include "miscadmin.h" +#include "nodes/makefuncs.h" +#include "parser/parse_func.h" +#include "parser/parse_type.h" +#include "utils/acl.h" +#include "utils/aclchk_internal.h" +#include "utils/builtins.h" +#include "utils/fmgroids.h" +#include "utils/lsyscache.h" +#include "utils/rel.h" +#include "utils/syscache.h" + +/* + * Internal format used by ALTER DEFAULT PRIVILEGES. + */ +typedef struct +{ + Oid roleid; /* owning role */ + Oid nspid; /* namespace, or InvalidOid if none */ + /* remaining fields are same as in InternalGrant: */ + bool is_grant; + ObjectType objtype; + bool all_privs; + AclMode privileges; + List *grantees; + bool grant_option; + DropBehavior behavior; +} InternalDefaultACL; + +/* + * When performing a binary-upgrade, pg_dump will call a function to set + * this variable to let us know that we need to populate the pg_init_privs + * table for the GRANT/REVOKE commands while this variable is set to true. + */ +bool binary_upgrade_record_init_privs = false; + +static void ExecGrantStmt_oids(InternalGrant *istmt); +static void ExecGrant_Relation(InternalGrant *grantStmt); +static void ExecGrant_Database(InternalGrant *grantStmt); +static void ExecGrant_Fdw(InternalGrant *grantStmt); +static void ExecGrant_ForeignServer(InternalGrant *grantStmt); +static void ExecGrant_Function(InternalGrant *grantStmt); +static void ExecGrant_Language(InternalGrant *grantStmt); +static void ExecGrant_Largeobject(InternalGrant *grantStmt); +static void ExecGrant_Namespace(InternalGrant *grantStmt); +static void ExecGrant_Tablespace(InternalGrant *grantStmt); +static void ExecGrant_Type(InternalGrant *grantStmt); + +static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames); +static void SetDefaultACL(InternalDefaultACL *iacls); + +static List *objectNamesToOids(ObjectType objtype, List *objnames); +static List *objectsInSchemaToOids(ObjectType objtype, List *nspnames); +static List *getRelationsInNamespace(Oid namespaceId, char relkind); +static void expand_col_privileges(List *colnames, Oid table_oid, + AclMode this_privileges, + AclMode *col_privileges, + int num_col_privileges); +static void expand_all_col_privileges(Oid table_oid, Form_pg_class classForm, + AclMode this_privileges, + AclMode *col_privileges, + int num_col_privileges); +static AclMode string_to_privilege(const char *privname); +static const char *privilege_to_string(AclMode privilege); +static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions, + bool all_privs, AclMode privileges, + Oid objectId, Oid grantorId, + ObjectType objtype, const char *objname, + AttrNumber att_number, const char *colname); +static AclMode pg_aclmask(ObjectType objtype, Oid table_oid, AttrNumber attnum, + Oid roleid, AclMode mask, AclMaskHow how); +static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, + Acl *new_acl); +static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, + Acl *new_acl); + + +/* + * If is_grant is true, adds the given privileges for the list of + * grantees to the existing old_acl. If is_grant is false, the + * privileges for the given grantees are removed from old_acl. + * + * NB: the original old_acl is pfree'd. + */ +static Acl * +merge_acl_with_grant(Acl *old_acl, bool is_grant, + bool grant_option, DropBehavior behavior, + List *grantees, AclMode privileges, + Oid grantorId, Oid ownerId) +{ + unsigned modechg; + ListCell *j; + Acl *new_acl; + + modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL; + + new_acl = old_acl; + + foreach(j, grantees) + { + AclItem aclitem; + Acl *newer_acl; + + aclitem.ai_grantee = lfirst_oid(j); + + /* + * Grant options can only be granted to individual roles, not PUBLIC. + * The reason is that if a user would re-grant a privilege that he + * held through PUBLIC, and later the user is removed, the situation + * is impossible to clean up. + */ + if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC) + ereport(ERROR, + (errcode(ERRCODE_INVALID_GRANT_OPERATION), + errmsg("grant options can only be granted to roles"))); + + aclitem.ai_grantor = grantorId; + + /* + * The asymmetry in the conditions here comes from the spec. In + * GRANT, the grant_option flag signals WITH GRANT OPTION, which means + * to grant both the basic privilege and its grant option. But in + * REVOKE, plain revoke revokes both the basic privilege and its grant + * option, while REVOKE GRANT OPTION revokes only the option. + */ + ACLITEM_SET_PRIVS_GOPTIONS(aclitem, + (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS, + (!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS); + + newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, behavior); + + /* avoid memory leak when there are many grantees */ + pfree(new_acl); + new_acl = newer_acl; + } + + return new_acl; +} + +/* + * Restrict the privileges to what we can actually grant, and emit + * the standards-mandated warning and error messages. + */ +static AclMode +restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs, + AclMode privileges, Oid objectId, Oid grantorId, + ObjectType objtype, const char *objname, + AttrNumber att_number, const char *colname) +{ + AclMode this_privileges; + AclMode whole_mask; + + switch (objtype) + { + case OBJECT_COLUMN: + whole_mask = ACL_ALL_RIGHTS_COLUMN; + break; + case OBJECT_TABLE: + whole_mask = ACL_ALL_RIGHTS_RELATION; + break; + case OBJECT_SEQUENCE: + whole_mask = ACL_ALL_RIGHTS_SEQUENCE; + break; + case OBJECT_DATABASE: + whole_mask = ACL_ALL_RIGHTS_DATABASE; + break; + case OBJECT_FUNCTION: + whole_mask = ACL_ALL_RIGHTS_FUNCTION; + break; + case OBJECT_LANGUAGE: + whole_mask = ACL_ALL_RIGHTS_LANGUAGE; + break; + case OBJECT_LARGEOBJECT: + whole_mask = ACL_ALL_RIGHTS_LARGEOBJECT; + break; + case OBJECT_SCHEMA: + whole_mask = ACL_ALL_RIGHTS_SCHEMA; + break; + case OBJECT_TABLESPACE: + whole_mask = ACL_ALL_RIGHTS_TABLESPACE; + break; + case OBJECT_FDW: + whole_mask = ACL_ALL_RIGHTS_FDW; + break; + case OBJECT_FOREIGN_SERVER: + whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER; + break; + case OBJECT_EVENT_TRIGGER: + elog(ERROR, "grantable rights not supported for event triggers"); + /* not reached, but keep compiler quiet */ + return ACL_NO_RIGHTS; + case OBJECT_TYPE: + whole_mask = ACL_ALL_RIGHTS_TYPE; + break; + default: + elog(ERROR, "unrecognized object type: %d", objtype); + /* not reached, but keep compiler quiet */ + return ACL_NO_RIGHTS; + } + + /* + * If we found no grant options, consider whether to issue a hard error. + * Per spec, having any privilege at all on the object will get you by + * here. + */ + if (avail_goptions == ACL_NO_RIGHTS) + { + if (pg_aclmask(objtype, objectId, att_number, grantorId, + whole_mask | ACL_GRANT_OPTION_FOR(whole_mask), + ACLMASK_ANY) == ACL_NO_RIGHTS) + { + if (objtype == OBJECT_COLUMN && colname) + aclcheck_error_col(ACLCHECK_NO_PRIV, objtype, objname, colname); + else + aclcheck_error(ACLCHECK_NO_PRIV, objtype, objname); + } + } + + /* + * Restrict the operation to what we can actually grant or revoke, and + * issue a warning if appropriate. (For REVOKE this isn't quite what the + * spec says to do: the spec seems to want a warning only if no privilege + * bits actually change in the ACL. In practice that behavior seems much + * too noisy, as well as inconsistent with the GRANT case.) + */ + this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions); + if (is_grant) + { + if (this_privileges == 0) + { + if (objtype == OBJECT_COLUMN && colname) + ereport(WARNING, + (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), + errmsg("no privileges were granted for column \"%s\" of relation \"%s\"", + colname, objname))); + else + ereport(WARNING, + (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), + errmsg("no privileges were granted for \"%s\"", + objname))); + } + else if (!all_privs && this_privileges != privileges) + { + if (objtype == OBJECT_COLUMN && colname) + ereport(WARNING, + (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), + errmsg("not all privileges were granted for column \"%s\" of relation \"%s\"", + colname, objname))); + else + ereport(WARNING, + (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), + errmsg("not all privileges were granted for \"%s\"", + objname))); + } + } + else + { + if (this_privileges == 0) + { + if (objtype == OBJECT_COLUMN && colname) + ereport(WARNING, + (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), + errmsg("no privileges could be revoked for column \"%s\" of relation \"%s\"", + colname, objname))); + else + ereport(WARNING, + (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), + errmsg("no privileges could be revoked for \"%s\"", + objname))); + } + else if (!all_privs && this_privileges != privileges) + { + if (objtype == OBJECT_COLUMN && colname) + ereport(WARNING, + (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), + errmsg("not all privileges could be revoked for column \"%s\" of relation \"%s\"", + colname, objname))); + else + ereport(WARNING, + (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), + errmsg("not all privileges could be revoked for \"%s\"", + objname))); + } + } + + return this_privileges; +} + +/* + * Called to execute the utility commands GRANT and REVOKE + */ +void +ExecuteGrantStmt(GrantStmt *stmt) +{ + InternalGrant istmt; + ListCell *cell; + const char *errormsg; + AclMode all_privileges; + + /* + * Turn the regular GrantStmt into the InternalGrant form. + */ + istmt.is_grant = stmt->is_grant; + istmt.objtype = stmt->objtype; + + /* Collect the OIDs of the target objects */ + switch (stmt->targtype) + { + case ACL_TARGET_OBJECT: + istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects); + break; + case ACL_TARGET_ALL_IN_SCHEMA: + istmt.objects = objectsInSchemaToOids(stmt->objtype, stmt->objects); + break; + /* ACL_TARGET_DEFAULTS should not be seen here */ + default: + elog(ERROR, "unrecognized GrantStmt.targtype: %d", + (int) stmt->targtype); + } + + /* all_privs to be filled below */ + /* privileges to be filled below */ + istmt.col_privs = NIL; /* may get filled below */ + istmt.grantees = NIL; /* filled below */ + istmt.grant_option = stmt->grant_option; + istmt.behavior = stmt->behavior; + + /* + * Convert the RoleSpec list into an Oid list. Note that at this point we + * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream + * there shouldn't be any additional work needed to support this case. + */ + foreach(cell, stmt->grantees) + { + RoleSpec *grantee = (RoleSpec *) lfirst(cell); + Oid grantee_uid; + + switch (grantee->roletype) + { + case ROLESPEC_PUBLIC: + grantee_uid = ACL_ID_PUBLIC; + break; + default: + grantee_uid = get_rolespec_oid(grantee, false); + break; + } + istmt.grantees = lappend_oid(istmt.grantees, grantee_uid); + } + + /* + * Convert stmt->privileges, a list of AccessPriv nodes, into an AclMode + * bitmask. Note: objtype can't be OBJECT_COLUMN. + */ + switch (stmt->objtype) + { + case OBJECT_TABLE: + + /* + * Because this might be a sequence, we test both relation and + * sequence bits, and later do a more limited test when we know + * the object type. + */ + all_privileges = ACL_ALL_RIGHTS_RELATION | ACL_ALL_RIGHTS_SEQUENCE; + errormsg = gettext_noop("invalid privilege type %s for relation"); + break; + case OBJECT_SEQUENCE: + all_privileges = ACL_ALL_RIGHTS_SEQUENCE; + errormsg = gettext_noop("invalid privilege type %s for sequence"); + break; + case OBJECT_DATABASE: + all_privileges = ACL_ALL_RIGHTS_DATABASE; + errormsg = gettext_noop("invalid privilege type %s for database"); + break; + case OBJECT_DOMAIN: + all_privileges = ACL_ALL_RIGHTS_TYPE; + errormsg = gettext_noop("invalid privilege type %s for domain"); + break; + case OBJECT_FUNCTION: + all_privileges = ACL_ALL_RIGHTS_FUNCTION; + errormsg = gettext_noop("invalid privilege type %s for function"); + break; + case OBJECT_LANGUAGE: + all_privileges = ACL_ALL_RIGHTS_LANGUAGE; + errormsg = gettext_noop("invalid privilege type %s for language"); + break; + case OBJECT_LARGEOBJECT: + all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT; + errormsg = gettext_noop("invalid privilege type %s for large object"); + break; + case OBJECT_SCHEMA: + all_privileges = ACL_ALL_RIGHTS_SCHEMA; + errormsg = gettext_noop("invalid privilege type %s for schema"); + break; + case OBJECT_PROCEDURE: + all_privileges = ACL_ALL_RIGHTS_FUNCTION; + errormsg = gettext_noop("invalid privilege type %s for procedure"); + break; + case OBJECT_ROUTINE: + all_privileges = ACL_ALL_RIGHTS_FUNCTION; + errormsg = gettext_noop("invalid privilege type %s for routine"); + break; + case OBJECT_TABLESPACE: + all_privileges = ACL_ALL_RIGHTS_TABLESPACE; + errormsg = gettext_noop("invalid privilege type %s for tablespace"); + break; + case OBJECT_TYPE: + all_privileges = ACL_ALL_RIGHTS_TYPE; + errormsg = gettext_noop("invalid privilege type %s for type"); + break; + case OBJECT_FDW: + all_privileges = ACL_ALL_RIGHTS_FDW; + errormsg = gettext_noop("invalid privilege type %s for foreign-data wrapper"); + break; + case OBJECT_FOREIGN_SERVER: + all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER; + errormsg = gettext_noop("invalid privilege type %s for foreign server"); + break; + default: + elog(ERROR, "unrecognized GrantStmt.objtype: %d", + (int) stmt->objtype); + /* keep compiler quiet */ + all_privileges = ACL_NO_RIGHTS; + errormsg = NULL; + } + + if (stmt->privileges == NIL) + { + istmt.all_privs = true; + + /* + * will be turned into ACL_ALL_RIGHTS_* by the internal routines + * depending on the object type + */ + istmt.privileges = ACL_NO_RIGHTS; + } + else + { + istmt.all_privs = false; + istmt.privileges = ACL_NO_RIGHTS; + + foreach(cell, stmt->privileges) + { + AccessPriv *privnode = (AccessPriv *) lfirst(cell); + AclMode priv; + + /* + * If it's a column-level specification, we just set it aside in + * col_privs for the moment; but insist it's for a relation. + */ + if (privnode->cols) + { + if (stmt->objtype != OBJECT_TABLE) + ereport(ERROR, + (errcode(ERRCODE_INVALID_GRANT_OPERATION), + errmsg("column privileges are only valid for relations"))); + istmt.col_privs = lappend(istmt.col_privs, privnode); + continue; + } + + if (privnode->priv_name == NULL) /* parser mistake? */ + elog(ERROR, "AccessPriv node must specify privilege or columns"); + priv = string_to_privilege(privnode->priv_name); + + if (priv & ~((AclMode) all_privileges)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_GRANT_OPERATION), + errmsg(errormsg, privilege_to_string(priv)))); + + istmt.privileges |= priv; + } + } + + ExecGrantStmt_oids(&istmt); +} + +/* + * ExecGrantStmt_oids + * + * Internal entry point for granting and revoking privileges. + */ +static void +ExecGrantStmt_oids(InternalGrant *istmt) +{ + switch (istmt->objtype) + { + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + ExecGrant_Relation(istmt); + break; + case OBJECT_DATABASE: + ExecGrant_Database(istmt); + break; + case OBJECT_DOMAIN: + case OBJECT_TYPE: + ExecGrant_Type(istmt); + break; + case OBJECT_FDW: + ExecGrant_Fdw(istmt); + break; + case OBJECT_FOREIGN_SERVER: + ExecGrant_ForeignServer(istmt); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + ExecGrant_Function(istmt); + break; + case OBJECT_LANGUAGE: + ExecGrant_Language(istmt); + break; + case OBJECT_LARGEOBJECT: + ExecGrant_Largeobject(istmt); + break; + case OBJECT_SCHEMA: + ExecGrant_Namespace(istmt); + break; + case OBJECT_TABLESPACE: + ExecGrant_Tablespace(istmt); + break; + default: + elog(ERROR, "unrecognized GrantStmt.objtype: %d", + (int) istmt->objtype); + } + + /* + * Pass the info to event triggers about the just-executed GRANT. Note + * that we prefer to do it after actually executing it, because that gives + * the functions a chance to adjust the istmt with privileges actually + * granted. + */ + if (EventTriggerSupportsObjectType(istmt->objtype)) + EventTriggerCollectGrant(istmt); +} + +/* + * objectNamesToOids + * + * Turn a list of object names of a given type into an Oid list. + * + * XXX: This function doesn't take any sort of locks on the objects whose + * names it looks up. In the face of concurrent DDL, we might easily latch + * onto an old version of an object, causing the GRANT or REVOKE statement + * to fail. + */ +static List * +objectNamesToOids(ObjectType objtype, List *objnames) +{ + List *objects = NIL; + ListCell *cell; + + Assert(objnames != NIL); + + switch (objtype) + { + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + foreach(cell, objnames) + { + RangeVar *relvar = (RangeVar *) lfirst(cell); + Oid relOid; + + relOid = RangeVarGetRelid(relvar, NoLock, false); + objects = lappend_oid(objects, relOid); + } + break; + case OBJECT_DATABASE: + foreach(cell, objnames) + { + char *dbname = strVal(lfirst(cell)); + Oid dbid; + + dbid = get_database_oid(dbname, false); + objects = lappend_oid(objects, dbid); + } + break; + case OBJECT_DOMAIN: + case OBJECT_TYPE: + foreach(cell, objnames) + { + List *typname = (List *) lfirst(cell); + Oid oid; + + oid = typenameTypeId(NULL, makeTypeNameFromNameList(typname)); + objects = lappend_oid(objects, oid); + } + break; + case OBJECT_FUNCTION: + foreach(cell, objnames) + { + ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell); + Oid funcid; + + funcid = LookupFuncWithArgs(OBJECT_FUNCTION, func, false); + objects = lappend_oid(objects, funcid); + } + break; + case OBJECT_LANGUAGE: + foreach(cell, objnames) + { + char *langname = strVal(lfirst(cell)); + Oid oid; + + oid = get_language_oid(langname, false); + objects = lappend_oid(objects, oid); + } + break; + case OBJECT_LARGEOBJECT: + foreach(cell, objnames) + { + Oid lobjOid = oidparse(lfirst(cell)); + + if (!LargeObjectExists(lobjOid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("large object %u does not exist", + lobjOid))); + + objects = lappend_oid(objects, lobjOid); + } + break; + case OBJECT_SCHEMA: + foreach(cell, objnames) + { + char *nspname = strVal(lfirst(cell)); + Oid oid; + + oid = get_namespace_oid(nspname, false); + objects = lappend_oid(objects, oid); + } + break; + case OBJECT_PROCEDURE: + foreach(cell, objnames) + { + ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell); + Oid procid; + + procid = LookupFuncWithArgs(OBJECT_PROCEDURE, func, false); + objects = lappend_oid(objects, procid); + } + break; + case OBJECT_ROUTINE: + foreach(cell, objnames) + { + ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell); + Oid routid; + + routid = LookupFuncWithArgs(OBJECT_ROUTINE, func, false); + objects = lappend_oid(objects, routid); + } + break; + case OBJECT_TABLESPACE: + foreach(cell, objnames) + { + char *spcname = strVal(lfirst(cell)); + Oid spcoid; + + spcoid = get_tablespace_oid(spcname, false); + objects = lappend_oid(objects, spcoid); + } + break; + case OBJECT_FDW: + foreach(cell, objnames) + { + char *fdwname = strVal(lfirst(cell)); + Oid fdwid = get_foreign_data_wrapper_oid(fdwname, false); + + objects = lappend_oid(objects, fdwid); + } + break; + case OBJECT_FOREIGN_SERVER: + foreach(cell, objnames) + { + char *srvname = strVal(lfirst(cell)); + Oid srvid = get_foreign_server_oid(srvname, false); + + objects = lappend_oid(objects, srvid); + } + break; + default: + elog(ERROR, "unrecognized GrantStmt.objtype: %d", + (int) objtype); + } + + return objects; +} + +/* + * objectsInSchemaToOids + * + * Find all objects of a given type in specified schemas, and make a list + * of their Oids. We check USAGE privilege on the schemas, but there is + * no privilege checking on the individual objects here. + */ +static List * +objectsInSchemaToOids(ObjectType objtype, List *nspnames) +{ + List *objects = NIL; + ListCell *cell; + + foreach(cell, nspnames) + { + char *nspname = strVal(lfirst(cell)); + Oid namespaceId; + List *objs; + + namespaceId = LookupExplicitNamespace(nspname, false); + + switch (objtype) + { + case OBJECT_TABLE: + objs = getRelationsInNamespace(namespaceId, RELKIND_RELATION); + objects = list_concat(objects, objs); + objs = getRelationsInNamespace(namespaceId, RELKIND_VIEW); + objects = list_concat(objects, objs); + objs = getRelationsInNamespace(namespaceId, RELKIND_MATVIEW); + objects = list_concat(objects, objs); + objs = getRelationsInNamespace(namespaceId, RELKIND_FOREIGN_TABLE); + objects = list_concat(objects, objs); + objs = getRelationsInNamespace(namespaceId, RELKIND_PARTITIONED_TABLE); + objects = list_concat(objects, objs); + break; + case OBJECT_SEQUENCE: + objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE); + objects = list_concat(objects, objs); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + { + ScanKeyData key[2]; + int keycount; + Relation rel; + TableScanDesc scan; + HeapTuple tuple; + + keycount = 0; + ScanKeyInit(&key[keycount++], + Anum_pg_proc_pronamespace, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(namespaceId)); + + if (objtype == OBJECT_FUNCTION) + /* includes aggregates and window functions */ + ScanKeyInit(&key[keycount++], + Anum_pg_proc_prokind, + BTEqualStrategyNumber, F_CHARNE, + CharGetDatum(PROKIND_PROCEDURE)); + else if (objtype == OBJECT_PROCEDURE) + ScanKeyInit(&key[keycount++], + Anum_pg_proc_prokind, + BTEqualStrategyNumber, F_CHAREQ, + CharGetDatum(PROKIND_PROCEDURE)); + + rel = table_open(ProcedureRelationId, AccessShareLock); + scan = table_beginscan_catalog(rel, keycount, key); + + while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) + { + Oid oid = ((Form_pg_proc) GETSTRUCT(tuple))->oid; + + objects = lappend_oid(objects, oid); + } + + table_endscan(scan); + table_close(rel, AccessShareLock); + } + break; + default: + /* should not happen */ + elog(ERROR, "unrecognized GrantStmt.objtype: %d", + (int) objtype); + } + } + + return objects; +} + +/* + * getRelationsInNamespace + * + * Return Oid list of relations in given namespace filtered by relation kind + */ +static List * +getRelationsInNamespace(Oid namespaceId, char relkind) +{ + List *relations = NIL; + ScanKeyData key[2]; + Relation rel; + TableScanDesc scan; + HeapTuple tuple; + + ScanKeyInit(&key[0], + Anum_pg_class_relnamespace, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(namespaceId)); + ScanKeyInit(&key[1], + Anum_pg_class_relkind, + BTEqualStrategyNumber, F_CHAREQ, + CharGetDatum(relkind)); + + rel = table_open(RelationRelationId, AccessShareLock); + scan = table_beginscan_catalog(rel, 2, key); + + while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) + { + Oid oid = ((Form_pg_class) GETSTRUCT(tuple))->oid; + + relations = lappend_oid(relations, oid); + } + + table_endscan(scan); + table_close(rel, AccessShareLock); + + return relations; +} + + +/* + * ALTER DEFAULT PRIVILEGES statement + */ +void +ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *stmt) +{ + GrantStmt *action = stmt->action; + InternalDefaultACL iacls; + ListCell *cell; + List *rolespecs = NIL; + List *nspnames = NIL; + DefElem *drolespecs = NULL; + DefElem *dnspnames = NULL; + AclMode all_privileges; + const char *errormsg; + + /* Deconstruct the "options" part of the statement */ + foreach(cell, stmt->options) + { + DefElem *defel = (DefElem *) lfirst(cell); + + if (strcmp(defel->defname, "schemas") == 0) + { + if (dnspnames) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); + dnspnames = defel; + } + else if (strcmp(defel->defname, "roles") == 0) + { + if (drolespecs) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); + drolespecs = defel; + } + else + elog(ERROR, "option \"%s\" not recognized", defel->defname); + } + + if (dnspnames) + nspnames = (List *) dnspnames->arg; + if (drolespecs) + rolespecs = (List *) drolespecs->arg; + + /* Prepare the InternalDefaultACL representation of the statement */ + /* roleid to be filled below */ + /* nspid to be filled in SetDefaultACLsInSchemas */ + iacls.is_grant = action->is_grant; + iacls.objtype = action->objtype; + /* all_privs to be filled below */ + /* privileges to be filled below */ + iacls.grantees = NIL; /* filled below */ + iacls.grant_option = action->grant_option; + iacls.behavior = action->behavior; + + /* + * Convert the RoleSpec list into an Oid list. Note that at this point we + * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream + * there shouldn't be any additional work needed to support this case. + */ + foreach(cell, action->grantees) + { + RoleSpec *grantee = (RoleSpec *) lfirst(cell); + Oid grantee_uid; + + switch (grantee->roletype) + { + case ROLESPEC_PUBLIC: + grantee_uid = ACL_ID_PUBLIC; + break; + default: + grantee_uid = get_rolespec_oid(grantee, false); + break; + } + iacls.grantees = lappend_oid(iacls.grantees, grantee_uid); + } + + /* + * Convert action->privileges, a list of privilege strings, into an + * AclMode bitmask. + */ + switch (action->objtype) + { + case OBJECT_TABLE: + all_privileges = ACL_ALL_RIGHTS_RELATION; + errormsg = gettext_noop("invalid privilege type %s for relation"); + break; + case OBJECT_SEQUENCE: + all_privileges = ACL_ALL_RIGHTS_SEQUENCE; + errormsg = gettext_noop("invalid privilege type %s for sequence"); + break; + case OBJECT_FUNCTION: + all_privileges = ACL_ALL_RIGHTS_FUNCTION; + errormsg = gettext_noop("invalid privilege type %s for function"); + break; + case OBJECT_PROCEDURE: + all_privileges = ACL_ALL_RIGHTS_FUNCTION; + errormsg = gettext_noop("invalid privilege type %s for procedure"); + break; + case OBJECT_ROUTINE: + all_privileges = ACL_ALL_RIGHTS_FUNCTION; + errormsg = gettext_noop("invalid privilege type %s for routine"); + break; + case OBJECT_TYPE: + all_privileges = ACL_ALL_RIGHTS_TYPE; + errormsg = gettext_noop("invalid privilege type %s for type"); + break; + case OBJECT_SCHEMA: + all_privileges = ACL_ALL_RIGHTS_SCHEMA; + errormsg = gettext_noop("invalid privilege type %s for schema"); + break; + default: + elog(ERROR, "unrecognized GrantStmt.objtype: %d", + (int) action->objtype); + /* keep compiler quiet */ + all_privileges = ACL_NO_RIGHTS; + errormsg = NULL; + } + + if (action->privileges == NIL) + { + iacls.all_privs = true; + + /* + * will be turned into ACL_ALL_RIGHTS_* by the internal routines + * depending on the object type + */ + iacls.privileges = ACL_NO_RIGHTS; + } + else + { + iacls.all_privs = false; + iacls.privileges = ACL_NO_RIGHTS; + + foreach(cell, action->privileges) + { + AccessPriv *privnode = (AccessPriv *) lfirst(cell); + AclMode priv; + + if (privnode->cols) + ereport(ERROR, + (errcode(ERRCODE_INVALID_GRANT_OPERATION), + errmsg("default privileges cannot be set for columns"))); + + if (privnode->priv_name == NULL) /* parser mistake? */ + elog(ERROR, "AccessPriv node must specify privilege"); + priv = string_to_privilege(privnode->priv_name); + + if (priv & ~((AclMode) all_privileges)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_GRANT_OPERATION), + errmsg(errormsg, privilege_to_string(priv)))); + + iacls.privileges |= priv; + } + } + + if (rolespecs == NIL) + { + /* Set permissions for myself */ + iacls.roleid = GetUserId(); + + SetDefaultACLsInSchemas(&iacls, nspnames); + } + else + { + /* Look up the role OIDs and do permissions checks */ + ListCell *rolecell; + + foreach(rolecell, rolespecs) + { + RoleSpec *rolespec = lfirst(rolecell); + + iacls.roleid = get_rolespec_oid(rolespec, false); + + /* + * We insist that calling user be a member of each target role. If + * he has that, he could become that role anyway via SET ROLE, so + * FOR ROLE is just a syntactic convenience and doesn't give any + * special privileges. + */ + check_is_member_of_role(GetUserId(), iacls.roleid); + + SetDefaultACLsInSchemas(&iacls, nspnames); + } + } +} + +/* + * Process ALTER DEFAULT PRIVILEGES for a list of target schemas + * + * All fields of *iacls except nspid were filled already + */ +static void +SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames) +{ + if (nspnames == NIL) + { + /* Set database-wide permissions if no schema was specified */ + iacls->nspid = InvalidOid; + + SetDefaultACL(iacls); + } + else + { + /* Look up the schema OIDs and set permissions for each one */ + ListCell *nspcell; + + foreach(nspcell, nspnames) + { + char *nspname = strVal(lfirst(nspcell)); + + iacls->nspid = get_namespace_oid(nspname, false); + + /* + * We used to insist that the target role have CREATE privileges + * on the schema, since without that it wouldn't be able to create + * an object for which these default privileges would apply. + * However, this check proved to be more confusing than helpful, + * and it also caused certain database states to not be + * dumpable/restorable, since revoking CREATE doesn't cause + * default privileges for the schema to go away. So now, we just + * allow the ALTER; if the user lacks CREATE he'll find out when + * he tries to create an object. + */ + + SetDefaultACL(iacls); + } + } +} + + +/* + * Create or update a pg_default_acl entry + */ +static void +SetDefaultACL(InternalDefaultACL *iacls) +{ + AclMode this_privileges = iacls->privileges; + char objtype; + Relation rel; + HeapTuple tuple; + bool isNew; + Acl *def_acl; + Acl *old_acl; + Acl *new_acl; + HeapTuple newtuple; + Datum values[Natts_pg_default_acl]; + bool nulls[Natts_pg_default_acl]; + bool replaces[Natts_pg_default_acl]; + int noldmembers; + int nnewmembers; + Oid *oldmembers; + Oid *newmembers; + + rel = table_open(DefaultAclRelationId, RowExclusiveLock); + + /* + * The default for a global entry is the hard-wired default ACL for the + * particular object type. The default for non-global entries is an empty + * ACL. This must be so because global entries replace the hard-wired + * defaults, while others are added on. + */ + if (!OidIsValid(iacls->nspid)) + def_acl = acldefault(iacls->objtype, iacls->roleid); + else + def_acl = make_empty_acl(); + + /* + * Convert ACL object type to pg_default_acl object type and handle + * all_privs option + */ + switch (iacls->objtype) + { + case OBJECT_TABLE: + objtype = DEFACLOBJ_RELATION; + if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS) + this_privileges = ACL_ALL_RIGHTS_RELATION; + break; + + case OBJECT_SEQUENCE: + objtype = DEFACLOBJ_SEQUENCE; + if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS) + this_privileges = ACL_ALL_RIGHTS_SEQUENCE; + break; + + case OBJECT_FUNCTION: + objtype = DEFACLOBJ_FUNCTION; + if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS) + this_privileges = ACL_ALL_RIGHTS_FUNCTION; + break; + + case OBJECT_TYPE: + objtype = DEFACLOBJ_TYPE; + if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS) + this_privileges = ACL_ALL_RIGHTS_TYPE; + break; + + case OBJECT_SCHEMA: + if (OidIsValid(iacls->nspid)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_GRANT_OPERATION), + errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS"))); + objtype = DEFACLOBJ_NAMESPACE; + if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS) + this_privileges = ACL_ALL_RIGHTS_SCHEMA; + break; + + default: + elog(ERROR, "unrecognized objtype: %d", + (int) iacls->objtype); + objtype = 0; /* keep compiler quiet */ + break; + } + + /* Search for existing row for this object type in catalog */ + tuple = SearchSysCache3(DEFACLROLENSPOBJ, + ObjectIdGetDatum(iacls->roleid), + ObjectIdGetDatum(iacls->nspid), + CharGetDatum(objtype)); + + if (HeapTupleIsValid(tuple)) + { + Datum aclDatum; + bool isNull; + + aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple, + Anum_pg_default_acl_defaclacl, + &isNull); + if (!isNull) + old_acl = DatumGetAclPCopy(aclDatum); + else + old_acl = NULL; /* this case shouldn't happen, probably */ + isNew = false; + } + else + { + old_acl = NULL; + isNew = true; + } + + if (old_acl != NULL) + { + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. Collect data before + * merge_acl_with_grant throws away old_acl. + */ + noldmembers = aclmembers(old_acl, &oldmembers); + } + else + { + /* If no or null entry, start with the default ACL value */ + old_acl = aclcopy(def_acl); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } + + /* + * Generate new ACL. Grantor of rights is always the same as the target + * role. + */ + new_acl = merge_acl_with_grant(old_acl, + iacls->is_grant, + iacls->grant_option, + iacls->behavior, + iacls->grantees, + this_privileges, + iacls->roleid, + iacls->roleid); + + /* + * If the result is the same as the default value, we do not need an + * explicit pg_default_acl entry, and should in fact remove the entry if + * it exists. Must sort both arrays to compare properly. + */ + aclitemsort(new_acl); + aclitemsort(def_acl); + if (aclequal(new_acl, def_acl)) + { + /* delete old entry, if indeed there is one */ + if (!isNew) + { + ObjectAddress myself; + + /* + * The dependency machinery will take care of removing all + * associated dependency entries. We use DROP_RESTRICT since + * there shouldn't be anything depending on this entry. + */ + myself.classId = DefaultAclRelationId; + myself.objectId = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid; + myself.objectSubId = 0; + + performDeletion(&myself, DROP_RESTRICT, 0); + } + } + else + { + Oid defAclOid; + + /* Prepare to insert or update pg_default_acl entry */ + MemSet(values, 0, sizeof(values)); + MemSet(nulls, false, sizeof(nulls)); + MemSet(replaces, false, sizeof(replaces)); + + if (isNew) + { + /* insert new entry */ + defAclOid = GetNewOidWithIndex(rel, DefaultAclOidIndexId, + Anum_pg_default_acl_oid); + values[Anum_pg_default_acl_oid - 1] = ObjectIdGetDatum(defAclOid); + values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid); + values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid); + values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype); + values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl); + + newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls); + CatalogTupleInsert(rel, newtuple); + } + else + { + defAclOid = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid; + + /* update existing entry */ + values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl); + replaces[Anum_pg_default_acl_defaclacl - 1] = true; + + newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel), + values, nulls, replaces); + CatalogTupleUpdate(rel, &newtuple->t_self, newtuple); + } + + /* these dependencies don't change in an update */ + if (isNew) + { + /* dependency on role */ + recordDependencyOnOwner(DefaultAclRelationId, defAclOid, + iacls->roleid); + + /* dependency on namespace */ + if (OidIsValid(iacls->nspid)) + { + ObjectAddress myself, + referenced; + + myself.classId = DefaultAclRelationId; + myself.objectId = defAclOid; + myself.objectSubId = 0; + + referenced.classId = NamespaceRelationId; + referenced.objectId = iacls->nspid; + referenced.objectSubId = 0; + + recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); + } + } + + /* + * Update the shared dependency ACL info + */ + nnewmembers = aclmembers(new_acl, &newmembers); + + updateAclDependencies(DefaultAclRelationId, + defAclOid, 0, + iacls->roleid, + noldmembers, oldmembers, + nnewmembers, newmembers); + + if (isNew) + InvokeObjectPostCreateHook(DefaultAclRelationId, defAclOid, 0); + else + InvokeObjectPostAlterHook(DefaultAclRelationId, defAclOid, 0); + } + + if (HeapTupleIsValid(tuple)) + ReleaseSysCache(tuple); + + table_close(rel, RowExclusiveLock); + + /* prevent error when processing duplicate objects */ + CommandCounterIncrement(); +} + + +/* + * RemoveRoleFromObjectACL + * + * Used by shdepDropOwned to remove mentions of a role in ACLs + */ +void +RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid) +{ + if (classid == DefaultAclRelationId) + { + InternalDefaultACL iacls; + Form_pg_default_acl pg_default_acl_tuple; + Relation rel; + ScanKeyData skey[1]; + SysScanDesc scan; + HeapTuple tuple; + + /* first fetch info needed by SetDefaultACL */ + rel = table_open(DefaultAclRelationId, AccessShareLock); + + ScanKeyInit(&skey[0], + Anum_pg_default_acl_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objid)); + + scan = systable_beginscan(rel, DefaultAclOidIndexId, true, + NULL, 1, skey); + + tuple = systable_getnext(scan); + + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "could not find tuple for default ACL %u", objid); + + pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple); + + iacls.roleid = pg_default_acl_tuple->defaclrole; + iacls.nspid = pg_default_acl_tuple->defaclnamespace; + + switch (pg_default_acl_tuple->defaclobjtype) + { + case DEFACLOBJ_RELATION: + iacls.objtype = OBJECT_TABLE; + break; + case DEFACLOBJ_SEQUENCE: + iacls.objtype = OBJECT_SEQUENCE; + break; + case DEFACLOBJ_FUNCTION: + iacls.objtype = OBJECT_FUNCTION; + break; + case DEFACLOBJ_TYPE: + iacls.objtype = OBJECT_TYPE; + break; + case DEFACLOBJ_NAMESPACE: + iacls.objtype = OBJECT_SCHEMA; + break; + default: + /* Shouldn't get here */ + elog(ERROR, "unexpected default ACL type: %d", + (int) pg_default_acl_tuple->defaclobjtype); + break; + } + + systable_endscan(scan); + table_close(rel, AccessShareLock); + + iacls.is_grant = false; + iacls.all_privs = true; + iacls.privileges = ACL_NO_RIGHTS; + iacls.grantees = list_make1_oid(roleid); + iacls.grant_option = false; + iacls.behavior = DROP_CASCADE; + + /* Do it */ + SetDefaultACL(&iacls); + } + else + { + InternalGrant istmt; + + switch (classid) + { + case RelationRelationId: + /* it's OK to use TABLE for a sequence */ + istmt.objtype = OBJECT_TABLE; + break; + case DatabaseRelationId: + istmt.objtype = OBJECT_DATABASE; + break; + case TypeRelationId: + istmt.objtype = OBJECT_TYPE; + break; + case ProcedureRelationId: + istmt.objtype = OBJECT_ROUTINE; + break; + case LanguageRelationId: + istmt.objtype = OBJECT_LANGUAGE; + break; + case LargeObjectRelationId: + istmt.objtype = OBJECT_LARGEOBJECT; + break; + case NamespaceRelationId: + istmt.objtype = OBJECT_SCHEMA; + break; + case TableSpaceRelationId: + istmt.objtype = OBJECT_TABLESPACE; + break; + case ForeignServerRelationId: + istmt.objtype = OBJECT_FOREIGN_SERVER; + break; + case ForeignDataWrapperRelationId: + istmt.objtype = OBJECT_FDW; + break; + default: + elog(ERROR, "unexpected object class %u", classid); + break; + } + istmt.is_grant = false; + istmt.objects = list_make1_oid(objid); + istmt.all_privs = true; + istmt.privileges = ACL_NO_RIGHTS; + istmt.col_privs = NIL; + istmt.grantees = list_make1_oid(roleid); + istmt.grant_option = false; + istmt.behavior = DROP_CASCADE; + + ExecGrantStmt_oids(&istmt); + } +} + + +/* + * Remove a pg_default_acl entry + */ +void +RemoveDefaultACLById(Oid defaclOid) +{ + Relation rel; + ScanKeyData skey[1]; + SysScanDesc scan; + HeapTuple tuple; + + rel = table_open(DefaultAclRelationId, RowExclusiveLock); + + ScanKeyInit(&skey[0], + Anum_pg_default_acl_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(defaclOid)); + + scan = systable_beginscan(rel, DefaultAclOidIndexId, true, + NULL, 1, skey); + + tuple = systable_getnext(scan); + + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "could not find tuple for default ACL %u", defaclOid); + + CatalogTupleDelete(rel, &tuple->t_self); + + systable_endscan(scan); + table_close(rel, RowExclusiveLock); +} + + +/* + * expand_col_privileges + * + * OR the specified privilege(s) into per-column array entries for each + * specified attribute. The per-column array is indexed starting at + * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute. + */ +static void +expand_col_privileges(List *colnames, Oid table_oid, + AclMode this_privileges, + AclMode *col_privileges, + int num_col_privileges) +{ + ListCell *cell; + + foreach(cell, colnames) + { + char *colname = strVal(lfirst(cell)); + AttrNumber attnum; + + attnum = get_attnum(table_oid, colname); + if (attnum == InvalidAttrNumber) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + colname, get_rel_name(table_oid)))); + attnum -= FirstLowInvalidHeapAttributeNumber; + if (attnum <= 0 || attnum >= num_col_privileges) + elog(ERROR, "column number out of range"); /* safety check */ + col_privileges[attnum] |= this_privileges; + } +} + +/* + * expand_all_col_privileges + * + * OR the specified privilege(s) into per-column array entries for each valid + * attribute of a relation. The per-column array is indexed starting at + * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute. + */ +static void +expand_all_col_privileges(Oid table_oid, Form_pg_class classForm, + AclMode this_privileges, + AclMode *col_privileges, + int num_col_privileges) +{ + AttrNumber curr_att; + + Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges); + for (curr_att = FirstLowInvalidHeapAttributeNumber + 1; + curr_att <= classForm->relnatts; + curr_att++) + { + HeapTuple attTuple; + bool isdropped; + + if (curr_att == InvalidAttrNumber) + continue; + + /* Views don't have any system columns at all */ + if (classForm->relkind == RELKIND_VIEW && curr_att < 0) + continue; + + attTuple = SearchSysCache2(ATTNUM, + ObjectIdGetDatum(table_oid), + Int16GetDatum(curr_att)); + if (!HeapTupleIsValid(attTuple)) + elog(ERROR, "cache lookup failed for attribute %d of relation %u", + curr_att, table_oid); + + isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped; + + ReleaseSysCache(attTuple); + + /* ignore dropped columns */ + if (isdropped) + continue; + + col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges; + } +} + +/* + * This processes attributes, but expects to be called from + * ExecGrant_Relation, not directly from ExecuteGrantStmt. + */ +static void +ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname, + AttrNumber attnum, Oid ownerId, AclMode col_privileges, + Relation attRelation, const Acl *old_rel_acl) +{ + HeapTuple attr_tuple; + Form_pg_attribute pg_attribute_tuple; + Acl *old_acl; + Acl *new_acl; + Acl *merged_acl; + Datum aclDatum; + bool isNull; + Oid grantorId; + AclMode avail_goptions; + bool need_update; + HeapTuple newtuple; + Datum values[Natts_pg_attribute]; + bool nulls[Natts_pg_attribute]; + bool replaces[Natts_pg_attribute]; + int noldmembers; + int nnewmembers; + Oid *oldmembers; + Oid *newmembers; + + attr_tuple = SearchSysCache2(ATTNUM, + ObjectIdGetDatum(relOid), + Int16GetDatum(attnum)); + if (!HeapTupleIsValid(attr_tuple)) + elog(ERROR, "cache lookup failed for attribute %d of relation %u", + attnum, relOid); + pg_attribute_tuple = (Form_pg_attribute) GETSTRUCT(attr_tuple); + + /* + * Get working copy of existing ACL. If there's no ACL, substitute the + * proper default. + */ + aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl, + &isNull); + if (isNull) + { + old_acl = acldefault(OBJECT_COLUMN, ownerId); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } + else + { + old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } + + /* + * In select_best_grantor we should consider existing table-level ACL bits + * as well as the per-column ACL. Build a new ACL that is their + * concatenation. (This is a bit cheap and dirty compared to merging them + * properly with no duplications, but it's all we need here.) + */ + merged_acl = aclconcat(old_rel_acl, old_acl); + + /* Determine ID to do the grant as, and available grant options */ + select_best_grantor(GetUserId(), col_privileges, + merged_acl, ownerId, + &grantorId, &avail_goptions); + + pfree(merged_acl); + + /* + * Restrict the privileges to what we can actually grant, and emit the + * standards-mandated warning and error messages. Note: we don't track + * whether the user actually used the ALL PRIVILEGES(columns) syntax for + * each column; we just approximate it by whether all the possible + * privileges are specified now. Since the all_privs flag only determines + * whether a warning is issued, this seems close enough. + */ + col_privileges = + restrict_and_check_grant(istmt->is_grant, avail_goptions, + (col_privileges == ACL_ALL_RIGHTS_COLUMN), + col_privileges, + relOid, grantorId, OBJECT_COLUMN, + relname, attnum, + NameStr(pg_attribute_tuple->attname)); + + /* + * Generate new ACL. + */ + new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, + istmt->grant_option, + istmt->behavior, istmt->grantees, + col_privileges, grantorId, + ownerId); + + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. + */ + nnewmembers = aclmembers(new_acl, &newmembers); + + /* finished building new ACL value, now insert it */ + MemSet(values, 0, sizeof(values)); + MemSet(nulls, false, sizeof(nulls)); + MemSet(replaces, false, sizeof(replaces)); + + /* + * If the updated ACL is empty, we can set attacl to null, and maybe even + * avoid an update of the pg_attribute row. This is worth testing because + * we'll come through here multiple times for any relation-level REVOKE, + * even if there were never any column GRANTs. Note we are assuming that + * the "default" ACL state for columns is empty. + */ + if (ACL_NUM(new_acl) > 0) + { + values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl); + need_update = true; + } + else + { + nulls[Anum_pg_attribute_attacl - 1] = true; + need_update = !isNull; + } + replaces[Anum_pg_attribute_attacl - 1] = true; + + if (need_update) + { + newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation), + values, nulls, replaces); + + CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple); + + /* Update initial privileges for extensions */ + recordExtensionInitPriv(relOid, RelationRelationId, attnum, + ACL_NUM(new_acl) > 0 ? new_acl : NULL); + + /* Update the shared dependency ACL info */ + updateAclDependencies(RelationRelationId, relOid, attnum, + ownerId, + noldmembers, oldmembers, + nnewmembers, newmembers); + } + + pfree(new_acl); + + ReleaseSysCache(attr_tuple); +} + +/* + * This processes both sequences and non-sequences. + */ +static void +ExecGrant_Relation(InternalGrant *istmt) +{ + Relation relation; + Relation attRelation; + ListCell *cell; + + relation = table_open(RelationRelationId, RowExclusiveLock); + attRelation = table_open(AttributeRelationId, RowExclusiveLock); + + foreach(cell, istmt->objects) + { + Oid relOid = lfirst_oid(cell); + Datum aclDatum; + Form_pg_class pg_class_tuple; + bool isNull; + AclMode this_privileges; + AclMode *col_privileges; + int num_col_privileges; + bool have_col_privileges; + Acl *old_acl; + Acl *old_rel_acl; + int noldmembers; + Oid *oldmembers; + Oid ownerId; + HeapTuple tuple; + ListCell *cell_colprivs; + + tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", relOid); + pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple); + + /* Not sensible to grant on an index */ + if (pg_class_tuple->relkind == RELKIND_INDEX || + pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is an index", + NameStr(pg_class_tuple->relname)))); + + /* Composite types aren't tables either */ + if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is a composite type", + NameStr(pg_class_tuple->relname)))); + + /* Used GRANT SEQUENCE on a non-sequence? */ + if (istmt->objtype == OBJECT_SEQUENCE && + pg_class_tuple->relkind != RELKIND_SEQUENCE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not a sequence", + NameStr(pg_class_tuple->relname)))); + + /* Adjust the default permissions based on object type */ + if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) + { + if (pg_class_tuple->relkind == RELKIND_SEQUENCE) + this_privileges = ACL_ALL_RIGHTS_SEQUENCE; + else + this_privileges = ACL_ALL_RIGHTS_RELATION; + } + else + this_privileges = istmt->privileges; + + /* + * The GRANT TABLE syntax can be used for sequences and non-sequences, + * so we have to look at the relkind to determine the supported + * permissions. The OR of table and sequence permissions were already + * checked. + */ + if (istmt->objtype == OBJECT_TABLE) + { + if (pg_class_tuple->relkind == RELKIND_SEQUENCE) + { + /* + * For backward compatibility, just throw a warning for + * invalid sequence permissions when using the non-sequence + * GRANT syntax. + */ + if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE)) + { + /* + * Mention the object name because the user needs to know + * which operations succeeded. This is required because + * WARNING allows the command to continue. + */ + ereport(WARNING, + (errcode(ERRCODE_INVALID_GRANT_OPERATION), + errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges", + NameStr(pg_class_tuple->relname)))); + this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE; + } + } + else + { + if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION)) + { + /* + * USAGE is the only permission supported by sequences but + * not by non-sequences. Don't mention the object name + * because we didn't in the combined TABLE | SEQUENCE + * check. + */ + ereport(ERROR, + (errcode(ERRCODE_INVALID_GRANT_OPERATION), + errmsg("invalid privilege type %s for table", + "USAGE"))); + } + } + } + + /* + * Set up array in which we'll accumulate any column privilege bits + * that need modification. The array is indexed such that entry [0] + * corresponds to FirstLowInvalidHeapAttributeNumber. + */ + num_col_privileges = pg_class_tuple->relnatts - FirstLowInvalidHeapAttributeNumber + 1; + col_privileges = (AclMode *) palloc0(num_col_privileges * sizeof(AclMode)); + have_col_privileges = false; + + /* + * If we are revoking relation privileges that are also column + * privileges, we must implicitly revoke them from each column too, + * per SQL spec. (We don't need to implicitly add column privileges + * during GRANT because the permissions-checking code always checks + * both relation and per-column privileges.) + */ + if (!istmt->is_grant && + (this_privileges & ACL_ALL_RIGHTS_COLUMN) != 0) + { + expand_all_col_privileges(relOid, pg_class_tuple, + this_privileges & ACL_ALL_RIGHTS_COLUMN, + col_privileges, + num_col_privileges); + have_col_privileges = true; + } + + /* + * Get owner ID and working copy of existing ACL. If there's no ACL, + * substitute the proper default. + */ + ownerId = pg_class_tuple->relowner; + aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl, + &isNull); + if (isNull) + { + switch (pg_class_tuple->relkind) + { + case RELKIND_SEQUENCE: + old_acl = acldefault(OBJECT_SEQUENCE, ownerId); + break; + default: + old_acl = acldefault(OBJECT_TABLE, ownerId); + break; + } + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } + else + { + old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } + + /* Need an extra copy of original rel ACL for column handling */ + old_rel_acl = aclcopy(old_acl); + + /* + * Handle relation-level privileges, if any were specified + */ + if (this_privileges != ACL_NO_RIGHTS) + { + AclMode avail_goptions; + Acl *new_acl; + Oid grantorId; + HeapTuple newtuple; + Datum values[Natts_pg_class]; + bool nulls[Natts_pg_class]; + bool replaces[Natts_pg_class]; + int nnewmembers; + Oid *newmembers; + ObjectType objtype; + + /* Determine ID to do the grant as, and available grant options */ + select_best_grantor(GetUserId(), this_privileges, + old_acl, ownerId, + &grantorId, &avail_goptions); + + switch (pg_class_tuple->relkind) + { + case RELKIND_SEQUENCE: + objtype = OBJECT_SEQUENCE; + break; + default: + objtype = OBJECT_TABLE; + break; + } + + /* + * Restrict the privileges to what we can actually grant, and emit + * the standards-mandated warning and error messages. + */ + this_privileges = + restrict_and_check_grant(istmt->is_grant, avail_goptions, + istmt->all_privs, this_privileges, + relOid, grantorId, objtype, + NameStr(pg_class_tuple->relname), + 0, NULL); + + /* + * Generate new ACL. + */ + new_acl = merge_acl_with_grant(old_acl, + istmt->is_grant, + istmt->grant_option, + istmt->behavior, + istmt->grantees, + this_privileges, + grantorId, + ownerId); + + /* + * We need the members of both old and new ACLs so we can correct + * the shared dependency information. + */ + nnewmembers = aclmembers(new_acl, &newmembers); + + /* finished building new ACL value, now insert it */ + MemSet(values, 0, sizeof(values)); + MemSet(nulls, false, sizeof(nulls)); + MemSet(replaces, false, sizeof(replaces)); + + replaces[Anum_pg_class_relacl - 1] = true; + values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl); + + newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), + values, nulls, replaces); + + CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); + + /* Update initial privileges for extensions */ + recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl); + + /* Update the shared dependency ACL info */ + updateAclDependencies(RelationRelationId, relOid, 0, + ownerId, + noldmembers, oldmembers, + nnewmembers, newmembers); + + pfree(new_acl); + } + + /* + * Handle column-level privileges, if any were specified or implied. + * We first expand the user-specified column privileges into the + * array, and then iterate over all nonempty array entries. + */ + foreach(cell_colprivs, istmt->col_privs) + { + AccessPriv *col_privs = (AccessPriv *) lfirst(cell_colprivs); + + if (col_privs->priv_name == NULL) + this_privileges = ACL_ALL_RIGHTS_COLUMN; + else + this_privileges = string_to_privilege(col_privs->priv_name); + + if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_COLUMN)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_GRANT_OPERATION), + errmsg("invalid privilege type %s for column", + privilege_to_string(this_privileges)))); + + if (pg_class_tuple->relkind == RELKIND_SEQUENCE && + this_privileges & ~((AclMode) ACL_SELECT)) + { + /* + * The only column privilege allowed on sequences is SELECT. + * This is a warning not error because we do it that way for + * relation-level privileges. + */ + ereport(WARNING, + (errcode(ERRCODE_INVALID_GRANT_OPERATION), + errmsg("sequence \"%s\" only supports SELECT column privileges", + NameStr(pg_class_tuple->relname)))); + + this_privileges &= (AclMode) ACL_SELECT; + } + + expand_col_privileges(col_privs->cols, relOid, + this_privileges, + col_privileges, + num_col_privileges); + have_col_privileges = true; + } + + if (have_col_privileges) + { + AttrNumber i; + + for (i = 0; i < num_col_privileges; i++) + { + if (col_privileges[i] == ACL_NO_RIGHTS) + continue; + ExecGrant_Attribute(istmt, + relOid, + NameStr(pg_class_tuple->relname), + i + FirstLowInvalidHeapAttributeNumber, + ownerId, + col_privileges[i], + attRelation, + old_rel_acl); + } + } + + pfree(old_rel_acl); + pfree(col_privileges); + + ReleaseSysCache(tuple); + + /* prevent error when processing duplicate objects */ + CommandCounterIncrement(); + } + + table_close(attRelation, RowExclusiveLock); + table_close(relation, RowExclusiveLock); +} + +static void +ExecGrant_Database(InternalGrant *istmt) +{ + Relation relation; + ListCell *cell; + + if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) + istmt->privileges = ACL_ALL_RIGHTS_DATABASE; + + relation = table_open(DatabaseRelationId, RowExclusiveLock); + + foreach(cell, istmt->objects) + { + Oid datId = lfirst_oid(cell); + Form_pg_database pg_database_tuple; + Datum aclDatum; + bool isNull; + AclMode avail_goptions; + AclMode this_privileges; + Acl *old_acl; + Acl *new_acl; + Oid grantorId; + Oid ownerId; + HeapTuple newtuple; + Datum values[Natts_pg_database]; + bool nulls[Natts_pg_database]; + bool replaces[Natts_pg_database]; + int noldmembers; + int nnewmembers; + Oid *oldmembers; + Oid *newmembers; + HeapTuple tuple; + + tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(datId)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for database %u", datId); + + pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple); + + /* + * Get owner ID and working copy of existing ACL. If there's no ACL, + * substitute the proper default. + */ + ownerId = pg_database_tuple->datdba; + aclDatum = heap_getattr(tuple, Anum_pg_database_datacl, + RelationGetDescr(relation), &isNull); + if (isNull) + { + old_acl = acldefault(OBJECT_DATABASE, ownerId); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } + else + { + old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } + + /* Determine ID to do the grant as, and available grant options */ + select_best_grantor(GetUserId(), istmt->privileges, + old_acl, ownerId, + &grantorId, &avail_goptions); + + /* + * Restrict the privileges to what we can actually grant, and emit the + * standards-mandated warning and error messages. + */ + this_privileges = + restrict_and_check_grant(istmt->is_grant, avail_goptions, + istmt->all_privs, istmt->privileges, + datId, grantorId, OBJECT_DATABASE, + NameStr(pg_database_tuple->datname), + 0, NULL); + + /* + * Generate new ACL. + */ + new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, + istmt->grant_option, istmt->behavior, + istmt->grantees, this_privileges, + grantorId, ownerId); + + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. + */ + nnewmembers = aclmembers(new_acl, &newmembers); + + /* finished building new ACL value, now insert it */ + MemSet(values, 0, sizeof(values)); + MemSet(nulls, false, sizeof(nulls)); + MemSet(replaces, false, sizeof(replaces)); + + replaces[Anum_pg_database_datacl - 1] = true; + values[Anum_pg_database_datacl - 1] = PointerGetDatum(new_acl); + + newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, + nulls, replaces); + + CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); + + /* Update the shared dependency ACL info */ + updateAclDependencies(DatabaseRelationId, pg_database_tuple->oid, 0, + ownerId, + noldmembers, oldmembers, + nnewmembers, newmembers); + + ReleaseSysCache(tuple); + + pfree(new_acl); + + /* prevent error when processing duplicate objects */ + CommandCounterIncrement(); + } + + table_close(relation, RowExclusiveLock); +} + +static void +ExecGrant_Fdw(InternalGrant *istmt) +{ + Relation relation; + ListCell *cell; + + if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) + istmt->privileges = ACL_ALL_RIGHTS_FDW; + + relation = table_open(ForeignDataWrapperRelationId, RowExclusiveLock); + + foreach(cell, istmt->objects) + { + Oid fdwid = lfirst_oid(cell); + Form_pg_foreign_data_wrapper pg_fdw_tuple; + Datum aclDatum; + bool isNull; + AclMode avail_goptions; + AclMode this_privileges; + Acl *old_acl; + Acl *new_acl; + Oid grantorId; + Oid ownerId; + HeapTuple tuple; + HeapTuple newtuple; + Datum values[Natts_pg_foreign_data_wrapper]; + bool nulls[Natts_pg_foreign_data_wrapper]; + bool replaces[Natts_pg_foreign_data_wrapper]; + int noldmembers; + int nnewmembers; + Oid *oldmembers; + Oid *newmembers; + + tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID, + ObjectIdGetDatum(fdwid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for foreign-data wrapper %u", fdwid); + + pg_fdw_tuple = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple); + + /* + * Get owner ID and working copy of existing ACL. If there's no ACL, + * substitute the proper default. + */ + ownerId = pg_fdw_tuple->fdwowner; + aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple, + Anum_pg_foreign_data_wrapper_fdwacl, + &isNull); + if (isNull) + { + old_acl = acldefault(OBJECT_FDW, ownerId); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } + else + { + old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } + + /* Determine ID to do the grant as, and available grant options */ + select_best_grantor(GetUserId(), istmt->privileges, + old_acl, ownerId, + &grantorId, &avail_goptions); + + /* + * Restrict the privileges to what we can actually grant, and emit the + * standards-mandated warning and error messages. + */ + this_privileges = + restrict_and_check_grant(istmt->is_grant, avail_goptions, + istmt->all_privs, istmt->privileges, + fdwid, grantorId, OBJECT_FDW, + NameStr(pg_fdw_tuple->fdwname), + 0, NULL); + + /* + * Generate new ACL. + */ + new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, + istmt->grant_option, istmt->behavior, + istmt->grantees, this_privileges, + grantorId, ownerId); + + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. + */ + nnewmembers = aclmembers(new_acl, &newmembers); + + /* finished building new ACL value, now insert it */ + MemSet(values, 0, sizeof(values)); + MemSet(nulls, false, sizeof(nulls)); + MemSet(replaces, false, sizeof(replaces)); + + replaces[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true; + values[Anum_pg_foreign_data_wrapper_fdwacl - 1] = PointerGetDatum(new_acl); + + newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, + nulls, replaces); + + CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); + + /* Update initial privileges for extensions */ + recordExtensionInitPriv(fdwid, ForeignDataWrapperRelationId, 0, + new_acl); + + /* Update the shared dependency ACL info */ + updateAclDependencies(ForeignDataWrapperRelationId, + pg_fdw_tuple->oid, 0, + ownerId, + noldmembers, oldmembers, + nnewmembers, newmembers); + + ReleaseSysCache(tuple); + + pfree(new_acl); + + /* prevent error when processing duplicate objects */ + CommandCounterIncrement(); + } + + table_close(relation, RowExclusiveLock); +} + +static void +ExecGrant_ForeignServer(InternalGrant *istmt) +{ + Relation relation; + ListCell *cell; + + if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) + istmt->privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER; + + relation = table_open(ForeignServerRelationId, RowExclusiveLock); + + foreach(cell, istmt->objects) + { + Oid srvid = lfirst_oid(cell); + Form_pg_foreign_server pg_server_tuple; + Datum aclDatum; + bool isNull; + AclMode avail_goptions; + AclMode this_privileges; + Acl *old_acl; + Acl *new_acl; + Oid grantorId; + Oid ownerId; + HeapTuple tuple; + HeapTuple newtuple; + Datum values[Natts_pg_foreign_server]; + bool nulls[Natts_pg_foreign_server]; + bool replaces[Natts_pg_foreign_server]; + int noldmembers; + int nnewmembers; + Oid *oldmembers; + Oid *newmembers; + + tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srvid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for foreign server %u", srvid); + + pg_server_tuple = (Form_pg_foreign_server) GETSTRUCT(tuple); + + /* + * Get owner ID and working copy of existing ACL. If there's no ACL, + * substitute the proper default. + */ + ownerId = pg_server_tuple->srvowner; + aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple, + Anum_pg_foreign_server_srvacl, + &isNull); + if (isNull) + { + old_acl = acldefault(OBJECT_FOREIGN_SERVER, ownerId); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } + else + { + old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } + + /* Determine ID to do the grant as, and available grant options */ + select_best_grantor(GetUserId(), istmt->privileges, + old_acl, ownerId, + &grantorId, &avail_goptions); + + /* + * Restrict the privileges to what we can actually grant, and emit the + * standards-mandated warning and error messages. + */ + this_privileges = + restrict_and_check_grant(istmt->is_grant, avail_goptions, + istmt->all_privs, istmt->privileges, + srvid, grantorId, OBJECT_FOREIGN_SERVER, + NameStr(pg_server_tuple->srvname), + 0, NULL); + + /* + * Generate new ACL. + */ + new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, + istmt->grant_option, istmt->behavior, + istmt->grantees, this_privileges, + grantorId, ownerId); + + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. + */ + nnewmembers = aclmembers(new_acl, &newmembers); + + /* finished building new ACL value, now insert it */ + MemSet(values, 0, sizeof(values)); + MemSet(nulls, false, sizeof(nulls)); + MemSet(replaces, false, sizeof(replaces)); + + replaces[Anum_pg_foreign_server_srvacl - 1] = true; + values[Anum_pg_foreign_server_srvacl - 1] = PointerGetDatum(new_acl); + + newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, + nulls, replaces); + + CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); + + /* Update initial privileges for extensions */ + recordExtensionInitPriv(srvid, ForeignServerRelationId, 0, new_acl); + + /* Update the shared dependency ACL info */ + updateAclDependencies(ForeignServerRelationId, + pg_server_tuple->oid, 0, + ownerId, + noldmembers, oldmembers, + nnewmembers, newmembers); + + ReleaseSysCache(tuple); + + pfree(new_acl); + + /* prevent error when processing duplicate objects */ + CommandCounterIncrement(); + } + + table_close(relation, RowExclusiveLock); +} + +static void +ExecGrant_Function(InternalGrant *istmt) +{ + Relation relation; + ListCell *cell; + + if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) + istmt->privileges = ACL_ALL_RIGHTS_FUNCTION; + + relation = table_open(ProcedureRelationId, RowExclusiveLock); + + foreach(cell, istmt->objects) + { + Oid funcId = lfirst_oid(cell); + Form_pg_proc pg_proc_tuple; + Datum aclDatum; + bool isNull; + AclMode avail_goptions; + AclMode this_privileges; + Acl *old_acl; + Acl *new_acl; + Oid grantorId; + Oid ownerId; + HeapTuple tuple; + HeapTuple newtuple; + Datum values[Natts_pg_proc]; + bool nulls[Natts_pg_proc]; + bool replaces[Natts_pg_proc]; + int noldmembers; + int nnewmembers; + Oid *oldmembers; + Oid *newmembers; + + tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcId)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for function %u", funcId); + + pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple); + + /* + * Get owner ID and working copy of existing ACL. If there's no ACL, + * substitute the proper default. + */ + ownerId = pg_proc_tuple->proowner; + aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl, + &isNull); + if (isNull) + { + old_acl = acldefault(OBJECT_FUNCTION, ownerId); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } + else + { + old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } + + /* Determine ID to do the grant as, and available grant options */ + select_best_grantor(GetUserId(), istmt->privileges, + old_acl, ownerId, + &grantorId, &avail_goptions); + + /* + * Restrict the privileges to what we can actually grant, and emit the + * standards-mandated warning and error messages. + */ + this_privileges = + restrict_and_check_grant(istmt->is_grant, avail_goptions, + istmt->all_privs, istmt->privileges, + funcId, grantorId, OBJECT_FUNCTION, + NameStr(pg_proc_tuple->proname), + 0, NULL); + + /* + * Generate new ACL. + */ + new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, + istmt->grant_option, istmt->behavior, + istmt->grantees, this_privileges, + grantorId, ownerId); + + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. + */ + nnewmembers = aclmembers(new_acl, &newmembers); + + /* finished building new ACL value, now insert it */ + MemSet(values, 0, sizeof(values)); + MemSet(nulls, false, sizeof(nulls)); + MemSet(replaces, false, sizeof(replaces)); + + replaces[Anum_pg_proc_proacl - 1] = true; + values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl); + + newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, + nulls, replaces); + + CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); + + /* Update initial privileges for extensions */ + recordExtensionInitPriv(funcId, ProcedureRelationId, 0, new_acl); + + /* Update the shared dependency ACL info */ + updateAclDependencies(ProcedureRelationId, funcId, 0, + ownerId, + noldmembers, oldmembers, + nnewmembers, newmembers); + + ReleaseSysCache(tuple); + + pfree(new_acl); + + /* prevent error when processing duplicate objects */ + CommandCounterIncrement(); + } + + table_close(relation, RowExclusiveLock); +} + +static void +ExecGrant_Language(InternalGrant *istmt) +{ + Relation relation; + ListCell *cell; + + if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) + istmt->privileges = ACL_ALL_RIGHTS_LANGUAGE; + + relation = table_open(LanguageRelationId, RowExclusiveLock); + + foreach(cell, istmt->objects) + { + Oid langId = lfirst_oid(cell); + Form_pg_language pg_language_tuple; + Datum aclDatum; + bool isNull; + AclMode avail_goptions; + AclMode this_privileges; + Acl *old_acl; + Acl *new_acl; + Oid grantorId; + Oid ownerId; + HeapTuple tuple; + HeapTuple newtuple; + Datum values[Natts_pg_language]; + bool nulls[Natts_pg_language]; + bool replaces[Natts_pg_language]; + int noldmembers; + int nnewmembers; + Oid *oldmembers; + Oid *newmembers; + + tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(langId)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for language %u", langId); + + pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple); + + if (!pg_language_tuple->lanpltrusted) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("language \"%s\" is not trusted", + NameStr(pg_language_tuple->lanname)), + errdetail("GRANT and REVOKE are not allowed on untrusted languages, " + "because only superusers can use untrusted languages."))); + + /* + * Get owner ID and working copy of existing ACL. If there's no ACL, + * substitute the proper default. + */ + ownerId = pg_language_tuple->lanowner; + aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl, + &isNull); + if (isNull) + { + old_acl = acldefault(OBJECT_LANGUAGE, ownerId); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } + else + { + old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } + + /* Determine ID to do the grant as, and available grant options */ + select_best_grantor(GetUserId(), istmt->privileges, + old_acl, ownerId, + &grantorId, &avail_goptions); + + /* + * Restrict the privileges to what we can actually grant, and emit the + * standards-mandated warning and error messages. + */ + this_privileges = + restrict_and_check_grant(istmt->is_grant, avail_goptions, + istmt->all_privs, istmt->privileges, + langId, grantorId, OBJECT_LANGUAGE, + NameStr(pg_language_tuple->lanname), + 0, NULL); + + /* + * Generate new ACL. + */ + new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, + istmt->grant_option, istmt->behavior, + istmt->grantees, this_privileges, + grantorId, ownerId); + + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. + */ + nnewmembers = aclmembers(new_acl, &newmembers); + + /* finished building new ACL value, now insert it */ + MemSet(values, 0, sizeof(values)); + MemSet(nulls, false, sizeof(nulls)); + MemSet(replaces, false, sizeof(replaces)); + + replaces[Anum_pg_language_lanacl - 1] = true; + values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl); + + newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, + nulls, replaces); + + CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); + + /* Update initial privileges for extensions */ + recordExtensionInitPriv(langId, LanguageRelationId, 0, new_acl); + + /* Update the shared dependency ACL info */ + updateAclDependencies(LanguageRelationId, pg_language_tuple->oid, 0, + ownerId, + noldmembers, oldmembers, + nnewmembers, newmembers); + + ReleaseSysCache(tuple); + + pfree(new_acl); + + /* prevent error when processing duplicate objects */ + CommandCounterIncrement(); + } + + table_close(relation, RowExclusiveLock); +} + +static void +ExecGrant_Largeobject(InternalGrant *istmt) +{ + Relation relation; + ListCell *cell; + + if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) + istmt->privileges = ACL_ALL_RIGHTS_LARGEOBJECT; + + relation = table_open(LargeObjectMetadataRelationId, + RowExclusiveLock); + + foreach(cell, istmt->objects) + { + Oid loid = lfirst_oid(cell); + Form_pg_largeobject_metadata form_lo_meta; + char loname[NAMEDATALEN]; + Datum aclDatum; + bool isNull; + AclMode avail_goptions; + AclMode this_privileges; + Acl *old_acl; + Acl *new_acl; + Oid grantorId; + Oid ownerId; + HeapTuple newtuple; + Datum values[Natts_pg_largeobject_metadata]; + bool nulls[Natts_pg_largeobject_metadata]; + bool replaces[Natts_pg_largeobject_metadata]; + int noldmembers; + int nnewmembers; + Oid *oldmembers; + Oid *newmembers; + ScanKeyData entry[1]; + SysScanDesc scan; + HeapTuple tuple; + + /* There's no syscache for pg_largeobject_metadata */ + ScanKeyInit(&entry[0], + Anum_pg_largeobject_metadata_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(loid)); + + scan = systable_beginscan(relation, + LargeObjectMetadataOidIndexId, true, + NULL, 1, entry); + + tuple = systable_getnext(scan); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "could not find tuple for large object %u", loid); + + form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple); + + /* + * Get owner ID and working copy of existing ACL. If there's no ACL, + * substitute the proper default. + */ + ownerId = form_lo_meta->lomowner; + aclDatum = heap_getattr(tuple, + Anum_pg_largeobject_metadata_lomacl, + RelationGetDescr(relation), &isNull); + if (isNull) + { + old_acl = acldefault(OBJECT_LARGEOBJECT, ownerId); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } + else + { + old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } + + /* Determine ID to do the grant as, and available grant options */ + select_best_grantor(GetUserId(), istmt->privileges, + old_acl, ownerId, + &grantorId, &avail_goptions); + + /* + * Restrict the privileges to what we can actually grant, and emit the + * standards-mandated warning and error messages. + */ + snprintf(loname, sizeof(loname), "large object %u", loid); + this_privileges = + restrict_and_check_grant(istmt->is_grant, avail_goptions, + istmt->all_privs, istmt->privileges, + loid, grantorId, OBJECT_LARGEOBJECT, + loname, 0, NULL); + + /* + * Generate new ACL. + */ + new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, + istmt->grant_option, istmt->behavior, + istmt->grantees, this_privileges, + grantorId, ownerId); + + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. + */ + nnewmembers = aclmembers(new_acl, &newmembers); + + /* finished building new ACL value, now insert it */ + MemSet(values, 0, sizeof(values)); + MemSet(nulls, false, sizeof(nulls)); + MemSet(replaces, false, sizeof(replaces)); + + replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true; + values[Anum_pg_largeobject_metadata_lomacl - 1] + = PointerGetDatum(new_acl); + + newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), + values, nulls, replaces); + + CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); + + /* Update initial privileges for extensions */ + recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl); + + /* Update the shared dependency ACL info */ + updateAclDependencies(LargeObjectRelationId, + form_lo_meta->oid, 0, + ownerId, + noldmembers, oldmembers, + nnewmembers, newmembers); + + systable_endscan(scan); + + pfree(new_acl); + + /* prevent error when processing duplicate objects */ + CommandCounterIncrement(); + } + + table_close(relation, RowExclusiveLock); +} + +static void +ExecGrant_Namespace(InternalGrant *istmt) +{ + Relation relation; + ListCell *cell; + + if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) + istmt->privileges = ACL_ALL_RIGHTS_SCHEMA; + + relation = table_open(NamespaceRelationId, RowExclusiveLock); + + foreach(cell, istmt->objects) + { + Oid nspid = lfirst_oid(cell); + Form_pg_namespace pg_namespace_tuple; + Datum aclDatum; + bool isNull; + AclMode avail_goptions; + AclMode this_privileges; + Acl *old_acl; + Acl *new_acl; + Oid grantorId; + Oid ownerId; + HeapTuple tuple; + HeapTuple newtuple; + Datum values[Natts_pg_namespace]; + bool nulls[Natts_pg_namespace]; + bool replaces[Natts_pg_namespace]; + int noldmembers; + int nnewmembers; + Oid *oldmembers; + Oid *newmembers; + + tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nspid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for namespace %u", nspid); + + pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple); + + /* + * Get owner ID and working copy of existing ACL. If there's no ACL, + * substitute the proper default. + */ + ownerId = pg_namespace_tuple->nspowner; + aclDatum = SysCacheGetAttr(NAMESPACENAME, tuple, + Anum_pg_namespace_nspacl, + &isNull); + if (isNull) + { + old_acl = acldefault(OBJECT_SCHEMA, ownerId); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } + else + { + old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } + + /* Determine ID to do the grant as, and available grant options */ + select_best_grantor(GetUserId(), istmt->privileges, + old_acl, ownerId, + &grantorId, &avail_goptions); + + /* + * Restrict the privileges to what we can actually grant, and emit the + * standards-mandated warning and error messages. + */ + this_privileges = + restrict_and_check_grant(istmt->is_grant, avail_goptions, + istmt->all_privs, istmt->privileges, + nspid, grantorId, OBJECT_SCHEMA, + NameStr(pg_namespace_tuple->nspname), + 0, NULL); + + /* + * Generate new ACL. + */ + new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, + istmt->grant_option, istmt->behavior, + istmt->grantees, this_privileges, + grantorId, ownerId); + + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. + */ + nnewmembers = aclmembers(new_acl, &newmembers); + + /* finished building new ACL value, now insert it */ + MemSet(values, 0, sizeof(values)); + MemSet(nulls, false, sizeof(nulls)); + MemSet(replaces, false, sizeof(replaces)); + + replaces[Anum_pg_namespace_nspacl - 1] = true; + values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(new_acl); + + newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, + nulls, replaces); + + CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); + + /* Update initial privileges for extensions */ + recordExtensionInitPriv(nspid, NamespaceRelationId, 0, new_acl); + + /* Update the shared dependency ACL info */ + updateAclDependencies(NamespaceRelationId, pg_namespace_tuple->oid, 0, + ownerId, + noldmembers, oldmembers, + nnewmembers, newmembers); + + ReleaseSysCache(tuple); + + pfree(new_acl); + + /* prevent error when processing duplicate objects */ + CommandCounterIncrement(); + } + + table_close(relation, RowExclusiveLock); +} + +static void +ExecGrant_Tablespace(InternalGrant *istmt) +{ + Relation relation; + ListCell *cell; + + if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) + istmt->privileges = ACL_ALL_RIGHTS_TABLESPACE; + + relation = table_open(TableSpaceRelationId, RowExclusiveLock); + + foreach(cell, istmt->objects) + { + Oid tblId = lfirst_oid(cell); + Form_pg_tablespace pg_tablespace_tuple; + Datum aclDatum; + bool isNull; + AclMode avail_goptions; + AclMode this_privileges; + Acl *old_acl; + Acl *new_acl; + Oid grantorId; + Oid ownerId; + HeapTuple newtuple; + Datum values[Natts_pg_tablespace]; + bool nulls[Natts_pg_tablespace]; + bool replaces[Natts_pg_tablespace]; + int noldmembers; + int nnewmembers; + Oid *oldmembers; + Oid *newmembers; + HeapTuple tuple; + + /* Search syscache for pg_tablespace */ + tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(tblId)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for tablespace %u", tblId); + + pg_tablespace_tuple = (Form_pg_tablespace) GETSTRUCT(tuple); + + /* + * Get owner ID and working copy of existing ACL. If there's no ACL, + * substitute the proper default. + */ + ownerId = pg_tablespace_tuple->spcowner; + aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl, + RelationGetDescr(relation), &isNull); + if (isNull) + { + old_acl = acldefault(OBJECT_TABLESPACE, ownerId); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } + else + { + old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } + + /* Determine ID to do the grant as, and available grant options */ + select_best_grantor(GetUserId(), istmt->privileges, + old_acl, ownerId, + &grantorId, &avail_goptions); + + /* + * Restrict the privileges to what we can actually grant, and emit the + * standards-mandated warning and error messages. + */ + this_privileges = + restrict_and_check_grant(istmt->is_grant, avail_goptions, + istmt->all_privs, istmt->privileges, + tblId, grantorId, OBJECT_TABLESPACE, + NameStr(pg_tablespace_tuple->spcname), + 0, NULL); + + /* + * Generate new ACL. + */ + new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, + istmt->grant_option, istmt->behavior, + istmt->grantees, this_privileges, + grantorId, ownerId); + + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. + */ + nnewmembers = aclmembers(new_acl, &newmembers); + + /* finished building new ACL value, now insert it */ + MemSet(values, 0, sizeof(values)); + MemSet(nulls, false, sizeof(nulls)); + MemSet(replaces, false, sizeof(replaces)); + + replaces[Anum_pg_tablespace_spcacl - 1] = true; + values[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(new_acl); + + newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, + nulls, replaces); + + CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); + + /* Update the shared dependency ACL info */ + updateAclDependencies(TableSpaceRelationId, tblId, 0, + ownerId, + noldmembers, oldmembers, + nnewmembers, newmembers); + + ReleaseSysCache(tuple); + pfree(new_acl); + + /* prevent error when processing duplicate objects */ + CommandCounterIncrement(); + } + + table_close(relation, RowExclusiveLock); +} + +static void +ExecGrant_Type(InternalGrant *istmt) +{ + Relation relation; + ListCell *cell; + + if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) + istmt->privileges = ACL_ALL_RIGHTS_TYPE; + + relation = table_open(TypeRelationId, RowExclusiveLock); + + foreach(cell, istmt->objects) + { + Oid typId = lfirst_oid(cell); + Form_pg_type pg_type_tuple; + Datum aclDatum; + bool isNull; + AclMode avail_goptions; + AclMode this_privileges; + Acl *old_acl; + Acl *new_acl; + Oid grantorId; + Oid ownerId; + HeapTuple newtuple; + Datum values[Natts_pg_type]; + bool nulls[Natts_pg_type]; + bool replaces[Natts_pg_type]; + int noldmembers; + int nnewmembers; + Oid *oldmembers; + Oid *newmembers; + HeapTuple tuple; + + /* Search syscache for pg_type */ + tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typId)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for type %u", typId); + + pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple); + + if (pg_type_tuple->typelem != 0 && pg_type_tuple->typlen == -1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_GRANT_OPERATION), + errmsg("cannot set privileges of array types"), + errhint("Set the privileges of the element type instead."))); + + /* Used GRANT DOMAIN on a non-domain? */ + if (istmt->objtype == OBJECT_DOMAIN && + pg_type_tuple->typtype != TYPTYPE_DOMAIN) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not a domain", + NameStr(pg_type_tuple->typname)))); + + /* + * Get owner ID and working copy of existing ACL. If there's no ACL, + * substitute the proper default. + */ + ownerId = pg_type_tuple->typowner; + aclDatum = heap_getattr(tuple, Anum_pg_type_typacl, + RelationGetDescr(relation), &isNull); + if (isNull) + { + old_acl = acldefault(istmt->objtype, ownerId); + /* There are no old member roles according to the catalogs */ + noldmembers = 0; + oldmembers = NULL; + } + else + { + old_acl = DatumGetAclPCopy(aclDatum); + /* Get the roles mentioned in the existing ACL */ + noldmembers = aclmembers(old_acl, &oldmembers); + } + + /* Determine ID to do the grant as, and available grant options */ + select_best_grantor(GetUserId(), istmt->privileges, + old_acl, ownerId, + &grantorId, &avail_goptions); + + /* + * Restrict the privileges to what we can actually grant, and emit the + * standards-mandated warning and error messages. + */ + this_privileges = + restrict_and_check_grant(istmt->is_grant, avail_goptions, + istmt->all_privs, istmt->privileges, + typId, grantorId, OBJECT_TYPE, + NameStr(pg_type_tuple->typname), + 0, NULL); + + /* + * Generate new ACL. + */ + new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, + istmt->grant_option, istmt->behavior, + istmt->grantees, this_privileges, + grantorId, ownerId); + + /* + * We need the members of both old and new ACLs so we can correct the + * shared dependency information. + */ + nnewmembers = aclmembers(new_acl, &newmembers); + + /* finished building new ACL value, now insert it */ + MemSet(values, 0, sizeof(values)); + MemSet(nulls, false, sizeof(nulls)); + MemSet(replaces, false, sizeof(replaces)); + + replaces[Anum_pg_type_typacl - 1] = true; + values[Anum_pg_type_typacl - 1] = PointerGetDatum(new_acl); + + newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, + nulls, replaces); + + CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); + + /* Update initial privileges for extensions */ + recordExtensionInitPriv(typId, TypeRelationId, 0, new_acl); + + /* Update the shared dependency ACL info */ + updateAclDependencies(TypeRelationId, typId, 0, + ownerId, + noldmembers, oldmembers, + nnewmembers, newmembers); + + ReleaseSysCache(tuple); + pfree(new_acl); + + /* prevent error when processing duplicate objects */ + CommandCounterIncrement(); + } + + table_close(relation, RowExclusiveLock); +} + + +static AclMode +string_to_privilege(const char *privname) +{ + if (strcmp(privname, "insert") == 0) + return ACL_INSERT; + if (strcmp(privname, "select") == 0) + return ACL_SELECT; + if (strcmp(privname, "update") == 0) + return ACL_UPDATE; + if (strcmp(privname, "delete") == 0) + return ACL_DELETE; + if (strcmp(privname, "truncate") == 0) + return ACL_TRUNCATE; + if (strcmp(privname, "references") == 0) + return ACL_REFERENCES; + if (strcmp(privname, "trigger") == 0) + return ACL_TRIGGER; + if (strcmp(privname, "execute") == 0) + return ACL_EXECUTE; + if (strcmp(privname, "usage") == 0) + return ACL_USAGE; + if (strcmp(privname, "create") == 0) + return ACL_CREATE; + if (strcmp(privname, "temporary") == 0) + return ACL_CREATE_TEMP; + if (strcmp(privname, "temp") == 0) + return ACL_CREATE_TEMP; + if (strcmp(privname, "connect") == 0) + return ACL_CONNECT; + if (strcmp(privname, "rule") == 0) + return 0; /* ignore old RULE privileges */ + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("unrecognized privilege type \"%s\"", privname))); + return 0; /* appease compiler */ +} + +static const char * +privilege_to_string(AclMode privilege) +{ + switch (privilege) + { + case ACL_INSERT: + return "INSERT"; + case ACL_SELECT: + return "SELECT"; + case ACL_UPDATE: + return "UPDATE"; + case ACL_DELETE: + return "DELETE"; + case ACL_TRUNCATE: + return "TRUNCATE"; + case ACL_REFERENCES: + return "REFERENCES"; + case ACL_TRIGGER: + return "TRIGGER"; + case ACL_EXECUTE: + return "EXECUTE"; + case ACL_USAGE: + return "USAGE"; + case ACL_CREATE: + return "CREATE"; + case ACL_CREATE_TEMP: + return "TEMP"; + case ACL_CONNECT: + return "CONNECT"; + default: + elog(ERROR, "unrecognized privilege: %d", (int) privilege); + } + return NULL; /* appease compiler */ +} + +/* + * Standardized reporting of aclcheck permissions failures. + * + * Note: we do not double-quote the %s's below, because many callers + * supply strings that might be already quoted. + */ +void +aclcheck_error(AclResult aclerr, ObjectType objtype, + const char *objectname) +{ + switch (aclerr) + { + case ACLCHECK_OK: + /* no error, so return to caller */ + break; + case ACLCHECK_NO_PRIV: + { + const char *msg = "???"; + + switch (objtype) + { + case OBJECT_AGGREGATE: + msg = gettext_noop("permission denied for aggregate %s"); + break; + case OBJECT_COLLATION: + msg = gettext_noop("permission denied for collation %s"); + break; + case OBJECT_COLUMN: + msg = gettext_noop("permission denied for column %s"); + break; + case OBJECT_CONVERSION: + msg = gettext_noop("permission denied for conversion %s"); + break; + case OBJECT_DATABASE: + msg = gettext_noop("permission denied for database %s"); + break; + case OBJECT_DOMAIN: + msg = gettext_noop("permission denied for domain %s"); + break; + case OBJECT_EVENT_TRIGGER: + msg = gettext_noop("permission denied for event trigger %s"); + break; + case OBJECT_EXTENSION: + msg = gettext_noop("permission denied for extension %s"); + break; + case OBJECT_FDW: + msg = gettext_noop("permission denied for foreign-data wrapper %s"); + break; + case OBJECT_FOREIGN_SERVER: + msg = gettext_noop("permission denied for foreign server %s"); + break; + case OBJECT_FOREIGN_TABLE: + msg = gettext_noop("permission denied for foreign table %s"); + break; + case OBJECT_FUNCTION: + msg = gettext_noop("permission denied for function %s"); + break; + case OBJECT_INDEX: + msg = gettext_noop("permission denied for index %s"); + break; + case OBJECT_LANGUAGE: + msg = gettext_noop("permission denied for language %s"); + break; + case OBJECT_LARGEOBJECT: + msg = gettext_noop("permission denied for large object %s"); + break; + case OBJECT_MATVIEW: + msg = gettext_noop("permission denied for materialized view %s"); + break; + case OBJECT_OPCLASS: + msg = gettext_noop("permission denied for operator class %s"); + break; + case OBJECT_OPERATOR: + msg = gettext_noop("permission denied for operator %s"); + break; + case OBJECT_OPFAMILY: + msg = gettext_noop("permission denied for operator family %s"); + break; + case OBJECT_POLICY: + msg = gettext_noop("permission denied for policy %s"); + break; + case OBJECT_PROCEDURE: + msg = gettext_noop("permission denied for procedure %s"); + break; + case OBJECT_PUBLICATION: + msg = gettext_noop("permission denied for publication %s"); + break; + case OBJECT_ROUTINE: + msg = gettext_noop("permission denied for routine %s"); + break; + case OBJECT_SCHEMA: + msg = gettext_noop("permission denied for schema %s"); + break; + case OBJECT_SEQUENCE: + msg = gettext_noop("permission denied for sequence %s"); + break; + case OBJECT_STATISTIC_EXT: + msg = gettext_noop("permission denied for statistics object %s"); + break; + case OBJECT_SUBSCRIPTION: + msg = gettext_noop("permission denied for subscription %s"); + break; + case OBJECT_TABLE: + msg = gettext_noop("permission denied for table %s"); + break; + case OBJECT_TABLESPACE: + msg = gettext_noop("permission denied for tablespace %s"); + break; + case OBJECT_TSCONFIGURATION: + msg = gettext_noop("permission denied for text search configuration %s"); + break; + case OBJECT_TSDICTIONARY: + msg = gettext_noop("permission denied for text search dictionary %s"); + break; + case OBJECT_TYPE: + msg = gettext_noop("permission denied for type %s"); + break; + case OBJECT_VIEW: + msg = gettext_noop("permission denied for view %s"); + break; + /* these currently aren't used */ + case OBJECT_ACCESS_METHOD: + case OBJECT_AMOP: + case OBJECT_AMPROC: + case OBJECT_ATTRIBUTE: + case OBJECT_CAST: + case OBJECT_DEFAULT: + case OBJECT_DEFACL: + case OBJECT_DOMCONSTRAINT: + case OBJECT_PUBLICATION_REL: + case OBJECT_ROLE: + case OBJECT_RULE: + case OBJECT_TABCONSTRAINT: + case OBJECT_TRANSFORM: + case OBJECT_TRIGGER: + case OBJECT_TSPARSER: + case OBJECT_TSTEMPLATE: + case OBJECT_USER_MAPPING: + elog(ERROR, "unsupported object type %d", objtype); + } + + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg(msg, objectname))); + break; + } + case ACLCHECK_NOT_OWNER: + { + const char *msg = "???"; + + switch (objtype) + { + case OBJECT_AGGREGATE: + msg = gettext_noop("must be owner of aggregate %s"); + break; + case OBJECT_COLLATION: + msg = gettext_noop("must be owner of collation %s"); + break; + case OBJECT_CONVERSION: + msg = gettext_noop("must be owner of conversion %s"); + break; + case OBJECT_DATABASE: + msg = gettext_noop("must be owner of database %s"); + break; + case OBJECT_DOMAIN: + msg = gettext_noop("must be owner of domain %s"); + break; + case OBJECT_EVENT_TRIGGER: + msg = gettext_noop("must be owner of event trigger %s"); + break; + case OBJECT_EXTENSION: + msg = gettext_noop("must be owner of extension %s"); + break; + case OBJECT_FDW: + msg = gettext_noop("must be owner of foreign-data wrapper %s"); + break; + case OBJECT_FOREIGN_SERVER: + msg = gettext_noop("must be owner of foreign server %s"); + break; + case OBJECT_FOREIGN_TABLE: + msg = gettext_noop("must be owner of foreign table %s"); + break; + case OBJECT_FUNCTION: + msg = gettext_noop("must be owner of function %s"); + break; + case OBJECT_INDEX: + msg = gettext_noop("must be owner of index %s"); + break; + case OBJECT_LANGUAGE: + msg = gettext_noop("must be owner of language %s"); + break; + case OBJECT_LARGEOBJECT: + msg = gettext_noop("must be owner of large object %s"); + break; + case OBJECT_MATVIEW: + msg = gettext_noop("must be owner of materialized view %s"); + break; + case OBJECT_OPCLASS: + msg = gettext_noop("must be owner of operator class %s"); + break; + case OBJECT_OPERATOR: + msg = gettext_noop("must be owner of operator %s"); + break; + case OBJECT_OPFAMILY: + msg = gettext_noop("must be owner of operator family %s"); + break; + case OBJECT_PROCEDURE: + msg = gettext_noop("must be owner of procedure %s"); + break; + case OBJECT_PUBLICATION: + msg = gettext_noop("must be owner of publication %s"); + break; + case OBJECT_ROUTINE: + msg = gettext_noop("must be owner of routine %s"); + break; + case OBJECT_SEQUENCE: + msg = gettext_noop("must be owner of sequence %s"); + break; + case OBJECT_SUBSCRIPTION: + msg = gettext_noop("must be owner of subscription %s"); + break; + case OBJECT_TABLE: + msg = gettext_noop("must be owner of table %s"); + break; + case OBJECT_TYPE: + msg = gettext_noop("must be owner of type %s"); + break; + case OBJECT_VIEW: + msg = gettext_noop("must be owner of view %s"); + break; + case OBJECT_SCHEMA: + msg = gettext_noop("must be owner of schema %s"); + break; + case OBJECT_STATISTIC_EXT: + msg = gettext_noop("must be owner of statistics object %s"); + break; + case OBJECT_TABLESPACE: + msg = gettext_noop("must be owner of tablespace %s"); + break; + case OBJECT_TSCONFIGURATION: + msg = gettext_noop("must be owner of text search configuration %s"); + break; + case OBJECT_TSDICTIONARY: + msg = gettext_noop("must be owner of text search dictionary %s"); + break; + + /* + * Special cases: For these, the error message talks + * about "relation", because that's where the + * ownership is attached. See also + * check_object_ownership(). + */ + case OBJECT_COLUMN: + case OBJECT_POLICY: + case OBJECT_RULE: + case OBJECT_TABCONSTRAINT: + case OBJECT_TRIGGER: + msg = gettext_noop("must be owner of relation %s"); + break; + /* these currently aren't used */ + case OBJECT_ACCESS_METHOD: + case OBJECT_AMOP: + case OBJECT_AMPROC: + case OBJECT_ATTRIBUTE: + case OBJECT_CAST: + case OBJECT_DEFAULT: + case OBJECT_DEFACL: + case OBJECT_DOMCONSTRAINT: + case OBJECT_PUBLICATION_REL: + case OBJECT_ROLE: + case OBJECT_TRANSFORM: + case OBJECT_TSPARSER: + case OBJECT_TSTEMPLATE: + case OBJECT_USER_MAPPING: + elog(ERROR, "unsupported object type %d", objtype); + } + + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg(msg, objectname))); + break; + } + default: + elog(ERROR, "unrecognized AclResult: %d", (int) aclerr); + break; + } +} + + +void +aclcheck_error_col(AclResult aclerr, ObjectType objtype, + const char *objectname, const char *colname) +{ + switch (aclerr) + { + case ACLCHECK_OK: + /* no error, so return to caller */ + break; + case ACLCHECK_NO_PRIV: + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied for column \"%s\" of relation \"%s\"", + colname, objectname))); + break; + case ACLCHECK_NOT_OWNER: + /* relation msg is OK since columns don't have separate owners */ + aclcheck_error(aclerr, objtype, objectname); + break; + default: + elog(ERROR, "unrecognized AclResult: %d", (int) aclerr); + break; + } +} + + +/* + * Special common handling for types: use element type instead of array type, + * and format nicely + */ +void +aclcheck_error_type(AclResult aclerr, Oid typeOid) +{ + Oid element_type = get_element_type(typeOid); + + aclcheck_error(aclerr, OBJECT_TYPE, format_type_be(element_type ? element_type : typeOid)); +} + + +/* + * Relay for the various pg_*_mask routines depending on object kind + */ +static AclMode +pg_aclmask(ObjectType objtype, Oid table_oid, AttrNumber attnum, Oid roleid, + AclMode mask, AclMaskHow how) +{ + switch (objtype) + { + case OBJECT_COLUMN: + return + pg_class_aclmask(table_oid, roleid, mask, how) | + pg_attribute_aclmask(table_oid, attnum, roleid, mask, how); + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + return pg_class_aclmask(table_oid, roleid, mask, how); + case OBJECT_DATABASE: + return pg_database_aclmask(table_oid, roleid, mask, how); + case OBJECT_FUNCTION: + return pg_proc_aclmask(table_oid, roleid, mask, how); + case OBJECT_LANGUAGE: + return pg_language_aclmask(table_oid, roleid, mask, how); + case OBJECT_LARGEOBJECT: + return pg_largeobject_aclmask_snapshot(table_oid, roleid, + mask, how, NULL); + case OBJECT_SCHEMA: + return pg_namespace_aclmask(table_oid, roleid, mask, how); + case OBJECT_STATISTIC_EXT: + elog(ERROR, "grantable rights not supported for statistics objects"); + /* not reached, but keep compiler quiet */ + return ACL_NO_RIGHTS; + case OBJECT_TABLESPACE: + return pg_tablespace_aclmask(table_oid, roleid, mask, how); + case OBJECT_FDW: + return pg_foreign_data_wrapper_aclmask(table_oid, roleid, mask, how); + case OBJECT_FOREIGN_SERVER: + return pg_foreign_server_aclmask(table_oid, roleid, mask, how); + case OBJECT_EVENT_TRIGGER: + elog(ERROR, "grantable rights not supported for event triggers"); + /* not reached, but keep compiler quiet */ + return ACL_NO_RIGHTS; + case OBJECT_TYPE: + return pg_type_aclmask(table_oid, roleid, mask, how); + default: + elog(ERROR, "unrecognized objtype: %d", + (int) objtype); + /* not reached, but keep compiler quiet */ + return ACL_NO_RIGHTS; + } +} + + +/* **************************************************************** + * Exported routines for examining a user's privileges for various objects + * + * See aclmask() for a description of the common API for these functions. + * + * Note: we give lookup failure the full ereport treatment because the + * has_xxx_privilege() family of functions allow users to pass any random + * OID to these functions. + * **************************************************************** + */ + +/* + * Exported routine for examining a user's privileges for a column + * + * Note: this considers only privileges granted specifically on the column. + * It is caller's responsibility to take relation-level privileges into account + * as appropriate. (For the same reason, we have no special case for + * superuser-ness here.) + */ +AclMode +pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid, + AclMode mask, AclMaskHow how) +{ + AclMode result; + HeapTuple classTuple; + HeapTuple attTuple; + Form_pg_class classForm; + Form_pg_attribute attributeForm; + Datum aclDatum; + bool isNull; + Acl *acl; + Oid ownerId; + + /* + * First, get the column's ACL from its pg_attribute entry + */ + attTuple = SearchSysCache2(ATTNUM, + ObjectIdGetDatum(table_oid), + Int16GetDatum(attnum)); + if (!HeapTupleIsValid(attTuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("attribute %d of relation with OID %u does not exist", + attnum, table_oid))); + attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple); + + /* Throw error on dropped columns, too */ + if (attributeForm->attisdropped) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("attribute %d of relation with OID %u does not exist", + attnum, table_oid))); + + aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl, + &isNull); + + /* + * Here we hard-wire knowledge that the default ACL for a column grants no + * privileges, so that we can fall out quickly in the very common case + * where attacl is null. + */ + if (isNull) + { + ReleaseSysCache(attTuple); + return 0; + } + + /* + * Must get the relation's ownerId from pg_class. Since we already found + * a pg_attribute entry, the only likely reason for this to fail is that a + * concurrent DROP of the relation committed since then (which could only + * happen if we don't have lock on the relation). We prefer to report "no + * privileges" rather than failing in such a case, so as to avoid unwanted + * failures in has_column_privilege() tests. + */ + classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid)); + if (!HeapTupleIsValid(classTuple)) + { + ReleaseSysCache(attTuple); + return 0; + } + classForm = (Form_pg_class) GETSTRUCT(classTuple); + + ownerId = classForm->relowner; + + ReleaseSysCache(classTuple); + + /* detoast column's ACL if necessary */ + acl = DatumGetAclP(aclDatum); + + result = aclmask(acl, roleid, ownerId, mask, how); + + /* if we have a detoasted copy, free it */ + if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) + pfree(acl); + + ReleaseSysCache(attTuple); + + return result; +} + +/* + * Exported routine for examining a user's privileges for a table + */ +AclMode +pg_class_aclmask(Oid table_oid, Oid roleid, + AclMode mask, AclMaskHow how) +{ + AclMode result; + HeapTuple tuple; + Form_pg_class classForm; + Datum aclDatum; + bool isNull; + Acl *acl; + Oid ownerId; + + /* + * Must get the relation's tuple from pg_class + */ + tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("relation with OID %u does not exist", + table_oid))); + classForm = (Form_pg_class) GETSTRUCT(tuple); + + /* + * Deny anyone permission to update a system catalog unless + * pg_authid.rolsuper is set. + * + * As of 7.4 we have some updatable system views; those shouldn't be + * protected in this way. Assume the view rules can take care of + * themselves. ACL_USAGE is if we ever have system sequences. + */ + if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) && + IsSystemClass(table_oid, classForm) && + classForm->relkind != RELKIND_VIEW && + !superuser_arg(roleid)) + mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE); + + /* + * Otherwise, superusers bypass all permission-checking. + */ + if (superuser_arg(roleid)) + { + ReleaseSysCache(tuple); + return mask; + } + + /* + * Normal case: get the relation's ACL from pg_class + */ + ownerId = classForm->relowner; + + aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl, + &isNull); + if (isNull) + { + /* No ACL, so build default ACL */ + switch (classForm->relkind) + { + case RELKIND_SEQUENCE: + acl = acldefault(OBJECT_SEQUENCE, ownerId); + break; + default: + acl = acldefault(OBJECT_TABLE, ownerId); + break; + } + aclDatum = (Datum) 0; + } + else + { + /* detoast rel's ACL if necessary */ + acl = DatumGetAclP(aclDatum); + } + + result = aclmask(acl, roleid, ownerId, mask, how); + + /* if we have a detoasted copy, free it */ + if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) + pfree(acl); + + ReleaseSysCache(tuple); + + return result; +} + +/* + * Exported routine for examining a user's privileges for a database + */ +AclMode +pg_database_aclmask(Oid db_oid, Oid roleid, + AclMode mask, AclMaskHow how) +{ + AclMode result; + HeapTuple tuple; + Datum aclDatum; + bool isNull; + Acl *acl; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return mask; + + /* + * Get the database's ACL from pg_database + */ + tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(db_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("database with OID %u does not exist", db_oid))); + + ownerId = ((Form_pg_database) GETSTRUCT(tuple))->datdba; + + aclDatum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_datacl, + &isNull); + if (isNull) + { + /* No ACL, so build default ACL */ + acl = acldefault(OBJECT_DATABASE, ownerId); + aclDatum = (Datum) 0; + } + else + { + /* detoast ACL if necessary */ + acl = DatumGetAclP(aclDatum); + } + + result = aclmask(acl, roleid, ownerId, mask, how); + + /* if we have a detoasted copy, free it */ + if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) + pfree(acl); + + ReleaseSysCache(tuple); + + return result; +} + +/* + * Exported routine for examining a user's privileges for a function + */ +AclMode +pg_proc_aclmask(Oid proc_oid, Oid roleid, + AclMode mask, AclMaskHow how) +{ + AclMode result; + HeapTuple tuple; + Datum aclDatum; + bool isNull; + Acl *acl; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return mask; + + /* + * Get the function's ACL from pg_proc + */ + tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(proc_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("function with OID %u does not exist", proc_oid))); + + ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner; + + aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl, + &isNull); + if (isNull) + { + /* No ACL, so build default ACL */ + acl = acldefault(OBJECT_FUNCTION, ownerId); + aclDatum = (Datum) 0; + } + else + { + /* detoast ACL if necessary */ + acl = DatumGetAclP(aclDatum); + } + + result = aclmask(acl, roleid, ownerId, mask, how); + + /* if we have a detoasted copy, free it */ + if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) + pfree(acl); + + ReleaseSysCache(tuple); + + return result; +} + +/* + * Exported routine for examining a user's privileges for a language + */ +AclMode +pg_language_aclmask(Oid lang_oid, Oid roleid, + AclMode mask, AclMaskHow how) +{ + AclMode result; + HeapTuple tuple; + Datum aclDatum; + bool isNull; + Acl *acl; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return mask; + + /* + * Get the language's ACL from pg_language + */ + tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(lang_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("language with OID %u does not exist", lang_oid))); + + ownerId = ((Form_pg_language) GETSTRUCT(tuple))->lanowner; + + aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl, + &isNull); + if (isNull) + { + /* No ACL, so build default ACL */ + acl = acldefault(OBJECT_LANGUAGE, ownerId); + aclDatum = (Datum) 0; + } + else + { + /* detoast ACL if necessary */ + acl = DatumGetAclP(aclDatum); + } + + result = aclmask(acl, roleid, ownerId, mask, how); + + /* if we have a detoasted copy, free it */ + if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) + pfree(acl); + + ReleaseSysCache(tuple); + + return result; +} + +/* + * Exported routine for examining a user's privileges for a largeobject + * + * When a large object is opened for reading, it is opened relative to the + * caller's snapshot, but when it is opened for writing, a current + * MVCC snapshot will be used. See doc/src/sgml/lobj.sgml. This function + * takes a snapshot argument so that the permissions check can be made + * relative to the same snapshot that will be used to read the underlying + * data. The caller will actually pass NULL for an instantaneous MVCC + * snapshot, since all we do with the snapshot argument is pass it through + * to systable_beginscan(). + */ +AclMode +pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid, + AclMode mask, AclMaskHow how, + Snapshot snapshot) +{ + AclMode result; + Relation pg_lo_meta; + ScanKeyData entry[1]; + SysScanDesc scan; + HeapTuple tuple; + Datum aclDatum; + bool isNull; + Acl *acl; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return mask; + + /* + * Get the largeobject's ACL from pg_largeobject_metadata + */ + pg_lo_meta = table_open(LargeObjectMetadataRelationId, + AccessShareLock); + + ScanKeyInit(&entry[0], + Anum_pg_largeobject_metadata_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(lobj_oid)); + + scan = systable_beginscan(pg_lo_meta, + LargeObjectMetadataOidIndexId, true, + snapshot, 1, entry); + + tuple = systable_getnext(scan); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("large object %u does not exist", lobj_oid))); + + ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner; + + aclDatum = heap_getattr(tuple, Anum_pg_largeobject_metadata_lomacl, + RelationGetDescr(pg_lo_meta), &isNull); + + if (isNull) + { + /* No ACL, so build default ACL */ + acl = acldefault(OBJECT_LARGEOBJECT, ownerId); + aclDatum = (Datum) 0; + } + else + { + /* detoast ACL if necessary */ + acl = DatumGetAclP(aclDatum); + } + + result = aclmask(acl, roleid, ownerId, mask, how); + + /* if we have a detoasted copy, free it */ + if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) + pfree(acl); + + systable_endscan(scan); + + table_close(pg_lo_meta, AccessShareLock); + + return result; +} + +/* + * Exported routine for examining a user's privileges for a namespace + */ +AclMode +pg_namespace_aclmask(Oid nsp_oid, Oid roleid, + AclMode mask, AclMaskHow how) +{ + AclMode result; + HeapTuple tuple; + Datum aclDatum; + bool isNull; + Acl *acl; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return mask; + + /* + * If we have been assigned this namespace as a temp namespace, check to + * make sure we have CREATE TEMP permission on the database, and if so act + * as though we have all standard (but not GRANT OPTION) permissions on + * the namespace. If we don't have CREATE TEMP, act as though we have + * only USAGE (and not CREATE) rights. + * + * This may seem redundant given the check in InitTempTableNamespace, but + * it really isn't since current user ID may have changed since then. The + * upshot of this behavior is that a SECURITY DEFINER function can create + * temp tables that can then be accessed (if permission is granted) by + * code in the same session that doesn't have permissions to create temp + * tables. + * + * XXX Would it be safe to ereport a special error message as + * InitTempTableNamespace does? Returning zero here means we'll get a + * generic "permission denied for schema pg_temp_N" message, which is not + * remarkably user-friendly. + */ + if (isTempNamespace(nsp_oid)) + { + if (pg_database_aclcheck(MyDatabaseId, roleid, + ACL_CREATE_TEMP) == ACLCHECK_OK) + return mask & ACL_ALL_RIGHTS_SCHEMA; + else + return mask & ACL_USAGE; + } + + /* + * Get the schema's ACL from pg_namespace + */ + tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("schema with OID %u does not exist", nsp_oid))); + + ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner; + + aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl, + &isNull); + if (isNull) + { + /* No ACL, so build default ACL */ + acl = acldefault(OBJECT_SCHEMA, ownerId); + aclDatum = (Datum) 0; + } + else + { + /* detoast ACL if necessary */ + acl = DatumGetAclP(aclDatum); + } + + result = aclmask(acl, roleid, ownerId, mask, how); + + /* if we have a detoasted copy, free it */ + if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) + pfree(acl); + + ReleaseSysCache(tuple); + + return result; +} + +/* + * Exported routine for examining a user's privileges for a tablespace + */ +AclMode +pg_tablespace_aclmask(Oid spc_oid, Oid roleid, + AclMode mask, AclMaskHow how) +{ + AclMode result; + HeapTuple tuple; + Datum aclDatum; + bool isNull; + Acl *acl; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return mask; + + /* + * Get the tablespace's ACL from pg_tablespace + */ + tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spc_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tablespace with OID %u does not exist", spc_oid))); + + ownerId = ((Form_pg_tablespace) GETSTRUCT(tuple))->spcowner; + + aclDatum = SysCacheGetAttr(TABLESPACEOID, tuple, + Anum_pg_tablespace_spcacl, + &isNull); + + if (isNull) + { + /* No ACL, so build default ACL */ + acl = acldefault(OBJECT_TABLESPACE, ownerId); + aclDatum = (Datum) 0; + } + else + { + /* detoast ACL if necessary */ + acl = DatumGetAclP(aclDatum); + } + + result = aclmask(acl, roleid, ownerId, mask, how); + + /* if we have a detoasted copy, free it */ + if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) + pfree(acl); + + ReleaseSysCache(tuple); + + return result; +} + +/* + * Exported routine for examining a user's privileges for a foreign + * data wrapper + */ +AclMode +pg_foreign_data_wrapper_aclmask(Oid fdw_oid, Oid roleid, + AclMode mask, AclMaskHow how) +{ + AclMode result; + HeapTuple tuple; + Datum aclDatum; + bool isNull; + Acl *acl; + Oid ownerId; + + Form_pg_foreign_data_wrapper fdwForm; + + /* Bypass permission checks for superusers */ + if (superuser_arg(roleid)) + return mask; + + /* + * Must get the FDW's tuple from pg_foreign_data_wrapper + */ + tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdw_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("foreign-data wrapper with OID %u does not exist", + fdw_oid))); + fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple); + + /* + * Normal case: get the FDW's ACL from pg_foreign_data_wrapper + */ + ownerId = fdwForm->fdwowner; + + aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple, + Anum_pg_foreign_data_wrapper_fdwacl, &isNull); + if (isNull) + { + /* No ACL, so build default ACL */ + acl = acldefault(OBJECT_FDW, ownerId); + aclDatum = (Datum) 0; + } + else + { + /* detoast rel's ACL if necessary */ + acl = DatumGetAclP(aclDatum); + } + + result = aclmask(acl, roleid, ownerId, mask, how); + + /* if we have a detoasted copy, free it */ + if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) + pfree(acl); + + ReleaseSysCache(tuple); + + return result; +} + +/* + * Exported routine for examining a user's privileges for a foreign + * server. + */ +AclMode +pg_foreign_server_aclmask(Oid srv_oid, Oid roleid, + AclMode mask, AclMaskHow how) +{ + AclMode result; + HeapTuple tuple; + Datum aclDatum; + bool isNull; + Acl *acl; + Oid ownerId; + + Form_pg_foreign_server srvForm; + + /* Bypass permission checks for superusers */ + if (superuser_arg(roleid)) + return mask; + + /* + * Must get the FDW's tuple from pg_foreign_data_wrapper + */ + tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srv_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("foreign server with OID %u does not exist", + srv_oid))); + srvForm = (Form_pg_foreign_server) GETSTRUCT(tuple); + + /* + * Normal case: get the foreign server's ACL from pg_foreign_server + */ + ownerId = srvForm->srvowner; + + aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple, + Anum_pg_foreign_server_srvacl, &isNull); + if (isNull) + { + /* No ACL, so build default ACL */ + acl = acldefault(OBJECT_FOREIGN_SERVER, ownerId); + aclDatum = (Datum) 0; + } + else + { + /* detoast rel's ACL if necessary */ + acl = DatumGetAclP(aclDatum); + } + + result = aclmask(acl, roleid, ownerId, mask, how); + + /* if we have a detoasted copy, free it */ + if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) + pfree(acl); + + ReleaseSysCache(tuple); + + return result; +} + +/* + * Exported routine for examining a user's privileges for a type. + */ +AclMode +pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how) +{ + AclMode result; + HeapTuple tuple; + Datum aclDatum; + bool isNull; + Acl *acl; + Oid ownerId; + + Form_pg_type typeForm; + + /* Bypass permission checks for superusers */ + if (superuser_arg(roleid)) + return mask; + + /* + * Must get the type's tuple from pg_type + */ + tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("type with OID %u does not exist", + type_oid))); + typeForm = (Form_pg_type) GETSTRUCT(tuple); + + /* + * "True" array types don't manage permissions of their own; consult the + * element type instead. + */ + if (OidIsValid(typeForm->typelem) && typeForm->typlen == -1) + { + Oid elttype_oid = typeForm->typelem; + + ReleaseSysCache(tuple); + + tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid)); + /* this case is not a user-facing error, so elog not ereport */ + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for type %u", elttype_oid); + typeForm = (Form_pg_type) GETSTRUCT(tuple); + } + + /* + * Now get the type's owner and ACL from the tuple + */ + ownerId = typeForm->typowner; + + aclDatum = SysCacheGetAttr(TYPEOID, tuple, + Anum_pg_type_typacl, &isNull); + if (isNull) + { + /* No ACL, so build default ACL */ + acl = acldefault(OBJECT_TYPE, ownerId); + aclDatum = (Datum) 0; + } + else + { + /* detoast rel's ACL if necessary */ + acl = DatumGetAclP(aclDatum); + } + + result = aclmask(acl, roleid, ownerId, mask, how); + + /* if we have a detoasted copy, free it */ + if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) + pfree(acl); + + ReleaseSysCache(tuple); + + return result; +} + +/* + * Exported routine for checking a user's access privileges to a column + * + * Returns ACLCHECK_OK if the user has any of the privileges identified by + * 'mode'; otherwise returns a suitable error code (in practice, always + * ACLCHECK_NO_PRIV). + * + * As with pg_attribute_aclmask, only privileges granted directly on the + * column are considered here. + */ +AclResult +pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, + Oid roleid, AclMode mode) +{ + if (pg_attribute_aclmask(table_oid, attnum, roleid, mode, ACLMASK_ANY) != 0) + return ACLCHECK_OK; + else + return ACLCHECK_NO_PRIV; +} + +/* + * Exported routine for checking a user's access privileges to any/all columns + * + * If 'how' is ACLMASK_ANY, then returns ACLCHECK_OK if user has any of the + * privileges identified by 'mode' on any non-dropped column in the relation; + * otherwise returns a suitable error code (in practice, always + * ACLCHECK_NO_PRIV). + * + * If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the + * privileges identified by 'mode' on each non-dropped column in the relation + * (and there must be at least one such column); otherwise returns a suitable + * error code (in practice, always ACLCHECK_NO_PRIV). + * + * As with pg_attribute_aclmask, only privileges granted directly on the + * column(s) are considered here. + * + * Note: system columns are not considered here; there are cases where that + * might be appropriate but there are also cases where it wouldn't. + */ +AclResult +pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode, + AclMaskHow how) +{ + AclResult result; + HeapTuple classTuple; + Form_pg_class classForm; + AttrNumber nattrs; + AttrNumber curr_att; + + /* + * Must fetch pg_class row to check number of attributes. As in + * pg_attribute_aclmask, we prefer to return "no privileges" instead of + * throwing an error if we get any unexpected lookup errors. + */ + classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid)); + if (!HeapTupleIsValid(classTuple)) + return ACLCHECK_NO_PRIV; + classForm = (Form_pg_class) GETSTRUCT(classTuple); + + nattrs = classForm->relnatts; + + ReleaseSysCache(classTuple); + + /* + * Initialize result in case there are no non-dropped columns. We want to + * report failure in such cases for either value of 'how'. + */ + result = ACLCHECK_NO_PRIV; + + for (curr_att = 1; curr_att <= nattrs; curr_att++) + { + HeapTuple attTuple; + AclMode attmask; + + attTuple = SearchSysCache2(ATTNUM, + ObjectIdGetDatum(table_oid), + Int16GetDatum(curr_att)); + if (!HeapTupleIsValid(attTuple)) + continue; + + /* ignore dropped columns */ + if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped) + { + ReleaseSysCache(attTuple); + continue; + } + + /* + * Here we hard-wire knowledge that the default ACL for a column + * grants no privileges, so that we can fall out quickly in the very + * common case where attacl is null. + */ + if (heap_attisnull(attTuple, Anum_pg_attribute_attacl, NULL)) + attmask = 0; + else + attmask = pg_attribute_aclmask(table_oid, curr_att, roleid, + mode, ACLMASK_ANY); + + ReleaseSysCache(attTuple); + + if (attmask != 0) + { + result = ACLCHECK_OK; + if (how == ACLMASK_ANY) + break; /* succeed on any success */ + } + else + { + result = ACLCHECK_NO_PRIV; + if (how == ACLMASK_ALL) + break; /* fail on any failure */ + } + } + + return result; +} + +/* + * Exported routine for checking a user's access privileges to a table + * + * Returns ACLCHECK_OK if the user has any of the privileges identified by + * 'mode'; otherwise returns a suitable error code (in practice, always + * ACLCHECK_NO_PRIV). + */ +AclResult +pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode) +{ + if (pg_class_aclmask(table_oid, roleid, mode, ACLMASK_ANY) != 0) + return ACLCHECK_OK; + else + return ACLCHECK_NO_PRIV; +} + +/* + * Exported routine for checking a user's access privileges to a database + */ +AclResult +pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode) +{ + if (pg_database_aclmask(db_oid, roleid, mode, ACLMASK_ANY) != 0) + return ACLCHECK_OK; + else + return ACLCHECK_NO_PRIV; +} + +/* + * Exported routine for checking a user's access privileges to a function + */ +AclResult +pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode) +{ + if (pg_proc_aclmask(proc_oid, roleid, mode, ACLMASK_ANY) != 0) + return ACLCHECK_OK; + else + return ACLCHECK_NO_PRIV; +} + +/* + * Exported routine for checking a user's access privileges to a language + */ +AclResult +pg_language_aclcheck(Oid lang_oid, Oid roleid, AclMode mode) +{ + if (pg_language_aclmask(lang_oid, roleid, mode, ACLMASK_ANY) != 0) + return ACLCHECK_OK; + else + return ACLCHECK_NO_PRIV; +} + +/* + * Exported routine for checking a user's access privileges to a largeobject + */ +AclResult +pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode, + Snapshot snapshot) +{ + if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode, + ACLMASK_ANY, snapshot) != 0) + return ACLCHECK_OK; + else + return ACLCHECK_NO_PRIV; +} + +/* + * Exported routine for checking a user's access privileges to a namespace + */ +AclResult +pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode) +{ + if (pg_namespace_aclmask(nsp_oid, roleid, mode, ACLMASK_ANY) != 0) + return ACLCHECK_OK; + else + return ACLCHECK_NO_PRIV; +} + +/* + * Exported routine for checking a user's access privileges to a tablespace + */ +AclResult +pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode) +{ + if (pg_tablespace_aclmask(spc_oid, roleid, mode, ACLMASK_ANY) != 0) + return ACLCHECK_OK; + else + return ACLCHECK_NO_PRIV; +} + +/* + * Exported routine for checking a user's access privileges to a foreign + * data wrapper + */ +AclResult +pg_foreign_data_wrapper_aclcheck(Oid fdw_oid, Oid roleid, AclMode mode) +{ + if (pg_foreign_data_wrapper_aclmask(fdw_oid, roleid, mode, ACLMASK_ANY) != 0) + return ACLCHECK_OK; + else + return ACLCHECK_NO_PRIV; +} + +/* + * Exported routine for checking a user's access privileges to a foreign + * server + */ +AclResult +pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode) +{ + if (pg_foreign_server_aclmask(srv_oid, roleid, mode, ACLMASK_ANY) != 0) + return ACLCHECK_OK; + else + return ACLCHECK_NO_PRIV; +} + +/* + * Exported routine for checking a user's access privileges to a type + */ +AclResult +pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode) +{ + if (pg_type_aclmask(type_oid, roleid, mode, ACLMASK_ANY) != 0) + return ACLCHECK_OK; + else + return ACLCHECK_NO_PRIV; +} + +/* + * Ownership check for a relation (specified by OID). + */ +bool +pg_class_ownercheck(Oid class_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(class_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("relation with OID %u does not exist", class_oid))); + + ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Ownership check for a type (specified by OID). + */ +bool +pg_type_ownercheck(Oid type_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("type with OID %u does not exist", type_oid))); + + ownerId = ((Form_pg_type) GETSTRUCT(tuple))->typowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Ownership check for an operator (specified by OID). + */ +bool +pg_oper_ownercheck(Oid oper_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(oper_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("operator with OID %u does not exist", oper_oid))); + + ownerId = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Ownership check for a function (specified by OID). + */ +bool +pg_proc_ownercheck(Oid proc_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(proc_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("function with OID %u does not exist", proc_oid))); + + ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Ownership check for a procedural language (specified by OID) + */ +bool +pg_language_ownercheck(Oid lan_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(lan_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("language with OID %u does not exist", lan_oid))); + + ownerId = ((Form_pg_language) GETSTRUCT(tuple))->lanowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Ownership check for a largeobject (specified by OID) + * + * This is only used for operations like ALTER LARGE OBJECT that are always + * relative to an up-to-date snapshot. + */ +bool +pg_largeobject_ownercheck(Oid lobj_oid, Oid roleid) +{ + Relation pg_lo_meta; + ScanKeyData entry[1]; + SysScanDesc scan; + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + /* There's no syscache for pg_largeobject_metadata */ + pg_lo_meta = table_open(LargeObjectMetadataRelationId, + AccessShareLock); + + ScanKeyInit(&entry[0], + Anum_pg_largeobject_metadata_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(lobj_oid)); + + scan = systable_beginscan(pg_lo_meta, + LargeObjectMetadataOidIndexId, true, + NULL, 1, entry); + + tuple = systable_getnext(scan); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("large object %u does not exist", lobj_oid))); + + ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner; + + systable_endscan(scan); + table_close(pg_lo_meta, AccessShareLock); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Ownership check for a namespace (specified by OID). + */ +bool +pg_namespace_ownercheck(Oid nsp_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("schema with OID %u does not exist", nsp_oid))); + + ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Ownership check for a tablespace (specified by OID). + */ +bool +pg_tablespace_ownercheck(Oid spc_oid, Oid roleid) +{ + HeapTuple spctuple; + Oid spcowner; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + /* Search syscache for pg_tablespace */ + spctuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spc_oid)); + if (!HeapTupleIsValid(spctuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tablespace with OID %u does not exist", spc_oid))); + + spcowner = ((Form_pg_tablespace) GETSTRUCT(spctuple))->spcowner; + + ReleaseSysCache(spctuple); + + return has_privs_of_role(roleid, spcowner); +} + +/* + * Ownership check for an operator class (specified by OID). + */ +bool +pg_opclass_ownercheck(Oid opc_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opc_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("operator class with OID %u does not exist", + opc_oid))); + + ownerId = ((Form_pg_opclass) GETSTRUCT(tuple))->opcowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Ownership check for an operator family (specified by OID). + */ +bool +pg_opfamily_ownercheck(Oid opf_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opf_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("operator family with OID %u does not exist", + opf_oid))); + + ownerId = ((Form_pg_opfamily) GETSTRUCT(tuple))->opfowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Ownership check for a text search dictionary (specified by OID). + */ +bool +pg_ts_dict_ownercheck(Oid dict_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dict_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("text search dictionary with OID %u does not exist", + dict_oid))); + + ownerId = ((Form_pg_ts_dict) GETSTRUCT(tuple))->dictowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Ownership check for a text search configuration (specified by OID). + */ +bool +pg_ts_config_ownercheck(Oid cfg_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfg_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("text search configuration with OID %u does not exist", + cfg_oid))); + + ownerId = ((Form_pg_ts_config) GETSTRUCT(tuple))->cfgowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Ownership check for a foreign-data wrapper (specified by OID). + */ +bool +pg_foreign_data_wrapper_ownercheck(Oid srv_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(srv_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("foreign-data wrapper with OID %u does not exist", + srv_oid))); + + ownerId = ((Form_pg_foreign_data_wrapper) GETSTRUCT(tuple))->fdwowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Ownership check for a foreign server (specified by OID). + */ +bool +pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srv_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("foreign server with OID %u does not exist", + srv_oid))); + + ownerId = ((Form_pg_foreign_server) GETSTRUCT(tuple))->srvowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Ownership check for an event trigger (specified by OID). + */ +bool +pg_event_trigger_ownercheck(Oid et_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(EVENTTRIGGEROID, ObjectIdGetDatum(et_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("event trigger with OID %u does not exist", + et_oid))); + + ownerId = ((Form_pg_event_trigger) GETSTRUCT(tuple))->evtowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Ownership check for a database (specified by OID). + */ +bool +pg_database_ownercheck(Oid db_oid, Oid roleid) +{ + HeapTuple tuple; + Oid dba; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(db_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("database with OID %u does not exist", db_oid))); + + dba = ((Form_pg_database) GETSTRUCT(tuple))->datdba; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, dba); +} + +/* + * Ownership check for a collation (specified by OID). + */ +bool +pg_collation_ownercheck(Oid coll_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(COLLOID, ObjectIdGetDatum(coll_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("collation with OID %u does not exist", coll_oid))); + + ownerId = ((Form_pg_collation) GETSTRUCT(tuple))->collowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Ownership check for a conversion (specified by OID). + */ +bool +pg_conversion_ownercheck(Oid conv_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(CONVOID, ObjectIdGetDatum(conv_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("conversion with OID %u does not exist", conv_oid))); + + ownerId = ((Form_pg_conversion) GETSTRUCT(tuple))->conowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Ownership check for an extension (specified by OID). + */ +bool +pg_extension_ownercheck(Oid ext_oid, Oid roleid) +{ + Relation pg_extension; + ScanKeyData entry[1]; + SysScanDesc scan; + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + /* There's no syscache for pg_extension, so do it the hard way */ + pg_extension = table_open(ExtensionRelationId, AccessShareLock); + + ScanKeyInit(&entry[0], + Anum_pg_extension_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(ext_oid)); + + scan = systable_beginscan(pg_extension, + ExtensionOidIndexId, true, + NULL, 1, entry); + + tuple = systable_getnext(scan); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("extension with OID %u does not exist", ext_oid))); + + ownerId = ((Form_pg_extension) GETSTRUCT(tuple))->extowner; + + systable_endscan(scan); + table_close(pg_extension, AccessShareLock); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Ownership check for a publication (specified by OID). + */ +bool +pg_publication_ownercheck(Oid pub_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pub_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("publication with OID %u does not exist", pub_oid))); + + ownerId = ((Form_pg_publication) GETSTRUCT(tuple))->pubowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Ownership check for a subscription (specified by OID). + */ +bool +pg_subscription_ownercheck(Oid sub_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(SUBSCRIPTIONOID, ObjectIdGetDatum(sub_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("subscription with OID %u does not exist", sub_oid))); + + ownerId = ((Form_pg_subscription) GETSTRUCT(tuple))->subowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Ownership check for a statistics object (specified by OID). + */ +bool +pg_statistics_object_ownercheck(Oid stat_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(stat_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("statistics object with OID %u does not exist", + stat_oid))); + + ownerId = ((Form_pg_statistic_ext) GETSTRUCT(tuple))->stxowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + +/* + * Check whether specified role has CREATEROLE privilege (or is a superuser) + * + * Note: roles do not have owners per se; instead we use this test in + * places where an ownership-like permissions test is needed for a role. + * Be sure to apply it to the role trying to do the operation, not the + * role being operated on! Also note that this generally should not be + * considered enough privilege if the target role is a superuser. + * (We don't handle that consideration here because we want to give a + * separate error message for such cases, so the caller has to deal with it.) + */ +bool +has_createrole_privilege(Oid roleid) +{ + bool result = false; + HeapTuple utup; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid)); + if (HeapTupleIsValid(utup)) + { + result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole; + ReleaseSysCache(utup); + } + return result; +} + +bool +has_bypassrls_privilege(Oid roleid) +{ + bool result = false; + HeapTuple utup; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid)); + if (HeapTupleIsValid(utup)) + { + result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls; + ReleaseSysCache(utup); + } + return result; +} + +/* + * Fetch pg_default_acl entry for given role, namespace and object type + * (object type must be given in pg_default_acl's encoding). + * Returns NULL if no such entry. + */ +static Acl * +get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype) +{ + Acl *result = NULL; + HeapTuple tuple; + + tuple = SearchSysCache3(DEFACLROLENSPOBJ, + ObjectIdGetDatum(roleId), + ObjectIdGetDatum(nsp_oid), + CharGetDatum(objtype)); + + if (HeapTupleIsValid(tuple)) + { + Datum aclDatum; + bool isNull; + + aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple, + Anum_pg_default_acl_defaclacl, + &isNull); + if (!isNull) + result = DatumGetAclPCopy(aclDatum); + ReleaseSysCache(tuple); + } + + return result; +} + +/* + * Get default permissions for newly created object within given schema + * + * Returns NULL if built-in system defaults should be used. + * + * If the result is not NULL, caller must call recordDependencyOnNewAcl + * once the OID of the new object is known. + */ +Acl * +get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid) +{ + Acl *result; + Acl *glob_acl; + Acl *schema_acl; + Acl *def_acl; + char defaclobjtype; + + /* + * Use NULL during bootstrap, since pg_default_acl probably isn't there + * yet. + */ + if (IsBootstrapProcessingMode()) + return NULL; + + /* Check if object type is supported in pg_default_acl */ + switch (objtype) + { + case OBJECT_TABLE: + defaclobjtype = DEFACLOBJ_RELATION; + break; + + case OBJECT_SEQUENCE: + defaclobjtype = DEFACLOBJ_SEQUENCE; + break; + + case OBJECT_FUNCTION: + defaclobjtype = DEFACLOBJ_FUNCTION; + break; + + case OBJECT_TYPE: + defaclobjtype = DEFACLOBJ_TYPE; + break; + + case OBJECT_SCHEMA: + defaclobjtype = DEFACLOBJ_NAMESPACE; + break; + + default: + return NULL; + } + + /* Look up the relevant pg_default_acl entries */ + glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype); + schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype); + + /* Quick out if neither entry exists */ + if (glob_acl == NULL && schema_acl == NULL) + return NULL; + + /* We need to know the hard-wired default value, too */ + def_acl = acldefault(objtype, ownerId); + + /* If there's no global entry, substitute the hard-wired default */ + if (glob_acl == NULL) + glob_acl = def_acl; + + /* Merge in any per-schema privileges */ + result = aclmerge(glob_acl, schema_acl, ownerId); + + /* + * For efficiency, we want to return NULL if the result equals default. + * This requires sorting both arrays to get an accurate comparison. + */ + aclitemsort(result); + aclitemsort(def_acl); + if (aclequal(result, def_acl)) + result = NULL; + + return result; +} + +/* + * Record dependencies on roles mentioned in a new object's ACL. + */ +void +recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId, + Oid ownerId, Acl *acl) +{ + int nmembers; + Oid *members; + + /* Nothing to do if ACL is defaulted */ + if (acl == NULL) + return; + + /* Extract roles mentioned in ACL */ + nmembers = aclmembers(acl, &members); + + /* Update the shared dependency ACL info */ + updateAclDependencies(classId, objectId, objsubId, + ownerId, + 0, NULL, + nmembers, members); +} + +/* + * Record initial privileges for the top-level object passed in. + * + * For the object passed in, this will record its ACL (if any) and the ACLs of + * any sub-objects (eg: columns) into pg_init_privs. + * + * Any new kinds of objects which have ACLs associated with them and can be + * added to an extension should be added to the if-else tree below. + */ +void +recordExtObjInitPriv(Oid objoid, Oid classoid) +{ + /* + * pg_class / pg_attribute + * + * If this is a relation then we need to see if there are any sub-objects + * (eg: columns) for it and, if so, be sure to call + * recordExtensionInitPrivWorker() for each one. + */ + if (classoid == RelationRelationId) + { + Form_pg_class pg_class_tuple; + Datum aclDatum; + bool isNull; + HeapTuple tuple; + + tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", objoid); + pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple); + + /* + * Indexes don't have permissions, neither do the pg_class rows for + * composite types. (These cases are unreachable given the + * restrictions in ALTER EXTENSION ADD, but let's check anyway.) + */ + if (pg_class_tuple->relkind == RELKIND_INDEX || + pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX || + pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE) + { + ReleaseSysCache(tuple); + return; + } + + /* + * If this isn't a sequence then it's possibly going to have + * column-level ACLs associated with it. + */ + if (pg_class_tuple->relkind != RELKIND_SEQUENCE) + { + AttrNumber curr_att; + AttrNumber nattrs = pg_class_tuple->relnatts; + + for (curr_att = 1; curr_att <= nattrs; curr_att++) + { + HeapTuple attTuple; + Datum attaclDatum; + + attTuple = SearchSysCache2(ATTNUM, + ObjectIdGetDatum(objoid), + Int16GetDatum(curr_att)); + + if (!HeapTupleIsValid(attTuple)) + continue; + + /* ignore dropped columns */ + if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped) + { + ReleaseSysCache(attTuple); + continue; + } + + attaclDatum = SysCacheGetAttr(ATTNUM, attTuple, + Anum_pg_attribute_attacl, + &isNull); + + /* no need to do anything for a NULL ACL */ + if (isNull) + { + ReleaseSysCache(attTuple); + continue; + } + + recordExtensionInitPrivWorker(objoid, classoid, curr_att, + DatumGetAclP(attaclDatum)); + + ReleaseSysCache(attTuple); + } + } + + aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl, + &isNull); + + /* Add the record, if any, for the top-level object */ + if (!isNull) + recordExtensionInitPrivWorker(objoid, classoid, 0, + DatumGetAclP(aclDatum)); + + ReleaseSysCache(tuple); + } + /* pg_foreign_data_wrapper */ + else if (classoid == ForeignDataWrapperRelationId) + { + Datum aclDatum; + bool isNull; + HeapTuple tuple; + + tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID, + ObjectIdGetDatum(objoid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for foreign data wrapper %u", + objoid); + + aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple, + Anum_pg_foreign_data_wrapper_fdwacl, + &isNull); + + /* Add the record, if any, for the top-level object */ + if (!isNull) + recordExtensionInitPrivWorker(objoid, classoid, 0, + DatumGetAclP(aclDatum)); + + ReleaseSysCache(tuple); + } + /* pg_foreign_server */ + else if (classoid == ForeignServerRelationId) + { + Datum aclDatum; + bool isNull; + HeapTuple tuple; + + tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(objoid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for foreign data wrapper %u", + objoid); + + aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple, + Anum_pg_foreign_server_srvacl, + &isNull); + + /* Add the record, if any, for the top-level object */ + if (!isNull) + recordExtensionInitPrivWorker(objoid, classoid, 0, + DatumGetAclP(aclDatum)); + + ReleaseSysCache(tuple); + } + /* pg_language */ + else if (classoid == LanguageRelationId) + { + Datum aclDatum; + bool isNull; + HeapTuple tuple; + + tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(objoid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for language %u", objoid); + + aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl, + &isNull); + + /* Add the record, if any, for the top-level object */ + if (!isNull) + recordExtensionInitPrivWorker(objoid, classoid, 0, + DatumGetAclP(aclDatum)); + + ReleaseSysCache(tuple); + } + /* pg_largeobject_metadata */ + else if (classoid == LargeObjectMetadataRelationId) + { + Datum aclDatum; + bool isNull; + HeapTuple tuple; + ScanKeyData entry[1]; + SysScanDesc scan; + Relation relation; + + /* + * Note: this is dead code, given that we don't allow large objects to + * be made extension members. But it seems worth carrying in case + * some future caller of this function has need for it. + */ + relation = table_open(LargeObjectMetadataRelationId, RowExclusiveLock); + + /* There's no syscache for pg_largeobject_metadata */ + ScanKeyInit(&entry[0], + Anum_pg_largeobject_metadata_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objoid)); + + scan = systable_beginscan(relation, + LargeObjectMetadataOidIndexId, true, + NULL, 1, entry); + + tuple = systable_getnext(scan); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "could not find tuple for large object %u", objoid); + + aclDatum = heap_getattr(tuple, + Anum_pg_largeobject_metadata_lomacl, + RelationGetDescr(relation), &isNull); + + /* Add the record, if any, for the top-level object */ + if (!isNull) + recordExtensionInitPrivWorker(objoid, classoid, 0, + DatumGetAclP(aclDatum)); + + systable_endscan(scan); + } + /* pg_namespace */ + else if (classoid == NamespaceRelationId) + { + Datum aclDatum; + bool isNull; + HeapTuple tuple; + + tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(objoid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for function %u", objoid); + + aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, + Anum_pg_namespace_nspacl, &isNull); + + /* Add the record, if any, for the top-level object */ + if (!isNull) + recordExtensionInitPrivWorker(objoid, classoid, 0, + DatumGetAclP(aclDatum)); + + ReleaseSysCache(tuple); + } + /* pg_proc */ + else if (classoid == ProcedureRelationId) + { + Datum aclDatum; + bool isNull; + HeapTuple tuple; + + tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(objoid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for function %u", objoid); + + aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl, + &isNull); + + /* Add the record, if any, for the top-level object */ + if (!isNull) + recordExtensionInitPrivWorker(objoid, classoid, 0, + DatumGetAclP(aclDatum)); + + ReleaseSysCache(tuple); + } + /* pg_type */ + else if (classoid == TypeRelationId) + { + Datum aclDatum; + bool isNull; + HeapTuple tuple; + + tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(objoid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for function %u", objoid); + + aclDatum = SysCacheGetAttr(TYPEOID, tuple, Anum_pg_type_typacl, + &isNull); + + /* Add the record, if any, for the top-level object */ + if (!isNull) + recordExtensionInitPrivWorker(objoid, classoid, 0, + DatumGetAclP(aclDatum)); + + ReleaseSysCache(tuple); + } + else if (classoid == AccessMethodRelationId || + classoid == AggregateRelationId || + classoid == CastRelationId || + classoid == CollationRelationId || + classoid == ConversionRelationId || + classoid == EventTriggerRelationId || + classoid == OperatorRelationId || + classoid == OperatorClassRelationId || + classoid == OperatorFamilyRelationId || + classoid == NamespaceRelationId || + classoid == TSConfigRelationId || + classoid == TSDictionaryRelationId || + classoid == TSParserRelationId || + classoid == TSTemplateRelationId || + classoid == TransformRelationId + ) + { + /* no ACL for these object types, so do nothing. */ + } + + /* + * complain if we are given a class OID for a class that extensions don't + * support or that we don't recognize. + */ + else + { + elog(ERROR, "unrecognized or unsupported class OID: %u", classoid); + } +} + +/* + * For the object passed in, remove its ACL and the ACLs of any object subIds + * from pg_init_privs (via recordExtensionInitPrivWorker()). + */ +void +removeExtObjInitPriv(Oid objoid, Oid classoid) +{ + /* + * If this is a relation then we need to see if there are any sub-objects + * (eg: columns) for it and, if so, be sure to call + * recordExtensionInitPrivWorker() for each one. + */ + if (classoid == RelationRelationId) + { + Form_pg_class pg_class_tuple; + HeapTuple tuple; + + tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", objoid); + pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple); + + /* + * Indexes don't have permissions, neither do the pg_class rows for + * composite types. (These cases are unreachable given the + * restrictions in ALTER EXTENSION DROP, but let's check anyway.) + */ + if (pg_class_tuple->relkind == RELKIND_INDEX || + pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX || + pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE) + { + ReleaseSysCache(tuple); + return; + } + + /* + * If this isn't a sequence then it's possibly going to have + * column-level ACLs associated with it. + */ + if (pg_class_tuple->relkind != RELKIND_SEQUENCE) + { + AttrNumber curr_att; + AttrNumber nattrs = pg_class_tuple->relnatts; + + for (curr_att = 1; curr_att <= nattrs; curr_att++) + { + HeapTuple attTuple; + + attTuple = SearchSysCache2(ATTNUM, + ObjectIdGetDatum(objoid), + Int16GetDatum(curr_att)); + + if (!HeapTupleIsValid(attTuple)) + continue; + + /* when removing, remove all entries, even dropped columns */ + + recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL); + + ReleaseSysCache(attTuple); + } + } + + ReleaseSysCache(tuple); + } + + /* Remove the record, if any, for the top-level object */ + recordExtensionInitPrivWorker(objoid, classoid, 0, NULL); +} + +/* + * Record initial ACL for an extension object + * + * Can be called at any time, we check if 'creating_extension' is set and, if + * not, exit immediately. + * + * Pass in the object OID, the OID of the class (the OID of the table which + * the object is defined in) and the 'sub' id of the object (objsubid), if + * any. If there is no 'sub' id (they are currently only used for columns of + * tables) then pass in '0'. Finally, pass in the complete ACL to store. + * + * If an ACL already exists for this object/sub-object then we will replace + * it with what is passed in. + * + * Passing in NULL for 'new_acl' will result in the entry for the object being + * removed, if one is found. + */ +static void +recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl) +{ + /* + * Generally, we only record the initial privileges when an extension is + * being created, but because we don't actually use CREATE EXTENSION + * during binary upgrades with pg_upgrade, there is a variable to let us + * know that the GRANT and REVOKE statements being issued, while this + * variable is true, are for the initial privileges of the extension + * object and therefore we need to record them. + */ + if (!creating_extension && !binary_upgrade_record_init_privs) + return; + + recordExtensionInitPrivWorker(objoid, classoid, objsubid, new_acl); +} + +/* + * Record initial ACL for an extension object, worker. + * + * This will perform a wholesale replacement of the entire ACL for the object + * passed in, therefore be sure to pass in the complete new ACL to use. + * + * Generally speaking, do *not* use this function directly but instead use + * recordExtensionInitPriv(), which checks if 'creating_extension' is set. + * This function does *not* check if 'creating_extension' is set as it is also + * used when an object is added to or removed from an extension via ALTER + * EXTENSION ... ADD/DROP. + */ +static void +recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, Acl *new_acl) +{ + Relation relation; + ScanKeyData key[3]; + SysScanDesc scan; + HeapTuple tuple; + HeapTuple oldtuple; + + relation = table_open(InitPrivsRelationId, RowExclusiveLock); + + ScanKeyInit(&key[0], + Anum_pg_init_privs_objoid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objoid)); + ScanKeyInit(&key[1], + Anum_pg_init_privs_classoid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(classoid)); + ScanKeyInit(&key[2], + Anum_pg_init_privs_objsubid, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(objsubid)); + + scan = systable_beginscan(relation, InitPrivsObjIndexId, true, + NULL, 3, key); + + /* There should exist only one entry or none. */ + oldtuple = systable_getnext(scan); + + /* If we find an entry, update it with the latest ACL. */ + if (HeapTupleIsValid(oldtuple)) + { + Datum values[Natts_pg_init_privs]; + bool nulls[Natts_pg_init_privs]; + bool replace[Natts_pg_init_privs]; + + /* If we have a new ACL to set, then update the row with it. */ + if (new_acl) + { + MemSet(values, 0, sizeof(values)); + MemSet(nulls, false, sizeof(nulls)); + MemSet(replace, false, sizeof(replace)); + + values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl); + replace[Anum_pg_init_privs_initprivs - 1] = true; + + oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation), + values, nulls, replace); + + CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple); + } + else + { + /* new_acl is NULL, so delete the entry we found. */ + CatalogTupleDelete(relation, &oldtuple->t_self); + } + } + else + { + Datum values[Natts_pg_init_privs]; + bool nulls[Natts_pg_init_privs]; + + /* + * Only add a new entry if the new ACL is non-NULL. + * + * If we are passed in a NULL ACL and no entry exists, we can just + * fall through and do nothing. + */ + if (new_acl) + { + /* No entry found, so add it. */ + MemSet(nulls, false, sizeof(nulls)); + + values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid); + values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid); + values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid); + + /* This function only handles initial privileges of extensions */ + values[Anum_pg_init_privs_privtype - 1] = + CharGetDatum(INITPRIVS_EXTENSION); + + values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl); + + tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls); + + CatalogTupleInsert(relation, tuple); + } + } + + systable_endscan(scan); + + /* prevent error when processing objects multiple times */ + CommandCounterIncrement(); + + table_close(relation, RowExclusiveLock); +} diff --git a/src/backend/catalog/bki-stamp b/src/backend/catalog/bki-stamp new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/backend/catalog/bki-stamp diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c new file mode 100644 index 0000000..7d6acae --- /dev/null +++ b/src/backend/catalog/catalog.c @@ -0,0 +1,533 @@ +/*------------------------------------------------------------------------- + * + * catalog.c + * routines concerned with catalog naming conventions and other + * bits of hard-wired knowledge + * + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/catalog.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include <fcntl.h> +#include <unistd.h> + +#include "access/genam.h" +#include "access/htup_details.h" +#include "access/sysattr.h" +#include "access/table.h" +#include "access/transam.h" +#include "catalog/catalog.h" +#include "catalog/indexing.h" +#include "catalog/namespace.h" +#include "catalog/pg_auth_members.h" +#include "catalog/pg_authid.h" +#include "catalog/pg_database.h" +#include "catalog/pg_db_role_setting.h" +#include "catalog/pg_namespace.h" +#include "catalog/pg_replication_origin.h" +#include "catalog/pg_shdepend.h" +#include "catalog/pg_shdescription.h" +#include "catalog/pg_shseclabel.h" +#include "catalog/pg_subscription.h" +#include "catalog/pg_tablespace.h" +#include "catalog/pg_type.h" +#include "catalog/toasting.h" +#include "miscadmin.h" +#include "storage/fd.h" +#include "utils/fmgroids.h" +#include "utils/fmgrprotos.h" +#include "utils/rel.h" +#include "utils/snapmgr.h" +#include "utils/syscache.h" + +/* + * IsSystemRelation + * True iff the relation is either a system catalog or a toast table. + * See IsCatalogRelation for the exact definition of a system catalog. + * + * We treat toast tables of user relations as "system relations" for + * protection purposes, e.g. you can't change their schemas without + * special permissions. Therefore, most uses of this function are + * checking whether allow_system_table_mods restrictions apply. + * For other purposes, consider whether you shouldn't be using + * IsCatalogRelation instead. + * + * This function does not perform any catalog accesses. + * Some callers rely on that! + */ +bool +IsSystemRelation(Relation relation) +{ + return IsSystemClass(RelationGetRelid(relation), relation->rd_rel); +} + +/* + * IsSystemClass + * Like the above, but takes a Form_pg_class as argument. + * Used when we do not want to open the relation and have to + * search pg_class directly. + */ +bool +IsSystemClass(Oid relid, Form_pg_class reltuple) +{ + /* IsCatalogRelationOid is a bit faster, so test that first */ + return (IsCatalogRelationOid(relid) || IsToastClass(reltuple)); +} + +/* + * IsCatalogRelation + * True iff the relation is a system catalog. + * + * By a system catalog, we mean one that is created during the bootstrap + * phase of initdb. That includes not just the catalogs per se, but + * also their indexes, and TOAST tables and indexes if any. + * + * This function does not perform any catalog accesses. + * Some callers rely on that! + */ +bool +IsCatalogRelation(Relation relation) +{ + return IsCatalogRelationOid(RelationGetRelid(relation)); +} + +/* + * IsCatalogRelationOid + * True iff the relation identified by this OID is a system catalog. + * + * By a system catalog, we mean one that is created during the bootstrap + * phase of initdb. That includes not just the catalogs per se, but + * also their indexes, and TOAST tables and indexes if any. + * + * This function does not perform any catalog accesses. + * Some callers rely on that! + */ +bool +IsCatalogRelationOid(Oid relid) +{ + /* + * We consider a relation to be a system catalog if it has an OID that was + * manually assigned or assigned by genbki.pl. This includes all the + * defined catalogs, their indexes, and their TOAST tables and indexes. + * + * This rule excludes the relations in information_schema, which are not + * integral to the system and can be treated the same as user relations. + * (Since it's valid to drop and recreate information_schema, any rule + * that did not act this way would be wrong.) + * + * This test is reliable since an OID wraparound will skip this range of + * OIDs; see GetNewObjectId(). + */ + return (relid < (Oid) FirstBootstrapObjectId); +} + +/* + * IsToastRelation + * True iff relation is a TOAST support relation (or index). + * + * Does not perform any catalog accesses. + */ +bool +IsToastRelation(Relation relation) +{ + /* + * What we actually check is whether the relation belongs to a pg_toast + * namespace. This should be equivalent because of restrictions that are + * enforced elsewhere against creating user relations in, or moving + * relations into/out of, a pg_toast namespace. Notice also that this + * will not say "true" for toast tables belonging to other sessions' temp + * tables; we expect that other mechanisms will prevent access to those. + */ + return IsToastNamespace(RelationGetNamespace(relation)); +} + +/* + * IsToastClass + * Like the above, but takes a Form_pg_class as argument. + * Used when we do not want to open the relation and have to + * search pg_class directly. + */ +bool +IsToastClass(Form_pg_class reltuple) +{ + Oid relnamespace = reltuple->relnamespace; + + return IsToastNamespace(relnamespace); +} + +/* + * IsCatalogNamespace + * True iff namespace is pg_catalog. + * + * Does not perform any catalog accesses. + * + * NOTE: the reason this isn't a macro is to avoid having to include + * catalog/pg_namespace.h in a lot of places. + */ +bool +IsCatalogNamespace(Oid namespaceId) +{ + return namespaceId == PG_CATALOG_NAMESPACE; +} + +/* + * IsToastNamespace + * True iff namespace is pg_toast or my temporary-toast-table namespace. + * + * Does not perform any catalog accesses. + * + * Note: this will return false for temporary-toast-table namespaces belonging + * to other backends. Those are treated the same as other backends' regular + * temp table namespaces, and access is prevented where appropriate. + * If you need to check for those, you may be able to use isAnyTempNamespace, + * but beware that that does involve a catalog access. + */ +bool +IsToastNamespace(Oid namespaceId) +{ + return (namespaceId == PG_TOAST_NAMESPACE) || + isTempToastNamespace(namespaceId); +} + + +/* + * IsReservedName + * True iff name starts with the pg_ prefix. + * + * For some classes of objects, the prefix pg_ is reserved for + * system objects only. As of 8.0, this was only true for + * schema and tablespace names. With 9.6, this is also true + * for roles. + */ +bool +IsReservedName(const char *name) +{ + /* ugly coding for speed */ + return (name[0] == 'p' && + name[1] == 'g' && + name[2] == '_'); +} + + +/* + * IsSharedRelation + * Given the OID of a relation, determine whether it's supposed to be + * shared across an entire database cluster. + * + * In older releases, this had to be hard-wired so that we could compute the + * locktag for a relation and lock it before examining its catalog entry. + * Since we now have MVCC catalog access, the race conditions that made that + * a hard requirement are gone, so we could look at relaxing this restriction. + * However, if we scanned the pg_class entry to find relisshared, and only + * then locked the relation, pg_class could get updated in the meantime, + * forcing us to scan the relation again, which would definitely be complex + * and might have undesirable performance consequences. Fortunately, the set + * of shared relations is fairly static, so a hand-maintained list of their + * OIDs isn't completely impractical. + */ +bool +IsSharedRelation(Oid relationId) +{ + /* These are the shared catalogs (look for BKI_SHARED_RELATION) */ + if (relationId == AuthIdRelationId || + relationId == AuthMemRelationId || + relationId == DatabaseRelationId || + relationId == SharedDescriptionRelationId || + relationId == SharedDependRelationId || + relationId == SharedSecLabelRelationId || + relationId == TableSpaceRelationId || + relationId == DbRoleSettingRelationId || + relationId == ReplicationOriginRelationId || + relationId == SubscriptionRelationId) + return true; + /* These are their indexes (see indexing.h) */ + if (relationId == AuthIdRolnameIndexId || + relationId == AuthIdOidIndexId || + relationId == AuthMemRoleMemIndexId || + relationId == AuthMemMemRoleIndexId || + relationId == DatabaseNameIndexId || + relationId == DatabaseOidIndexId || + relationId == SharedDescriptionObjIndexId || + relationId == SharedDependDependerIndexId || + relationId == SharedDependReferenceIndexId || + relationId == SharedSecLabelObjectIndexId || + relationId == TablespaceOidIndexId || + relationId == TablespaceNameIndexId || + relationId == DbRoleSettingDatidRolidIndexId || + relationId == ReplicationOriginIdentIndex || + relationId == ReplicationOriginNameIndex || + relationId == SubscriptionObjectIndexId || + relationId == SubscriptionNameIndexId) + return true; + /* These are their toast tables and toast indexes (see toasting.h) */ + if (relationId == PgAuthidToastTable || + relationId == PgAuthidToastIndex || + relationId == PgDatabaseToastTable || + relationId == PgDatabaseToastIndex || + relationId == PgDbRoleSettingToastTable || + relationId == PgDbRoleSettingToastIndex || + relationId == PgReplicationOriginToastTable || + relationId == PgReplicationOriginToastIndex || + relationId == PgShdescriptionToastTable || + relationId == PgShdescriptionToastIndex || + relationId == PgShseclabelToastTable || + relationId == PgShseclabelToastIndex || + relationId == PgSubscriptionToastTable || + relationId == PgSubscriptionToastIndex || + relationId == PgTablespaceToastTable || + relationId == PgTablespaceToastIndex) + return true; + return false; +} + + +/* + * GetNewOidWithIndex + * Generate a new OID that is unique within the system relation. + * + * Since the OID is not immediately inserted into the table, there is a + * race condition here; but a problem could occur only if someone else + * managed to cycle through 2^32 OIDs and generate the same OID before we + * finish inserting our row. This seems unlikely to be a problem. Note + * that if we had to *commit* the row to end the race condition, the risk + * would be rather higher; therefore we use SnapshotAny in the test, so that + * we will see uncommitted rows. (We used to use SnapshotDirty, but that has + * the disadvantage that it ignores recently-deleted rows, creating a risk + * of transient conflicts for as long as our own MVCC snapshots think a + * recently-deleted row is live. The risk is far higher when selecting TOAST + * OIDs, because SnapshotToast considers dead rows as active indefinitely.) + * + * Note that we are effectively assuming that the table has a relatively small + * number of entries (much less than 2^32) and there aren't very long runs of + * consecutive existing OIDs. This is a mostly reasonable assumption for + * system catalogs. + * + * Caller must have a suitable lock on the relation. + */ +Oid +GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn) +{ + Oid newOid; + SysScanDesc scan; + ScanKeyData key; + bool collides; + + /* Only system relations are supported */ + Assert(IsSystemRelation(relation)); + + /* In bootstrap mode, we don't have any indexes to use */ + if (IsBootstrapProcessingMode()) + return GetNewObjectId(); + + /* + * We should never be asked to generate a new pg_type OID during + * pg_upgrade; doing so would risk collisions with the OIDs it wants to + * assign. Hitting this assert means there's some path where we failed to + * ensure that a type OID is determined by commands in the dump script. + */ + Assert(!IsBinaryUpgrade || RelationGetRelid(relation) != TypeRelationId); + + /* Generate new OIDs until we find one not in the table */ + do + { + CHECK_FOR_INTERRUPTS(); + + newOid = GetNewObjectId(); + + ScanKeyInit(&key, + oidcolumn, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(newOid)); + + /* see notes above about using SnapshotAny */ + scan = systable_beginscan(relation, indexId, true, + SnapshotAny, 1, &key); + + collides = HeapTupleIsValid(systable_getnext(scan)); + + systable_endscan(scan); + } while (collides); + + return newOid; +} + +/* + * GetNewRelFileNode + * Generate a new relfilenode number that is unique within the + * database of the given tablespace. + * + * If the relfilenode will also be used as the relation's OID, pass the + * opened pg_class catalog, and this routine will guarantee that the result + * is also an unused OID within pg_class. If the result is to be used only + * as a relfilenode for an existing relation, pass NULL for pg_class. + * + * As with GetNewOidWithIndex(), there is some theoretical risk of a race + * condition, but it doesn't seem worth worrying about. + * + * Note: we don't support using this in bootstrap mode. All relations + * created by bootstrap have preassigned OIDs, so there's no need. + */ +Oid +GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence) +{ + RelFileNodeBackend rnode; + char *rpath; + bool collides; + BackendId backend; + + /* + * If we ever get here during pg_upgrade, there's something wrong; all + * relfilenode assignments during a binary-upgrade run should be + * determined by commands in the dump script. + */ + Assert(!IsBinaryUpgrade); + + switch (relpersistence) + { + case RELPERSISTENCE_TEMP: + backend = BackendIdForTempRelations(); + break; + case RELPERSISTENCE_UNLOGGED: + case RELPERSISTENCE_PERMANENT: + backend = InvalidBackendId; + break; + default: + elog(ERROR, "invalid relpersistence: %c", relpersistence); + return InvalidOid; /* placate compiler */ + } + + /* This logic should match RelationInitPhysicalAddr */ + rnode.node.spcNode = reltablespace ? reltablespace : MyDatabaseTableSpace; + rnode.node.dbNode = (rnode.node.spcNode == GLOBALTABLESPACE_OID) ? InvalidOid : MyDatabaseId; + + /* + * The relpath will vary based on the backend ID, so we must initialize + * that properly here to make sure that any collisions based on filename + * are properly detected. + */ + rnode.backend = backend; + + do + { + CHECK_FOR_INTERRUPTS(); + + /* Generate the OID */ + if (pg_class) + rnode.node.relNode = GetNewOidWithIndex(pg_class, ClassOidIndexId, + Anum_pg_class_oid); + else + rnode.node.relNode = GetNewObjectId(); + + /* Check for existing file of same name */ + rpath = relpath(rnode, MAIN_FORKNUM); + + if (access(rpath, F_OK) == 0) + { + /* definite collision */ + collides = true; + } + else + { + /* + * Here we have a little bit of a dilemma: if errno is something + * other than ENOENT, should we declare a collision and loop? In + * practice it seems best to go ahead regardless of the errno. If + * there is a colliding file we will get an smgr failure when we + * attempt to create the new relation file. + */ + collides = false; + } + + pfree(rpath); + } while (collides); + + return rnode.node.relNode; +} + +/* + * SQL callable interface for GetNewOidWithIndex(). Outside of initdb's + * direct insertions into catalog tables, and recovering from corruption, this + * should rarely be needed. + * + * Function is intentionally not documented in the user facing docs. + */ +Datum +pg_nextoid(PG_FUNCTION_ARGS) +{ + Oid reloid = PG_GETARG_OID(0); + Name attname = PG_GETARG_NAME(1); + Oid idxoid = PG_GETARG_OID(2); + Relation rel; + Relation idx; + HeapTuple atttuple; + Form_pg_attribute attform; + AttrNumber attno; + Oid newoid; + + /* + * As this function is not intended to be used during normal running, and + * only supports system catalogs (which require superuser permissions to + * modify), just checking for superuser ought to not obstruct valid + * usecases. + */ + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to call pg_nextoid()"))); + + rel = table_open(reloid, RowExclusiveLock); + idx = index_open(idxoid, RowExclusiveLock); + + if (!IsSystemRelation(rel)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("pg_nextoid() can only be used on system catalogs"))); + + if (idx->rd_index->indrelid != RelationGetRelid(rel)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("index \"%s\" does not belong to table \"%s\"", + RelationGetRelationName(idx), + RelationGetRelationName(rel)))); + + atttuple = SearchSysCacheAttName(reloid, NameStr(*attname)); + if (!HeapTupleIsValid(atttuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + NameStr(*attname), RelationGetRelationName(rel)))); + + attform = ((Form_pg_attribute) GETSTRUCT(atttuple)); + attno = attform->attnum; + + if (attform->atttypid != OIDOID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("column \"%s\" is not of type oid", + NameStr(*attname)))); + + if (IndexRelationGetNumberOfKeyAttributes(idx) != 1 || + idx->rd_index->indkey.values[0] != attno) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("index \"%s\" is not the index for column \"%s\"", + RelationGetRelationName(idx), + NameStr(*attname)))); + + newoid = GetNewOidWithIndex(rel, idxoid, attno); + + ReleaseSysCache(atttuple); + table_close(rel, RowExclusiveLock); + index_close(idx, RowExclusiveLock); + + return newoid; +} diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c new file mode 100644 index 0000000..5565e6f --- /dev/null +++ b/src/backend/catalog/dependency.c @@ -0,0 +1,2894 @@ +/*------------------------------------------------------------------------- + * + * dependency.c + * Routines to support inter-object dependencies. + * + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/catalog/dependency.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/genam.h" +#include "access/htup_details.h" +#include "access/table.h" +#include "access/xact.h" +#include "catalog/dependency.h" +#include "catalog/heap.h" +#include "catalog/index.h" +#include "catalog/objectaccess.h" +#include "catalog/pg_am.h" +#include "catalog/pg_amop.h" +#include "catalog/pg_amproc.h" +#include "catalog/pg_attrdef.h" +#include "catalog/pg_authid.h" +#include "catalog/pg_cast.h" +#include "catalog/pg_collation.h" +#include "catalog/pg_constraint.h" +#include "catalog/pg_conversion.h" +#include "catalog/pg_database.h" +#include "catalog/pg_default_acl.h" +#include "catalog/pg_depend.h" +#include "catalog/pg_event_trigger.h" +#include "catalog/pg_extension.h" +#include "catalog/pg_foreign_data_wrapper.h" +#include "catalog/pg_foreign_server.h" +#include "catalog/pg_init_privs.h" +#include "catalog/pg_language.h" +#include "catalog/pg_largeobject.h" +#include "catalog/pg_namespace.h" +#include "catalog/pg_opclass.h" +#include "catalog/pg_operator.h" +#include "catalog/pg_opfamily.h" +#include "catalog/pg_policy.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_publication.h" +#include "catalog/pg_publication_rel.h" +#include "catalog/pg_rewrite.h" +#include "catalog/pg_statistic_ext.h" +#include "catalog/pg_subscription.h" +#include "catalog/pg_tablespace.h" +#include "catalog/pg_transform.h" +#include "catalog/pg_trigger.h" +#include "catalog/pg_ts_config.h" +#include "catalog/pg_ts_dict.h" +#include "catalog/pg_ts_parser.h" +#include "catalog/pg_ts_template.h" +#include "catalog/pg_type.h" +#include "catalog/pg_user_mapping.h" +#include "commands/comment.h" +#include "commands/defrem.h" +#include "commands/event_trigger.h" +#include "commands/extension.h" +#include "commands/policy.h" +#include "commands/proclang.h" +#include "commands/publicationcmds.h" +#include "commands/schemacmds.h" +#include "commands/seclabel.h" +#include "commands/sequence.h" +#include "commands/trigger.h" +#include "commands/typecmds.h" +#include "nodes/nodeFuncs.h" +#include "parser/parsetree.h" +#include "rewrite/rewriteRemove.h" +#include "storage/lmgr.h" +#include "utils/acl.h" +#include "utils/fmgroids.h" +#include "utils/guc.h" +#include "utils/lsyscache.h" +#include "utils/syscache.h" + + +/* + * Deletion processing requires additional state for each ObjectAddress that + * it's planning to delete. For simplicity and code-sharing we make the + * ObjectAddresses code support arrays with or without this extra state. + */ +typedef struct +{ + int flags; /* bitmask, see bit definitions below */ + ObjectAddress dependee; /* object whose deletion forced this one */ +} ObjectAddressExtra; + +/* ObjectAddressExtra flag bits */ +#define DEPFLAG_ORIGINAL 0x0001 /* an original deletion target */ +#define DEPFLAG_NORMAL 0x0002 /* reached via normal dependency */ +#define DEPFLAG_AUTO 0x0004 /* reached via auto dependency */ +#define DEPFLAG_INTERNAL 0x0008 /* reached via internal dependency */ +#define DEPFLAG_PARTITION 0x0010 /* reached via partition dependency */ +#define DEPFLAG_EXTENSION 0x0020 /* reached via extension dependency */ +#define DEPFLAG_REVERSE 0x0040 /* reverse internal/extension link */ +#define DEPFLAG_IS_PART 0x0080 /* has a partition dependency */ +#define DEPFLAG_SUBOBJECT 0x0100 /* subobject of another deletable object */ + + +/* expansible list of ObjectAddresses */ +struct ObjectAddresses +{ + ObjectAddress *refs; /* => palloc'd array */ + ObjectAddressExtra *extras; /* => palloc'd array, or NULL if not used */ + int numrefs; /* current number of references */ + int maxrefs; /* current size of palloc'd array(s) */ +}; + +/* typedef ObjectAddresses appears in dependency.h */ + +/* threaded list of ObjectAddresses, for recursion detection */ +typedef struct ObjectAddressStack +{ + const ObjectAddress *object; /* object being visited */ + int flags; /* its current flag bits */ + struct ObjectAddressStack *next; /* next outer stack level */ +} ObjectAddressStack; + +/* temporary storage in findDependentObjects */ +typedef struct +{ + ObjectAddress obj; /* object to be deleted --- MUST BE FIRST */ + int subflags; /* flags to pass down when recursing to obj */ +} ObjectAddressAndFlags; + +/* for find_expr_references_walker */ +typedef struct +{ + ObjectAddresses *addrs; /* addresses being accumulated */ + List *rtables; /* list of rangetables to resolve Vars */ +} find_expr_references_context; + +/* + * This constant table maps ObjectClasses to the corresponding catalog OIDs. + * See also getObjectClass(). + */ +static const Oid object_classes[] = { + RelationRelationId, /* OCLASS_CLASS */ + ProcedureRelationId, /* OCLASS_PROC */ + TypeRelationId, /* OCLASS_TYPE */ + CastRelationId, /* OCLASS_CAST */ + CollationRelationId, /* OCLASS_COLLATION */ + ConstraintRelationId, /* OCLASS_CONSTRAINT */ + ConversionRelationId, /* OCLASS_CONVERSION */ + AttrDefaultRelationId, /* OCLASS_DEFAULT */ + LanguageRelationId, /* OCLASS_LANGUAGE */ + LargeObjectRelationId, /* OCLASS_LARGEOBJECT */ + OperatorRelationId, /* OCLASS_OPERATOR */ + OperatorClassRelationId, /* OCLASS_OPCLASS */ + OperatorFamilyRelationId, /* OCLASS_OPFAMILY */ + AccessMethodRelationId, /* OCLASS_AM */ + AccessMethodOperatorRelationId, /* OCLASS_AMOP */ + AccessMethodProcedureRelationId, /* OCLASS_AMPROC */ + RewriteRelationId, /* OCLASS_REWRITE */ + TriggerRelationId, /* OCLASS_TRIGGER */ + NamespaceRelationId, /* OCLASS_SCHEMA */ + StatisticExtRelationId, /* OCLASS_STATISTIC_EXT */ + TSParserRelationId, /* OCLASS_TSPARSER */ + TSDictionaryRelationId, /* OCLASS_TSDICT */ + TSTemplateRelationId, /* OCLASS_TSTEMPLATE */ + TSConfigRelationId, /* OCLASS_TSCONFIG */ + AuthIdRelationId, /* OCLASS_ROLE */ + DatabaseRelationId, /* OCLASS_DATABASE */ + TableSpaceRelationId, /* OCLASS_TBLSPACE */ + ForeignDataWrapperRelationId, /* OCLASS_FDW */ + ForeignServerRelationId, /* OCLASS_FOREIGN_SERVER */ + UserMappingRelationId, /* OCLASS_USER_MAPPING */ + DefaultAclRelationId, /* OCLASS_DEFACL */ + ExtensionRelationId, /* OCLASS_EXTENSION */ + EventTriggerRelationId, /* OCLASS_EVENT_TRIGGER */ + PolicyRelationId, /* OCLASS_POLICY */ + PublicationRelationId, /* OCLASS_PUBLICATION */ + PublicationRelRelationId, /* OCLASS_PUBLICATION_REL */ + SubscriptionRelationId, /* OCLASS_SUBSCRIPTION */ + TransformRelationId /* OCLASS_TRANSFORM */ +}; + + +static void findDependentObjects(const ObjectAddress *object, + int objflags, + int flags, + ObjectAddressStack *stack, + ObjectAddresses *targetObjects, + const ObjectAddresses *pendingObjects, + Relation *depRel); +static void reportDependentObjects(const ObjectAddresses *targetObjects, + DropBehavior behavior, + int flags, + const ObjectAddress *origObject); +static void deleteOneObject(const ObjectAddress *object, + Relation *depRel, int32 flags); +static void doDeletion(const ObjectAddress *object, int flags); +static bool find_expr_references_walker(Node *node, + find_expr_references_context *context); +static void eliminate_duplicate_dependencies(ObjectAddresses *addrs); +static int object_address_comparator(const void *a, const void *b); +static void add_object_address(ObjectClass oclass, Oid objectId, int32 subId, + ObjectAddresses *addrs); +static void add_exact_object_address_extra(const ObjectAddress *object, + const ObjectAddressExtra *extra, + ObjectAddresses *addrs); +static bool object_address_present_add_flags(const ObjectAddress *object, + int flags, + ObjectAddresses *addrs); +static bool stack_address_present_add_flags(const ObjectAddress *object, + int flags, + ObjectAddressStack *stack); +static void DeleteInitPrivs(const ObjectAddress *object); + + +/* + * Go through the objects given running the final actions on them, and execute + * the actual deletion. + */ +static void +deleteObjectsInList(ObjectAddresses *targetObjects, Relation *depRel, + int flags) +{ + int i; + + /* + * Keep track of objects for event triggers, if necessary. + */ + if (trackDroppedObjectsNeeded() && !(flags & PERFORM_DELETION_INTERNAL)) + { + for (i = 0; i < targetObjects->numrefs; i++) + { + const ObjectAddress *thisobj = &targetObjects->refs[i]; + const ObjectAddressExtra *extra = &targetObjects->extras[i]; + bool original = false; + bool normal = false; + + if (extra->flags & DEPFLAG_ORIGINAL) + original = true; + if (extra->flags & DEPFLAG_NORMAL) + normal = true; + if (extra->flags & DEPFLAG_REVERSE) + normal = true; + + if (EventTriggerSupportsObjectClass(getObjectClass(thisobj))) + { + EventTriggerSQLDropAddObject(thisobj, original, normal); + } + } + } + + /* + * Delete all the objects in the proper order, except that if told to, we + * should skip the original object(s). + */ + for (i = 0; i < targetObjects->numrefs; i++) + { + ObjectAddress *thisobj = targetObjects->refs + i; + ObjectAddressExtra *thisextra = targetObjects->extras + i; + + if ((flags & PERFORM_DELETION_SKIP_ORIGINAL) && + (thisextra->flags & DEPFLAG_ORIGINAL)) + continue; + + deleteOneObject(thisobj, depRel, flags); + } +} + +/* + * performDeletion: attempt to drop the specified object. If CASCADE + * behavior is specified, also drop any dependent objects (recursively). + * If RESTRICT behavior is specified, error out if there are any dependent + * objects, except for those that should be implicitly dropped anyway + * according to the dependency type. + * + * This is the outer control routine for all forms of DROP that drop objects + * that can participate in dependencies. Note that performMultipleDeletions + * is a variant on the same theme; if you change anything here you'll likely + * need to fix that too. + * + * Bits in the flags argument can include: + * + * PERFORM_DELETION_INTERNAL: indicates that the drop operation is not the + * direct result of a user-initiated action. For example, when a temporary + * schema is cleaned out so that a new backend can use it, or when a column + * default is dropped as an intermediate step while adding a new one, that's + * an internal operation. On the other hand, when we drop something because + * the user issued a DROP statement against it, that's not internal. Currently + * this suppresses calling event triggers and making some permissions checks. + * + * PERFORM_DELETION_CONCURRENTLY: perform the drop concurrently. This does + * not currently work for anything except dropping indexes; don't set it for + * other object types or you may get strange results. + * + * PERFORM_DELETION_QUIETLY: reduce message level from NOTICE to DEBUG2. + * + * PERFORM_DELETION_SKIP_ORIGINAL: do not delete the specified object(s), + * but only what depends on it/them. + * + * PERFORM_DELETION_SKIP_EXTENSIONS: do not delete extensions, even when + * deleting objects that are part of an extension. This should generally + * be used only when dropping temporary objects. + * + * PERFORM_DELETION_CONCURRENT_LOCK: perform the drop normally but with a lock + * as if it were concurrent. This is used by REINDEX CONCURRENTLY. + * + */ +void +performDeletion(const ObjectAddress *object, + DropBehavior behavior, int flags) +{ + Relation depRel; + ObjectAddresses *targetObjects; + + /* + * We save some cycles by opening pg_depend just once and passing the + * Relation pointer down to all the recursive deletion steps. + */ + depRel = table_open(DependRelationId, RowExclusiveLock); + + /* + * Acquire deletion lock on the target object. (Ideally the caller has + * done this already, but many places are sloppy about it.) + */ + AcquireDeletionLock(object, 0); + + /* + * Construct a list of objects to delete (ie, the given object plus + * everything directly or indirectly dependent on it). + */ + targetObjects = new_object_addresses(); + + findDependentObjects(object, + DEPFLAG_ORIGINAL, + flags, + NULL, /* empty stack */ + targetObjects, + NULL, /* no pendingObjects */ + &depRel); + + /* + * Check if deletion is allowed, and report about cascaded deletes. + */ + reportDependentObjects(targetObjects, + behavior, + flags, + object); + + /* do the deed */ + deleteObjectsInList(targetObjects, &depRel, flags); + + /* And clean up */ + free_object_addresses(targetObjects); + + table_close(depRel, RowExclusiveLock); +} + +/* + * performMultipleDeletions: Similar to performDeletion, but act on multiple + * objects at once. + * + * The main difference from issuing multiple performDeletion calls is that the + * list of objects that would be implicitly dropped, for each object to be + * dropped, is the union of the implicit-object list for all objects. This + * makes each check be more relaxed. + */ +void +performMultipleDeletions(const ObjectAddresses *objects, + DropBehavior behavior, int flags) +{ + Relation depRel; + ObjectAddresses *targetObjects; + int i; + + /* No work if no objects... */ + if (objects->numrefs <= 0) + return; + + /* + * We save some cycles by opening pg_depend just once and passing the + * Relation pointer down to all the recursive deletion steps. + */ + depRel = table_open(DependRelationId, RowExclusiveLock); + + /* + * Construct a list of objects to delete (ie, the given objects plus + * everything directly or indirectly dependent on them). Note that + * because we pass the whole objects list as pendingObjects context, we + * won't get a failure from trying to delete an object that is internally + * dependent on another one in the list; we'll just skip that object and + * delete it when we reach its owner. + */ + targetObjects = new_object_addresses(); + + for (i = 0; i < objects->numrefs; i++) + { + const ObjectAddress *thisobj = objects->refs + i; + + /* + * Acquire deletion lock on each target object. (Ideally the caller + * has done this already, but many places are sloppy about it.) + */ + AcquireDeletionLock(thisobj, flags); + + findDependentObjects(thisobj, + DEPFLAG_ORIGINAL, + flags, + NULL, /* empty stack */ + targetObjects, + objects, + &depRel); + } + + /* + * Check if deletion is allowed, and report about cascaded deletes. + * + * If there's exactly one object being deleted, report it the same way as + * in performDeletion(), else we have to be vaguer. + */ + reportDependentObjects(targetObjects, + behavior, + flags, + (objects->numrefs == 1 ? objects->refs : NULL)); + + /* do the deed */ + deleteObjectsInList(targetObjects, &depRel, flags); + + /* And clean up */ + free_object_addresses(targetObjects); + + table_close(depRel, RowExclusiveLock); +} + +/* + * findDependentObjects - find all objects that depend on 'object' + * + * For every object that depends on the starting object, acquire a deletion + * lock on the object, add it to targetObjects (if not already there), + * and recursively find objects that depend on it. An object's dependencies + * will be placed into targetObjects before the object itself; this means + * that the finished list's order represents a safe deletion order. + * + * The caller must already have a deletion lock on 'object' itself, + * but must not have added it to targetObjects. (Note: there are corner + * cases where we won't add the object either, and will also release the + * caller-taken lock. This is a bit ugly, but the API is set up this way + * to allow easy rechecking of an object's liveness after we lock it. See + * notes within the function.) + * + * When dropping a whole object (subId = 0), we find dependencies for + * its sub-objects too. + * + * object: the object to add to targetObjects and find dependencies on + * objflags: flags to be ORed into the object's targetObjects entry + * flags: PERFORM_DELETION_xxx flags for the deletion operation as a whole + * stack: list of objects being visited in current recursion; topmost item + * is the object that we recursed from (NULL for external callers) + * targetObjects: list of objects that are scheduled to be deleted + * pendingObjects: list of other objects slated for destruction, but + * not necessarily in targetObjects yet (can be NULL if none) + * *depRel: already opened pg_depend relation + * + * Note: objflags describes the reason for visiting this particular object + * at this time, and is not passed down when recursing. The flags argument + * is passed down, since it describes what we're doing overall. + */ +static void +findDependentObjects(const ObjectAddress *object, + int objflags, + int flags, + ObjectAddressStack *stack, + ObjectAddresses *targetObjects, + const ObjectAddresses *pendingObjects, + Relation *depRel) +{ + ScanKeyData key[3]; + int nkeys; + SysScanDesc scan; + HeapTuple tup; + ObjectAddress otherObject; + ObjectAddress owningObject; + ObjectAddress partitionObject; + ObjectAddressAndFlags *dependentObjects; + int numDependentObjects; + int maxDependentObjects; + ObjectAddressStack mystack; + ObjectAddressExtra extra; + + /* + * If the target object is already being visited in an outer recursion + * level, just report the current objflags back to that level and exit. + * This is needed to avoid infinite recursion in the face of circular + * dependencies. + * + * The stack check alone would result in dependency loops being broken at + * an arbitrary point, ie, the first member object of the loop to be + * visited is the last one to be deleted. This is obviously unworkable. + * However, the check for internal dependency below guarantees that we + * will not break a loop at an internal dependency: if we enter the loop + * at an "owned" object we will switch and start at the "owning" object + * instead. We could probably hack something up to avoid breaking at an + * auto dependency, too, if we had to. However there are no known cases + * where that would be necessary. + */ + if (stack_address_present_add_flags(object, objflags, stack)) + return; + + /* + * It's also possible that the target object has already been completely + * processed and put into targetObjects. If so, again we just add the + * specified objflags to its entry and return. + * + * (Note: in these early-exit cases we could release the caller-taken + * lock, since the object is presumably now locked multiple times; but it + * seems not worth the cycles.) + */ + if (object_address_present_add_flags(object, objflags, targetObjects)) + return; + + /* + * The target object might be internally dependent on some other object + * (its "owner"), and/or be a member of an extension (also considered its + * owner). If so, and if we aren't recursing from the owning object, we + * have to transform this deletion request into a deletion request of the + * owning object. (We'll eventually recurse back to this object, but the + * owning object has to be visited first so it will be deleted after.) The + * way to find out about this is to scan the pg_depend entries that show + * what this object depends on. + */ + ScanKeyInit(&key[0], + Anum_pg_depend_classid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->classId)); + ScanKeyInit(&key[1], + Anum_pg_depend_objid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + if (object->objectSubId != 0) + { + /* Consider only dependencies of this sub-object */ + ScanKeyInit(&key[2], + Anum_pg_depend_objsubid, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(object->objectSubId)); + nkeys = 3; + } + else + { + /* Consider dependencies of this object and any sub-objects it has */ + nkeys = 2; + } + + scan = systable_beginscan(*depRel, DependDependerIndexId, true, + NULL, nkeys, key); + + /* initialize variables that loop may fill */ + memset(&owningObject, 0, sizeof(owningObject)); + memset(&partitionObject, 0, sizeof(partitionObject)); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup); + + otherObject.classId = foundDep->refclassid; + otherObject.objectId = foundDep->refobjid; + otherObject.objectSubId = foundDep->refobjsubid; + + /* + * When scanning dependencies of a whole object, we may find rows + * linking sub-objects of the object to the object itself. (Normally, + * such a dependency is implicit, but we must make explicit ones in + * some cases involving partitioning.) We must ignore such rows to + * avoid infinite recursion. + */ + if (otherObject.classId == object->classId && + otherObject.objectId == object->objectId && + object->objectSubId == 0) + continue; + + switch (foundDep->deptype) + { + case DEPENDENCY_NORMAL: + case DEPENDENCY_AUTO: + case DEPENDENCY_AUTO_EXTENSION: + /* no problem */ + break; + + case DEPENDENCY_EXTENSION: + + /* + * If told to, ignore EXTENSION dependencies altogether. This + * flag is normally used to prevent dropping extensions during + * temporary-object cleanup, even if a temp object was created + * during an extension script. + */ + if (flags & PERFORM_DELETION_SKIP_EXTENSIONS) + break; + + /* + * If the other object is the extension currently being + * created/altered, ignore this dependency and continue with + * the deletion. This allows dropping of an extension's + * objects within the extension's scripts, as well as corner + * cases such as dropping a transient object created within + * such a script. + */ + if (creating_extension && + otherObject.classId == ExtensionRelationId && + otherObject.objectId == CurrentExtensionObject) + break; + + /* Otherwise, treat this like an internal dependency */ + /* FALL THRU */ + + case DEPENDENCY_INTERNAL: + + /* + * This object is part of the internal implementation of + * another object, or is part of the extension that is the + * other object. We have three cases: + * + * 1. At the outermost recursion level, we must disallow the + * DROP. However, if the owning object is listed in + * pendingObjects, just release the caller's lock and return; + * we'll eventually complete the DROP when we reach that entry + * in the pending list. + * + * Note: the above statement is true only if this pg_depend + * entry still exists by then; in principle, therefore, we + * could miss deleting an item the user told us to delete. + * However, no inconsistency can result: since we're at outer + * level, there is no object depending on this one. + */ + if (stack == NULL) + { + if (pendingObjects && + object_address_present(&otherObject, pendingObjects)) + { + systable_endscan(scan); + /* need to release caller's lock; see notes below */ + ReleaseDeletionLock(object); + return; + } + + /* + * We postpone actually issuing the error message until + * after this loop, so that we can make the behavior + * independent of the ordering of pg_depend entries, at + * least if there's not more than one INTERNAL and one + * EXTENSION dependency. (If there's more, we'll complain + * about a random one of them.) Prefer to complain about + * EXTENSION, since that's generally a more important + * dependency. + */ + if (!OidIsValid(owningObject.classId) || + foundDep->deptype == DEPENDENCY_EXTENSION) + owningObject = otherObject; + break; + } + + /* + * 2. When recursing from the other end of this dependency, + * it's okay to continue with the deletion. This holds when + * recursing from a whole object that includes the nominal + * other end as a component, too. Since there can be more + * than one "owning" object, we have to allow matches that are + * more than one level down in the stack. + */ + if (stack_address_present_add_flags(&otherObject, 0, stack)) + break; + + /* + * 3. Not all the owning objects have been visited, so + * transform this deletion request into a delete of this + * owning object. + * + * First, release caller's lock on this object and get + * deletion lock on the owning object. (We must release + * caller's lock to avoid deadlock against a concurrent + * deletion of the owning object.) + */ + ReleaseDeletionLock(object); + AcquireDeletionLock(&otherObject, 0); + + /* + * The owning object might have been deleted while we waited + * to lock it; if so, neither it nor the current object are + * interesting anymore. We test this by checking the + * pg_depend entry (see notes below). + */ + if (!systable_recheck_tuple(scan, tup)) + { + systable_endscan(scan); + ReleaseDeletionLock(&otherObject); + return; + } + + /* + * One way or the other, we're done with the scan; might as + * well close it down before recursing, to reduce peak + * resource consumption. + */ + systable_endscan(scan); + + /* + * Okay, recurse to the owning object instead of proceeding. + * + * We do not need to stack the current object; we want the + * traversal order to be as if the original reference had + * linked to the owning object instead of this one. + * + * The dependency type is a "reverse" dependency: we need to + * delete the owning object if this one is to be deleted, but + * this linkage is never a reason for an automatic deletion. + */ + findDependentObjects(&otherObject, + DEPFLAG_REVERSE, + flags, + stack, + targetObjects, + pendingObjects, + depRel); + + /* + * The current target object should have been added to + * targetObjects while processing the owning object; but it + * probably got only the flag bits associated with the + * dependency we're looking at. We need to add the objflags + * that were passed to this recursion level, too, else we may + * get a bogus failure in reportDependentObjects (if, for + * example, we were called due to a partition dependency). + * + * If somehow the current object didn't get scheduled for + * deletion, bleat. (That would imply that somebody deleted + * this dependency record before the recursion got to it.) + * Another idea would be to reacquire lock on the current + * object and resume trying to delete it, but it seems not + * worth dealing with the race conditions inherent in that. + */ + if (!object_address_present_add_flags(object, objflags, + targetObjects)) + elog(ERROR, "deletion of owning object %s failed to delete %s", + getObjectDescription(&otherObject), + getObjectDescription(object)); + + /* And we're done here. */ + return; + + case DEPENDENCY_PARTITION_PRI: + + /* + * Remember that this object has a partition-type dependency. + * After the dependency scan, we'll complain if we didn't find + * a reason to delete one of its partition dependencies. + */ + objflags |= DEPFLAG_IS_PART; + + /* + * Also remember the primary partition owner, for error + * messages. If there are multiple primary owners (which + * there should not be), we'll report a random one of them. + */ + partitionObject = otherObject; + break; + + case DEPENDENCY_PARTITION_SEC: + + /* + * Only use secondary partition owners in error messages if we + * find no primary owner (which probably shouldn't happen). + */ + if (!(objflags & DEPFLAG_IS_PART)) + partitionObject = otherObject; + + /* + * Remember that this object has a partition-type dependency. + * After the dependency scan, we'll complain if we didn't find + * a reason to delete one of its partition dependencies. + */ + objflags |= DEPFLAG_IS_PART; + break; + + case DEPENDENCY_PIN: + + /* + * Should not happen; PIN dependencies should have zeroes in + * the depender fields... + */ + elog(ERROR, "incorrect use of PIN dependency with %s", + getObjectDescription(object)); + break; + default: + elog(ERROR, "unrecognized dependency type '%c' for %s", + foundDep->deptype, getObjectDescription(object)); + break; + } + } + + systable_endscan(scan); + + /* + * If we found an INTERNAL or EXTENSION dependency when we're at outer + * level, complain about it now. If we also found a PARTITION dependency, + * we prefer to report the PARTITION dependency. This is arbitrary but + * seems to be more useful in practice. + */ + if (OidIsValid(owningObject.classId)) + { + char *otherObjDesc; + + if (OidIsValid(partitionObject.classId)) + otherObjDesc = getObjectDescription(&partitionObject); + else + otherObjDesc = getObjectDescription(&owningObject); + + ereport(ERROR, + (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), + errmsg("cannot drop %s because %s requires it", + getObjectDescription(object), otherObjDesc), + errhint("You can drop %s instead.", otherObjDesc))); + } + + /* + * Next, identify all objects that directly depend on the current object. + * To ensure predictable deletion order, we collect them up in + * dependentObjects and sort the list before actually recursing. (The + * deletion order would be valid in any case, but doing this ensures + * consistent output from DROP CASCADE commands, which is helpful for + * regression testing.) + */ + maxDependentObjects = 128; /* arbitrary initial allocation */ + dependentObjects = (ObjectAddressAndFlags *) + palloc(maxDependentObjects * sizeof(ObjectAddressAndFlags)); + numDependentObjects = 0; + + ScanKeyInit(&key[0], + Anum_pg_depend_refclassid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->classId)); + ScanKeyInit(&key[1], + Anum_pg_depend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + if (object->objectSubId != 0) + { + ScanKeyInit(&key[2], + Anum_pg_depend_refobjsubid, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(object->objectSubId)); + nkeys = 3; + } + else + nkeys = 2; + + scan = systable_beginscan(*depRel, DependReferenceIndexId, true, + NULL, nkeys, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup); + int subflags; + + otherObject.classId = foundDep->classid; + otherObject.objectId = foundDep->objid; + otherObject.objectSubId = foundDep->objsubid; + + /* + * If what we found is a sub-object of the current object, just ignore + * it. (Normally, such a dependency is implicit, but we must make + * explicit ones in some cases involving partitioning.) + */ + if (otherObject.classId == object->classId && + otherObject.objectId == object->objectId && + object->objectSubId == 0) + continue; + + /* + * Must lock the dependent object before recursing to it. + */ + AcquireDeletionLock(&otherObject, 0); + + /* + * The dependent object might have been deleted while we waited to + * lock it; if so, we don't need to do anything more with it. We can + * test this cheaply and independently of the object's type by seeing + * if the pg_depend tuple we are looking at is still live. (If the + * object got deleted, the tuple would have been deleted too.) + */ + if (!systable_recheck_tuple(scan, tup)) + { + /* release the now-useless lock */ + ReleaseDeletionLock(&otherObject); + /* and continue scanning for dependencies */ + continue; + } + + /* + * We do need to delete it, so identify objflags to be passed down, + * which depend on the dependency type. + */ + switch (foundDep->deptype) + { + case DEPENDENCY_NORMAL: + subflags = DEPFLAG_NORMAL; + break; + case DEPENDENCY_AUTO: + case DEPENDENCY_AUTO_EXTENSION: + subflags = DEPFLAG_AUTO; + break; + case DEPENDENCY_INTERNAL: + subflags = DEPFLAG_INTERNAL; + break; + case DEPENDENCY_PARTITION_PRI: + case DEPENDENCY_PARTITION_SEC: + subflags = DEPFLAG_PARTITION; + break; + case DEPENDENCY_EXTENSION: + subflags = DEPFLAG_EXTENSION; + break; + case DEPENDENCY_PIN: + + /* + * For a PIN dependency we just ereport immediately; there + * won't be any others to report. + */ + ereport(ERROR, + (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), + errmsg("cannot drop %s because it is required by the database system", + getObjectDescription(object)))); + subflags = 0; /* keep compiler quiet */ + break; + default: + elog(ERROR, "unrecognized dependency type '%c' for %s", + foundDep->deptype, getObjectDescription(object)); + subflags = 0; /* keep compiler quiet */ + break; + } + + /* And add it to the pending-objects list */ + if (numDependentObjects >= maxDependentObjects) + { + /* enlarge array if needed */ + maxDependentObjects *= 2; + dependentObjects = (ObjectAddressAndFlags *) + repalloc(dependentObjects, + maxDependentObjects * sizeof(ObjectAddressAndFlags)); + } + + dependentObjects[numDependentObjects].obj = otherObject; + dependentObjects[numDependentObjects].subflags = subflags; + numDependentObjects++; + } + + systable_endscan(scan); + + /* + * Now we can sort the dependent objects into a stable visitation order. + * It's safe to use object_address_comparator here since the obj field is + * first within ObjectAddressAndFlags. + */ + if (numDependentObjects > 1) + qsort((void *) dependentObjects, numDependentObjects, + sizeof(ObjectAddressAndFlags), + object_address_comparator); + + /* + * Now recurse to the dependent objects. We must visit them first since + * they have to be deleted before the current object. + */ + mystack.object = object; /* set up a new stack level */ + mystack.flags = objflags; + mystack.next = stack; + + for (int i = 0; i < numDependentObjects; i++) + { + ObjectAddressAndFlags *depObj = dependentObjects + i; + + findDependentObjects(&depObj->obj, + depObj->subflags, + flags, + &mystack, + targetObjects, + pendingObjects, + depRel); + } + + pfree(dependentObjects); + + /* + * Finally, we can add the target object to targetObjects. Be careful to + * include any flags that were passed back down to us from inner recursion + * levels. Record the "dependee" as being either the most important + * partition owner if there is one, else the object we recursed from, if + * any. (The logic in reportDependentObjects() is such that it can only + * need one of those objects.) + */ + extra.flags = mystack.flags; + if (extra.flags & DEPFLAG_IS_PART) + extra.dependee = partitionObject; + else if (stack) + extra.dependee = *stack->object; + else + memset(&extra.dependee, 0, sizeof(extra.dependee)); + add_exact_object_address_extra(object, &extra, targetObjects); +} + +/* + * reportDependentObjects - report about dependencies, and fail if RESTRICT + * + * Tell the user about dependent objects that we are going to delete + * (or would need to delete, but are prevented by RESTRICT mode); + * then error out if there are any and it's not CASCADE mode. + * + * targetObjects: list of objects that are scheduled to be deleted + * behavior: RESTRICT or CASCADE + * flags: other flags for the deletion operation + * origObject: base object of deletion, or NULL if not available + * (the latter case occurs in DROP OWNED) + */ +static void +reportDependentObjects(const ObjectAddresses *targetObjects, + DropBehavior behavior, + int flags, + const ObjectAddress *origObject) +{ + int msglevel = (flags & PERFORM_DELETION_QUIETLY) ? DEBUG2 : NOTICE; + bool ok = true; + StringInfoData clientdetail; + StringInfoData logdetail; + int numReportedClient = 0; + int numNotReportedClient = 0; + int i; + + /* + * If we need to delete any partition-dependent objects, make sure that + * we're deleting at least one of their partition dependencies, too. That + * can be detected by checking that we reached them by a PARTITION + * dependency at some point. + * + * We just report the first such object, as in most cases the only way to + * trigger this complaint is to explicitly try to delete one partition of + * a partitioned object. + */ + for (i = 0; i < targetObjects->numrefs; i++) + { + const ObjectAddressExtra *extra = &targetObjects->extras[i]; + + if ((extra->flags & DEPFLAG_IS_PART) && + !(extra->flags & DEPFLAG_PARTITION)) + { + const ObjectAddress *object = &targetObjects->refs[i]; + char *otherObjDesc = getObjectDescription(&extra->dependee); + + ereport(ERROR, + (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), + errmsg("cannot drop %s because %s requires it", + getObjectDescription(object), otherObjDesc), + errhint("You can drop %s instead.", otherObjDesc))); + } + } + + /* + * If no error is to be thrown, and the msglevel is too low to be shown to + * either client or server log, there's no need to do any of the rest of + * the work. + * + * Note: this code doesn't know all there is to be known about elog + * levels, but it works for NOTICE and DEBUG2, which are the only values + * msglevel can currently have. We also assume we are running in a normal + * operating environment. + */ + if (behavior == DROP_CASCADE && + msglevel < client_min_messages && + (msglevel < log_min_messages || log_min_messages == LOG)) + return; + + /* + * We limit the number of dependencies reported to the client to + * MAX_REPORTED_DEPS, since client software may not deal well with + * enormous error strings. The server log always gets a full report. + */ +#define MAX_REPORTED_DEPS 100 + + initStringInfo(&clientdetail); + initStringInfo(&logdetail); + + /* + * We process the list back to front (ie, in dependency order not deletion + * order), since this makes for a more understandable display. + */ + for (i = targetObjects->numrefs - 1; i >= 0; i--) + { + const ObjectAddress *obj = &targetObjects->refs[i]; + const ObjectAddressExtra *extra = &targetObjects->extras[i]; + char *objDesc; + + /* Ignore the original deletion target(s) */ + if (extra->flags & DEPFLAG_ORIGINAL) + continue; + + /* Also ignore sub-objects; we'll report the whole object elsewhere */ + if (extra->flags & DEPFLAG_SUBOBJECT) + continue; + + objDesc = getObjectDescription(obj); + + /* + * If, at any stage of the recursive search, we reached the object via + * an AUTO, INTERNAL, PARTITION, or EXTENSION dependency, then it's + * okay to delete it even in RESTRICT mode. + */ + if (extra->flags & (DEPFLAG_AUTO | + DEPFLAG_INTERNAL | + DEPFLAG_PARTITION | + DEPFLAG_EXTENSION)) + { + /* + * auto-cascades are reported at DEBUG2, not msglevel. We don't + * try to combine them with the regular message because the + * results are too confusing when client_min_messages and + * log_min_messages are different. + */ + ereport(DEBUG2, + (errmsg("drop auto-cascades to %s", + objDesc))); + } + else if (behavior == DROP_RESTRICT) + { + char *otherDesc = getObjectDescription(&extra->dependee); + + if (numReportedClient < MAX_REPORTED_DEPS) + { + /* separate entries with a newline */ + if (clientdetail.len != 0) + appendStringInfoChar(&clientdetail, '\n'); + appendStringInfo(&clientdetail, _("%s depends on %s"), + objDesc, otherDesc); + numReportedClient++; + } + else + numNotReportedClient++; + /* separate entries with a newline */ + if (logdetail.len != 0) + appendStringInfoChar(&logdetail, '\n'); + appendStringInfo(&logdetail, _("%s depends on %s"), + objDesc, otherDesc); + pfree(otherDesc); + ok = false; + } + else + { + if (numReportedClient < MAX_REPORTED_DEPS) + { + /* separate entries with a newline */ + if (clientdetail.len != 0) + appendStringInfoChar(&clientdetail, '\n'); + appendStringInfo(&clientdetail, _("drop cascades to %s"), + objDesc); + numReportedClient++; + } + else + numNotReportedClient++; + /* separate entries with a newline */ + if (logdetail.len != 0) + appendStringInfoChar(&logdetail, '\n'); + appendStringInfo(&logdetail, _("drop cascades to %s"), + objDesc); + } + + pfree(objDesc); + } + + if (numNotReportedClient > 0) + appendStringInfo(&clientdetail, ngettext("\nand %d other object " + "(see server log for list)", + "\nand %d other objects " + "(see server log for list)", + numNotReportedClient), + numNotReportedClient); + + if (!ok) + { + if (origObject) + ereport(ERROR, + (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), + errmsg("cannot drop %s because other objects depend on it", + getObjectDescription(origObject)), + errdetail("%s", clientdetail.data), + errdetail_log("%s", logdetail.data), + errhint("Use DROP ... CASCADE to drop the dependent objects too."))); + else + ereport(ERROR, + (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), + errmsg("cannot drop desired object(s) because other objects depend on them"), + errdetail("%s", clientdetail.data), + errdetail_log("%s", logdetail.data), + errhint("Use DROP ... CASCADE to drop the dependent objects too."))); + } + else if (numReportedClient > 1) + { + ereport(msglevel, + /* translator: %d always has a value larger than 1 */ + (errmsg_plural("drop cascades to %d other object", + "drop cascades to %d other objects", + numReportedClient + numNotReportedClient, + numReportedClient + numNotReportedClient), + errdetail("%s", clientdetail.data), + errdetail_log("%s", logdetail.data))); + } + else if (numReportedClient == 1) + { + /* we just use the single item as-is */ + ereport(msglevel, + (errmsg_internal("%s", clientdetail.data))); + } + + pfree(clientdetail.data); + pfree(logdetail.data); +} + +/* + * deleteOneObject: delete a single object for performDeletion. + * + * *depRel is the already-open pg_depend relation. + */ +static void +deleteOneObject(const ObjectAddress *object, Relation *depRel, int flags) +{ + ScanKeyData key[3]; + int nkeys; + SysScanDesc scan; + HeapTuple tup; + + /* DROP hook of the objects being removed */ + InvokeObjectDropHookArg(object->classId, object->objectId, + object->objectSubId, flags); + + /* + * Close depRel if we are doing a drop concurrently. The object deletion + * subroutine will commit the current transaction, so we can't keep the + * relation open across doDeletion(). + */ + if (flags & PERFORM_DELETION_CONCURRENTLY) + table_close(*depRel, RowExclusiveLock); + + /* + * Delete the object itself, in an object-type-dependent way. + * + * We used to do this after removing the outgoing dependency links, but it + * seems just as reasonable to do it beforehand. In the concurrent case + * we *must* do it in this order, because we can't make any transactional + * updates before calling doDeletion() --- they'd get committed right + * away, which is not cool if the deletion then fails. + */ + doDeletion(object, flags); + + /* + * Reopen depRel if we closed it above + */ + if (flags & PERFORM_DELETION_CONCURRENTLY) + *depRel = table_open(DependRelationId, RowExclusiveLock); + + /* + * Now remove any pg_depend records that link from this object to others. + * (Any records linking to this object should be gone already.) + * + * When dropping a whole object (subId = 0), remove all pg_depend records + * for its sub-objects too. + */ + ScanKeyInit(&key[0], + Anum_pg_depend_classid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->classId)); + ScanKeyInit(&key[1], + Anum_pg_depend_objid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + if (object->objectSubId != 0) + { + ScanKeyInit(&key[2], + Anum_pg_depend_objsubid, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(object->objectSubId)); + nkeys = 3; + } + else + nkeys = 2; + + scan = systable_beginscan(*depRel, DependDependerIndexId, true, + NULL, nkeys, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + CatalogTupleDelete(*depRel, &tup->t_self); + } + + systable_endscan(scan); + + /* + * Delete shared dependency references related to this object. Again, if + * subId = 0, remove records for sub-objects too. + */ + deleteSharedDependencyRecordsFor(object->classId, object->objectId, + object->objectSubId); + + + /* + * Delete any comments, security labels, or initial privileges associated + * with this object. (This is a convenient place to do these things, + * rather than having every object type know to do it.) + */ + DeleteComments(object->objectId, object->classId, object->objectSubId); + DeleteSecurityLabel(object); + DeleteInitPrivs(object); + + /* + * CommandCounterIncrement here to ensure that preceding changes are all + * visible to the next deletion step. + */ + CommandCounterIncrement(); + + /* + * And we're done! + */ +} + +/* + * doDeletion: actually delete a single object + */ +static void +doDeletion(const ObjectAddress *object, int flags) +{ + switch (getObjectClass(object)) + { + case OCLASS_CLASS: + { + char relKind = get_rel_relkind(object->objectId); + + if (relKind == RELKIND_INDEX || + relKind == RELKIND_PARTITIONED_INDEX) + { + bool concurrent = ((flags & PERFORM_DELETION_CONCURRENTLY) != 0); + bool concurrent_lock_mode = ((flags & PERFORM_DELETION_CONCURRENT_LOCK) != 0); + + Assert(object->objectSubId == 0); + index_drop(object->objectId, concurrent, concurrent_lock_mode); + } + else + { + if (object->objectSubId != 0) + RemoveAttributeById(object->objectId, + object->objectSubId); + else + heap_drop_with_catalog(object->objectId); + } + + /* + * for a sequence, in addition to dropping the heap, also + * delete pg_sequence tuple + */ + if (relKind == RELKIND_SEQUENCE) + DeleteSequenceTuple(object->objectId); + break; + } + + case OCLASS_PROC: + RemoveFunctionById(object->objectId); + break; + + case OCLASS_TYPE: + RemoveTypeById(object->objectId); + break; + + case OCLASS_CAST: + DropCastById(object->objectId); + break; + + case OCLASS_COLLATION: + RemoveCollationById(object->objectId); + break; + + case OCLASS_CONSTRAINT: + RemoveConstraintById(object->objectId); + break; + + case OCLASS_CONVERSION: + RemoveConversionById(object->objectId); + break; + + case OCLASS_DEFAULT: + RemoveAttrDefaultById(object->objectId); + break; + + case OCLASS_LANGUAGE: + DropProceduralLanguageById(object->objectId); + break; + + case OCLASS_LARGEOBJECT: + LargeObjectDrop(object->objectId); + break; + + case OCLASS_OPERATOR: + RemoveOperatorById(object->objectId); + break; + + case OCLASS_OPCLASS: + RemoveOpClassById(object->objectId); + break; + + case OCLASS_OPFAMILY: + RemoveOpFamilyById(object->objectId); + break; + + case OCLASS_AM: + RemoveAccessMethodById(object->objectId); + break; + + case OCLASS_AMOP: + RemoveAmOpEntryById(object->objectId); + break; + + case OCLASS_AMPROC: + RemoveAmProcEntryById(object->objectId); + break; + + case OCLASS_REWRITE: + RemoveRewriteRuleById(object->objectId); + break; + + case OCLASS_TRIGGER: + RemoveTriggerById(object->objectId); + break; + + case OCLASS_SCHEMA: + RemoveSchemaById(object->objectId); + break; + + case OCLASS_STATISTIC_EXT: + RemoveStatisticsById(object->objectId); + break; + + case OCLASS_TSPARSER: + RemoveTSParserById(object->objectId); + break; + + case OCLASS_TSDICT: + RemoveTSDictionaryById(object->objectId); + break; + + case OCLASS_TSTEMPLATE: + RemoveTSTemplateById(object->objectId); + break; + + case OCLASS_TSCONFIG: + RemoveTSConfigurationById(object->objectId); + break; + + /* + * OCLASS_ROLE, OCLASS_DATABASE, OCLASS_TBLSPACE intentionally not + * handled here + */ + + case OCLASS_FDW: + RemoveForeignDataWrapperById(object->objectId); + break; + + case OCLASS_FOREIGN_SERVER: + RemoveForeignServerById(object->objectId); + break; + + case OCLASS_USER_MAPPING: + RemoveUserMappingById(object->objectId); + break; + + case OCLASS_DEFACL: + RemoveDefaultACLById(object->objectId); + break; + + case OCLASS_EXTENSION: + RemoveExtensionById(object->objectId); + break; + + case OCLASS_EVENT_TRIGGER: + RemoveEventTriggerById(object->objectId); + break; + + case OCLASS_POLICY: + RemovePolicyById(object->objectId); + break; + + case OCLASS_PUBLICATION: + RemovePublicationById(object->objectId); + break; + + case OCLASS_PUBLICATION_REL: + RemovePublicationRelById(object->objectId); + break; + + case OCLASS_TRANSFORM: + DropTransformById(object->objectId); + break; + + /* + * These global object types are not supported here. + */ + case OCLASS_ROLE: + case OCLASS_DATABASE: + case OCLASS_TBLSPACE: + case OCLASS_SUBSCRIPTION: + elog(ERROR, "global objects cannot be deleted by doDeletion"); + break; + + /* + * There's intentionally no default: case here; we want the + * compiler to warn if a new OCLASS hasn't been handled above. + */ + } +} + +/* + * AcquireDeletionLock - acquire a suitable lock for deleting an object + * + * Accepts the same flags as performDeletion (though currently only + * PERFORM_DELETION_CONCURRENTLY does anything). + * + * We use LockRelation for relations, LockDatabaseObject for everything + * else. Shared-across-databases objects are not currently supported + * because no caller cares, but could be modified to use LockSharedObject. + */ +void +AcquireDeletionLock(const ObjectAddress *object, int flags) +{ + if (object->classId == RelationRelationId) + { + /* + * In DROP INDEX CONCURRENTLY, take only ShareUpdateExclusiveLock on + * the index for the moment. index_drop() will promote the lock once + * it's safe to do so. In all other cases we need full exclusive + * lock. + */ + if (flags & PERFORM_DELETION_CONCURRENTLY) + LockRelationOid(object->objectId, ShareUpdateExclusiveLock); + else + LockRelationOid(object->objectId, AccessExclusiveLock); + } + else + { + /* assume we should lock the whole object not a sub-object */ + LockDatabaseObject(object->classId, object->objectId, 0, + AccessExclusiveLock); + } +} + +/* + * ReleaseDeletionLock - release an object deletion lock + * + * Companion to AcquireDeletionLock. + */ +void +ReleaseDeletionLock(const ObjectAddress *object) +{ + if (object->classId == RelationRelationId) + UnlockRelationOid(object->objectId, AccessExclusiveLock); + else + /* assume we should lock the whole object not a sub-object */ + UnlockDatabaseObject(object->classId, object->objectId, 0, + AccessExclusiveLock); +} + +/* + * recordDependencyOnExpr - find expression dependencies + * + * This is used to find the dependencies of rules, constraint expressions, + * etc. + * + * Given an expression or query in node-tree form, find all the objects + * it refers to (tables, columns, operators, functions, etc). Record + * a dependency of the specified type from the given depender object + * to each object mentioned in the expression. + * + * rtable is the rangetable to be used to interpret Vars with varlevelsup=0. + * It can be NIL if no such variables are expected. + */ +void +recordDependencyOnExpr(const ObjectAddress *depender, + Node *expr, List *rtable, + DependencyType behavior) +{ + find_expr_references_context context; + + context.addrs = new_object_addresses(); + + /* Set up interpretation for Vars at varlevelsup = 0 */ + context.rtables = list_make1(rtable); + + /* Scan the expression tree for referenceable objects */ + find_expr_references_walker(expr, &context); + + /* Remove any duplicates */ + eliminate_duplicate_dependencies(context.addrs); + + /* And record 'em */ + recordMultipleDependencies(depender, + context.addrs->refs, context.addrs->numrefs, + behavior); + + free_object_addresses(context.addrs); +} + +/* + * recordDependencyOnSingleRelExpr - find expression dependencies + * + * As above, but only one relation is expected to be referenced (with + * varno = 1 and varlevelsup = 0). Pass the relation OID instead of a + * range table. An additional frammish is that dependencies on that + * relation's component columns will be marked with 'self_behavior', + * whereas 'behavior' is used for everything else; also, if 'reverse_self' + * is true, those dependencies are reversed so that the columns are made + * to depend on the table not vice versa. + * + * NOTE: the caller should ensure that a whole-table dependency on the + * specified relation is created separately, if one is needed. In particular, + * a whole-row Var "relation.*" will not cause this routine to emit any + * dependency item. This is appropriate behavior for subexpressions of an + * ordinary query, so other cases need to cope as necessary. + */ +void +recordDependencyOnSingleRelExpr(const ObjectAddress *depender, + Node *expr, Oid relId, + DependencyType behavior, + DependencyType self_behavior, + bool reverse_self) +{ + find_expr_references_context context; + RangeTblEntry rte; + + context.addrs = new_object_addresses(); + + /* We gin up a rather bogus rangetable list to handle Vars */ + MemSet(&rte, 0, sizeof(rte)); + rte.type = T_RangeTblEntry; + rte.rtekind = RTE_RELATION; + rte.relid = relId; + rte.relkind = RELKIND_RELATION; /* no need for exactness here */ + rte.rellockmode = AccessShareLock; + + context.rtables = list_make1(list_make1(&rte)); + + /* Scan the expression tree for referenceable objects */ + find_expr_references_walker(expr, &context); + + /* Remove any duplicates */ + eliminate_duplicate_dependencies(context.addrs); + + /* Separate self-dependencies if necessary */ + if ((behavior != self_behavior || reverse_self) && + context.addrs->numrefs > 0) + { + ObjectAddresses *self_addrs; + ObjectAddress *outobj; + int oldref, + outrefs; + + self_addrs = new_object_addresses(); + + outobj = context.addrs->refs; + outrefs = 0; + for (oldref = 0; oldref < context.addrs->numrefs; oldref++) + { + ObjectAddress *thisobj = context.addrs->refs + oldref; + + if (thisobj->classId == RelationRelationId && + thisobj->objectId == relId) + { + /* Move this ref into self_addrs */ + add_exact_object_address(thisobj, self_addrs); + } + else + { + /* Keep it in context.addrs */ + *outobj = *thisobj; + outobj++; + outrefs++; + } + } + context.addrs->numrefs = outrefs; + + /* Record the self-dependencies with the appropriate direction */ + if (!reverse_self) + recordMultipleDependencies(depender, + self_addrs->refs, self_addrs->numrefs, + self_behavior); + else + { + /* Can't use recordMultipleDependencies, so do it the hard way */ + int selfref; + + for (selfref = 0; selfref < self_addrs->numrefs; selfref++) + { + ObjectAddress *thisobj = self_addrs->refs + selfref; + + recordDependencyOn(thisobj, depender, self_behavior); + } + } + + free_object_addresses(self_addrs); + } + + /* Record the external dependencies */ + recordMultipleDependencies(depender, + context.addrs->refs, context.addrs->numrefs, + behavior); + + free_object_addresses(context.addrs); +} + +/* + * Recursively search an expression tree for object references. + * + * Note: in many cases we do not need to create dependencies on the datatypes + * involved in an expression, because we'll have an indirect dependency via + * some other object. For instance Var nodes depend on a column which depends + * on the datatype, and OpExpr nodes depend on the operator which depends on + * the datatype. However we do need a type dependency if there is no such + * indirect dependency, as for example in Const and CoerceToDomain nodes. + * + * Similarly, we don't need to create dependencies on collations except where + * the collation is being freshly introduced to the expression. + */ +static bool +find_expr_references_walker(Node *node, + find_expr_references_context *context) +{ + if (node == NULL) + return false; + if (IsA(node, Var)) + { + Var *var = (Var *) node; + List *rtable; + RangeTblEntry *rte; + + /* Find matching rtable entry, or complain if not found */ + if (var->varlevelsup >= list_length(context->rtables)) + elog(ERROR, "invalid varlevelsup %d", var->varlevelsup); + rtable = (List *) list_nth(context->rtables, var->varlevelsup); + if (var->varno <= 0 || var->varno > list_length(rtable)) + elog(ERROR, "invalid varno %d", var->varno); + rte = rt_fetch(var->varno, rtable); + + /* + * A whole-row Var references no specific columns, so adds no new + * dependency. (We assume that there is a whole-table dependency + * arising from each underlying rangetable entry. While we could + * record such a dependency when finding a whole-row Var that + * references a relation directly, it's quite unclear how to extend + * that to whole-row Vars for JOINs, so it seems better to leave the + * responsibility with the range table. Note that this poses some + * risks for identifying dependencies of stand-alone expressions: + * whole-table references may need to be created separately.) + */ + if (var->varattno == InvalidAttrNumber) + return false; + if (rte->rtekind == RTE_RELATION) + { + /* If it's a plain relation, reference this column */ + add_object_address(OCLASS_CLASS, rte->relid, var->varattno, + context->addrs); + } + + /* + * Vars referencing other RTE types require no additional work. In + * particular, a join alias Var can be ignored, because it must + * reference a merged USING column. The relevant join input columns + * will also be referenced in the join qual, and any type coercion + * functions involved in the alias expression will be dealt with when + * we scan the RTE itself. + */ + return false; + } + else if (IsA(node, Const)) + { + Const *con = (Const *) node; + Oid objoid; + + /* A constant must depend on the constant's datatype */ + add_object_address(OCLASS_TYPE, con->consttype, 0, + context->addrs); + + /* + * We must also depend on the constant's collation: it could be + * different from the datatype's, if a CollateExpr was const-folded to + * a simple constant. However we can save work in the most common + * case where the collation is "default", since we know that's pinned. + */ + if (OidIsValid(con->constcollid) && + con->constcollid != DEFAULT_COLLATION_OID) + add_object_address(OCLASS_COLLATION, con->constcollid, 0, + context->addrs); + + /* + * If it's a regclass or similar literal referring to an existing + * object, add a reference to that object. (Currently, only the + * regclass and regconfig cases have any likely use, but we may as + * well handle all the OID-alias datatypes consistently.) + */ + if (!con->constisnull) + { + switch (con->consttype) + { + case REGPROCOID: + case REGPROCEDUREOID: + objoid = DatumGetObjectId(con->constvalue); + if (SearchSysCacheExists1(PROCOID, + ObjectIdGetDatum(objoid))) + add_object_address(OCLASS_PROC, objoid, 0, + context->addrs); + break; + case REGOPEROID: + case REGOPERATOROID: + objoid = DatumGetObjectId(con->constvalue); + if (SearchSysCacheExists1(OPEROID, + ObjectIdGetDatum(objoid))) + add_object_address(OCLASS_OPERATOR, objoid, 0, + context->addrs); + break; + case REGCLASSOID: + objoid = DatumGetObjectId(con->constvalue); + if (SearchSysCacheExists1(RELOID, + ObjectIdGetDatum(objoid))) + add_object_address(OCLASS_CLASS, objoid, 0, + context->addrs); + break; + case REGTYPEOID: + objoid = DatumGetObjectId(con->constvalue); + if (SearchSysCacheExists1(TYPEOID, + ObjectIdGetDatum(objoid))) + add_object_address(OCLASS_TYPE, objoid, 0, + context->addrs); + break; + case REGCONFIGOID: + objoid = DatumGetObjectId(con->constvalue); + if (SearchSysCacheExists1(TSCONFIGOID, + ObjectIdGetDatum(objoid))) + add_object_address(OCLASS_TSCONFIG, objoid, 0, + context->addrs); + break; + case REGDICTIONARYOID: + objoid = DatumGetObjectId(con->constvalue); + if (SearchSysCacheExists1(TSDICTOID, + ObjectIdGetDatum(objoid))) + add_object_address(OCLASS_TSDICT, objoid, 0, + context->addrs); + break; + + case REGNAMESPACEOID: + objoid = DatumGetObjectId(con->constvalue); + if (SearchSysCacheExists1(NAMESPACEOID, + ObjectIdGetDatum(objoid))) + add_object_address(OCLASS_SCHEMA, objoid, 0, + context->addrs); + break; + + /* + * Dependencies for regrole should be shared among all + * databases, so explicitly inhibit to have dependencies. + */ + case REGROLEOID: + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("constant of the type %s cannot be used here", + "regrole"))); + break; + } + } + return false; + } + else if (IsA(node, Param)) + { + Param *param = (Param *) node; + + /* A parameter must depend on the parameter's datatype */ + add_object_address(OCLASS_TYPE, param->paramtype, 0, + context->addrs); + /* and its collation, just as for Consts */ + if (OidIsValid(param->paramcollid) && + param->paramcollid != DEFAULT_COLLATION_OID) + add_object_address(OCLASS_COLLATION, param->paramcollid, 0, + context->addrs); + } + else if (IsA(node, FuncExpr)) + { + FuncExpr *funcexpr = (FuncExpr *) node; + + add_object_address(OCLASS_PROC, funcexpr->funcid, 0, + context->addrs); + /* fall through to examine arguments */ + } + else if (IsA(node, OpExpr)) + { + OpExpr *opexpr = (OpExpr *) node; + + add_object_address(OCLASS_OPERATOR, opexpr->opno, 0, + context->addrs); + /* fall through to examine arguments */ + } + else if (IsA(node, DistinctExpr)) + { + DistinctExpr *distinctexpr = (DistinctExpr *) node; + + add_object_address(OCLASS_OPERATOR, distinctexpr->opno, 0, + context->addrs); + /* fall through to examine arguments */ + } + else if (IsA(node, NullIfExpr)) + { + NullIfExpr *nullifexpr = (NullIfExpr *) node; + + add_object_address(OCLASS_OPERATOR, nullifexpr->opno, 0, + context->addrs); + /* fall through to examine arguments */ + } + else if (IsA(node, ScalarArrayOpExpr)) + { + ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node; + + add_object_address(OCLASS_OPERATOR, opexpr->opno, 0, + context->addrs); + /* fall through to examine arguments */ + } + else if (IsA(node, Aggref)) + { + Aggref *aggref = (Aggref *) node; + + add_object_address(OCLASS_PROC, aggref->aggfnoid, 0, + context->addrs); + /* fall through to examine arguments */ + } + else if (IsA(node, WindowFunc)) + { + WindowFunc *wfunc = (WindowFunc *) node; + + add_object_address(OCLASS_PROC, wfunc->winfnoid, 0, + context->addrs); + /* fall through to examine arguments */ + } + else if (IsA(node, SubPlan)) + { + /* Extra work needed here if we ever need this case */ + elog(ERROR, "already-planned subqueries not supported"); + } + else if (IsA(node, FieldSelect)) + { + FieldSelect *fselect = (FieldSelect *) node; + Oid argtype = getBaseType(exprType((Node *) fselect->arg)); + Oid reltype = get_typ_typrelid(argtype); + + /* + * We need a dependency on the specific column named in FieldSelect, + * assuming we can identify the pg_class OID for it. (Probably we + * always can at the moment, but in future it might be possible for + * argtype to be RECORDOID.) If we can make a column dependency then + * we shouldn't need a dependency on the column's type; but if we + * can't, make a dependency on the type, as it might not appear + * anywhere else in the expression. + */ + if (OidIsValid(reltype)) + add_object_address(OCLASS_CLASS, reltype, fselect->fieldnum, + context->addrs); + else + add_object_address(OCLASS_TYPE, fselect->resulttype, 0, + context->addrs); + /* the collation might not be referenced anywhere else, either */ + if (OidIsValid(fselect->resultcollid) && + fselect->resultcollid != DEFAULT_COLLATION_OID) + add_object_address(OCLASS_COLLATION, fselect->resultcollid, 0, + context->addrs); + } + else if (IsA(node, FieldStore)) + { + FieldStore *fstore = (FieldStore *) node; + Oid reltype = get_typ_typrelid(fstore->resulttype); + + /* similar considerations to FieldSelect, but multiple column(s) */ + if (OidIsValid(reltype)) + { + ListCell *l; + + foreach(l, fstore->fieldnums) + add_object_address(OCLASS_CLASS, reltype, lfirst_int(l), + context->addrs); + } + else + add_object_address(OCLASS_TYPE, fstore->resulttype, 0, + context->addrs); + } + else if (IsA(node, RelabelType)) + { + RelabelType *relab = (RelabelType *) node; + + /* since there is no function dependency, need to depend on type */ + add_object_address(OCLASS_TYPE, relab->resulttype, 0, + context->addrs); + /* the collation might not be referenced anywhere else, either */ + if (OidIsValid(relab->resultcollid) && + relab->resultcollid != DEFAULT_COLLATION_OID) + add_object_address(OCLASS_COLLATION, relab->resultcollid, 0, + context->addrs); + } + else if (IsA(node, CoerceViaIO)) + { + CoerceViaIO *iocoerce = (CoerceViaIO *) node; + + /* since there is no exposed function, need to depend on type */ + add_object_address(OCLASS_TYPE, iocoerce->resulttype, 0, + context->addrs); + /* the collation might not be referenced anywhere else, either */ + if (OidIsValid(iocoerce->resultcollid) && + iocoerce->resultcollid != DEFAULT_COLLATION_OID) + add_object_address(OCLASS_COLLATION, iocoerce->resultcollid, 0, + context->addrs); + } + else if (IsA(node, ArrayCoerceExpr)) + { + ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; + + /* as above, depend on type */ + add_object_address(OCLASS_TYPE, acoerce->resulttype, 0, + context->addrs); + /* the collation might not be referenced anywhere else, either */ + if (OidIsValid(acoerce->resultcollid) && + acoerce->resultcollid != DEFAULT_COLLATION_OID) + add_object_address(OCLASS_COLLATION, acoerce->resultcollid, 0, + context->addrs); + /* fall through to examine arguments */ + } + else if (IsA(node, ConvertRowtypeExpr)) + { + ConvertRowtypeExpr *cvt = (ConvertRowtypeExpr *) node; + + /* since there is no function dependency, need to depend on type */ + add_object_address(OCLASS_TYPE, cvt->resulttype, 0, + context->addrs); + } + else if (IsA(node, CollateExpr)) + { + CollateExpr *coll = (CollateExpr *) node; + + add_object_address(OCLASS_COLLATION, coll->collOid, 0, + context->addrs); + } + else if (IsA(node, RowExpr)) + { + RowExpr *rowexpr = (RowExpr *) node; + + add_object_address(OCLASS_TYPE, rowexpr->row_typeid, 0, + context->addrs); + } + else if (IsA(node, RowCompareExpr)) + { + RowCompareExpr *rcexpr = (RowCompareExpr *) node; + ListCell *l; + + foreach(l, rcexpr->opnos) + { + add_object_address(OCLASS_OPERATOR, lfirst_oid(l), 0, + context->addrs); + } + foreach(l, rcexpr->opfamilies) + { + add_object_address(OCLASS_OPFAMILY, lfirst_oid(l), 0, + context->addrs); + } + /* fall through to examine arguments */ + } + else if (IsA(node, CoerceToDomain)) + { + CoerceToDomain *cd = (CoerceToDomain *) node; + + add_object_address(OCLASS_TYPE, cd->resulttype, 0, + context->addrs); + } + else if (IsA(node, NextValueExpr)) + { + NextValueExpr *nve = (NextValueExpr *) node; + + add_object_address(OCLASS_CLASS, nve->seqid, 0, + context->addrs); + } + else if (IsA(node, OnConflictExpr)) + { + OnConflictExpr *onconflict = (OnConflictExpr *) node; + + if (OidIsValid(onconflict->constraint)) + add_object_address(OCLASS_CONSTRAINT, onconflict->constraint, 0, + context->addrs); + /* fall through to examine arguments */ + } + else if (IsA(node, SortGroupClause)) + { + SortGroupClause *sgc = (SortGroupClause *) node; + + add_object_address(OCLASS_OPERATOR, sgc->eqop, 0, + context->addrs); + if (OidIsValid(sgc->sortop)) + add_object_address(OCLASS_OPERATOR, sgc->sortop, 0, + context->addrs); + return false; + } + else if (IsA(node, WindowClause)) + { + WindowClause *wc = (WindowClause *) node; + + if (OidIsValid(wc->startInRangeFunc)) + add_object_address(OCLASS_PROC, wc->startInRangeFunc, 0, + context->addrs); + if (OidIsValid(wc->endInRangeFunc)) + add_object_address(OCLASS_PROC, wc->endInRangeFunc, 0, + context->addrs); + if (OidIsValid(wc->inRangeColl) && + wc->inRangeColl != DEFAULT_COLLATION_OID) + add_object_address(OCLASS_COLLATION, wc->inRangeColl, 0, + context->addrs); + /* fall through to examine substructure */ + } + else if (IsA(node, Query)) + { + /* Recurse into RTE subquery or not-yet-planned sublink subquery */ + Query *query = (Query *) node; + ListCell *lc; + bool result; + + /* + * Add whole-relation refs for each plain relation mentioned in the + * subquery's rtable, and ensure we add refs for any type-coercion + * functions used in join alias lists. + * + * Note: query_tree_walker takes care of recursing into RTE_FUNCTION + * RTEs, subqueries, etc, so no need to do that here. But we must + * tell it not to visit join alias lists, or we'll add refs for join + * input columns whether or not they are actually used in our query. + * + * Note: we don't need to worry about collations mentioned in + * RTE_VALUES or RTE_CTE RTEs, because those must just duplicate + * collations referenced in other parts of the Query. We do have to + * worry about collations mentioned in RTE_FUNCTION, but we take care + * of those when we recurse to the RangeTblFunction node(s). + */ + foreach(lc, query->rtable) + { + RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc); + + switch (rte->rtekind) + { + case RTE_RELATION: + add_object_address(OCLASS_CLASS, rte->relid, 0, + context->addrs); + break; + case RTE_JOIN: + + /* + * Examine joinaliasvars entries only for merged JOIN + * USING columns. Only those entries could contain + * type-coercion functions. Also, their join input + * columns must be referenced in the join quals, so this + * won't accidentally add refs to otherwise-unused join + * input columns. (We want to ref the type coercion + * functions even if the merged column isn't explicitly + * used anywhere, to protect possible expansion of the + * join RTE as a whole-row var, and because it seems like + * a bad idea to allow dropping a function that's present + * in our query tree, whether or not it could get called.) + */ + context->rtables = lcons(query->rtable, context->rtables); + for (int i = 0; i < rte->joinmergedcols; i++) + { + Node *aliasvar = list_nth(rte->joinaliasvars, i); + + if (!IsA(aliasvar, Var)) + find_expr_references_walker(aliasvar, context); + } + context->rtables = list_delete_first(context->rtables); + break; + default: + break; + } + } + + /* + * If the query is an INSERT or UPDATE, we should create a dependency + * on each target column, to prevent the specific target column from + * being dropped. Although we will visit the TargetEntry nodes again + * during query_tree_walker, we won't have enough context to do this + * conveniently, so do it here. + */ + if (query->commandType == CMD_INSERT || + query->commandType == CMD_UPDATE) + { + RangeTblEntry *rte; + + if (query->resultRelation <= 0 || + query->resultRelation > list_length(query->rtable)) + elog(ERROR, "invalid resultRelation %d", + query->resultRelation); + rte = rt_fetch(query->resultRelation, query->rtable); + if (rte->rtekind == RTE_RELATION) + { + foreach(lc, query->targetList) + { + TargetEntry *tle = (TargetEntry *) lfirst(lc); + + if (tle->resjunk) + continue; /* ignore junk tlist items */ + add_object_address(OCLASS_CLASS, rte->relid, tle->resno, + context->addrs); + } + } + } + + /* + * Add dependencies on constraints listed in query's constraintDeps + */ + foreach(lc, query->constraintDeps) + { + add_object_address(OCLASS_CONSTRAINT, lfirst_oid(lc), 0, + context->addrs); + } + + /* Examine substructure of query */ + context->rtables = lcons(query->rtable, context->rtables); + result = query_tree_walker(query, + find_expr_references_walker, + (void *) context, + QTW_IGNORE_JOINALIASES | + QTW_EXAMINE_SORTGROUP); + context->rtables = list_delete_first(context->rtables); + return result; + } + else if (IsA(node, SetOperationStmt)) + { + SetOperationStmt *setop = (SetOperationStmt *) node; + + /* we need to look at the groupClauses for operator references */ + find_expr_references_walker((Node *) setop->groupClauses, context); + /* fall through to examine child nodes */ + } + else if (IsA(node, RangeTblFunction)) + { + RangeTblFunction *rtfunc = (RangeTblFunction *) node; + ListCell *ct; + + /* + * Add refs for any datatypes and collations used in a column + * definition list for a RECORD function. (For other cases, it should + * be enough to depend on the function itself.) + */ + foreach(ct, rtfunc->funccoltypes) + { + add_object_address(OCLASS_TYPE, lfirst_oid(ct), 0, + context->addrs); + } + foreach(ct, rtfunc->funccolcollations) + { + Oid collid = lfirst_oid(ct); + + if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID) + add_object_address(OCLASS_COLLATION, collid, 0, + context->addrs); + } + } + else if (IsA(node, TableFunc)) + { + TableFunc *tf = (TableFunc *) node; + ListCell *ct; + + /* + * Add refs for the datatypes and collations used in the TableFunc. + */ + foreach(ct, tf->coltypes) + { + add_object_address(OCLASS_TYPE, lfirst_oid(ct), 0, + context->addrs); + } + foreach(ct, tf->colcollations) + { + Oid collid = lfirst_oid(ct); + + if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID) + add_object_address(OCLASS_COLLATION, collid, 0, + context->addrs); + } + } + else if (IsA(node, TableSampleClause)) + { + TableSampleClause *tsc = (TableSampleClause *) node; + + add_object_address(OCLASS_PROC, tsc->tsmhandler, 0, + context->addrs); + /* fall through to examine arguments */ + } + + return expression_tree_walker(node, find_expr_references_walker, + (void *) context); +} + +/* + * Given an array of dependency references, eliminate any duplicates. + */ +static void +eliminate_duplicate_dependencies(ObjectAddresses *addrs) +{ + ObjectAddress *priorobj; + int oldref, + newrefs; + + /* + * We can't sort if the array has "extra" data, because there's no way to + * keep it in sync. Fortunately that combination of features is not + * needed. + */ + Assert(!addrs->extras); + + if (addrs->numrefs <= 1) + return; /* nothing to do */ + + /* Sort the refs so that duplicates are adjacent */ + qsort((void *) addrs->refs, addrs->numrefs, sizeof(ObjectAddress), + object_address_comparator); + + /* Remove dups */ + priorobj = addrs->refs; + newrefs = 1; + for (oldref = 1; oldref < addrs->numrefs; oldref++) + { + ObjectAddress *thisobj = addrs->refs + oldref; + + if (priorobj->classId == thisobj->classId && + priorobj->objectId == thisobj->objectId) + { + if (priorobj->objectSubId == thisobj->objectSubId) + continue; /* identical, so drop thisobj */ + + /* + * If we have a whole-object reference and a reference to a part + * of the same object, we don't need the whole-object reference + * (for example, we don't need to reference both table foo and + * column foo.bar). The whole-object reference will always appear + * first in the sorted list. + */ + if (priorobj->objectSubId == 0) + { + /* replace whole ref with partial */ + priorobj->objectSubId = thisobj->objectSubId; + continue; + } + } + /* Not identical, so add thisobj to output set */ + priorobj++; + *priorobj = *thisobj; + newrefs++; + } + + addrs->numrefs = newrefs; +} + +/* + * qsort comparator for ObjectAddress items + */ +static int +object_address_comparator(const void *a, const void *b) +{ + const ObjectAddress *obja = (const ObjectAddress *) a; + const ObjectAddress *objb = (const ObjectAddress *) b; + + /* + * Primary sort key is OID descending. Most of the time, this will result + * in putting newer objects before older ones, which is likely to be the + * right order to delete in. + */ + if (obja->objectId > objb->objectId) + return -1; + if (obja->objectId < objb->objectId) + return 1; + + /* + * Next sort on catalog ID, in case identical OIDs appear in different + * catalogs. Sort direction is pretty arbitrary here. + */ + if (obja->classId < objb->classId) + return -1; + if (obja->classId > objb->classId) + return 1; + + /* + * Last, sort on object subId. + * + * We sort the subId as an unsigned int so that 0 (the whole object) will + * come first. This is essential for eliminate_duplicate_dependencies, + * and is also the best order for findDependentObjects. + */ + if ((unsigned int) obja->objectSubId < (unsigned int) objb->objectSubId) + return -1; + if ((unsigned int) obja->objectSubId > (unsigned int) objb->objectSubId) + return 1; + return 0; +} + +/* + * Routines for handling an expansible array of ObjectAddress items. + * + * new_object_addresses: create a new ObjectAddresses array. + */ +ObjectAddresses * +new_object_addresses(void) +{ + ObjectAddresses *addrs; + + addrs = palloc(sizeof(ObjectAddresses)); + + addrs->numrefs = 0; + addrs->maxrefs = 32; + addrs->refs = (ObjectAddress *) + palloc(addrs->maxrefs * sizeof(ObjectAddress)); + addrs->extras = NULL; /* until/unless needed */ + + return addrs; +} + +/* + * Add an entry to an ObjectAddresses array. + * + * It is convenient to specify the class by ObjectClass rather than directly + * by catalog OID. + */ +static void +add_object_address(ObjectClass oclass, Oid objectId, int32 subId, + ObjectAddresses *addrs) +{ + ObjectAddress *item; + + /* + * Make sure object_classes is kept up to date with the ObjectClass enum. + */ + StaticAssertStmt(lengthof(object_classes) == LAST_OCLASS + 1, + "object_classes[] must cover all ObjectClasses"); + + /* enlarge array if needed */ + if (addrs->numrefs >= addrs->maxrefs) + { + addrs->maxrefs *= 2; + addrs->refs = (ObjectAddress *) + repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress)); + Assert(!addrs->extras); + } + /* record this item */ + item = addrs->refs + addrs->numrefs; + item->classId = object_classes[oclass]; + item->objectId = objectId; + item->objectSubId = subId; + addrs->numrefs++; +} + +/* + * Add an entry to an ObjectAddresses array. + * + * As above, but specify entry exactly. + */ +void +add_exact_object_address(const ObjectAddress *object, + ObjectAddresses *addrs) +{ + ObjectAddress *item; + + /* enlarge array if needed */ + if (addrs->numrefs >= addrs->maxrefs) + { + addrs->maxrefs *= 2; + addrs->refs = (ObjectAddress *) + repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress)); + Assert(!addrs->extras); + } + /* record this item */ + item = addrs->refs + addrs->numrefs; + *item = *object; + addrs->numrefs++; +} + +/* + * Add an entry to an ObjectAddresses array. + * + * As above, but specify entry exactly and provide some "extra" data too. + */ +static void +add_exact_object_address_extra(const ObjectAddress *object, + const ObjectAddressExtra *extra, + ObjectAddresses *addrs) +{ + ObjectAddress *item; + ObjectAddressExtra *itemextra; + + /* allocate extra space if first time */ + if (!addrs->extras) + addrs->extras = (ObjectAddressExtra *) + palloc(addrs->maxrefs * sizeof(ObjectAddressExtra)); + + /* enlarge array if needed */ + if (addrs->numrefs >= addrs->maxrefs) + { + addrs->maxrefs *= 2; + addrs->refs = (ObjectAddress *) + repalloc(addrs->refs, addrs->maxrefs * sizeof(ObjectAddress)); + addrs->extras = (ObjectAddressExtra *) + repalloc(addrs->extras, addrs->maxrefs * sizeof(ObjectAddressExtra)); + } + /* record this item */ + item = addrs->refs + addrs->numrefs; + *item = *object; + itemextra = addrs->extras + addrs->numrefs; + *itemextra = *extra; + addrs->numrefs++; +} + +/* + * Test whether an object is present in an ObjectAddresses array. + * + * We return "true" if object is a subobject of something in the array, too. + */ +bool +object_address_present(const ObjectAddress *object, + const ObjectAddresses *addrs) +{ + int i; + + for (i = addrs->numrefs - 1; i >= 0; i--) + { + const ObjectAddress *thisobj = addrs->refs + i; + + if (object->classId == thisobj->classId && + object->objectId == thisobj->objectId) + { + if (object->objectSubId == thisobj->objectSubId || + thisobj->objectSubId == 0) + return true; + } + } + + return false; +} + +/* + * As above, except that if the object is present then also OR the given + * flags into its associated extra data (which must exist). + */ +static bool +object_address_present_add_flags(const ObjectAddress *object, + int flags, + ObjectAddresses *addrs) +{ + bool result = false; + int i; + + for (i = addrs->numrefs - 1; i >= 0; i--) + { + ObjectAddress *thisobj = addrs->refs + i; + + if (object->classId == thisobj->classId && + object->objectId == thisobj->objectId) + { + if (object->objectSubId == thisobj->objectSubId) + { + ObjectAddressExtra *thisextra = addrs->extras + i; + + thisextra->flags |= flags; + result = true; + } + else if (thisobj->objectSubId == 0) + { + /* + * We get here if we find a need to delete a column after + * having already decided to drop its whole table. Obviously + * we no longer need to drop the subobject, so report that we + * found the subobject in the array. But don't plaster its + * flags on the whole object. + */ + result = true; + } + else if (object->objectSubId == 0) + { + /* + * We get here if we find a need to delete a whole table after + * having already decided to drop one of its columns. We + * can't report that the whole object is in the array, but we + * should mark the subobject with the whole object's flags. + * + * It might seem attractive to physically delete the column's + * array entry, or at least mark it as no longer needing + * separate deletion. But that could lead to, e.g., dropping + * the column's datatype before we drop the table, which does + * not seem like a good idea. This is a very rare situation + * in practice, so we just take the hit of doing a separate + * DROP COLUMN action even though we know we're gonna delete + * the table later. + * + * What we can do, though, is mark this as a subobject so that + * we don't report it separately, which is confusing because + * it's unpredictable whether it happens or not. But do so + * only if flags != 0 (flags == 0 is a read-only probe). + * + * Because there could be other subobjects of this object in + * the array, this case means we always have to loop through + * the whole array; we cannot exit early on a match. + */ + ObjectAddressExtra *thisextra = addrs->extras + i; + + if (flags) + thisextra->flags |= (flags | DEPFLAG_SUBOBJECT); + } + } + } + + return result; +} + +/* + * Similar to above, except we search an ObjectAddressStack. + */ +static bool +stack_address_present_add_flags(const ObjectAddress *object, + int flags, + ObjectAddressStack *stack) +{ + bool result = false; + ObjectAddressStack *stackptr; + + for (stackptr = stack; stackptr; stackptr = stackptr->next) + { + const ObjectAddress *thisobj = stackptr->object; + + if (object->classId == thisobj->classId && + object->objectId == thisobj->objectId) + { + if (object->objectSubId == thisobj->objectSubId) + { + stackptr->flags |= flags; + result = true; + } + else if (thisobj->objectSubId == 0) + { + /* + * We're visiting a column with whole table already on stack. + * As in object_address_present_add_flags(), we can skip + * further processing of the subobject, but we don't want to + * propagate flags for the subobject to the whole object. + */ + result = true; + } + else if (object->objectSubId == 0) + { + /* + * We're visiting a table with column already on stack. As in + * object_address_present_add_flags(), we should propagate + * flags for the whole object to each of its subobjects. + */ + if (flags) + stackptr->flags |= (flags | DEPFLAG_SUBOBJECT); + } + } + } + + return result; +} + +/* + * Record multiple dependencies from an ObjectAddresses array, after first + * removing any duplicates. + */ +void +record_object_address_dependencies(const ObjectAddress *depender, + ObjectAddresses *referenced, + DependencyType behavior) +{ + eliminate_duplicate_dependencies(referenced); + recordMultipleDependencies(depender, + referenced->refs, referenced->numrefs, + behavior); +} + +/* + * Sort the items in an ObjectAddresses array. + * + * The major sort key is OID-descending, so that newer objects will be listed + * first in most cases. This is primarily useful for ensuring stable outputs + * from regression tests; it's not recommended if the order of the objects is + * determined by user input, such as the order of targets in a DROP command. + */ +void +sort_object_addresses(ObjectAddresses *addrs) +{ + if (addrs->numrefs > 1) + qsort((void *) addrs->refs, addrs->numrefs, + sizeof(ObjectAddress), + object_address_comparator); +} + +/* + * Clean up when done with an ObjectAddresses array. + */ +void +free_object_addresses(ObjectAddresses *addrs) +{ + pfree(addrs->refs); + if (addrs->extras) + pfree(addrs->extras); + pfree(addrs); +} + +/* + * Determine the class of a given object identified by objectAddress. + * + * This function is essentially the reverse mapping for the object_classes[] + * table. We implement it as a function because the OIDs aren't consecutive. + */ +ObjectClass +getObjectClass(const ObjectAddress *object) +{ + /* only pg_class entries can have nonzero objectSubId */ + if (object->classId != RelationRelationId && + object->objectSubId != 0) + elog(ERROR, "invalid non-zero objectSubId for object class %u", + object->classId); + + switch (object->classId) + { + case RelationRelationId: + /* caller must check objectSubId */ + return OCLASS_CLASS; + + case ProcedureRelationId: + return OCLASS_PROC; + + case TypeRelationId: + return OCLASS_TYPE; + + case CastRelationId: + return OCLASS_CAST; + + case CollationRelationId: + return OCLASS_COLLATION; + + case ConstraintRelationId: + return OCLASS_CONSTRAINT; + + case ConversionRelationId: + return OCLASS_CONVERSION; + + case AttrDefaultRelationId: + return OCLASS_DEFAULT; + + case LanguageRelationId: + return OCLASS_LANGUAGE; + + case LargeObjectRelationId: + return OCLASS_LARGEOBJECT; + + case OperatorRelationId: + return OCLASS_OPERATOR; + + case OperatorClassRelationId: + return OCLASS_OPCLASS; + + case OperatorFamilyRelationId: + return OCLASS_OPFAMILY; + + case AccessMethodRelationId: + return OCLASS_AM; + + case AccessMethodOperatorRelationId: + return OCLASS_AMOP; + + case AccessMethodProcedureRelationId: + return OCLASS_AMPROC; + + case RewriteRelationId: + return OCLASS_REWRITE; + + case TriggerRelationId: + return OCLASS_TRIGGER; + + case NamespaceRelationId: + return OCLASS_SCHEMA; + + case StatisticExtRelationId: + return OCLASS_STATISTIC_EXT; + + case TSParserRelationId: + return OCLASS_TSPARSER; + + case TSDictionaryRelationId: + return OCLASS_TSDICT; + + case TSTemplateRelationId: + return OCLASS_TSTEMPLATE; + + case TSConfigRelationId: + return OCLASS_TSCONFIG; + + case AuthIdRelationId: + return OCLASS_ROLE; + + case DatabaseRelationId: + return OCLASS_DATABASE; + + case TableSpaceRelationId: + return OCLASS_TBLSPACE; + + case ForeignDataWrapperRelationId: + return OCLASS_FDW; + + case ForeignServerRelationId: + return OCLASS_FOREIGN_SERVER; + + case UserMappingRelationId: + return OCLASS_USER_MAPPING; + + case DefaultAclRelationId: + return OCLASS_DEFACL; + + case ExtensionRelationId: + return OCLASS_EXTENSION; + + case EventTriggerRelationId: + return OCLASS_EVENT_TRIGGER; + + case PolicyRelationId: + return OCLASS_POLICY; + + case PublicationRelationId: + return OCLASS_PUBLICATION; + + case PublicationRelRelationId: + return OCLASS_PUBLICATION_REL; + + case SubscriptionRelationId: + return OCLASS_SUBSCRIPTION; + + case TransformRelationId: + return OCLASS_TRANSFORM; + } + + /* shouldn't get here */ + elog(ERROR, "unrecognized object class: %u", object->classId); + return OCLASS_CLASS; /* keep compiler quiet */ +} + +/* + * delete initial ACL for extension objects + */ +static void +DeleteInitPrivs(const ObjectAddress *object) +{ + Relation relation; + ScanKeyData key[3]; + SysScanDesc scan; + HeapTuple oldtuple; + + relation = table_open(InitPrivsRelationId, RowExclusiveLock); + + ScanKeyInit(&key[0], + Anum_pg_init_privs_objoid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + ScanKeyInit(&key[1], + Anum_pg_init_privs_classoid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->classId)); + ScanKeyInit(&key[2], + Anum_pg_init_privs_objsubid, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(object->objectSubId)); + + scan = systable_beginscan(relation, InitPrivsObjIndexId, true, + NULL, 3, key); + + while (HeapTupleIsValid(oldtuple = systable_getnext(scan))) + CatalogTupleDelete(relation, &oldtuple->t_self); + + systable_endscan(scan); + + table_close(relation, RowExclusiveLock); +} diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl new file mode 100644 index 0000000..b07537f --- /dev/null +++ b/src/backend/catalog/genbki.pl @@ -0,0 +1,977 @@ +#!/usr/bin/perl +#---------------------------------------------------------------------- +# +# genbki.pl +# Perl script that generates postgres.bki and symbol definition +# headers from specially formatted header files and data files. +# postgres.bki is used to initialize the postgres template database. +# +# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/backend/catalog/genbki.pl +# +#---------------------------------------------------------------------- + +use strict; +use warnings; +use Getopt::Long; + +use FindBin; +use lib $FindBin::RealBin; + +use Catalog; + +my $output_path = ''; +my $major_version; +my $include_path; + +GetOptions( + 'output:s' => \$output_path, + 'set-version:s' => \$major_version, + 'include-path:s' => \$include_path) || usage(); + +# Sanity check arguments. +die "No input files.\n" unless @ARGV; +die "--set-version must be specified.\n" unless $major_version; +die "Invalid version string: $major_version\n" + unless $major_version =~ /^\d+$/; +die "--include-path must be specified.\n" unless $include_path; + +# Make sure paths end with a slash. +if ($output_path ne '' && substr($output_path, -1) ne '/') +{ + $output_path .= '/'; +} +if (substr($include_path, -1) ne '/') +{ + $include_path .= '/'; +} + +# Read all the files into internal data structures. +my @catnames; +my %catalogs; +my %catalog_data; +my @toast_decls; +my @index_decls; +my %oidcounts; + +foreach my $header (@ARGV) +{ + $header =~ /(.+)\.h$/ + or die "Input files need to be header files.\n"; + my $datfile = "$1.dat"; + + my $catalog = Catalog::ParseHeader($header); + my $catname = $catalog->{catname}; + my $schema = $catalog->{columns}; + + if (defined $catname) + { + push @catnames, $catname; + $catalogs{$catname} = $catalog; + } + + # While checking for duplicated OIDs, we ignore the pg_class OID and + # rowtype OID of bootstrap catalogs, as those are expected to appear + # in the initial data for pg_class and pg_type. For regular catalogs, + # include these OIDs. (See also Catalog::FindAllOidsFromHeaders + # if you change this logic.) + if (!$catalog->{bootstrap}) + { + $oidcounts{ $catalog->{relation_oid} }++ + if ($catalog->{relation_oid}); + $oidcounts{ $catalog->{rowtype_oid} }++ + if ($catalog->{rowtype_oid}); + } + + # Not all catalogs have a data file. + if (-e $datfile) + { + my $data = Catalog::ParseData($datfile, $schema, 0); + $catalog_data{$catname} = $data; + + foreach my $row (@$data) + { + # Generate entries for pg_description and pg_shdescription. + if (defined $row->{descr}) + { + my %descr = ( + objoid => $row->{oid}, + classoid => $catalog->{relation_oid}, + objsubid => 0, + description => $row->{descr}); + + if ($catalog->{shared_relation}) + { + delete $descr{objsubid}; + push @{ $catalog_data{pg_shdescription} }, \%descr; + } + else + { + push @{ $catalog_data{pg_description} }, \%descr; + } + } + + # Check for duplicated OIDs while we're at it. + $oidcounts{ $row->{oid} }++ if defined $row->{oid}; + } + } + + # If the header file contained toast or index info, build BKI + # commands for those, which we'll output later. + foreach my $toast (@{ $catalog->{toasting} }) + { + push @toast_decls, + sprintf "declare toast %s %s on %s\n", + $toast->{toast_oid}, $toast->{toast_index_oid}, + $toast->{parent_table}; + $oidcounts{ $toast->{toast_oid} }++; + $oidcounts{ $toast->{toast_index_oid} }++; + } + foreach my $index (@{ $catalog->{indexing} }) + { + push @index_decls, + sprintf "declare %sindex %s %s %s\n", + $index->{is_unique} ? 'unique ' : '', + $index->{index_name}, $index->{index_oid}, + $index->{index_decl}; + $oidcounts{ $index->{index_oid} }++; + } +} + +# Complain and exit if we found any duplicate OIDs. +# While duplicate OIDs would only cause a failure if they appear in +# the same catalog, our project policy is that manually assigned OIDs +# should be globally unique, to avoid confusion. +my $found = 0; +foreach my $oid (keys %oidcounts) +{ + next unless $oidcounts{$oid} > 1; + print STDERR "Duplicate OIDs detected:\n" if !$found; + print STDERR "$oid\n"; + $found++; +} +die "found $found duplicate OID(s) in catalog data\n" if $found; + + +# Oids not specified in the input files are automatically assigned, +# starting at FirstGenbkiObjectId, extending up to FirstBootstrapObjectId. +my $FirstGenbkiObjectId = + Catalog::FindDefinedSymbol('access/transam.h', $include_path, + 'FirstGenbkiObjectId'); +my $FirstBootstrapObjectId = + Catalog::FindDefinedSymbol('access/transam.h', $include_path, + 'FirstBootstrapObjectId'); +my $GenbkiNextOid = $FirstGenbkiObjectId; + + +# Fetch some special data that we will substitute into the output file. +# CAUTION: be wary about what symbols you substitute into the .bki file here! +# It's okay to substitute things that are expected to be really constant +# within a given Postgres release, such as fixed OIDs. Do not substitute +# anything that could depend on platform or configuration. (The right place +# to handle those sorts of things is in initdb.c's bootstrap_template1().) +my $BOOTSTRAP_SUPERUSERID = + Catalog::FindDefinedSymbolFromData($catalog_data{pg_authid}, + 'BOOTSTRAP_SUPERUSERID'); +my $C_COLLATION_OID = + Catalog::FindDefinedSymbolFromData($catalog_data{pg_collation}, + 'C_COLLATION_OID'); +my $PG_CATALOG_NAMESPACE = + Catalog::FindDefinedSymbolFromData($catalog_data{pg_namespace}, + 'PG_CATALOG_NAMESPACE'); + + +# Fill in pg_class.relnatts by looking at the referenced catalog's schema. +# This is ugly but there's no better place; Catalog::AddDefaultValues +# can't do it, for lack of easy access to the other catalog. +foreach my $row (@{ $catalog_data{pg_class} }) +{ + $row->{relnatts} = scalar(@{ $catalogs{ $row->{relname} }->{columns} }); +} + + +# Build lookup tables. + +# access method OID lookup +my %amoids; +foreach my $row (@{ $catalog_data{pg_am} }) +{ + $amoids{ $row->{amname} } = $row->{oid}; +} + +# class (relation) OID lookup (note this only covers bootstrap catalogs!) +my %classoids; +foreach my $row (@{ $catalog_data{pg_class} }) +{ + $classoids{ $row->{relname} } = $row->{oid}; +} + +# collation OID lookup +my %collationoids; +foreach my $row (@{ $catalog_data{pg_collation} }) +{ + $collationoids{ $row->{collname} } = $row->{oid}; +} + +# language OID lookup +my %langoids; +foreach my $row (@{ $catalog_data{pg_language} }) +{ + $langoids{ $row->{lanname} } = $row->{oid}; +} + +# opclass OID lookup +my %opcoids; +foreach my $row (@{ $catalog_data{pg_opclass} }) +{ + # There is no unique name, so we need to combine access method + # and opclass name. + my $key = sprintf "%s/%s", $row->{opcmethod}, $row->{opcname}; + $opcoids{$key} = $row->{oid}; +} + +# operator OID lookup +my %operoids; +foreach my $row (@{ $catalog_data{pg_operator} }) +{ + # There is no unique name, so we need to invent one that contains + # the relevant type names. + my $key = sprintf "%s(%s,%s)", + $row->{oprname}, $row->{oprleft}, $row->{oprright}; + $operoids{$key} = $row->{oid}; +} + +# opfamily OID lookup +my %opfoids; +foreach my $row (@{ $catalog_data{pg_opfamily} }) +{ + # There is no unique name, so we need to combine access method + # and opfamily name. + my $key = sprintf "%s/%s", $row->{opfmethod}, $row->{opfname}; + $opfoids{$key} = $row->{oid}; +} + +# procedure OID lookup +my %procoids; +foreach my $row (@{ $catalog_data{pg_proc} }) +{ + # Generate an entry under just the proname (corresponds to regproc lookup) + my $prokey = $row->{proname}; + if (defined $procoids{$prokey}) + { + $procoids{$prokey} = 'MULTIPLE'; + } + else + { + $procoids{$prokey} = $row->{oid}; + } + + # Also generate an entry using proname(proargtypes). This is not quite + # identical to regprocedure lookup because we don't worry much about + # special SQL names for types etc; we just use the names in the source + # proargtypes field. These *should* be unique, but do a multiplicity + # check anyway. + $prokey .= '(' . join(',', split(/\s+/, $row->{proargtypes})) . ')'; + if (defined $procoids{$prokey}) + { + $procoids{$prokey} = 'MULTIPLE'; + } + else + { + $procoids{$prokey} = $row->{oid}; + } +} + +# tablespace OID lookup +my %tablespaceoids; +foreach my $row (@{ $catalog_data{pg_tablespace} }) +{ + $tablespaceoids{ $row->{spcname} } = $row->{oid}; +} + +# text search configuration OID lookup +my %tsconfigoids; +foreach my $row (@{ $catalog_data{pg_ts_config} }) +{ + $tsconfigoids{ $row->{cfgname} } = $row->{oid}; +} + +# text search dictionary OID lookup +my %tsdictoids; +foreach my $row (@{ $catalog_data{pg_ts_dict} }) +{ + $tsdictoids{ $row->{dictname} } = $row->{oid}; +} + +# text search parser OID lookup +my %tsparseroids; +foreach my $row (@{ $catalog_data{pg_ts_parser} }) +{ + $tsparseroids{ $row->{prsname} } = $row->{oid}; +} + +# text search template OID lookup +my %tstemplateoids; +foreach my $row (@{ $catalog_data{pg_ts_template} }) +{ + $tstemplateoids{ $row->{tmplname} } = $row->{oid}; +} + +# type lookups +my %typeoids; +my %types; +foreach my $row (@{ $catalog_data{pg_type} }) +{ + # for OID macro substitutions + $typeoids{ $row->{typname} } = $row->{oid}; + + # for pg_attribute copies of pg_type values + $types{ $row->{typname} } = $row; +} + +# Encoding identifier lookup. This uses the same replacement machinery +# as for OIDs, but we have to dig the values out of pg_wchar.h. +my %encids; + +my $encfile = $include_path . 'mb/pg_wchar.h'; +open(my $ef, '<', $encfile) || die "$encfile: $!"; + +# We're parsing an enum, so start with 0 and increment +# every time we find an enum member. +my $encid = 0; +my $collect_encodings = 0; +while (<$ef>) +{ + if (/typedef\s+enum\s+pg_enc/) + { + $collect_encodings = 1; + next; + } + + last if /_PG_LAST_ENCODING_/; + + if ($collect_encodings and /^\s+(PG_\w+)/) + { + $encids{$1} = $encid; + $encid++; + } +} + +close $ef; + +# Map lookup name to the corresponding hash table. +my %lookup_kind = ( + pg_am => \%amoids, + pg_class => \%classoids, + pg_collation => \%collationoids, + pg_language => \%langoids, + pg_opclass => \%opcoids, + pg_operator => \%operoids, + pg_opfamily => \%opfoids, + pg_proc => \%procoids, + pg_tablespace => \%tablespaceoids, + pg_ts_config => \%tsconfigoids, + pg_ts_dict => \%tsdictoids, + pg_ts_parser => \%tsparseroids, + pg_ts_template => \%tstemplateoids, + pg_type => \%typeoids, + encoding => \%encids); + + +# Open temp files +my $tmpext = ".tmp$$"; +my $bkifile = $output_path . 'postgres.bki'; +open my $bki, '>', $bkifile . $tmpext + or die "can't open $bkifile$tmpext: $!"; +my $schemafile = $output_path . 'schemapg.h'; +open my $schemapg, '>', $schemafile . $tmpext + or die "can't open $schemafile$tmpext: $!"; + +# Generate postgres.bki and pg_*_d.h headers. + +# version marker for .bki file +print $bki "# PostgreSQL $major_version\n"; + +# vars to hold data needed for schemapg.h +my %schemapg_entries; +my @tables_needing_macros; + +# produce output, one catalog at a time +foreach my $catname (@catnames) +{ + my $catalog = $catalogs{$catname}; + + # Create one definition header with macro definitions for each catalog. + my $def_file = $output_path . $catname . '_d.h'; + open my $def, '>', $def_file . $tmpext + or die "can't open $def_file$tmpext: $!"; + + # Opening boilerplate for pg_*_d.h + printf $def <<EOM, $catname, $catname, uc $catname, uc $catname; +/*------------------------------------------------------------------------- + * + * %s_d.h + * Macro definitions for %s + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef %s_D_H +#define %s_D_H + +EOM + + # Emit OID macros for catalog's OID and rowtype OID, if wanted + printf $def "#define %s %s\n", + $catalog->{relation_oid_macro}, $catalog->{relation_oid} + if $catalog->{relation_oid_macro}; + printf $def "#define %s %s\n", + $catalog->{rowtype_oid_macro}, $catalog->{rowtype_oid} + if $catalog->{rowtype_oid_macro}; + print $def "\n"; + + # .bki CREATE command for this catalog + print $bki "create $catname $catalog->{relation_oid}" + . $catalog->{shared_relation} + . $catalog->{bootstrap} + . $catalog->{rowtype_oid_clause}; + + my $first = 1; + + print $bki "\n (\n"; + my $schema = $catalog->{columns}; + my %attnames; + my $attnum = 0; + foreach my $column (@$schema) + { + $attnum++; + my $attname = $column->{name}; + my $atttype = $column->{type}; + + # Build hash of column names for use later + $attnames{$attname} = 1; + + # Emit column definitions + if (!$first) + { + print $bki " ,\n"; + } + $first = 0; + + print $bki " $attname = $atttype"; + + if (defined $column->{forcenotnull}) + { + print $bki " FORCE NOT NULL"; + } + elsif (defined $column->{forcenull}) + { + print $bki " FORCE NULL"; + } + + # Emit Anum_* constants + printf $def "#define Anum_%s_%s %s\n", $catname, $attname, $attnum; + } + print $bki "\n )\n"; + + # Emit Natts_* constant + print $def "\n#define Natts_$catname $attnum\n\n"; + + # Emit client code copied from source header + foreach my $line (@{ $catalog->{client_code} }) + { + print $def $line; + } + + # Open it, unless it's a bootstrap catalog (create bootstrap does this + # automatically) + if (!$catalog->{bootstrap}) + { + print $bki "open $catname\n"; + } + + # For pg_attribute.h, we generate data entries ourselves. + if ($catname eq 'pg_attribute') + { + gen_pg_attribute($schema); + } + + # Ordinary catalog with a data file + foreach my $row (@{ $catalog_data{$catname} }) + { + my %bki_values = %$row; + + # Complain about unrecognized keys; they are presumably misspelled + foreach my $key (keys %bki_values) + { + next + if $key eq "oid_symbol" + || $key eq "array_type_oid" + || $key eq "descr" + || $key eq "autogenerated" + || $key eq "line_number"; + die sprintf "unrecognized field name \"%s\" in %s.dat line %s\n", + $key, $catname, $bki_values{line_number} + if (!exists($attnames{$key})); + } + + # Perform required substitutions on fields + foreach my $column (@$schema) + { + my $attname = $column->{name}; + my $atttype = $column->{type}; + + # Assign oid if oid column exists and no explicit assignment in row + if ($attname eq "oid" and not defined $bki_values{$attname}) + { + $bki_values{$attname} = $GenbkiNextOid; + $GenbkiNextOid++; + } + + # Substitute constant values we acquired above. + # (It's intentional that this can apply to parts of a field). + $bki_values{$attname} =~ s/\bPGUID\b/$BOOTSTRAP_SUPERUSERID/g; + $bki_values{$attname} =~ s/\bPGNSP\b/$PG_CATALOG_NAMESPACE/g; + + # Replace OID synonyms with OIDs per the appropriate lookup rule. + # + # If the column type is oidvector or _oid, we have to replace + # each element of the array as per the lookup rule. + if ($column->{lookup}) + { + my $lookup = $lookup_kind{ $column->{lookup} }; + my @lookupnames; + my @lookupoids; + + die "unrecognized BKI_LOOKUP type " . $column->{lookup} + if !defined($lookup); + + if ($atttype eq 'oidvector') + { + @lookupnames = split /\s+/, $bki_values{$attname}; + @lookupoids = lookup_oids($lookup, $catname, \%bki_values, + @lookupnames); + $bki_values{$attname} = join(' ', @lookupoids); + } + elsif ($atttype eq '_oid') + { + if ($bki_values{$attname} ne '_null_') + { + $bki_values{$attname} =~ s/[{}]//g; + @lookupnames = split /,/, $bki_values{$attname}; + @lookupoids = + lookup_oids($lookup, $catname, \%bki_values, + @lookupnames); + $bki_values{$attname} = sprintf "{%s}", + join(',', @lookupoids); + } + } + else + { + $lookupnames[0] = $bki_values{$attname}; + @lookupoids = lookup_oids($lookup, $catname, \%bki_values, + @lookupnames); + $bki_values{$attname} = $lookupoids[0]; + } + } + } + + # Special hack to generate OID symbols for pg_type entries + # that lack one. + if ($catname eq 'pg_type' and !exists $bki_values{oid_symbol}) + { + my $symbol = form_pg_type_symbol($bki_values{typname}); + $bki_values{oid_symbol} = $symbol + if defined $symbol; + } + + # Write to postgres.bki + print_bki_insert(\%bki_values, $schema); + + # Emit OID symbol + if (defined $bki_values{oid_symbol}) + { + printf $def "#define %s %s\n", + $bki_values{oid_symbol}, $bki_values{oid}; + } + } + + print $bki "close $catname\n"; + printf $def "\n#endif\t\t\t\t\t\t\t/* %s_D_H */\n", uc $catname; + + # Close and rename definition header + close $def; + Catalog::RenameTempFile($def_file, $tmpext); +} + +# Any information needed for the BKI that is not contained in a pg_*.h header +# (i.e., not contained in a header with a CATALOG() statement) comes here + +# Write out declare toast/index statements +foreach my $declaration (@toast_decls) +{ + print $bki $declaration; +} + +foreach my $declaration (@index_decls) +{ + print $bki $declaration; +} + +# last command in the BKI file: build the indexes declared above +print $bki "build indices\n"; + +# check that we didn't overrun available OIDs +die + "genbki OID counter reached $GenbkiNextOid, overrunning FirstBootstrapObjectId\n" + if $GenbkiNextOid > $FirstBootstrapObjectId; + + +# Now generate schemapg.h + +# Opening boilerplate for schemapg.h +print $schemapg <<EOM; +/*------------------------------------------------------------------------- + * + * schemapg.h + * Schema_pg_xxx macros for use by relcache.c + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef SCHEMAPG_H +#define SCHEMAPG_H +EOM + +# Emit schemapg declarations +foreach my $table_name (@tables_needing_macros) +{ + print $schemapg "\n#define Schema_$table_name \\\n"; + print $schemapg join ", \\\n", @{ $schemapg_entries{$table_name} }; + print $schemapg "\n"; +} + +# Closing boilerplate for schemapg.h +print $schemapg "\n#endif\t\t\t\t\t\t\t/* SCHEMAPG_H */\n"; + +# We're done emitting data +close $bki; +close $schemapg; + +# Finally, rename the completed files into place. +Catalog::RenameTempFile($bkifile, $tmpext); +Catalog::RenameTempFile($schemafile, $tmpext); + +exit 0; + +#################### Subroutines ######################## + + +# For each catalog marked as needing a schema macro, generate the +# per-user-attribute data to be incorporated into schemapg.h. Also, for +# bootstrap catalogs, emit pg_attribute entries into the .bki file +# for both user and system attributes. +sub gen_pg_attribute +{ + my $schema = shift; + + my @attnames; + foreach my $column (@$schema) + { + push @attnames, $column->{name}; + } + + foreach my $table_name (@catnames) + { + my $table = $catalogs{$table_name}; + + # Currently, all bootstrap catalogs also need schemapg.h + # entries, so skip if it isn't to be in schemapg.h. + next if !$table->{schema_macro}; + + $schemapg_entries{$table_name} = []; + push @tables_needing_macros, $table_name; + + # Generate entries for user attributes. + my $attnum = 0; + my $priornotnull = 1; + foreach my $attr (@{ $table->{columns} }) + { + $attnum++; + my %row; + $row{attnum} = $attnum; + $row{attrelid} = $table->{relation_oid}; + + morph_row_for_pgattr(\%row, $schema, $attr, $priornotnull); + $priornotnull &= ($row{attnotnull} eq 't'); + + # If it's bootstrapped, put an entry in postgres.bki. + print_bki_insert(\%row, $schema) if $table->{bootstrap}; + + # Store schemapg entries for later. + morph_row_for_schemapg(\%row, $schema); + push @{ $schemapg_entries{$table_name} }, + sprintf "{ %s }", + join(', ', grep { defined $_ } @row{@attnames}); + } + + # Generate entries for system attributes. + # We only need postgres.bki entries, not schemapg.h entries. + if ($table->{bootstrap}) + { + $attnum = 0; + my @SYS_ATTRS = ( + { name => 'ctid', type => 'tid' }, + { name => 'xmin', type => 'xid' }, + { name => 'cmin', type => 'cid' }, + { name => 'xmax', type => 'xid' }, + { name => 'cmax', type => 'cid' }, + { name => 'tableoid', type => 'oid' }); + foreach my $attr (@SYS_ATTRS) + { + $attnum--; + my %row; + $row{attnum} = $attnum; + $row{attrelid} = $table->{relation_oid}; + $row{attstattarget} = '0'; + + morph_row_for_pgattr(\%row, $schema, $attr, 1); + print_bki_insert(\%row, $schema); + } + } + } + return; +} + +# Given $pgattr_schema (the pg_attribute schema for a catalog sufficient for +# AddDefaultValues), $attr (the description of a catalog row), and +# $priornotnull (whether all prior attributes in this catalog are not null), +# modify the $row hashref for print_bki_insert. This includes setting data +# from the corresponding pg_type element and filling in any default values. +# Any value not handled here must be supplied by caller. +sub morph_row_for_pgattr +{ + my ($row, $pgattr_schema, $attr, $priornotnull) = @_; + my $attname = $attr->{name}; + my $atttype = $attr->{type}; + + $row->{attname} = $attname; + + # Copy the type data from pg_type, and add some type-dependent items + my $type = $types{$atttype}; + + $row->{atttypid} = $type->{oid}; + $row->{attlen} = $type->{typlen}; + $row->{attbyval} = $type->{typbyval}; + $row->{attstorage} = $type->{typstorage}; + $row->{attalign} = $type->{typalign}; + + # set attndims if it's an array type + $row->{attndims} = $type->{typcategory} eq 'A' ? '1' : '0'; + + # collation-aware catalog columns must use C collation + $row->{attcollation} = + $type->{typcollation} ne '0' ? $C_COLLATION_OID : 0; + + if (defined $attr->{forcenotnull}) + { + $row->{attnotnull} = 't'; + } + elsif (defined $attr->{forcenull}) + { + $row->{attnotnull} = 'f'; + } + elsif ($priornotnull) + { + + # attnotnull will automatically be set if the type is + # fixed-width and prior columns are all NOT NULL --- + # compare DefineAttr in bootstrap.c. oidvector and + # int2vector are also treated as not-nullable. + $row->{attnotnull} = + $type->{typname} eq 'oidvector' ? 't' + : $type->{typname} eq 'int2vector' ? 't' + : $type->{typlen} eq 'NAMEDATALEN' ? 't' + : $type->{typlen} > 0 ? 't' + : 'f'; + } + else + { + $row->{attnotnull} = 'f'; + } + + Catalog::AddDefaultValues($row, $pgattr_schema, 'pg_attribute'); + return; +} + +# Write an entry to postgres.bki. +sub print_bki_insert +{ + my $row = shift; + my $schema = shift; + + my @bki_values; + + foreach my $column (@$schema) + { + my $attname = $column->{name}; + my $atttype = $column->{type}; + my $bki_value = $row->{$attname}; + + # Fold backslash-zero to empty string if it's the entire string, + # since that represents a NUL char in C code. + $bki_value = '' if $bki_value eq '\0'; + + # Handle single quotes by doubling them, and double quotes by + # converting them to octal escapes, because that's what the + # bootstrap scanner requires. We do not process backslashes + # specially; this allows escape-string-style backslash escapes + # to be used in catalog data. + $bki_value =~ s/'/''/g; + $bki_value =~ s/"/\\042/g; + + # Quote value if needed. We need not quote values that satisfy + # the "id" pattern in bootscanner.l, currently "[-A-Za-z0-9_]+". + $bki_value = sprintf(qq'"%s"', $bki_value) + if length($bki_value) == 0 + or $bki_value =~ /[^-A-Za-z0-9_]/; + + push @bki_values, $bki_value; + } + printf $bki "insert ( %s )\n", join(' ', @bki_values); + return; +} + +# Given a row reference, modify it so that it becomes a valid entry for +# a catalog schema declaration in schemapg.h. +# +# The field values of a Schema_pg_xxx declaration are similar, but not +# quite identical, to the corresponding values in postgres.bki. +sub morph_row_for_schemapg +{ + my $row = shift; + my $pgattr_schema = shift; + + foreach my $column (@$pgattr_schema) + { + my $attname = $column->{name}; + my $atttype = $column->{type}; + + # Some data types have special formatting rules. + if ($atttype eq 'name') + { + # add {" ... "} quoting + $row->{$attname} = sprintf(qq'{"%s"}', $row->{$attname}); + } + elsif ($atttype eq 'char') + { + # Add single quotes + $row->{$attname} = sprintf("'%s'", $row->{$attname}); + } + + # Expand booleans from 'f'/'t' to 'false'/'true'. + # Some values might be other macros (eg FLOAT8PASSBYVAL), + # don't change. + elsif ($atttype eq 'bool') + { + $row->{$attname} = 'true' if $row->{$attname} eq 't'; + $row->{$attname} = 'false' if $row->{$attname} eq 'f'; + } + + # We don't emit initializers for the variable length fields at all. + # Only the fixed-size portions of the descriptors are ever used. + delete $row->{$attname} if $column->{is_varlen}; + } + return; +} + +# Perform OID lookups on an array of OID names. +# If we don't have a unique value to substitute, warn and +# leave the entry unchanged. +# (A warning seems sufficient because the bootstrap backend will reject +# non-numeric values anyway. So we might as well detect multiple problems +# within this genbki.pl run.) +sub lookup_oids +{ + my ($lookup, $catname, $bki_values, @lookupnames) = @_; + + my @lookupoids; + foreach my $lookupname (@lookupnames) + { + my $lookupoid = $lookup->{$lookupname}; + if (defined($lookupoid) and $lookupoid ne 'MULTIPLE') + { + push @lookupoids, $lookupoid; + } + else + { + push @lookupoids, $lookupname; + warn sprintf + "unresolved OID reference \"%s\" in %s.dat line %s\n", + $lookupname, $catname, $bki_values->{line_number} + if $lookupname ne '-' and $lookupname ne '0'; + } + } + return @lookupoids; +} + +# Determine canonical pg_type OID #define symbol from the type name. +sub form_pg_type_symbol +{ + my $typename = shift; + + # Skip for rowtypes of bootstrap catalogs, since they have their + # own naming convention defined elsewhere. + return + if $typename eq 'pg_type' + or $typename eq 'pg_proc' + or $typename eq 'pg_attribute' + or $typename eq 'pg_class'; + + # Transform like so: + # foo_bar -> FOO_BAROID + # _foo_bar -> FOO_BARARRAYOID + $typename =~ /(_)?(.+)/; + my $arraystr = $1 ? 'ARRAY' : ''; + my $name = uc $2; + return $name . $arraystr . 'OID'; +} + +sub usage +{ + die <<EOM; +Usage: perl -I [directory of Catalog.pm] genbki.pl [--output/-o <path>] [--include-path/-i <path>] header... + +Options: + --output Output directory (default '.') + --set-version PostgreSQL version number for initdb cross-check + --include-path Include path in source tree + +genbki.pl generates postgres.bki and symbol definition +headers from specially formatted header files and .dat +files. postgres.bki is used to initialize the +postgres template database. + +Report bugs to <pgsql-bugs\@lists.postgresql.org>. +EOM +} diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c new file mode 100644 index 0000000..a42070f --- /dev/null +++ b/src/backend/catalog/heap.c @@ -0,0 +1,3826 @@ +/*------------------------------------------------------------------------- + * + * heap.c + * code to create and destroy POSTGRES heap relations + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/heap.c + * + * + * INTERFACE ROUTINES + * heap_create() - Create an uncataloged heap relation + * heap_create_with_catalog() - Create a cataloged relation + * heap_drop_with_catalog() - Removes named relation from catalogs + * + * NOTES + * this code taken from access/heap/create.c, which contains + * the old heap_create_with_catalog, amcreate, and amdestroy. + * those routines will soon call these routines using the function + * manager, + * just like the poorly named "NewXXX" routines do. The + * "New" routines are all going to die soon, once and for all! + * -cim 1/13/91 + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/genam.h" +#include "access/htup_details.h" +#include "access/multixact.h" +#include "access/relation.h" +#include "access/sysattr.h" +#include "access/table.h" +#include "access/tableam.h" +#include "access/transam.h" +#include "access/xact.h" +#include "access/xlog.h" +#include "catalog/binary_upgrade.h" +#include "catalog/catalog.h" +#include "catalog/dependency.h" +#include "catalog/heap.h" +#include "catalog/index.h" +#include "catalog/objectaccess.h" +#include "catalog/partition.h" +#include "catalog/pg_am.h" +#include "catalog/pg_attrdef.h" +#include "catalog/pg_collation.h" +#include "catalog/pg_constraint.h" +#include "catalog/pg_foreign_table.h" +#include "catalog/pg_inherits.h" +#include "catalog/pg_namespace.h" +#include "catalog/pg_opclass.h" +#include "catalog/pg_partitioned_table.h" +#include "catalog/pg_statistic.h" +#include "catalog/pg_subscription_rel.h" +#include "catalog/pg_tablespace.h" +#include "catalog/pg_type.h" +#include "catalog/storage.h" +#include "catalog/storage_xlog.h" +#include "commands/tablecmds.h" +#include "commands/typecmds.h" +#include "executor/executor.h" +#include "miscadmin.h" +#include "nodes/nodeFuncs.h" +#include "optimizer/optimizer.h" +#include "parser/parse_coerce.h" +#include "parser/parse_collate.h" +#include "parser/parse_expr.h" +#include "parser/parse_relation.h" +#include "parser/parsetree.h" +#include "partitioning/partdesc.h" +#include "storage/lmgr.h" +#include "storage/predicate.h" +#include "storage/smgr.h" +#include "utils/acl.h" +#include "utils/builtins.h" +#include "utils/datum.h" +#include "utils/fmgroids.h" +#include "utils/inval.h" +#include "utils/lsyscache.h" +#include "utils/partcache.h" +#include "utils/ruleutils.h" +#include "utils/snapmgr.h" +#include "utils/syscache.h" + + +/* Potentially set by pg_upgrade_support functions */ +Oid binary_upgrade_next_heap_pg_class_oid = InvalidOid; +Oid binary_upgrade_next_toast_pg_class_oid = InvalidOid; + +static void AddNewRelationTuple(Relation pg_class_desc, + Relation new_rel_desc, + Oid new_rel_oid, + Oid new_type_oid, + Oid reloftype, + Oid relowner, + char relkind, + TransactionId relfrozenxid, + TransactionId relminmxid, + Datum relacl, + Datum reloptions); +static ObjectAddress AddNewRelationType(const char *typeName, + Oid typeNamespace, + Oid new_rel_oid, + char new_rel_kind, + Oid ownerid, + Oid new_row_type, + Oid new_array_type); +static void RelationRemoveInheritance(Oid relid); +static Oid StoreRelCheck(Relation rel, const char *ccname, Node *expr, + bool is_validated, bool is_local, int inhcount, + bool is_no_inherit, bool is_internal); +static void StoreConstraints(Relation rel, List *cooked_constraints, + bool is_internal); +static bool MergeWithExistingConstraint(Relation rel, const char *ccname, Node *expr, + bool allow_merge, bool is_local, + bool is_initially_valid, + bool is_no_inherit); +static void SetRelationNumChecks(Relation rel, int numchecks); +static Node *cookConstraint(ParseState *pstate, + Node *raw_constraint, + char *relname); + + +/* ---------------------------------------------------------------- + * XXX UGLY HARD CODED BADNESS FOLLOWS XXX + * + * these should all be moved to someplace in the lib/catalog + * module, if not obliterated first. + * ---------------------------------------------------------------- + */ + + +/* + * Note: + * Should the system special case these attributes in the future? + * Advantage: consume much less space in the ATTRIBUTE relation. + * Disadvantage: special cases will be all over the place. + */ + +/* + * The initializers below do not include trailing variable length fields, + * but that's OK - we're never going to reference anything beyond the + * fixed-size portion of the structure anyway. + */ + +static const FormData_pg_attribute a1 = { + .attname = {"ctid"}, + .atttypid = TIDOID, + .attlen = sizeof(ItemPointerData), + .attnum = SelfItemPointerAttributeNumber, + .attcacheoff = -1, + .atttypmod = -1, + .attbyval = false, + .attstorage = TYPSTORAGE_PLAIN, + .attalign = TYPALIGN_SHORT, + .attnotnull = true, + .attislocal = true, +}; + +static const FormData_pg_attribute a2 = { + .attname = {"xmin"}, + .atttypid = XIDOID, + .attlen = sizeof(TransactionId), + .attnum = MinTransactionIdAttributeNumber, + .attcacheoff = -1, + .atttypmod = -1, + .attbyval = true, + .attstorage = TYPSTORAGE_PLAIN, + .attalign = TYPALIGN_INT, + .attnotnull = true, + .attislocal = true, +}; + +static const FormData_pg_attribute a3 = { + .attname = {"cmin"}, + .atttypid = CIDOID, + .attlen = sizeof(CommandId), + .attnum = MinCommandIdAttributeNumber, + .attcacheoff = -1, + .atttypmod = -1, + .attbyval = true, + .attstorage = TYPSTORAGE_PLAIN, + .attalign = TYPALIGN_INT, + .attnotnull = true, + .attislocal = true, +}; + +static const FormData_pg_attribute a4 = { + .attname = {"xmax"}, + .atttypid = XIDOID, + .attlen = sizeof(TransactionId), + .attnum = MaxTransactionIdAttributeNumber, + .attcacheoff = -1, + .atttypmod = -1, + .attbyval = true, + .attstorage = TYPSTORAGE_PLAIN, + .attalign = TYPALIGN_INT, + .attnotnull = true, + .attislocal = true, +}; + +static const FormData_pg_attribute a5 = { + .attname = {"cmax"}, + .atttypid = CIDOID, + .attlen = sizeof(CommandId), + .attnum = MaxCommandIdAttributeNumber, + .attcacheoff = -1, + .atttypmod = -1, + .attbyval = true, + .attstorage = TYPSTORAGE_PLAIN, + .attalign = TYPALIGN_INT, + .attnotnull = true, + .attislocal = true, +}; + +/* + * We decided to call this attribute "tableoid" rather than say + * "classoid" on the basis that in the future there may be more than one + * table of a particular class/type. In any case table is still the word + * used in SQL. + */ +static const FormData_pg_attribute a6 = { + .attname = {"tableoid"}, + .atttypid = OIDOID, + .attlen = sizeof(Oid), + .attnum = TableOidAttributeNumber, + .attcacheoff = -1, + .atttypmod = -1, + .attbyval = true, + .attstorage = TYPSTORAGE_PLAIN, + .attalign = TYPALIGN_INT, + .attnotnull = true, + .attislocal = true, +}; + +static const FormData_pg_attribute *SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6}; + +/* + * This function returns a Form_pg_attribute pointer for a system attribute. + * Note that we elog if the presented attno is invalid, which would only + * happen if there's a problem upstream. + */ +const FormData_pg_attribute * +SystemAttributeDefinition(AttrNumber attno) +{ + if (attno >= 0 || attno < -(int) lengthof(SysAtt)) + elog(ERROR, "invalid system attribute number %d", attno); + return SysAtt[-attno - 1]; +} + +/* + * If the given name is a system attribute name, return a Form_pg_attribute + * pointer for a prototype definition. If not, return NULL. + */ +const FormData_pg_attribute * +SystemAttributeByName(const char *attname) +{ + int j; + + for (j = 0; j < (int) lengthof(SysAtt); j++) + { + const FormData_pg_attribute *att = SysAtt[j]; + + if (strcmp(NameStr(att->attname), attname) == 0) + return att; + } + + return NULL; +} + + +/* ---------------------------------------------------------------- + * XXX END OF UGLY HARD CODED BADNESS XXX + * ---------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------- + * heap_create - Create an uncataloged heap relation + * + * Note API change: the caller must now always provide the OID + * to use for the relation. The relfilenode may (and, normally, + * should) be left unspecified. + * + * rel->rd_rel is initialized by RelationBuildLocalRelation, + * and is mostly zeroes at return. + * ---------------------------------------------------------------- + */ +Relation +heap_create(const char *relname, + Oid relnamespace, + Oid reltablespace, + Oid relid, + Oid relfilenode, + Oid accessmtd, + TupleDesc tupDesc, + char relkind, + char relpersistence, + bool shared_relation, + bool mapped_relation, + bool allow_system_table_mods, + TransactionId *relfrozenxid, + MultiXactId *relminmxid) +{ + bool create_storage; + Relation rel; + + /* The caller must have provided an OID for the relation. */ + Assert(OidIsValid(relid)); + + /* + * Don't allow creating relations in pg_catalog directly, even though it + * is allowed to move user defined relations there. Semantics with search + * paths including pg_catalog are too confusing for now. + * + * But allow creating indexes on relations in pg_catalog even if + * allow_system_table_mods = off, upper layers already guarantee it's on a + * user defined relation, not a system one. + */ + if (!allow_system_table_mods && + ((IsCatalogNamespace(relnamespace) && relkind != RELKIND_INDEX) || + IsToastNamespace(relnamespace)) && + IsNormalProcessingMode()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied to create \"%s.%s\"", + get_namespace_name(relnamespace), relname), + errdetail("System catalog modifications are currently disallowed."))); + + *relfrozenxid = InvalidTransactionId; + *relminmxid = InvalidMultiXactId; + + /* Handle reltablespace for specific relkinds. */ + switch (relkind) + { + case RELKIND_VIEW: + case RELKIND_COMPOSITE_TYPE: + case RELKIND_FOREIGN_TABLE: + + /* + * Force reltablespace to zero if the relation has no physical + * storage. This is mainly just for cleanliness' sake. + * + * Partitioned tables and indexes don't have physical storage + * either, but we want to keep their tablespace settings so that + * their children can inherit it. + */ + reltablespace = InvalidOid; + break; + + case RELKIND_SEQUENCE: + + /* + * Force reltablespace to zero for sequences, since we don't + * support moving them around into different tablespaces. + */ + reltablespace = InvalidOid; + break; + default: + break; + } + + /* + * Decide whether to create storage. If caller passed a valid relfilenode, + * storage is already created, so don't do it here. Also don't create it + * for relkinds without physical storage. + */ + if (!RELKIND_HAS_STORAGE(relkind) || OidIsValid(relfilenode)) + create_storage = false; + else + { + create_storage = true; + relfilenode = relid; + } + + /* + * Never allow a pg_class entry to explicitly specify the database's + * default tablespace in reltablespace; force it to zero instead. This + * ensures that if the database is cloned with a different default + * tablespace, the pg_class entry will still match where CREATE DATABASE + * will put the physically copied relation. + * + * Yes, this is a bit of a hack. + */ + if (reltablespace == MyDatabaseTableSpace) + reltablespace = InvalidOid; + + /* + * build the relcache entry. + */ + rel = RelationBuildLocalRelation(relname, + relnamespace, + tupDesc, + relid, + accessmtd, + relfilenode, + reltablespace, + shared_relation, + mapped_relation, + relpersistence, + relkind); + + /* + * Have the storage manager create the relation's disk file, if needed. + * + * For relations the callback creates both the main and the init fork, for + * indexes only the main fork is created. The other forks will be created + * on demand. + */ + if (create_storage) + { + RelationOpenSmgr(rel); + + switch (rel->rd_rel->relkind) + { + case RELKIND_VIEW: + case RELKIND_COMPOSITE_TYPE: + case RELKIND_FOREIGN_TABLE: + case RELKIND_PARTITIONED_TABLE: + case RELKIND_PARTITIONED_INDEX: + Assert(false); + break; + + case RELKIND_INDEX: + case RELKIND_SEQUENCE: + RelationCreateStorage(rel->rd_node, relpersistence); + break; + + case RELKIND_RELATION: + case RELKIND_TOASTVALUE: + case RELKIND_MATVIEW: + table_relation_set_new_filenode(rel, &rel->rd_node, + relpersistence, + relfrozenxid, relminmxid); + break; + } + } + + /* + * If a tablespace is specified, removal of that tablespace is normally + * protected by the existence of a physical file; but for relations with + * no files, add a pg_shdepend entry to account for that. + */ + if (!create_storage && reltablespace != InvalidOid) + recordDependencyOnTablespace(RelationRelationId, relid, + reltablespace); + + return rel; +} + +/* ---------------------------------------------------------------- + * heap_create_with_catalog - Create a cataloged relation + * + * this is done in multiple steps: + * + * 1) CheckAttributeNamesTypes() is used to make certain the tuple + * descriptor contains a valid set of attribute names and types + * + * 2) pg_class is opened and get_relname_relid() + * performs a scan to ensure that no relation with the + * same name already exists. + * + * 3) heap_create() is called to create the new relation on disk. + * + * 4) TypeCreate() is called to define a new type corresponding + * to the new relation. + * + * 5) AddNewRelationTuple() is called to register the + * relation in pg_class. + * + * 6) AddNewAttributeTuples() is called to register the + * new relation's schema in pg_attribute. + * + * 7) StoreConstraints is called () - vadim 08/22/97 + * + * 8) the relations are closed and the new relation's oid + * is returned. + * + * ---------------------------------------------------------------- + */ + +/* -------------------------------- + * CheckAttributeNamesTypes + * + * this is used to make certain the tuple descriptor contains a + * valid set of attribute names and datatypes. a problem simply + * generates ereport(ERROR) which aborts the current transaction. + * + * relkind is the relkind of the relation to be created. + * flags controls which datatypes are allowed, cf CheckAttributeType. + * -------------------------------- + */ +void +CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind, + int flags) +{ + int i; + int j; + int natts = tupdesc->natts; + + /* Sanity check on column count */ + if (natts < 0 || natts > MaxHeapAttributeNumber) + ereport(ERROR, + (errcode(ERRCODE_TOO_MANY_COLUMNS), + errmsg("tables can have at most %d columns", + MaxHeapAttributeNumber))); + + /* + * first check for collision with system attribute names + * + * Skip this for a view or type relation, since those don't have system + * attributes. + */ + if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE) + { + for (i = 0; i < natts; i++) + { + Form_pg_attribute attr = TupleDescAttr(tupdesc, i); + + if (SystemAttributeByName(NameStr(attr->attname)) != NULL) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_COLUMN), + errmsg("column name \"%s\" conflicts with a system column name", + NameStr(attr->attname)))); + } + } + + /* + * next check for repeated attribute names + */ + for (i = 1; i < natts; i++) + { + for (j = 0; j < i; j++) + { + if (strcmp(NameStr(TupleDescAttr(tupdesc, j)->attname), + NameStr(TupleDescAttr(tupdesc, i)->attname)) == 0) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_COLUMN), + errmsg("column name \"%s\" specified more than once", + NameStr(TupleDescAttr(tupdesc, j)->attname)))); + } + } + + /* + * next check the attribute types + */ + for (i = 0; i < natts; i++) + { + CheckAttributeType(NameStr(TupleDescAttr(tupdesc, i)->attname), + TupleDescAttr(tupdesc, i)->atttypid, + TupleDescAttr(tupdesc, i)->attcollation, + NIL, /* assume we're creating a new rowtype */ + flags); + } +} + +/* -------------------------------- + * CheckAttributeType + * + * Verify that the proposed datatype of an attribute is legal. + * This is needed mainly because there are types (and pseudo-types) + * in the catalogs that we do not support as elements of real tuples. + * We also check some other properties required of a table column. + * + * If the attribute is being proposed for addition to an existing table or + * composite type, pass a one-element list of the rowtype OID as + * containing_rowtypes. When checking a to-be-created rowtype, it's + * sufficient to pass NIL, because there could not be any recursive reference + * to a not-yet-existing rowtype. + * + * flags is a bitmask controlling which datatypes we allow. For the most + * part, pseudo-types are disallowed as attribute types, but there are some + * exceptions: ANYARRAYOID, RECORDOID, and RECORDARRAYOID can be allowed + * in some cases. (This works because values of those type classes are + * self-identifying to some extent. However, RECORDOID and RECORDARRAYOID + * are reliably identifiable only within a session, since the identity info + * may use a typmod that is only locally assigned. The caller is expected + * to know whether these cases are safe.) + * + * flags can also control the phrasing of the error messages. If + * CHKATYPE_IS_PARTKEY is specified, "attname" should be a partition key + * column number as text, not a real column name. + * -------------------------------- + */ +void +CheckAttributeType(const char *attname, + Oid atttypid, Oid attcollation, + List *containing_rowtypes, + int flags) +{ + char att_typtype = get_typtype(atttypid); + Oid att_typelem; + + if (att_typtype == TYPTYPE_PSEUDO) + { + /* + * We disallow pseudo-type columns, with the exception of ANYARRAY, + * RECORD, and RECORD[] when the caller says that those are OK. + * + * We don't need to worry about recursive containment for RECORD and + * RECORD[] because (a) no named composite type should be allowed to + * contain those, and (b) two "anonymous" record types couldn't be + * considered to be the same type, so infinite recursion isn't + * possible. + */ + if (!((atttypid == ANYARRAYOID && (flags & CHKATYPE_ANYARRAY)) || + (atttypid == RECORDOID && (flags & CHKATYPE_ANYRECORD)) || + (atttypid == RECORDARRAYOID && (flags & CHKATYPE_ANYRECORD)))) + { + if (flags & CHKATYPE_IS_PARTKEY) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + /* translator: first %s is an integer not a name */ + errmsg("partition key column %s has pseudo-type %s", + attname, format_type_be(atttypid)))); + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("column \"%s\" has pseudo-type %s", + attname, format_type_be(atttypid)))); + } + } + else if (att_typtype == TYPTYPE_DOMAIN) + { + /* + * If it's a domain, recurse to check its base type. + */ + CheckAttributeType(attname, getBaseType(atttypid), attcollation, + containing_rowtypes, + flags); + } + else if (att_typtype == TYPTYPE_COMPOSITE) + { + /* + * For a composite type, recurse into its attributes. + */ + Relation relation; + TupleDesc tupdesc; + int i; + + /* + * Check for self-containment. Eventually we might be able to allow + * this (just return without complaint, if so) but it's not clear how + * many other places would require anti-recursion defenses before it + * would be safe to allow tables to contain their own rowtype. + */ + if (list_member_oid(containing_rowtypes, atttypid)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("composite type %s cannot be made a member of itself", + format_type_be(atttypid)))); + + containing_rowtypes = lappend_oid(containing_rowtypes, atttypid); + + relation = relation_open(get_typ_typrelid(atttypid), AccessShareLock); + + tupdesc = RelationGetDescr(relation); + + for (i = 0; i < tupdesc->natts; i++) + { + Form_pg_attribute attr = TupleDescAttr(tupdesc, i); + + if (attr->attisdropped) + continue; + CheckAttributeType(NameStr(attr->attname), + attr->atttypid, attr->attcollation, + containing_rowtypes, + flags & ~CHKATYPE_IS_PARTKEY); + } + + relation_close(relation, AccessShareLock); + + containing_rowtypes = list_delete_last(containing_rowtypes); + } + else if (att_typtype == TYPTYPE_RANGE) + { + /* + * If it's a range, recurse to check its subtype. + */ + CheckAttributeType(attname, get_range_subtype(atttypid), + get_range_collation(atttypid), + containing_rowtypes, + flags); + } + else if (OidIsValid((att_typelem = get_element_type(atttypid)))) + { + /* + * Must recurse into array types, too, in case they are composite. + */ + CheckAttributeType(attname, att_typelem, attcollation, + containing_rowtypes, + flags); + } + + /* + * This might not be strictly invalid per SQL standard, but it is pretty + * useless, and it cannot be dumped, so we must disallow it. + */ + if (!OidIsValid(attcollation) && type_is_collatable(atttypid)) + { + if (flags & CHKATYPE_IS_PARTKEY) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + /* translator: first %s is an integer not a name */ + errmsg("no collation was derived for partition key column %s with collatable type %s", + attname, format_type_be(atttypid)), + errhint("Use the COLLATE clause to set the collation explicitly."))); + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("no collation was derived for column \"%s\" with collatable type %s", + attname, format_type_be(atttypid)), + errhint("Use the COLLATE clause to set the collation explicitly."))); + } +} + +/* + * InsertPgAttributeTuple + * Construct and insert a new tuple in pg_attribute. + * + * Caller has already opened and locked pg_attribute. new_attribute is the + * attribute to insert. attcacheoff is always initialized to -1, attacl and + * attoptions are always initialized to NULL. + * + * indstate is the index state for CatalogTupleInsertWithInfo. It can be + * passed as NULL, in which case we'll fetch the necessary info. (Don't do + * this when inserting multiple attributes, because it's a tad more + * expensive.) + */ +void +InsertPgAttributeTuple(Relation pg_attribute_rel, + Form_pg_attribute new_attribute, + Datum attoptions, + CatalogIndexState indstate) +{ + Datum values[Natts_pg_attribute]; + bool nulls[Natts_pg_attribute]; + HeapTuple tup; + + /* This is a tad tedious, but way cleaner than what we used to do... */ + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + + values[Anum_pg_attribute_attrelid - 1] = ObjectIdGetDatum(new_attribute->attrelid); + values[Anum_pg_attribute_attname - 1] = NameGetDatum(&new_attribute->attname); + values[Anum_pg_attribute_atttypid - 1] = ObjectIdGetDatum(new_attribute->atttypid); + values[Anum_pg_attribute_attstattarget - 1] = Int32GetDatum(new_attribute->attstattarget); + values[Anum_pg_attribute_attlen - 1] = Int16GetDatum(new_attribute->attlen); + values[Anum_pg_attribute_attnum - 1] = Int16GetDatum(new_attribute->attnum); + values[Anum_pg_attribute_attndims - 1] = Int32GetDatum(new_attribute->attndims); + values[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1); + values[Anum_pg_attribute_atttypmod - 1] = Int32GetDatum(new_attribute->atttypmod); + values[Anum_pg_attribute_attbyval - 1] = BoolGetDatum(new_attribute->attbyval); + values[Anum_pg_attribute_attstorage - 1] = CharGetDatum(new_attribute->attstorage); + values[Anum_pg_attribute_attalign - 1] = CharGetDatum(new_attribute->attalign); + values[Anum_pg_attribute_attnotnull - 1] = BoolGetDatum(new_attribute->attnotnull); + values[Anum_pg_attribute_atthasdef - 1] = BoolGetDatum(new_attribute->atthasdef); + values[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(new_attribute->atthasmissing); + values[Anum_pg_attribute_attidentity - 1] = CharGetDatum(new_attribute->attidentity); + values[Anum_pg_attribute_attgenerated - 1] = CharGetDatum(new_attribute->attgenerated); + values[Anum_pg_attribute_attisdropped - 1] = BoolGetDatum(new_attribute->attisdropped); + values[Anum_pg_attribute_attislocal - 1] = BoolGetDatum(new_attribute->attislocal); + values[Anum_pg_attribute_attinhcount - 1] = Int32GetDatum(new_attribute->attinhcount); + values[Anum_pg_attribute_attcollation - 1] = ObjectIdGetDatum(new_attribute->attcollation); + values[Anum_pg_attribute_attoptions - 1] = attoptions; + + /* start out with empty permissions and empty options */ + nulls[Anum_pg_attribute_attacl - 1] = true; + nulls[Anum_pg_attribute_attoptions - 1] = attoptions == (Datum) 0; + nulls[Anum_pg_attribute_attfdwoptions - 1] = true; + nulls[Anum_pg_attribute_attmissingval - 1] = true; + + tup = heap_form_tuple(RelationGetDescr(pg_attribute_rel), values, nulls); + + /* finally insert the new tuple, update the indexes, and clean up */ + if (indstate != NULL) + CatalogTupleInsertWithInfo(pg_attribute_rel, tup, indstate); + else + CatalogTupleInsert(pg_attribute_rel, tup); + + heap_freetuple(tup); +} + +/* -------------------------------- + * AddNewAttributeTuples + * + * this registers the new relation's schema by adding + * tuples to pg_attribute. + * -------------------------------- + */ +static void +AddNewAttributeTuples(Oid new_rel_oid, + TupleDesc tupdesc, + char relkind) +{ + Form_pg_attribute attr; + int i; + Relation rel; + CatalogIndexState indstate; + int natts = tupdesc->natts; + ObjectAddress myself, + referenced; + + /* + * open pg_attribute and its indexes. + */ + rel = table_open(AttributeRelationId, RowExclusiveLock); + + indstate = CatalogOpenIndexes(rel); + + /* + * First we add the user attributes. This is also a convenient place to + * add dependencies on their datatypes and collations. + */ + for (i = 0; i < natts; i++) + { + attr = TupleDescAttr(tupdesc, i); + /* Fill in the correct relation OID */ + attr->attrelid = new_rel_oid; + /* Make sure this is OK, too */ + attr->attstattarget = -1; + + InsertPgAttributeTuple(rel, attr, (Datum) 0, indstate); + + /* Add dependency info */ + myself.classId = RelationRelationId; + myself.objectId = new_rel_oid; + myself.objectSubId = i + 1; + referenced.classId = TypeRelationId; + referenced.objectId = attr->atttypid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + /* The default collation is pinned, so don't bother recording it */ + if (OidIsValid(attr->attcollation) && + attr->attcollation != DEFAULT_COLLATION_OID) + { + referenced.classId = CollationRelationId; + referenced.objectId = attr->attcollation; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + } + + /* + * Next we add the system attributes. Skip OID if rel has no OIDs. Skip + * all for a view or type relation. We don't bother with making datatype + * dependencies here, since presumably all these types are pinned. + */ + if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE) + { + for (i = 0; i < (int) lengthof(SysAtt); i++) + { + FormData_pg_attribute attStruct; + + memcpy(&attStruct, SysAtt[i], sizeof(FormData_pg_attribute)); + + /* Fill in the correct relation OID in the copied tuple */ + attStruct.attrelid = new_rel_oid; + + InsertPgAttributeTuple(rel, &attStruct, (Datum) 0, indstate); + } + } + + /* + * clean up + */ + CatalogCloseIndexes(indstate); + + table_close(rel, RowExclusiveLock); +} + +/* -------------------------------- + * InsertPgClassTuple + * + * Construct and insert a new tuple in pg_class. + * + * Caller has already opened and locked pg_class. + * Tuple data is taken from new_rel_desc->rd_rel, except for the + * variable-width fields which are not present in a cached reldesc. + * relacl and reloptions are passed in Datum form (to avoid having + * to reference the data types in heap.h). Pass (Datum) 0 to set them + * to NULL. + * -------------------------------- + */ +void +InsertPgClassTuple(Relation pg_class_desc, + Relation new_rel_desc, + Oid new_rel_oid, + Datum relacl, + Datum reloptions) +{ + Form_pg_class rd_rel = new_rel_desc->rd_rel; + Datum values[Natts_pg_class]; + bool nulls[Natts_pg_class]; + HeapTuple tup; + + /* This is a tad tedious, but way cleaner than what we used to do... */ + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + + values[Anum_pg_class_oid - 1] = ObjectIdGetDatum(new_rel_oid); + values[Anum_pg_class_relname - 1] = NameGetDatum(&rd_rel->relname); + values[Anum_pg_class_relnamespace - 1] = ObjectIdGetDatum(rd_rel->relnamespace); + values[Anum_pg_class_reltype - 1] = ObjectIdGetDatum(rd_rel->reltype); + values[Anum_pg_class_reloftype - 1] = ObjectIdGetDatum(rd_rel->reloftype); + values[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(rd_rel->relowner); + values[Anum_pg_class_relam - 1] = ObjectIdGetDatum(rd_rel->relam); + values[Anum_pg_class_relfilenode - 1] = ObjectIdGetDatum(rd_rel->relfilenode); + values[Anum_pg_class_reltablespace - 1] = ObjectIdGetDatum(rd_rel->reltablespace); + values[Anum_pg_class_relpages - 1] = Int32GetDatum(rd_rel->relpages); + values[Anum_pg_class_reltuples - 1] = Float4GetDatum(rd_rel->reltuples); + values[Anum_pg_class_relallvisible - 1] = Int32GetDatum(rd_rel->relallvisible); + values[Anum_pg_class_reltoastrelid - 1] = ObjectIdGetDatum(rd_rel->reltoastrelid); + values[Anum_pg_class_relhasindex - 1] = BoolGetDatum(rd_rel->relhasindex); + values[Anum_pg_class_relisshared - 1] = BoolGetDatum(rd_rel->relisshared); + values[Anum_pg_class_relpersistence - 1] = CharGetDatum(rd_rel->relpersistence); + values[Anum_pg_class_relkind - 1] = CharGetDatum(rd_rel->relkind); + values[Anum_pg_class_relnatts - 1] = Int16GetDatum(rd_rel->relnatts); + values[Anum_pg_class_relchecks - 1] = Int16GetDatum(rd_rel->relchecks); + values[Anum_pg_class_relhasrules - 1] = BoolGetDatum(rd_rel->relhasrules); + values[Anum_pg_class_relhastriggers - 1] = BoolGetDatum(rd_rel->relhastriggers); + values[Anum_pg_class_relrowsecurity - 1] = BoolGetDatum(rd_rel->relrowsecurity); + values[Anum_pg_class_relforcerowsecurity - 1] = BoolGetDatum(rd_rel->relforcerowsecurity); + values[Anum_pg_class_relhassubclass - 1] = BoolGetDatum(rd_rel->relhassubclass); + values[Anum_pg_class_relispopulated - 1] = BoolGetDatum(rd_rel->relispopulated); + values[Anum_pg_class_relreplident - 1] = CharGetDatum(rd_rel->relreplident); + values[Anum_pg_class_relispartition - 1] = BoolGetDatum(rd_rel->relispartition); + values[Anum_pg_class_relrewrite - 1] = ObjectIdGetDatum(rd_rel->relrewrite); + values[Anum_pg_class_relfrozenxid - 1] = TransactionIdGetDatum(rd_rel->relfrozenxid); + values[Anum_pg_class_relminmxid - 1] = MultiXactIdGetDatum(rd_rel->relminmxid); + if (relacl != (Datum) 0) + values[Anum_pg_class_relacl - 1] = relacl; + else + nulls[Anum_pg_class_relacl - 1] = true; + if (reloptions != (Datum) 0) + values[Anum_pg_class_reloptions - 1] = reloptions; + else + nulls[Anum_pg_class_reloptions - 1] = true; + + /* relpartbound is set by updating this tuple, if necessary */ + nulls[Anum_pg_class_relpartbound - 1] = true; + + tup = heap_form_tuple(RelationGetDescr(pg_class_desc), values, nulls); + + /* finally insert the new tuple, update the indexes, and clean up */ + CatalogTupleInsert(pg_class_desc, tup); + + heap_freetuple(tup); +} + +/* -------------------------------- + * AddNewRelationTuple + * + * this registers the new relation in the catalogs by + * adding a tuple to pg_class. + * -------------------------------- + */ +static void +AddNewRelationTuple(Relation pg_class_desc, + Relation new_rel_desc, + Oid new_rel_oid, + Oid new_type_oid, + Oid reloftype, + Oid relowner, + char relkind, + TransactionId relfrozenxid, + TransactionId relminmxid, + Datum relacl, + Datum reloptions) +{ + Form_pg_class new_rel_reltup; + + /* + * first we update some of the information in our uncataloged relation's + * relation descriptor. + */ + new_rel_reltup = new_rel_desc->rd_rel; + + switch (relkind) + { + case RELKIND_RELATION: + case RELKIND_MATVIEW: + case RELKIND_INDEX: + case RELKIND_TOASTVALUE: + /* The relation is real, but as yet empty */ + new_rel_reltup->relpages = 0; + new_rel_reltup->reltuples = 0; + new_rel_reltup->relallvisible = 0; + break; + case RELKIND_SEQUENCE: + /* Sequences always have a known size */ + new_rel_reltup->relpages = 1; + new_rel_reltup->reltuples = 1; + new_rel_reltup->relallvisible = 0; + break; + default: + /* Views, etc, have no disk storage */ + new_rel_reltup->relpages = 0; + new_rel_reltup->reltuples = 0; + new_rel_reltup->relallvisible = 0; + break; + } + + new_rel_reltup->relfrozenxid = relfrozenxid; + new_rel_reltup->relminmxid = relminmxid; + new_rel_reltup->relowner = relowner; + new_rel_reltup->reltype = new_type_oid; + new_rel_reltup->reloftype = reloftype; + + /* relispartition is always set by updating this tuple later */ + new_rel_reltup->relispartition = false; + + new_rel_desc->rd_att->tdtypeid = new_type_oid; + + /* Now build and insert the tuple */ + InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid, + relacl, reloptions); +} + + +/* -------------------------------- + * AddNewRelationType - + * + * define a composite type corresponding to the new relation + * -------------------------------- + */ +static ObjectAddress +AddNewRelationType(const char *typeName, + Oid typeNamespace, + Oid new_rel_oid, + char new_rel_kind, + Oid ownerid, + Oid new_row_type, + Oid new_array_type) +{ + return + TypeCreate(new_row_type, /* optional predetermined OID */ + typeName, /* type name */ + typeNamespace, /* type namespace */ + new_rel_oid, /* relation oid */ + new_rel_kind, /* relation kind */ + ownerid, /* owner's ID */ + -1, /* internal size (varlena) */ + TYPTYPE_COMPOSITE, /* type-type (composite) */ + TYPCATEGORY_COMPOSITE, /* type-category (ditto) */ + false, /* composite types are never preferred */ + DEFAULT_TYPDELIM, /* default array delimiter */ + F_RECORD_IN, /* input procedure */ + F_RECORD_OUT, /* output procedure */ + F_RECORD_RECV, /* receive procedure */ + F_RECORD_SEND, /* send procedure */ + InvalidOid, /* typmodin procedure - none */ + InvalidOid, /* typmodout procedure - none */ + InvalidOid, /* analyze procedure - default */ + InvalidOid, /* array element type - irrelevant */ + false, /* this is not an array type */ + new_array_type, /* array type if any */ + InvalidOid, /* domain base type - irrelevant */ + NULL, /* default value - none */ + NULL, /* default binary representation */ + false, /* passed by reference */ + TYPALIGN_DOUBLE, /* alignment - must be the largest! */ + TYPSTORAGE_EXTENDED, /* fully TOASTable */ + -1, /* typmod */ + 0, /* array dimensions for typBaseType */ + false, /* Type NOT NULL */ + InvalidOid); /* rowtypes never have a collation */ +} + +/* -------------------------------- + * heap_create_with_catalog + * + * creates a new cataloged relation. see comments above. + * + * Arguments: + * relname: name to give to new rel + * relnamespace: OID of namespace it goes in + * reltablespace: OID of tablespace it goes in + * relid: OID to assign to new rel, or InvalidOid to select a new OID + * reltypeid: OID to assign to rel's rowtype, or InvalidOid to select one + * reloftypeid: if a typed table, OID of underlying type; else InvalidOid + * ownerid: OID of new rel's owner + * tupdesc: tuple descriptor (source of column definitions) + * cooked_constraints: list of precooked check constraints and defaults + * relkind: relkind for new rel + * relpersistence: rel's persistence status (permanent, temp, or unlogged) + * shared_relation: true if it's to be a shared relation + * mapped_relation: true if the relation will use the relfilenode map + * oncommit: ON COMMIT marking (only relevant if it's a temp table) + * reloptions: reloptions in Datum form, or (Datum) 0 if none + * use_user_acl: true if should look for user-defined default permissions; + * if false, relacl is always set NULL + * allow_system_table_mods: true to allow creation in system namespaces + * is_internal: is this a system-generated catalog? + * + * Output parameters: + * typaddress: if not null, gets the object address of the new pg_type entry + * + * Returns the OID of the new relation + * -------------------------------- + */ +Oid +heap_create_with_catalog(const char *relname, + Oid relnamespace, + Oid reltablespace, + Oid relid, + Oid reltypeid, + Oid reloftypeid, + Oid ownerid, + Oid accessmtd, + TupleDesc tupdesc, + List *cooked_constraints, + char relkind, + char relpersistence, + bool shared_relation, + bool mapped_relation, + OnCommitAction oncommit, + Datum reloptions, + bool use_user_acl, + bool allow_system_table_mods, + bool is_internal, + Oid relrewrite, + ObjectAddress *typaddress) +{ + Relation pg_class_desc; + Relation new_rel_desc; + Acl *relacl; + Oid existing_relid; + Oid old_type_oid; + Oid new_type_oid; + ObjectAddress new_type_addr; + Oid new_array_oid = InvalidOid; + TransactionId relfrozenxid; + MultiXactId relminmxid; + + pg_class_desc = table_open(RelationRelationId, RowExclusiveLock); + + /* + * sanity checks + */ + Assert(IsNormalProcessingMode() || IsBootstrapProcessingMode()); + + /* + * Validate proposed tupdesc for the desired relkind. If + * allow_system_table_mods is on, allow ANYARRAY to be used; this is a + * hack to allow creating pg_statistic and cloning it during VACUUM FULL. + */ + CheckAttributeNamesTypes(tupdesc, relkind, + allow_system_table_mods ? CHKATYPE_ANYARRAY : 0); + + /* + * This would fail later on anyway, if the relation already exists. But + * by catching it here we can emit a nicer error message. + */ + existing_relid = get_relname_relid(relname, relnamespace); + if (existing_relid != InvalidOid) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_TABLE), + errmsg("relation \"%s\" already exists", relname))); + + /* + * Since we are going to create a rowtype as well, also check for + * collision with an existing type name. If there is one and it's an + * autogenerated array, we can rename it out of the way; otherwise we can + * at least give a good error message. + */ + old_type_oid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, + CStringGetDatum(relname), + ObjectIdGetDatum(relnamespace)); + if (OidIsValid(old_type_oid)) + { + if (!moveArrayTypeName(old_type_oid, relname, relnamespace)) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("type \"%s\" already exists", relname), + errhint("A relation has an associated type of the same name, " + "so you must use a name that doesn't conflict " + "with any existing type."))); + } + + /* + * Shared relations must be in pg_global (last-ditch check) + */ + if (shared_relation && reltablespace != GLOBALTABLESPACE_OID) + elog(ERROR, "shared relations must be placed in pg_global tablespace"); + + /* + * Allocate an OID for the relation, unless we were told what to use. + * + * The OID will be the relfilenode as well, so make sure it doesn't + * collide with either pg_class OIDs or existing physical files. + */ + if (!OidIsValid(relid)) + { + /* Use binary-upgrade override for pg_class.oid/relfilenode? */ + if (IsBinaryUpgrade && + (relkind == RELKIND_RELATION || relkind == RELKIND_SEQUENCE || + relkind == RELKIND_VIEW || relkind == RELKIND_MATVIEW || + relkind == RELKIND_COMPOSITE_TYPE || relkind == RELKIND_FOREIGN_TABLE || + relkind == RELKIND_PARTITIONED_TABLE)) + { + if (!OidIsValid(binary_upgrade_next_heap_pg_class_oid)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("pg_class heap OID value not set when in binary upgrade mode"))); + + relid = binary_upgrade_next_heap_pg_class_oid; + binary_upgrade_next_heap_pg_class_oid = InvalidOid; + } + /* There might be no TOAST table, so we have to test for it. */ + else if (IsBinaryUpgrade && + OidIsValid(binary_upgrade_next_toast_pg_class_oid) && + relkind == RELKIND_TOASTVALUE) + { + relid = binary_upgrade_next_toast_pg_class_oid; + binary_upgrade_next_toast_pg_class_oid = InvalidOid; + } + else + relid = GetNewRelFileNode(reltablespace, pg_class_desc, + relpersistence); + } + + /* + * Determine the relation's initial permissions. + */ + if (use_user_acl) + { + switch (relkind) + { + case RELKIND_RELATION: + case RELKIND_VIEW: + case RELKIND_MATVIEW: + case RELKIND_FOREIGN_TABLE: + case RELKIND_PARTITIONED_TABLE: + relacl = get_user_default_acl(OBJECT_TABLE, ownerid, + relnamespace); + break; + case RELKIND_SEQUENCE: + relacl = get_user_default_acl(OBJECT_SEQUENCE, ownerid, + relnamespace); + break; + default: + relacl = NULL; + break; + } + } + else + relacl = NULL; + + /* + * Create the relcache entry (mostly dummy at this point) and the physical + * disk file. (If we fail further down, it's the smgr's responsibility to + * remove the disk file again.) + */ + new_rel_desc = heap_create(relname, + relnamespace, + reltablespace, + relid, + InvalidOid, + accessmtd, + tupdesc, + relkind, + relpersistence, + shared_relation, + mapped_relation, + allow_system_table_mods, + &relfrozenxid, + &relminmxid); + + Assert(relid == RelationGetRelid(new_rel_desc)); + + new_rel_desc->rd_rel->relrewrite = relrewrite; + + /* + * Decide whether to create an array type over the relation's rowtype. We + * do not create any array types for system catalogs (ie, those made + * during initdb). We do not create them where the use of a relation as + * such is an implementation detail: toast tables, sequences and indexes. + */ + if (IsUnderPostmaster && (relkind == RELKIND_RELATION || + relkind == RELKIND_VIEW || + relkind == RELKIND_MATVIEW || + relkind == RELKIND_FOREIGN_TABLE || + relkind == RELKIND_COMPOSITE_TYPE || + relkind == RELKIND_PARTITIONED_TABLE)) + new_array_oid = AssignTypeArrayOid(); + + /* + * Since defining a relation also defines a complex type, we add a new + * system type corresponding to the new relation. The OID of the type can + * be preselected by the caller, but if reltypeid is InvalidOid, we'll + * generate a new OID for it. + * + * NOTE: we could get a unique-index failure here, in case someone else is + * creating the same type name in parallel but hadn't committed yet when + * we checked for a duplicate name above. + */ + new_type_addr = AddNewRelationType(relname, + relnamespace, + relid, + relkind, + ownerid, + reltypeid, + new_array_oid); + new_type_oid = new_type_addr.objectId; + if (typaddress) + *typaddress = new_type_addr; + + /* + * Now make the array type if wanted. + */ + if (OidIsValid(new_array_oid)) + { + char *relarrayname; + + relarrayname = makeArrayTypeName(relname, relnamespace); + + TypeCreate(new_array_oid, /* force the type's OID to this */ + relarrayname, /* Array type name */ + relnamespace, /* Same namespace as parent */ + InvalidOid, /* Not composite, no relationOid */ + 0, /* relkind, also N/A here */ + ownerid, /* owner's ID */ + -1, /* Internal size (varlena) */ + TYPTYPE_BASE, /* Not composite - typelem is */ + TYPCATEGORY_ARRAY, /* type-category (array) */ + false, /* array types are never preferred */ + DEFAULT_TYPDELIM, /* default array delimiter */ + F_ARRAY_IN, /* array input proc */ + F_ARRAY_OUT, /* array output proc */ + F_ARRAY_RECV, /* array recv (bin) proc */ + F_ARRAY_SEND, /* array send (bin) proc */ + InvalidOid, /* typmodin procedure - none */ + InvalidOid, /* typmodout procedure - none */ + F_ARRAY_TYPANALYZE, /* array analyze procedure */ + new_type_oid, /* array element type - the rowtype */ + true, /* yes, this is an array type */ + InvalidOid, /* this has no array type */ + InvalidOid, /* domain base type - irrelevant */ + NULL, /* default value - none */ + NULL, /* default binary representation */ + false, /* passed by reference */ + TYPALIGN_DOUBLE, /* alignment - must be the largest! */ + TYPSTORAGE_EXTENDED, /* fully TOASTable */ + -1, /* typmod */ + 0, /* array dimensions for typBaseType */ + false, /* Type NOT NULL */ + InvalidOid); /* rowtypes never have a collation */ + + pfree(relarrayname); + } + + /* + * now create an entry in pg_class for the relation. + * + * NOTE: we could get a unique-index failure here, in case someone else is + * creating the same relation name in parallel but hadn't committed yet + * when we checked for a duplicate name above. + */ + AddNewRelationTuple(pg_class_desc, + new_rel_desc, + relid, + new_type_oid, + reloftypeid, + ownerid, + relkind, + relfrozenxid, + relminmxid, + PointerGetDatum(relacl), + reloptions); + + /* + * now add tuples to pg_attribute for the attributes in our new relation. + */ + AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind); + + /* + * Make a dependency link to force the relation to be deleted if its + * namespace is. Also make a dependency link to its owner, as well as + * dependencies for any roles mentioned in the default ACL. + * + * For composite types, these dependencies are tracked for the pg_type + * entry, so we needn't record them here. Likewise, TOAST tables don't + * need a namespace dependency (they live in a pinned namespace) nor an + * owner dependency (they depend indirectly through the parent table), nor + * should they have any ACL entries. The same applies for extension + * dependencies. + * + * Also, skip this in bootstrap mode, since we don't make dependencies + * while bootstrapping. + */ + if (relkind != RELKIND_COMPOSITE_TYPE && + relkind != RELKIND_TOASTVALUE && + !IsBootstrapProcessingMode()) + { + ObjectAddress myself, + referenced; + + myself.classId = RelationRelationId; + myself.objectId = relid; + myself.objectSubId = 0; + + referenced.classId = NamespaceRelationId; + referenced.objectId = relnamespace; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + recordDependencyOnOwner(RelationRelationId, relid, ownerid); + + recordDependencyOnNewAcl(RelationRelationId, relid, 0, ownerid, relacl); + + recordDependencyOnCurrentExtension(&myself, false); + + if (reloftypeid) + { + referenced.classId = TypeRelationId; + referenced.objectId = reloftypeid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* + * Make a dependency link to force the relation to be deleted if its + * access method is. Do this only for relation and materialized views. + * + * No need to add an explicit dependency for the toast table, as the + * main table depends on it. + */ + if (relkind == RELKIND_RELATION || + relkind == RELKIND_MATVIEW) + { + referenced.classId = AccessMethodRelationId; + referenced.objectId = accessmtd; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + } + + /* Post creation hook for new relation */ + InvokeObjectPostCreateHookArg(RelationRelationId, relid, 0, is_internal); + + /* + * Store any supplied constraints and defaults. + * + * NB: this may do a CommandCounterIncrement and rebuild the relcache + * entry, so the relation must be valid and self-consistent at this point. + * In particular, there are not yet constraints and defaults anywhere. + */ + StoreConstraints(new_rel_desc, cooked_constraints, is_internal); + + /* + * If there's a special on-commit action, remember it + */ + if (oncommit != ONCOMMIT_NOOP) + register_on_commit_action(relid, oncommit); + + /* + * ok, the relation has been cataloged, so close our relations and return + * the OID of the newly created relation. + */ + table_close(new_rel_desc, NoLock); /* do not unlock till end of xact */ + table_close(pg_class_desc, RowExclusiveLock); + + return relid; +} + +/* + * RelationRemoveInheritance + * + * Formerly, this routine checked for child relations and aborted the + * deletion if any were found. Now we rely on the dependency mechanism + * to check for or delete child relations. By the time we get here, + * there are no children and we need only remove any pg_inherits rows + * linking this relation to its parent(s). + */ +static void +RelationRemoveInheritance(Oid relid) +{ + Relation catalogRelation; + SysScanDesc scan; + ScanKeyData key; + HeapTuple tuple; + + catalogRelation = table_open(InheritsRelationId, RowExclusiveLock); + + ScanKeyInit(&key, + Anum_pg_inherits_inhrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(relid)); + + scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true, + NULL, 1, &key); + + while (HeapTupleIsValid(tuple = systable_getnext(scan))) + CatalogTupleDelete(catalogRelation, &tuple->t_self); + + systable_endscan(scan); + table_close(catalogRelation, RowExclusiveLock); +} + +/* + * DeleteRelationTuple + * + * Remove pg_class row for the given relid. + * + * Note: this is shared by relation deletion and index deletion. It's + * not intended for use anyplace else. + */ +void +DeleteRelationTuple(Oid relid) +{ + Relation pg_class_desc; + HeapTuple tup; + + /* Grab an appropriate lock on the pg_class relation */ + pg_class_desc = table_open(RelationRelationId, RowExclusiveLock); + + tup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for relation %u", relid); + + /* delete the relation tuple from pg_class, and finish up */ + CatalogTupleDelete(pg_class_desc, &tup->t_self); + + ReleaseSysCache(tup); + + table_close(pg_class_desc, RowExclusiveLock); +} + +/* + * DeleteAttributeTuples + * + * Remove pg_attribute rows for the given relid. + * + * Note: this is shared by relation deletion and index deletion. It's + * not intended for use anyplace else. + */ +void +DeleteAttributeTuples(Oid relid) +{ + Relation attrel; + SysScanDesc scan; + ScanKeyData key[1]; + HeapTuple atttup; + + /* Grab an appropriate lock on the pg_attribute relation */ + attrel = table_open(AttributeRelationId, RowExclusiveLock); + + /* Use the index to scan only attributes of the target relation */ + ScanKeyInit(&key[0], + Anum_pg_attribute_attrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(relid)); + + scan = systable_beginscan(attrel, AttributeRelidNumIndexId, true, + NULL, 1, key); + + /* Delete all the matching tuples */ + while ((atttup = systable_getnext(scan)) != NULL) + CatalogTupleDelete(attrel, &atttup->t_self); + + /* Clean up after the scan */ + systable_endscan(scan); + table_close(attrel, RowExclusiveLock); +} + +/* + * DeleteSystemAttributeTuples + * + * Remove pg_attribute rows for system columns of the given relid. + * + * Note: this is only used when converting a table to a view. Views don't + * have system columns, so we should remove them from pg_attribute. + */ +void +DeleteSystemAttributeTuples(Oid relid) +{ + Relation attrel; + SysScanDesc scan; + ScanKeyData key[2]; + HeapTuple atttup; + + /* Grab an appropriate lock on the pg_attribute relation */ + attrel = table_open(AttributeRelationId, RowExclusiveLock); + + /* Use the index to scan only system attributes of the target relation */ + ScanKeyInit(&key[0], + Anum_pg_attribute_attrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(relid)); + ScanKeyInit(&key[1], + Anum_pg_attribute_attnum, + BTLessEqualStrategyNumber, F_INT2LE, + Int16GetDatum(0)); + + scan = systable_beginscan(attrel, AttributeRelidNumIndexId, true, + NULL, 2, key); + + /* Delete all the matching tuples */ + while ((atttup = systable_getnext(scan)) != NULL) + CatalogTupleDelete(attrel, &atttup->t_self); + + /* Clean up after the scan */ + systable_endscan(scan); + table_close(attrel, RowExclusiveLock); +} + +/* + * RemoveAttributeById + * + * This is the guts of ALTER TABLE DROP COLUMN: actually mark the attribute + * deleted in pg_attribute. We also remove pg_statistic entries for it. + * (Everything else needed, such as getting rid of any pg_attrdef entry, + * is handled by dependency.c.) + */ +void +RemoveAttributeById(Oid relid, AttrNumber attnum) +{ + Relation rel; + Relation attr_rel; + HeapTuple tuple; + Form_pg_attribute attStruct; + char newattname[NAMEDATALEN]; + + /* + * Grab an exclusive lock on the target table, which we will NOT release + * until end of transaction. (In the simple case where we are directly + * dropping this column, ATExecDropColumn already did this ... but when + * cascading from a drop of some other object, we may not have any lock.) + */ + rel = relation_open(relid, AccessExclusiveLock); + + attr_rel = table_open(AttributeRelationId, RowExclusiveLock); + + tuple = SearchSysCacheCopy2(ATTNUM, + ObjectIdGetDatum(relid), + Int16GetDatum(attnum)); + if (!HeapTupleIsValid(tuple)) /* shouldn't happen */ + elog(ERROR, "cache lookup failed for attribute %d of relation %u", + attnum, relid); + attStruct = (Form_pg_attribute) GETSTRUCT(tuple); + + if (attnum < 0) + { + /* System attribute (probably OID) ... just delete the row */ + + CatalogTupleDelete(attr_rel, &tuple->t_self); + } + else + { + /* Dropping user attributes is lots harder */ + + /* Mark the attribute as dropped */ + attStruct->attisdropped = true; + + /* + * Set the type OID to invalid. A dropped attribute's type link + * cannot be relied on (once the attribute is dropped, the type might + * be too). Fortunately we do not need the type row --- the only + * really essential information is the type's typlen and typalign, + * which are preserved in the attribute's attlen and attalign. We set + * atttypid to zero here as a means of catching code that incorrectly + * expects it to be valid. + */ + attStruct->atttypid = InvalidOid; + + /* Remove any NOT NULL constraint the column may have */ + attStruct->attnotnull = false; + + /* We don't want to keep stats for it anymore */ + attStruct->attstattarget = 0; + + /* Unset this so no one tries to look up the generation expression */ + attStruct->attgenerated = '\0'; + + /* + * Change the column name to something that isn't likely to conflict + */ + snprintf(newattname, sizeof(newattname), + "........pg.dropped.%d........", attnum); + namestrcpy(&(attStruct->attname), newattname); + + /* clear the missing value if any */ + if (attStruct->atthasmissing) + { + Datum valuesAtt[Natts_pg_attribute]; + bool nullsAtt[Natts_pg_attribute]; + bool replacesAtt[Natts_pg_attribute]; + + /* update the tuple - set atthasmissing and attmissingval */ + MemSet(valuesAtt, 0, sizeof(valuesAtt)); + MemSet(nullsAtt, false, sizeof(nullsAtt)); + MemSet(replacesAtt, false, sizeof(replacesAtt)); + + valuesAtt[Anum_pg_attribute_atthasmissing - 1] = + BoolGetDatum(false); + replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true; + valuesAtt[Anum_pg_attribute_attmissingval - 1] = (Datum) 0; + nullsAtt[Anum_pg_attribute_attmissingval - 1] = true; + replacesAtt[Anum_pg_attribute_attmissingval - 1] = true; + + tuple = heap_modify_tuple(tuple, RelationGetDescr(attr_rel), + valuesAtt, nullsAtt, replacesAtt); + } + + CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple); + } + + /* + * Because updating the pg_attribute row will trigger a relcache flush for + * the target relation, we need not do anything else to notify other + * backends of the change. + */ + + table_close(attr_rel, RowExclusiveLock); + + if (attnum > 0) + RemoveStatistics(relid, attnum); + + relation_close(rel, NoLock); +} + +/* + * RemoveAttrDefault + * + * If the specified relation/attribute has a default, remove it. + * (If no default, raise error if complain is true, else return quietly.) + */ +void +RemoveAttrDefault(Oid relid, AttrNumber attnum, + DropBehavior behavior, bool complain, bool internal) +{ + Relation attrdef_rel; + ScanKeyData scankeys[2]; + SysScanDesc scan; + HeapTuple tuple; + bool found = false; + + attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock); + + ScanKeyInit(&scankeys[0], + Anum_pg_attrdef_adrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(relid)); + ScanKeyInit(&scankeys[1], + Anum_pg_attrdef_adnum, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(attnum)); + + scan = systable_beginscan(attrdef_rel, AttrDefaultIndexId, true, + NULL, 2, scankeys); + + /* There should be at most one matching tuple, but we loop anyway */ + while (HeapTupleIsValid(tuple = systable_getnext(scan))) + { + ObjectAddress object; + Form_pg_attrdef attrtuple = (Form_pg_attrdef) GETSTRUCT(tuple); + + object.classId = AttrDefaultRelationId; + object.objectId = attrtuple->oid; + object.objectSubId = 0; + + performDeletion(&object, behavior, + internal ? PERFORM_DELETION_INTERNAL : 0); + + found = true; + } + + systable_endscan(scan); + table_close(attrdef_rel, RowExclusiveLock); + + if (complain && !found) + elog(ERROR, "could not find attrdef tuple for relation %u attnum %d", + relid, attnum); +} + +/* + * RemoveAttrDefaultById + * + * Remove a pg_attrdef entry specified by OID. This is the guts of + * attribute-default removal. Note it should be called via performDeletion, + * not directly. + */ +void +RemoveAttrDefaultById(Oid attrdefId) +{ + Relation attrdef_rel; + Relation attr_rel; + Relation myrel; + ScanKeyData scankeys[1]; + SysScanDesc scan; + HeapTuple tuple; + Oid myrelid; + AttrNumber myattnum; + + /* Grab an appropriate lock on the pg_attrdef relation */ + attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock); + + /* Find the pg_attrdef tuple */ + ScanKeyInit(&scankeys[0], + Anum_pg_attrdef_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(attrdefId)); + + scan = systable_beginscan(attrdef_rel, AttrDefaultOidIndexId, true, + NULL, 1, scankeys); + + tuple = systable_getnext(scan); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "could not find tuple for attrdef %u", attrdefId); + + myrelid = ((Form_pg_attrdef) GETSTRUCT(tuple))->adrelid; + myattnum = ((Form_pg_attrdef) GETSTRUCT(tuple))->adnum; + + /* Get an exclusive lock on the relation owning the attribute */ + myrel = relation_open(myrelid, AccessExclusiveLock); + + /* Now we can delete the pg_attrdef row */ + CatalogTupleDelete(attrdef_rel, &tuple->t_self); + + systable_endscan(scan); + table_close(attrdef_rel, RowExclusiveLock); + + /* Fix the pg_attribute row */ + attr_rel = table_open(AttributeRelationId, RowExclusiveLock); + + tuple = SearchSysCacheCopy2(ATTNUM, + ObjectIdGetDatum(myrelid), + Int16GetDatum(myattnum)); + if (!HeapTupleIsValid(tuple)) /* shouldn't happen */ + elog(ERROR, "cache lookup failed for attribute %d of relation %u", + myattnum, myrelid); + + ((Form_pg_attribute) GETSTRUCT(tuple))->atthasdef = false; + + CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple); + + /* + * Our update of the pg_attribute row will force a relcache rebuild, so + * there's nothing else to do here. + */ + table_close(attr_rel, RowExclusiveLock); + + /* Keep lock on attribute's rel until end of xact */ + relation_close(myrel, NoLock); +} + +/* + * heap_drop_with_catalog - removes specified relation from catalogs + * + * Note that this routine is not responsible for dropping objects that are + * linked to the pg_class entry via dependencies (for example, indexes and + * constraints). Those are deleted by the dependency-tracing logic in + * dependency.c before control gets here. In general, therefore, this routine + * should never be called directly; go through performDeletion() instead. + */ +void +heap_drop_with_catalog(Oid relid) +{ + Relation rel; + HeapTuple tuple; + Oid parentOid = InvalidOid, + defaultPartOid = InvalidOid; + + /* + * To drop a partition safely, we must grab exclusive lock on its parent, + * because another backend might be about to execute a query on the parent + * table. If it relies on previously cached partition descriptor, then it + * could attempt to access the just-dropped relation as its partition. We + * must therefore take a table lock strong enough to prevent all queries + * on the table from proceeding until we commit and send out a + * shared-cache-inval notice that will make them update their partition + * descriptors. + */ + tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", relid); + if (((Form_pg_class) GETSTRUCT(tuple))->relispartition) + { + parentOid = get_partition_parent(relid); + LockRelationOid(parentOid, AccessExclusiveLock); + + /* + * If this is not the default partition, dropping it will change the + * default partition's partition constraint, so we must lock it. + */ + defaultPartOid = get_default_partition_oid(parentOid); + if (OidIsValid(defaultPartOid) && relid != defaultPartOid) + LockRelationOid(defaultPartOid, AccessExclusiveLock); + } + + ReleaseSysCache(tuple); + + /* + * Open and lock the relation. + */ + rel = relation_open(relid, AccessExclusiveLock); + + /* + * There can no longer be anyone *else* touching the relation, but we + * might still have open queries or cursors, or pending trigger events, in + * our own session. + */ + CheckTableNotInUse(rel, "DROP TABLE"); + + /* + * This effectively deletes all rows in the table, and may be done in a + * serializable transaction. In that case we must record a rw-conflict in + * to this transaction from each transaction holding a predicate lock on + * the table. + */ + CheckTableForSerializableConflictIn(rel); + + /* + * Delete pg_foreign_table tuple first. + */ + if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE) + { + Relation rel; + HeapTuple tuple; + + rel = table_open(ForeignTableRelationId, RowExclusiveLock); + + tuple = SearchSysCache1(FOREIGNTABLEREL, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for foreign table %u", relid); + + CatalogTupleDelete(rel, &tuple->t_self); + + ReleaseSysCache(tuple); + table_close(rel, RowExclusiveLock); + } + + /* + * If a partitioned table, delete the pg_partitioned_table tuple. + */ + if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + RemovePartitionKeyByRelId(relid); + + /* + * If the relation being dropped is the default partition itself, + * invalidate its entry in pg_partitioned_table. + */ + if (relid == defaultPartOid) + update_default_partition_oid(parentOid, InvalidOid); + + /* + * Schedule unlinking of the relation's physical files at commit. + */ + if (rel->rd_rel->relkind != RELKIND_VIEW && + rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE && + rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE && + rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) + { + RelationDropStorage(rel); + } + + /* + * Close relcache entry, but *keep* AccessExclusiveLock on the relation + * until transaction commit. This ensures no one else will try to do + * something with the doomed relation. + */ + relation_close(rel, NoLock); + + /* + * Remove any associated relation synchronization states. + */ + RemoveSubscriptionRel(InvalidOid, relid); + + /* + * Forget any ON COMMIT action for the rel + */ + remove_on_commit_action(relid); + + /* + * Flush the relation from the relcache. We want to do this before + * starting to remove catalog entries, just to be certain that no relcache + * entry rebuild will happen partway through. (That should not really + * matter, since we don't do CommandCounterIncrement here, but let's be + * safe.) + */ + RelationForgetRelation(relid); + + /* + * remove inheritance information + */ + RelationRemoveInheritance(relid); + + /* + * delete statistics + */ + RemoveStatistics(relid, 0); + + /* + * delete attribute tuples + */ + DeleteAttributeTuples(relid); + + /* + * delete relation tuple + */ + DeleteRelationTuple(relid); + + if (OidIsValid(parentOid)) + { + /* + * If this is not the default partition, the partition constraint of + * the default partition has changed to include the portion of the key + * space previously covered by the dropped partition. + */ + if (OidIsValid(defaultPartOid) && relid != defaultPartOid) + CacheInvalidateRelcacheByRelid(defaultPartOid); + + /* + * Invalidate the parent's relcache so that the partition is no longer + * included in its partition descriptor. + */ + CacheInvalidateRelcacheByRelid(parentOid); + /* keep the lock */ + } +} + + +/* + * RelationClearMissing + * + * Set atthasmissing and attmissingval to false/null for all attributes + * where they are currently set. This can be safely and usefully done if + * the table is rewritten (e.g. by VACUUM FULL or CLUSTER) where we know there + * are no rows left with less than a full complement of attributes. + * + * The caller must have an AccessExclusive lock on the relation. + */ +void +RelationClearMissing(Relation rel) +{ + Relation attr_rel; + Oid relid = RelationGetRelid(rel); + int natts = RelationGetNumberOfAttributes(rel); + int attnum; + Datum repl_val[Natts_pg_attribute]; + bool repl_null[Natts_pg_attribute]; + bool repl_repl[Natts_pg_attribute]; + Form_pg_attribute attrtuple; + HeapTuple tuple, + newtuple; + + memset(repl_val, 0, sizeof(repl_val)); + memset(repl_null, false, sizeof(repl_null)); + memset(repl_repl, false, sizeof(repl_repl)); + + repl_val[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(false); + repl_null[Anum_pg_attribute_attmissingval - 1] = true; + + repl_repl[Anum_pg_attribute_atthasmissing - 1] = true; + repl_repl[Anum_pg_attribute_attmissingval - 1] = true; + + + /* Get a lock on pg_attribute */ + attr_rel = table_open(AttributeRelationId, RowExclusiveLock); + + /* process each non-system attribute, including any dropped columns */ + for (attnum = 1; attnum <= natts; attnum++) + { + tuple = SearchSysCache2(ATTNUM, + ObjectIdGetDatum(relid), + Int16GetDatum(attnum)); + if (!HeapTupleIsValid(tuple)) /* shouldn't happen */ + elog(ERROR, "cache lookup failed for attribute %d of relation %u", + attnum, relid); + + attrtuple = (Form_pg_attribute) GETSTRUCT(tuple); + + /* ignore any where atthasmissing is not true */ + if (attrtuple->atthasmissing) + { + newtuple = heap_modify_tuple(tuple, RelationGetDescr(attr_rel), + repl_val, repl_null, repl_repl); + + CatalogTupleUpdate(attr_rel, &newtuple->t_self, newtuple); + + heap_freetuple(newtuple); + } + + ReleaseSysCache(tuple); + } + + /* + * Our update of the pg_attribute rows will force a relcache rebuild, so + * there's nothing else to do here. + */ + table_close(attr_rel, RowExclusiveLock); +} + +/* + * SetAttrMissing + * + * Set the missing value of a single attribute. This should only be used by + * binary upgrade. Takes an AccessExclusive lock on the relation owning the + * attribute. + */ +void +SetAttrMissing(Oid relid, char *attname, char *value) +{ + Datum valuesAtt[Natts_pg_attribute]; + bool nullsAtt[Natts_pg_attribute]; + bool replacesAtt[Natts_pg_attribute]; + Datum missingval; + Form_pg_attribute attStruct; + Relation attrrel, + tablerel; + HeapTuple atttup, + newtup; + + /* lock the table the attribute belongs to */ + tablerel = table_open(relid, AccessExclusiveLock); + + /* Don't do anything unless it's a plain table */ + if (tablerel->rd_rel->relkind != RELKIND_RELATION) + { + table_close(tablerel, AccessExclusiveLock); + return; + } + + /* Lock the attribute row and get the data */ + attrrel = table_open(AttributeRelationId, RowExclusiveLock); + atttup = SearchSysCacheAttName(relid, attname); + if (!HeapTupleIsValid(atttup)) + elog(ERROR, "cache lookup failed for attribute %s of relation %u", + attname, relid); + attStruct = (Form_pg_attribute) GETSTRUCT(atttup); + + /* get an array value from the value string */ + missingval = OidFunctionCall3(F_ARRAY_IN, + CStringGetDatum(value), + ObjectIdGetDatum(attStruct->atttypid), + Int32GetDatum(attStruct->atttypmod)); + + /* update the tuple - set atthasmissing and attmissingval */ + MemSet(valuesAtt, 0, sizeof(valuesAtt)); + MemSet(nullsAtt, false, sizeof(nullsAtt)); + MemSet(replacesAtt, false, sizeof(replacesAtt)); + + valuesAtt[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(true); + replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true; + valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval; + replacesAtt[Anum_pg_attribute_attmissingval - 1] = true; + + newtup = heap_modify_tuple(atttup, RelationGetDescr(attrrel), + valuesAtt, nullsAtt, replacesAtt); + CatalogTupleUpdate(attrrel, &newtup->t_self, newtup); + + /* clean up */ + ReleaseSysCache(atttup); + table_close(attrrel, RowExclusiveLock); + table_close(tablerel, AccessExclusiveLock); +} + +/* + * Store a default expression for column attnum of relation rel. + * + * Returns the OID of the new pg_attrdef tuple. + * + * add_column_mode must be true if we are storing the default for a new + * attribute, and false if it's for an already existing attribute. The reason + * for this is that the missing value must never be updated after it is set, + * which can only be when a column is added to the table. Otherwise we would + * in effect be changing existing tuples. + */ +Oid +StoreAttrDefault(Relation rel, AttrNumber attnum, + Node *expr, bool is_internal, bool add_column_mode) +{ + char *adbin; + Relation adrel; + HeapTuple tuple; + Datum values[4]; + static bool nulls[4] = {false, false, false, false}; + Relation attrrel; + HeapTuple atttup; + Form_pg_attribute attStruct; + char attgenerated; + Oid attrdefOid; + ObjectAddress colobject, + defobject; + + adrel = table_open(AttrDefaultRelationId, RowExclusiveLock); + + /* + * Flatten expression to string form for storage. + */ + adbin = nodeToString(expr); + + /* + * Make the pg_attrdef entry. + */ + attrdefOid = GetNewOidWithIndex(adrel, AttrDefaultOidIndexId, + Anum_pg_attrdef_oid); + values[Anum_pg_attrdef_oid - 1] = ObjectIdGetDatum(attrdefOid); + values[Anum_pg_attrdef_adrelid - 1] = RelationGetRelid(rel); + values[Anum_pg_attrdef_adnum - 1] = attnum; + values[Anum_pg_attrdef_adbin - 1] = CStringGetTextDatum(adbin); + + tuple = heap_form_tuple(adrel->rd_att, values, nulls); + CatalogTupleInsert(adrel, tuple); + + defobject.classId = AttrDefaultRelationId; + defobject.objectId = attrdefOid; + defobject.objectSubId = 0; + + table_close(adrel, RowExclusiveLock); + + /* now can free some of the stuff allocated above */ + pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1])); + heap_freetuple(tuple); + pfree(adbin); + + /* + * Update the pg_attribute entry for the column to show that a default + * exists. + */ + attrrel = table_open(AttributeRelationId, RowExclusiveLock); + atttup = SearchSysCacheCopy2(ATTNUM, + ObjectIdGetDatum(RelationGetRelid(rel)), + Int16GetDatum(attnum)); + if (!HeapTupleIsValid(atttup)) + elog(ERROR, "cache lookup failed for attribute %d of relation %u", + attnum, RelationGetRelid(rel)); + attStruct = (Form_pg_attribute) GETSTRUCT(atttup); + attgenerated = attStruct->attgenerated; + if (!attStruct->atthasdef) + { + Form_pg_attribute defAttStruct; + + ExprState *exprState; + Expr *expr2 = (Expr *) expr; + EState *estate = NULL; + ExprContext *econtext; + Datum valuesAtt[Natts_pg_attribute]; + bool nullsAtt[Natts_pg_attribute]; + bool replacesAtt[Natts_pg_attribute]; + Datum missingval = (Datum) 0; + bool missingIsNull = true; + + MemSet(valuesAtt, 0, sizeof(valuesAtt)); + MemSet(nullsAtt, false, sizeof(nullsAtt)); + MemSet(replacesAtt, false, sizeof(replacesAtt)); + valuesAtt[Anum_pg_attribute_atthasdef - 1] = true; + replacesAtt[Anum_pg_attribute_atthasdef - 1] = true; + + if (rel->rd_rel->relkind == RELKIND_RELATION && add_column_mode && + !attgenerated) + { + expr2 = expression_planner(expr2); + estate = CreateExecutorState(); + exprState = ExecPrepareExpr(expr2, estate); + econtext = GetPerTupleExprContext(estate); + + missingval = ExecEvalExpr(exprState, econtext, + &missingIsNull); + + FreeExecutorState(estate); + + defAttStruct = TupleDescAttr(rel->rd_att, attnum - 1); + + if (missingIsNull) + { + /* if the default evaluates to NULL, just store a NULL array */ + missingval = (Datum) 0; + } + else + { + /* otherwise make a one-element array of the value */ + missingval = PointerGetDatum(construct_array(&missingval, + 1, + defAttStruct->atttypid, + defAttStruct->attlen, + defAttStruct->attbyval, + defAttStruct->attalign)); + } + + valuesAtt[Anum_pg_attribute_atthasmissing - 1] = !missingIsNull; + replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true; + valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval; + replacesAtt[Anum_pg_attribute_attmissingval - 1] = true; + nullsAtt[Anum_pg_attribute_attmissingval - 1] = missingIsNull; + } + atttup = heap_modify_tuple(atttup, RelationGetDescr(attrrel), + valuesAtt, nullsAtt, replacesAtt); + + CatalogTupleUpdate(attrrel, &atttup->t_self, atttup); + + if (!missingIsNull) + pfree(DatumGetPointer(missingval)); + + } + table_close(attrrel, RowExclusiveLock); + heap_freetuple(atttup); + + /* + * Make a dependency so that the pg_attrdef entry goes away if the column + * (or whole table) is deleted. + */ + colobject.classId = RelationRelationId; + colobject.objectId = RelationGetRelid(rel); + colobject.objectSubId = attnum; + + recordDependencyOn(&defobject, &colobject, DEPENDENCY_AUTO); + + /* + * Record dependencies on objects used in the expression, too. + */ + if (attgenerated) + { + /* + * Generated column: Dropping anything that the generation expression + * refers to automatically drops the generated column. + */ + recordDependencyOnSingleRelExpr(&colobject, expr, RelationGetRelid(rel), + DEPENDENCY_AUTO, + DEPENDENCY_AUTO, false); + } + else + { + /* + * Normal default: Dropping anything that the default refers to + * requires CASCADE and drops the default only. + */ + recordDependencyOnSingleRelExpr(&defobject, expr, RelationGetRelid(rel), + DEPENDENCY_NORMAL, + DEPENDENCY_NORMAL, false); + } + + /* + * Post creation hook for attribute defaults. + * + * XXX. ALTER TABLE ALTER COLUMN SET/DROP DEFAULT is implemented with a + * couple of deletion/creation of the attribute's default entry, so the + * callee should check existence of an older version of this entry if it + * needs to distinguish. + */ + InvokeObjectPostCreateHookArg(AttrDefaultRelationId, + RelationGetRelid(rel), attnum, is_internal); + + return attrdefOid; +} + +/* + * Store a check-constraint expression for the given relation. + * + * Caller is responsible for updating the count of constraints + * in the pg_class entry for the relation. + * + * The OID of the new constraint is returned. + */ +static Oid +StoreRelCheck(Relation rel, const char *ccname, Node *expr, + bool is_validated, bool is_local, int inhcount, + bool is_no_inherit, bool is_internal) +{ + char *ccbin; + List *varList; + int keycount; + int16 *attNos; + Oid constrOid; + + /* + * Flatten expression to string form for storage. + */ + ccbin = nodeToString(expr); + + /* + * Find columns of rel that are used in expr + * + * NB: pull_var_clause is okay here only because we don't allow subselects + * in check constraints; it would fail to examine the contents of + * subselects. + */ + varList = pull_var_clause(expr, 0); + keycount = list_length(varList); + + if (keycount > 0) + { + ListCell *vl; + int i = 0; + + attNos = (int16 *) palloc(keycount * sizeof(int16)); + foreach(vl, varList) + { + Var *var = (Var *) lfirst(vl); + int j; + + for (j = 0; j < i; j++) + if (attNos[j] == var->varattno) + break; + if (j == i) + attNos[i++] = var->varattno; + } + keycount = i; + } + else + attNos = NULL; + + /* + * Partitioned tables do not contain any rows themselves, so a NO INHERIT + * constraint makes no sense. + */ + if (is_no_inherit && + rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("cannot add NO INHERIT constraint to partitioned table \"%s\"", + RelationGetRelationName(rel)))); + + /* + * Create the Check Constraint + */ + constrOid = + CreateConstraintEntry(ccname, /* Constraint Name */ + RelationGetNamespace(rel), /* namespace */ + CONSTRAINT_CHECK, /* Constraint Type */ + false, /* Is Deferrable */ + false, /* Is Deferred */ + is_validated, + InvalidOid, /* no parent constraint */ + RelationGetRelid(rel), /* relation */ + attNos, /* attrs in the constraint */ + keycount, /* # key attrs in the constraint */ + keycount, /* # total attrs in the constraint */ + InvalidOid, /* not a domain constraint */ + InvalidOid, /* no associated index */ + InvalidOid, /* Foreign key fields */ + NULL, + NULL, + NULL, + NULL, + 0, + ' ', + ' ', + ' ', + NULL, /* not an exclusion constraint */ + expr, /* Tree form of check constraint */ + ccbin, /* Binary form of check constraint */ + is_local, /* conislocal */ + inhcount, /* coninhcount */ + is_no_inherit, /* connoinherit */ + is_internal); /* internally constructed? */ + + pfree(ccbin); + + return constrOid; +} + +/* + * Store defaults and constraints (passed as a list of CookedConstraint). + * + * Each CookedConstraint struct is modified to store the new catalog tuple OID. + * + * NOTE: only pre-cooked expressions will be passed this way, which is to + * say expressions inherited from an existing relation. Newly parsed + * expressions can be added later, by direct calls to StoreAttrDefault + * and StoreRelCheck (see AddRelationNewConstraints()). + */ +static void +StoreConstraints(Relation rel, List *cooked_constraints, bool is_internal) +{ + int numchecks = 0; + ListCell *lc; + + if (cooked_constraints == NIL) + return; /* nothing to do */ + + /* + * Deparsing of constraint expressions will fail unless the just-created + * pg_attribute tuples for this relation are made visible. So, bump the + * command counter. CAUTION: this will cause a relcache entry rebuild. + */ + CommandCounterIncrement(); + + foreach(lc, cooked_constraints) + { + CookedConstraint *con = (CookedConstraint *) lfirst(lc); + + switch (con->contype) + { + case CONSTR_DEFAULT: + con->conoid = StoreAttrDefault(rel, con->attnum, con->expr, + is_internal, false); + break; + case CONSTR_CHECK: + con->conoid = + StoreRelCheck(rel, con->name, con->expr, + !con->skip_validation, con->is_local, + con->inhcount, con->is_no_inherit, + is_internal); + numchecks++; + break; + default: + elog(ERROR, "unrecognized constraint type: %d", + (int) con->contype); + } + } + + if (numchecks > 0) + SetRelationNumChecks(rel, numchecks); +} + +/* + * AddRelationNewConstraints + * + * Add new column default expressions and/or constraint check expressions + * to an existing relation. This is defined to do both for efficiency in + * DefineRelation, but of course you can do just one or the other by passing + * empty lists. + * + * rel: relation to be modified + * newColDefaults: list of RawColumnDefault structures + * newConstraints: list of Constraint nodes + * allow_merge: true if check constraints may be merged with existing ones + * is_local: true if definition is local, false if it's inherited + * is_internal: true if result of some internal process, not a user request + * + * All entries in newColDefaults will be processed. Entries in newConstraints + * will be processed only if they are CONSTR_CHECK type. + * + * Returns a list of CookedConstraint nodes that shows the cooked form of + * the default and constraint expressions added to the relation. + * + * NB: caller should have opened rel with AccessExclusiveLock, and should + * hold that lock till end of transaction. Also, we assume the caller has + * done a CommandCounterIncrement if necessary to make the relation's catalog + * tuples visible. + */ +List * +AddRelationNewConstraints(Relation rel, + List *newColDefaults, + List *newConstraints, + bool allow_merge, + bool is_local, + bool is_internal, + const char *queryString) +{ + List *cookedConstraints = NIL; + TupleDesc tupleDesc; + TupleConstr *oldconstr; + int numoldchecks; + ParseState *pstate; + ParseNamespaceItem *nsitem; + int numchecks; + List *checknames; + ListCell *cell; + Node *expr; + CookedConstraint *cooked; + + /* + * Get info about existing constraints. + */ + tupleDesc = RelationGetDescr(rel); + oldconstr = tupleDesc->constr; + if (oldconstr) + numoldchecks = oldconstr->num_check; + else + numoldchecks = 0; + + /* + * Create a dummy ParseState and insert the target relation as its sole + * rangetable entry. We need a ParseState for transformExpr. + */ + pstate = make_parsestate(NULL); + pstate->p_sourcetext = queryString; + nsitem = addRangeTableEntryForRelation(pstate, + rel, + AccessShareLock, + NULL, + false, + true); + addNSItemToQuery(pstate, nsitem, true, true, true); + + /* + * Process column default expressions. + */ + foreach(cell, newColDefaults) + { + RawColumnDefault *colDef = (RawColumnDefault *) lfirst(cell); + Form_pg_attribute atp = TupleDescAttr(rel->rd_att, colDef->attnum - 1); + Oid defOid; + + expr = cookDefault(pstate, colDef->raw_default, + atp->atttypid, atp->atttypmod, + NameStr(atp->attname), + atp->attgenerated); + + /* + * If the expression is just a NULL constant, we do not bother to make + * an explicit pg_attrdef entry, since the default behavior is + * equivalent. This applies to column defaults, but not for + * generation expressions. + * + * Note a nonobvious property of this test: if the column is of a + * domain type, what we'll get is not a bare null Const but a + * CoerceToDomain expr, so we will not discard the default. This is + * critical because the column default needs to be retained to + * override any default that the domain might have. + */ + if (expr == NULL || + (!colDef->generated && + IsA(expr, Const) && + castNode(Const, expr)->constisnull)) + continue; + + /* If the DEFAULT is volatile we cannot use a missing value */ + if (colDef->missingMode && contain_volatile_functions((Node *) expr)) + colDef->missingMode = false; + + defOid = StoreAttrDefault(rel, colDef->attnum, expr, is_internal, + colDef->missingMode); + + cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint)); + cooked->contype = CONSTR_DEFAULT; + cooked->conoid = defOid; + cooked->name = NULL; + cooked->attnum = colDef->attnum; + cooked->expr = expr; + cooked->skip_validation = false; + cooked->is_local = is_local; + cooked->inhcount = is_local ? 0 : 1; + cooked->is_no_inherit = false; + cookedConstraints = lappend(cookedConstraints, cooked); + } + + /* + * Process constraint expressions. + */ + numchecks = numoldchecks; + checknames = NIL; + foreach(cell, newConstraints) + { + Constraint *cdef = (Constraint *) lfirst(cell); + char *ccname; + Oid constrOid; + + if (cdef->contype != CONSTR_CHECK) + continue; + + if (cdef->raw_expr != NULL) + { + Assert(cdef->cooked_expr == NULL); + + /* + * Transform raw parsetree to executable expression, and verify + * it's valid as a CHECK constraint. + */ + expr = cookConstraint(pstate, cdef->raw_expr, + RelationGetRelationName(rel)); + } + else + { + Assert(cdef->cooked_expr != NULL); + + /* + * Here, we assume the parser will only pass us valid CHECK + * expressions, so we do no particular checking. + */ + expr = stringToNode(cdef->cooked_expr); + } + + /* + * Check name uniqueness, or generate a name if none was given. + */ + if (cdef->conname != NULL) + { + ListCell *cell2; + + ccname = cdef->conname; + /* Check against other new constraints */ + /* Needed because we don't do CommandCounterIncrement in loop */ + foreach(cell2, checknames) + { + if (strcmp((char *) lfirst(cell2), ccname) == 0) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("check constraint \"%s\" already exists", + ccname))); + } + + /* save name for future checks */ + checknames = lappend(checknames, ccname); + + /* + * Check against pre-existing constraints. If we are allowed to + * merge with an existing constraint, there's no more to do here. + * (We omit the duplicate constraint from the result, which is + * what ATAddCheckConstraint wants.) + */ + if (MergeWithExistingConstraint(rel, ccname, expr, + allow_merge, is_local, + cdef->initially_valid, + cdef->is_no_inherit)) + continue; + } + else + { + /* + * When generating a name, we want to create "tab_col_check" for a + * column constraint and "tab_check" for a table constraint. We + * no longer have any info about the syntactic positioning of the + * constraint phrase, so we approximate this by seeing whether the + * expression references more than one column. (If the user + * played by the rules, the result is the same...) + * + * Note: pull_var_clause() doesn't descend into sublinks, but we + * eliminated those above; and anyway this only needs to be an + * approximate answer. + */ + List *vars; + char *colname; + + vars = pull_var_clause(expr, 0); + + /* eliminate duplicates */ + vars = list_union(NIL, vars); + + if (list_length(vars) == 1) + colname = get_attname(RelationGetRelid(rel), + ((Var *) linitial(vars))->varattno, + true); + else + colname = NULL; + + ccname = ChooseConstraintName(RelationGetRelationName(rel), + colname, + "check", + RelationGetNamespace(rel), + checknames); + + /* save name for future checks */ + checknames = lappend(checknames, ccname); + } + + /* + * OK, store it. + */ + constrOid = + StoreRelCheck(rel, ccname, expr, cdef->initially_valid, is_local, + is_local ? 0 : 1, cdef->is_no_inherit, is_internal); + + numchecks++; + + cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint)); + cooked->contype = CONSTR_CHECK; + cooked->conoid = constrOid; + cooked->name = ccname; + cooked->attnum = 0; + cooked->expr = expr; + cooked->skip_validation = cdef->skip_validation; + cooked->is_local = is_local; + cooked->inhcount = is_local ? 0 : 1; + cooked->is_no_inherit = cdef->is_no_inherit; + cookedConstraints = lappend(cookedConstraints, cooked); + } + + /* + * Update the count of constraints in the relation's pg_class tuple. We do + * this even if there was no change, in order to ensure that an SI update + * message is sent out for the pg_class tuple, which will force other + * backends to rebuild their relcache entries for the rel. (This is + * critical if we added defaults but not constraints.) + */ + SetRelationNumChecks(rel, numchecks); + + return cookedConstraints; +} + +/* + * Check for a pre-existing check constraint that conflicts with a proposed + * new one, and either adjust its conislocal/coninhcount settings or throw + * error as needed. + * + * Returns true if merged (constraint is a duplicate), or false if it's + * got a so-far-unique name, or throws error if conflict. + * + * XXX See MergeConstraintsIntoExisting too if you change this code. + */ +static bool +MergeWithExistingConstraint(Relation rel, const char *ccname, Node *expr, + bool allow_merge, bool is_local, + bool is_initially_valid, + bool is_no_inherit) +{ + bool found; + Relation conDesc; + SysScanDesc conscan; + ScanKeyData skey[3]; + HeapTuple tup; + + /* Search for a pg_constraint entry with same name and relation */ + conDesc = table_open(ConstraintRelationId, RowExclusiveLock); + + found = false; + + ScanKeyInit(&skey[0], + Anum_pg_constraint_conrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationGetRelid(rel))); + ScanKeyInit(&skey[1], + Anum_pg_constraint_contypid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(InvalidOid)); + ScanKeyInit(&skey[2], + Anum_pg_constraint_conname, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(ccname)); + + conscan = systable_beginscan(conDesc, ConstraintRelidTypidNameIndexId, true, + NULL, 3, skey); + + /* There can be at most one matching row */ + if (HeapTupleIsValid(tup = systable_getnext(conscan))) + { + Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup); + + /* Found it. Conflicts if not identical check constraint */ + if (con->contype == CONSTRAINT_CHECK) + { + Datum val; + bool isnull; + + val = fastgetattr(tup, + Anum_pg_constraint_conbin, + conDesc->rd_att, &isnull); + if (isnull) + elog(ERROR, "null conbin for rel %s", + RelationGetRelationName(rel)); + if (equal(expr, stringToNode(TextDatumGetCString(val)))) + found = true; + } + + /* + * If the existing constraint is purely inherited (no local + * definition) then interpret addition of a local constraint as a + * legal merge. This allows ALTER ADD CONSTRAINT on parent and child + * tables to be given in either order with same end state. However if + * the relation is a partition, all inherited constraints are always + * non-local, including those that were merged. + */ + if (is_local && !con->conislocal && !rel->rd_rel->relispartition) + allow_merge = true; + + if (!found || !allow_merge) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("constraint \"%s\" for relation \"%s\" already exists", + ccname, RelationGetRelationName(rel)))); + + /* If the child constraint is "no inherit" then cannot merge */ + if (con->connoinherit) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("constraint \"%s\" conflicts with non-inherited constraint on relation \"%s\"", + ccname, RelationGetRelationName(rel)))); + + /* + * Must not change an existing inherited constraint to "no inherit" + * status. That's because inherited constraints should be able to + * propagate to lower-level children. + */ + if (con->coninhcount > 0 && is_no_inherit) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("constraint \"%s\" conflicts with inherited constraint on relation \"%s\"", + ccname, RelationGetRelationName(rel)))); + + /* + * If the child constraint is "not valid" then cannot merge with a + * valid parent constraint. + */ + if (is_initially_valid && !con->convalidated) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("constraint \"%s\" conflicts with NOT VALID constraint on relation \"%s\"", + ccname, RelationGetRelationName(rel)))); + + /* OK to update the tuple */ + ereport(NOTICE, + (errmsg("merging constraint \"%s\" with inherited definition", + ccname))); + + tup = heap_copytuple(tup); + con = (Form_pg_constraint) GETSTRUCT(tup); + + /* + * In case of partitions, an inherited constraint must be inherited + * only once since it cannot have multiple parents and it is never + * considered local. + */ + if (rel->rd_rel->relispartition) + { + con->coninhcount = 1; + con->conislocal = false; + } + else + { + if (is_local) + con->conislocal = true; + else + con->coninhcount++; + } + + if (is_no_inherit) + { + Assert(is_local); + con->connoinherit = true; + } + + CatalogTupleUpdate(conDesc, &tup->t_self, tup); + } + + systable_endscan(conscan); + table_close(conDesc, RowExclusiveLock); + + return found; +} + +/* + * Update the count of constraints in the relation's pg_class tuple. + * + * Caller had better hold exclusive lock on the relation. + * + * An important side effect is that a SI update message will be sent out for + * the pg_class tuple, which will force other backends to rebuild their + * relcache entries for the rel. Also, this backend will rebuild its + * own relcache entry at the next CommandCounterIncrement. + */ +static void +SetRelationNumChecks(Relation rel, int numchecks) +{ + Relation relrel; + HeapTuple reltup; + Form_pg_class relStruct; + + relrel = table_open(RelationRelationId, RowExclusiveLock); + reltup = SearchSysCacheCopy1(RELOID, + ObjectIdGetDatum(RelationGetRelid(rel))); + if (!HeapTupleIsValid(reltup)) + elog(ERROR, "cache lookup failed for relation %u", + RelationGetRelid(rel)); + relStruct = (Form_pg_class) GETSTRUCT(reltup); + + if (relStruct->relchecks != numchecks) + { + relStruct->relchecks = numchecks; + + CatalogTupleUpdate(relrel, &reltup->t_self, reltup); + } + else + { + /* Skip the disk update, but force relcache inval anyway */ + CacheInvalidateRelcache(rel); + } + + heap_freetuple(reltup); + table_close(relrel, RowExclusiveLock); +} + +/* + * Check for references to generated columns + */ +static bool +check_nested_generated_walker(Node *node, void *context) +{ + ParseState *pstate = context; + + if (node == NULL) + return false; + else if (IsA(node, Var)) + { + Var *var = (Var *) node; + Oid relid; + AttrNumber attnum; + + relid = rt_fetch(var->varno, pstate->p_rtable)->relid; + if (!OidIsValid(relid)) + return false; /* XXX shouldn't we raise an error? */ + + attnum = var->varattno; + + if (attnum > 0 && get_attgenerated(relid, attnum)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("cannot use generated column \"%s\" in column generation expression", + get_attname(relid, attnum, false)), + errdetail("A generated column cannot reference another generated column."), + parser_errposition(pstate, var->location))); + /* A whole-row Var is necessarily self-referential, so forbid it */ + if (attnum == 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("cannot use whole-row variable in column generation expression"), + errdetail("This would cause the generated column to depend on its own value."), + parser_errposition(pstate, var->location))); + /* System columns were already checked in the parser */ + + return false; + } + else + return expression_tree_walker(node, check_nested_generated_walker, + (void *) context); +} + +static void +check_nested_generated(ParseState *pstate, Node *node) +{ + check_nested_generated_walker(node, pstate); +} + +/* + * Take a raw default and convert it to a cooked format ready for + * storage. + * + * Parse state should be set up to recognize any vars that might appear + * in the expression. (Even though we plan to reject vars, it's more + * user-friendly to give the correct error message than "unknown var".) + * + * If atttypid is not InvalidOid, coerce the expression to the specified + * type (and typmod atttypmod). attname is only needed in this case: + * it is used in the error message, if any. + */ +Node * +cookDefault(ParseState *pstate, + Node *raw_default, + Oid atttypid, + int32 atttypmod, + const char *attname, + char attgenerated) +{ + Node *expr; + + Assert(raw_default != NULL); + + /* + * Transform raw parsetree to executable expression. + */ + expr = transformExpr(pstate, raw_default, attgenerated ? EXPR_KIND_GENERATED_COLUMN : EXPR_KIND_COLUMN_DEFAULT); + + if (attgenerated) + { + check_nested_generated(pstate, expr); + + if (contain_mutable_functions(expr)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("generation expression is not immutable"))); + } + else + { + /* + * For a default expression, transformExpr() should have rejected + * column references. + */ + Assert(!contain_var_clause(expr)); + } + + /* + * Coerce the expression to the correct type and typmod, if given. This + * should match the parser's processing of non-defaulted expressions --- + * see transformAssignedExpr(). + */ + if (OidIsValid(atttypid)) + { + Oid type_id = exprType(expr); + + expr = coerce_to_target_type(pstate, expr, type_id, + atttypid, atttypmod, + COERCION_ASSIGNMENT, + COERCE_IMPLICIT_CAST, + -1); + if (expr == NULL) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("column \"%s\" is of type %s" + " but default expression is of type %s", + attname, + format_type_be(atttypid), + format_type_be(type_id)), + errhint("You will need to rewrite or cast the expression."))); + } + + /* + * Finally, take care of collations in the finished expression. + */ + assign_expr_collations(pstate, expr); + + return expr; +} + +/* + * Take a raw CHECK constraint expression and convert it to a cooked format + * ready for storage. + * + * Parse state must be set up to recognize any vars that might appear + * in the expression. + */ +static Node * +cookConstraint(ParseState *pstate, + Node *raw_constraint, + char *relname) +{ + Node *expr; + + /* + * Transform raw parsetree to executable expression. + */ + expr = transformExpr(pstate, raw_constraint, EXPR_KIND_CHECK_CONSTRAINT); + + /* + * Make sure it yields a boolean result. + */ + expr = coerce_to_boolean(pstate, expr, "CHECK"); + + /* + * Take care of collations. + */ + assign_expr_collations(pstate, expr); + + /* + * Make sure no outside relations are referred to (this is probably dead + * code now that add_missing_from is history). + */ + if (list_length(pstate->p_rtable) != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), + errmsg("only table \"%s\" can be referenced in check constraint", + relname))); + + return expr; +} + +/* + * CopyStatistics --- copy entries in pg_statistic from one rel to another + */ +void +CopyStatistics(Oid fromrelid, Oid torelid) +{ + HeapTuple tup; + SysScanDesc scan; + ScanKeyData key[1]; + Relation statrel; + + statrel = table_open(StatisticRelationId, RowExclusiveLock); + + /* Now search for stat records */ + ScanKeyInit(&key[0], + Anum_pg_statistic_starelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(fromrelid)); + + scan = systable_beginscan(statrel, StatisticRelidAttnumInhIndexId, + true, NULL, 1, key); + + while (HeapTupleIsValid((tup = systable_getnext(scan)))) + { + Form_pg_statistic statform; + + /* make a modifiable copy */ + tup = heap_copytuple(tup); + statform = (Form_pg_statistic) GETSTRUCT(tup); + + /* update the copy of the tuple and insert it */ + statform->starelid = torelid; + CatalogTupleInsert(statrel, tup); + + heap_freetuple(tup); + } + + systable_endscan(scan); + + table_close(statrel, RowExclusiveLock); +} + +/* + * RemoveStatistics --- remove entries in pg_statistic for a rel or column + * + * If attnum is zero, remove all entries for rel; else remove only the one(s) + * for that column. + */ +void +RemoveStatistics(Oid relid, AttrNumber attnum) +{ + Relation pgstatistic; + SysScanDesc scan; + ScanKeyData key[2]; + int nkeys; + HeapTuple tuple; + + pgstatistic = table_open(StatisticRelationId, RowExclusiveLock); + + ScanKeyInit(&key[0], + Anum_pg_statistic_starelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(relid)); + + if (attnum == 0) + nkeys = 1; + else + { + ScanKeyInit(&key[1], + Anum_pg_statistic_staattnum, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(attnum)); + nkeys = 2; + } + + scan = systable_beginscan(pgstatistic, StatisticRelidAttnumInhIndexId, true, + NULL, nkeys, key); + + /* we must loop even when attnum != 0, in case of inherited stats */ + while (HeapTupleIsValid(tuple = systable_getnext(scan))) + CatalogTupleDelete(pgstatistic, &tuple->t_self); + + systable_endscan(scan); + + table_close(pgstatistic, RowExclusiveLock); +} + + +/* + * RelationTruncateIndexes - truncate all indexes associated + * with the heap relation to zero tuples. + * + * The routine will truncate and then reconstruct the indexes on + * the specified relation. Caller must hold exclusive lock on rel. + */ +static void +RelationTruncateIndexes(Relation heapRelation) +{ + ListCell *indlist; + + /* Ask the relcache to produce a list of the indexes of the rel */ + foreach(indlist, RelationGetIndexList(heapRelation)) + { + Oid indexId = lfirst_oid(indlist); + Relation currentIndex; + IndexInfo *indexInfo; + + /* Open the index relation; use exclusive lock, just to be sure */ + currentIndex = index_open(indexId, AccessExclusiveLock); + + /* + * Fetch info needed for index_build. Since we know there are no + * tuples that actually need indexing, we can use a dummy IndexInfo. + * This is slightly cheaper to build, but the real point is to avoid + * possibly running user-defined code in index expressions or + * predicates. We might be getting invoked during ON COMMIT + * processing, and we don't want to run any such code then. + */ + indexInfo = BuildDummyIndexInfo(currentIndex); + + /* + * Now truncate the actual file (and discard buffers). + */ + RelationTruncate(currentIndex, 0); + + /* Initialize the index and rebuild */ + /* Note: we do not need to re-establish pkey setting */ + index_build(heapRelation, currentIndex, indexInfo, true, false); + + /* We're done with this index */ + index_close(currentIndex, NoLock); + } +} + +/* + * heap_truncate + * + * This routine deletes all data within all the specified relations. + * + * This is not transaction-safe! There is another, transaction-safe + * implementation in commands/tablecmds.c. We now use this only for + * ON COMMIT truncation of temporary tables, where it doesn't matter. + */ +void +heap_truncate(List *relids) +{ + List *relations = NIL; + ListCell *cell; + + /* Open relations for processing, and grab exclusive access on each */ + foreach(cell, relids) + { + Oid rid = lfirst_oid(cell); + Relation rel; + + rel = table_open(rid, AccessExclusiveLock); + relations = lappend(relations, rel); + } + + /* Don't allow truncate on tables that are referenced by foreign keys */ + heap_truncate_check_FKs(relations, true); + + /* OK to do it */ + foreach(cell, relations) + { + Relation rel = lfirst(cell); + + /* Truncate the relation */ + heap_truncate_one_rel(rel); + + /* Close the relation, but keep exclusive lock on it until commit */ + table_close(rel, NoLock); + } +} + +/* + * heap_truncate_one_rel + * + * This routine deletes all data within the specified relation. + * + * This is not transaction-safe, because the truncation is done immediately + * and cannot be rolled back later. Caller is responsible for having + * checked permissions etc, and must have obtained AccessExclusiveLock. + */ +void +heap_truncate_one_rel(Relation rel) +{ + Oid toastrelid; + + /* + * Truncate the relation. Partitioned tables have no storage, so there is + * nothing to do for them here. + */ + if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + return; + + /* Truncate the underlying relation */ + table_relation_nontransactional_truncate(rel); + + /* If the relation has indexes, truncate the indexes too */ + RelationTruncateIndexes(rel); + + /* If there is a toast table, truncate that too */ + toastrelid = rel->rd_rel->reltoastrelid; + if (OidIsValid(toastrelid)) + { + Relation toastrel = table_open(toastrelid, AccessExclusiveLock); + + table_relation_nontransactional_truncate(toastrel); + RelationTruncateIndexes(toastrel); + /* keep the lock... */ + table_close(toastrel, NoLock); + } +} + +/* + * heap_truncate_check_FKs + * Check for foreign keys referencing a list of relations that + * are to be truncated, and raise error if there are any + * + * We disallow such FKs (except self-referential ones) since the whole point + * of TRUNCATE is to not scan the individual rows to be thrown away. + * + * This is split out so it can be shared by both implementations of truncate. + * Caller should already hold a suitable lock on the relations. + * + * tempTables is only used to select an appropriate error message. + */ +void +heap_truncate_check_FKs(List *relations, bool tempTables) +{ + List *oids = NIL; + List *dependents; + ListCell *cell; + + /* + * Build a list of OIDs of the interesting relations. + * + * If a relation has no triggers, then it can neither have FKs nor be + * referenced by a FK from another table, so we can ignore it. For + * partitioned tables, FKs have no triggers, so we must include them + * anyway. + */ + foreach(cell, relations) + { + Relation rel = lfirst(cell); + + if (rel->rd_rel->relhastriggers || + rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + oids = lappend_oid(oids, RelationGetRelid(rel)); + } + + /* + * Fast path: if no relation has triggers, none has FKs either. + */ + if (oids == NIL) + return; + + /* + * Otherwise, must scan pg_constraint. We make one pass with all the + * relations considered; if this finds nothing, then all is well. + */ + dependents = heap_truncate_find_FKs(oids); + if (dependents == NIL) + return; + + /* + * Otherwise we repeat the scan once per relation to identify a particular + * pair of relations to complain about. This is pretty slow, but + * performance shouldn't matter much in a failure path. The reason for + * doing things this way is to ensure that the message produced is not + * dependent on chance row locations within pg_constraint. + */ + foreach(cell, oids) + { + Oid relid = lfirst_oid(cell); + ListCell *cell2; + + dependents = heap_truncate_find_FKs(list_make1_oid(relid)); + + foreach(cell2, dependents) + { + Oid relid2 = lfirst_oid(cell2); + + if (!list_member_oid(oids, relid2)) + { + char *relname = get_rel_name(relid); + char *relname2 = get_rel_name(relid2); + + if (tempTables) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("unsupported ON COMMIT and foreign key combination"), + errdetail("Table \"%s\" references \"%s\", but they do not have the same ON COMMIT setting.", + relname2, relname))); + else + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot truncate a table referenced in a foreign key constraint"), + errdetail("Table \"%s\" references \"%s\".", + relname2, relname), + errhint("Truncate table \"%s\" at the same time, " + "or use TRUNCATE ... CASCADE.", + relname2))); + } + } + } +} + +/* + * heap_truncate_find_FKs + * Find relations having foreign keys referencing any of the given rels + * + * Input and result are both lists of relation OIDs. The result contains + * no duplicates, does *not* include any rels that were already in the input + * list, and is sorted in OID order. (The last property is enforced mainly + * to guarantee consistent behavior in the regression tests; we don't want + * behavior to change depending on chance locations of rows in pg_constraint.) + * + * Note: caller should already have appropriate lock on all rels mentioned + * in relationIds. Since adding or dropping an FK requires exclusive lock + * on both rels, this ensures that the answer will be stable. + */ +List * +heap_truncate_find_FKs(List *relationIds) +{ + List *result = NIL; + List *oids = list_copy(relationIds); + List *parent_cons; + ListCell *cell; + ScanKeyData key; + Relation fkeyRel; + SysScanDesc fkeyScan; + HeapTuple tuple; + bool restart; + + oids = list_copy(relationIds); + + /* + * Must scan pg_constraint. Right now, it is a seqscan because there is + * no available index on confrelid. + */ + fkeyRel = table_open(ConstraintRelationId, AccessShareLock); + +restart: + restart = false; + parent_cons = NIL; + + fkeyScan = systable_beginscan(fkeyRel, InvalidOid, false, + NULL, 0, NULL); + + while (HeapTupleIsValid(tuple = systable_getnext(fkeyScan))) + { + Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple); + + /* Not a foreign key */ + if (con->contype != CONSTRAINT_FOREIGN) + continue; + + /* Not referencing one of our list of tables */ + if (!list_member_oid(oids, con->confrelid)) + continue; + + /* + * If this constraint has a parent constraint which we have not seen + * yet, keep track of it for the second loop, below. Tracking parent + * constraints allows us to climb up to the top-level level constraint + * and look for all possible relations referencing the partitioned + * table. + */ + if (OidIsValid(con->conparentid) && + !list_member_oid(parent_cons, con->conparentid)) + parent_cons = lappend_oid(parent_cons, con->conparentid); + + /* + * Add referencer to result, unless present in input list. (Don't + * worry about dupes: we'll fix that below). + */ + if (!list_member_oid(relationIds, con->conrelid)) + result = lappend_oid(result, con->conrelid); + } + + systable_endscan(fkeyScan); + + /* + * Process each parent constraint we found to add the list of referenced + * relations by them to the oids list. If we do add any new such + * relations, redo the first loop above. Also, if we see that the parent + * constraint in turn has a parent, add that so that we process all + * relations in a single additional pass. + */ + foreach(cell, parent_cons) + { + Oid parent = lfirst_oid(cell); + + ScanKeyInit(&key, + Anum_pg_constraint_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(parent)); + + fkeyScan = systable_beginscan(fkeyRel, ConstraintOidIndexId, + true, NULL, 1, &key); + + tuple = systable_getnext(fkeyScan); + if (HeapTupleIsValid(tuple)) + { + Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple); + + /* + * pg_constraint rows always appear for partitioned hierarchies + * this way: on the each side of the constraint, one row appears + * for each partition that points to the top-most table on the + * other side. + * + * Because of this arrangement, we can correctly catch all + * relevant relations by adding to 'parent_cons' all rows with + * valid conparentid, and to the 'oids' list all rows with a zero + * conparentid. If any oids are added to 'oids', redo the first + * loop above by setting 'restart'. + */ + if (OidIsValid(con->conparentid)) + parent_cons = list_append_unique_oid(parent_cons, + con->conparentid); + else if (!list_member_oid(oids, con->confrelid)) + { + oids = lappend_oid(oids, con->confrelid); + restart = true; + } + } + + systable_endscan(fkeyScan); + } + + list_free(parent_cons); + if (restart) + goto restart; + + table_close(fkeyRel, AccessShareLock); + list_free(oids); + + /* Now sort and de-duplicate the result list */ + list_sort(result, list_oid_cmp); + list_deduplicate_oid(result); + + return result; +} + +/* + * StorePartitionKey + * Store information about the partition key rel into the catalog + */ +void +StorePartitionKey(Relation rel, + char strategy, + int16 partnatts, + AttrNumber *partattrs, + List *partexprs, + Oid *partopclass, + Oid *partcollation) +{ + int i; + int2vector *partattrs_vec; + oidvector *partopclass_vec; + oidvector *partcollation_vec; + Datum partexprDatum; + Relation pg_partitioned_table; + HeapTuple tuple; + Datum values[Natts_pg_partitioned_table]; + bool nulls[Natts_pg_partitioned_table]; + ObjectAddress myself; + ObjectAddress referenced; + + Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE); + + /* Copy the partition attribute numbers, opclass OIDs into arrays */ + partattrs_vec = buildint2vector(partattrs, partnatts); + partopclass_vec = buildoidvector(partopclass, partnatts); + partcollation_vec = buildoidvector(partcollation, partnatts); + + /* Convert the expressions (if any) to a text datum */ + if (partexprs) + { + char *exprString; + + exprString = nodeToString(partexprs); + partexprDatum = CStringGetTextDatum(exprString); + pfree(exprString); + } + else + partexprDatum = (Datum) 0; + + pg_partitioned_table = table_open(PartitionedRelationId, RowExclusiveLock); + + MemSet(nulls, false, sizeof(nulls)); + + /* Only this can ever be NULL */ + if (!partexprDatum) + nulls[Anum_pg_partitioned_table_partexprs - 1] = true; + + values[Anum_pg_partitioned_table_partrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel)); + values[Anum_pg_partitioned_table_partstrat - 1] = CharGetDatum(strategy); + values[Anum_pg_partitioned_table_partnatts - 1] = Int16GetDatum(partnatts); + values[Anum_pg_partitioned_table_partdefid - 1] = ObjectIdGetDatum(InvalidOid); + values[Anum_pg_partitioned_table_partattrs - 1] = PointerGetDatum(partattrs_vec); + values[Anum_pg_partitioned_table_partclass - 1] = PointerGetDatum(partopclass_vec); + values[Anum_pg_partitioned_table_partcollation - 1] = PointerGetDatum(partcollation_vec); + values[Anum_pg_partitioned_table_partexprs - 1] = partexprDatum; + + tuple = heap_form_tuple(RelationGetDescr(pg_partitioned_table), values, nulls); + + CatalogTupleInsert(pg_partitioned_table, tuple); + table_close(pg_partitioned_table, RowExclusiveLock); + + /* Mark this relation as dependent on a few things as follows */ + myself.classId = RelationRelationId; + myself.objectId = RelationGetRelid(rel); + myself.objectSubId = 0; + + /* Operator class and collation per key column */ + for (i = 0; i < partnatts; i++) + { + referenced.classId = OperatorClassRelationId; + referenced.objectId = partopclass[i]; + referenced.objectSubId = 0; + + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + /* The default collation is pinned, so don't bother recording it */ + if (OidIsValid(partcollation[i]) && + partcollation[i] != DEFAULT_COLLATION_OID) + { + referenced.classId = CollationRelationId; + referenced.objectId = partcollation[i]; + referenced.objectSubId = 0; + + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + } + + /* + * The partitioning columns are made internally dependent on the table, + * because we cannot drop any of them without dropping the whole table. + * (ATExecDropColumn independently enforces that, but it's not bulletproof + * so we need the dependencies too.) + */ + for (i = 0; i < partnatts; i++) + { + if (partattrs[i] == 0) + continue; /* ignore expressions here */ + + referenced.classId = RelationRelationId; + referenced.objectId = RelationGetRelid(rel); + referenced.objectSubId = partattrs[i]; + + recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL); + } + + /* + * Also consider anything mentioned in partition expressions. External + * references (e.g. functions) get NORMAL dependencies. Table columns + * mentioned in the expressions are handled the same as plain partitioning + * columns, i.e. they become internally dependent on the whole table. + */ + if (partexprs) + recordDependencyOnSingleRelExpr(&myself, + (Node *) partexprs, + RelationGetRelid(rel), + DEPENDENCY_NORMAL, + DEPENDENCY_INTERNAL, + true /* reverse the self-deps */ ); + + /* + * We must invalidate the relcache so that the next + * CommandCounterIncrement() will cause the same to be rebuilt using the + * information in just created catalog entry. + */ + CacheInvalidateRelcache(rel); +} + +/* + * RemovePartitionKeyByRelId + * Remove pg_partitioned_table entry for a relation + */ +void +RemovePartitionKeyByRelId(Oid relid) +{ + Relation rel; + HeapTuple tuple; + + rel = table_open(PartitionedRelationId, RowExclusiveLock); + + tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for partition key of relation %u", + relid); + + CatalogTupleDelete(rel, &tuple->t_self); + + ReleaseSysCache(tuple); + table_close(rel, RowExclusiveLock); +} + +/* + * StorePartitionBound + * Update pg_class tuple of rel to store the partition bound and set + * relispartition to true + * + * If this is the default partition, also update the default partition OID in + * pg_partitioned_table. + * + * Also, invalidate the parent's relcache, so that the next rebuild will load + * the new partition's info into its partition descriptor. If there is a + * default partition, we must invalidate its relcache entry as well. + */ +void +StorePartitionBound(Relation rel, Relation parent, PartitionBoundSpec *bound) +{ + Relation classRel; + HeapTuple tuple, + newtuple; + Datum new_val[Natts_pg_class]; + bool new_null[Natts_pg_class], + new_repl[Natts_pg_class]; + Oid defaultPartOid; + + /* Update pg_class tuple */ + classRel = table_open(RelationRelationId, RowExclusiveLock); + tuple = SearchSysCacheCopy1(RELOID, + ObjectIdGetDatum(RelationGetRelid(rel))); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", + RelationGetRelid(rel)); + +#ifdef USE_ASSERT_CHECKING + { + Form_pg_class classForm; + bool isnull; + + classForm = (Form_pg_class) GETSTRUCT(tuple); + Assert(!classForm->relispartition); + (void) SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relpartbound, + &isnull); + Assert(isnull); + } +#endif + + /* Fill in relpartbound value */ + memset(new_val, 0, sizeof(new_val)); + memset(new_null, false, sizeof(new_null)); + memset(new_repl, false, sizeof(new_repl)); + new_val[Anum_pg_class_relpartbound - 1] = CStringGetTextDatum(nodeToString(bound)); + new_null[Anum_pg_class_relpartbound - 1] = false; + new_repl[Anum_pg_class_relpartbound - 1] = true; + newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel), + new_val, new_null, new_repl); + /* Also set the flag */ + ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = true; + CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple); + heap_freetuple(newtuple); + table_close(classRel, RowExclusiveLock); + + /* + * If we're storing bounds for the default partition, update + * pg_partitioned_table too. + */ + if (bound->is_default) + update_default_partition_oid(RelationGetRelid(parent), + RelationGetRelid(rel)); + + /* Make these updates visible */ + CommandCounterIncrement(); + + /* + * The partition constraint for the default partition depends on the + * partition bounds of every other partition, so we must invalidate the + * relcache entry for that partition every time a partition is added or + * removed. + */ + defaultPartOid = get_default_oid_from_partdesc(RelationGetPartitionDesc(parent)); + if (OidIsValid(defaultPartOid)) + CacheInvalidateRelcacheByRelid(defaultPartOid); + + CacheInvalidateRelcache(parent); +} diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c new file mode 100644 index 0000000..852b948 --- /dev/null +++ b/src/backend/catalog/index.c @@ -0,0 +1,4034 @@ +/*------------------------------------------------------------------------- + * + * index.c + * code to create and destroy POSTGRES index relations + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/index.c + * + * + * INTERFACE ROUTINES + * index_create() - Create a cataloged index relation + * index_drop() - Removes index relation from catalogs + * BuildIndexInfo() - Prepare to insert index tuples + * FormIndexDatum() - Construct datum vector for one index tuple + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include <unistd.h> + +#include "access/amapi.h" +#include "access/heapam.h" +#include "access/multixact.h" +#include "access/reloptions.h" +#include "access/relscan.h" +#include "access/sysattr.h" +#include "access/tableam.h" +#include "access/transam.h" +#include "access/visibilitymap.h" +#include "access/xact.h" +#include "bootstrap/bootstrap.h" +#include "catalog/binary_upgrade.h" +#include "catalog/catalog.h" +#include "catalog/dependency.h" +#include "catalog/heap.h" +#include "catalog/index.h" +#include "catalog/objectaccess.h" +#include "catalog/partition.h" +#include "catalog/pg_am.h" +#include "catalog/pg_collation.h" +#include "catalog/pg_constraint.h" +#include "catalog/pg_depend.h" +#include "catalog/pg_description.h" +#include "catalog/pg_inherits.h" +#include "catalog/pg_opclass.h" +#include "catalog/pg_operator.h" +#include "catalog/pg_tablespace.h" +#include "catalog/pg_trigger.h" +#include "catalog/pg_type.h" +#include "catalog/storage.h" +#include "commands/event_trigger.h" +#include "commands/progress.h" +#include "commands/tablecmds.h" +#include "commands/trigger.h" +#include "executor/executor.h" +#include "miscadmin.h" +#include "nodes/makefuncs.h" +#include "nodes/nodeFuncs.h" +#include "optimizer/optimizer.h" +#include "parser/parser.h" +#include "pgstat.h" +#include "rewrite/rewriteManip.h" +#include "storage/bufmgr.h" +#include "storage/lmgr.h" +#include "storage/predicate.h" +#include "storage/procarray.h" +#include "storage/smgr.h" +#include "utils/builtins.h" +#include "utils/fmgroids.h" +#include "utils/guc.h" +#include "utils/inval.h" +#include "utils/lsyscache.h" +#include "utils/memutils.h" +#include "utils/pg_rusage.h" +#include "utils/snapmgr.h" +#include "utils/syscache.h" +#include "utils/tuplesort.h" + +/* Potentially set by pg_upgrade_support functions */ +Oid binary_upgrade_next_index_pg_class_oid = InvalidOid; + +/* + * Pointer-free representation of variables used when reindexing system + * catalogs; we use this to propagate those values to parallel workers. + */ +typedef struct +{ + Oid currentlyReindexedHeap; + Oid currentlyReindexedIndex; + int numPendingReindexedIndexes; + Oid pendingReindexedIndexes[FLEXIBLE_ARRAY_MEMBER]; +} SerializedReindexState; + +/* non-export function prototypes */ +static bool relationHasPrimaryKey(Relation rel); +static TupleDesc ConstructTupleDescriptor(Relation heapRelation, + IndexInfo *indexInfo, + List *indexColNames, + Oid accessMethodObjectId, + Oid *collationObjectId, + Oid *classObjectId); +static void InitializeAttributeOids(Relation indexRelation, + int numatts, Oid indexoid); +static void AppendAttributeTuples(Relation indexRelation, int numatts, + Datum *attopts); +static void UpdateIndexRelation(Oid indexoid, Oid heapoid, + Oid parentIndexId, + IndexInfo *indexInfo, + Oid *collationOids, + Oid *classOids, + int16 *coloptions, + bool primary, + bool isexclusion, + bool immediate, + bool isvalid, + bool isready); +static void index_update_stats(Relation rel, + bool hasindex, + double reltuples); +static void IndexCheckExclusion(Relation heapRelation, + Relation indexRelation, + IndexInfo *indexInfo); +static bool validate_index_callback(ItemPointer itemptr, void *opaque); +static bool ReindexIsCurrentlyProcessingIndex(Oid indexOid); +static void SetReindexProcessing(Oid heapOid, Oid indexOid); +static void ResetReindexProcessing(void); +static void SetReindexPending(List *indexes); +static void RemoveReindexPending(Oid indexOid); + + +/* + * relationHasPrimaryKey + * See whether an existing relation has a primary key. + * + * Caller must have suitable lock on the relation. + * + * Note: we intentionally do not check indisvalid here; that's because this + * is used to enforce the rule that there can be only one indisprimary index, + * and we want that to be true even if said index is invalid. + */ +static bool +relationHasPrimaryKey(Relation rel) +{ + bool result = false; + List *indexoidlist; + ListCell *indexoidscan; + + /* + * Get the list of index OIDs for the table from the relcache, and look up + * each one in the pg_index syscache until we find one marked primary key + * (hopefully there isn't more than one such). + */ + indexoidlist = RelationGetIndexList(rel); + + foreach(indexoidscan, indexoidlist) + { + Oid indexoid = lfirst_oid(indexoidscan); + HeapTuple indexTuple; + + indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexoid)); + if (!HeapTupleIsValid(indexTuple)) /* should not happen */ + elog(ERROR, "cache lookup failed for index %u", indexoid); + result = ((Form_pg_index) GETSTRUCT(indexTuple))->indisprimary; + ReleaseSysCache(indexTuple); + if (result) + break; + } + + list_free(indexoidlist); + + return result; +} + +/* + * index_check_primary_key + * Apply special checks needed before creating a PRIMARY KEY index + * + * This processing used to be in DefineIndex(), but has been split out + * so that it can be applied during ALTER TABLE ADD PRIMARY KEY USING INDEX. + * + * We check for a pre-existing primary key, and that all columns of the index + * are simple column references (not expressions), and that all those + * columns are marked NOT NULL. If not, fail. + * + * We used to automatically change unmarked columns to NOT NULL here by doing + * our own local ALTER TABLE command. But that doesn't work well if we're + * executing one subcommand of an ALTER TABLE: the operations may not get + * performed in the right order overall. Now we expect that the parser + * inserted any required ALTER TABLE SET NOT NULL operations before trying + * to create a primary-key index. + * + * Caller had better have at least ShareLock on the table, else the not-null + * checking isn't trustworthy. + */ +void +index_check_primary_key(Relation heapRel, + IndexInfo *indexInfo, + bool is_alter_table, + IndexStmt *stmt) +{ + int i; + + /* + * If ALTER TABLE or CREATE TABLE .. PARTITION OF, check that there isn't + * already a PRIMARY KEY. In CREATE TABLE for an ordinary relation, we + * have faith that the parser rejected multiple pkey clauses; and CREATE + * INDEX doesn't have a way to say PRIMARY KEY, so it's no problem either. + */ + if ((is_alter_table || heapRel->rd_rel->relispartition) && + relationHasPrimaryKey(heapRel)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("multiple primary keys for table \"%s\" are not allowed", + RelationGetRelationName(heapRel)))); + } + + /* + * Check that all of the attributes in a primary key are marked as not + * null. (We don't really expect to see that; it'd mean the parser messed + * up. But it seems wise to check anyway.) + */ + for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++) + { + AttrNumber attnum = indexInfo->ii_IndexAttrNumbers[i]; + HeapTuple atttuple; + Form_pg_attribute attform; + + if (attnum == 0) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("primary keys cannot be expressions"))); + + /* System attributes are never null, so no need to check */ + if (attnum < 0) + continue; + + atttuple = SearchSysCache2(ATTNUM, + ObjectIdGetDatum(RelationGetRelid(heapRel)), + Int16GetDatum(attnum)); + if (!HeapTupleIsValid(atttuple)) + elog(ERROR, "cache lookup failed for attribute %d of relation %u", + attnum, RelationGetRelid(heapRel)); + attform = (Form_pg_attribute) GETSTRUCT(atttuple); + + if (!attform->attnotnull) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("primary key column \"%s\" is not marked NOT NULL", + NameStr(attform->attname)))); + + ReleaseSysCache(atttuple); + } +} + +/* + * ConstructTupleDescriptor + * + * Build an index tuple descriptor for a new index + */ +static TupleDesc +ConstructTupleDescriptor(Relation heapRelation, + IndexInfo *indexInfo, + List *indexColNames, + Oid accessMethodObjectId, + Oid *collationObjectId, + Oid *classObjectId) +{ + int numatts = indexInfo->ii_NumIndexAttrs; + int numkeyatts = indexInfo->ii_NumIndexKeyAttrs; + ListCell *colnames_item = list_head(indexColNames); + ListCell *indexpr_item = list_head(indexInfo->ii_Expressions); + IndexAmRoutine *amroutine; + TupleDesc heapTupDesc; + TupleDesc indexTupDesc; + int natts; /* #atts in heap rel --- for error checks */ + int i; + + /* We need access to the index AM's API struct */ + amroutine = GetIndexAmRoutineByAmId(accessMethodObjectId, false); + + /* ... and to the table's tuple descriptor */ + heapTupDesc = RelationGetDescr(heapRelation); + natts = RelationGetForm(heapRelation)->relnatts; + + /* + * allocate the new tuple descriptor + */ + indexTupDesc = CreateTemplateTupleDesc(numatts); + + /* + * Fill in the pg_attribute row. + */ + for (i = 0; i < numatts; i++) + { + AttrNumber atnum = indexInfo->ii_IndexAttrNumbers[i]; + Form_pg_attribute to = TupleDescAttr(indexTupDesc, i); + HeapTuple tuple; + Form_pg_type typeTup; + Form_pg_opclass opclassTup; + Oid keyType; + + MemSet(to, 0, ATTRIBUTE_FIXED_PART_SIZE); + to->attnum = i + 1; + to->attstattarget = -1; + to->attcacheoff = -1; + to->attislocal = true; + to->attcollation = (i < numkeyatts) ? + collationObjectId[i] : InvalidOid; + + /* + * Set the attribute name as specified by caller. + */ + if (colnames_item == NULL) /* shouldn't happen */ + elog(ERROR, "too few entries in colnames list"); + namestrcpy(&to->attname, (const char *) lfirst(colnames_item)); + colnames_item = lnext(indexColNames, colnames_item); + + /* + * For simple index columns, we copy some pg_attribute fields from the + * parent relation. For expressions we have to look at the expression + * result. + */ + if (atnum != 0) + { + /* Simple index column */ + const FormData_pg_attribute *from; + + Assert(atnum > 0); /* should've been caught above */ + + if (atnum > natts) /* safety check */ + elog(ERROR, "invalid column number %d", atnum); + from = TupleDescAttr(heapTupDesc, + AttrNumberGetAttrOffset(atnum)); + + to->atttypid = from->atttypid; + to->attlen = from->attlen; + to->attndims = from->attndims; + to->atttypmod = from->atttypmod; + to->attbyval = from->attbyval; + to->attstorage = from->attstorage; + to->attalign = from->attalign; + } + else + { + /* Expressional index */ + Node *indexkey; + + if (indexpr_item == NULL) /* shouldn't happen */ + elog(ERROR, "too few entries in indexprs list"); + indexkey = (Node *) lfirst(indexpr_item); + indexpr_item = lnext(indexInfo->ii_Expressions, indexpr_item); + + /* + * Lookup the expression type in pg_type for the type length etc. + */ + keyType = exprType(indexkey); + tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(keyType)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for type %u", keyType); + typeTup = (Form_pg_type) GETSTRUCT(tuple); + + /* + * Assign some of the attributes values. Leave the rest. + */ + to->atttypid = keyType; + to->attlen = typeTup->typlen; + to->attbyval = typeTup->typbyval; + to->attstorage = typeTup->typstorage; + to->attalign = typeTup->typalign; + to->atttypmod = exprTypmod(indexkey); + + ReleaseSysCache(tuple); + + /* + * Make sure the expression yields a type that's safe to store in + * an index. We need this defense because we have index opclasses + * for pseudo-types such as "record", and the actually stored type + * had better be safe; eg, a named composite type is okay, an + * anonymous record type is not. The test is the same as for + * whether a table column is of a safe type (which is why we + * needn't check for the non-expression case). + */ + CheckAttributeType(NameStr(to->attname), + to->atttypid, to->attcollation, + NIL, 0); + } + + /* + * We do not yet have the correct relation OID for the index, so just + * set it invalid for now. InitializeAttributeOids() will fix it + * later. + */ + to->attrelid = InvalidOid; + + /* + * Check the opclass and index AM to see if either provides a keytype + * (overriding the attribute type). Opclass (if exists) takes + * precedence. + */ + keyType = amroutine->amkeytype; + + if (i < indexInfo->ii_NumIndexKeyAttrs) + { + tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(classObjectId[i])); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for opclass %u", + classObjectId[i]); + opclassTup = (Form_pg_opclass) GETSTRUCT(tuple); + if (OidIsValid(opclassTup->opckeytype)) + keyType = opclassTup->opckeytype; + + /* + * If keytype is specified as ANYELEMENT, and opcintype is + * ANYARRAY, then the attribute type must be an array (else it'd + * not have matched this opclass); use its element type. + * + * We could also allow ANYCOMPATIBLE/ANYCOMPATIBLEARRAY here, but + * there seems no need to do so; there's no reason to declare an + * opclass as taking ANYCOMPATIBLEARRAY rather than ANYARRAY. + */ + if (keyType == ANYELEMENTOID && opclassTup->opcintype == ANYARRAYOID) + { + keyType = get_base_element_type(to->atttypid); + if (!OidIsValid(keyType)) + elog(ERROR, "could not get element type of array type %u", + to->atttypid); + } + + ReleaseSysCache(tuple); + } + + /* + * If a key type different from the heap value is specified, update + * the type-related fields in the index tupdesc. + */ + if (OidIsValid(keyType) && keyType != to->atttypid) + { + tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(keyType)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for type %u", keyType); + typeTup = (Form_pg_type) GETSTRUCT(tuple); + + to->atttypid = keyType; + to->atttypmod = -1; + to->attlen = typeTup->typlen; + to->attbyval = typeTup->typbyval; + to->attalign = typeTup->typalign; + to->attstorage = typeTup->typstorage; + + ReleaseSysCache(tuple); + } + } + + pfree(amroutine); + + return indexTupDesc; +} + +/* ---------------------------------------------------------------- + * InitializeAttributeOids + * ---------------------------------------------------------------- + */ +static void +InitializeAttributeOids(Relation indexRelation, + int numatts, + Oid indexoid) +{ + TupleDesc tupleDescriptor; + int i; + + tupleDescriptor = RelationGetDescr(indexRelation); + + for (i = 0; i < numatts; i += 1) + TupleDescAttr(tupleDescriptor, i)->attrelid = indexoid; +} + +/* ---------------------------------------------------------------- + * AppendAttributeTuples + * ---------------------------------------------------------------- + */ +static void +AppendAttributeTuples(Relation indexRelation, int numatts, Datum *attopts) +{ + Relation pg_attribute; + CatalogIndexState indstate; + TupleDesc indexTupDesc; + int i; + + /* + * open the attribute relation and its indexes + */ + pg_attribute = table_open(AttributeRelationId, RowExclusiveLock); + + indstate = CatalogOpenIndexes(pg_attribute); + + /* + * insert data from new index's tupdesc into pg_attribute + */ + indexTupDesc = RelationGetDescr(indexRelation); + + for (i = 0; i < numatts; i++) + { + Form_pg_attribute attr = TupleDescAttr(indexTupDesc, i); + Datum attoptions = attopts ? attopts[i] : (Datum) 0; + + Assert(attr->attnum == i + 1); + + InsertPgAttributeTuple(pg_attribute, attr, attoptions, indstate); + } + + CatalogCloseIndexes(indstate); + + table_close(pg_attribute, RowExclusiveLock); +} + +/* ---------------------------------------------------------------- + * UpdateIndexRelation + * + * Construct and insert a new entry in the pg_index catalog + * ---------------------------------------------------------------- + */ +static void +UpdateIndexRelation(Oid indexoid, + Oid heapoid, + Oid parentIndexId, + IndexInfo *indexInfo, + Oid *collationOids, + Oid *classOids, + int16 *coloptions, + bool primary, + bool isexclusion, + bool immediate, + bool isvalid, + bool isready) +{ + int2vector *indkey; + oidvector *indcollation; + oidvector *indclass; + int2vector *indoption; + Datum exprsDatum; + Datum predDatum; + Datum values[Natts_pg_index]; + bool nulls[Natts_pg_index]; + Relation pg_index; + HeapTuple tuple; + int i; + + /* + * Copy the index key, opclass, and indoption info into arrays (should we + * make the caller pass them like this to start with?) + */ + indkey = buildint2vector(NULL, indexInfo->ii_NumIndexAttrs); + for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++) + indkey->values[i] = indexInfo->ii_IndexAttrNumbers[i]; + indcollation = buildoidvector(collationOids, indexInfo->ii_NumIndexKeyAttrs); + indclass = buildoidvector(classOids, indexInfo->ii_NumIndexKeyAttrs); + indoption = buildint2vector(coloptions, indexInfo->ii_NumIndexKeyAttrs); + + /* + * Convert the index expressions (if any) to a text datum + */ + if (indexInfo->ii_Expressions != NIL) + { + char *exprsString; + + exprsString = nodeToString(indexInfo->ii_Expressions); + exprsDatum = CStringGetTextDatum(exprsString); + pfree(exprsString); + } + else + exprsDatum = (Datum) 0; + + /* + * Convert the index predicate (if any) to a text datum. Note we convert + * implicit-AND format to normal explicit-AND for storage. + */ + if (indexInfo->ii_Predicate != NIL) + { + char *predString; + + predString = nodeToString(make_ands_explicit(indexInfo->ii_Predicate)); + predDatum = CStringGetTextDatum(predString); + pfree(predString); + } + else + predDatum = (Datum) 0; + + + /* + * open the system catalog index relation + */ + pg_index = table_open(IndexRelationId, RowExclusiveLock); + + /* + * Build a pg_index tuple + */ + MemSet(nulls, false, sizeof(nulls)); + + values[Anum_pg_index_indexrelid - 1] = ObjectIdGetDatum(indexoid); + values[Anum_pg_index_indrelid - 1] = ObjectIdGetDatum(heapoid); + values[Anum_pg_index_indnatts - 1] = Int16GetDatum(indexInfo->ii_NumIndexAttrs); + values[Anum_pg_index_indnkeyatts - 1] = Int16GetDatum(indexInfo->ii_NumIndexKeyAttrs); + values[Anum_pg_index_indisunique - 1] = BoolGetDatum(indexInfo->ii_Unique); + values[Anum_pg_index_indisprimary - 1] = BoolGetDatum(primary); + values[Anum_pg_index_indisexclusion - 1] = BoolGetDatum(isexclusion); + values[Anum_pg_index_indimmediate - 1] = BoolGetDatum(immediate); + values[Anum_pg_index_indisclustered - 1] = BoolGetDatum(false); + values[Anum_pg_index_indisvalid - 1] = BoolGetDatum(isvalid); + values[Anum_pg_index_indcheckxmin - 1] = BoolGetDatum(false); + values[Anum_pg_index_indisready - 1] = BoolGetDatum(isready); + values[Anum_pg_index_indislive - 1] = BoolGetDatum(true); + values[Anum_pg_index_indisreplident - 1] = BoolGetDatum(false); + values[Anum_pg_index_indkey - 1] = PointerGetDatum(indkey); + values[Anum_pg_index_indcollation - 1] = PointerGetDatum(indcollation); + values[Anum_pg_index_indclass - 1] = PointerGetDatum(indclass); + values[Anum_pg_index_indoption - 1] = PointerGetDatum(indoption); + values[Anum_pg_index_indexprs - 1] = exprsDatum; + if (exprsDatum == (Datum) 0) + nulls[Anum_pg_index_indexprs - 1] = true; + values[Anum_pg_index_indpred - 1] = predDatum; + if (predDatum == (Datum) 0) + nulls[Anum_pg_index_indpred - 1] = true; + + tuple = heap_form_tuple(RelationGetDescr(pg_index), values, nulls); + + /* + * insert the tuple into the pg_index catalog + */ + CatalogTupleInsert(pg_index, tuple); + + /* + * close the relation and free the tuple + */ + table_close(pg_index, RowExclusiveLock); + heap_freetuple(tuple); +} + + +/* + * index_create + * + * heapRelation: table to build index on (suitably locked by caller) + * indexRelationName: what it say + * indexRelationId: normally, pass InvalidOid to let this routine + * generate an OID for the index. During bootstrap this may be + * nonzero to specify a preselected OID. + * parentIndexRelid: if creating an index partition, the OID of the + * parent index; otherwise InvalidOid. + * parentConstraintId: if creating a constraint on a partition, the OID + * of the constraint in the parent; otherwise InvalidOid. + * relFileNode: normally, pass InvalidOid to get new storage. May be + * nonzero to attach an existing valid build. + * indexInfo: same info executor uses to insert into the index + * indexColNames: column names to use for index (List of char *) + * accessMethodObjectId: OID of index AM to use + * tableSpaceId: OID of tablespace to use + * collationObjectId: array of collation OIDs, one per index column + * classObjectId: array of index opclass OIDs, one per index column + * coloptions: array of per-index-column indoption settings + * reloptions: AM-specific options + * flags: bitmask that can include any combination of these bits: + * INDEX_CREATE_IS_PRIMARY + * the index is a primary key + * INDEX_CREATE_ADD_CONSTRAINT: + * invoke index_constraint_create also + * INDEX_CREATE_SKIP_BUILD: + * skip the index_build() step for the moment; caller must do it + * later (typically via reindex_index()) + * INDEX_CREATE_CONCURRENT: + * do not lock the table against writers. The index will be + * marked "invalid" and the caller must take additional steps + * to fix it up. + * INDEX_CREATE_IF_NOT_EXISTS: + * do not throw an error if a relation with the same name + * already exists. + * INDEX_CREATE_PARTITIONED: + * create a partitioned index (table must be partitioned) + * constr_flags: flags passed to index_constraint_create + * (only if INDEX_CREATE_ADD_CONSTRAINT is set) + * allow_system_table_mods: allow table to be a system catalog + * is_internal: if true, post creation hook for new index + * constraintId: if not NULL, receives OID of created constraint + * + * Returns the OID of the created index. + */ +Oid +index_create(Relation heapRelation, + const char *indexRelationName, + Oid indexRelationId, + Oid parentIndexRelid, + Oid parentConstraintId, + Oid relFileNode, + IndexInfo *indexInfo, + List *indexColNames, + Oid accessMethodObjectId, + Oid tableSpaceId, + Oid *collationObjectId, + Oid *classObjectId, + int16 *coloptions, + Datum reloptions, + bits16 flags, + bits16 constr_flags, + bool allow_system_table_mods, + bool is_internal, + Oid *constraintId) +{ + Oid heapRelationId = RelationGetRelid(heapRelation); + Relation pg_class; + Relation indexRelation; + TupleDesc indexTupDesc; + bool shared_relation; + bool mapped_relation; + bool is_exclusion; + Oid namespaceId; + int i; + char relpersistence; + bool isprimary = (flags & INDEX_CREATE_IS_PRIMARY) != 0; + bool invalid = (flags & INDEX_CREATE_INVALID) != 0; + bool concurrent = (flags & INDEX_CREATE_CONCURRENT) != 0; + bool partitioned = (flags & INDEX_CREATE_PARTITIONED) != 0; + char relkind; + TransactionId relfrozenxid; + MultiXactId relminmxid; + + /* constraint flags can only be set when a constraint is requested */ + Assert((constr_flags == 0) || + ((flags & INDEX_CREATE_ADD_CONSTRAINT) != 0)); + /* partitioned indexes must never be "built" by themselves */ + Assert(!partitioned || (flags & INDEX_CREATE_SKIP_BUILD)); + + relkind = partitioned ? RELKIND_PARTITIONED_INDEX : RELKIND_INDEX; + is_exclusion = (indexInfo->ii_ExclusionOps != NULL); + + pg_class = table_open(RelationRelationId, RowExclusiveLock); + + /* + * The index will be in the same namespace as its parent table, and is + * shared across databases if and only if the parent is. Likewise, it + * will use the relfilenode map if and only if the parent does; and it + * inherits the parent's relpersistence. + */ + namespaceId = RelationGetNamespace(heapRelation); + shared_relation = heapRelation->rd_rel->relisshared; + mapped_relation = RelationIsMapped(heapRelation); + relpersistence = heapRelation->rd_rel->relpersistence; + + /* + * check parameters + */ + if (indexInfo->ii_NumIndexAttrs < 1) + elog(ERROR, "must index at least one column"); + + if (!allow_system_table_mods && + IsSystemRelation(heapRelation) && + IsNormalProcessingMode()) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("user-defined indexes on system catalog tables are not supported"))); + + /* + * Btree text_pattern_ops uses text_eq as the equality operator, which is + * fine as long as the collation is deterministic; text_eq then reduces to + * bitwise equality and so it is semantically compatible with the other + * operators and functions in that opclass. But with a nondeterministic + * collation, text_eq could yield results that are incompatible with the + * actual behavior of the index (which is determined by the opclass's + * comparison function). We prevent such problems by refusing creation of + * an index with that opclass and a nondeterministic collation. + * + * The same applies to varchar_pattern_ops and bpchar_pattern_ops. If we + * find more cases, we might decide to create a real mechanism for marking + * opclasses as incompatible with nondeterminism; but for now, this small + * hack suffices. + * + * Another solution is to use a special operator, not text_eq, as the + * equality opclass member; but that is undesirable because it would + * prevent index usage in many queries that work fine today. + */ + for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++) + { + Oid collation = collationObjectId[i]; + Oid opclass = classObjectId[i]; + + if (collation) + { + if ((opclass == TEXT_BTREE_PATTERN_OPS_OID || + opclass == VARCHAR_BTREE_PATTERN_OPS_OID || + opclass == BPCHAR_BTREE_PATTERN_OPS_OID) && + !get_collation_isdeterministic(collation)) + { + HeapTuple classtup; + + classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass)); + if (!HeapTupleIsValid(classtup)) + elog(ERROR, "cache lookup failed for operator class %u", opclass); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("nondeterministic collations are not supported for operator class \"%s\"", + NameStr(((Form_pg_opclass) GETSTRUCT(classtup))->opcname)))); + ReleaseSysCache(classtup); + } + } + } + + /* + * Concurrent index build on a system catalog is unsafe because we tend to + * release locks before committing in catalogs. + */ + if (concurrent && + IsCatalogRelation(heapRelation)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("concurrent index creation on system catalog tables is not supported"))); + + /* + * This case is currently not supported. There's no way to ask for it in + * the grammar with CREATE INDEX, but it can happen with REINDEX. + */ + if (concurrent && is_exclusion) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("concurrent index creation for exclusion constraints is not supported"))); + + /* + * We cannot allow indexing a shared relation after initdb (because + * there's no way to make the entry in other databases' pg_class). + */ + if (shared_relation && !IsBootstrapProcessingMode()) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("shared indexes cannot be created after initdb"))); + + /* + * Shared relations must be in pg_global, too (last-ditch check) + */ + if (shared_relation && tableSpaceId != GLOBALTABLESPACE_OID) + elog(ERROR, "shared relations must be placed in pg_global tablespace"); + + /* + * Check for duplicate name (both as to the index, and as to the + * associated constraint if any). Such cases would fail on the relevant + * catalogs' unique indexes anyway, but we prefer to give a friendlier + * error message. + */ + if (get_relname_relid(indexRelationName, namespaceId)) + { + if ((flags & INDEX_CREATE_IF_NOT_EXISTS) != 0) + { + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_TABLE), + errmsg("relation \"%s\" already exists, skipping", + indexRelationName))); + table_close(pg_class, RowExclusiveLock); + return InvalidOid; + } + + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_TABLE), + errmsg("relation \"%s\" already exists", + indexRelationName))); + } + + if ((flags & INDEX_CREATE_ADD_CONSTRAINT) != 0 && + ConstraintNameIsUsed(CONSTRAINT_RELATION, heapRelationId, + indexRelationName)) + { + /* + * INDEX_CREATE_IF_NOT_EXISTS does not apply here, since the + * conflicting constraint is not an index. + */ + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("constraint \"%s\" for relation \"%s\" already exists", + indexRelationName, RelationGetRelationName(heapRelation)))); + } + + /* + * construct tuple descriptor for index tuples + */ + indexTupDesc = ConstructTupleDescriptor(heapRelation, + indexInfo, + indexColNames, + accessMethodObjectId, + collationObjectId, + classObjectId); + + /* + * Allocate an OID for the index, unless we were told what to use. + * + * The OID will be the relfilenode as well, so make sure it doesn't + * collide with either pg_class OIDs or existing physical files. + */ + if (!OidIsValid(indexRelationId)) + { + /* Use binary-upgrade override for pg_class.oid/relfilenode? */ + if (IsBinaryUpgrade) + { + if (!OidIsValid(binary_upgrade_next_index_pg_class_oid)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("pg_class index OID value not set when in binary upgrade mode"))); + + indexRelationId = binary_upgrade_next_index_pg_class_oid; + binary_upgrade_next_index_pg_class_oid = InvalidOid; + } + else + { + indexRelationId = + GetNewRelFileNode(tableSpaceId, pg_class, relpersistence); + } + } + + /* + * create the index relation's relcache entry and, if necessary, the + * physical disk file. (If we fail further down, it's the smgr's + * responsibility to remove the disk file again, if any.) + */ + indexRelation = heap_create(indexRelationName, + namespaceId, + tableSpaceId, + indexRelationId, + relFileNode, + accessMethodObjectId, + indexTupDesc, + relkind, + relpersistence, + shared_relation, + mapped_relation, + allow_system_table_mods, + &relfrozenxid, + &relminmxid); + + Assert(relfrozenxid == InvalidTransactionId); + Assert(relminmxid == InvalidMultiXactId); + Assert(indexRelationId == RelationGetRelid(indexRelation)); + + /* + * Obtain exclusive lock on it. Although no other transactions can see it + * until we commit, this prevents deadlock-risk complaints from lock + * manager in cases such as CLUSTER. + */ + LockRelation(indexRelation, AccessExclusiveLock); + + /* + * Fill in fields of the index's pg_class entry that are not set correctly + * by heap_create. + * + * XXX should have a cleaner way to create cataloged indexes + */ + indexRelation->rd_rel->relowner = heapRelation->rd_rel->relowner; + indexRelation->rd_rel->relam = accessMethodObjectId; + indexRelation->rd_rel->relispartition = OidIsValid(parentIndexRelid); + + /* + * store index's pg_class entry + */ + InsertPgClassTuple(pg_class, indexRelation, + RelationGetRelid(indexRelation), + (Datum) 0, + reloptions); + + /* done with pg_class */ + table_close(pg_class, RowExclusiveLock); + + /* + * now update the object id's of all the attribute tuple forms in the + * index relation's tuple descriptor + */ + InitializeAttributeOids(indexRelation, + indexInfo->ii_NumIndexAttrs, + indexRelationId); + + /* + * append ATTRIBUTE tuples for the index + */ + AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs, + indexInfo->ii_OpclassOptions); + + /* ---------------- + * update pg_index + * (append INDEX tuple) + * + * Note that this stows away a representation of "predicate". + * (Or, could define a rule to maintain the predicate) --Nels, Feb '92 + * ---------------- + */ + UpdateIndexRelation(indexRelationId, heapRelationId, parentIndexRelid, + indexInfo, + collationObjectId, classObjectId, coloptions, + isprimary, is_exclusion, + (constr_flags & INDEX_CONSTR_CREATE_DEFERRABLE) == 0, + !concurrent && !invalid, + !concurrent); + + /* + * Register relcache invalidation on the indexes' heap relation, to + * maintain consistency of its index list + */ + CacheInvalidateRelcache(heapRelation); + + /* update pg_inherits and the parent's relhassubclass, if needed */ + if (OidIsValid(parentIndexRelid)) + { + StoreSingleInheritance(indexRelationId, parentIndexRelid, 1); + SetRelationHasSubclass(parentIndexRelid, true); + } + + /* + * Register constraint and dependencies for the index. + * + * If the index is from a CONSTRAINT clause, construct a pg_constraint + * entry. The index will be linked to the constraint, which in turn is + * linked to the table. If it's not a CONSTRAINT, we need to make a + * dependency directly on the table. + * + * We don't need a dependency on the namespace, because there'll be an + * indirect dependency via our parent table. + * + * During bootstrap we can't register any dependencies, and we don't try + * to make a constraint either. + */ + if (!IsBootstrapProcessingMode()) + { + ObjectAddress myself, + referenced; + + myself.classId = RelationRelationId; + myself.objectId = indexRelationId; + myself.objectSubId = 0; + + if ((flags & INDEX_CREATE_ADD_CONSTRAINT) != 0) + { + char constraintType; + ObjectAddress localaddr; + + if (isprimary) + constraintType = CONSTRAINT_PRIMARY; + else if (indexInfo->ii_Unique) + constraintType = CONSTRAINT_UNIQUE; + else if (is_exclusion) + constraintType = CONSTRAINT_EXCLUSION; + else + { + elog(ERROR, "constraint must be PRIMARY, UNIQUE or EXCLUDE"); + constraintType = 0; /* keep compiler quiet */ + } + + localaddr = index_constraint_create(heapRelation, + indexRelationId, + parentConstraintId, + indexInfo, + indexRelationName, + constraintType, + constr_flags, + allow_system_table_mods, + is_internal); + if (constraintId) + *constraintId = localaddr.objectId; + } + else + { + bool have_simple_col = false; + + /* Create auto dependencies on simply-referenced columns */ + for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++) + { + if (indexInfo->ii_IndexAttrNumbers[i] != 0) + { + referenced.classId = RelationRelationId; + referenced.objectId = heapRelationId; + referenced.objectSubId = indexInfo->ii_IndexAttrNumbers[i]; + + recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); + + have_simple_col = true; + } + } + + /* + * If there are no simply-referenced columns, give the index an + * auto dependency on the whole table. In most cases, this will + * be redundant, but it might not be if the index expressions and + * predicate contain no Vars or only whole-row Vars. + */ + if (!have_simple_col) + { + referenced.classId = RelationRelationId; + referenced.objectId = heapRelationId; + referenced.objectSubId = 0; + + recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); + } + } + + /* + * If this is an index partition, create partition dependencies on + * both the parent index and the table. (Note: these must be *in + * addition to*, not instead of, all other dependencies. Otherwise + * we'll be short some dependencies after DETACH PARTITION.) + */ + if (OidIsValid(parentIndexRelid)) + { + referenced.classId = RelationRelationId; + referenced.objectId = parentIndexRelid; + referenced.objectSubId = 0; + + recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_PRI); + + referenced.classId = RelationRelationId; + referenced.objectId = heapRelationId; + referenced.objectSubId = 0; + + recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC); + } + + /* Store dependency on collations */ + /* The default collation is pinned, so don't bother recording it */ + for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++) + { + if (OidIsValid(collationObjectId[i]) && + collationObjectId[i] != DEFAULT_COLLATION_OID) + { + referenced.classId = CollationRelationId; + referenced.objectId = collationObjectId[i]; + referenced.objectSubId = 0; + + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + } + + /* Store dependency on operator classes */ + for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++) + { + referenced.classId = OperatorClassRelationId; + referenced.objectId = classObjectId[i]; + referenced.objectSubId = 0; + + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* Store dependencies on anything mentioned in index expressions */ + if (indexInfo->ii_Expressions) + { + recordDependencyOnSingleRelExpr(&myself, + (Node *) indexInfo->ii_Expressions, + heapRelationId, + DEPENDENCY_NORMAL, + DEPENDENCY_AUTO, false); + } + + /* Store dependencies on anything mentioned in predicate */ + if (indexInfo->ii_Predicate) + { + recordDependencyOnSingleRelExpr(&myself, + (Node *) indexInfo->ii_Predicate, + heapRelationId, + DEPENDENCY_NORMAL, + DEPENDENCY_AUTO, false); + } + } + else + { + /* Bootstrap mode - assert we weren't asked for constraint support */ + Assert((flags & INDEX_CREATE_ADD_CONSTRAINT) == 0); + } + + /* Post creation hook for new index */ + InvokeObjectPostCreateHookArg(RelationRelationId, + indexRelationId, 0, is_internal); + + /* + * Advance the command counter so that we can see the newly-entered + * catalog tuples for the index. + */ + CommandCounterIncrement(); + + /* + * In bootstrap mode, we have to fill in the index strategy structure with + * information from the catalogs. If we aren't bootstrapping, then the + * relcache entry has already been rebuilt thanks to sinval update during + * CommandCounterIncrement. + */ + if (IsBootstrapProcessingMode()) + RelationInitIndexAccessInfo(indexRelation); + else + Assert(indexRelation->rd_indexcxt != NULL); + + indexRelation->rd_index->indnkeyatts = indexInfo->ii_NumIndexKeyAttrs; + + /* Validate opclass-specific options */ + if (indexInfo->ii_OpclassOptions) + for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++) + (void) index_opclass_options(indexRelation, i + 1, + indexInfo->ii_OpclassOptions[i], + true); + + /* + * If this is bootstrap (initdb) time, then we don't actually fill in the + * index yet. We'll be creating more indexes and classes later, so we + * delay filling them in until just before we're done with bootstrapping. + * Similarly, if the caller specified to skip the build then filling the + * index is delayed till later (ALTER TABLE can save work in some cases + * with this). Otherwise, we call the AM routine that constructs the + * index. + */ + if (IsBootstrapProcessingMode()) + { + index_register(heapRelationId, indexRelationId, indexInfo); + } + else if ((flags & INDEX_CREATE_SKIP_BUILD) != 0) + { + /* + * Caller is responsible for filling the index later on. However, + * we'd better make sure that the heap relation is correctly marked as + * having an index. + */ + index_update_stats(heapRelation, + true, + -1.0); + /* Make the above update visible */ + CommandCounterIncrement(); + } + else + { + index_build(heapRelation, indexRelation, indexInfo, false, true); + } + + /* + * Close the index; but we keep the lock that we acquired above until end + * of transaction. Closing the heap is caller's responsibility. + */ + index_close(indexRelation, NoLock); + + return indexRelationId; +} + +/* + * index_concurrently_create_copy + * + * Create concurrently an index based on the definition of the one provided by + * caller. The index is inserted into catalogs and needs to be built later + * on. This is called during concurrent reindex processing. + */ +Oid +index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char *newName) +{ + Relation indexRelation; + IndexInfo *oldInfo, + *newInfo; + Oid newIndexId = InvalidOid; + HeapTuple indexTuple, + classTuple; + Datum indclassDatum, + colOptionDatum, + optionDatum; + oidvector *indclass; + int2vector *indcoloptions; + bool isnull; + List *indexColNames = NIL; + List *indexExprs = NIL; + List *indexPreds = NIL; + + indexRelation = index_open(oldIndexId, RowExclusiveLock); + + /* The new index needs some information from the old index */ + oldInfo = BuildIndexInfo(indexRelation); + + /* + * Concurrent build of an index with exclusion constraints is not + * supported. + */ + if (oldInfo->ii_ExclusionOps != NULL) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("concurrent index creation for exclusion constraints is not supported"))); + + /* Get the array of class and column options IDs from index info */ + indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(oldIndexId)); + if (!HeapTupleIsValid(indexTuple)) + elog(ERROR, "cache lookup failed for index %u", oldIndexId); + indclassDatum = SysCacheGetAttr(INDEXRELID, indexTuple, + Anum_pg_index_indclass, &isnull); + Assert(!isnull); + indclass = (oidvector *) DatumGetPointer(indclassDatum); + + colOptionDatum = SysCacheGetAttr(INDEXRELID, indexTuple, + Anum_pg_index_indoption, &isnull); + Assert(!isnull); + indcoloptions = (int2vector *) DatumGetPointer(colOptionDatum); + + /* Fetch options of index if any */ + classTuple = SearchSysCache1(RELOID, oldIndexId); + if (!HeapTupleIsValid(classTuple)) + elog(ERROR, "cache lookup failed for relation %u", oldIndexId); + optionDatum = SysCacheGetAttr(RELOID, classTuple, + Anum_pg_class_reloptions, &isnull); + + /* + * Fetch the list of expressions and predicates directly from the + * catalogs. This cannot rely on the information from IndexInfo of the + * old index as these have been flattened for the planner. + */ + if (oldInfo->ii_Expressions != NIL) + { + Datum exprDatum; + char *exprString; + + exprDatum = SysCacheGetAttr(INDEXRELID, indexTuple, + Anum_pg_index_indexprs, &isnull); + Assert(!isnull); + exprString = TextDatumGetCString(exprDatum); + indexExprs = (List *) stringToNode(exprString); + pfree(exprString); + } + if (oldInfo->ii_Predicate != NIL) + { + Datum predDatum; + char *predString; + + predDatum = SysCacheGetAttr(INDEXRELID, indexTuple, + Anum_pg_index_indpred, &isnull); + Assert(!isnull); + predString = TextDatumGetCString(predDatum); + indexPreds = (List *) stringToNode(predString); + + /* Also convert to implicit-AND format */ + indexPreds = make_ands_implicit((Expr *) indexPreds); + pfree(predString); + } + + /* + * Build the index information for the new index. Note that rebuild of + * indexes with exclusion constraints is not supported, hence there is no + * need to fill all the ii_Exclusion* fields. + */ + newInfo = makeIndexInfo(oldInfo->ii_NumIndexAttrs, + oldInfo->ii_NumIndexKeyAttrs, + oldInfo->ii_Am, + indexExprs, + indexPreds, + oldInfo->ii_Unique, + false, /* not ready for inserts */ + true); + + /* + * Extract the list of column names and the column numbers for the new + * index information. All this information will be used for the index + * creation. + */ + for (int i = 0; i < oldInfo->ii_NumIndexAttrs; i++) + { + TupleDesc indexTupDesc = RelationGetDescr(indexRelation); + Form_pg_attribute att = TupleDescAttr(indexTupDesc, i); + + indexColNames = lappend(indexColNames, NameStr(att->attname)); + newInfo->ii_IndexAttrNumbers[i] = oldInfo->ii_IndexAttrNumbers[i]; + } + + /* + * Now create the new index. + * + * For a partition index, we adjust the partition dependency later, to + * ensure a consistent state at all times. That is why parentIndexRelid + * is not set here. + */ + newIndexId = index_create(heapRelation, + newName, + InvalidOid, /* indexRelationId */ + InvalidOid, /* parentIndexRelid */ + InvalidOid, /* parentConstraintId */ + InvalidOid, /* relFileNode */ + newInfo, + indexColNames, + indexRelation->rd_rel->relam, + indexRelation->rd_rel->reltablespace, + indexRelation->rd_indcollation, + indclass->values, + indcoloptions->values, + optionDatum, + INDEX_CREATE_SKIP_BUILD | INDEX_CREATE_CONCURRENT, + 0, + true, /* allow table to be a system catalog? */ + false, /* is_internal? */ + NULL); + + /* Close the relations used and clean up */ + index_close(indexRelation, NoLock); + ReleaseSysCache(indexTuple); + ReleaseSysCache(classTuple); + + return newIndexId; +} + +/* + * index_concurrently_build + * + * Build index for a concurrent operation. Low-level locks are taken when + * this operation is performed to prevent only schema changes, but they need + * to be kept until the end of the transaction performing this operation. + * 'indexOid' refers to an index relation OID already created as part of + * previous processing, and 'heapOid' refers to its parent heap relation. + */ +void +index_concurrently_build(Oid heapRelationId, + Oid indexRelationId) +{ + Relation heapRel; + Relation indexRelation; + IndexInfo *indexInfo; + + /* This had better make sure that a snapshot is active */ + Assert(ActiveSnapshotSet()); + + /* Open and lock the parent heap relation */ + heapRel = table_open(heapRelationId, ShareUpdateExclusiveLock); + + /* And the target index relation */ + indexRelation = index_open(indexRelationId, RowExclusiveLock); + + /* + * We have to re-build the IndexInfo struct, since it was lost in the + * commit of the transaction where this concurrent index was created at + * the catalog level. + */ + indexInfo = BuildIndexInfo(indexRelation); + Assert(!indexInfo->ii_ReadyForInserts); + indexInfo->ii_Concurrent = true; + indexInfo->ii_BrokenHotChain = false; + + /* Now build the index */ + index_build(heapRel, indexRelation, indexInfo, false, true); + + /* Close both the relations, but keep the locks */ + table_close(heapRel, NoLock); + index_close(indexRelation, NoLock); + + /* + * Update the pg_index row to mark the index as ready for inserts. Once we + * commit this transaction, any new transactions that open the table must + * insert new entries into the index for insertions and non-HOT updates. + */ + index_set_state_flags(indexRelationId, INDEX_CREATE_SET_READY); +} + +/* + * index_concurrently_swap + * + * Swap name, dependencies, and constraints of the old index over to the new + * index, while marking the old index as invalid and the new as valid. + */ +void +index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName) +{ + Relation pg_class, + pg_index, + pg_constraint, + pg_trigger; + Relation oldClassRel, + newClassRel; + HeapTuple oldClassTuple, + newClassTuple; + Form_pg_class oldClassForm, + newClassForm; + HeapTuple oldIndexTuple, + newIndexTuple; + Form_pg_index oldIndexForm, + newIndexForm; + bool isPartition; + Oid indexConstraintOid; + List *constraintOids = NIL; + ListCell *lc; + + /* + * Take a necessary lock on the old and new index before swapping them. + */ + oldClassRel = relation_open(oldIndexId, ShareUpdateExclusiveLock); + newClassRel = relation_open(newIndexId, ShareUpdateExclusiveLock); + + /* Now swap names and dependencies of those indexes */ + pg_class = table_open(RelationRelationId, RowExclusiveLock); + + oldClassTuple = SearchSysCacheCopy1(RELOID, + ObjectIdGetDatum(oldIndexId)); + if (!HeapTupleIsValid(oldClassTuple)) + elog(ERROR, "could not find tuple for relation %u", oldIndexId); + newClassTuple = SearchSysCacheCopy1(RELOID, + ObjectIdGetDatum(newIndexId)); + if (!HeapTupleIsValid(newClassTuple)) + elog(ERROR, "could not find tuple for relation %u", newIndexId); + + oldClassForm = (Form_pg_class) GETSTRUCT(oldClassTuple); + newClassForm = (Form_pg_class) GETSTRUCT(newClassTuple); + + /* Swap the names */ + namestrcpy(&newClassForm->relname, NameStr(oldClassForm->relname)); + namestrcpy(&oldClassForm->relname, oldName); + + /* Swap the partition flags to track inheritance properly */ + isPartition = newClassForm->relispartition; + newClassForm->relispartition = oldClassForm->relispartition; + oldClassForm->relispartition = isPartition; + + CatalogTupleUpdate(pg_class, &oldClassTuple->t_self, oldClassTuple); + CatalogTupleUpdate(pg_class, &newClassTuple->t_self, newClassTuple); + + heap_freetuple(oldClassTuple); + heap_freetuple(newClassTuple); + + /* Now swap index info */ + pg_index = table_open(IndexRelationId, RowExclusiveLock); + + oldIndexTuple = SearchSysCacheCopy1(INDEXRELID, + ObjectIdGetDatum(oldIndexId)); + if (!HeapTupleIsValid(oldIndexTuple)) + elog(ERROR, "could not find tuple for relation %u", oldIndexId); + newIndexTuple = SearchSysCacheCopy1(INDEXRELID, + ObjectIdGetDatum(newIndexId)); + if (!HeapTupleIsValid(newIndexTuple)) + elog(ERROR, "could not find tuple for relation %u", newIndexId); + + oldIndexForm = (Form_pg_index) GETSTRUCT(oldIndexTuple); + newIndexForm = (Form_pg_index) GETSTRUCT(newIndexTuple); + + /* + * Copy constraint flags from the old index. This is safe because the old + * index guaranteed uniqueness. + */ + newIndexForm->indisprimary = oldIndexForm->indisprimary; + oldIndexForm->indisprimary = false; + newIndexForm->indisexclusion = oldIndexForm->indisexclusion; + oldIndexForm->indisexclusion = false; + newIndexForm->indimmediate = oldIndexForm->indimmediate; + oldIndexForm->indimmediate = true; + + /* Preserve indisreplident in the new index */ + newIndexForm->indisreplident = oldIndexForm->indisreplident; + oldIndexForm->indisreplident = false; + + /* Preserve indisclustered in the new index */ + newIndexForm->indisclustered = oldIndexForm->indisclustered; + + /* + * Mark the new index as valid, and the old index as invalid similarly to + * what index_set_state_flags() does. + */ + newIndexForm->indisvalid = true; + oldIndexForm->indisvalid = false; + oldIndexForm->indisclustered = false; + + CatalogTupleUpdate(pg_index, &oldIndexTuple->t_self, oldIndexTuple); + CatalogTupleUpdate(pg_index, &newIndexTuple->t_self, newIndexTuple); + + heap_freetuple(oldIndexTuple); + heap_freetuple(newIndexTuple); + + /* + * Move constraints and triggers over to the new index + */ + + constraintOids = get_index_ref_constraints(oldIndexId); + + indexConstraintOid = get_index_constraint(oldIndexId); + + if (OidIsValid(indexConstraintOid)) + constraintOids = lappend_oid(constraintOids, indexConstraintOid); + + pg_constraint = table_open(ConstraintRelationId, RowExclusiveLock); + pg_trigger = table_open(TriggerRelationId, RowExclusiveLock); + + foreach(lc, constraintOids) + { + HeapTuple constraintTuple, + triggerTuple; + Form_pg_constraint conForm; + ScanKeyData key[1]; + SysScanDesc scan; + Oid constraintOid = lfirst_oid(lc); + + /* Move the constraint from the old to the new index */ + constraintTuple = SearchSysCacheCopy1(CONSTROID, + ObjectIdGetDatum(constraintOid)); + if (!HeapTupleIsValid(constraintTuple)) + elog(ERROR, "could not find tuple for constraint %u", constraintOid); + + conForm = ((Form_pg_constraint) GETSTRUCT(constraintTuple)); + + if (conForm->conindid == oldIndexId) + { + conForm->conindid = newIndexId; + + CatalogTupleUpdate(pg_constraint, &constraintTuple->t_self, constraintTuple); + } + + heap_freetuple(constraintTuple); + + /* Search for trigger records */ + ScanKeyInit(&key[0], + Anum_pg_trigger_tgconstraint, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(constraintOid)); + + scan = systable_beginscan(pg_trigger, TriggerConstraintIndexId, true, + NULL, 1, key); + + while (HeapTupleIsValid((triggerTuple = systable_getnext(scan)))) + { + Form_pg_trigger tgForm = (Form_pg_trigger) GETSTRUCT(triggerTuple); + + if (tgForm->tgconstrindid != oldIndexId) + continue; + + /* Make a modifiable copy */ + triggerTuple = heap_copytuple(triggerTuple); + tgForm = (Form_pg_trigger) GETSTRUCT(triggerTuple); + + tgForm->tgconstrindid = newIndexId; + + CatalogTupleUpdate(pg_trigger, &triggerTuple->t_self, triggerTuple); + + heap_freetuple(triggerTuple); + } + + systable_endscan(scan); + } + + /* + * Move comment if any + */ + { + Relation description; + ScanKeyData skey[3]; + SysScanDesc sd; + HeapTuple tuple; + Datum values[Natts_pg_description] = {0}; + bool nulls[Natts_pg_description] = {0}; + bool replaces[Natts_pg_description] = {0}; + + values[Anum_pg_description_objoid - 1] = ObjectIdGetDatum(newIndexId); + replaces[Anum_pg_description_objoid - 1] = true; + + ScanKeyInit(&skey[0], + Anum_pg_description_objoid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(oldIndexId)); + ScanKeyInit(&skey[1], + Anum_pg_description_classoid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationRelationId)); + ScanKeyInit(&skey[2], + Anum_pg_description_objsubid, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(0)); + + description = table_open(DescriptionRelationId, RowExclusiveLock); + + sd = systable_beginscan(description, DescriptionObjIndexId, true, + NULL, 3, skey); + + while ((tuple = systable_getnext(sd)) != NULL) + { + tuple = heap_modify_tuple(tuple, RelationGetDescr(description), + values, nulls, replaces); + CatalogTupleUpdate(description, &tuple->t_self, tuple); + + break; /* Assume there can be only one match */ + } + + systable_endscan(sd); + table_close(description, NoLock); + } + + /* + * Swap inheritance relationship with parent index + */ + if (get_rel_relispartition(oldIndexId)) + { + List *ancestors = get_partition_ancestors(oldIndexId); + Oid parentIndexRelid = linitial_oid(ancestors); + + DeleteInheritsTuple(oldIndexId, parentIndexRelid); + StoreSingleInheritance(newIndexId, parentIndexRelid, 1); + + list_free(ancestors); + } + + /* + * Swap all dependencies of and on the old index to the new one, and + * vice-versa. Note that a call to CommandCounterIncrement() would cause + * duplicate entries in pg_depend, so this should not be done. + */ + changeDependenciesOf(RelationRelationId, newIndexId, oldIndexId); + changeDependenciesOn(RelationRelationId, newIndexId, oldIndexId); + + changeDependenciesOf(RelationRelationId, oldIndexId, newIndexId); + changeDependenciesOn(RelationRelationId, oldIndexId, newIndexId); + + /* + * Copy over statistics from old to new index + */ + { + PgStat_StatTabEntry *tabentry; + + tabentry = pgstat_fetch_stat_tabentry(oldIndexId); + if (tabentry) + { + if (newClassRel->pgstat_info) + { + newClassRel->pgstat_info->t_counts.t_numscans = tabentry->numscans; + newClassRel->pgstat_info->t_counts.t_tuples_returned = tabentry->tuples_returned; + newClassRel->pgstat_info->t_counts.t_tuples_fetched = tabentry->tuples_fetched; + newClassRel->pgstat_info->t_counts.t_blocks_fetched = tabentry->blocks_fetched; + newClassRel->pgstat_info->t_counts.t_blocks_hit = tabentry->blocks_hit; + + /* + * The data will be sent by the next pgstat_report_stat() + * call. + */ + } + } + } + + /* Copy data of pg_statistic from the old index to the new one */ + CopyStatistics(oldIndexId, newIndexId); + + /* Copy pg_attribute.attstattarget for each index attribute */ + { + HeapTuple attrTuple; + Relation pg_attribute; + SysScanDesc scan; + ScanKeyData key[1]; + + pg_attribute = table_open(AttributeRelationId, RowExclusiveLock); + ScanKeyInit(&key[0], + Anum_pg_attribute_attrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(newIndexId)); + scan = systable_beginscan(pg_attribute, AttributeRelidNumIndexId, + true, NULL, 1, key); + + while (HeapTupleIsValid((attrTuple = systable_getnext(scan)))) + { + Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attrTuple); + Datum repl_val[Natts_pg_attribute]; + bool repl_null[Natts_pg_attribute]; + bool repl_repl[Natts_pg_attribute]; + int attstattarget; + HeapTuple newTuple; + + /* Ignore dropped columns */ + if (att->attisdropped) + continue; + + /* + * Get attstattarget from the old index and refresh the new value. + */ + attstattarget = get_attstattarget(oldIndexId, att->attnum); + + /* no need for a refresh if both match */ + if (attstattarget == att->attstattarget) + continue; + + memset(repl_val, 0, sizeof(repl_val)); + memset(repl_null, false, sizeof(repl_null)); + memset(repl_repl, false, sizeof(repl_repl)); + + repl_repl[Anum_pg_attribute_attstattarget - 1] = true; + repl_val[Anum_pg_attribute_attstattarget - 1] = Int32GetDatum(attstattarget); + + newTuple = heap_modify_tuple(attrTuple, + RelationGetDescr(pg_attribute), + repl_val, repl_null, repl_repl); + CatalogTupleUpdate(pg_attribute, &newTuple->t_self, newTuple); + + heap_freetuple(newTuple); + } + + systable_endscan(scan); + table_close(pg_attribute, RowExclusiveLock); + } + + /* Close relations */ + table_close(pg_class, RowExclusiveLock); + table_close(pg_index, RowExclusiveLock); + table_close(pg_constraint, RowExclusiveLock); + table_close(pg_trigger, RowExclusiveLock); + + /* The lock taken previously is not released until the end of transaction */ + relation_close(oldClassRel, NoLock); + relation_close(newClassRel, NoLock); +} + +/* + * index_concurrently_set_dead + * + * Perform the last invalidation stage of DROP INDEX CONCURRENTLY or REINDEX + * CONCURRENTLY before actually dropping the index. After calling this + * function, the index is seen by all the backends as dead. Low-level locks + * taken here are kept until the end of the transaction calling this function. + */ +void +index_concurrently_set_dead(Oid heapId, Oid indexId) +{ + Relation userHeapRelation; + Relation userIndexRelation; + + /* + * No more predicate locks will be acquired on this index, and we're about + * to stop doing inserts into the index which could show conflicts with + * existing predicate locks, so now is the time to move them to the heap + * relation. + */ + userHeapRelation = table_open(heapId, ShareUpdateExclusiveLock); + userIndexRelation = index_open(indexId, ShareUpdateExclusiveLock); + TransferPredicateLocksToHeapRelation(userIndexRelation); + + /* + * Now we are sure that nobody uses the index for queries; they just might + * have it open for updating it. So now we can unset indisready and + * indislive, then wait till nobody could be using it at all anymore. + */ + index_set_state_flags(indexId, INDEX_DROP_SET_DEAD); + + /* + * Invalidate the relcache for the table, so that after this commit all + * sessions will refresh the table's index list. Forgetting just the + * index's relcache entry is not enough. + */ + CacheInvalidateRelcache(userHeapRelation); + + /* + * Close the relations again, though still holding session lock. + */ + table_close(userHeapRelation, NoLock); + index_close(userIndexRelation, NoLock); +} + +/* + * index_constraint_create + * + * Set up a constraint associated with an index. Return the new constraint's + * address. + * + * heapRelation: table owning the index (must be suitably locked by caller) + * indexRelationId: OID of the index + * parentConstraintId: if constraint is on a partition, the OID of the + * constraint in the parent. + * indexInfo: same info executor uses to insert into the index + * constraintName: what it say (generally, should match name of index) + * constraintType: one of CONSTRAINT_PRIMARY, CONSTRAINT_UNIQUE, or + * CONSTRAINT_EXCLUSION + * flags: bitmask that can include any combination of these bits: + * INDEX_CONSTR_CREATE_MARK_AS_PRIMARY: index is a PRIMARY KEY + * INDEX_CONSTR_CREATE_DEFERRABLE: constraint is DEFERRABLE + * INDEX_CONSTR_CREATE_INIT_DEFERRED: constraint is INITIALLY DEFERRED + * INDEX_CONSTR_CREATE_UPDATE_INDEX: update the pg_index row + * INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS: remove existing dependencies + * of index on table's columns + * allow_system_table_mods: allow table to be a system catalog + * is_internal: index is constructed due to internal process + */ +ObjectAddress +index_constraint_create(Relation heapRelation, + Oid indexRelationId, + Oid parentConstraintId, + IndexInfo *indexInfo, + const char *constraintName, + char constraintType, + bits16 constr_flags, + bool allow_system_table_mods, + bool is_internal) +{ + Oid namespaceId = RelationGetNamespace(heapRelation); + ObjectAddress myself, + idxaddr; + Oid conOid; + bool deferrable; + bool initdeferred; + bool mark_as_primary; + bool islocal; + bool noinherit; + int inhcount; + + deferrable = (constr_flags & INDEX_CONSTR_CREATE_DEFERRABLE) != 0; + initdeferred = (constr_flags & INDEX_CONSTR_CREATE_INIT_DEFERRED) != 0; + mark_as_primary = (constr_flags & INDEX_CONSTR_CREATE_MARK_AS_PRIMARY) != 0; + + /* constraint creation support doesn't work while bootstrapping */ + Assert(!IsBootstrapProcessingMode()); + + /* enforce system-table restriction */ + if (!allow_system_table_mods && + IsSystemRelation(heapRelation) && + IsNormalProcessingMode()) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("user-defined indexes on system catalog tables are not supported"))); + + /* primary/unique constraints shouldn't have any expressions */ + if (indexInfo->ii_Expressions && + constraintType != CONSTRAINT_EXCLUSION) + elog(ERROR, "constraints cannot have index expressions"); + + /* + * If we're manufacturing a constraint for a pre-existing index, we need + * to get rid of the existing auto dependencies for the index (the ones + * that index_create() would have made instead of calling this function). + * + * Note: this code would not necessarily do the right thing if the index + * has any expressions or predicate, but we'd never be turning such an + * index into a UNIQUE or PRIMARY KEY constraint. + */ + if (constr_flags & INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS) + deleteDependencyRecordsForClass(RelationRelationId, indexRelationId, + RelationRelationId, DEPENDENCY_AUTO); + + if (OidIsValid(parentConstraintId)) + { + islocal = false; + inhcount = 1; + noinherit = false; + } + else + { + islocal = true; + inhcount = 0; + noinherit = true; + } + + /* + * Construct a pg_constraint entry. + */ + conOid = CreateConstraintEntry(constraintName, + namespaceId, + constraintType, + deferrable, + initdeferred, + true, + parentConstraintId, + RelationGetRelid(heapRelation), + indexInfo->ii_IndexAttrNumbers, + indexInfo->ii_NumIndexKeyAttrs, + indexInfo->ii_NumIndexAttrs, + InvalidOid, /* no domain */ + indexRelationId, /* index OID */ + InvalidOid, /* no foreign key */ + NULL, + NULL, + NULL, + NULL, + 0, + ' ', + ' ', + ' ', + indexInfo->ii_ExclusionOps, + NULL, /* no check constraint */ + NULL, + islocal, + inhcount, + noinherit, + is_internal); + + /* + * Register the index as internally dependent on the constraint. + * + * Note that the constraint has a dependency on the table, so we don't + * need (or want) any direct dependency from the index to the table. + */ + ObjectAddressSet(myself, ConstraintRelationId, conOid); + ObjectAddressSet(idxaddr, RelationRelationId, indexRelationId); + recordDependencyOn(&idxaddr, &myself, DEPENDENCY_INTERNAL); + + /* + * Also, if this is a constraint on a partition, give it partition-type + * dependencies on the parent constraint as well as the table. + */ + if (OidIsValid(parentConstraintId)) + { + ObjectAddress referenced; + + ObjectAddressSet(referenced, ConstraintRelationId, parentConstraintId); + recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_PRI); + ObjectAddressSet(referenced, RelationRelationId, + RelationGetRelid(heapRelation)); + recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC); + } + + /* + * If the constraint is deferrable, create the deferred uniqueness + * checking trigger. (The trigger will be given an internal dependency on + * the constraint by CreateTrigger.) + */ + if (deferrable) + { + CreateTrigStmt *trigger; + + trigger = makeNode(CreateTrigStmt); + trigger->trigname = (constraintType == CONSTRAINT_PRIMARY) ? + "PK_ConstraintTrigger" : + "Unique_ConstraintTrigger"; + trigger->relation = NULL; + trigger->funcname = SystemFuncName("unique_key_recheck"); + trigger->args = NIL; + trigger->row = true; + trigger->timing = TRIGGER_TYPE_AFTER; + trigger->events = TRIGGER_TYPE_INSERT | TRIGGER_TYPE_UPDATE; + trigger->columns = NIL; + trigger->whenClause = NULL; + trigger->isconstraint = true; + trigger->deferrable = true; + trigger->initdeferred = initdeferred; + trigger->constrrel = NULL; + + (void) CreateTrigger(trigger, NULL, RelationGetRelid(heapRelation), + InvalidOid, conOid, indexRelationId, InvalidOid, + InvalidOid, NULL, true, false); + } + + /* + * If needed, mark the index as primary and/or deferred in pg_index. + * + * Note: When making an existing index into a constraint, caller must have + * a table lock that prevents concurrent table updates; otherwise, there + * is a risk that concurrent readers of the table will miss seeing this + * index at all. + */ + if ((constr_flags & INDEX_CONSTR_CREATE_UPDATE_INDEX) && + (mark_as_primary || deferrable)) + { + Relation pg_index; + HeapTuple indexTuple; + Form_pg_index indexForm; + bool dirty = false; + + pg_index = table_open(IndexRelationId, RowExclusiveLock); + + indexTuple = SearchSysCacheCopy1(INDEXRELID, + ObjectIdGetDatum(indexRelationId)); + if (!HeapTupleIsValid(indexTuple)) + elog(ERROR, "cache lookup failed for index %u", indexRelationId); + indexForm = (Form_pg_index) GETSTRUCT(indexTuple); + + if (mark_as_primary && !indexForm->indisprimary) + { + indexForm->indisprimary = true; + dirty = true; + } + + if (deferrable && indexForm->indimmediate) + { + indexForm->indimmediate = false; + dirty = true; + } + + if (dirty) + { + CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple); + + InvokeObjectPostAlterHookArg(IndexRelationId, indexRelationId, 0, + InvalidOid, is_internal); + } + + heap_freetuple(indexTuple); + table_close(pg_index, RowExclusiveLock); + } + + return myself; +} + +/* + * index_drop + * + * NOTE: this routine should now only be called through performDeletion(), + * else associated dependencies won't be cleaned up. + * + * If concurrent is true, do a DROP INDEX CONCURRENTLY. If concurrent is + * false but concurrent_lock_mode is true, then do a normal DROP INDEX but + * take a lock for CONCURRENTLY processing. That is used as part of REINDEX + * CONCURRENTLY. + */ +void +index_drop(Oid indexId, bool concurrent, bool concurrent_lock_mode) +{ + Oid heapId; + Relation userHeapRelation; + Relation userIndexRelation; + Relation indexRelation; + HeapTuple tuple; + bool hasexprs; + LockRelId heaprelid, + indexrelid; + LOCKTAG heaplocktag; + LOCKMODE lockmode; + + /* + * A temporary relation uses a non-concurrent DROP. Other backends can't + * access a temporary relation, so there's no harm in grabbing a stronger + * lock (see comments in RemoveRelations), and a non-concurrent DROP is + * more efficient. + */ + Assert(get_rel_persistence(indexId) != RELPERSISTENCE_TEMP || + (!concurrent && !concurrent_lock_mode)); + + /* + * To drop an index safely, we must grab exclusive lock on its parent + * table. Exclusive lock on the index alone is insufficient because + * another backend might be about to execute a query on the parent table. + * If it relies on a previously cached list of index OIDs, then it could + * attempt to access the just-dropped index. We must therefore take a + * table lock strong enough to prevent all queries on the table from + * proceeding until we commit and send out a shared-cache-inval notice + * that will make them update their index lists. + * + * In the concurrent case we avoid this requirement by disabling index use + * in multiple steps and waiting out any transactions that might be using + * the index, so we don't need exclusive lock on the parent table. Instead + * we take ShareUpdateExclusiveLock, to ensure that two sessions aren't + * doing CREATE/DROP INDEX CONCURRENTLY on the same index. (We will get + * AccessExclusiveLock on the index below, once we're sure nobody else is + * using it.) + */ + heapId = IndexGetRelation(indexId, false); + lockmode = (concurrent || concurrent_lock_mode) ? ShareUpdateExclusiveLock : AccessExclusiveLock; + userHeapRelation = table_open(heapId, lockmode); + userIndexRelation = index_open(indexId, lockmode); + + /* + * We might still have open queries using it in our own session, which the + * above locking won't prevent, so test explicitly. + */ + CheckTableNotInUse(userIndexRelation, "DROP INDEX"); + + /* + * Drop Index Concurrently is more or less the reverse process of Create + * Index Concurrently. + * + * First we unset indisvalid so queries starting afterwards don't use the + * index to answer queries anymore. We have to keep indisready = true so + * transactions that are still scanning the index can continue to see + * valid index contents. For instance, if they are using READ COMMITTED + * mode, and another transaction makes changes and commits, they need to + * see those new tuples in the index. + * + * After all transactions that could possibly have used the index for + * queries end, we can unset indisready and indislive, then wait till + * nobody could be touching it anymore. (Note: we need indislive because + * this state must be distinct from the initial state during CREATE INDEX + * CONCURRENTLY, which has indislive true while indisready and indisvalid + * are false. That's because in that state, transactions must examine the + * index for HOT-safety decisions, while in this state we don't want them + * to open it at all.) + * + * Since all predicate locks on the index are about to be made invalid, we + * must promote them to predicate locks on the heap. In the + * non-concurrent case we can just do that now. In the concurrent case + * it's a bit trickier. The predicate locks must be moved when there are + * no index scans in progress on the index and no more can subsequently + * start, so that no new predicate locks can be made on the index. Also, + * they must be moved before heap inserts stop maintaining the index, else + * the conflict with the predicate lock on the index gap could be missed + * before the lock on the heap relation is in place to detect a conflict + * based on the heap tuple insert. + */ + if (concurrent) + { + /* + * We must commit our transaction in order to make the first pg_index + * state update visible to other sessions. If the DROP machinery has + * already performed any other actions (removal of other objects, + * pg_depend entries, etc), the commit would make those actions + * permanent, which would leave us with inconsistent catalog state if + * we fail partway through the following sequence. Since DROP INDEX + * CONCURRENTLY is restricted to dropping just one index that has no + * dependencies, we should get here before anything's been done --- + * but let's check that to be sure. We can verify that the current + * transaction has not executed any transactional updates by checking + * that no XID has been assigned. + */ + if (GetTopTransactionIdIfAny() != InvalidTransactionId) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("DROP INDEX CONCURRENTLY must be first action in transaction"))); + + /* + * Mark index invalid by updating its pg_index entry + */ + index_set_state_flags(indexId, INDEX_DROP_CLEAR_VALID); + + /* + * Invalidate the relcache for the table, so that after this commit + * all sessions will refresh any cached plans that might reference the + * index. + */ + CacheInvalidateRelcache(userHeapRelation); + + /* save lockrelid and locktag for below, then close but keep locks */ + heaprelid = userHeapRelation->rd_lockInfo.lockRelId; + SET_LOCKTAG_RELATION(heaplocktag, heaprelid.dbId, heaprelid.relId); + indexrelid = userIndexRelation->rd_lockInfo.lockRelId; + + table_close(userHeapRelation, NoLock); + index_close(userIndexRelation, NoLock); + + /* + * We must commit our current transaction so that the indisvalid + * update becomes visible to other transactions; then start another. + * Note that any previously-built data structures are lost in the + * commit. The only data we keep past here are the relation IDs. + * + * Before committing, get a session-level lock on the table, to ensure + * that neither it nor the index can be dropped before we finish. This + * cannot block, even if someone else is waiting for access, because + * we already have the same lock within our transaction. + */ + LockRelationIdForSession(&heaprelid, ShareUpdateExclusiveLock); + LockRelationIdForSession(&indexrelid, ShareUpdateExclusiveLock); + + PopActiveSnapshot(); + CommitTransactionCommand(); + StartTransactionCommand(); + + /* + * Now we must wait until no running transaction could be using the + * index for a query. Use AccessExclusiveLock here to check for + * running transactions that hold locks of any kind on the table. Note + * we do not need to worry about xacts that open the table for reading + * after this point; they will see the index as invalid when they open + * the relation. + * + * Note: the reason we use actual lock acquisition here, rather than + * just checking the ProcArray and sleeping, is that deadlock is + * possible if one of the transactions in question is blocked trying + * to acquire an exclusive lock on our table. The lock code will + * detect deadlock and error out properly. + * + * Note: we report progress through WaitForLockers() unconditionally + * here, even though it will only be used when we're called by REINDEX + * CONCURRENTLY and not when called by DROP INDEX CONCURRENTLY. + */ + WaitForLockers(heaplocktag, AccessExclusiveLock, true); + + /* Finish invalidation of index and mark it as dead */ + index_concurrently_set_dead(heapId, indexId); + + /* + * Again, commit the transaction to make the pg_index update visible + * to other sessions. + */ + CommitTransactionCommand(); + StartTransactionCommand(); + + /* + * Wait till every transaction that saw the old index state has + * finished. See above about progress reporting. + */ + WaitForLockers(heaplocktag, AccessExclusiveLock, true); + + /* + * Re-open relations to allow us to complete our actions. + * + * At this point, nothing should be accessing the index, but lets + * leave nothing to chance and grab AccessExclusiveLock on the index + * before the physical deletion. + */ + userHeapRelation = table_open(heapId, ShareUpdateExclusiveLock); + userIndexRelation = index_open(indexId, AccessExclusiveLock); + } + else + { + /* Not concurrent, so just transfer predicate locks and we're good */ + TransferPredicateLocksToHeapRelation(userIndexRelation); + } + + /* + * Schedule physical removal of the files (if any) + */ + if (userIndexRelation->rd_rel->relkind != RELKIND_PARTITIONED_INDEX) + RelationDropStorage(userIndexRelation); + + /* + * Close and flush the index's relcache entry, to ensure relcache doesn't + * try to rebuild it while we're deleting catalog entries. We keep the + * lock though. + */ + index_close(userIndexRelation, NoLock); + + RelationForgetRelation(indexId); + + /* + * fix INDEX relation, and check for expressional index + */ + indexRelation = table_open(IndexRelationId, RowExclusiveLock); + + tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for index %u", indexId); + + hasexprs = !heap_attisnull(tuple, Anum_pg_index_indexprs, + RelationGetDescr(indexRelation)); + + CatalogTupleDelete(indexRelation, &tuple->t_self); + + ReleaseSysCache(tuple); + table_close(indexRelation, RowExclusiveLock); + + /* + * if it has any expression columns, we might have stored statistics about + * them. + */ + if (hasexprs) + RemoveStatistics(indexId, 0); + + /* + * fix ATTRIBUTE relation + */ + DeleteAttributeTuples(indexId); + + /* + * fix RELATION relation + */ + DeleteRelationTuple(indexId); + + /* + * fix INHERITS relation + */ + DeleteInheritsTuple(indexId, InvalidOid); + + /* + * We are presently too lazy to attempt to compute the new correct value + * of relhasindex (the next VACUUM will fix it if necessary). So there is + * no need to update the pg_class tuple for the owning relation. But we + * must send out a shared-cache-inval notice on the owning relation to + * ensure other backends update their relcache lists of indexes. (In the + * concurrent case, this is redundant but harmless.) + */ + CacheInvalidateRelcache(userHeapRelation); + + /* + * Close owning rel, but keep lock + */ + table_close(userHeapRelation, NoLock); + + /* + * Release the session locks before we go. + */ + if (concurrent) + { + UnlockRelationIdForSession(&heaprelid, ShareUpdateExclusiveLock); + UnlockRelationIdForSession(&indexrelid, ShareUpdateExclusiveLock); + } +} + +/* ---------------------------------------------------------------- + * index_build support + * ---------------------------------------------------------------- + */ + +/* ---------------- + * BuildIndexInfo + * Construct an IndexInfo record for an open index + * + * IndexInfo stores the information about the index that's needed by + * FormIndexDatum, which is used for both index_build() and later insertion + * of individual index tuples. Normally we build an IndexInfo for an index + * just once per command, and then use it for (potentially) many tuples. + * ---------------- + */ +IndexInfo * +BuildIndexInfo(Relation index) +{ + IndexInfo *ii; + Form_pg_index indexStruct = index->rd_index; + int i; + int numAtts; + + /* check the number of keys, and copy attr numbers into the IndexInfo */ + numAtts = indexStruct->indnatts; + if (numAtts < 1 || numAtts > INDEX_MAX_KEYS) + elog(ERROR, "invalid indnatts %d for index %u", + numAtts, RelationGetRelid(index)); + + /* + * Create the node, fetching any expressions needed for expressional + * indexes and index predicate if any. + */ + ii = makeIndexInfo(indexStruct->indnatts, + indexStruct->indnkeyatts, + index->rd_rel->relam, + RelationGetIndexExpressions(index), + RelationGetIndexPredicate(index), + indexStruct->indisunique, + indexStruct->indisready, + false); + + /* fill in attribute numbers */ + for (i = 0; i < numAtts; i++) + ii->ii_IndexAttrNumbers[i] = indexStruct->indkey.values[i]; + + /* fetch exclusion constraint info if any */ + if (indexStruct->indisexclusion) + { + RelationGetExclusionInfo(index, + &ii->ii_ExclusionOps, + &ii->ii_ExclusionProcs, + &ii->ii_ExclusionStrats); + } + + ii->ii_OpclassOptions = RelationGetIndexRawAttOptions(index); + + return ii; +} + +/* ---------------- + * BuildDummyIndexInfo + * Construct a dummy IndexInfo record for an open index + * + * This differs from the real BuildIndexInfo in that it will never run any + * user-defined code that might exist in index expressions or predicates. + * Instead of the real index expressions, we return null constants that have + * the right types/typmods/collations. Predicates and exclusion clauses are + * just ignored. This is sufficient for the purpose of truncating an index, + * since we will not need to actually evaluate the expressions or predicates; + * the only thing that's likely to be done with the data is construction of + * a tupdesc describing the index's rowtype. + * ---------------- + */ +IndexInfo * +BuildDummyIndexInfo(Relation index) +{ + IndexInfo *ii; + Form_pg_index indexStruct = index->rd_index; + int i; + int numAtts; + + /* check the number of keys, and copy attr numbers into the IndexInfo */ + numAtts = indexStruct->indnatts; + if (numAtts < 1 || numAtts > INDEX_MAX_KEYS) + elog(ERROR, "invalid indnatts %d for index %u", + numAtts, RelationGetRelid(index)); + + /* + * Create the node, using dummy index expressions, and pretending there is + * no predicate. + */ + ii = makeIndexInfo(indexStruct->indnatts, + indexStruct->indnkeyatts, + index->rd_rel->relam, + RelationGetDummyIndexExpressions(index), + NIL, + indexStruct->indisunique, + indexStruct->indisready, + false); + + /* fill in attribute numbers */ + for (i = 0; i < numAtts; i++) + ii->ii_IndexAttrNumbers[i] = indexStruct->indkey.values[i]; + + /* We ignore the exclusion constraint if any */ + + return ii; +} + +/* + * CompareIndexInfo + * Return whether the properties of two indexes (in different tables) + * indicate that they have the "same" definitions. + * + * Note: passing collations and opfamilies separately is a kludge. Adding + * them to IndexInfo may result in better coding here and elsewhere. + * + * Use build_attrmap_by_name(index2, index1) to build the attmap. + */ +bool +CompareIndexInfo(IndexInfo *info1, IndexInfo *info2, + Oid *collations1, Oid *collations2, + Oid *opfamilies1, Oid *opfamilies2, + AttrMap *attmap) +{ + int i; + + if (info1->ii_Unique != info2->ii_Unique) + return false; + + /* indexes are only equivalent if they have the same access method */ + if (info1->ii_Am != info2->ii_Am) + return false; + + /* and same number of attributes */ + if (info1->ii_NumIndexAttrs != info2->ii_NumIndexAttrs) + return false; + + /* and same number of key attributes */ + if (info1->ii_NumIndexKeyAttrs != info2->ii_NumIndexKeyAttrs) + return false; + + /* + * and columns match through the attribute map (actual attribute numbers + * might differ!) Note that this implies that index columns that are + * expressions appear in the same positions. We will next compare the + * expressions themselves. + */ + for (i = 0; i < info1->ii_NumIndexAttrs; i++) + { + if (attmap->maplen < info2->ii_IndexAttrNumbers[i]) + elog(ERROR, "incorrect attribute map"); + + /* ignore expressions at this stage */ + if ((info1->ii_IndexAttrNumbers[i] != InvalidAttrNumber) && + (attmap->attnums[info2->ii_IndexAttrNumbers[i] - 1] != + info1->ii_IndexAttrNumbers[i])) + return false; + + /* collation and opfamily is not valid for including columns */ + if (i >= info1->ii_NumIndexKeyAttrs) + continue; + + if (collations1[i] != collations2[i]) + return false; + if (opfamilies1[i] != opfamilies2[i]) + return false; + } + + /* + * For expression indexes: either both are expression indexes, or neither + * is; if they are, make sure the expressions match. + */ + if ((info1->ii_Expressions != NIL) != (info2->ii_Expressions != NIL)) + return false; + if (info1->ii_Expressions != NIL) + { + bool found_whole_row; + Node *mapped; + + mapped = map_variable_attnos((Node *) info2->ii_Expressions, + 1, 0, attmap, + InvalidOid, &found_whole_row); + if (found_whole_row) + { + /* + * we could throw an error here, but seems out of scope for this + * routine. + */ + return false; + } + + if (!equal(info1->ii_Expressions, mapped)) + return false; + } + + /* Partial index predicates must be identical, if they exist */ + if ((info1->ii_Predicate == NULL) != (info2->ii_Predicate == NULL)) + return false; + if (info1->ii_Predicate != NULL) + { + bool found_whole_row; + Node *mapped; + + mapped = map_variable_attnos((Node *) info2->ii_Predicate, + 1, 0, attmap, + InvalidOid, &found_whole_row); + if (found_whole_row) + { + /* + * we could throw an error here, but seems out of scope for this + * routine. + */ + return false; + } + if (!equal(info1->ii_Predicate, mapped)) + return false; + } + + /* No support currently for comparing exclusion indexes. */ + if (info1->ii_ExclusionOps != NULL || info2->ii_ExclusionOps != NULL) + return false; + + return true; +} + +/* ---------------- + * BuildSpeculativeIndexInfo + * Add extra state to IndexInfo record + * + * For unique indexes, we usually don't want to add info to the IndexInfo for + * checking uniqueness, since the B-Tree AM handles that directly. However, + * in the case of speculative insertion, additional support is required. + * + * Do this processing here rather than in BuildIndexInfo() to not incur the + * overhead in the common non-speculative cases. + * ---------------- + */ +void +BuildSpeculativeIndexInfo(Relation index, IndexInfo *ii) +{ + int indnkeyatts; + int i; + + indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index); + + /* + * fetch info for checking unique indexes + */ + Assert(ii->ii_Unique); + + if (index->rd_rel->relam != BTREE_AM_OID) + elog(ERROR, "unexpected non-btree speculative unique index"); + + ii->ii_UniqueOps = (Oid *) palloc(sizeof(Oid) * indnkeyatts); + ii->ii_UniqueProcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts); + ii->ii_UniqueStrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts); + + /* + * We have to look up the operator's strategy number. This provides a + * cross-check that the operator does match the index. + */ + /* We need the func OIDs and strategy numbers too */ + for (i = 0; i < indnkeyatts; i++) + { + ii->ii_UniqueStrats[i] = BTEqualStrategyNumber; + ii->ii_UniqueOps[i] = + get_opfamily_member(index->rd_opfamily[i], + index->rd_opcintype[i], + index->rd_opcintype[i], + ii->ii_UniqueStrats[i]); + if (!OidIsValid(ii->ii_UniqueOps[i])) + elog(ERROR, "missing operator %d(%u,%u) in opfamily %u", + ii->ii_UniqueStrats[i], index->rd_opcintype[i], + index->rd_opcintype[i], index->rd_opfamily[i]); + ii->ii_UniqueProcs[i] = get_opcode(ii->ii_UniqueOps[i]); + } +} + +/* ---------------- + * FormIndexDatum + * Construct values[] and isnull[] arrays for a new index tuple. + * + * indexInfo Info about the index + * slot Heap tuple for which we must prepare an index entry + * estate executor state for evaluating any index expressions + * values Array of index Datums (output area) + * isnull Array of is-null indicators (output area) + * + * When there are no index expressions, estate may be NULL. Otherwise it + * must be supplied, *and* the ecxt_scantuple slot of its per-tuple expr + * context must point to the heap tuple passed in. + * + * Notice we don't actually call index_form_tuple() here; we just prepare + * its input arrays values[] and isnull[]. This is because the index AM + * may wish to alter the data before storage. + * ---------------- + */ +void +FormIndexDatum(IndexInfo *indexInfo, + TupleTableSlot *slot, + EState *estate, + Datum *values, + bool *isnull) +{ + ListCell *indexpr_item; + int i; + + if (indexInfo->ii_Expressions != NIL && + indexInfo->ii_ExpressionsState == NIL) + { + /* First time through, set up expression evaluation state */ + indexInfo->ii_ExpressionsState = + ExecPrepareExprList(indexInfo->ii_Expressions, estate); + /* Check caller has set up context correctly */ + Assert(GetPerTupleExprContext(estate)->ecxt_scantuple == slot); + } + indexpr_item = list_head(indexInfo->ii_ExpressionsState); + + for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++) + { + int keycol = indexInfo->ii_IndexAttrNumbers[i]; + Datum iDatum; + bool isNull; + + if (keycol < 0) + iDatum = slot_getsysattr(slot, keycol, &isNull); + else if (keycol != 0) + { + /* + * Plain index column; get the value we need directly from the + * heap tuple. + */ + iDatum = slot_getattr(slot, keycol, &isNull); + } + else + { + /* + * Index expression --- need to evaluate it. + */ + if (indexpr_item == NULL) + elog(ERROR, "wrong number of index expressions"); + iDatum = ExecEvalExprSwitchContext((ExprState *) lfirst(indexpr_item), + GetPerTupleExprContext(estate), + &isNull); + indexpr_item = lnext(indexInfo->ii_ExpressionsState, indexpr_item); + } + values[i] = iDatum; + isnull[i] = isNull; + } + + if (indexpr_item != NULL) + elog(ERROR, "wrong number of index expressions"); +} + + +/* + * index_update_stats --- update pg_class entry after CREATE INDEX or REINDEX + * + * This routine updates the pg_class row of either an index or its parent + * relation after CREATE INDEX or REINDEX. Its rather bizarre API is designed + * to ensure we can do all the necessary work in just one update. + * + * hasindex: set relhasindex to this value + * reltuples: if >= 0, set reltuples to this value; else no change + * + * If reltuples >= 0, relpages and relallvisible are also updated (using + * RelationGetNumberOfBlocks() and visibilitymap_count()). + * + * NOTE: an important side-effect of this operation is that an SI invalidation + * message is sent out to all backends --- including me --- causing relcache + * entries to be flushed or updated with the new data. This must happen even + * if we find that no change is needed in the pg_class row. When updating + * a heap entry, this ensures that other backends find out about the new + * index. When updating an index, it's important because some index AMs + * expect a relcache flush to occur after REINDEX. + */ +static void +index_update_stats(Relation rel, + bool hasindex, + double reltuples) +{ + Oid relid = RelationGetRelid(rel); + Relation pg_class; + HeapTuple tuple; + Form_pg_class rd_rel; + bool dirty; + + /* + * We always update the pg_class row using a non-transactional, + * overwrite-in-place update. There are several reasons for this: + * + * 1. In bootstrap mode, we have no choice --- UPDATE wouldn't work. + * + * 2. We could be reindexing pg_class itself, in which case we can't move + * its pg_class row because CatalogTupleInsert/CatalogTupleUpdate might + * not know about all the indexes yet (see reindex_relation). + * + * 3. Because we execute CREATE INDEX with just share lock on the parent + * rel (to allow concurrent index creations), an ordinary update could + * suffer a tuple-concurrently-updated failure against another CREATE + * INDEX committing at about the same time. We can avoid that by having + * them both do nontransactional updates (we assume they will both be + * trying to change the pg_class row to the same thing, so it doesn't + * matter which goes first). + * + * It is safe to use a non-transactional update even though our + * transaction could still fail before committing. Setting relhasindex + * true is safe even if there are no indexes (VACUUM will eventually fix + * it). And of course the new relpages and reltuples counts are correct + * regardless. However, we don't want to change relpages (or + * relallvisible) if the caller isn't providing an updated reltuples + * count, because that would bollix the reltuples/relpages ratio which is + * what's really important. + */ + + pg_class = table_open(RelationRelationId, RowExclusiveLock); + + /* + * Make a copy of the tuple to update. Normally we use the syscache, but + * we can't rely on that during bootstrap or while reindexing pg_class + * itself. + */ + if (IsBootstrapProcessingMode() || + ReindexIsProcessingHeap(RelationRelationId)) + { + /* don't assume syscache will work */ + TableScanDesc pg_class_scan; + ScanKeyData key[1]; + + ScanKeyInit(&key[0], + Anum_pg_class_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(relid)); + + pg_class_scan = table_beginscan_catalog(pg_class, 1, key); + tuple = heap_getnext(pg_class_scan, ForwardScanDirection); + tuple = heap_copytuple(tuple); + table_endscan(pg_class_scan); + } + else + { + /* normal case, use syscache */ + tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid)); + } + + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "could not find tuple for relation %u", relid); + rd_rel = (Form_pg_class) GETSTRUCT(tuple); + + /* Should this be a more comprehensive test? */ + Assert(rd_rel->relkind != RELKIND_PARTITIONED_INDEX); + + /* Apply required updates, if any, to copied tuple */ + + dirty = false; + if (rd_rel->relhasindex != hasindex) + { + rd_rel->relhasindex = hasindex; + dirty = true; + } + + if (reltuples >= 0) + { + BlockNumber relpages = RelationGetNumberOfBlocks(rel); + BlockNumber relallvisible; + + if (rd_rel->relkind != RELKIND_INDEX) + visibilitymap_count(rel, &relallvisible, NULL); + else /* don't bother for indexes */ + relallvisible = 0; + + if (rd_rel->relpages != (int32) relpages) + { + rd_rel->relpages = (int32) relpages; + dirty = true; + } + if (rd_rel->reltuples != (float4) reltuples) + { + rd_rel->reltuples = (float4) reltuples; + dirty = true; + } + if (rd_rel->relallvisible != (int32) relallvisible) + { + rd_rel->relallvisible = (int32) relallvisible; + dirty = true; + } + } + + /* + * If anything changed, write out the tuple + */ + if (dirty) + { + heap_inplace_update(pg_class, tuple); + /* the above sends a cache inval message */ + } + else + { + /* no need to change tuple, but force relcache inval anyway */ + CacheInvalidateRelcacheByTuple(tuple); + } + + heap_freetuple(tuple); + + table_close(pg_class, RowExclusiveLock); +} + + +/* + * index_build - invoke access-method-specific index build procedure + * + * On entry, the index's catalog entries are valid, and its physical disk + * file has been created but is empty. We call the AM-specific build + * procedure to fill in the index contents. We then update the pg_class + * entries of the index and heap relation as needed, using statistics + * returned by ambuild as well as data passed by the caller. + * + * isreindex indicates we are recreating a previously-existing index. + * parallel indicates if parallelism may be useful. + * + * Note: before Postgres 8.2, the passed-in heap and index Relations + * were automatically closed by this routine. This is no longer the case. + * The caller opened 'em, and the caller should close 'em. + */ +void +index_build(Relation heapRelation, + Relation indexRelation, + IndexInfo *indexInfo, + bool isreindex, + bool parallel) +{ + IndexBuildResult *stats; + Oid save_userid; + int save_sec_context; + int save_nestlevel; + + /* + * sanity checks + */ + Assert(RelationIsValid(indexRelation)); + Assert(PointerIsValid(indexRelation->rd_indam)); + Assert(PointerIsValid(indexRelation->rd_indam->ambuild)); + Assert(PointerIsValid(indexRelation->rd_indam->ambuildempty)); + + /* + * Determine worker process details for parallel CREATE INDEX. Currently, + * only btree has support for parallel builds. + * + * Note that planner considers parallel safety for us. + */ + if (parallel && IsNormalProcessingMode() && + indexRelation->rd_rel->relam == BTREE_AM_OID) + indexInfo->ii_ParallelWorkers = + plan_create_index_workers(RelationGetRelid(heapRelation), + RelationGetRelid(indexRelation)); + + if (indexInfo->ii_ParallelWorkers == 0) + ereport(DEBUG1, + (errmsg("building index \"%s\" on table \"%s\" serially", + RelationGetRelationName(indexRelation), + RelationGetRelationName(heapRelation)))); + else + ereport(DEBUG1, + (errmsg_plural("building index \"%s\" on table \"%s\" with request for %d parallel worker", + "building index \"%s\" on table \"%s\" with request for %d parallel workers", + indexInfo->ii_ParallelWorkers, + RelationGetRelationName(indexRelation), + RelationGetRelationName(heapRelation), + indexInfo->ii_ParallelWorkers))); + + /* + * Switch to the table owner's userid, so that any index functions are run + * as that user. Also lock down security-restricted operations and + * arrange to make GUC variable changes local to this command. + */ + GetUserIdAndSecContext(&save_userid, &save_sec_context); + SetUserIdAndSecContext(heapRelation->rd_rel->relowner, + save_sec_context | SECURITY_RESTRICTED_OPERATION); + save_nestlevel = NewGUCNestLevel(); + + /* Set up initial progress report status */ + { + const int index[] = { + PROGRESS_CREATEIDX_PHASE, + PROGRESS_CREATEIDX_SUBPHASE, + PROGRESS_CREATEIDX_TUPLES_DONE, + PROGRESS_CREATEIDX_TUPLES_TOTAL, + PROGRESS_SCAN_BLOCKS_DONE, + PROGRESS_SCAN_BLOCKS_TOTAL + }; + const int64 val[] = { + PROGRESS_CREATEIDX_PHASE_BUILD, + PROGRESS_CREATEIDX_SUBPHASE_INITIALIZE, + 0, 0, 0, 0 + }; + + pgstat_progress_update_multi_param(6, index, val); + } + + /* + * Call the access method's build procedure + */ + stats = indexRelation->rd_indam->ambuild(heapRelation, indexRelation, + indexInfo); + Assert(PointerIsValid(stats)); + + /* + * If this is an unlogged index, we may need to write out an init fork for + * it -- but we must first check whether one already exists. If, for + * example, an unlogged relation is truncated in the transaction that + * created it, or truncated twice in a subsequent transaction, the + * relfilenode won't change, and nothing needs to be done here. + */ + if (indexRelation->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED && + !smgrexists(indexRelation->rd_smgr, INIT_FORKNUM)) + { + RelationOpenSmgr(indexRelation); + smgrcreate(indexRelation->rd_smgr, INIT_FORKNUM, false); + indexRelation->rd_indam->ambuildempty(indexRelation); + } + + /* + * If we found any potentially broken HOT chains, mark the index as not + * being usable until the current transaction is below the event horizon. + * See src/backend/access/heap/README.HOT for discussion. Also set this + * if early pruning/vacuuming is enabled for the heap relation. While it + * might become safe to use the index earlier based on actual cleanup + * activity and other active transactions, the test for that would be much + * more complex and would require some form of blocking, so keep it simple + * and fast by just using the current transaction. + * + * However, when reindexing an existing index, we should do nothing here. + * Any HOT chains that are broken with respect to the index must predate + * the index's original creation, so there is no need to change the + * index's usability horizon. Moreover, we *must not* try to change the + * index's pg_index entry while reindexing pg_index itself, and this + * optimization nicely prevents that. The more complex rules needed for a + * reindex are handled separately after this function returns. + * + * We also need not set indcheckxmin during a concurrent index build, + * because we won't set indisvalid true until all transactions that care + * about the broken HOT chains or early pruning/vacuuming are gone. + * + * Therefore, this code path can only be taken during non-concurrent + * CREATE INDEX. Thus the fact that heap_update will set the pg_index + * tuple's xmin doesn't matter, because that tuple was created in the + * current transaction anyway. That also means we don't need to worry + * about any concurrent readers of the tuple; no other transaction can see + * it yet. + */ + if ((indexInfo->ii_BrokenHotChain || EarlyPruningEnabled(heapRelation)) && + !isreindex && + !indexInfo->ii_Concurrent) + { + Oid indexId = RelationGetRelid(indexRelation); + Relation pg_index; + HeapTuple indexTuple; + Form_pg_index indexForm; + + pg_index = table_open(IndexRelationId, RowExclusiveLock); + + indexTuple = SearchSysCacheCopy1(INDEXRELID, + ObjectIdGetDatum(indexId)); + if (!HeapTupleIsValid(indexTuple)) + elog(ERROR, "cache lookup failed for index %u", indexId); + indexForm = (Form_pg_index) GETSTRUCT(indexTuple); + + /* If it's a new index, indcheckxmin shouldn't be set ... */ + Assert(!indexForm->indcheckxmin); + + indexForm->indcheckxmin = true; + CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple); + + heap_freetuple(indexTuple); + table_close(pg_index, RowExclusiveLock); + } + + /* + * Update heap and index pg_class rows + */ + index_update_stats(heapRelation, + true, + stats->heap_tuples); + + index_update_stats(indexRelation, + false, + stats->index_tuples); + + /* Make the updated catalog row versions visible */ + CommandCounterIncrement(); + + /* + * If it's for an exclusion constraint, make a second pass over the heap + * to verify that the constraint is satisfied. We must not do this until + * the index is fully valid. (Broken HOT chains shouldn't matter, though; + * see comments for IndexCheckExclusion.) + */ + if (indexInfo->ii_ExclusionOps != NULL) + IndexCheckExclusion(heapRelation, indexRelation, indexInfo); + + /* Roll back any GUC changes executed by index functions */ + AtEOXact_GUC(false, save_nestlevel); + + /* Restore userid and security context */ + SetUserIdAndSecContext(save_userid, save_sec_context); +} + +/* + * IndexCheckExclusion - verify that a new exclusion constraint is satisfied + * + * When creating an exclusion constraint, we first build the index normally + * and then rescan the heap to check for conflicts. We assume that we only + * need to validate tuples that are live according to an up-to-date snapshot, + * and that these were correctly indexed even in the presence of broken HOT + * chains. This should be OK since we are holding at least ShareLock on the + * table, meaning there can be no uncommitted updates from other transactions. + * (Note: that wouldn't necessarily work for system catalogs, since many + * operations release write lock early on the system catalogs.) + */ +static void +IndexCheckExclusion(Relation heapRelation, + Relation indexRelation, + IndexInfo *indexInfo) +{ + TableScanDesc scan; + Datum values[INDEX_MAX_KEYS]; + bool isnull[INDEX_MAX_KEYS]; + ExprState *predicate; + TupleTableSlot *slot; + EState *estate; + ExprContext *econtext; + Snapshot snapshot; + + /* + * If we are reindexing the target index, mark it as no longer being + * reindexed, to forestall an Assert in index_beginscan when we try to use + * the index for probes. This is OK because the index is now fully valid. + */ + if (ReindexIsCurrentlyProcessingIndex(RelationGetRelid(indexRelation))) + ResetReindexProcessing(); + + /* + * Need an EState for evaluation of index expressions and partial-index + * predicates. Also a slot to hold the current tuple. + */ + estate = CreateExecutorState(); + econtext = GetPerTupleExprContext(estate); + slot = table_slot_create(heapRelation, NULL); + + /* Arrange for econtext's scan tuple to be the tuple under test */ + econtext->ecxt_scantuple = slot; + + /* Set up execution state for predicate, if any. */ + predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate); + + /* + * Scan all live tuples in the base relation. + */ + snapshot = RegisterSnapshot(GetLatestSnapshot()); + scan = table_beginscan_strat(heapRelation, /* relation */ + snapshot, /* snapshot */ + 0, /* number of keys */ + NULL, /* scan key */ + true, /* buffer access strategy OK */ + true); /* syncscan OK */ + + while (table_scan_getnextslot(scan, ForwardScanDirection, slot)) + { + CHECK_FOR_INTERRUPTS(); + + /* + * In a partial index, ignore tuples that don't satisfy the predicate. + */ + if (predicate != NULL) + { + if (!ExecQual(predicate, econtext)) + continue; + } + + /* + * Extract index column values, including computing expressions. + */ + FormIndexDatum(indexInfo, + slot, + estate, + values, + isnull); + + /* + * Check that this tuple has no conflicts. + */ + check_exclusion_constraint(heapRelation, + indexRelation, indexInfo, + &(slot->tts_tid), values, isnull, + estate, true); + + MemoryContextReset(econtext->ecxt_per_tuple_memory); + } + + table_endscan(scan); + UnregisterSnapshot(snapshot); + + ExecDropSingleTupleTableSlot(slot); + + FreeExecutorState(estate); + + /* These may have been pointing to the now-gone estate */ + indexInfo->ii_ExpressionsState = NIL; + indexInfo->ii_PredicateState = NULL; +} + + +/* + * validate_index - support code for concurrent index builds + * + * We do a concurrent index build by first inserting the catalog entry for the + * index via index_create(), marking it not indisready and not indisvalid. + * Then we commit our transaction and start a new one, then we wait for all + * transactions that could have been modifying the table to terminate. Now + * we know that any subsequently-started transactions will see the index and + * honor its constraints on HOT updates; so while existing HOT-chains might + * be broken with respect to the index, no currently live tuple will have an + * incompatible HOT update done to it. We now build the index normally via + * index_build(), while holding a weak lock that allows concurrent + * insert/update/delete. Also, we index only tuples that are valid + * as of the start of the scan (see table_index_build_scan), whereas a normal + * build takes care to include recently-dead tuples. This is OK because + * we won't mark the index valid until all transactions that might be able + * to see those tuples are gone. The reason for doing that is to avoid + * bogus unique-index failures due to concurrent UPDATEs (we might see + * different versions of the same row as being valid when we pass over them, + * if we used HeapTupleSatisfiesVacuum). This leaves us with an index that + * does not contain any tuples added to the table while we built the index. + * + * Next, we mark the index "indisready" (but still not "indisvalid") and + * commit the second transaction and start a third. Again we wait for all + * transactions that could have been modifying the table to terminate. Now + * we know that any subsequently-started transactions will see the index and + * insert their new tuples into it. We then take a new reference snapshot + * which is passed to validate_index(). Any tuples that are valid according + * to this snap, but are not in the index, must be added to the index. + * (Any tuples committed live after the snap will be inserted into the + * index by their originating transaction. Any tuples committed dead before + * the snap need not be indexed, because we will wait out all transactions + * that might care about them before we mark the index valid.) + * + * validate_index() works by first gathering all the TIDs currently in the + * index, using a bulkdelete callback that just stores the TIDs and doesn't + * ever say "delete it". (This should be faster than a plain indexscan; + * also, not all index AMs support full-index indexscan.) Then we sort the + * TIDs, and finally scan the table doing a "merge join" against the TID list + * to see which tuples are missing from the index. Thus we will ensure that + * all tuples valid according to the reference snapshot are in the index. + * + * Building a unique index this way is tricky: we might try to insert a + * tuple that is already dead or is in process of being deleted, and we + * mustn't have a uniqueness failure against an updated version of the same + * row. We could try to check the tuple to see if it's already dead and tell + * index_insert() not to do the uniqueness check, but that still leaves us + * with a race condition against an in-progress update. To handle that, + * we expect the index AM to recheck liveness of the to-be-inserted tuple + * before it declares a uniqueness error. + * + * After completing validate_index(), we wait until all transactions that + * were alive at the time of the reference snapshot are gone; this is + * necessary to be sure there are none left with a transaction snapshot + * older than the reference (and hence possibly able to see tuples we did + * not index). Then we mark the index "indisvalid" and commit. Subsequent + * transactions will be able to use it for queries. + * + * Doing two full table scans is a brute-force strategy. We could try to be + * cleverer, eg storing new tuples in a special area of the table (perhaps + * making the table append-only by setting use_fsm). However that would + * add yet more locking issues. + */ +void +validate_index(Oid heapId, Oid indexId, Snapshot snapshot) +{ + Relation heapRelation, + indexRelation; + IndexInfo *indexInfo; + IndexVacuumInfo ivinfo; + ValidateIndexState state; + Oid save_userid; + int save_sec_context; + int save_nestlevel; + + { + const int index[] = { + PROGRESS_CREATEIDX_PHASE, + PROGRESS_CREATEIDX_TUPLES_DONE, + PROGRESS_CREATEIDX_TUPLES_TOTAL, + PROGRESS_SCAN_BLOCKS_DONE, + PROGRESS_SCAN_BLOCKS_TOTAL + }; + const int64 val[] = { + PROGRESS_CREATEIDX_PHASE_VALIDATE_IDXSCAN, + 0, 0, 0, 0 + }; + + pgstat_progress_update_multi_param(5, index, val); + } + + /* Open and lock the parent heap relation */ + heapRelation = table_open(heapId, ShareUpdateExclusiveLock); + /* And the target index relation */ + indexRelation = index_open(indexId, RowExclusiveLock); + + /* + * Fetch info needed for index_insert. (You might think this should be + * passed in from DefineIndex, but its copy is long gone due to having + * been built in a previous transaction.) + */ + indexInfo = BuildIndexInfo(indexRelation); + + /* mark build is concurrent just for consistency */ + indexInfo->ii_Concurrent = true; + + /* + * Switch to the table owner's userid, so that any index functions are run + * as that user. Also lock down security-restricted operations and + * arrange to make GUC variable changes local to this command. + */ + GetUserIdAndSecContext(&save_userid, &save_sec_context); + SetUserIdAndSecContext(heapRelation->rd_rel->relowner, + save_sec_context | SECURITY_RESTRICTED_OPERATION); + save_nestlevel = NewGUCNestLevel(); + + /* + * Scan the index and gather up all the TIDs into a tuplesort object. + */ + ivinfo.index = indexRelation; + ivinfo.analyze_only = false; + ivinfo.report_progress = true; + ivinfo.estimated_count = true; + ivinfo.message_level = DEBUG2; + ivinfo.num_heap_tuples = heapRelation->rd_rel->reltuples; + ivinfo.strategy = NULL; + + /* + * Encode TIDs as int8 values for the sort, rather than directly sorting + * item pointers. This can be significantly faster, primarily because TID + * is a pass-by-reference type on all platforms, whereas int8 is + * pass-by-value on most platforms. + */ + state.tuplesort = tuplesort_begin_datum(INT8OID, Int8LessOperator, + InvalidOid, false, + maintenance_work_mem, + NULL, false); + state.htups = state.itups = state.tups_inserted = 0; + + /* ambulkdelete updates progress metrics */ + (void) index_bulk_delete(&ivinfo, NULL, + validate_index_callback, (void *) &state); + + /* Execute the sort */ + { + const int index[] = { + PROGRESS_CREATEIDX_PHASE, + PROGRESS_SCAN_BLOCKS_DONE, + PROGRESS_SCAN_BLOCKS_TOTAL + }; + const int64 val[] = { + PROGRESS_CREATEIDX_PHASE_VALIDATE_SORT, + 0, 0 + }; + + pgstat_progress_update_multi_param(3, index, val); + } + tuplesort_performsort(state.tuplesort); + + /* + * Now scan the heap and "merge" it with the index + */ + pgstat_progress_update_param(PROGRESS_CREATEIDX_PHASE, + PROGRESS_CREATEIDX_PHASE_VALIDATE_TABLESCAN); + table_index_validate_scan(heapRelation, + indexRelation, + indexInfo, + snapshot, + &state); + + /* Done with tuplesort object */ + tuplesort_end(state.tuplesort); + + elog(DEBUG2, + "validate_index found %.0f heap tuples, %.0f index tuples; inserted %.0f missing tuples", + state.htups, state.itups, state.tups_inserted); + + /* Roll back any GUC changes executed by index functions */ + AtEOXact_GUC(false, save_nestlevel); + + /* Restore userid and security context */ + SetUserIdAndSecContext(save_userid, save_sec_context); + + /* Close rels, but keep locks */ + index_close(indexRelation, NoLock); + table_close(heapRelation, NoLock); +} + +/* + * validate_index_callback - bulkdelete callback to collect the index TIDs + */ +static bool +validate_index_callback(ItemPointer itemptr, void *opaque) +{ + ValidateIndexState *state = (ValidateIndexState *) opaque; + int64 encoded = itemptr_encode(itemptr); + + tuplesort_putdatum(state->tuplesort, Int64GetDatum(encoded), false); + state->itups += 1; + return false; /* never actually delete anything */ +} + +/* + * index_set_state_flags - adjust pg_index state flags + * + * This is used during CREATE/DROP INDEX CONCURRENTLY to adjust the pg_index + * flags that denote the index's state. + * + * Note that CatalogTupleUpdate() sends a cache invalidation message for the + * tuple, so other sessions will hear about the update as soon as we commit. + */ +void +index_set_state_flags(Oid indexId, IndexStateFlagsAction action) +{ + Relation pg_index; + HeapTuple indexTuple; + Form_pg_index indexForm; + + /* Open pg_index and fetch a writable copy of the index's tuple */ + pg_index = table_open(IndexRelationId, RowExclusiveLock); + + indexTuple = SearchSysCacheCopy1(INDEXRELID, + ObjectIdGetDatum(indexId)); + if (!HeapTupleIsValid(indexTuple)) + elog(ERROR, "cache lookup failed for index %u", indexId); + indexForm = (Form_pg_index) GETSTRUCT(indexTuple); + + /* Perform the requested state change on the copy */ + switch (action) + { + case INDEX_CREATE_SET_READY: + /* Set indisready during a CREATE INDEX CONCURRENTLY sequence */ + Assert(indexForm->indislive); + Assert(!indexForm->indisready); + Assert(!indexForm->indisvalid); + indexForm->indisready = true; + break; + case INDEX_CREATE_SET_VALID: + /* Set indisvalid during a CREATE INDEX CONCURRENTLY sequence */ + Assert(indexForm->indislive); + Assert(indexForm->indisready); + Assert(!indexForm->indisvalid); + indexForm->indisvalid = true; + break; + case INDEX_DROP_CLEAR_VALID: + + /* + * Clear indisvalid during a DROP INDEX CONCURRENTLY sequence + * + * If indisready == true we leave it set so the index still gets + * maintained by active transactions. We only need to ensure that + * indisvalid is false. (We don't assert that either is initially + * true, though, since we want to be able to retry a DROP INDEX + * CONCURRENTLY that failed partway through.) + * + * Note: the CLUSTER logic assumes that indisclustered cannot be + * set on any invalid index, so clear that flag too. + */ + indexForm->indisvalid = false; + indexForm->indisclustered = false; + break; + case INDEX_DROP_SET_DEAD: + + /* + * Clear indisready/indislive during DROP INDEX CONCURRENTLY + * + * We clear both indisready and indislive, because we not only + * want to stop updates, we want to prevent sessions from touching + * the index at all. + */ + Assert(!indexForm->indisvalid); + indexForm->indisready = false; + indexForm->indislive = false; + break; + } + + /* ... and update it */ + CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple); + + table_close(pg_index, RowExclusiveLock); +} + + +/* + * IndexGetRelation: given an index's relation OID, get the OID of the + * relation it is an index on. Uses the system cache. + */ +Oid +IndexGetRelation(Oid indexId, bool missing_ok) +{ + HeapTuple tuple; + Form_pg_index index; + Oid result; + + tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId)); + if (!HeapTupleIsValid(tuple)) + { + if (missing_ok) + return InvalidOid; + elog(ERROR, "cache lookup failed for index %u", indexId); + } + index = (Form_pg_index) GETSTRUCT(tuple); + Assert(index->indexrelid == indexId); + + result = index->indrelid; + ReleaseSysCache(tuple); + return result; +} + +/* + * reindex_index - This routine is used to recreate a single index + */ +void +reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, + int options) +{ + Relation iRel, + heapRelation; + Oid heapId; + IndexInfo *indexInfo; + volatile bool skipped_constraint = false; + PGRUsage ru0; + bool progress = (options & REINDEXOPT_REPORT_PROGRESS) != 0; + + pg_rusage_init(&ru0); + + /* + * Open and lock the parent heap relation. ShareLock is sufficient since + * we only need to be sure no schema or data changes are going on. + */ + heapId = IndexGetRelation(indexId, false); + heapRelation = table_open(heapId, ShareLock); + + if (progress) + { + pgstat_progress_start_command(PROGRESS_COMMAND_CREATE_INDEX, + heapId); + pgstat_progress_update_param(PROGRESS_CREATEIDX_COMMAND, + PROGRESS_CREATEIDX_COMMAND_REINDEX); + pgstat_progress_update_param(PROGRESS_CREATEIDX_INDEX_OID, + indexId); + } + + /* + * Open the target index relation and get an exclusive lock on it, to + * ensure that no one else is touching this particular index. + */ + iRel = index_open(indexId, AccessExclusiveLock); + + if (progress) + pgstat_progress_update_param(PROGRESS_CREATEIDX_ACCESS_METHOD_OID, + iRel->rd_rel->relam); + + /* + * The case of reindexing partitioned tables and indexes is handled + * differently by upper layers, so this case shouldn't arise. + */ + if (iRel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) + elog(ERROR, "unsupported relation kind for index \"%s\"", + RelationGetRelationName(iRel)); + + /* + * Don't allow reindex on temp tables of other backends ... their local + * buffer manager is not going to cope. + */ + if (RELATION_IS_OTHER_TEMP(iRel)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot reindex temporary tables of other sessions"))); + + /* + * Don't allow reindex of an invalid index on TOAST table. This is a + * leftover from a failed REINDEX CONCURRENTLY, and if rebuilt it would + * not be possible to drop it anymore. + */ + if (IsToastNamespace(RelationGetNamespace(iRel)) && + !get_index_isvalid(indexId)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot reindex invalid index on TOAST table"))); + + /* + * Also check for active uses of the index in the current transaction; we + * don't want to reindex underneath an open indexscan. + */ + CheckTableNotInUse(iRel, "REINDEX INDEX"); + + /* + * All predicate locks on the index are about to be made invalid. Promote + * them to relation locks on the heap. + */ + TransferPredicateLocksToHeapRelation(iRel); + + /* Fetch info needed for index_build */ + indexInfo = BuildIndexInfo(iRel); + + /* If requested, skip checking uniqueness/exclusion constraints */ + if (skip_constraint_checks) + { + if (indexInfo->ii_Unique || indexInfo->ii_ExclusionOps != NULL) + skipped_constraint = true; + indexInfo->ii_Unique = false; + indexInfo->ii_ExclusionOps = NULL; + indexInfo->ii_ExclusionProcs = NULL; + indexInfo->ii_ExclusionStrats = NULL; + } + + /* Suppress use of the target index while rebuilding it */ + SetReindexProcessing(heapId, indexId); + + /* Create a new physical relation for the index */ + RelationSetNewRelfilenode(iRel, persistence); + + /* Initialize the index and rebuild */ + /* Note: we do not need to re-establish pkey setting */ + index_build(heapRelation, iRel, indexInfo, true, true); + + /* Re-allow use of target index */ + ResetReindexProcessing(); + + /* + * If the index is marked invalid/not-ready/dead (ie, it's from a failed + * CREATE INDEX CONCURRENTLY, or a DROP INDEX CONCURRENTLY failed midway), + * and we didn't skip a uniqueness check, we can now mark it valid. This + * allows REINDEX to be used to clean up in such cases. + * + * We can also reset indcheckxmin, because we have now done a + * non-concurrent index build, *except* in the case where index_build + * found some still-broken HOT chains. If it did, and we don't have to + * change any of the other flags, we just leave indcheckxmin alone (note + * that index_build won't have changed it, because this is a reindex). + * This is okay and desirable because not updating the tuple leaves the + * index's usability horizon (recorded as the tuple's xmin value) the same + * as it was. + * + * But, if the index was invalid/not-ready/dead and there were broken HOT + * chains, we had better force indcheckxmin true, because the normal + * argument that the HOT chains couldn't conflict with the index is + * suspect for an invalid index. (A conflict is definitely possible if + * the index was dead. It probably shouldn't happen otherwise, but let's + * be conservative.) In this case advancing the usability horizon is + * appropriate. + * + * Another reason for avoiding unnecessary updates here is that while + * reindexing pg_index itself, we must not try to update tuples in it. + * pg_index's indexes should always have these flags in their clean state, + * so that won't happen. + * + * If early pruning/vacuuming is enabled for the heap relation, the + * usability horizon must be advanced to the current transaction on every + * build or rebuild. pg_index is OK in this regard because catalog tables + * are not subject to early cleanup. + */ + if (!skipped_constraint) + { + Relation pg_index; + HeapTuple indexTuple; + Form_pg_index indexForm; + bool index_bad; + bool early_pruning_enabled = EarlyPruningEnabled(heapRelation); + + pg_index = table_open(IndexRelationId, RowExclusiveLock); + + indexTuple = SearchSysCacheCopy1(INDEXRELID, + ObjectIdGetDatum(indexId)); + if (!HeapTupleIsValid(indexTuple)) + elog(ERROR, "cache lookup failed for index %u", indexId); + indexForm = (Form_pg_index) GETSTRUCT(indexTuple); + + index_bad = (!indexForm->indisvalid || + !indexForm->indisready || + !indexForm->indislive); + if (index_bad || + (indexForm->indcheckxmin && !indexInfo->ii_BrokenHotChain) || + early_pruning_enabled) + { + if (!indexInfo->ii_BrokenHotChain && !early_pruning_enabled) + indexForm->indcheckxmin = false; + else if (index_bad || early_pruning_enabled) + indexForm->indcheckxmin = true; + indexForm->indisvalid = true; + indexForm->indisready = true; + indexForm->indislive = true; + CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple); + + /* + * Invalidate the relcache for the table, so that after we commit + * all sessions will refresh the table's index list. This ensures + * that if anyone misses seeing the pg_index row during this + * update, they'll refresh their list before attempting any update + * on the table. + */ + CacheInvalidateRelcache(heapRelation); + } + + table_close(pg_index, RowExclusiveLock); + } + + /* Log what we did */ + if (options & REINDEXOPT_VERBOSE) + ereport(INFO, + (errmsg("index \"%s\" was reindexed", + get_rel_name(indexId)), + errdetail_internal("%s", + pg_rusage_show(&ru0)))); + + if (progress) + pgstat_progress_end_command(); + + /* Close rels, but keep locks */ + index_close(iRel, NoLock); + table_close(heapRelation, NoLock); +} + +/* + * reindex_relation - This routine is used to recreate all indexes + * of a relation (and optionally its toast relation too, if any). + * + * "flags" is a bitmask that can include any combination of these bits: + * + * REINDEX_REL_PROCESS_TOAST: if true, process the toast table too (if any). + * + * REINDEX_REL_SUPPRESS_INDEX_USE: if true, the relation was just completely + * rebuilt by an operation such as VACUUM FULL or CLUSTER, and therefore its + * indexes are inconsistent with it. This makes things tricky if the relation + * is a system catalog that we might consult during the reindexing. To deal + * with that case, we mark all of the indexes as pending rebuild so that they + * won't be trusted until rebuilt. The caller is required to call us *without* + * having made the rebuilt table visible by doing CommandCounterIncrement; + * we'll do CCI after having collected the index list. (This way we can still + * use catalog indexes while collecting the list.) + * + * REINDEX_REL_CHECK_CONSTRAINTS: if true, recheck unique and exclusion + * constraint conditions, else don't. To avoid deadlocks, VACUUM FULL or + * CLUSTER on a system catalog must omit this flag. REINDEX should be used to + * rebuild an index if constraint inconsistency is suspected. For optimal + * performance, other callers should include the flag only after transforming + * the data in a manner that risks a change in constraint validity. + * + * REINDEX_REL_FORCE_INDEXES_UNLOGGED: if true, set the persistence of the + * rebuilt indexes to unlogged. + * + * REINDEX_REL_FORCE_INDEXES_PERMANENT: if true, set the persistence of the + * rebuilt indexes to permanent. + * + * Returns true if any indexes were rebuilt (including toast table's index + * when relevant). Note that a CommandCounterIncrement will occur after each + * index rebuild. + */ +bool +reindex_relation(Oid relid, int flags, int options) +{ + Relation rel; + Oid toast_relid; + List *indexIds; + char persistence; + bool result; + ListCell *indexId; + int i; + + /* + * Open and lock the relation. ShareLock is sufficient since we only need + * to prevent schema and data changes in it. The lock level used here + * should match ReindexTable(). + */ + rel = table_open(relid, ShareLock); + + /* + * This may be useful when implemented someday; but that day is not today. + * For now, avoid erroring out when called in a multi-table context + * (REINDEX SCHEMA) and happen to come across a partitioned table. The + * partitions may be reindexed on their own anyway. + */ + if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + { + ereport(WARNING, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("REINDEX of partitioned tables is not yet implemented, skipping \"%s\"", + RelationGetRelationName(rel)))); + table_close(rel, ShareLock); + return false; + } + + toast_relid = rel->rd_rel->reltoastrelid; + + /* + * Get the list of index OIDs for this relation. (We trust to the + * relcache to get this with a sequential scan if ignoring system + * indexes.) + */ + indexIds = RelationGetIndexList(rel); + + if (flags & REINDEX_REL_SUPPRESS_INDEX_USE) + { + /* Suppress use of all the indexes until they are rebuilt */ + SetReindexPending(indexIds); + + /* + * Make the new heap contents visible --- now things might be + * inconsistent! + */ + CommandCounterIncrement(); + } + + /* + * Compute persistence of indexes: same as that of owning rel, unless + * caller specified otherwise. + */ + if (flags & REINDEX_REL_FORCE_INDEXES_UNLOGGED) + persistence = RELPERSISTENCE_UNLOGGED; + else if (flags & REINDEX_REL_FORCE_INDEXES_PERMANENT) + persistence = RELPERSISTENCE_PERMANENT; + else + persistence = rel->rd_rel->relpersistence; + + /* Reindex all the indexes. */ + i = 1; + foreach(indexId, indexIds) + { + Oid indexOid = lfirst_oid(indexId); + Oid indexNamespaceId = get_rel_namespace(indexOid); + + /* + * Skip any invalid indexes on a TOAST table. These can only be + * duplicate leftovers from a failed REINDEX CONCURRENTLY, and if + * rebuilt it would not be possible to drop them anymore. + */ + if (IsToastNamespace(indexNamespaceId) && + !get_index_isvalid(indexOid)) + { + ereport(WARNING, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot reindex invalid index \"%s.%s\" on TOAST table, skipping", + get_namespace_name(indexNamespaceId), + get_rel_name(indexOid)))); + continue; + } + + reindex_index(indexOid, !(flags & REINDEX_REL_CHECK_CONSTRAINTS), + persistence, options); + + CommandCounterIncrement(); + + /* Index should no longer be in the pending list */ + Assert(!ReindexIsProcessingIndex(indexOid)); + + /* Set index rebuild count */ + pgstat_progress_update_param(PROGRESS_CLUSTER_INDEX_REBUILD_COUNT, + i); + i++; + } + + /* + * Close rel, but continue to hold the lock. + */ + table_close(rel, NoLock); + + result = (indexIds != NIL); + + /* + * If the relation has a secondary toast rel, reindex that too while we + * still hold the lock on the master table. + */ + if ((flags & REINDEX_REL_PROCESS_TOAST) && OidIsValid(toast_relid)) + result |= reindex_relation(toast_relid, flags, options); + + return result; +} + + +/* ---------------------------------------------------------------- + * System index reindexing support + * + * When we are busy reindexing a system index, this code provides support + * for preventing catalog lookups from using that index. We also make use + * of this to catch attempted uses of user indexes during reindexing of + * those indexes. This information is propagated to parallel workers; + * attempting to change it during a parallel operation is not permitted. + * ---------------------------------------------------------------- + */ + +static Oid currentlyReindexedHeap = InvalidOid; +static Oid currentlyReindexedIndex = InvalidOid; +static List *pendingReindexedIndexes = NIL; +static int reindexingNestLevel = 0; + +/* + * ReindexIsProcessingHeap + * True if heap specified by OID is currently being reindexed. + */ +bool +ReindexIsProcessingHeap(Oid heapOid) +{ + return heapOid == currentlyReindexedHeap; +} + +/* + * ReindexIsCurrentlyProcessingIndex + * True if index specified by OID is currently being reindexed. + */ +static bool +ReindexIsCurrentlyProcessingIndex(Oid indexOid) +{ + return indexOid == currentlyReindexedIndex; +} + +/* + * ReindexIsProcessingIndex + * True if index specified by OID is currently being reindexed, + * or should be treated as invalid because it is awaiting reindex. + */ +bool +ReindexIsProcessingIndex(Oid indexOid) +{ + return indexOid == currentlyReindexedIndex || + list_member_oid(pendingReindexedIndexes, indexOid); +} + +/* + * SetReindexProcessing + * Set flag that specified heap/index are being reindexed. + */ +static void +SetReindexProcessing(Oid heapOid, Oid indexOid) +{ + Assert(OidIsValid(heapOid) && OidIsValid(indexOid)); + /* Reindexing is not re-entrant. */ + if (OidIsValid(currentlyReindexedHeap)) + elog(ERROR, "cannot reindex while reindexing"); + currentlyReindexedHeap = heapOid; + currentlyReindexedIndex = indexOid; + /* Index is no longer "pending" reindex. */ + RemoveReindexPending(indexOid); + /* This may have been set already, but in case it isn't, do so now. */ + reindexingNestLevel = GetCurrentTransactionNestLevel(); +} + +/* + * ResetReindexProcessing + * Unset reindexing status. + */ +static void +ResetReindexProcessing(void) +{ + currentlyReindexedHeap = InvalidOid; + currentlyReindexedIndex = InvalidOid; + /* reindexingNestLevel remains set till end of (sub)transaction */ +} + +/* + * SetReindexPending + * Mark the given indexes as pending reindex. + * + * NB: we assume that the current memory context stays valid throughout. + */ +static void +SetReindexPending(List *indexes) +{ + /* Reindexing is not re-entrant. */ + if (pendingReindexedIndexes) + elog(ERROR, "cannot reindex while reindexing"); + if (IsInParallelMode()) + elog(ERROR, "cannot modify reindex state during a parallel operation"); + pendingReindexedIndexes = list_copy(indexes); + reindexingNestLevel = GetCurrentTransactionNestLevel(); +} + +/* + * RemoveReindexPending + * Remove the given index from the pending list. + */ +static void +RemoveReindexPending(Oid indexOid) +{ + if (IsInParallelMode()) + elog(ERROR, "cannot modify reindex state during a parallel operation"); + pendingReindexedIndexes = list_delete_oid(pendingReindexedIndexes, + indexOid); +} + +/* + * ResetReindexState + * Clear all reindexing state during (sub)transaction abort. + */ +void +ResetReindexState(int nestLevel) +{ + /* + * Because reindexing is not re-entrant, we don't need to cope with nested + * reindexing states. We just need to avoid messing up the outer-level + * state in case a subtransaction fails within a REINDEX. So checking the + * current nest level against that of the reindex operation is sufficient. + */ + if (reindexingNestLevel >= nestLevel) + { + currentlyReindexedHeap = InvalidOid; + currentlyReindexedIndex = InvalidOid; + + /* + * We needn't try to release the contents of pendingReindexedIndexes; + * that list should be in a transaction-lifespan context, so it will + * go away automatically. + */ + pendingReindexedIndexes = NIL; + + reindexingNestLevel = 0; + } +} + +/* + * EstimateReindexStateSpace + * Estimate space needed to pass reindex state to parallel workers. + */ +Size +EstimateReindexStateSpace(void) +{ + return offsetof(SerializedReindexState, pendingReindexedIndexes) + + mul_size(sizeof(Oid), list_length(pendingReindexedIndexes)); +} + +/* + * SerializeReindexState + * Serialize reindex state for parallel workers. + */ +void +SerializeReindexState(Size maxsize, char *start_address) +{ + SerializedReindexState *sistate = (SerializedReindexState *) start_address; + int c = 0; + ListCell *lc; + + sistate->currentlyReindexedHeap = currentlyReindexedHeap; + sistate->currentlyReindexedIndex = currentlyReindexedIndex; + sistate->numPendingReindexedIndexes = list_length(pendingReindexedIndexes); + foreach(lc, pendingReindexedIndexes) + sistate->pendingReindexedIndexes[c++] = lfirst_oid(lc); +} + +/* + * RestoreReindexState + * Restore reindex state in a parallel worker. + */ +void +RestoreReindexState(void *reindexstate) +{ + SerializedReindexState *sistate = (SerializedReindexState *) reindexstate; + int c = 0; + MemoryContext oldcontext; + + currentlyReindexedHeap = sistate->currentlyReindexedHeap; + currentlyReindexedIndex = sistate->currentlyReindexedIndex; + + Assert(pendingReindexedIndexes == NIL); + oldcontext = MemoryContextSwitchTo(TopMemoryContext); + for (c = 0; c < sistate->numPendingReindexedIndexes; ++c) + pendingReindexedIndexes = + lappend_oid(pendingReindexedIndexes, + sistate->pendingReindexedIndexes[c]); + MemoryContextSwitchTo(oldcontext); + + /* Note the worker has its own transaction nesting level */ + reindexingNestLevel = GetCurrentTransactionNestLevel(); +} diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c new file mode 100644 index 0000000..fe277f3 --- /dev/null +++ b/src/backend/catalog/indexing.c @@ -0,0 +1,317 @@ +/*------------------------------------------------------------------------- + * + * indexing.c + * This file contains routines to support indexes defined on system + * catalogs. + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/indexing.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/genam.h" +#include "access/heapam.h" +#include "access/htup_details.h" +#include "catalog/index.h" +#include "catalog/indexing.h" +#include "executor/executor.h" +#include "utils/rel.h" + + +/* + * CatalogOpenIndexes - open the indexes on a system catalog. + * + * When inserting or updating tuples in a system catalog, call this + * to prepare to update the indexes for the catalog. + * + * In the current implementation, we share code for opening/closing the + * indexes with execUtils.c. But we do not use ExecInsertIndexTuples, + * because we don't want to create an EState. This implies that we + * do not support partial or expressional indexes on system catalogs, + * nor can we support generalized exclusion constraints. + * This could be fixed with localized changes here if we wanted to pay + * the extra overhead of building an EState. + */ +CatalogIndexState +CatalogOpenIndexes(Relation heapRel) +{ + ResultRelInfo *resultRelInfo; + + resultRelInfo = makeNode(ResultRelInfo); + resultRelInfo->ri_RangeTableIndex = 0; /* dummy */ + resultRelInfo->ri_RelationDesc = heapRel; + resultRelInfo->ri_TrigDesc = NULL; /* we don't fire triggers */ + + ExecOpenIndices(resultRelInfo, false); + + return resultRelInfo; +} + +/* + * CatalogCloseIndexes - clean up resources allocated by CatalogOpenIndexes + */ +void +CatalogCloseIndexes(CatalogIndexState indstate) +{ + ExecCloseIndices(indstate); + pfree(indstate); +} + +/* + * CatalogIndexInsert - insert index entries for one catalog tuple + * + * This should be called for each inserted or updated catalog tuple. + * + * This is effectively a cut-down version of ExecInsertIndexTuples. + */ +static void +CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple) +{ + int i; + int numIndexes; + RelationPtr relationDescs; + Relation heapRelation; + TupleTableSlot *slot; + IndexInfo **indexInfoArray; + Datum values[INDEX_MAX_KEYS]; + bool isnull[INDEX_MAX_KEYS]; + + /* + * HOT update does not require index inserts. But with asserts enabled we + * want to check that it'd be legal to currently insert into the + * table/index. + */ +#ifndef USE_ASSERT_CHECKING + if (HeapTupleIsHeapOnly(heapTuple)) + return; +#endif + + /* + * Get information from the state structure. Fall out if nothing to do. + */ + numIndexes = indstate->ri_NumIndices; + if (numIndexes == 0) + return; + relationDescs = indstate->ri_IndexRelationDescs; + indexInfoArray = indstate->ri_IndexRelationInfo; + heapRelation = indstate->ri_RelationDesc; + + /* Need a slot to hold the tuple being examined */ + slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation), + &TTSOpsHeapTuple); + ExecStoreHeapTuple(heapTuple, slot, false); + + /* + * for each index, form and insert the index tuple + */ + for (i = 0; i < numIndexes; i++) + { + IndexInfo *indexInfo; + Relation index; + + indexInfo = indexInfoArray[i]; + index = relationDescs[i]; + + /* If the index is marked as read-only, ignore it */ + if (!indexInfo->ii_ReadyForInserts) + continue; + + /* + * Expressional and partial indexes on system catalogs are not + * supported, nor exclusion constraints, nor deferred uniqueness + */ + Assert(indexInfo->ii_Expressions == NIL); + Assert(indexInfo->ii_Predicate == NIL); + Assert(indexInfo->ii_ExclusionOps == NULL); + Assert(index->rd_index->indimmediate); + Assert(indexInfo->ii_NumIndexKeyAttrs != 0); + + /* see earlier check above */ +#ifdef USE_ASSERT_CHECKING + if (HeapTupleIsHeapOnly(heapTuple)) + { + Assert(!ReindexIsProcessingIndex(RelationGetRelid(index))); + continue; + } +#endif /* USE_ASSERT_CHECKING */ + + /* + * FormIndexDatum fills in its values and isnull parameters with the + * appropriate values for the column(s) of the index. + */ + FormIndexDatum(indexInfo, + slot, + NULL, /* no expression eval to do */ + values, + isnull); + + /* + * The index AM does the rest. + */ + index_insert(index, /* index relation */ + values, /* array of index Datums */ + isnull, /* is-null flags */ + &(heapTuple->t_self), /* tid of heap tuple */ + heapRelation, + index->rd_index->indisunique ? + UNIQUE_CHECK_YES : UNIQUE_CHECK_NO, + indexInfo); + } + + ExecDropSingleTupleTableSlot(slot); +} + +/* + * Subroutine to verify that catalog constraints are honored. + * + * Tuples inserted via CatalogTupleInsert/CatalogTupleUpdate are generally + * "hand made", so that it's possible that they fail to satisfy constraints + * that would be checked if they were being inserted by the executor. That's + * a coding error, so we only bother to check for it in assert-enabled builds. + */ +#ifdef USE_ASSERT_CHECKING + +static void +CatalogTupleCheckConstraints(Relation heapRel, HeapTuple tup) +{ + /* + * Currently, the only constraints implemented for system catalogs are + * attnotnull constraints. + */ + if (HeapTupleHasNulls(tup)) + { + TupleDesc tupdesc = RelationGetDescr(heapRel); + bits8 *bp = tup->t_data->t_bits; + + for (int attnum = 0; attnum < tupdesc->natts; attnum++) + { + Form_pg_attribute thisatt = TupleDescAttr(tupdesc, attnum); + + Assert(!(thisatt->attnotnull && att_isnull(attnum, bp))); + } + } +} + +#else /* !USE_ASSERT_CHECKING */ + +#define CatalogTupleCheckConstraints(heapRel, tup) ((void) 0) + +#endif /* USE_ASSERT_CHECKING */ + +/* + * CatalogTupleInsert - do heap and indexing work for a new catalog tuple + * + * Insert the tuple data in "tup" into the specified catalog relation. + * The Oid of the inserted tuple is returned. + * + * This is a convenience routine for the common case of inserting a single + * tuple in a system catalog; it inserts a new heap tuple, keeping indexes + * current. Avoid using it for multiple tuples, since opening the indexes + * and building the index info structures is moderately expensive. + * (Use CatalogTupleInsertWithInfo in such cases.) + */ +void +CatalogTupleInsert(Relation heapRel, HeapTuple tup) +{ + CatalogIndexState indstate; + + CatalogTupleCheckConstraints(heapRel, tup); + + indstate = CatalogOpenIndexes(heapRel); + + simple_heap_insert(heapRel, tup); + + CatalogIndexInsert(indstate, tup); + CatalogCloseIndexes(indstate); +} + +/* + * CatalogTupleInsertWithInfo - as above, but with caller-supplied index info + * + * This should be used when it's important to amortize CatalogOpenIndexes/ + * CatalogCloseIndexes work across multiple insertions. At some point we + * might cache the CatalogIndexState data somewhere (perhaps in the relcache) + * so that callers needn't trouble over this ... but we don't do so today. + */ +void +CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup, + CatalogIndexState indstate) +{ + CatalogTupleCheckConstraints(heapRel, tup); + + simple_heap_insert(heapRel, tup); + + CatalogIndexInsert(indstate, tup); +} + +/* + * CatalogTupleUpdate - do heap and indexing work for updating a catalog tuple + * + * Update the tuple identified by "otid", replacing it with the data in "tup". + * + * This is a convenience routine for the common case of updating a single + * tuple in a system catalog; it updates one heap tuple, keeping indexes + * current. Avoid using it for multiple tuples, since opening the indexes + * and building the index info structures is moderately expensive. + * (Use CatalogTupleUpdateWithInfo in such cases.) + */ +void +CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup) +{ + CatalogIndexState indstate; + + CatalogTupleCheckConstraints(heapRel, tup); + + indstate = CatalogOpenIndexes(heapRel); + + simple_heap_update(heapRel, otid, tup); + + CatalogIndexInsert(indstate, tup); + CatalogCloseIndexes(indstate); +} + +/* + * CatalogTupleUpdateWithInfo - as above, but with caller-supplied index info + * + * This should be used when it's important to amortize CatalogOpenIndexes/ + * CatalogCloseIndexes work across multiple updates. At some point we + * might cache the CatalogIndexState data somewhere (perhaps in the relcache) + * so that callers needn't trouble over this ... but we don't do so today. + */ +void +CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup, + CatalogIndexState indstate) +{ + CatalogTupleCheckConstraints(heapRel, tup); + + simple_heap_update(heapRel, otid, tup); + + CatalogIndexInsert(indstate, tup); +} + +/* + * CatalogTupleDelete - do heap and indexing work for deleting a catalog tuple + * + * Delete the tuple identified by "tid" in the specified catalog. + * + * With Postgres heaps, there is no index work to do at deletion time; + * cleanup will be done later by VACUUM. However, callers of this function + * shouldn't have to know that; we'd like a uniform abstraction for all + * catalog tuple changes. Hence, provide this currently-trivial wrapper. + * + * The abstraction is a bit leaky in that we don't provide an optimized + * CatalogTupleDeleteWithInfo version, because there is currently nothing to + * optimize. If we ever need that, rather than touching a lot of call sites, + * it might be better to do something about caching CatalogIndexState. + */ +void +CatalogTupleDelete(Relation heapRel, ItemPointer tid) +{ + simple_heap_delete(heapRel, tid); +} diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql new file mode 100644 index 0000000..3e07fb1 --- /dev/null +++ b/src/backend/catalog/information_schema.sql @@ -0,0 +1,2937 @@ +/* + * SQL Information Schema + * as defined in ISO/IEC 9075-11:2016 + * + * Copyright (c) 2003-2020, PostgreSQL Global Development Group + * + * src/backend/catalog/information_schema.sql + * + * Note: this file is read in single-user -j mode, which means that the + * command terminator is semicolon-newline-newline; whenever the backend + * sees that, it stops and executes what it's got. If you write a lot of + * statements without empty lines between, they'll all get quoted to you + * in any error message about one of them, so don't do that. Also, you + * cannot write a semicolon immediately followed by an empty line in a + * string literal (including a function body!) or a multiline comment. + */ + +/* + * Note: Generally, the definitions in this file should be ordered + * according to the clause numbers in the SQL standard, which is also the + * alphabetical order. In some cases it is convenient or necessary to + * define one information schema view by using another one; in that case, + * put the referencing view at the very end and leave a note where it + * should have been put. + */ + + +/* + * 5.1 + * INFORMATION_SCHEMA schema + */ + +CREATE SCHEMA information_schema; +GRANT USAGE ON SCHEMA information_schema TO PUBLIC; +SET search_path TO information_schema; + + +/* + * A few supporting functions first ... + */ + +/* Expand any 1-D array into a set with integers 1..N */ +CREATE FUNCTION _pg_expandarray(IN anyarray, OUT x anyelement, OUT n int) + RETURNS SETOF RECORD + LANGUAGE sql STRICT IMMUTABLE PARALLEL SAFE + AS 'select $1[s], s - pg_catalog.array_lower($1,1) + 1 + from pg_catalog.generate_series(pg_catalog.array_lower($1,1), + pg_catalog.array_upper($1,1), + 1) as g(s)'; + +/* Given an index's OID and an underlying-table column number, return the + * column's position in the index (NULL if not there) */ +CREATE FUNCTION _pg_index_position(oid, smallint) RETURNS int + LANGUAGE sql STRICT STABLE + AS $$ +SELECT (ss.a).n FROM + (SELECT information_schema._pg_expandarray(indkey) AS a + FROM pg_catalog.pg_index WHERE indexrelid = $1) ss + WHERE (ss.a).x = $2; +$$; + +CREATE FUNCTION _pg_truetypid(pg_attribute, pg_type) RETURNS oid + LANGUAGE sql + IMMUTABLE + PARALLEL SAFE + RETURNS NULL ON NULL INPUT + AS +$$SELECT CASE WHEN $2.typtype = 'd' THEN $2.typbasetype ELSE $1.atttypid END$$; + +CREATE FUNCTION _pg_truetypmod(pg_attribute, pg_type) RETURNS int4 + LANGUAGE sql + IMMUTABLE + PARALLEL SAFE + RETURNS NULL ON NULL INPUT + AS +$$SELECT CASE WHEN $2.typtype = 'd' THEN $2.typtypmod ELSE $1.atttypmod END$$; + +-- these functions encapsulate knowledge about the encoding of typmod: + +CREATE FUNCTION _pg_char_max_length(typid oid, typmod int4) RETURNS integer + LANGUAGE sql + IMMUTABLE + PARALLEL SAFE + RETURNS NULL ON NULL INPUT + AS +$$SELECT + CASE WHEN $2 = -1 /* default typmod */ + THEN null + WHEN $1 IN (1042, 1043) /* char, varchar */ + THEN $2 - 4 + WHEN $1 IN (1560, 1562) /* bit, varbit */ + THEN $2 + ELSE null + END$$; + +CREATE FUNCTION _pg_char_octet_length(typid oid, typmod int4) RETURNS integer + LANGUAGE sql + IMMUTABLE + PARALLEL SAFE + RETURNS NULL ON NULL INPUT + AS +$$SELECT + CASE WHEN $1 IN (25, 1042, 1043) /* text, char, varchar */ + THEN CASE WHEN $2 = -1 /* default typmod */ + THEN CAST(2^30 AS integer) + ELSE information_schema._pg_char_max_length($1, $2) * + pg_catalog.pg_encoding_max_length((SELECT encoding FROM pg_catalog.pg_database WHERE datname = pg_catalog.current_database())) + END + ELSE null + END$$; + +CREATE FUNCTION _pg_numeric_precision(typid oid, typmod int4) RETURNS integer + LANGUAGE sql + IMMUTABLE + PARALLEL SAFE + RETURNS NULL ON NULL INPUT + AS +$$SELECT + CASE $1 + WHEN 21 /*int2*/ THEN 16 + WHEN 23 /*int4*/ THEN 32 + WHEN 20 /*int8*/ THEN 64 + WHEN 1700 /*numeric*/ THEN + CASE WHEN $2 = -1 + THEN null + ELSE (($2 - 4) >> 16) & 65535 + END + WHEN 700 /*float4*/ THEN 24 /*FLT_MANT_DIG*/ + WHEN 701 /*float8*/ THEN 53 /*DBL_MANT_DIG*/ + ELSE null + END$$; + +CREATE FUNCTION _pg_numeric_precision_radix(typid oid, typmod int4) RETURNS integer + LANGUAGE sql + IMMUTABLE + PARALLEL SAFE + RETURNS NULL ON NULL INPUT + AS +$$SELECT + CASE WHEN $1 IN (21, 23, 20, 700, 701) THEN 2 + WHEN $1 IN (1700) THEN 10 + ELSE null + END$$; + +CREATE FUNCTION _pg_numeric_scale(typid oid, typmod int4) RETURNS integer + LANGUAGE sql + IMMUTABLE + PARALLEL SAFE + RETURNS NULL ON NULL INPUT + AS +$$SELECT + CASE WHEN $1 IN (21, 23, 20) THEN 0 + WHEN $1 IN (1700) THEN + CASE WHEN $2 = -1 + THEN null + ELSE ($2 - 4) & 65535 + END + ELSE null + END$$; + +CREATE FUNCTION _pg_datetime_precision(typid oid, typmod int4) RETURNS integer + LANGUAGE sql + IMMUTABLE + PARALLEL SAFE + RETURNS NULL ON NULL INPUT + AS +$$SELECT + CASE WHEN $1 IN (1082) /* date */ + THEN 0 + WHEN $1 IN (1083, 1114, 1184, 1266) /* time, timestamp, same + tz */ + THEN CASE WHEN $2 < 0 THEN 6 ELSE $2 END + WHEN $1 IN (1186) /* interval */ + THEN CASE WHEN $2 < 0 OR $2 & 65535 = 65535 THEN 6 ELSE $2 & 65535 END + ELSE null + END$$; + +CREATE FUNCTION _pg_interval_type(typid oid, mod int4) RETURNS text + LANGUAGE sql + IMMUTABLE + PARALLEL SAFE + RETURNS NULL ON NULL INPUT + AS +$$SELECT + CASE WHEN $1 IN (1186) /* interval */ + THEN pg_catalog.upper(substring(pg_catalog.format_type($1, $2) from 'interval[()0-9]* #"%#"' for '#')) + ELSE null + END$$; + + +-- 5.2 INFORMATION_SCHEMA_CATALOG_NAME view appears later. + + +/* + * 5.3 + * CARDINAL_NUMBER domain + */ + +CREATE DOMAIN cardinal_number AS integer + CONSTRAINT cardinal_number_domain_check CHECK (value >= 0); + + +/* + * 5.4 + * CHARACTER_DATA domain + */ + +CREATE DOMAIN character_data AS character varying COLLATE "C"; + + +/* + * 5.5 + * SQL_IDENTIFIER domain + */ + +CREATE DOMAIN sql_identifier AS name; + + +/* + * 5.2 + * INFORMATION_SCHEMA_CATALOG_NAME view + */ + +CREATE VIEW information_schema_catalog_name AS + SELECT CAST(current_database() AS sql_identifier) AS catalog_name; + +GRANT SELECT ON information_schema_catalog_name TO PUBLIC; + + +/* + * 5.6 + * TIME_STAMP domain + */ + +CREATE DOMAIN time_stamp AS timestamp(2) with time zone + DEFAULT current_timestamp(2); + +/* + * 5.7 + * YES_OR_NO domain + */ + +CREATE DOMAIN yes_or_no AS character varying(3) COLLATE "C" + CONSTRAINT yes_or_no_check CHECK (value IN ('YES', 'NO')); + + +-- 5.8 ADMINISTRABLE_ROLE_AUTHORIZATIONS view appears later. + + +/* + * 5.9 + * APPLICABLE_ROLES view + */ + +CREATE VIEW applicable_roles AS + SELECT CAST(a.rolname AS sql_identifier) AS grantee, + CAST(b.rolname AS sql_identifier) AS role_name, + CAST(CASE WHEN m.admin_option THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable + FROM pg_auth_members m + JOIN pg_authid a ON (m.member = a.oid) + JOIN pg_authid b ON (m.roleid = b.oid) + WHERE pg_has_role(a.oid, 'USAGE'); + +GRANT SELECT ON applicable_roles TO PUBLIC; + + +/* + * 5.8 + * ADMINISTRABLE_ROLE_AUTHORIZATIONS view + */ + +CREATE VIEW administrable_role_authorizations AS + SELECT * + FROM applicable_roles + WHERE is_grantable = 'YES'; + +GRANT SELECT ON administrable_role_authorizations TO PUBLIC; + + +/* + * 5.10 + * ASSERTIONS view + */ + +-- feature not supported + + +/* + * 5.11 + * ATTRIBUTES view + */ + +CREATE VIEW attributes AS + SELECT CAST(current_database() AS sql_identifier) AS udt_catalog, + CAST(nc.nspname AS sql_identifier) AS udt_schema, + CAST(c.relname AS sql_identifier) AS udt_name, + CAST(a.attname AS sql_identifier) AS attribute_name, + CAST(a.attnum AS cardinal_number) AS ordinal_position, + CAST(pg_get_expr(ad.adbin, ad.adrelid) AS character_data) AS attribute_default, + CAST(CASE WHEN a.attnotnull OR (t.typtype = 'd' AND t.typnotnull) THEN 'NO' ELSE 'YES' END + AS yes_or_no) + AS is_nullable, -- This column was apparently removed between SQL:2003 and SQL:2008. + + CAST( + CASE WHEN t.typelem <> 0 AND t.typlen = -1 THEN 'ARRAY' + WHEN nt.nspname = 'pg_catalog' THEN format_type(a.atttypid, null) + ELSE 'USER-DEFINED' END + AS character_data) + AS data_type, + + CAST( + _pg_char_max_length(_pg_truetypid(a, t), _pg_truetypmod(a, t)) + AS cardinal_number) + AS character_maximum_length, + + CAST( + _pg_char_octet_length(_pg_truetypid(a, t), _pg_truetypmod(a, t)) + AS cardinal_number) + AS character_octet_length, + + CAST(null AS sql_identifier) AS character_set_catalog, + CAST(null AS sql_identifier) AS character_set_schema, + CAST(null AS sql_identifier) AS character_set_name, + + CAST(CASE WHEN nco.nspname IS NOT NULL THEN current_database() END AS sql_identifier) AS collation_catalog, + CAST(nco.nspname AS sql_identifier) AS collation_schema, + CAST(co.collname AS sql_identifier) AS collation_name, + + CAST( + _pg_numeric_precision(_pg_truetypid(a, t), _pg_truetypmod(a, t)) + AS cardinal_number) + AS numeric_precision, + + CAST( + _pg_numeric_precision_radix(_pg_truetypid(a, t), _pg_truetypmod(a, t)) + AS cardinal_number) + AS numeric_precision_radix, + + CAST( + _pg_numeric_scale(_pg_truetypid(a, t), _pg_truetypmod(a, t)) + AS cardinal_number) + AS numeric_scale, + + CAST( + _pg_datetime_precision(_pg_truetypid(a, t), _pg_truetypmod(a, t)) + AS cardinal_number) + AS datetime_precision, + + CAST( + _pg_interval_type(_pg_truetypid(a, t), _pg_truetypmod(a, t)) + AS character_data) + AS interval_type, + CAST(null AS cardinal_number) AS interval_precision, + + CAST(current_database() AS sql_identifier) AS attribute_udt_catalog, + CAST(nt.nspname AS sql_identifier) AS attribute_udt_schema, + CAST(t.typname AS sql_identifier) AS attribute_udt_name, + + CAST(null AS sql_identifier) AS scope_catalog, + CAST(null AS sql_identifier) AS scope_schema, + CAST(null AS sql_identifier) AS scope_name, + + CAST(null AS cardinal_number) AS maximum_cardinality, + CAST(a.attnum AS sql_identifier) AS dtd_identifier, + CAST('NO' AS yes_or_no) AS is_derived_reference_attribute + + FROM (pg_attribute a LEFT JOIN pg_attrdef ad ON attrelid = adrelid AND attnum = adnum) + JOIN (pg_class c JOIN pg_namespace nc ON (c.relnamespace = nc.oid)) ON a.attrelid = c.oid + JOIN (pg_type t JOIN pg_namespace nt ON (t.typnamespace = nt.oid)) ON a.atttypid = t.oid + LEFT JOIN (pg_collation co JOIN pg_namespace nco ON (co.collnamespace = nco.oid)) + ON a.attcollation = co.oid AND (nco.nspname, co.collname) <> ('pg_catalog', 'default') + + WHERE a.attnum > 0 AND NOT a.attisdropped + AND c.relkind IN ('c') + AND (pg_has_role(c.relowner, 'USAGE') + OR has_type_privilege(c.reltype, 'USAGE')); + +GRANT SELECT ON attributes TO PUBLIC; + + +/* + * 5.12 + * CHARACTER_SETS view + */ + +CREATE VIEW character_sets AS + SELECT CAST(null AS sql_identifier) AS character_set_catalog, + CAST(null AS sql_identifier) AS character_set_schema, + CAST(getdatabaseencoding() AS sql_identifier) AS character_set_name, + CAST(CASE WHEN getdatabaseencoding() = 'UTF8' THEN 'UCS' ELSE getdatabaseencoding() END AS sql_identifier) AS character_repertoire, + CAST(getdatabaseencoding() AS sql_identifier) AS form_of_use, + CAST(current_database() AS sql_identifier) AS default_collate_catalog, + CAST(nc.nspname AS sql_identifier) AS default_collate_schema, + CAST(c.collname AS sql_identifier) AS default_collate_name + FROM pg_database d + LEFT JOIN (pg_collation c JOIN pg_namespace nc ON (c.collnamespace = nc.oid)) + ON (datcollate = collcollate AND datctype = collctype) + WHERE d.datname = current_database() + ORDER BY char_length(c.collname) DESC, c.collname ASC -- prefer full/canonical name + LIMIT 1; + +GRANT SELECT ON character_sets TO PUBLIC; + + +/* + * 5.13 + * CHECK_CONSTRAINT_ROUTINE_USAGE view + */ + +CREATE VIEW check_constraint_routine_usage AS + SELECT CAST(current_database() AS sql_identifier) AS constraint_catalog, + CAST(nc.nspname AS sql_identifier) AS constraint_schema, + CAST(c.conname AS sql_identifier) AS constraint_name, + CAST(current_database() AS sql_identifier) AS specific_catalog, + CAST(np.nspname AS sql_identifier) AS specific_schema, + CAST(nameconcatoid(p.proname, p.oid) AS sql_identifier) AS specific_name + FROM pg_namespace nc, pg_constraint c, pg_depend d, pg_proc p, pg_namespace np + WHERE nc.oid = c.connamespace + AND c.contype = 'c' + AND c.oid = d.objid + AND d.classid = 'pg_catalog.pg_constraint'::regclass + AND d.refobjid = p.oid + AND d.refclassid = 'pg_catalog.pg_proc'::regclass + AND p.pronamespace = np.oid + AND pg_has_role(p.proowner, 'USAGE'); + +GRANT SELECT ON check_constraint_routine_usage TO PUBLIC; + + +/* + * 5.14 + * CHECK_CONSTRAINTS view + */ + +CREATE VIEW check_constraints AS + SELECT CAST(current_database() AS sql_identifier) AS constraint_catalog, + CAST(rs.nspname AS sql_identifier) AS constraint_schema, + CAST(con.conname AS sql_identifier) AS constraint_name, + CAST(substring(pg_get_constraintdef(con.oid) from 7) AS character_data) + AS check_clause + FROM pg_constraint con + LEFT OUTER JOIN pg_namespace rs ON (rs.oid = con.connamespace) + LEFT OUTER JOIN pg_class c ON (c.oid = con.conrelid) + LEFT OUTER JOIN pg_type t ON (t.oid = con.contypid) + WHERE pg_has_role(coalesce(c.relowner, t.typowner), 'USAGE') + AND con.contype = 'c' + + UNION + -- not-null constraints + + SELECT CAST(current_database() AS sql_identifier) AS constraint_catalog, + CAST(n.nspname AS sql_identifier) AS constraint_schema, + CAST(CAST(n.oid AS text) || '_' || CAST(r.oid AS text) || '_' || CAST(a.attnum AS text) || '_not_null' AS sql_identifier) AS constraint_name, -- XXX + CAST(a.attname || ' IS NOT NULL' AS character_data) + AS check_clause + FROM pg_namespace n, pg_class r, pg_attribute a + WHERE n.oid = r.relnamespace + AND r.oid = a.attrelid + AND a.attnum > 0 + AND NOT a.attisdropped + AND a.attnotnull + AND r.relkind IN ('r', 'p') + AND pg_has_role(r.relowner, 'USAGE'); + +GRANT SELECT ON check_constraints TO PUBLIC; + + +/* + * 5.15 + * COLLATIONS view + */ + +CREATE VIEW collations AS + SELECT CAST(current_database() AS sql_identifier) AS collation_catalog, + CAST(nc.nspname AS sql_identifier) AS collation_schema, + CAST(c.collname AS sql_identifier) AS collation_name, + CAST('NO PAD' AS character_data) AS pad_attribute + FROM pg_collation c, pg_namespace nc + WHERE c.collnamespace = nc.oid + AND collencoding IN (-1, (SELECT encoding FROM pg_database WHERE datname = current_database())); + +GRANT SELECT ON collations TO PUBLIC; + + +/* + * 5.16 + * COLLATION_CHARACTER_SET_APPLICABILITY view + */ + +CREATE VIEW collation_character_set_applicability AS + SELECT CAST(current_database() AS sql_identifier) AS collation_catalog, + CAST(nc.nspname AS sql_identifier) AS collation_schema, + CAST(c.collname AS sql_identifier) AS collation_name, + CAST(null AS sql_identifier) AS character_set_catalog, + CAST(null AS sql_identifier) AS character_set_schema, + CAST(getdatabaseencoding() AS sql_identifier) AS character_set_name + FROM pg_collation c, pg_namespace nc + WHERE c.collnamespace = nc.oid + AND collencoding IN (-1, (SELECT encoding FROM pg_database WHERE datname = current_database())); + +GRANT SELECT ON collation_character_set_applicability TO PUBLIC; + + +/* + * 5.17 + * COLUMN_COLUMN_USAGE view + */ + +CREATE VIEW column_column_usage AS + SELECT CAST(current_database() AS sql_identifier) AS table_catalog, + CAST(n.nspname AS sql_identifier) AS table_schema, + CAST(c.relname AS sql_identifier) AS table_name, + CAST(ac.attname AS sql_identifier) AS column_name, + CAST(ad.attname AS sql_identifier) AS dependent_column + + FROM pg_namespace n, pg_class c, pg_depend d, + pg_attribute ac, pg_attribute ad + + WHERE n.oid = c.relnamespace + AND c.oid = ac.attrelid + AND c.oid = ad.attrelid + AND d.classid = 'pg_catalog.pg_class'::regclass + AND d.refclassid = 'pg_catalog.pg_class'::regclass + AND d.objid = d.refobjid + AND c.oid = d.objid + AND d.objsubid = ad.attnum + AND d.refobjsubid = ac.attnum + AND ad.attgenerated <> '' + AND pg_has_role(c.relowner, 'USAGE'); + +GRANT SELECT ON column_column_usage TO PUBLIC; + + +/* + * 5.18 + * COLUMN_DOMAIN_USAGE view + */ + +CREATE VIEW column_domain_usage AS + SELECT CAST(current_database() AS sql_identifier) AS domain_catalog, + CAST(nt.nspname AS sql_identifier) AS domain_schema, + CAST(t.typname AS sql_identifier) AS domain_name, + CAST(current_database() AS sql_identifier) AS table_catalog, + CAST(nc.nspname AS sql_identifier) AS table_schema, + CAST(c.relname AS sql_identifier) AS table_name, + CAST(a.attname AS sql_identifier) AS column_name + + FROM pg_type t, pg_namespace nt, pg_class c, pg_namespace nc, + pg_attribute a + + WHERE t.typnamespace = nt.oid + AND c.relnamespace = nc.oid + AND a.attrelid = c.oid + AND a.atttypid = t.oid + AND t.typtype = 'd' + AND c.relkind IN ('r', 'v', 'f', 'p') + AND a.attnum > 0 + AND NOT a.attisdropped + AND pg_has_role(t.typowner, 'USAGE'); + +GRANT SELECT ON column_domain_usage TO PUBLIC; + + +/* + * 5.19 + * COLUMN_PRIVILEGES + */ + +CREATE VIEW column_privileges AS + SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor, + CAST(grantee.rolname AS sql_identifier) AS grantee, + CAST(current_database() AS sql_identifier) AS table_catalog, + CAST(nc.nspname AS sql_identifier) AS table_schema, + CAST(x.relname AS sql_identifier) AS table_name, + CAST(x.attname AS sql_identifier) AS column_name, + CAST(x.prtype AS character_data) AS privilege_type, + CAST( + CASE WHEN + -- object owner always has grant options + pg_has_role(x.grantee, x.relowner, 'USAGE') + OR x.grantable + THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable + + FROM ( + SELECT pr_c.grantor, + pr_c.grantee, + attname, + relname, + relnamespace, + pr_c.prtype, + pr_c.grantable, + pr_c.relowner + FROM (SELECT oid, relname, relnamespace, relowner, (aclexplode(coalesce(relacl, acldefault('r', relowner)))).* + FROM pg_class + WHERE relkind IN ('r', 'v', 'f', 'p') + ) pr_c (oid, relname, relnamespace, relowner, grantor, grantee, prtype, grantable), + pg_attribute a + WHERE a.attrelid = pr_c.oid + AND a.attnum > 0 + AND NOT a.attisdropped + UNION + SELECT pr_a.grantor, + pr_a.grantee, + attname, + relname, + relnamespace, + pr_a.prtype, + pr_a.grantable, + c.relowner + FROM (SELECT attrelid, attname, (aclexplode(coalesce(attacl, acldefault('c', relowner)))).* + FROM pg_attribute a JOIN pg_class cc ON (a.attrelid = cc.oid) + WHERE attnum > 0 + AND NOT attisdropped + ) pr_a (attrelid, attname, grantor, grantee, prtype, grantable), + pg_class c + WHERE pr_a.attrelid = c.oid + AND relkind IN ('r', 'v', 'f', 'p') + ) x, + pg_namespace nc, + pg_authid u_grantor, + ( + SELECT oid, rolname FROM pg_authid + UNION ALL + SELECT 0::oid, 'PUBLIC' + ) AS grantee (oid, rolname) + + WHERE x.relnamespace = nc.oid + AND x.grantee = grantee.oid + AND x.grantor = u_grantor.oid + AND x.prtype IN ('INSERT', 'SELECT', 'UPDATE', 'REFERENCES') + AND (pg_has_role(u_grantor.oid, 'USAGE') + OR pg_has_role(grantee.oid, 'USAGE') + OR grantee.rolname = 'PUBLIC'); + +GRANT SELECT ON column_privileges TO PUBLIC; + + +/* + * 5.20 + * COLUMN_UDT_USAGE view + */ + +CREATE VIEW column_udt_usage AS + SELECT CAST(current_database() AS sql_identifier) AS udt_catalog, + CAST(coalesce(nbt.nspname, nt.nspname) AS sql_identifier) AS udt_schema, + CAST(coalesce(bt.typname, t.typname) AS sql_identifier) AS udt_name, + CAST(current_database() AS sql_identifier) AS table_catalog, + CAST(nc.nspname AS sql_identifier) AS table_schema, + CAST(c.relname AS sql_identifier) AS table_name, + CAST(a.attname AS sql_identifier) AS column_name + + FROM pg_attribute a, pg_class c, pg_namespace nc, + (pg_type t JOIN pg_namespace nt ON (t.typnamespace = nt.oid)) + LEFT JOIN (pg_type bt JOIN pg_namespace nbt ON (bt.typnamespace = nbt.oid)) + ON (t.typtype = 'd' AND t.typbasetype = bt.oid) + + WHERE a.attrelid = c.oid + AND a.atttypid = t.oid + AND nc.oid = c.relnamespace + AND a.attnum > 0 AND NOT a.attisdropped + AND c.relkind in ('r', 'v', 'f', 'p') + AND pg_has_role(coalesce(bt.typowner, t.typowner), 'USAGE'); + +GRANT SELECT ON column_udt_usage TO PUBLIC; + + +/* + * 5.21 + * COLUMNS view + */ + +CREATE VIEW columns AS + SELECT CAST(current_database() AS sql_identifier) AS table_catalog, + CAST(nc.nspname AS sql_identifier) AS table_schema, + CAST(c.relname AS sql_identifier) AS table_name, + CAST(a.attname AS sql_identifier) AS column_name, + CAST(a.attnum AS cardinal_number) AS ordinal_position, + CAST(CASE WHEN a.attgenerated = '' THEN pg_get_expr(ad.adbin, ad.adrelid) END AS character_data) AS column_default, + CAST(CASE WHEN a.attnotnull OR (t.typtype = 'd' AND t.typnotnull) THEN 'NO' ELSE 'YES' END + AS yes_or_no) + AS is_nullable, + + CAST( + CASE WHEN t.typtype = 'd' THEN + CASE WHEN bt.typelem <> 0 AND bt.typlen = -1 THEN 'ARRAY' + WHEN nbt.nspname = 'pg_catalog' THEN format_type(t.typbasetype, null) + ELSE 'USER-DEFINED' END + ELSE + CASE WHEN t.typelem <> 0 AND t.typlen = -1 THEN 'ARRAY' + WHEN nt.nspname = 'pg_catalog' THEN format_type(a.atttypid, null) + ELSE 'USER-DEFINED' END + END + AS character_data) + AS data_type, + + CAST( + _pg_char_max_length(_pg_truetypid(a, t), _pg_truetypmod(a, t)) + AS cardinal_number) + AS character_maximum_length, + + CAST( + _pg_char_octet_length(_pg_truetypid(a, t), _pg_truetypmod(a, t)) + AS cardinal_number) + AS character_octet_length, + + CAST( + _pg_numeric_precision(_pg_truetypid(a, t), _pg_truetypmod(a, t)) + AS cardinal_number) + AS numeric_precision, + + CAST( + _pg_numeric_precision_radix(_pg_truetypid(a, t), _pg_truetypmod(a, t)) + AS cardinal_number) + AS numeric_precision_radix, + + CAST( + _pg_numeric_scale(_pg_truetypid(a, t), _pg_truetypmod(a, t)) + AS cardinal_number) + AS numeric_scale, + + CAST( + _pg_datetime_precision(_pg_truetypid(a, t), _pg_truetypmod(a, t)) + AS cardinal_number) + AS datetime_precision, + + CAST( + _pg_interval_type(_pg_truetypid(a, t), _pg_truetypmod(a, t)) + AS character_data) + AS interval_type, + CAST(null AS cardinal_number) AS interval_precision, + + CAST(null AS sql_identifier) AS character_set_catalog, + CAST(null AS sql_identifier) AS character_set_schema, + CAST(null AS sql_identifier) AS character_set_name, + + CAST(CASE WHEN nco.nspname IS NOT NULL THEN current_database() END AS sql_identifier) AS collation_catalog, + CAST(nco.nspname AS sql_identifier) AS collation_schema, + CAST(co.collname AS sql_identifier) AS collation_name, + + CAST(CASE WHEN t.typtype = 'd' THEN current_database() ELSE null END + AS sql_identifier) AS domain_catalog, + CAST(CASE WHEN t.typtype = 'd' THEN nt.nspname ELSE null END + AS sql_identifier) AS domain_schema, + CAST(CASE WHEN t.typtype = 'd' THEN t.typname ELSE null END + AS sql_identifier) AS domain_name, + + CAST(current_database() AS sql_identifier) AS udt_catalog, + CAST(coalesce(nbt.nspname, nt.nspname) AS sql_identifier) AS udt_schema, + CAST(coalesce(bt.typname, t.typname) AS sql_identifier) AS udt_name, + + CAST(null AS sql_identifier) AS scope_catalog, + CAST(null AS sql_identifier) AS scope_schema, + CAST(null AS sql_identifier) AS scope_name, + + CAST(null AS cardinal_number) AS maximum_cardinality, + CAST(a.attnum AS sql_identifier) AS dtd_identifier, + CAST('NO' AS yes_or_no) AS is_self_referencing, + + CAST(CASE WHEN a.attidentity IN ('a', 'd') THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_identity, + CAST(CASE a.attidentity WHEN 'a' THEN 'ALWAYS' WHEN 'd' THEN 'BY DEFAULT' END AS character_data) AS identity_generation, + CAST(seq.seqstart AS character_data) AS identity_start, + CAST(seq.seqincrement AS character_data) AS identity_increment, + CAST(seq.seqmax AS character_data) AS identity_maximum, + CAST(seq.seqmin AS character_data) AS identity_minimum, + CAST(CASE WHEN seq.seqcycle THEN 'YES' ELSE 'NO' END AS yes_or_no) AS identity_cycle, + + CAST(CASE WHEN a.attgenerated <> '' THEN 'ALWAYS' ELSE 'NEVER' END AS character_data) AS is_generated, + CAST(CASE WHEN a.attgenerated <> '' THEN pg_get_expr(ad.adbin, ad.adrelid) END AS character_data) AS generation_expression, + + CAST(CASE WHEN c.relkind IN ('r', 'p') OR + (c.relkind IN ('v', 'f') AND + pg_column_is_updatable(c.oid, a.attnum, false)) + THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_updatable + + FROM (pg_attribute a LEFT JOIN pg_attrdef ad ON attrelid = adrelid AND attnum = adnum) + JOIN (pg_class c JOIN pg_namespace nc ON (c.relnamespace = nc.oid)) ON a.attrelid = c.oid + JOIN (pg_type t JOIN pg_namespace nt ON (t.typnamespace = nt.oid)) ON a.atttypid = t.oid + LEFT JOIN (pg_type bt JOIN pg_namespace nbt ON (bt.typnamespace = nbt.oid)) + ON (t.typtype = 'd' AND t.typbasetype = bt.oid) + LEFT JOIN (pg_collation co JOIN pg_namespace nco ON (co.collnamespace = nco.oid)) + ON a.attcollation = co.oid AND (nco.nspname, co.collname) <> ('pg_catalog', 'default') + LEFT JOIN (pg_depend dep JOIN pg_sequence seq ON (dep.classid = 'pg_class'::regclass AND dep.objid = seq.seqrelid AND dep.deptype = 'i')) + ON (dep.refclassid = 'pg_class'::regclass AND dep.refobjid = c.oid AND dep.refobjsubid = a.attnum) + + WHERE (NOT pg_is_other_temp_schema(nc.oid)) + + AND a.attnum > 0 AND NOT a.attisdropped + AND c.relkind IN ('r', 'v', 'f', 'p') + + AND (pg_has_role(c.relowner, 'USAGE') + OR has_column_privilege(c.oid, a.attnum, + 'SELECT, INSERT, UPDATE, REFERENCES')); + +GRANT SELECT ON columns TO PUBLIC; + + +/* + * 5.22 + * CONSTRAINT_COLUMN_USAGE view + */ + +CREATE VIEW constraint_column_usage AS + SELECT CAST(current_database() AS sql_identifier) AS table_catalog, + CAST(tblschema AS sql_identifier) AS table_schema, + CAST(tblname AS sql_identifier) AS table_name, + CAST(colname AS sql_identifier) AS column_name, + CAST(current_database() AS sql_identifier) AS constraint_catalog, + CAST(cstrschema AS sql_identifier) AS constraint_schema, + CAST(cstrname AS sql_identifier) AS constraint_name + + FROM ( + /* check constraints */ + SELECT DISTINCT nr.nspname, r.relname, r.relowner, a.attname, nc.nspname, c.conname + FROM pg_namespace nr, pg_class r, pg_attribute a, pg_depend d, pg_namespace nc, pg_constraint c + WHERE nr.oid = r.relnamespace + AND r.oid = a.attrelid + AND d.refclassid = 'pg_catalog.pg_class'::regclass + AND d.refobjid = r.oid + AND d.refobjsubid = a.attnum + AND d.classid = 'pg_catalog.pg_constraint'::regclass + AND d.objid = c.oid + AND c.connamespace = nc.oid + AND c.contype = 'c' + AND r.relkind IN ('r', 'p') + AND NOT a.attisdropped + + UNION ALL + + /* unique/primary key/foreign key constraints */ + SELECT nr.nspname, r.relname, r.relowner, a.attname, nc.nspname, c.conname + FROM pg_namespace nr, pg_class r, pg_attribute a, pg_namespace nc, + pg_constraint c + WHERE nr.oid = r.relnamespace + AND r.oid = a.attrelid + AND nc.oid = c.connamespace + AND r.oid = CASE c.contype WHEN 'f' THEN c.confrelid ELSE c.conrelid END + AND a.attnum = ANY (CASE c.contype WHEN 'f' THEN c.confkey ELSE c.conkey END) + AND NOT a.attisdropped + AND c.contype IN ('p', 'u', 'f') + AND r.relkind IN ('r', 'p') + + ) AS x (tblschema, tblname, tblowner, colname, cstrschema, cstrname) + + WHERE pg_has_role(x.tblowner, 'USAGE'); + +GRANT SELECT ON constraint_column_usage TO PUBLIC; + + +/* + * 5.23 + * CONSTRAINT_PERIOD_USAGE view + */ + +-- feature not supported + + +/* + * 5.24 + * CONSTRAINT_TABLE_USAGE view + */ + +CREATE VIEW constraint_table_usage AS + SELECT CAST(current_database() AS sql_identifier) AS table_catalog, + CAST(nr.nspname AS sql_identifier) AS table_schema, + CAST(r.relname AS sql_identifier) AS table_name, + CAST(current_database() AS sql_identifier) AS constraint_catalog, + CAST(nc.nspname AS sql_identifier) AS constraint_schema, + CAST(c.conname AS sql_identifier) AS constraint_name + + FROM pg_constraint c, pg_namespace nc, + pg_class r, pg_namespace nr + + WHERE c.connamespace = nc.oid AND r.relnamespace = nr.oid + AND ( (c.contype = 'f' AND c.confrelid = r.oid) + OR (c.contype IN ('p', 'u') AND c.conrelid = r.oid) ) + AND r.relkind IN ('r', 'p') + AND pg_has_role(r.relowner, 'USAGE'); + +GRANT SELECT ON constraint_table_usage TO PUBLIC; + + +-- 5.25 DATA_TYPE_PRIVILEGES view appears later. + + +/* + * 5.26 + * DIRECT_SUPERTABLES view + */ + +-- feature not supported + + +/* + * 5.27 + * DIRECT_SUPERTYPES view + */ + +-- feature not supported + + +/* + * 5.28 + * DOMAIN_CONSTRAINTS view + */ + +CREATE VIEW domain_constraints AS + SELECT CAST(current_database() AS sql_identifier) AS constraint_catalog, + CAST(rs.nspname AS sql_identifier) AS constraint_schema, + CAST(con.conname AS sql_identifier) AS constraint_name, + CAST(current_database() AS sql_identifier) AS domain_catalog, + CAST(n.nspname AS sql_identifier) AS domain_schema, + CAST(t.typname AS sql_identifier) AS domain_name, + CAST(CASE WHEN condeferrable THEN 'YES' ELSE 'NO' END + AS yes_or_no) AS is_deferrable, + CAST(CASE WHEN condeferred THEN 'YES' ELSE 'NO' END + AS yes_or_no) AS initially_deferred + FROM pg_namespace rs, pg_namespace n, pg_constraint con, pg_type t + WHERE rs.oid = con.connamespace + AND n.oid = t.typnamespace + AND t.oid = con.contypid + AND (pg_has_role(t.typowner, 'USAGE') + OR has_type_privilege(t.oid, 'USAGE')); + +GRANT SELECT ON domain_constraints TO PUBLIC; + + +/* + * DOMAIN_UDT_USAGE view + * apparently removed in SQL:2003 + */ + +CREATE VIEW domain_udt_usage AS + SELECT CAST(current_database() AS sql_identifier) AS udt_catalog, + CAST(nbt.nspname AS sql_identifier) AS udt_schema, + CAST(bt.typname AS sql_identifier) AS udt_name, + CAST(current_database() AS sql_identifier) AS domain_catalog, + CAST(nt.nspname AS sql_identifier) AS domain_schema, + CAST(t.typname AS sql_identifier) AS domain_name + + FROM pg_type t, pg_namespace nt, + pg_type bt, pg_namespace nbt + + WHERE t.typnamespace = nt.oid + AND t.typbasetype = bt.oid + AND bt.typnamespace = nbt.oid + AND t.typtype = 'd' + AND pg_has_role(bt.typowner, 'USAGE'); + +GRANT SELECT ON domain_udt_usage TO PUBLIC; + + +/* + * 5.29 + * DOMAINS view + */ + +CREATE VIEW domains AS + SELECT CAST(current_database() AS sql_identifier) AS domain_catalog, + CAST(nt.nspname AS sql_identifier) AS domain_schema, + CAST(t.typname AS sql_identifier) AS domain_name, + + CAST( + CASE WHEN t.typelem <> 0 AND t.typlen = -1 THEN 'ARRAY' + WHEN nbt.nspname = 'pg_catalog' THEN format_type(t.typbasetype, null) + ELSE 'USER-DEFINED' END + AS character_data) + AS data_type, + + CAST( + _pg_char_max_length(t.typbasetype, t.typtypmod) + AS cardinal_number) + AS character_maximum_length, + + CAST( + _pg_char_octet_length(t.typbasetype, t.typtypmod) + AS cardinal_number) + AS character_octet_length, + + CAST(null AS sql_identifier) AS character_set_catalog, + CAST(null AS sql_identifier) AS character_set_schema, + CAST(null AS sql_identifier) AS character_set_name, + + CAST(CASE WHEN nco.nspname IS NOT NULL THEN current_database() END AS sql_identifier) AS collation_catalog, + CAST(nco.nspname AS sql_identifier) AS collation_schema, + CAST(co.collname AS sql_identifier) AS collation_name, + + CAST( + _pg_numeric_precision(t.typbasetype, t.typtypmod) + AS cardinal_number) + AS numeric_precision, + + CAST( + _pg_numeric_precision_radix(t.typbasetype, t.typtypmod) + AS cardinal_number) + AS numeric_precision_radix, + + CAST( + _pg_numeric_scale(t.typbasetype, t.typtypmod) + AS cardinal_number) + AS numeric_scale, + + CAST( + _pg_datetime_precision(t.typbasetype, t.typtypmod) + AS cardinal_number) + AS datetime_precision, + + CAST( + _pg_interval_type(t.typbasetype, t.typtypmod) + AS character_data) + AS interval_type, + CAST(null AS cardinal_number) AS interval_precision, + + CAST(t.typdefault AS character_data) AS domain_default, + + CAST(current_database() AS sql_identifier) AS udt_catalog, + CAST(nbt.nspname AS sql_identifier) AS udt_schema, + CAST(bt.typname AS sql_identifier) AS udt_name, + + CAST(null AS sql_identifier) AS scope_catalog, + CAST(null AS sql_identifier) AS scope_schema, + CAST(null AS sql_identifier) AS scope_name, + + CAST(null AS cardinal_number) AS maximum_cardinality, + CAST(1 AS sql_identifier) AS dtd_identifier + + FROM (pg_type t JOIN pg_namespace nt ON t.typnamespace = nt.oid) + JOIN (pg_type bt JOIN pg_namespace nbt ON bt.typnamespace = nbt.oid) + ON (t.typbasetype = bt.oid AND t.typtype = 'd') + LEFT JOIN (pg_collation co JOIN pg_namespace nco ON (co.collnamespace = nco.oid)) + ON t.typcollation = co.oid AND (nco.nspname, co.collname) <> ('pg_catalog', 'default') + + WHERE (pg_has_role(t.typowner, 'USAGE') + OR has_type_privilege(t.oid, 'USAGE')); + +GRANT SELECT ON domains TO PUBLIC; + + +-- 5.30 ELEMENT_TYPES view appears later. + + +/* + * 5.31 + * ENABLED_ROLES view + */ + +CREATE VIEW enabled_roles AS + SELECT CAST(a.rolname AS sql_identifier) AS role_name + FROM pg_authid a + WHERE pg_has_role(a.oid, 'USAGE'); + +GRANT SELECT ON enabled_roles TO PUBLIC; + + +/* + * 5.32 + * FIELDS view + */ + +-- feature not supported + + +/* + * 5.33 + * KEY_COLUMN_USAGE view + */ + +CREATE VIEW key_column_usage AS + SELECT CAST(current_database() AS sql_identifier) AS constraint_catalog, + CAST(nc_nspname AS sql_identifier) AS constraint_schema, + CAST(conname AS sql_identifier) AS constraint_name, + CAST(current_database() AS sql_identifier) AS table_catalog, + CAST(nr_nspname AS sql_identifier) AS table_schema, + CAST(relname AS sql_identifier) AS table_name, + CAST(a.attname AS sql_identifier) AS column_name, + CAST((ss.x).n AS cardinal_number) AS ordinal_position, + CAST(CASE WHEN contype = 'f' THEN + _pg_index_position(ss.conindid, ss.confkey[(ss.x).n]) + ELSE NULL + END AS cardinal_number) + AS position_in_unique_constraint + FROM pg_attribute a, + (SELECT r.oid AS roid, r.relname, r.relowner, + nc.nspname AS nc_nspname, nr.nspname AS nr_nspname, + c.oid AS coid, c.conname, c.contype, c.conindid, + c.confkey, c.confrelid, + _pg_expandarray(c.conkey) AS x + FROM pg_namespace nr, pg_class r, pg_namespace nc, + pg_constraint c + WHERE nr.oid = r.relnamespace + AND r.oid = c.conrelid + AND nc.oid = c.connamespace + AND c.contype IN ('p', 'u', 'f') + AND r.relkind IN ('r', 'p') + AND (NOT pg_is_other_temp_schema(nr.oid)) ) AS ss + WHERE ss.roid = a.attrelid + AND a.attnum = (ss.x).x + AND NOT a.attisdropped + AND (pg_has_role(relowner, 'USAGE') + OR has_column_privilege(roid, a.attnum, + 'SELECT, INSERT, UPDATE, REFERENCES')); + +GRANT SELECT ON key_column_usage TO PUBLIC; + + +/* + * 5.34 + * KEY_PERIOD_USAGE view + */ + +-- feature not supported + + +/* + * 5.35 + * METHOD_SPECIFICATION_PARAMETERS view + */ + +-- feature not supported + + +/* + * 5.36 + * METHOD_SPECIFICATIONS view + */ + +-- feature not supported + + +/* + * 5.37 + * PARAMETERS view + */ + +CREATE VIEW parameters AS + SELECT CAST(current_database() AS sql_identifier) AS specific_catalog, + CAST(n_nspname AS sql_identifier) AS specific_schema, + CAST(nameconcatoid(proname, p_oid) AS sql_identifier) AS specific_name, + CAST((ss.x).n AS cardinal_number) AS ordinal_position, + CAST( + CASE WHEN proargmodes IS NULL THEN 'IN' + WHEN proargmodes[(ss.x).n] = 'i' THEN 'IN' + WHEN proargmodes[(ss.x).n] = 'o' THEN 'OUT' + WHEN proargmodes[(ss.x).n] = 'b' THEN 'INOUT' + WHEN proargmodes[(ss.x).n] = 'v' THEN 'IN' + WHEN proargmodes[(ss.x).n] = 't' THEN 'OUT' + END AS character_data) AS parameter_mode, + CAST('NO' AS yes_or_no) AS is_result, + CAST('NO' AS yes_or_no) AS as_locator, + CAST(NULLIF(proargnames[(ss.x).n], '') AS sql_identifier) AS parameter_name, + CAST( + CASE WHEN t.typelem <> 0 AND t.typlen = -1 THEN 'ARRAY' + WHEN nt.nspname = 'pg_catalog' THEN format_type(t.oid, null) + ELSE 'USER-DEFINED' END AS character_data) + AS data_type, + CAST(null AS cardinal_number) AS character_maximum_length, + CAST(null AS cardinal_number) AS character_octet_length, + CAST(null AS sql_identifier) AS character_set_catalog, + CAST(null AS sql_identifier) AS character_set_schema, + CAST(null AS sql_identifier) AS character_set_name, + CAST(null AS sql_identifier) AS collation_catalog, + CAST(null AS sql_identifier) AS collation_schema, + CAST(null AS sql_identifier) AS collation_name, + CAST(null AS cardinal_number) AS numeric_precision, + CAST(null AS cardinal_number) AS numeric_precision_radix, + CAST(null AS cardinal_number) AS numeric_scale, + CAST(null AS cardinal_number) AS datetime_precision, + CAST(null AS character_data) AS interval_type, + CAST(null AS cardinal_number) AS interval_precision, + CAST(current_database() AS sql_identifier) AS udt_catalog, + CAST(nt.nspname AS sql_identifier) AS udt_schema, + CAST(t.typname AS sql_identifier) AS udt_name, + CAST(null AS sql_identifier) AS scope_catalog, + CAST(null AS sql_identifier) AS scope_schema, + CAST(null AS sql_identifier) AS scope_name, + CAST(null AS cardinal_number) AS maximum_cardinality, + CAST((ss.x).n AS sql_identifier) AS dtd_identifier, + CAST( + CASE WHEN pg_has_role(proowner, 'USAGE') + THEN pg_get_function_arg_default(p_oid, (ss.x).n) + ELSE NULL END + AS character_data) AS parameter_default + + FROM pg_type t, pg_namespace nt, + (SELECT n.nspname AS n_nspname, p.proname, p.oid AS p_oid, p.proowner, + p.proargnames, p.proargmodes, + _pg_expandarray(coalesce(p.proallargtypes, p.proargtypes::oid[])) AS x + FROM pg_namespace n, pg_proc p + WHERE n.oid = p.pronamespace + AND (pg_has_role(p.proowner, 'USAGE') OR + has_function_privilege(p.oid, 'EXECUTE'))) AS ss + WHERE t.oid = (ss.x).x AND t.typnamespace = nt.oid; + +GRANT SELECT ON parameters TO PUBLIC; + + +/* + * 5.38 + * PERIODS view + */ + +-- feature not supported + + +/* + * 5.39 + * PRIVATE_PARAMETERS view + */ + +-- feature not supported + + +/* + * 5.40 + * REFERENCED_TYPES view + */ + +-- feature not supported + + +/* + * 5.41 + * REFERENTIAL_CONSTRAINTS view + */ + +CREATE VIEW referential_constraints AS + SELECT CAST(current_database() AS sql_identifier) AS constraint_catalog, + CAST(ncon.nspname AS sql_identifier) AS constraint_schema, + CAST(con.conname AS sql_identifier) AS constraint_name, + CAST( + CASE WHEN npkc.nspname IS NULL THEN NULL + ELSE current_database() END + AS sql_identifier) AS unique_constraint_catalog, + CAST(npkc.nspname AS sql_identifier) AS unique_constraint_schema, + CAST(pkc.conname AS sql_identifier) AS unique_constraint_name, + + CAST( + CASE con.confmatchtype WHEN 'f' THEN 'FULL' + WHEN 'p' THEN 'PARTIAL' + WHEN 's' THEN 'NONE' END + AS character_data) AS match_option, + + CAST( + CASE con.confupdtype WHEN 'c' THEN 'CASCADE' + WHEN 'n' THEN 'SET NULL' + WHEN 'd' THEN 'SET DEFAULT' + WHEN 'r' THEN 'RESTRICT' + WHEN 'a' THEN 'NO ACTION' END + AS character_data) AS update_rule, + + CAST( + CASE con.confdeltype WHEN 'c' THEN 'CASCADE' + WHEN 'n' THEN 'SET NULL' + WHEN 'd' THEN 'SET DEFAULT' + WHEN 'r' THEN 'RESTRICT' + WHEN 'a' THEN 'NO ACTION' END + AS character_data) AS delete_rule + + FROM (pg_namespace ncon + INNER JOIN pg_constraint con ON ncon.oid = con.connamespace + INNER JOIN pg_class c ON con.conrelid = c.oid AND con.contype = 'f') + LEFT JOIN pg_depend d1 -- find constraint's dependency on an index + ON d1.objid = con.oid AND d1.classid = 'pg_constraint'::regclass + AND d1.refclassid = 'pg_class'::regclass AND d1.refobjsubid = 0 + LEFT JOIN pg_depend d2 -- find pkey/unique constraint for that index + ON d2.refclassid = 'pg_constraint'::regclass + AND d2.classid = 'pg_class'::regclass + AND d2.objid = d1.refobjid AND d2.objsubid = 0 + AND d2.deptype = 'i' + LEFT JOIN pg_constraint pkc ON pkc.oid = d2.refobjid + AND pkc.contype IN ('p', 'u') + AND pkc.conrelid = con.confrelid + LEFT JOIN pg_namespace npkc ON pkc.connamespace = npkc.oid + + WHERE pg_has_role(c.relowner, 'USAGE') + -- SELECT privilege omitted, per SQL standard + OR has_table_privilege(c.oid, 'INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER') + OR has_any_column_privilege(c.oid, 'INSERT, UPDATE, REFERENCES') ; + +GRANT SELECT ON referential_constraints TO PUBLIC; + + +/* + * 5.42 + * ROLE_COLUMN_GRANTS view + */ + +CREATE VIEW role_column_grants AS + SELECT grantor, + grantee, + table_catalog, + table_schema, + table_name, + column_name, + privilege_type, + is_grantable + FROM column_privileges + WHERE grantor IN (SELECT role_name FROM enabled_roles) + OR grantee IN (SELECT role_name FROM enabled_roles); + +GRANT SELECT ON role_column_grants TO PUBLIC; + + +-- 5.43 ROLE_ROUTINE_GRANTS view is based on 5.50 ROUTINE_PRIVILEGES and is defined there instead. + + +-- 5.44 ROLE_TABLE_GRANTS view is based on 5.63 TABLE_PRIVILEGES and is defined there instead. + + +/* + * 5.45 + * ROLE_TABLE_METHOD_GRANTS view + */ + +-- feature not supported + + + +-- 5.46 ROLE_USAGE_GRANTS view is based on 5.75 USAGE_PRIVILEGES and is defined there instead. + + +-- 5.47 ROLE_UDT_GRANTS view is based on 5.74 UDT_PRIVILEGES and is defined there instead. + + +/* + * 5.48 + * ROUTINE_COLUMN_USAGE view + */ + +-- not tracked by PostgreSQL + + +/* + * 5.49 + * ROUTINE_PERIOD_USAGE view + */ + +-- feature not supported + + +/* + * 5.50 + * ROUTINE_PRIVILEGES view + */ + +CREATE VIEW routine_privileges AS + SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor, + CAST(grantee.rolname AS sql_identifier) AS grantee, + CAST(current_database() AS sql_identifier) AS specific_catalog, + CAST(n.nspname AS sql_identifier) AS specific_schema, + CAST(nameconcatoid(p.proname, p.oid) AS sql_identifier) AS specific_name, + CAST(current_database() AS sql_identifier) AS routine_catalog, + CAST(n.nspname AS sql_identifier) AS routine_schema, + CAST(p.proname AS sql_identifier) AS routine_name, + CAST('EXECUTE' AS character_data) AS privilege_type, + CAST( + CASE WHEN + -- object owner always has grant options + pg_has_role(grantee.oid, p.proowner, 'USAGE') + OR p.grantable + THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable + + FROM ( + SELECT oid, proname, proowner, pronamespace, (aclexplode(coalesce(proacl, acldefault('f', proowner)))).* FROM pg_proc + ) p (oid, proname, proowner, pronamespace, grantor, grantee, prtype, grantable), + pg_namespace n, + pg_authid u_grantor, + ( + SELECT oid, rolname FROM pg_authid + UNION ALL + SELECT 0::oid, 'PUBLIC' + ) AS grantee (oid, rolname) + + WHERE p.pronamespace = n.oid + AND grantee.oid = p.grantee + AND u_grantor.oid = p.grantor + AND p.prtype IN ('EXECUTE') + AND (pg_has_role(u_grantor.oid, 'USAGE') + OR pg_has_role(grantee.oid, 'USAGE') + OR grantee.rolname = 'PUBLIC'); + +GRANT SELECT ON routine_privileges TO PUBLIC; + + +/* + * 5.42 + * ROLE_ROUTINE_GRANTS view + */ + +CREATE VIEW role_routine_grants AS + SELECT grantor, + grantee, + specific_catalog, + specific_schema, + specific_name, + routine_catalog, + routine_schema, + routine_name, + privilege_type, + is_grantable + FROM routine_privileges + WHERE grantor IN (SELECT role_name FROM enabled_roles) + OR grantee IN (SELECT role_name FROM enabled_roles); + +GRANT SELECT ON role_routine_grants TO PUBLIC; + + +/* + * 5.51 + * ROUTINE_ROUTINE_USAGE view + */ + +-- not tracked by PostgreSQL + + +/* + * 5.52 + * ROUTINE_SEQUENCE_USAGE view + */ + +-- not tracked by PostgreSQL + + +/* + * 5.53 + * ROUTINE_TABLE_USAGE view + */ + +-- not tracked by PostgreSQL + + +/* + * 5.54 + * ROUTINES view + */ + +CREATE VIEW routines AS + SELECT CAST(current_database() AS sql_identifier) AS specific_catalog, + CAST(n.nspname AS sql_identifier) AS specific_schema, + CAST(nameconcatoid(p.proname, p.oid) AS sql_identifier) AS specific_name, + CAST(current_database() AS sql_identifier) AS routine_catalog, + CAST(n.nspname AS sql_identifier) AS routine_schema, + CAST(p.proname AS sql_identifier) AS routine_name, + CAST(CASE p.prokind WHEN 'f' THEN 'FUNCTION' WHEN 'p' THEN 'PROCEDURE' END + AS character_data) AS routine_type, + CAST(null AS sql_identifier) AS module_catalog, + CAST(null AS sql_identifier) AS module_schema, + CAST(null AS sql_identifier) AS module_name, + CAST(null AS sql_identifier) AS udt_catalog, + CAST(null AS sql_identifier) AS udt_schema, + CAST(null AS sql_identifier) AS udt_name, + + CAST( + CASE WHEN p.prokind = 'p' THEN NULL + WHEN t.typelem <> 0 AND t.typlen = -1 THEN 'ARRAY' + WHEN nt.nspname = 'pg_catalog' THEN format_type(t.oid, null) + ELSE 'USER-DEFINED' END AS character_data) + AS data_type, + CAST(null AS cardinal_number) AS character_maximum_length, + CAST(null AS cardinal_number) AS character_octet_length, + CAST(null AS sql_identifier) AS character_set_catalog, + CAST(null AS sql_identifier) AS character_set_schema, + CAST(null AS sql_identifier) AS character_set_name, + CAST(null AS sql_identifier) AS collation_catalog, + CAST(null AS sql_identifier) AS collation_schema, + CAST(null AS sql_identifier) AS collation_name, + CAST(null AS cardinal_number) AS numeric_precision, + CAST(null AS cardinal_number) AS numeric_precision_radix, + CAST(null AS cardinal_number) AS numeric_scale, + CAST(null AS cardinal_number) AS datetime_precision, + CAST(null AS character_data) AS interval_type, + CAST(null AS cardinal_number) AS interval_precision, + CAST(CASE WHEN nt.nspname IS NOT NULL THEN current_database() END AS sql_identifier) AS type_udt_catalog, + CAST(nt.nspname AS sql_identifier) AS type_udt_schema, + CAST(t.typname AS sql_identifier) AS type_udt_name, + CAST(null AS sql_identifier) AS scope_catalog, + CAST(null AS sql_identifier) AS scope_schema, + CAST(null AS sql_identifier) AS scope_name, + CAST(null AS cardinal_number) AS maximum_cardinality, + CAST(CASE WHEN p.prokind <> 'p' THEN 0 END AS sql_identifier) AS dtd_identifier, + + CAST(CASE WHEN l.lanname = 'sql' THEN 'SQL' ELSE 'EXTERNAL' END AS character_data) + AS routine_body, + CAST( + CASE WHEN pg_has_role(p.proowner, 'USAGE') THEN p.prosrc ELSE null END + AS character_data) AS routine_definition, + CAST( + CASE WHEN l.lanname = 'c' THEN p.prosrc ELSE null END + AS character_data) AS external_name, + CAST(upper(l.lanname) AS character_data) AS external_language, + + CAST('GENERAL' AS character_data) AS parameter_style, + CAST(CASE WHEN p.provolatile = 'i' THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_deterministic, + CAST('MODIFIES' AS character_data) AS sql_data_access, + CAST(CASE WHEN p.prokind <> 'p' THEN + CASE WHEN p.proisstrict THEN 'YES' ELSE 'NO' END END AS yes_or_no) AS is_null_call, + CAST(null AS character_data) AS sql_path, + CAST('YES' AS yes_or_no) AS schema_level_routine, + CAST(0 AS cardinal_number) AS max_dynamic_result_sets, + CAST(null AS yes_or_no) AS is_user_defined_cast, + CAST(null AS yes_or_no) AS is_implicitly_invocable, + CAST(CASE WHEN p.prosecdef THEN 'DEFINER' ELSE 'INVOKER' END AS character_data) AS security_type, + CAST(null AS sql_identifier) AS to_sql_specific_catalog, + CAST(null AS sql_identifier) AS to_sql_specific_schema, + CAST(null AS sql_identifier) AS to_sql_specific_name, + CAST('NO' AS yes_or_no) AS as_locator, + CAST(null AS time_stamp) AS created, + CAST(null AS time_stamp) AS last_altered, + CAST(null AS yes_or_no) AS new_savepoint_level, + CAST('NO' AS yes_or_no) AS is_udt_dependent, + + CAST(null AS character_data) AS result_cast_from_data_type, + CAST(null AS yes_or_no) AS result_cast_as_locator, + CAST(null AS cardinal_number) AS result_cast_char_max_length, + CAST(null AS cardinal_number) AS result_cast_char_octet_length, + CAST(null AS sql_identifier) AS result_cast_char_set_catalog, + CAST(null AS sql_identifier) AS result_cast_char_set_schema, + CAST(null AS sql_identifier) AS result_cast_char_set_name, + CAST(null AS sql_identifier) AS result_cast_collation_catalog, + CAST(null AS sql_identifier) AS result_cast_collation_schema, + CAST(null AS sql_identifier) AS result_cast_collation_name, + CAST(null AS cardinal_number) AS result_cast_numeric_precision, + CAST(null AS cardinal_number) AS result_cast_numeric_precision_radix, + CAST(null AS cardinal_number) AS result_cast_numeric_scale, + CAST(null AS cardinal_number) AS result_cast_datetime_precision, + CAST(null AS character_data) AS result_cast_interval_type, + CAST(null AS cardinal_number) AS result_cast_interval_precision, + CAST(null AS sql_identifier) AS result_cast_type_udt_catalog, + CAST(null AS sql_identifier) AS result_cast_type_udt_schema, + CAST(null AS sql_identifier) AS result_cast_type_udt_name, + CAST(null AS sql_identifier) AS result_cast_scope_catalog, + CAST(null AS sql_identifier) AS result_cast_scope_schema, + CAST(null AS sql_identifier) AS result_cast_scope_name, + CAST(null AS cardinal_number) AS result_cast_maximum_cardinality, + CAST(null AS sql_identifier) AS result_cast_dtd_identifier + + FROM (pg_namespace n + JOIN pg_proc p ON n.oid = p.pronamespace + JOIN pg_language l ON p.prolang = l.oid) + LEFT JOIN + (pg_type t JOIN pg_namespace nt ON t.typnamespace = nt.oid) + ON p.prorettype = t.oid AND p.prokind <> 'p' + + WHERE (pg_has_role(p.proowner, 'USAGE') + OR has_function_privilege(p.oid, 'EXECUTE')); + +GRANT SELECT ON routines TO PUBLIC; + + +/* + * 5.55 + * SCHEMATA view + */ + +CREATE VIEW schemata AS + SELECT CAST(current_database() AS sql_identifier) AS catalog_name, + CAST(n.nspname AS sql_identifier) AS schema_name, + CAST(u.rolname AS sql_identifier) AS schema_owner, + CAST(null AS sql_identifier) AS default_character_set_catalog, + CAST(null AS sql_identifier) AS default_character_set_schema, + CAST(null AS sql_identifier) AS default_character_set_name, + CAST(null AS character_data) AS sql_path + FROM pg_namespace n, pg_authid u + WHERE n.nspowner = u.oid + AND (pg_has_role(n.nspowner, 'USAGE') + OR has_schema_privilege(n.oid, 'CREATE, USAGE')); + +GRANT SELECT ON schemata TO PUBLIC; + + +/* + * 5.56 + * SEQUENCES view + */ + +CREATE VIEW sequences AS + SELECT CAST(current_database() AS sql_identifier) AS sequence_catalog, + CAST(nc.nspname AS sql_identifier) AS sequence_schema, + CAST(c.relname AS sql_identifier) AS sequence_name, + CAST(format_type(s.seqtypid, null) AS character_data) AS data_type, + CAST(_pg_numeric_precision(s.seqtypid, -1) AS cardinal_number) AS numeric_precision, + CAST(2 AS cardinal_number) AS numeric_precision_radix, + CAST(0 AS cardinal_number) AS numeric_scale, + CAST(s.seqstart AS character_data) AS start_value, + CAST(s.seqmin AS character_data) AS minimum_value, + CAST(s.seqmax AS character_data) AS maximum_value, + CAST(s.seqincrement AS character_data) AS increment, + CAST(CASE WHEN s.seqcycle THEN 'YES' ELSE 'NO' END AS yes_or_no) AS cycle_option + FROM pg_namespace nc, pg_class c, pg_sequence s + WHERE c.relnamespace = nc.oid + AND c.relkind = 'S' + AND NOT EXISTS (SELECT 1 FROM pg_depend WHERE classid = 'pg_class'::regclass AND objid = c.oid AND deptype = 'i') + AND (NOT pg_is_other_temp_schema(nc.oid)) + AND c.oid = s.seqrelid + AND (pg_has_role(c.relowner, 'USAGE') + OR has_sequence_privilege(c.oid, 'SELECT, UPDATE, USAGE') ); + +GRANT SELECT ON sequences TO PUBLIC; + + +/* + * 5.57 + * SQL_FEATURES table + */ + +CREATE TABLE sql_features ( + feature_id character_data, + feature_name character_data, + sub_feature_id character_data, + sub_feature_name character_data, + is_supported yes_or_no, + is_verified_by character_data, + comments character_data +); + +-- Will be filled with external data by initdb. + +GRANT SELECT ON sql_features TO PUBLIC; + + +/* + * 5.58 + * SQL_IMPLEMENTATION_INFO table + */ + +-- Note: Implementation information items are defined in ISO/IEC 9075-3:2008, +-- clause 9.1. + +CREATE TABLE sql_implementation_info ( + implementation_info_id character_data, + implementation_info_name character_data, + integer_value cardinal_number, + character_value character_data, + comments character_data +); + +INSERT INTO sql_implementation_info VALUES ('10003', 'CATALOG NAME', NULL, 'Y', NULL); +INSERT INTO sql_implementation_info VALUES ('10004', 'COLLATING SEQUENCE', NULL, (SELECT default_collate_name FROM character_sets), NULL); +INSERT INTO sql_implementation_info VALUES ('23', 'CURSOR COMMIT BEHAVIOR', 1, NULL, 'close cursors and retain prepared statements'); +INSERT INTO sql_implementation_info VALUES ('2', 'DATA SOURCE NAME', NULL, '', NULL); +INSERT INTO sql_implementation_info VALUES ('17', 'DBMS NAME', NULL, (select trim(trailing ' ' from substring(version() from '^[^0-9]*'))), NULL); +INSERT INTO sql_implementation_info VALUES ('18', 'DBMS VERSION', NULL, '???', NULL); -- filled by initdb +INSERT INTO sql_implementation_info VALUES ('26', 'DEFAULT TRANSACTION ISOLATION', 2, NULL, 'READ COMMITTED; user-settable'); +INSERT INTO sql_implementation_info VALUES ('28', 'IDENTIFIER CASE', 3, NULL, 'stored in mixed case - case sensitive'); +INSERT INTO sql_implementation_info VALUES ('85', 'NULL COLLATION', 0, NULL, 'nulls higher than non-nulls'); +INSERT INTO sql_implementation_info VALUES ('13', 'SERVER NAME', NULL, '', NULL); +INSERT INTO sql_implementation_info VALUES ('94', 'SPECIAL CHARACTERS', NULL, '', 'all non-ASCII characters allowed'); +INSERT INTO sql_implementation_info VALUES ('46', 'TRANSACTION CAPABLE', 2, NULL, 'both DML and DDL'); + +GRANT SELECT ON sql_implementation_info TO PUBLIC; + + +/* + * 5.59 + * SQL_PARTS table + */ + +CREATE TABLE sql_parts ( + feature_id character_data, + feature_name character_data, + is_supported yes_or_no, + is_verified_by character_data, + comments character_data +); + +INSERT INTO sql_parts VALUES ('1', 'Framework (SQL/Framework)', 'NO', NULL, ''); +INSERT INTO sql_parts VALUES ('2', 'Foundation (SQL/Foundation)', 'NO', NULL, ''); +INSERT INTO sql_parts VALUES ('3', 'Call-Level Interface (SQL/CLI)', 'NO', NULL, ''); +INSERT INTO sql_parts VALUES ('4', 'Persistent Stored Modules (SQL/PSM)', 'NO', NULL, ''); +INSERT INTO sql_parts VALUES ('9', 'Management of External Data (SQL/MED)', 'NO', NULL, ''); +INSERT INTO sql_parts VALUES ('10', 'Object Language Bindings (SQL/OLB)', 'NO', NULL, ''); +INSERT INTO sql_parts VALUES ('11', 'Information and Definition Schema (SQL/Schemata)', 'NO', NULL, ''); +INSERT INTO sql_parts VALUES ('13', 'Routines and Types Using the Java Programming Language (SQL/JRT)', 'NO', NULL, ''); +INSERT INTO sql_parts VALUES ('14', 'XML-Related Specifications (SQL/XML)', 'NO', NULL, ''); +INSERT INTO sql_parts VALUES ('15', 'Multi-Dimensional Arrays (SQL/MDA)', 'NO', NULL, ''); + + +/* + * 5.60 + * SQL_SIZING table + */ + +-- Note: Sizing items are defined in ISO/IEC 9075-3:2008, clause 9.2. + +CREATE TABLE sql_sizing ( + sizing_id cardinal_number, + sizing_name character_data, + supported_value cardinal_number, + comments character_data +); + +INSERT INTO sql_sizing VALUES (34, 'MAXIMUM CATALOG NAME LENGTH', 63, NULL); +INSERT INTO sql_sizing VALUES (30, 'MAXIMUM COLUMN NAME LENGTH', 63, NULL); +INSERT INTO sql_sizing VALUES (97, 'MAXIMUM COLUMNS IN GROUP BY', 0, NULL); +INSERT INTO sql_sizing VALUES (99, 'MAXIMUM COLUMNS IN ORDER BY', 0, NULL); +INSERT INTO sql_sizing VALUES (100, 'MAXIMUM COLUMNS IN SELECT', 1664, NULL); -- match MaxTupleAttributeNumber +INSERT INTO sql_sizing VALUES (101, 'MAXIMUM COLUMNS IN TABLE', 1600, NULL); -- match MaxHeapAttributeNumber +INSERT INTO sql_sizing VALUES (1, 'MAXIMUM CONCURRENT ACTIVITIES', 0, NULL); +INSERT INTO sql_sizing VALUES (31, 'MAXIMUM CURSOR NAME LENGTH', 63, NULL); +INSERT INTO sql_sizing VALUES (0, 'MAXIMUM DRIVER CONNECTIONS', NULL, NULL); +INSERT INTO sql_sizing VALUES (10005, 'MAXIMUM IDENTIFIER LENGTH', 63, NULL); +INSERT INTO sql_sizing VALUES (32, 'MAXIMUM SCHEMA NAME LENGTH', 63, NULL); +INSERT INTO sql_sizing VALUES (20000, 'MAXIMUM STATEMENT OCTETS', 0, NULL); +INSERT INTO sql_sizing VALUES (20001, 'MAXIMUM STATEMENT OCTETS DATA', 0, NULL); +INSERT INTO sql_sizing VALUES (20002, 'MAXIMUM STATEMENT OCTETS SCHEMA', 0, NULL); +INSERT INTO sql_sizing VALUES (35, 'MAXIMUM TABLE NAME LENGTH', 63, NULL); +INSERT INTO sql_sizing VALUES (106, 'MAXIMUM TABLES IN SELECT', 0, NULL); +INSERT INTO sql_sizing VALUES (107, 'MAXIMUM USER NAME LENGTH', 63, NULL); +INSERT INTO sql_sizing VALUES (25000, 'MAXIMUM CURRENT DEFAULT TRANSFORM GROUP LENGTH', NULL, NULL); +INSERT INTO sql_sizing VALUES (25001, 'MAXIMUM CURRENT TRANSFORM GROUP LENGTH', NULL, NULL); +INSERT INTO sql_sizing VALUES (25002, 'MAXIMUM CURRENT PATH LENGTH', 0, NULL); +INSERT INTO sql_sizing VALUES (25003, 'MAXIMUM CURRENT ROLE LENGTH', NULL, NULL); +INSERT INTO sql_sizing VALUES (25004, 'MAXIMUM SESSION USER LENGTH', 63, NULL); +INSERT INTO sql_sizing VALUES (25005, 'MAXIMUM SYSTEM USER LENGTH', 63, NULL); + +UPDATE sql_sizing + SET supported_value = (SELECT typlen-1 FROM pg_catalog.pg_type WHERE typname = 'name'), + comments = 'Might be less, depending on character set.' + WHERE supported_value = 63; + +GRANT SELECT ON sql_sizing TO PUBLIC; + + +/* + * 5.61 + * TABLE_CONSTRAINTS view + */ + +CREATE VIEW table_constraints AS + SELECT CAST(current_database() AS sql_identifier) AS constraint_catalog, + CAST(nc.nspname AS sql_identifier) AS constraint_schema, + CAST(c.conname AS sql_identifier) AS constraint_name, + CAST(current_database() AS sql_identifier) AS table_catalog, + CAST(nr.nspname AS sql_identifier) AS table_schema, + CAST(r.relname AS sql_identifier) AS table_name, + CAST( + CASE c.contype WHEN 'c' THEN 'CHECK' + WHEN 'f' THEN 'FOREIGN KEY' + WHEN 'p' THEN 'PRIMARY KEY' + WHEN 'u' THEN 'UNIQUE' END + AS character_data) AS constraint_type, + CAST(CASE WHEN c.condeferrable THEN 'YES' ELSE 'NO' END AS yes_or_no) + AS is_deferrable, + CAST(CASE WHEN c.condeferred THEN 'YES' ELSE 'NO' END AS yes_or_no) + AS initially_deferred, + CAST('YES' AS yes_or_no) AS enforced + + FROM pg_namespace nc, + pg_namespace nr, + pg_constraint c, + pg_class r + + WHERE nc.oid = c.connamespace AND nr.oid = r.relnamespace + AND c.conrelid = r.oid + AND c.contype NOT IN ('t', 'x') -- ignore nonstandard constraints + AND r.relkind IN ('r', 'p') + AND (NOT pg_is_other_temp_schema(nr.oid)) + AND (pg_has_role(r.relowner, 'USAGE') + -- SELECT privilege omitted, per SQL standard + OR has_table_privilege(r.oid, 'INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER') + OR has_any_column_privilege(r.oid, 'INSERT, UPDATE, REFERENCES') ) + + UNION ALL + + -- not-null constraints + + SELECT CAST(current_database() AS sql_identifier) AS constraint_catalog, + CAST(nr.nspname AS sql_identifier) AS constraint_schema, + CAST(CAST(nr.oid AS text) || '_' || CAST(r.oid AS text) || '_' || CAST(a.attnum AS text) || '_not_null' AS sql_identifier) AS constraint_name, -- XXX + CAST(current_database() AS sql_identifier) AS table_catalog, + CAST(nr.nspname AS sql_identifier) AS table_schema, + CAST(r.relname AS sql_identifier) AS table_name, + CAST('CHECK' AS character_data) AS constraint_type, + CAST('NO' AS yes_or_no) AS is_deferrable, + CAST('NO' AS yes_or_no) AS initially_deferred, + CAST('YES' AS yes_or_no) AS enforced + + FROM pg_namespace nr, + pg_class r, + pg_attribute a + + WHERE nr.oid = r.relnamespace + AND r.oid = a.attrelid + AND a.attnotnull + AND a.attnum > 0 + AND NOT a.attisdropped + AND r.relkind IN ('r', 'p') + AND (NOT pg_is_other_temp_schema(nr.oid)) + AND (pg_has_role(r.relowner, 'USAGE') + -- SELECT privilege omitted, per SQL standard + OR has_table_privilege(r.oid, 'INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER') + OR has_any_column_privilege(r.oid, 'INSERT, UPDATE, REFERENCES') ); + +GRANT SELECT ON table_constraints TO PUBLIC; + + +/* + * 5.62 + * TABLE_METHOD_PRIVILEGES view + */ + +-- feature not supported + + +/* + * 5.63 + * TABLE_PRIVILEGES view + */ + +CREATE VIEW table_privileges AS + SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor, + CAST(grantee.rolname AS sql_identifier) AS grantee, + CAST(current_database() AS sql_identifier) AS table_catalog, + CAST(nc.nspname AS sql_identifier) AS table_schema, + CAST(c.relname AS sql_identifier) AS table_name, + CAST(c.prtype AS character_data) AS privilege_type, + CAST( + CASE WHEN + -- object owner always has grant options + pg_has_role(grantee.oid, c.relowner, 'USAGE') + OR c.grantable + THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable, + CAST(CASE WHEN c.prtype = 'SELECT' THEN 'YES' ELSE 'NO' END AS yes_or_no) AS with_hierarchy + + FROM ( + SELECT oid, relname, relnamespace, relkind, relowner, (aclexplode(coalesce(relacl, acldefault('r', relowner)))).* FROM pg_class + ) AS c (oid, relname, relnamespace, relkind, relowner, grantor, grantee, prtype, grantable), + pg_namespace nc, + pg_authid u_grantor, + ( + SELECT oid, rolname FROM pg_authid + UNION ALL + SELECT 0::oid, 'PUBLIC' + ) AS grantee (oid, rolname) + + WHERE c.relnamespace = nc.oid + AND c.relkind IN ('r', 'v', 'f', 'p') + AND c.grantee = grantee.oid + AND c.grantor = u_grantor.oid + AND c.prtype IN ('INSERT', 'SELECT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER') + AND (pg_has_role(u_grantor.oid, 'USAGE') + OR pg_has_role(grantee.oid, 'USAGE') + OR grantee.rolname = 'PUBLIC'); + +GRANT SELECT ON table_privileges TO PUBLIC; + + +/* + * 5.43 + * ROLE_TABLE_GRANTS view + */ + +CREATE VIEW role_table_grants AS + SELECT grantor, + grantee, + table_catalog, + table_schema, + table_name, + privilege_type, + is_grantable, + with_hierarchy + FROM table_privileges + WHERE grantor IN (SELECT role_name FROM enabled_roles) + OR grantee IN (SELECT role_name FROM enabled_roles); + +GRANT SELECT ON role_table_grants TO PUBLIC; + + +/* + * 5.63 + * TABLES view + */ + +CREATE VIEW tables AS + SELECT CAST(current_database() AS sql_identifier) AS table_catalog, + CAST(nc.nspname AS sql_identifier) AS table_schema, + CAST(c.relname AS sql_identifier) AS table_name, + + CAST( + CASE WHEN nc.oid = pg_my_temp_schema() THEN 'LOCAL TEMPORARY' + WHEN c.relkind IN ('r', 'p') THEN 'BASE TABLE' + WHEN c.relkind = 'v' THEN 'VIEW' + WHEN c.relkind = 'f' THEN 'FOREIGN' + ELSE null END + AS character_data) AS table_type, + + CAST(null AS sql_identifier) AS self_referencing_column_name, + CAST(null AS character_data) AS reference_generation, + + CAST(CASE WHEN t.typname IS NOT NULL THEN current_database() ELSE null END AS sql_identifier) AS user_defined_type_catalog, + CAST(nt.nspname AS sql_identifier) AS user_defined_type_schema, + CAST(t.typname AS sql_identifier) AS user_defined_type_name, + + CAST(CASE WHEN c.relkind IN ('r', 'p') OR + (c.relkind IN ('v', 'f') AND + -- 1 << CMD_INSERT + pg_relation_is_updatable(c.oid, false) & 8 = 8) + THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_insertable_into, + + CAST(CASE WHEN t.typname IS NOT NULL THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_typed, + CAST(null AS character_data) AS commit_action + + FROM pg_namespace nc JOIN pg_class c ON (nc.oid = c.relnamespace) + LEFT JOIN (pg_type t JOIN pg_namespace nt ON (t.typnamespace = nt.oid)) ON (c.reloftype = t.oid) + + WHERE c.relkind IN ('r', 'v', 'f', 'p') + AND (NOT pg_is_other_temp_schema(nc.oid)) + AND (pg_has_role(c.relowner, 'USAGE') + OR has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER') + OR has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES') ); + +GRANT SELECT ON tables TO PUBLIC; + + +/* + * 5.65 + * TRANSFORMS view + */ + +CREATE VIEW transforms AS + SELECT CAST(current_database() AS sql_identifier) AS udt_catalog, + CAST(nt.nspname AS sql_identifier) AS udt_schema, + CAST(t.typname AS sql_identifier) AS udt_name, + CAST(current_database() AS sql_identifier) AS specific_catalog, + CAST(np.nspname AS sql_identifier) AS specific_schema, + CAST(nameconcatoid(p.proname, p.oid) AS sql_identifier) AS specific_name, + CAST(l.lanname AS sql_identifier) AS group_name, + CAST('FROM SQL' AS character_data) AS transform_type + FROM pg_type t JOIN pg_transform x ON t.oid = x.trftype + JOIN pg_language l ON x.trflang = l.oid + JOIN pg_proc p ON x.trffromsql = p.oid + JOIN pg_namespace nt ON t.typnamespace = nt.oid + JOIN pg_namespace np ON p.pronamespace = np.oid + + UNION + + SELECT CAST(current_database() AS sql_identifier) AS udt_catalog, + CAST(nt.nspname AS sql_identifier) AS udt_schema, + CAST(t.typname AS sql_identifier) AS udt_name, + CAST(current_database() AS sql_identifier) AS specific_catalog, + CAST(np.nspname AS sql_identifier) AS specific_schema, + CAST(nameconcatoid(p.proname, p.oid) AS sql_identifier) AS specific_name, + CAST(l.lanname AS sql_identifier) AS group_name, + CAST('TO SQL' AS character_data) AS transform_type + FROM pg_type t JOIN pg_transform x ON t.oid = x.trftype + JOIN pg_language l ON x.trflang = l.oid + JOIN pg_proc p ON x.trftosql = p.oid + JOIN pg_namespace nt ON t.typnamespace = nt.oid + JOIN pg_namespace np ON p.pronamespace = np.oid + + ORDER BY udt_catalog, udt_schema, udt_name, group_name, transform_type -- some sensible grouping for interactive use +; + + +/* + * 5.66 + * TRANSLATIONS view + */ + +-- feature not supported + + +/* + * 5.67 + * TRIGGERED_UPDATE_COLUMNS view + */ + +CREATE VIEW triggered_update_columns AS + SELECT CAST(current_database() AS sql_identifier) AS trigger_catalog, + CAST(n.nspname AS sql_identifier) AS trigger_schema, + CAST(t.tgname AS sql_identifier) AS trigger_name, + CAST(current_database() AS sql_identifier) AS event_object_catalog, + CAST(n.nspname AS sql_identifier) AS event_object_schema, + CAST(c.relname AS sql_identifier) AS event_object_table, + CAST(a.attname AS sql_identifier) AS event_object_column + + FROM pg_namespace n, pg_class c, pg_trigger t, + (SELECT tgoid, (ta0.tgat).x AS tgattnum, (ta0.tgat).n AS tgattpos + FROM (SELECT oid AS tgoid, information_schema._pg_expandarray(tgattr) AS tgat FROM pg_trigger) AS ta0) AS ta, + pg_attribute a + + WHERE n.oid = c.relnamespace + AND c.oid = t.tgrelid + AND t.oid = ta.tgoid + AND (a.attrelid, a.attnum) = (t.tgrelid, ta.tgattnum) + AND NOT t.tgisinternal + AND (NOT pg_is_other_temp_schema(n.oid)) + AND (pg_has_role(c.relowner, 'USAGE') + -- SELECT privilege omitted, per SQL standard + OR has_column_privilege(c.oid, a.attnum, 'INSERT, UPDATE, REFERENCES') ); + +GRANT SELECT ON triggered_update_columns TO PUBLIC; + + +/* + * 5.68 + * TRIGGER_COLUMN_USAGE view + */ + +-- not tracked by PostgreSQL + + +/* + * 5.69 + * TRIGGER_PERIOD_USAGE view + */ + +-- feature not supported + + +/* + * 5.70 + * TRIGGER_ROUTINE_USAGE view + */ + +-- not tracked by PostgreSQL + + +/* + * 5.71 + * TRIGGER_SEQUENCE_USAGE view + */ + +-- not tracked by PostgreSQL + + +/* + * 5.72 + * TRIGGER_TABLE_USAGE view + */ + +-- not tracked by PostgreSQL + + +/* + * 5.73 + * TRIGGERS view + */ + +CREATE VIEW triggers AS + SELECT CAST(current_database() AS sql_identifier) AS trigger_catalog, + CAST(n.nspname AS sql_identifier) AS trigger_schema, + CAST(t.tgname AS sql_identifier) AS trigger_name, + CAST(em.text AS character_data) AS event_manipulation, + CAST(current_database() AS sql_identifier) AS event_object_catalog, + CAST(n.nspname AS sql_identifier) AS event_object_schema, + CAST(c.relname AS sql_identifier) AS event_object_table, + CAST( + -- To determine action order, partition by schema, table, + -- event_manipulation (INSERT/DELETE/UPDATE), ROW/STATEMENT (1), + -- BEFORE/AFTER (66), then order by trigger name. It's preferable + -- to partition by view output columns, so that query constraints + -- can be pushed down below the window function. + rank() OVER (PARTITION BY CAST(n.nspname AS sql_identifier), + CAST(c.relname AS sql_identifier), + em.num, + t.tgtype & 1, + t.tgtype & 66 + ORDER BY t.tgname) + AS cardinal_number) AS action_order, + CAST( + CASE WHEN pg_has_role(c.relowner, 'USAGE') + THEN (regexp_match(pg_get_triggerdef(t.oid), E'.{35,} WHEN \\((.+)\\) EXECUTE FUNCTION'))[1] + ELSE null END + AS character_data) AS action_condition, + CAST( + substring(pg_get_triggerdef(t.oid) from + position('EXECUTE FUNCTION' in substring(pg_get_triggerdef(t.oid) from 48)) + 47) + AS character_data) AS action_statement, + CAST( + -- hard-wired reference to TRIGGER_TYPE_ROW + CASE t.tgtype & 1 WHEN 1 THEN 'ROW' ELSE 'STATEMENT' END + AS character_data) AS action_orientation, + CAST( + -- hard-wired refs to TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_INSTEAD + CASE t.tgtype & 66 WHEN 2 THEN 'BEFORE' WHEN 64 THEN 'INSTEAD OF' ELSE 'AFTER' END + AS character_data) AS action_timing, + CAST(tgoldtable AS sql_identifier) AS action_reference_old_table, + CAST(tgnewtable AS sql_identifier) AS action_reference_new_table, + CAST(null AS sql_identifier) AS action_reference_old_row, + CAST(null AS sql_identifier) AS action_reference_new_row, + CAST(null AS time_stamp) AS created + + FROM pg_namespace n, pg_class c, pg_trigger t, + -- hard-wired refs to TRIGGER_TYPE_INSERT, TRIGGER_TYPE_DELETE, + -- TRIGGER_TYPE_UPDATE; we intentionally omit TRIGGER_TYPE_TRUNCATE + (VALUES (4, 'INSERT'), + (8, 'DELETE'), + (16, 'UPDATE')) AS em (num, text) + + WHERE n.oid = c.relnamespace + AND c.oid = t.tgrelid + AND t.tgtype & em.num <> 0 + AND NOT t.tgisinternal + AND (NOT pg_is_other_temp_schema(n.oid)) + AND (pg_has_role(c.relowner, 'USAGE') + -- SELECT privilege omitted, per SQL standard + OR has_table_privilege(c.oid, 'INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER') + OR has_any_column_privilege(c.oid, 'INSERT, UPDATE, REFERENCES') ); + +GRANT SELECT ON triggers TO PUBLIC; + + +/* + * 5.74 + * UDT_PRIVILEGES view + */ + +CREATE VIEW udt_privileges AS + SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor, + CAST(grantee.rolname AS sql_identifier) AS grantee, + CAST(current_database() AS sql_identifier) AS udt_catalog, + CAST(n.nspname AS sql_identifier) AS udt_schema, + CAST(t.typname AS sql_identifier) AS udt_name, + CAST('TYPE USAGE' AS character_data) AS privilege_type, -- sic + CAST( + CASE WHEN + -- object owner always has grant options + pg_has_role(grantee.oid, t.typowner, 'USAGE') + OR t.grantable + THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable + + FROM ( + SELECT oid, typname, typnamespace, typtype, typowner, (aclexplode(coalesce(typacl, acldefault('T', typowner)))).* FROM pg_type + ) AS t (oid, typname, typnamespace, typtype, typowner, grantor, grantee, prtype, grantable), + pg_namespace n, + pg_authid u_grantor, + ( + SELECT oid, rolname FROM pg_authid + UNION ALL + SELECT 0::oid, 'PUBLIC' + ) AS grantee (oid, rolname) + + WHERE t.typnamespace = n.oid + AND t.typtype = 'c' + AND t.grantee = grantee.oid + AND t.grantor = u_grantor.oid + AND t.prtype IN ('USAGE') + AND (pg_has_role(u_grantor.oid, 'USAGE') + OR pg_has_role(grantee.oid, 'USAGE') + OR grantee.rolname = 'PUBLIC'); + +GRANT SELECT ON udt_privileges TO PUBLIC; + + +/* + * 5.46 + * ROLE_UDT_GRANTS view + */ + +CREATE VIEW role_udt_grants AS + SELECT grantor, + grantee, + udt_catalog, + udt_schema, + udt_name, + privilege_type, + is_grantable + FROM udt_privileges + WHERE grantor IN (SELECT role_name FROM enabled_roles) + OR grantee IN (SELECT role_name FROM enabled_roles); + +GRANT SELECT ON role_udt_grants TO PUBLIC; + + +/* + * 5.75 + * USAGE_PRIVILEGES view + */ + +CREATE VIEW usage_privileges AS + + /* collations */ + -- Collations have no real privileges, so we represent all collations with implicit usage privilege here. + SELECT CAST(u.rolname AS sql_identifier) AS grantor, + CAST('PUBLIC' AS sql_identifier) AS grantee, + CAST(current_database() AS sql_identifier) AS object_catalog, + CAST(n.nspname AS sql_identifier) AS object_schema, + CAST(c.collname AS sql_identifier) AS object_name, + CAST('COLLATION' AS character_data) AS object_type, + CAST('USAGE' AS character_data) AS privilege_type, + CAST('NO' AS yes_or_no) AS is_grantable + + FROM pg_authid u, + pg_namespace n, + pg_collation c + + WHERE u.oid = c.collowner + AND c.collnamespace = n.oid + AND collencoding IN (-1, (SELECT encoding FROM pg_database WHERE datname = current_database())) + + UNION ALL + + /* domains */ + SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor, + CAST(grantee.rolname AS sql_identifier) AS grantee, + CAST(current_database() AS sql_identifier) AS object_catalog, + CAST(n.nspname AS sql_identifier) AS object_schema, + CAST(t.typname AS sql_identifier) AS object_name, + CAST('DOMAIN' AS character_data) AS object_type, + CAST('USAGE' AS character_data) AS privilege_type, + CAST( + CASE WHEN + -- object owner always has grant options + pg_has_role(grantee.oid, t.typowner, 'USAGE') + OR t.grantable + THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable + + FROM ( + SELECT oid, typname, typnamespace, typtype, typowner, (aclexplode(coalesce(typacl, acldefault('T', typowner)))).* FROM pg_type + ) AS t (oid, typname, typnamespace, typtype, typowner, grantor, grantee, prtype, grantable), + pg_namespace n, + pg_authid u_grantor, + ( + SELECT oid, rolname FROM pg_authid + UNION ALL + SELECT 0::oid, 'PUBLIC' + ) AS grantee (oid, rolname) + + WHERE t.typnamespace = n.oid + AND t.typtype = 'd' + AND t.grantee = grantee.oid + AND t.grantor = u_grantor.oid + AND t.prtype IN ('USAGE') + AND (pg_has_role(u_grantor.oid, 'USAGE') + OR pg_has_role(grantee.oid, 'USAGE') + OR grantee.rolname = 'PUBLIC') + + UNION ALL + + /* foreign-data wrappers */ + SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor, + CAST(grantee.rolname AS sql_identifier) AS grantee, + CAST(current_database() AS sql_identifier) AS object_catalog, + CAST('' AS sql_identifier) AS object_schema, + CAST(fdw.fdwname AS sql_identifier) AS object_name, + CAST('FOREIGN DATA WRAPPER' AS character_data) AS object_type, + CAST('USAGE' AS character_data) AS privilege_type, + CAST( + CASE WHEN + -- object owner always has grant options + pg_has_role(grantee.oid, fdw.fdwowner, 'USAGE') + OR fdw.grantable + THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable + + FROM ( + SELECT fdwname, fdwowner, (aclexplode(coalesce(fdwacl, acldefault('F', fdwowner)))).* FROM pg_foreign_data_wrapper + ) AS fdw (fdwname, fdwowner, grantor, grantee, prtype, grantable), + pg_authid u_grantor, + ( + SELECT oid, rolname FROM pg_authid + UNION ALL + SELECT 0::oid, 'PUBLIC' + ) AS grantee (oid, rolname) + + WHERE u_grantor.oid = fdw.grantor + AND grantee.oid = fdw.grantee + AND fdw.prtype IN ('USAGE') + AND (pg_has_role(u_grantor.oid, 'USAGE') + OR pg_has_role(grantee.oid, 'USAGE') + OR grantee.rolname = 'PUBLIC') + + UNION ALL + + /* foreign servers */ + SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor, + CAST(grantee.rolname AS sql_identifier) AS grantee, + CAST(current_database() AS sql_identifier) AS object_catalog, + CAST('' AS sql_identifier) AS object_schema, + CAST(srv.srvname AS sql_identifier) AS object_name, + CAST('FOREIGN SERVER' AS character_data) AS object_type, + CAST('USAGE' AS character_data) AS privilege_type, + CAST( + CASE WHEN + -- object owner always has grant options + pg_has_role(grantee.oid, srv.srvowner, 'USAGE') + OR srv.grantable + THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable + + FROM ( + SELECT srvname, srvowner, (aclexplode(coalesce(srvacl, acldefault('S', srvowner)))).* FROM pg_foreign_server + ) AS srv (srvname, srvowner, grantor, grantee, prtype, grantable), + pg_authid u_grantor, + ( + SELECT oid, rolname FROM pg_authid + UNION ALL + SELECT 0::oid, 'PUBLIC' + ) AS grantee (oid, rolname) + + WHERE u_grantor.oid = srv.grantor + AND grantee.oid = srv.grantee + AND srv.prtype IN ('USAGE') + AND (pg_has_role(u_grantor.oid, 'USAGE') + OR pg_has_role(grantee.oid, 'USAGE') + OR grantee.rolname = 'PUBLIC') + + UNION ALL + + /* sequences */ + SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor, + CAST(grantee.rolname AS sql_identifier) AS grantee, + CAST(current_database() AS sql_identifier) AS object_catalog, + CAST(n.nspname AS sql_identifier) AS object_schema, + CAST(c.relname AS sql_identifier) AS object_name, + CAST('SEQUENCE' AS character_data) AS object_type, + CAST('USAGE' AS character_data) AS privilege_type, + CAST( + CASE WHEN + -- object owner always has grant options + pg_has_role(grantee.oid, c.relowner, 'USAGE') + OR c.grantable + THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable + + FROM ( + SELECT oid, relname, relnamespace, relkind, relowner, (aclexplode(coalesce(relacl, acldefault('r', relowner)))).* FROM pg_class + ) AS c (oid, relname, relnamespace, relkind, relowner, grantor, grantee, prtype, grantable), + pg_namespace n, + pg_authid u_grantor, + ( + SELECT oid, rolname FROM pg_authid + UNION ALL + SELECT 0::oid, 'PUBLIC' + ) AS grantee (oid, rolname) + + WHERE c.relnamespace = n.oid + AND c.relkind = 'S' + AND c.grantee = grantee.oid + AND c.grantor = u_grantor.oid + AND c.prtype IN ('USAGE') + AND (pg_has_role(u_grantor.oid, 'USAGE') + OR pg_has_role(grantee.oid, 'USAGE') + OR grantee.rolname = 'PUBLIC'); + +GRANT SELECT ON usage_privileges TO PUBLIC; + + +/* + * 5.45 + * ROLE_USAGE_GRANTS view + */ + +CREATE VIEW role_usage_grants AS + SELECT grantor, + grantee, + object_catalog, + object_schema, + object_name, + object_type, + privilege_type, + is_grantable + FROM usage_privileges + WHERE grantor IN (SELECT role_name FROM enabled_roles) + OR grantee IN (SELECT role_name FROM enabled_roles); + +GRANT SELECT ON role_usage_grants TO PUBLIC; + + +/* + * 5.76 + * USER_DEFINED_TYPES view + */ + +CREATE VIEW user_defined_types AS + SELECT CAST(current_database() AS sql_identifier) AS user_defined_type_catalog, + CAST(n.nspname AS sql_identifier) AS user_defined_type_schema, + CAST(c.relname AS sql_identifier) AS user_defined_type_name, + CAST('STRUCTURED' AS character_data) AS user_defined_type_category, + CAST('YES' AS yes_or_no) AS is_instantiable, + CAST(null AS yes_or_no) AS is_final, + CAST(null AS character_data) AS ordering_form, + CAST(null AS character_data) AS ordering_category, + CAST(null AS sql_identifier) AS ordering_routine_catalog, + CAST(null AS sql_identifier) AS ordering_routine_schema, + CAST(null AS sql_identifier) AS ordering_routine_name, + CAST(null AS character_data) AS reference_type, + CAST(null AS character_data) AS data_type, + CAST(null AS cardinal_number) AS character_maximum_length, + CAST(null AS cardinal_number) AS character_octet_length, + CAST(null AS sql_identifier) AS character_set_catalog, + CAST(null AS sql_identifier) AS character_set_schema, + CAST(null AS sql_identifier) AS character_set_name, + CAST(null AS sql_identifier) AS collation_catalog, + CAST(null AS sql_identifier) AS collation_schema, + CAST(null AS sql_identifier) AS collation_name, + CAST(null AS cardinal_number) AS numeric_precision, + CAST(null AS cardinal_number) AS numeric_precision_radix, + CAST(null AS cardinal_number) AS numeric_scale, + CAST(null AS cardinal_number) AS datetime_precision, + CAST(null AS character_data) AS interval_type, + CAST(null AS cardinal_number) AS interval_precision, + CAST(null AS sql_identifier) AS source_dtd_identifier, + CAST(null AS sql_identifier) AS ref_dtd_identifier + + FROM pg_namespace n, pg_class c, pg_type t + + WHERE n.oid = c.relnamespace + AND t.typrelid = c.oid + AND c.relkind = 'c' + AND (pg_has_role(t.typowner, 'USAGE') + OR has_type_privilege(t.oid, 'USAGE')); + +GRANT SELECT ON user_defined_types TO PUBLIC; + + +/* + * 5.77 + * VIEW_COLUMN_USAGE + */ + +CREATE VIEW view_column_usage AS + SELECT DISTINCT + CAST(current_database() AS sql_identifier) AS view_catalog, + CAST(nv.nspname AS sql_identifier) AS view_schema, + CAST(v.relname AS sql_identifier) AS view_name, + CAST(current_database() AS sql_identifier) AS table_catalog, + CAST(nt.nspname AS sql_identifier) AS table_schema, + CAST(t.relname AS sql_identifier) AS table_name, + CAST(a.attname AS sql_identifier) AS column_name + + FROM pg_namespace nv, pg_class v, pg_depend dv, + pg_depend dt, pg_class t, pg_namespace nt, + pg_attribute a + + WHERE nv.oid = v.relnamespace + AND v.relkind = 'v' + AND v.oid = dv.refobjid + AND dv.refclassid = 'pg_catalog.pg_class'::regclass + AND dv.classid = 'pg_catalog.pg_rewrite'::regclass + AND dv.deptype = 'i' + AND dv.objid = dt.objid + AND dv.refobjid <> dt.refobjid + AND dt.classid = 'pg_catalog.pg_rewrite'::regclass + AND dt.refclassid = 'pg_catalog.pg_class'::regclass + AND dt.refobjid = t.oid + AND t.relnamespace = nt.oid + AND t.relkind IN ('r', 'v', 'f', 'p') + AND t.oid = a.attrelid + AND dt.refobjsubid = a.attnum + AND pg_has_role(t.relowner, 'USAGE'); + +GRANT SELECT ON view_column_usage TO PUBLIC; + + +/* + * 5.78 + * VIEW_PERIOD_USAGE + */ + +-- feature not supported + + +/* + * 5.79 + * VIEW_ROUTINE_USAGE + */ + +CREATE VIEW view_routine_usage AS + SELECT DISTINCT + CAST(current_database() AS sql_identifier) AS table_catalog, + CAST(nv.nspname AS sql_identifier) AS table_schema, + CAST(v.relname AS sql_identifier) AS table_name, + CAST(current_database() AS sql_identifier) AS specific_catalog, + CAST(np.nspname AS sql_identifier) AS specific_schema, + CAST(nameconcatoid(p.proname, p.oid) AS sql_identifier) AS specific_name + + FROM pg_namespace nv, pg_class v, pg_depend dv, + pg_depend dp, pg_proc p, pg_namespace np + + WHERE nv.oid = v.relnamespace + AND v.relkind = 'v' + AND v.oid = dv.refobjid + AND dv.refclassid = 'pg_catalog.pg_class'::regclass + AND dv.classid = 'pg_catalog.pg_rewrite'::regclass + AND dv.deptype = 'i' + AND dv.objid = dp.objid + AND dp.classid = 'pg_catalog.pg_rewrite'::regclass + AND dp.refclassid = 'pg_catalog.pg_proc'::regclass + AND dp.refobjid = p.oid + AND p.pronamespace = np.oid + AND pg_has_role(p.proowner, 'USAGE'); + +GRANT SELECT ON view_routine_usage TO PUBLIC; + + +/* + * 5.80 + * VIEW_TABLE_USAGE + */ + +CREATE VIEW view_table_usage AS + SELECT DISTINCT + CAST(current_database() AS sql_identifier) AS view_catalog, + CAST(nv.nspname AS sql_identifier) AS view_schema, + CAST(v.relname AS sql_identifier) AS view_name, + CAST(current_database() AS sql_identifier) AS table_catalog, + CAST(nt.nspname AS sql_identifier) AS table_schema, + CAST(t.relname AS sql_identifier) AS table_name + + FROM pg_namespace nv, pg_class v, pg_depend dv, + pg_depend dt, pg_class t, pg_namespace nt + + WHERE nv.oid = v.relnamespace + AND v.relkind = 'v' + AND v.oid = dv.refobjid + AND dv.refclassid = 'pg_catalog.pg_class'::regclass + AND dv.classid = 'pg_catalog.pg_rewrite'::regclass + AND dv.deptype = 'i' + AND dv.objid = dt.objid + AND dv.refobjid <> dt.refobjid + AND dt.classid = 'pg_catalog.pg_rewrite'::regclass + AND dt.refclassid = 'pg_catalog.pg_class'::regclass + AND dt.refobjid = t.oid + AND t.relnamespace = nt.oid + AND t.relkind IN ('r', 'v', 'f', 'p') + AND pg_has_role(t.relowner, 'USAGE'); + +GRANT SELECT ON view_table_usage TO PUBLIC; + + +/* + * 5.81 + * VIEWS view + */ + +CREATE VIEW views AS + SELECT CAST(current_database() AS sql_identifier) AS table_catalog, + CAST(nc.nspname AS sql_identifier) AS table_schema, + CAST(c.relname AS sql_identifier) AS table_name, + + CAST( + CASE WHEN pg_has_role(c.relowner, 'USAGE') + THEN pg_get_viewdef(c.oid) + ELSE null END + AS character_data) AS view_definition, + + CAST( + CASE WHEN 'check_option=cascaded' = ANY (c.reloptions) + THEN 'CASCADED' + WHEN 'check_option=local' = ANY (c.reloptions) + THEN 'LOCAL' + ELSE 'NONE' END + AS character_data) AS check_option, + + CAST( + -- (1 << CMD_UPDATE) + (1 << CMD_DELETE) + CASE WHEN pg_relation_is_updatable(c.oid, false) & 20 = 20 + THEN 'YES' ELSE 'NO' END + AS yes_or_no) AS is_updatable, + + CAST( + -- 1 << CMD_INSERT + CASE WHEN pg_relation_is_updatable(c.oid, false) & 8 = 8 + THEN 'YES' ELSE 'NO' END + AS yes_or_no) AS is_insertable_into, + + CAST( + -- TRIGGER_TYPE_ROW + TRIGGER_TYPE_INSTEAD + TRIGGER_TYPE_UPDATE + CASE WHEN EXISTS (SELECT 1 FROM pg_trigger WHERE tgrelid = c.oid AND tgtype & 81 = 81) + THEN 'YES' ELSE 'NO' END + AS yes_or_no) AS is_trigger_updatable, + + CAST( + -- TRIGGER_TYPE_ROW + TRIGGER_TYPE_INSTEAD + TRIGGER_TYPE_DELETE + CASE WHEN EXISTS (SELECT 1 FROM pg_trigger WHERE tgrelid = c.oid AND tgtype & 73 = 73) + THEN 'YES' ELSE 'NO' END + AS yes_or_no) AS is_trigger_deletable, + + CAST( + -- TRIGGER_TYPE_ROW + TRIGGER_TYPE_INSTEAD + TRIGGER_TYPE_INSERT + CASE WHEN EXISTS (SELECT 1 FROM pg_trigger WHERE tgrelid = c.oid AND tgtype & 69 = 69) + THEN 'YES' ELSE 'NO' END + AS yes_or_no) AS is_trigger_insertable_into + + FROM pg_namespace nc, pg_class c + + WHERE c.relnamespace = nc.oid + AND c.relkind = 'v' + AND (NOT pg_is_other_temp_schema(nc.oid)) + AND (pg_has_role(c.relowner, 'USAGE') + OR has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER') + OR has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES') ); + +GRANT SELECT ON views TO PUBLIC; + + +-- The following views have dependencies that force them to appear out of order. + +/* + * 5.25 + * DATA_TYPE_PRIVILEGES view + */ + +CREATE VIEW data_type_privileges AS + SELECT CAST(current_database() AS sql_identifier) AS object_catalog, + CAST(x.objschema AS sql_identifier) AS object_schema, + CAST(x.objname AS sql_identifier) AS object_name, + CAST(x.objtype AS character_data) AS object_type, + CAST(x.objdtdid AS sql_identifier) AS dtd_identifier + + FROM + ( + SELECT udt_schema, udt_name, 'USER-DEFINED TYPE'::text, dtd_identifier FROM attributes + UNION ALL + SELECT table_schema, table_name, 'TABLE'::text, dtd_identifier FROM columns + UNION ALL + SELECT domain_schema, domain_name, 'DOMAIN'::text, dtd_identifier FROM domains + UNION ALL + SELECT specific_schema, specific_name, 'ROUTINE'::text, dtd_identifier FROM parameters + UNION ALL + SELECT specific_schema, specific_name, 'ROUTINE'::text, dtd_identifier FROM routines + ) AS x (objschema, objname, objtype, objdtdid); + +GRANT SELECT ON data_type_privileges TO PUBLIC; + + +/* + * 5.30 + * ELEMENT_TYPES view + */ + +CREATE VIEW element_types AS + SELECT CAST(current_database() AS sql_identifier) AS object_catalog, + CAST(n.nspname AS sql_identifier) AS object_schema, + CAST(x.objname AS sql_identifier) AS object_name, + CAST(x.objtype AS character_data) AS object_type, + CAST(x.objdtdid AS sql_identifier) AS collection_type_identifier, + CAST( + CASE WHEN nbt.nspname = 'pg_catalog' THEN format_type(bt.oid, null) + ELSE 'USER-DEFINED' END AS character_data) AS data_type, + + CAST(null AS cardinal_number) AS character_maximum_length, + CAST(null AS cardinal_number) AS character_octet_length, + CAST(null AS sql_identifier) AS character_set_catalog, + CAST(null AS sql_identifier) AS character_set_schema, + CAST(null AS sql_identifier) AS character_set_name, + CAST(CASE WHEN nco.nspname IS NOT NULL THEN current_database() END AS sql_identifier) AS collation_catalog, + CAST(nco.nspname AS sql_identifier) AS collation_schema, + CAST(co.collname AS sql_identifier) AS collation_name, + CAST(null AS cardinal_number) AS numeric_precision, + CAST(null AS cardinal_number) AS numeric_precision_radix, + CAST(null AS cardinal_number) AS numeric_scale, + CAST(null AS cardinal_number) AS datetime_precision, + CAST(null AS character_data) AS interval_type, + CAST(null AS cardinal_number) AS interval_precision, + + CAST(null AS character_data) AS domain_default, -- XXX maybe a bug in the standard + + CAST(current_database() AS sql_identifier) AS udt_catalog, + CAST(nbt.nspname AS sql_identifier) AS udt_schema, + CAST(bt.typname AS sql_identifier) AS udt_name, + + CAST(null AS sql_identifier) AS scope_catalog, + CAST(null AS sql_identifier) AS scope_schema, + CAST(null AS sql_identifier) AS scope_name, + + CAST(null AS cardinal_number) AS maximum_cardinality, + CAST('a' || CAST(x.objdtdid AS text) AS sql_identifier) AS dtd_identifier + + FROM pg_namespace n, pg_type at, pg_namespace nbt, pg_type bt, + ( + /* columns, attributes */ + SELECT c.relnamespace, CAST(c.relname AS sql_identifier), + CASE WHEN c.relkind = 'c' THEN 'USER-DEFINED TYPE'::text ELSE 'TABLE'::text END, + a.attnum, a.atttypid, a.attcollation + FROM pg_class c, pg_attribute a + WHERE c.oid = a.attrelid + AND c.relkind IN ('r', 'v', 'f', 'c', 'p') + AND attnum > 0 AND NOT attisdropped + + UNION ALL + + /* domains */ + SELECT t.typnamespace, CAST(t.typname AS sql_identifier), + 'DOMAIN'::text, 1, t.typbasetype, t.typcollation + FROM pg_type t + WHERE t.typtype = 'd' + + UNION ALL + + /* parameters */ + SELECT pronamespace, + CAST(nameconcatoid(proname, oid) AS sql_identifier), + 'ROUTINE'::text, (ss.x).n, (ss.x).x, 0 + FROM (SELECT p.pronamespace, p.proname, p.oid, + _pg_expandarray(coalesce(p.proallargtypes, p.proargtypes::oid[])) AS x + FROM pg_proc p) AS ss + + UNION ALL + + /* result types */ + SELECT p.pronamespace, + CAST(nameconcatoid(p.proname, p.oid) AS sql_identifier), + 'ROUTINE'::text, 0, p.prorettype, 0 + FROM pg_proc p + + ) AS x (objschema, objname, objtype, objdtdid, objtypeid, objcollation) + LEFT JOIN (pg_collation co JOIN pg_namespace nco ON (co.collnamespace = nco.oid)) + ON x.objcollation = co.oid AND (nco.nspname, co.collname) <> ('pg_catalog', 'default') + + WHERE n.oid = x.objschema + AND at.oid = x.objtypeid + AND (at.typelem <> 0 AND at.typlen = -1) + AND at.typelem = bt.oid + AND nbt.oid = bt.typnamespace + + AND (n.nspname, x.objname, x.objtype, CAST(x.objdtdid AS sql_identifier)) IN + ( SELECT object_schema, object_name, object_type, dtd_identifier + FROM data_type_privileges ); + +GRANT SELECT ON element_types TO PUBLIC; + + +-- SQL/MED views; these use section numbers from part 9 of the standard. + +/* Base view for foreign table columns */ +CREATE VIEW _pg_foreign_table_columns AS + SELECT n.nspname, + c.relname, + a.attname, + a.attfdwoptions + FROM pg_foreign_table t, pg_authid u, pg_namespace n, pg_class c, + pg_attribute a + WHERE u.oid = c.relowner + AND (pg_has_role(c.relowner, 'USAGE') + OR has_column_privilege(c.oid, a.attnum, 'SELECT, INSERT, UPDATE, REFERENCES')) + AND n.oid = c.relnamespace + AND c.oid = t.ftrelid + AND c.relkind = 'f' + AND a.attrelid = c.oid + AND a.attnum > 0; + +/* + * 24.2 + * COLUMN_OPTIONS view + */ +CREATE VIEW column_options AS + SELECT CAST(current_database() AS sql_identifier) AS table_catalog, + CAST(c.nspname AS sql_identifier) AS table_schema, + CAST(c.relname AS sql_identifier) AS table_name, + CAST(c.attname AS sql_identifier) AS column_name, + CAST((pg_options_to_table(c.attfdwoptions)).option_name AS sql_identifier) AS option_name, + CAST((pg_options_to_table(c.attfdwoptions)).option_value AS character_data) AS option_value + FROM _pg_foreign_table_columns c; + +GRANT SELECT ON column_options TO PUBLIC; + + +/* Base view for foreign-data wrappers */ +CREATE VIEW _pg_foreign_data_wrappers AS + SELECT w.oid, + w.fdwowner, + w.fdwoptions, + CAST(current_database() AS sql_identifier) AS foreign_data_wrapper_catalog, + CAST(fdwname AS sql_identifier) AS foreign_data_wrapper_name, + CAST(u.rolname AS sql_identifier) AS authorization_identifier, + CAST('c' AS character_data) AS foreign_data_wrapper_language + FROM pg_foreign_data_wrapper w, pg_authid u + WHERE u.oid = w.fdwowner + AND (pg_has_role(fdwowner, 'USAGE') + OR has_foreign_data_wrapper_privilege(w.oid, 'USAGE')); + + +/* + * 24.4 + * FOREIGN_DATA_WRAPPER_OPTIONS view + */ +CREATE VIEW foreign_data_wrapper_options AS + SELECT foreign_data_wrapper_catalog, + foreign_data_wrapper_name, + CAST((pg_options_to_table(w.fdwoptions)).option_name AS sql_identifier) AS option_name, + CAST((pg_options_to_table(w.fdwoptions)).option_value AS character_data) AS option_value + FROM _pg_foreign_data_wrappers w; + +GRANT SELECT ON foreign_data_wrapper_options TO PUBLIC; + + +/* + * 24.5 + * FOREIGN_DATA_WRAPPERS view + */ +CREATE VIEW foreign_data_wrappers AS + SELECT foreign_data_wrapper_catalog, + foreign_data_wrapper_name, + authorization_identifier, + CAST(NULL AS character_data) AS library_name, + foreign_data_wrapper_language + FROM _pg_foreign_data_wrappers w; + +GRANT SELECT ON foreign_data_wrappers TO PUBLIC; + + +/* Base view for foreign servers */ +CREATE VIEW _pg_foreign_servers AS + SELECT s.oid, + s.srvoptions, + CAST(current_database() AS sql_identifier) AS foreign_server_catalog, + CAST(srvname AS sql_identifier) AS foreign_server_name, + CAST(current_database() AS sql_identifier) AS foreign_data_wrapper_catalog, + CAST(w.fdwname AS sql_identifier) AS foreign_data_wrapper_name, + CAST(srvtype AS character_data) AS foreign_server_type, + CAST(srvversion AS character_data) AS foreign_server_version, + CAST(u.rolname AS sql_identifier) AS authorization_identifier + FROM pg_foreign_server s, pg_foreign_data_wrapper w, pg_authid u + WHERE w.oid = s.srvfdw + AND u.oid = s.srvowner + AND (pg_has_role(s.srvowner, 'USAGE') + OR has_server_privilege(s.oid, 'USAGE')); + + +/* + * 24.6 + * FOREIGN_SERVER_OPTIONS view + */ +CREATE VIEW foreign_server_options AS + SELECT foreign_server_catalog, + foreign_server_name, + CAST((pg_options_to_table(s.srvoptions)).option_name AS sql_identifier) AS option_name, + CAST((pg_options_to_table(s.srvoptions)).option_value AS character_data) AS option_value + FROM _pg_foreign_servers s; + +GRANT SELECT ON TABLE foreign_server_options TO PUBLIC; + + +/* + * 24.7 + * FOREIGN_SERVERS view + */ +CREATE VIEW foreign_servers AS + SELECT foreign_server_catalog, + foreign_server_name, + foreign_data_wrapper_catalog, + foreign_data_wrapper_name, + foreign_server_type, + foreign_server_version, + authorization_identifier + FROM _pg_foreign_servers; + +GRANT SELECT ON foreign_servers TO PUBLIC; + + +/* Base view for foreign tables */ +CREATE VIEW _pg_foreign_tables AS + SELECT + CAST(current_database() AS sql_identifier) AS foreign_table_catalog, + CAST(n.nspname AS sql_identifier) AS foreign_table_schema, + CAST(c.relname AS sql_identifier) AS foreign_table_name, + t.ftoptions AS ftoptions, + CAST(current_database() AS sql_identifier) AS foreign_server_catalog, + CAST(srvname AS sql_identifier) AS foreign_server_name, + CAST(u.rolname AS sql_identifier) AS authorization_identifier + FROM pg_foreign_table t, pg_foreign_server s, pg_foreign_data_wrapper w, + pg_authid u, pg_namespace n, pg_class c + WHERE w.oid = s.srvfdw + AND u.oid = c.relowner + AND (pg_has_role(c.relowner, 'USAGE') + OR has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER') + OR has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES')) + AND n.oid = c.relnamespace + AND c.oid = t.ftrelid + AND c.relkind = 'f' + AND s.oid = t.ftserver; + + +/* + * 24.8 + * FOREIGN_TABLE_OPTIONS view + */ +CREATE VIEW foreign_table_options AS + SELECT foreign_table_catalog, + foreign_table_schema, + foreign_table_name, + CAST((pg_options_to_table(t.ftoptions)).option_name AS sql_identifier) AS option_name, + CAST((pg_options_to_table(t.ftoptions)).option_value AS character_data) AS option_value + FROM _pg_foreign_tables t; + +GRANT SELECT ON TABLE foreign_table_options TO PUBLIC; + + +/* + * 24.9 + * FOREIGN_TABLES view + */ +CREATE VIEW foreign_tables AS + SELECT foreign_table_catalog, + foreign_table_schema, + foreign_table_name, + foreign_server_catalog, + foreign_server_name + FROM _pg_foreign_tables; + +GRANT SELECT ON foreign_tables TO PUBLIC; + + + +/* Base view for user mappings */ +CREATE VIEW _pg_user_mappings AS + SELECT um.oid, + um.umoptions, + um.umuser, + CAST(COALESCE(u.rolname,'PUBLIC') AS sql_identifier ) AS authorization_identifier, + s.foreign_server_catalog, + s.foreign_server_name, + s.authorization_identifier AS srvowner + FROM pg_user_mapping um LEFT JOIN pg_authid u ON (u.oid = um.umuser), + _pg_foreign_servers s + WHERE s.oid = um.umserver; + + +/* + * 24.12 + * USER_MAPPING_OPTIONS view + */ +CREATE VIEW user_mapping_options AS + SELECT authorization_identifier, + foreign_server_catalog, + foreign_server_name, + CAST(opts.option_name AS sql_identifier) AS option_name, + CAST(CASE WHEN (umuser <> 0 AND authorization_identifier = current_user) + OR (umuser = 0 AND pg_has_role(srvowner, 'USAGE')) + OR (SELECT rolsuper FROM pg_authid WHERE rolname = current_user) + THEN opts.option_value + ELSE NULL END AS character_data) AS option_value + FROM _pg_user_mappings um, + pg_options_to_table(um.umoptions) opts; + +GRANT SELECT ON user_mapping_options TO PUBLIC; + + +/* + * 24.13 + * USER_MAPPINGS view + */ +CREATE VIEW user_mappings AS + SELECT authorization_identifier, + foreign_server_catalog, + foreign_server_name + FROM _pg_user_mappings; + +GRANT SELECT ON user_mappings TO PUBLIC; diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c new file mode 100644 index 0000000..2ec2301 --- /dev/null +++ b/src/backend/catalog/namespace.c @@ -0,0 +1,4614 @@ +/*------------------------------------------------------------------------- + * + * namespace.c + * code to support accessing and searching namespaces + * + * This is separate from pg_namespace.c, which contains the routines that + * directly manipulate the pg_namespace system catalog. This module + * provides routines associated with defining a "namespace search path" + * and implementing search-path-controlled searches. + * + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/catalog/namespace.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/htup_details.h" +#include "access/parallel.h" +#include "access/xact.h" +#include "access/xlog.h" +#include "catalog/dependency.h" +#include "catalog/objectaccess.h" +#include "catalog/pg_authid.h" +#include "catalog/pg_collation.h" +#include "catalog/pg_conversion.h" +#include "catalog/pg_namespace.h" +#include "catalog/pg_opclass.h" +#include "catalog/pg_operator.h" +#include "catalog/pg_opfamily.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_statistic_ext.h" +#include "catalog/pg_ts_config.h" +#include "catalog/pg_ts_dict.h" +#include "catalog/pg_ts_parser.h" +#include "catalog/pg_ts_template.h" +#include "catalog/pg_type.h" +#include "commands/dbcommands.h" +#include "funcapi.h" +#include "mb/pg_wchar.h" +#include "miscadmin.h" +#include "nodes/makefuncs.h" +#include "parser/parse_func.h" +#include "storage/ipc.h" +#include "storage/lmgr.h" +#include "storage/sinvaladt.h" +#include "utils/acl.h" +#include "utils/builtins.h" +#include "utils/catcache.h" +#include "utils/guc.h" +#include "utils/inval.h" +#include "utils/lsyscache.h" +#include "utils/memutils.h" +#include "utils/syscache.h" +#include "utils/varlena.h" + + +/* + * The namespace search path is a possibly-empty list of namespace OIDs. + * In addition to the explicit list, implicitly-searched namespaces + * may be included: + * + * 1. If a TEMP table namespace has been initialized in this session, it + * is implicitly searched first. (The only time this doesn't happen is + * when we are obeying an override search path spec that says not to use the + * temp namespace, or the temp namespace is included in the explicit list.) + * + * 2. The system catalog namespace is always searched. If the system + * namespace is present in the explicit path then it will be searched in + * the specified order; otherwise it will be searched after TEMP tables and + * *before* the explicit list. (It might seem that the system namespace + * should be implicitly last, but this behavior appears to be required by + * SQL99. Also, this provides a way to search the system namespace first + * without thereby making it the default creation target namespace.) + * + * For security reasons, searches using the search path will ignore the temp + * namespace when searching for any object type other than relations and + * types. (We must allow types since temp tables have rowtypes.) + * + * The default creation target namespace is always the first element of the + * explicit list. If the explicit list is empty, there is no default target. + * + * The textual specification of search_path can include "$user" to refer to + * the namespace named the same as the current user, if any. (This is just + * ignored if there is no such namespace.) Also, it can include "pg_temp" + * to refer to the current backend's temp namespace. This is usually also + * ignorable if the temp namespace hasn't been set up, but there's a special + * case: if "pg_temp" appears first then it should be the default creation + * target. We kluge this case a little bit so that the temp namespace isn't + * set up until the first attempt to create something in it. (The reason for + * klugery is that we can't create the temp namespace outside a transaction, + * but initial GUC processing of search_path happens outside a transaction.) + * activeTempCreationPending is true if "pg_temp" appears first in the string + * but is not reflected in activeCreationNamespace because the namespace isn't + * set up yet. + * + * In bootstrap mode, the search path is set equal to "pg_catalog", so that + * the system namespace is the only one searched or inserted into. + * initdb is also careful to set search_path to "pg_catalog" for its + * post-bootstrap standalone backend runs. Otherwise the default search + * path is determined by GUC. The factory default path contains the PUBLIC + * namespace (if it exists), preceded by the user's personal namespace + * (if one exists). + * + * We support a stack of "override" search path settings for use within + * specific sections of backend code. namespace_search_path is ignored + * whenever the override stack is nonempty. activeSearchPath is always + * the actually active path; it points either to the search list of the + * topmost stack entry, or to baseSearchPath which is the list derived + * from namespace_search_path. + * + * If baseSearchPathValid is false, then baseSearchPath (and other + * derived variables) need to be recomputed from namespace_search_path. + * We mark it invalid upon an assignment to namespace_search_path or receipt + * of a syscache invalidation event for pg_namespace. The recomputation + * is done during the next non-overridden lookup attempt. Note that an + * override spec is never subject to recomputation. + * + * Any namespaces mentioned in namespace_search_path that are not readable + * by the current user ID are simply left out of baseSearchPath; so + * we have to be willing to recompute the path when current userid changes. + * namespaceUser is the userid the path has been computed for. + * + * Note: all data pointed to by these List variables is in TopMemoryContext. + * + * activePathGeneration is incremented whenever the effective values of + * activeSearchPath/activeCreationNamespace/activeTempCreationPending change. + * This can be used to quickly detect whether any change has happened since + * a previous examination of the search path state. + */ + +/* These variables define the actually active state: */ + +static List *activeSearchPath = NIL; + +/* default place to create stuff; if InvalidOid, no default */ +static Oid activeCreationNamespace = InvalidOid; + +/* if true, activeCreationNamespace is wrong, it should be temp namespace */ +static bool activeTempCreationPending = false; + +/* current generation counter; make sure this is never zero */ +static uint64 activePathGeneration = 1; + +/* These variables are the values last derived from namespace_search_path: */ + +static List *baseSearchPath = NIL; + +static Oid baseCreationNamespace = InvalidOid; + +static bool baseTempCreationPending = false; + +static Oid namespaceUser = InvalidOid; + +/* The above four values are valid only if baseSearchPathValid */ +static bool baseSearchPathValid = true; + +/* Override requests are remembered in a stack of OverrideStackEntry structs */ + +typedef struct +{ + List *searchPath; /* the desired search path */ + Oid creationNamespace; /* the desired creation namespace */ + int nestLevel; /* subtransaction nesting level */ +} OverrideStackEntry; + +static List *overrideStack = NIL; + +/* + * myTempNamespace is InvalidOid until and unless a TEMP namespace is set up + * in a particular backend session (this happens when a CREATE TEMP TABLE + * command is first executed). Thereafter it's the OID of the temp namespace. + * + * myTempToastNamespace is the OID of the namespace for my temp tables' toast + * tables. It is set when myTempNamespace is, and is InvalidOid before that. + * + * myTempNamespaceSubID shows whether we've created the TEMP namespace in the + * current subtransaction. The flag propagates up the subtransaction tree, + * so the main transaction will correctly recognize the flag if all + * intermediate subtransactions commit. When it is InvalidSubTransactionId, + * we either haven't made the TEMP namespace yet, or have successfully + * committed its creation, depending on whether myTempNamespace is valid. + */ +static Oid myTempNamespace = InvalidOid; + +static Oid myTempToastNamespace = InvalidOid; + +static SubTransactionId myTempNamespaceSubID = InvalidSubTransactionId; + +/* + * This is the user's textual search path specification --- it's the value + * of the GUC variable 'search_path'. + */ +char *namespace_search_path = NULL; + + +/* Local functions */ +static void recomputeNamespacePath(void); +static void AccessTempTableNamespace(bool force); +static void InitTempTableNamespace(void); +static void RemoveTempRelations(Oid tempNamespaceId); +static void RemoveTempRelationsCallback(int code, Datum arg); +static void NamespaceCallback(Datum arg, int cacheid, uint32 hashvalue); +static bool MatchNamedCall(HeapTuple proctup, int nargs, List *argnames, + int **argnumbers); + + +/* + * RangeVarGetRelidExtended + * Given a RangeVar describing an existing relation, + * select the proper namespace and look up the relation OID. + * + * If the schema or relation is not found, return InvalidOid if flags contains + * RVR_MISSING_OK, otherwise raise an error. + * + * If flags contains RVR_NOWAIT, throw an error if we'd have to wait for a + * lock. + * + * If flags contains RVR_SKIP_LOCKED, return InvalidOid if we'd have to wait + * for a lock. + * + * flags cannot contain both RVR_NOWAIT and RVR_SKIP_LOCKED. + * + * Note that if RVR_MISSING_OK and RVR_SKIP_LOCKED are both specified, a + * return value of InvalidOid could either mean the relation is missing or it + * could not be locked. + * + * Callback allows caller to check permissions or acquire additional locks + * prior to grabbing the relation lock. + */ +Oid +RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, + uint32 flags, + RangeVarGetRelidCallback callback, void *callback_arg) +{ + uint64 inval_count; + Oid relId; + Oid oldRelId = InvalidOid; + bool retry = false; + bool missing_ok = (flags & RVR_MISSING_OK) != 0; + + /* verify that flags do no conflict */ + Assert(!((flags & RVR_NOWAIT) && (flags & RVR_SKIP_LOCKED))); + + /* + * We check the catalog name and then ignore it. + */ + if (relation->catalogname) + { + if (strcmp(relation->catalogname, get_database_name(MyDatabaseId)) != 0) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cross-database references are not implemented: \"%s.%s.%s\"", + relation->catalogname, relation->schemaname, + relation->relname))); + } + + /* + * DDL operations can change the results of a name lookup. Since all such + * operations will generate invalidation messages, we keep track of + * whether any such messages show up while we're performing the operation, + * and retry until either (1) no more invalidation messages show up or (2) + * the answer doesn't change. + * + * But if lockmode = NoLock, then we assume that either the caller is OK + * with the answer changing under them, or that they already hold some + * appropriate lock, and therefore return the first answer we get without + * checking for invalidation messages. Also, if the requested lock is + * already held, LockRelationOid will not AcceptInvalidationMessages, so + * we may fail to notice a change. We could protect against that case by + * calling AcceptInvalidationMessages() before beginning this loop, but + * that would add a significant amount overhead, so for now we don't. + */ + for (;;) + { + /* + * Remember this value, so that, after looking up the relation name + * and locking its OID, we can check whether any invalidation messages + * have been processed that might require a do-over. + */ + inval_count = SharedInvalidMessageCounter; + + /* + * Some non-default relpersistence value may have been specified. The + * parser never generates such a RangeVar in simple DML, but it can + * happen in contexts such as "CREATE TEMP TABLE foo (f1 int PRIMARY + * KEY)". Such a command will generate an added CREATE INDEX + * operation, which must be careful to find the temp table, even when + * pg_temp is not first in the search path. + */ + if (relation->relpersistence == RELPERSISTENCE_TEMP) + { + if (!OidIsValid(myTempNamespace)) + relId = InvalidOid; /* this probably can't happen? */ + else + { + if (relation->schemaname) + { + Oid namespaceId; + + namespaceId = LookupExplicitNamespace(relation->schemaname, missing_ok); + + /* + * For missing_ok, allow a non-existent schema name to + * return InvalidOid. + */ + if (namespaceId != myTempNamespace) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("temporary tables cannot specify a schema name"))); + } + + relId = get_relname_relid(relation->relname, myTempNamespace); + } + } + else if (relation->schemaname) + { + Oid namespaceId; + + /* use exact schema given */ + namespaceId = LookupExplicitNamespace(relation->schemaname, missing_ok); + if (missing_ok && !OidIsValid(namespaceId)) + relId = InvalidOid; + else + relId = get_relname_relid(relation->relname, namespaceId); + } + else + { + /* search the namespace path */ + relId = RelnameGetRelid(relation->relname); + } + + /* + * Invoke caller-supplied callback, if any. + * + * This callback is a good place to check permissions: we haven't + * taken the table lock yet (and it's really best to check permissions + * before locking anything!), but we've gotten far enough to know what + * OID we think we should lock. Of course, concurrent DDL might + * change things while we're waiting for the lock, but in that case + * the callback will be invoked again for the new OID. + */ + if (callback) + callback(relation, relId, oldRelId, callback_arg); + + /* + * If no lock requested, we assume the caller knows what they're + * doing. They should have already acquired a heavyweight lock on + * this relation earlier in the processing of this same statement, so + * it wouldn't be appropriate to AcceptInvalidationMessages() here, as + * that might pull the rug out from under them. + */ + if (lockmode == NoLock) + break; + + /* + * If, upon retry, we get back the same OID we did last time, then the + * invalidation messages we processed did not change the final answer. + * So we're done. + * + * If we got a different OID, we've locked the relation that used to + * have this name rather than the one that does now. So release the + * lock. + */ + if (retry) + { + if (relId == oldRelId) + break; + if (OidIsValid(oldRelId)) + UnlockRelationOid(oldRelId, lockmode); + } + + /* + * Lock relation. This will also accept any pending invalidation + * messages. If we got back InvalidOid, indicating not found, then + * there's nothing to lock, but we accept invalidation messages + * anyway, to flush any negative catcache entries that may be + * lingering. + */ + if (!OidIsValid(relId)) + AcceptInvalidationMessages(); + else if (!(flags & (RVR_NOWAIT | RVR_SKIP_LOCKED))) + LockRelationOid(relId, lockmode); + else if (!ConditionalLockRelationOid(relId, lockmode)) + { + int elevel = (flags & RVR_SKIP_LOCKED) ? DEBUG1 : ERROR; + + if (relation->schemaname) + ereport(elevel, + (errcode(ERRCODE_LOCK_NOT_AVAILABLE), + errmsg("could not obtain lock on relation \"%s.%s\"", + relation->schemaname, relation->relname))); + else + ereport(elevel, + (errcode(ERRCODE_LOCK_NOT_AVAILABLE), + errmsg("could not obtain lock on relation \"%s\"", + relation->relname))); + + return InvalidOid; + } + + /* + * If no invalidation message were processed, we're done! + */ + if (inval_count == SharedInvalidMessageCounter) + break; + + /* + * Something may have changed. Let's repeat the name lookup, to make + * sure this name still references the same relation it did + * previously. + */ + retry = true; + oldRelId = relId; + } + + if (!OidIsValid(relId)) + { + int elevel = missing_ok ? DEBUG1 : ERROR; + + if (relation->schemaname) + ereport(elevel, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("relation \"%s.%s\" does not exist", + relation->schemaname, relation->relname))); + else + ereport(elevel, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("relation \"%s\" does not exist", + relation->relname))); + } + return relId; +} + +/* + * RangeVarGetCreationNamespace + * Given a RangeVar describing a to-be-created relation, + * choose which namespace to create it in. + * + * Note: calling this may result in a CommandCounterIncrement operation. + * That will happen on the first request for a temp table in any particular + * backend run; we will need to either create or clean out the temp schema. + */ +Oid +RangeVarGetCreationNamespace(const RangeVar *newRelation) +{ + Oid namespaceId; + + /* + * We check the catalog name and then ignore it. + */ + if (newRelation->catalogname) + { + if (strcmp(newRelation->catalogname, get_database_name(MyDatabaseId)) != 0) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cross-database references are not implemented: \"%s.%s.%s\"", + newRelation->catalogname, newRelation->schemaname, + newRelation->relname))); + } + + if (newRelation->schemaname) + { + /* check for pg_temp alias */ + if (strcmp(newRelation->schemaname, "pg_temp") == 0) + { + /* Initialize temp namespace */ + AccessTempTableNamespace(false); + return myTempNamespace; + } + /* use exact schema given */ + namespaceId = get_namespace_oid(newRelation->schemaname, false); + /* we do not check for USAGE rights here! */ + } + else if (newRelation->relpersistence == RELPERSISTENCE_TEMP) + { + /* Initialize temp namespace */ + AccessTempTableNamespace(false); + return myTempNamespace; + } + else + { + /* use the default creation namespace */ + recomputeNamespacePath(); + if (activeTempCreationPending) + { + /* Need to initialize temp namespace */ + AccessTempTableNamespace(true); + return myTempNamespace; + } + namespaceId = activeCreationNamespace; + if (!OidIsValid(namespaceId)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("no schema has been selected to create in"))); + } + + /* Note: callers will check for CREATE rights when appropriate */ + + return namespaceId; +} + +/* + * RangeVarGetAndCheckCreationNamespace + * + * This function returns the OID of the namespace in which a new relation + * with a given name should be created. If the user does not have CREATE + * permission on the target namespace, this function will instead signal + * an ERROR. + * + * If non-NULL, *existing_relation_id is set to the OID of any existing relation + * with the same name which already exists in that namespace, or to InvalidOid + * if no such relation exists. + * + * If lockmode != NoLock, the specified lock mode is acquired on the existing + * relation, if any, provided that the current user owns the target relation. + * However, if lockmode != NoLock and the user does not own the target + * relation, we throw an ERROR, as we must not try to lock relations the + * user does not have permissions on. + * + * As a side effect, this function acquires AccessShareLock on the target + * namespace. Without this, the namespace could be dropped before our + * transaction commits, leaving behind relations with relnamespace pointing + * to a no-longer-existent namespace. + * + * As a further side-effect, if the selected namespace is a temporary namespace, + * we mark the RangeVar as RELPERSISTENCE_TEMP. + */ +Oid +RangeVarGetAndCheckCreationNamespace(RangeVar *relation, + LOCKMODE lockmode, + Oid *existing_relation_id) +{ + uint64 inval_count; + Oid relid; + Oid oldrelid = InvalidOid; + Oid nspid; + Oid oldnspid = InvalidOid; + bool retry = false; + + /* + * We check the catalog name and then ignore it. + */ + if (relation->catalogname) + { + if (strcmp(relation->catalogname, get_database_name(MyDatabaseId)) != 0) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cross-database references are not implemented: \"%s.%s.%s\"", + relation->catalogname, relation->schemaname, + relation->relname))); + } + + /* + * As in RangeVarGetRelidExtended(), we guard against concurrent DDL + * operations by tracking whether any invalidation messages are processed + * while we're doing the name lookups and acquiring locks. See comments + * in that function for a more detailed explanation of this logic. + */ + for (;;) + { + AclResult aclresult; + + inval_count = SharedInvalidMessageCounter; + + /* Look up creation namespace and check for existing relation. */ + nspid = RangeVarGetCreationNamespace(relation); + Assert(OidIsValid(nspid)); + if (existing_relation_id != NULL) + relid = get_relname_relid(relation->relname, nspid); + else + relid = InvalidOid; + + /* + * In bootstrap processing mode, we don't bother with permissions or + * locking. Permissions might not be working yet, and locking is + * unnecessary. + */ + if (IsBootstrapProcessingMode()) + break; + + /* Check namespace permissions. */ + aclresult = pg_namespace_aclcheck(nspid, GetUserId(), ACL_CREATE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, OBJECT_SCHEMA, + get_namespace_name(nspid)); + + if (retry) + { + /* If nothing changed, we're done. */ + if (relid == oldrelid && nspid == oldnspid) + break; + /* If creation namespace has changed, give up old lock. */ + if (nspid != oldnspid) + UnlockDatabaseObject(NamespaceRelationId, oldnspid, 0, + AccessShareLock); + /* If name points to something different, give up old lock. */ + if (relid != oldrelid && OidIsValid(oldrelid) && lockmode != NoLock) + UnlockRelationOid(oldrelid, lockmode); + } + + /* Lock namespace. */ + if (nspid != oldnspid) + LockDatabaseObject(NamespaceRelationId, nspid, 0, AccessShareLock); + + /* Lock relation, if required if and we have permission. */ + if (lockmode != NoLock && OidIsValid(relid)) + { + if (!pg_class_ownercheck(relid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relid)), + relation->relname); + if (relid != oldrelid) + LockRelationOid(relid, lockmode); + } + + /* If no invalidation message were processed, we're done! */ + if (inval_count == SharedInvalidMessageCounter) + break; + + /* Something may have changed, so recheck our work. */ + retry = true; + oldrelid = relid; + oldnspid = nspid; + } + + RangeVarAdjustRelationPersistence(relation, nspid); + if (existing_relation_id != NULL) + *existing_relation_id = relid; + return nspid; +} + +/* + * Adjust the relpersistence for an about-to-be-created relation based on the + * creation namespace, and throw an error for invalid combinations. + */ +void +RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid) +{ + switch (newRelation->relpersistence) + { + case RELPERSISTENCE_TEMP: + if (!isTempOrTempToastNamespace(nspid)) + { + if (isAnyTempNamespace(nspid)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("cannot create relations in temporary schemas of other sessions"))); + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("cannot create temporary relation in non-temporary schema"))); + } + break; + case RELPERSISTENCE_PERMANENT: + if (isTempOrTempToastNamespace(nspid)) + newRelation->relpersistence = RELPERSISTENCE_TEMP; + else if (isAnyTempNamespace(nspid)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("cannot create relations in temporary schemas of other sessions"))); + break; + default: + if (isAnyTempNamespace(nspid)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("only temporary relations may be created in temporary schemas"))); + } +} + +/* + * RelnameGetRelid + * Try to resolve an unqualified relation name. + * Returns OID if relation found in search path, else InvalidOid. + */ +Oid +RelnameGetRelid(const char *relname) +{ + Oid relid; + ListCell *l; + + recomputeNamespacePath(); + + foreach(l, activeSearchPath) + { + Oid namespaceId = lfirst_oid(l); + + relid = get_relname_relid(relname, namespaceId); + if (OidIsValid(relid)) + return relid; + } + + /* Not found in path */ + return InvalidOid; +} + + +/* + * RelationIsVisible + * Determine whether a relation (identified by OID) is visible in the + * current search path. Visible means "would be found by searching + * for the unqualified relation name". + */ +bool +RelationIsVisible(Oid relid) +{ + HeapTuple reltup; + Form_pg_class relform; + Oid relnamespace; + bool visible; + + reltup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(reltup)) + elog(ERROR, "cache lookup failed for relation %u", relid); + relform = (Form_pg_class) GETSTRUCT(reltup); + + recomputeNamespacePath(); + + /* + * Quick check: if it ain't in the path at all, it ain't visible. Items in + * the system namespace are surely in the path and so we needn't even do + * list_member_oid() for them. + */ + relnamespace = relform->relnamespace; + if (relnamespace != PG_CATALOG_NAMESPACE && + !list_member_oid(activeSearchPath, relnamespace)) + visible = false; + else + { + /* + * If it is in the path, it might still not be visible; it could be + * hidden by another relation of the same name earlier in the path. So + * we must do a slow check for conflicting relations. + */ + char *relname = NameStr(relform->relname); + ListCell *l; + + visible = false; + foreach(l, activeSearchPath) + { + Oid namespaceId = lfirst_oid(l); + + if (namespaceId == relnamespace) + { + /* Found it first in path */ + visible = true; + break; + } + if (OidIsValid(get_relname_relid(relname, namespaceId))) + { + /* Found something else first in path */ + break; + } + } + } + + ReleaseSysCache(reltup); + + return visible; +} + + +/* + * TypenameGetTypid + * Wrapper for binary compatibility. + */ +Oid +TypenameGetTypid(const char *typname) +{ + return TypenameGetTypidExtended(typname, true); +} + +/* + * TypenameGetTypidExtended + * Try to resolve an unqualified datatype name. + * Returns OID if type found in search path, else InvalidOid. + * + * This is essentially the same as RelnameGetRelid. + */ +Oid +TypenameGetTypidExtended(const char *typname, bool temp_ok) +{ + Oid typid; + ListCell *l; + + recomputeNamespacePath(); + + foreach(l, activeSearchPath) + { + Oid namespaceId = lfirst_oid(l); + + if (!temp_ok && namespaceId == myTempNamespace) + continue; /* do not look in temp namespace */ + + typid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, + PointerGetDatum(typname), + ObjectIdGetDatum(namespaceId)); + if (OidIsValid(typid)) + return typid; + } + + /* Not found in path */ + return InvalidOid; +} + +/* + * TypeIsVisible + * Determine whether a type (identified by OID) is visible in the + * current search path. Visible means "would be found by searching + * for the unqualified type name". + */ +bool +TypeIsVisible(Oid typid) +{ + HeapTuple typtup; + Form_pg_type typform; + Oid typnamespace; + bool visible; + + typtup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); + if (!HeapTupleIsValid(typtup)) + elog(ERROR, "cache lookup failed for type %u", typid); + typform = (Form_pg_type) GETSTRUCT(typtup); + + recomputeNamespacePath(); + + /* + * Quick check: if it ain't in the path at all, it ain't visible. Items in + * the system namespace are surely in the path and so we needn't even do + * list_member_oid() for them. + */ + typnamespace = typform->typnamespace; + if (typnamespace != PG_CATALOG_NAMESPACE && + !list_member_oid(activeSearchPath, typnamespace)) + visible = false; + else + { + /* + * If it is in the path, it might still not be visible; it could be + * hidden by another type of the same name earlier in the path. So we + * must do a slow check for conflicting types. + */ + char *typname = NameStr(typform->typname); + ListCell *l; + + visible = false; + foreach(l, activeSearchPath) + { + Oid namespaceId = lfirst_oid(l); + + if (namespaceId == typnamespace) + { + /* Found it first in path */ + visible = true; + break; + } + if (SearchSysCacheExists2(TYPENAMENSP, + PointerGetDatum(typname), + ObjectIdGetDatum(namespaceId))) + { + /* Found something else first in path */ + break; + } + } + } + + ReleaseSysCache(typtup); + + return visible; +} + + +/* + * FuncnameGetCandidates + * Given a possibly-qualified function name and argument count, + * retrieve a list of the possible matches. + * + * If nargs is -1, we return all functions matching the given name, + * regardless of argument count. (argnames must be NIL, and expand_variadic + * and expand_defaults must be false, in this case.) + * + * If argnames isn't NIL, we are considering a named- or mixed-notation call, + * and only functions having all the listed argument names will be returned. + * (We assume that length(argnames) <= nargs and all the passed-in names are + * distinct.) The returned structs will include an argnumbers array showing + * the actual argument index for each logical argument position. + * + * If expand_variadic is true, then variadic functions having the same number + * or fewer arguments will be retrieved, with the variadic argument and any + * additional argument positions filled with the variadic element type. + * nvargs in the returned struct is set to the number of such arguments. + * If expand_variadic is false, variadic arguments are not treated specially, + * and the returned nvargs will always be zero. + * + * If expand_defaults is true, functions that could match after insertion of + * default argument values will also be retrieved. In this case the returned + * structs could have nargs > passed-in nargs, and ndargs is set to the number + * of additional args (which can be retrieved from the function's + * proargdefaults entry). + * + * It is not possible for nvargs and ndargs to both be nonzero in the same + * list entry, since default insertion allows matches to functions with more + * than nargs arguments while the variadic transformation requires the same + * number or less. + * + * When argnames isn't NIL, the returned args[] type arrays are not ordered + * according to the functions' declarations, but rather according to the call: + * first any positional arguments, then the named arguments, then defaulted + * arguments (if needed and allowed by expand_defaults). The argnumbers[] + * array can be used to map this back to the catalog information. + * argnumbers[k] is set to the proargtypes index of the k'th call argument. + * + * We search a single namespace if the function name is qualified, else + * all namespaces in the search path. In the multiple-namespace case, + * we arrange for entries in earlier namespaces to mask identical entries in + * later namespaces. + * + * When expanding variadics, we arrange for non-variadic functions to mask + * variadic ones if the expanded argument list is the same. It is still + * possible for there to be conflicts between different variadic functions, + * however. + * + * It is guaranteed that the return list will never contain multiple entries + * with identical argument lists. When expand_defaults is true, the entries + * could have more than nargs positions, but we still guarantee that they are + * distinct in the first nargs positions. However, if argnames isn't NIL or + * either expand_variadic or expand_defaults is true, there might be multiple + * candidate functions that expand to identical argument lists. Rather than + * throw error here, we report such situations by returning a single entry + * with oid = 0 that represents a set of such conflicting candidates. + * The caller might end up discarding such an entry anyway, but if it selects + * such an entry it should react as though the call were ambiguous. + * + * If missing_ok is true, an empty list (NULL) is returned if the name was + * schema- qualified with a schema that does not exist. Likewise if no + * candidate is found for other reasons. + */ +FuncCandidateList +FuncnameGetCandidates(List *names, int nargs, List *argnames, + bool expand_variadic, bool expand_defaults, + bool missing_ok) +{ + FuncCandidateList resultList = NULL; + bool any_special = false; + char *schemaname; + char *funcname; + Oid namespaceId; + CatCList *catlist; + int i; + + /* check for caller error */ + Assert(nargs >= 0 || !(expand_variadic | expand_defaults)); + + /* deconstruct the name list */ + DeconstructQualifiedName(names, &schemaname, &funcname); + + if (schemaname) + { + /* use exact schema given */ + namespaceId = LookupExplicitNamespace(schemaname, missing_ok); + if (!OidIsValid(namespaceId)) + return NULL; + } + else + { + /* flag to indicate we need namespace search */ + namespaceId = InvalidOid; + recomputeNamespacePath(); + } + + /* Search syscache by name only */ + catlist = SearchSysCacheList1(PROCNAMEARGSNSP, CStringGetDatum(funcname)); + + for (i = 0; i < catlist->n_members; i++) + { + HeapTuple proctup = &catlist->members[i]->tuple; + Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup); + int pronargs = procform->pronargs; + int effective_nargs; + int pathpos = 0; + bool variadic; + bool use_defaults; + Oid va_elem_type; + int *argnumbers = NULL; + FuncCandidateList newResult; + + if (OidIsValid(namespaceId)) + { + /* Consider only procs in specified namespace */ + if (procform->pronamespace != namespaceId) + continue; + } + else + { + /* + * Consider only procs that are in the search path and are not in + * the temp namespace. + */ + ListCell *nsp; + + foreach(nsp, activeSearchPath) + { + if (procform->pronamespace == lfirst_oid(nsp) && + procform->pronamespace != myTempNamespace) + break; + pathpos++; + } + if (nsp == NULL) + continue; /* proc is not in search path */ + } + + if (argnames != NIL) + { + /* + * Call uses named or mixed notation + * + * Named or mixed notation can match a variadic function only if + * expand_variadic is off; otherwise there is no way to match the + * presumed-nameless parameters expanded from the variadic array. + */ + if (OidIsValid(procform->provariadic) && expand_variadic) + continue; + va_elem_type = InvalidOid; + variadic = false; + + /* + * Check argument count. + */ + Assert(nargs >= 0); /* -1 not supported with argnames */ + + if (pronargs > nargs && expand_defaults) + { + /* Ignore if not enough default expressions */ + if (nargs + procform->pronargdefaults < pronargs) + continue; + use_defaults = true; + } + else + use_defaults = false; + + /* Ignore if it doesn't match requested argument count */ + if (pronargs != nargs && !use_defaults) + continue; + + /* Check for argument name match, generate positional mapping */ + if (!MatchNamedCall(proctup, nargs, argnames, + &argnumbers)) + continue; + + /* Named argument matching is always "special" */ + any_special = true; + } + else + { + /* + * Call uses positional notation + * + * Check if function is variadic, and get variadic element type if + * so. If expand_variadic is false, we should just ignore + * variadic-ness. + */ + if (pronargs <= nargs && expand_variadic) + { + va_elem_type = procform->provariadic; + variadic = OidIsValid(va_elem_type); + any_special |= variadic; + } + else + { + va_elem_type = InvalidOid; + variadic = false; + } + + /* + * Check if function can match by using parameter defaults. + */ + if (pronargs > nargs && expand_defaults) + { + /* Ignore if not enough default expressions */ + if (nargs + procform->pronargdefaults < pronargs) + continue; + use_defaults = true; + any_special = true; + } + else + use_defaults = false; + + /* Ignore if it doesn't match requested argument count */ + if (nargs >= 0 && pronargs != nargs && !variadic && !use_defaults) + continue; + } + + /* + * We must compute the effective argument list so that we can easily + * compare it to earlier results. We waste a palloc cycle if it gets + * masked by an earlier result, but really that's a pretty infrequent + * case so it's not worth worrying about. + */ + effective_nargs = Max(pronargs, nargs); + newResult = (FuncCandidateList) + palloc(offsetof(struct _FuncCandidateList, args) + + effective_nargs * sizeof(Oid)); + newResult->pathpos = pathpos; + newResult->oid = procform->oid; + newResult->nargs = effective_nargs; + newResult->argnumbers = argnumbers; + if (argnumbers) + { + /* Re-order the argument types into call's logical order */ + Oid *proargtypes = procform->proargtypes.values; + int i; + + for (i = 0; i < pronargs; i++) + newResult->args[i] = proargtypes[argnumbers[i]]; + } + else + { + /* Simple positional case, just copy proargtypes as-is */ + memcpy(newResult->args, procform->proargtypes.values, + pronargs * sizeof(Oid)); + } + if (variadic) + { + int i; + + newResult->nvargs = effective_nargs - pronargs + 1; + /* Expand variadic argument into N copies of element type */ + for (i = pronargs - 1; i < effective_nargs; i++) + newResult->args[i] = va_elem_type; + } + else + newResult->nvargs = 0; + newResult->ndargs = use_defaults ? pronargs - nargs : 0; + + /* + * Does it have the same arguments as something we already accepted? + * If so, decide what to do to avoid returning duplicate argument + * lists. We can skip this check for the single-namespace case if no + * special (named, variadic or defaults) match has been made, since + * then the unique index on pg_proc guarantees all the matches have + * different argument lists. + */ + if (resultList != NULL && + (any_special || !OidIsValid(namespaceId))) + { + /* + * If we have an ordered list from SearchSysCacheList (the normal + * case), then any conflicting proc must immediately adjoin this + * one in the list, so we only need to look at the newest result + * item. If we have an unordered list, we have to scan the whole + * result list. Also, if either the current candidate or any + * previous candidate is a special match, we can't assume that + * conflicts are adjacent. + * + * We ignore defaulted arguments in deciding what is a match. + */ + FuncCandidateList prevResult; + + if (catlist->ordered && !any_special) + { + /* ndargs must be 0 if !any_special */ + if (effective_nargs == resultList->nargs && + memcmp(newResult->args, + resultList->args, + effective_nargs * sizeof(Oid)) == 0) + prevResult = resultList; + else + prevResult = NULL; + } + else + { + int cmp_nargs = newResult->nargs - newResult->ndargs; + + for (prevResult = resultList; + prevResult; + prevResult = prevResult->next) + { + if (cmp_nargs == prevResult->nargs - prevResult->ndargs && + memcmp(newResult->args, + prevResult->args, + cmp_nargs * sizeof(Oid)) == 0) + break; + } + } + + if (prevResult) + { + /* + * We have a match with a previous result. Decide which one + * to keep, or mark it ambiguous if we can't decide. The + * logic here is preference > 0 means prefer the old result, + * preference < 0 means prefer the new, preference = 0 means + * ambiguous. + */ + int preference; + + if (pathpos != prevResult->pathpos) + { + /* + * Prefer the one that's earlier in the search path. + */ + preference = pathpos - prevResult->pathpos; + } + else if (variadic && prevResult->nvargs == 0) + { + /* + * With variadic functions we could have, for example, + * both foo(numeric) and foo(variadic numeric[]) in the + * same namespace; if so we prefer the non-variadic match + * on efficiency grounds. + */ + preference = 1; + } + else if (!variadic && prevResult->nvargs > 0) + { + preference = -1; + } + else + { + /*---------- + * We can't decide. This can happen with, for example, + * both foo(numeric, variadic numeric[]) and + * foo(variadic numeric[]) in the same namespace, or + * both foo(int) and foo (int, int default something) + * in the same namespace, or both foo(a int, b text) + * and foo(b text, a int) in the same namespace. + *---------- + */ + preference = 0; + } + + if (preference > 0) + { + /* keep previous result */ + pfree(newResult); + continue; + } + else if (preference < 0) + { + /* remove previous result from the list */ + if (prevResult == resultList) + resultList = prevResult->next; + else + { + FuncCandidateList prevPrevResult; + + for (prevPrevResult = resultList; + prevPrevResult; + prevPrevResult = prevPrevResult->next) + { + if (prevResult == prevPrevResult->next) + { + prevPrevResult->next = prevResult->next; + break; + } + } + Assert(prevPrevResult); /* assert we found it */ + } + pfree(prevResult); + /* fall through to add newResult to list */ + } + else + { + /* mark old result as ambiguous, discard new */ + prevResult->oid = InvalidOid; + pfree(newResult); + continue; + } + } + } + + /* + * Okay to add it to result list + */ + newResult->next = resultList; + resultList = newResult; + } + + ReleaseSysCacheList(catlist); + + return resultList; +} + +/* + * MatchNamedCall + * Given a pg_proc heap tuple and a call's list of argument names, + * check whether the function could match the call. + * + * The call could match if all supplied argument names are accepted by + * the function, in positions after the last positional argument, and there + * are defaults for all unsupplied arguments. + * + * The number of positional arguments is nargs - list_length(argnames). + * Note caller has already done basic checks on argument count. + * + * On match, return true and fill *argnumbers with a palloc'd array showing + * the mapping from call argument positions to actual function argument + * numbers. Defaulted arguments are included in this map, at positions + * after the last supplied argument. + */ +static bool +MatchNamedCall(HeapTuple proctup, int nargs, List *argnames, + int **argnumbers) +{ + Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup); + int pronargs = procform->pronargs; + int numposargs = nargs - list_length(argnames); + int pronallargs; + Oid *p_argtypes; + char **p_argnames; + char *p_argmodes; + bool arggiven[FUNC_MAX_ARGS]; + bool isnull; + int ap; /* call args position */ + int pp; /* proargs position */ + ListCell *lc; + + Assert(argnames != NIL); + Assert(numposargs >= 0); + Assert(nargs <= pronargs); + + /* Ignore this function if its proargnames is null */ + (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proargnames, + &isnull); + if (isnull) + return false; + + /* OK, let's extract the argument names and types */ + pronallargs = get_func_arg_info(proctup, + &p_argtypes, &p_argnames, &p_argmodes); + Assert(p_argnames != NULL); + + /* initialize state for matching */ + *argnumbers = (int *) palloc(pronargs * sizeof(int)); + memset(arggiven, false, pronargs * sizeof(bool)); + + /* there are numposargs positional args before the named args */ + for (ap = 0; ap < numposargs; ap++) + { + (*argnumbers)[ap] = ap; + arggiven[ap] = true; + } + + /* now examine the named args */ + foreach(lc, argnames) + { + char *argname = (char *) lfirst(lc); + bool found; + int i; + + pp = 0; + found = false; + for (i = 0; i < pronallargs; i++) + { + /* consider only input parameters */ + if (p_argmodes && + (p_argmodes[i] != FUNC_PARAM_IN && + p_argmodes[i] != FUNC_PARAM_INOUT && + p_argmodes[i] != FUNC_PARAM_VARIADIC)) + continue; + if (p_argnames[i] && strcmp(p_argnames[i], argname) == 0) + { + /* fail if argname matches a positional argument */ + if (arggiven[pp]) + return false; + arggiven[pp] = true; + (*argnumbers)[ap] = pp; + found = true; + break; + } + /* increase pp only for input parameters */ + pp++; + } + /* if name isn't in proargnames, fail */ + if (!found) + return false; + ap++; + } + + Assert(ap == nargs); /* processed all actual parameters */ + + /* Check for default arguments */ + if (nargs < pronargs) + { + int first_arg_with_default = pronargs - procform->pronargdefaults; + + for (pp = numposargs; pp < pronargs; pp++) + { + if (arggiven[pp]) + continue; + /* fail if arg not given and no default available */ + if (pp < first_arg_with_default) + return false; + (*argnumbers)[ap++] = pp; + } + } + + Assert(ap == pronargs); /* processed all function parameters */ + + return true; +} + +/* + * FunctionIsVisible + * Determine whether a function (identified by OID) is visible in the + * current search path. Visible means "would be found by searching + * for the unqualified function name with exact argument matches". + */ +bool +FunctionIsVisible(Oid funcid) +{ + HeapTuple proctup; + Form_pg_proc procform; + Oid pronamespace; + bool visible; + + proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); + if (!HeapTupleIsValid(proctup)) + elog(ERROR, "cache lookup failed for function %u", funcid); + procform = (Form_pg_proc) GETSTRUCT(proctup); + + recomputeNamespacePath(); + + /* + * Quick check: if it ain't in the path at all, it ain't visible. Items in + * the system namespace are surely in the path and so we needn't even do + * list_member_oid() for them. + */ + pronamespace = procform->pronamespace; + if (pronamespace != PG_CATALOG_NAMESPACE && + !list_member_oid(activeSearchPath, pronamespace)) + visible = false; + else + { + /* + * If it is in the path, it might still not be visible; it could be + * hidden by another proc of the same name and arguments earlier in + * the path. So we must do a slow check to see if this is the same + * proc that would be found by FuncnameGetCandidates. + */ + char *proname = NameStr(procform->proname); + int nargs = procform->pronargs; + FuncCandidateList clist; + + visible = false; + + clist = FuncnameGetCandidates(list_make1(makeString(proname)), + nargs, NIL, false, false, false); + + for (; clist; clist = clist->next) + { + if (memcmp(clist->args, procform->proargtypes.values, + nargs * sizeof(Oid)) == 0) + { + /* Found the expected entry; is it the right proc? */ + visible = (clist->oid == funcid); + break; + } + } + } + + ReleaseSysCache(proctup); + + return visible; +} + + +/* + * OpernameGetOprid + * Given a possibly-qualified operator name and exact input datatypes, + * look up the operator. Returns InvalidOid if not found. + * + * Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for + * a postfix op. + * + * If the operator name is not schema-qualified, it is sought in the current + * namespace search path. If the name is schema-qualified and the given + * schema does not exist, InvalidOid is returned. + */ +Oid +OpernameGetOprid(List *names, Oid oprleft, Oid oprright) +{ + char *schemaname; + char *opername; + CatCList *catlist; + ListCell *l; + + /* deconstruct the name list */ + DeconstructQualifiedName(names, &schemaname, &opername); + + if (schemaname) + { + /* search only in exact schema given */ + Oid namespaceId; + + namespaceId = LookupExplicitNamespace(schemaname, true); + if (OidIsValid(namespaceId)) + { + HeapTuple opertup; + + opertup = SearchSysCache4(OPERNAMENSP, + CStringGetDatum(opername), + ObjectIdGetDatum(oprleft), + ObjectIdGetDatum(oprright), + ObjectIdGetDatum(namespaceId)); + if (HeapTupleIsValid(opertup)) + { + Form_pg_operator operclass = (Form_pg_operator) GETSTRUCT(opertup); + Oid result = operclass->oid; + + ReleaseSysCache(opertup); + return result; + } + } + + return InvalidOid; + } + + /* Search syscache by name and argument types */ + catlist = SearchSysCacheList3(OPERNAMENSP, + CStringGetDatum(opername), + ObjectIdGetDatum(oprleft), + ObjectIdGetDatum(oprright)); + + if (catlist->n_members == 0) + { + /* no hope, fall out early */ + ReleaseSysCacheList(catlist); + return InvalidOid; + } + + /* + * We have to find the list member that is first in the search path, if + * there's more than one. This doubly-nested loop looks ugly, but in + * practice there should usually be few catlist members. + */ + recomputeNamespacePath(); + + foreach(l, activeSearchPath) + { + Oid namespaceId = lfirst_oid(l); + int i; + + if (namespaceId == myTempNamespace) + continue; /* do not look in temp namespace */ + + for (i = 0; i < catlist->n_members; i++) + { + HeapTuple opertup = &catlist->members[i]->tuple; + Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup); + + if (operform->oprnamespace == namespaceId) + { + Oid result = operform->oid; + + ReleaseSysCacheList(catlist); + return result; + } + } + } + + ReleaseSysCacheList(catlist); + return InvalidOid; +} + +/* + * OpernameGetCandidates + * Given a possibly-qualified operator name and operator kind, + * retrieve a list of the possible matches. + * + * If oprkind is '\0', we return all operators matching the given name, + * regardless of arguments. + * + * We search a single namespace if the operator name is qualified, else + * all namespaces in the search path. The return list will never contain + * multiple entries with identical argument lists --- in the multiple- + * namespace case, we arrange for entries in earlier namespaces to mask + * identical entries in later namespaces. + * + * The returned items always have two args[] entries --- one or the other + * will be InvalidOid for a prefix or postfix oprkind. nargs is 2, too. + */ +FuncCandidateList +OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok) +{ + FuncCandidateList resultList = NULL; + char *resultSpace = NULL; + int nextResult = 0; + char *schemaname; + char *opername; + Oid namespaceId; + CatCList *catlist; + int i; + + /* deconstruct the name list */ + DeconstructQualifiedName(names, &schemaname, &opername); + + if (schemaname) + { + /* use exact schema given */ + namespaceId = LookupExplicitNamespace(schemaname, missing_schema_ok); + if (missing_schema_ok && !OidIsValid(namespaceId)) + return NULL; + } + else + { + /* flag to indicate we need namespace search */ + namespaceId = InvalidOid; + recomputeNamespacePath(); + } + + /* Search syscache by name only */ + catlist = SearchSysCacheList1(OPERNAMENSP, CStringGetDatum(opername)); + + /* + * In typical scenarios, most if not all of the operators found by the + * catcache search will end up getting returned; and there can be quite a + * few, for common operator names such as '=' or '+'. To reduce the time + * spent in palloc, we allocate the result space as an array large enough + * to hold all the operators. The original coding of this routine did a + * separate palloc for each operator, but profiling revealed that the + * pallocs used an unreasonably large fraction of parsing time. + */ +#define SPACE_PER_OP MAXALIGN(offsetof(struct _FuncCandidateList, args) + \ + 2 * sizeof(Oid)) + + if (catlist->n_members > 0) + resultSpace = palloc(catlist->n_members * SPACE_PER_OP); + + for (i = 0; i < catlist->n_members; i++) + { + HeapTuple opertup = &catlist->members[i]->tuple; + Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup); + int pathpos = 0; + FuncCandidateList newResult; + + /* Ignore operators of wrong kind, if specific kind requested */ + if (oprkind && operform->oprkind != oprkind) + continue; + + if (OidIsValid(namespaceId)) + { + /* Consider only opers in specified namespace */ + if (operform->oprnamespace != namespaceId) + continue; + /* No need to check args, they must all be different */ + } + else + { + /* + * Consider only opers that are in the search path and are not in + * the temp namespace. + */ + ListCell *nsp; + + foreach(nsp, activeSearchPath) + { + if (operform->oprnamespace == lfirst_oid(nsp) && + operform->oprnamespace != myTempNamespace) + break; + pathpos++; + } + if (nsp == NULL) + continue; /* oper is not in search path */ + + /* + * Okay, it's in the search path, but does it have the same + * arguments as something we already accepted? If so, keep only + * the one that appears earlier in the search path. + * + * If we have an ordered list from SearchSysCacheList (the normal + * case), then any conflicting oper must immediately adjoin this + * one in the list, so we only need to look at the newest result + * item. If we have an unordered list, we have to scan the whole + * result list. + */ + if (resultList) + { + FuncCandidateList prevResult; + + if (catlist->ordered) + { + if (operform->oprleft == resultList->args[0] && + operform->oprright == resultList->args[1]) + prevResult = resultList; + else + prevResult = NULL; + } + else + { + for (prevResult = resultList; + prevResult; + prevResult = prevResult->next) + { + if (operform->oprleft == prevResult->args[0] && + operform->oprright == prevResult->args[1]) + break; + } + } + if (prevResult) + { + /* We have a match with a previous result */ + Assert(pathpos != prevResult->pathpos); + if (pathpos > prevResult->pathpos) + continue; /* keep previous result */ + /* replace previous result */ + prevResult->pathpos = pathpos; + prevResult->oid = operform->oid; + continue; /* args are same, of course */ + } + } + } + + /* + * Okay to add it to result list + */ + newResult = (FuncCandidateList) (resultSpace + nextResult); + nextResult += SPACE_PER_OP; + + newResult->pathpos = pathpos; + newResult->oid = operform->oid; + newResult->nargs = 2; + newResult->nvargs = 0; + newResult->ndargs = 0; + newResult->argnumbers = NULL; + newResult->args[0] = operform->oprleft; + newResult->args[1] = operform->oprright; + newResult->next = resultList; + resultList = newResult; + } + + ReleaseSysCacheList(catlist); + + return resultList; +} + +/* + * OperatorIsVisible + * Determine whether an operator (identified by OID) is visible in the + * current search path. Visible means "would be found by searching + * for the unqualified operator name with exact argument matches". + */ +bool +OperatorIsVisible(Oid oprid) +{ + HeapTuple oprtup; + Form_pg_operator oprform; + Oid oprnamespace; + bool visible; + + oprtup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprid)); + if (!HeapTupleIsValid(oprtup)) + elog(ERROR, "cache lookup failed for operator %u", oprid); + oprform = (Form_pg_operator) GETSTRUCT(oprtup); + + recomputeNamespacePath(); + + /* + * Quick check: if it ain't in the path at all, it ain't visible. Items in + * the system namespace are surely in the path and so we needn't even do + * list_member_oid() for them. + */ + oprnamespace = oprform->oprnamespace; + if (oprnamespace != PG_CATALOG_NAMESPACE && + !list_member_oid(activeSearchPath, oprnamespace)) + visible = false; + else + { + /* + * If it is in the path, it might still not be visible; it could be + * hidden by another operator of the same name and arguments earlier + * in the path. So we must do a slow check to see if this is the same + * operator that would be found by OpernameGetOprid. + */ + char *oprname = NameStr(oprform->oprname); + + visible = (OpernameGetOprid(list_make1(makeString(oprname)), + oprform->oprleft, oprform->oprright) + == oprid); + } + + ReleaseSysCache(oprtup); + + return visible; +} + + +/* + * OpclassnameGetOpcid + * Try to resolve an unqualified index opclass name. + * Returns OID if opclass found in search path, else InvalidOid. + * + * This is essentially the same as TypenameGetTypid, but we have to have + * an extra argument for the index AM OID. + */ +Oid +OpclassnameGetOpcid(Oid amid, const char *opcname) +{ + Oid opcid; + ListCell *l; + + recomputeNamespacePath(); + + foreach(l, activeSearchPath) + { + Oid namespaceId = lfirst_oid(l); + + if (namespaceId == myTempNamespace) + continue; /* do not look in temp namespace */ + + opcid = GetSysCacheOid3(CLAAMNAMENSP, Anum_pg_opclass_oid, + ObjectIdGetDatum(amid), + PointerGetDatum(opcname), + ObjectIdGetDatum(namespaceId)); + if (OidIsValid(opcid)) + return opcid; + } + + /* Not found in path */ + return InvalidOid; +} + +/* + * OpclassIsVisible + * Determine whether an opclass (identified by OID) is visible in the + * current search path. Visible means "would be found by searching + * for the unqualified opclass name". + */ +bool +OpclassIsVisible(Oid opcid) +{ + HeapTuple opctup; + Form_pg_opclass opcform; + Oid opcnamespace; + bool visible; + + opctup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcid)); + if (!HeapTupleIsValid(opctup)) + elog(ERROR, "cache lookup failed for opclass %u", opcid); + opcform = (Form_pg_opclass) GETSTRUCT(opctup); + + recomputeNamespacePath(); + + /* + * Quick check: if it ain't in the path at all, it ain't visible. Items in + * the system namespace are surely in the path and so we needn't even do + * list_member_oid() for them. + */ + opcnamespace = opcform->opcnamespace; + if (opcnamespace != PG_CATALOG_NAMESPACE && + !list_member_oid(activeSearchPath, opcnamespace)) + visible = false; + else + { + /* + * If it is in the path, it might still not be visible; it could be + * hidden by another opclass of the same name earlier in the path. So + * we must do a slow check to see if this opclass would be found by + * OpclassnameGetOpcid. + */ + char *opcname = NameStr(opcform->opcname); + + visible = (OpclassnameGetOpcid(opcform->opcmethod, opcname) == opcid); + } + + ReleaseSysCache(opctup); + + return visible; +} + +/* + * OpfamilynameGetOpfid + * Try to resolve an unqualified index opfamily name. + * Returns OID if opfamily found in search path, else InvalidOid. + * + * This is essentially the same as TypenameGetTypid, but we have to have + * an extra argument for the index AM OID. + */ +Oid +OpfamilynameGetOpfid(Oid amid, const char *opfname) +{ + Oid opfid; + ListCell *l; + + recomputeNamespacePath(); + + foreach(l, activeSearchPath) + { + Oid namespaceId = lfirst_oid(l); + + if (namespaceId == myTempNamespace) + continue; /* do not look in temp namespace */ + + opfid = GetSysCacheOid3(OPFAMILYAMNAMENSP, Anum_pg_opfamily_oid, + ObjectIdGetDatum(amid), + PointerGetDatum(opfname), + ObjectIdGetDatum(namespaceId)); + if (OidIsValid(opfid)) + return opfid; + } + + /* Not found in path */ + return InvalidOid; +} + +/* + * OpfamilyIsVisible + * Determine whether an opfamily (identified by OID) is visible in the + * current search path. Visible means "would be found by searching + * for the unqualified opfamily name". + */ +bool +OpfamilyIsVisible(Oid opfid) +{ + HeapTuple opftup; + Form_pg_opfamily opfform; + Oid opfnamespace; + bool visible; + + opftup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid)); + if (!HeapTupleIsValid(opftup)) + elog(ERROR, "cache lookup failed for opfamily %u", opfid); + opfform = (Form_pg_opfamily) GETSTRUCT(opftup); + + recomputeNamespacePath(); + + /* + * Quick check: if it ain't in the path at all, it ain't visible. Items in + * the system namespace are surely in the path and so we needn't even do + * list_member_oid() for them. + */ + opfnamespace = opfform->opfnamespace; + if (opfnamespace != PG_CATALOG_NAMESPACE && + !list_member_oid(activeSearchPath, opfnamespace)) + visible = false; + else + { + /* + * If it is in the path, it might still not be visible; it could be + * hidden by another opfamily of the same name earlier in the path. So + * we must do a slow check to see if this opfamily would be found by + * OpfamilynameGetOpfid. + */ + char *opfname = NameStr(opfform->opfname); + + visible = (OpfamilynameGetOpfid(opfform->opfmethod, opfname) == opfid); + } + + ReleaseSysCache(opftup); + + return visible; +} + +/* + * lookup_collation + * If there's a collation of the given name/namespace, and it works + * with the given encoding, return its OID. Else return InvalidOid. + */ +static Oid +lookup_collation(const char *collname, Oid collnamespace, int32 encoding) +{ + Oid collid; + HeapTuple colltup; + Form_pg_collation collform; + + /* Check for encoding-specific entry (exact match) */ + collid = GetSysCacheOid3(COLLNAMEENCNSP, Anum_pg_collation_oid, + PointerGetDatum(collname), + Int32GetDatum(encoding), + ObjectIdGetDatum(collnamespace)); + if (OidIsValid(collid)) + return collid; + + /* + * Check for any-encoding entry. This takes a bit more work: while libc + * collations with collencoding = -1 do work with all encodings, ICU + * collations only work with certain encodings, so we have to check that + * aspect before deciding it's a match. + */ + colltup = SearchSysCache3(COLLNAMEENCNSP, + PointerGetDatum(collname), + Int32GetDatum(-1), + ObjectIdGetDatum(collnamespace)); + if (!HeapTupleIsValid(colltup)) + return InvalidOid; + collform = (Form_pg_collation) GETSTRUCT(colltup); + if (collform->collprovider == COLLPROVIDER_ICU) + { + if (is_encoding_supported_by_icu(encoding)) + collid = collform->oid; + else + collid = InvalidOid; + } + else + { + collid = collform->oid; + } + ReleaseSysCache(colltup); + return collid; +} + +/* + * CollationGetCollid + * Try to resolve an unqualified collation name. + * Returns OID if collation found in search path, else InvalidOid. + * + * Note that this will only find collations that work with the current + * database's encoding. + */ +Oid +CollationGetCollid(const char *collname) +{ + int32 dbencoding = GetDatabaseEncoding(); + ListCell *l; + + recomputeNamespacePath(); + + foreach(l, activeSearchPath) + { + Oid namespaceId = lfirst_oid(l); + Oid collid; + + if (namespaceId == myTempNamespace) + continue; /* do not look in temp namespace */ + + collid = lookup_collation(collname, namespaceId, dbencoding); + if (OidIsValid(collid)) + return collid; + } + + /* Not found in path */ + return InvalidOid; +} + +/* + * CollationIsVisible + * Determine whether a collation (identified by OID) is visible in the + * current search path. Visible means "would be found by searching + * for the unqualified collation name". + * + * Note that only collations that work with the current database's encoding + * will be considered visible. + */ +bool +CollationIsVisible(Oid collid) +{ + HeapTuple colltup; + Form_pg_collation collform; + Oid collnamespace; + bool visible; + + colltup = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid)); + if (!HeapTupleIsValid(colltup)) + elog(ERROR, "cache lookup failed for collation %u", collid); + collform = (Form_pg_collation) GETSTRUCT(colltup); + + recomputeNamespacePath(); + + /* + * Quick check: if it ain't in the path at all, it ain't visible. Items in + * the system namespace are surely in the path and so we needn't even do + * list_member_oid() for them. + */ + collnamespace = collform->collnamespace; + if (collnamespace != PG_CATALOG_NAMESPACE && + !list_member_oid(activeSearchPath, collnamespace)) + visible = false; + else + { + /* + * If it is in the path, it might still not be visible; it could be + * hidden by another collation of the same name earlier in the path, + * or it might not work with the current DB encoding. So we must do a + * slow check to see if this collation would be found by + * CollationGetCollid. + */ + char *collname = NameStr(collform->collname); + + visible = (CollationGetCollid(collname) == collid); + } + + ReleaseSysCache(colltup); + + return visible; +} + + +/* + * ConversionGetConid + * Try to resolve an unqualified conversion name. + * Returns OID if conversion found in search path, else InvalidOid. + * + * This is essentially the same as RelnameGetRelid. + */ +Oid +ConversionGetConid(const char *conname) +{ + Oid conid; + ListCell *l; + + recomputeNamespacePath(); + + foreach(l, activeSearchPath) + { + Oid namespaceId = lfirst_oid(l); + + if (namespaceId == myTempNamespace) + continue; /* do not look in temp namespace */ + + conid = GetSysCacheOid2(CONNAMENSP, Anum_pg_conversion_oid, + PointerGetDatum(conname), + ObjectIdGetDatum(namespaceId)); + if (OidIsValid(conid)) + return conid; + } + + /* Not found in path */ + return InvalidOid; +} + +/* + * ConversionIsVisible + * Determine whether a conversion (identified by OID) is visible in the + * current search path. Visible means "would be found by searching + * for the unqualified conversion name". + */ +bool +ConversionIsVisible(Oid conid) +{ + HeapTuple contup; + Form_pg_conversion conform; + Oid connamespace; + bool visible; + + contup = SearchSysCache1(CONVOID, ObjectIdGetDatum(conid)); + if (!HeapTupleIsValid(contup)) + elog(ERROR, "cache lookup failed for conversion %u", conid); + conform = (Form_pg_conversion) GETSTRUCT(contup); + + recomputeNamespacePath(); + + /* + * Quick check: if it ain't in the path at all, it ain't visible. Items in + * the system namespace are surely in the path and so we needn't even do + * list_member_oid() for them. + */ + connamespace = conform->connamespace; + if (connamespace != PG_CATALOG_NAMESPACE && + !list_member_oid(activeSearchPath, connamespace)) + visible = false; + else + { + /* + * If it is in the path, it might still not be visible; it could be + * hidden by another conversion of the same name earlier in the path. + * So we must do a slow check to see if this conversion would be found + * by ConversionGetConid. + */ + char *conname = NameStr(conform->conname); + + visible = (ConversionGetConid(conname) == conid); + } + + ReleaseSysCache(contup); + + return visible; +} + +/* + * get_statistics_object_oid - find a statistics object by possibly qualified name + * + * If not found, returns InvalidOid if missing_ok, else throws error + */ +Oid +get_statistics_object_oid(List *names, bool missing_ok) +{ + char *schemaname; + char *stats_name; + Oid namespaceId; + Oid stats_oid = InvalidOid; + ListCell *l; + + /* deconstruct the name list */ + DeconstructQualifiedName(names, &schemaname, &stats_name); + + if (schemaname) + { + /* use exact schema given */ + namespaceId = LookupExplicitNamespace(schemaname, missing_ok); + if (missing_ok && !OidIsValid(namespaceId)) + stats_oid = InvalidOid; + else + stats_oid = GetSysCacheOid2(STATEXTNAMENSP, Anum_pg_statistic_ext_oid, + PointerGetDatum(stats_name), + ObjectIdGetDatum(namespaceId)); + } + else + { + /* search for it in search path */ + recomputeNamespacePath(); + + foreach(l, activeSearchPath) + { + namespaceId = lfirst_oid(l); + + if (namespaceId == myTempNamespace) + continue; /* do not look in temp namespace */ + stats_oid = GetSysCacheOid2(STATEXTNAMENSP, Anum_pg_statistic_ext_oid, + PointerGetDatum(stats_name), + ObjectIdGetDatum(namespaceId)); + if (OidIsValid(stats_oid)) + break; + } + } + + if (!OidIsValid(stats_oid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("statistics object \"%s\" does not exist", + NameListToString(names)))); + + return stats_oid; +} + +/* + * StatisticsObjIsVisible + * Determine whether a statistics object (identified by OID) is visible in + * the current search path. Visible means "would be found by searching + * for the unqualified statistics object name". + */ +bool +StatisticsObjIsVisible(Oid relid) +{ + HeapTuple stxtup; + Form_pg_statistic_ext stxform; + Oid stxnamespace; + bool visible; + + stxtup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(stxtup)) + elog(ERROR, "cache lookup failed for statistics object %u", relid); + stxform = (Form_pg_statistic_ext) GETSTRUCT(stxtup); + + recomputeNamespacePath(); + + /* + * Quick check: if it ain't in the path at all, it ain't visible. Items in + * the system namespace are surely in the path and so we needn't even do + * list_member_oid() for them. + */ + stxnamespace = stxform->stxnamespace; + if (stxnamespace != PG_CATALOG_NAMESPACE && + !list_member_oid(activeSearchPath, stxnamespace)) + visible = false; + else + { + /* + * If it is in the path, it might still not be visible; it could be + * hidden by another statistics object of the same name earlier in the + * path. So we must do a slow check for conflicting objects. + */ + char *stxname = NameStr(stxform->stxname); + ListCell *l; + + visible = false; + foreach(l, activeSearchPath) + { + Oid namespaceId = lfirst_oid(l); + + if (namespaceId == stxnamespace) + { + /* Found it first in path */ + visible = true; + break; + } + if (SearchSysCacheExists2(STATEXTNAMENSP, + PointerGetDatum(stxname), + ObjectIdGetDatum(namespaceId))) + { + /* Found something else first in path */ + break; + } + } + } + + ReleaseSysCache(stxtup); + + return visible; +} + +/* + * get_ts_parser_oid - find a TS parser by possibly qualified name + * + * If not found, returns InvalidOid if missing_ok, else throws error + */ +Oid +get_ts_parser_oid(List *names, bool missing_ok) +{ + char *schemaname; + char *parser_name; + Oid namespaceId; + Oid prsoid = InvalidOid; + ListCell *l; + + /* deconstruct the name list */ + DeconstructQualifiedName(names, &schemaname, &parser_name); + + if (schemaname) + { + /* use exact schema given */ + namespaceId = LookupExplicitNamespace(schemaname, missing_ok); + if (missing_ok && !OidIsValid(namespaceId)) + prsoid = InvalidOid; + else + prsoid = GetSysCacheOid2(TSPARSERNAMENSP, Anum_pg_ts_parser_oid, + PointerGetDatum(parser_name), + ObjectIdGetDatum(namespaceId)); + } + else + { + /* search for it in search path */ + recomputeNamespacePath(); + + foreach(l, activeSearchPath) + { + namespaceId = lfirst_oid(l); + + if (namespaceId == myTempNamespace) + continue; /* do not look in temp namespace */ + + prsoid = GetSysCacheOid2(TSPARSERNAMENSP, Anum_pg_ts_parser_oid, + PointerGetDatum(parser_name), + ObjectIdGetDatum(namespaceId)); + if (OidIsValid(prsoid)) + break; + } + } + + if (!OidIsValid(prsoid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("text search parser \"%s\" does not exist", + NameListToString(names)))); + + return prsoid; +} + +/* + * TSParserIsVisible + * Determine whether a parser (identified by OID) is visible in the + * current search path. Visible means "would be found by searching + * for the unqualified parser name". + */ +bool +TSParserIsVisible(Oid prsId) +{ + HeapTuple tup; + Form_pg_ts_parser form; + Oid namespace; + bool visible; + + tup = SearchSysCache1(TSPARSEROID, ObjectIdGetDatum(prsId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for text search parser %u", prsId); + form = (Form_pg_ts_parser) GETSTRUCT(tup); + + recomputeNamespacePath(); + + /* + * Quick check: if it ain't in the path at all, it ain't visible. Items in + * the system namespace are surely in the path and so we needn't even do + * list_member_oid() for them. + */ + namespace = form->prsnamespace; + if (namespace != PG_CATALOG_NAMESPACE && + !list_member_oid(activeSearchPath, namespace)) + visible = false; + else + { + /* + * If it is in the path, it might still not be visible; it could be + * hidden by another parser of the same name earlier in the path. So + * we must do a slow check for conflicting parsers. + */ + char *name = NameStr(form->prsname); + ListCell *l; + + visible = false; + foreach(l, activeSearchPath) + { + Oid namespaceId = lfirst_oid(l); + + if (namespaceId == myTempNamespace) + continue; /* do not look in temp namespace */ + + if (namespaceId == namespace) + { + /* Found it first in path */ + visible = true; + break; + } + if (SearchSysCacheExists2(TSPARSERNAMENSP, + PointerGetDatum(name), + ObjectIdGetDatum(namespaceId))) + { + /* Found something else first in path */ + break; + } + } + } + + ReleaseSysCache(tup); + + return visible; +} + +/* + * get_ts_dict_oid - find a TS dictionary by possibly qualified name + * + * If not found, returns InvalidOid if missing_ok, else throws error + */ +Oid +get_ts_dict_oid(List *names, bool missing_ok) +{ + char *schemaname; + char *dict_name; + Oid namespaceId; + Oid dictoid = InvalidOid; + ListCell *l; + + /* deconstruct the name list */ + DeconstructQualifiedName(names, &schemaname, &dict_name); + + if (schemaname) + { + /* use exact schema given */ + namespaceId = LookupExplicitNamespace(schemaname, missing_ok); + if (missing_ok && !OidIsValid(namespaceId)) + dictoid = InvalidOid; + else + dictoid = GetSysCacheOid2(TSDICTNAMENSP, Anum_pg_ts_dict_oid, + PointerGetDatum(dict_name), + ObjectIdGetDatum(namespaceId)); + } + else + { + /* search for it in search path */ + recomputeNamespacePath(); + + foreach(l, activeSearchPath) + { + namespaceId = lfirst_oid(l); + + if (namespaceId == myTempNamespace) + continue; /* do not look in temp namespace */ + + dictoid = GetSysCacheOid2(TSDICTNAMENSP, Anum_pg_ts_dict_oid, + PointerGetDatum(dict_name), + ObjectIdGetDatum(namespaceId)); + if (OidIsValid(dictoid)) + break; + } + } + + if (!OidIsValid(dictoid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("text search dictionary \"%s\" does not exist", + NameListToString(names)))); + + return dictoid; +} + +/* + * TSDictionaryIsVisible + * Determine whether a dictionary (identified by OID) is visible in the + * current search path. Visible means "would be found by searching + * for the unqualified dictionary name". + */ +bool +TSDictionaryIsVisible(Oid dictId) +{ + HeapTuple tup; + Form_pg_ts_dict form; + Oid namespace; + bool visible; + + tup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for text search dictionary %u", + dictId); + form = (Form_pg_ts_dict) GETSTRUCT(tup); + + recomputeNamespacePath(); + + /* + * Quick check: if it ain't in the path at all, it ain't visible. Items in + * the system namespace are surely in the path and so we needn't even do + * list_member_oid() for them. + */ + namespace = form->dictnamespace; + if (namespace != PG_CATALOG_NAMESPACE && + !list_member_oid(activeSearchPath, namespace)) + visible = false; + else + { + /* + * If it is in the path, it might still not be visible; it could be + * hidden by another dictionary of the same name earlier in the path. + * So we must do a slow check for conflicting dictionaries. + */ + char *name = NameStr(form->dictname); + ListCell *l; + + visible = false; + foreach(l, activeSearchPath) + { + Oid namespaceId = lfirst_oid(l); + + if (namespaceId == myTempNamespace) + continue; /* do not look in temp namespace */ + + if (namespaceId == namespace) + { + /* Found it first in path */ + visible = true; + break; + } + if (SearchSysCacheExists2(TSDICTNAMENSP, + PointerGetDatum(name), + ObjectIdGetDatum(namespaceId))) + { + /* Found something else first in path */ + break; + } + } + } + + ReleaseSysCache(tup); + + return visible; +} + +/* + * get_ts_template_oid - find a TS template by possibly qualified name + * + * If not found, returns InvalidOid if missing_ok, else throws error + */ +Oid +get_ts_template_oid(List *names, bool missing_ok) +{ + char *schemaname; + char *template_name; + Oid namespaceId; + Oid tmploid = InvalidOid; + ListCell *l; + + /* deconstruct the name list */ + DeconstructQualifiedName(names, &schemaname, &template_name); + + if (schemaname) + { + /* use exact schema given */ + namespaceId = LookupExplicitNamespace(schemaname, missing_ok); + if (missing_ok && !OidIsValid(namespaceId)) + tmploid = InvalidOid; + else + tmploid = GetSysCacheOid2(TSTEMPLATENAMENSP, Anum_pg_ts_template_oid, + PointerGetDatum(template_name), + ObjectIdGetDatum(namespaceId)); + } + else + { + /* search for it in search path */ + recomputeNamespacePath(); + + foreach(l, activeSearchPath) + { + namespaceId = lfirst_oid(l); + + if (namespaceId == myTempNamespace) + continue; /* do not look in temp namespace */ + + tmploid = GetSysCacheOid2(TSTEMPLATENAMENSP, Anum_pg_ts_template_oid, + PointerGetDatum(template_name), + ObjectIdGetDatum(namespaceId)); + if (OidIsValid(tmploid)) + break; + } + } + + if (!OidIsValid(tmploid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("text search template \"%s\" does not exist", + NameListToString(names)))); + + return tmploid; +} + +/* + * TSTemplateIsVisible + * Determine whether a template (identified by OID) is visible in the + * current search path. Visible means "would be found by searching + * for the unqualified template name". + */ +bool +TSTemplateIsVisible(Oid tmplId) +{ + HeapTuple tup; + Form_pg_ts_template form; + Oid namespace; + bool visible; + + tup = SearchSysCache1(TSTEMPLATEOID, ObjectIdGetDatum(tmplId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for text search template %u", tmplId); + form = (Form_pg_ts_template) GETSTRUCT(tup); + + recomputeNamespacePath(); + + /* + * Quick check: if it ain't in the path at all, it ain't visible. Items in + * the system namespace are surely in the path and so we needn't even do + * list_member_oid() for them. + */ + namespace = form->tmplnamespace; + if (namespace != PG_CATALOG_NAMESPACE && + !list_member_oid(activeSearchPath, namespace)) + visible = false; + else + { + /* + * If it is in the path, it might still not be visible; it could be + * hidden by another template of the same name earlier in the path. So + * we must do a slow check for conflicting templates. + */ + char *name = NameStr(form->tmplname); + ListCell *l; + + visible = false; + foreach(l, activeSearchPath) + { + Oid namespaceId = lfirst_oid(l); + + if (namespaceId == myTempNamespace) + continue; /* do not look in temp namespace */ + + if (namespaceId == namespace) + { + /* Found it first in path */ + visible = true; + break; + } + if (SearchSysCacheExists2(TSTEMPLATENAMENSP, + PointerGetDatum(name), + ObjectIdGetDatum(namespaceId))) + { + /* Found something else first in path */ + break; + } + } + } + + ReleaseSysCache(tup); + + return visible; +} + +/* + * get_ts_config_oid - find a TS config by possibly qualified name + * + * If not found, returns InvalidOid if missing_ok, else throws error + */ +Oid +get_ts_config_oid(List *names, bool missing_ok) +{ + char *schemaname; + char *config_name; + Oid namespaceId; + Oid cfgoid = InvalidOid; + ListCell *l; + + /* deconstruct the name list */ + DeconstructQualifiedName(names, &schemaname, &config_name); + + if (schemaname) + { + /* use exact schema given */ + namespaceId = LookupExplicitNamespace(schemaname, missing_ok); + if (missing_ok && !OidIsValid(namespaceId)) + cfgoid = InvalidOid; + else + cfgoid = GetSysCacheOid2(TSCONFIGNAMENSP, Anum_pg_ts_config_oid, + PointerGetDatum(config_name), + ObjectIdGetDatum(namespaceId)); + } + else + { + /* search for it in search path */ + recomputeNamespacePath(); + + foreach(l, activeSearchPath) + { + namespaceId = lfirst_oid(l); + + if (namespaceId == myTempNamespace) + continue; /* do not look in temp namespace */ + + cfgoid = GetSysCacheOid2(TSCONFIGNAMENSP, Anum_pg_ts_config_oid, + PointerGetDatum(config_name), + ObjectIdGetDatum(namespaceId)); + if (OidIsValid(cfgoid)) + break; + } + } + + if (!OidIsValid(cfgoid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("text search configuration \"%s\" does not exist", + NameListToString(names)))); + + return cfgoid; +} + +/* + * TSConfigIsVisible + * Determine whether a text search configuration (identified by OID) + * is visible in the current search path. Visible means "would be found + * by searching for the unqualified text search configuration name". + */ +bool +TSConfigIsVisible(Oid cfgid) +{ + HeapTuple tup; + Form_pg_ts_config form; + Oid namespace; + bool visible; + + tup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgid)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for text search configuration %u", + cfgid); + form = (Form_pg_ts_config) GETSTRUCT(tup); + + recomputeNamespacePath(); + + /* + * Quick check: if it ain't in the path at all, it ain't visible. Items in + * the system namespace are surely in the path and so we needn't even do + * list_member_oid() for them. + */ + namespace = form->cfgnamespace; + if (namespace != PG_CATALOG_NAMESPACE && + !list_member_oid(activeSearchPath, namespace)) + visible = false; + else + { + /* + * If it is in the path, it might still not be visible; it could be + * hidden by another configuration of the same name earlier in the + * path. So we must do a slow check for conflicting configurations. + */ + char *name = NameStr(form->cfgname); + ListCell *l; + + visible = false; + foreach(l, activeSearchPath) + { + Oid namespaceId = lfirst_oid(l); + + if (namespaceId == myTempNamespace) + continue; /* do not look in temp namespace */ + + if (namespaceId == namespace) + { + /* Found it first in path */ + visible = true; + break; + } + if (SearchSysCacheExists2(TSCONFIGNAMENSP, + PointerGetDatum(name), + ObjectIdGetDatum(namespaceId))) + { + /* Found something else first in path */ + break; + } + } + } + + ReleaseSysCache(tup); + + return visible; +} + + +/* + * DeconstructQualifiedName + * Given a possibly-qualified name expressed as a list of String nodes, + * extract the schema name and object name. + * + * *nspname_p is set to NULL if there is no explicit schema name. + */ +void +DeconstructQualifiedName(List *names, + char **nspname_p, + char **objname_p) +{ + char *catalogname; + char *schemaname = NULL; + char *objname = NULL; + + switch (list_length(names)) + { + case 1: + objname = strVal(linitial(names)); + break; + case 2: + schemaname = strVal(linitial(names)); + objname = strVal(lsecond(names)); + break; + case 3: + catalogname = strVal(linitial(names)); + schemaname = strVal(lsecond(names)); + objname = strVal(lthird(names)); + + /* + * We check the catalog name and then ignore it. + */ + if (strcmp(catalogname, get_database_name(MyDatabaseId)) != 0) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cross-database references are not implemented: %s", + NameListToString(names)))); + break; + default: + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("improper qualified name (too many dotted names): %s", + NameListToString(names)))); + break; + } + + *nspname_p = schemaname; + *objname_p = objname; +} + +/* + * LookupNamespaceNoError + * Look up a schema name. + * + * Returns the namespace OID, or InvalidOid if not found. + * + * Note this does NOT perform any permissions check --- callers are + * responsible for being sure that an appropriate check is made. + * In the majority of cases LookupExplicitNamespace is preferable. + */ +Oid +LookupNamespaceNoError(const char *nspname) +{ + /* check for pg_temp alias */ + if (strcmp(nspname, "pg_temp") == 0) + { + if (OidIsValid(myTempNamespace)) + { + InvokeNamespaceSearchHook(myTempNamespace, true); + return myTempNamespace; + } + + /* + * Since this is used only for looking up existing objects, there is + * no point in trying to initialize the temp namespace here; and doing + * so might create problems for some callers. Just report "not found". + */ + return InvalidOid; + } + + return get_namespace_oid(nspname, true); +} + +/* + * LookupExplicitNamespace + * Process an explicitly-specified schema name: look up the schema + * and verify we have USAGE (lookup) rights in it. + * + * Returns the namespace OID + */ +Oid +LookupExplicitNamespace(const char *nspname, bool missing_ok) +{ + Oid namespaceId; + AclResult aclresult; + + /* check for pg_temp alias */ + if (strcmp(nspname, "pg_temp") == 0) + { + if (OidIsValid(myTempNamespace)) + return myTempNamespace; + + /* + * Since this is used only for looking up existing objects, there is + * no point in trying to initialize the temp namespace here; and doing + * so might create problems for some callers --- just fall through. + */ + } + + namespaceId = get_namespace_oid(nspname, missing_ok); + if (missing_ok && !OidIsValid(namespaceId)) + return InvalidOid; + + aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, OBJECT_SCHEMA, + nspname); + /* Schema search hook for this lookup */ + InvokeNamespaceSearchHook(namespaceId, true); + + return namespaceId; +} + +/* + * LookupCreationNamespace + * Look up the schema and verify we have CREATE rights on it. + * + * This is just like LookupExplicitNamespace except for the different + * permission check, and that we are willing to create pg_temp if needed. + * + * Note: calling this may result in a CommandCounterIncrement operation, + * if we have to create or clean out the temp namespace. + */ +Oid +LookupCreationNamespace(const char *nspname) +{ + Oid namespaceId; + AclResult aclresult; + + /* check for pg_temp alias */ + if (strcmp(nspname, "pg_temp") == 0) + { + /* Initialize temp namespace */ + AccessTempTableNamespace(false); + return myTempNamespace; + } + + namespaceId = get_namespace_oid(nspname, false); + + aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, OBJECT_SCHEMA, + nspname); + + return namespaceId; +} + +/* + * Common checks on switching namespaces. + * + * We complain if either the old or new namespaces is a temporary schema + * (or temporary toast schema), or if either the old or new namespaces is the + * TOAST schema. + */ +void +CheckSetNamespace(Oid oldNspOid, Oid nspOid) +{ + /* disallow renaming into or out of temp schemas */ + if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot move objects into or out of temporary schemas"))); + + /* same for TOAST schema */ + if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot move objects into or out of TOAST schema"))); +} + +/* + * QualifiedNameGetCreationNamespace + * Given a possibly-qualified name for an object (in List-of-Values + * format), determine what namespace the object should be created in. + * Also extract and return the object name (last component of list). + * + * Note: this does not apply any permissions check. Callers must check + * for CREATE rights on the selected namespace when appropriate. + * + * Note: calling this may result in a CommandCounterIncrement operation, + * if we have to create or clean out the temp namespace. + */ +Oid +QualifiedNameGetCreationNamespace(List *names, char **objname_p) +{ + char *schemaname; + Oid namespaceId; + + /* deconstruct the name list */ + DeconstructQualifiedName(names, &schemaname, objname_p); + + if (schemaname) + { + /* check for pg_temp alias */ + if (strcmp(schemaname, "pg_temp") == 0) + { + /* Initialize temp namespace */ + AccessTempTableNamespace(false); + return myTempNamespace; + } + /* use exact schema given */ + namespaceId = get_namespace_oid(schemaname, false); + /* we do not check for USAGE rights here! */ + } + else + { + /* use the default creation namespace */ + recomputeNamespacePath(); + if (activeTempCreationPending) + { + /* Need to initialize temp namespace */ + AccessTempTableNamespace(true); + return myTempNamespace; + } + namespaceId = activeCreationNamespace; + if (!OidIsValid(namespaceId)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("no schema has been selected to create in"))); + } + + return namespaceId; +} + +/* + * get_namespace_oid - given a namespace name, look up the OID + * + * If missing_ok is false, throw an error if namespace name not found. If + * true, just return InvalidOid. + */ +Oid +get_namespace_oid(const char *nspname, bool missing_ok) +{ + Oid oid; + + oid = GetSysCacheOid1(NAMESPACENAME, Anum_pg_namespace_oid, + CStringGetDatum(nspname)); + if (!OidIsValid(oid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("schema \"%s\" does not exist", nspname))); + + return oid; +} + +/* + * makeRangeVarFromNameList + * Utility routine to convert a qualified-name list into RangeVar form. + */ +RangeVar * +makeRangeVarFromNameList(List *names) +{ + RangeVar *rel = makeRangeVar(NULL, NULL, -1); + + switch (list_length(names)) + { + case 1: + rel->relname = strVal(linitial(names)); + break; + case 2: + rel->schemaname = strVal(linitial(names)); + rel->relname = strVal(lsecond(names)); + break; + case 3: + rel->catalogname = strVal(linitial(names)); + rel->schemaname = strVal(lsecond(names)); + rel->relname = strVal(lthird(names)); + break; + default: + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("improper relation name (too many dotted names): %s", + NameListToString(names)))); + break; + } + + return rel; +} + +/* + * NameListToString + * Utility routine to convert a qualified-name list into a string. + * + * This is used primarily to form error messages, and so we do not quote + * the list elements, for the sake of legibility. + * + * In most scenarios the list elements should always be Value strings, + * but we also allow A_Star for the convenience of ColumnRef processing. + */ +char * +NameListToString(List *names) +{ + StringInfoData string; + ListCell *l; + + initStringInfo(&string); + + foreach(l, names) + { + Node *name = (Node *) lfirst(l); + + if (l != list_head(names)) + appendStringInfoChar(&string, '.'); + + if (IsA(name, String)) + appendStringInfoString(&string, strVal(name)); + else if (IsA(name, A_Star)) + appendStringInfoChar(&string, '*'); + else + elog(ERROR, "unexpected node type in name list: %d", + (int) nodeTag(name)); + } + + return string.data; +} + +/* + * NameListToQuotedString + * Utility routine to convert a qualified-name list into a string. + * + * Same as above except that names will be double-quoted where necessary, + * so the string could be re-parsed (eg, by textToQualifiedNameList). + */ +char * +NameListToQuotedString(List *names) +{ + StringInfoData string; + ListCell *l; + + initStringInfo(&string); + + foreach(l, names) + { + if (l != list_head(names)) + appendStringInfoChar(&string, '.'); + appendStringInfoString(&string, quote_identifier(strVal(lfirst(l)))); + } + + return string.data; +} + +/* + * isTempNamespace - is the given namespace my temporary-table namespace? + */ +bool +isTempNamespace(Oid namespaceId) +{ + if (OidIsValid(myTempNamespace) && myTempNamespace == namespaceId) + return true; + return false; +} + +/* + * isTempToastNamespace - is the given namespace my temporary-toast-table + * namespace? + */ +bool +isTempToastNamespace(Oid namespaceId) +{ + if (OidIsValid(myTempToastNamespace) && myTempToastNamespace == namespaceId) + return true; + return false; +} + +/* + * isTempOrTempToastNamespace - is the given namespace my temporary-table + * namespace or my temporary-toast-table namespace? + */ +bool +isTempOrTempToastNamespace(Oid namespaceId) +{ + if (OidIsValid(myTempNamespace) && + (myTempNamespace == namespaceId || myTempToastNamespace == namespaceId)) + return true; + return false; +} + +/* + * isAnyTempNamespace - is the given namespace a temporary-table namespace + * (either my own, or another backend's)? Temporary-toast-table namespaces + * are included, too. + */ +bool +isAnyTempNamespace(Oid namespaceId) +{ + bool result; + char *nspname; + + /* True if the namespace name starts with "pg_temp_" or "pg_toast_temp_" */ + nspname = get_namespace_name(namespaceId); + if (!nspname) + return false; /* no such namespace? */ + result = (strncmp(nspname, "pg_temp_", 8) == 0) || + (strncmp(nspname, "pg_toast_temp_", 14) == 0); + pfree(nspname); + return result; +} + +/* + * isOtherTempNamespace - is the given namespace some other backend's + * temporary-table namespace (including temporary-toast-table namespaces)? + * + * Note: for most purposes in the C code, this function is obsolete. Use + * RELATION_IS_OTHER_TEMP() instead to detect non-local temp relations. + */ +bool +isOtherTempNamespace(Oid namespaceId) +{ + /* If it's my own temp namespace, say "false" */ + if (isTempOrTempToastNamespace(namespaceId)) + return false; + /* Else, if it's any temp namespace, say "true" */ + return isAnyTempNamespace(namespaceId); +} + +/* + * checkTempNamespaceStatus - is the given namespace owned and actively used + * by a backend? + * + * Note: this can be used while scanning relations in pg_class to detect + * orphaned temporary tables or namespaces with a backend connected to a + * given database. The result may be out of date quickly, so the caller + * must be careful how to handle this information. + */ +TempNamespaceStatus +checkTempNamespaceStatus(Oid namespaceId) +{ + PGPROC *proc; + int backendId; + + Assert(OidIsValid(MyDatabaseId)); + + backendId = GetTempNamespaceBackendId(namespaceId); + + /* No such namespace, or its name shows it's not temp? */ + if (backendId == InvalidBackendId) + return TEMP_NAMESPACE_NOT_TEMP; + + /* Is the backend alive? */ + proc = BackendIdGetProc(backendId); + if (proc == NULL) + return TEMP_NAMESPACE_IDLE; + + /* Is the backend connected to the same database we are looking at? */ + if (proc->databaseId != MyDatabaseId) + return TEMP_NAMESPACE_IDLE; + + /* Does the backend own the temporary namespace? */ + if (proc->tempNamespaceId != namespaceId) + return TEMP_NAMESPACE_IDLE; + + /* Yup, so namespace is busy */ + return TEMP_NAMESPACE_IN_USE; +} + +/* + * GetTempNamespaceBackendId - if the given namespace is a temporary-table + * namespace (either my own, or another backend's), return the BackendId + * that owns it. Temporary-toast-table namespaces are included, too. + * If it isn't a temp namespace, return InvalidBackendId. + */ +int +GetTempNamespaceBackendId(Oid namespaceId) +{ + int result; + char *nspname; + + /* See if the namespace name starts with "pg_temp_" or "pg_toast_temp_" */ + nspname = get_namespace_name(namespaceId); + if (!nspname) + return InvalidBackendId; /* no such namespace? */ + if (strncmp(nspname, "pg_temp_", 8) == 0) + result = atoi(nspname + 8); + else if (strncmp(nspname, "pg_toast_temp_", 14) == 0) + result = atoi(nspname + 14); + else + result = InvalidBackendId; + pfree(nspname); + return result; +} + +/* + * GetTempToastNamespace - get the OID of my temporary-toast-table namespace, + * which must already be assigned. (This is only used when creating a toast + * table for a temp table, so we must have already done InitTempTableNamespace) + */ +Oid +GetTempToastNamespace(void) +{ + Assert(OidIsValid(myTempToastNamespace)); + return myTempToastNamespace; +} + + +/* + * GetTempNamespaceState - fetch status of session's temporary namespace + * + * This is used for conveying state to a parallel worker, and is not meant + * for general-purpose access. + */ +void +GetTempNamespaceState(Oid *tempNamespaceId, Oid *tempToastNamespaceId) +{ + /* Return namespace OIDs, or 0 if session has not created temp namespace */ + *tempNamespaceId = myTempNamespace; + *tempToastNamespaceId = myTempToastNamespace; +} + +/* + * SetTempNamespaceState - set status of session's temporary namespace + * + * This is used for conveying state to a parallel worker, and is not meant for + * general-purpose access. By transferring these namespace OIDs to workers, + * we ensure they will have the same notion of the search path as their leader + * does. + */ +void +SetTempNamespaceState(Oid tempNamespaceId, Oid tempToastNamespaceId) +{ + /* Worker should not have created its own namespaces ... */ + Assert(myTempNamespace == InvalidOid); + Assert(myTempToastNamespace == InvalidOid); + Assert(myTempNamespaceSubID == InvalidSubTransactionId); + + /* Assign same namespace OIDs that leader has */ + myTempNamespace = tempNamespaceId; + myTempToastNamespace = tempToastNamespaceId; + + /* + * It's fine to leave myTempNamespaceSubID == InvalidSubTransactionId. + * Even if the namespace is new so far as the leader is concerned, it's + * not new to the worker, and we certainly wouldn't want the worker trying + * to destroy it. + */ + + baseSearchPathValid = false; /* may need to rebuild list */ +} + + +/* + * GetOverrideSearchPath - fetch current search path definition in form + * used by PushOverrideSearchPath. + * + * The result structure is allocated in the specified memory context + * (which might or might not be equal to CurrentMemoryContext); but any + * junk created by revalidation calculations will be in CurrentMemoryContext. + */ +OverrideSearchPath * +GetOverrideSearchPath(MemoryContext context) +{ + OverrideSearchPath *result; + List *schemas; + MemoryContext oldcxt; + + recomputeNamespacePath(); + + oldcxt = MemoryContextSwitchTo(context); + + result = (OverrideSearchPath *) palloc0(sizeof(OverrideSearchPath)); + schemas = list_copy(activeSearchPath); + while (schemas && linitial_oid(schemas) != activeCreationNamespace) + { + if (linitial_oid(schemas) == myTempNamespace) + result->addTemp = true; + else + { + Assert(linitial_oid(schemas) == PG_CATALOG_NAMESPACE); + result->addCatalog = true; + } + schemas = list_delete_first(schemas); + } + result->schemas = schemas; + result->generation = activePathGeneration; + + MemoryContextSwitchTo(oldcxt); + + return result; +} + +/* + * CopyOverrideSearchPath - copy the specified OverrideSearchPath. + * + * The result structure is allocated in CurrentMemoryContext. + */ +OverrideSearchPath * +CopyOverrideSearchPath(OverrideSearchPath *path) +{ + OverrideSearchPath *result; + + result = (OverrideSearchPath *) palloc(sizeof(OverrideSearchPath)); + result->schemas = list_copy(path->schemas); + result->addCatalog = path->addCatalog; + result->addTemp = path->addTemp; + result->generation = path->generation; + + return result; +} + +/* + * OverrideSearchPathMatchesCurrent - does path match current setting? + * + * This is tested over and over in some common code paths, and in the typical + * scenario where the active search path seldom changes, it'll always succeed. + * We make that case fast by keeping a generation counter that is advanced + * whenever the active search path changes. + */ +bool +OverrideSearchPathMatchesCurrent(OverrideSearchPath *path) +{ + ListCell *lc, + *lcp; + + recomputeNamespacePath(); + + /* Quick out if already known equal to active path. */ + if (path->generation == activePathGeneration) + return true; + + /* We scan down the activeSearchPath to see if it matches the input. */ + lc = list_head(activeSearchPath); + + /* If path->addTemp, first item should be my temp namespace. */ + if (path->addTemp) + { + if (lc && lfirst_oid(lc) == myTempNamespace) + lc = lnext(activeSearchPath, lc); + else + return false; + } + /* If path->addCatalog, next item should be pg_catalog. */ + if (path->addCatalog) + { + if (lc && lfirst_oid(lc) == PG_CATALOG_NAMESPACE) + lc = lnext(activeSearchPath, lc); + else + return false; + } + /* We should now be looking at the activeCreationNamespace. */ + if (activeCreationNamespace != (lc ? lfirst_oid(lc) : InvalidOid)) + return false; + /* The remainder of activeSearchPath should match path->schemas. */ + foreach(lcp, path->schemas) + { + if (lc && lfirst_oid(lc) == lfirst_oid(lcp)) + lc = lnext(activeSearchPath, lc); + else + return false; + } + if (lc) + return false; + + /* + * Update path->generation so that future tests will return quickly, so + * long as the active search path doesn't change. + */ + path->generation = activePathGeneration; + + return true; +} + +/* + * PushOverrideSearchPath - temporarily override the search path + * + * We allow nested overrides, hence the push/pop terminology. The GUC + * search_path variable is ignored while an override is active. + * + * It's possible that newpath->useTemp is set but there is no longer any + * active temp namespace, if the path was saved during a transaction that + * created a temp namespace and was later rolled back. In that case we just + * ignore useTemp. A plausible alternative would be to create a new temp + * namespace, but for existing callers that's not necessary because an empty + * temp namespace wouldn't affect their results anyway. + * + * It's also worth noting that other schemas listed in newpath might not + * exist anymore either. We don't worry about this because OIDs that match + * no existing namespace will simply not produce any hits during searches. + */ +void +PushOverrideSearchPath(OverrideSearchPath *newpath) +{ + OverrideStackEntry *entry; + List *oidlist; + Oid firstNS; + MemoryContext oldcxt; + + /* + * Copy the list for safekeeping, and insert implicitly-searched + * namespaces as needed. This code should track recomputeNamespacePath. + */ + oldcxt = MemoryContextSwitchTo(TopMemoryContext); + + oidlist = list_copy(newpath->schemas); + + /* + * Remember the first member of the explicit list. + */ + if (oidlist == NIL) + firstNS = InvalidOid; + else + firstNS = linitial_oid(oidlist); + + /* + * Add any implicitly-searched namespaces to the list. Note these go on + * the front, not the back; also notice that we do not check USAGE + * permissions for these. + */ + if (newpath->addCatalog) + oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist); + + if (newpath->addTemp && OidIsValid(myTempNamespace)) + oidlist = lcons_oid(myTempNamespace, oidlist); + + /* + * Build the new stack entry, then insert it at the head of the list. + */ + entry = (OverrideStackEntry *) palloc(sizeof(OverrideStackEntry)); + entry->searchPath = oidlist; + entry->creationNamespace = firstNS; + entry->nestLevel = GetCurrentTransactionNestLevel(); + + overrideStack = lcons(entry, overrideStack); + + /* And make it active. */ + activeSearchPath = entry->searchPath; + activeCreationNamespace = entry->creationNamespace; + activeTempCreationPending = false; /* XXX is this OK? */ + + /* + * We always increment activePathGeneration when pushing/popping an + * override path. In current usage, these actions always change the + * effective path state, so there's no value in checking to see if it + * didn't change. + */ + activePathGeneration++; + + MemoryContextSwitchTo(oldcxt); +} + +/* + * PopOverrideSearchPath - undo a previous PushOverrideSearchPath + * + * Any push during a (sub)transaction will be popped automatically at abort. + * But it's caller error if a push isn't popped in normal control flow. + */ +void +PopOverrideSearchPath(void) +{ + OverrideStackEntry *entry; + + /* Sanity checks. */ + if (overrideStack == NIL) + elog(ERROR, "bogus PopOverrideSearchPath call"); + entry = (OverrideStackEntry *) linitial(overrideStack); + if (entry->nestLevel != GetCurrentTransactionNestLevel()) + elog(ERROR, "bogus PopOverrideSearchPath call"); + + /* Pop the stack and free storage. */ + overrideStack = list_delete_first(overrideStack); + list_free(entry->searchPath); + pfree(entry); + + /* Activate the next level down. */ + if (overrideStack) + { + entry = (OverrideStackEntry *) linitial(overrideStack); + activeSearchPath = entry->searchPath; + activeCreationNamespace = entry->creationNamespace; + activeTempCreationPending = false; /* XXX is this OK? */ + } + else + { + /* If not baseSearchPathValid, this is useless but harmless */ + activeSearchPath = baseSearchPath; + activeCreationNamespace = baseCreationNamespace; + activeTempCreationPending = baseTempCreationPending; + } + + /* As above, the generation always increments. */ + activePathGeneration++; +} + + +/* + * get_collation_oid - find a collation by possibly qualified name + * + * Note that this will only find collations that work with the current + * database's encoding. + */ +Oid +get_collation_oid(List *name, bool missing_ok) +{ + char *schemaname; + char *collation_name; + int32 dbencoding = GetDatabaseEncoding(); + Oid namespaceId; + Oid colloid; + ListCell *l; + + /* deconstruct the name list */ + DeconstructQualifiedName(name, &schemaname, &collation_name); + + if (schemaname) + { + /* use exact schema given */ + namespaceId = LookupExplicitNamespace(schemaname, missing_ok); + if (missing_ok && !OidIsValid(namespaceId)) + return InvalidOid; + + colloid = lookup_collation(collation_name, namespaceId, dbencoding); + if (OidIsValid(colloid)) + return colloid; + } + else + { + /* search for it in search path */ + recomputeNamespacePath(); + + foreach(l, activeSearchPath) + { + namespaceId = lfirst_oid(l); + + if (namespaceId == myTempNamespace) + continue; /* do not look in temp namespace */ + + colloid = lookup_collation(collation_name, namespaceId, dbencoding); + if (OidIsValid(colloid)) + return colloid; + } + } + + /* Not found in path */ + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("collation \"%s\" for encoding \"%s\" does not exist", + NameListToString(name), GetDatabaseEncodingName()))); + return InvalidOid; +} + +/* + * get_conversion_oid - find a conversion by possibly qualified name + */ +Oid +get_conversion_oid(List *name, bool missing_ok) +{ + char *schemaname; + char *conversion_name; + Oid namespaceId; + Oid conoid = InvalidOid; + ListCell *l; + + /* deconstruct the name list */ + DeconstructQualifiedName(name, &schemaname, &conversion_name); + + if (schemaname) + { + /* use exact schema given */ + namespaceId = LookupExplicitNamespace(schemaname, missing_ok); + if (missing_ok && !OidIsValid(namespaceId)) + conoid = InvalidOid; + else + conoid = GetSysCacheOid2(CONNAMENSP, Anum_pg_conversion_oid, + PointerGetDatum(conversion_name), + ObjectIdGetDatum(namespaceId)); + } + else + { + /* search for it in search path */ + recomputeNamespacePath(); + + foreach(l, activeSearchPath) + { + namespaceId = lfirst_oid(l); + + if (namespaceId == myTempNamespace) + continue; /* do not look in temp namespace */ + + conoid = GetSysCacheOid2(CONNAMENSP, Anum_pg_conversion_oid, + PointerGetDatum(conversion_name), + ObjectIdGetDatum(namespaceId)); + if (OidIsValid(conoid)) + return conoid; + } + } + + /* Not found in path */ + if (!OidIsValid(conoid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("conversion \"%s\" does not exist", + NameListToString(name)))); + return conoid; +} + +/* + * FindDefaultConversionProc - find default encoding conversion proc + */ +Oid +FindDefaultConversionProc(int32 for_encoding, int32 to_encoding) +{ + Oid proc; + ListCell *l; + + recomputeNamespacePath(); + + foreach(l, activeSearchPath) + { + Oid namespaceId = lfirst_oid(l); + + if (namespaceId == myTempNamespace) + continue; /* do not look in temp namespace */ + + proc = FindDefaultConversion(namespaceId, for_encoding, to_encoding); + if (OidIsValid(proc)) + return proc; + } + + /* Not found in path */ + return InvalidOid; +} + +/* + * recomputeNamespacePath - recompute path derived variables if needed. + */ +static void +recomputeNamespacePath(void) +{ + Oid roleid = GetUserId(); + char *rawname; + List *namelist; + List *oidlist; + List *newpath; + ListCell *l; + bool temp_missing; + Oid firstNS; + bool pathChanged; + MemoryContext oldcxt; + + /* Do nothing if an override search spec is active. */ + if (overrideStack) + return; + + /* Do nothing if path is already valid. */ + if (baseSearchPathValid && namespaceUser == roleid) + return; + + /* Need a modifiable copy of namespace_search_path string */ + rawname = pstrdup(namespace_search_path); + + /* Parse string into list of identifiers */ + if (!SplitIdentifierString(rawname, ',', &namelist)) + { + /* syntax error in name list */ + /* this should not happen if GUC checked check_search_path */ + elog(ERROR, "invalid list syntax"); + } + + /* + * Convert the list of names to a list of OIDs. If any names are not + * recognizable or we don't have read access, just leave them out of the + * list. (We can't raise an error, since the search_path setting has + * already been accepted.) Don't make duplicate entries, either. + */ + oidlist = NIL; + temp_missing = false; + foreach(l, namelist) + { + char *curname = (char *) lfirst(l); + Oid namespaceId; + + if (strcmp(curname, "$user") == 0) + { + /* $user --- substitute namespace matching user name, if any */ + HeapTuple tuple; + + tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid)); + if (HeapTupleIsValid(tuple)) + { + char *rname; + + rname = NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname); + namespaceId = get_namespace_oid(rname, true); + ReleaseSysCache(tuple); + if (OidIsValid(namespaceId) && + !list_member_oid(oidlist, namespaceId) && + pg_namespace_aclcheck(namespaceId, roleid, + ACL_USAGE) == ACLCHECK_OK && + InvokeNamespaceSearchHook(namespaceId, false)) + oidlist = lappend_oid(oidlist, namespaceId); + } + } + else if (strcmp(curname, "pg_temp") == 0) + { + /* pg_temp --- substitute temp namespace, if any */ + if (OidIsValid(myTempNamespace)) + { + if (!list_member_oid(oidlist, myTempNamespace) && + InvokeNamespaceSearchHook(myTempNamespace, false)) + oidlist = lappend_oid(oidlist, myTempNamespace); + } + else + { + /* If it ought to be the creation namespace, set flag */ + if (oidlist == NIL) + temp_missing = true; + } + } + else + { + /* normal namespace reference */ + namespaceId = get_namespace_oid(curname, true); + if (OidIsValid(namespaceId) && + !list_member_oid(oidlist, namespaceId) && + pg_namespace_aclcheck(namespaceId, roleid, + ACL_USAGE) == ACLCHECK_OK && + InvokeNamespaceSearchHook(namespaceId, false)) + oidlist = lappend_oid(oidlist, namespaceId); + } + } + + /* + * Remember the first member of the explicit list. (Note: this is + * nominally wrong if temp_missing, but we need it anyway to distinguish + * explicit from implicit mention of pg_catalog.) + */ + if (oidlist == NIL) + firstNS = InvalidOid; + else + firstNS = linitial_oid(oidlist); + + /* + * Add any implicitly-searched namespaces to the list. Note these go on + * the front, not the back; also notice that we do not check USAGE + * permissions for these. + */ + if (!list_member_oid(oidlist, PG_CATALOG_NAMESPACE)) + oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist); + + if (OidIsValid(myTempNamespace) && + !list_member_oid(oidlist, myTempNamespace)) + oidlist = lcons_oid(myTempNamespace, oidlist); + + /* + * We want to detect the case where the effective value of the base search + * path variables didn't change. As long as we're doing so, we can avoid + * copying the OID list unncessarily. + */ + if (baseCreationNamespace == firstNS && + baseTempCreationPending == temp_missing && + equal(oidlist, baseSearchPath)) + { + pathChanged = false; + } + else + { + pathChanged = true; + + /* Must save OID list in permanent storage. */ + oldcxt = MemoryContextSwitchTo(TopMemoryContext); + newpath = list_copy(oidlist); + MemoryContextSwitchTo(oldcxt); + + /* Now safe to assign to state variables. */ + list_free(baseSearchPath); + baseSearchPath = newpath; + baseCreationNamespace = firstNS; + baseTempCreationPending = temp_missing; + } + + /* Mark the path valid. */ + baseSearchPathValid = true; + namespaceUser = roleid; + + /* And make it active. */ + activeSearchPath = baseSearchPath; + activeCreationNamespace = baseCreationNamespace; + activeTempCreationPending = baseTempCreationPending; + + /* + * Bump the generation only if something actually changed. (Notice that + * what we compared to was the old state of the base path variables; so + * this does not deal with the situation where we have just popped an + * override path and restored the prior state of the base path. Instead + * we rely on the override-popping logic to have bumped the generation.) + */ + if (pathChanged) + activePathGeneration++; + + /* Clean up. */ + pfree(rawname); + list_free(namelist); + list_free(oidlist); +} + +/* + * AccessTempTableNamespace + * Provide access to a temporary namespace, potentially creating it + * if not present yet. This routine registers if the namespace gets + * in use in this transaction. 'force' can be set to true to allow + * the caller to enforce the creation of the temporary namespace for + * use in this backend, which happens if its creation is pending. + */ +static void +AccessTempTableNamespace(bool force) +{ + /* + * Make note that this temporary namespace has been accessed in this + * transaction. + */ + MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE; + + /* + * If the caller attempting to access a temporary schema expects the + * creation of the namespace to be pending and should be enforced, then go + * through the creation. + */ + if (!force && OidIsValid(myTempNamespace)) + return; + + /* + * The temporary tablespace does not exist yet and is wanted, so + * initialize it. + */ + InitTempTableNamespace(); +} + +/* + * InitTempTableNamespace + * Initialize temp table namespace on first use in a particular backend + */ +static void +InitTempTableNamespace(void) +{ + char namespaceName[NAMEDATALEN]; + Oid namespaceId; + Oid toastspaceId; + + Assert(!OidIsValid(myTempNamespace)); + + /* + * First, do permission check to see if we are authorized to make temp + * tables. We use a nonstandard error message here since "databasename: + * permission denied" might be a tad cryptic. + * + * Note that ACL_CREATE_TEMP rights are rechecked in pg_namespace_aclmask; + * that's necessary since current user ID could change during the session. + * But there's no need to make the namespace in the first place until a + * temp table creation request is made by someone with appropriate rights. + */ + if (pg_database_aclcheck(MyDatabaseId, GetUserId(), + ACL_CREATE_TEMP) != ACLCHECK_OK) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied to create temporary tables in database \"%s\"", + get_database_name(MyDatabaseId)))); + + /* + * Do not allow a Hot Standby session to make temp tables. Aside from + * problems with modifying the system catalogs, there is a naming + * conflict: pg_temp_N belongs to the session with BackendId N on the + * master, not to a hot standby session with the same BackendId. We + * should not be able to get here anyway due to XactReadOnly checks, but + * let's just make real sure. Note that this also backstops various + * operations that allow XactReadOnly transactions to modify temp tables; + * they'd need RecoveryInProgress checks if not for this. + */ + if (RecoveryInProgress()) + ereport(ERROR, + (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION), + errmsg("cannot create temporary tables during recovery"))); + + /* Parallel workers can't create temporary tables, either. */ + if (IsParallelWorker()) + ereport(ERROR, + (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION), + errmsg("cannot create temporary tables during a parallel operation"))); + + snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId); + + namespaceId = get_namespace_oid(namespaceName, true); + if (!OidIsValid(namespaceId)) + { + /* + * First use of this temp namespace in this database; create it. The + * temp namespaces are always owned by the superuser. We leave their + * permissions at default --- i.e., no access except to superuser --- + * to ensure that unprivileged users can't peek at other backends' + * temp tables. This works because the places that access the temp + * namespace for my own backend skip permissions checks on it. + */ + namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID, + true); + /* Advance command counter to make namespace visible */ + CommandCounterIncrement(); + } + else + { + /* + * If the namespace already exists, clean it out (in case the former + * owner crashed without doing so). + */ + RemoveTempRelations(namespaceId); + } + + /* + * If the corresponding toast-table namespace doesn't exist yet, create + * it. (We assume there is no need to clean it out if it does exist, since + * dropping a parent table should make its toast table go away.) + */ + snprintf(namespaceName, sizeof(namespaceName), "pg_toast_temp_%d", + MyBackendId); + + toastspaceId = get_namespace_oid(namespaceName, true); + if (!OidIsValid(toastspaceId)) + { + toastspaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID, + true); + /* Advance command counter to make namespace visible */ + CommandCounterIncrement(); + } + + /* + * Okay, we've prepared the temp namespace ... but it's not committed yet, + * so all our work could be undone by transaction rollback. Set flag for + * AtEOXact_Namespace to know what to do. + */ + myTempNamespace = namespaceId; + myTempToastNamespace = toastspaceId; + + /* + * Mark MyProc as owning this namespace which other processes can use to + * decide if a temporary namespace is in use or not. We assume that + * assignment of namespaceId is an atomic operation. Even if it is not, + * the temporary relation which resulted in the creation of this temporary + * namespace is still locked until the current transaction commits, and + * its pg_namespace row is not visible yet. However it does not matter: + * this flag makes the namespace as being in use, so no objects created on + * it would be removed concurrently. + */ + MyProc->tempNamespaceId = namespaceId; + + /* It should not be done already. */ + AssertState(myTempNamespaceSubID == InvalidSubTransactionId); + myTempNamespaceSubID = GetCurrentSubTransactionId(); + + baseSearchPathValid = false; /* need to rebuild list */ +} + +/* + * End-of-transaction cleanup for namespaces. + */ +void +AtEOXact_Namespace(bool isCommit, bool parallel) +{ + /* + * If we abort the transaction in which a temp namespace was selected, + * we'll have to do any creation or cleanout work over again. So, just + * forget the namespace entirely until next time. On the other hand, if + * we commit then register an exit callback to clean out the temp tables + * at backend shutdown. (We only want to register the callback once per + * session, so this is a good place to do it.) + */ + if (myTempNamespaceSubID != InvalidSubTransactionId && !parallel) + { + if (isCommit) + before_shmem_exit(RemoveTempRelationsCallback, 0); + else + { + myTempNamespace = InvalidOid; + myTempToastNamespace = InvalidOid; + baseSearchPathValid = false; /* need to rebuild list */ + + /* + * Reset the temporary namespace flag in MyProc. We assume that + * this operation is atomic. + * + * Because this transaction is aborting, the pg_namespace row is + * not visible to anyone else anyway, but that doesn't matter: + * it's not a problem if objects contained in this namespace are + * removed concurrently. + */ + MyProc->tempNamespaceId = InvalidOid; + } + myTempNamespaceSubID = InvalidSubTransactionId; + } + + /* + * Clean up if someone failed to do PopOverrideSearchPath + */ + if (overrideStack) + { + if (isCommit) + elog(WARNING, "leaked override search path"); + while (overrideStack) + { + OverrideStackEntry *entry; + + entry = (OverrideStackEntry *) linitial(overrideStack); + overrideStack = list_delete_first(overrideStack); + list_free(entry->searchPath); + pfree(entry); + } + /* If not baseSearchPathValid, this is useless but harmless */ + activeSearchPath = baseSearchPath; + activeCreationNamespace = baseCreationNamespace; + activeTempCreationPending = baseTempCreationPending; + /* Always bump generation --- see note in recomputeNamespacePath */ + activePathGeneration++; + } +} + +/* + * AtEOSubXact_Namespace + * + * At subtransaction commit, propagate the temp-namespace-creation + * flag to the parent subtransaction. + * + * At subtransaction abort, forget the flag if we set it up. + */ +void +AtEOSubXact_Namespace(bool isCommit, SubTransactionId mySubid, + SubTransactionId parentSubid) +{ + OverrideStackEntry *entry; + + if (myTempNamespaceSubID == mySubid) + { + if (isCommit) + myTempNamespaceSubID = parentSubid; + else + { + myTempNamespaceSubID = InvalidSubTransactionId; + /* TEMP namespace creation failed, so reset state */ + myTempNamespace = InvalidOid; + myTempToastNamespace = InvalidOid; + baseSearchPathValid = false; /* need to rebuild list */ + + /* + * Reset the temporary namespace flag in MyProc. We assume that + * this operation is atomic. + * + * Because this subtransaction is aborting, the pg_namespace row + * is not visible to anyone else anyway, but that doesn't matter: + * it's not a problem if objects contained in this namespace are + * removed concurrently. + */ + MyProc->tempNamespaceId = InvalidOid; + } + } + + /* + * Clean up if someone failed to do PopOverrideSearchPath + */ + while (overrideStack) + { + entry = (OverrideStackEntry *) linitial(overrideStack); + if (entry->nestLevel < GetCurrentTransactionNestLevel()) + break; + if (isCommit) + elog(WARNING, "leaked override search path"); + overrideStack = list_delete_first(overrideStack); + list_free(entry->searchPath); + pfree(entry); + /* Always bump generation --- see note in recomputeNamespacePath */ + activePathGeneration++; + } + + /* Activate the next level down. */ + if (overrideStack) + { + entry = (OverrideStackEntry *) linitial(overrideStack); + activeSearchPath = entry->searchPath; + activeCreationNamespace = entry->creationNamespace; + activeTempCreationPending = false; /* XXX is this OK? */ + + /* + * It's probably unnecessary to bump generation here, but this should + * not be a performance-critical case, so better to be over-cautious. + */ + activePathGeneration++; + } + else + { + /* If not baseSearchPathValid, this is useless but harmless */ + activeSearchPath = baseSearchPath; + activeCreationNamespace = baseCreationNamespace; + activeTempCreationPending = baseTempCreationPending; + + /* + * If we popped an override stack entry, then we already bumped the + * generation above. If we did not, then the above assignments did + * nothing and we need not bump the generation. + */ + } +} + +/* + * Remove all relations in the specified temp namespace. + * + * This is called at backend shutdown (if we made any temp relations). + * It is also called when we begin using a pre-existing temp namespace, + * in order to clean out any relations that might have been created by + * a crashed backend. + */ +static void +RemoveTempRelations(Oid tempNamespaceId) +{ + ObjectAddress object; + + /* + * We want to get rid of everything in the target namespace, but not the + * namespace itself (deleting it only to recreate it later would be a + * waste of cycles). Hence, specify SKIP_ORIGINAL. It's also an INTERNAL + * deletion, and we want to not drop any extensions that might happen to + * own temp objects. + */ + object.classId = NamespaceRelationId; + object.objectId = tempNamespaceId; + object.objectSubId = 0; + + performDeletion(&object, DROP_CASCADE, + PERFORM_DELETION_INTERNAL | + PERFORM_DELETION_QUIETLY | + PERFORM_DELETION_SKIP_ORIGINAL | + PERFORM_DELETION_SKIP_EXTENSIONS); +} + +/* + * Callback to remove temp relations at backend exit. + */ +static void +RemoveTempRelationsCallback(int code, Datum arg) +{ + if (OidIsValid(myTempNamespace)) /* should always be true */ + { + /* Need to ensure we have a usable transaction. */ + AbortOutOfAnyTransaction(); + StartTransactionCommand(); + + RemoveTempRelations(myTempNamespace); + + CommitTransactionCommand(); + } +} + +/* + * Remove all temp tables from the temporary namespace. + */ +void +ResetTempTableNamespace(void) +{ + if (OidIsValid(myTempNamespace)) + RemoveTempRelations(myTempNamespace); +} + + +/* + * Routines for handling the GUC variable 'search_path'. + */ + +/* check_hook: validate new search_path value */ +bool +check_search_path(char **newval, void **extra, GucSource source) +{ + char *rawname; + List *namelist; + + /* Need a modifiable copy of string */ + rawname = pstrdup(*newval); + + /* Parse string into list of identifiers */ + if (!SplitIdentifierString(rawname, ',', &namelist)) + { + /* syntax error in name list */ + GUC_check_errdetail("List syntax is invalid."); + pfree(rawname); + list_free(namelist); + return false; + } + + /* + * We used to try to check that the named schemas exist, but there are + * many valid use-cases for having search_path settings that include + * schemas that don't exist; and often, we are not inside a transaction + * here and so can't consult the system catalogs anyway. So now, the only + * requirement is syntactic validity of the identifier list. + */ + + pfree(rawname); + list_free(namelist); + + return true; +} + +/* assign_hook: do extra actions as needed */ +void +assign_search_path(const char *newval, void *extra) +{ + /* + * We mark the path as needing recomputation, but don't do anything until + * it's needed. This avoids trying to do database access during GUC + * initialization, or outside a transaction. + */ + baseSearchPathValid = false; +} + +/* + * InitializeSearchPath: initialize module during InitPostgres. + * + * This is called after we are up enough to be able to do catalog lookups. + */ +void +InitializeSearchPath(void) +{ + if (IsBootstrapProcessingMode()) + { + /* + * In bootstrap mode, the search path must be 'pg_catalog' so that + * tables are created in the proper namespace; ignore the GUC setting. + */ + MemoryContext oldcxt; + + oldcxt = MemoryContextSwitchTo(TopMemoryContext); + baseSearchPath = list_make1_oid(PG_CATALOG_NAMESPACE); + MemoryContextSwitchTo(oldcxt); + baseCreationNamespace = PG_CATALOG_NAMESPACE; + baseTempCreationPending = false; + baseSearchPathValid = true; + namespaceUser = GetUserId(); + activeSearchPath = baseSearchPath; + activeCreationNamespace = baseCreationNamespace; + activeTempCreationPending = baseTempCreationPending; + activePathGeneration++; /* pro forma */ + } + else + { + /* + * In normal mode, arrange for a callback on any syscache invalidation + * of pg_namespace rows. + */ + CacheRegisterSyscacheCallback(NAMESPACEOID, + NamespaceCallback, + (Datum) 0); + /* Force search path to be recomputed on next use */ + baseSearchPathValid = false; + } +} + +/* + * NamespaceCallback + * Syscache inval callback function + */ +static void +NamespaceCallback(Datum arg, int cacheid, uint32 hashvalue) +{ + /* Force search path to be recomputed on next use */ + baseSearchPathValid = false; +} + +/* + * Fetch the active search path. The return value is a palloc'ed list + * of OIDs; the caller is responsible for freeing this storage as + * appropriate. + * + * The returned list includes the implicitly-prepended namespaces only if + * includeImplicit is true. + * + * Note: calling this may result in a CommandCounterIncrement operation, + * if we have to create or clean out the temp namespace. + */ +List * +fetch_search_path(bool includeImplicit) +{ + List *result; + + recomputeNamespacePath(); + + /* + * If the temp namespace should be first, force it to exist. This is so + * that callers can trust the result to reflect the actual default + * creation namespace. It's a bit bogus to do this here, since + * current_schema() is supposedly a stable function without side-effects, + * but the alternatives seem worse. + */ + if (activeTempCreationPending) + { + AccessTempTableNamespace(true); + recomputeNamespacePath(); + } + + result = list_copy(activeSearchPath); + if (!includeImplicit) + { + while (result && linitial_oid(result) != activeCreationNamespace) + result = list_delete_first(result); + } + + return result; +} + +/* + * Fetch the active search path into a caller-allocated array of OIDs. + * Returns the number of path entries. (If this is more than sarray_len, + * then the data didn't fit and is not all stored.) + * + * The returned list always includes the implicitly-prepended namespaces, + * but never includes the temp namespace. (This is suitable for existing + * users, which would want to ignore the temp namespace anyway.) This + * definition allows us to not worry about initializing the temp namespace. + */ +int +fetch_search_path_array(Oid *sarray, int sarray_len) +{ + int count = 0; + ListCell *l; + + recomputeNamespacePath(); + + foreach(l, activeSearchPath) + { + Oid namespaceId = lfirst_oid(l); + + if (namespaceId == myTempNamespace) + continue; /* do not include temp namespace */ + + if (count < sarray_len) + sarray[count] = namespaceId; + count++; + } + + return count; +} + + +/* + * Export the FooIsVisible functions as SQL-callable functions. + * + * Note: as of Postgres 8.4, these will silently return NULL if called on + * a nonexistent object OID, rather than failing. This is to avoid race + * condition errors when a query that's scanning a catalog using an MVCC + * snapshot uses one of these functions. The underlying IsVisible functions + * always use an up-to-date snapshot and so might see the object as already + * gone when it's still visible to the transaction snapshot. (There is no race + * condition in the current coding because we don't accept sinval messages + * between the SearchSysCacheExists test and the subsequent lookup.) + */ + +Datum +pg_table_is_visible(PG_FUNCTION_ARGS) +{ + Oid oid = PG_GETARG_OID(0); + + if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(oid))) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(RelationIsVisible(oid)); +} + +Datum +pg_type_is_visible(PG_FUNCTION_ARGS) +{ + Oid oid = PG_GETARG_OID(0); + + if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(oid))) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(TypeIsVisible(oid)); +} + +Datum +pg_function_is_visible(PG_FUNCTION_ARGS) +{ + Oid oid = PG_GETARG_OID(0); + + if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(oid))) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(FunctionIsVisible(oid)); +} + +Datum +pg_operator_is_visible(PG_FUNCTION_ARGS) +{ + Oid oid = PG_GETARG_OID(0); + + if (!SearchSysCacheExists1(OPEROID, ObjectIdGetDatum(oid))) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(OperatorIsVisible(oid)); +} + +Datum +pg_opclass_is_visible(PG_FUNCTION_ARGS) +{ + Oid oid = PG_GETARG_OID(0); + + if (!SearchSysCacheExists1(CLAOID, ObjectIdGetDatum(oid))) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(OpclassIsVisible(oid)); +} + +Datum +pg_opfamily_is_visible(PG_FUNCTION_ARGS) +{ + Oid oid = PG_GETARG_OID(0); + + if (!SearchSysCacheExists1(OPFAMILYOID, ObjectIdGetDatum(oid))) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(OpfamilyIsVisible(oid)); +} + +Datum +pg_collation_is_visible(PG_FUNCTION_ARGS) +{ + Oid oid = PG_GETARG_OID(0); + + if (!SearchSysCacheExists1(COLLOID, ObjectIdGetDatum(oid))) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(CollationIsVisible(oid)); +} + +Datum +pg_conversion_is_visible(PG_FUNCTION_ARGS) +{ + Oid oid = PG_GETARG_OID(0); + + if (!SearchSysCacheExists1(CONVOID, ObjectIdGetDatum(oid))) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(ConversionIsVisible(oid)); +} + +Datum +pg_statistics_obj_is_visible(PG_FUNCTION_ARGS) +{ + Oid oid = PG_GETARG_OID(0); + + if (!SearchSysCacheExists1(STATEXTOID, ObjectIdGetDatum(oid))) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(StatisticsObjIsVisible(oid)); +} + +Datum +pg_ts_parser_is_visible(PG_FUNCTION_ARGS) +{ + Oid oid = PG_GETARG_OID(0); + + if (!SearchSysCacheExists1(TSPARSEROID, ObjectIdGetDatum(oid))) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(TSParserIsVisible(oid)); +} + +Datum +pg_ts_dict_is_visible(PG_FUNCTION_ARGS) +{ + Oid oid = PG_GETARG_OID(0); + + if (!SearchSysCacheExists1(TSDICTOID, ObjectIdGetDatum(oid))) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(TSDictionaryIsVisible(oid)); +} + +Datum +pg_ts_template_is_visible(PG_FUNCTION_ARGS) +{ + Oid oid = PG_GETARG_OID(0); + + if (!SearchSysCacheExists1(TSTEMPLATEOID, ObjectIdGetDatum(oid))) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(TSTemplateIsVisible(oid)); +} + +Datum +pg_ts_config_is_visible(PG_FUNCTION_ARGS) +{ + Oid oid = PG_GETARG_OID(0); + + if (!SearchSysCacheExists1(TSCONFIGOID, ObjectIdGetDatum(oid))) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(TSConfigIsVisible(oid)); +} + +Datum +pg_my_temp_schema(PG_FUNCTION_ARGS) +{ + PG_RETURN_OID(myTempNamespace); +} + +Datum +pg_is_other_temp_schema(PG_FUNCTION_ARGS) +{ + Oid oid = PG_GETARG_OID(0); + + PG_RETURN_BOOL(isOtherTempNamespace(oid)); +} diff --git a/src/backend/catalog/objectaccess.c b/src/backend/catalog/objectaccess.c new file mode 100644 index 0000000..17d7c56 --- /dev/null +++ b/src/backend/catalog/objectaccess.c @@ -0,0 +1,145 @@ +/* ------------------------------------------------------------------------- + * + * objectaccess.c + * functions for object_access_hook on various events + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * ------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "catalog/objectaccess.h" +#include "catalog/pg_class.h" +#include "catalog/pg_namespace.h" +#include "catalog/pg_proc.h" + +/* + * Hook on object accesses. This is intended as infrastructure for security + * and logging plugins. + */ +object_access_hook_type object_access_hook = NULL; + +/* + * RunObjectPostCreateHook + * + * It is entrypoint of OAT_POST_CREATE event + */ +void +RunObjectPostCreateHook(Oid classId, Oid objectId, int subId, + bool is_internal) +{ + ObjectAccessPostCreate pc_arg; + + /* caller should check, but just in case... */ + Assert(object_access_hook != NULL); + + memset(&pc_arg, 0, sizeof(ObjectAccessPostCreate)); + pc_arg.is_internal = is_internal; + + (*object_access_hook) (OAT_POST_CREATE, + classId, objectId, subId, + (void *) &pc_arg); +} + +/* + * RunObjectDropHook + * + * It is entrypoint of OAT_DROP event + */ +void +RunObjectDropHook(Oid classId, Oid objectId, int subId, + int dropflags) +{ + ObjectAccessDrop drop_arg; + + /* caller should check, but just in case... */ + Assert(object_access_hook != NULL); + + memset(&drop_arg, 0, sizeof(ObjectAccessDrop)); + drop_arg.dropflags = dropflags; + + (*object_access_hook) (OAT_DROP, + classId, objectId, subId, + (void *) &drop_arg); +} + +/* + * RunObjectTruncateHook + * + * It is the entrypoint of OAT_TRUNCATE event + */ +void +RunObjectTruncateHook(Oid objectId) +{ + /* caller should check, but just in case... */ + Assert(object_access_hook != NULL); + + (*object_access_hook) (OAT_TRUNCATE, + RelationRelationId, objectId, 0, + NULL); +} + +/* + * RunObjectPostAlterHook + * + * It is entrypoint of OAT_POST_ALTER event + */ +void +RunObjectPostAlterHook(Oid classId, Oid objectId, int subId, + Oid auxiliaryId, bool is_internal) +{ + ObjectAccessPostAlter pa_arg; + + /* caller should check, but just in case... */ + Assert(object_access_hook != NULL); + + memset(&pa_arg, 0, sizeof(ObjectAccessPostAlter)); + pa_arg.auxiliary_id = auxiliaryId; + pa_arg.is_internal = is_internal; + + (*object_access_hook) (OAT_POST_ALTER, + classId, objectId, subId, + (void *) &pa_arg); +} + +/* + * RunNamespaceSearchHook + * + * It is entrypoint of OAT_NAMESPACE_SEARCH event + */ +bool +RunNamespaceSearchHook(Oid objectId, bool ereport_on_violation) +{ + ObjectAccessNamespaceSearch ns_arg; + + /* caller should check, but just in case... */ + Assert(object_access_hook != NULL); + + memset(&ns_arg, 0, sizeof(ObjectAccessNamespaceSearch)); + ns_arg.ereport_on_violation = ereport_on_violation; + ns_arg.result = true; + + (*object_access_hook) (OAT_NAMESPACE_SEARCH, + NamespaceRelationId, objectId, 0, + (void *) &ns_arg); + + return ns_arg.result; +} + +/* + * RunFunctionExecuteHook + * + * It is entrypoint of OAT_FUNCTION_EXECUTE event + */ +void +RunFunctionExecuteHook(Oid objectId) +{ + /* caller should check, but just in case... */ + Assert(object_access_hook != NULL); + + (*object_access_hook) (OAT_FUNCTION_EXECUTE, + ProcedureRelationId, objectId, 0, + NULL); +} diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c new file mode 100644 index 0000000..64ceccb --- /dev/null +++ b/src/backend/catalog/objectaddress.c @@ -0,0 +1,5378 @@ +/*------------------------------------------------------------------------- + * + * objectaddress.c + * functions for working with ObjectAddresses + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/objectaddress.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/genam.h" +#include "access/htup_details.h" +#include "access/relation.h" +#include "access/sysattr.h" +#include "access/table.h" +#include "catalog/catalog.h" +#include "catalog/indexing.h" +#include "catalog/objectaddress.h" +#include "catalog/pg_am.h" +#include "catalog/pg_amop.h" +#include "catalog/pg_amproc.h" +#include "catalog/pg_attrdef.h" +#include "catalog/pg_authid.h" +#include "catalog/pg_cast.h" +#include "catalog/pg_collation.h" +#include "catalog/pg_constraint.h" +#include "catalog/pg_conversion.h" +#include "catalog/pg_database.h" +#include "catalog/pg_default_acl.h" +#include "catalog/pg_enum.h" +#include "catalog/pg_event_trigger.h" +#include "catalog/pg_extension.h" +#include "catalog/pg_foreign_data_wrapper.h" +#include "catalog/pg_foreign_server.h" +#include "catalog/pg_language.h" +#include "catalog/pg_largeobject.h" +#include "catalog/pg_largeobject_metadata.h" +#include "catalog/pg_namespace.h" +#include "catalog/pg_opclass.h" +#include "catalog/pg_operator.h" +#include "catalog/pg_opfamily.h" +#include "catalog/pg_policy.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_publication.h" +#include "catalog/pg_publication_rel.h" +#include "catalog/pg_rewrite.h" +#include "catalog/pg_statistic_ext.h" +#include "catalog/pg_subscription.h" +#include "catalog/pg_tablespace.h" +#include "catalog/pg_transform.h" +#include "catalog/pg_trigger.h" +#include "catalog/pg_ts_config.h" +#include "catalog/pg_ts_dict.h" +#include "catalog/pg_ts_parser.h" +#include "catalog/pg_ts_template.h" +#include "catalog/pg_type.h" +#include "catalog/pg_user_mapping.h" +#include "commands/dbcommands.h" +#include "commands/defrem.h" +#include "commands/event_trigger.h" +#include "commands/extension.h" +#include "commands/policy.h" +#include "commands/proclang.h" +#include "commands/tablespace.h" +#include "commands/trigger.h" +#include "foreign/foreign.h" +#include "funcapi.h" +#include "miscadmin.h" +#include "nodes/makefuncs.h" +#include "parser/parse_func.h" +#include "parser/parse_oper.h" +#include "parser/parse_type.h" +#include "rewrite/rewriteSupport.h" +#include "storage/large_object.h" +#include "storage/lmgr.h" +#include "storage/sinval.h" +#include "utils/acl.h" +#include "utils/builtins.h" +#include "utils/fmgroids.h" +#include "utils/lsyscache.h" +#include "utils/memutils.h" +#include "utils/regproc.h" +#include "utils/syscache.h" + +/* + * ObjectProperty + * + * This array provides a common part of system object structure; to help + * consolidate routines to handle various kind of object classes. + */ +typedef struct +{ + Oid class_oid; /* oid of catalog */ + Oid oid_index_oid; /* oid of index on system oid column */ + int oid_catcache_id; /* id of catcache on system oid column */ + int name_catcache_id; /* id of catcache on (name,namespace), or + * (name) if the object does not live in a + * namespace */ + AttrNumber attnum_oid; /* attribute number of oid column */ + AttrNumber attnum_name; /* attnum of name field */ + AttrNumber attnum_namespace; /* attnum of namespace field */ + AttrNumber attnum_owner; /* attnum of owner field */ + AttrNumber attnum_acl; /* attnum of acl field */ + ObjectType objtype; /* OBJECT_* of this object type */ + bool is_nsp_name_unique; /* can the nsp/name combination (or name + * alone, if there's no namespace) be + * considered a unique identifier for an + * object of this class? */ +} ObjectPropertyType; + +static const ObjectPropertyType ObjectProperty[] = +{ + { + AccessMethodRelationId, + AmOidIndexId, + AMOID, + AMNAME, + Anum_pg_am_oid, + Anum_pg_am_amname, + InvalidAttrNumber, + InvalidAttrNumber, + InvalidAttrNumber, + -1, + true + }, + { + CastRelationId, + CastOidIndexId, + -1, + -1, + Anum_pg_cast_oid, + InvalidAttrNumber, + InvalidAttrNumber, + InvalidAttrNumber, + InvalidAttrNumber, + -1, + false + }, + { + CollationRelationId, + CollationOidIndexId, + COLLOID, + -1, /* COLLNAMEENCNSP also takes encoding */ + Anum_pg_collation_oid, + Anum_pg_collation_collname, + Anum_pg_collation_collnamespace, + Anum_pg_collation_collowner, + InvalidAttrNumber, + OBJECT_COLLATION, + true + }, + { + ConstraintRelationId, + ConstraintOidIndexId, + CONSTROID, + -1, + Anum_pg_constraint_oid, + Anum_pg_constraint_conname, + Anum_pg_constraint_connamespace, + InvalidAttrNumber, + InvalidAttrNumber, + -1, + false + }, + { + ConversionRelationId, + ConversionOidIndexId, + CONVOID, + CONNAMENSP, + Anum_pg_conversion_oid, + Anum_pg_conversion_conname, + Anum_pg_conversion_connamespace, + Anum_pg_conversion_conowner, + InvalidAttrNumber, + OBJECT_CONVERSION, + true + }, + { + DatabaseRelationId, + DatabaseOidIndexId, + DATABASEOID, + -1, + Anum_pg_database_oid, + Anum_pg_database_datname, + InvalidAttrNumber, + Anum_pg_database_datdba, + Anum_pg_database_datacl, + OBJECT_DATABASE, + true + }, + { + ExtensionRelationId, + ExtensionOidIndexId, + -1, + -1, + Anum_pg_extension_oid, + Anum_pg_extension_extname, + InvalidAttrNumber, /* extension doesn't belong to extnamespace */ + Anum_pg_extension_extowner, + InvalidAttrNumber, + OBJECT_EXTENSION, + true + }, + { + ForeignDataWrapperRelationId, + ForeignDataWrapperOidIndexId, + FOREIGNDATAWRAPPEROID, + FOREIGNDATAWRAPPERNAME, + Anum_pg_foreign_data_wrapper_oid, + Anum_pg_foreign_data_wrapper_fdwname, + InvalidAttrNumber, + Anum_pg_foreign_data_wrapper_fdwowner, + Anum_pg_foreign_data_wrapper_fdwacl, + OBJECT_FDW, + true + }, + { + ForeignServerRelationId, + ForeignServerOidIndexId, + FOREIGNSERVEROID, + FOREIGNSERVERNAME, + Anum_pg_foreign_server_oid, + Anum_pg_foreign_server_srvname, + InvalidAttrNumber, + Anum_pg_foreign_server_srvowner, + Anum_pg_foreign_server_srvacl, + OBJECT_FOREIGN_SERVER, + true + }, + { + ProcedureRelationId, + ProcedureOidIndexId, + PROCOID, + -1, /* PROCNAMEARGSNSP also takes argument types */ + Anum_pg_proc_oid, + Anum_pg_proc_proname, + Anum_pg_proc_pronamespace, + Anum_pg_proc_proowner, + Anum_pg_proc_proacl, + OBJECT_FUNCTION, + false + }, + { + LanguageRelationId, + LanguageOidIndexId, + LANGOID, + LANGNAME, + Anum_pg_language_oid, + Anum_pg_language_lanname, + InvalidAttrNumber, + Anum_pg_language_lanowner, + Anum_pg_language_lanacl, + OBJECT_LANGUAGE, + true + }, + { + LargeObjectMetadataRelationId, + LargeObjectMetadataOidIndexId, + -1, + -1, + Anum_pg_largeobject_metadata_oid, + InvalidAttrNumber, + InvalidAttrNumber, + Anum_pg_largeobject_metadata_lomowner, + Anum_pg_largeobject_metadata_lomacl, + OBJECT_LARGEOBJECT, + false + }, + { + OperatorClassRelationId, + OpclassOidIndexId, + CLAOID, + -1, /* CLAAMNAMENSP also takes opcmethod */ + Anum_pg_opclass_oid, + Anum_pg_opclass_opcname, + Anum_pg_opclass_opcnamespace, + Anum_pg_opclass_opcowner, + InvalidAttrNumber, + OBJECT_OPCLASS, + true + }, + { + OperatorRelationId, + OperatorOidIndexId, + OPEROID, + -1, /* OPERNAMENSP also takes left and right type */ + Anum_pg_operator_oid, + Anum_pg_operator_oprname, + Anum_pg_operator_oprnamespace, + Anum_pg_operator_oprowner, + InvalidAttrNumber, + OBJECT_OPERATOR, + false + }, + { + OperatorFamilyRelationId, + OpfamilyOidIndexId, + OPFAMILYOID, + -1, /* OPFAMILYAMNAMENSP also takes opfmethod */ + Anum_pg_opfamily_oid, + Anum_pg_opfamily_opfname, + Anum_pg_opfamily_opfnamespace, + Anum_pg_opfamily_opfowner, + InvalidAttrNumber, + OBJECT_OPFAMILY, + true + }, + { + AuthIdRelationId, + AuthIdOidIndexId, + AUTHOID, + AUTHNAME, + Anum_pg_authid_oid, + Anum_pg_authid_rolname, + InvalidAttrNumber, + InvalidAttrNumber, + InvalidAttrNumber, + -1, + true + }, + { + RewriteRelationId, + RewriteOidIndexId, + -1, + -1, + Anum_pg_rewrite_oid, + Anum_pg_rewrite_rulename, + InvalidAttrNumber, + InvalidAttrNumber, + InvalidAttrNumber, + -1, + false + }, + { + NamespaceRelationId, + NamespaceOidIndexId, + NAMESPACEOID, + NAMESPACENAME, + Anum_pg_namespace_oid, + Anum_pg_namespace_nspname, + InvalidAttrNumber, + Anum_pg_namespace_nspowner, + Anum_pg_namespace_nspacl, + OBJECT_SCHEMA, + true + }, + { + RelationRelationId, + ClassOidIndexId, + RELOID, + RELNAMENSP, + Anum_pg_class_oid, + Anum_pg_class_relname, + Anum_pg_class_relnamespace, + Anum_pg_class_relowner, + Anum_pg_class_relacl, + OBJECT_TABLE, + true + }, + { + TableSpaceRelationId, + TablespaceOidIndexId, + TABLESPACEOID, + -1, + Anum_pg_tablespace_oid, + Anum_pg_tablespace_spcname, + InvalidAttrNumber, + Anum_pg_tablespace_spcowner, + Anum_pg_tablespace_spcacl, + OBJECT_TABLESPACE, + true + }, + { + TransformRelationId, + TransformOidIndexId, + TRFOID, + InvalidAttrNumber, + Anum_pg_transform_oid + }, + { + TriggerRelationId, + TriggerOidIndexId, + -1, + -1, + Anum_pg_trigger_oid, + Anum_pg_trigger_tgname, + InvalidAttrNumber, + InvalidAttrNumber, + InvalidAttrNumber, + -1, + false + }, + { + PolicyRelationId, + PolicyOidIndexId, + -1, + -1, + Anum_pg_policy_oid, + Anum_pg_policy_polname, + InvalidAttrNumber, + InvalidAttrNumber, + InvalidAttrNumber, + -1, + false + }, + { + EventTriggerRelationId, + EventTriggerOidIndexId, + EVENTTRIGGEROID, + EVENTTRIGGERNAME, + Anum_pg_event_trigger_oid, + Anum_pg_event_trigger_evtname, + InvalidAttrNumber, + Anum_pg_event_trigger_evtowner, + InvalidAttrNumber, + OBJECT_EVENT_TRIGGER, + true + }, + { + TSConfigRelationId, + TSConfigOidIndexId, + TSCONFIGOID, + TSCONFIGNAMENSP, + Anum_pg_ts_config_oid, + Anum_pg_ts_config_cfgname, + Anum_pg_ts_config_cfgnamespace, + Anum_pg_ts_config_cfgowner, + InvalidAttrNumber, + OBJECT_TSCONFIGURATION, + true + }, + { + TSDictionaryRelationId, + TSDictionaryOidIndexId, + TSDICTOID, + TSDICTNAMENSP, + Anum_pg_ts_dict_oid, + Anum_pg_ts_dict_dictname, + Anum_pg_ts_dict_dictnamespace, + Anum_pg_ts_dict_dictowner, + InvalidAttrNumber, + OBJECT_TSDICTIONARY, + true + }, + { + TSParserRelationId, + TSParserOidIndexId, + TSPARSEROID, + TSPARSERNAMENSP, + Anum_pg_ts_parser_oid, + Anum_pg_ts_parser_prsname, + Anum_pg_ts_parser_prsnamespace, + InvalidAttrNumber, + InvalidAttrNumber, + -1, + true + }, + { + TSTemplateRelationId, + TSTemplateOidIndexId, + TSTEMPLATEOID, + TSTEMPLATENAMENSP, + Anum_pg_ts_template_oid, + Anum_pg_ts_template_tmplname, + Anum_pg_ts_template_tmplnamespace, + InvalidAttrNumber, + InvalidAttrNumber, + -1, + true, + }, + { + TypeRelationId, + TypeOidIndexId, + TYPEOID, + TYPENAMENSP, + Anum_pg_type_oid, + Anum_pg_type_typname, + Anum_pg_type_typnamespace, + Anum_pg_type_typowner, + Anum_pg_type_typacl, + OBJECT_TYPE, + true + }, + { + PublicationRelationId, + PublicationObjectIndexId, + PUBLICATIONOID, + PUBLICATIONNAME, + Anum_pg_publication_oid, + Anum_pg_publication_pubname, + InvalidAttrNumber, + Anum_pg_publication_pubowner, + InvalidAttrNumber, + OBJECT_PUBLICATION, + true + }, + { + SubscriptionRelationId, + SubscriptionObjectIndexId, + SUBSCRIPTIONOID, + SUBSCRIPTIONNAME, + Anum_pg_subscription_oid, + Anum_pg_subscription_subname, + InvalidAttrNumber, + Anum_pg_subscription_subowner, + InvalidAttrNumber, + OBJECT_SUBSCRIPTION, + true + }, + { + StatisticExtRelationId, + StatisticExtOidIndexId, + STATEXTOID, + STATEXTNAMENSP, + Anum_pg_statistic_ext_oid, + Anum_pg_statistic_ext_stxname, + Anum_pg_statistic_ext_stxnamespace, + Anum_pg_statistic_ext_stxowner, + InvalidAttrNumber, /* no ACL (same as relation) */ + OBJECT_STATISTIC_EXT, + true + } +}; + +/* + * This struct maps the string object types as returned by + * getObjectTypeDescription into ObjectType enum values. Note that some enum + * values can be obtained by different names, and that some string object types + * do not have corresponding values in the output enum. The user of this map + * must be careful to test for invalid values being returned. + * + * To ease maintenance, this follows the order of getObjectTypeDescription. + */ +static const struct object_type_map +{ + const char *tm_name; + ObjectType tm_type; +} + + ObjectTypeMap[] = +{ + /* OCLASS_CLASS, all kinds of relations */ + { + "table", OBJECT_TABLE + }, + { + "index", OBJECT_INDEX + }, + { + "sequence", OBJECT_SEQUENCE + }, + { + "toast table", -1 + }, /* unmapped */ + { + "view", OBJECT_VIEW + }, + { + "materialized view", OBJECT_MATVIEW + }, + { + "composite type", -1 + }, /* unmapped */ + { + "foreign table", OBJECT_FOREIGN_TABLE + }, + { + "table column", OBJECT_COLUMN + }, + { + "index column", -1 + }, /* unmapped */ + { + "sequence column", -1 + }, /* unmapped */ + { + "toast table column", -1 + }, /* unmapped */ + { + "view column", -1 + }, /* unmapped */ + { + "materialized view column", -1 + }, /* unmapped */ + { + "composite type column", -1 + }, /* unmapped */ + { + "foreign table column", OBJECT_COLUMN + }, + /* OCLASS_PROC */ + { + "aggregate", OBJECT_AGGREGATE + }, + { + "function", OBJECT_FUNCTION + }, + { + "procedure", OBJECT_PROCEDURE + }, + /* OCLASS_TYPE */ + { + "type", OBJECT_TYPE + }, + /* OCLASS_CAST */ + { + "cast", OBJECT_CAST + }, + /* OCLASS_COLLATION */ + { + "collation", OBJECT_COLLATION + }, + /* OCLASS_CONSTRAINT */ + { + "table constraint", OBJECT_TABCONSTRAINT + }, + { + "domain constraint", OBJECT_DOMCONSTRAINT + }, + /* OCLASS_CONVERSION */ + { + "conversion", OBJECT_CONVERSION + }, + /* OCLASS_DEFAULT */ + { + "default value", OBJECT_DEFAULT + }, + /* OCLASS_LANGUAGE */ + { + "language", OBJECT_LANGUAGE + }, + /* OCLASS_LARGEOBJECT */ + { + "large object", OBJECT_LARGEOBJECT + }, + /* OCLASS_OPERATOR */ + { + "operator", OBJECT_OPERATOR + }, + /* OCLASS_OPCLASS */ + { + "operator class", OBJECT_OPCLASS + }, + /* OCLASS_OPFAMILY */ + { + "operator family", OBJECT_OPFAMILY + }, + /* OCLASS_AM */ + { + "access method", OBJECT_ACCESS_METHOD + }, + /* OCLASS_AMOP */ + { + "operator of access method", OBJECT_AMOP + }, + /* OCLASS_AMPROC */ + { + "function of access method", OBJECT_AMPROC + }, + /* OCLASS_REWRITE */ + { + "rule", OBJECT_RULE + }, + /* OCLASS_TRIGGER */ + { + "trigger", OBJECT_TRIGGER + }, + /* OCLASS_SCHEMA */ + { + "schema", OBJECT_SCHEMA + }, + /* OCLASS_TSPARSER */ + { + "text search parser", OBJECT_TSPARSER + }, + /* OCLASS_TSDICT */ + { + "text search dictionary", OBJECT_TSDICTIONARY + }, + /* OCLASS_TSTEMPLATE */ + { + "text search template", OBJECT_TSTEMPLATE + }, + /* OCLASS_TSCONFIG */ + { + "text search configuration", OBJECT_TSCONFIGURATION + }, + /* OCLASS_ROLE */ + { + "role", OBJECT_ROLE + }, + /* OCLASS_DATABASE */ + { + "database", OBJECT_DATABASE + }, + /* OCLASS_TBLSPACE */ + { + "tablespace", OBJECT_TABLESPACE + }, + /* OCLASS_FDW */ + { + "foreign-data wrapper", OBJECT_FDW + }, + /* OCLASS_FOREIGN_SERVER */ + { + "server", OBJECT_FOREIGN_SERVER + }, + /* OCLASS_USER_MAPPING */ + { + "user mapping", OBJECT_USER_MAPPING + }, + /* OCLASS_DEFACL */ + { + "default acl", OBJECT_DEFACL + }, + /* OCLASS_EXTENSION */ + { + "extension", OBJECT_EXTENSION + }, + /* OCLASS_EVENT_TRIGGER */ + { + "event trigger", OBJECT_EVENT_TRIGGER + }, + /* OCLASS_POLICY */ + { + "policy", OBJECT_POLICY + }, + /* OCLASS_PUBLICATION */ + { + "publication", OBJECT_PUBLICATION + }, + /* OCLASS_PUBLICATION_REL */ + { + "publication relation", OBJECT_PUBLICATION_REL + }, + /* OCLASS_SUBSCRIPTION */ + { + "subscription", OBJECT_SUBSCRIPTION + }, + /* OCLASS_TRANSFORM */ + { + "transform", OBJECT_TRANSFORM + }, + /* OCLASS_STATISTIC_EXT */ + { + "statistics object", OBJECT_STATISTIC_EXT + } +}; + +const ObjectAddress InvalidObjectAddress = +{ + InvalidOid, + InvalidOid, + 0 +}; + +static ObjectAddress get_object_address_unqualified(ObjectType objtype, + Value *strval, bool missing_ok); +static ObjectAddress get_relation_by_qualified_name(ObjectType objtype, + List *object, Relation *relp, + LOCKMODE lockmode, bool missing_ok); +static ObjectAddress get_object_address_relobject(ObjectType objtype, + List *object, Relation *relp, bool missing_ok); +static ObjectAddress get_object_address_attribute(ObjectType objtype, + List *object, Relation *relp, + LOCKMODE lockmode, bool missing_ok); +static ObjectAddress get_object_address_attrdef(ObjectType objtype, + List *object, Relation *relp, LOCKMODE lockmode, + bool missing_ok); +static ObjectAddress get_object_address_type(ObjectType objtype, + TypeName *typename, bool missing_ok); +static ObjectAddress get_object_address_opcf(ObjectType objtype, List *object, + bool missing_ok); +static ObjectAddress get_object_address_opf_member(ObjectType objtype, + List *object, bool missing_ok); + +static ObjectAddress get_object_address_usermapping(List *object, + bool missing_ok); +static ObjectAddress get_object_address_publication_rel(List *object, + Relation *relp, + bool missing_ok); +static ObjectAddress get_object_address_defacl(List *object, + bool missing_ok); +static const ObjectPropertyType *get_object_property_data(Oid class_id); + +static void getRelationDescription(StringInfo buffer, Oid relid); +static void getOpFamilyDescription(StringInfo buffer, Oid opfid); +static void getRelationTypeDescription(StringInfo buffer, Oid relid, + int32 objectSubId); +static void getProcedureTypeDescription(StringInfo buffer, Oid procid); +static void getConstraintTypeDescription(StringInfo buffer, Oid constroid); +static void getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object); +static void getRelationIdentity(StringInfo buffer, Oid relid, List **object); + +/* + * Translate an object name and arguments (as passed by the parser) to an + * ObjectAddress. + * + * The returned object will be locked using the specified lockmode. If a + * sub-object is looked up, the parent object will be locked instead. + * + * If the object is a relation or a child object of a relation (e.g. an + * attribute or constraint), the relation is also opened and *relp receives + * the open relcache entry pointer; otherwise, *relp is set to NULL. This + * is a bit grotty but it makes life simpler, since the caller will + * typically need the relcache entry too. Caller must close the relcache + * entry when done with it. The relation is locked with the specified lockmode + * if the target object is the relation itself or an attribute, but for other + * child objects, only AccessShareLock is acquired on the relation. + * + * If the object is not found, an error is thrown, unless missing_ok is + * true. In this case, no lock is acquired, relp is set to NULL, and the + * returned address has objectId set to InvalidOid. + * + * We don't currently provide a function to release the locks acquired here; + * typically, the lock must be held until commit to guard against a concurrent + * drop operation. + * + * Note: If the object is not found, we don't give any indication of the + * reason. (It might have been a missing schema if the name was qualified, or + * a nonexistent type name in case of a cast, function or operator; etc). + * Currently there is only one caller that might be interested in such info, so + * we don't spend much effort here. If more callers start to care, it might be + * better to add some support for that in this function. + */ +ObjectAddress +get_object_address(ObjectType objtype, Node *object, + Relation *relp, LOCKMODE lockmode, bool missing_ok) +{ + ObjectAddress address; + ObjectAddress old_address = {InvalidOid, InvalidOid, 0}; + Relation relation = NULL; + uint64 inval_count; + + /* Some kind of lock must be taken. */ + Assert(lockmode != NoLock); + + for (;;) + { + /* + * Remember this value, so that, after looking up the object name and + * locking it, we can check whether any invalidation messages have + * been processed that might require a do-over. + */ + inval_count = SharedInvalidMessageCounter; + + /* Look up object address. */ + switch (objtype) + { + case OBJECT_INDEX: + case OBJECT_SEQUENCE: + case OBJECT_TABLE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_FOREIGN_TABLE: + address = + get_relation_by_qualified_name(objtype, castNode(List, object), + &relation, lockmode, + missing_ok); + break; + case OBJECT_COLUMN: + address = + get_object_address_attribute(objtype, castNode(List, object), + &relation, lockmode, + missing_ok); + break; + case OBJECT_DEFAULT: + address = + get_object_address_attrdef(objtype, castNode(List, object), + &relation, lockmode, + missing_ok); + break; + case OBJECT_RULE: + case OBJECT_TRIGGER: + case OBJECT_TABCONSTRAINT: + case OBJECT_POLICY: + address = get_object_address_relobject(objtype, castNode(List, object), + &relation, missing_ok); + break; + case OBJECT_DOMCONSTRAINT: + { + List *objlist; + ObjectAddress domaddr; + char *constrname; + + objlist = castNode(List, object); + domaddr = get_object_address_type(OBJECT_DOMAIN, + linitial_node(TypeName, objlist), + missing_ok); + constrname = strVal(lsecond(objlist)); + + address.classId = ConstraintRelationId; + address.objectId = get_domain_constraint_oid(domaddr.objectId, + constrname, missing_ok); + address.objectSubId = 0; + + } + break; + case OBJECT_DATABASE: + case OBJECT_EXTENSION: + case OBJECT_TABLESPACE: + case OBJECT_ROLE: + case OBJECT_SCHEMA: + case OBJECT_LANGUAGE: + case OBJECT_FDW: + case OBJECT_FOREIGN_SERVER: + case OBJECT_EVENT_TRIGGER: + case OBJECT_ACCESS_METHOD: + case OBJECT_PUBLICATION: + case OBJECT_SUBSCRIPTION: + address = get_object_address_unqualified(objtype, + (Value *) object, missing_ok); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + address = get_object_address_type(objtype, castNode(TypeName, object), missing_ok); + break; + case OBJECT_AGGREGATE: + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + address.classId = ProcedureRelationId; + address.objectId = LookupFuncWithArgs(objtype, castNode(ObjectWithArgs, object), missing_ok); + address.objectSubId = 0; + break; + case OBJECT_OPERATOR: + address.classId = OperatorRelationId; + address.objectId = LookupOperWithArgs(castNode(ObjectWithArgs, object), missing_ok); + address.objectSubId = 0; + break; + case OBJECT_COLLATION: + address.classId = CollationRelationId; + address.objectId = get_collation_oid(castNode(List, object), missing_ok); + address.objectSubId = 0; + break; + case OBJECT_CONVERSION: + address.classId = ConversionRelationId; + address.objectId = get_conversion_oid(castNode(List, object), missing_ok); + address.objectSubId = 0; + break; + case OBJECT_OPCLASS: + case OBJECT_OPFAMILY: + address = get_object_address_opcf(objtype, castNode(List, object), missing_ok); + break; + case OBJECT_AMOP: + case OBJECT_AMPROC: + address = get_object_address_opf_member(objtype, castNode(List, object), missing_ok); + break; + case OBJECT_LARGEOBJECT: + address.classId = LargeObjectRelationId; + address.objectId = oidparse(object); + address.objectSubId = 0; + if (!LargeObjectExists(address.objectId)) + { + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("large object %u does not exist", + address.objectId))); + } + break; + case OBJECT_CAST: + { + TypeName *sourcetype = linitial_node(TypeName, castNode(List, object)); + TypeName *targettype = lsecond_node(TypeName, castNode(List, object)); + Oid sourcetypeid; + Oid targettypeid; + + sourcetypeid = LookupTypeNameOid(NULL, sourcetype, missing_ok); + targettypeid = LookupTypeNameOid(NULL, targettype, missing_ok); + address.classId = CastRelationId; + address.objectId = + get_cast_oid(sourcetypeid, targettypeid, missing_ok); + address.objectSubId = 0; + } + break; + case OBJECT_TRANSFORM: + { + TypeName *typename = linitial_node(TypeName, castNode(List, object)); + char *langname = strVal(lsecond(castNode(List, object))); + Oid type_id = LookupTypeNameOid(NULL, typename, missing_ok); + Oid lang_id = get_language_oid(langname, missing_ok); + + address.classId = TransformRelationId; + address.objectId = + get_transform_oid(type_id, lang_id, missing_ok); + address.objectSubId = 0; + } + break; + case OBJECT_TSPARSER: + address.classId = TSParserRelationId; + address.objectId = get_ts_parser_oid(castNode(List, object), missing_ok); + address.objectSubId = 0; + break; + case OBJECT_TSDICTIONARY: + address.classId = TSDictionaryRelationId; + address.objectId = get_ts_dict_oid(castNode(List, object), missing_ok); + address.objectSubId = 0; + break; + case OBJECT_TSTEMPLATE: + address.classId = TSTemplateRelationId; + address.objectId = get_ts_template_oid(castNode(List, object), missing_ok); + address.objectSubId = 0; + break; + case OBJECT_TSCONFIGURATION: + address.classId = TSConfigRelationId; + address.objectId = get_ts_config_oid(castNode(List, object), missing_ok); + address.objectSubId = 0; + break; + case OBJECT_USER_MAPPING: + address = get_object_address_usermapping(castNode(List, object), + missing_ok); + break; + case OBJECT_PUBLICATION_REL: + address = get_object_address_publication_rel(castNode(List, object), + &relation, + missing_ok); + break; + case OBJECT_DEFACL: + address = get_object_address_defacl(castNode(List, object), + missing_ok); + break; + case OBJECT_STATISTIC_EXT: + address.classId = StatisticExtRelationId; + address.objectId = get_statistics_object_oid(castNode(List, object), + missing_ok); + address.objectSubId = 0; + break; + default: + elog(ERROR, "unrecognized objtype: %d", (int) objtype); + /* placate compiler, in case it thinks elog might return */ + address.classId = InvalidOid; + address.objectId = InvalidOid; + address.objectSubId = 0; + } + + /* + * If we could not find the supplied object, return without locking. + */ + if (!OidIsValid(address.objectId)) + { + Assert(missing_ok); + return address; + } + + /* + * If we're retrying, see if we got the same answer as last time. If + * so, we're done; if not, we locked the wrong thing, so give up our + * lock. + */ + if (OidIsValid(old_address.classId)) + { + if (old_address.classId == address.classId + && old_address.objectId == address.objectId + && old_address.objectSubId == address.objectSubId) + break; + if (old_address.classId != RelationRelationId) + { + if (IsSharedRelation(old_address.classId)) + UnlockSharedObject(old_address.classId, + old_address.objectId, + 0, lockmode); + else + UnlockDatabaseObject(old_address.classId, + old_address.objectId, + 0, lockmode); + } + } + + /* + * If we're dealing with a relation or attribute, then the relation is + * already locked. Otherwise, we lock it now. + */ + if (address.classId != RelationRelationId) + { + if (IsSharedRelation(address.classId)) + LockSharedObject(address.classId, address.objectId, 0, + lockmode); + else + LockDatabaseObject(address.classId, address.objectId, 0, + lockmode); + } + + /* + * At this point, we've resolved the name to an OID and locked the + * corresponding database object. However, it's possible that by the + * time we acquire the lock on the object, concurrent DDL has modified + * the database in such a way that the name we originally looked up no + * longer resolves to that OID. + * + * We can be certain that this isn't an issue if (a) no shared + * invalidation messages have been processed or (b) we've locked a + * relation somewhere along the line. All the relation name lookups + * in this module ultimately use RangeVarGetRelid() to acquire a + * relation lock, and that function protects against the same kinds of + * races we're worried about here. Even when operating on a + * constraint, rule, or trigger, we still acquire AccessShareLock on + * the relation, which is enough to freeze out any concurrent DDL. + * + * In all other cases, however, it's possible that the name we looked + * up no longer refers to the object we locked, so we retry the lookup + * and see whether we get the same answer. + */ + if (inval_count == SharedInvalidMessageCounter || relation != NULL) + break; + old_address = address; + } + + /* Return the object address and the relation. */ + *relp = relation; + return address; +} + +/* + * Return an ObjectAddress based on a RangeVar and an object name. The + * name of the relation identified by the RangeVar is prepended to the + * (possibly empty) list passed in as object. This is useful to find + * the ObjectAddress of objects that depend on a relation. All other + * considerations are exactly as for get_object_address above. + */ +ObjectAddress +get_object_address_rv(ObjectType objtype, RangeVar *rel, List *object, + Relation *relp, LOCKMODE lockmode, + bool missing_ok) +{ + if (rel) + { + object = lcons(makeString(rel->relname), object); + if (rel->schemaname) + object = lcons(makeString(rel->schemaname), object); + if (rel->catalogname) + object = lcons(makeString(rel->catalogname), object); + } + + return get_object_address(objtype, (Node *) object, + relp, lockmode, missing_ok); +} + +/* + * Find an ObjectAddress for a type of object that is identified by an + * unqualified name. + */ +static ObjectAddress +get_object_address_unqualified(ObjectType objtype, + Value *strval, bool missing_ok) +{ + const char *name; + ObjectAddress address; + + name = strVal(strval); + + /* Translate name to OID. */ + switch (objtype) + { + case OBJECT_ACCESS_METHOD: + address.classId = AccessMethodRelationId; + address.objectId = get_am_oid(name, missing_ok); + address.objectSubId = 0; + break; + case OBJECT_DATABASE: + address.classId = DatabaseRelationId; + address.objectId = get_database_oid(name, missing_ok); + address.objectSubId = 0; + break; + case OBJECT_EXTENSION: + address.classId = ExtensionRelationId; + address.objectId = get_extension_oid(name, missing_ok); + address.objectSubId = 0; + break; + case OBJECT_TABLESPACE: + address.classId = TableSpaceRelationId; + address.objectId = get_tablespace_oid(name, missing_ok); + address.objectSubId = 0; + break; + case OBJECT_ROLE: + address.classId = AuthIdRelationId; + address.objectId = get_role_oid(name, missing_ok); + address.objectSubId = 0; + break; + case OBJECT_SCHEMA: + address.classId = NamespaceRelationId; + address.objectId = get_namespace_oid(name, missing_ok); + address.objectSubId = 0; + break; + case OBJECT_LANGUAGE: + address.classId = LanguageRelationId; + address.objectId = get_language_oid(name, missing_ok); + address.objectSubId = 0; + break; + case OBJECT_FDW: + address.classId = ForeignDataWrapperRelationId; + address.objectId = get_foreign_data_wrapper_oid(name, missing_ok); + address.objectSubId = 0; + break; + case OBJECT_FOREIGN_SERVER: + address.classId = ForeignServerRelationId; + address.objectId = get_foreign_server_oid(name, missing_ok); + address.objectSubId = 0; + break; + case OBJECT_EVENT_TRIGGER: + address.classId = EventTriggerRelationId; + address.objectId = get_event_trigger_oid(name, missing_ok); + address.objectSubId = 0; + break; + case OBJECT_PUBLICATION: + address.classId = PublicationRelationId; + address.objectId = get_publication_oid(name, missing_ok); + address.objectSubId = 0; + break; + case OBJECT_SUBSCRIPTION: + address.classId = SubscriptionRelationId; + address.objectId = get_subscription_oid(name, missing_ok); + address.objectSubId = 0; + break; + default: + elog(ERROR, "unrecognized objtype: %d", (int) objtype); + /* placate compiler, which doesn't know elog won't return */ + address.classId = InvalidOid; + address.objectId = InvalidOid; + address.objectSubId = 0; + } + + return address; +} + +/* + * Locate a relation by qualified name. + */ +static ObjectAddress +get_relation_by_qualified_name(ObjectType objtype, List *object, + Relation *relp, LOCKMODE lockmode, + bool missing_ok) +{ + Relation relation; + ObjectAddress address; + + address.classId = RelationRelationId; + address.objectId = InvalidOid; + address.objectSubId = 0; + + relation = relation_openrv_extended(makeRangeVarFromNameList(object), + lockmode, missing_ok); + if (!relation) + return address; + + switch (objtype) + { + case OBJECT_INDEX: + if (relation->rd_rel->relkind != RELKIND_INDEX && + relation->rd_rel->relkind != RELKIND_PARTITIONED_INDEX) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not an index", + RelationGetRelationName(relation)))); + break; + case OBJECT_SEQUENCE: + if (relation->rd_rel->relkind != RELKIND_SEQUENCE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not a sequence", + RelationGetRelationName(relation)))); + break; + case OBJECT_TABLE: + if (relation->rd_rel->relkind != RELKIND_RELATION && + relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not a table", + RelationGetRelationName(relation)))); + break; + case OBJECT_VIEW: + if (relation->rd_rel->relkind != RELKIND_VIEW) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not a view", + RelationGetRelationName(relation)))); + break; + case OBJECT_MATVIEW: + if (relation->rd_rel->relkind != RELKIND_MATVIEW) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not a materialized view", + RelationGetRelationName(relation)))); + break; + case OBJECT_FOREIGN_TABLE: + if (relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not a foreign table", + RelationGetRelationName(relation)))); + break; + default: + elog(ERROR, "unrecognized objtype: %d", (int) objtype); + break; + } + + /* Done. */ + address.objectId = RelationGetRelid(relation); + *relp = relation; + + return address; +} + +/* + * Find object address for an object that is attached to a relation. + * + * Note that we take only an AccessShareLock on the relation. We need not + * pass down the LOCKMODE from get_object_address(), because that is the lock + * mode for the object itself, not the relation to which it is attached. + */ +static ObjectAddress +get_object_address_relobject(ObjectType objtype, List *object, + Relation *relp, bool missing_ok) +{ + ObjectAddress address; + Relation relation = NULL; + int nnames; + const char *depname; + List *relname; + Oid reloid; + + /* Extract name of dependent object. */ + depname = strVal(llast(object)); + + /* Separate relation name from dependent object name. */ + nnames = list_length(object); + if (nnames < 2) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("must specify relation and object name"))); + + /* Extract relation name and open relation. */ + relname = list_truncate(list_copy(object), nnames - 1); + relation = table_openrv_extended(makeRangeVarFromNameList(relname), + AccessShareLock, + missing_ok); + + reloid = relation ? RelationGetRelid(relation) : InvalidOid; + + switch (objtype) + { + case OBJECT_RULE: + address.classId = RewriteRelationId; + address.objectId = relation ? + get_rewrite_oid(reloid, depname, missing_ok) : InvalidOid; + address.objectSubId = 0; + break; + case OBJECT_TRIGGER: + address.classId = TriggerRelationId; + address.objectId = relation ? + get_trigger_oid(reloid, depname, missing_ok) : InvalidOid; + address.objectSubId = 0; + break; + case OBJECT_TABCONSTRAINT: + address.classId = ConstraintRelationId; + address.objectId = relation ? + get_relation_constraint_oid(reloid, depname, missing_ok) : + InvalidOid; + address.objectSubId = 0; + break; + case OBJECT_POLICY: + address.classId = PolicyRelationId; + address.objectId = relation ? + get_relation_policy_oid(reloid, depname, missing_ok) : + InvalidOid; + address.objectSubId = 0; + break; + default: + elog(ERROR, "unrecognized objtype: %d", (int) objtype); + } + + /* Avoid relcache leak when object not found. */ + if (!OidIsValid(address.objectId)) + { + if (relation != NULL) + table_close(relation, AccessShareLock); + + relation = NULL; /* department of accident prevention */ + return address; + } + + /* Done. */ + *relp = relation; + return address; +} + +/* + * Find the ObjectAddress for an attribute. + */ +static ObjectAddress +get_object_address_attribute(ObjectType objtype, List *object, + Relation *relp, LOCKMODE lockmode, + bool missing_ok) +{ + ObjectAddress address; + List *relname; + Oid reloid; + Relation relation; + const char *attname; + AttrNumber attnum; + + /* Extract relation name and open relation. */ + if (list_length(object) < 2) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("column name must be qualified"))); + attname = strVal(lfirst(list_tail(object))); + relname = list_truncate(list_copy(object), list_length(object) - 1); + /* XXX no missing_ok support here */ + relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode); + reloid = RelationGetRelid(relation); + + /* Look up attribute and construct return value. */ + attnum = get_attnum(reloid, attname); + if (attnum == InvalidAttrNumber) + { + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + attname, NameListToString(relname)))); + + address.classId = RelationRelationId; + address.objectId = InvalidOid; + address.objectSubId = InvalidAttrNumber; + relation_close(relation, lockmode); + return address; + } + + address.classId = RelationRelationId; + address.objectId = reloid; + address.objectSubId = attnum; + + *relp = relation; + return address; +} + +/* + * Find the ObjectAddress for an attribute's default value. + */ +static ObjectAddress +get_object_address_attrdef(ObjectType objtype, List *object, + Relation *relp, LOCKMODE lockmode, + bool missing_ok) +{ + ObjectAddress address; + List *relname; + Oid reloid; + Relation relation; + const char *attname; + AttrNumber attnum; + TupleDesc tupdesc; + Oid defoid; + + /* Extract relation name and open relation. */ + if (list_length(object) < 2) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("column name must be qualified"))); + attname = strVal(llast(object)); + relname = list_truncate(list_copy(object), list_length(object) - 1); + /* XXX no missing_ok support here */ + relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode); + reloid = RelationGetRelid(relation); + + tupdesc = RelationGetDescr(relation); + + /* Look up attribute number and scan pg_attrdef to find its tuple */ + attnum = get_attnum(reloid, attname); + defoid = InvalidOid; + if (attnum != InvalidAttrNumber && tupdesc->constr != NULL) + { + Relation attrdef; + ScanKeyData keys[2]; + SysScanDesc scan; + HeapTuple tup; + + attrdef = relation_open(AttrDefaultRelationId, AccessShareLock); + ScanKeyInit(&keys[0], + Anum_pg_attrdef_adrelid, + BTEqualStrategyNumber, + F_OIDEQ, + ObjectIdGetDatum(reloid)); + ScanKeyInit(&keys[1], + Anum_pg_attrdef_adnum, + BTEqualStrategyNumber, + F_INT2EQ, + Int16GetDatum(attnum)); + scan = systable_beginscan(attrdef, AttrDefaultIndexId, true, + NULL, 2, keys); + if (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_attrdef atdform = (Form_pg_attrdef) GETSTRUCT(tup); + + defoid = atdform->oid; + } + + systable_endscan(scan); + relation_close(attrdef, AccessShareLock); + } + if (!OidIsValid(defoid)) + { + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("default value for column \"%s\" of relation \"%s\" does not exist", + attname, NameListToString(relname)))); + + address.classId = AttrDefaultRelationId; + address.objectId = InvalidOid; + address.objectSubId = InvalidAttrNumber; + relation_close(relation, lockmode); + return address; + } + + address.classId = AttrDefaultRelationId; + address.objectId = defoid; + address.objectSubId = 0; + + *relp = relation; + return address; +} + +/* + * Find the ObjectAddress for a type or domain + */ +static ObjectAddress +get_object_address_type(ObjectType objtype, TypeName *typename, bool missing_ok) +{ + ObjectAddress address; + Type tup; + + address.classId = TypeRelationId; + address.objectId = InvalidOid; + address.objectSubId = 0; + + tup = LookupTypeName(NULL, typename, NULL, missing_ok); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("type \"%s\" does not exist", + TypeNameToString(typename)))); + return address; + } + address.objectId = typeTypeId(tup); + + if (objtype == OBJECT_DOMAIN) + { + if (((Form_pg_type) GETSTRUCT(tup))->typtype != TYPTYPE_DOMAIN) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not a domain", + TypeNameToString(typename)))); + } + + ReleaseSysCache(tup); + + return address; +} + +/* + * Find the ObjectAddress for an opclass or opfamily. + */ +static ObjectAddress +get_object_address_opcf(ObjectType objtype, List *object, bool missing_ok) +{ + Oid amoid; + ObjectAddress address; + + /* XXX no missing_ok support here */ + amoid = get_index_am_oid(strVal(linitial(object)), false); + object = list_copy_tail(object, 1); + + switch (objtype) + { + case OBJECT_OPCLASS: + address.classId = OperatorClassRelationId; + address.objectId = get_opclass_oid(amoid, object, missing_ok); + address.objectSubId = 0; + break; + case OBJECT_OPFAMILY: + address.classId = OperatorFamilyRelationId; + address.objectId = get_opfamily_oid(amoid, object, missing_ok); + address.objectSubId = 0; + break; + default: + elog(ERROR, "unrecognized objtype: %d", (int) objtype); + /* placate compiler, which doesn't know elog won't return */ + address.classId = InvalidOid; + address.objectId = InvalidOid; + address.objectSubId = 0; + } + + return address; +} + +/* + * Find the ObjectAddress for an opclass/opfamily member. + * + * (The returned address corresponds to a pg_amop/pg_amproc object). + */ +static ObjectAddress +get_object_address_opf_member(ObjectType objtype, + List *object, bool missing_ok) +{ + ObjectAddress famaddr; + ObjectAddress address; + ListCell *cell; + List *copy; + TypeName *typenames[2]; + Oid typeoids[2]; + int membernum; + int i; + + /* + * The last element of the object list contains the strategy or procedure + * number. We need to strip that out before getting the opclass/family + * address. The rest can be used directly by get_object_address_opcf(). + */ + membernum = atoi(strVal(llast(linitial(object)))); + copy = list_truncate(list_copy(linitial(object)), list_length(linitial(object)) - 1); + + /* no missing_ok support here */ + famaddr = get_object_address_opcf(OBJECT_OPFAMILY, copy, false); + + /* find out left/right type names and OIDs */ + typenames[0] = typenames[1] = NULL; + typeoids[0] = typeoids[1] = InvalidOid; + i = 0; + foreach(cell, lsecond(object)) + { + ObjectAddress typaddr; + + typenames[i] = lfirst_node(TypeName, cell); + typaddr = get_object_address_type(OBJECT_TYPE, typenames[i], missing_ok); + typeoids[i] = typaddr.objectId; + if (++i >= 2) + break; + } + + switch (objtype) + { + case OBJECT_AMOP: + { + HeapTuple tp; + + ObjectAddressSet(address, AccessMethodOperatorRelationId, + InvalidOid); + + tp = SearchSysCache4(AMOPSTRATEGY, + ObjectIdGetDatum(famaddr.objectId), + ObjectIdGetDatum(typeoids[0]), + ObjectIdGetDatum(typeoids[1]), + Int16GetDatum(membernum)); + if (!HeapTupleIsValid(tp)) + { + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("operator %d (%s, %s) of %s does not exist", + membernum, + TypeNameToString(typenames[0]), + TypeNameToString(typenames[1]), + getObjectDescription(&famaddr)))); + } + else + { + address.objectId = ((Form_pg_amop) GETSTRUCT(tp))->oid; + ReleaseSysCache(tp); + } + } + break; + + case OBJECT_AMPROC: + { + HeapTuple tp; + + ObjectAddressSet(address, AccessMethodProcedureRelationId, + InvalidOid); + + tp = SearchSysCache4(AMPROCNUM, + ObjectIdGetDatum(famaddr.objectId), + ObjectIdGetDatum(typeoids[0]), + ObjectIdGetDatum(typeoids[1]), + Int16GetDatum(membernum)); + if (!HeapTupleIsValid(tp)) + { + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("function %d (%s, %s) of %s does not exist", + membernum, + TypeNameToString(typenames[0]), + TypeNameToString(typenames[1]), + getObjectDescription(&famaddr)))); + } + else + { + address.objectId = ((Form_pg_amproc) GETSTRUCT(tp))->oid; + ReleaseSysCache(tp); + } + } + break; + default: + elog(ERROR, "unrecognized objtype: %d", (int) objtype); + } + + return address; +} + +/* + * Find the ObjectAddress for a user mapping. + */ +static ObjectAddress +get_object_address_usermapping(List *object, bool missing_ok) +{ + ObjectAddress address; + Oid userid; + char *username; + char *servername; + ForeignServer *server; + HeapTuple tp; + + ObjectAddressSet(address, UserMappingRelationId, InvalidOid); + + /* fetch string names from input lists, for error messages */ + username = strVal(linitial(object)); + servername = strVal(lsecond(object)); + + /* look up pg_authid OID of mapped user; InvalidOid if PUBLIC */ + if (strcmp(username, "public") == 0) + userid = InvalidOid; + else + { + tp = SearchSysCache1(AUTHNAME, + CStringGetDatum(username)); + if (!HeapTupleIsValid(tp)) + { + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("user mapping for user \"%s\" on server \"%s\" does not exist", + username, servername))); + return address; + } + userid = ((Form_pg_authid) GETSTRUCT(tp))->oid; + ReleaseSysCache(tp); + } + + /* Now look up the pg_user_mapping tuple */ + server = GetForeignServerByName(servername, true); + if (!server) + { + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("server \"%s\" does not exist", servername))); + return address; + } + tp = SearchSysCache2(USERMAPPINGUSERSERVER, + ObjectIdGetDatum(userid), + ObjectIdGetDatum(server->serverid)); + if (!HeapTupleIsValid(tp)) + { + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("user mapping for user \"%s\" on server \"%s\" does not exist", + username, servername))); + return address; + } + + address.objectId = ((Form_pg_user_mapping) GETSTRUCT(tp))->oid; + + ReleaseSysCache(tp); + + return address; +} + +/* + * Find the ObjectAddress for a publication relation. The first element of + * the object parameter is the relation name, the second is the + * publication name. + */ +static ObjectAddress +get_object_address_publication_rel(List *object, + Relation *relp, bool missing_ok) +{ + ObjectAddress address; + Relation relation; + List *relname; + char *pubname; + Publication *pub; + + ObjectAddressSet(address, PublicationRelRelationId, InvalidOid); + + relname = linitial(object); + relation = relation_openrv_extended(makeRangeVarFromNameList(relname), + AccessShareLock, missing_ok); + if (!relation) + return address; + + /* fetch publication name from input list */ + pubname = strVal(lsecond(object)); + + /* Now look up the pg_publication tuple */ + pub = GetPublicationByName(pubname, missing_ok); + if (!pub) + { + relation_close(relation, AccessShareLock); + return address; + } + + /* Find the publication relation mapping in syscache. */ + address.objectId = + GetSysCacheOid2(PUBLICATIONRELMAP, Anum_pg_publication_rel_oid, + ObjectIdGetDatum(RelationGetRelid(relation)), + ObjectIdGetDatum(pub->oid)); + if (!OidIsValid(address.objectId)) + { + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("publication relation \"%s\" in publication \"%s\" does not exist", + RelationGetRelationName(relation), pubname))); + relation_close(relation, AccessShareLock); + return address; + } + + *relp = relation; + return address; +} + +/* + * Find the ObjectAddress for a default ACL. + */ +static ObjectAddress +get_object_address_defacl(List *object, bool missing_ok) +{ + HeapTuple tp; + Oid userid; + Oid schemaid; + char *username; + char *schema; + char objtype; + char *objtype_str; + ObjectAddress address; + + ObjectAddressSet(address, DefaultAclRelationId, InvalidOid); + + /* + * First figure out the textual attributes so that they can be used for + * error reporting. + */ + username = strVal(lsecond(object)); + if (list_length(object) >= 3) + schema = (char *) strVal(lthird(object)); + else + schema = NULL; + + /* + * Decode defaclobjtype. Only first char is considered; the rest of the + * string, if any, is blissfully ignored. + */ + objtype = ((char *) strVal(linitial(object)))[0]; + switch (objtype) + { + case DEFACLOBJ_RELATION: + objtype_str = "tables"; + break; + case DEFACLOBJ_SEQUENCE: + objtype_str = "sequences"; + break; + case DEFACLOBJ_FUNCTION: + objtype_str = "functions"; + break; + case DEFACLOBJ_TYPE: + objtype_str = "types"; + break; + case DEFACLOBJ_NAMESPACE: + objtype_str = "schemas"; + break; + default: + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unrecognized default ACL object type \"%c\"", objtype), + errhint("Valid object types are \"%c\", \"%c\", \"%c\", \"%c\", \"%c\".", + DEFACLOBJ_RELATION, + DEFACLOBJ_SEQUENCE, + DEFACLOBJ_FUNCTION, + DEFACLOBJ_TYPE, + DEFACLOBJ_NAMESPACE))); + } + + /* + * Look up user ID. Behave as "default ACL not found" if the user doesn't + * exist. + */ + tp = SearchSysCache1(AUTHNAME, + CStringGetDatum(username)); + if (!HeapTupleIsValid(tp)) + goto not_found; + userid = ((Form_pg_authid) GETSTRUCT(tp))->oid; + ReleaseSysCache(tp); + + /* + * If a schema name was given, look up its OID. If it doesn't exist, + * behave as "default ACL not found". + */ + if (schema) + { + schemaid = get_namespace_oid(schema, true); + if (schemaid == InvalidOid) + goto not_found; + } + else + schemaid = InvalidOid; + + /* Finally, look up the pg_default_acl object */ + tp = SearchSysCache3(DEFACLROLENSPOBJ, + ObjectIdGetDatum(userid), + ObjectIdGetDatum(schemaid), + CharGetDatum(objtype)); + if (!HeapTupleIsValid(tp)) + goto not_found; + + address.objectId = ((Form_pg_default_acl) GETSTRUCT(tp))->oid; + ReleaseSysCache(tp); + + return address; + +not_found: + if (!missing_ok) + { + if (schema) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("default ACL for user \"%s\" in schema \"%s\" on %s does not exist", + username, schema, objtype_str))); + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("default ACL for user \"%s\" on %s does not exist", + username, objtype_str))); + } + return address; +} + +/* + * Convert an array of TEXT into a List of string Values, as emitted by the + * parser, which is what get_object_address uses as input. + */ +static List * +textarray_to_strvaluelist(ArrayType *arr) +{ + Datum *elems; + bool *nulls; + int nelems; + List *list = NIL; + int i; + + deconstruct_array(arr, TEXTOID, -1, false, TYPALIGN_INT, + &elems, &nulls, &nelems); + + for (i = 0; i < nelems; i++) + { + if (nulls[i]) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("name or argument lists may not contain nulls"))); + list = lappend(list, makeString(TextDatumGetCString(elems[i]))); + } + + return list; +} + +/* + * SQL-callable version of get_object_address + */ +Datum +pg_get_object_address(PG_FUNCTION_ARGS) +{ + char *ttype = TextDatumGetCString(PG_GETARG_DATUM(0)); + ArrayType *namearr = PG_GETARG_ARRAYTYPE_P(1); + ArrayType *argsarr = PG_GETARG_ARRAYTYPE_P(2); + int itype; + ObjectType type; + List *name = NIL; + TypeName *typename = NULL; + List *args = NIL; + Node *objnode = NULL; + ObjectAddress addr; + TupleDesc tupdesc; + Datum values[3]; + bool nulls[3]; + HeapTuple htup; + Relation relation; + + /* Decode object type, raise error if unknown */ + itype = read_objtype_from_string(ttype); + if (itype < 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unsupported object type \"%s\"", ttype))); + type = (ObjectType) itype; + + /* + * Convert the text array to the representation appropriate for the given + * object type. Most use a simple string Values list, but there are some + * exceptions. + */ + if (type == OBJECT_TYPE || type == OBJECT_DOMAIN || type == OBJECT_CAST || + type == OBJECT_TRANSFORM || type == OBJECT_DOMCONSTRAINT) + { + Datum *elems; + bool *nulls; + int nelems; + + deconstruct_array(namearr, TEXTOID, -1, false, TYPALIGN_INT, + &elems, &nulls, &nelems); + if (nelems != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("name list length must be exactly %d", 1))); + if (nulls[0]) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("name or argument lists may not contain nulls"))); + typename = typeStringToTypeName(TextDatumGetCString(elems[0])); + } + else if (type == OBJECT_LARGEOBJECT) + { + Datum *elems; + bool *nulls; + int nelems; + + deconstruct_array(namearr, TEXTOID, -1, false, TYPALIGN_INT, + &elems, &nulls, &nelems); + if (nelems != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("name list length must be exactly %d", 1))); + if (nulls[0]) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("large object OID may not be null"))); + objnode = (Node *) makeFloat(TextDatumGetCString(elems[0])); + } + else + { + name = textarray_to_strvaluelist(namearr); + if (list_length(name) < 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("name list length must be at least %d", 1))); + } + + /* + * If args are given, decode them according to the object type. + */ + if (type == OBJECT_AGGREGATE || + type == OBJECT_FUNCTION || + type == OBJECT_PROCEDURE || + type == OBJECT_ROUTINE || + type == OBJECT_OPERATOR || + type == OBJECT_CAST || + type == OBJECT_AMOP || + type == OBJECT_AMPROC) + { + /* in these cases, the args list must be of TypeName */ + Datum *elems; + bool *nulls; + int nelems; + int i; + + deconstruct_array(argsarr, TEXTOID, -1, false, TYPALIGN_INT, + &elems, &nulls, &nelems); + + args = NIL; + for (i = 0; i < nelems; i++) + { + if (nulls[i]) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("name or argument lists may not contain nulls"))); + args = lappend(args, + typeStringToTypeName(TextDatumGetCString(elems[i]))); + } + } + else + { + /* For all other object types, use string Values */ + args = textarray_to_strvaluelist(argsarr); + } + + /* + * get_object_address is pretty sensitive to the length of its input + * lists; check that they're what it wants. + */ + switch (type) + { + case OBJECT_DOMCONSTRAINT: + case OBJECT_CAST: + case OBJECT_USER_MAPPING: + case OBJECT_PUBLICATION_REL: + case OBJECT_DEFACL: + case OBJECT_TRANSFORM: + if (list_length(args) != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("argument list length must be exactly %d", 1))); + break; + case OBJECT_OPFAMILY: + case OBJECT_OPCLASS: + if (list_length(name) < 2) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("name list length must be at least %d", 2))); + break; + case OBJECT_AMOP: + case OBJECT_AMPROC: + if (list_length(name) < 3) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("name list length must be at least %d", 3))); + /* fall through to check args length */ + /* FALLTHROUGH */ + case OBJECT_OPERATOR: + if (list_length(args) != 2) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("argument list length must be exactly %d", 2))); + break; + default: + break; + } + + /* + * Now build the Node type that get_object_address() expects for the given + * type. + */ + switch (type) + { + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_FOREIGN_TABLE: + case OBJECT_COLUMN: + case OBJECT_ATTRIBUTE: + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_STATISTIC_EXT: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_DEFAULT: + case OBJECT_POLICY: + case OBJECT_RULE: + case OBJECT_TRIGGER: + case OBJECT_TABCONSTRAINT: + case OBJECT_OPCLASS: + case OBJECT_OPFAMILY: + objnode = (Node *) name; + break; + case OBJECT_ACCESS_METHOD: + case OBJECT_DATABASE: + case OBJECT_EVENT_TRIGGER: + case OBJECT_EXTENSION: + case OBJECT_FDW: + case OBJECT_FOREIGN_SERVER: + case OBJECT_LANGUAGE: + case OBJECT_PUBLICATION: + case OBJECT_ROLE: + case OBJECT_SCHEMA: + case OBJECT_SUBSCRIPTION: + case OBJECT_TABLESPACE: + if (list_length(name) != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("name list length must be exactly %d", 1))); + objnode = linitial(name); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + objnode = (Node *) typename; + break; + case OBJECT_CAST: + case OBJECT_DOMCONSTRAINT: + case OBJECT_TRANSFORM: + objnode = (Node *) list_make2(typename, linitial(args)); + break; + case OBJECT_PUBLICATION_REL: + objnode = (Node *) list_make2(name, linitial(args)); + break; + case OBJECT_USER_MAPPING: + objnode = (Node *) list_make2(linitial(name), linitial(args)); + break; + case OBJECT_DEFACL: + objnode = (Node *) lcons(linitial(args), name); + break; + case OBJECT_AMOP: + case OBJECT_AMPROC: + objnode = (Node *) list_make2(name, args); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + case OBJECT_AGGREGATE: + case OBJECT_OPERATOR: + { + ObjectWithArgs *owa = makeNode(ObjectWithArgs); + + owa->objname = name; + owa->objargs = args; + objnode = (Node *) owa; + break; + } + case OBJECT_LARGEOBJECT: + /* already handled above */ + break; + /* no default, to let compiler warn about missing case */ + } + + if (objnode == NULL) + elog(ERROR, "unrecognized object type: %d", type); + + addr = get_object_address(type, objnode, + &relation, AccessShareLock, false); + + /* We don't need the relcache entry, thank you very much */ + if (relation) + relation_close(relation, AccessShareLock); + + tupdesc = CreateTemplateTupleDesc(3); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "classid", + OIDOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "objid", + OIDOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "objsubid", + INT4OID, -1, 0); + tupdesc = BlessTupleDesc(tupdesc); + + values[0] = ObjectIdGetDatum(addr.classId); + values[1] = ObjectIdGetDatum(addr.objectId); + values[2] = Int32GetDatum(addr.objectSubId); + nulls[0] = false; + nulls[1] = false; + nulls[2] = false; + + htup = heap_form_tuple(tupdesc, values, nulls); + + PG_RETURN_DATUM(HeapTupleGetDatum(htup)); +} + +/* + * Check ownership of an object previously identified by get_object_address. + */ +void +check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, + Node *object, Relation relation) +{ + switch (objtype) + { + case OBJECT_INDEX: + case OBJECT_SEQUENCE: + case OBJECT_TABLE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_FOREIGN_TABLE: + case OBJECT_COLUMN: + case OBJECT_RULE: + case OBJECT_TRIGGER: + case OBJECT_POLICY: + case OBJECT_TABCONSTRAINT: + if (!pg_class_ownercheck(RelationGetRelid(relation), roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + RelationGetRelationName(relation)); + break; + case OBJECT_DATABASE: + if (!pg_database_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + strVal((Value *) object)); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + case OBJECT_ATTRIBUTE: + if (!pg_type_ownercheck(address.objectId, roleid)) + aclcheck_error_type(ACLCHECK_NOT_OWNER, address.objectId); + break; + case OBJECT_DOMCONSTRAINT: + { + HeapTuple tuple; + Oid contypid; + + tuple = SearchSysCache1(CONSTROID, + ObjectIdGetDatum(address.objectId)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "constraint with OID %u does not exist", + address.objectId); + + contypid = ((Form_pg_constraint) GETSTRUCT(tuple))->contypid; + + ReleaseSysCache(tuple); + + /* + * Fallback to type ownership check in this case as this is + * what domain constraints rely on. + */ + if (!pg_type_ownercheck(contypid, roleid)) + aclcheck_error_type(ACLCHECK_NOT_OWNER, contypid); + } + break; + case OBJECT_AGGREGATE: + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + if (!pg_proc_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + NameListToString((castNode(ObjectWithArgs, object))->objname)); + break; + case OBJECT_OPERATOR: + if (!pg_oper_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + NameListToString((castNode(ObjectWithArgs, object))->objname)); + break; + case OBJECT_SCHEMA: + if (!pg_namespace_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + strVal((Value *) object)); + break; + case OBJECT_COLLATION: + if (!pg_collation_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + NameListToString(castNode(List, object))); + break; + case OBJECT_CONVERSION: + if (!pg_conversion_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + NameListToString(castNode(List, object))); + break; + case OBJECT_EXTENSION: + if (!pg_extension_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + strVal((Value *) object)); + break; + case OBJECT_FDW: + if (!pg_foreign_data_wrapper_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + strVal((Value *) object)); + break; + case OBJECT_FOREIGN_SERVER: + if (!pg_foreign_server_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + strVal((Value *) object)); + break; + case OBJECT_EVENT_TRIGGER: + if (!pg_event_trigger_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + strVal((Value *) object)); + break; + case OBJECT_LANGUAGE: + if (!pg_language_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + strVal((Value *) object)); + break; + case OBJECT_OPCLASS: + if (!pg_opclass_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + NameListToString(castNode(List, object))); + break; + case OBJECT_OPFAMILY: + if (!pg_opfamily_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + NameListToString(castNode(List, object))); + break; + case OBJECT_LARGEOBJECT: + if (!lo_compat_privileges && + !pg_largeobject_ownercheck(address.objectId, roleid)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be owner of large object %u", + address.objectId))); + break; + case OBJECT_CAST: + { + /* We can only check permissions on the source/target types */ + TypeName *sourcetype = linitial_node(TypeName, castNode(List, object)); + TypeName *targettype = lsecond_node(TypeName, castNode(List, object)); + Oid sourcetypeid = typenameTypeId(NULL, sourcetype); + Oid targettypeid = typenameTypeId(NULL, targettype); + + if (!pg_type_ownercheck(sourcetypeid, roleid) + && !pg_type_ownercheck(targettypeid, roleid)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be owner of type %s or type %s", + format_type_be(sourcetypeid), + format_type_be(targettypeid)))); + } + break; + case OBJECT_PUBLICATION: + if (!pg_publication_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + strVal((Value *) object)); + break; + case OBJECT_SUBSCRIPTION: + if (!pg_subscription_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + strVal((Value *) object)); + break; + case OBJECT_TRANSFORM: + { + TypeName *typename = linitial_node(TypeName, castNode(List, object)); + Oid typeid = typenameTypeId(NULL, typename); + + if (!pg_type_ownercheck(typeid, roleid)) + aclcheck_error_type(ACLCHECK_NOT_OWNER, typeid); + } + break; + case OBJECT_TABLESPACE: + if (!pg_tablespace_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + strVal((Value *) object)); + break; + case OBJECT_TSDICTIONARY: + if (!pg_ts_dict_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + NameListToString(castNode(List, object))); + break; + case OBJECT_TSCONFIGURATION: + if (!pg_ts_config_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + NameListToString(castNode(List, object))); + break; + case OBJECT_ROLE: + + /* + * We treat roles as being "owned" by those with CREATEROLE priv, + * except that superusers are only owned by superusers. + */ + if (superuser_arg(address.objectId)) + { + if (!superuser_arg(roleid)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser"))); + } + else + { + if (!has_createrole_privilege(roleid)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must have CREATEROLE privilege"))); + } + break; + case OBJECT_TSPARSER: + case OBJECT_TSTEMPLATE: + case OBJECT_ACCESS_METHOD: + /* We treat these object types as being owned by superusers */ + if (!superuser_arg(roleid)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser"))); + break; + case OBJECT_STATISTIC_EXT: + if (!pg_statistics_object_ownercheck(address.objectId, roleid)) + aclcheck_error_type(ACLCHECK_NOT_OWNER, address.objectId); + break; + default: + elog(ERROR, "unrecognized object type: %d", + (int) objtype); + } +} + +/* + * get_object_namespace + * + * Find the schema containing the specified object. For non-schema objects, + * this function returns InvalidOid. + */ +Oid +get_object_namespace(const ObjectAddress *address) +{ + int cache; + HeapTuple tuple; + bool isnull; + Oid oid; + const ObjectPropertyType *property; + + /* If not owned by a namespace, just return InvalidOid. */ + property = get_object_property_data(address->classId); + if (property->attnum_namespace == InvalidAttrNumber) + return InvalidOid; + + /* Currently, we can only handle object types with system caches. */ + cache = property->oid_catcache_id; + Assert(cache != -1); + + /* Fetch tuple from syscache and extract namespace attribute. */ + tuple = SearchSysCache1(cache, ObjectIdGetDatum(address->objectId)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for cache %d oid %u", + cache, address->objectId); + oid = DatumGetObjectId(SysCacheGetAttr(cache, + tuple, + property->attnum_namespace, + &isnull)); + Assert(!isnull); + ReleaseSysCache(tuple); + + return oid; +} + +/* + * Return ObjectType for the given object type as given by + * getObjectTypeDescription; if no valid ObjectType code exists, but it's a + * possible output type from getObjectTypeDescription, return -1. + * Otherwise, an error is thrown. + */ +int +read_objtype_from_string(const char *objtype) +{ + int i; + + for (i = 0; i < lengthof(ObjectTypeMap); i++) + { + if (strcmp(ObjectTypeMap[i].tm_name, objtype) == 0) + return ObjectTypeMap[i].tm_type; + } + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unrecognized object type \"%s\"", objtype))); + + return -1; /* keep compiler quiet */ +} + +/* + * Interfaces to reference fields of ObjectPropertyType + */ +Oid +get_object_oid_index(Oid class_id) +{ + const ObjectPropertyType *prop = get_object_property_data(class_id); + + return prop->oid_index_oid; +} + +int +get_object_catcache_oid(Oid class_id) +{ + const ObjectPropertyType *prop = get_object_property_data(class_id); + + return prop->oid_catcache_id; +} + +int +get_object_catcache_name(Oid class_id) +{ + const ObjectPropertyType *prop = get_object_property_data(class_id); + + return prop->name_catcache_id; +} + +AttrNumber +get_object_attnum_oid(Oid class_id) +{ + const ObjectPropertyType *prop = get_object_property_data(class_id); + + return prop->attnum_oid; +} + +AttrNumber +get_object_attnum_name(Oid class_id) +{ + const ObjectPropertyType *prop = get_object_property_data(class_id); + + return prop->attnum_name; +} + +AttrNumber +get_object_attnum_namespace(Oid class_id) +{ + const ObjectPropertyType *prop = get_object_property_data(class_id); + + return prop->attnum_namespace; +} + +AttrNumber +get_object_attnum_owner(Oid class_id) +{ + const ObjectPropertyType *prop = get_object_property_data(class_id); + + return prop->attnum_owner; +} + +AttrNumber +get_object_attnum_acl(Oid class_id) +{ + const ObjectPropertyType *prop = get_object_property_data(class_id); + + return prop->attnum_acl; +} + +/* + * get_object_type + * + * Return the object type associated with a given object. This routine + * is primarily used to determine the object type to mention in ACL check + * error messages, so it's desirable for it to avoid failing. + */ +ObjectType +get_object_type(Oid class_id, Oid object_id) +{ + const ObjectPropertyType *prop = get_object_property_data(class_id); + + if (prop->objtype == OBJECT_TABLE) + { + /* + * If the property data says it's a table, dig a little deeper to get + * the real relation kind, so that callers can produce more precise + * error messages. + */ + return get_relkind_objtype(get_rel_relkind(object_id)); + } + else + return prop->objtype; +} + +bool +get_object_namensp_unique(Oid class_id) +{ + const ObjectPropertyType *prop = get_object_property_data(class_id); + + return prop->is_nsp_name_unique; +} + +/* + * Return whether we have useful data for the given object class in the + * ObjectProperty table. + */ +bool +is_objectclass_supported(Oid class_id) +{ + int index; + + for (index = 0; index < lengthof(ObjectProperty); index++) + { + if (ObjectProperty[index].class_oid == class_id) + return true; + } + + return false; +} + +/* + * Find ObjectProperty structure by class_id. + */ +static const ObjectPropertyType * +get_object_property_data(Oid class_id) +{ + static const ObjectPropertyType *prop_last = NULL; + int index; + + /* + * A shortcut to speed up multiple consecutive lookups of a particular + * object class. + */ + if (prop_last && prop_last->class_oid == class_id) + return prop_last; + + for (index = 0; index < lengthof(ObjectProperty); index++) + { + if (ObjectProperty[index].class_oid == class_id) + { + prop_last = &ObjectProperty[index]; + return &ObjectProperty[index]; + } + } + + ereport(ERROR, + (errmsg_internal("unrecognized class ID: %u", class_id))); + + return NULL; /* keep MSC compiler happy */ +} + +/* + * Return a copy of the tuple for the object with the given object OID, from + * the given catalog (which must have been opened by the caller and suitably + * locked). NULL is returned if the OID is not found. + * + * We try a syscache first, if available. + */ +HeapTuple +get_catalog_object_by_oid(Relation catalog, AttrNumber oidcol, Oid objectId) +{ + HeapTuple tuple; + Oid classId = RelationGetRelid(catalog); + int oidCacheId = get_object_catcache_oid(classId); + + if (oidCacheId > 0) + { + tuple = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objectId)); + if (!HeapTupleIsValid(tuple)) /* should not happen */ + return NULL; + } + else + { + Oid oidIndexId = get_object_oid_index(classId); + SysScanDesc scan; + ScanKeyData skey; + + Assert(OidIsValid(oidIndexId)); + + ScanKeyInit(&skey, + oidcol, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objectId)); + + scan = systable_beginscan(catalog, oidIndexId, true, + NULL, 1, &skey); + tuple = systable_getnext(scan); + if (!HeapTupleIsValid(tuple)) + { + systable_endscan(scan); + return NULL; + } + tuple = heap_copytuple(tuple); + + systable_endscan(scan); + } + + return tuple; +} + +/* + * getObjectDescription: build an object description for messages + * + * The result is a palloc'd string. + */ +char * +getObjectDescription(const ObjectAddress *object) +{ + StringInfoData buffer; + + initStringInfo(&buffer); + + switch (getObjectClass(object)) + { + case OCLASS_CLASS: + if (object->objectSubId == 0) + getRelationDescription(&buffer, object->objectId); + else + { + /* column, not whole relation */ + StringInfoData rel; + + initStringInfo(&rel); + getRelationDescription(&rel, object->objectId); + /* translator: second %s is, e.g., "table %s" */ + appendStringInfo(&buffer, _("column %s of %s"), + get_attname(object->objectId, + object->objectSubId, + false), + rel.data); + pfree(rel.data); + } + break; + + case OCLASS_PROC: + appendStringInfo(&buffer, _("function %s"), + format_procedure(object->objectId)); + break; + + case OCLASS_TYPE: + appendStringInfo(&buffer, _("type %s"), + format_type_be(object->objectId)); + break; + + case OCLASS_CAST: + { + Relation castDesc; + ScanKeyData skey[1]; + SysScanDesc rcscan; + HeapTuple tup; + Form_pg_cast castForm; + + castDesc = table_open(CastRelationId, AccessShareLock); + + ScanKeyInit(&skey[0], + Anum_pg_cast_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + rcscan = systable_beginscan(castDesc, CastOidIndexId, true, + NULL, 1, skey); + + tup = systable_getnext(rcscan); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "could not find tuple for cast %u", + object->objectId); + + castForm = (Form_pg_cast) GETSTRUCT(tup); + + appendStringInfo(&buffer, _("cast from %s to %s"), + format_type_be(castForm->castsource), + format_type_be(castForm->casttarget)); + + systable_endscan(rcscan); + table_close(castDesc, AccessShareLock); + break; + } + + case OCLASS_COLLATION: + { + HeapTuple collTup; + Form_pg_collation coll; + char *nspname; + + collTup = SearchSysCache1(COLLOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(collTup)) + elog(ERROR, "cache lookup failed for collation %u", + object->objectId); + coll = (Form_pg_collation) GETSTRUCT(collTup); + + /* Qualify the name if not visible in search path */ + if (CollationIsVisible(object->objectId)) + nspname = NULL; + else + nspname = get_namespace_name(coll->collnamespace); + + appendStringInfo(&buffer, _("collation %s"), + quote_qualified_identifier(nspname, + NameStr(coll->collname))); + ReleaseSysCache(collTup); + break; + } + + case OCLASS_CONSTRAINT: + { + HeapTuple conTup; + Form_pg_constraint con; + + conTup = SearchSysCache1(CONSTROID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(conTup)) + elog(ERROR, "cache lookup failed for constraint %u", + object->objectId); + con = (Form_pg_constraint) GETSTRUCT(conTup); + + if (OidIsValid(con->conrelid)) + { + StringInfoData rel; + + initStringInfo(&rel); + getRelationDescription(&rel, con->conrelid); + /* translator: second %s is, e.g., "table %s" */ + appendStringInfo(&buffer, _("constraint %s on %s"), + NameStr(con->conname), rel.data); + pfree(rel.data); + } + else + { + appendStringInfo(&buffer, _("constraint %s"), + NameStr(con->conname)); + } + + ReleaseSysCache(conTup); + break; + } + + case OCLASS_CONVERSION: + { + HeapTuple conTup; + Form_pg_conversion conv; + char *nspname; + + conTup = SearchSysCache1(CONVOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(conTup)) + elog(ERROR, "cache lookup failed for conversion %u", + object->objectId); + conv = (Form_pg_conversion) GETSTRUCT(conTup); + + /* Qualify the name if not visible in search path */ + if (ConversionIsVisible(object->objectId)) + nspname = NULL; + else + nspname = get_namespace_name(conv->connamespace); + + appendStringInfo(&buffer, _("conversion %s"), + quote_qualified_identifier(nspname, + NameStr(conv->conname))); + ReleaseSysCache(conTup); + break; + } + + case OCLASS_DEFAULT: + { + Relation attrdefDesc; + ScanKeyData skey[1]; + SysScanDesc adscan; + HeapTuple tup; + Form_pg_attrdef attrdef; + ObjectAddress colobject; + + attrdefDesc = table_open(AttrDefaultRelationId, AccessShareLock); + + ScanKeyInit(&skey[0], + Anum_pg_attrdef_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(adscan); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "could not find tuple for attrdef %u", + object->objectId); + + attrdef = (Form_pg_attrdef) GETSTRUCT(tup); + + colobject.classId = RelationRelationId; + colobject.objectId = attrdef->adrelid; + colobject.objectSubId = attrdef->adnum; + + /* translator: %s is typically "column %s of table %s" */ + appendStringInfo(&buffer, _("default value for %s"), + getObjectDescription(&colobject)); + + systable_endscan(adscan); + table_close(attrdefDesc, AccessShareLock); + break; + } + + case OCLASS_LANGUAGE: + appendStringInfo(&buffer, _("language %s"), + get_language_name(object->objectId, false)); + break; + + case OCLASS_LARGEOBJECT: + appendStringInfo(&buffer, _("large object %u"), + object->objectId); + break; + + case OCLASS_OPERATOR: + appendStringInfo(&buffer, _("operator %s"), + format_operator(object->objectId)); + break; + + case OCLASS_OPCLASS: + { + HeapTuple opcTup; + Form_pg_opclass opcForm; + HeapTuple amTup; + Form_pg_am amForm; + char *nspname; + + opcTup = SearchSysCache1(CLAOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(opcTup)) + elog(ERROR, "cache lookup failed for opclass %u", + object->objectId); + opcForm = (Form_pg_opclass) GETSTRUCT(opcTup); + + amTup = SearchSysCache1(AMOID, + ObjectIdGetDatum(opcForm->opcmethod)); + if (!HeapTupleIsValid(amTup)) + elog(ERROR, "cache lookup failed for access method %u", + opcForm->opcmethod); + amForm = (Form_pg_am) GETSTRUCT(amTup); + + /* Qualify the name if not visible in search path */ + if (OpclassIsVisible(object->objectId)) + nspname = NULL; + else + nspname = get_namespace_name(opcForm->opcnamespace); + + appendStringInfo(&buffer, _("operator class %s for access method %s"), + quote_qualified_identifier(nspname, + NameStr(opcForm->opcname)), + NameStr(amForm->amname)); + + ReleaseSysCache(amTup); + ReleaseSysCache(opcTup); + break; + } + + case OCLASS_OPFAMILY: + getOpFamilyDescription(&buffer, object->objectId); + break; + + case OCLASS_AM: + { + HeapTuple tup; + + tup = SearchSysCache1(AMOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for access method %u", + object->objectId); + appendStringInfo(&buffer, _("access method %s"), + NameStr(((Form_pg_am) GETSTRUCT(tup))->amname)); + ReleaseSysCache(tup); + break; + } + + case OCLASS_AMOP: + { + Relation amopDesc; + HeapTuple tup; + ScanKeyData skey[1]; + SysScanDesc amscan; + Form_pg_amop amopForm; + StringInfoData opfam; + + amopDesc = table_open(AccessMethodOperatorRelationId, + AccessShareLock); + + ScanKeyInit(&skey[0], + Anum_pg_amop_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true, + NULL, 1, skey); + + tup = systable_getnext(amscan); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "could not find tuple for amop entry %u", + object->objectId); + + amopForm = (Form_pg_amop) GETSTRUCT(tup); + + initStringInfo(&opfam); + getOpFamilyDescription(&opfam, amopForm->amopfamily); + + /*------ + translator: %d is the operator strategy (a number), the + first two %s's are data type names, the third %s is the + description of the operator family, and the last %s is the + textual form of the operator with arguments. */ + appendStringInfo(&buffer, _("operator %d (%s, %s) of %s: %s"), + amopForm->amopstrategy, + format_type_be(amopForm->amoplefttype), + format_type_be(amopForm->amoprighttype), + opfam.data, + format_operator(amopForm->amopopr)); + + pfree(opfam.data); + + systable_endscan(amscan); + table_close(amopDesc, AccessShareLock); + break; + } + + case OCLASS_AMPROC: + { + Relation amprocDesc; + ScanKeyData skey[1]; + SysScanDesc amscan; + HeapTuple tup; + Form_pg_amproc amprocForm; + StringInfoData opfam; + + amprocDesc = table_open(AccessMethodProcedureRelationId, + AccessShareLock); + + ScanKeyInit(&skey[0], + Anum_pg_amproc_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true, + NULL, 1, skey); + + tup = systable_getnext(amscan); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "could not find tuple for amproc entry %u", + object->objectId); + + amprocForm = (Form_pg_amproc) GETSTRUCT(tup); + + initStringInfo(&opfam); + getOpFamilyDescription(&opfam, amprocForm->amprocfamily); + + /*------ + translator: %d is the function number, the first two %s's + are data type names, the third %s is the description of the + operator family, and the last %s is the textual form of the + function with arguments. */ + appendStringInfo(&buffer, _("function %d (%s, %s) of %s: %s"), + amprocForm->amprocnum, + format_type_be(amprocForm->amproclefttype), + format_type_be(amprocForm->amprocrighttype), + opfam.data, + format_procedure(amprocForm->amproc)); + + pfree(opfam.data); + + systable_endscan(amscan); + table_close(amprocDesc, AccessShareLock); + break; + } + + case OCLASS_REWRITE: + { + Relation ruleDesc; + ScanKeyData skey[1]; + SysScanDesc rcscan; + HeapTuple tup; + Form_pg_rewrite rule; + StringInfoData rel; + + ruleDesc = table_open(RewriteRelationId, AccessShareLock); + + ScanKeyInit(&skey[0], + Anum_pg_rewrite_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + rcscan = systable_beginscan(ruleDesc, RewriteOidIndexId, true, + NULL, 1, skey); + + tup = systable_getnext(rcscan); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "could not find tuple for rule %u", + object->objectId); + rule = (Form_pg_rewrite) GETSTRUCT(tup); + + initStringInfo(&rel); + getRelationDescription(&rel, rule->ev_class); + + /* translator: second %s is, e.g., "table %s" */ + appendStringInfo(&buffer, _("rule %s on %s"), + NameStr(rule->rulename), rel.data); + pfree(rel.data); + systable_endscan(rcscan); + table_close(ruleDesc, AccessShareLock); + break; + } + + case OCLASS_TRIGGER: + { + Relation trigDesc; + ScanKeyData skey[1]; + SysScanDesc tgscan; + HeapTuple tup; + Form_pg_trigger trig; + StringInfoData rel; + + trigDesc = table_open(TriggerRelationId, AccessShareLock); + + ScanKeyInit(&skey[0], + Anum_pg_trigger_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + tgscan = systable_beginscan(trigDesc, TriggerOidIndexId, true, + NULL, 1, skey); + + tup = systable_getnext(tgscan); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "could not find tuple for trigger %u", + object->objectId); + trig = (Form_pg_trigger) GETSTRUCT(tup); + + initStringInfo(&rel); + getRelationDescription(&rel, trig->tgrelid); + + /* translator: second %s is, e.g., "table %s" */ + appendStringInfo(&buffer, _("trigger %s on %s"), + NameStr(trig->tgname), rel.data); + pfree(rel.data); + systable_endscan(tgscan); + table_close(trigDesc, AccessShareLock); + break; + } + + case OCLASS_SCHEMA: + { + char *nspname; + + nspname = get_namespace_name(object->objectId); + if (!nspname) + elog(ERROR, "cache lookup failed for namespace %u", + object->objectId); + appendStringInfo(&buffer, _("schema %s"), nspname); + break; + } + + case OCLASS_STATISTIC_EXT: + { + HeapTuple stxTup; + Form_pg_statistic_ext stxForm; + char *nspname; + + stxTup = SearchSysCache1(STATEXTOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(stxTup)) + elog(ERROR, "could not find tuple for statistics object %u", + object->objectId); + stxForm = (Form_pg_statistic_ext) GETSTRUCT(stxTup); + + /* Qualify the name if not visible in search path */ + if (StatisticsObjIsVisible(object->objectId)) + nspname = NULL; + else + nspname = get_namespace_name(stxForm->stxnamespace); + + appendStringInfo(&buffer, _("statistics object %s"), + quote_qualified_identifier(nspname, + NameStr(stxForm->stxname))); + + ReleaseSysCache(stxTup); + break; + } + + case OCLASS_TSPARSER: + { + HeapTuple tup; + Form_pg_ts_parser prsForm; + char *nspname; + + tup = SearchSysCache1(TSPARSEROID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for text search parser %u", + object->objectId); + prsForm = (Form_pg_ts_parser) GETSTRUCT(tup); + + /* Qualify the name if not visible in search path */ + if (TSParserIsVisible(object->objectId)) + nspname = NULL; + else + nspname = get_namespace_name(prsForm->prsnamespace); + + appendStringInfo(&buffer, _("text search parser %s"), + quote_qualified_identifier(nspname, + NameStr(prsForm->prsname))); + ReleaseSysCache(tup); + break; + } + + case OCLASS_TSDICT: + { + HeapTuple tup; + Form_pg_ts_dict dictForm; + char *nspname; + + tup = SearchSysCache1(TSDICTOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for text search dictionary %u", + object->objectId); + dictForm = (Form_pg_ts_dict) GETSTRUCT(tup); + + /* Qualify the name if not visible in search path */ + if (TSDictionaryIsVisible(object->objectId)) + nspname = NULL; + else + nspname = get_namespace_name(dictForm->dictnamespace); + + appendStringInfo(&buffer, _("text search dictionary %s"), + quote_qualified_identifier(nspname, + NameStr(dictForm->dictname))); + ReleaseSysCache(tup); + break; + } + + case OCLASS_TSTEMPLATE: + { + HeapTuple tup; + Form_pg_ts_template tmplForm; + char *nspname; + + tup = SearchSysCache1(TSTEMPLATEOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for text search template %u", + object->objectId); + tmplForm = (Form_pg_ts_template) GETSTRUCT(tup); + + /* Qualify the name if not visible in search path */ + if (TSTemplateIsVisible(object->objectId)) + nspname = NULL; + else + nspname = get_namespace_name(tmplForm->tmplnamespace); + + appendStringInfo(&buffer, _("text search template %s"), + quote_qualified_identifier(nspname, + NameStr(tmplForm->tmplname))); + ReleaseSysCache(tup); + break; + } + + case OCLASS_TSCONFIG: + { + HeapTuple tup; + Form_pg_ts_config cfgForm; + char *nspname; + + tup = SearchSysCache1(TSCONFIGOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for text search configuration %u", + object->objectId); + cfgForm = (Form_pg_ts_config) GETSTRUCT(tup); + + /* Qualify the name if not visible in search path */ + if (TSConfigIsVisible(object->objectId)) + nspname = NULL; + else + nspname = get_namespace_name(cfgForm->cfgnamespace); + + appendStringInfo(&buffer, _("text search configuration %s"), + quote_qualified_identifier(nspname, + NameStr(cfgForm->cfgname))); + ReleaseSysCache(tup); + break; + } + + case OCLASS_ROLE: + { + appendStringInfo(&buffer, _("role %s"), + GetUserNameFromId(object->objectId, false)); + break; + } + + case OCLASS_DATABASE: + { + char *datname; + + datname = get_database_name(object->objectId); + if (!datname) + elog(ERROR, "cache lookup failed for database %u", + object->objectId); + appendStringInfo(&buffer, _("database %s"), datname); + break; + } + + case OCLASS_TBLSPACE: + { + char *tblspace; + + tblspace = get_tablespace_name(object->objectId); + if (!tblspace) + elog(ERROR, "cache lookup failed for tablespace %u", + object->objectId); + appendStringInfo(&buffer, _("tablespace %s"), tblspace); + break; + } + + case OCLASS_FDW: + { + ForeignDataWrapper *fdw; + + fdw = GetForeignDataWrapper(object->objectId); + appendStringInfo(&buffer, _("foreign-data wrapper %s"), fdw->fdwname); + break; + } + + case OCLASS_FOREIGN_SERVER: + { + ForeignServer *srv; + + srv = GetForeignServer(object->objectId); + appendStringInfo(&buffer, _("server %s"), srv->servername); + break; + } + + case OCLASS_USER_MAPPING: + { + HeapTuple tup; + Oid useid; + char *usename; + Form_pg_user_mapping umform; + ForeignServer *srv; + + tup = SearchSysCache1(USERMAPPINGOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for user mapping %u", + object->objectId); + umform = (Form_pg_user_mapping) GETSTRUCT(tup); + useid = umform->umuser; + srv = GetForeignServer(umform->umserver); + + ReleaseSysCache(tup); + + if (OidIsValid(useid)) + usename = GetUserNameFromId(useid, false); + else + usename = "public"; + + appendStringInfo(&buffer, _("user mapping for %s on server %s"), usename, + srv->servername); + break; + } + + case OCLASS_DEFACL: + { + Relation defaclrel; + ScanKeyData skey[1]; + SysScanDesc rcscan; + HeapTuple tup; + Form_pg_default_acl defacl; + char *rolename; + char *nspname; + + defaclrel = table_open(DefaultAclRelationId, AccessShareLock); + + ScanKeyInit(&skey[0], + Anum_pg_default_acl_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(rcscan); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "could not find tuple for default ACL %u", + object->objectId); + + defacl = (Form_pg_default_acl) GETSTRUCT(tup); + + rolename = GetUserNameFromId(defacl->defaclrole, false); + + if (OidIsValid(defacl->defaclnamespace)) + nspname = get_namespace_name(defacl->defaclnamespace); + else + nspname = NULL; + + switch (defacl->defaclobjtype) + { + case DEFACLOBJ_RELATION: + if (nspname) + appendStringInfo(&buffer, + _("default privileges on new relations belonging to role %s in schema %s"), + rolename, nspname); + else + appendStringInfo(&buffer, + _("default privileges on new relations belonging to role %s"), + rolename); + break; + case DEFACLOBJ_SEQUENCE: + if (nspname) + appendStringInfo(&buffer, + _("default privileges on new sequences belonging to role %s in schema %s"), + rolename, nspname); + else + appendStringInfo(&buffer, + _("default privileges on new sequences belonging to role %s"), + rolename); + break; + case DEFACLOBJ_FUNCTION: + if (nspname) + appendStringInfo(&buffer, + _("default privileges on new functions belonging to role %s in schema %s"), + rolename, nspname); + else + appendStringInfo(&buffer, + _("default privileges on new functions belonging to role %s"), + rolename); + break; + case DEFACLOBJ_TYPE: + if (nspname) + appendStringInfo(&buffer, + _("default privileges on new types belonging to role %s in schema %s"), + rolename, nspname); + else + appendStringInfo(&buffer, + _("default privileges on new types belonging to role %s"), + rolename); + break; + case DEFACLOBJ_NAMESPACE: + Assert(!nspname); + appendStringInfo(&buffer, + _("default privileges on new schemas belonging to role %s"), + rolename); + break; + default: + /* shouldn't get here */ + if (nspname) + appendStringInfo(&buffer, + _("default privileges belonging to role %s in schema %s"), + rolename, nspname); + else + appendStringInfo(&buffer, + _("default privileges belonging to role %s"), + rolename); + break; + } + + systable_endscan(rcscan); + table_close(defaclrel, AccessShareLock); + break; + } + + case OCLASS_EXTENSION: + { + char *extname; + + extname = get_extension_name(object->objectId); + if (!extname) + elog(ERROR, "cache lookup failed for extension %u", + object->objectId); + appendStringInfo(&buffer, _("extension %s"), extname); + break; + } + + case OCLASS_EVENT_TRIGGER: + { + HeapTuple tup; + + tup = SearchSysCache1(EVENTTRIGGEROID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for event trigger %u", + object->objectId); + appendStringInfo(&buffer, _("event trigger %s"), + NameStr(((Form_pg_event_trigger) GETSTRUCT(tup))->evtname)); + ReleaseSysCache(tup); + break; + } + + case OCLASS_POLICY: + { + Relation policy_rel; + ScanKeyData skey[1]; + SysScanDesc sscan; + HeapTuple tuple; + Form_pg_policy form_policy; + StringInfoData rel; + + policy_rel = table_open(PolicyRelationId, AccessShareLock); + + ScanKeyInit(&skey[0], + Anum_pg_policy_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + sscan = systable_beginscan(policy_rel, PolicyOidIndexId, + true, NULL, 1, skey); + + tuple = systable_getnext(sscan); + + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "could not find tuple for policy %u", + object->objectId); + form_policy = (Form_pg_policy) GETSTRUCT(tuple); + + initStringInfo(&rel); + getRelationDescription(&rel, form_policy->polrelid); + + /* translator: second %s is, e.g., "table %s" */ + appendStringInfo(&buffer, _("policy %s on %s"), + NameStr(form_policy->polname), rel.data); + pfree(rel.data); + systable_endscan(sscan); + table_close(policy_rel, AccessShareLock); + break; + } + + case OCLASS_PUBLICATION: + { + appendStringInfo(&buffer, _("publication %s"), + get_publication_name(object->objectId, + false)); + break; + } + + case OCLASS_PUBLICATION_REL: + { + HeapTuple tup; + char *pubname; + Form_pg_publication_rel prform; + StringInfoData rel; + + tup = SearchSysCache1(PUBLICATIONREL, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for publication table %u", + object->objectId); + + prform = (Form_pg_publication_rel) GETSTRUCT(tup); + pubname = get_publication_name(prform->prpubid, false); + + initStringInfo(&rel); + getRelationDescription(&rel, prform->prrelid); + + /* translator: first %s is, e.g., "table %s" */ + appendStringInfo(&buffer, _("publication of %s in publication %s"), + rel.data, pubname); + pfree(rel.data); + ReleaseSysCache(tup); + break; + } + + case OCLASS_SUBSCRIPTION: + { + appendStringInfo(&buffer, _("subscription %s"), + get_subscription_name(object->objectId, + false)); + break; + } + + case OCLASS_TRANSFORM: + { + HeapTuple trfTup; + Form_pg_transform trfForm; + + trfTup = SearchSysCache1(TRFOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(trfTup)) + elog(ERROR, "could not find tuple for transform %u", + object->objectId); + + trfForm = (Form_pg_transform) GETSTRUCT(trfTup); + + appendStringInfo(&buffer, _("transform for %s language %s"), + format_type_be(trfForm->trftype), + get_language_name(trfForm->trflang, false)); + + ReleaseSysCache(trfTup); + break; + } + + /* + * There's intentionally no default: case here; we want the + * compiler to warn if a new OCLASS hasn't been handled above. + */ + } + + return buffer.data; +} + +/* + * getObjectDescriptionOids: as above, except the object is specified by Oids + */ +char * +getObjectDescriptionOids(Oid classid, Oid objid) +{ + ObjectAddress address; + + address.classId = classid; + address.objectId = objid; + address.objectSubId = 0; + + return getObjectDescription(&address); +} + +/* + * subroutine for getObjectDescription: describe a relation + * + * The result is appended to "buffer". + */ +static void +getRelationDescription(StringInfo buffer, Oid relid) +{ + HeapTuple relTup; + Form_pg_class relForm; + char *nspname; + char *relname; + + relTup = SearchSysCache1(RELOID, + ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(relTup)) + elog(ERROR, "cache lookup failed for relation %u", relid); + relForm = (Form_pg_class) GETSTRUCT(relTup); + + /* Qualify the name if not visible in search path */ + if (RelationIsVisible(relid)) + nspname = NULL; + else + nspname = get_namespace_name(relForm->relnamespace); + + relname = quote_qualified_identifier(nspname, NameStr(relForm->relname)); + + switch (relForm->relkind) + { + case RELKIND_RELATION: + case RELKIND_PARTITIONED_TABLE: + appendStringInfo(buffer, _("table %s"), + relname); + break; + case RELKIND_INDEX: + case RELKIND_PARTITIONED_INDEX: + appendStringInfo(buffer, _("index %s"), + relname); + break; + case RELKIND_SEQUENCE: + appendStringInfo(buffer, _("sequence %s"), + relname); + break; + case RELKIND_TOASTVALUE: + appendStringInfo(buffer, _("toast table %s"), + relname); + break; + case RELKIND_VIEW: + appendStringInfo(buffer, _("view %s"), + relname); + break; + case RELKIND_MATVIEW: + appendStringInfo(buffer, _("materialized view %s"), + relname); + break; + case RELKIND_COMPOSITE_TYPE: + appendStringInfo(buffer, _("composite type %s"), + relname); + break; + case RELKIND_FOREIGN_TABLE: + appendStringInfo(buffer, _("foreign table %s"), + relname); + break; + default: + /* shouldn't get here */ + appendStringInfo(buffer, _("relation %s"), + relname); + break; + } + + ReleaseSysCache(relTup); +} + +/* + * subroutine for getObjectDescription: describe an operator family + */ +static void +getOpFamilyDescription(StringInfo buffer, Oid opfid) +{ + HeapTuple opfTup; + Form_pg_opfamily opfForm; + HeapTuple amTup; + Form_pg_am amForm; + char *nspname; + + opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid)); + if (!HeapTupleIsValid(opfTup)) + elog(ERROR, "cache lookup failed for opfamily %u", opfid); + opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup); + + amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod)); + if (!HeapTupleIsValid(amTup)) + elog(ERROR, "cache lookup failed for access method %u", + opfForm->opfmethod); + amForm = (Form_pg_am) GETSTRUCT(amTup); + + /* Qualify the name if not visible in search path */ + if (OpfamilyIsVisible(opfid)) + nspname = NULL; + else + nspname = get_namespace_name(opfForm->opfnamespace); + + appendStringInfo(buffer, _("operator family %s for access method %s"), + quote_qualified_identifier(nspname, + NameStr(opfForm->opfname)), + NameStr(amForm->amname)); + + ReleaseSysCache(amTup); + ReleaseSysCache(opfTup); +} + +/* + * SQL-level callable version of getObjectDescription + */ +Datum +pg_describe_object(PG_FUNCTION_ARGS) +{ + Oid classid = PG_GETARG_OID(0); + Oid objid = PG_GETARG_OID(1); + int32 objsubid = PG_GETARG_INT32(2); + char *description; + ObjectAddress address; + + /* for "pinned" items in pg_depend, return null */ + if (!OidIsValid(classid) && !OidIsValid(objid)) + PG_RETURN_NULL(); + + address.classId = classid; + address.objectId = objid; + address.objectSubId = objsubid; + + description = getObjectDescription(&address); + PG_RETURN_TEXT_P(cstring_to_text(description)); +} + +/* + * SQL-level callable function to obtain object type + identity + */ +Datum +pg_identify_object(PG_FUNCTION_ARGS) +{ + Oid classid = PG_GETARG_OID(0); + Oid objid = PG_GETARG_OID(1); + int32 objsubid = PG_GETARG_INT32(2); + Oid schema_oid = InvalidOid; + const char *objname = NULL; + ObjectAddress address; + Datum values[4]; + bool nulls[4]; + TupleDesc tupdesc; + HeapTuple htup; + + address.classId = classid; + address.objectId = objid; + address.objectSubId = objsubid; + + /* + * Construct a tuple descriptor for the result row. This must match this + * function's pg_proc entry! + */ + tupdesc = CreateTemplateTupleDesc(4); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "type", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "schema", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "name", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "identity", + TEXTOID, -1, 0); + + tupdesc = BlessTupleDesc(tupdesc); + + if (is_objectclass_supported(address.classId)) + { + HeapTuple objtup; + Relation catalog = table_open(address.classId, AccessShareLock); + + objtup = get_catalog_object_by_oid(catalog, + get_object_attnum_oid(address.classId), + address.objectId); + if (objtup != NULL) + { + bool isnull; + AttrNumber nspAttnum; + AttrNumber nameAttnum; + + nspAttnum = get_object_attnum_namespace(address.classId); + if (nspAttnum != InvalidAttrNumber) + { + schema_oid = heap_getattr(objtup, nspAttnum, + RelationGetDescr(catalog), &isnull); + if (isnull) + elog(ERROR, "invalid null namespace in object %u/%u/%d", + address.classId, address.objectId, address.objectSubId); + } + + /* + * We only return the object name if it can be used (together with + * the schema name, if any) as a unique identifier. + */ + if (get_object_namensp_unique(address.classId)) + { + nameAttnum = get_object_attnum_name(address.classId); + if (nameAttnum != InvalidAttrNumber) + { + Datum nameDatum; + + nameDatum = heap_getattr(objtup, nameAttnum, + RelationGetDescr(catalog), &isnull); + if (isnull) + elog(ERROR, "invalid null name in object %u/%u/%d", + address.classId, address.objectId, address.objectSubId); + objname = quote_identifier(NameStr(*(DatumGetName(nameDatum)))); + } + } + } + + table_close(catalog, AccessShareLock); + } + + /* object type */ + values[0] = CStringGetTextDatum(getObjectTypeDescription(&address)); + nulls[0] = false; + + /* schema name */ + if (OidIsValid(schema_oid)) + { + const char *schema = quote_identifier(get_namespace_name(schema_oid)); + + values[1] = CStringGetTextDatum(schema); + nulls[1] = false; + } + else + nulls[1] = true; + + /* object name */ + if (objname) + { + values[2] = CStringGetTextDatum(objname); + nulls[2] = false; + } + else + nulls[2] = true; + + /* object identity */ + values[3] = CStringGetTextDatum(getObjectIdentity(&address)); + nulls[3] = false; + + htup = heap_form_tuple(tupdesc, values, nulls); + + PG_RETURN_DATUM(HeapTupleGetDatum(htup)); +} + +/* + * SQL-level callable function to obtain object type + identity + */ +Datum +pg_identify_object_as_address(PG_FUNCTION_ARGS) +{ + Oid classid = PG_GETARG_OID(0); + Oid objid = PG_GETARG_OID(1); + int32 objsubid = PG_GETARG_INT32(2); + ObjectAddress address; + char *identity; + List *names; + List *args; + Datum values[3]; + bool nulls[3]; + TupleDesc tupdesc; + HeapTuple htup; + + address.classId = classid; + address.objectId = objid; + address.objectSubId = objsubid; + + /* + * Construct a tuple descriptor for the result row. This must match this + * function's pg_proc entry! + */ + tupdesc = CreateTemplateTupleDesc(3); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "type", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "object_names", + TEXTARRAYOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "object_args", + TEXTARRAYOID, -1, 0); + + tupdesc = BlessTupleDesc(tupdesc); + + /* object type */ + values[0] = CStringGetTextDatum(getObjectTypeDescription(&address)); + nulls[0] = false; + + /* object identity */ + identity = getObjectIdentityParts(&address, &names, &args); + pfree(identity); + + /* object_names */ + if (names != NIL) + values[1] = PointerGetDatum(strlist_to_textarray(names)); + else + values[1] = PointerGetDatum(construct_empty_array(TEXTOID)); + nulls[1] = false; + + /* object_args */ + if (args) + values[2] = PointerGetDatum(strlist_to_textarray(args)); + else + values[2] = PointerGetDatum(construct_empty_array(TEXTOID)); + nulls[2] = false; + + htup = heap_form_tuple(tupdesc, values, nulls); + + PG_RETURN_DATUM(HeapTupleGetDatum(htup)); +} + +/* + * Return a palloc'ed string that describes the type of object that the + * passed address is for. + * + * Keep ObjectTypeMap in sync with this. + */ +char * +getObjectTypeDescription(const ObjectAddress *object) +{ + StringInfoData buffer; + + initStringInfo(&buffer); + + switch (getObjectClass(object)) + { + case OCLASS_CLASS: + getRelationTypeDescription(&buffer, object->objectId, + object->objectSubId); + break; + + case OCLASS_PROC: + getProcedureTypeDescription(&buffer, object->objectId); + break; + + case OCLASS_TYPE: + appendStringInfoString(&buffer, "type"); + break; + + case OCLASS_CAST: + appendStringInfoString(&buffer, "cast"); + break; + + case OCLASS_COLLATION: + appendStringInfoString(&buffer, "collation"); + break; + + case OCLASS_CONSTRAINT: + getConstraintTypeDescription(&buffer, object->objectId); + break; + + case OCLASS_CONVERSION: + appendStringInfoString(&buffer, "conversion"); + break; + + case OCLASS_DEFAULT: + appendStringInfoString(&buffer, "default value"); + break; + + case OCLASS_LANGUAGE: + appendStringInfoString(&buffer, "language"); + break; + + case OCLASS_LARGEOBJECT: + appendStringInfoString(&buffer, "large object"); + break; + + case OCLASS_OPERATOR: + appendStringInfoString(&buffer, "operator"); + break; + + case OCLASS_OPCLASS: + appendStringInfoString(&buffer, "operator class"); + break; + + case OCLASS_OPFAMILY: + appendStringInfoString(&buffer, "operator family"); + break; + + case OCLASS_AM: + appendStringInfoString(&buffer, "access method"); + break; + + case OCLASS_AMOP: + appendStringInfoString(&buffer, "operator of access method"); + break; + + case OCLASS_AMPROC: + appendStringInfoString(&buffer, "function of access method"); + break; + + case OCLASS_REWRITE: + appendStringInfoString(&buffer, "rule"); + break; + + case OCLASS_TRIGGER: + appendStringInfoString(&buffer, "trigger"); + break; + + case OCLASS_SCHEMA: + appendStringInfoString(&buffer, "schema"); + break; + + case OCLASS_STATISTIC_EXT: + appendStringInfoString(&buffer, "statistics object"); + break; + + case OCLASS_TSPARSER: + appendStringInfoString(&buffer, "text search parser"); + break; + + case OCLASS_TSDICT: + appendStringInfoString(&buffer, "text search dictionary"); + break; + + case OCLASS_TSTEMPLATE: + appendStringInfoString(&buffer, "text search template"); + break; + + case OCLASS_TSCONFIG: + appendStringInfoString(&buffer, "text search configuration"); + break; + + case OCLASS_ROLE: + appendStringInfoString(&buffer, "role"); + break; + + case OCLASS_DATABASE: + appendStringInfoString(&buffer, "database"); + break; + + case OCLASS_TBLSPACE: + appendStringInfoString(&buffer, "tablespace"); + break; + + case OCLASS_FDW: + appendStringInfoString(&buffer, "foreign-data wrapper"); + break; + + case OCLASS_FOREIGN_SERVER: + appendStringInfoString(&buffer, "server"); + break; + + case OCLASS_USER_MAPPING: + appendStringInfoString(&buffer, "user mapping"); + break; + + case OCLASS_DEFACL: + appendStringInfoString(&buffer, "default acl"); + break; + + case OCLASS_EXTENSION: + appendStringInfoString(&buffer, "extension"); + break; + + case OCLASS_EVENT_TRIGGER: + appendStringInfoString(&buffer, "event trigger"); + break; + + case OCLASS_POLICY: + appendStringInfoString(&buffer, "policy"); + break; + + case OCLASS_PUBLICATION: + appendStringInfoString(&buffer, "publication"); + break; + + case OCLASS_PUBLICATION_REL: + appendStringInfoString(&buffer, "publication relation"); + break; + + case OCLASS_SUBSCRIPTION: + appendStringInfoString(&buffer, "subscription"); + break; + + case OCLASS_TRANSFORM: + appendStringInfoString(&buffer, "transform"); + break; + + /* + * There's intentionally no default: case here; we want the + * compiler to warn if a new OCLASS hasn't been handled above. + */ + } + + return buffer.data; +} + +/* + * subroutine for getObjectTypeDescription: describe a relation type + */ +static void +getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId) +{ + HeapTuple relTup; + Form_pg_class relForm; + + relTup = SearchSysCache1(RELOID, + ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(relTup)) + elog(ERROR, "cache lookup failed for relation %u", relid); + relForm = (Form_pg_class) GETSTRUCT(relTup); + + switch (relForm->relkind) + { + case RELKIND_RELATION: + case RELKIND_PARTITIONED_TABLE: + appendStringInfoString(buffer, "table"); + break; + case RELKIND_INDEX: + case RELKIND_PARTITIONED_INDEX: + appendStringInfoString(buffer, "index"); + break; + case RELKIND_SEQUENCE: + appendStringInfoString(buffer, "sequence"); + break; + case RELKIND_TOASTVALUE: + appendStringInfoString(buffer, "toast table"); + break; + case RELKIND_VIEW: + appendStringInfoString(buffer, "view"); + break; + case RELKIND_MATVIEW: + appendStringInfoString(buffer, "materialized view"); + break; + case RELKIND_COMPOSITE_TYPE: + appendStringInfoString(buffer, "composite type"); + break; + case RELKIND_FOREIGN_TABLE: + appendStringInfoString(buffer, "foreign table"); + break; + default: + /* shouldn't get here */ + appendStringInfoString(buffer, "relation"); + break; + } + + if (objectSubId != 0) + appendStringInfoString(buffer, " column"); + + ReleaseSysCache(relTup); +} + +/* + * subroutine for getObjectTypeDescription: describe a constraint type + */ +static void +getConstraintTypeDescription(StringInfo buffer, Oid constroid) +{ + Relation constrRel; + HeapTuple constrTup; + Form_pg_constraint constrForm; + + constrRel = table_open(ConstraintRelationId, AccessShareLock); + constrTup = get_catalog_object_by_oid(constrRel, Anum_pg_constraint_oid, + constroid); + if (!HeapTupleIsValid(constrTup)) + elog(ERROR, "cache lookup failed for constraint %u", constroid); + + constrForm = (Form_pg_constraint) GETSTRUCT(constrTup); + + if (OidIsValid(constrForm->conrelid)) + appendStringInfoString(buffer, "table constraint"); + else if (OidIsValid(constrForm->contypid)) + appendStringInfoString(buffer, "domain constraint"); + else + elog(ERROR, "invalid constraint %u", constrForm->oid); + + table_close(constrRel, AccessShareLock); +} + +/* + * subroutine for getObjectTypeDescription: describe a procedure type + */ +static void +getProcedureTypeDescription(StringInfo buffer, Oid procid) +{ + HeapTuple procTup; + Form_pg_proc procForm; + + procTup = SearchSysCache1(PROCOID, + ObjectIdGetDatum(procid)); + if (!HeapTupleIsValid(procTup)) + elog(ERROR, "cache lookup failed for procedure %u", procid); + procForm = (Form_pg_proc) GETSTRUCT(procTup); + + if (procForm->prokind == PROKIND_AGGREGATE) + appendStringInfoString(buffer, "aggregate"); + else if (procForm->prokind == PROKIND_PROCEDURE) + appendStringInfoString(buffer, "procedure"); + else /* function or window function */ + appendStringInfoString(buffer, "function"); + + ReleaseSysCache(procTup); +} + +/* + * Obtain a given object's identity, as a palloc'ed string. + * + * This is for machine consumption, so it's not translated. All elements are + * schema-qualified when appropriate. + */ +char * +getObjectIdentity(const ObjectAddress *object) +{ + return getObjectIdentityParts(object, NULL, NULL); +} + +/* + * As above, but more detailed. + * + * There are two sets of return values: the identity itself as a palloc'd + * string is returned. objname and objargs, if not NULL, are output parameters + * that receive lists of C-strings that are useful to give back to + * get_object_address() to reconstruct the ObjectAddress. + */ +char * +getObjectIdentityParts(const ObjectAddress *object, + List **objname, List **objargs) +{ + StringInfoData buffer; + + initStringInfo(&buffer); + + /* + * Make sure that both objname and objargs were passed, or none was; and + * initialize them to empty lists. For objname this is useless because it + * will be initialized in all cases inside the switch; but we do it anyway + * so that we can test below that no branch leaves it unset. + */ + Assert(PointerIsValid(objname) == PointerIsValid(objargs)); + if (objname) + { + *objname = NIL; + *objargs = NIL; + } + + switch (getObjectClass(object)) + { + case OCLASS_CLASS: + getRelationIdentity(&buffer, object->objectId, objname); + if (object->objectSubId != 0) + { + char *attr; + + attr = get_attname(object->objectId, object->objectSubId, + false); + appendStringInfo(&buffer, ".%s", quote_identifier(attr)); + if (objname) + *objname = lappend(*objname, attr); + } + break; + + case OCLASS_PROC: + appendStringInfoString(&buffer, + format_procedure_qualified(object->objectId)); + if (objname) + format_procedure_parts(object->objectId, objname, objargs); + break; + + case OCLASS_TYPE: + { + char *typeout; + + typeout = format_type_be_qualified(object->objectId); + appendStringInfoString(&buffer, typeout); + if (objname) + *objname = list_make1(typeout); + } + break; + + case OCLASS_CAST: + { + Relation castRel; + HeapTuple tup; + Form_pg_cast castForm; + + castRel = table_open(CastRelationId, AccessShareLock); + + tup = get_catalog_object_by_oid(castRel, Anum_pg_cast_oid, + object->objectId); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "could not find tuple for cast %u", + object->objectId); + + castForm = (Form_pg_cast) GETSTRUCT(tup); + + appendStringInfo(&buffer, "(%s AS %s)", + format_type_be_qualified(castForm->castsource), + format_type_be_qualified(castForm->casttarget)); + + if (objname) + { + *objname = list_make1(format_type_be_qualified(castForm->castsource)); + *objargs = list_make1(format_type_be_qualified(castForm->casttarget)); + } + + table_close(castRel, AccessShareLock); + break; + } + + case OCLASS_COLLATION: + { + HeapTuple collTup; + Form_pg_collation coll; + char *schema; + + collTup = SearchSysCache1(COLLOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(collTup)) + elog(ERROR, "cache lookup failed for collation %u", + object->objectId); + coll = (Form_pg_collation) GETSTRUCT(collTup); + schema = get_namespace_name_or_temp(coll->collnamespace); + appendStringInfoString(&buffer, + quote_qualified_identifier(schema, + NameStr(coll->collname))); + if (objname) + *objname = list_make2(schema, + pstrdup(NameStr(coll->collname))); + ReleaseSysCache(collTup); + break; + } + + case OCLASS_CONSTRAINT: + { + HeapTuple conTup; + Form_pg_constraint con; + + conTup = SearchSysCache1(CONSTROID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(conTup)) + elog(ERROR, "cache lookup failed for constraint %u", + object->objectId); + con = (Form_pg_constraint) GETSTRUCT(conTup); + + if (OidIsValid(con->conrelid)) + { + appendStringInfo(&buffer, "%s on ", + quote_identifier(NameStr(con->conname))); + getRelationIdentity(&buffer, con->conrelid, objname); + if (objname) + *objname = lappend(*objname, pstrdup(NameStr(con->conname))); + } + else + { + ObjectAddress domain; + + Assert(OidIsValid(con->contypid)); + domain.classId = TypeRelationId; + domain.objectId = con->contypid; + domain.objectSubId = 0; + + appendStringInfo(&buffer, "%s on %s", + quote_identifier(NameStr(con->conname)), + getObjectIdentityParts(&domain, objname, objargs)); + + if (objname) + *objargs = lappend(*objargs, pstrdup(NameStr(con->conname))); + } + + ReleaseSysCache(conTup); + break; + } + + case OCLASS_CONVERSION: + { + HeapTuple conTup; + Form_pg_conversion conForm; + char *schema; + + conTup = SearchSysCache1(CONVOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(conTup)) + elog(ERROR, "cache lookup failed for conversion %u", + object->objectId); + conForm = (Form_pg_conversion) GETSTRUCT(conTup); + schema = get_namespace_name_or_temp(conForm->connamespace); + appendStringInfoString(&buffer, + quote_qualified_identifier(schema, + NameStr(conForm->conname))); + if (objname) + *objname = list_make2(schema, + pstrdup(NameStr(conForm->conname))); + ReleaseSysCache(conTup); + break; + } + + case OCLASS_DEFAULT: + { + Relation attrdefDesc; + ScanKeyData skey[1]; + SysScanDesc adscan; + + HeapTuple tup; + Form_pg_attrdef attrdef; + ObjectAddress colobject; + + attrdefDesc = table_open(AttrDefaultRelationId, AccessShareLock); + + ScanKeyInit(&skey[0], + Anum_pg_attrdef_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(adscan); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "could not find tuple for attrdef %u", + object->objectId); + + attrdef = (Form_pg_attrdef) GETSTRUCT(tup); + + colobject.classId = RelationRelationId; + colobject.objectId = attrdef->adrelid; + colobject.objectSubId = attrdef->adnum; + + appendStringInfo(&buffer, "for %s", + getObjectIdentityParts(&colobject, + objname, objargs)); + + systable_endscan(adscan); + table_close(attrdefDesc, AccessShareLock); + break; + } + + case OCLASS_LANGUAGE: + { + HeapTuple langTup; + Form_pg_language langForm; + + langTup = SearchSysCache1(LANGOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(langTup)) + elog(ERROR, "cache lookup failed for language %u", + object->objectId); + langForm = (Form_pg_language) GETSTRUCT(langTup); + appendStringInfoString(&buffer, + quote_identifier(NameStr(langForm->lanname))); + if (objname) + *objname = list_make1(pstrdup(NameStr(langForm->lanname))); + ReleaseSysCache(langTup); + break; + } + case OCLASS_LARGEOBJECT: + appendStringInfo(&buffer, "%u", + object->objectId); + if (objname) + *objname = list_make1(psprintf("%u", object->objectId)); + break; + + case OCLASS_OPERATOR: + appendStringInfoString(&buffer, + format_operator_qualified(object->objectId)); + if (objname) + format_operator_parts(object->objectId, objname, objargs); + break; + + case OCLASS_OPCLASS: + { + HeapTuple opcTup; + Form_pg_opclass opcForm; + HeapTuple amTup; + Form_pg_am amForm; + char *schema; + + opcTup = SearchSysCache1(CLAOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(opcTup)) + elog(ERROR, "cache lookup failed for opclass %u", + object->objectId); + opcForm = (Form_pg_opclass) GETSTRUCT(opcTup); + schema = get_namespace_name_or_temp(opcForm->opcnamespace); + + amTup = SearchSysCache1(AMOID, + ObjectIdGetDatum(opcForm->opcmethod)); + if (!HeapTupleIsValid(amTup)) + elog(ERROR, "cache lookup failed for access method %u", + opcForm->opcmethod); + amForm = (Form_pg_am) GETSTRUCT(amTup); + + appendStringInfo(&buffer, "%s USING %s", + quote_qualified_identifier(schema, + NameStr(opcForm->opcname)), + quote_identifier(NameStr(amForm->amname))); + if (objname) + *objname = list_make3(pstrdup(NameStr(amForm->amname)), + schema, + pstrdup(NameStr(opcForm->opcname))); + + ReleaseSysCache(amTup); + ReleaseSysCache(opcTup); + break; + } + + case OCLASS_OPFAMILY: + getOpFamilyIdentity(&buffer, object->objectId, objname); + break; + + case OCLASS_AM: + { + char *amname; + + amname = get_am_name(object->objectId); + if (!amname) + elog(ERROR, "cache lookup failed for access method %u", + object->objectId); + appendStringInfoString(&buffer, quote_identifier(amname)); + if (objname) + *objname = list_make1(amname); + } + break; + + case OCLASS_AMOP: + { + Relation amopDesc; + HeapTuple tup; + ScanKeyData skey[1]; + SysScanDesc amscan; + Form_pg_amop amopForm; + StringInfoData opfam; + char *ltype; + char *rtype; + + amopDesc = table_open(AccessMethodOperatorRelationId, + AccessShareLock); + + ScanKeyInit(&skey[0], + Anum_pg_amop_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true, + NULL, 1, skey); + + tup = systable_getnext(amscan); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "could not find tuple for amop entry %u", + object->objectId); + + amopForm = (Form_pg_amop) GETSTRUCT(tup); + + initStringInfo(&opfam); + getOpFamilyIdentity(&opfam, amopForm->amopfamily, objname); + + ltype = format_type_be_qualified(amopForm->amoplefttype); + rtype = format_type_be_qualified(amopForm->amoprighttype); + + if (objname) + { + *objname = lappend(*objname, + psprintf("%d", amopForm->amopstrategy)); + *objargs = list_make2(ltype, rtype); + } + + appendStringInfo(&buffer, "operator %d (%s, %s) of %s", + amopForm->amopstrategy, + ltype, rtype, opfam.data); + + pfree(opfam.data); + + systable_endscan(amscan); + table_close(amopDesc, AccessShareLock); + break; + } + + case OCLASS_AMPROC: + { + Relation amprocDesc; + ScanKeyData skey[1]; + SysScanDesc amscan; + HeapTuple tup; + Form_pg_amproc amprocForm; + StringInfoData opfam; + char *ltype; + char *rtype; + + amprocDesc = table_open(AccessMethodProcedureRelationId, + AccessShareLock); + + ScanKeyInit(&skey[0], + Anum_pg_amproc_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true, + NULL, 1, skey); + + tup = systable_getnext(amscan); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "could not find tuple for amproc entry %u", + object->objectId); + + amprocForm = (Form_pg_amproc) GETSTRUCT(tup); + + initStringInfo(&opfam); + getOpFamilyIdentity(&opfam, amprocForm->amprocfamily, objname); + + ltype = format_type_be_qualified(amprocForm->amproclefttype); + rtype = format_type_be_qualified(amprocForm->amprocrighttype); + + if (objname) + { + *objname = lappend(*objname, + psprintf("%d", amprocForm->amprocnum)); + *objargs = list_make2(ltype, rtype); + } + + appendStringInfo(&buffer, "function %d (%s, %s) of %s", + amprocForm->amprocnum, + ltype, rtype, opfam.data); + + pfree(opfam.data); + + systable_endscan(amscan); + table_close(amprocDesc, AccessShareLock); + break; + } + + case OCLASS_REWRITE: + { + Relation ruleDesc; + HeapTuple tup; + Form_pg_rewrite rule; + + ruleDesc = table_open(RewriteRelationId, AccessShareLock); + + tup = get_catalog_object_by_oid(ruleDesc, Anum_pg_rewrite_oid, + object->objectId); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "could not find tuple for rule %u", + object->objectId); + + rule = (Form_pg_rewrite) GETSTRUCT(tup); + + appendStringInfo(&buffer, "%s on ", + quote_identifier(NameStr(rule->rulename))); + getRelationIdentity(&buffer, rule->ev_class, objname); + if (objname) + *objname = lappend(*objname, pstrdup(NameStr(rule->rulename))); + + table_close(ruleDesc, AccessShareLock); + break; + } + + case OCLASS_TRIGGER: + { + Relation trigDesc; + HeapTuple tup; + Form_pg_trigger trig; + + trigDesc = table_open(TriggerRelationId, AccessShareLock); + + tup = get_catalog_object_by_oid(trigDesc, Anum_pg_trigger_oid, + object->objectId); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "could not find tuple for trigger %u", + object->objectId); + + trig = (Form_pg_trigger) GETSTRUCT(tup); + + appendStringInfo(&buffer, "%s on ", + quote_identifier(NameStr(trig->tgname))); + getRelationIdentity(&buffer, trig->tgrelid, objname); + if (objname) + *objname = lappend(*objname, pstrdup(NameStr(trig->tgname))); + + table_close(trigDesc, AccessShareLock); + break; + } + + case OCLASS_SCHEMA: + { + char *nspname; + + nspname = get_namespace_name_or_temp(object->objectId); + if (!nspname) + elog(ERROR, "cache lookup failed for namespace %u", + object->objectId); + appendStringInfoString(&buffer, + quote_identifier(nspname)); + if (objname) + *objname = list_make1(nspname); + break; + } + + case OCLASS_STATISTIC_EXT: + { + HeapTuple tup; + Form_pg_statistic_ext formStatistic; + char *schema; + + tup = SearchSysCache1(STATEXTOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for statistics object %u", + object->objectId); + formStatistic = (Form_pg_statistic_ext) GETSTRUCT(tup); + schema = get_namespace_name_or_temp(formStatistic->stxnamespace); + appendStringInfoString(&buffer, + quote_qualified_identifier(schema, + NameStr(formStatistic->stxname))); + if (objname) + *objname = list_make2(schema, + pstrdup(NameStr(formStatistic->stxname))); + ReleaseSysCache(tup); + } + break; + + case OCLASS_TSPARSER: + { + HeapTuple tup; + Form_pg_ts_parser formParser; + char *schema; + + tup = SearchSysCache1(TSPARSEROID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for text search parser %u", + object->objectId); + formParser = (Form_pg_ts_parser) GETSTRUCT(tup); + schema = get_namespace_name_or_temp(formParser->prsnamespace); + appendStringInfoString(&buffer, + quote_qualified_identifier(schema, + NameStr(formParser->prsname))); + if (objname) + *objname = list_make2(schema, + pstrdup(NameStr(formParser->prsname))); + ReleaseSysCache(tup); + break; + } + + case OCLASS_TSDICT: + { + HeapTuple tup; + Form_pg_ts_dict formDict; + char *schema; + + tup = SearchSysCache1(TSDICTOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for text search dictionary %u", + object->objectId); + formDict = (Form_pg_ts_dict) GETSTRUCT(tup); + schema = get_namespace_name_or_temp(formDict->dictnamespace); + appendStringInfoString(&buffer, + quote_qualified_identifier(schema, + NameStr(formDict->dictname))); + if (objname) + *objname = list_make2(schema, + pstrdup(NameStr(formDict->dictname))); + ReleaseSysCache(tup); + break; + } + + case OCLASS_TSTEMPLATE: + { + HeapTuple tup; + Form_pg_ts_template formTmpl; + char *schema; + + tup = SearchSysCache1(TSTEMPLATEOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for text search template %u", + object->objectId); + formTmpl = (Form_pg_ts_template) GETSTRUCT(tup); + schema = get_namespace_name_or_temp(formTmpl->tmplnamespace); + appendStringInfoString(&buffer, + quote_qualified_identifier(schema, + NameStr(formTmpl->tmplname))); + if (objname) + *objname = list_make2(schema, + pstrdup(NameStr(formTmpl->tmplname))); + ReleaseSysCache(tup); + break; + } + + case OCLASS_TSCONFIG: + { + HeapTuple tup; + Form_pg_ts_config formCfg; + char *schema; + + tup = SearchSysCache1(TSCONFIGOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for text search configuration %u", + object->objectId); + formCfg = (Form_pg_ts_config) GETSTRUCT(tup); + schema = get_namespace_name_or_temp(formCfg->cfgnamespace); + appendStringInfoString(&buffer, + quote_qualified_identifier(schema, + NameStr(formCfg->cfgname))); + if (objname) + *objname = list_make2(schema, + pstrdup(NameStr(formCfg->cfgname))); + ReleaseSysCache(tup); + break; + } + + case OCLASS_ROLE: + { + char *username; + + username = GetUserNameFromId(object->objectId, false); + if (objname) + *objname = list_make1(username); + appendStringInfoString(&buffer, + quote_identifier(username)); + break; + } + + case OCLASS_DATABASE: + { + char *datname; + + datname = get_database_name(object->objectId); + if (!datname) + elog(ERROR, "cache lookup failed for database %u", + object->objectId); + if (objname) + *objname = list_make1(datname); + appendStringInfoString(&buffer, + quote_identifier(datname)); + break; + } + + case OCLASS_TBLSPACE: + { + char *tblspace; + + tblspace = get_tablespace_name(object->objectId); + if (!tblspace) + elog(ERROR, "cache lookup failed for tablespace %u", + object->objectId); + if (objname) + *objname = list_make1(tblspace); + appendStringInfoString(&buffer, + quote_identifier(tblspace)); + break; + } + + case OCLASS_FDW: + { + ForeignDataWrapper *fdw; + + fdw = GetForeignDataWrapper(object->objectId); + appendStringInfoString(&buffer, quote_identifier(fdw->fdwname)); + if (objname) + *objname = list_make1(pstrdup(fdw->fdwname)); + break; + } + + case OCLASS_FOREIGN_SERVER: + { + ForeignServer *srv; + + srv = GetForeignServer(object->objectId); + appendStringInfoString(&buffer, + quote_identifier(srv->servername)); + if (objname) + *objname = list_make1(pstrdup(srv->servername)); + break; + } + + case OCLASS_USER_MAPPING: + { + HeapTuple tup; + Oid useid; + Form_pg_user_mapping umform; + ForeignServer *srv; + const char *usename; + + tup = SearchSysCache1(USERMAPPINGOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for user mapping %u", + object->objectId); + umform = (Form_pg_user_mapping) GETSTRUCT(tup); + useid = umform->umuser; + srv = GetForeignServer(umform->umserver); + + ReleaseSysCache(tup); + + if (OidIsValid(useid)) + usename = GetUserNameFromId(useid, false); + else + usename = "public"; + + if (objname) + { + *objname = list_make1(pstrdup(usename)); + *objargs = list_make1(pstrdup(srv->servername)); + } + + appendStringInfo(&buffer, "%s on server %s", + quote_identifier(usename), + srv->servername); + break; + } + + case OCLASS_DEFACL: + { + Relation defaclrel; + ScanKeyData skey[1]; + SysScanDesc rcscan; + HeapTuple tup; + Form_pg_default_acl defacl; + char *schema; + char *username; + + defaclrel = table_open(DefaultAclRelationId, AccessShareLock); + + ScanKeyInit(&skey[0], + Anum_pg_default_acl_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(rcscan); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "could not find tuple for default ACL %u", + object->objectId); + + defacl = (Form_pg_default_acl) GETSTRUCT(tup); + + username = GetUserNameFromId(defacl->defaclrole, false); + appendStringInfo(&buffer, + "for role %s", + quote_identifier(username)); + + if (OidIsValid(defacl->defaclnamespace)) + { + schema = get_namespace_name_or_temp(defacl->defaclnamespace); + appendStringInfo(&buffer, + " in schema %s", + quote_identifier(schema)); + } + else + schema = NULL; + + switch (defacl->defaclobjtype) + { + case DEFACLOBJ_RELATION: + appendStringInfoString(&buffer, + " on tables"); + break; + case DEFACLOBJ_SEQUENCE: + appendStringInfoString(&buffer, + " on sequences"); + break; + case DEFACLOBJ_FUNCTION: + appendStringInfoString(&buffer, + " on functions"); + break; + case DEFACLOBJ_TYPE: + appendStringInfoString(&buffer, + " on types"); + break; + case DEFACLOBJ_NAMESPACE: + appendStringInfoString(&buffer, + " on schemas"); + break; + } + + if (objname) + { + *objname = list_make1(username); + if (schema) + *objname = lappend(*objname, schema); + *objargs = list_make1(psprintf("%c", defacl->defaclobjtype)); + } + + systable_endscan(rcscan); + table_close(defaclrel, AccessShareLock); + break; + } + + case OCLASS_EXTENSION: + { + char *extname; + + extname = get_extension_name(object->objectId); + if (!extname) + elog(ERROR, "cache lookup failed for extension %u", + object->objectId); + appendStringInfoString(&buffer, quote_identifier(extname)); + if (objname) + *objname = list_make1(extname); + break; + } + + case OCLASS_EVENT_TRIGGER: + { + HeapTuple tup; + Form_pg_event_trigger trigForm; + char *evtname; + + tup = SearchSysCache1(EVENTTRIGGEROID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for event trigger %u", + object->objectId); + trigForm = (Form_pg_event_trigger) GETSTRUCT(tup); + evtname = pstrdup(NameStr(trigForm->evtname)); + appendStringInfoString(&buffer, quote_identifier(evtname)); + if (objname) + *objname = list_make1(evtname); + ReleaseSysCache(tup); + break; + } + + case OCLASS_POLICY: + { + Relation polDesc; + HeapTuple tup; + Form_pg_policy policy; + + polDesc = table_open(PolicyRelationId, AccessShareLock); + + tup = get_catalog_object_by_oid(polDesc, Anum_pg_policy_oid, + object->objectId); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "could not find tuple for policy %u", + object->objectId); + + policy = (Form_pg_policy) GETSTRUCT(tup); + + appendStringInfo(&buffer, "%s on ", + quote_identifier(NameStr(policy->polname))); + getRelationIdentity(&buffer, policy->polrelid, objname); + if (objname) + *objname = lappend(*objname, pstrdup(NameStr(policy->polname))); + + table_close(polDesc, AccessShareLock); + break; + } + + case OCLASS_PUBLICATION: + { + char *pubname; + + pubname = get_publication_name(object->objectId, false); + appendStringInfoString(&buffer, + quote_identifier(pubname)); + if (objname) + *objname = list_make1(pubname); + break; + } + + case OCLASS_PUBLICATION_REL: + { + HeapTuple tup; + char *pubname; + Form_pg_publication_rel prform; + + tup = SearchSysCache1(PUBLICATIONREL, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for publication table %u", + object->objectId); + + prform = (Form_pg_publication_rel) GETSTRUCT(tup); + pubname = get_publication_name(prform->prpubid, false); + + getRelationIdentity(&buffer, prform->prrelid, objname); + appendStringInfo(&buffer, " in publication %s", pubname); + + if (objargs) + *objargs = list_make1(pubname); + + ReleaseSysCache(tup); + break; + } + + case OCLASS_SUBSCRIPTION: + { + char *subname; + + subname = get_subscription_name(object->objectId, false); + appendStringInfoString(&buffer, + quote_identifier(subname)); + if (objname) + *objname = list_make1(subname); + break; + } + + case OCLASS_TRANSFORM: + { + Relation transformDesc; + HeapTuple tup; + Form_pg_transform transform; + char *transformLang; + char *transformType; + + transformDesc = table_open(TransformRelationId, AccessShareLock); + + tup = get_catalog_object_by_oid(transformDesc, + Anum_pg_transform_oid, + object->objectId); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "could not find tuple for transform %u", + object->objectId); + + transform = (Form_pg_transform) GETSTRUCT(tup); + + transformType = format_type_be_qualified(transform->trftype); + transformLang = get_language_name(transform->trflang, false); + + appendStringInfo(&buffer, "for %s on language %s", + transformType, + transformLang); + if (objname) + { + *objname = list_make1(transformType); + *objargs = list_make1(pstrdup(transformLang)); + } + + table_close(transformDesc, AccessShareLock); + } + break; + + /* + * There's intentionally no default: case here; we want the + * compiler to warn if a new OCLASS hasn't been handled above. + */ + } + + /* + * If a get_object_address representation was requested, make sure we are + * providing one. We don't check objargs, because many of the cases above + * leave it as NIL. + */ + if (objname && *objname == NIL) + elog(ERROR, "requested object address for unsupported object class %d: text result \"%s\"", + (int) getObjectClass(object), buffer.data); + + return buffer.data; +} + +static void +getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object) +{ + HeapTuple opfTup; + Form_pg_opfamily opfForm; + HeapTuple amTup; + Form_pg_am amForm; + char *schema; + + opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid)); + if (!HeapTupleIsValid(opfTup)) + elog(ERROR, "cache lookup failed for opfamily %u", opfid); + opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup); + + amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod)); + if (!HeapTupleIsValid(amTup)) + elog(ERROR, "cache lookup failed for access method %u", + opfForm->opfmethod); + amForm = (Form_pg_am) GETSTRUCT(amTup); + + schema = get_namespace_name_or_temp(opfForm->opfnamespace); + appendStringInfo(buffer, "%s USING %s", + quote_qualified_identifier(schema, + NameStr(opfForm->opfname)), + NameStr(amForm->amname)); + + if (object) + *object = list_make3(pstrdup(NameStr(amForm->amname)), + pstrdup(schema), + pstrdup(NameStr(opfForm->opfname))); + + ReleaseSysCache(amTup); + ReleaseSysCache(opfTup); +} + +/* + * Append the relation identity (quoted qualified name) to the given + * StringInfo. + */ +static void +getRelationIdentity(StringInfo buffer, Oid relid, List **object) +{ + HeapTuple relTup; + Form_pg_class relForm; + char *schema; + + relTup = SearchSysCache1(RELOID, + ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(relTup)) + elog(ERROR, "cache lookup failed for relation %u", relid); + relForm = (Form_pg_class) GETSTRUCT(relTup); + + schema = get_namespace_name_or_temp(relForm->relnamespace); + appendStringInfoString(buffer, + quote_qualified_identifier(schema, + NameStr(relForm->relname))); + if (object) + *object = list_make2(schema, pstrdup(NameStr(relForm->relname))); + + ReleaseSysCache(relTup); +} + +/* + * Auxiliary function to build a TEXT array out of a list of C-strings. + */ +ArrayType * +strlist_to_textarray(List *list) +{ + ArrayType *arr; + Datum *datums; + bool *nulls; + int j = 0; + ListCell *cell; + MemoryContext memcxt; + MemoryContext oldcxt; + int lb[1]; + + /* Work in a temp context; easier than individually pfree'ing the Datums */ + memcxt = AllocSetContextCreate(CurrentMemoryContext, + "strlist to array", + ALLOCSET_DEFAULT_SIZES); + oldcxt = MemoryContextSwitchTo(memcxt); + + datums = (Datum *) palloc(sizeof(Datum) * list_length(list)); + nulls = palloc(sizeof(bool) * list_length(list)); + + foreach(cell, list) + { + char *name = lfirst(cell); + + if (name) + { + nulls[j] = false; + datums[j++] = CStringGetTextDatum(name); + } + else + nulls[j] = true; + } + + MemoryContextSwitchTo(oldcxt); + + lb[0] = 1; + arr = construct_md_array(datums, nulls, 1, &j, + lb, TEXTOID, -1, false, TYPALIGN_INT); + + MemoryContextDelete(memcxt); + + return arr; +} + +/* + * get_relkind_objtype + * + * Return the object type for the relkind given by the caller. + * + * If an unexpected relkind is passed, we say OBJECT_TABLE rather than + * failing. That's because this is mostly used for generating error messages + * for failed ACL checks on relations, and we'd rather produce a generic + * message saying "table" than fail entirely. + */ +ObjectType +get_relkind_objtype(char relkind) +{ + switch (relkind) + { + case RELKIND_RELATION: + case RELKIND_PARTITIONED_TABLE: + return OBJECT_TABLE; + case RELKIND_INDEX: + case RELKIND_PARTITIONED_INDEX: + return OBJECT_INDEX; + case RELKIND_SEQUENCE: + return OBJECT_SEQUENCE; + case RELKIND_VIEW: + return OBJECT_VIEW; + case RELKIND_MATVIEW: + return OBJECT_MATVIEW; + case RELKIND_FOREIGN_TABLE: + return OBJECT_FOREIGN_TABLE; + case RELKIND_TOASTVALUE: + return OBJECT_TABLE; + default: + /* Per above, don't raise an error */ + return OBJECT_TABLE; + } +} diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c new file mode 100644 index 0000000..4dfac39 --- /dev/null +++ b/src/backend/catalog/partition.c @@ -0,0 +1,368 @@ +/*------------------------------------------------------------------------- + * + * partition.c + * Partitioning related data structures and functions. + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/partition.c + * + *------------------------------------------------------------------------- +*/ +#include "postgres.h" + +#include "access/attmap.h" +#include "access/genam.h" +#include "access/htup_details.h" +#include "access/sysattr.h" +#include "access/table.h" +#include "catalog/indexing.h" +#include "catalog/partition.h" +#include "catalog/pg_inherits.h" +#include "catalog/pg_partitioned_table.h" +#include "nodes/makefuncs.h" +#include "optimizer/optimizer.h" +#include "partitioning/partbounds.h" +#include "rewrite/rewriteManip.h" +#include "utils/fmgroids.h" +#include "utils/partcache.h" +#include "utils/rel.h" +#include "utils/syscache.h" + +static Oid get_partition_parent_worker(Relation inhRel, Oid relid); +static void get_partition_ancestors_worker(Relation inhRel, Oid relid, + List **ancestors); + +/* + * get_partition_parent + * Obtain direct parent of given relation + * + * Returns inheritance parent of a partition by scanning pg_inherits + * + * Note: Because this function assumes that the relation whose OID is passed + * as an argument will have precisely one parent, it should only be called + * when it is known that the relation is a partition. + */ +Oid +get_partition_parent(Oid relid) +{ + Relation catalogRelation; + Oid result; + + catalogRelation = table_open(InheritsRelationId, AccessShareLock); + + result = get_partition_parent_worker(catalogRelation, relid); + + if (!OidIsValid(result)) + elog(ERROR, "could not find tuple for parent of relation %u", relid); + + table_close(catalogRelation, AccessShareLock); + + return result; +} + +/* + * get_partition_parent_worker + * Scan the pg_inherits relation to return the OID of the parent of the + * given relation + */ +static Oid +get_partition_parent_worker(Relation inhRel, Oid relid) +{ + SysScanDesc scan; + ScanKeyData key[2]; + Oid result = InvalidOid; + HeapTuple tuple; + + ScanKeyInit(&key[0], + Anum_pg_inherits_inhrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(relid)); + ScanKeyInit(&key[1], + Anum_pg_inherits_inhseqno, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(1)); + + scan = systable_beginscan(inhRel, InheritsRelidSeqnoIndexId, true, + NULL, 2, key); + tuple = systable_getnext(scan); + if (HeapTupleIsValid(tuple)) + { + Form_pg_inherits form = (Form_pg_inherits) GETSTRUCT(tuple); + + result = form->inhparent; + } + + systable_endscan(scan); + + return result; +} + +/* + * get_partition_ancestors + * Obtain ancestors of given relation + * + * Returns a list of ancestors of the given relation. + * + * Note: Because this function assumes that the relation whose OID is passed + * as an argument and each ancestor will have precisely one parent, it should + * only be called when it is known that the relation is a partition. + */ +List * +get_partition_ancestors(Oid relid) +{ + List *result = NIL; + Relation inhRel; + + inhRel = table_open(InheritsRelationId, AccessShareLock); + + get_partition_ancestors_worker(inhRel, relid, &result); + + table_close(inhRel, AccessShareLock); + + return result; +} + +/* + * get_partition_ancestors_worker + * recursive worker for get_partition_ancestors + */ +static void +get_partition_ancestors_worker(Relation inhRel, Oid relid, List **ancestors) +{ + Oid parentOid; + + /* Recursion ends at the topmost level, ie., when there's no parent */ + parentOid = get_partition_parent_worker(inhRel, relid); + if (parentOid == InvalidOid) + return; + + *ancestors = lappend_oid(*ancestors, parentOid); + get_partition_ancestors_worker(inhRel, parentOid, ancestors); +} + +/* + * index_get_partition + * Return the OID of index of the given partition that is a child + * of the given index, or InvalidOid if there isn't one. + */ +Oid +index_get_partition(Relation partition, Oid indexId) +{ + List *idxlist = RelationGetIndexList(partition); + ListCell *l; + + foreach(l, idxlist) + { + Oid partIdx = lfirst_oid(l); + HeapTuple tup; + Form_pg_class classForm; + bool ispartition; + + tup = SearchSysCache1(RELOID, ObjectIdGetDatum(partIdx)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for relation %u", partIdx); + classForm = (Form_pg_class) GETSTRUCT(tup); + ispartition = classForm->relispartition; + ReleaseSysCache(tup); + if (!ispartition) + continue; + if (get_partition_parent(partIdx) == indexId) + { + list_free(idxlist); + return partIdx; + } + } + + list_free(idxlist); + return InvalidOid; +} + +/* + * map_partition_varattnos - maps varattnos of all Vars in 'expr' (that have + * varno 'fromrel_varno') from the attnums of 'from_rel' to the attnums of + * 'to_rel', each of which may be either a leaf partition or a partitioned + * table, but both of which must be from the same partitioning hierarchy. + * + * We need this because even though all of the same column names must be + * present in all relations in the hierarchy, and they must also have the + * same types, the attnums may be different. + * + * Note: this will work on any node tree, so really the argument and result + * should be declared "Node *". But a substantial majority of the callers + * are working on Lists, so it's less messy to do the casts internally. + */ +List * +map_partition_varattnos(List *expr, int fromrel_varno, + Relation to_rel, Relation from_rel) +{ + if (expr != NIL) + { + AttrMap *part_attmap; + bool found_whole_row; + + part_attmap = build_attrmap_by_name(RelationGetDescr(to_rel), + RelationGetDescr(from_rel)); + expr = (List *) map_variable_attnos((Node *) expr, + fromrel_varno, 0, + part_attmap, + RelationGetForm(to_rel)->reltype, + &found_whole_row); + /* Since we provided a to_rowtype, we may ignore found_whole_row. */ + } + + return expr; +} + +/* + * Checks if any of the 'attnums' is a partition key attribute for rel + * + * Sets *used_in_expr if any of the 'attnums' is found to be referenced in some + * partition key expression. It's possible for a column to be both used + * directly and as part of an expression; if that happens, *used_in_expr may + * end up as either true or false. That's OK for current uses of this + * function, because *used_in_expr is only used to tailor the error message + * text. + */ +bool +has_partition_attrs(Relation rel, Bitmapset *attnums, bool *used_in_expr) +{ + PartitionKey key; + int partnatts; + List *partexprs; + ListCell *partexprs_item; + int i; + + if (attnums == NULL || rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) + return false; + + key = RelationGetPartitionKey(rel); + partnatts = get_partition_natts(key); + partexprs = get_partition_exprs(key); + + partexprs_item = list_head(partexprs); + for (i = 0; i < partnatts; i++) + { + AttrNumber partattno = get_partition_col_attnum(key, i); + + if (partattno != 0) + { + if (bms_is_member(partattno - FirstLowInvalidHeapAttributeNumber, + attnums)) + { + if (used_in_expr) + *used_in_expr = false; + return true; + } + } + else + { + /* Arbitrary expression */ + Node *expr = (Node *) lfirst(partexprs_item); + Bitmapset *expr_attrs = NULL; + + /* Find all attributes referenced */ + pull_varattnos(expr, 1, &expr_attrs); + partexprs_item = lnext(partexprs, partexprs_item); + + if (bms_overlap(attnums, expr_attrs)) + { + if (used_in_expr) + *used_in_expr = true; + return true; + } + } + } + + return false; +} + +/* + * get_default_partition_oid + * + * Given a relation OID, return the OID of the default partition, if one + * exists. Use get_default_oid_from_partdesc where possible, for + * efficiency. + */ +Oid +get_default_partition_oid(Oid parentId) +{ + HeapTuple tuple; + Oid defaultPartId = InvalidOid; + + tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(parentId)); + + if (HeapTupleIsValid(tuple)) + { + Form_pg_partitioned_table part_table_form; + + part_table_form = (Form_pg_partitioned_table) GETSTRUCT(tuple); + defaultPartId = part_table_form->partdefid; + ReleaseSysCache(tuple); + } + + return defaultPartId; +} + +/* + * update_default_partition_oid + * + * Update pg_partitioned_table.partdefid with a new default partition OID. + */ +void +update_default_partition_oid(Oid parentId, Oid defaultPartId) +{ + HeapTuple tuple; + Relation pg_partitioned_table; + Form_pg_partitioned_table part_table_form; + + pg_partitioned_table = table_open(PartitionedRelationId, RowExclusiveLock); + + tuple = SearchSysCacheCopy1(PARTRELID, ObjectIdGetDatum(parentId)); + + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for partition key of relation %u", + parentId); + + part_table_form = (Form_pg_partitioned_table) GETSTRUCT(tuple); + part_table_form->partdefid = defaultPartId; + CatalogTupleUpdate(pg_partitioned_table, &tuple->t_self, tuple); + + heap_freetuple(tuple); + table_close(pg_partitioned_table, RowExclusiveLock); +} + +/* + * get_proposed_default_constraint + * + * This function returns the negation of new_part_constraints, which + * would be an integral part of the default partition constraints after + * addition of the partition to which the new_part_constraints belongs. + */ +List * +get_proposed_default_constraint(List *new_part_constraints) +{ + Expr *defPartConstraint; + + defPartConstraint = make_ands_explicit(new_part_constraints); + + /* + * Derive the partition constraints of default partition by negating the + * given partition constraints. The partition constraint never evaluates + * to NULL, so negating it like this is safe. + */ + defPartConstraint = makeBoolExpr(NOT_EXPR, + list_make1(defPartConstraint), + -1); + + /* Simplify, to put the negated expression into canonical form */ + defPartConstraint = + (Expr *) eval_const_expressions(NULL, + (Node *) defPartConstraint); + defPartConstraint = canonicalize_qual(defPartConstraint, true); + + return make_ands_implicit(defPartConstraint); +} diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c new file mode 100644 index 0000000..6707fbc --- /dev/null +++ b/src/backend/catalog/pg_aggregate.c @@ -0,0 +1,926 @@ +/*------------------------------------------------------------------------- + * + * pg_aggregate.c + * routines to support manipulation of the pg_aggregate relation + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/pg_aggregate.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/htup_details.h" +#include "access/table.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/pg_aggregate.h" +#include "catalog/pg_language.h" +#include "catalog/pg_operator.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_type.h" +#include "miscadmin.h" +#include "parser/parse_coerce.h" +#include "parser/parse_func.h" +#include "parser/parse_oper.h" +#include "utils/acl.h" +#include "utils/builtins.h" +#include "utils/lsyscache.h" +#include "utils/rel.h" +#include "utils/syscache.h" + + +static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types, + Oid variadicArgType, + Oid *rettype); + + +/* + * AggregateCreate + */ +ObjectAddress +AggregateCreate(const char *aggName, + Oid aggNamespace, + bool replace, + char aggKind, + int numArgs, + int numDirectArgs, + oidvector *parameterTypes, + Datum allParameterTypes, + Datum parameterModes, + Datum parameterNames, + List *parameterDefaults, + Oid variadicArgType, + List *aggtransfnName, + List *aggfinalfnName, + List *aggcombinefnName, + List *aggserialfnName, + List *aggdeserialfnName, + List *aggmtransfnName, + List *aggminvtransfnName, + List *aggmfinalfnName, + bool finalfnExtraArgs, + bool mfinalfnExtraArgs, + char finalfnModify, + char mfinalfnModify, + List *aggsortopName, + Oid aggTransType, + int32 aggTransSpace, + Oid aggmTransType, + int32 aggmTransSpace, + const char *agginitval, + const char *aggminitval, + char proparallel) +{ + Relation aggdesc; + HeapTuple tup; + HeapTuple oldtup; + bool nulls[Natts_pg_aggregate]; + Datum values[Natts_pg_aggregate]; + bool replaces[Natts_pg_aggregate]; + Form_pg_proc proc; + Oid transfn; + Oid finalfn = InvalidOid; /* can be omitted */ + Oid combinefn = InvalidOid; /* can be omitted */ + Oid serialfn = InvalidOid; /* can be omitted */ + Oid deserialfn = InvalidOid; /* can be omitted */ + Oid mtransfn = InvalidOid; /* can be omitted */ + Oid minvtransfn = InvalidOid; /* can be omitted */ + Oid mfinalfn = InvalidOid; /* can be omitted */ + Oid sortop = InvalidOid; /* can be omitted */ + Oid *aggArgTypes = parameterTypes->values; + bool mtransIsStrict = false; + Oid rettype; + Oid finaltype; + Oid fnArgs[FUNC_MAX_ARGS]; + int nargs_transfn; + int nargs_finalfn; + Oid procOid; + TupleDesc tupDesc; + char *detailmsg; + int i; + ObjectAddress myself, + referenced; + AclResult aclresult; + + /* sanity checks (caller should have caught these) */ + if (!aggName) + elog(ERROR, "no aggregate name supplied"); + + if (!aggtransfnName) + elog(ERROR, "aggregate must have a transition function"); + + if (numDirectArgs < 0 || numDirectArgs > numArgs) + elog(ERROR, "incorrect number of direct arguments for aggregate"); + + /* + * Aggregates can have at most FUNC_MAX_ARGS-1 args, else the transfn + * and/or finalfn will be unrepresentable in pg_proc. We must check now + * to protect fixed-size arrays here and possibly in called functions. + */ + if (numArgs < 0 || numArgs > FUNC_MAX_ARGS - 1) + ereport(ERROR, + (errcode(ERRCODE_TOO_MANY_ARGUMENTS), + errmsg_plural("aggregates cannot have more than %d argument", + "aggregates cannot have more than %d arguments", + FUNC_MAX_ARGS - 1, + FUNC_MAX_ARGS - 1))); + + /* + * If transtype is polymorphic, must have polymorphic argument also; else + * we will have no way to deduce the actual transtype. + */ + detailmsg = check_valid_polymorphic_signature(aggTransType, + aggArgTypes, + numArgs); + if (detailmsg) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("cannot determine transition data type"), + errdetail_internal("%s", detailmsg))); + + /* + * Likewise for moving-aggregate transtype, if any + */ + if (OidIsValid(aggmTransType)) + { + detailmsg = check_valid_polymorphic_signature(aggmTransType, + aggArgTypes, + numArgs); + if (detailmsg) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("cannot determine transition data type"), + errdetail_internal("%s", detailmsg))); + } + + /* + * An ordered-set aggregate that is VARIADIC must be VARIADIC ANY. In + * principle we could support regular variadic types, but it would make + * things much more complicated because we'd have to assemble the correct + * subsets of arguments into array values. Since no standard aggregates + * have use for such a case, we aren't bothering for now. + */ + if (AGGKIND_IS_ORDERED_SET(aggKind) && OidIsValid(variadicArgType) && + variadicArgType != ANYOID) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("a variadic ordered-set aggregate must use VARIADIC type ANY"))); + + /* + * If it's a hypothetical-set aggregate, there must be at least as many + * direct arguments as aggregated ones, and the last N direct arguments + * must match the aggregated ones in type. (We have to check this again + * when the aggregate is called, in case ANY is involved, but it makes + * sense to reject the aggregate definition now if the declared arg types + * don't match up.) It's unconditionally OK if numDirectArgs == numArgs, + * indicating that the grammar merged identical VARIADIC entries from both + * lists. Otherwise, if the agg is VARIADIC, then we had VARIADIC only on + * the aggregated side, which is not OK. Otherwise, insist on the last N + * parameter types on each side matching exactly. + */ + if (aggKind == AGGKIND_HYPOTHETICAL && + numDirectArgs < numArgs) + { + int numAggregatedArgs = numArgs - numDirectArgs; + + if (OidIsValid(variadicArgType) || + numDirectArgs < numAggregatedArgs || + memcmp(aggArgTypes + (numDirectArgs - numAggregatedArgs), + aggArgTypes + numDirectArgs, + numAggregatedArgs * sizeof(Oid)) != 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("a hypothetical-set aggregate must have direct arguments matching its aggregated arguments"))); + } + + /* + * Find the transfn. For ordinary aggs, it takes the transtype plus all + * aggregate arguments. For ordered-set aggs, it takes the transtype plus + * all aggregated args, but not direct args. However, we have to treat + * specially the case where a trailing VARIADIC item is considered to + * cover both direct and aggregated args. + */ + if (AGGKIND_IS_ORDERED_SET(aggKind)) + { + if (numDirectArgs < numArgs) + nargs_transfn = numArgs - numDirectArgs + 1; + else + { + /* special case with VARIADIC last arg */ + Assert(variadicArgType != InvalidOid); + nargs_transfn = 2; + } + fnArgs[0] = aggTransType; + memcpy(fnArgs + 1, aggArgTypes + (numArgs - (nargs_transfn - 1)), + (nargs_transfn - 1) * sizeof(Oid)); + } + else + { + nargs_transfn = numArgs + 1; + fnArgs[0] = aggTransType; + memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid)); + } + transfn = lookup_agg_function(aggtransfnName, nargs_transfn, + fnArgs, variadicArgType, + &rettype); + + /* + * Return type of transfn (possibly after refinement by + * enforce_generic_type_consistency, if transtype isn't polymorphic) must + * exactly match declared transtype. + * + * In the non-polymorphic-transtype case, it might be okay to allow a + * rettype that's binary-coercible to transtype, but I'm not quite + * convinced that it's either safe or useful. When transtype is + * polymorphic we *must* demand exact equality. + */ + if (rettype != aggTransType) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("return type of transition function %s is not %s", + NameListToString(aggtransfnName), + format_type_be(aggTransType)))); + + tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(transfn)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for function %u", transfn); + proc = (Form_pg_proc) GETSTRUCT(tup); + + /* + * If the transfn is strict and the initval is NULL, make sure first input + * type and transtype are the same (or at least binary-compatible), so + * that it's OK to use the first input value as the initial transValue. + */ + if (proc->proisstrict && agginitval == NULL) + { + if (numArgs < 1 || + !IsBinaryCoercible(aggArgTypes[0], aggTransType)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type"))); + } + + ReleaseSysCache(tup); + + /* handle moving-aggregate transfn, if supplied */ + if (aggmtransfnName) + { + /* + * The arguments are the same as for the regular transfn, except that + * the transition data type might be different. So re-use the fnArgs + * values set up above, except for that one. + */ + Assert(OidIsValid(aggmTransType)); + fnArgs[0] = aggmTransType; + + mtransfn = lookup_agg_function(aggmtransfnName, nargs_transfn, + fnArgs, variadicArgType, + &rettype); + + /* As above, return type must exactly match declared mtranstype. */ + if (rettype != aggmTransType) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("return type of transition function %s is not %s", + NameListToString(aggmtransfnName), + format_type_be(aggmTransType)))); + + tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(mtransfn)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for function %u", mtransfn); + proc = (Form_pg_proc) GETSTRUCT(tup); + + /* + * If the mtransfn is strict and the minitval is NULL, check first + * input type and mtranstype are binary-compatible. + */ + if (proc->proisstrict && aggminitval == NULL) + { + if (numArgs < 1 || + !IsBinaryCoercible(aggArgTypes[0], aggmTransType)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type"))); + } + + /* Remember if mtransfn is strict; we may need this below */ + mtransIsStrict = proc->proisstrict; + + ReleaseSysCache(tup); + } + + /* handle minvtransfn, if supplied */ + if (aggminvtransfnName) + { + /* + * This must have the same number of arguments with the same types as + * the forward transition function, so just re-use the fnArgs data. + */ + Assert(aggmtransfnName); + + minvtransfn = lookup_agg_function(aggminvtransfnName, nargs_transfn, + fnArgs, variadicArgType, + &rettype); + + /* As above, return type must exactly match declared mtranstype. */ + if (rettype != aggmTransType) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("return type of inverse transition function %s is not %s", + NameListToString(aggminvtransfnName), + format_type_be(aggmTransType)))); + + tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(minvtransfn)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for function %u", minvtransfn); + proc = (Form_pg_proc) GETSTRUCT(tup); + + /* + * We require the strictness settings of the forward and inverse + * transition functions to agree. This saves having to handle + * assorted special cases at execution time. + */ + if (proc->proisstrict != mtransIsStrict) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("strictness of aggregate's forward and inverse transition functions must match"))); + + ReleaseSysCache(tup); + } + + /* handle finalfn, if supplied */ + if (aggfinalfnName) + { + /* + * If finalfnExtraArgs is specified, the transfn takes the transtype + * plus all args; otherwise, it just takes the transtype plus any + * direct args. (Non-direct args are useless at runtime, and are + * actually passed as NULLs, but we may need them in the function + * signature to allow resolution of a polymorphic agg's result type.) + */ + Oid ffnVariadicArgType = variadicArgType; + + fnArgs[0] = aggTransType; + memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid)); + if (finalfnExtraArgs) + nargs_finalfn = numArgs + 1; + else + { + nargs_finalfn = numDirectArgs + 1; + if (numDirectArgs < numArgs) + { + /* variadic argument doesn't affect finalfn */ + ffnVariadicArgType = InvalidOid; + } + } + + finalfn = lookup_agg_function(aggfinalfnName, nargs_finalfn, + fnArgs, ffnVariadicArgType, + &finaltype); + + /* + * When finalfnExtraArgs is specified, the finalfn will certainly be + * passed at least one null argument, so complain if it's strict. + * Nothing bad would happen at runtime (you'd just get a null result), + * but it's surely not what the user wants, so let's complain now. + */ + if (finalfnExtraArgs && func_strict(finalfn)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("final function with extra arguments must not be declared STRICT"))); + } + else + { + /* + * If no finalfn, aggregate result type is type of the state value + */ + finaltype = aggTransType; + } + Assert(OidIsValid(finaltype)); + + /* handle the combinefn, if supplied */ + if (aggcombinefnName) + { + Oid combineType; + + /* + * Combine function must have 2 arguments, each of which is the trans + * type. VARIADIC doesn't affect it. + */ + fnArgs[0] = aggTransType; + fnArgs[1] = aggTransType; + + combinefn = lookup_agg_function(aggcombinefnName, 2, + fnArgs, InvalidOid, + &combineType); + + /* Ensure the return type matches the aggregate's trans type */ + if (combineType != aggTransType) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("return type of combine function %s is not %s", + NameListToString(aggcombinefnName), + format_type_be(aggTransType)))); + + /* + * A combine function to combine INTERNAL states must accept nulls and + * ensure that the returned state is in the correct memory context. We + * cannot directly check the latter, but we can check the former. + */ + if (aggTransType == INTERNALOID && func_strict(combinefn)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("combine function with transition type %s must not be declared STRICT", + format_type_be(aggTransType)))); + } + + /* + * Validate the serialization function, if present. + */ + if (aggserialfnName) + { + /* signature is always serialize(internal) returns bytea */ + fnArgs[0] = INTERNALOID; + + serialfn = lookup_agg_function(aggserialfnName, 1, + fnArgs, InvalidOid, + &rettype); + + if (rettype != BYTEAOID) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("return type of serialization function %s is not %s", + NameListToString(aggserialfnName), + format_type_be(BYTEAOID)))); + } + + /* + * Validate the deserialization function, if present. + */ + if (aggdeserialfnName) + { + /* signature is always deserialize(bytea, internal) returns internal */ + fnArgs[0] = BYTEAOID; + fnArgs[1] = INTERNALOID; /* dummy argument for type safety */ + + deserialfn = lookup_agg_function(aggdeserialfnName, 2, + fnArgs, InvalidOid, + &rettype); + + if (rettype != INTERNALOID) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("return type of deserialization function %s is not %s", + NameListToString(aggdeserialfnName), + format_type_be(INTERNALOID)))); + } + + /* + * If finaltype (i.e. aggregate return type) is polymorphic, inputs must + * be polymorphic also, else parser will fail to deduce result type. + * (Note: given the previous test on transtype and inputs, this cannot + * happen, unless someone has snuck a finalfn definition into the catalogs + * that itself violates the rule against polymorphic result with no + * polymorphic input.) + */ + detailmsg = check_valid_polymorphic_signature(finaltype, + aggArgTypes, + numArgs); + if (detailmsg) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("cannot determine result data type"), + errdetail_internal("%s", detailmsg))); + + /* + * Also, the return type can't be INTERNAL unless there's at least one + * INTERNAL argument. This is the same type-safety restriction we enforce + * for regular functions, but at the level of aggregates. We must test + * this explicitly because we allow INTERNAL as the transtype. + */ + detailmsg = check_valid_internal_signature(finaltype, + aggArgTypes, + numArgs); + if (detailmsg) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("unsafe use of pseudo-type \"internal\""), + errdetail_internal("%s", detailmsg))); + + /* + * If a moving-aggregate implementation is supplied, look up its finalfn + * if any, and check that the implied aggregate result type matches the + * plain implementation. + */ + if (OidIsValid(aggmTransType)) + { + /* handle finalfn, if supplied */ + if (aggmfinalfnName) + { + /* + * The arguments are figured the same way as for the regular + * finalfn, but using aggmTransType and mfinalfnExtraArgs. + */ + Oid ffnVariadicArgType = variadicArgType; + + fnArgs[0] = aggmTransType; + memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid)); + if (mfinalfnExtraArgs) + nargs_finalfn = numArgs + 1; + else + { + nargs_finalfn = numDirectArgs + 1; + if (numDirectArgs < numArgs) + { + /* variadic argument doesn't affect finalfn */ + ffnVariadicArgType = InvalidOid; + } + } + + mfinalfn = lookup_agg_function(aggmfinalfnName, nargs_finalfn, + fnArgs, ffnVariadicArgType, + &rettype); + + /* As above, check strictness if mfinalfnExtraArgs is given */ + if (mfinalfnExtraArgs && func_strict(mfinalfn)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("final function with extra arguments must not be declared STRICT"))); + } + else + { + /* + * If no finalfn, aggregate result type is type of the state value + */ + rettype = aggmTransType; + } + Assert(OidIsValid(rettype)); + if (rettype != finaltype) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("moving-aggregate implementation returns type %s, but plain implementation returns type %s", + format_type_be(rettype), + format_type_be(finaltype)))); + } + + /* handle sortop, if supplied */ + if (aggsortopName) + { + if (numArgs != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("sort operator can only be specified for single-argument aggregates"))); + sortop = LookupOperName(NULL, aggsortopName, + aggArgTypes[0], aggArgTypes[0], + false, -1); + } + + /* + * permission checks on used types + */ + for (i = 0; i < numArgs; i++) + { + aclresult = pg_type_aclcheck(aggArgTypes[i], GetUserId(), ACL_USAGE); + if (aclresult != ACLCHECK_OK) + aclcheck_error_type(aclresult, aggArgTypes[i]); + } + + aclresult = pg_type_aclcheck(aggTransType, GetUserId(), ACL_USAGE); + if (aclresult != ACLCHECK_OK) + aclcheck_error_type(aclresult, aggTransType); + + if (OidIsValid(aggmTransType)) + { + aclresult = pg_type_aclcheck(aggmTransType, GetUserId(), ACL_USAGE); + if (aclresult != ACLCHECK_OK) + aclcheck_error_type(aclresult, aggmTransType); + } + + aclresult = pg_type_aclcheck(finaltype, GetUserId(), ACL_USAGE); + if (aclresult != ACLCHECK_OK) + aclcheck_error_type(aclresult, finaltype); + + + /* + * Everything looks okay. Try to create the pg_proc entry for the + * aggregate. (This could fail if there's already a conflicting entry.) + */ + + myself = ProcedureCreate(aggName, + aggNamespace, + replace, /* maybe replacement */ + false, /* doesn't return a set */ + finaltype, /* returnType */ + GetUserId(), /* proowner */ + INTERNALlanguageId, /* languageObjectId */ + InvalidOid, /* no validator */ + "aggregate_dummy", /* placeholder proc */ + NULL, /* probin */ + PROKIND_AGGREGATE, + false, /* security invoker (currently not + * definable for agg) */ + false, /* isLeakProof */ + false, /* isStrict (not needed for agg) */ + PROVOLATILE_IMMUTABLE, /* volatility (not needed + * for agg) */ + proparallel, + parameterTypes, /* paramTypes */ + allParameterTypes, /* allParamTypes */ + parameterModes, /* parameterModes */ + parameterNames, /* parameterNames */ + parameterDefaults, /* parameterDefaults */ + PointerGetDatum(NULL), /* trftypes */ + PointerGetDatum(NULL), /* proconfig */ + InvalidOid, /* no prosupport */ + 1, /* procost */ + 0); /* prorows */ + procOid = myself.objectId; + + /* + * Okay to create the pg_aggregate entry. + */ + aggdesc = table_open(AggregateRelationId, RowExclusiveLock); + tupDesc = aggdesc->rd_att; + + /* initialize nulls and values */ + for (i = 0; i < Natts_pg_aggregate; i++) + { + nulls[i] = false; + values[i] = (Datum) NULL; + replaces[i] = true; + } + values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid); + values[Anum_pg_aggregate_aggkind - 1] = CharGetDatum(aggKind); + values[Anum_pg_aggregate_aggnumdirectargs - 1] = Int16GetDatum(numDirectArgs); + values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn); + values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn); + values[Anum_pg_aggregate_aggcombinefn - 1] = ObjectIdGetDatum(combinefn); + values[Anum_pg_aggregate_aggserialfn - 1] = ObjectIdGetDatum(serialfn); + values[Anum_pg_aggregate_aggdeserialfn - 1] = ObjectIdGetDatum(deserialfn); + values[Anum_pg_aggregate_aggmtransfn - 1] = ObjectIdGetDatum(mtransfn); + values[Anum_pg_aggregate_aggminvtransfn - 1] = ObjectIdGetDatum(minvtransfn); + values[Anum_pg_aggregate_aggmfinalfn - 1] = ObjectIdGetDatum(mfinalfn); + values[Anum_pg_aggregate_aggfinalextra - 1] = BoolGetDatum(finalfnExtraArgs); + values[Anum_pg_aggregate_aggmfinalextra - 1] = BoolGetDatum(mfinalfnExtraArgs); + values[Anum_pg_aggregate_aggfinalmodify - 1] = CharGetDatum(finalfnModify); + values[Anum_pg_aggregate_aggmfinalmodify - 1] = CharGetDatum(mfinalfnModify); + values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop); + values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType); + values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace); + values[Anum_pg_aggregate_aggmtranstype - 1] = ObjectIdGetDatum(aggmTransType); + values[Anum_pg_aggregate_aggmtransspace - 1] = Int32GetDatum(aggmTransSpace); + if (agginitval) + values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval); + else + nulls[Anum_pg_aggregate_agginitval - 1] = true; + if (aggminitval) + values[Anum_pg_aggregate_aggminitval - 1] = CStringGetTextDatum(aggminitval); + else + nulls[Anum_pg_aggregate_aggminitval - 1] = true; + + if (replace) + oldtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(procOid)); + else + oldtup = NULL; + + if (HeapTupleIsValid(oldtup)) + { + Form_pg_aggregate oldagg = (Form_pg_aggregate) GETSTRUCT(oldtup); + + /* + * If we're replacing an existing entry, we need to validate that + * we're not changing anything that would break callers. Specifically + * we must not change aggkind or aggnumdirectargs, which affect how an + * aggregate call is treated in parse analysis. + */ + if (aggKind != oldagg->aggkind) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot change routine kind"), + (oldagg->aggkind == AGGKIND_NORMAL ? + errdetail("\"%s\" is an ordinary aggregate function.", aggName) : + oldagg->aggkind == AGGKIND_ORDERED_SET ? + errdetail("\"%s\" is an ordered-set aggregate.", aggName) : + oldagg->aggkind == AGGKIND_HYPOTHETICAL ? + errdetail("\"%s\" is a hypothetical-set aggregate.", aggName) : + 0))); + if (numDirectArgs != oldagg->aggnumdirectargs) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("cannot change number of direct arguments of an aggregate function"))); + + replaces[Anum_pg_aggregate_aggfnoid - 1] = false; + replaces[Anum_pg_aggregate_aggkind - 1] = false; + replaces[Anum_pg_aggregate_aggnumdirectargs - 1] = false; + + tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces); + CatalogTupleUpdate(aggdesc, &tup->t_self, tup); + ReleaseSysCache(oldtup); + } + else + { + tup = heap_form_tuple(tupDesc, values, nulls); + CatalogTupleInsert(aggdesc, tup); + } + + table_close(aggdesc, RowExclusiveLock); + + /* + * Create dependencies for the aggregate (above and beyond those already + * made by ProcedureCreate). Note: we don't need an explicit dependency + * on aggTransType since we depend on it indirectly through transfn. + * Likewise for aggmTransType using the mtransfn, if it exists. + * + * If we're replacing an existing definition, ProcedureCreate deleted all + * our existing dependencies, so we have to do the same things here either + * way. + */ + + /* Depends on transition function */ + referenced.classId = ProcedureRelationId; + referenced.objectId = transfn; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + /* Depends on final function, if any */ + if (OidIsValid(finalfn)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = finalfn; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* Depends on combine function, if any */ + if (OidIsValid(combinefn)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = combinefn; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* Depends on serialization function, if any */ + if (OidIsValid(serialfn)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = serialfn; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* Depends on deserialization function, if any */ + if (OidIsValid(deserialfn)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = deserialfn; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* Depends on forward transition function, if any */ + if (OidIsValid(mtransfn)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = mtransfn; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* Depends on inverse transition function, if any */ + if (OidIsValid(minvtransfn)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = minvtransfn; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* Depends on final function, if any */ + if (OidIsValid(mfinalfn)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = mfinalfn; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* Depends on sort operator, if any */ + if (OidIsValid(sortop)) + { + referenced.classId = OperatorRelationId; + referenced.objectId = sortop; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + return myself; +} + +/* + * lookup_agg_function + * common code for finding aggregate support functions + * + * fnName: possibly-schema-qualified function name + * nargs, input_types: expected function argument types + * variadicArgType: type of variadic argument if any, else InvalidOid + * + * Returns OID of function, and stores its return type into *rettype + * + * NB: must not scribble on input_types[], as we may re-use those + */ +static Oid +lookup_agg_function(List *fnName, + int nargs, + Oid *input_types, + Oid variadicArgType, + Oid *rettype) +{ + Oid fnOid; + bool retset; + int nvargs; + Oid vatype; + Oid *true_oid_array; + FuncDetailCode fdresult; + AclResult aclresult; + int i; + + /* + * func_get_detail looks up the function in the catalogs, does + * disambiguation for polymorphic functions, handles inheritance, and + * returns the funcid and type and set or singleton status of the + * function's return value. it also returns the true argument types to + * the function. + */ + fdresult = func_get_detail(fnName, NIL, NIL, + nargs, input_types, false, false, + &fnOid, rettype, &retset, + &nvargs, &vatype, + &true_oid_array, NULL); + + /* only valid case is a normal function not returning a set */ + if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("function %s does not exist", + func_signature_string(fnName, nargs, + NIL, input_types)))); + if (retset) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("function %s returns a set", + func_signature_string(fnName, nargs, + NIL, input_types)))); + + /* + * If the agg is declared to take VARIADIC ANY, the underlying functions + * had better be declared that way too, else they may receive too many + * parameters; but func_get_detail would have been happy with plain ANY. + * (Probably nothing very bad would happen, but it wouldn't work as the + * user expects.) Other combinations should work without any special + * pushups, given that we told func_get_detail not to expand VARIADIC. + */ + if (variadicArgType == ANYOID && vatype != ANYOID) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("function %s must accept VARIADIC ANY to be used in this aggregate", + func_signature_string(fnName, nargs, + NIL, input_types)))); + + /* + * If there are any polymorphic types involved, enforce consistency, and + * possibly refine the result type. It's OK if the result is still + * polymorphic at this point, though. + */ + *rettype = enforce_generic_type_consistency(input_types, + true_oid_array, + nargs, + *rettype, + true); + + /* + * func_get_detail will find functions requiring run-time argument type + * coercion, but nodeAgg.c isn't prepared to deal with that + */ + for (i = 0; i < nargs; i++) + { + if (!IsBinaryCoercible(input_types[i], true_oid_array[i])) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("function %s requires run-time type coercion", + func_signature_string(fnName, nargs, + NIL, true_oid_array)))); + } + + /* Check aggregate creator has permission to call the function */ + aclresult = pg_proc_aclcheck(fnOid, GetUserId(), ACL_EXECUTE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(fnOid)); + + return fnOid; +} diff --git a/src/backend/catalog/pg_aggregate_d.h b/src/backend/catalog/pg_aggregate_d.h new file mode 100644 index 0000000..a00cd1f --- /dev/null +++ b/src/backend/catalog/pg_aggregate_d.h @@ -0,0 +1,77 @@ +/*------------------------------------------------------------------------- + * + * pg_aggregate_d.h + * Macro definitions for pg_aggregate + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_AGGREGATE_D_H +#define PG_AGGREGATE_D_H + +#define AggregateRelationId 2600 + +#define Anum_pg_aggregate_aggfnoid 1 +#define Anum_pg_aggregate_aggkind 2 +#define Anum_pg_aggregate_aggnumdirectargs 3 +#define Anum_pg_aggregate_aggtransfn 4 +#define Anum_pg_aggregate_aggfinalfn 5 +#define Anum_pg_aggregate_aggcombinefn 6 +#define Anum_pg_aggregate_aggserialfn 7 +#define Anum_pg_aggregate_aggdeserialfn 8 +#define Anum_pg_aggregate_aggmtransfn 9 +#define Anum_pg_aggregate_aggminvtransfn 10 +#define Anum_pg_aggregate_aggmfinalfn 11 +#define Anum_pg_aggregate_aggfinalextra 12 +#define Anum_pg_aggregate_aggmfinalextra 13 +#define Anum_pg_aggregate_aggfinalmodify 14 +#define Anum_pg_aggregate_aggmfinalmodify 15 +#define Anum_pg_aggregate_aggsortop 16 +#define Anum_pg_aggregate_aggtranstype 17 +#define Anum_pg_aggregate_aggtransspace 18 +#define Anum_pg_aggregate_aggmtranstype 19 +#define Anum_pg_aggregate_aggmtransspace 20 +#define Anum_pg_aggregate_agginitval 21 +#define Anum_pg_aggregate_aggminitval 22 + +#define Natts_pg_aggregate 22 + + +/* + * Symbolic values for aggkind column. We distinguish normal aggregates + * from ordered-set aggregates (which have two sets of arguments, namely + * direct and aggregated arguments) and from hypothetical-set aggregates + * (which are a subclass of ordered-set aggregates in which the last + * direct arguments have to match up in number and datatypes with the + * aggregated arguments). + */ +#define AGGKIND_NORMAL 'n' +#define AGGKIND_ORDERED_SET 'o' +#define AGGKIND_HYPOTHETICAL 'h' + +/* Use this macro to test for "ordered-set agg including hypothetical case" */ +#define AGGKIND_IS_ORDERED_SET(kind) ((kind) != AGGKIND_NORMAL) + +/* + * Symbolic values for aggfinalmodify and aggmfinalmodify columns. + * Preferably, finalfns do not modify the transition state value at all, + * but in some cases that would cost too much performance. We distinguish + * "pure read only" and "trashes it arbitrarily" cases, as well as the + * intermediate case where multiple finalfn calls are allowed but the + * transfn cannot be applied anymore after the first finalfn call. + */ +#define AGGMODIFY_READ_ONLY 'r' +#define AGGMODIFY_SHAREABLE 's' +#define AGGMODIFY_READ_WRITE 'w' + + +#endif /* PG_AGGREGATE_D_H */ diff --git a/src/backend/catalog/pg_am_d.h b/src/backend/catalog/pg_am_d.h new file mode 100644 index 0000000..2b6b941 --- /dev/null +++ b/src/backend/catalog/pg_am_d.h @@ -0,0 +1,45 @@ +/*------------------------------------------------------------------------- + * + * pg_am_d.h + * Macro definitions for pg_am + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_AM_D_H +#define PG_AM_D_H + +#define AccessMethodRelationId 2601 + +#define Anum_pg_am_oid 1 +#define Anum_pg_am_amname 2 +#define Anum_pg_am_amhandler 3 +#define Anum_pg_am_amtype 4 + +#define Natts_pg_am 4 + + +/* + * Allowed values for amtype + */ +#define AMTYPE_INDEX 'i' /* index access method */ +#define AMTYPE_TABLE 't' /* table access method */ + +#define HEAP_TABLE_AM_OID 2 +#define BTREE_AM_OID 403 +#define HASH_AM_OID 405 +#define GIST_AM_OID 783 +#define GIN_AM_OID 2742 +#define SPGIST_AM_OID 4000 +#define BRIN_AM_OID 3580 + +#endif /* PG_AM_D_H */ diff --git a/src/backend/catalog/pg_amop_d.h b/src/backend/catalog/pg_amop_d.h new file mode 100644 index 0000000..7d34ee6 --- /dev/null +++ b/src/backend/catalog/pg_amop_d.h @@ -0,0 +1,41 @@ +/*------------------------------------------------------------------------- + * + * pg_amop_d.h + * Macro definitions for pg_amop + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_AMOP_D_H +#define PG_AMOP_D_H + +#define AccessMethodOperatorRelationId 2602 + +#define Anum_pg_amop_oid 1 +#define Anum_pg_amop_amopfamily 2 +#define Anum_pg_amop_amoplefttype 3 +#define Anum_pg_amop_amoprighttype 4 +#define Anum_pg_amop_amopstrategy 5 +#define Anum_pg_amop_amoppurpose 6 +#define Anum_pg_amop_amopopr 7 +#define Anum_pg_amop_amopmethod 8 +#define Anum_pg_amop_amopsortfamily 9 + +#define Natts_pg_amop 9 + + +/* allowed values of amoppurpose: */ +#define AMOP_SEARCH 's' /* operator is for search */ +#define AMOP_ORDER 'o' /* operator is for ordering */ + + +#endif /* PG_AMOP_D_H */ diff --git a/src/backend/catalog/pg_amproc_d.h b/src/backend/catalog/pg_amproc_d.h new file mode 100644 index 0000000..9b51d1d --- /dev/null +++ b/src/backend/catalog/pg_amproc_d.h @@ -0,0 +1,33 @@ +/*------------------------------------------------------------------------- + * + * pg_amproc_d.h + * Macro definitions for pg_amproc + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_AMPROC_D_H +#define PG_AMPROC_D_H + +#define AccessMethodProcedureRelationId 2603 + +#define Anum_pg_amproc_oid 1 +#define Anum_pg_amproc_amprocfamily 2 +#define Anum_pg_amproc_amproclefttype 3 +#define Anum_pg_amproc_amprocrighttype 4 +#define Anum_pg_amproc_amprocnum 5 +#define Anum_pg_amproc_amproc 6 + +#define Natts_pg_amproc 6 + + +#endif /* PG_AMPROC_D_H */ diff --git a/src/backend/catalog/pg_attrdef_d.h b/src/backend/catalog/pg_attrdef_d.h new file mode 100644 index 0000000..b426981 --- /dev/null +++ b/src/backend/catalog/pg_attrdef_d.h @@ -0,0 +1,31 @@ +/*------------------------------------------------------------------------- + * + * pg_attrdef_d.h + * Macro definitions for pg_attrdef + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_ATTRDEF_D_H +#define PG_ATTRDEF_D_H + +#define AttrDefaultRelationId 2604 + +#define Anum_pg_attrdef_oid 1 +#define Anum_pg_attrdef_adrelid 2 +#define Anum_pg_attrdef_adnum 3 +#define Anum_pg_attrdef_adbin 4 + +#define Natts_pg_attrdef 4 + + +#endif /* PG_ATTRDEF_D_H */ diff --git a/src/backend/catalog/pg_attribute_d.h b/src/backend/catalog/pg_attribute_d.h new file mode 100644 index 0000000..d736b6c --- /dev/null +++ b/src/backend/catalog/pg_attribute_d.h @@ -0,0 +1,59 @@ +/*------------------------------------------------------------------------- + * + * pg_attribute_d.h + * Macro definitions for pg_attribute + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_ATTRIBUTE_D_H +#define PG_ATTRIBUTE_D_H + +#define AttributeRelationId 1249 +#define AttributeRelation_Rowtype_Id 75 + +#define Anum_pg_attribute_attrelid 1 +#define Anum_pg_attribute_attname 2 +#define Anum_pg_attribute_atttypid 3 +#define Anum_pg_attribute_attstattarget 4 +#define Anum_pg_attribute_attlen 5 +#define Anum_pg_attribute_attnum 6 +#define Anum_pg_attribute_attndims 7 +#define Anum_pg_attribute_attcacheoff 8 +#define Anum_pg_attribute_atttypmod 9 +#define Anum_pg_attribute_attbyval 10 +#define Anum_pg_attribute_attstorage 11 +#define Anum_pg_attribute_attalign 12 +#define Anum_pg_attribute_attnotnull 13 +#define Anum_pg_attribute_atthasdef 14 +#define Anum_pg_attribute_atthasmissing 15 +#define Anum_pg_attribute_attidentity 16 +#define Anum_pg_attribute_attgenerated 17 +#define Anum_pg_attribute_attisdropped 18 +#define Anum_pg_attribute_attislocal 19 +#define Anum_pg_attribute_attinhcount 20 +#define Anum_pg_attribute_attcollation 21 +#define Anum_pg_attribute_attacl 22 +#define Anum_pg_attribute_attoptions 23 +#define Anum_pg_attribute_attfdwoptions 24 +#define Anum_pg_attribute_attmissingval 25 + +#define Natts_pg_attribute 25 + + +#define ATTRIBUTE_IDENTITY_ALWAYS 'a' +#define ATTRIBUTE_IDENTITY_BY_DEFAULT 'd' + +#define ATTRIBUTE_GENERATED_STORED 's' + + +#endif /* PG_ATTRIBUTE_D_H */ diff --git a/src/backend/catalog/pg_auth_members_d.h b/src/backend/catalog/pg_auth_members_d.h new file mode 100644 index 0000000..5fb40c3 --- /dev/null +++ b/src/backend/catalog/pg_auth_members_d.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * pg_auth_members_d.h + * Macro definitions for pg_auth_members + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_AUTH_MEMBERS_D_H +#define PG_AUTH_MEMBERS_D_H + +#define AuthMemRelationId 1261 +#define AuthMemRelation_Rowtype_Id 2843 + +#define Anum_pg_auth_members_roleid 1 +#define Anum_pg_auth_members_member 2 +#define Anum_pg_auth_members_grantor 3 +#define Anum_pg_auth_members_admin_option 4 + +#define Natts_pg_auth_members 4 + + +#endif /* PG_AUTH_MEMBERS_D_H */ diff --git a/src/backend/catalog/pg_authid_d.h b/src/backend/catalog/pg_authid_d.h new file mode 100644 index 0000000..e894479 --- /dev/null +++ b/src/backend/catalog/pg_authid_d.h @@ -0,0 +1,49 @@ +/*------------------------------------------------------------------------- + * + * pg_authid_d.h + * Macro definitions for pg_authid + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_AUTHID_D_H +#define PG_AUTHID_D_H + +#define AuthIdRelationId 1260 +#define AuthIdRelation_Rowtype_Id 2842 + +#define Anum_pg_authid_oid 1 +#define Anum_pg_authid_rolname 2 +#define Anum_pg_authid_rolsuper 3 +#define Anum_pg_authid_rolinherit 4 +#define Anum_pg_authid_rolcreaterole 5 +#define Anum_pg_authid_rolcreatedb 6 +#define Anum_pg_authid_rolcanlogin 7 +#define Anum_pg_authid_rolreplication 8 +#define Anum_pg_authid_rolbypassrls 9 +#define Anum_pg_authid_rolconnlimit 10 +#define Anum_pg_authid_rolpassword 11 +#define Anum_pg_authid_rolvaliduntil 12 + +#define Natts_pg_authid 12 + +#define BOOTSTRAP_SUPERUSERID 10 +#define DEFAULT_ROLE_MONITOR 3373 +#define DEFAULT_ROLE_READ_ALL_SETTINGS 3374 +#define DEFAULT_ROLE_READ_ALL_STATS 3375 +#define DEFAULT_ROLE_STAT_SCAN_TABLES 3377 +#define DEFAULT_ROLE_READ_SERVER_FILES 4569 +#define DEFAULT_ROLE_WRITE_SERVER_FILES 4570 +#define DEFAULT_ROLE_EXECUTE_SERVER_PROGRAM 4571 +#define DEFAULT_ROLE_SIGNAL_BACKENDID 4200 + +#endif /* PG_AUTHID_D_H */ diff --git a/src/backend/catalog/pg_cast.c b/src/backend/catalog/pg_cast.c new file mode 100644 index 0000000..56aacd7 --- /dev/null +++ b/src/backend/catalog/pg_cast.c @@ -0,0 +1,123 @@ +/*------------------------------------------------------------------------- + * + * pg_cast.c + * routines to support manipulation of the pg_cast relation + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/pg_cast.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/htup_details.h" +#include "access/table.h" +#include "catalog/catalog.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/objectaccess.h" +#include "catalog/pg_cast.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_type.h" +#include "utils/builtins.h" +#include "utils/rel.h" +#include "utils/syscache.h" + +/* + * ---------------------------------------------------------------- + * CastCreate + * + * Forms and inserts catalog tuples for a new cast being created. + * Caller must have already checked privileges, and done consistency + * checks on the given datatypes and cast function (if applicable). + * + * 'behavior' indicates the types of the dependencies that the new + * cast will have on its input and output types and the cast function. + * ---------------------------------------------------------------- + */ +ObjectAddress +CastCreate(Oid sourcetypeid, Oid targettypeid, Oid funcid, char castcontext, + char castmethod, DependencyType behavior) +{ + Relation relation; + HeapTuple tuple; + Oid castid; + Datum values[Natts_pg_cast]; + bool nulls[Natts_pg_cast]; + ObjectAddress myself, + referenced; + + relation = table_open(CastRelationId, RowExclusiveLock); + + /* + * Check for duplicate. This is just to give a friendly error message, + * the unique index would catch it anyway (so no need to sweat about race + * conditions). + */ + tuple = SearchSysCache2(CASTSOURCETARGET, + ObjectIdGetDatum(sourcetypeid), + ObjectIdGetDatum(targettypeid)); + if (HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("cast from type %s to type %s already exists", + format_type_be(sourcetypeid), + format_type_be(targettypeid)))); + + /* ready to go */ + castid = GetNewOidWithIndex(relation, CastOidIndexId, Anum_pg_cast_oid); + values[Anum_pg_cast_oid - 1] = ObjectIdGetDatum(castid); + values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid); + values[Anum_pg_cast_casttarget - 1] = ObjectIdGetDatum(targettypeid); + values[Anum_pg_cast_castfunc - 1] = ObjectIdGetDatum(funcid); + values[Anum_pg_cast_castcontext - 1] = CharGetDatum(castcontext); + values[Anum_pg_cast_castmethod - 1] = CharGetDatum(castmethod); + + MemSet(nulls, false, sizeof(nulls)); + + tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls); + + CatalogTupleInsert(relation, tuple); + + /* make dependency entries */ + myself.classId = CastRelationId; + myself.objectId = castid; + myself.objectSubId = 0; + + /* dependency on source type */ + referenced.classId = TypeRelationId; + referenced.objectId = sourcetypeid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, behavior); + + /* dependency on target type */ + referenced.classId = TypeRelationId; + referenced.objectId = targettypeid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, behavior); + + /* dependency on function */ + if (OidIsValid(funcid)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = funcid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, behavior); + } + + /* dependency on extension */ + recordDependencyOnCurrentExtension(&myself, false); + + /* Post creation hook for new cast */ + InvokeObjectPostCreateHook(CastRelationId, castid, 0); + + heap_freetuple(tuple); + + table_close(relation, RowExclusiveLock); + + return myself; +} diff --git a/src/backend/catalog/pg_cast_d.h b/src/backend/catalog/pg_cast_d.h new file mode 100644 index 0000000..425aab7 --- /dev/null +++ b/src/backend/catalog/pg_cast_d.h @@ -0,0 +1,62 @@ +/*------------------------------------------------------------------------- + * + * pg_cast_d.h + * Macro definitions for pg_cast + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_CAST_D_H +#define PG_CAST_D_H + +#define CastRelationId 2605 + +#define Anum_pg_cast_oid 1 +#define Anum_pg_cast_castsource 2 +#define Anum_pg_cast_casttarget 3 +#define Anum_pg_cast_castfunc 4 +#define Anum_pg_cast_castcontext 5 +#define Anum_pg_cast_castmethod 6 + +#define Natts_pg_cast 6 + + +/* + * The allowable values for pg_cast.castcontext are specified by this enum. + * Since castcontext is stored as a "char", we use ASCII codes for human + * convenience in reading the table. Note that internally to the backend, + * these values are converted to the CoercionContext enum (see primnodes.h), + * which is defined to sort in a convenient order; the ASCII codes don't + * have to sort in any special order. + */ + +typedef enum CoercionCodes +{ + COERCION_CODE_IMPLICIT = 'i', /* coercion in context of expression */ + COERCION_CODE_ASSIGNMENT = 'a', /* coercion in context of assignment */ + COERCION_CODE_EXPLICIT = 'e' /* explicit cast operation */ +} CoercionCodes; + +/* + * The allowable values for pg_cast.castmethod are specified by this enum. + * Since castmethod is stored as a "char", we use ASCII codes for human + * convenience in reading the table. + */ +typedef enum CoercionMethod +{ + COERCION_METHOD_FUNCTION = 'f', /* use a function */ + COERCION_METHOD_BINARY = 'b', /* types are binary-compatible */ + COERCION_METHOD_INOUT = 'i' /* use input/output functions */ +} CoercionMethod; + + +#endif /* PG_CAST_D_H */ diff --git a/src/backend/catalog/pg_class_d.h b/src/backend/catalog/pg_class_d.h new file mode 100644 index 0000000..7f9a66c --- /dev/null +++ b/src/backend/catalog/pg_class_d.h @@ -0,0 +1,103 @@ +/*------------------------------------------------------------------------- + * + * pg_class_d.h + * Macro definitions for pg_class + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_CLASS_D_H +#define PG_CLASS_D_H + +#define RelationRelationId 1259 +#define RelationRelation_Rowtype_Id 83 + +#define Anum_pg_class_oid 1 +#define Anum_pg_class_relname 2 +#define Anum_pg_class_relnamespace 3 +#define Anum_pg_class_reltype 4 +#define Anum_pg_class_reloftype 5 +#define Anum_pg_class_relowner 6 +#define Anum_pg_class_relam 7 +#define Anum_pg_class_relfilenode 8 +#define Anum_pg_class_reltablespace 9 +#define Anum_pg_class_relpages 10 +#define Anum_pg_class_reltuples 11 +#define Anum_pg_class_relallvisible 12 +#define Anum_pg_class_reltoastrelid 13 +#define Anum_pg_class_relhasindex 14 +#define Anum_pg_class_relisshared 15 +#define Anum_pg_class_relpersistence 16 +#define Anum_pg_class_relkind 17 +#define Anum_pg_class_relnatts 18 +#define Anum_pg_class_relchecks 19 +#define Anum_pg_class_relhasrules 20 +#define Anum_pg_class_relhastriggers 21 +#define Anum_pg_class_relhassubclass 22 +#define Anum_pg_class_relrowsecurity 23 +#define Anum_pg_class_relforcerowsecurity 24 +#define Anum_pg_class_relispopulated 25 +#define Anum_pg_class_relreplident 26 +#define Anum_pg_class_relispartition 27 +#define Anum_pg_class_relrewrite 28 +#define Anum_pg_class_relfrozenxid 29 +#define Anum_pg_class_relminmxid 30 +#define Anum_pg_class_relacl 31 +#define Anum_pg_class_reloptions 32 +#define Anum_pg_class_relpartbound 33 + +#define Natts_pg_class 33 + + +#define RELKIND_RELATION 'r' /* ordinary table */ +#define RELKIND_INDEX 'i' /* secondary index */ +#define RELKIND_SEQUENCE 'S' /* sequence object */ +#define RELKIND_TOASTVALUE 't' /* for out-of-line values */ +#define RELKIND_VIEW 'v' /* view */ +#define RELKIND_MATVIEW 'm' /* materialized view */ +#define RELKIND_COMPOSITE_TYPE 'c' /* composite type */ +#define RELKIND_FOREIGN_TABLE 'f' /* foreign table */ +#define RELKIND_PARTITIONED_TABLE 'p' /* partitioned table */ +#define RELKIND_PARTITIONED_INDEX 'I' /* partitioned index */ + +#define RELPERSISTENCE_PERMANENT 'p' /* regular table */ +#define RELPERSISTENCE_UNLOGGED 'u' /* unlogged permanent table */ +#define RELPERSISTENCE_TEMP 't' /* temporary table */ + +/* default selection for replica identity (primary key or nothing) */ +#define REPLICA_IDENTITY_DEFAULT 'd' +/* no replica identity is logged for this relation */ +#define REPLICA_IDENTITY_NOTHING 'n' +/* all columns are logged as replica identity */ +#define REPLICA_IDENTITY_FULL 'f' +/* + * an explicitly chosen candidate key's columns are used as replica identity. + * Note this will still be set if the index has been dropped; in that case it + * has the same meaning as 'd'. + */ +#define REPLICA_IDENTITY_INDEX 'i' + +/* + * Relation kinds that have physical storage. These relations normally have + * relfilenode set to non-zero, but it can also be zero if the relation is + * mapped. + */ +#define RELKIND_HAS_STORAGE(relkind) \ + ((relkind) == RELKIND_RELATION || \ + (relkind) == RELKIND_INDEX || \ + (relkind) == RELKIND_SEQUENCE || \ + (relkind) == RELKIND_TOASTVALUE || \ + (relkind) == RELKIND_MATVIEW) + + + +#endif /* PG_CLASS_D_H */ diff --git a/src/backend/catalog/pg_collation.c b/src/backend/catalog/pg_collation.c new file mode 100644 index 0000000..8559779 --- /dev/null +++ b/src/backend/catalog/pg_collation.c @@ -0,0 +1,241 @@ +/*------------------------------------------------------------------------- + * + * pg_collation.c + * routines to support manipulation of the pg_collation relation + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/pg_collation.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/genam.h" +#include "access/htup_details.h" +#include "access/sysattr.h" +#include "access/table.h" +#include "catalog/catalog.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/objectaccess.h" +#include "catalog/pg_collation.h" +#include "catalog/pg_namespace.h" +#include "mb/pg_wchar.h" +#include "utils/builtins.h" +#include "utils/fmgroids.h" +#include "utils/pg_locale.h" +#include "utils/rel.h" +#include "utils/syscache.h" + + +/* + * CollationCreate + * + * Add a new tuple to pg_collation. + * + * if_not_exists: if true, don't fail on duplicate name, just print a notice + * and return InvalidOid. + * quiet: if true, don't fail on duplicate name, just silently return + * InvalidOid (overrides if_not_exists). + */ +Oid +CollationCreate(const char *collname, Oid collnamespace, + Oid collowner, + char collprovider, + bool collisdeterministic, + int32 collencoding, + const char *collcollate, const char *collctype, + const char *collversion, + bool if_not_exists, + bool quiet) +{ + Relation rel; + TupleDesc tupDesc; + HeapTuple tup; + Datum values[Natts_pg_collation]; + bool nulls[Natts_pg_collation]; + NameData name_name, + name_collate, + name_ctype; + Oid oid; + ObjectAddress myself, + referenced; + + AssertArg(collname); + AssertArg(collnamespace); + AssertArg(collowner); + AssertArg(collcollate); + AssertArg(collctype); + + /* + * Make sure there is no existing collation of same name & encoding. + * + * This would be caught by the unique index anyway; we're just giving a + * friendlier error message. The unique index provides a backstop against + * race conditions. + */ + if (SearchSysCacheExists3(COLLNAMEENCNSP, + PointerGetDatum(collname), + Int32GetDatum(collencoding), + ObjectIdGetDatum(collnamespace))) + { + if (quiet) + return InvalidOid; + else if (if_not_exists) + { + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_OBJECT), + collencoding == -1 + ? errmsg("collation \"%s\" already exists, skipping", + collname) + : errmsg("collation \"%s\" for encoding \"%s\" already exists, skipping", + collname, pg_encoding_to_char(collencoding)))); + return InvalidOid; + } + else + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + collencoding == -1 + ? errmsg("collation \"%s\" already exists", + collname) + : errmsg("collation \"%s\" for encoding \"%s\" already exists", + collname, pg_encoding_to_char(collencoding)))); + } + + /* open pg_collation; see below about the lock level */ + rel = table_open(CollationRelationId, ShareRowExclusiveLock); + + /* + * Also forbid a specific-encoding collation shadowing an any-encoding + * collation, or an any-encoding collation being shadowed (see + * get_collation_name()). This test is not backed up by the unique index, + * so we take a ShareRowExclusiveLock earlier, to protect against + * concurrent changes fooling this check. + */ + if ((collencoding == -1 && + SearchSysCacheExists3(COLLNAMEENCNSP, + PointerGetDatum(collname), + Int32GetDatum(GetDatabaseEncoding()), + ObjectIdGetDatum(collnamespace))) || + (collencoding != -1 && + SearchSysCacheExists3(COLLNAMEENCNSP, + PointerGetDatum(collname), + Int32GetDatum(-1), + ObjectIdGetDatum(collnamespace)))) + { + if (quiet) + { + table_close(rel, NoLock); + return InvalidOid; + } + else if (if_not_exists) + { + table_close(rel, NoLock); + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("collation \"%s\" already exists, skipping", + collname))); + return InvalidOid; + } + else + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("collation \"%s\" already exists", + collname))); + } + + tupDesc = RelationGetDescr(rel); + + /* form a tuple */ + memset(nulls, 0, sizeof(nulls)); + + namestrcpy(&name_name, collname); + oid = GetNewOidWithIndex(rel, CollationOidIndexId, + Anum_pg_collation_oid); + values[Anum_pg_collation_oid - 1] = ObjectIdGetDatum(oid); + values[Anum_pg_collation_collname - 1] = NameGetDatum(&name_name); + values[Anum_pg_collation_collnamespace - 1] = ObjectIdGetDatum(collnamespace); + values[Anum_pg_collation_collowner - 1] = ObjectIdGetDatum(collowner); + values[Anum_pg_collation_collprovider - 1] = CharGetDatum(collprovider); + values[Anum_pg_collation_collisdeterministic - 1] = BoolGetDatum(collisdeterministic); + values[Anum_pg_collation_collencoding - 1] = Int32GetDatum(collencoding); + namestrcpy(&name_collate, collcollate); + values[Anum_pg_collation_collcollate - 1] = NameGetDatum(&name_collate); + namestrcpy(&name_ctype, collctype); + values[Anum_pg_collation_collctype - 1] = NameGetDatum(&name_ctype); + if (collversion) + values[Anum_pg_collation_collversion - 1] = CStringGetTextDatum(collversion); + else + nulls[Anum_pg_collation_collversion - 1] = true; + + tup = heap_form_tuple(tupDesc, values, nulls); + + /* insert a new tuple */ + CatalogTupleInsert(rel, tup); + Assert(OidIsValid(oid)); + + /* set up dependencies for the new collation */ + myself.classId = CollationRelationId; + myself.objectId = oid; + myself.objectSubId = 0; + + /* create dependency on namespace */ + referenced.classId = NamespaceRelationId; + referenced.objectId = collnamespace; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + /* create dependency on owner */ + recordDependencyOnOwner(CollationRelationId, oid, collowner); + + /* dependency on extension */ + recordDependencyOnCurrentExtension(&myself, false); + + /* Post creation hook for new collation */ + InvokeObjectPostCreateHook(CollationRelationId, oid, 0); + + heap_freetuple(tup); + table_close(rel, NoLock); + + return oid; +} + +/* + * RemoveCollationById + * + * Remove a tuple from pg_collation by Oid. This function is solely + * called inside catalog/dependency.c + */ +void +RemoveCollationById(Oid collationOid) +{ + Relation rel; + ScanKeyData scanKeyData; + SysScanDesc scandesc; + HeapTuple tuple; + + rel = table_open(CollationRelationId, RowExclusiveLock); + + ScanKeyInit(&scanKeyData, + Anum_pg_collation_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(collationOid)); + + scandesc = systable_beginscan(rel, CollationOidIndexId, true, + NULL, 1, &scanKeyData); + + tuple = systable_getnext(scandesc); + + if (HeapTupleIsValid(tuple)) + CatalogTupleDelete(rel, &tuple->t_self); + else + elog(ERROR, "could not find tuple for collation %u", collationOid); + + systable_endscan(scandesc); + + table_close(rel, RowExclusiveLock); +} diff --git a/src/backend/catalog/pg_collation_d.h b/src/backend/catalog/pg_collation_d.h new file mode 100644 index 0000000..e7545ff --- /dev/null +++ b/src/backend/catalog/pg_collation_d.h @@ -0,0 +1,45 @@ +/*------------------------------------------------------------------------- + * + * pg_collation_d.h + * Macro definitions for pg_collation + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_COLLATION_D_H +#define PG_COLLATION_D_H + +#define CollationRelationId 3456 + +#define Anum_pg_collation_oid 1 +#define Anum_pg_collation_collname 2 +#define Anum_pg_collation_collnamespace 3 +#define Anum_pg_collation_collowner 4 +#define Anum_pg_collation_collprovider 5 +#define Anum_pg_collation_collisdeterministic 6 +#define Anum_pg_collation_collencoding 7 +#define Anum_pg_collation_collcollate 8 +#define Anum_pg_collation_collctype 9 +#define Anum_pg_collation_collversion 10 + +#define Natts_pg_collation 10 + + +#define COLLPROVIDER_DEFAULT 'd' +#define COLLPROVIDER_ICU 'i' +#define COLLPROVIDER_LIBC 'c' + +#define DEFAULT_COLLATION_OID 100 +#define C_COLLATION_OID 950 +#define POSIX_COLLATION_OID 951 + +#endif /* PG_COLLATION_D_H */ diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c new file mode 100644 index 0000000..90932be --- /dev/null +++ b/src/backend/catalog/pg_constraint.c @@ -0,0 +1,1318 @@ +/*------------------------------------------------------------------------- + * + * pg_constraint.c + * routines to support manipulation of the pg_constraint relation + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/pg_constraint.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/genam.h" +#include "access/htup_details.h" +#include "access/sysattr.h" +#include "access/table.h" +#include "access/xact.h" +#include "catalog/catalog.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/objectaccess.h" +#include "catalog/pg_constraint.h" +#include "catalog/pg_operator.h" +#include "catalog/pg_type.h" +#include "commands/defrem.h" +#include "commands/tablecmds.h" +#include "utils/array.h" +#include "utils/builtins.h" +#include "utils/fmgroids.h" +#include "utils/lsyscache.h" +#include "utils/rel.h" +#include "utils/syscache.h" + + +/* + * CreateConstraintEntry + * Create a constraint table entry. + * + * Subsidiary records (such as triggers or indexes to implement the + * constraint) are *not* created here. But we do make dependency links + * from the constraint to the things it depends on. + * + * The new constraint's OID is returned. + */ +Oid +CreateConstraintEntry(const char *constraintName, + Oid constraintNamespace, + char constraintType, + bool isDeferrable, + bool isDeferred, + bool isValidated, + Oid parentConstrId, + Oid relId, + const int16 *constraintKey, + int constraintNKeys, + int constraintNTotalKeys, + Oid domainId, + Oid indexRelId, + Oid foreignRelId, + const int16 *foreignKey, + const Oid *pfEqOp, + const Oid *ppEqOp, + const Oid *ffEqOp, + int foreignNKeys, + char foreignUpdateType, + char foreignDeleteType, + char foreignMatchType, + const Oid *exclOp, + Node *conExpr, + const char *conBin, + bool conIsLocal, + int conInhCount, + bool conNoInherit, + bool is_internal) +{ + Relation conDesc; + Oid conOid; + HeapTuple tup; + bool nulls[Natts_pg_constraint]; + Datum values[Natts_pg_constraint]; + ArrayType *conkeyArray; + ArrayType *confkeyArray; + ArrayType *conpfeqopArray; + ArrayType *conppeqopArray; + ArrayType *conffeqopArray; + ArrayType *conexclopArray; + NameData cname; + int i; + ObjectAddress conobject; + + conDesc = table_open(ConstraintRelationId, RowExclusiveLock); + + Assert(constraintName); + namestrcpy(&cname, constraintName); + + /* + * Convert C arrays into Postgres arrays. + */ + if (constraintNKeys > 0) + { + Datum *conkey; + + conkey = (Datum *) palloc(constraintNKeys * sizeof(Datum)); + for (i = 0; i < constraintNKeys; i++) + conkey[i] = Int16GetDatum(constraintKey[i]); + conkeyArray = construct_array(conkey, constraintNKeys, + INT2OID, 2, true, TYPALIGN_SHORT); + } + else + conkeyArray = NULL; + + if (foreignNKeys > 0) + { + Datum *fkdatums; + + fkdatums = (Datum *) palloc(foreignNKeys * sizeof(Datum)); + for (i = 0; i < foreignNKeys; i++) + fkdatums[i] = Int16GetDatum(foreignKey[i]); + confkeyArray = construct_array(fkdatums, foreignNKeys, + INT2OID, 2, true, TYPALIGN_SHORT); + for (i = 0; i < foreignNKeys; i++) + fkdatums[i] = ObjectIdGetDatum(pfEqOp[i]); + conpfeqopArray = construct_array(fkdatums, foreignNKeys, + OIDOID, sizeof(Oid), true, TYPALIGN_INT); + for (i = 0; i < foreignNKeys; i++) + fkdatums[i] = ObjectIdGetDatum(ppEqOp[i]); + conppeqopArray = construct_array(fkdatums, foreignNKeys, + OIDOID, sizeof(Oid), true, TYPALIGN_INT); + for (i = 0; i < foreignNKeys; i++) + fkdatums[i] = ObjectIdGetDatum(ffEqOp[i]); + conffeqopArray = construct_array(fkdatums, foreignNKeys, + OIDOID, sizeof(Oid), true, TYPALIGN_INT); + } + else + { + confkeyArray = NULL; + conpfeqopArray = NULL; + conppeqopArray = NULL; + conffeqopArray = NULL; + } + + if (exclOp != NULL) + { + Datum *opdatums; + + opdatums = (Datum *) palloc(constraintNKeys * sizeof(Datum)); + for (i = 0; i < constraintNKeys; i++) + opdatums[i] = ObjectIdGetDatum(exclOp[i]); + conexclopArray = construct_array(opdatums, constraintNKeys, + OIDOID, sizeof(Oid), true, TYPALIGN_INT); + } + else + conexclopArray = NULL; + + /* initialize nulls and values */ + for (i = 0; i < Natts_pg_constraint; i++) + { + nulls[i] = false; + values[i] = (Datum) NULL; + } + + conOid = GetNewOidWithIndex(conDesc, ConstraintOidIndexId, + Anum_pg_constraint_oid); + values[Anum_pg_constraint_oid - 1] = ObjectIdGetDatum(conOid); + values[Anum_pg_constraint_conname - 1] = NameGetDatum(&cname); + values[Anum_pg_constraint_connamespace - 1] = ObjectIdGetDatum(constraintNamespace); + values[Anum_pg_constraint_contype - 1] = CharGetDatum(constraintType); + values[Anum_pg_constraint_condeferrable - 1] = BoolGetDatum(isDeferrable); + values[Anum_pg_constraint_condeferred - 1] = BoolGetDatum(isDeferred); + values[Anum_pg_constraint_convalidated - 1] = BoolGetDatum(isValidated); + values[Anum_pg_constraint_conrelid - 1] = ObjectIdGetDatum(relId); + values[Anum_pg_constraint_contypid - 1] = ObjectIdGetDatum(domainId); + values[Anum_pg_constraint_conindid - 1] = ObjectIdGetDatum(indexRelId); + values[Anum_pg_constraint_conparentid - 1] = ObjectIdGetDatum(parentConstrId); + values[Anum_pg_constraint_confrelid - 1] = ObjectIdGetDatum(foreignRelId); + values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType); + values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType); + values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType); + values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal); + values[Anum_pg_constraint_coninhcount - 1] = Int32GetDatum(conInhCount); + values[Anum_pg_constraint_connoinherit - 1] = BoolGetDatum(conNoInherit); + + if (conkeyArray) + values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray); + else + nulls[Anum_pg_constraint_conkey - 1] = true; + + if (confkeyArray) + values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray); + else + nulls[Anum_pg_constraint_confkey - 1] = true; + + if (conpfeqopArray) + values[Anum_pg_constraint_conpfeqop - 1] = PointerGetDatum(conpfeqopArray); + else + nulls[Anum_pg_constraint_conpfeqop - 1] = true; + + if (conppeqopArray) + values[Anum_pg_constraint_conppeqop - 1] = PointerGetDatum(conppeqopArray); + else + nulls[Anum_pg_constraint_conppeqop - 1] = true; + + if (conffeqopArray) + values[Anum_pg_constraint_conffeqop - 1] = PointerGetDatum(conffeqopArray); + else + nulls[Anum_pg_constraint_conffeqop - 1] = true; + + if (conexclopArray) + values[Anum_pg_constraint_conexclop - 1] = PointerGetDatum(conexclopArray); + else + nulls[Anum_pg_constraint_conexclop - 1] = true; + + if (conBin) + values[Anum_pg_constraint_conbin - 1] = CStringGetTextDatum(conBin); + else + nulls[Anum_pg_constraint_conbin - 1] = true; + + tup = heap_form_tuple(RelationGetDescr(conDesc), values, nulls); + + CatalogTupleInsert(conDesc, tup); + + conobject.classId = ConstraintRelationId; + conobject.objectId = conOid; + conobject.objectSubId = 0; + + table_close(conDesc, RowExclusiveLock); + + if (OidIsValid(relId)) + { + /* + * Register auto dependency from constraint to owning relation, or to + * specific column(s) if any are mentioned. + */ + ObjectAddress relobject; + + relobject.classId = RelationRelationId; + relobject.objectId = relId; + if (constraintNTotalKeys > 0) + { + for (i = 0; i < constraintNTotalKeys; i++) + { + relobject.objectSubId = constraintKey[i]; + + recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO); + } + } + else + { + relobject.objectSubId = 0; + + recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO); + } + } + + if (OidIsValid(domainId)) + { + /* + * Register auto dependency from constraint to owning domain + */ + ObjectAddress domobject; + + domobject.classId = TypeRelationId; + domobject.objectId = domainId; + domobject.objectSubId = 0; + + recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO); + } + + if (OidIsValid(foreignRelId)) + { + /* + * Register normal dependency from constraint to foreign relation, or + * to specific column(s) if any are mentioned. + */ + ObjectAddress relobject; + + relobject.classId = RelationRelationId; + relobject.objectId = foreignRelId; + if (foreignNKeys > 0) + { + for (i = 0; i < foreignNKeys; i++) + { + relobject.objectSubId = foreignKey[i]; + + recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL); + } + } + else + { + relobject.objectSubId = 0; + + recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL); + } + } + + if (OidIsValid(indexRelId) && constraintType == CONSTRAINT_FOREIGN) + { + /* + * Register normal dependency on the unique index that supports a + * foreign-key constraint. (Note: for indexes associated with unique + * or primary-key constraints, the dependency runs the other way, and + * is not made here.) + */ + ObjectAddress relobject; + + relobject.classId = RelationRelationId; + relobject.objectId = indexRelId; + relobject.objectSubId = 0; + + recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL); + } + + if (foreignNKeys > 0) + { + /* + * Register normal dependencies on the equality operators that support + * a foreign-key constraint. If the PK and FK types are the same then + * all three operators for a column are the same; otherwise they are + * different. + */ + ObjectAddress oprobject; + + oprobject.classId = OperatorRelationId; + oprobject.objectSubId = 0; + + for (i = 0; i < foreignNKeys; i++) + { + oprobject.objectId = pfEqOp[i]; + recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL); + if (ppEqOp[i] != pfEqOp[i]) + { + oprobject.objectId = ppEqOp[i]; + recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL); + } + if (ffEqOp[i] != pfEqOp[i]) + { + oprobject.objectId = ffEqOp[i]; + recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL); + } + } + } + + /* + * We don't bother to register dependencies on the exclusion operators of + * an exclusion constraint. We assume they are members of the opclass + * supporting the index, so there's an indirect dependency via that. (This + * would be pretty dicey for cross-type operators, but exclusion operators + * can never be cross-type.) + */ + + if (conExpr != NULL) + { + /* + * Register dependencies from constraint to objects mentioned in CHECK + * expression. + */ + recordDependencyOnSingleRelExpr(&conobject, conExpr, relId, + DEPENDENCY_NORMAL, + DEPENDENCY_NORMAL, false); + } + + /* Post creation hook for new constraint */ + InvokeObjectPostCreateHookArg(ConstraintRelationId, conOid, 0, + is_internal); + + return conOid; +} + +/* + * Test whether given name is currently used as a constraint name + * for the given object (relation or domain). + * + * This is used to decide whether to accept a user-specified constraint name. + * It is deliberately not the same test as ChooseConstraintName uses to decide + * whether an auto-generated name is OK: here, we will allow it unless there + * is an identical constraint name in use *on the same object*. + * + * NB: Caller should hold exclusive lock on the given object, else + * this test can be fooled by concurrent additions. + */ +bool +ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, + const char *conname) +{ + bool found; + Relation conDesc; + SysScanDesc conscan; + ScanKeyData skey[3]; + + conDesc = table_open(ConstraintRelationId, AccessShareLock); + + ScanKeyInit(&skey[0], + Anum_pg_constraint_conrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum((conCat == CONSTRAINT_RELATION) + ? objId : InvalidOid)); + ScanKeyInit(&skey[1], + Anum_pg_constraint_contypid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum((conCat == CONSTRAINT_DOMAIN) + ? objId : InvalidOid)); + ScanKeyInit(&skey[2], + Anum_pg_constraint_conname, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(conname)); + + conscan = systable_beginscan(conDesc, ConstraintRelidTypidNameIndexId, + true, NULL, 3, skey); + + /* There can be at most one matching row */ + found = (HeapTupleIsValid(systable_getnext(conscan))); + + systable_endscan(conscan); + table_close(conDesc, AccessShareLock); + + return found; +} + +/* + * Does any constraint of the given name exist in the given namespace? + * + * This is used for code that wants to match ChooseConstraintName's rule + * that we should avoid autogenerating duplicate constraint names within a + * namespace. + */ +bool +ConstraintNameExists(const char *conname, Oid namespaceid) +{ + bool found; + Relation conDesc; + SysScanDesc conscan; + ScanKeyData skey[2]; + + conDesc = table_open(ConstraintRelationId, AccessShareLock); + + ScanKeyInit(&skey[0], + Anum_pg_constraint_conname, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(conname)); + + ScanKeyInit(&skey[1], + Anum_pg_constraint_connamespace, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(namespaceid)); + + conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true, + NULL, 2, skey); + + found = (HeapTupleIsValid(systable_getnext(conscan))); + + systable_endscan(conscan); + table_close(conDesc, AccessShareLock); + + return found; +} + +/* + * Select a nonconflicting name for a new constraint. + * + * The objective here is to choose a name that is unique within the + * specified namespace. Postgres does not require this, but the SQL + * spec does, and some apps depend on it. Therefore we avoid choosing + * default names that so conflict. + * + * name1, name2, and label are used the same way as for makeObjectName(), + * except that the label can't be NULL; digits will be appended to the label + * if needed to create a name that is unique within the specified namespace. + * + * 'others' can be a list of string names already chosen within the current + * command (but not yet reflected into the catalogs); we will not choose + * a duplicate of one of these either. + * + * Note: it is theoretically possible to get a collision anyway, if someone + * else chooses the same name concurrently. This is fairly unlikely to be + * a problem in practice, especially if one is holding an exclusive lock on + * the relation identified by name1. + * + * Returns a palloc'd string. + */ +char * +ChooseConstraintName(const char *name1, const char *name2, + const char *label, Oid namespaceid, + List *others) +{ + int pass = 0; + char *conname = NULL; + char modlabel[NAMEDATALEN]; + Relation conDesc; + SysScanDesc conscan; + ScanKeyData skey[2]; + bool found; + ListCell *l; + + conDesc = table_open(ConstraintRelationId, AccessShareLock); + + /* try the unmodified label first */ + StrNCpy(modlabel, label, sizeof(modlabel)); + + for (;;) + { + conname = makeObjectName(name1, name2, modlabel); + + found = false; + + foreach(l, others) + { + if (strcmp((char *) lfirst(l), conname) == 0) + { + found = true; + break; + } + } + + if (!found) + { + ScanKeyInit(&skey[0], + Anum_pg_constraint_conname, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(conname)); + + ScanKeyInit(&skey[1], + Anum_pg_constraint_connamespace, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(namespaceid)); + + conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true, + NULL, 2, skey); + + found = (HeapTupleIsValid(systable_getnext(conscan))); + + systable_endscan(conscan); + } + + if (!found) + break; + + /* found a conflict, so try a new name component */ + pfree(conname); + snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass); + } + + table_close(conDesc, AccessShareLock); + + return conname; +} + +/* + * Delete a single constraint record. + */ +void +RemoveConstraintById(Oid conId) +{ + Relation conDesc; + HeapTuple tup; + Form_pg_constraint con; + + conDesc = table_open(ConstraintRelationId, RowExclusiveLock); + + tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conId)); + if (!HeapTupleIsValid(tup)) /* should not happen */ + elog(ERROR, "cache lookup failed for constraint %u", conId); + con = (Form_pg_constraint) GETSTRUCT(tup); + + /* + * Special processing depending on what the constraint is for. + */ + if (OidIsValid(con->conrelid)) + { + Relation rel; + + /* + * If the constraint is for a relation, open and exclusive-lock the + * relation it's for. + */ + rel = table_open(con->conrelid, AccessExclusiveLock); + + /* + * We need to update the relchecks count if it is a check constraint + * being dropped. This update will force backends to rebuild relcache + * entries when we commit. + */ + if (con->contype == CONSTRAINT_CHECK) + { + Relation pgrel; + HeapTuple relTup; + Form_pg_class classForm; + + pgrel = table_open(RelationRelationId, RowExclusiveLock); + relTup = SearchSysCacheCopy1(RELOID, + ObjectIdGetDatum(con->conrelid)); + if (!HeapTupleIsValid(relTup)) + elog(ERROR, "cache lookup failed for relation %u", + con->conrelid); + classForm = (Form_pg_class) GETSTRUCT(relTup); + + if (classForm->relchecks == 0) /* should not happen */ + elog(ERROR, "relation \"%s\" has relchecks = 0", + RelationGetRelationName(rel)); + classForm->relchecks--; + + CatalogTupleUpdate(pgrel, &relTup->t_self, relTup); + + heap_freetuple(relTup); + + table_close(pgrel, RowExclusiveLock); + } + + /* Keep lock on constraint's rel until end of xact */ + table_close(rel, NoLock); + } + else if (OidIsValid(con->contypid)) + { + /* + * XXX for now, do nothing special when dropping a domain constraint + * + * Probably there should be some form of locking on the domain type, + * but we have no such concept at the moment. + */ + } + else + elog(ERROR, "constraint %u is not of a known type", conId); + + /* Fry the constraint itself */ + CatalogTupleDelete(conDesc, &tup->t_self); + + /* Clean up */ + ReleaseSysCache(tup); + table_close(conDesc, RowExclusiveLock); +} + +/* + * RenameConstraintById + * Rename a constraint. + * + * Note: this isn't intended to be a user-exposed function; it doesn't check + * permissions etc. Currently this is only invoked when renaming an index + * that is associated with a constraint, but it's made a little more general + * than that with the expectation of someday having ALTER TABLE RENAME + * CONSTRAINT. + */ +void +RenameConstraintById(Oid conId, const char *newname) +{ + Relation conDesc; + HeapTuple tuple; + Form_pg_constraint con; + + conDesc = table_open(ConstraintRelationId, RowExclusiveLock); + + tuple = SearchSysCacheCopy1(CONSTROID, ObjectIdGetDatum(conId)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for constraint %u", conId); + con = (Form_pg_constraint) GETSTRUCT(tuple); + + /* + * For user-friendliness, check whether the name is already in use. + */ + if (OidIsValid(con->conrelid) && + ConstraintNameIsUsed(CONSTRAINT_RELATION, + con->conrelid, + newname)) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("constraint \"%s\" for relation \"%s\" already exists", + newname, get_rel_name(con->conrelid)))); + if (OidIsValid(con->contypid) && + ConstraintNameIsUsed(CONSTRAINT_DOMAIN, + con->contypid, + newname)) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("constraint \"%s\" for domain %s already exists", + newname, format_type_be(con->contypid)))); + + /* OK, do the rename --- tuple is a copy, so OK to scribble on it */ + namestrcpy(&(con->conname), newname); + + CatalogTupleUpdate(conDesc, &tuple->t_self, tuple); + + InvokeObjectPostAlterHook(ConstraintRelationId, conId, 0); + + heap_freetuple(tuple); + table_close(conDesc, RowExclusiveLock); +} + +/* + * AlterConstraintNamespaces + * Find any constraints belonging to the specified object, + * and move them to the specified new namespace. + * + * isType indicates whether the owning object is a type or a relation. + */ +void +AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, + Oid newNspId, bool isType, ObjectAddresses *objsMoved) +{ + Relation conRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + + conRel = table_open(ConstraintRelationId, RowExclusiveLock); + + ScanKeyInit(&key[0], + Anum_pg_constraint_conrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(isType ? InvalidOid : ownerId)); + ScanKeyInit(&key[1], + Anum_pg_constraint_contypid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(isType ? ownerId : InvalidOid)); + + scan = systable_beginscan(conRel, ConstraintRelidTypidNameIndexId, true, + NULL, 2, key); + + while (HeapTupleIsValid((tup = systable_getnext(scan)))) + { + Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(tup); + ObjectAddress thisobj; + + thisobj.classId = ConstraintRelationId; + thisobj.objectId = conform->oid; + thisobj.objectSubId = 0; + + if (object_address_present(&thisobj, objsMoved)) + continue; + + /* Don't update if the object is already part of the namespace */ + if (conform->connamespace == oldNspId && oldNspId != newNspId) + { + tup = heap_copytuple(tup); + conform = (Form_pg_constraint) GETSTRUCT(tup); + + conform->connamespace = newNspId; + + CatalogTupleUpdate(conRel, &tup->t_self, tup); + + /* + * Note: currently, the constraint will not have its own + * dependency on the namespace, so we don't need to do + * changeDependencyFor(). + */ + } + + InvokeObjectPostAlterHook(ConstraintRelationId, thisobj.objectId, 0); + + add_exact_object_address(&thisobj, objsMoved); + } + + systable_endscan(scan); + + table_close(conRel, RowExclusiveLock); +} + +/* + * ConstraintSetParentConstraint + * Set a partition's constraint as child of its parent constraint, + * or remove the linkage if parentConstrId is InvalidOid. + * + * This updates the constraint's pg_constraint row to show it as inherited, and + * adds PARTITION dependencies to prevent the constraint from being deleted + * on its own. Alternatively, reverse that. + */ +void +ConstraintSetParentConstraint(Oid childConstrId, + Oid parentConstrId, + Oid childTableId) +{ + Relation constrRel; + Form_pg_constraint constrForm; + HeapTuple tuple, + newtup; + ObjectAddress depender; + ObjectAddress referenced; + + constrRel = table_open(ConstraintRelationId, RowExclusiveLock); + tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(childConstrId)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for constraint %u", childConstrId); + newtup = heap_copytuple(tuple); + constrForm = (Form_pg_constraint) GETSTRUCT(newtup); + if (OidIsValid(parentConstrId)) + { + /* don't allow setting parent for a constraint that already has one */ + Assert(constrForm->coninhcount == 0); + if (constrForm->conparentid != InvalidOid) + elog(ERROR, "constraint %u already has a parent constraint", + childConstrId); + + constrForm->conislocal = false; + constrForm->coninhcount++; + constrForm->conparentid = parentConstrId; + + CatalogTupleUpdate(constrRel, &tuple->t_self, newtup); + + ObjectAddressSet(depender, ConstraintRelationId, childConstrId); + + ObjectAddressSet(referenced, ConstraintRelationId, parentConstrId); + recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_PRI); + + ObjectAddressSet(referenced, RelationRelationId, childTableId); + recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_SEC); + } + else + { + constrForm->coninhcount--; + constrForm->conislocal = true; + constrForm->conparentid = InvalidOid; + + /* Make sure there's no further inheritance. */ + Assert(constrForm->coninhcount == 0); + + CatalogTupleUpdate(constrRel, &tuple->t_self, newtup); + + deleteDependencyRecordsForClass(ConstraintRelationId, childConstrId, + ConstraintRelationId, + DEPENDENCY_PARTITION_PRI); + deleteDependencyRecordsForClass(ConstraintRelationId, childConstrId, + RelationRelationId, + DEPENDENCY_PARTITION_SEC); + } + + ReleaseSysCache(tuple); + table_close(constrRel, RowExclusiveLock); +} + + +/* + * get_relation_constraint_oid + * Find a constraint on the specified relation with the specified name. + * Returns constraint's OID. + */ +Oid +get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok) +{ + Relation pg_constraint; + HeapTuple tuple; + SysScanDesc scan; + ScanKeyData skey[3]; + Oid conOid = InvalidOid; + + pg_constraint = table_open(ConstraintRelationId, AccessShareLock); + + ScanKeyInit(&skey[0], + Anum_pg_constraint_conrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(relid)); + ScanKeyInit(&skey[1], + Anum_pg_constraint_contypid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(InvalidOid)); + ScanKeyInit(&skey[2], + Anum_pg_constraint_conname, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(conname)); + + scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true, + NULL, 3, skey); + + /* There can be at most one matching row */ + if (HeapTupleIsValid(tuple = systable_getnext(scan))) + conOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid; + + systable_endscan(scan); + + /* If no such constraint exists, complain */ + if (!OidIsValid(conOid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("constraint \"%s\" for table \"%s\" does not exist", + conname, get_rel_name(relid)))); + + table_close(pg_constraint, AccessShareLock); + + return conOid; +} + +/* + * get_relation_constraint_attnos + * Find a constraint on the specified relation with the specified name + * and return the constrained columns. + * + * Returns a Bitmapset of the column attnos of the constrained columns, with + * attnos being offset by FirstLowInvalidHeapAttributeNumber so that system + * columns can be represented. + * + * *constraintOid is set to the OID of the constraint, or InvalidOid on + * failure. + */ +Bitmapset * +get_relation_constraint_attnos(Oid relid, const char *conname, + bool missing_ok, Oid *constraintOid) +{ + Bitmapset *conattnos = NULL; + Relation pg_constraint; + HeapTuple tuple; + SysScanDesc scan; + ScanKeyData skey[3]; + + /* Set *constraintOid, to avoid complaints about uninitialized vars */ + *constraintOid = InvalidOid; + + pg_constraint = table_open(ConstraintRelationId, AccessShareLock); + + ScanKeyInit(&skey[0], + Anum_pg_constraint_conrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(relid)); + ScanKeyInit(&skey[1], + Anum_pg_constraint_contypid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(InvalidOid)); + ScanKeyInit(&skey[2], + Anum_pg_constraint_conname, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(conname)); + + scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true, + NULL, 3, skey); + + /* There can be at most one matching row */ + if (HeapTupleIsValid(tuple = systable_getnext(scan))) + { + Datum adatum; + bool isNull; + + *constraintOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid; + + /* Extract the conkey array, ie, attnums of constrained columns */ + adatum = heap_getattr(tuple, Anum_pg_constraint_conkey, + RelationGetDescr(pg_constraint), &isNull); + if (!isNull) + { + ArrayType *arr; + int numcols; + int16 *attnums; + int i; + + arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ + numcols = ARR_DIMS(arr)[0]; + if (ARR_NDIM(arr) != 1 || + numcols < 0 || + ARR_HASNULL(arr) || + ARR_ELEMTYPE(arr) != INT2OID) + elog(ERROR, "conkey is not a 1-D smallint array"); + attnums = (int16 *) ARR_DATA_PTR(arr); + + /* Construct the result value */ + for (i = 0; i < numcols; i++) + { + conattnos = bms_add_member(conattnos, + attnums[i] - FirstLowInvalidHeapAttributeNumber); + } + } + } + + systable_endscan(scan); + + /* If no such constraint exists, complain */ + if (!OidIsValid(*constraintOid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("constraint \"%s\" for table \"%s\" does not exist", + conname, get_rel_name(relid)))); + + table_close(pg_constraint, AccessShareLock); + + return conattnos; +} + +/* + * Return the OID of the constraint associated with the given index in the + * given relation; or InvalidOid if no such index is catalogued. + */ +Oid +get_relation_idx_constraint_oid(Oid relationId, Oid indexId) +{ + Relation pg_constraint; + SysScanDesc scan; + ScanKeyData key; + HeapTuple tuple; + Oid constraintId = InvalidOid; + + pg_constraint = table_open(ConstraintRelationId, AccessShareLock); + + ScanKeyInit(&key, + Anum_pg_constraint_conrelid, + BTEqualStrategyNumber, + F_OIDEQ, + ObjectIdGetDatum(relationId)); + scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, + true, NULL, 1, &key); + while ((tuple = systable_getnext(scan)) != NULL) + { + Form_pg_constraint constrForm; + + constrForm = (Form_pg_constraint) GETSTRUCT(tuple); + if (constrForm->conindid == indexId) + { + constraintId = constrForm->oid; + break; + } + } + systable_endscan(scan); + + table_close(pg_constraint, AccessShareLock); + return constraintId; +} + +/* + * get_domain_constraint_oid + * Find a constraint on the specified domain with the specified name. + * Returns constraint's OID. + */ +Oid +get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok) +{ + Relation pg_constraint; + HeapTuple tuple; + SysScanDesc scan; + ScanKeyData skey[3]; + Oid conOid = InvalidOid; + + pg_constraint = table_open(ConstraintRelationId, AccessShareLock); + + ScanKeyInit(&skey[0], + Anum_pg_constraint_conrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(InvalidOid)); + ScanKeyInit(&skey[1], + Anum_pg_constraint_contypid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(typid)); + ScanKeyInit(&skey[2], + Anum_pg_constraint_conname, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(conname)); + + scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true, + NULL, 3, skey); + + /* There can be at most one matching row */ + if (HeapTupleIsValid(tuple = systable_getnext(scan))) + conOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid; + + systable_endscan(scan); + + /* If no such constraint exists, complain */ + if (!OidIsValid(conOid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("constraint \"%s\" for domain %s does not exist", + conname, format_type_be(typid)))); + + table_close(pg_constraint, AccessShareLock); + + return conOid; +} + +/* + * get_primary_key_attnos + * Identify the columns in a relation's primary key, if any. + * + * Returns a Bitmapset of the column attnos of the primary key's columns, + * with attnos being offset by FirstLowInvalidHeapAttributeNumber so that + * system columns can be represented. + * + * If there is no primary key, return NULL. We also return NULL if the pkey + * constraint is deferrable and deferrableOk is false. + * + * *constraintOid is set to the OID of the pkey constraint, or InvalidOid + * on failure. + */ +Bitmapset * +get_primary_key_attnos(Oid relid, bool deferrableOk, Oid *constraintOid) +{ + Bitmapset *pkattnos = NULL; + Relation pg_constraint; + HeapTuple tuple; + SysScanDesc scan; + ScanKeyData skey[1]; + + /* Set *constraintOid, to avoid complaints about uninitialized vars */ + *constraintOid = InvalidOid; + + /* Scan pg_constraint for constraints of the target rel */ + pg_constraint = table_open(ConstraintRelationId, AccessShareLock); + + ScanKeyInit(&skey[0], + Anum_pg_constraint_conrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(relid)); + + scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true, + NULL, 1, skey); + + while (HeapTupleIsValid(tuple = systable_getnext(scan))) + { + Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple); + Datum adatum; + bool isNull; + ArrayType *arr; + int16 *attnums; + int numkeys; + int i; + + /* Skip constraints that are not PRIMARY KEYs */ + if (con->contype != CONSTRAINT_PRIMARY) + continue; + + /* + * If the primary key is deferrable, but we've been instructed to + * ignore deferrable constraints, then we might as well give up + * searching, since there can only be a single primary key on a table. + */ + if (con->condeferrable && !deferrableOk) + break; + + /* Extract the conkey array, ie, attnums of PK's columns */ + adatum = heap_getattr(tuple, Anum_pg_constraint_conkey, + RelationGetDescr(pg_constraint), &isNull); + if (isNull) + elog(ERROR, "null conkey for constraint %u", + ((Form_pg_constraint) GETSTRUCT(tuple))->oid); + arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ + numkeys = ARR_DIMS(arr)[0]; + if (ARR_NDIM(arr) != 1 || + numkeys < 0 || + ARR_HASNULL(arr) || + ARR_ELEMTYPE(arr) != INT2OID) + elog(ERROR, "conkey is not a 1-D smallint array"); + attnums = (int16 *) ARR_DATA_PTR(arr); + + /* Construct the result value */ + for (i = 0; i < numkeys; i++) + { + pkattnos = bms_add_member(pkattnos, + attnums[i] - FirstLowInvalidHeapAttributeNumber); + } + *constraintOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid; + + /* No need to search further */ + break; + } + + systable_endscan(scan); + + table_close(pg_constraint, AccessShareLock); + + return pkattnos; +} + +/* + * Extract data from the pg_constraint tuple of a foreign-key constraint. + * + * All arguments save the first are output arguments; the last three of them + * can be passed as NULL if caller doesn't need them. + */ +void +DeconstructFkConstraintRow(HeapTuple tuple, int *numfks, + AttrNumber *conkey, AttrNumber *confkey, + Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs) +{ + Oid constrId; + Datum adatum; + bool isNull; + ArrayType *arr; + int numkeys; + + constrId = ((Form_pg_constraint) GETSTRUCT(tuple))->oid; + + /* + * We expect the arrays to be 1-D arrays of the right types; verify that. + * We don't need to use deconstruct_array() since the array data is just + * going to look like a C array of values. + */ + adatum = SysCacheGetAttr(CONSTROID, tuple, + Anum_pg_constraint_conkey, &isNull); + if (isNull) + elog(ERROR, "null conkey for constraint %u", constrId); + arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ + if (ARR_NDIM(arr) != 1 || + ARR_HASNULL(arr) || + ARR_ELEMTYPE(arr) != INT2OID) + elog(ERROR, "conkey is not a 1-D smallint array"); + numkeys = ARR_DIMS(arr)[0]; + if (numkeys <= 0 || numkeys > INDEX_MAX_KEYS) + elog(ERROR, "foreign key constraint cannot have %d columns", numkeys); + memcpy(conkey, ARR_DATA_PTR(arr), numkeys * sizeof(int16)); + if ((Pointer) arr != DatumGetPointer(adatum)) + pfree(arr); /* free de-toasted copy, if any */ + + adatum = SysCacheGetAttr(CONSTROID, tuple, + Anum_pg_constraint_confkey, &isNull); + if (isNull) + elog(ERROR, "null confkey for constraint %u", constrId); + arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ + if (ARR_NDIM(arr) != 1 || + ARR_DIMS(arr)[0] != numkeys || + ARR_HASNULL(arr) || + ARR_ELEMTYPE(arr) != INT2OID) + elog(ERROR, "confkey is not a 1-D smallint array"); + memcpy(confkey, ARR_DATA_PTR(arr), numkeys * sizeof(int16)); + if ((Pointer) arr != DatumGetPointer(adatum)) + pfree(arr); /* free de-toasted copy, if any */ + + if (pf_eq_oprs) + { + adatum = SysCacheGetAttr(CONSTROID, tuple, + Anum_pg_constraint_conpfeqop, &isNull); + if (isNull) + elog(ERROR, "null conpfeqop for constraint %u", constrId); + arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ + /* see TryReuseForeignKey if you change the test below */ + if (ARR_NDIM(arr) != 1 || + ARR_DIMS(arr)[0] != numkeys || + ARR_HASNULL(arr) || + ARR_ELEMTYPE(arr) != OIDOID) + elog(ERROR, "conpfeqop is not a 1-D Oid array"); + memcpy(pf_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid)); + if ((Pointer) arr != DatumGetPointer(adatum)) + pfree(arr); /* free de-toasted copy, if any */ + } + + if (pp_eq_oprs) + { + adatum = SysCacheGetAttr(CONSTROID, tuple, + Anum_pg_constraint_conppeqop, &isNull); + if (isNull) + elog(ERROR, "null conppeqop for constraint %u", constrId); + arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ + if (ARR_NDIM(arr) != 1 || + ARR_DIMS(arr)[0] != numkeys || + ARR_HASNULL(arr) || + ARR_ELEMTYPE(arr) != OIDOID) + elog(ERROR, "conppeqop is not a 1-D Oid array"); + memcpy(pp_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid)); + if ((Pointer) arr != DatumGetPointer(adatum)) + pfree(arr); /* free de-toasted copy, if any */ + } + + if (ff_eq_oprs) + { + adatum = SysCacheGetAttr(CONSTROID, tuple, + Anum_pg_constraint_conffeqop, &isNull); + if (isNull) + elog(ERROR, "null conffeqop for constraint %u", constrId); + arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ + if (ARR_NDIM(arr) != 1 || + ARR_DIMS(arr)[0] != numkeys || + ARR_HASNULL(arr) || + ARR_ELEMTYPE(arr) != OIDOID) + elog(ERROR, "conffeqop is not a 1-D Oid array"); + memcpy(ff_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid)); + if ((Pointer) arr != DatumGetPointer(adatum)) + pfree(arr); /* free de-toasted copy, if any */ + } + + *numfks = numkeys; +} + +/* + * Determine whether a relation can be proven functionally dependent on + * a set of grouping columns. If so, return true and add the pg_constraint + * OIDs of the constraints needed for the proof to the *constraintDeps list. + * + * grouping_columns is a list of grouping expressions, in which columns of + * the rel of interest are Vars with the indicated varno/varlevelsup. + * + * Currently we only check to see if the rel has a primary key that is a + * subset of the grouping_columns. We could also use plain unique constraints + * if all their columns are known not null, but there's a problem: we need + * to be able to represent the not-null-ness as part of the constraints added + * to *constraintDeps. FIXME whenever not-null constraints get represented + * in pg_constraint. + */ +bool +check_functional_grouping(Oid relid, + Index varno, Index varlevelsup, + List *grouping_columns, + List **constraintDeps) +{ + Bitmapset *pkattnos; + Bitmapset *groupbyattnos; + Oid constraintOid; + ListCell *gl; + + /* If the rel has no PK, then we can't prove functional dependency */ + pkattnos = get_primary_key_attnos(relid, false, &constraintOid); + if (pkattnos == NULL) + return false; + + /* Identify all the rel's columns that appear in grouping_columns */ + groupbyattnos = NULL; + foreach(gl, grouping_columns) + { + Var *gvar = (Var *) lfirst(gl); + + if (IsA(gvar, Var) && + gvar->varno == varno && + gvar->varlevelsup == varlevelsup) + groupbyattnos = bms_add_member(groupbyattnos, + gvar->varattno - FirstLowInvalidHeapAttributeNumber); + } + + if (bms_is_subset(pkattnos, groupbyattnos)) + { + /* The PK is a subset of grouping_columns, so we win */ + *constraintDeps = lappend_oid(*constraintDeps, constraintOid); + return true; + } + + return false; +} diff --git a/src/backend/catalog/pg_constraint_d.h b/src/backend/catalog/pg_constraint_d.h new file mode 100644 index 0000000..3d98c62 --- /dev/null +++ b/src/backend/catalog/pg_constraint_d.h @@ -0,0 +1,67 @@ +/*------------------------------------------------------------------------- + * + * pg_constraint_d.h + * Macro definitions for pg_constraint + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_CONSTRAINT_D_H +#define PG_CONSTRAINT_D_H + +#define ConstraintRelationId 2606 + +#define Anum_pg_constraint_oid 1 +#define Anum_pg_constraint_conname 2 +#define Anum_pg_constraint_connamespace 3 +#define Anum_pg_constraint_contype 4 +#define Anum_pg_constraint_condeferrable 5 +#define Anum_pg_constraint_condeferred 6 +#define Anum_pg_constraint_convalidated 7 +#define Anum_pg_constraint_conrelid 8 +#define Anum_pg_constraint_contypid 9 +#define Anum_pg_constraint_conindid 10 +#define Anum_pg_constraint_conparentid 11 +#define Anum_pg_constraint_confrelid 12 +#define Anum_pg_constraint_confupdtype 13 +#define Anum_pg_constraint_confdeltype 14 +#define Anum_pg_constraint_confmatchtype 15 +#define Anum_pg_constraint_conislocal 16 +#define Anum_pg_constraint_coninhcount 17 +#define Anum_pg_constraint_connoinherit 18 +#define Anum_pg_constraint_conkey 19 +#define Anum_pg_constraint_confkey 20 +#define Anum_pg_constraint_conpfeqop 21 +#define Anum_pg_constraint_conppeqop 22 +#define Anum_pg_constraint_conffeqop 23 +#define Anum_pg_constraint_conexclop 24 +#define Anum_pg_constraint_conbin 25 + +#define Natts_pg_constraint 25 + + +/* Valid values for contype */ +#define CONSTRAINT_CHECK 'c' +#define CONSTRAINT_FOREIGN 'f' +#define CONSTRAINT_PRIMARY 'p' +#define CONSTRAINT_UNIQUE 'u' +#define CONSTRAINT_TRIGGER 't' +#define CONSTRAINT_EXCLUSION 'x' + +/* + * Valid values for confupdtype and confdeltype are the FKCONSTR_ACTION_xxx + * constants defined in parsenodes.h. Valid values for confmatchtype are + * the FKCONSTR_MATCH_xxx constants defined in parsenodes.h. + */ + + +#endif /* PG_CONSTRAINT_D_H */ diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c new file mode 100644 index 0000000..b38df4f --- /dev/null +++ b/src/backend/catalog/pg_conversion.c @@ -0,0 +1,213 @@ +/*------------------------------------------------------------------------- + * + * pg_conversion.c + * routines to support manipulation of the pg_conversion relation + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/pg_conversion.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/heapam.h" +#include "access/htup_details.h" +#include "access/sysattr.h" +#include "access/tableam.h" +#include "catalog/catalog.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/objectaccess.h" +#include "catalog/pg_conversion.h" +#include "catalog/pg_namespace.h" +#include "catalog/pg_proc.h" +#include "mb/pg_wchar.h" +#include "utils/builtins.h" +#include "utils/catcache.h" +#include "utils/fmgroids.h" +#include "utils/rel.h" +#include "utils/syscache.h" + +/* + * ConversionCreate + * + * Add a new tuple to pg_conversion. + */ +ObjectAddress +ConversionCreate(const char *conname, Oid connamespace, + Oid conowner, + int32 conforencoding, int32 contoencoding, + Oid conproc, bool def) +{ + int i; + Relation rel; + TupleDesc tupDesc; + HeapTuple tup; + Oid oid; + bool nulls[Natts_pg_conversion]; + Datum values[Natts_pg_conversion]; + NameData cname; + ObjectAddress myself, + referenced; + + /* sanity checks */ + if (!conname) + elog(ERROR, "no conversion name supplied"); + + /* make sure there is no existing conversion of same name */ + if (SearchSysCacheExists2(CONNAMENSP, + PointerGetDatum(conname), + ObjectIdGetDatum(connamespace))) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("conversion \"%s\" already exists", conname))); + + if (def) + { + /* + * make sure there is no existing default <for encoding><to encoding> + * pair in this name space + */ + if (FindDefaultConversion(connamespace, + conforencoding, + contoencoding)) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("default conversion for %s to %s already exists", + pg_encoding_to_char(conforencoding), + pg_encoding_to_char(contoencoding)))); + } + + /* open pg_conversion */ + rel = table_open(ConversionRelationId, RowExclusiveLock); + tupDesc = rel->rd_att; + + /* initialize nulls and values */ + for (i = 0; i < Natts_pg_conversion; i++) + { + nulls[i] = false; + values[i] = (Datum) NULL; + } + + /* form a tuple */ + namestrcpy(&cname, conname); + oid = GetNewOidWithIndex(rel, ConversionOidIndexId, + Anum_pg_conversion_oid); + values[Anum_pg_conversion_oid - 1] = ObjectIdGetDatum(oid); + values[Anum_pg_conversion_conname - 1] = NameGetDatum(&cname); + values[Anum_pg_conversion_connamespace - 1] = ObjectIdGetDatum(connamespace); + values[Anum_pg_conversion_conowner - 1] = ObjectIdGetDatum(conowner); + values[Anum_pg_conversion_conforencoding - 1] = Int32GetDatum(conforencoding); + values[Anum_pg_conversion_contoencoding - 1] = Int32GetDatum(contoencoding); + values[Anum_pg_conversion_conproc - 1] = ObjectIdGetDatum(conproc); + values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(def); + + tup = heap_form_tuple(tupDesc, values, nulls); + + /* insert a new tuple */ + CatalogTupleInsert(rel, tup); + + myself.classId = ConversionRelationId; + myself.objectId = oid; + myself.objectSubId = 0; + + /* create dependency on conversion procedure */ + referenced.classId = ProcedureRelationId; + referenced.objectId = conproc; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + /* create dependency on namespace */ + referenced.classId = NamespaceRelationId; + referenced.objectId = connamespace; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + /* create dependency on owner */ + recordDependencyOnOwner(ConversionRelationId, oid, conowner); + + /* dependency on extension */ + recordDependencyOnCurrentExtension(&myself, false); + + /* Post creation hook for new conversion */ + InvokeObjectPostCreateHook(ConversionRelationId, oid, 0); + + heap_freetuple(tup); + table_close(rel, RowExclusiveLock); + + return myself; +} + +/* + * RemoveConversionById + * + * Remove a tuple from pg_conversion by Oid. This function is solely + * called inside catalog/dependency.c + */ +void +RemoveConversionById(Oid conversionOid) +{ + Relation rel; + HeapTuple tuple; + TableScanDesc scan; + ScanKeyData scanKeyData; + + ScanKeyInit(&scanKeyData, + Anum_pg_conversion_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(conversionOid)); + + /* open pg_conversion */ + rel = table_open(ConversionRelationId, RowExclusiveLock); + + scan = table_beginscan_catalog(rel, 1, &scanKeyData); + + /* search for the target tuple */ + if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection))) + CatalogTupleDelete(rel, &tuple->t_self); + else + elog(ERROR, "could not find tuple for conversion %u", conversionOid); + table_endscan(scan); + table_close(rel, RowExclusiveLock); +} + +/* + * FindDefaultConversion + * + * Find "default" conversion proc by for_encoding and to_encoding in the + * given namespace. + * + * If found, returns the procedure's oid, otherwise InvalidOid. Note that + * you get the procedure's OID not the conversion's OID! + */ +Oid +FindDefaultConversion(Oid name_space, int32 for_encoding, int32 to_encoding) +{ + CatCList *catlist; + HeapTuple tuple; + Form_pg_conversion body; + Oid proc = InvalidOid; + int i; + + catlist = SearchSysCacheList3(CONDEFAULT, + ObjectIdGetDatum(name_space), + Int32GetDatum(for_encoding), + Int32GetDatum(to_encoding)); + + for (i = 0; i < catlist->n_members; i++) + { + tuple = &catlist->members[i]->tuple; + body = (Form_pg_conversion) GETSTRUCT(tuple); + if (body->condefault) + { + proc = body->conproc; + break; + } + } + ReleaseSysCacheList(catlist); + return proc; +} diff --git a/src/backend/catalog/pg_conversion_d.h b/src/backend/catalog/pg_conversion_d.h new file mode 100644 index 0000000..c991871 --- /dev/null +++ b/src/backend/catalog/pg_conversion_d.h @@ -0,0 +1,35 @@ +/*------------------------------------------------------------------------- + * + * pg_conversion_d.h + * Macro definitions for pg_conversion + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_CONVERSION_D_H +#define PG_CONVERSION_D_H + +#define ConversionRelationId 2607 + +#define Anum_pg_conversion_oid 1 +#define Anum_pg_conversion_conname 2 +#define Anum_pg_conversion_connamespace 3 +#define Anum_pg_conversion_conowner 4 +#define Anum_pg_conversion_conforencoding 5 +#define Anum_pg_conversion_contoencoding 6 +#define Anum_pg_conversion_conproc 7 +#define Anum_pg_conversion_condefault 8 + +#define Natts_pg_conversion 8 + + +#endif /* PG_CONVERSION_D_H */ diff --git a/src/backend/catalog/pg_database_d.h b/src/backend/catalog/pg_database_d.h new file mode 100644 index 0000000..7335d03 --- /dev/null +++ b/src/backend/catalog/pg_database_d.h @@ -0,0 +1,43 @@ +/*------------------------------------------------------------------------- + * + * pg_database_d.h + * Macro definitions for pg_database + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_DATABASE_D_H +#define PG_DATABASE_D_H + +#define DatabaseRelationId 1262 +#define DatabaseRelation_Rowtype_Id 1248 + +#define Anum_pg_database_oid 1 +#define Anum_pg_database_datname 2 +#define Anum_pg_database_datdba 3 +#define Anum_pg_database_encoding 4 +#define Anum_pg_database_datcollate 5 +#define Anum_pg_database_datctype 6 +#define Anum_pg_database_datistemplate 7 +#define Anum_pg_database_datallowconn 8 +#define Anum_pg_database_datconnlimit 9 +#define Anum_pg_database_datlastsysoid 10 +#define Anum_pg_database_datfrozenxid 11 +#define Anum_pg_database_datminmxid 12 +#define Anum_pg_database_dattablespace 13 +#define Anum_pg_database_datacl 14 + +#define Natts_pg_database 14 + +#define TemplateDbOid 1 + +#endif /* PG_DATABASE_D_H */ diff --git a/src/backend/catalog/pg_db_role_setting.c b/src/backend/catalog/pg_db_role_setting.c new file mode 100644 index 0000000..33fc53a --- /dev/null +++ b/src/backend/catalog/pg_db_role_setting.c @@ -0,0 +1,261 @@ +/* + * pg_db_role_setting.c + * Routines to support manipulation of the pg_db_role_setting relation + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/catalog/pg_db_role_setting.c + */ +#include "postgres.h" + +#include "access/genam.h" +#include "access/heapam.h" +#include "access/htup_details.h" +#include "access/tableam.h" +#include "catalog/indexing.h" +#include "catalog/objectaccess.h" +#include "catalog/pg_db_role_setting.h" +#include "utils/fmgroids.h" +#include "utils/rel.h" + +void +AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt) +{ + char *valuestr; + HeapTuple tuple; + Relation rel; + ScanKeyData scankey[2]; + SysScanDesc scan; + + valuestr = ExtractSetVariableArgs(setstmt); + + /* Get the old tuple, if any. */ + + rel = table_open(DbRoleSettingRelationId, RowExclusiveLock); + ScanKeyInit(&scankey[0], + Anum_pg_db_role_setting_setdatabase, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(databaseid)); + ScanKeyInit(&scankey[1], + Anum_pg_db_role_setting_setrole, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(roleid)); + scan = systable_beginscan(rel, DbRoleSettingDatidRolidIndexId, true, + NULL, 2, scankey); + tuple = systable_getnext(scan); + + /* + * There are three cases: + * + * - in RESET ALL, request GUC to reset the settings array and update the + * catalog if there's anything left, delete it otherwise + * + * - in other commands, if there's a tuple in pg_db_role_setting, update + * it; if it ends up empty, delete it + * + * - otherwise, insert a new pg_db_role_setting tuple, but only if the + * command is not RESET + */ + if (setstmt->kind == VAR_RESET_ALL) + { + if (HeapTupleIsValid(tuple)) + { + ArrayType *new = NULL; + Datum datum; + bool isnull; + + datum = heap_getattr(tuple, Anum_pg_db_role_setting_setconfig, + RelationGetDescr(rel), &isnull); + + if (!isnull) + new = GUCArrayReset(DatumGetArrayTypeP(datum)); + + if (new) + { + Datum repl_val[Natts_pg_db_role_setting]; + bool repl_null[Natts_pg_db_role_setting]; + bool repl_repl[Natts_pg_db_role_setting]; + HeapTuple newtuple; + + memset(repl_repl, false, sizeof(repl_repl)); + + repl_val[Anum_pg_db_role_setting_setconfig - 1] = + PointerGetDatum(new); + repl_repl[Anum_pg_db_role_setting_setconfig - 1] = true; + repl_null[Anum_pg_db_role_setting_setconfig - 1] = false; + + newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel), + repl_val, repl_null, repl_repl); + CatalogTupleUpdate(rel, &tuple->t_self, newtuple); + } + else + CatalogTupleDelete(rel, &tuple->t_self); + } + } + else if (HeapTupleIsValid(tuple)) + { + Datum repl_val[Natts_pg_db_role_setting]; + bool repl_null[Natts_pg_db_role_setting]; + bool repl_repl[Natts_pg_db_role_setting]; + HeapTuple newtuple; + Datum datum; + bool isnull; + ArrayType *a; + + memset(repl_repl, false, sizeof(repl_repl)); + repl_repl[Anum_pg_db_role_setting_setconfig - 1] = true; + repl_null[Anum_pg_db_role_setting_setconfig - 1] = false; + + /* Extract old value of setconfig */ + datum = heap_getattr(tuple, Anum_pg_db_role_setting_setconfig, + RelationGetDescr(rel), &isnull); + a = isnull ? NULL : DatumGetArrayTypeP(datum); + + /* Update (valuestr is NULL in RESET cases) */ + if (valuestr) + a = GUCArrayAdd(a, setstmt->name, valuestr); + else + a = GUCArrayDelete(a, setstmt->name); + + if (a) + { + repl_val[Anum_pg_db_role_setting_setconfig - 1] = + PointerGetDatum(a); + + newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel), + repl_val, repl_null, repl_repl); + CatalogTupleUpdate(rel, &tuple->t_self, newtuple); + } + else + CatalogTupleDelete(rel, &tuple->t_self); + } + else if (valuestr) + { + /* non-null valuestr means it's not RESET, so insert a new tuple */ + HeapTuple newtuple; + Datum values[Natts_pg_db_role_setting]; + bool nulls[Natts_pg_db_role_setting]; + ArrayType *a; + + memset(nulls, false, sizeof(nulls)); + + a = GUCArrayAdd(NULL, setstmt->name, valuestr); + + values[Anum_pg_db_role_setting_setdatabase - 1] = + ObjectIdGetDatum(databaseid); + values[Anum_pg_db_role_setting_setrole - 1] = ObjectIdGetDatum(roleid); + values[Anum_pg_db_role_setting_setconfig - 1] = PointerGetDatum(a); + newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls); + + CatalogTupleInsert(rel, newtuple); + } + + InvokeObjectPostAlterHookArg(DbRoleSettingRelationId, + databaseid, 0, roleid, false); + + systable_endscan(scan); + + /* Close pg_db_role_setting, but keep lock till commit */ + table_close(rel, NoLock); +} + +/* + * Drop some settings from the catalog. These can be for a particular + * database, or for a particular role. (It is of course possible to do both + * too, but it doesn't make sense for current uses.) + */ +void +DropSetting(Oid databaseid, Oid roleid) +{ + Relation relsetting; + TableScanDesc scan; + ScanKeyData keys[2]; + HeapTuple tup; + int numkeys = 0; + + relsetting = table_open(DbRoleSettingRelationId, RowExclusiveLock); + + if (OidIsValid(databaseid)) + { + ScanKeyInit(&keys[numkeys], + Anum_pg_db_role_setting_setdatabase, + BTEqualStrategyNumber, + F_OIDEQ, + ObjectIdGetDatum(databaseid)); + numkeys++; + } + if (OidIsValid(roleid)) + { + ScanKeyInit(&keys[numkeys], + Anum_pg_db_role_setting_setrole, + BTEqualStrategyNumber, + F_OIDEQ, + ObjectIdGetDatum(roleid)); + numkeys++; + } + + scan = table_beginscan_catalog(relsetting, numkeys, keys); + while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection))) + { + CatalogTupleDelete(relsetting, &tup->t_self); + } + table_endscan(scan); + + table_close(relsetting, RowExclusiveLock); +} + +/* + * Scan pg_db_role_setting looking for applicable settings, and load them on + * the current process. + * + * relsetting is pg_db_role_setting, already opened and locked. + * + * Note: we only consider setting for the exact databaseid/roleid combination. + * This probably needs to be called more than once, with InvalidOid passed as + * databaseid/roleid. + */ +void +ApplySetting(Snapshot snapshot, Oid databaseid, Oid roleid, + Relation relsetting, GucSource source) +{ + SysScanDesc scan; + ScanKeyData keys[2]; + HeapTuple tup; + + ScanKeyInit(&keys[0], + Anum_pg_db_role_setting_setdatabase, + BTEqualStrategyNumber, + F_OIDEQ, + ObjectIdGetDatum(databaseid)); + ScanKeyInit(&keys[1], + Anum_pg_db_role_setting_setrole, + BTEqualStrategyNumber, + F_OIDEQ, + ObjectIdGetDatum(roleid)); + + scan = systable_beginscan(relsetting, DbRoleSettingDatidRolidIndexId, true, + snapshot, 2, keys); + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + bool isnull; + Datum datum; + + datum = heap_getattr(tup, Anum_pg_db_role_setting_setconfig, + RelationGetDescr(relsetting), &isnull); + if (!isnull) + { + ArrayType *a = DatumGetArrayTypeP(datum); + + /* + * We process all the options at SUSET level. We assume that the + * right to insert an option into pg_db_role_setting was checked + * when it was inserted. + */ + ProcessGUCArray(a, PGC_SUSET, source, GUC_ACTION_SET); + } + } + + systable_endscan(scan); +} diff --git a/src/backend/catalog/pg_db_role_setting_d.h b/src/backend/catalog/pg_db_role_setting_d.h new file mode 100644 index 0000000..b1414de --- /dev/null +++ b/src/backend/catalog/pg_db_role_setting_d.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * pg_db_role_setting_d.h + * Macro definitions for pg_db_role_setting + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_DB_ROLE_SETTING_D_H +#define PG_DB_ROLE_SETTING_D_H + +#define DbRoleSettingRelationId 2964 + +#define Anum_pg_db_role_setting_setdatabase 1 +#define Anum_pg_db_role_setting_setrole 2 +#define Anum_pg_db_role_setting_setconfig 3 + +#define Natts_pg_db_role_setting 3 + + +#endif /* PG_DB_ROLE_SETTING_D_H */ diff --git a/src/backend/catalog/pg_default_acl_d.h b/src/backend/catalog/pg_default_acl_d.h new file mode 100644 index 0000000..0ba9892 --- /dev/null +++ b/src/backend/catalog/pg_default_acl_d.h @@ -0,0 +1,44 @@ +/*------------------------------------------------------------------------- + * + * pg_default_acl_d.h + * Macro definitions for pg_default_acl + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_DEFAULT_ACL_D_H +#define PG_DEFAULT_ACL_D_H + +#define DefaultAclRelationId 826 + +#define Anum_pg_default_acl_oid 1 +#define Anum_pg_default_acl_defaclrole 2 +#define Anum_pg_default_acl_defaclnamespace 3 +#define Anum_pg_default_acl_defaclobjtype 4 +#define Anum_pg_default_acl_defaclacl 5 + +#define Natts_pg_default_acl 5 + + +/* + * Types of objects for which the user is allowed to specify default + * permissions through pg_default_acl. These codes are used in the + * defaclobjtype column. + */ +#define DEFACLOBJ_RELATION 'r' /* table, view */ +#define DEFACLOBJ_SEQUENCE 'S' /* sequence */ +#define DEFACLOBJ_FUNCTION 'f' /* function */ +#define DEFACLOBJ_TYPE 'T' /* type */ +#define DEFACLOBJ_NAMESPACE 'n' /* namespace */ + + +#endif /* PG_DEFAULT_ACL_D_H */ diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c new file mode 100644 index 0000000..21cfdca --- /dev/null +++ b/src/backend/catalog/pg_depend.c @@ -0,0 +1,1068 @@ +/*------------------------------------------------------------------------- + * + * pg_depend.c + * routines to support manipulation of the pg_depend relation + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/pg_depend.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/genam.h" +#include "access/htup_details.h" +#include "access/table.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/pg_constraint.h" +#include "catalog/pg_depend.h" +#include "catalog/pg_extension.h" +#include "commands/extension.h" +#include "miscadmin.h" +#include "utils/fmgroids.h" +#include "utils/lsyscache.h" +#include "utils/rel.h" + + +static bool isObjectPinned(const ObjectAddress *object, Relation rel); + + +/* + * Record a dependency between 2 objects via their respective objectAddress. + * The first argument is the dependent object, the second the one it + * references. + * + * This simply creates an entry in pg_depend, without any other processing. + */ +void +recordDependencyOn(const ObjectAddress *depender, + const ObjectAddress *referenced, + DependencyType behavior) +{ + recordMultipleDependencies(depender, referenced, 1, behavior); +} + +/* + * Record multiple dependencies (of the same kind) for a single dependent + * object. This has a little less overhead than recording each separately. + */ +void +recordMultipleDependencies(const ObjectAddress *depender, + const ObjectAddress *referenced, + int nreferenced, + DependencyType behavior) +{ + Relation dependDesc; + CatalogIndexState indstate; + HeapTuple tup; + int i; + bool nulls[Natts_pg_depend]; + Datum values[Natts_pg_depend]; + + if (nreferenced <= 0) + return; /* nothing to do */ + + /* + * During bootstrap, do nothing since pg_depend may not exist yet. initdb + * will fill in appropriate pg_depend entries after bootstrap. + */ + if (IsBootstrapProcessingMode()) + return; + + dependDesc = table_open(DependRelationId, RowExclusiveLock); + + /* Don't open indexes unless we need to make an update */ + indstate = NULL; + + memset(nulls, false, sizeof(nulls)); + + for (i = 0; i < nreferenced; i++, referenced++) + { + /* + * If the referenced object is pinned by the system, there's no real + * need to record dependencies on it. This saves lots of space in + * pg_depend, so it's worth the time taken to check. + */ + if (!isObjectPinned(referenced, dependDesc)) + { + /* + * Record the Dependency. Note we don't bother to check for + * duplicate dependencies; there's no harm in them. + */ + values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId); + values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId); + values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId); + + values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId); + values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId); + values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId); + + values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior); + + tup = heap_form_tuple(dependDesc->rd_att, values, nulls); + + /* fetch index info only when we know we need it */ + if (indstate == NULL) + indstate = CatalogOpenIndexes(dependDesc); + + CatalogTupleInsertWithInfo(dependDesc, tup, indstate); + + heap_freetuple(tup); + } + } + + if (indstate != NULL) + CatalogCloseIndexes(indstate); + + table_close(dependDesc, RowExclusiveLock); +} + +/* + * If we are executing a CREATE EXTENSION operation, mark the given object + * as being a member of the extension. Otherwise, do nothing. + * + * This must be called during creation of any user-definable object type + * that could be a member of an extension. + * + * If isReplace is true, the object already existed (or might have already + * existed), so we must check for a pre-existing extension membership entry. + * Passing false is a guarantee that the object is newly created, and so + * could not already be a member of any extension. + */ +void +recordDependencyOnCurrentExtension(const ObjectAddress *object, + bool isReplace) +{ + /* Only whole objects can be extension members */ + Assert(object->objectSubId == 0); + + if (creating_extension) + { + ObjectAddress extension; + + /* Only need to check for existing membership if isReplace */ + if (isReplace) + { + Oid oldext; + + oldext = getExtensionOfObject(object->classId, object->objectId); + if (OidIsValid(oldext)) + { + /* If already a member of this extension, nothing to do */ + if (oldext == CurrentExtensionObject) + return; + /* Already a member of some other extension, so reject */ + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("%s is already a member of extension \"%s\"", + getObjectDescription(object), + get_extension_name(oldext)))); + } + } + + /* OK, record it as a member of CurrentExtensionObject */ + extension.classId = ExtensionRelationId; + extension.objectId = CurrentExtensionObject; + extension.objectSubId = 0; + + recordDependencyOn(object, &extension, DEPENDENCY_EXTENSION); + } +} + +/* + * deleteDependencyRecordsFor -- delete all records with given depender + * classId/objectId. Returns the number of records deleted. + * + * This is used when redefining an existing object. Links leading to the + * object do not change, and links leading from it will be recreated + * (possibly with some differences from before). + * + * If skipExtensionDeps is true, we do not delete any dependencies that + * show that the given object is a member of an extension. This avoids + * needing a lot of extra logic to fetch and recreate that dependency. + */ +long +deleteDependencyRecordsFor(Oid classId, Oid objectId, + bool skipExtensionDeps) +{ + long count = 0; + Relation depRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + + depRel = table_open(DependRelationId, RowExclusiveLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_classid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(classId)); + ScanKeyInit(&key[1], + Anum_pg_depend_objid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objectId)); + + scan = systable_beginscan(depRel, DependDependerIndexId, true, + NULL, 2, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + if (skipExtensionDeps && + ((Form_pg_depend) GETSTRUCT(tup))->deptype == DEPENDENCY_EXTENSION) + continue; + + CatalogTupleDelete(depRel, &tup->t_self); + count++; + } + + systable_endscan(scan); + + table_close(depRel, RowExclusiveLock); + + return count; +} + +/* + * deleteDependencyRecordsForClass -- delete all records with given depender + * classId/objectId, dependee classId, and deptype. + * Returns the number of records deleted. + * + * This is a variant of deleteDependencyRecordsFor, useful when revoking + * an object property that is expressed by a dependency record (such as + * extension membership). + */ +long +deleteDependencyRecordsForClass(Oid classId, Oid objectId, + Oid refclassId, char deptype) +{ + long count = 0; + Relation depRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + + depRel = table_open(DependRelationId, RowExclusiveLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_classid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(classId)); + ScanKeyInit(&key[1], + Anum_pg_depend_objid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objectId)); + + scan = systable_beginscan(depRel, DependDependerIndexId, true, + NULL, 2, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup); + + if (depform->refclassid == refclassId && depform->deptype == deptype) + { + CatalogTupleDelete(depRel, &tup->t_self); + count++; + } + } + + systable_endscan(scan); + + table_close(depRel, RowExclusiveLock); + + return count; +} + +/* + * deleteDependencyRecordsForSpecific -- delete all records with given depender + * classId/objectId, dependee classId/objectId, of the given deptype. + * Returns the number of records deleted. + */ +long +deleteDependencyRecordsForSpecific(Oid classId, Oid objectId, char deptype, + Oid refclassId, Oid refobjectId) +{ + long count = 0; + Relation depRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + + depRel = table_open(DependRelationId, RowExclusiveLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_classid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(classId)); + ScanKeyInit(&key[1], + Anum_pg_depend_objid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objectId)); + + scan = systable_beginscan(depRel, DependDependerIndexId, true, + NULL, 2, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup); + + if (depform->refclassid == refclassId && + depform->refobjid == refobjectId && + depform->deptype == deptype) + { + CatalogTupleDelete(depRel, &tup->t_self); + count++; + } + } + + systable_endscan(scan); + + table_close(depRel, RowExclusiveLock); + + return count; +} + +/* + * Adjust dependency record(s) to point to a different object of the same type + * + * classId/objectId specify the referencing object. + * refClassId/oldRefObjectId specify the old referenced object. + * newRefObjectId is the new referenced object (must be of class refClassId). + * + * Note the lack of objsubid parameters. If there are subobject references + * they will all be readjusted. Also, there is an expectation that we are + * dealing with NORMAL dependencies: if we have to replace an (implicit) + * dependency on a pinned object with an explicit dependency on an unpinned + * one, the new one will be NORMAL. + * + * Returns the number of records updated -- zero indicates a problem. + */ +long +changeDependencyFor(Oid classId, Oid objectId, + Oid refClassId, Oid oldRefObjectId, + Oid newRefObjectId) +{ + long count = 0; + Relation depRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + ObjectAddress objAddr; + ObjectAddress depAddr; + bool oldIsPinned; + bool newIsPinned; + + depRel = table_open(DependRelationId, RowExclusiveLock); + + /* + * Check to see if either oldRefObjectId or newRefObjectId is pinned. + * Pinned objects should not have any dependency entries pointing to them, + * so in these cases we should add or remove a pg_depend entry, or do + * nothing at all, rather than update an entry as in the normal case. + */ + objAddr.classId = refClassId; + objAddr.objectId = oldRefObjectId; + objAddr.objectSubId = 0; + + oldIsPinned = isObjectPinned(&objAddr, depRel); + + objAddr.objectId = newRefObjectId; + + newIsPinned = isObjectPinned(&objAddr, depRel); + + if (oldIsPinned) + { + table_close(depRel, RowExclusiveLock); + + /* + * If both are pinned, we need do nothing. However, return 1 not 0, + * else callers will think this is an error case. + */ + if (newIsPinned) + return 1; + + /* + * There is no old dependency record, but we should insert a new one. + * Assume a normal dependency is wanted. + */ + depAddr.classId = classId; + depAddr.objectId = objectId; + depAddr.objectSubId = 0; + recordDependencyOn(&depAddr, &objAddr, DEPENDENCY_NORMAL); + + return 1; + } + + /* There should be existing dependency record(s), so search. */ + ScanKeyInit(&key[0], + Anum_pg_depend_classid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(classId)); + ScanKeyInit(&key[1], + Anum_pg_depend_objid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objectId)); + + scan = systable_beginscan(depRel, DependDependerIndexId, true, + NULL, 2, key); + + while (HeapTupleIsValid((tup = systable_getnext(scan)))) + { + Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup); + + if (depform->refclassid == refClassId && + depform->refobjid == oldRefObjectId) + { + if (newIsPinned) + CatalogTupleDelete(depRel, &tup->t_self); + else + { + /* make a modifiable copy */ + tup = heap_copytuple(tup); + depform = (Form_pg_depend) GETSTRUCT(tup); + + depform->refobjid = newRefObjectId; + + CatalogTupleUpdate(depRel, &tup->t_self, tup); + + heap_freetuple(tup); + } + + count++; + } + } + + systable_endscan(scan); + + table_close(depRel, RowExclusiveLock); + + return count; +} + +/* + * Adjust all dependency records to come from a different object of the same type + * + * classId/oldObjectId specify the old referencing object. + * newObjectId is the new referencing object (must be of class classId). + * + * Returns the number of records updated. + */ +long +changeDependenciesOf(Oid classId, Oid oldObjectId, + Oid newObjectId) +{ + long count = 0; + Relation depRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + + depRel = table_open(DependRelationId, RowExclusiveLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_classid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(classId)); + ScanKeyInit(&key[1], + Anum_pg_depend_objid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(oldObjectId)); + + scan = systable_beginscan(depRel, DependDependerIndexId, true, + NULL, 2, key); + + while (HeapTupleIsValid((tup = systable_getnext(scan)))) + { + Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup); + + /* make a modifiable copy */ + tup = heap_copytuple(tup); + depform = (Form_pg_depend) GETSTRUCT(tup); + + depform->objid = newObjectId; + + CatalogTupleUpdate(depRel, &tup->t_self, tup); + + heap_freetuple(tup); + + count++; + } + + systable_endscan(scan); + + table_close(depRel, RowExclusiveLock); + + return count; +} + +/* + * Adjust all dependency records to point to a different object of the same type + * + * refClassId/oldRefObjectId specify the old referenced object. + * newRefObjectId is the new referenced object (must be of class refClassId). + * + * Returns the number of records updated. + */ +long +changeDependenciesOn(Oid refClassId, Oid oldRefObjectId, + Oid newRefObjectId) +{ + long count = 0; + Relation depRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + ObjectAddress objAddr; + bool newIsPinned; + + depRel = table_open(DependRelationId, RowExclusiveLock); + + /* + * If oldRefObjectId is pinned, there won't be any dependency entries on + * it --- we can't cope in that case. (This isn't really worth expending + * code to fix, in current usage; it just means you can't rename stuff out + * of pg_catalog, which would likely be a bad move anyway.) + */ + objAddr.classId = refClassId; + objAddr.objectId = oldRefObjectId; + objAddr.objectSubId = 0; + + if (isObjectPinned(&objAddr, depRel)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot remove dependency on %s because it is a system object", + getObjectDescription(&objAddr)))); + + /* + * We can handle adding a dependency on something pinned, though, since + * that just means deleting the dependency entry. + */ + objAddr.objectId = newRefObjectId; + + newIsPinned = isObjectPinned(&objAddr, depRel); + + /* Now search for dependency records */ + ScanKeyInit(&key[0], + Anum_pg_depend_refclassid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(refClassId)); + ScanKeyInit(&key[1], + Anum_pg_depend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(oldRefObjectId)); + + scan = systable_beginscan(depRel, DependReferenceIndexId, true, + NULL, 2, key); + + while (HeapTupleIsValid((tup = systable_getnext(scan)))) + { + Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup); + + if (newIsPinned) + CatalogTupleDelete(depRel, &tup->t_self); + else + { + /* make a modifiable copy */ + tup = heap_copytuple(tup); + depform = (Form_pg_depend) GETSTRUCT(tup); + + depform->refobjid = newRefObjectId; + + CatalogTupleUpdate(depRel, &tup->t_self, tup); + + heap_freetuple(tup); + } + + count++; + } + + systable_endscan(scan); + + table_close(depRel, RowExclusiveLock); + + return count; +} + +/* + * isObjectPinned() + * + * Test if an object is required for basic database functionality. + * Caller must already have opened pg_depend. + * + * The passed subId, if any, is ignored; we assume that only whole objects + * are pinned (and that this implies pinning their components). + */ +static bool +isObjectPinned(const ObjectAddress *object, Relation rel) +{ + bool ret = false; + SysScanDesc scan; + HeapTuple tup; + ScanKeyData key[2]; + + ScanKeyInit(&key[0], + Anum_pg_depend_refclassid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->classId)); + + ScanKeyInit(&key[1], + Anum_pg_depend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + scan = systable_beginscan(rel, DependReferenceIndexId, true, + NULL, 2, key); + + /* + * Since we won't generate additional pg_depend entries for pinned + * objects, there can be at most one entry referencing a pinned object. + * Hence, it's sufficient to look at the first returned tuple; we don't + * need to loop. + */ + tup = systable_getnext(scan); + if (HeapTupleIsValid(tup)) + { + Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup); + + if (foundDep->deptype == DEPENDENCY_PIN) + ret = true; + } + + systable_endscan(scan); + + return ret; +} + + +/* + * Various special-purpose lookups and manipulations of pg_depend. + */ + + +/* + * Find the extension containing the specified object, if any + * + * Returns the OID of the extension, or InvalidOid if the object does not + * belong to any extension. + * + * Extension membership is marked by an EXTENSION dependency from the object + * to the extension. Note that the result will be indeterminate if pg_depend + * contains links from this object to more than one extension ... but that + * should never happen. + */ +Oid +getExtensionOfObject(Oid classId, Oid objectId) +{ + Oid result = InvalidOid; + Relation depRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + + depRel = table_open(DependRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_classid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(classId)); + ScanKeyInit(&key[1], + Anum_pg_depend_objid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objectId)); + + scan = systable_beginscan(depRel, DependDependerIndexId, true, + NULL, 2, key); + + while (HeapTupleIsValid((tup = systable_getnext(scan)))) + { + Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup); + + if (depform->refclassid == ExtensionRelationId && + depform->deptype == DEPENDENCY_EXTENSION) + { + result = depform->refobjid; + break; /* no need to keep scanning */ + } + } + + systable_endscan(scan); + + table_close(depRel, AccessShareLock); + + return result; +} + +/* + * Return (possibly NIL) list of extensions that the given object depends on + * in DEPENDENCY_AUTO_EXTENSION mode. + */ +List * +getAutoExtensionsOfObject(Oid classId, Oid objectId) +{ + List *result = NIL; + Relation depRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + + depRel = table_open(DependRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_classid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(classId)); + ScanKeyInit(&key[1], + Anum_pg_depend_objid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objectId)); + + scan = systable_beginscan(depRel, DependDependerIndexId, true, + NULL, 2, key); + + while (HeapTupleIsValid((tup = systable_getnext(scan)))) + { + Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup); + + if (depform->refclassid == ExtensionRelationId && + depform->deptype == DEPENDENCY_AUTO_EXTENSION) + result = lappend_oid(result, depform->refobjid); + } + + systable_endscan(scan); + + table_close(depRel, AccessShareLock); + + return result; +} + +/* + * Detect whether a sequence is marked as "owned" by a column + * + * An ownership marker is an AUTO or INTERNAL dependency from the sequence to the + * column. If we find one, store the identity of the owning column + * into *tableId and *colId and return true; else return false. + * + * Note: if there's more than one such pg_depend entry then you get + * a random one of them returned into the out parameters. This should + * not happen, though. + */ +bool +sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId) +{ + bool ret = false; + Relation depRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + + depRel = table_open(DependRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_classid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationRelationId)); + ScanKeyInit(&key[1], + Anum_pg_depend_objid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(seqId)); + + scan = systable_beginscan(depRel, DependDependerIndexId, true, + NULL, 2, key); + + while (HeapTupleIsValid((tup = systable_getnext(scan)))) + { + Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup); + + if (depform->refclassid == RelationRelationId && + depform->deptype == deptype) + { + *tableId = depform->refobjid; + *colId = depform->refobjsubid; + ret = true; + break; /* no need to keep scanning */ + } + } + + systable_endscan(scan); + + table_close(depRel, AccessShareLock); + + return ret; +} + +/* + * Collect a list of OIDs of all sequences owned by the specified relation, + * and column if specified. If deptype is not zero, then only find sequences + * with the specified dependency type. + */ +static List * +getOwnedSequences_internal(Oid relid, AttrNumber attnum, char deptype) +{ + List *result = NIL; + Relation depRel; + ScanKeyData key[3]; + SysScanDesc scan; + HeapTuple tup; + + depRel = table_open(DependRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_refclassid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationRelationId)); + ScanKeyInit(&key[1], + Anum_pg_depend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(relid)); + if (attnum) + ScanKeyInit(&key[2], + Anum_pg_depend_refobjsubid, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(attnum)); + + scan = systable_beginscan(depRel, DependReferenceIndexId, true, + NULL, attnum ? 3 : 2, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup); + + /* + * We assume any auto or internal dependency of a sequence on a column + * must be what we are looking for. (We need the relkind test because + * indexes can also have auto dependencies on columns.) + */ + if (deprec->classid == RelationRelationId && + deprec->objsubid == 0 && + deprec->refobjsubid != 0 && + (deprec->deptype == DEPENDENCY_AUTO || deprec->deptype == DEPENDENCY_INTERNAL) && + get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE) + { + if (!deptype || deprec->deptype == deptype) + result = lappend_oid(result, deprec->objid); + } + } + + systable_endscan(scan); + + table_close(depRel, AccessShareLock); + + return result; +} + +/* + * Collect a list of OIDs of all sequences owned (identity or serial) by the + * specified relation. + */ +List * +getOwnedSequences(Oid relid) +{ + return getOwnedSequences_internal(relid, 0, 0); +} + +/* + * Get owned identity sequence, error if not exactly one. + */ +Oid +getIdentitySequence(Oid relid, AttrNumber attnum, bool missing_ok) +{ + List *seqlist = getOwnedSequences_internal(relid, attnum, DEPENDENCY_INTERNAL); + + if (list_length(seqlist) > 1) + elog(ERROR, "more than one owned sequence found"); + else if (list_length(seqlist) < 1) + { + if (missing_ok) + return InvalidOid; + else + elog(ERROR, "no owned sequence found"); + } + + return linitial_oid(seqlist); +} + +/* + * get_constraint_index + * Given the OID of a unique, primary-key, or exclusion constraint, + * return the OID of the underlying index. + * + * Return InvalidOid if the index couldn't be found; this suggests the + * given OID is bogus, but we leave it to caller to decide what to do. + */ +Oid +get_constraint_index(Oid constraintId) +{ + Oid indexId = InvalidOid; + Relation depRel; + ScanKeyData key[3]; + SysScanDesc scan; + HeapTuple tup; + + /* Search the dependency table for the dependent index */ + depRel = table_open(DependRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_refclassid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(ConstraintRelationId)); + ScanKeyInit(&key[1], + Anum_pg_depend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(constraintId)); + ScanKeyInit(&key[2], + Anum_pg_depend_refobjsubid, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(0)); + + scan = systable_beginscan(depRel, DependReferenceIndexId, true, + NULL, 3, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup); + + /* + * We assume any internal dependency of an index on the constraint + * must be what we are looking for. + */ + if (deprec->classid == RelationRelationId && + deprec->objsubid == 0 && + deprec->deptype == DEPENDENCY_INTERNAL) + { + char relkind = get_rel_relkind(deprec->objid); + + /* + * This is pure paranoia; there shouldn't be any other relkinds + * dependent on a constraint. + */ + if (relkind != RELKIND_INDEX && + relkind != RELKIND_PARTITIONED_INDEX) + continue; + + indexId = deprec->objid; + break; + } + } + + systable_endscan(scan); + table_close(depRel, AccessShareLock); + + return indexId; +} + +/* + * get_index_constraint + * Given the OID of an index, return the OID of the owning unique, + * primary-key, or exclusion constraint, or InvalidOid if there + * is no owning constraint. + */ +Oid +get_index_constraint(Oid indexId) +{ + Oid constraintId = InvalidOid; + Relation depRel; + ScanKeyData key[3]; + SysScanDesc scan; + HeapTuple tup; + + /* Search the dependency table for the index */ + depRel = table_open(DependRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_classid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationRelationId)); + ScanKeyInit(&key[1], + Anum_pg_depend_objid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(indexId)); + ScanKeyInit(&key[2], + Anum_pg_depend_objsubid, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(0)); + + scan = systable_beginscan(depRel, DependDependerIndexId, true, + NULL, 3, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup); + + /* + * We assume any internal dependency on a constraint must be what we + * are looking for. + */ + if (deprec->refclassid == ConstraintRelationId && + deprec->refobjsubid == 0 && + deprec->deptype == DEPENDENCY_INTERNAL) + { + constraintId = deprec->refobjid; + break; + } + } + + systable_endscan(scan); + table_close(depRel, AccessShareLock); + + return constraintId; +} + +/* + * get_index_ref_constraints + * Given the OID of an index, return the OID of all foreign key + * constraints which reference the index. + */ +List * +get_index_ref_constraints(Oid indexId) +{ + List *result = NIL; + Relation depRel; + ScanKeyData key[3]; + SysScanDesc scan; + HeapTuple tup; + + /* Search the dependency table for the index */ + depRel = table_open(DependRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_refclassid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationRelationId)); + ScanKeyInit(&key[1], + Anum_pg_depend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(indexId)); + ScanKeyInit(&key[2], + Anum_pg_depend_refobjsubid, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(0)); + + scan = systable_beginscan(depRel, DependReferenceIndexId, true, + NULL, 3, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup); + + /* + * We assume any normal dependency from a constraint must be what we + * are looking for. + */ + if (deprec->classid == ConstraintRelationId && + deprec->objsubid == 0 && + deprec->deptype == DEPENDENCY_NORMAL) + { + result = lappend_oid(result, deprec->objid); + } + } + + systable_endscan(scan); + table_close(depRel, AccessShareLock); + + return result; +} diff --git a/src/backend/catalog/pg_depend_d.h b/src/backend/catalog/pg_depend_d.h new file mode 100644 index 0000000..c0bbe9a --- /dev/null +++ b/src/backend/catalog/pg_depend_d.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- + * + * pg_depend_d.h + * Macro definitions for pg_depend + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_DEPEND_D_H +#define PG_DEPEND_D_H + +#define DependRelationId 2608 + +#define Anum_pg_depend_classid 1 +#define Anum_pg_depend_objid 2 +#define Anum_pg_depend_objsubid 3 +#define Anum_pg_depend_refclassid 4 +#define Anum_pg_depend_refobjid 5 +#define Anum_pg_depend_refobjsubid 6 +#define Anum_pg_depend_deptype 7 + +#define Natts_pg_depend 7 + + +#endif /* PG_DEPEND_D_H */ diff --git a/src/backend/catalog/pg_description_d.h b/src/backend/catalog/pg_description_d.h new file mode 100644 index 0000000..583dc98 --- /dev/null +++ b/src/backend/catalog/pg_description_d.h @@ -0,0 +1,31 @@ +/*------------------------------------------------------------------------- + * + * pg_description_d.h + * Macro definitions for pg_description + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_DESCRIPTION_D_H +#define PG_DESCRIPTION_D_H + +#define DescriptionRelationId 2609 + +#define Anum_pg_description_objoid 1 +#define Anum_pg_description_classoid 2 +#define Anum_pg_description_objsubid 3 +#define Anum_pg_description_description 4 + +#define Natts_pg_description 4 + + +#endif /* PG_DESCRIPTION_D_H */ diff --git a/src/backend/catalog/pg_enum.c b/src/backend/catalog/pg_enum.c new file mode 100644 index 0000000..27e4100 --- /dev/null +++ b/src/backend/catalog/pg_enum.c @@ -0,0 +1,761 @@ +/*------------------------------------------------------------------------- + * + * pg_enum.c + * routines to support manipulation of the pg_enum relation + * + * Copyright (c) 2006-2020, PostgreSQL Global Development Group + * + * + * IDENTIFICATION + * src/backend/catalog/pg_enum.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/genam.h" +#include "access/htup_details.h" +#include "access/table.h" +#include "access/xact.h" +#include "catalog/binary_upgrade.h" +#include "catalog/catalog.h" +#include "catalog/indexing.h" +#include "catalog/pg_enum.h" +#include "catalog/pg_type.h" +#include "miscadmin.h" +#include "nodes/value.h" +#include "storage/lmgr.h" +#include "utils/builtins.h" +#include "utils/catcache.h" +#include "utils/fmgroids.h" +#include "utils/hsearch.h" +#include "utils/memutils.h" +#include "utils/syscache.h" + +/* Potentially set by pg_upgrade_support functions */ +Oid binary_upgrade_next_pg_enum_oid = InvalidOid; + +/* + * Hash table of enum value OIDs created during the current transaction by + * AddEnumLabel. We disallow using these values until the transaction is + * committed; otherwise, they might get into indexes where we can't clean + * them up, and then if the transaction rolls back we have a broken index. + * (See comments for check_safe_enum_use() in enum.c.) Values created by + * EnumValuesCreate are *not* blacklisted; we assume those are created during + * CREATE TYPE, so they can't go away unless the enum type itself does. + */ +static HTAB *enum_blacklist = NULL; + +static void RenumberEnumType(Relation pg_enum, HeapTuple *existing, int nelems); +static int sort_order_cmp(const void *p1, const void *p2); + + +/* + * EnumValuesCreate + * Create an entry in pg_enum for each of the supplied enum values. + * + * vals is a list of Value strings. + */ +void +EnumValuesCreate(Oid enumTypeOid, List *vals) +{ + Relation pg_enum; + NameData enumlabel; + Oid *oids; + int elemno, + num_elems; + Datum values[Natts_pg_enum]; + bool nulls[Natts_pg_enum]; + ListCell *lc; + HeapTuple tup; + + num_elems = list_length(vals); + + /* + * We do not bother to check the list of values for duplicates --- if you + * have any, you'll get a less-than-friendly unique-index violation. It is + * probably not worth trying harder. + */ + + pg_enum = table_open(EnumRelationId, RowExclusiveLock); + + /* + * Allocate OIDs for the enum's members. + * + * While this method does not absolutely guarantee that we generate no + * duplicate OIDs (since we haven't entered each oid into the table before + * allocating the next), trouble could only occur if the OID counter wraps + * all the way around before we finish. Which seems unlikely. + */ + oids = (Oid *) palloc(num_elems * sizeof(Oid)); + + for (elemno = 0; elemno < num_elems; elemno++) + { + /* + * We assign even-numbered OIDs to all the new enum labels. This + * tells the comparison functions the OIDs are in the correct sort + * order and can be compared directly. + */ + Oid new_oid; + + do + { + new_oid = GetNewOidWithIndex(pg_enum, EnumOidIndexId, + Anum_pg_enum_oid); + } while (new_oid & 1); + oids[elemno] = new_oid; + } + + /* sort them, just in case OID counter wrapped from high to low */ + qsort(oids, num_elems, sizeof(Oid), oid_cmp); + + /* and make the entries */ + memset(nulls, false, sizeof(nulls)); + + elemno = 0; + foreach(lc, vals) + { + char *lab = strVal(lfirst(lc)); + + /* + * labels are stored in a name field, for easier syscache lookup, so + * check the length to make sure it's within range. + */ + if (strlen(lab) > (NAMEDATALEN - 1)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("invalid enum label \"%s\"", lab), + errdetail("Labels must be %d characters or less.", + NAMEDATALEN - 1))); + + values[Anum_pg_enum_oid - 1] = ObjectIdGetDatum(oids[elemno]); + values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid); + values[Anum_pg_enum_enumsortorder - 1] = Float4GetDatum(elemno + 1); + namestrcpy(&enumlabel, lab); + values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel); + + tup = heap_form_tuple(RelationGetDescr(pg_enum), values, nulls); + + CatalogTupleInsert(pg_enum, tup); + heap_freetuple(tup); + + elemno++; + } + + /* clean up */ + pfree(oids); + table_close(pg_enum, RowExclusiveLock); +} + + +/* + * EnumValuesDelete + * Remove all the pg_enum entries for the specified enum type. + */ +void +EnumValuesDelete(Oid enumTypeOid) +{ + Relation pg_enum; + ScanKeyData key[1]; + SysScanDesc scan; + HeapTuple tup; + + pg_enum = table_open(EnumRelationId, RowExclusiveLock); + + ScanKeyInit(&key[0], + Anum_pg_enum_enumtypid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(enumTypeOid)); + + scan = systable_beginscan(pg_enum, EnumTypIdLabelIndexId, true, + NULL, 1, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + CatalogTupleDelete(pg_enum, &tup->t_self); + } + + systable_endscan(scan); + + table_close(pg_enum, RowExclusiveLock); +} + +/* + * Initialize the enum blacklist for this transaction. + */ +static void +init_enum_blacklist(void) +{ + HASHCTL hash_ctl; + + memset(&hash_ctl, 0, sizeof(hash_ctl)); + hash_ctl.keysize = sizeof(Oid); + hash_ctl.entrysize = sizeof(Oid); + hash_ctl.hcxt = TopTransactionContext; + enum_blacklist = hash_create("Enum value blacklist", + 32, + &hash_ctl, + HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); +} + +/* + * AddEnumLabel + * Add a new label to the enum set. By default it goes at + * the end, but the user can choose to place it before or + * after any existing set member. + */ +void +AddEnumLabel(Oid enumTypeOid, + const char *newVal, + const char *neighbor, + bool newValIsAfter, + bool skipIfExists) +{ + Relation pg_enum; + Oid newOid; + Datum values[Natts_pg_enum]; + bool nulls[Natts_pg_enum]; + NameData enumlabel; + HeapTuple enum_tup; + float4 newelemorder; + HeapTuple *existing; + CatCList *list; + int nelems; + int i; + + /* check length of new label is ok */ + if (strlen(newVal) > (NAMEDATALEN - 1)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("invalid enum label \"%s\"", newVal), + errdetail("Labels must be %d characters or less.", + NAMEDATALEN - 1))); + + /* + * Acquire a lock on the enum type, which we won't release until commit. + * This ensures that two backends aren't concurrently modifying the same + * enum type. Without that, we couldn't be sure to get a consistent view + * of the enum members via the syscache. Note that this does not block + * other backends from inspecting the type; see comments for + * RenumberEnumType. + */ + LockDatabaseObject(TypeRelationId, enumTypeOid, 0, ExclusiveLock); + + /* + * Check if label is already in use. The unique index on pg_enum would + * catch this anyway, but we prefer a friendlier error message, and + * besides we need a check to support IF NOT EXISTS. + */ + enum_tup = SearchSysCache2(ENUMTYPOIDNAME, + ObjectIdGetDatum(enumTypeOid), + CStringGetDatum(newVal)); + if (HeapTupleIsValid(enum_tup)) + { + ReleaseSysCache(enum_tup); + if (skipIfExists) + { + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("enum label \"%s\" already exists, skipping", + newVal))); + return; + } + else + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("enum label \"%s\" already exists", + newVal))); + } + + pg_enum = table_open(EnumRelationId, RowExclusiveLock); + + /* If we have to renumber the existing members, we restart from here */ +restart: + + /* Get the list of existing members of the enum */ + list = SearchSysCacheList1(ENUMTYPOIDNAME, + ObjectIdGetDatum(enumTypeOid)); + nelems = list->n_members; + + /* Sort the existing members by enumsortorder */ + existing = (HeapTuple *) palloc(nelems * sizeof(HeapTuple)); + for (i = 0; i < nelems; i++) + existing[i] = &(list->members[i]->tuple); + + qsort(existing, nelems, sizeof(HeapTuple), sort_order_cmp); + + if (neighbor == NULL) + { + /* + * Put the new label at the end of the list. No change to existing + * tuples is required. + */ + if (nelems > 0) + { + Form_pg_enum en = (Form_pg_enum) GETSTRUCT(existing[nelems - 1]); + + newelemorder = en->enumsortorder + 1; + } + else + newelemorder = 1; + } + else + { + /* BEFORE or AFTER was specified */ + int nbr_index; + int other_nbr_index; + Form_pg_enum nbr_en; + Form_pg_enum other_nbr_en; + + /* Locate the neighbor element */ + for (nbr_index = 0; nbr_index < nelems; nbr_index++) + { + Form_pg_enum en = (Form_pg_enum) GETSTRUCT(existing[nbr_index]); + + if (strcmp(NameStr(en->enumlabel), neighbor) == 0) + break; + } + if (nbr_index >= nelems) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("\"%s\" is not an existing enum label", + neighbor))); + nbr_en = (Form_pg_enum) GETSTRUCT(existing[nbr_index]); + + /* + * Attempt to assign an appropriate enumsortorder value: one less than + * the smallest member, one more than the largest member, or halfway + * between two existing members. + * + * In the "halfway" case, because of the finite precision of float4, + * we might compute a value that's actually equal to one or the other + * of its neighbors. In that case we renumber the existing members + * and try again. + */ + if (newValIsAfter) + other_nbr_index = nbr_index + 1; + else + other_nbr_index = nbr_index - 1; + + if (other_nbr_index < 0) + newelemorder = nbr_en->enumsortorder - 1; + else if (other_nbr_index >= nelems) + newelemorder = nbr_en->enumsortorder + 1; + else + { + /* + * The midpoint value computed here has to be rounded to float4 + * precision, else our equality comparisons against the adjacent + * values are meaningless. The most portable way of forcing that + * to happen with non-C-standard-compliant compilers is to store + * it into a volatile variable. + */ + volatile float4 midpoint; + + other_nbr_en = (Form_pg_enum) GETSTRUCT(existing[other_nbr_index]); + midpoint = (nbr_en->enumsortorder + + other_nbr_en->enumsortorder) / 2; + + if (midpoint == nbr_en->enumsortorder || + midpoint == other_nbr_en->enumsortorder) + { + RenumberEnumType(pg_enum, existing, nelems); + /* Clean up and start over */ + pfree(existing); + ReleaseCatCacheList(list); + goto restart; + } + + newelemorder = midpoint; + } + } + + /* Get a new OID for the new label */ + if (IsBinaryUpgrade) + { + if (!OidIsValid(binary_upgrade_next_pg_enum_oid)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("pg_enum OID value not set when in binary upgrade mode"))); + + /* + * Use binary-upgrade override for pg_enum.oid, if supplied. During + * binary upgrade, all pg_enum.oid's are set this way so they are + * guaranteed to be consistent. + */ + if (neighbor != NULL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("ALTER TYPE ADD BEFORE/AFTER is incompatible with binary upgrade"))); + + newOid = binary_upgrade_next_pg_enum_oid; + binary_upgrade_next_pg_enum_oid = InvalidOid; + } + else + { + /* + * Normal case: we need to allocate a new Oid for the value. + * + * We want to give the new element an even-numbered Oid if it's safe, + * which is to say it compares correctly to all pre-existing even + * numbered Oids in the enum. Otherwise, we must give it an odd Oid. + */ + for (;;) + { + bool sorts_ok; + + /* Get a new OID (different from all existing pg_enum tuples) */ + newOid = GetNewOidWithIndex(pg_enum, EnumOidIndexId, + Anum_pg_enum_oid); + + /* + * Detect whether it sorts correctly relative to existing + * even-numbered labels of the enum. We can ignore existing + * labels with odd Oids, since a comparison involving one of those + * will not take the fast path anyway. + */ + sorts_ok = true; + for (i = 0; i < nelems; i++) + { + HeapTuple exists_tup = existing[i]; + Form_pg_enum exists_en = (Form_pg_enum) GETSTRUCT(exists_tup); + Oid exists_oid = exists_en->oid; + + if (exists_oid & 1) + continue; /* ignore odd Oids */ + + if (exists_en->enumsortorder < newelemorder) + { + /* should sort before */ + if (exists_oid >= newOid) + { + sorts_ok = false; + break; + } + } + else + { + /* should sort after */ + if (exists_oid <= newOid) + { + sorts_ok = false; + break; + } + } + } + + if (sorts_ok) + { + /* If it's even and sorts OK, we're done. */ + if ((newOid & 1) == 0) + break; + + /* + * If it's odd, and sorts OK, loop back to get another OID and + * try again. Probably, the next available even OID will sort + * correctly too, so it's worth trying. + */ + } + else + { + /* + * If it's odd, and does not sort correctly, we're done. + * (Probably, the next available even OID would sort + * incorrectly too, so no point in trying again.) + */ + if (newOid & 1) + break; + + /* + * If it's even, and does not sort correctly, loop back to get + * another OID and try again. (We *must* reject this case.) + */ + } + } + } + + /* Done with info about existing members */ + pfree(existing); + ReleaseCatCacheList(list); + + /* Create the new pg_enum entry */ + memset(nulls, false, sizeof(nulls)); + values[Anum_pg_enum_oid - 1] = ObjectIdGetDatum(newOid); + values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid); + values[Anum_pg_enum_enumsortorder - 1] = Float4GetDatum(newelemorder); + namestrcpy(&enumlabel, newVal); + values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel); + enum_tup = heap_form_tuple(RelationGetDescr(pg_enum), values, nulls); + CatalogTupleInsert(pg_enum, enum_tup); + heap_freetuple(enum_tup); + + table_close(pg_enum, RowExclusiveLock); + + /* Set up the blacklist hash if not already done in this transaction */ + if (enum_blacklist == NULL) + init_enum_blacklist(); + + /* Add the new value to the blacklist */ + (void) hash_search(enum_blacklist, &newOid, HASH_ENTER, NULL); +} + + +/* + * RenameEnumLabel + * Rename a label in an enum set. + */ +void +RenameEnumLabel(Oid enumTypeOid, + const char *oldVal, + const char *newVal) +{ + Relation pg_enum; + HeapTuple enum_tup; + Form_pg_enum en; + CatCList *list; + int nelems; + HeapTuple old_tup; + bool found_new; + int i; + + /* check length of new label is ok */ + if (strlen(newVal) > (NAMEDATALEN - 1)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("invalid enum label \"%s\"", newVal), + errdetail("Labels must be %d characters or less.", + NAMEDATALEN - 1))); + + /* + * Acquire a lock on the enum type, which we won't release until commit. + * This ensures that two backends aren't concurrently modifying the same + * enum type. Since we are not changing the type's sort order, this is + * probably not really necessary, but there seems no reason not to take + * the lock to be sure. + */ + LockDatabaseObject(TypeRelationId, enumTypeOid, 0, ExclusiveLock); + + pg_enum = table_open(EnumRelationId, RowExclusiveLock); + + /* Get the list of existing members of the enum */ + list = SearchSysCacheList1(ENUMTYPOIDNAME, + ObjectIdGetDatum(enumTypeOid)); + nelems = list->n_members; + + /* + * Locate the element to rename and check if the new label is already in + * use. (The unique index on pg_enum would catch that anyway, but we + * prefer a friendlier error message.) + */ + old_tup = NULL; + found_new = false; + for (i = 0; i < nelems; i++) + { + enum_tup = &(list->members[i]->tuple); + en = (Form_pg_enum) GETSTRUCT(enum_tup); + if (strcmp(NameStr(en->enumlabel), oldVal) == 0) + old_tup = enum_tup; + if (strcmp(NameStr(en->enumlabel), newVal) == 0) + found_new = true; + } + if (!old_tup) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("\"%s\" is not an existing enum label", + oldVal))); + if (found_new) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("enum label \"%s\" already exists", + newVal))); + + /* OK, make a writable copy of old tuple */ + enum_tup = heap_copytuple(old_tup); + en = (Form_pg_enum) GETSTRUCT(enum_tup); + + ReleaseCatCacheList(list); + + /* Update the pg_enum entry */ + namestrcpy(&en->enumlabel, newVal); + CatalogTupleUpdate(pg_enum, &enum_tup->t_self, enum_tup); + heap_freetuple(enum_tup); + + table_close(pg_enum, RowExclusiveLock); +} + + +/* + * Test if the given enum value is on the blacklist + */ +bool +EnumBlacklisted(Oid enum_id) +{ + bool found; + + /* If we've made no blacklist table, all values are safe */ + if (enum_blacklist == NULL) + return false; + + /* Else, is it in the table? */ + (void) hash_search(enum_blacklist, &enum_id, HASH_FIND, &found); + return found; +} + + +/* + * Clean up enum stuff after end of top-level transaction. + */ +void +AtEOXact_Enum(void) +{ + /* + * Reset the blacklist table, as all our enum values are now committed. + * The memory will go away automatically when TopTransactionContext is + * freed; it's sufficient to clear our pointer. + */ + enum_blacklist = NULL; +} + + +/* + * RenumberEnumType + * Renumber existing enum elements to have sort positions 1..n. + * + * We avoid doing this unless absolutely necessary; in most installations + * it will never happen. The reason is that updating existing pg_enum + * entries creates hazards for other backends that are concurrently reading + * pg_enum. Although system catalog scans now use MVCC semantics, the + * syscache machinery might read different pg_enum entries under different + * snapshots, so some other backend might get confused about the proper + * ordering if a concurrent renumbering occurs. + * + * We therefore make the following choices: + * + * 1. Any code that is interested in the enumsortorder values MUST read + * all the relevant pg_enum entries with a single MVCC snapshot, or else + * acquire lock on the enum type to prevent concurrent execution of + * AddEnumLabel(). + * + * 2. Code that is not examining enumsortorder can use a syscache + * (for example, enum_in and enum_out do so). + */ +static void +RenumberEnumType(Relation pg_enum, HeapTuple *existing, int nelems) +{ + int i; + + /* + * We should only need to increase existing elements' enumsortorders, + * never decrease them. Therefore, work from the end backwards, to avoid + * unwanted uniqueness violations. + */ + for (i = nelems - 1; i >= 0; i--) + { + HeapTuple newtup; + Form_pg_enum en; + float4 newsortorder; + + newtup = heap_copytuple(existing[i]); + en = (Form_pg_enum) GETSTRUCT(newtup); + + newsortorder = i + 1; + if (en->enumsortorder != newsortorder) + { + en->enumsortorder = newsortorder; + + CatalogTupleUpdate(pg_enum, &newtup->t_self, newtup); + } + + heap_freetuple(newtup); + } + + /* Make the updates visible */ + CommandCounterIncrement(); +} + + +/* qsort comparison function for tuples by sort order */ +static int +sort_order_cmp(const void *p1, const void *p2) +{ + HeapTuple v1 = *((const HeapTuple *) p1); + HeapTuple v2 = *((const HeapTuple *) p2); + Form_pg_enum en1 = (Form_pg_enum) GETSTRUCT(v1); + Form_pg_enum en2 = (Form_pg_enum) GETSTRUCT(v2); + + if (en1->enumsortorder < en2->enumsortorder) + return -1; + else if (en1->enumsortorder > en2->enumsortorder) + return 1; + else + return 0; +} + +Size +EstimateEnumBlacklistSpace(void) +{ + size_t entries; + + if (enum_blacklist) + entries = hash_get_num_entries(enum_blacklist); + else + entries = 0; + + /* Add one for the terminator. */ + return sizeof(Oid) * (entries + 1); +} + +void +SerializeEnumBlacklist(void *space, Size size) +{ + Oid *serialized = (Oid *) space; + + /* + * Make sure the hash table hasn't changed in size since the caller + * reserved the space. + */ + Assert(size == EstimateEnumBlacklistSpace()); + + /* Write out all the values from the hash table, if there is one. */ + if (enum_blacklist) + { + HASH_SEQ_STATUS status; + Oid *value; + + hash_seq_init(&status, enum_blacklist); + while ((value = (Oid *) hash_seq_search(&status))) + *serialized++ = *value; + } + + /* Write out the terminator. */ + *serialized = InvalidOid; + + /* + * Make sure the amount of space we actually used matches what was + * estimated. + */ + Assert((char *) (serialized + 1) == ((char *) space) + size); +} + +void +RestoreEnumBlacklist(void *space) +{ + Oid *serialized = (Oid *) space; + + Assert(!enum_blacklist); + + /* + * As a special case, if the list is empty then don't even bother to + * create the hash table. This is the usual case, since enum alteration + * is expected to be rare. + */ + if (!OidIsValid(*serialized)) + return; + + /* Read all the values into a new hash table. */ + init_enum_blacklist(); + do + { + hash_search(enum_blacklist, serialized++, HASH_ENTER, NULL); + } while (OidIsValid(*serialized)); +} diff --git a/src/backend/catalog/pg_enum_d.h b/src/backend/catalog/pg_enum_d.h new file mode 100644 index 0000000..cda305a --- /dev/null +++ b/src/backend/catalog/pg_enum_d.h @@ -0,0 +1,31 @@ +/*------------------------------------------------------------------------- + * + * pg_enum_d.h + * Macro definitions for pg_enum + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_ENUM_D_H +#define PG_ENUM_D_H + +#define EnumRelationId 3501 + +#define Anum_pg_enum_oid 1 +#define Anum_pg_enum_enumtypid 2 +#define Anum_pg_enum_enumsortorder 3 +#define Anum_pg_enum_enumlabel 4 + +#define Natts_pg_enum 4 + + +#endif /* PG_ENUM_D_H */ diff --git a/src/backend/catalog/pg_event_trigger_d.h b/src/backend/catalog/pg_event_trigger_d.h new file mode 100644 index 0000000..aa8aaa2 --- /dev/null +++ b/src/backend/catalog/pg_event_trigger_d.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- + * + * pg_event_trigger_d.h + * Macro definitions for pg_event_trigger + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_EVENT_TRIGGER_D_H +#define PG_EVENT_TRIGGER_D_H + +#define EventTriggerRelationId 3466 + +#define Anum_pg_event_trigger_oid 1 +#define Anum_pg_event_trigger_evtname 2 +#define Anum_pg_event_trigger_evtevent 3 +#define Anum_pg_event_trigger_evtowner 4 +#define Anum_pg_event_trigger_evtfoid 5 +#define Anum_pg_event_trigger_evtenabled 6 +#define Anum_pg_event_trigger_evttags 7 + +#define Natts_pg_event_trigger 7 + + +#endif /* PG_EVENT_TRIGGER_D_H */ diff --git a/src/backend/catalog/pg_extension_d.h b/src/backend/catalog/pg_extension_d.h new file mode 100644 index 0000000..fe36244 --- /dev/null +++ b/src/backend/catalog/pg_extension_d.h @@ -0,0 +1,35 @@ +/*------------------------------------------------------------------------- + * + * pg_extension_d.h + * Macro definitions for pg_extension + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_EXTENSION_D_H +#define PG_EXTENSION_D_H + +#define ExtensionRelationId 3079 + +#define Anum_pg_extension_oid 1 +#define Anum_pg_extension_extname 2 +#define Anum_pg_extension_extowner 3 +#define Anum_pg_extension_extnamespace 4 +#define Anum_pg_extension_extrelocatable 5 +#define Anum_pg_extension_extversion 6 +#define Anum_pg_extension_extconfig 7 +#define Anum_pg_extension_extcondition 8 + +#define Natts_pg_extension 8 + + +#endif /* PG_EXTENSION_D_H */ diff --git a/src/backend/catalog/pg_foreign_data_wrapper_d.h b/src/backend/catalog/pg_foreign_data_wrapper_d.h new file mode 100644 index 0000000..7921677 --- /dev/null +++ b/src/backend/catalog/pg_foreign_data_wrapper_d.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- + * + * pg_foreign_data_wrapper_d.h + * Macro definitions for pg_foreign_data_wrapper + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_FOREIGN_DATA_WRAPPER_D_H +#define PG_FOREIGN_DATA_WRAPPER_D_H + +#define ForeignDataWrapperRelationId 2328 + +#define Anum_pg_foreign_data_wrapper_oid 1 +#define Anum_pg_foreign_data_wrapper_fdwname 2 +#define Anum_pg_foreign_data_wrapper_fdwowner 3 +#define Anum_pg_foreign_data_wrapper_fdwhandler 4 +#define Anum_pg_foreign_data_wrapper_fdwvalidator 5 +#define Anum_pg_foreign_data_wrapper_fdwacl 6 +#define Anum_pg_foreign_data_wrapper_fdwoptions 7 + +#define Natts_pg_foreign_data_wrapper 7 + + +#endif /* PG_FOREIGN_DATA_WRAPPER_D_H */ diff --git a/src/backend/catalog/pg_foreign_server_d.h b/src/backend/catalog/pg_foreign_server_d.h new file mode 100644 index 0000000..7164795 --- /dev/null +++ b/src/backend/catalog/pg_foreign_server_d.h @@ -0,0 +1,35 @@ +/*------------------------------------------------------------------------- + * + * pg_foreign_server_d.h + * Macro definitions for pg_foreign_server + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_FOREIGN_SERVER_D_H +#define PG_FOREIGN_SERVER_D_H + +#define ForeignServerRelationId 1417 + +#define Anum_pg_foreign_server_oid 1 +#define Anum_pg_foreign_server_srvname 2 +#define Anum_pg_foreign_server_srvowner 3 +#define Anum_pg_foreign_server_srvfdw 4 +#define Anum_pg_foreign_server_srvtype 5 +#define Anum_pg_foreign_server_srvversion 6 +#define Anum_pg_foreign_server_srvacl 7 +#define Anum_pg_foreign_server_srvoptions 8 + +#define Natts_pg_foreign_server 8 + + +#endif /* PG_FOREIGN_SERVER_D_H */ diff --git a/src/backend/catalog/pg_foreign_table_d.h b/src/backend/catalog/pg_foreign_table_d.h new file mode 100644 index 0000000..2638228 --- /dev/null +++ b/src/backend/catalog/pg_foreign_table_d.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * pg_foreign_table_d.h + * Macro definitions for pg_foreign_table + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_FOREIGN_TABLE_D_H +#define PG_FOREIGN_TABLE_D_H + +#define ForeignTableRelationId 3118 + +#define Anum_pg_foreign_table_ftrelid 1 +#define Anum_pg_foreign_table_ftserver 2 +#define Anum_pg_foreign_table_ftoptions 3 + +#define Natts_pg_foreign_table 3 + + +#endif /* PG_FOREIGN_TABLE_D_H */ diff --git a/src/backend/catalog/pg_index_d.h b/src/backend/catalog/pg_index_d.h new file mode 100644 index 0000000..80835e7 --- /dev/null +++ b/src/backend/catalog/pg_index_d.h @@ -0,0 +1,56 @@ +/*------------------------------------------------------------------------- + * + * pg_index_d.h + * Macro definitions for pg_index + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_INDEX_D_H +#define PG_INDEX_D_H + +#define IndexRelationId 2610 + +#define Anum_pg_index_indexrelid 1 +#define Anum_pg_index_indrelid 2 +#define Anum_pg_index_indnatts 3 +#define Anum_pg_index_indnkeyatts 4 +#define Anum_pg_index_indisunique 5 +#define Anum_pg_index_indisprimary 6 +#define Anum_pg_index_indisexclusion 7 +#define Anum_pg_index_indimmediate 8 +#define Anum_pg_index_indisclustered 9 +#define Anum_pg_index_indisvalid 10 +#define Anum_pg_index_indcheckxmin 11 +#define Anum_pg_index_indisready 12 +#define Anum_pg_index_indislive 13 +#define Anum_pg_index_indisreplident 14 +#define Anum_pg_index_indkey 15 +#define Anum_pg_index_indcollation 16 +#define Anum_pg_index_indclass 17 +#define Anum_pg_index_indoption 18 +#define Anum_pg_index_indexprs 19 +#define Anum_pg_index_indpred 20 + +#define Natts_pg_index 20 + + +/* + * Index AMs that support ordered scans must support these two indoption + * bits. Otherwise, the content of the per-column indoption fields is + * open for future definition. + */ +#define INDOPTION_DESC 0x0001 /* values are in reverse order */ +#define INDOPTION_NULLS_FIRST 0x0002 /* NULLs are first instead of last */ + + +#endif /* PG_INDEX_D_H */ diff --git a/src/backend/catalog/pg_inherits.c b/src/backend/catalog/pg_inherits.c new file mode 100644 index 0000000..5145a56 --- /dev/null +++ b/src/backend/catalog/pg_inherits.c @@ -0,0 +1,493 @@ +/*------------------------------------------------------------------------- + * + * pg_inherits.c + * routines to support manipulation of the pg_inherits relation + * + * Note: currently, this module mostly contains inquiry functions; actual + * creation and deletion of pg_inherits entries is mostly done in tablecmds.c. + * Perhaps someday that code should be moved here, but it'd have to be + * disentangled from other stuff such as pg_depend updates. + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/pg_inherits.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/genam.h" +#include "access/htup_details.h" +#include "access/table.h" +#include "catalog/indexing.h" +#include "catalog/pg_inherits.h" +#include "parser/parse_type.h" +#include "storage/lmgr.h" +#include "utils/builtins.h" +#include "utils/fmgroids.h" +#include "utils/memutils.h" +#include "utils/syscache.h" + +/* + * Entry of a hash table used in find_all_inheritors. See below. + */ +typedef struct SeenRelsEntry +{ + Oid rel_id; /* relation oid */ + int list_index; /* its position in output list(s) */ +} SeenRelsEntry; + +/* + * find_inheritance_children + * + * Returns a list containing the OIDs of all relations which + * inherit *directly* from the relation with OID 'parentrelId'. + * + * The specified lock type is acquired on each child relation (but not on the + * given rel; caller should already have locked it). If lockmode is NoLock + * then no locks are acquired, but caller must beware of race conditions + * against possible DROPs of child relations. + */ +List * +find_inheritance_children(Oid parentrelId, LOCKMODE lockmode) +{ + List *list = NIL; + Relation relation; + SysScanDesc scan; + ScanKeyData key[1]; + HeapTuple inheritsTuple; + Oid inhrelid; + Oid *oidarr; + int maxoids, + numoids, + i; + + /* + * Can skip the scan if pg_class shows the relation has never had a + * subclass. + */ + if (!has_subclass(parentrelId)) + return NIL; + + /* + * Scan pg_inherits and build a working array of subclass OIDs. + */ + maxoids = 32; + oidarr = (Oid *) palloc(maxoids * sizeof(Oid)); + numoids = 0; + + relation = table_open(InheritsRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_inherits_inhparent, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(parentrelId)); + + scan = systable_beginscan(relation, InheritsParentIndexId, true, + NULL, 1, key); + + while ((inheritsTuple = systable_getnext(scan)) != NULL) + { + inhrelid = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhrelid; + if (numoids >= maxoids) + { + maxoids *= 2; + oidarr = (Oid *) repalloc(oidarr, maxoids * sizeof(Oid)); + } + oidarr[numoids++] = inhrelid; + } + + systable_endscan(scan); + + table_close(relation, AccessShareLock); + + /* + * If we found more than one child, sort them by OID. This ensures + * reasonably consistent behavior regardless of the vagaries of an + * indexscan. This is important since we need to be sure all backends + * lock children in the same order to avoid needless deadlocks. + */ + if (numoids > 1) + qsort(oidarr, numoids, sizeof(Oid), oid_cmp); + + /* + * Acquire locks and build the result list. + */ + for (i = 0; i < numoids; i++) + { + inhrelid = oidarr[i]; + + if (lockmode != NoLock) + { + /* Get the lock to synchronize against concurrent drop */ + LockRelationOid(inhrelid, lockmode); + + /* + * Now that we have the lock, double-check to see if the relation + * really exists or not. If not, assume it was dropped while we + * waited to acquire lock, and ignore it. + */ + if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(inhrelid))) + { + /* Release useless lock */ + UnlockRelationOid(inhrelid, lockmode); + /* And ignore this relation */ + continue; + } + } + + list = lappend_oid(list, inhrelid); + } + + pfree(oidarr); + + return list; +} + + +/* + * find_all_inheritors - + * Returns a list of relation OIDs including the given rel plus + * all relations that inherit from it, directly or indirectly. + * Optionally, it also returns the number of parents found for + * each such relation within the inheritance tree rooted at the + * given rel. + * + * The specified lock type is acquired on all child relations (but not on the + * given rel; caller should already have locked it). If lockmode is NoLock + * then no locks are acquired, but caller must beware of race conditions + * against possible DROPs of child relations. + */ +List * +find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents) +{ + /* hash table for O(1) rel_oid -> rel_numparents cell lookup */ + HTAB *seen_rels; + HASHCTL ctl; + List *rels_list, + *rel_numparents; + ListCell *l; + + memset(&ctl, 0, sizeof(ctl)); + ctl.keysize = sizeof(Oid); + ctl.entrysize = sizeof(SeenRelsEntry); + ctl.hcxt = CurrentMemoryContext; + + seen_rels = hash_create("find_all_inheritors temporary table", + 32, /* start small and extend */ + &ctl, + HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); + + /* + * We build a list starting with the given rel and adding all direct and + * indirect children. We can use a single list as both the record of + * already-found rels and the agenda of rels yet to be scanned for more + * children. This is a bit tricky but works because the foreach() macro + * doesn't fetch the next list element until the bottom of the loop. Note + * that we can't keep pointers into the output lists; but an index is + * sufficient. + */ + rels_list = list_make1_oid(parentrelId); + rel_numparents = list_make1_int(0); + + foreach(l, rels_list) + { + Oid currentrel = lfirst_oid(l); + List *currentchildren; + ListCell *lc; + + /* Get the direct children of this rel */ + currentchildren = find_inheritance_children(currentrel, lockmode); + + /* + * Add to the queue only those children not already seen. This avoids + * making duplicate entries in case of multiple inheritance paths from + * the same parent. (It'll also keep us from getting into an infinite + * loop, though theoretically there can't be any cycles in the + * inheritance graph anyway.) + */ + foreach(lc, currentchildren) + { + Oid child_oid = lfirst_oid(lc); + bool found; + SeenRelsEntry *hash_entry; + + hash_entry = hash_search(seen_rels, &child_oid, HASH_ENTER, &found); + if (found) + { + /* if the rel is already there, bump number-of-parents counter */ + ListCell *numparents_cell; + + numparents_cell = list_nth_cell(rel_numparents, + hash_entry->list_index); + lfirst_int(numparents_cell)++; + } + else + { + /* if it's not there, add it. expect 1 parent, initially. */ + hash_entry->list_index = list_length(rels_list); + rels_list = lappend_oid(rels_list, child_oid); + rel_numparents = lappend_int(rel_numparents, 1); + } + } + } + + if (numparents) + *numparents = rel_numparents; + else + list_free(rel_numparents); + + hash_destroy(seen_rels); + + return rels_list; +} + + +/* + * has_subclass - does this relation have any children? + * + * In the current implementation, has_subclass returns whether a + * particular class *might* have a subclass. It will not return the + * correct result if a class had a subclass which was later dropped. + * This is because relhassubclass in pg_class is not updated immediately + * when a subclass is dropped, primarily because of concurrency concerns. + * + * Currently has_subclass is only used as an efficiency hack to skip + * unnecessary inheritance searches, so this is OK. Note that ANALYZE + * on a childless table will clean up the obsolete relhassubclass flag. + * + * Although this doesn't actually touch pg_inherits, it seems reasonable + * to keep it here since it's normally used with the other routines here. + */ +bool +has_subclass(Oid relationId) +{ + HeapTuple tuple; + bool result; + + tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationId)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", relationId); + + result = ((Form_pg_class) GETSTRUCT(tuple))->relhassubclass; + ReleaseSysCache(tuple); + return result; +} + +/* + * has_superclass - does this relation inherit from another? + * + * Unlike has_subclass, this can be relied on to give an accurate answer. + * However, the caller must hold a lock on the given relation so that it + * can't be concurrently added to or removed from an inheritance hierarchy. + */ +bool +has_superclass(Oid relationId) +{ + Relation catalog; + SysScanDesc scan; + ScanKeyData skey; + bool result; + + catalog = table_open(InheritsRelationId, AccessShareLock); + ScanKeyInit(&skey, Anum_pg_inherits_inhrelid, BTEqualStrategyNumber, + F_OIDEQ, ObjectIdGetDatum(relationId)); + scan = systable_beginscan(catalog, InheritsRelidSeqnoIndexId, true, + NULL, 1, &skey); + result = HeapTupleIsValid(systable_getnext(scan)); + systable_endscan(scan); + table_close(catalog, AccessShareLock); + + return result; +} + +/* + * Given two type OIDs, determine whether the first is a complex type + * (class type) that inherits from the second. + * + * This essentially asks whether the first type is guaranteed to be coercible + * to the second. Therefore, we allow the first type to be a domain over a + * complex type that inherits from the second; that creates no difficulties. + * But the second type cannot be a domain. + */ +bool +typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId) +{ + bool result = false; + Oid subclassRelid; + Oid superclassRelid; + Relation inhrel; + List *visited, + *queue; + ListCell *queue_item; + + /* We need to work with the associated relation OIDs */ + subclassRelid = typeOrDomainTypeRelid(subclassTypeId); + if (subclassRelid == InvalidOid) + return false; /* not a complex type or domain over one */ + superclassRelid = typeidTypeRelid(superclassTypeId); + if (superclassRelid == InvalidOid) + return false; /* not a complex type */ + + /* No point in searching if the superclass has no subclasses */ + if (!has_subclass(superclassRelid)) + return false; + + /* + * Begin the search at the relation itself, so add its relid to the queue. + */ + queue = list_make1_oid(subclassRelid); + visited = NIL; + + inhrel = table_open(InheritsRelationId, AccessShareLock); + + /* + * Use queue to do a breadth-first traversal of the inheritance graph from + * the relid supplied up to the root. Notice that we append to the queue + * inside the loop --- this is okay because the foreach() macro doesn't + * advance queue_item until the next loop iteration begins. + */ + foreach(queue_item, queue) + { + Oid this_relid = lfirst_oid(queue_item); + ScanKeyData skey; + SysScanDesc inhscan; + HeapTuple inhtup; + + /* + * If we've seen this relid already, skip it. This avoids extra work + * in multiple-inheritance scenarios, and also protects us from an + * infinite loop in case there is a cycle in pg_inherits (though + * theoretically that shouldn't happen). + */ + if (list_member_oid(visited, this_relid)) + continue; + + /* + * Okay, this is a not-yet-seen relid. Add it to the list of + * already-visited OIDs, then find all the types this relid inherits + * from and add them to the queue. + */ + visited = lappend_oid(visited, this_relid); + + ScanKeyInit(&skey, + Anum_pg_inherits_inhrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(this_relid)); + + inhscan = systable_beginscan(inhrel, InheritsRelidSeqnoIndexId, true, + NULL, 1, &skey); + + while ((inhtup = systable_getnext(inhscan)) != NULL) + { + Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inhtup); + Oid inhparent = inh->inhparent; + + /* If this is the target superclass, we're done */ + if (inhparent == superclassRelid) + { + result = true; + break; + } + + /* Else add to queue */ + queue = lappend_oid(queue, inhparent); + } + + systable_endscan(inhscan); + + if (result) + break; + } + + /* clean up ... */ + table_close(inhrel, AccessShareLock); + + list_free(visited); + list_free(queue); + + return result; +} + +/* + * Create a single pg_inherits row with the given data + */ +void +StoreSingleInheritance(Oid relationId, Oid parentOid, int32 seqNumber) +{ + Datum values[Natts_pg_inherits]; + bool nulls[Natts_pg_inherits]; + HeapTuple tuple; + Relation inhRelation; + + inhRelation = table_open(InheritsRelationId, RowExclusiveLock); + + /* + * Make the pg_inherits entry + */ + values[Anum_pg_inherits_inhrelid - 1] = ObjectIdGetDatum(relationId); + values[Anum_pg_inherits_inhparent - 1] = ObjectIdGetDatum(parentOid); + values[Anum_pg_inherits_inhseqno - 1] = Int32GetDatum(seqNumber); + + memset(nulls, 0, sizeof(nulls)); + + tuple = heap_form_tuple(RelationGetDescr(inhRelation), values, nulls); + + CatalogTupleInsert(inhRelation, tuple); + + heap_freetuple(tuple); + + table_close(inhRelation, RowExclusiveLock); +} + +/* + * DeleteInheritsTuple + * + * Delete pg_inherits tuples with the given inhrelid. inhparent may be given + * as InvalidOid, in which case all tuples matching inhrelid are deleted; + * otherwise only delete tuples with the specified inhparent. + * + * Returns whether at least one row was deleted. + */ +bool +DeleteInheritsTuple(Oid inhrelid, Oid inhparent) +{ + bool found = false; + Relation catalogRelation; + ScanKeyData key; + SysScanDesc scan; + HeapTuple inheritsTuple; + + /* + * Find pg_inherits entries by inhrelid. + */ + catalogRelation = table_open(InheritsRelationId, RowExclusiveLock); + ScanKeyInit(&key, + Anum_pg_inherits_inhrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(inhrelid)); + scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, + true, NULL, 1, &key); + + while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan))) + { + Oid parent; + + /* Compare inhparent if it was given, and do the actual deletion. */ + parent = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhparent; + if (!OidIsValid(inhparent) || parent == inhparent) + { + CatalogTupleDelete(catalogRelation, &inheritsTuple->t_self); + found = true; + } + } + + /* Done */ + systable_endscan(scan); + table_close(catalogRelation, RowExclusiveLock); + + return found; +} diff --git a/src/backend/catalog/pg_inherits_d.h b/src/backend/catalog/pg_inherits_d.h new file mode 100644 index 0000000..6028071 --- /dev/null +++ b/src/backend/catalog/pg_inherits_d.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * pg_inherits_d.h + * Macro definitions for pg_inherits + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_INHERITS_D_H +#define PG_INHERITS_D_H + +#define InheritsRelationId 2611 + +#define Anum_pg_inherits_inhrelid 1 +#define Anum_pg_inherits_inhparent 2 +#define Anum_pg_inherits_inhseqno 3 + +#define Natts_pg_inherits 3 + + +#endif /* PG_INHERITS_D_H */ diff --git a/src/backend/catalog/pg_init_privs_d.h b/src/backend/catalog/pg_init_privs_d.h new file mode 100644 index 0000000..304fa0a --- /dev/null +++ b/src/backend/catalog/pg_init_privs_d.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * pg_init_privs_d.h + * Macro definitions for pg_init_privs + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_INIT_PRIVS_D_H +#define PG_INIT_PRIVS_D_H + +#define InitPrivsRelationId 3394 + +#define Anum_pg_init_privs_objoid 1 +#define Anum_pg_init_privs_classoid 2 +#define Anum_pg_init_privs_objsubid 3 +#define Anum_pg_init_privs_privtype 4 +#define Anum_pg_init_privs_initprivs 5 + +#define Natts_pg_init_privs 5 + + +#endif /* PG_INIT_PRIVS_D_H */ diff --git a/src/backend/catalog/pg_language_d.h b/src/backend/catalog/pg_language_d.h new file mode 100644 index 0000000..be46167 --- /dev/null +++ b/src/backend/catalog/pg_language_d.h @@ -0,0 +1,39 @@ +/*------------------------------------------------------------------------- + * + * pg_language_d.h + * Macro definitions for pg_language + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_LANGUAGE_D_H +#define PG_LANGUAGE_D_H + +#define LanguageRelationId 2612 + +#define Anum_pg_language_oid 1 +#define Anum_pg_language_lanname 2 +#define Anum_pg_language_lanowner 3 +#define Anum_pg_language_lanispl 4 +#define Anum_pg_language_lanpltrusted 5 +#define Anum_pg_language_lanplcallfoid 6 +#define Anum_pg_language_laninline 7 +#define Anum_pg_language_lanvalidator 8 +#define Anum_pg_language_lanacl 9 + +#define Natts_pg_language 9 + +#define INTERNALlanguageId 12 +#define ClanguageId 13 +#define SQLlanguageId 14 + +#endif /* PG_LANGUAGE_D_H */ diff --git a/src/backend/catalog/pg_largeobject.c b/src/backend/catalog/pg_largeobject.c new file mode 100644 index 0000000..ae9365e --- /dev/null +++ b/src/backend/catalog/pg_largeobject.c @@ -0,0 +1,187 @@ +/*------------------------------------------------------------------------- + * + * pg_largeobject.c + * routines to support manipulation of the pg_largeobject relation + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/pg_largeobject.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/genam.h" +#include "access/htup_details.h" +#include "access/sysattr.h" +#include "access/table.h" +#include "catalog/catalog.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/pg_largeobject.h" +#include "catalog/pg_largeobject_metadata.h" +#include "miscadmin.h" +#include "utils/acl.h" +#include "utils/fmgroids.h" +#include "utils/rel.h" + + +/* + * Create a large object having the given LO identifier. + * + * We create a new large object by inserting an entry into + * pg_largeobject_metadata without any data pages, so that the object + * will appear to exist with size 0. + */ +Oid +LargeObjectCreate(Oid loid) +{ + Relation pg_lo_meta; + HeapTuple ntup; + Oid loid_new; + Datum values[Natts_pg_largeobject_metadata]; + bool nulls[Natts_pg_largeobject_metadata]; + + pg_lo_meta = table_open(LargeObjectMetadataRelationId, + RowExclusiveLock); + + /* + * Insert metadata of the largeobject + */ + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + + if (OidIsValid(loid)) + loid_new = loid; + else + loid_new = GetNewOidWithIndex(pg_lo_meta, + LargeObjectMetadataOidIndexId, + Anum_pg_largeobject_metadata_oid); + + values[Anum_pg_largeobject_metadata_oid - 1] = ObjectIdGetDatum(loid_new); + values[Anum_pg_largeobject_metadata_lomowner - 1] + = ObjectIdGetDatum(GetUserId()); + nulls[Anum_pg_largeobject_metadata_lomacl - 1] = true; + + ntup = heap_form_tuple(RelationGetDescr(pg_lo_meta), + values, nulls); + + CatalogTupleInsert(pg_lo_meta, ntup); + + heap_freetuple(ntup); + + table_close(pg_lo_meta, RowExclusiveLock); + + return loid_new; +} + +/* + * Drop a large object having the given LO identifier. Both the data pages + * and metadata must be dropped. + */ +void +LargeObjectDrop(Oid loid) +{ + Relation pg_lo_meta; + Relation pg_largeobject; + ScanKeyData skey[1]; + SysScanDesc scan; + HeapTuple tuple; + + pg_lo_meta = table_open(LargeObjectMetadataRelationId, + RowExclusiveLock); + + pg_largeobject = table_open(LargeObjectRelationId, + RowExclusiveLock); + + /* + * Delete an entry from pg_largeobject_metadata + */ + ScanKeyInit(&skey[0], + Anum_pg_largeobject_metadata_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(loid)); + + scan = systable_beginscan(pg_lo_meta, + LargeObjectMetadataOidIndexId, true, + NULL, 1, skey); + + tuple = systable_getnext(scan); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("large object %u does not exist", loid))); + + CatalogTupleDelete(pg_lo_meta, &tuple->t_self); + + systable_endscan(scan); + + /* + * Delete all the associated entries from pg_largeobject + */ + ScanKeyInit(&skey[0], + Anum_pg_largeobject_loid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(loid)); + + scan = systable_beginscan(pg_largeobject, + LargeObjectLOidPNIndexId, true, + NULL, 1, skey); + while (HeapTupleIsValid(tuple = systable_getnext(scan))) + { + CatalogTupleDelete(pg_largeobject, &tuple->t_self); + } + + systable_endscan(scan); + + table_close(pg_largeobject, RowExclusiveLock); + + table_close(pg_lo_meta, RowExclusiveLock); +} + +/* + * LargeObjectExists + * + * We don't use the system cache for large object metadata, for fear of + * using too much local memory. + * + * This function always scans the system catalog using an up-to-date snapshot, + * so it should not be used when a large object is opened in read-only mode + * (because large objects opened in read only mode are supposed to be viewed + * relative to the caller's snapshot, whereas in read-write mode they are + * relative to a current snapshot). + */ +bool +LargeObjectExists(Oid loid) +{ + Relation pg_lo_meta; + ScanKeyData skey[1]; + SysScanDesc sd; + HeapTuple tuple; + bool retval = false; + + ScanKeyInit(&skey[0], + Anum_pg_largeobject_metadata_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(loid)); + + pg_lo_meta = table_open(LargeObjectMetadataRelationId, + AccessShareLock); + + sd = systable_beginscan(pg_lo_meta, + LargeObjectMetadataOidIndexId, true, + NULL, 1, skey); + + tuple = systable_getnext(sd); + if (HeapTupleIsValid(tuple)) + retval = true; + + systable_endscan(sd); + + table_close(pg_lo_meta, AccessShareLock); + + return retval; +} diff --git a/src/backend/catalog/pg_largeobject_d.h b/src/backend/catalog/pg_largeobject_d.h new file mode 100644 index 0000000..b9e95f9 --- /dev/null +++ b/src/backend/catalog/pg_largeobject_d.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * pg_largeobject_d.h + * Macro definitions for pg_largeobject + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_LARGEOBJECT_D_H +#define PG_LARGEOBJECT_D_H + +#define LargeObjectRelationId 2613 + +#define Anum_pg_largeobject_loid 1 +#define Anum_pg_largeobject_pageno 2 +#define Anum_pg_largeobject_data 3 + +#define Natts_pg_largeobject 3 + + +#endif /* PG_LARGEOBJECT_D_H */ diff --git a/src/backend/catalog/pg_largeobject_metadata_d.h b/src/backend/catalog/pg_largeobject_metadata_d.h new file mode 100644 index 0000000..eb4a013 --- /dev/null +++ b/src/backend/catalog/pg_largeobject_metadata_d.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * pg_largeobject_metadata_d.h + * Macro definitions for pg_largeobject_metadata + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_LARGEOBJECT_METADATA_D_H +#define PG_LARGEOBJECT_METADATA_D_H + +#define LargeObjectMetadataRelationId 2995 + +#define Anum_pg_largeobject_metadata_oid 1 +#define Anum_pg_largeobject_metadata_lomowner 2 +#define Anum_pg_largeobject_metadata_lomacl 3 + +#define Natts_pg_largeobject_metadata 3 + + +#endif /* PG_LARGEOBJECT_METADATA_D_H */ diff --git a/src/backend/catalog/pg_namespace.c b/src/backend/catalog/pg_namespace.c new file mode 100644 index 0000000..ed85276 --- /dev/null +++ b/src/backend/catalog/pg_namespace.c @@ -0,0 +1,120 @@ +/*------------------------------------------------------------------------- + * + * pg_namespace.c + * routines to support manipulation of the pg_namespace relation + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/pg_namespace.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/htup_details.h" +#include "access/table.h" +#include "catalog/catalog.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/objectaccess.h" +#include "catalog/pg_namespace.h" +#include "utils/builtins.h" +#include "utils/rel.h" +#include "utils/syscache.h" + + +/* ---------------- + * NamespaceCreate + * + * Create a namespace (schema) with the given name and owner OID. + * + * If isTemp is true, this schema is a per-backend schema for holding + * temporary tables. Currently, it is used to prevent it from being + * linked as a member of any active extension. (If someone does CREATE + * TEMP TABLE in an extension script, we don't want the temp schema to + * become part of the extension). And to avoid checking for default ACL + * for temp namespace (as it is not necessary). + * --------------- + */ +Oid +NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp) +{ + Relation nspdesc; + HeapTuple tup; + Oid nspoid; + bool nulls[Natts_pg_namespace]; + Datum values[Natts_pg_namespace]; + NameData nname; + TupleDesc tupDesc; + ObjectAddress myself; + int i; + Acl *nspacl; + + /* sanity checks */ + if (!nspName) + elog(ERROR, "no namespace name supplied"); + + /* make sure there is no existing namespace of same name */ + if (SearchSysCacheExists1(NAMESPACENAME, PointerGetDatum(nspName))) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_SCHEMA), + errmsg("schema \"%s\" already exists", nspName))); + + if (!isTemp) + nspacl = get_user_default_acl(OBJECT_SCHEMA, ownerId, + InvalidOid); + else + nspacl = NULL; + + nspdesc = table_open(NamespaceRelationId, RowExclusiveLock); + tupDesc = nspdesc->rd_att; + + /* initialize nulls and values */ + for (i = 0; i < Natts_pg_namespace; i++) + { + nulls[i] = false; + values[i] = (Datum) NULL; + } + + nspoid = GetNewOidWithIndex(nspdesc, NamespaceOidIndexId, + Anum_pg_namespace_oid); + values[Anum_pg_namespace_oid - 1] = ObjectIdGetDatum(nspoid); + namestrcpy(&nname, nspName); + values[Anum_pg_namespace_nspname - 1] = NameGetDatum(&nname); + values[Anum_pg_namespace_nspowner - 1] = ObjectIdGetDatum(ownerId); + if (nspacl != NULL) + values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(nspacl); + else + nulls[Anum_pg_namespace_nspacl - 1] = true; + + + tup = heap_form_tuple(tupDesc, values, nulls); + + CatalogTupleInsert(nspdesc, tup); + Assert(OidIsValid(nspoid)); + + table_close(nspdesc, RowExclusiveLock); + + /* Record dependencies */ + myself.classId = NamespaceRelationId; + myself.objectId = nspoid; + myself.objectSubId = 0; + + /* dependency on owner */ + recordDependencyOnOwner(NamespaceRelationId, nspoid, ownerId); + + /* dependences on roles mentioned in default ACL */ + recordDependencyOnNewAcl(NamespaceRelationId, nspoid, 0, ownerId, nspacl); + + /* dependency on extension ... but not for magic temp schemas */ + if (!isTemp) + recordDependencyOnCurrentExtension(&myself, false); + + /* Post creation hook for new schema */ + InvokeObjectPostCreateHook(NamespaceRelationId, nspoid, 0); + + return nspoid; +} diff --git a/src/backend/catalog/pg_namespace_d.h b/src/backend/catalog/pg_namespace_d.h new file mode 100644 index 0000000..44493fb --- /dev/null +++ b/src/backend/catalog/pg_namespace_d.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- + * + * pg_namespace_d.h + * Macro definitions for pg_namespace + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_NAMESPACE_D_H +#define PG_NAMESPACE_D_H + +#define NamespaceRelationId 2615 + +#define Anum_pg_namespace_oid 1 +#define Anum_pg_namespace_nspname 2 +#define Anum_pg_namespace_nspowner 3 +#define Anum_pg_namespace_nspacl 4 + +#define Natts_pg_namespace 4 + +#define PG_CATALOG_NAMESPACE 11 +#define PG_TOAST_NAMESPACE 99 +#define PG_PUBLIC_NAMESPACE 2200 + +#endif /* PG_NAMESPACE_D_H */ diff --git a/src/backend/catalog/pg_opclass_d.h b/src/backend/catalog/pg_opclass_d.h new file mode 100644 index 0000000..bc7b468 --- /dev/null +++ b/src/backend/catalog/pg_opclass_d.h @@ -0,0 +1,49 @@ +/*------------------------------------------------------------------------- + * + * pg_opclass_d.h + * Macro definitions for pg_opclass + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_OPCLASS_D_H +#define PG_OPCLASS_D_H + +#define OperatorClassRelationId 2616 + +#define Anum_pg_opclass_oid 1 +#define Anum_pg_opclass_opcmethod 2 +#define Anum_pg_opclass_opcname 3 +#define Anum_pg_opclass_opcnamespace 4 +#define Anum_pg_opclass_opcowner 5 +#define Anum_pg_opclass_opcfamily 6 +#define Anum_pg_opclass_opcintype 7 +#define Anum_pg_opclass_opcdefault 8 +#define Anum_pg_opclass_opckeytype 9 + +#define Natts_pg_opclass 9 + +#define DATE_BTREE_OPS_OID 3122 +#define FLOAT8_BTREE_OPS_OID 3123 +#define INT2_BTREE_OPS_OID 1979 +#define INT4_BTREE_OPS_OID 1978 +#define INT8_BTREE_OPS_OID 3124 +#define NUMERIC_BTREE_OPS_OID 3125 +#define OID_BTREE_OPS_OID 1981 +#define TEXT_BTREE_OPS_OID 3126 +#define TIMESTAMPTZ_BTREE_OPS_OID 3127 +#define TIMESTAMP_BTREE_OPS_OID 3128 +#define TEXT_BTREE_PATTERN_OPS_OID 4217 +#define VARCHAR_BTREE_PATTERN_OPS_OID 4218 +#define BPCHAR_BTREE_PATTERN_OPS_OID 4219 + +#endif /* PG_OPCLASS_D_H */ diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c new file mode 100644 index 0000000..340e284 --- /dev/null +++ b/src/backend/catalog/pg_operator.c @@ -0,0 +1,873 @@ +/*------------------------------------------------------------------------- + * + * pg_operator.c + * routines to support manipulation of the pg_operator relation + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/pg_operator.c + * + * NOTES + * these routines moved here from commands/define.c and somewhat cleaned up. + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/htup_details.h" +#include "access/table.h" +#include "access/xact.h" +#include "catalog/catalog.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/namespace.h" +#include "catalog/objectaccess.h" +#include "catalog/pg_namespace.h" +#include "catalog/pg_operator.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_type.h" +#include "miscadmin.h" +#include "parser/parse_oper.h" +#include "utils/acl.h" +#include "utils/builtins.h" +#include "utils/lsyscache.h" +#include "utils/rel.h" +#include "utils/syscache.h" + + +static Oid OperatorGet(const char *operatorName, + Oid operatorNamespace, + Oid leftObjectId, + Oid rightObjectId, + bool *defined); + +static Oid OperatorLookup(List *operatorName, + Oid leftObjectId, + Oid rightObjectId, + bool *defined); + +static Oid OperatorShellMake(const char *operatorName, + Oid operatorNamespace, + Oid leftTypeId, + Oid rightTypeId); + +static Oid get_other_operator(List *otherOp, + Oid otherLeftTypeId, Oid otherRightTypeId, + const char *operatorName, Oid operatorNamespace, + Oid leftTypeId, Oid rightTypeId, + bool isCommutator); + + +/* + * Check whether a proposed operator name is legal + * + * This had better match the behavior of parser/scan.l! + * + * We need this because the parser is not smart enough to check that + * the arguments of CREATE OPERATOR's COMMUTATOR, NEGATOR, etc clauses + * are operator names rather than some other lexical entity. + */ +static bool +validOperatorName(const char *name) +{ + size_t len = strlen(name); + + /* Can't be empty or too long */ + if (len == 0 || len >= NAMEDATALEN) + return false; + + /* Can't contain any invalid characters */ + /* Test string here should match op_chars in scan.l */ + if (strspn(name, "~!@#^&|`?+-*/%<>=") != len) + return false; + + /* Can't contain slash-star or dash-dash (comment starts) */ + if (strstr(name, "/*") || strstr(name, "--")) + return false; + + /* + * For SQL standard compatibility, '+' and '-' cannot be the last char of + * a multi-char operator unless the operator contains chars that are not + * in SQL operators. The idea is to lex '=-' as two operators, but not to + * forbid operator names like '?-' that could not be sequences of standard + * SQL operators. + */ + if (len > 1 && + (name[len - 1] == '+' || + name[len - 1] == '-')) + { + int ic; + + for (ic = len - 2; ic >= 0; ic--) + { + if (strchr("~!@#^&|`?%", name[ic])) + break; + } + if (ic < 0) + return false; /* nope, not valid */ + } + + /* != isn't valid either, because parser will convert it to <> */ + if (strcmp(name, "!=") == 0) + return false; + + return true; +} + + +/* + * OperatorGet + * + * finds an operator given an exact specification (name, namespace, + * left and right type IDs). + * + * *defined is set true if defined (not a shell) + */ +static Oid +OperatorGet(const char *operatorName, + Oid operatorNamespace, + Oid leftObjectId, + Oid rightObjectId, + bool *defined) +{ + HeapTuple tup; + Oid operatorObjectId; + + tup = SearchSysCache4(OPERNAMENSP, + PointerGetDatum(operatorName), + ObjectIdGetDatum(leftObjectId), + ObjectIdGetDatum(rightObjectId), + ObjectIdGetDatum(operatorNamespace)); + if (HeapTupleIsValid(tup)) + { + Form_pg_operator oprform = (Form_pg_operator) GETSTRUCT(tup); + + operatorObjectId = oprform->oid; + *defined = RegProcedureIsValid(oprform->oprcode); + ReleaseSysCache(tup); + } + else + { + operatorObjectId = InvalidOid; + *defined = false; + } + + return operatorObjectId; +} + +/* + * OperatorLookup + * + * looks up an operator given a possibly-qualified name and + * left and right type IDs. + * + * *defined is set true if defined (not a shell) + */ +static Oid +OperatorLookup(List *operatorName, + Oid leftObjectId, + Oid rightObjectId, + bool *defined) +{ + Oid operatorObjectId; + RegProcedure oprcode; + + operatorObjectId = LookupOperName(NULL, operatorName, + leftObjectId, rightObjectId, + true, -1); + if (!OidIsValid(operatorObjectId)) + { + *defined = false; + return InvalidOid; + } + + oprcode = get_opcode(operatorObjectId); + *defined = RegProcedureIsValid(oprcode); + + return operatorObjectId; +} + + +/* + * OperatorShellMake + * Make a "shell" entry for a not-yet-existing operator. + */ +static Oid +OperatorShellMake(const char *operatorName, + Oid operatorNamespace, + Oid leftTypeId, + Oid rightTypeId) +{ + Relation pg_operator_desc; + Oid operatorObjectId; + int i; + HeapTuple tup; + Datum values[Natts_pg_operator]; + bool nulls[Natts_pg_operator]; + NameData oname; + TupleDesc tupDesc; + + /* + * validate operator name + */ + if (!validOperatorName(operatorName)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("\"%s\" is not a valid operator name", + operatorName))); + + /* + * open pg_operator + */ + pg_operator_desc = table_open(OperatorRelationId, RowExclusiveLock); + tupDesc = pg_operator_desc->rd_att; + + /* + * initialize our *nulls and *values arrays + */ + for (i = 0; i < Natts_pg_operator; ++i) + { + nulls[i] = false; + values[i] = (Datum) NULL; /* redundant, but safe */ + } + + /* + * initialize values[] with the operator name and input data types. Note + * that oprcode is set to InvalidOid, indicating it's a shell. + */ + operatorObjectId = GetNewOidWithIndex(pg_operator_desc, OperatorOidIndexId, + Anum_pg_operator_oid); + values[Anum_pg_operator_oid - 1] = ObjectIdGetDatum(operatorObjectId); + namestrcpy(&oname, operatorName); + values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname); + values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace); + values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId()); + values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l'); + values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false); + values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false); + values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId); + values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId); + values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(InvalidOid); + values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(InvalidOid); + values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(InvalidOid); + values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(InvalidOid); + values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid); + values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid); + + /* + * create a new operator tuple + */ + tup = heap_form_tuple(tupDesc, values, nulls); + + /* + * insert our "shell" operator tuple + */ + CatalogTupleInsert(pg_operator_desc, tup); + + /* Add dependencies for the entry */ + makeOperatorDependencies(tup, false); + + heap_freetuple(tup); + + /* Post creation hook for new shell operator */ + InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0); + + /* + * Make sure the tuple is visible for subsequent lookups/updates. + */ + CommandCounterIncrement(); + + /* + * close the operator relation and return the oid. + */ + table_close(pg_operator_desc, RowExclusiveLock); + + return operatorObjectId; +} + +/* + * OperatorCreate + * + * "X" indicates an optional argument (i.e. one that can be NULL or 0) + * operatorName name for new operator + * operatorNamespace namespace for new operator + * leftTypeId X left type ID + * rightTypeId X right type ID + * procedureId procedure ID for operator + * commutatorName X commutator operator + * negatorName X negator operator + * restrictionId X restriction selectivity procedure ID + * joinId X join selectivity procedure ID + * canMerge merge join can be used with this operator + * canHash hash join can be used with this operator + * + * The caller should have validated properties and permissions for the + * objects passed as OID references. We must handle the commutator and + * negator operator references specially, however, since those need not + * exist beforehand. + * + * This routine gets complicated because it allows the user to + * specify operators that do not exist. For example, if operator + * "op" is being defined, the negator operator "negop" and the + * commutator "commop" can also be defined without specifying + * any information other than their names. Since in order to + * add "op" to the PG_OPERATOR catalog, all the Oid's for these + * operators must be placed in the fields of "op", a forward + * declaration is done on the commutator and negator operators. + * This is called creating a shell, and its main effect is to + * create a tuple in the PG_OPERATOR catalog with minimal + * information about the operator (just its name and types). + * Forward declaration is used only for this purpose, it is + * not available to the user as it is for type definition. + */ +ObjectAddress +OperatorCreate(const char *operatorName, + Oid operatorNamespace, + Oid leftTypeId, + Oid rightTypeId, + Oid procedureId, + List *commutatorName, + List *negatorName, + Oid restrictionId, + Oid joinId, + bool canMerge, + bool canHash) +{ + Relation pg_operator_desc; + HeapTuple tup; + bool isUpdate; + bool nulls[Natts_pg_operator]; + bool replaces[Natts_pg_operator]; + Datum values[Natts_pg_operator]; + Oid operatorObjectId; + bool operatorAlreadyDefined; + Oid operResultType; + Oid commutatorId, + negatorId; + bool selfCommutator = false; + NameData oname; + int i; + ObjectAddress address; + + /* + * Sanity checks + */ + if (!validOperatorName(operatorName)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("\"%s\" is not a valid operator name", + operatorName))); + + if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId))) + { + /* If it's not a binary op, these things mustn't be set: */ + if (commutatorName) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("only binary operators can have commutators"))); + if (OidIsValid(joinId)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("only binary operators can have join selectivity"))); + if (canMerge) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("only binary operators can merge join"))); + if (canHash) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("only binary operators can hash"))); + } + + operResultType = get_func_rettype(procedureId); + + if (operResultType != BOOLOID) + { + /* If it's not a boolean op, these things mustn't be set: */ + if (negatorName) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("only boolean operators can have negators"))); + if (OidIsValid(restrictionId)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("only boolean operators can have restriction selectivity"))); + if (OidIsValid(joinId)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("only boolean operators can have join selectivity"))); + if (canMerge) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("only boolean operators can merge join"))); + if (canHash) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("only boolean operators can hash"))); + } + + operatorObjectId = OperatorGet(operatorName, + operatorNamespace, + leftTypeId, + rightTypeId, + &operatorAlreadyDefined); + + if (operatorAlreadyDefined) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_FUNCTION), + errmsg("operator %s already exists", + operatorName))); + + /* + * At this point, if operatorObjectId is not InvalidOid then we are + * filling in a previously-created shell. Insist that the user own any + * such shell. + */ + if (OidIsValid(operatorObjectId) && + !pg_oper_ownercheck(operatorObjectId, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR, + operatorName); + + /* + * Set up the other operators. If they do not currently exist, create + * shells in order to get ObjectId's. + */ + + if (commutatorName) + { + /* commutator has reversed arg types */ + commutatorId = get_other_operator(commutatorName, + rightTypeId, leftTypeId, + operatorName, operatorNamespace, + leftTypeId, rightTypeId, + true); + + /* Permission check: must own other operator */ + if (OidIsValid(commutatorId) && + !pg_oper_ownercheck(commutatorId, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR, + NameListToString(commutatorName)); + + /* + * self-linkage to this operator; will fix below. Note that only + * self-linkage for commutation makes sense. + */ + if (!OidIsValid(commutatorId)) + selfCommutator = true; + } + else + commutatorId = InvalidOid; + + if (negatorName) + { + /* negator has same arg types */ + negatorId = get_other_operator(negatorName, + leftTypeId, rightTypeId, + operatorName, operatorNamespace, + leftTypeId, rightTypeId, + false); + + /* Permission check: must own other operator */ + if (OidIsValid(negatorId) && + !pg_oper_ownercheck(negatorId, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR, + NameListToString(negatorName)); + } + else + negatorId = InvalidOid; + + /* + * set up values in the operator tuple + */ + + for (i = 0; i < Natts_pg_operator; ++i) + { + values[i] = (Datum) NULL; + replaces[i] = true; + nulls[i] = false; + } + + namestrcpy(&oname, operatorName); + values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname); + values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace); + values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId()); + values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l'); + values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge); + values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash); + values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId); + values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId); + values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(operResultType); + values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorId); + values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorId); + values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(procedureId); + values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionId); + values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinId); + + pg_operator_desc = table_open(OperatorRelationId, RowExclusiveLock); + + /* + * If we are replacing an operator shell, update; else insert + */ + if (operatorObjectId) + { + isUpdate = true; + + tup = SearchSysCacheCopy1(OPEROID, + ObjectIdGetDatum(operatorObjectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for operator %u", + operatorObjectId); + + replaces[Anum_pg_operator_oid - 1] = false; + tup = heap_modify_tuple(tup, + RelationGetDescr(pg_operator_desc), + values, + nulls, + replaces); + + CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup); + } + else + { + isUpdate = false; + + operatorObjectId = GetNewOidWithIndex(pg_operator_desc, + OperatorOidIndexId, + Anum_pg_operator_oid); + values[Anum_pg_operator_oid - 1] = ObjectIdGetDatum(operatorObjectId); + + tup = heap_form_tuple(RelationGetDescr(pg_operator_desc), + values, nulls); + + CatalogTupleInsert(pg_operator_desc, tup); + } + + /* Add dependencies for the entry */ + address = makeOperatorDependencies(tup, isUpdate); + + /* Post creation hook for new operator */ + InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0); + + table_close(pg_operator_desc, RowExclusiveLock); + + /* + * If a commutator and/or negator link is provided, update the other + * operator(s) to point at this one, if they don't already have a link. + * This supports an alternative style of operator definition wherein the + * user first defines one operator without giving negator or commutator, + * then defines the other operator of the pair with the proper commutator + * or negator attribute. That style doesn't require creation of a shell, + * and it's the only style that worked right before Postgres version 6.5. + * This code also takes care of the situation where the new operator is + * its own commutator. + */ + if (selfCommutator) + commutatorId = operatorObjectId; + + if (OidIsValid(commutatorId) || OidIsValid(negatorId)) + OperatorUpd(operatorObjectId, commutatorId, negatorId, false); + + return address; +} + +/* + * Try to lookup another operator (commutator, etc) + * + * If not found, check to see if it is exactly the operator we are trying + * to define; if so, return InvalidOid. (Note that this case is only + * sensible for a commutator, so we error out otherwise.) If it is not + * the same operator, create a shell operator. + */ +static Oid +get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId, + const char *operatorName, Oid operatorNamespace, + Oid leftTypeId, Oid rightTypeId, bool isCommutator) +{ + Oid other_oid; + bool otherDefined; + char *otherName; + Oid otherNamespace; + AclResult aclresult; + + other_oid = OperatorLookup(otherOp, + otherLeftTypeId, + otherRightTypeId, + &otherDefined); + + if (OidIsValid(other_oid)) + { + /* other op already in catalogs */ + return other_oid; + } + + otherNamespace = QualifiedNameGetCreationNamespace(otherOp, + &otherName); + + if (strcmp(otherName, operatorName) == 0 && + otherNamespace == operatorNamespace && + otherLeftTypeId == leftTypeId && + otherRightTypeId == rightTypeId) + { + /* + * self-linkage to this operator; caller will fix later. Note that + * only self-linkage for commutation makes sense. + */ + if (!isCommutator) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("operator cannot be its own negator or sort operator"))); + return InvalidOid; + } + + /* not in catalogs, different from operator, so make shell */ + + aclresult = pg_namespace_aclcheck(otherNamespace, GetUserId(), + ACL_CREATE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, OBJECT_SCHEMA, + get_namespace_name(otherNamespace)); + + other_oid = OperatorShellMake(otherName, + otherNamespace, + otherLeftTypeId, + otherRightTypeId); + return other_oid; +} + +/* + * OperatorUpd + * + * For a given operator, look up its negator and commutator operators. + * When isDelete is false, update their negator and commutator fields to + * point back to the given operator; when isDelete is true, update those + * fields to no longer point back to the given operator. + * + * The !isDelete case solves a problem for users who need to insert two new + * operators that are the negator or commutator of each other, while the + * isDelete case is needed so as not to leave dangling OID links behind + * after dropping an operator. + */ +void +OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete) +{ + Relation pg_operator_desc; + HeapTuple tup; + + /* + * If we're making an operator into its own commutator, then we need a + * command-counter increment here, since we've just inserted the tuple + * we're about to update. But when we're dropping an operator, we can + * skip this because we're at the beginning of the command. + */ + if (!isDelete) + CommandCounterIncrement(); + + /* Open the relation. */ + pg_operator_desc = table_open(OperatorRelationId, RowExclusiveLock); + + /* Get a writable copy of the commutator's tuple. */ + if (OidIsValid(commId)) + tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(commId)); + else + tup = NULL; + + /* Update the commutator's tuple if need be. */ + if (HeapTupleIsValid(tup)) + { + Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup); + bool update_commutator = false; + + /* + * Out of due caution, we only change the commutator's oprcom field if + * it has the exact value we expected: InvalidOid when creating an + * operator, or baseId when dropping one. + */ + if (isDelete && t->oprcom == baseId) + { + t->oprcom = InvalidOid; + update_commutator = true; + } + else if (!isDelete && !OidIsValid(t->oprcom)) + { + t->oprcom = baseId; + update_commutator = true; + } + + /* If any columns were found to need modification, update tuple. */ + if (update_commutator) + { + CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup); + + /* + * Do CCI to make the updated tuple visible. We must do this in + * case the commutator is also the negator. (Which would be a + * logic error on the operator definer's part, but that's not a + * good reason to fail here.) We would need a CCI anyway in the + * deletion case for a self-commutator with no negator. + */ + CommandCounterIncrement(); + } + } + + /* + * Similarly find and update the negator, if any. + */ + if (OidIsValid(negId)) + tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(negId)); + else + tup = NULL; + + if (HeapTupleIsValid(tup)) + { + Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup); + bool update_negator = false; + + /* + * Out of due caution, we only change the negator's oprnegate field if + * it has the exact value we expected: InvalidOid when creating an + * operator, or baseId when dropping one. + */ + if (isDelete && t->oprnegate == baseId) + { + t->oprnegate = InvalidOid; + update_negator = true; + } + else if (!isDelete && !OidIsValid(t->oprnegate)) + { + t->oprnegate = baseId; + update_negator = true; + } + + /* If any columns were found to need modification, update tuple. */ + if (update_negator) + { + CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup); + + /* + * In the deletion case, do CCI to make the updated tuple visible. + * We must do this in case the operator is its own negator. (Which + * would be a logic error on the operator definer's part, but + * that's not a good reason to fail here.) + */ + if (isDelete) + CommandCounterIncrement(); + } + } + + /* Close relation and release catalog lock. */ + table_close(pg_operator_desc, RowExclusiveLock); +} + +/* + * Create dependencies for an operator (either a freshly inserted + * complete operator, a new shell operator, a just-updated shell, + * or an operator that's being modified by ALTER OPERATOR). + * + * NB: the OidIsValid tests in this routine are necessary, in case + * the given operator is a shell. + */ +ObjectAddress +makeOperatorDependencies(HeapTuple tuple, bool isUpdate) +{ + Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple); + ObjectAddress myself, + referenced; + + myself.classId = OperatorRelationId; + myself.objectId = oper->oid; + myself.objectSubId = 0; + + /* + * If we are updating the operator, delete any existing entries, except + * for extension membership which should remain the same. + */ + if (isUpdate) + { + deleteDependencyRecordsFor(myself.classId, myself.objectId, true); + deleteSharedDependencyRecordsFor(myself.classId, myself.objectId, 0); + } + + /* Dependency on namespace */ + if (OidIsValid(oper->oprnamespace)) + { + referenced.classId = NamespaceRelationId; + referenced.objectId = oper->oprnamespace; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* Dependency on left type */ + if (OidIsValid(oper->oprleft)) + { + referenced.classId = TypeRelationId; + referenced.objectId = oper->oprleft; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* Dependency on right type */ + if (OidIsValid(oper->oprright)) + { + referenced.classId = TypeRelationId; + referenced.objectId = oper->oprright; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* Dependency on result type */ + if (OidIsValid(oper->oprresult)) + { + referenced.classId = TypeRelationId; + referenced.objectId = oper->oprresult; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* + * NOTE: we do not consider the operator to depend on the associated + * operators oprcom and oprnegate. We would not want to delete this + * operator if those go away, but only reset the link fields; which is not + * a function that the dependency code can presently handle. (Something + * could perhaps be done with objectSubId though.) For now, it's okay to + * let those links dangle if a referenced operator is removed. + */ + + /* Dependency on implementation function */ + if (OidIsValid(oper->oprcode)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = oper->oprcode; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* Dependency on restriction selectivity function */ + if (OidIsValid(oper->oprrest)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = oper->oprrest; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* Dependency on join selectivity function */ + if (OidIsValid(oper->oprjoin)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = oper->oprjoin; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* Dependency on owner */ + recordDependencyOnOwner(OperatorRelationId, oper->oid, + oper->oprowner); + + /* Dependency on extension */ + recordDependencyOnCurrentExtension(&myself, true); + + return myself; +} diff --git a/src/backend/catalog/pg_operator_d.h b/src/backend/catalog/pg_operator_d.h new file mode 100644 index 0000000..02a5956 --- /dev/null +++ b/src/backend/catalog/pg_operator_d.h @@ -0,0 +1,106 @@ +/*------------------------------------------------------------------------- + * + * pg_operator_d.h + * Macro definitions for pg_operator + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_OPERATOR_D_H +#define PG_OPERATOR_D_H + +#define OperatorRelationId 2617 + +#define Anum_pg_operator_oid 1 +#define Anum_pg_operator_oprname 2 +#define Anum_pg_operator_oprnamespace 3 +#define Anum_pg_operator_oprowner 4 +#define Anum_pg_operator_oprkind 5 +#define Anum_pg_operator_oprcanmerge 6 +#define Anum_pg_operator_oprcanhash 7 +#define Anum_pg_operator_oprleft 8 +#define Anum_pg_operator_oprright 9 +#define Anum_pg_operator_oprresult 10 +#define Anum_pg_operator_oprcom 11 +#define Anum_pg_operator_oprnegate 12 +#define Anum_pg_operator_oprcode 13 +#define Anum_pg_operator_oprrest 14 +#define Anum_pg_operator_oprjoin 15 + +#define Natts_pg_operator 15 + +#define BooleanNotEqualOperator 85 +#define BooleanEqualOperator 91 +#define Int4EqualOperator 96 +#define Int4LessOperator 97 +#define TextEqualOperator 98 +#define NameEqualTextOperator 254 +#define NameLessTextOperator 255 +#define NameGreaterEqualTextOperator 257 +#define TIDEqualOperator 387 +#define TIDLessOperator 2799 +#define Int8LessOperator 412 +#define OID_NAME_REGEXEQ_OP 639 +#define OID_TEXT_REGEXEQ_OP 641 +#define TextLessOperator 664 +#define TextGreaterEqualOperator 667 +#define Float8LessOperator 672 +#define BpcharEqualOperator 1054 +#define OID_BPCHAR_REGEXEQ_OP 1055 +#define BpcharLessOperator 1058 +#define BpcharGreaterEqualOperator 1061 +#define ARRAY_EQ_OP 1070 +#define ARRAY_LT_OP 1072 +#define ARRAY_GT_OP 1073 +#define OID_NAME_LIKE_OP 1207 +#define OID_TEXT_LIKE_OP 1209 +#define OID_BPCHAR_LIKE_OP 1211 +#define OID_NAME_ICREGEXEQ_OP 1226 +#define OID_TEXT_ICREGEXEQ_OP 1228 +#define OID_BPCHAR_ICREGEXEQ_OP 1234 +#define OID_INET_SUB_OP 931 +#define OID_INET_SUBEQ_OP 932 +#define OID_INET_SUP_OP 933 +#define OID_INET_SUPEQ_OP 934 +#define OID_INET_OVERLAP_OP 3552 +#define OID_NAME_ICLIKE_OP 1625 +#define OID_TEXT_ICLIKE_OP 1627 +#define OID_BPCHAR_ICLIKE_OP 1629 +#define ByteaEqualOperator 1955 +#define ByteaLessOperator 1957 +#define ByteaGreaterEqualOperator 1960 +#define OID_BYTEA_LIKE_OP 2016 +#define TextPatternLessOperator 2314 +#define TextPatternGreaterEqualOperator 2317 +#define BpcharPatternLessOperator 2326 +#define BpcharPatternGreaterEqualOperator 2329 +#define OID_ARRAY_OVERLAP_OP 2750 +#define OID_ARRAY_CONTAINS_OP 2751 +#define OID_ARRAY_CONTAINED_OP 2752 +#define RECORD_EQ_OP 2988 +#define RECORD_LT_OP 2990 +#define RECORD_GT_OP 2991 +#define OID_RANGE_LESS_OP 3884 +#define OID_RANGE_LESS_EQUAL_OP 3885 +#define OID_RANGE_GREATER_EQUAL_OP 3886 +#define OID_RANGE_GREATER_OP 3887 +#define OID_RANGE_OVERLAP_OP 3888 +#define OID_RANGE_CONTAINS_ELEM_OP 3889 +#define OID_RANGE_CONTAINS_OP 3890 +#define OID_RANGE_ELEM_CONTAINED_OP 3891 +#define OID_RANGE_CONTAINED_OP 3892 +#define OID_RANGE_LEFT_OP 3893 +#define OID_RANGE_RIGHT_OP 3894 +#define OID_RANGE_OVERLAPS_LEFT_OP 3895 +#define OID_RANGE_OVERLAPS_RIGHT_OP 3896 + +#endif /* PG_OPERATOR_D_H */ diff --git a/src/backend/catalog/pg_opfamily_d.h b/src/backend/catalog/pg_opfamily_d.h new file mode 100644 index 0000000..353f686 --- /dev/null +++ b/src/backend/catalog/pg_opfamily_d.h @@ -0,0 +1,47 @@ +/*------------------------------------------------------------------------- + * + * pg_opfamily_d.h + * Macro definitions for pg_opfamily + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_OPFAMILY_D_H +#define PG_OPFAMILY_D_H + +#define OperatorFamilyRelationId 2753 + +#define Anum_pg_opfamily_oid 1 +#define Anum_pg_opfamily_opfmethod 2 +#define Anum_pg_opfamily_opfname 3 +#define Anum_pg_opfamily_opfnamespace 4 +#define Anum_pg_opfamily_opfowner 5 + +#define Natts_pg_opfamily 5 + + +#define IsBooleanOpfamily(opfamily) \ + ((opfamily) == BOOL_BTREE_FAM_OID || (opfamily) == BOOL_HASH_FAM_OID) + +#define BOOL_BTREE_FAM_OID 424 +#define BPCHAR_BTREE_FAM_OID 426 +#define BYTEA_BTREE_FAM_OID 428 +#define NETWORK_BTREE_FAM_OID 1974 +#define INTEGER_BTREE_FAM_OID 1976 +#define OID_BTREE_FAM_OID 1989 +#define TEXT_BTREE_FAM_OID 1994 +#define TEXT_PATTERN_BTREE_FAM_OID 2095 +#define BPCHAR_PATTERN_BTREE_FAM_OID 2097 +#define BOOL_HASH_FAM_OID 2222 +#define TEXT_SPGIST_FAM_OID 4017 + +#endif /* PG_OPFAMILY_D_H */ diff --git a/src/backend/catalog/pg_partitioned_table_d.h b/src/backend/catalog/pg_partitioned_table_d.h new file mode 100644 index 0000000..cc27349 --- /dev/null +++ b/src/backend/catalog/pg_partitioned_table_d.h @@ -0,0 +1,35 @@ +/*------------------------------------------------------------------------- + * + * pg_partitioned_table_d.h + * Macro definitions for pg_partitioned_table + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_PARTITIONED_TABLE_D_H +#define PG_PARTITIONED_TABLE_D_H + +#define PartitionedRelationId 3350 + +#define Anum_pg_partitioned_table_partrelid 1 +#define Anum_pg_partitioned_table_partstrat 2 +#define Anum_pg_partitioned_table_partnatts 3 +#define Anum_pg_partitioned_table_partdefid 4 +#define Anum_pg_partitioned_table_partattrs 5 +#define Anum_pg_partitioned_table_partclass 6 +#define Anum_pg_partitioned_table_partcollation 7 +#define Anum_pg_partitioned_table_partexprs 8 + +#define Natts_pg_partitioned_table 8 + + +#endif /* PG_PARTITIONED_TABLE_D_H */ diff --git a/src/backend/catalog/pg_policy_d.h b/src/backend/catalog/pg_policy_d.h new file mode 100644 index 0000000..1d1dd56 --- /dev/null +++ b/src/backend/catalog/pg_policy_d.h @@ -0,0 +1,35 @@ +/*------------------------------------------------------------------------- + * + * pg_policy_d.h + * Macro definitions for pg_policy + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_POLICY_D_H +#define PG_POLICY_D_H + +#define PolicyRelationId 3256 + +#define Anum_pg_policy_oid 1 +#define Anum_pg_policy_polname 2 +#define Anum_pg_policy_polrelid 3 +#define Anum_pg_policy_polcmd 4 +#define Anum_pg_policy_polpermissive 5 +#define Anum_pg_policy_polroles 6 +#define Anum_pg_policy_polqual 7 +#define Anum_pg_policy_polwithcheck 8 + +#define Natts_pg_policy 8 + + +#endif /* PG_POLICY_D_H */ diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c new file mode 100644 index 0000000..7c0a18d --- /dev/null +++ b/src/backend/catalog/pg_proc.c @@ -0,0 +1,1157 @@ +/*------------------------------------------------------------------------- + * + * pg_proc.c + * routines to support manipulation of the pg_proc relation + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/pg_proc.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/htup_details.h" +#include "access/table.h" +#include "access/xact.h" +#include "catalog/catalog.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/objectaccess.h" +#include "catalog/pg_language.h" +#include "catalog/pg_namespace.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_transform.h" +#include "catalog/pg_type.h" +#include "commands/defrem.h" +#include "executor/functions.h" +#include "funcapi.h" +#include "mb/pg_wchar.h" +#include "miscadmin.h" +#include "nodes/nodeFuncs.h" +#include "parser/parse_coerce.h" +#include "parser/parse_type.h" +#include "tcop/pquery.h" +#include "tcop/tcopprot.h" +#include "utils/acl.h" +#include "utils/builtins.h" +#include "utils/lsyscache.h" +#include "utils/regproc.h" +#include "utils/rel.h" +#include "utils/syscache.h" + + +typedef struct +{ + char *proname; + char *prosrc; +} parse_error_callback_arg; + +static void sql_function_parse_error_callback(void *arg); +static int match_prosrc_to_query(const char *prosrc, const char *queryText, + int cursorpos); +static bool match_prosrc_to_literal(const char *prosrc, const char *literal, + int cursorpos, int *newcursorpos); + + +/* ---------------------------------------------------------------- + * ProcedureCreate + * + * Note: allParameterTypes, parameterModes, parameterNames, trftypes, and proconfig + * are either arrays of the proper types or NULL. We declare them Datum, + * not "ArrayType *", to avoid importing array.h into pg_proc.h. + * ---------------------------------------------------------------- + */ +ObjectAddress +ProcedureCreate(const char *procedureName, + Oid procNamespace, + bool replace, + bool returnsSet, + Oid returnType, + Oid proowner, + Oid languageObjectId, + Oid languageValidator, + const char *prosrc, + const char *probin, + char prokind, + bool security_definer, + bool isLeakProof, + bool isStrict, + char volatility, + char parallel, + oidvector *parameterTypes, + Datum allParameterTypes, + Datum parameterModes, + Datum parameterNames, + List *parameterDefaults, + Datum trftypes, + Datum proconfig, + Oid prosupport, + float4 procost, + float4 prorows) +{ + Oid retval; + int parameterCount; + int allParamCount; + Oid *allParams; + char *paramModes = NULL; + Oid variadicType = InvalidOid; + Acl *proacl = NULL; + Relation rel; + HeapTuple tup; + HeapTuple oldtup; + bool nulls[Natts_pg_proc]; + Datum values[Natts_pg_proc]; + bool replaces[Natts_pg_proc]; + NameData procname; + TupleDesc tupDesc; + bool is_update; + ObjectAddress myself, + referenced; + char *detailmsg; + int i; + Oid trfid; + + /* + * sanity checks + */ + Assert(PointerIsValid(prosrc)); + + parameterCount = parameterTypes->dim1; + if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS) + ereport(ERROR, + (errcode(ERRCODE_TOO_MANY_ARGUMENTS), + errmsg_plural("functions cannot have more than %d argument", + "functions cannot have more than %d arguments", + FUNC_MAX_ARGS, + FUNC_MAX_ARGS))); + /* note: the above is correct, we do NOT count output arguments */ + + /* Deconstruct array inputs */ + if (allParameterTypes != PointerGetDatum(NULL)) + { + /* + * We expect the array to be a 1-D OID array; verify that. We don't + * need to use deconstruct_array() since the array data is just going + * to look like a C array of OID values. + */ + ArrayType *allParamArray = (ArrayType *) DatumGetPointer(allParameterTypes); + + allParamCount = ARR_DIMS(allParamArray)[0]; + if (ARR_NDIM(allParamArray) != 1 || + allParamCount <= 0 || + ARR_HASNULL(allParamArray) || + ARR_ELEMTYPE(allParamArray) != OIDOID) + elog(ERROR, "allParameterTypes is not a 1-D Oid array"); + allParams = (Oid *) ARR_DATA_PTR(allParamArray); + Assert(allParamCount >= parameterCount); + /* we assume caller got the contents right */ + } + else + { + allParamCount = parameterCount; + allParams = parameterTypes->values; + } + + if (parameterModes != PointerGetDatum(NULL)) + { + /* + * We expect the array to be a 1-D CHAR array; verify that. We don't + * need to use deconstruct_array() since the array data is just going + * to look like a C array of char values. + */ + ArrayType *modesArray = (ArrayType *) DatumGetPointer(parameterModes); + + if (ARR_NDIM(modesArray) != 1 || + ARR_DIMS(modesArray)[0] != allParamCount || + ARR_HASNULL(modesArray) || + ARR_ELEMTYPE(modesArray) != CHAROID) + elog(ERROR, "parameterModes is not a 1-D char array"); + paramModes = (char *) ARR_DATA_PTR(modesArray); + } + + /* + * Do not allow polymorphic return type unless there is a polymorphic + * input argument that we can use to deduce the actual return type. + */ + detailmsg = check_valid_polymorphic_signature(returnType, + parameterTypes->values, + parameterCount); + if (detailmsg) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("cannot determine result data type"), + errdetail_internal("%s", detailmsg))); + + /* + * Also, do not allow return type INTERNAL unless at least one input + * argument is INTERNAL. + */ + detailmsg = check_valid_internal_signature(returnType, + parameterTypes->values, + parameterCount); + if (detailmsg) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("unsafe use of pseudo-type \"internal\""), + errdetail_internal("%s", detailmsg))); + + /* + * Apply the same tests to any OUT arguments. + */ + if (allParameterTypes != PointerGetDatum(NULL)) + { + for (i = 0; i < allParamCount; i++) + { + if (paramModes == NULL || + paramModes[i] == PROARGMODE_IN || + paramModes[i] == PROARGMODE_VARIADIC) + continue; /* ignore input-only params */ + + detailmsg = check_valid_polymorphic_signature(allParams[i], + parameterTypes->values, + parameterCount); + if (detailmsg) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("cannot determine result data type"), + errdetail_internal("%s", detailmsg))); + detailmsg = check_valid_internal_signature(allParams[i], + parameterTypes->values, + parameterCount); + if (detailmsg) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("unsafe use of pseudo-type \"internal\""), + errdetail_internal("%s", detailmsg))); + } + } + + /* Identify variadic argument type, if any */ + if (paramModes != NULL) + { + /* + * Only the last input parameter can be variadic; if it is, save its + * element type. Errors here are just elog since caller should have + * checked this already. + */ + for (i = 0; i < allParamCount; i++) + { + switch (paramModes[i]) + { + case PROARGMODE_IN: + case PROARGMODE_INOUT: + if (OidIsValid(variadicType)) + elog(ERROR, "variadic parameter must be last"); + break; + case PROARGMODE_OUT: + case PROARGMODE_TABLE: + /* okay */ + break; + case PROARGMODE_VARIADIC: + if (OidIsValid(variadicType)) + elog(ERROR, "variadic parameter must be last"); + switch (allParams[i]) + { + case ANYOID: + variadicType = ANYOID; + break; + case ANYARRAYOID: + variadicType = ANYELEMENTOID; + break; + case ANYCOMPATIBLEARRAYOID: + variadicType = ANYCOMPATIBLEOID; + break; + default: + variadicType = get_element_type(allParams[i]); + if (!OidIsValid(variadicType)) + elog(ERROR, "variadic parameter is not an array"); + break; + } + break; + default: + elog(ERROR, "invalid parameter mode '%c'", paramModes[i]); + break; + } + } + } + + /* + * All seems OK; prepare the data to be inserted into pg_proc. + */ + + for (i = 0; i < Natts_pg_proc; ++i) + { + nulls[i] = false; + values[i] = (Datum) 0; + replaces[i] = true; + } + + namestrcpy(&procname, procedureName); + values[Anum_pg_proc_proname - 1] = NameGetDatum(&procname); + values[Anum_pg_proc_pronamespace - 1] = ObjectIdGetDatum(procNamespace); + values[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(proowner); + values[Anum_pg_proc_prolang - 1] = ObjectIdGetDatum(languageObjectId); + values[Anum_pg_proc_procost - 1] = Float4GetDatum(procost); + values[Anum_pg_proc_prorows - 1] = Float4GetDatum(prorows); + values[Anum_pg_proc_provariadic - 1] = ObjectIdGetDatum(variadicType); + values[Anum_pg_proc_prosupport - 1] = ObjectIdGetDatum(prosupport); + values[Anum_pg_proc_prokind - 1] = CharGetDatum(prokind); + values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer); + values[Anum_pg_proc_proleakproof - 1] = BoolGetDatum(isLeakProof); + values[Anum_pg_proc_proisstrict - 1] = BoolGetDatum(isStrict); + values[Anum_pg_proc_proretset - 1] = BoolGetDatum(returnsSet); + values[Anum_pg_proc_provolatile - 1] = CharGetDatum(volatility); + values[Anum_pg_proc_proparallel - 1] = CharGetDatum(parallel); + values[Anum_pg_proc_pronargs - 1] = UInt16GetDatum(parameterCount); + values[Anum_pg_proc_pronargdefaults - 1] = UInt16GetDatum(list_length(parameterDefaults)); + values[Anum_pg_proc_prorettype - 1] = ObjectIdGetDatum(returnType); + values[Anum_pg_proc_proargtypes - 1] = PointerGetDatum(parameterTypes); + if (allParameterTypes != PointerGetDatum(NULL)) + values[Anum_pg_proc_proallargtypes - 1] = allParameterTypes; + else + nulls[Anum_pg_proc_proallargtypes - 1] = true; + if (parameterModes != PointerGetDatum(NULL)) + values[Anum_pg_proc_proargmodes - 1] = parameterModes; + else + nulls[Anum_pg_proc_proargmodes - 1] = true; + if (parameterNames != PointerGetDatum(NULL)) + values[Anum_pg_proc_proargnames - 1] = parameterNames; + else + nulls[Anum_pg_proc_proargnames - 1] = true; + if (parameterDefaults != NIL) + values[Anum_pg_proc_proargdefaults - 1] = CStringGetTextDatum(nodeToString(parameterDefaults)); + else + nulls[Anum_pg_proc_proargdefaults - 1] = true; + if (trftypes != PointerGetDatum(NULL)) + values[Anum_pg_proc_protrftypes - 1] = trftypes; + else + nulls[Anum_pg_proc_protrftypes - 1] = true; + values[Anum_pg_proc_prosrc - 1] = CStringGetTextDatum(prosrc); + if (probin) + values[Anum_pg_proc_probin - 1] = CStringGetTextDatum(probin); + else + nulls[Anum_pg_proc_probin - 1] = true; + if (proconfig != PointerGetDatum(NULL)) + values[Anum_pg_proc_proconfig - 1] = proconfig; + else + nulls[Anum_pg_proc_proconfig - 1] = true; + /* proacl will be determined later */ + + rel = table_open(ProcedureRelationId, RowExclusiveLock); + tupDesc = RelationGetDescr(rel); + + /* Check for pre-existing definition */ + oldtup = SearchSysCache3(PROCNAMEARGSNSP, + PointerGetDatum(procedureName), + PointerGetDatum(parameterTypes), + ObjectIdGetDatum(procNamespace)); + + if (HeapTupleIsValid(oldtup)) + { + /* There is one; okay to replace it? */ + Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup); + Datum proargnames; + bool isnull; + const char *dropcmd; + + if (!replace) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_FUNCTION), + errmsg("function \"%s\" already exists with same argument types", + procedureName))); + if (!pg_proc_ownercheck(oldproc->oid, proowner)) + aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION, + procedureName); + + /* Not okay to change routine kind */ + if (oldproc->prokind != prokind) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot change routine kind"), + (oldproc->prokind == PROKIND_AGGREGATE ? + errdetail("\"%s\" is an aggregate function.", procedureName) : + oldproc->prokind == PROKIND_FUNCTION ? + errdetail("\"%s\" is a function.", procedureName) : + oldproc->prokind == PROKIND_PROCEDURE ? + errdetail("\"%s\" is a procedure.", procedureName) : + oldproc->prokind == PROKIND_WINDOW ? + errdetail("\"%s\" is a window function.", procedureName) : + 0))); + + dropcmd = (prokind == PROKIND_PROCEDURE ? "DROP PROCEDURE" : + prokind == PROKIND_AGGREGATE ? "DROP AGGREGATE" : + "DROP FUNCTION"); + + /* + * Not okay to change the return type of the existing proc, since + * existing rules, views, etc may depend on the return type. + * + * In case of a procedure, a changing return type means that whether + * the procedure has output parameters was changed. Since there is no + * user visible return type, we produce a more specific error message. + */ + if (returnType != oldproc->prorettype || + returnsSet != oldproc->proretset) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + prokind == PROKIND_PROCEDURE + ? errmsg("cannot change whether a procedure has output parameters") + : errmsg("cannot change return type of existing function"), + + /* + * translator: first %s is DROP FUNCTION, DROP PROCEDURE, or DROP + * AGGREGATE + */ + errhint("Use %s %s first.", + dropcmd, + format_procedure(oldproc->oid)))); + + /* + * If it returns RECORD, check for possible change of record type + * implied by OUT parameters + */ + if (returnType == RECORDOID) + { + TupleDesc olddesc; + TupleDesc newdesc; + + olddesc = build_function_result_tupdesc_t(oldtup); + newdesc = build_function_result_tupdesc_d(prokind, + allParameterTypes, + parameterModes, + parameterNames); + if (olddesc == NULL && newdesc == NULL) + /* ok, both are runtime-defined RECORDs */ ; + else if (olddesc == NULL || newdesc == NULL || + !equalTupleDescs(olddesc, newdesc)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("cannot change return type of existing function"), + errdetail("Row type defined by OUT parameters is different."), + /* translator: first %s is DROP FUNCTION or DROP PROCEDURE */ + errhint("Use %s %s first.", + dropcmd, + format_procedure(oldproc->oid)))); + } + + /* + * If there were any named input parameters, check to make sure the + * names have not been changed, as this could break existing calls. We + * allow adding names to formerly unnamed parameters, though. + */ + proargnames = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup, + Anum_pg_proc_proargnames, + &isnull); + if (!isnull) + { + Datum proargmodes; + char **old_arg_names; + char **new_arg_names; + int n_old_arg_names; + int n_new_arg_names; + int j; + + proargmodes = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup, + Anum_pg_proc_proargmodes, + &isnull); + if (isnull) + proargmodes = PointerGetDatum(NULL); /* just to be sure */ + + n_old_arg_names = get_func_input_arg_names(proargnames, + proargmodes, + &old_arg_names); + n_new_arg_names = get_func_input_arg_names(parameterNames, + parameterModes, + &new_arg_names); + for (j = 0; j < n_old_arg_names; j++) + { + if (old_arg_names[j] == NULL) + continue; + if (j >= n_new_arg_names || new_arg_names[j] == NULL || + strcmp(old_arg_names[j], new_arg_names[j]) != 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("cannot change name of input parameter \"%s\"", + old_arg_names[j]), + /* translator: first %s is DROP FUNCTION or DROP PROCEDURE */ + errhint("Use %s %s first.", + dropcmd, + format_procedure(oldproc->oid)))); + } + } + + /* + * If there are existing defaults, check compatibility: redefinition + * must not remove any defaults nor change their types. (Removing a + * default might cause a function to fail to satisfy an existing call. + * Changing type would only be possible if the associated parameter is + * polymorphic, and in such cases a change of default type might alter + * the resolved output type of existing calls.) + */ + if (oldproc->pronargdefaults != 0) + { + Datum proargdefaults; + List *oldDefaults; + ListCell *oldlc; + ListCell *newlc; + + if (list_length(parameterDefaults) < oldproc->pronargdefaults) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("cannot remove parameter defaults from existing function"), + /* translator: first %s is DROP FUNCTION or DROP PROCEDURE */ + errhint("Use %s %s first.", + dropcmd, + format_procedure(oldproc->oid)))); + + proargdefaults = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup, + Anum_pg_proc_proargdefaults, + &isnull); + Assert(!isnull); + oldDefaults = castNode(List, stringToNode(TextDatumGetCString(proargdefaults))); + Assert(list_length(oldDefaults) == oldproc->pronargdefaults); + + /* new list can have more defaults than old, advance over 'em */ + newlc = list_nth_cell(parameterDefaults, + list_length(parameterDefaults) - + oldproc->pronargdefaults); + + foreach(oldlc, oldDefaults) + { + Node *oldDef = (Node *) lfirst(oldlc); + Node *newDef = (Node *) lfirst(newlc); + + if (exprType(oldDef) != exprType(newDef)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("cannot change data type of existing parameter default value"), + /* translator: first %s is DROP FUNCTION or DROP PROCEDURE */ + errhint("Use %s %s first.", + dropcmd, + format_procedure(oldproc->oid)))); + newlc = lnext(parameterDefaults, newlc); + } + } + + /* + * Do not change existing oid, ownership or permissions, either. Note + * dependency-update code below has to agree with this decision. + */ + replaces[Anum_pg_proc_oid - 1] = false; + replaces[Anum_pg_proc_proowner - 1] = false; + replaces[Anum_pg_proc_proacl - 1] = false; + + /* Okay, do it... */ + tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces); + CatalogTupleUpdate(rel, &tup->t_self, tup); + + ReleaseSysCache(oldtup); + is_update = true; + } + else + { + /* Creating a new procedure */ + Oid newOid; + + /* First, get default permissions and set up proacl */ + proacl = get_user_default_acl(OBJECT_FUNCTION, proowner, + procNamespace); + if (proacl != NULL) + values[Anum_pg_proc_proacl - 1] = PointerGetDatum(proacl); + else + nulls[Anum_pg_proc_proacl - 1] = true; + + newOid = GetNewOidWithIndex(rel, ProcedureOidIndexId, + Anum_pg_proc_oid); + values[Anum_pg_proc_oid - 1] = ObjectIdGetDatum(newOid); + tup = heap_form_tuple(tupDesc, values, nulls); + CatalogTupleInsert(rel, tup); + is_update = false; + } + + + retval = ((Form_pg_proc) GETSTRUCT(tup))->oid; + + /* + * Create dependencies for the new function. If we are updating an + * existing function, first delete any existing pg_depend entries. + * (However, since we are not changing ownership or permissions, the + * shared dependencies do *not* need to change, and we leave them alone.) + */ + if (is_update) + deleteDependencyRecordsFor(ProcedureRelationId, retval, true); + + myself.classId = ProcedureRelationId; + myself.objectId = retval; + myself.objectSubId = 0; + + /* dependency on namespace */ + referenced.classId = NamespaceRelationId; + referenced.objectId = procNamespace; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + /* dependency on implementation language */ + referenced.classId = LanguageRelationId; + referenced.objectId = languageObjectId; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + /* dependency on return type */ + referenced.classId = TypeRelationId; + referenced.objectId = returnType; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + /* dependency on transform used by return type, if any */ + if ((trfid = get_transform_oid(returnType, languageObjectId, true))) + { + referenced.classId = TransformRelationId; + referenced.objectId = trfid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* dependency on parameter types */ + for (i = 0; i < allParamCount; i++) + { + referenced.classId = TypeRelationId; + referenced.objectId = allParams[i]; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + /* dependency on transform used by parameter type, if any */ + if ((trfid = get_transform_oid(allParams[i], languageObjectId, true))) + { + referenced.classId = TransformRelationId; + referenced.objectId = trfid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + } + + /* dependency on parameter default expressions */ + if (parameterDefaults) + recordDependencyOnExpr(&myself, (Node *) parameterDefaults, + NIL, DEPENDENCY_NORMAL); + + /* dependency on support function, if any */ + if (OidIsValid(prosupport)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = prosupport; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* dependency on owner */ + if (!is_update) + recordDependencyOnOwner(ProcedureRelationId, retval, proowner); + + /* dependency on any roles mentioned in ACL */ + if (!is_update) + recordDependencyOnNewAcl(ProcedureRelationId, retval, 0, + proowner, proacl); + + /* dependency on extension */ + recordDependencyOnCurrentExtension(&myself, is_update); + + heap_freetuple(tup); + + /* Post creation hook for new function */ + InvokeObjectPostCreateHook(ProcedureRelationId, retval, 0); + + table_close(rel, RowExclusiveLock); + + /* Verify function body */ + if (OidIsValid(languageValidator)) + { + ArrayType *set_items = NULL; + int save_nestlevel = 0; + + /* Advance command counter so new tuple can be seen by validator */ + CommandCounterIncrement(); + + /* + * Set per-function configuration parameters so that the validation is + * done with the environment the function expects. However, if + * check_function_bodies is off, we don't do this, because that would + * create dump ordering hazards that pg_dump doesn't know how to deal + * with. (For example, a SET clause might refer to a not-yet-created + * text search configuration.) This means that the validator + * shouldn't complain about anything that might depend on a GUC + * parameter when check_function_bodies is off. + */ + if (check_function_bodies) + { + set_items = (ArrayType *) DatumGetPointer(proconfig); + if (set_items) /* Need a new GUC nesting level */ + { + save_nestlevel = NewGUCNestLevel(); + ProcessGUCArray(set_items, + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, + GUC_ACTION_SAVE); + } + } + + OidFunctionCall1(languageValidator, ObjectIdGetDatum(retval)); + + if (set_items) + AtEOXact_GUC(true, save_nestlevel); + } + + return myself; +} + + + +/* + * Validator for internal functions + * + * Check that the given internal function name (the "prosrc" value) is + * a known builtin function. + */ +Datum +fmgr_internal_validator(PG_FUNCTION_ARGS) +{ + Oid funcoid = PG_GETARG_OID(0); + HeapTuple tuple; + bool isnull; + Datum tmp; + char *prosrc; + + if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid)) + PG_RETURN_VOID(); + + /* + * We do not honor check_function_bodies since it's unlikely the function + * name will be found later if it isn't there now. + */ + + tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for function %u", funcoid); + + tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull); + if (isnull) + elog(ERROR, "null prosrc"); + prosrc = TextDatumGetCString(tmp); + + if (fmgr_internal_function(prosrc) == InvalidOid) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("there is no built-in function named \"%s\"", + prosrc))); + + ReleaseSysCache(tuple); + + PG_RETURN_VOID(); +} + + + +/* + * Validator for C language functions + * + * Make sure that the library file exists, is loadable, and contains + * the specified link symbol. Also check for a valid function + * information record. + */ +Datum +fmgr_c_validator(PG_FUNCTION_ARGS) +{ + Oid funcoid = PG_GETARG_OID(0); + void *libraryhandle; + HeapTuple tuple; + bool isnull; + Datum tmp; + char *prosrc; + char *probin; + + if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid)) + PG_RETURN_VOID(); + + /* + * It'd be most consistent to skip the check if !check_function_bodies, + * but the purpose of that switch is to be helpful for pg_dump loading, + * and for pg_dump loading it's much better if we *do* check. + */ + + tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for function %u", funcoid); + + tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull); + if (isnull) + elog(ERROR, "null prosrc for C function %u", funcoid); + prosrc = TextDatumGetCString(tmp); + + tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_probin, &isnull); + if (isnull) + elog(ERROR, "null probin for C function %u", funcoid); + probin = TextDatumGetCString(tmp); + + (void) load_external_function(probin, prosrc, true, &libraryhandle); + (void) fetch_finfo_record(libraryhandle, prosrc); + + ReleaseSysCache(tuple); + + PG_RETURN_VOID(); +} + + +/* + * Validator for SQL language functions + * + * Parse it here in order to be sure that it contains no syntax errors. + */ +Datum +fmgr_sql_validator(PG_FUNCTION_ARGS) +{ + Oid funcoid = PG_GETARG_OID(0); + HeapTuple tuple; + Form_pg_proc proc; + List *raw_parsetree_list; + List *querytree_list; + ListCell *lc; + bool isnull; + Datum tmp; + char *prosrc; + parse_error_callback_arg callback_arg; + ErrorContextCallback sqlerrcontext; + bool haspolyarg; + int i; + + if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid)) + PG_RETURN_VOID(); + + tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for function %u", funcoid); + proc = (Form_pg_proc) GETSTRUCT(tuple); + + /* Disallow pseudotype result */ + /* except for RECORD, VOID, or polymorphic */ + if (get_typtype(proc->prorettype) == TYPTYPE_PSEUDO && + proc->prorettype != RECORDOID && + proc->prorettype != VOIDOID && + !IsPolymorphicType(proc->prorettype)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("SQL functions cannot return type %s", + format_type_be(proc->prorettype)))); + + /* Disallow pseudotypes in arguments */ + /* except for polymorphic */ + haspolyarg = false; + for (i = 0; i < proc->pronargs; i++) + { + if (get_typtype(proc->proargtypes.values[i]) == TYPTYPE_PSEUDO) + { + if (IsPolymorphicType(proc->proargtypes.values[i])) + haspolyarg = true; + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("SQL functions cannot have arguments of type %s", + format_type_be(proc->proargtypes.values[i])))); + } + } + + /* Postpone body checks if !check_function_bodies */ + if (check_function_bodies) + { + tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull); + if (isnull) + elog(ERROR, "null prosrc"); + + prosrc = TextDatumGetCString(tmp); + + /* + * Setup error traceback support for ereport(). + */ + callback_arg.proname = NameStr(proc->proname); + callback_arg.prosrc = prosrc; + + sqlerrcontext.callback = sql_function_parse_error_callback; + sqlerrcontext.arg = (void *) &callback_arg; + sqlerrcontext.previous = error_context_stack; + error_context_stack = &sqlerrcontext; + + /* + * We can't do full prechecking of the function definition if there + * are any polymorphic input types, because actual datatypes of + * expression results will be unresolvable. The check will be done at + * runtime instead. + * + * We can run the text through the raw parser though; this will at + * least catch silly syntactic errors. + */ + raw_parsetree_list = pg_parse_query(prosrc); + + if (!haspolyarg) + { + /* + * OK to do full precheck: analyze and rewrite the queries, then + * verify the result type. + */ + SQLFunctionParseInfoPtr pinfo; + Oid rettype; + TupleDesc rettupdesc; + + /* But first, set up parameter information */ + pinfo = prepare_sql_fn_parse_info(tuple, NULL, InvalidOid); + + querytree_list = NIL; + foreach(lc, raw_parsetree_list) + { + RawStmt *parsetree = lfirst_node(RawStmt, lc); + List *querytree_sublist; + + querytree_sublist = pg_analyze_and_rewrite_params(parsetree, + prosrc, + (ParserSetupHook) sql_fn_parser_setup, + pinfo, + NULL); + querytree_list = lappend(querytree_list, + querytree_sublist); + } + + check_sql_fn_statements(querytree_list); + + (void) get_func_result_type(funcoid, &rettype, &rettupdesc); + + (void) check_sql_fn_retval(querytree_list, + rettype, rettupdesc, + false, NULL); + } + + error_context_stack = sqlerrcontext.previous; + } + + ReleaseSysCache(tuple); + + PG_RETURN_VOID(); +} + +/* + * Error context callback for handling errors in SQL function definitions + */ +static void +sql_function_parse_error_callback(void *arg) +{ + parse_error_callback_arg *callback_arg = (parse_error_callback_arg *) arg; + + /* See if it's a syntax error; if so, transpose to CREATE FUNCTION */ + if (!function_parse_error_transpose(callback_arg->prosrc)) + { + /* If it's not a syntax error, push info onto context stack */ + errcontext("SQL function \"%s\"", callback_arg->proname); + } +} + +/* + * Adjust a syntax error occurring inside the function body of a CREATE + * FUNCTION or DO command. This can be used by any function validator or + * anonymous-block handler, not only for SQL-language functions. + * It is assumed that the syntax error position is initially relative to the + * function body string (as passed in). If possible, we adjust the position + * to reference the original command text; if we can't manage that, we set + * up an "internal query" syntax error instead. + * + * Returns true if a syntax error was processed, false if not. + */ +bool +function_parse_error_transpose(const char *prosrc) +{ + int origerrposition; + int newerrposition; + const char *queryText; + + /* + * Nothing to do unless we are dealing with a syntax error that has a + * cursor position. + * + * Some PLs may prefer to report the error position as an internal error + * to begin with, so check that too. + */ + origerrposition = geterrposition(); + if (origerrposition <= 0) + { + origerrposition = getinternalerrposition(); + if (origerrposition <= 0) + return false; + } + + /* We can get the original query text from the active portal (hack...) */ + Assert(ActivePortal && ActivePortal->status == PORTAL_ACTIVE); + queryText = ActivePortal->sourceText; + + /* Try to locate the prosrc in the original text */ + newerrposition = match_prosrc_to_query(prosrc, queryText, origerrposition); + + if (newerrposition > 0) + { + /* Successful, so fix error position to reference original query */ + errposition(newerrposition); + /* Get rid of any report of the error as an "internal query" */ + internalerrposition(0); + internalerrquery(NULL); + } + else + { + /* + * If unsuccessful, convert the position to an internal position + * marker and give the function text as the internal query. + */ + errposition(0); + internalerrposition(origerrposition); + internalerrquery(prosrc); + } + + return true; +} + +/* + * Try to locate the string literal containing the function body in the + * given text of the CREATE FUNCTION or DO command. If successful, return + * the character (not byte) index within the command corresponding to the + * given character index within the literal. If not successful, return 0. + */ +static int +match_prosrc_to_query(const char *prosrc, const char *queryText, + int cursorpos) +{ + /* + * Rather than fully parsing the original command, we just scan the + * command looking for $prosrc$ or 'prosrc'. This could be fooled (though + * not in any very probable scenarios), so fail if we find more than one + * match. + */ + int prosrclen = strlen(prosrc); + int querylen = strlen(queryText); + int matchpos = 0; + int curpos; + int newcursorpos; + + for (curpos = 0; curpos < querylen - prosrclen; curpos++) + { + if (queryText[curpos] == '$' && + strncmp(prosrc, &queryText[curpos + 1], prosrclen) == 0 && + queryText[curpos + 1 + prosrclen] == '$') + { + /* + * Found a $foo$ match. Since there are no embedded quoting + * characters in a dollar-quoted literal, we don't have to do any + * fancy arithmetic; just offset by the starting position. + */ + if (matchpos) + return 0; /* multiple matches, fail */ + matchpos = pg_mbstrlen_with_len(queryText, curpos + 1) + + cursorpos; + } + else if (queryText[curpos] == '\'' && + match_prosrc_to_literal(prosrc, &queryText[curpos + 1], + cursorpos, &newcursorpos)) + { + /* + * Found a 'foo' match. match_prosrc_to_literal() has adjusted + * for any quotes or backslashes embedded in the literal. + */ + if (matchpos) + return 0; /* multiple matches, fail */ + matchpos = pg_mbstrlen_with_len(queryText, curpos + 1) + + newcursorpos; + } + } + + return matchpos; +} + +/* + * Try to match the given source text to a single-quoted literal. + * If successful, adjust newcursorpos to correspond to the character + * (not byte) index corresponding to cursorpos in the source text. + * + * At entry, literal points just past a ' character. We must check for the + * trailing quote. + */ +static bool +match_prosrc_to_literal(const char *prosrc, const char *literal, + int cursorpos, int *newcursorpos) +{ + int newcp = cursorpos; + int chlen; + + /* + * This implementation handles backslashes and doubled quotes in the + * string literal. It does not handle the SQL syntax for literals + * continued across line boundaries. + * + * We do the comparison a character at a time, not a byte at a time, so + * that we can do the correct cursorpos math. + */ + while (*prosrc) + { + cursorpos--; /* characters left before cursor */ + + /* + * Check for backslashes and doubled quotes in the literal; adjust + * newcp when one is found before the cursor. + */ + if (*literal == '\\') + { + literal++; + if (cursorpos > 0) + newcp++; + } + else if (*literal == '\'') + { + if (literal[1] != '\'') + goto fail; + literal++; + if (cursorpos > 0) + newcp++; + } + chlen = pg_mblen(prosrc); + if (strncmp(prosrc, literal, chlen) != 0) + goto fail; + prosrc += chlen; + literal += chlen; + } + + if (*literal == '\'' && literal[1] != '\'') + { + /* success */ + *newcursorpos = newcp; + return true; + } + +fail: + /* Must set *newcursorpos to suppress compiler warning */ + *newcursorpos = newcp; + return false; +} + +List * +oid_array_to_list(Datum datum) +{ + ArrayType *array = DatumGetArrayTypeP(datum); + Datum *values; + int nelems; + int i; + List *result = NIL; + + deconstruct_array(array, + OIDOID, + sizeof(Oid), true, TYPALIGN_INT, + &values, NULL, &nelems); + for (i = 0; i < nelems; i++) + result = lappend_oid(result, values[i]); + return result; +} diff --git a/src/backend/catalog/pg_proc_d.h b/src/backend/catalog/pg_proc_d.h new file mode 100644 index 0000000..973c779 --- /dev/null +++ b/src/backend/catalog/pg_proc_d.h @@ -0,0 +1,99 @@ +/*------------------------------------------------------------------------- + * + * pg_proc_d.h + * Macro definitions for pg_proc + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_PROC_D_H +#define PG_PROC_D_H + +#define ProcedureRelationId 1255 +#define ProcedureRelation_Rowtype_Id 81 + +#define Anum_pg_proc_oid 1 +#define Anum_pg_proc_proname 2 +#define Anum_pg_proc_pronamespace 3 +#define Anum_pg_proc_proowner 4 +#define Anum_pg_proc_prolang 5 +#define Anum_pg_proc_procost 6 +#define Anum_pg_proc_prorows 7 +#define Anum_pg_proc_provariadic 8 +#define Anum_pg_proc_prosupport 9 +#define Anum_pg_proc_prokind 10 +#define Anum_pg_proc_prosecdef 11 +#define Anum_pg_proc_proleakproof 12 +#define Anum_pg_proc_proisstrict 13 +#define Anum_pg_proc_proretset 14 +#define Anum_pg_proc_provolatile 15 +#define Anum_pg_proc_proparallel 16 +#define Anum_pg_proc_pronargs 17 +#define Anum_pg_proc_pronargdefaults 18 +#define Anum_pg_proc_prorettype 19 +#define Anum_pg_proc_proargtypes 20 +#define Anum_pg_proc_proallargtypes 21 +#define Anum_pg_proc_proargmodes 22 +#define Anum_pg_proc_proargnames 23 +#define Anum_pg_proc_proargdefaults 24 +#define Anum_pg_proc_protrftypes 25 +#define Anum_pg_proc_prosrc 26 +#define Anum_pg_proc_probin 27 +#define Anum_pg_proc_proconfig 28 +#define Anum_pg_proc_proacl 29 + +#define Natts_pg_proc 29 + + +/* + * Symbolic values for prokind column + */ +#define PROKIND_FUNCTION 'f' +#define PROKIND_AGGREGATE 'a' +#define PROKIND_WINDOW 'w' +#define PROKIND_PROCEDURE 'p' + +/* + * Symbolic values for provolatile column: these indicate whether the result + * of a function is dependent *only* on the values of its explicit arguments, + * or can change due to outside factors (such as parameter variables or + * table contents). NOTE: functions having side-effects, such as setval(), + * must be labeled volatile to ensure they will not get optimized away, + * even if the actual return value is not changeable. + */ +#define PROVOLATILE_IMMUTABLE 'i' /* never changes for given input */ +#define PROVOLATILE_STABLE 's' /* does not change within a scan */ +#define PROVOLATILE_VOLATILE 'v' /* can change even within a scan */ + +/* + * Symbolic values for proparallel column: these indicate whether a function + * can be safely be run in a parallel backend, during parallelism but + * necessarily in the master, or only in non-parallel mode. + */ +#define PROPARALLEL_SAFE 's' /* can run in worker or master */ +#define PROPARALLEL_RESTRICTED 'r' /* can run in parallel master only */ +#define PROPARALLEL_UNSAFE 'u' /* banned while in parallel mode */ + +/* + * Symbolic values for proargmodes column. Note that these must agree with + * the FunctionParameterMode enum in parsenodes.h; we declare them here to + * be accessible from either header. + */ +#define PROARGMODE_IN 'i' +#define PROARGMODE_OUT 'o' +#define PROARGMODE_INOUT 'b' +#define PROARGMODE_VARIADIC 'v' +#define PROARGMODE_TABLE 't' + +#define HEAP_TABLE_AM_HANDLER_OID 3 + +#endif /* PG_PROC_D_H */ diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c new file mode 100644 index 0000000..61bed1d --- /dev/null +++ b/src/backend/catalog/pg_publication.c @@ -0,0 +1,557 @@ +/*------------------------------------------------------------------------- + * + * pg_publication.c + * publication C API manipulation + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * pg_publication.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/genam.h" +#include "access/heapam.h" +#include "access/htup_details.h" +#include "access/tableam.h" +#include "access/xact.h" +#include "catalog/catalog.h" +#include "catalog/dependency.h" +#include "catalog/index.h" +#include "catalog/indexing.h" +#include "catalog/namespace.h" +#include "catalog/partition.h" +#include "catalog/objectaccess.h" +#include "catalog/objectaddress.h" +#include "catalog/pg_inherits.h" +#include "catalog/pg_publication.h" +#include "catalog/pg_publication_rel.h" +#include "catalog/pg_type.h" +#include "funcapi.h" +#include "miscadmin.h" +#include "utils/array.h" +#include "utils/builtins.h" +#include "utils/catcache.h" +#include "utils/fmgroids.h" +#include "utils/inval.h" +#include "utils/lsyscache.h" +#include "utils/rel.h" +#include "utils/syscache.h" + +/* + * Check if relation can be in given publication and throws appropriate + * error if not. + */ +static void +check_publication_add_relation(Relation targetrel) +{ + /* Must be a regular or partitioned table */ + if (RelationGetForm(targetrel)->relkind != RELKIND_RELATION && + RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("\"%s\" is not a table", + RelationGetRelationName(targetrel)), + errdetail("Only tables can be added to publications."))); + + /* Can't be system table */ + if (IsCatalogRelation(targetrel)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("\"%s\" is a system table", + RelationGetRelationName(targetrel)), + errdetail("System tables cannot be added to publications."))); + + /* UNLOGGED and TEMP relations cannot be part of publication. */ + if (targetrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("table \"%s\" cannot be replicated", + RelationGetRelationName(targetrel)), + errdetail("Temporary and unlogged relations cannot be replicated."))); +} + +/* + * Returns if relation represented by oid and Form_pg_class entry + * is publishable. + * + * Does same checks as the above, but does not need relation to be opened + * and also does not throw errors. + * + * XXX This also excludes all tables with relid < FirstNormalObjectId, + * ie all tables created during initdb. This mainly affects the preinstalled + * information_schema. IsCatalogRelationOid() only excludes tables with + * relid < FirstBootstrapObjectId, making that test rather redundant, + * but really we should get rid of the FirstNormalObjectId test not + * IsCatalogRelationOid. We can't do so today because we don't want + * information_schema tables to be considered publishable; but this test + * is really inadequate for that, since the information_schema could be + * dropped and reloaded and then it'll be considered publishable. The best + * long-term solution may be to add a "relispublishable" bool to pg_class, + * and depend on that instead of OID checks. + */ +static bool +is_publishable_class(Oid relid, Form_pg_class reltuple) +{ + return (reltuple->relkind == RELKIND_RELATION || + reltuple->relkind == RELKIND_PARTITIONED_TABLE) && + !IsCatalogRelationOid(relid) && + reltuple->relpersistence == RELPERSISTENCE_PERMANENT && + relid >= FirstNormalObjectId; +} + +/* + * Another variant of this, taking a Relation. + */ +bool +is_publishable_relation(Relation rel) +{ + return is_publishable_class(RelationGetRelid(rel), rel->rd_rel); +} + + +/* + * SQL-callable variant of the above + * + * This returns null when the relation does not exist. This is intended to be + * used for example in psql to avoid gratuitous errors when there are + * concurrent catalog changes. + */ +Datum +pg_relation_is_publishable(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + HeapTuple tuple; + bool result; + + tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(tuple)) + PG_RETURN_NULL(); + result = is_publishable_class(relid, (Form_pg_class) GETSTRUCT(tuple)); + ReleaseSysCache(tuple); + PG_RETURN_BOOL(result); +} + + +/* + * Insert new publication / relation mapping. + */ +ObjectAddress +publication_add_relation(Oid pubid, Relation targetrel, + bool if_not_exists) +{ + Relation rel; + HeapTuple tup; + Datum values[Natts_pg_publication_rel]; + bool nulls[Natts_pg_publication_rel]; + Oid relid = RelationGetRelid(targetrel); + Oid prrelid; + Publication *pub = GetPublication(pubid); + ObjectAddress myself, + referenced; + + rel = table_open(PublicationRelRelationId, RowExclusiveLock); + + /* + * Check for duplicates. Note that this does not really prevent + * duplicates, it's here just to provide nicer error message in common + * case. The real protection is the unique key on the catalog. + */ + if (SearchSysCacheExists2(PUBLICATIONRELMAP, ObjectIdGetDatum(relid), + ObjectIdGetDatum(pubid))) + { + table_close(rel, RowExclusiveLock); + + if (if_not_exists) + return InvalidObjectAddress; + + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("relation \"%s\" is already member of publication \"%s\"", + RelationGetRelationName(targetrel), pub->name))); + } + + check_publication_add_relation(targetrel); + + /* Form a tuple. */ + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + + prrelid = GetNewOidWithIndex(rel, PublicationRelObjectIndexId, + Anum_pg_publication_rel_oid); + values[Anum_pg_publication_rel_oid - 1] = ObjectIdGetDatum(prrelid); + values[Anum_pg_publication_rel_prpubid - 1] = + ObjectIdGetDatum(pubid); + values[Anum_pg_publication_rel_prrelid - 1] = + ObjectIdGetDatum(relid); + + tup = heap_form_tuple(RelationGetDescr(rel), values, nulls); + + /* Insert tuple into catalog. */ + CatalogTupleInsert(rel, tup); + heap_freetuple(tup); + + ObjectAddressSet(myself, PublicationRelRelationId, prrelid); + + /* Add dependency on the publication */ + ObjectAddressSet(referenced, PublicationRelationId, pubid); + recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); + + /* Add dependency on the relation */ + ObjectAddressSet(referenced, RelationRelationId, relid); + recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); + + /* Close the table. */ + table_close(rel, RowExclusiveLock); + + /* Invalidate relcache so that publication info is rebuilt. */ + CacheInvalidateRelcache(targetrel); + + return myself; +} + +/* Gets list of publication oids for a relation */ +List * +GetRelationPublications(Oid relid) +{ + List *result = NIL; + CatCList *pubrellist; + int i; + + /* Find all publications associated with the relation. */ + pubrellist = SearchSysCacheList1(PUBLICATIONRELMAP, + ObjectIdGetDatum(relid)); + for (i = 0; i < pubrellist->n_members; i++) + { + HeapTuple tup = &pubrellist->members[i]->tuple; + Oid pubid = ((Form_pg_publication_rel) GETSTRUCT(tup))->prpubid; + + result = lappend_oid(result, pubid); + } + + ReleaseSysCacheList(pubrellist); + + return result; +} + +/* + * Gets list of relation oids for a publication. + * + * This should only be used for normal publications, the FOR ALL TABLES + * should use GetAllTablesPublicationRelations(). + */ +List * +GetPublicationRelations(Oid pubid, PublicationPartOpt pub_partopt) +{ + List *result; + Relation pubrelsrel; + ScanKeyData scankey; + SysScanDesc scan; + HeapTuple tup; + + /* Find all publications associated with the relation. */ + pubrelsrel = table_open(PublicationRelRelationId, AccessShareLock); + + ScanKeyInit(&scankey, + Anum_pg_publication_rel_prpubid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(pubid)); + + scan = systable_beginscan(pubrelsrel, PublicationRelPrrelidPrpubidIndexId, + true, NULL, 1, &scankey); + + result = NIL; + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_publication_rel pubrel; + + pubrel = (Form_pg_publication_rel) GETSTRUCT(tup); + + if (get_rel_relkind(pubrel->prrelid) == RELKIND_PARTITIONED_TABLE && + pub_partopt != PUBLICATION_PART_ROOT) + { + List *all_parts = find_all_inheritors(pubrel->prrelid, NoLock, + NULL); + + if (pub_partopt == PUBLICATION_PART_ALL) + result = list_concat(result, all_parts); + else if (pub_partopt == PUBLICATION_PART_LEAF) + { + ListCell *lc; + + foreach(lc, all_parts) + { + Oid partOid = lfirst_oid(lc); + + if (get_rel_relkind(partOid) != RELKIND_PARTITIONED_TABLE) + result = lappend_oid(result, partOid); + } + } + else + Assert(false); + } + else + result = lappend_oid(result, pubrel->prrelid); + } + + systable_endscan(scan); + table_close(pubrelsrel, AccessShareLock); + + return result; +} + +/* + * Gets list of publication oids for publications marked as FOR ALL TABLES. + */ +List * +GetAllTablesPublications(void) +{ + List *result; + Relation rel; + ScanKeyData scankey; + SysScanDesc scan; + HeapTuple tup; + + /* Find all publications that are marked as for all tables. */ + rel = table_open(PublicationRelationId, AccessShareLock); + + ScanKeyInit(&scankey, + Anum_pg_publication_puballtables, + BTEqualStrategyNumber, F_BOOLEQ, + BoolGetDatum(true)); + + scan = systable_beginscan(rel, InvalidOid, false, + NULL, 1, &scankey); + + result = NIL; + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Oid oid = ((Form_pg_publication) GETSTRUCT(tup))->oid; + + result = lappend_oid(result, oid); + } + + systable_endscan(scan); + table_close(rel, AccessShareLock); + + return result; +} + +/* + * Gets list of all relation published by FOR ALL TABLES publication(s). + * + * If the publication publishes partition changes via their respective root + * partitioned tables, we must exclude partitions in favor of including the + * root partitioned tables. + */ +List * +GetAllTablesPublicationRelations(bool pubviaroot) +{ + Relation classRel; + ScanKeyData key[1]; + TableScanDesc scan; + HeapTuple tuple; + List *result = NIL; + + classRel = table_open(RelationRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_class_relkind, + BTEqualStrategyNumber, F_CHAREQ, + CharGetDatum(RELKIND_RELATION)); + + scan = table_beginscan_catalog(classRel, 1, key); + + while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) + { + Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple); + Oid relid = relForm->oid; + + if (is_publishable_class(relid, relForm) && + !(relForm->relispartition && pubviaroot)) + result = lappend_oid(result, relid); + } + + table_endscan(scan); + + if (pubviaroot) + { + ScanKeyInit(&key[0], + Anum_pg_class_relkind, + BTEqualStrategyNumber, F_CHAREQ, + CharGetDatum(RELKIND_PARTITIONED_TABLE)); + + scan = table_beginscan_catalog(classRel, 1, key); + + while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) + { + Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple); + Oid relid = relForm->oid; + + if (is_publishable_class(relid, relForm) && + !relForm->relispartition) + result = lappend_oid(result, relid); + } + + table_endscan(scan); + } + + table_close(classRel, AccessShareLock); + return result; +} + +/* + * Get publication using oid + * + * The Publication struct and its data are palloc'ed here. + */ +Publication * +GetPublication(Oid pubid) +{ + HeapTuple tup; + Publication *pub; + Form_pg_publication pubform; + + tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for publication %u", pubid); + + pubform = (Form_pg_publication) GETSTRUCT(tup); + + pub = (Publication *) palloc(sizeof(Publication)); + pub->oid = pubid; + pub->name = pstrdup(NameStr(pubform->pubname)); + pub->alltables = pubform->puballtables; + pub->pubactions.pubinsert = pubform->pubinsert; + pub->pubactions.pubupdate = pubform->pubupdate; + pub->pubactions.pubdelete = pubform->pubdelete; + pub->pubactions.pubtruncate = pubform->pubtruncate; + pub->pubviaroot = pubform->pubviaroot; + + ReleaseSysCache(tup); + + return pub; +} + + +/* + * Get Publication using name. + */ +Publication * +GetPublicationByName(const char *pubname, bool missing_ok) +{ + Oid oid; + + oid = get_publication_oid(pubname, missing_ok); + + return OidIsValid(oid) ? GetPublication(oid) : NULL; +} + +/* + * get_publication_oid - given a publication name, look up the OID + * + * If missing_ok is false, throw an error if name not found. If true, just + * return InvalidOid. + */ +Oid +get_publication_oid(const char *pubname, bool missing_ok) +{ + Oid oid; + + oid = GetSysCacheOid1(PUBLICATIONNAME, Anum_pg_publication_oid, + CStringGetDatum(pubname)); + if (!OidIsValid(oid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("publication \"%s\" does not exist", pubname))); + return oid; +} + +/* + * get_publication_name - given a publication Oid, look up the name + * + * If missing_ok is false, throw an error if name not found. If true, just + * return NULL. + */ +char * +get_publication_name(Oid pubid, bool missing_ok) +{ + HeapTuple tup; + char *pubname; + Form_pg_publication pubform; + + tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid)); + + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "cache lookup failed for publication %u", pubid); + return NULL; + } + + pubform = (Form_pg_publication) GETSTRUCT(tup); + pubname = pstrdup(NameStr(pubform->pubname)); + + ReleaseSysCache(tup); + + return pubname; +} + +/* + * Returns Oids of tables in a publication. + */ +Datum +pg_get_publication_tables(PG_FUNCTION_ARGS) +{ + FuncCallContext *funcctx; + char *pubname = text_to_cstring(PG_GETARG_TEXT_PP(0)); + Publication *publication; + List *tables; + + /* stuff done only on the first call of the function */ + if (SRF_IS_FIRSTCALL()) + { + MemoryContext oldcontext; + + /* create a function context for cross-call persistence */ + funcctx = SRF_FIRSTCALL_INIT(); + + /* switch to memory context appropriate for multiple function calls */ + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + publication = GetPublicationByName(pubname, false); + + /* + * Publications support partitioned tables, although all changes are + * replicated using leaf partition identity and schema, so we only + * need those. + */ + if (publication->alltables) + tables = GetAllTablesPublicationRelations(publication->pubviaroot); + else + tables = GetPublicationRelations(publication->oid, + publication->pubviaroot ? + PUBLICATION_PART_ROOT : + PUBLICATION_PART_LEAF); + funcctx->user_fctx = (void *) tables; + + MemoryContextSwitchTo(oldcontext); + } + + /* stuff done on every call of the function */ + funcctx = SRF_PERCALL_SETUP(); + tables = (List *) funcctx->user_fctx; + + if (funcctx->call_cntr < list_length(tables)) + { + Oid relid = list_nth_oid(tables, funcctx->call_cntr); + + SRF_RETURN_NEXT(funcctx, ObjectIdGetDatum(relid)); + } + + SRF_RETURN_DONE(funcctx); +} diff --git a/src/backend/catalog/pg_publication_d.h b/src/backend/catalog/pg_publication_d.h new file mode 100644 index 0000000..ac09853 --- /dev/null +++ b/src/backend/catalog/pg_publication_d.h @@ -0,0 +1,36 @@ +/*------------------------------------------------------------------------- + * + * pg_publication_d.h + * Macro definitions for pg_publication + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_PUBLICATION_D_H +#define PG_PUBLICATION_D_H + +#define PublicationRelationId 6104 + +#define Anum_pg_publication_oid 1 +#define Anum_pg_publication_pubname 2 +#define Anum_pg_publication_pubowner 3 +#define Anum_pg_publication_puballtables 4 +#define Anum_pg_publication_pubinsert 5 +#define Anum_pg_publication_pubupdate 6 +#define Anum_pg_publication_pubdelete 7 +#define Anum_pg_publication_pubtruncate 8 +#define Anum_pg_publication_pubviaroot 9 + +#define Natts_pg_publication 9 + + +#endif /* PG_PUBLICATION_D_H */ diff --git a/src/backend/catalog/pg_publication_rel_d.h b/src/backend/catalog/pg_publication_rel_d.h new file mode 100644 index 0000000..ed1b500 --- /dev/null +++ b/src/backend/catalog/pg_publication_rel_d.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * pg_publication_rel_d.h + * Macro definitions for pg_publication_rel + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_PUBLICATION_REL_D_H +#define PG_PUBLICATION_REL_D_H + +#define PublicationRelRelationId 6106 + +#define Anum_pg_publication_rel_oid 1 +#define Anum_pg_publication_rel_prpubid 2 +#define Anum_pg_publication_rel_prrelid 3 + +#define Natts_pg_publication_rel 3 + + +#endif /* PG_PUBLICATION_REL_D_H */ diff --git a/src/backend/catalog/pg_range.c b/src/backend/catalog/pg_range.c new file mode 100644 index 0000000..b5bc36c --- /dev/null +++ b/src/backend/catalog/pg_range.c @@ -0,0 +1,137 @@ +/*------------------------------------------------------------------------- + * + * pg_range.c + * routines to support manipulation of the pg_range relation + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/pg_range.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/genam.h" +#include "access/htup_details.h" +#include "access/table.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/pg_collation.h" +#include "catalog/pg_opclass.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_range.h" +#include "catalog/pg_type.h" +#include "utils/fmgroids.h" +#include "utils/rel.h" + + +/* + * RangeCreate + * Create an entry in pg_range. + */ +void +RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation, + Oid rangeSubOpclass, RegProcedure rangeCanonical, + RegProcedure rangeSubDiff) +{ + Relation pg_range; + Datum values[Natts_pg_range]; + bool nulls[Natts_pg_range]; + HeapTuple tup; + ObjectAddress myself; + ObjectAddress referenced; + + pg_range = table_open(RangeRelationId, RowExclusiveLock); + + memset(nulls, 0, sizeof(nulls)); + + values[Anum_pg_range_rngtypid - 1] = ObjectIdGetDatum(rangeTypeOid); + values[Anum_pg_range_rngsubtype - 1] = ObjectIdGetDatum(rangeSubType); + values[Anum_pg_range_rngcollation - 1] = ObjectIdGetDatum(rangeCollation); + values[Anum_pg_range_rngsubopc - 1] = ObjectIdGetDatum(rangeSubOpclass); + values[Anum_pg_range_rngcanonical - 1] = ObjectIdGetDatum(rangeCanonical); + values[Anum_pg_range_rngsubdiff - 1] = ObjectIdGetDatum(rangeSubDiff); + + tup = heap_form_tuple(RelationGetDescr(pg_range), values, nulls); + + CatalogTupleInsert(pg_range, tup); + heap_freetuple(tup); + + /* record type's dependencies on range-related items */ + + myself.classId = TypeRelationId; + myself.objectId = rangeTypeOid; + myself.objectSubId = 0; + + referenced.classId = TypeRelationId; + referenced.objectId = rangeSubType; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + referenced.classId = OperatorClassRelationId; + referenced.objectId = rangeSubOpclass; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + if (OidIsValid(rangeCollation)) + { + referenced.classId = CollationRelationId; + referenced.objectId = rangeCollation; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + if (OidIsValid(rangeCanonical)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = rangeCanonical; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + if (OidIsValid(rangeSubDiff)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = rangeSubDiff; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + table_close(pg_range, RowExclusiveLock); +} + + +/* + * RangeDelete + * Remove the pg_range entry for the specified type. + */ +void +RangeDelete(Oid rangeTypeOid) +{ + Relation pg_range; + ScanKeyData key[1]; + SysScanDesc scan; + HeapTuple tup; + + pg_range = table_open(RangeRelationId, RowExclusiveLock); + + ScanKeyInit(&key[0], + Anum_pg_range_rngtypid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(rangeTypeOid)); + + scan = systable_beginscan(pg_range, RangeTypidIndexId, true, + NULL, 1, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + CatalogTupleDelete(pg_range, &tup->t_self); + } + + systable_endscan(scan); + + table_close(pg_range, RowExclusiveLock); +} diff --git a/src/backend/catalog/pg_range_d.h b/src/backend/catalog/pg_range_d.h new file mode 100644 index 0000000..332a506 --- /dev/null +++ b/src/backend/catalog/pg_range_d.h @@ -0,0 +1,33 @@ +/*------------------------------------------------------------------------- + * + * pg_range_d.h + * Macro definitions for pg_range + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_RANGE_D_H +#define PG_RANGE_D_H + +#define RangeRelationId 3541 + +#define Anum_pg_range_rngtypid 1 +#define Anum_pg_range_rngsubtype 2 +#define Anum_pg_range_rngcollation 3 +#define Anum_pg_range_rngsubopc 4 +#define Anum_pg_range_rngcanonical 5 +#define Anum_pg_range_rngsubdiff 6 + +#define Natts_pg_range 6 + + +#endif /* PG_RANGE_D_H */ diff --git a/src/backend/catalog/pg_replication_origin_d.h b/src/backend/catalog/pg_replication_origin_d.h new file mode 100644 index 0000000..2fcdd7c --- /dev/null +++ b/src/backend/catalog/pg_replication_origin_d.h @@ -0,0 +1,29 @@ +/*------------------------------------------------------------------------- + * + * pg_replication_origin_d.h + * Macro definitions for pg_replication_origin + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_REPLICATION_ORIGIN_D_H +#define PG_REPLICATION_ORIGIN_D_H + +#define ReplicationOriginRelationId 6000 + +#define Anum_pg_replication_origin_roident 1 +#define Anum_pg_replication_origin_roname 2 + +#define Natts_pg_replication_origin 2 + + +#endif /* PG_REPLICATION_ORIGIN_D_H */ diff --git a/src/backend/catalog/pg_rewrite_d.h b/src/backend/catalog/pg_rewrite_d.h new file mode 100644 index 0000000..9825de8 --- /dev/null +++ b/src/backend/catalog/pg_rewrite_d.h @@ -0,0 +1,35 @@ +/*------------------------------------------------------------------------- + * + * pg_rewrite_d.h + * Macro definitions for pg_rewrite + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_REWRITE_D_H +#define PG_REWRITE_D_H + +#define RewriteRelationId 2618 + +#define Anum_pg_rewrite_oid 1 +#define Anum_pg_rewrite_rulename 2 +#define Anum_pg_rewrite_ev_class 3 +#define Anum_pg_rewrite_ev_type 4 +#define Anum_pg_rewrite_ev_enabled 5 +#define Anum_pg_rewrite_is_instead 6 +#define Anum_pg_rewrite_ev_qual 7 +#define Anum_pg_rewrite_ev_action 8 + +#define Natts_pg_rewrite 8 + + +#endif /* PG_REWRITE_D_H */ diff --git a/src/backend/catalog/pg_seclabel_d.h b/src/backend/catalog/pg_seclabel_d.h new file mode 100644 index 0000000..3b34c5c --- /dev/null +++ b/src/backend/catalog/pg_seclabel_d.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * pg_seclabel_d.h + * Macro definitions for pg_seclabel + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_SECLABEL_D_H +#define PG_SECLABEL_D_H + +#define SecLabelRelationId 3596 + +#define Anum_pg_seclabel_objoid 1 +#define Anum_pg_seclabel_classoid 2 +#define Anum_pg_seclabel_objsubid 3 +#define Anum_pg_seclabel_provider 4 +#define Anum_pg_seclabel_label 5 + +#define Natts_pg_seclabel 5 + + +#endif /* PG_SECLABEL_D_H */ diff --git a/src/backend/catalog/pg_sequence_d.h b/src/backend/catalog/pg_sequence_d.h new file mode 100644 index 0000000..d46c817 --- /dev/null +++ b/src/backend/catalog/pg_sequence_d.h @@ -0,0 +1,35 @@ +/*------------------------------------------------------------------------- + * + * pg_sequence_d.h + * Macro definitions for pg_sequence + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_SEQUENCE_D_H +#define PG_SEQUENCE_D_H + +#define SequenceRelationId 2224 + +#define Anum_pg_sequence_seqrelid 1 +#define Anum_pg_sequence_seqtypid 2 +#define Anum_pg_sequence_seqstart 3 +#define Anum_pg_sequence_seqincrement 4 +#define Anum_pg_sequence_seqmax 5 +#define Anum_pg_sequence_seqmin 6 +#define Anum_pg_sequence_seqcache 7 +#define Anum_pg_sequence_seqcycle 8 + +#define Natts_pg_sequence 8 + + +#endif /* PG_SEQUENCE_D_H */ diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c new file mode 100644 index 0000000..cac89e0 --- /dev/null +++ b/src/backend/catalog/pg_shdepend.c @@ -0,0 +1,1618 @@ +/*------------------------------------------------------------------------- + * + * pg_shdepend.c + * routines to support manipulation of the pg_shdepend relation + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/pg_shdepend.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/genam.h" +#include "access/htup_details.h" +#include "access/table.h" +#include "access/xact.h" +#include "catalog/catalog.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/pg_authid.h" +#include "catalog/pg_collation.h" +#include "catalog/pg_conversion.h" +#include "catalog/pg_database.h" +#include "catalog/pg_default_acl.h" +#include "catalog/pg_event_trigger.h" +#include "catalog/pg_extension.h" +#include "catalog/pg_foreign_data_wrapper.h" +#include "catalog/pg_foreign_server.h" +#include "catalog/pg_language.h" +#include "catalog/pg_largeobject.h" +#include "catalog/pg_largeobject_metadata.h" +#include "catalog/pg_namespace.h" +#include "catalog/pg_opclass.h" +#include "catalog/pg_operator.h" +#include "catalog/pg_opfamily.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_shdepend.h" +#include "catalog/pg_statistic_ext.h" +#include "catalog/pg_subscription.h" +#include "catalog/pg_tablespace.h" +#include "catalog/pg_ts_config.h" +#include "catalog/pg_ts_dict.h" +#include "catalog/pg_type.h" +#include "catalog/pg_user_mapping.h" +#include "commands/alter.h" +#include "commands/collationcmds.h" +#include "commands/conversioncmds.h" +#include "commands/dbcommands.h" +#include "commands/defrem.h" +#include "commands/event_trigger.h" +#include "commands/extension.h" +#include "commands/policy.h" +#include "commands/proclang.h" +#include "commands/publicationcmds.h" +#include "commands/schemacmds.h" +#include "commands/subscriptioncmds.h" +#include "commands/tablecmds.h" +#include "commands/tablespace.h" +#include "commands/typecmds.h" +#include "miscadmin.h" +#include "storage/lmgr.h" +#include "utils/acl.h" +#include "utils/fmgroids.h" +#include "utils/syscache.h" + +typedef enum +{ + LOCAL_OBJECT, + SHARED_OBJECT, + REMOTE_OBJECT +} SharedDependencyObjectType; + +typedef struct +{ + ObjectAddress object; + char deptype; + SharedDependencyObjectType objtype; +} ShDependObjectInfo; + +static void getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2); +static Oid classIdGetDbId(Oid classId); +static void shdepChangeDep(Relation sdepRel, + Oid classid, Oid objid, int32 objsubid, + Oid refclassid, Oid refobjid, + SharedDependencyType deptype); +static void shdepAddDependency(Relation sdepRel, + Oid classId, Oid objectId, int32 objsubId, + Oid refclassId, Oid refobjId, + SharedDependencyType deptype); +static void shdepDropDependency(Relation sdepRel, + Oid classId, Oid objectId, int32 objsubId, + bool drop_subobjects, + Oid refclassId, Oid refobjId, + SharedDependencyType deptype); +static void storeObjectDescription(StringInfo descs, + SharedDependencyObjectType type, + ObjectAddress *object, + SharedDependencyType deptype, + int count); +static bool isSharedObjectPinned(Oid classId, Oid objectId, Relation sdepRel); + + +/* + * recordSharedDependencyOn + * + * Record a dependency between 2 objects via their respective ObjectAddresses. + * The first argument is the dependent object, the second the one it + * references (which must be a shared object). + * + * This locks the referenced object and makes sure it still exists. + * Then it creates an entry in pg_shdepend. The lock is kept until + * the end of the transaction. + * + * Dependencies on pinned objects are not recorded. + */ +void +recordSharedDependencyOn(ObjectAddress *depender, + ObjectAddress *referenced, + SharedDependencyType deptype) +{ + Relation sdepRel; + + /* + * Objects in pg_shdepend can't have SubIds. + */ + Assert(depender->objectSubId == 0); + Assert(referenced->objectSubId == 0); + + /* + * During bootstrap, do nothing since pg_shdepend may not exist yet. + * initdb will fill in appropriate pg_shdepend entries after bootstrap. + */ + if (IsBootstrapProcessingMode()) + return; + + sdepRel = table_open(SharedDependRelationId, RowExclusiveLock); + + /* If the referenced object is pinned, do nothing. */ + if (!isSharedObjectPinned(referenced->classId, referenced->objectId, + sdepRel)) + { + shdepAddDependency(sdepRel, depender->classId, depender->objectId, + depender->objectSubId, + referenced->classId, referenced->objectId, + deptype); + } + + table_close(sdepRel, RowExclusiveLock); +} + +/* + * recordDependencyOnOwner + * + * A convenient wrapper of recordSharedDependencyOn -- register the specified + * user as owner of the given object. + * + * Note: it's the caller's responsibility to ensure that there isn't an owner + * entry for the object already. + */ +void +recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner) +{ + ObjectAddress myself, + referenced; + + myself.classId = classId; + myself.objectId = objectId; + myself.objectSubId = 0; + + referenced.classId = AuthIdRelationId; + referenced.objectId = owner; + referenced.objectSubId = 0; + + recordSharedDependencyOn(&myself, &referenced, SHARED_DEPENDENCY_OWNER); +} + +/* + * shdepChangeDep + * + * Update shared dependency records to account for an updated referenced + * object. This is an internal workhorse for operations such as changing + * an object's owner. + * + * There must be no more than one existing entry for the given dependent + * object and dependency type! So in practice this can only be used for + * updating SHARED_DEPENDENCY_OWNER and SHARED_DEPENDENCY_TABLESPACE + * entries, which should have that property. + * + * If there is no previous entry, we assume it was referencing a PINned + * object, so we create a new entry. If the new referenced object is + * PINned, we don't create an entry (and drop the old one, if any). + * (For tablespaces, we don't record dependencies in certain cases, so + * there are other possible reasons for entries to be missing.) + * + * sdepRel must be the pg_shdepend relation, already opened and suitably + * locked. + */ +static void +shdepChangeDep(Relation sdepRel, + Oid classid, Oid objid, int32 objsubid, + Oid refclassid, Oid refobjid, + SharedDependencyType deptype) +{ + Oid dbid = classIdGetDbId(classid); + HeapTuple oldtup = NULL; + HeapTuple scantup; + ScanKeyData key[4]; + SysScanDesc scan; + + /* + * Make sure the new referenced object doesn't go away while we record the + * dependency. + */ + shdepLockAndCheckObject(refclassid, refobjid); + + /* + * Look for a previous entry + */ + ScanKeyInit(&key[0], + Anum_pg_shdepend_dbid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(dbid)); + ScanKeyInit(&key[1], + Anum_pg_shdepend_classid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(classid)); + ScanKeyInit(&key[2], + Anum_pg_shdepend_objid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objid)); + ScanKeyInit(&key[3], + Anum_pg_shdepend_objsubid, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(objsubid)); + + scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true, + NULL, 4, key); + + while ((scantup = systable_getnext(scan)) != NULL) + { + /* Ignore if not of the target dependency type */ + if (((Form_pg_shdepend) GETSTRUCT(scantup))->deptype != deptype) + continue; + /* Caller screwed up if multiple matches */ + if (oldtup) + elog(ERROR, + "multiple pg_shdepend entries for object %u/%u/%d deptype %c", + classid, objid, objsubid, deptype); + oldtup = heap_copytuple(scantup); + } + + systable_endscan(scan); + + if (isSharedObjectPinned(refclassid, refobjid, sdepRel)) + { + /* No new entry needed, so just delete existing entry if any */ + if (oldtup) + CatalogTupleDelete(sdepRel, &oldtup->t_self); + } + else if (oldtup) + { + /* Need to update existing entry */ + Form_pg_shdepend shForm = (Form_pg_shdepend) GETSTRUCT(oldtup); + + /* Since oldtup is a copy, we can just modify it in-memory */ + shForm->refclassid = refclassid; + shForm->refobjid = refobjid; + + CatalogTupleUpdate(sdepRel, &oldtup->t_self, oldtup); + } + else + { + /* Need to insert new entry */ + Datum values[Natts_pg_shdepend]; + bool nulls[Natts_pg_shdepend]; + + memset(nulls, false, sizeof(nulls)); + + values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(dbid); + values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classid); + values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objid); + values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubid); + + values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassid); + values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjid); + values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype); + + /* + * we are reusing oldtup just to avoid declaring a new variable, but + * it's certainly a new tuple + */ + oldtup = heap_form_tuple(RelationGetDescr(sdepRel), values, nulls); + CatalogTupleInsert(sdepRel, oldtup); + } + + if (oldtup) + heap_freetuple(oldtup); +} + +/* + * changeDependencyOnOwner + * + * Update the shared dependencies to account for the new owner. + * + * Note: we don't need an objsubid argument because only whole objects + * have owners. + */ +void +changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId) +{ + Relation sdepRel; + + sdepRel = table_open(SharedDependRelationId, RowExclusiveLock); + + /* Adjust the SHARED_DEPENDENCY_OWNER entry */ + shdepChangeDep(sdepRel, + classId, objectId, 0, + AuthIdRelationId, newOwnerId, + SHARED_DEPENDENCY_OWNER); + + /*---------- + * There should never be a SHARED_DEPENDENCY_ACL entry for the owner, + * so get rid of it if there is one. This can happen if the new owner + * was previously granted some rights to the object. + * + * This step is analogous to aclnewowner's removal of duplicate entries + * in the ACL. We have to do it to handle this scenario: + * A grants some rights on an object to B + * ALTER OWNER changes the object's owner to B + * ALTER OWNER changes the object's owner to C + * The third step would remove all mention of B from the object's ACL, + * but we'd still have a SHARED_DEPENDENCY_ACL for B if we did not do + * things this way. + * + * The rule against having a SHARED_DEPENDENCY_ACL entry for the owner + * allows us to fix things up in just this one place, without having + * to make the various ALTER OWNER routines each know about it. + *---------- + */ + shdepDropDependency(sdepRel, classId, objectId, 0, true, + AuthIdRelationId, newOwnerId, + SHARED_DEPENDENCY_ACL); + + table_close(sdepRel, RowExclusiveLock); +} + +/* + * recordDependencyOnTablespace + * + * A convenient wrapper of recordSharedDependencyOn -- register the specified + * tablespace as default for the given object. + * + * Note: it's the caller's responsibility to ensure that there isn't a + * tablespace entry for the object already. + */ +void +recordDependencyOnTablespace(Oid classId, Oid objectId, Oid tablespace) +{ + ObjectAddress myself, + referenced; + + ObjectAddressSet(myself, classId, objectId); + ObjectAddressSet(referenced, TableSpaceRelationId, tablespace); + + recordSharedDependencyOn(&myself, &referenced, + SHARED_DEPENDENCY_TABLESPACE); +} + +/* + * changeDependencyOnTablespace + * + * Update the shared dependencies to account for the new tablespace. + * + * Note: we don't need an objsubid argument because only whole objects + * have tablespaces. + */ +void +changeDependencyOnTablespace(Oid classId, Oid objectId, Oid newTablespaceId) +{ + Relation sdepRel; + + sdepRel = table_open(SharedDependRelationId, RowExclusiveLock); + + if (newTablespaceId != DEFAULTTABLESPACE_OID && + newTablespaceId != InvalidOid) + shdepChangeDep(sdepRel, + classId, objectId, 0, + TableSpaceRelationId, newTablespaceId, + SHARED_DEPENDENCY_TABLESPACE); + else + shdepDropDependency(sdepRel, + classId, objectId, 0, true, + InvalidOid, InvalidOid, + SHARED_DEPENDENCY_INVALID); + + table_close(sdepRel, RowExclusiveLock); +} + +/* + * getOidListDiff + * Helper for updateAclDependencies. + * + * Takes two Oid arrays and removes elements that are common to both arrays, + * leaving just those that are in one input but not the other. + * We assume both arrays have been sorted and de-duped. + */ +static void +getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2) +{ + int in1, + in2, + out1, + out2; + + in1 = in2 = out1 = out2 = 0; + while (in1 < *nlist1 && in2 < *nlist2) + { + if (list1[in1] == list2[in2]) + { + /* skip over duplicates */ + in1++; + in2++; + } + else if (list1[in1] < list2[in2]) + { + /* list1[in1] is not in list2 */ + list1[out1++] = list1[in1++]; + } + else + { + /* list2[in2] is not in list1 */ + list2[out2++] = list2[in2++]; + } + } + + /* any remaining list1 entries are not in list2 */ + while (in1 < *nlist1) + { + list1[out1++] = list1[in1++]; + } + + /* any remaining list2 entries are not in list1 */ + while (in2 < *nlist2) + { + list2[out2++] = list2[in2++]; + } + + *nlist1 = out1; + *nlist2 = out2; +} + +/* + * updateAclDependencies + * Update the pg_shdepend info for an object's ACL during GRANT/REVOKE. + * + * classId, objectId, objsubId: identify the object whose ACL this is + * ownerId: role owning the object + * noldmembers, oldmembers: array of roleids appearing in old ACL + * nnewmembers, newmembers: array of roleids appearing in new ACL + * + * We calculate the differences between the new and old lists of roles, + * and then insert or delete from pg_shdepend as appropriate. + * + * Note that we can't just insert all referenced roles blindly during GRANT, + * because we would end up with duplicate registered dependencies. We could + * check for existence of the tuples before inserting, but that seems to be + * more expensive than what we are doing here. Likewise we can't just delete + * blindly during REVOKE, because the user may still have other privileges. + * It is also possible that REVOKE actually adds dependencies, due to + * instantiation of a formerly implicit default ACL (although at present, + * all such dependencies should be for the owning role, which we ignore here). + * + * NOTE: Both input arrays must be sorted and de-duped. (Typically they + * are extracted from an ACL array by aclmembers(), which takes care of + * both requirements.) The arrays are pfreed before return. + */ +void +updateAclDependencies(Oid classId, Oid objectId, int32 objsubId, + Oid ownerId, + int noldmembers, Oid *oldmembers, + int nnewmembers, Oid *newmembers) +{ + Relation sdepRel; + int i; + + /* + * Remove entries that are common to both lists; those represent existing + * dependencies we don't need to change. + * + * OK to overwrite the inputs since we'll pfree them anyway. + */ + getOidListDiff(oldmembers, &noldmembers, newmembers, &nnewmembers); + + if (noldmembers > 0 || nnewmembers > 0) + { + sdepRel = table_open(SharedDependRelationId, RowExclusiveLock); + + /* Add new dependencies that weren't already present */ + for (i = 0; i < nnewmembers; i++) + { + Oid roleid = newmembers[i]; + + /* + * Skip the owner: he has an OWNER shdep entry instead. (This is + * not just a space optimization; it makes ALTER OWNER easier. See + * notes in changeDependencyOnOwner.) + */ + if (roleid == ownerId) + continue; + + /* Skip pinned roles; they don't need dependency entries */ + if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel)) + continue; + + shdepAddDependency(sdepRel, classId, objectId, objsubId, + AuthIdRelationId, roleid, + SHARED_DEPENDENCY_ACL); + } + + /* Drop no-longer-used old dependencies */ + for (i = 0; i < noldmembers; i++) + { + Oid roleid = oldmembers[i]; + + /* Skip the owner, same as above */ + if (roleid == ownerId) + continue; + + /* Skip pinned roles */ + if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel)) + continue; + + shdepDropDependency(sdepRel, classId, objectId, objsubId, + false, /* exact match on objsubId */ + AuthIdRelationId, roleid, + SHARED_DEPENDENCY_ACL); + } + + table_close(sdepRel, RowExclusiveLock); + } + + if (oldmembers) + pfree(oldmembers); + if (newmembers) + pfree(newmembers); +} + +/* + * A struct to keep track of dependencies found in other databases. + */ +typedef struct +{ + Oid dbOid; + int count; +} remoteDep; + +/* + * qsort comparator for ShDependObjectInfo items + */ +static int +shared_dependency_comparator(const void *a, const void *b) +{ + const ShDependObjectInfo *obja = (const ShDependObjectInfo *) a; + const ShDependObjectInfo *objb = (const ShDependObjectInfo *) b; + + /* + * Primary sort key is OID ascending. + */ + if (obja->object.objectId < objb->object.objectId) + return -1; + if (obja->object.objectId > objb->object.objectId) + return 1; + + /* + * Next sort on catalog ID, in case identical OIDs appear in different + * catalogs. Sort direction is pretty arbitrary here. + */ + if (obja->object.classId < objb->object.classId) + return -1; + if (obja->object.classId > objb->object.classId) + return 1; + + /* + * Sort on object subId. + * + * We sort the subId as an unsigned int so that 0 (the whole object) will + * come first. + */ + if ((unsigned int) obja->object.objectSubId < (unsigned int) objb->object.objectSubId) + return -1; + if ((unsigned int) obja->object.objectSubId > (unsigned int) objb->object.objectSubId) + return 1; + + /* + * Last, sort on deptype, in case the same object has multiple dependency + * types. (Note that there's no need to consider objtype, as that's + * determined by the catalog OID.) + */ + if (obja->deptype < objb->deptype) + return -1; + if (obja->deptype > objb->deptype) + return 1; + + return 0; +} + +/* + * checkSharedDependencies + * + * Check whether there are shared dependency entries for a given shared + * object; return true if so. + * + * In addition, return a string containing a newline-separated list of object + * descriptions that depend on the shared object, or NULL if none is found. + * We actually return two such strings; the "detail" result is suitable for + * returning to the client as an errdetail() string, and is limited in size. + * The "detail_log" string is potentially much longer, and should be emitted + * to the server log only. + * + * We can find three different kinds of dependencies: dependencies on objects + * of the current database; dependencies on shared objects; and dependencies + * on objects local to other databases. We can (and do) provide descriptions + * of the two former kinds of objects, but we can't do that for "remote" + * objects, so we just provide a count of them. + * + * If we find a SHARED_DEPENDENCY_PIN entry, we can error out early. + */ +bool +checkSharedDependencies(Oid classId, Oid objectId, + char **detail_msg, char **detail_log_msg) +{ + Relation sdepRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + int numReportedDeps = 0; + int numNotReportedDeps = 0; + int numNotReportedDbs = 0; + List *remDeps = NIL; + ListCell *cell; + ObjectAddress object; + ShDependObjectInfo *objects; + int numobjects; + int allocedobjects; + StringInfoData descs; + StringInfoData alldescs; + + /* + * We limit the number of dependencies reported to the client to + * MAX_REPORTED_DEPS, since client software may not deal well with + * enormous error strings. The server log always gets a full report. + * + * For stability of regression test results, we sort local and shared + * objects by OID before reporting them. We don't worry about the order + * in which other databases are reported, though. + */ +#define MAX_REPORTED_DEPS 100 + + allocedobjects = 128; /* arbitrary initial array size */ + objects = (ShDependObjectInfo *) + palloc(allocedobjects * sizeof(ShDependObjectInfo)); + numobjects = 0; + initStringInfo(&descs); + initStringInfo(&alldescs); + + sdepRel = table_open(SharedDependRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_shdepend_refclassid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(classId)); + ScanKeyInit(&key[1], + Anum_pg_shdepend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objectId)); + + scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true, + NULL, 2, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tup); + + /* This case can be dispatched quickly */ + if (sdepForm->deptype == SHARED_DEPENDENCY_PIN) + { + object.classId = classId; + object.objectId = objectId; + object.objectSubId = 0; + ereport(ERROR, + (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), + errmsg("cannot drop %s because it is required by the database system", + getObjectDescription(&object)))); + } + + object.classId = sdepForm->classid; + object.objectId = sdepForm->objid; + object.objectSubId = sdepForm->objsubid; + + /* + * If it's a dependency local to this database or it's a shared + * object, add it to the objects array. + * + * If it's a remote dependency, keep track of it so we can report the + * number of them later. + */ + if (sdepForm->dbid == MyDatabaseId || + sdepForm->dbid == InvalidOid) + { + if (numobjects >= allocedobjects) + { + allocedobjects *= 2; + objects = (ShDependObjectInfo *) + repalloc(objects, + allocedobjects * sizeof(ShDependObjectInfo)); + } + objects[numobjects].object = object; + objects[numobjects].deptype = sdepForm->deptype; + objects[numobjects].objtype = (sdepForm->dbid == MyDatabaseId) ? + LOCAL_OBJECT : SHARED_OBJECT; + numobjects++; + } + else + { + /* It's not local nor shared, so it must be remote. */ + remoteDep *dep; + bool stored = false; + + /* + * XXX this info is kept on a simple List. Maybe it's not good + * for performance, but using a hash table seems needlessly + * complex. The expected number of databases is not high anyway, + * I suppose. + */ + foreach(cell, remDeps) + { + dep = lfirst(cell); + if (dep->dbOid == sdepForm->dbid) + { + dep->count++; + stored = true; + break; + } + } + if (!stored) + { + dep = (remoteDep *) palloc(sizeof(remoteDep)); + dep->dbOid = sdepForm->dbid; + dep->count = 1; + remDeps = lappend(remDeps, dep); + } + } + } + + systable_endscan(scan); + + table_close(sdepRel, AccessShareLock); + + /* + * Sort and report local and shared objects. + */ + if (numobjects > 1) + qsort((void *) objects, numobjects, + sizeof(ShDependObjectInfo), shared_dependency_comparator); + + for (int i = 0; i < numobjects; i++) + { + if (numReportedDeps < MAX_REPORTED_DEPS) + { + numReportedDeps++; + storeObjectDescription(&descs, + objects[i].objtype, + &objects[i].object, + objects[i].deptype, + 0); + } + else + numNotReportedDeps++; + storeObjectDescription(&alldescs, + objects[i].objtype, + &objects[i].object, + objects[i].deptype, + 0); + } + + /* + * Summarize dependencies in remote databases. + */ + foreach(cell, remDeps) + { + remoteDep *dep = lfirst(cell); + + object.classId = DatabaseRelationId; + object.objectId = dep->dbOid; + object.objectSubId = 0; + + if (numReportedDeps < MAX_REPORTED_DEPS) + { + numReportedDeps++; + storeObjectDescription(&descs, REMOTE_OBJECT, &object, + SHARED_DEPENDENCY_INVALID, dep->count); + } + else + numNotReportedDbs++; + storeObjectDescription(&alldescs, REMOTE_OBJECT, &object, + SHARED_DEPENDENCY_INVALID, dep->count); + } + + pfree(objects); + list_free_deep(remDeps); + + if (descs.len == 0) + { + pfree(descs.data); + pfree(alldescs.data); + *detail_msg = *detail_log_msg = NULL; + return false; + } + + if (numNotReportedDeps > 0) + appendStringInfo(&descs, ngettext("\nand %d other object " + "(see server log for list)", + "\nand %d other objects " + "(see server log for list)", + numNotReportedDeps), + numNotReportedDeps); + if (numNotReportedDbs > 0) + appendStringInfo(&descs, ngettext("\nand objects in %d other database " + "(see server log for list)", + "\nand objects in %d other databases " + "(see server log for list)", + numNotReportedDbs), + numNotReportedDbs); + + *detail_msg = descs.data; + *detail_log_msg = alldescs.data; + return true; +} + +/* + * copyTemplateDependencies + * + * Routine to create the initial shared dependencies of a new database. + * We simply copy the dependencies from the template database. + */ +void +copyTemplateDependencies(Oid templateDbId, Oid newDbId) +{ + Relation sdepRel; + TupleDesc sdepDesc; + ScanKeyData key[1]; + SysScanDesc scan; + HeapTuple tup; + CatalogIndexState indstate; + Datum values[Natts_pg_shdepend]; + bool nulls[Natts_pg_shdepend]; + bool replace[Natts_pg_shdepend]; + + sdepRel = table_open(SharedDependRelationId, RowExclusiveLock); + sdepDesc = RelationGetDescr(sdepRel); + + indstate = CatalogOpenIndexes(sdepRel); + + /* Scan all entries with dbid = templateDbId */ + ScanKeyInit(&key[0], + Anum_pg_shdepend_dbid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(templateDbId)); + + scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true, + NULL, 1, key); + + /* Set up to copy the tuples except for inserting newDbId */ + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + memset(replace, false, sizeof(replace)); + + replace[Anum_pg_shdepend_dbid - 1] = true; + values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(newDbId); + + /* + * Copy the entries of the original database, changing the database Id to + * that of the new database. Note that because we are not copying rows + * with dbId == 0 (ie, rows describing dependent shared objects) we won't + * copy the ownership dependency of the template database itself; this is + * what we want. + */ + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + HeapTuple newtup; + + newtup = heap_modify_tuple(tup, sdepDesc, values, nulls, replace); + CatalogTupleInsertWithInfo(sdepRel, newtup, indstate); + + heap_freetuple(newtup); + } + + systable_endscan(scan); + + CatalogCloseIndexes(indstate); + table_close(sdepRel, RowExclusiveLock); +} + +/* + * dropDatabaseDependencies + * + * Delete pg_shdepend entries corresponding to a database that's being + * dropped. + */ +void +dropDatabaseDependencies(Oid databaseId) +{ + Relation sdepRel; + ScanKeyData key[1]; + SysScanDesc scan; + HeapTuple tup; + + sdepRel = table_open(SharedDependRelationId, RowExclusiveLock); + + /* + * First, delete all the entries that have the database Oid in the dbid + * field. + */ + ScanKeyInit(&key[0], + Anum_pg_shdepend_dbid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(databaseId)); + /* We leave the other index fields unspecified */ + + scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true, + NULL, 1, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + CatalogTupleDelete(sdepRel, &tup->t_self); + } + + systable_endscan(scan); + + /* Now delete all entries corresponding to the database itself */ + shdepDropDependency(sdepRel, DatabaseRelationId, databaseId, 0, true, + InvalidOid, InvalidOid, + SHARED_DEPENDENCY_INVALID); + + table_close(sdepRel, RowExclusiveLock); +} + +/* + * deleteSharedDependencyRecordsFor + * + * Delete all pg_shdepend entries corresponding to an object that's being + * dropped or modified. The object is assumed to be either a shared object + * or local to the current database (the classId tells us which). + * + * If objectSubId is zero, we are deleting a whole object, so get rid of + * pg_shdepend entries for subobjects as well. + */ +void +deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId) +{ + Relation sdepRel; + + sdepRel = table_open(SharedDependRelationId, RowExclusiveLock); + + shdepDropDependency(sdepRel, classId, objectId, objectSubId, + (objectSubId == 0), + InvalidOid, InvalidOid, + SHARED_DEPENDENCY_INVALID); + + table_close(sdepRel, RowExclusiveLock); +} + +/* + * shdepAddDependency + * Internal workhorse for inserting into pg_shdepend + * + * sdepRel must be the pg_shdepend relation, already opened and suitably + * locked. + */ +static void +shdepAddDependency(Relation sdepRel, + Oid classId, Oid objectId, int32 objsubId, + Oid refclassId, Oid refobjId, + SharedDependencyType deptype) +{ + HeapTuple tup; + Datum values[Natts_pg_shdepend]; + bool nulls[Natts_pg_shdepend]; + + /* + * Make sure the object doesn't go away while we record the dependency on + * it. DROP routines should lock the object exclusively before they check + * shared dependencies. + */ + shdepLockAndCheckObject(refclassId, refobjId); + + memset(nulls, false, sizeof(nulls)); + + /* + * Form the new tuple and record the dependency. + */ + values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(classIdGetDbId(classId)); + values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classId); + values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objectId); + values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubId); + + values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassId); + values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjId); + values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype); + + tup = heap_form_tuple(sdepRel->rd_att, values, nulls); + + CatalogTupleInsert(sdepRel, tup); + + /* clean up */ + heap_freetuple(tup); +} + +/* + * shdepDropDependency + * Internal workhorse for deleting entries from pg_shdepend. + * + * We drop entries having the following properties: + * dependent object is the one identified by classId/objectId/objsubId + * if refclassId isn't InvalidOid, it must match the entry's refclassid + * if refobjId isn't InvalidOid, it must match the entry's refobjid + * if deptype isn't SHARED_DEPENDENCY_INVALID, it must match entry's deptype + * + * If drop_subobjects is true, we ignore objsubId and consider all entries + * matching classId/objectId. + * + * sdepRel must be the pg_shdepend relation, already opened and suitably + * locked. + */ +static void +shdepDropDependency(Relation sdepRel, + Oid classId, Oid objectId, int32 objsubId, + bool drop_subobjects, + Oid refclassId, Oid refobjId, + SharedDependencyType deptype) +{ + ScanKeyData key[4]; + int nkeys; + SysScanDesc scan; + HeapTuple tup; + + /* Scan for entries matching the dependent object */ + ScanKeyInit(&key[0], + Anum_pg_shdepend_dbid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(classIdGetDbId(classId))); + ScanKeyInit(&key[1], + Anum_pg_shdepend_classid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(classId)); + ScanKeyInit(&key[2], + Anum_pg_shdepend_objid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objectId)); + if (drop_subobjects) + nkeys = 3; + else + { + ScanKeyInit(&key[3], + Anum_pg_shdepend_objsubid, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(objsubId)); + nkeys = 4; + } + + scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true, + NULL, nkeys, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_shdepend shdepForm = (Form_pg_shdepend) GETSTRUCT(tup); + + /* Filter entries according to additional parameters */ + if (OidIsValid(refclassId) && shdepForm->refclassid != refclassId) + continue; + if (OidIsValid(refobjId) && shdepForm->refobjid != refobjId) + continue; + if (deptype != SHARED_DEPENDENCY_INVALID && + shdepForm->deptype != deptype) + continue; + + /* OK, delete it */ + CatalogTupleDelete(sdepRel, &tup->t_self); + } + + systable_endscan(scan); +} + +/* + * classIdGetDbId + * + * Get the database Id that should be used in pg_shdepend, given the OID + * of the catalog containing the object. For shared objects, it's 0 + * (InvalidOid); for all other objects, it's the current database Id. + */ +static Oid +classIdGetDbId(Oid classId) +{ + Oid dbId; + + if (IsSharedRelation(classId)) + dbId = InvalidOid; + else + dbId = MyDatabaseId; + + return dbId; +} + +/* + * shdepLockAndCheckObject + * + * Lock the object that we are about to record a dependency on. + * After it's locked, verify that it hasn't been dropped while we + * weren't looking. If the object has been dropped, this function + * does not return! + */ +void +shdepLockAndCheckObject(Oid classId, Oid objectId) +{ + /* AccessShareLock should be OK, since we are not modifying the object */ + LockSharedObject(classId, objectId, 0, AccessShareLock); + + switch (classId) + { + case AuthIdRelationId: + if (!SearchSysCacheExists1(AUTHOID, ObjectIdGetDatum(objectId))) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("role %u was concurrently dropped", + objectId))); + break; + + case TableSpaceRelationId: + { + /* For lack of a syscache on pg_tablespace, do this: */ + char *tablespace = get_tablespace_name(objectId); + + if (tablespace == NULL) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tablespace %u was concurrently dropped", + objectId))); + pfree(tablespace); + break; + } + + case DatabaseRelationId: + { + /* For lack of a syscache on pg_database, do this: */ + char *database = get_database_name(objectId); + + if (database == NULL) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("database %u was concurrently dropped", + objectId))); + pfree(database); + break; + } + + + default: + elog(ERROR, "unrecognized shared classId: %u", classId); + } +} + + +/* + * storeObjectDescription + * Append the description of a dependent object to "descs" + * + * While searching for dependencies of a shared object, we stash the + * descriptions of dependent objects we find in a single string, which we + * later pass to ereport() in the DETAIL field when somebody attempts to + * drop a referenced shared object. + * + * When type is LOCAL_OBJECT or SHARED_OBJECT, we expect object to be the + * dependent object, deptype is the dependency type, and count is not used. + * When type is REMOTE_OBJECT, we expect object to be the database object, + * and count to be nonzero; deptype is not used in this case. + */ +static void +storeObjectDescription(StringInfo descs, + SharedDependencyObjectType type, + ObjectAddress *object, + SharedDependencyType deptype, + int count) +{ + char *objdesc = getObjectDescription(object); + + /* separate entries with a newline */ + if (descs->len != 0) + appendStringInfoChar(descs, '\n'); + + switch (type) + { + case LOCAL_OBJECT: + case SHARED_OBJECT: + if (deptype == SHARED_DEPENDENCY_OWNER) + appendStringInfo(descs, _("owner of %s"), objdesc); + else if (deptype == SHARED_DEPENDENCY_ACL) + appendStringInfo(descs, _("privileges for %s"), objdesc); + else if (deptype == SHARED_DEPENDENCY_POLICY) + appendStringInfo(descs, _("target of %s"), objdesc); + else if (deptype == SHARED_DEPENDENCY_TABLESPACE) + appendStringInfo(descs, _("tablespace for %s"), objdesc); + else + elog(ERROR, "unrecognized dependency type: %d", + (int) deptype); + break; + + case REMOTE_OBJECT: + /* translator: %s will always be "database %s" */ + appendStringInfo(descs, ngettext("%d object in %s", + "%d objects in %s", + count), + count, objdesc); + break; + + default: + elog(ERROR, "unrecognized object type: %d", type); + } + + pfree(objdesc); +} + + +/* + * isSharedObjectPinned + * Return whether a given shared object has a SHARED_DEPENDENCY_PIN entry. + * + * sdepRel must be the pg_shdepend relation, already opened and suitably + * locked. + */ +static bool +isSharedObjectPinned(Oid classId, Oid objectId, Relation sdepRel) +{ + bool result = false; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + + ScanKeyInit(&key[0], + Anum_pg_shdepend_refclassid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(classId)); + ScanKeyInit(&key[1], + Anum_pg_shdepend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objectId)); + + scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true, + NULL, 2, key); + + /* + * Since we won't generate additional pg_shdepend entries for pinned + * objects, there can be at most one entry referencing a pinned object. + * Hence, it's sufficient to look at the first returned tuple; we don't + * need to loop. + */ + tup = systable_getnext(scan); + if (HeapTupleIsValid(tup)) + { + Form_pg_shdepend shdepForm = (Form_pg_shdepend) GETSTRUCT(tup); + + if (shdepForm->deptype == SHARED_DEPENDENCY_PIN) + result = true; + } + + systable_endscan(scan); + + return result; +} + +/* + * shdepDropOwned + * + * Drop the objects owned by any one of the given RoleIds. If a role has + * access to an object, the grant will be removed as well (but the object + * will not, of course). + * + * We can revoke grants immediately while doing the scan, but drops are + * saved up and done all at once with performMultipleDeletions. This + * is necessary so that we don't get failures from trying to delete + * interdependent objects in the wrong order. + */ +void +shdepDropOwned(List *roleids, DropBehavior behavior) +{ + Relation sdepRel; + ListCell *cell; + ObjectAddresses *deleteobjs; + + deleteobjs = new_object_addresses(); + + /* + * We don't need this strong a lock here, but we'll call routines that + * acquire RowExclusiveLock. Better get that right now to avoid potential + * deadlock failures. + */ + sdepRel = table_open(SharedDependRelationId, RowExclusiveLock); + + /* + * For each role, find the dependent objects and drop them using the + * regular (non-shared) dependency management. + */ + foreach(cell, roleids) + { + Oid roleid = lfirst_oid(cell); + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tuple; + + /* Doesn't work for pinned objects */ + if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel)) + { + ObjectAddress obj; + + obj.classId = AuthIdRelationId; + obj.objectId = roleid; + obj.objectSubId = 0; + + ereport(ERROR, + (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), + errmsg("cannot drop objects owned by %s because they are " + "required by the database system", + getObjectDescription(&obj)))); + } + + ScanKeyInit(&key[0], + Anum_pg_shdepend_refclassid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(AuthIdRelationId)); + ScanKeyInit(&key[1], + Anum_pg_shdepend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(roleid)); + + scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true, + NULL, 2, key); + + while ((tuple = systable_getnext(scan)) != NULL) + { + Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple); + ObjectAddress obj; + + /* + * We only operate on shared objects and objects in the current + * database + */ + if (sdepForm->dbid != MyDatabaseId && + sdepForm->dbid != InvalidOid) + continue; + + switch (sdepForm->deptype) + { + /* Shouldn't happen */ + case SHARED_DEPENDENCY_PIN: + case SHARED_DEPENDENCY_INVALID: + elog(ERROR, "unexpected dependency type"); + break; + case SHARED_DEPENDENCY_ACL: + RemoveRoleFromObjectACL(roleid, + sdepForm->classid, + sdepForm->objid); + break; + case SHARED_DEPENDENCY_POLICY: + + /* + * Try to remove role from policy; if unable to, remove + * policy. + */ + if (!RemoveRoleFromObjectPolicy(roleid, + sdepForm->classid, + sdepForm->objid)) + { + obj.classId = sdepForm->classid; + obj.objectId = sdepForm->objid; + obj.objectSubId = sdepForm->objsubid; + + /* + * Acquire lock on object, then verify this dependency + * is still relevant. If not, the object might have + * been dropped or the policy modified. Ignore the + * object in that case. + */ + AcquireDeletionLock(&obj, 0); + if (!systable_recheck_tuple(scan, tuple)) + { + ReleaseDeletionLock(&obj); + break; + } + add_exact_object_address(&obj, deleteobjs); + } + break; + case SHARED_DEPENDENCY_OWNER: + /* If a local object, save it for deletion below */ + if (sdepForm->dbid == MyDatabaseId) + { + obj.classId = sdepForm->classid; + obj.objectId = sdepForm->objid; + obj.objectSubId = sdepForm->objsubid; + /* as above */ + AcquireDeletionLock(&obj, 0); + if (!systable_recheck_tuple(scan, tuple)) + { + ReleaseDeletionLock(&obj); + break; + } + add_exact_object_address(&obj, deleteobjs); + } + break; + } + } + + systable_endscan(scan); + } + + /* + * For stability of deletion-report ordering, sort the objects into + * approximate reverse creation order before deletion. (This might also + * make the deletion go a bit faster, since there's less chance of having + * to rearrange the objects due to dependencies.) + */ + sort_object_addresses(deleteobjs); + + /* the dependency mechanism does the actual work */ + performMultipleDeletions(deleteobjs, behavior, 0); + + table_close(sdepRel, RowExclusiveLock); + + free_object_addresses(deleteobjs); +} + +/* + * shdepReassignOwned + * + * Change the owner of objects owned by any of the roles in roleids to + * newrole. Grants are not touched. + */ +void +shdepReassignOwned(List *roleids, Oid newrole) +{ + Relation sdepRel; + ListCell *cell; + + /* + * We don't need this strong a lock here, but we'll call routines that + * acquire RowExclusiveLock. Better get that right now to avoid potential + * deadlock problems. + */ + sdepRel = table_open(SharedDependRelationId, RowExclusiveLock); + + foreach(cell, roleids) + { + SysScanDesc scan; + ScanKeyData key[2]; + HeapTuple tuple; + Oid roleid = lfirst_oid(cell); + + /* Refuse to work on pinned roles */ + if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel)) + { + ObjectAddress obj; + + obj.classId = AuthIdRelationId; + obj.objectId = roleid; + obj.objectSubId = 0; + + ereport(ERROR, + (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), + errmsg("cannot reassign ownership of objects owned by %s because they are required by the database system", + getObjectDescription(&obj)))); + + /* + * There's no need to tell the whole truth, which is that we + * didn't track these dependencies at all ... + */ + } + + ScanKeyInit(&key[0], + Anum_pg_shdepend_refclassid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(AuthIdRelationId)); + ScanKeyInit(&key[1], + Anum_pg_shdepend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(roleid)); + + scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true, + NULL, 2, key); + + while ((tuple = systable_getnext(scan)) != NULL) + { + Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple); + + /* + * We only operate on shared objects and objects in the current + * database + */ + if (sdepForm->dbid != MyDatabaseId && + sdepForm->dbid != InvalidOid) + continue; + + /* Unexpected because we checked for pins above */ + if (sdepForm->deptype == SHARED_DEPENDENCY_PIN) + elog(ERROR, "unexpected shared pin"); + + /* We leave non-owner dependencies alone */ + if (sdepForm->deptype != SHARED_DEPENDENCY_OWNER) + continue; + + /* Issue the appropriate ALTER OWNER call */ + switch (sdepForm->classid) + { + case TypeRelationId: + AlterTypeOwner_oid(sdepForm->objid, newrole, true); + break; + + case NamespaceRelationId: + AlterSchemaOwner_oid(sdepForm->objid, newrole); + break; + + case RelationRelationId: + + /* + * Pass recursing = true so that we don't fail on indexes, + * owned sequences, etc when we happen to visit them + * before their parent table. + */ + ATExecChangeOwner(sdepForm->objid, newrole, true, AccessExclusiveLock); + break; + + case DefaultAclRelationId: + + /* + * Ignore default ACLs; they should be handled by DROP + * OWNED, not REASSIGN OWNED. + */ + break; + + case UserMappingRelationId: + /* ditto */ + break; + + case ForeignServerRelationId: + AlterForeignServerOwner_oid(sdepForm->objid, newrole); + break; + + case ForeignDataWrapperRelationId: + AlterForeignDataWrapperOwner_oid(sdepForm->objid, newrole); + break; + + case EventTriggerRelationId: + AlterEventTriggerOwner_oid(sdepForm->objid, newrole); + break; + + case PublicationRelationId: + AlterPublicationOwner_oid(sdepForm->objid, newrole); + break; + + case SubscriptionRelationId: + AlterSubscriptionOwner_oid(sdepForm->objid, newrole); + break; + + /* Generic alter owner cases */ + case CollationRelationId: + case ConversionRelationId: + case OperatorRelationId: + case ProcedureRelationId: + case LanguageRelationId: + case LargeObjectRelationId: + case OperatorFamilyRelationId: + case OperatorClassRelationId: + case ExtensionRelationId: + case StatisticExtRelationId: + case TableSpaceRelationId: + case DatabaseRelationId: + case TSConfigRelationId: + case TSDictionaryRelationId: + { + Oid classId = sdepForm->classid; + Relation catalog; + + if (classId == LargeObjectRelationId) + classId = LargeObjectMetadataRelationId; + + catalog = table_open(classId, RowExclusiveLock); + + AlterObjectOwner_internal(catalog, sdepForm->objid, + newrole); + + table_close(catalog, NoLock); + } + break; + + default: + elog(ERROR, "unexpected classid %u", sdepForm->classid); + break; + } + /* Make sure the next iteration will see my changes */ + CommandCounterIncrement(); + } + + systable_endscan(scan); + } + + table_close(sdepRel, RowExclusiveLock); +} diff --git a/src/backend/catalog/pg_shdepend_d.h b/src/backend/catalog/pg_shdepend_d.h new file mode 100644 index 0000000..b62d5c9 --- /dev/null +++ b/src/backend/catalog/pg_shdepend_d.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- + * + * pg_shdepend_d.h + * Macro definitions for pg_shdepend + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_SHDEPEND_D_H +#define PG_SHDEPEND_D_H + +#define SharedDependRelationId 1214 + +#define Anum_pg_shdepend_dbid 1 +#define Anum_pg_shdepend_classid 2 +#define Anum_pg_shdepend_objid 3 +#define Anum_pg_shdepend_objsubid 4 +#define Anum_pg_shdepend_refclassid 5 +#define Anum_pg_shdepend_refobjid 6 +#define Anum_pg_shdepend_deptype 7 + +#define Natts_pg_shdepend 7 + + +#endif /* PG_SHDEPEND_D_H */ diff --git a/src/backend/catalog/pg_shdescription_d.h b/src/backend/catalog/pg_shdescription_d.h new file mode 100644 index 0000000..238da96 --- /dev/null +++ b/src/backend/catalog/pg_shdescription_d.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * pg_shdescription_d.h + * Macro definitions for pg_shdescription + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_SHDESCRIPTION_D_H +#define PG_SHDESCRIPTION_D_H + +#define SharedDescriptionRelationId 2396 + +#define Anum_pg_shdescription_objoid 1 +#define Anum_pg_shdescription_classoid 2 +#define Anum_pg_shdescription_description 3 + +#define Natts_pg_shdescription 3 + + +#endif /* PG_SHDESCRIPTION_D_H */ diff --git a/src/backend/catalog/pg_shseclabel_d.h b/src/backend/catalog/pg_shseclabel_d.h new file mode 100644 index 0000000..f6058f3 --- /dev/null +++ b/src/backend/catalog/pg_shseclabel_d.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * pg_shseclabel_d.h + * Macro definitions for pg_shseclabel + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_SHSECLABEL_D_H +#define PG_SHSECLABEL_D_H + +#define SharedSecLabelRelationId 3592 +#define SharedSecLabelRelation_Rowtype_Id 4066 + +#define Anum_pg_shseclabel_objoid 1 +#define Anum_pg_shseclabel_classoid 2 +#define Anum_pg_shseclabel_provider 3 +#define Anum_pg_shseclabel_label 4 + +#define Natts_pg_shseclabel 4 + + +#endif /* PG_SHSECLABEL_D_H */ diff --git a/src/backend/catalog/pg_statistic_d.h b/src/backend/catalog/pg_statistic_d.h new file mode 100644 index 0000000..1174daa --- /dev/null +++ b/src/backend/catalog/pg_statistic_d.h @@ -0,0 +1,194 @@ +/*------------------------------------------------------------------------- + * + * pg_statistic_d.h + * Macro definitions for pg_statistic + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_STATISTIC_D_H +#define PG_STATISTIC_D_H + +#define StatisticRelationId 2619 + +#define Anum_pg_statistic_starelid 1 +#define Anum_pg_statistic_staattnum 2 +#define Anum_pg_statistic_stainherit 3 +#define Anum_pg_statistic_stanullfrac 4 +#define Anum_pg_statistic_stawidth 5 +#define Anum_pg_statistic_stadistinct 6 +#define Anum_pg_statistic_stakind1 7 +#define Anum_pg_statistic_stakind2 8 +#define Anum_pg_statistic_stakind3 9 +#define Anum_pg_statistic_stakind4 10 +#define Anum_pg_statistic_stakind5 11 +#define Anum_pg_statistic_staop1 12 +#define Anum_pg_statistic_staop2 13 +#define Anum_pg_statistic_staop3 14 +#define Anum_pg_statistic_staop4 15 +#define Anum_pg_statistic_staop5 16 +#define Anum_pg_statistic_stacoll1 17 +#define Anum_pg_statistic_stacoll2 18 +#define Anum_pg_statistic_stacoll3 19 +#define Anum_pg_statistic_stacoll4 20 +#define Anum_pg_statistic_stacoll5 21 +#define Anum_pg_statistic_stanumbers1 22 +#define Anum_pg_statistic_stanumbers2 23 +#define Anum_pg_statistic_stanumbers3 24 +#define Anum_pg_statistic_stanumbers4 25 +#define Anum_pg_statistic_stanumbers5 26 +#define Anum_pg_statistic_stavalues1 27 +#define Anum_pg_statistic_stavalues2 28 +#define Anum_pg_statistic_stavalues3 29 +#define Anum_pg_statistic_stavalues4 30 +#define Anum_pg_statistic_stavalues5 31 + +#define Natts_pg_statistic 31 + + +/* + * Several statistical slot "kinds" are defined by core PostgreSQL, as + * documented below. Also, custom data types can define their own "kind" + * codes by mutual agreement between a custom typanalyze routine and the + * selectivity estimation functions of the type's operators. + * + * Code reading the pg_statistic relation should not assume that a particular + * data "kind" will appear in any particular slot. Instead, search the + * stakind fields to see if the desired data is available. (The standard + * function get_attstatsslot() may be used for this.) + */ + +/* + * The present allocation of "kind" codes is: + * + * 1-99: reserved for assignment by the core PostgreSQL project + * (values in this range will be documented in this file) + * 100-199: reserved for assignment by the PostGIS project + * (values to be documented in PostGIS documentation) + * 200-299: reserved for assignment by the ESRI ST_Geometry project + * (values to be documented in ESRI ST_Geometry documentation) + * 300-9999: reserved for future public assignments + * + * For private use you may choose a "kind" code at random in the range + * 10000-30000. However, for code that is to be widely disseminated it is + * better to obtain a publicly defined "kind" code by request from the + * PostgreSQL Global Development Group. + */ + +/* + * In a "most common values" slot, staop is the OID of the "=" operator + * used to decide whether values are the same or not, and stacoll is the + * collation used (same as column's collation). stavalues contains + * the K most common non-null values appearing in the column, and stanumbers + * contains their frequencies (fractions of total row count). The values + * shall be ordered in decreasing frequency. Note that since the arrays are + * variable-size, K may be chosen by the statistics collector. Values should + * not appear in MCV unless they have been observed to occur more than once; + * a unique column will have no MCV slot. + */ +#define STATISTIC_KIND_MCV 1 + +/* + * A "histogram" slot describes the distribution of scalar data. staop is + * the OID of the "<" operator that describes the sort ordering, and stacoll + * is the relevant collation. (In theory more than one histogram could appear, + * if a datatype has more than one useful sort operator or we care about more + * than one collation. Currently the collation will always be that of the + * underlying column.) stavalues contains M (>=2) non-null values that + * divide the non-null column data values into M-1 bins of approximately equal + * population. The first stavalues item is the MIN and the last is the MAX. + * stanumbers is not used and should be NULL. IMPORTANT POINT: if an MCV + * slot is also provided, then the histogram describes the data distribution + * *after removing the values listed in MCV* (thus, it's a "compressed + * histogram" in the technical parlance). This allows a more accurate + * representation of the distribution of a column with some very-common + * values. In a column with only a few distinct values, it's possible that + * the MCV list describes the entire data population; in this case the + * histogram reduces to empty and should be omitted. + */ +#define STATISTIC_KIND_HISTOGRAM 2 + +/* + * A "correlation" slot describes the correlation between the physical order + * of table tuples and the ordering of data values of this column, as seen + * by the "<" operator identified by staop with the collation identified by + * stacoll. (As with the histogram, more than one entry could theoretically + * appear.) stavalues is not used and should be NULL. stanumbers contains + * a single entry, the correlation coefficient between the sequence of data + * values and the sequence of their actual tuple positions. The coefficient + * ranges from +1 to -1. + */ +#define STATISTIC_KIND_CORRELATION 3 + +/* + * A "most common elements" slot is similar to a "most common values" slot, + * except that it stores the most common non-null *elements* of the column + * values. This is useful when the column datatype is an array or some other + * type with identifiable elements (for instance, tsvector). staop contains + * the equality operator appropriate to the element type, and stacoll + * contains the collation to use with it. stavalues contains + * the most common element values, and stanumbers their frequencies. Unlike + * MCV slots, frequencies are measured as the fraction of non-null rows the + * element value appears in, not the frequency of all rows. Also unlike + * MCV slots, the values are sorted into the element type's default order + * (to support binary search for a particular value). Since this puts the + * minimum and maximum frequencies at unpredictable spots in stanumbers, + * there are two extra members of stanumbers, holding copies of the minimum + * and maximum frequencies. Optionally, there can be a third extra member, + * which holds the frequency of null elements (expressed in the same terms: + * the fraction of non-null rows that contain at least one null element). If + * this member is omitted, the column is presumed to contain no null elements. + * + * Note: in current usage for tsvector columns, the stavalues elements are of + * type text, even though their representation within tsvector is not + * exactly text. + */ +#define STATISTIC_KIND_MCELEM 4 + +/* + * A "distinct elements count histogram" slot describes the distribution of + * the number of distinct element values present in each row of an array-type + * column. Only non-null rows are considered, and only non-null elements. + * staop contains the equality operator appropriate to the element type, + * and stacoll contains the collation to use with it. + * stavalues is not used and should be NULL. The last member of stanumbers is + * the average count of distinct element values over all non-null rows. The + * preceding M (>=2) members form a histogram that divides the population of + * distinct-elements counts into M-1 bins of approximately equal population. + * The first of these is the minimum observed count, and the last the maximum. + */ +#define STATISTIC_KIND_DECHIST 5 + +/* + * A "length histogram" slot describes the distribution of range lengths in + * rows of a range-type column. stanumbers contains a single entry, the + * fraction of empty ranges. stavalues is a histogram of non-empty lengths, in + * a format similar to STATISTIC_KIND_HISTOGRAM: it contains M (>=2) range + * values that divide the column data values into M-1 bins of approximately + * equal population. The lengths are stored as float8s, as measured by the + * range type's subdiff function. Only non-null rows are considered. + */ +#define STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM 6 + +/* + * A "bounds histogram" slot is similar to STATISTIC_KIND_HISTOGRAM, but for + * a range-type column. stavalues contains M (>=2) range values that divide + * the column data values into M-1 bins of approximately equal population. + * Unlike a regular scalar histogram, this is actually two histograms combined + * into a single array, with the lower bounds of each value forming a + * histogram of lower bounds, and the upper bounds a histogram of upper + * bounds. Only non-NULL, non-empty ranges are included. + */ +#define STATISTIC_KIND_BOUNDS_HISTOGRAM 7 + + +#endif /* PG_STATISTIC_D_H */ diff --git a/src/backend/catalog/pg_statistic_ext_d.h b/src/backend/catalog/pg_statistic_ext_d.h new file mode 100644 index 0000000..809e97e --- /dev/null +++ b/src/backend/catalog/pg_statistic_ext_d.h @@ -0,0 +1,40 @@ +/*------------------------------------------------------------------------- + * + * pg_statistic_ext_d.h + * Macro definitions for pg_statistic_ext + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_STATISTIC_EXT_D_H +#define PG_STATISTIC_EXT_D_H + +#define StatisticExtRelationId 3381 + +#define Anum_pg_statistic_ext_oid 1 +#define Anum_pg_statistic_ext_stxrelid 2 +#define Anum_pg_statistic_ext_stxname 3 +#define Anum_pg_statistic_ext_stxnamespace 4 +#define Anum_pg_statistic_ext_stxowner 5 +#define Anum_pg_statistic_ext_stxstattarget 6 +#define Anum_pg_statistic_ext_stxkeys 7 +#define Anum_pg_statistic_ext_stxkind 8 + +#define Natts_pg_statistic_ext 8 + + +#define STATS_EXT_NDISTINCT 'd' +#define STATS_EXT_DEPENDENCIES 'f' +#define STATS_EXT_MCV 'm' + + +#endif /* PG_STATISTIC_EXT_D_H */ diff --git a/src/backend/catalog/pg_statistic_ext_data_d.h b/src/backend/catalog/pg_statistic_ext_data_d.h new file mode 100644 index 0000000..79df16d --- /dev/null +++ b/src/backend/catalog/pg_statistic_ext_data_d.h @@ -0,0 +1,31 @@ +/*------------------------------------------------------------------------- + * + * pg_statistic_ext_data_d.h + * Macro definitions for pg_statistic_ext_data + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_STATISTIC_EXT_DATA_D_H +#define PG_STATISTIC_EXT_DATA_D_H + +#define StatisticExtDataRelationId 3429 + +#define Anum_pg_statistic_ext_data_stxoid 1 +#define Anum_pg_statistic_ext_data_stxdndistinct 2 +#define Anum_pg_statistic_ext_data_stxddependencies 3 +#define Anum_pg_statistic_ext_data_stxdmcv 4 + +#define Natts_pg_statistic_ext_data 4 + + +#endif /* PG_STATISTIC_EXT_DATA_D_H */ diff --git a/src/backend/catalog/pg_subscription.c b/src/backend/catalog/pg_subscription.c new file mode 100644 index 0000000..0d23b20 --- /dev/null +++ b/src/backend/catalog/pg_subscription.c @@ -0,0 +1,536 @@ +/*------------------------------------------------------------------------- + * + * pg_subscription.c + * replication subscriptions + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/catalog/pg_subscription.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/genam.h" +#include "access/heapam.h" +#include "access/htup_details.h" +#include "access/tableam.h" +#include "access/xact.h" +#include "catalog/indexing.h" +#include "catalog/pg_subscription.h" +#include "catalog/pg_subscription_rel.h" +#include "catalog/pg_type.h" +#include "miscadmin.h" +#include "nodes/makefuncs.h" +#include "storage/lmgr.h" +#include "utils/array.h" +#include "utils/builtins.h" +#include "utils/fmgroids.h" +#include "utils/pg_lsn.h" +#include "utils/rel.h" +#include "utils/syscache.h" + +static List *textarray_to_stringlist(ArrayType *textarray); + +/* + * Fetch the subscription from the syscache. + */ +Subscription * +GetSubscription(Oid subid, bool missing_ok) +{ + HeapTuple tup; + Subscription *sub; + Form_pg_subscription subform; + Datum datum; + bool isnull; + + tup = SearchSysCache1(SUBSCRIPTIONOID, ObjectIdGetDatum(subid)); + + if (!HeapTupleIsValid(tup)) + { + if (missing_ok) + return NULL; + + elog(ERROR, "cache lookup failed for subscription %u", subid); + } + + subform = (Form_pg_subscription) GETSTRUCT(tup); + + sub = (Subscription *) palloc(sizeof(Subscription)); + sub->oid = subid; + sub->dbid = subform->subdbid; + sub->name = pstrdup(NameStr(subform->subname)); + sub->owner = subform->subowner; + sub->enabled = subform->subenabled; + + /* Get conninfo */ + datum = SysCacheGetAttr(SUBSCRIPTIONOID, + tup, + Anum_pg_subscription_subconninfo, + &isnull); + Assert(!isnull); + sub->conninfo = TextDatumGetCString(datum); + + /* Get slotname */ + datum = SysCacheGetAttr(SUBSCRIPTIONOID, + tup, + Anum_pg_subscription_subslotname, + &isnull); + if (!isnull) + sub->slotname = pstrdup(NameStr(*DatumGetName(datum))); + else + sub->slotname = NULL; + + /* Get synccommit */ + datum = SysCacheGetAttr(SUBSCRIPTIONOID, + tup, + Anum_pg_subscription_subsynccommit, + &isnull); + Assert(!isnull); + sub->synccommit = TextDatumGetCString(datum); + + /* Get publications */ + datum = SysCacheGetAttr(SUBSCRIPTIONOID, + tup, + Anum_pg_subscription_subpublications, + &isnull); + Assert(!isnull); + sub->publications = textarray_to_stringlist(DatumGetArrayTypeP(datum)); + + ReleaseSysCache(tup); + + return sub; +} + +/* + * Return number of subscriptions defined in given database. + * Used by dropdb() to check if database can indeed be dropped. + */ +int +CountDBSubscriptions(Oid dbid) +{ + int nsubs = 0; + Relation rel; + ScanKeyData scankey; + SysScanDesc scan; + HeapTuple tup; + + rel = table_open(SubscriptionRelationId, RowExclusiveLock); + + ScanKeyInit(&scankey, + Anum_pg_subscription_subdbid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(dbid)); + + scan = systable_beginscan(rel, InvalidOid, false, + NULL, 1, &scankey); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + nsubs++; + + systable_endscan(scan); + + table_close(rel, NoLock); + + return nsubs; +} + +/* + * Free memory allocated by subscription struct. + */ +void +FreeSubscription(Subscription *sub) +{ + pfree(sub->name); + pfree(sub->conninfo); + if (sub->slotname) + pfree(sub->slotname); + list_free_deep(sub->publications); + pfree(sub); +} + +/* + * get_subscription_oid - given a subscription name, look up the OID + * + * If missing_ok is false, throw an error if name not found. If true, just + * return InvalidOid. + */ +Oid +get_subscription_oid(const char *subname, bool missing_ok) +{ + Oid oid; + + oid = GetSysCacheOid2(SUBSCRIPTIONNAME, Anum_pg_subscription_oid, + MyDatabaseId, CStringGetDatum(subname)); + if (!OidIsValid(oid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("subscription \"%s\" does not exist", subname))); + return oid; +} + +/* + * get_subscription_name - given a subscription OID, look up the name + * + * If missing_ok is false, throw an error if name not found. If true, just + * return NULL. + */ +char * +get_subscription_name(Oid subid, bool missing_ok) +{ + HeapTuple tup; + char *subname; + Form_pg_subscription subform; + + tup = SearchSysCache1(SUBSCRIPTIONOID, ObjectIdGetDatum(subid)); + + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "cache lookup failed for subscription %u", subid); + return NULL; + } + + subform = (Form_pg_subscription) GETSTRUCT(tup); + subname = pstrdup(NameStr(subform->subname)); + + ReleaseSysCache(tup); + + return subname; +} + +/* + * Convert text array to list of strings. + * + * Note: the resulting list of strings is pallocated here. + */ +static List * +textarray_to_stringlist(ArrayType *textarray) +{ + Datum *elems; + int nelems, + i; + List *res = NIL; + + deconstruct_array(textarray, + TEXTOID, -1, false, TYPALIGN_INT, + &elems, NULL, &nelems); + + if (nelems == 0) + return NIL; + + for (i = 0; i < nelems; i++) + res = lappend(res, makeString(TextDatumGetCString(elems[i]))); + + return res; +} + +/* + * Add new state record for a subscription table. + */ +void +AddSubscriptionRelState(Oid subid, Oid relid, char state, + XLogRecPtr sublsn) +{ + Relation rel; + HeapTuple tup; + bool nulls[Natts_pg_subscription_rel]; + Datum values[Natts_pg_subscription_rel]; + + LockSharedObject(SubscriptionRelationId, subid, 0, AccessShareLock); + + rel = table_open(SubscriptionRelRelationId, RowExclusiveLock); + + /* Try finding existing mapping. */ + tup = SearchSysCacheCopy2(SUBSCRIPTIONRELMAP, + ObjectIdGetDatum(relid), + ObjectIdGetDatum(subid)); + if (HeapTupleIsValid(tup)) + elog(ERROR, "subscription table %u in subscription %u already exists", + relid, subid); + + /* Form the tuple. */ + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + values[Anum_pg_subscription_rel_srsubid - 1] = ObjectIdGetDatum(subid); + values[Anum_pg_subscription_rel_srrelid - 1] = ObjectIdGetDatum(relid); + values[Anum_pg_subscription_rel_srsubstate - 1] = CharGetDatum(state); + if (sublsn != InvalidXLogRecPtr) + values[Anum_pg_subscription_rel_srsublsn - 1] = LSNGetDatum(sublsn); + else + nulls[Anum_pg_subscription_rel_srsublsn - 1] = true; + + tup = heap_form_tuple(RelationGetDescr(rel), values, nulls); + + /* Insert tuple into catalog. */ + CatalogTupleInsert(rel, tup); + + heap_freetuple(tup); + + /* Cleanup. */ + table_close(rel, NoLock); +} + +/* + * Update the state of a subscription table. + */ +void +UpdateSubscriptionRelState(Oid subid, Oid relid, char state, + XLogRecPtr sublsn) +{ + Relation rel; + HeapTuple tup; + bool nulls[Natts_pg_subscription_rel]; + Datum values[Natts_pg_subscription_rel]; + bool replaces[Natts_pg_subscription_rel]; + + LockSharedObject(SubscriptionRelationId, subid, 0, AccessShareLock); + + rel = table_open(SubscriptionRelRelationId, RowExclusiveLock); + + /* Try finding existing mapping. */ + tup = SearchSysCacheCopy2(SUBSCRIPTIONRELMAP, + ObjectIdGetDatum(relid), + ObjectIdGetDatum(subid)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "subscription table %u in subscription %u does not exist", + relid, subid); + + /* Update the tuple. */ + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + memset(replaces, false, sizeof(replaces)); + + replaces[Anum_pg_subscription_rel_srsubstate - 1] = true; + values[Anum_pg_subscription_rel_srsubstate - 1] = CharGetDatum(state); + + replaces[Anum_pg_subscription_rel_srsublsn - 1] = true; + if (sublsn != InvalidXLogRecPtr) + values[Anum_pg_subscription_rel_srsublsn - 1] = LSNGetDatum(sublsn); + else + nulls[Anum_pg_subscription_rel_srsublsn - 1] = true; + + tup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls, + replaces); + + /* Update the catalog. */ + CatalogTupleUpdate(rel, &tup->t_self, tup); + + /* Cleanup. */ + table_close(rel, NoLock); +} + +/* + * Get state of subscription table. + * + * Returns SUBREL_STATE_UNKNOWN when not found and missing_ok is true. + */ +char +GetSubscriptionRelState(Oid subid, Oid relid, XLogRecPtr *sublsn, + bool missing_ok) +{ + Relation rel; + HeapTuple tup; + char substate; + bool isnull; + Datum d; + + rel = table_open(SubscriptionRelRelationId, AccessShareLock); + + /* Try finding the mapping. */ + tup = SearchSysCache2(SUBSCRIPTIONRELMAP, + ObjectIdGetDatum(relid), + ObjectIdGetDatum(subid)); + + if (!HeapTupleIsValid(tup)) + { + if (missing_ok) + { + table_close(rel, AccessShareLock); + *sublsn = InvalidXLogRecPtr; + return SUBREL_STATE_UNKNOWN; + } + + elog(ERROR, "subscription table %u in subscription %u does not exist", + relid, subid); + } + + /* Get the state. */ + d = SysCacheGetAttr(SUBSCRIPTIONRELMAP, tup, + Anum_pg_subscription_rel_srsubstate, &isnull); + Assert(!isnull); + substate = DatumGetChar(d); + d = SysCacheGetAttr(SUBSCRIPTIONRELMAP, tup, + Anum_pg_subscription_rel_srsublsn, &isnull); + if (isnull) + *sublsn = InvalidXLogRecPtr; + else + *sublsn = DatumGetLSN(d); + + /* Cleanup */ + ReleaseSysCache(tup); + table_close(rel, AccessShareLock); + + return substate; +} + +/* + * Drop subscription relation mapping. These can be for a particular + * subscription, or for a particular relation, or both. + */ +void +RemoveSubscriptionRel(Oid subid, Oid relid) +{ + Relation rel; + TableScanDesc scan; + ScanKeyData skey[2]; + HeapTuple tup; + int nkeys = 0; + + rel = table_open(SubscriptionRelRelationId, RowExclusiveLock); + + if (OidIsValid(subid)) + { + ScanKeyInit(&skey[nkeys++], + Anum_pg_subscription_rel_srsubid, + BTEqualStrategyNumber, + F_OIDEQ, + ObjectIdGetDatum(subid)); + } + + if (OidIsValid(relid)) + { + ScanKeyInit(&skey[nkeys++], + Anum_pg_subscription_rel_srrelid, + BTEqualStrategyNumber, + F_OIDEQ, + ObjectIdGetDatum(relid)); + } + + /* Do the search and delete what we found. */ + scan = table_beginscan_catalog(rel, nkeys, skey); + while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection))) + { + CatalogTupleDelete(rel, &tup->t_self); + } + table_endscan(scan); + + table_close(rel, RowExclusiveLock); +} + + +/* + * Get all relations for subscription. + * + * Returned list is palloc'ed in current memory context. + */ +List * +GetSubscriptionRelations(Oid subid) +{ + List *res = NIL; + Relation rel; + HeapTuple tup; + int nkeys = 0; + ScanKeyData skey[2]; + SysScanDesc scan; + + rel = table_open(SubscriptionRelRelationId, AccessShareLock); + + ScanKeyInit(&skey[nkeys++], + Anum_pg_subscription_rel_srsubid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(subid)); + + scan = systable_beginscan(rel, InvalidOid, false, + NULL, nkeys, skey); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_subscription_rel subrel; + SubscriptionRelState *relstate; + Datum d; + bool isnull; + + subrel = (Form_pg_subscription_rel) GETSTRUCT(tup); + + relstate = (SubscriptionRelState *) palloc(sizeof(SubscriptionRelState)); + relstate->relid = subrel->srrelid; + relstate->state = subrel->srsubstate; + d = SysCacheGetAttr(SUBSCRIPTIONRELMAP, tup, + Anum_pg_subscription_rel_srsublsn, &isnull); + if (isnull) + relstate->lsn = InvalidXLogRecPtr; + else + relstate->lsn = DatumGetLSN(d); + + res = lappend(res, relstate); + } + + /* Cleanup */ + systable_endscan(scan); + table_close(rel, AccessShareLock); + + return res; +} + +/* + * Get all relations for subscription that are not in a ready state. + * + * Returned list is palloc'ed in current memory context. + */ +List * +GetSubscriptionNotReadyRelations(Oid subid) +{ + List *res = NIL; + Relation rel; + HeapTuple tup; + int nkeys = 0; + ScanKeyData skey[2]; + SysScanDesc scan; + + rel = table_open(SubscriptionRelRelationId, AccessShareLock); + + ScanKeyInit(&skey[nkeys++], + Anum_pg_subscription_rel_srsubid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(subid)); + + ScanKeyInit(&skey[nkeys++], + Anum_pg_subscription_rel_srsubstate, + BTEqualStrategyNumber, F_CHARNE, + CharGetDatum(SUBREL_STATE_READY)); + + scan = systable_beginscan(rel, InvalidOid, false, + NULL, nkeys, skey); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_subscription_rel subrel; + SubscriptionRelState *relstate; + Datum d; + bool isnull; + + subrel = (Form_pg_subscription_rel) GETSTRUCT(tup); + + relstate = (SubscriptionRelState *) palloc(sizeof(SubscriptionRelState)); + relstate->relid = subrel->srrelid; + relstate->state = subrel->srsubstate; + d = SysCacheGetAttr(SUBSCRIPTIONRELMAP, tup, + Anum_pg_subscription_rel_srsublsn, &isnull); + if (isnull) + relstate->lsn = InvalidXLogRecPtr; + else + relstate->lsn = DatumGetLSN(d); + + res = lappend(res, relstate); + } + + /* Cleanup */ + systable_endscan(scan); + table_close(rel, AccessShareLock); + + return res; +} diff --git a/src/backend/catalog/pg_subscription_d.h b/src/backend/catalog/pg_subscription_d.h new file mode 100644 index 0000000..de5c027 --- /dev/null +++ b/src/backend/catalog/pg_subscription_d.h @@ -0,0 +1,37 @@ +/*------------------------------------------------------------------------- + * + * pg_subscription_d.h + * Macro definitions for pg_subscription + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_SUBSCRIPTION_D_H +#define PG_SUBSCRIPTION_D_H + +#define SubscriptionRelationId 6100 +#define SubscriptionRelation_Rowtype_Id 6101 + +#define Anum_pg_subscription_oid 1 +#define Anum_pg_subscription_subdbid 2 +#define Anum_pg_subscription_subname 3 +#define Anum_pg_subscription_subowner 4 +#define Anum_pg_subscription_subenabled 5 +#define Anum_pg_subscription_subconninfo 6 +#define Anum_pg_subscription_subslotname 7 +#define Anum_pg_subscription_subsynccommit 8 +#define Anum_pg_subscription_subpublications 9 + +#define Natts_pg_subscription 9 + + +#endif /* PG_SUBSCRIPTION_D_H */ diff --git a/src/backend/catalog/pg_subscription_rel_d.h b/src/backend/catalog/pg_subscription_rel_d.h new file mode 100644 index 0000000..71ec769 --- /dev/null +++ b/src/backend/catalog/pg_subscription_rel_d.h @@ -0,0 +1,48 @@ +/*------------------------------------------------------------------------- + * + * pg_subscription_rel_d.h + * Macro definitions for pg_subscription_rel + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_SUBSCRIPTION_REL_D_H +#define PG_SUBSCRIPTION_REL_D_H + +#define SubscriptionRelRelationId 6102 + +#define Anum_pg_subscription_rel_srsubid 1 +#define Anum_pg_subscription_rel_srrelid 2 +#define Anum_pg_subscription_rel_srsubstate 3 +#define Anum_pg_subscription_rel_srsublsn 4 + +#define Natts_pg_subscription_rel 4 + + +/* ---------------- + * substate constants + * ---------------- + */ +#define SUBREL_STATE_INIT 'i' /* initializing (sublsn NULL) */ +#define SUBREL_STATE_DATASYNC 'd' /* data is being synchronized (sublsn + * NULL) */ +#define SUBREL_STATE_SYNCDONE 's' /* synchronization finished in front of + * apply (sublsn set) */ +#define SUBREL_STATE_READY 'r' /* ready (sublsn set) */ + +/* These are never stored in the catalog, we only use them for IPC. */ +#define SUBREL_STATE_UNKNOWN '\0' /* unknown state */ +#define SUBREL_STATE_SYNCWAIT 'w' /* waiting for sync */ +#define SUBREL_STATE_CATCHUP 'c' /* catching up with apply */ + + +#endif /* PG_SUBSCRIPTION_REL_D_H */ diff --git a/src/backend/catalog/pg_tablespace_d.h b/src/backend/catalog/pg_tablespace_d.h new file mode 100644 index 0000000..c66ad17 --- /dev/null +++ b/src/backend/catalog/pg_tablespace_d.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- + * + * pg_tablespace_d.h + * Macro definitions for pg_tablespace + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TABLESPACE_D_H +#define PG_TABLESPACE_D_H + +#define TableSpaceRelationId 1213 + +#define Anum_pg_tablespace_oid 1 +#define Anum_pg_tablespace_spcname 2 +#define Anum_pg_tablespace_spcowner 3 +#define Anum_pg_tablespace_spcacl 4 +#define Anum_pg_tablespace_spcoptions 5 + +#define Natts_pg_tablespace 5 + +#define DEFAULTTABLESPACE_OID 1663 +#define GLOBALTABLESPACE_OID 1664 + +#endif /* PG_TABLESPACE_D_H */ diff --git a/src/backend/catalog/pg_transform_d.h b/src/backend/catalog/pg_transform_d.h new file mode 100644 index 0000000..3bc064b --- /dev/null +++ b/src/backend/catalog/pg_transform_d.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * pg_transform_d.h + * Macro definitions for pg_transform + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TRANSFORM_D_H +#define PG_TRANSFORM_D_H + +#define TransformRelationId 3576 + +#define Anum_pg_transform_oid 1 +#define Anum_pg_transform_trftype 2 +#define Anum_pg_transform_trflang 3 +#define Anum_pg_transform_trffromsql 4 +#define Anum_pg_transform_trftosql 5 + +#define Natts_pg_transform 5 + + +#endif /* PG_TRANSFORM_D_H */ diff --git a/src/backend/catalog/pg_trigger_d.h b/src/backend/catalog/pg_trigger_d.h new file mode 100644 index 0000000..90d3058 --- /dev/null +++ b/src/backend/catalog/pg_trigger_d.h @@ -0,0 +1,106 @@ +/*------------------------------------------------------------------------- + * + * pg_trigger_d.h + * Macro definitions for pg_trigger + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TRIGGER_D_H +#define PG_TRIGGER_D_H + +#define TriggerRelationId 2620 + +#define Anum_pg_trigger_oid 1 +#define Anum_pg_trigger_tgrelid 2 +#define Anum_pg_trigger_tgparentid 3 +#define Anum_pg_trigger_tgname 4 +#define Anum_pg_trigger_tgfoid 5 +#define Anum_pg_trigger_tgtype 6 +#define Anum_pg_trigger_tgenabled 7 +#define Anum_pg_trigger_tgisinternal 8 +#define Anum_pg_trigger_tgconstrrelid 9 +#define Anum_pg_trigger_tgconstrindid 10 +#define Anum_pg_trigger_tgconstraint 11 +#define Anum_pg_trigger_tgdeferrable 12 +#define Anum_pg_trigger_tginitdeferred 13 +#define Anum_pg_trigger_tgnargs 14 +#define Anum_pg_trigger_tgattr 15 +#define Anum_pg_trigger_tgargs 16 +#define Anum_pg_trigger_tgqual 17 +#define Anum_pg_trigger_tgoldtable 18 +#define Anum_pg_trigger_tgnewtable 19 + +#define Natts_pg_trigger 19 + + +/* Bits within tgtype */ +#define TRIGGER_TYPE_ROW (1 << 0) +#define TRIGGER_TYPE_BEFORE (1 << 1) +#define TRIGGER_TYPE_INSERT (1 << 2) +#define TRIGGER_TYPE_DELETE (1 << 3) +#define TRIGGER_TYPE_UPDATE (1 << 4) +#define TRIGGER_TYPE_TRUNCATE (1 << 5) +#define TRIGGER_TYPE_INSTEAD (1 << 6) + +#define TRIGGER_TYPE_LEVEL_MASK (TRIGGER_TYPE_ROW) +#define TRIGGER_TYPE_STATEMENT 0 + +/* Note bits within TRIGGER_TYPE_TIMING_MASK aren't adjacent */ +#define TRIGGER_TYPE_TIMING_MASK \ + (TRIGGER_TYPE_BEFORE | TRIGGER_TYPE_INSTEAD) +#define TRIGGER_TYPE_AFTER 0 + +#define TRIGGER_TYPE_EVENT_MASK \ + (TRIGGER_TYPE_INSERT | TRIGGER_TYPE_DELETE | TRIGGER_TYPE_UPDATE | TRIGGER_TYPE_TRUNCATE) + +/* Macros for manipulating tgtype */ +#define TRIGGER_CLEAR_TYPE(type) ((type) = 0) + +#define TRIGGER_SETT_ROW(type) ((type) |= TRIGGER_TYPE_ROW) +#define TRIGGER_SETT_STATEMENT(type) ((type) |= TRIGGER_TYPE_STATEMENT) +#define TRIGGER_SETT_BEFORE(type) ((type) |= TRIGGER_TYPE_BEFORE) +#define TRIGGER_SETT_AFTER(type) ((type) |= TRIGGER_TYPE_AFTER) +#define TRIGGER_SETT_INSTEAD(type) ((type) |= TRIGGER_TYPE_INSTEAD) +#define TRIGGER_SETT_INSERT(type) ((type) |= TRIGGER_TYPE_INSERT) +#define TRIGGER_SETT_DELETE(type) ((type) |= TRIGGER_TYPE_DELETE) +#define TRIGGER_SETT_UPDATE(type) ((type) |= TRIGGER_TYPE_UPDATE) +#define TRIGGER_SETT_TRUNCATE(type) ((type) |= TRIGGER_TYPE_TRUNCATE) + +#define TRIGGER_FOR_ROW(type) ((type) & TRIGGER_TYPE_ROW) +#define TRIGGER_FOR_BEFORE(type) (((type) & TRIGGER_TYPE_TIMING_MASK) == TRIGGER_TYPE_BEFORE) +#define TRIGGER_FOR_AFTER(type) (((type) & TRIGGER_TYPE_TIMING_MASK) == TRIGGER_TYPE_AFTER) +#define TRIGGER_FOR_INSTEAD(type) (((type) & TRIGGER_TYPE_TIMING_MASK) == TRIGGER_TYPE_INSTEAD) +#define TRIGGER_FOR_INSERT(type) ((type) & TRIGGER_TYPE_INSERT) +#define TRIGGER_FOR_DELETE(type) ((type) & TRIGGER_TYPE_DELETE) +#define TRIGGER_FOR_UPDATE(type) ((type) & TRIGGER_TYPE_UPDATE) +#define TRIGGER_FOR_TRUNCATE(type) ((type) & TRIGGER_TYPE_TRUNCATE) + +/* + * Efficient macro for checking if tgtype matches a particular level + * (TRIGGER_TYPE_ROW or TRIGGER_TYPE_STATEMENT), timing (TRIGGER_TYPE_BEFORE, + * TRIGGER_TYPE_AFTER or TRIGGER_TYPE_INSTEAD), and event (TRIGGER_TYPE_INSERT, + * TRIGGER_TYPE_DELETE, TRIGGER_TYPE_UPDATE, or TRIGGER_TYPE_TRUNCATE). Note + * that a tgtype can match more than one event, but only one level or timing. + */ +#define TRIGGER_TYPE_MATCHES(type, level, timing, event) \ + (((type) & (TRIGGER_TYPE_LEVEL_MASK | TRIGGER_TYPE_TIMING_MASK | (event))) == ((level) | (timing) | (event))) + +/* + * Macro to determine whether tgnewtable or tgoldtable has been specified for + * a trigger. + */ +#define TRIGGER_USES_TRANSITION_TABLE(namepointer) \ + ((namepointer) != (char *) NULL) + + +#endif /* PG_TRIGGER_D_H */ diff --git a/src/backend/catalog/pg_ts_config_d.h b/src/backend/catalog/pg_ts_config_d.h new file mode 100644 index 0000000..7f2c933 --- /dev/null +++ b/src/backend/catalog/pg_ts_config_d.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * pg_ts_config_d.h + * Macro definitions for pg_ts_config + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TS_CONFIG_D_H +#define PG_TS_CONFIG_D_H + +#define TSConfigRelationId 3602 + +#define Anum_pg_ts_config_oid 1 +#define Anum_pg_ts_config_cfgname 2 +#define Anum_pg_ts_config_cfgnamespace 3 +#define Anum_pg_ts_config_cfgowner 4 +#define Anum_pg_ts_config_cfgparser 5 + +#define Natts_pg_ts_config 5 + + +#endif /* PG_TS_CONFIG_D_H */ diff --git a/src/backend/catalog/pg_ts_config_map_d.h b/src/backend/catalog/pg_ts_config_map_d.h new file mode 100644 index 0000000..f5b7748 --- /dev/null +++ b/src/backend/catalog/pg_ts_config_map_d.h @@ -0,0 +1,31 @@ +/*------------------------------------------------------------------------- + * + * pg_ts_config_map_d.h + * Macro definitions for pg_ts_config_map + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TS_CONFIG_MAP_D_H +#define PG_TS_CONFIG_MAP_D_H + +#define TSConfigMapRelationId 3603 + +#define Anum_pg_ts_config_map_mapcfg 1 +#define Anum_pg_ts_config_map_maptokentype 2 +#define Anum_pg_ts_config_map_mapseqno 3 +#define Anum_pg_ts_config_map_mapdict 4 + +#define Natts_pg_ts_config_map 4 + + +#endif /* PG_TS_CONFIG_MAP_D_H */ diff --git a/src/backend/catalog/pg_ts_dict_d.h b/src/backend/catalog/pg_ts_dict_d.h new file mode 100644 index 0000000..d2e8382 --- /dev/null +++ b/src/backend/catalog/pg_ts_dict_d.h @@ -0,0 +1,33 @@ +/*------------------------------------------------------------------------- + * + * pg_ts_dict_d.h + * Macro definitions for pg_ts_dict + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TS_DICT_D_H +#define PG_TS_DICT_D_H + +#define TSDictionaryRelationId 3600 + +#define Anum_pg_ts_dict_oid 1 +#define Anum_pg_ts_dict_dictname 2 +#define Anum_pg_ts_dict_dictnamespace 3 +#define Anum_pg_ts_dict_dictowner 4 +#define Anum_pg_ts_dict_dicttemplate 5 +#define Anum_pg_ts_dict_dictinitoption 6 + +#define Natts_pg_ts_dict 6 + + +#endif /* PG_TS_DICT_D_H */ diff --git a/src/backend/catalog/pg_ts_parser_d.h b/src/backend/catalog/pg_ts_parser_d.h new file mode 100644 index 0000000..635a4e4 --- /dev/null +++ b/src/backend/catalog/pg_ts_parser_d.h @@ -0,0 +1,35 @@ +/*------------------------------------------------------------------------- + * + * pg_ts_parser_d.h + * Macro definitions for pg_ts_parser + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TS_PARSER_D_H +#define PG_TS_PARSER_D_H + +#define TSParserRelationId 3601 + +#define Anum_pg_ts_parser_oid 1 +#define Anum_pg_ts_parser_prsname 2 +#define Anum_pg_ts_parser_prsnamespace 3 +#define Anum_pg_ts_parser_prsstart 4 +#define Anum_pg_ts_parser_prstoken 5 +#define Anum_pg_ts_parser_prsend 6 +#define Anum_pg_ts_parser_prsheadline 7 +#define Anum_pg_ts_parser_prslextype 8 + +#define Natts_pg_ts_parser 8 + + +#endif /* PG_TS_PARSER_D_H */ diff --git a/src/backend/catalog/pg_ts_template_d.h b/src/backend/catalog/pg_ts_template_d.h new file mode 100644 index 0000000..1a5f8f2 --- /dev/null +++ b/src/backend/catalog/pg_ts_template_d.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * pg_ts_template_d.h + * Macro definitions for pg_ts_template + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TS_TEMPLATE_D_H +#define PG_TS_TEMPLATE_D_H + +#define TSTemplateRelationId 3764 + +#define Anum_pg_ts_template_oid 1 +#define Anum_pg_ts_template_tmplname 2 +#define Anum_pg_ts_template_tmplnamespace 3 +#define Anum_pg_ts_template_tmplinit 4 +#define Anum_pg_ts_template_tmpllexize 5 + +#define Natts_pg_ts_template 5 + + +#endif /* PG_TS_TEMPLATE_D_H */ diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c new file mode 100644 index 0000000..cd56714 --- /dev/null +++ b/src/backend/catalog/pg_type.c @@ -0,0 +1,906 @@ +/*------------------------------------------------------------------------- + * + * pg_type.c + * routines to support manipulation of the pg_type relation + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/pg_type.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/htup_details.h" +#include "access/table.h" +#include "access/xact.h" +#include "catalog/binary_upgrade.h" +#include "catalog/catalog.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/objectaccess.h" +#include "catalog/pg_collation.h" +#include "catalog/pg_namespace.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_type.h" +#include "commands/typecmds.h" +#include "miscadmin.h" +#include "parser/scansup.h" +#include "utils/acl.h" +#include "utils/builtins.h" +#include "utils/fmgroids.h" +#include "utils/lsyscache.h" +#include "utils/rel.h" +#include "utils/syscache.h" + +/* Potentially set by pg_upgrade_support functions */ +Oid binary_upgrade_next_pg_type_oid = InvalidOid; + +/* ---------------------------------------------------------------- + * TypeShellMake + * + * This procedure inserts a "shell" tuple into the pg_type relation. + * The type tuple inserted has valid but dummy values, and its + * "typisdefined" field is false indicating it's not really defined. + * + * This is used so that a tuple exists in the catalogs. The I/O + * functions for the type will link to this tuple. When the full + * CREATE TYPE command is issued, the bogus values will be replaced + * with correct ones, and "typisdefined" will be set to true. + * ---------------------------------------------------------------- + */ +ObjectAddress +TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId) +{ + Relation pg_type_desc; + TupleDesc tupDesc; + int i; + HeapTuple tup; + Datum values[Natts_pg_type]; + bool nulls[Natts_pg_type]; + Oid typoid; + NameData name; + ObjectAddress address; + + Assert(PointerIsValid(typeName)); + + /* + * open pg_type + */ + pg_type_desc = table_open(TypeRelationId, RowExclusiveLock); + tupDesc = pg_type_desc->rd_att; + + /* + * initialize our *nulls and *values arrays + */ + for (i = 0; i < Natts_pg_type; ++i) + { + nulls[i] = false; + values[i] = (Datum) NULL; /* redundant, but safe */ + } + + /* + * initialize *values with the type name and dummy values + * + * The representational details are the same as int4 ... it doesn't really + * matter what they are so long as they are consistent. Also note that we + * give it typtype = TYPTYPE_PSEUDO as extra insurance that it won't be + * mistaken for a usable type. + */ + namestrcpy(&name, typeName); + values[Anum_pg_type_typname - 1] = NameGetDatum(&name); + values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace); + values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId); + values[Anum_pg_type_typlen - 1] = Int16GetDatum(sizeof(int32)); + values[Anum_pg_type_typbyval - 1] = BoolGetDatum(true); + values[Anum_pg_type_typtype - 1] = CharGetDatum(TYPTYPE_PSEUDO); + values[Anum_pg_type_typcategory - 1] = CharGetDatum(TYPCATEGORY_PSEUDOTYPE); + values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(false); + values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(false); + values[Anum_pg_type_typdelim - 1] = CharGetDatum(DEFAULT_TYPDELIM); + values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(InvalidOid); + values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(InvalidOid); + values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(InvalidOid); + values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(F_SHELL_IN); + values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(F_SHELL_OUT); + values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(InvalidOid); + values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(InvalidOid); + values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(InvalidOid); + values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(InvalidOid); + values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(InvalidOid); + values[Anum_pg_type_typalign - 1] = CharGetDatum(TYPALIGN_INT); + values[Anum_pg_type_typstorage - 1] = CharGetDatum(TYPSTORAGE_PLAIN); + values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(false); + values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(InvalidOid); + values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(-1); + values[Anum_pg_type_typndims - 1] = Int32GetDatum(0); + values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(InvalidOid); + nulls[Anum_pg_type_typdefaultbin - 1] = true; + nulls[Anum_pg_type_typdefault - 1] = true; + nulls[Anum_pg_type_typacl - 1] = true; + + /* Use binary-upgrade override for pg_type.oid? */ + if (IsBinaryUpgrade) + { + if (!OidIsValid(binary_upgrade_next_pg_type_oid)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("pg_type OID value not set when in binary upgrade mode"))); + + typoid = binary_upgrade_next_pg_type_oid; + binary_upgrade_next_pg_type_oid = InvalidOid; + } + else + { + typoid = GetNewOidWithIndex(pg_type_desc, TypeOidIndexId, + Anum_pg_type_oid); + } + + values[Anum_pg_type_oid - 1] = ObjectIdGetDatum(typoid); + + /* + * create a new type tuple + */ + tup = heap_form_tuple(tupDesc, values, nulls); + + /* + * insert the tuple in the relation and get the tuple's oid. + */ + CatalogTupleInsert(pg_type_desc, tup); + + /* + * Create dependencies. We can/must skip this in bootstrap mode. + */ + if (!IsBootstrapProcessingMode()) + GenerateTypeDependencies(tup, + pg_type_desc, + NULL, + NULL, + 0, + false, + false, + false); + + /* Post creation hook for new shell type */ + InvokeObjectPostCreateHook(TypeRelationId, typoid, 0); + + ObjectAddressSet(address, TypeRelationId, typoid); + + /* + * clean up and return the type-oid + */ + heap_freetuple(tup); + table_close(pg_type_desc, RowExclusiveLock); + + return address; +} + +/* ---------------------------------------------------------------- + * TypeCreate + * + * This does all the necessary work needed to define a new type. + * + * Returns the ObjectAddress assigned to the new type. + * If newTypeOid is zero (the normal case), a new OID is created; + * otherwise we use exactly that OID. + * ---------------------------------------------------------------- + */ +ObjectAddress +TypeCreate(Oid newTypeOid, + const char *typeName, + Oid typeNamespace, + Oid relationOid, /* only for relation rowtypes */ + char relationKind, /* ditto */ + Oid ownerId, + int16 internalSize, + char typeType, + char typeCategory, + bool typePreferred, + char typDelim, + Oid inputProcedure, + Oid outputProcedure, + Oid receiveProcedure, + Oid sendProcedure, + Oid typmodinProcedure, + Oid typmodoutProcedure, + Oid analyzeProcedure, + Oid elementType, + bool isImplicitArray, + Oid arrayType, + Oid baseType, + const char *defaultTypeValue, /* human readable rep */ + char *defaultTypeBin, /* cooked rep */ + bool passedByValue, + char alignment, + char storage, + int32 typeMod, + int32 typNDims, /* Array dimensions for baseType */ + bool typeNotNull, + Oid typeCollation) +{ + Relation pg_type_desc; + Oid typeObjectId; + bool isDependentType; + bool rebuildDeps = false; + Acl *typacl; + HeapTuple tup; + bool nulls[Natts_pg_type]; + bool replaces[Natts_pg_type]; + Datum values[Natts_pg_type]; + NameData name; + int i; + ObjectAddress address; + + /* + * We assume that the caller validated the arguments individually, but did + * not check for bad combinations. + * + * Validate size specifications: either positive (fixed-length) or -1 + * (varlena) or -2 (cstring). + */ + if (!(internalSize > 0 || + internalSize == -1 || + internalSize == -2)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("invalid type internal size %d", + internalSize))); + + if (passedByValue) + { + /* + * Pass-by-value types must have a fixed length that is one of the + * values supported by fetch_att() and store_att_byval(); and the + * alignment had better agree, too. All this code must match + * access/tupmacs.h! + */ + if (internalSize == (int16) sizeof(char)) + { + if (alignment != TYPALIGN_CHAR) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d", + alignment, internalSize))); + } + else if (internalSize == (int16) sizeof(int16)) + { + if (alignment != TYPALIGN_SHORT) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d", + alignment, internalSize))); + } + else if (internalSize == (int16) sizeof(int32)) + { + if (alignment != TYPALIGN_INT) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d", + alignment, internalSize))); + } +#if SIZEOF_DATUM == 8 + else if (internalSize == (int16) sizeof(Datum)) + { + if (alignment != TYPALIGN_DOUBLE) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d", + alignment, internalSize))); + } +#endif + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("internal size %d is invalid for passed-by-value type", + internalSize))); + } + else + { + /* varlena types must have int align or better */ + if (internalSize == -1 && + !(alignment == TYPALIGN_INT || alignment == TYPALIGN_DOUBLE)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("alignment \"%c\" is invalid for variable-length type", + alignment))); + /* cstring must have char alignment */ + if (internalSize == -2 && !(alignment == TYPALIGN_CHAR)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("alignment \"%c\" is invalid for variable-length type", + alignment))); + } + + /* Only varlena types can be toasted */ + if (storage != TYPSTORAGE_PLAIN && internalSize != -1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("fixed-size types must have storage PLAIN"))); + + /* + * This is a dependent type if it's an implicitly-created array type, or + * if it's a relation rowtype that's not a composite type. For such types + * we'll leave the ACL empty, and we'll skip creating some dependency + * records because there will be a dependency already through the + * depended-on type or relation. (Caution: this is closely intertwined + * with some behavior in GenerateTypeDependencies.) + */ + isDependentType = isImplicitArray || + (OidIsValid(relationOid) && relationKind != RELKIND_COMPOSITE_TYPE); + + /* + * initialize arrays needed for heap_form_tuple or heap_modify_tuple + */ + for (i = 0; i < Natts_pg_type; ++i) + { + nulls[i] = false; + replaces[i] = true; + values[i] = (Datum) 0; + } + + /* + * insert data values + */ + namestrcpy(&name, typeName); + values[Anum_pg_type_typname - 1] = NameGetDatum(&name); + values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace); + values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId); + values[Anum_pg_type_typlen - 1] = Int16GetDatum(internalSize); + values[Anum_pg_type_typbyval - 1] = BoolGetDatum(passedByValue); + values[Anum_pg_type_typtype - 1] = CharGetDatum(typeType); + values[Anum_pg_type_typcategory - 1] = CharGetDatum(typeCategory); + values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(typePreferred); + values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(true); + values[Anum_pg_type_typdelim - 1] = CharGetDatum(typDelim); + values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(relationOid); + values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(elementType); + values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(arrayType); + values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(inputProcedure); + values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(outputProcedure); + values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(receiveProcedure); + values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(sendProcedure); + values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(typmodinProcedure); + values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(typmodoutProcedure); + values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(analyzeProcedure); + values[Anum_pg_type_typalign - 1] = CharGetDatum(alignment); + values[Anum_pg_type_typstorage - 1] = CharGetDatum(storage); + values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(typeNotNull); + values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(baseType); + values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(typeMod); + values[Anum_pg_type_typndims - 1] = Int32GetDatum(typNDims); + values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(typeCollation); + + /* + * initialize the default binary value for this type. Check for nulls of + * course. + */ + if (defaultTypeBin) + values[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(defaultTypeBin); + else + nulls[Anum_pg_type_typdefaultbin - 1] = true; + + /* + * initialize the default value for this type. + */ + if (defaultTypeValue) + values[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultTypeValue); + else + nulls[Anum_pg_type_typdefault - 1] = true; + + /* + * Initialize the type's ACL, too. But dependent types don't get one. + */ + if (isDependentType) + typacl = NULL; + else + typacl = get_user_default_acl(OBJECT_TYPE, ownerId, + typeNamespace); + if (typacl != NULL) + values[Anum_pg_type_typacl - 1] = PointerGetDatum(typacl); + else + nulls[Anum_pg_type_typacl - 1] = true; + + /* + * open pg_type and prepare to insert or update a row. + * + * NOTE: updating will not work correctly in bootstrap mode; but we don't + * expect to be overwriting any shell types in bootstrap mode. + */ + pg_type_desc = table_open(TypeRelationId, RowExclusiveLock); + + tup = SearchSysCacheCopy2(TYPENAMENSP, + CStringGetDatum(typeName), + ObjectIdGetDatum(typeNamespace)); + if (HeapTupleIsValid(tup)) + { + Form_pg_type typform = (Form_pg_type) GETSTRUCT(tup); + + /* + * check that the type is not already defined. It may exist as a + * shell type, however. + */ + if (typform->typisdefined) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("type \"%s\" already exists", typeName))); + + /* + * shell type must have been created by same owner + */ + if (typform->typowner != ownerId) + aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_TYPE, typeName); + + /* trouble if caller wanted to force the OID */ + if (OidIsValid(newTypeOid)) + elog(ERROR, "cannot assign new OID to existing shell type"); + + replaces[Anum_pg_type_oid - 1] = false; + + /* + * Okay to update existing shell type tuple + */ + tup = heap_modify_tuple(tup, + RelationGetDescr(pg_type_desc), + values, + nulls, + replaces); + + CatalogTupleUpdate(pg_type_desc, &tup->t_self, tup); + + typeObjectId = typform->oid; + + rebuildDeps = true; /* get rid of shell type's dependencies */ + } + else + { + /* Force the OID if requested by caller */ + if (OidIsValid(newTypeOid)) + typeObjectId = newTypeOid; + /* Use binary-upgrade override for pg_type.oid, if supplied. */ + else if (IsBinaryUpgrade) + { + if (!OidIsValid(binary_upgrade_next_pg_type_oid)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("pg_type OID value not set when in binary upgrade mode"))); + + typeObjectId = binary_upgrade_next_pg_type_oid; + binary_upgrade_next_pg_type_oid = InvalidOid; + } + else + { + typeObjectId = GetNewOidWithIndex(pg_type_desc, TypeOidIndexId, + Anum_pg_type_oid); + } + + values[Anum_pg_type_oid - 1] = ObjectIdGetDatum(typeObjectId); + + tup = heap_form_tuple(RelationGetDescr(pg_type_desc), + values, nulls); + + CatalogTupleInsert(pg_type_desc, tup); + } + + /* + * Create dependencies. We can/must skip this in bootstrap mode. + */ + if (!IsBootstrapProcessingMode()) + GenerateTypeDependencies(tup, + pg_type_desc, + (defaultTypeBin ? + stringToNode(defaultTypeBin) : + NULL), + typacl, + relationKind, + isImplicitArray, + isDependentType, + rebuildDeps); + + /* Post creation hook for new type */ + InvokeObjectPostCreateHook(TypeRelationId, typeObjectId, 0); + + ObjectAddressSet(address, TypeRelationId, typeObjectId); + + /* + * finish up + */ + table_close(pg_type_desc, RowExclusiveLock); + + return address; +} + +/* + * GenerateTypeDependencies: build the dependencies needed for a type + * + * Most of what this function needs to know about the type is passed as the + * new pg_type row, typeTuple. We make callers pass the pg_type Relation + * as well, so that we have easy access to a tuple descriptor for the row. + * + * While this is able to extract the defaultExpr and typacl from the tuple, + * doing so is relatively expensive, and callers may have those values at + * hand already. Pass those if handy, otherwise pass NULL. (typacl is really + * "Acl *", but we declare it "void *" to avoid including acl.h in pg_type.h.) + * + * relationKind and isImplicitArray are likewise somewhat expensive to deduce + * from the tuple, so we make callers pass those (they're not optional). + * + * isDependentType is true if this is an implicit array or relation rowtype; + * that means it doesn't need its own dependencies on owner etc. + * + * If rebuild is true, we remove existing dependencies and rebuild them + * from scratch. This is needed for ALTER TYPE, and also when replacing + * a shell type. We don't remove an existing extension dependency, though. + * (That means an extension can't absorb a shell type created in another + * extension, nor ALTER a type created by another extension. Also, if it + * replaces a free-standing shell type or ALTERs a free-standing type, + * that type will become a member of the extension.) + */ +void +GenerateTypeDependencies(HeapTuple typeTuple, + Relation typeCatalog, + Node *defaultExpr, + void *typacl, + char relationKind, /* only for relation rowtypes */ + bool isImplicitArray, + bool isDependentType, + bool rebuild) +{ + Form_pg_type typeForm = (Form_pg_type) GETSTRUCT(typeTuple); + Oid typeObjectId = typeForm->oid; + Datum datum; + bool isNull; + ObjectAddress myself, + referenced; + + /* Extract defaultExpr if caller didn't pass it */ + if (defaultExpr == NULL) + { + datum = heap_getattr(typeTuple, Anum_pg_type_typdefaultbin, + RelationGetDescr(typeCatalog), &isNull); + if (!isNull) + defaultExpr = stringToNode(TextDatumGetCString(datum)); + } + /* Extract typacl if caller didn't pass it */ + if (typacl == NULL) + { + datum = heap_getattr(typeTuple, Anum_pg_type_typacl, + RelationGetDescr(typeCatalog), &isNull); + if (!isNull) + typacl = DatumGetAclPCopy(datum); + } + + /* If rebuild, first flush old dependencies, except extension deps */ + if (rebuild) + { + deleteDependencyRecordsFor(TypeRelationId, typeObjectId, true); + deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId, 0); + } + + myself.classId = TypeRelationId; + myself.objectId = typeObjectId; + myself.objectSubId = 0; + + /* + * Make dependencies on namespace, owner, ACL, extension. + * + * Skip these for a dependent type, since it will have such dependencies + * indirectly through its depended-on type or relation. + */ + if (!isDependentType) + { + referenced.classId = NamespaceRelationId; + referenced.objectId = typeForm->typnamespace; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + recordDependencyOnOwner(TypeRelationId, typeObjectId, + typeForm->typowner); + + recordDependencyOnNewAcl(TypeRelationId, typeObjectId, 0, + typeForm->typowner, typacl); + + recordDependencyOnCurrentExtension(&myself, rebuild); + } + + /* Normal dependencies on the I/O functions */ + if (OidIsValid(typeForm->typinput)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = typeForm->typinput; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + if (OidIsValid(typeForm->typoutput)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = typeForm->typoutput; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + if (OidIsValid(typeForm->typreceive)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = typeForm->typreceive; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + if (OidIsValid(typeForm->typsend)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = typeForm->typsend; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + if (OidIsValid(typeForm->typmodin)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = typeForm->typmodin; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + if (OidIsValid(typeForm->typmodout)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = typeForm->typmodout; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + if (OidIsValid(typeForm->typanalyze)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = typeForm->typanalyze; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* + * If the type is a rowtype for a relation, mark it as internally + * dependent on the relation, *unless* it is a stand-alone composite type + * relation. For the latter case, we have to reverse the dependency. + * + * In the former case, this allows the type to be auto-dropped when the + * relation is, and not otherwise. And in the latter, of course we get the + * opposite effect. + */ + if (OidIsValid(typeForm->typrelid)) + { + referenced.classId = RelationRelationId; + referenced.objectId = typeForm->typrelid; + referenced.objectSubId = 0; + + if (relationKind != RELKIND_COMPOSITE_TYPE) + recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); + else + recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL); + } + + /* + * If the type is an implicitly-created array type, mark it as internally + * dependent on the element type. Otherwise, if it has an element type, + * the dependency is a normal one. + */ + if (OidIsValid(typeForm->typelem)) + { + referenced.classId = TypeRelationId; + referenced.objectId = typeForm->typelem; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, + isImplicitArray ? DEPENDENCY_INTERNAL : DEPENDENCY_NORMAL); + } + + /* Normal dependency from a domain to its base type. */ + if (OidIsValid(typeForm->typbasetype)) + { + referenced.classId = TypeRelationId; + referenced.objectId = typeForm->typbasetype; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* Normal dependency from a domain to its collation. */ + /* We know the default collation is pinned, so don't bother recording it */ + if (OidIsValid(typeForm->typcollation) && + typeForm->typcollation != DEFAULT_COLLATION_OID) + { + referenced.classId = CollationRelationId; + referenced.objectId = typeForm->typcollation; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + /* Normal dependency on the default expression. */ + if (defaultExpr) + recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL); +} + +/* + * RenameTypeInternal + * This renames a type, as well as any associated array type. + * + * Caller must have already checked privileges. + * + * Currently this is used for renaming table rowtypes and for + * ALTER TYPE RENAME TO command. + */ +void +RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace) +{ + Relation pg_type_desc; + HeapTuple tuple; + Form_pg_type typ; + Oid arrayOid; + Oid oldTypeOid; + + pg_type_desc = table_open(TypeRelationId, RowExclusiveLock); + + tuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for type %u", typeOid); + typ = (Form_pg_type) GETSTRUCT(tuple); + + /* We are not supposed to be changing schemas here */ + Assert(typeNamespace == typ->typnamespace); + + arrayOid = typ->typarray; + + /* Check for a conflicting type name. */ + oldTypeOid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, + CStringGetDatum(newTypeName), + ObjectIdGetDatum(typeNamespace)); + + /* + * If there is one, see if it's an autogenerated array type, and if so + * rename it out of the way. (But we must skip that for a shell type + * because moveArrayTypeName will do the wrong thing in that case.) + * Otherwise, we can at least give a more friendly error than unique-index + * violation. + */ + if (OidIsValid(oldTypeOid)) + { + if (get_typisdefined(oldTypeOid) && + moveArrayTypeName(oldTypeOid, newTypeName, typeNamespace)) + /* successfully dodged the problem */ ; + else + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("type \"%s\" already exists", newTypeName))); + } + + /* OK, do the rename --- tuple is a copy, so OK to scribble on it */ + namestrcpy(&(typ->typname), newTypeName); + + CatalogTupleUpdate(pg_type_desc, &tuple->t_self, tuple); + + InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0); + + heap_freetuple(tuple); + table_close(pg_type_desc, RowExclusiveLock); + + /* + * If the type has an array type, recurse to handle that. But we don't + * need to do anything more if we already renamed that array type above + * (which would happen when, eg, renaming "foo" to "_foo"). + */ + if (OidIsValid(arrayOid) && arrayOid != oldTypeOid) + { + char *arrname = makeArrayTypeName(newTypeName, typeNamespace); + + RenameTypeInternal(arrayOid, arrname, typeNamespace); + pfree(arrname); + } +} + + +/* + * makeArrayTypeName + * - given a base type name, make an array type name for it + * + * the caller is responsible for pfreeing the result + */ +char * +makeArrayTypeName(const char *typeName, Oid typeNamespace) +{ + char *arr = (char *) palloc(NAMEDATALEN); + int namelen = strlen(typeName); + int i; + + /* + * The idea is to prepend underscores as needed until we make a name that + * doesn't collide with anything... + */ + for (i = 1; i < NAMEDATALEN - 1; i++) + { + arr[i - 1] = '_'; + if (i + namelen < NAMEDATALEN) + strcpy(arr + i, typeName); + else + { + memcpy(arr + i, typeName, NAMEDATALEN - i); + truncate_identifier(arr, NAMEDATALEN, false); + } + if (!SearchSysCacheExists2(TYPENAMENSP, + CStringGetDatum(arr), + ObjectIdGetDatum(typeNamespace))) + break; + } + + if (i >= NAMEDATALEN - 1) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("could not form array type name for type \"%s\"", + typeName))); + + return arr; +} + + +/* + * moveArrayTypeName + * - try to reassign an array type name that the user wants to use. + * + * The given type name has been discovered to already exist (with the given + * OID). If it is an autogenerated array type, change the array type's name + * to not conflict. This allows the user to create type "foo" followed by + * type "_foo" without problems. (Of course, there are race conditions if + * two backends try to create similarly-named types concurrently, but the + * worst that can happen is an unnecessary failure --- anything we do here + * will be rolled back if the type creation fails due to conflicting names.) + * + * Note that this must be called *before* calling makeArrayTypeName to + * determine the new type's own array type name; else the latter will + * certainly pick the same name. + * + * Returns true if successfully moved the type, false if not. + * + * We also return true if the given type is a shell type. In this case + * the type has not been renamed out of the way, but nonetheless it can + * be expected that TypeCreate will succeed. This behavior is convenient + * for most callers --- those that need to distinguish the shell-type case + * must do their own typisdefined test. + */ +bool +moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace) +{ + Oid elemOid; + char *newname; + + /* We need do nothing if it's a shell type. */ + if (!get_typisdefined(typeOid)) + return true; + + /* Can't change it if it's not an autogenerated array type. */ + elemOid = get_element_type(typeOid); + if (!OidIsValid(elemOid) || + get_array_type(elemOid) != typeOid) + return false; + + /* + * OK, use makeArrayTypeName to pick an unused modification of the name. + * Note that since makeArrayTypeName is an iterative process, this will + * produce a name that it might have produced the first time, had the + * conflicting type we are about to create already existed. + */ + newname = makeArrayTypeName(typeName, typeNamespace); + + /* Apply the rename */ + RenameTypeInternal(typeOid, newname, typeNamespace); + + /* + * We must bump the command counter so that any subsequent use of + * makeArrayTypeName sees what we just did and doesn't pick the same name. + */ + CommandCounterIncrement(); + + pfree(newname); + + return true; +} diff --git a/src/backend/catalog/pg_type_d.h b/src/backend/catalog/pg_type_d.h new file mode 100644 index 0000000..d967a69 --- /dev/null +++ b/src/backend/catalog/pg_type_d.h @@ -0,0 +1,285 @@ +/*------------------------------------------------------------------------- + * + * pg_type_d.h + * Macro definitions for pg_type + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TYPE_D_H +#define PG_TYPE_D_H + +#define TypeRelationId 1247 +#define TypeRelation_Rowtype_Id 71 + +#define Anum_pg_type_oid 1 +#define Anum_pg_type_typname 2 +#define Anum_pg_type_typnamespace 3 +#define Anum_pg_type_typowner 4 +#define Anum_pg_type_typlen 5 +#define Anum_pg_type_typbyval 6 +#define Anum_pg_type_typtype 7 +#define Anum_pg_type_typcategory 8 +#define Anum_pg_type_typispreferred 9 +#define Anum_pg_type_typisdefined 10 +#define Anum_pg_type_typdelim 11 +#define Anum_pg_type_typrelid 12 +#define Anum_pg_type_typelem 13 +#define Anum_pg_type_typarray 14 +#define Anum_pg_type_typinput 15 +#define Anum_pg_type_typoutput 16 +#define Anum_pg_type_typreceive 17 +#define Anum_pg_type_typsend 18 +#define Anum_pg_type_typmodin 19 +#define Anum_pg_type_typmodout 20 +#define Anum_pg_type_typanalyze 21 +#define Anum_pg_type_typalign 22 +#define Anum_pg_type_typstorage 23 +#define Anum_pg_type_typnotnull 24 +#define Anum_pg_type_typbasetype 25 +#define Anum_pg_type_typtypmod 26 +#define Anum_pg_type_typndims 27 +#define Anum_pg_type_typcollation 28 +#define Anum_pg_type_typdefaultbin 29 +#define Anum_pg_type_typdefault 30 +#define Anum_pg_type_typacl 31 + +#define Natts_pg_type 31 + + +/* + * macros for values of poor-mans-enumerated-type columns + */ +#define TYPTYPE_BASE 'b' /* base type (ordinary scalar type) */ +#define TYPTYPE_COMPOSITE 'c' /* composite (e.g., table's rowtype) */ +#define TYPTYPE_DOMAIN 'd' /* domain over another type */ +#define TYPTYPE_ENUM 'e' /* enumerated type */ +#define TYPTYPE_PSEUDO 'p' /* pseudo-type */ +#define TYPTYPE_RANGE 'r' /* range type */ + +#define TYPCATEGORY_INVALID '\0' /* not an allowed category */ +#define TYPCATEGORY_ARRAY 'A' +#define TYPCATEGORY_BOOLEAN 'B' +#define TYPCATEGORY_COMPOSITE 'C' +#define TYPCATEGORY_DATETIME 'D' +#define TYPCATEGORY_ENUM 'E' +#define TYPCATEGORY_GEOMETRIC 'G' +#define TYPCATEGORY_NETWORK 'I' /* think INET */ +#define TYPCATEGORY_NUMERIC 'N' +#define TYPCATEGORY_PSEUDOTYPE 'P' +#define TYPCATEGORY_RANGE 'R' +#define TYPCATEGORY_STRING 'S' +#define TYPCATEGORY_TIMESPAN 'T' +#define TYPCATEGORY_USER 'U' +#define TYPCATEGORY_BITSTRING 'V' /* er ... "varbit"? */ +#define TYPCATEGORY_UNKNOWN 'X' + +#define TYPALIGN_CHAR 'c' /* char alignment (i.e. unaligned) */ +#define TYPALIGN_SHORT 's' /* short alignment (typically 2 bytes) */ +#define TYPALIGN_INT 'i' /* int alignment (typically 4 bytes) */ +#define TYPALIGN_DOUBLE 'd' /* double alignment (often 8 bytes) */ + +#define TYPSTORAGE_PLAIN 'p' /* type not prepared for toasting */ +#define TYPSTORAGE_EXTERNAL 'e' /* toastable, don't try to compress */ +#define TYPSTORAGE_EXTENDED 'x' /* fully toastable */ +#define TYPSTORAGE_MAIN 'm' /* like 'x' but try to store inline */ + +/* Is a type OID a polymorphic pseudotype? (Beware of multiple evaluation) */ +#define IsPolymorphicType(typid) \ + (IsPolymorphicTypeFamily1(typid) || \ + IsPolymorphicTypeFamily2(typid)) + +/* Code not part of polymorphic type resolution should not use these macros: */ +#define IsPolymorphicTypeFamily1(typid) \ + ((typid) == ANYELEMENTOID || \ + (typid) == ANYARRAYOID || \ + (typid) == ANYNONARRAYOID || \ + (typid) == ANYENUMOID || \ + (typid) == ANYRANGEOID) + +#define IsPolymorphicTypeFamily2(typid) \ + ((typid) == ANYCOMPATIBLEOID || \ + (typid) == ANYCOMPATIBLEARRAYOID || \ + (typid) == ANYCOMPATIBLENONARRAYOID || \ + (typid) == ANYCOMPATIBLERANGEOID) + +#define BOOLOID 16 +#define BYTEAOID 17 +#define CHAROID 18 +#define NAMEOID 19 +#define INT8OID 20 +#define INT2OID 21 +#define INT2VECTOROID 22 +#define INT4OID 23 +#define REGPROCOID 24 +#define TEXTOID 25 +#define OIDOID 26 +#define TIDOID 27 +#define XIDOID 28 +#define CIDOID 29 +#define OIDVECTOROID 30 +#define JSONOID 114 +#define XMLOID 142 +#define PGNODETREEOID 194 +#define PGNDISTINCTOID 3361 +#define PGDEPENDENCIESOID 3402 +#define PGMCVLISTOID 5017 +#define PGDDLCOMMANDOID 32 +#define XID8OID 5069 +#define POINTOID 600 +#define LSEGOID 601 +#define PATHOID 602 +#define BOXOID 603 +#define POLYGONOID 604 +#define LINEOID 628 +#define FLOAT4OID 700 +#define FLOAT8OID 701 +#define UNKNOWNOID 705 +#define CIRCLEOID 718 +#define CASHOID 790 +#define MACADDROID 829 +#define INETOID 869 +#define CIDROID 650 +#define MACADDR8OID 774 +#define ACLITEMOID 1033 +#define BPCHAROID 1042 +#define VARCHAROID 1043 +#define DATEOID 1082 +#define TIMEOID 1083 +#define TIMESTAMPOID 1114 +#define TIMESTAMPTZOID 1184 +#define INTERVALOID 1186 +#define TIMETZOID 1266 +#define BITOID 1560 +#define VARBITOID 1562 +#define NUMERICOID 1700 +#define REFCURSOROID 1790 +#define REGPROCEDUREOID 2202 +#define REGOPEROID 2203 +#define REGOPERATOROID 2204 +#define REGCLASSOID 2205 +#define REGCOLLATIONOID 4191 +#define REGTYPEOID 2206 +#define REGROLEOID 4096 +#define REGNAMESPACEOID 4089 +#define UUIDOID 2950 +#define LSNOID 3220 +#define TSVECTOROID 3614 +#define GTSVECTOROID 3642 +#define TSQUERYOID 3615 +#define REGCONFIGOID 3734 +#define REGDICTIONARYOID 3769 +#define JSONBOID 3802 +#define JSONPATHOID 4072 +#define TXID_SNAPSHOTOID 2970 +#define PG_SNAPSHOTOID 5038 +#define INT4RANGEOID 3904 +#define NUMRANGEOID 3906 +#define TSRANGEOID 3908 +#define TSTZRANGEOID 3910 +#define DATERANGEOID 3912 +#define INT8RANGEOID 3926 +#define RECORDOID 2249 +#define RECORDARRAYOID 2287 +#define CSTRINGOID 2275 +#define ANYOID 2276 +#define ANYARRAYOID 2277 +#define VOIDOID 2278 +#define TRIGGEROID 2279 +#define EVTTRIGGEROID 3838 +#define LANGUAGE_HANDLEROID 2280 +#define INTERNALOID 2281 +#define ANYELEMENTOID 2283 +#define ANYNONARRAYOID 2776 +#define ANYENUMOID 3500 +#define FDW_HANDLEROID 3115 +#define INDEX_AM_HANDLEROID 325 +#define TSM_HANDLEROID 3310 +#define TABLE_AM_HANDLEROID 269 +#define ANYRANGEOID 3831 +#define ANYCOMPATIBLEOID 5077 +#define ANYCOMPATIBLEARRAYOID 5078 +#define ANYCOMPATIBLENONARRAYOID 5079 +#define ANYCOMPATIBLERANGEOID 5080 +#define BOOLARRAYOID 1000 +#define BYTEAARRAYOID 1001 +#define CHARARRAYOID 1002 +#define NAMEARRAYOID 1003 +#define INT8ARRAYOID 1016 +#define INT2ARRAYOID 1005 +#define INT2VECTORARRAYOID 1006 +#define INT4ARRAYOID 1007 +#define REGPROCARRAYOID 1008 +#define TEXTARRAYOID 1009 +#define OIDARRAYOID 1028 +#define TIDARRAYOID 1010 +#define XIDARRAYOID 1011 +#define CIDARRAYOID 1012 +#define OIDVECTORARRAYOID 1013 +#define JSONARRAYOID 199 +#define XMLARRAYOID 143 +#define XID8ARRAYOID 271 +#define POINTARRAYOID 1017 +#define LSEGARRAYOID 1018 +#define PATHARRAYOID 1019 +#define BOXARRAYOID 1020 +#define POLYGONARRAYOID 1027 +#define LINEARRAYOID 629 +#define FLOAT4ARRAYOID 1021 +#define FLOAT8ARRAYOID 1022 +#define CIRCLEARRAYOID 719 +#define MONEYARRAYOID 791 +#define MACADDRARRAYOID 1040 +#define INETARRAYOID 1041 +#define CIDRARRAYOID 651 +#define MACADDR8ARRAYOID 775 +#define ACLITEMARRAYOID 1034 +#define BPCHARARRAYOID 1014 +#define VARCHARARRAYOID 1015 +#define DATEARRAYOID 1182 +#define TIMEARRAYOID 1183 +#define TIMESTAMPARRAYOID 1115 +#define TIMESTAMPTZARRAYOID 1185 +#define INTERVALARRAYOID 1187 +#define TIMETZARRAYOID 1270 +#define BITARRAYOID 1561 +#define VARBITARRAYOID 1563 +#define NUMERICARRAYOID 1231 +#define REFCURSORARRAYOID 2201 +#define REGPROCEDUREARRAYOID 2207 +#define REGOPERARRAYOID 2208 +#define REGOPERATORARRAYOID 2209 +#define REGCLASSARRAYOID 2210 +#define REGCOLLATIONARRAYOID 4192 +#define REGTYPEARRAYOID 2211 +#define REGROLEARRAYOID 4097 +#define REGNAMESPACEARRAYOID 4090 +#define UUIDARRAYOID 2951 +#define PG_LSNARRAYOID 3221 +#define TSVECTORARRAYOID 3643 +#define GTSVECTORARRAYOID 3644 +#define TSQUERYARRAYOID 3645 +#define REGCONFIGARRAYOID 3735 +#define REGDICTIONARYARRAYOID 3770 +#define JSONBARRAYOID 3807 +#define JSONPATHARRAYOID 4073 +#define TXID_SNAPSHOTARRAYOID 2949 +#define PG_SNAPSHOTARRAYOID 5039 +#define INT4RANGEARRAYOID 3905 +#define NUMRANGEARRAYOID 3907 +#define TSRANGEARRAYOID 3909 +#define TSTZRANGEARRAYOID 3911 +#define DATERANGEARRAYOID 3913 +#define INT8RANGEARRAYOID 3927 +#define CSTRINGARRAYOID 1263 + +#endif /* PG_TYPE_D_H */ diff --git a/src/backend/catalog/pg_user_mapping_d.h b/src/backend/catalog/pg_user_mapping_d.h new file mode 100644 index 0000000..48bea90 --- /dev/null +++ b/src/backend/catalog/pg_user_mapping_d.h @@ -0,0 +1,31 @@ +/*------------------------------------------------------------------------- + * + * pg_user_mapping_d.h + * Macro definitions for pg_user_mapping + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_USER_MAPPING_D_H +#define PG_USER_MAPPING_D_H + +#define UserMappingRelationId 1418 + +#define Anum_pg_user_mapping_oid 1 +#define Anum_pg_user_mapping_umuser 2 +#define Anum_pg_user_mapping_umserver 3 +#define Anum_pg_user_mapping_umoptions 4 + +#define Natts_pg_user_mapping 4 + + +#endif /* PG_USER_MAPPING_D_H */ diff --git a/src/backend/catalog/postgres.bki b/src/backend/catalog/postgres.bki new file mode 100644 index 0000000..4badf4d --- /dev/null +++ b/src/backend/catalog/postgres.bki @@ -0,0 +1,10432 @@ +# PostgreSQL 13 +create pg_proc 1255 bootstrap rowtype_oid 81 + ( + oid = oid , + proname = name , + pronamespace = oid , + proowner = oid , + prolang = oid , + procost = float4 , + prorows = float4 , + provariadic = oid , + prosupport = regproc , + prokind = char , + prosecdef = bool , + proleakproof = bool , + proisstrict = bool , + proretset = bool , + provolatile = char , + proparallel = char , + pronargs = int2 , + pronargdefaults = int2 , + prorettype = oid , + proargtypes = oidvector , + proallargtypes = _oid , + proargmodes = _char , + proargnames = _text , + proargdefaults = pg_node_tree , + protrftypes = _oid , + prosrc = text FORCE NOT NULL , + probin = text , + proconfig = _text , + proacl = _aclitem + ) +insert ( 1242 boolin 11 10 12 1 0 0 0 f f f t f i s 1 0 16 2275 _null_ _null_ _null_ _null_ _null_ boolin _null_ _null_ _null_ ) +insert ( 1243 boolout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 16 _null_ _null_ _null_ _null_ _null_ boolout _null_ _null_ _null_ ) +insert ( 1244 byteain 11 10 12 1 0 0 0 f f f t f i s 1 0 17 2275 _null_ _null_ _null_ _null_ _null_ byteain _null_ _null_ _null_ ) +insert ( 31 byteaout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 17 _null_ _null_ _null_ _null_ _null_ byteaout _null_ _null_ _null_ ) +insert ( 1245 charin 11 10 12 1 0 0 0 f f f t f i s 1 0 18 2275 _null_ _null_ _null_ _null_ _null_ charin _null_ _null_ _null_ ) +insert ( 33 charout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 18 _null_ _null_ _null_ _null_ _null_ charout _null_ _null_ _null_ ) +insert ( 34 namein 11 10 12 1 0 0 0 f f f t f i s 1 0 19 2275 _null_ _null_ _null_ _null_ _null_ namein _null_ _null_ _null_ ) +insert ( 35 nameout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 19 _null_ _null_ _null_ _null_ _null_ nameout _null_ _null_ _null_ ) +insert ( 38 int2in 11 10 12 1 0 0 0 f f f t f i s 1 0 21 2275 _null_ _null_ _null_ _null_ _null_ int2in _null_ _null_ _null_ ) +insert ( 39 int2out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 21 _null_ _null_ _null_ _null_ _null_ int2out _null_ _null_ _null_ ) +insert ( 40 int2vectorin 11 10 12 1 0 0 0 f f f t f i s 1 0 22 2275 _null_ _null_ _null_ _null_ _null_ int2vectorin _null_ _null_ _null_ ) +insert ( 41 int2vectorout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 22 _null_ _null_ _null_ _null_ _null_ int2vectorout _null_ _null_ _null_ ) +insert ( 42 int4in 11 10 12 1 0 0 0 f f f t f i s 1 0 23 2275 _null_ _null_ _null_ _null_ _null_ int4in _null_ _null_ _null_ ) +insert ( 43 int4out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 23 _null_ _null_ _null_ _null_ _null_ int4out _null_ _null_ _null_ ) +insert ( 44 regprocin 11 10 12 1 0 0 0 f f f t f s s 1 0 24 2275 _null_ _null_ _null_ _null_ _null_ regprocin _null_ _null_ _null_ ) +insert ( 45 regprocout 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 24 _null_ _null_ _null_ _null_ _null_ regprocout _null_ _null_ _null_ ) +insert ( 3494 to_regproc 11 10 12 1 0 0 0 f f f t f s s 1 0 24 25 _null_ _null_ _null_ _null_ _null_ to_regproc _null_ _null_ _null_ ) +insert ( 3479 to_regprocedure 11 10 12 1 0 0 0 f f f t f s s 1 0 2202 25 _null_ _null_ _null_ _null_ _null_ to_regprocedure _null_ _null_ _null_ ) +insert ( 46 textin 11 10 12 1 0 0 0 f f f t f i s 1 0 25 2275 _null_ _null_ _null_ _null_ _null_ textin _null_ _null_ _null_ ) +insert ( 47 textout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 25 _null_ _null_ _null_ _null_ _null_ textout _null_ _null_ _null_ ) +insert ( 48 tidin 11 10 12 1 0 0 0 f f f t f i s 1 0 27 2275 _null_ _null_ _null_ _null_ _null_ tidin _null_ _null_ _null_ ) +insert ( 49 tidout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 27 _null_ _null_ _null_ _null_ _null_ tidout _null_ _null_ _null_ ) +insert ( 50 xidin 11 10 12 1 0 0 0 f f f t f i s 1 0 28 2275 _null_ _null_ _null_ _null_ _null_ xidin _null_ _null_ _null_ ) +insert ( 51 xidout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 28 _null_ _null_ _null_ _null_ _null_ xidout _null_ _null_ _null_ ) +insert ( 5070 xid8in 11 10 12 1 0 0 0 f f f t f i s 1 0 5069 2275 _null_ _null_ _null_ _null_ _null_ xid8in _null_ _null_ _null_ ) +insert ( 5081 xid8out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 5069 _null_ _null_ _null_ _null_ _null_ xid8out _null_ _null_ _null_ ) +insert ( 5082 xid8recv 11 10 12 1 0 0 0 f f f t f i s 1 0 5069 2281 _null_ _null_ _null_ _null_ _null_ xid8recv _null_ _null_ _null_ ) +insert ( 5083 xid8send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 5069 _null_ _null_ _null_ _null_ _null_ xid8send _null_ _null_ _null_ ) +insert ( 52 cidin 11 10 12 1 0 0 0 f f f t f i s 1 0 29 2275 _null_ _null_ _null_ _null_ _null_ cidin _null_ _null_ _null_ ) +insert ( 53 cidout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 29 _null_ _null_ _null_ _null_ _null_ cidout _null_ _null_ _null_ ) +insert ( 54 oidvectorin 11 10 12 1 0 0 0 f f f t f i s 1 0 30 2275 _null_ _null_ _null_ _null_ _null_ oidvectorin _null_ _null_ _null_ ) +insert ( 55 oidvectorout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 30 _null_ _null_ _null_ _null_ _null_ oidvectorout _null_ _null_ _null_ ) +insert ( 56 boollt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "16 16" _null_ _null_ _null_ _null_ _null_ boollt _null_ _null_ _null_ ) +insert ( 57 boolgt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "16 16" _null_ _null_ _null_ _null_ _null_ boolgt _null_ _null_ _null_ ) +insert ( 60 booleq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "16 16" _null_ _null_ _null_ _null_ _null_ booleq _null_ _null_ _null_ ) +insert ( 61 chareq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "18 18" _null_ _null_ _null_ _null_ _null_ chareq _null_ _null_ _null_ ) +insert ( 62 nameeq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "19 19" _null_ _null_ _null_ _null_ _null_ nameeq _null_ _null_ _null_ ) +insert ( 63 int2eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "21 21" _null_ _null_ _null_ _null_ _null_ int2eq _null_ _null_ _null_ ) +insert ( 64 int2lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "21 21" _null_ _null_ _null_ _null_ _null_ int2lt _null_ _null_ _null_ ) +insert ( 65 int4eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "23 23" _null_ _null_ _null_ _null_ _null_ int4eq _null_ _null_ _null_ ) +insert ( 66 int4lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "23 23" _null_ _null_ _null_ _null_ _null_ int4lt _null_ _null_ _null_ ) +insert ( 67 texteq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ texteq _null_ _null_ _null_ ) +insert ( 3696 starts_with 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ text_starts_with _null_ _null_ _null_ ) +insert ( 68 xideq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "28 28" _null_ _null_ _null_ _null_ _null_ xideq _null_ _null_ _null_ ) +insert ( 3308 xidneq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "28 28" _null_ _null_ _null_ _null_ _null_ xidneq _null_ _null_ _null_ ) +insert ( 5084 xid8eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "5069 5069" _null_ _null_ _null_ _null_ _null_ xid8eq _null_ _null_ _null_ ) +insert ( 5085 xid8ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "5069 5069" _null_ _null_ _null_ _null_ _null_ xid8ne _null_ _null_ _null_ ) +insert ( 5034 xid8lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "5069 5069" _null_ _null_ _null_ _null_ _null_ xid8lt _null_ _null_ _null_ ) +insert ( 5035 xid8gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "5069 5069" _null_ _null_ _null_ _null_ _null_ xid8gt _null_ _null_ _null_ ) +insert ( 5036 xid8le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "5069 5069" _null_ _null_ _null_ _null_ _null_ xid8le _null_ _null_ _null_ ) +insert ( 5037 xid8ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "5069 5069" _null_ _null_ _null_ _null_ _null_ xid8ge _null_ _null_ _null_ ) +insert ( 5096 xid8cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "5069 5069" _null_ _null_ _null_ _null_ _null_ xid8cmp _null_ _null_ _null_ ) +insert ( 5071 xid 11 10 12 1 0 0 0 f f f t f i s 1 0 28 5069 _null_ _null_ _null_ _null_ _null_ xid8toxid _null_ _null_ _null_ ) +insert ( 69 cideq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "29 29" _null_ _null_ _null_ _null_ _null_ cideq _null_ _null_ _null_ ) +insert ( 70 charne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "18 18" _null_ _null_ _null_ _null_ _null_ charne _null_ _null_ _null_ ) +insert ( 1246 charlt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "18 18" _null_ _null_ _null_ _null_ _null_ charlt _null_ _null_ _null_ ) +insert ( 72 charle 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "18 18" _null_ _null_ _null_ _null_ _null_ charle _null_ _null_ _null_ ) +insert ( 73 chargt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "18 18" _null_ _null_ _null_ _null_ _null_ chargt _null_ _null_ _null_ ) +insert ( 74 charge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "18 18" _null_ _null_ _null_ _null_ _null_ charge _null_ _null_ _null_ ) +insert ( 77 int4 11 10 12 1 0 0 0 f f f t f i s 1 0 23 18 _null_ _null_ _null_ _null_ _null_ chartoi4 _null_ _null_ _null_ ) +insert ( 78 char 11 10 12 1 0 0 0 f f f t f i s 1 0 18 23 _null_ _null_ _null_ _null_ _null_ i4tochar _null_ _null_ _null_ ) +insert ( 79 nameregexeq 11 10 12 1 0 0 1364 f f f t f i s 2 0 16 "19 25" _null_ _null_ _null_ _null_ _null_ nameregexeq _null_ _null_ _null_ ) +insert ( 1252 nameregexne 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "19 25" _null_ _null_ _null_ _null_ _null_ nameregexne _null_ _null_ _null_ ) +insert ( 1254 textregexeq 11 10 12 1 0 0 1364 f f f t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ textregexeq _null_ _null_ _null_ ) +insert ( 1256 textregexne 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ textregexne _null_ _null_ _null_ ) +insert ( 1364 textregexeq_support 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ textregexeq_support _null_ _null_ _null_ ) +insert ( 1257 textlen 11 10 12 1 0 0 0 f f f t f i s 1 0 23 25 _null_ _null_ _null_ _null_ _null_ textlen _null_ _null_ _null_ ) +insert ( 1258 textcat 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "25 25" _null_ _null_ _null_ _null_ _null_ textcat _null_ _null_ _null_ ) +insert ( 84 boolne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "16 16" _null_ _null_ _null_ _null_ _null_ boolne _null_ _null_ _null_ ) +insert ( 89 version 11 10 12 1 0 0 0 f f f t f s s 0 0 25 "" _null_ _null_ _null_ _null_ _null_ pgsql_version _null_ _null_ _null_ ) +insert ( 86 pg_ddl_command_in 11 10 12 1 0 0 0 f f f t f i s 1 0 32 2275 _null_ _null_ _null_ _null_ _null_ pg_ddl_command_in _null_ _null_ _null_ ) +insert ( 87 pg_ddl_command_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 32 _null_ _null_ _null_ _null_ _null_ pg_ddl_command_out _null_ _null_ _null_ ) +insert ( 88 pg_ddl_command_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 32 2281 _null_ _null_ _null_ _null_ _null_ pg_ddl_command_recv _null_ _null_ _null_ ) +insert ( 90 pg_ddl_command_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 32 _null_ _null_ _null_ _null_ _null_ pg_ddl_command_send _null_ _null_ _null_ ) +insert ( 101 eqsel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ eqsel _null_ _null_ _null_ ) +insert ( 102 neqsel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ neqsel _null_ _null_ _null_ ) +insert ( 103 scalarltsel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ scalarltsel _null_ _null_ _null_ ) +insert ( 104 scalargtsel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ scalargtsel _null_ _null_ _null_ ) +insert ( 105 eqjoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ eqjoinsel _null_ _null_ _null_ ) +insert ( 106 neqjoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ neqjoinsel _null_ _null_ _null_ ) +insert ( 107 scalarltjoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ scalarltjoinsel _null_ _null_ _null_ ) +insert ( 108 scalargtjoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ scalargtjoinsel _null_ _null_ _null_ ) +insert ( 336 scalarlesel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ scalarlesel _null_ _null_ _null_ ) +insert ( 337 scalargesel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ scalargesel _null_ _null_ _null_ ) +insert ( 386 scalarlejoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ scalarlejoinsel _null_ _null_ _null_ ) +insert ( 398 scalargejoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ scalargejoinsel _null_ _null_ _null_ ) +insert ( 109 unknownin 11 10 12 1 0 0 0 f f f t f i s 1 0 705 2275 _null_ _null_ _null_ _null_ _null_ unknownin _null_ _null_ _null_ ) +insert ( 110 unknownout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 705 _null_ _null_ _null_ _null_ _null_ unknownout _null_ _null_ _null_ ) +insert ( 111 numeric_fac 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 20 _null_ _null_ _null_ _null_ _null_ numeric_fac _null_ _null_ _null_ ) +insert ( 115 box_above_eq 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_above_eq _null_ _null_ _null_ ) +insert ( 116 box_below_eq 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_below_eq _null_ _null_ _null_ ) +insert ( 117 point_in 11 10 12 1 0 0 0 f f f t f i s 1 0 600 2275 _null_ _null_ _null_ _null_ _null_ point_in _null_ _null_ _null_ ) +insert ( 118 point_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 600 _null_ _null_ _null_ _null_ _null_ point_out _null_ _null_ _null_ ) +insert ( 119 lseg_in 11 10 12 1 0 0 0 f f f t f i s 1 0 601 2275 _null_ _null_ _null_ _null_ _null_ lseg_in _null_ _null_ _null_ ) +insert ( 120 lseg_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 601 _null_ _null_ _null_ _null_ _null_ lseg_out _null_ _null_ _null_ ) +insert ( 121 path_in 11 10 12 1 0 0 0 f f f t f i s 1 0 602 2275 _null_ _null_ _null_ _null_ _null_ path_in _null_ _null_ _null_ ) +insert ( 122 path_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 602 _null_ _null_ _null_ _null_ _null_ path_out _null_ _null_ _null_ ) +insert ( 123 box_in 11 10 12 1 0 0 0 f f f t f i s 1 0 603 2275 _null_ _null_ _null_ _null_ _null_ box_in _null_ _null_ _null_ ) +insert ( 124 box_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 603 _null_ _null_ _null_ _null_ _null_ box_out _null_ _null_ _null_ ) +insert ( 125 box_overlap 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_overlap _null_ _null_ _null_ ) +insert ( 126 box_ge 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_ge _null_ _null_ _null_ ) +insert ( 127 box_gt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_gt _null_ _null_ _null_ ) +insert ( 128 box_eq 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_eq _null_ _null_ _null_ ) +insert ( 129 box_lt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_lt _null_ _null_ _null_ ) +insert ( 130 box_le 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_le _null_ _null_ _null_ ) +insert ( 131 point_above 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "600 600" _null_ _null_ _null_ _null_ _null_ point_above _null_ _null_ _null_ ) +insert ( 132 point_left 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "600 600" _null_ _null_ _null_ _null_ _null_ point_left _null_ _null_ _null_ ) +insert ( 133 point_right 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "600 600" _null_ _null_ _null_ _null_ _null_ point_right _null_ _null_ _null_ ) +insert ( 134 point_below 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "600 600" _null_ _null_ _null_ _null_ _null_ point_below _null_ _null_ _null_ ) +insert ( 135 point_eq 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "600 600" _null_ _null_ _null_ _null_ _null_ point_eq _null_ _null_ _null_ ) +insert ( 136 on_pb 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "600 603" _null_ _null_ _null_ _null_ _null_ on_pb _null_ _null_ _null_ ) +insert ( 137 on_ppath 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "600 602" _null_ _null_ _null_ _null_ _null_ on_ppath _null_ _null_ _null_ ) +insert ( 138 box_center 11 10 12 1 0 0 0 f f f t f i s 1 0 600 603 _null_ _null_ _null_ _null_ _null_ box_center _null_ _null_ _null_ ) +insert ( 139 areasel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ areasel _null_ _null_ _null_ ) +insert ( 140 areajoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ areajoinsel _null_ _null_ _null_ ) +insert ( 141 int4mul 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "23 23" _null_ _null_ _null_ _null_ _null_ int4mul _null_ _null_ _null_ ) +insert ( 144 int4ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "23 23" _null_ _null_ _null_ _null_ _null_ int4ne _null_ _null_ _null_ ) +insert ( 145 int2ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "21 21" _null_ _null_ _null_ _null_ _null_ int2ne _null_ _null_ _null_ ) +insert ( 146 int2gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "21 21" _null_ _null_ _null_ _null_ _null_ int2gt _null_ _null_ _null_ ) +insert ( 147 int4gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "23 23" _null_ _null_ _null_ _null_ _null_ int4gt _null_ _null_ _null_ ) +insert ( 148 int2le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "21 21" _null_ _null_ _null_ _null_ _null_ int2le _null_ _null_ _null_ ) +insert ( 149 int4le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "23 23" _null_ _null_ _null_ _null_ _null_ int4le _null_ _null_ _null_ ) +insert ( 150 int4ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "23 23" _null_ _null_ _null_ _null_ _null_ int4ge _null_ _null_ _null_ ) +insert ( 151 int2ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "21 21" _null_ _null_ _null_ _null_ _null_ int2ge _null_ _null_ _null_ ) +insert ( 152 int2mul 11 10 12 1 0 0 0 f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2mul _null_ _null_ _null_ ) +insert ( 153 int2div 11 10 12 1 0 0 0 f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2div _null_ _null_ _null_ ) +insert ( 154 int4div 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "23 23" _null_ _null_ _null_ _null_ _null_ int4div _null_ _null_ _null_ ) +insert ( 155 int2mod 11 10 12 1 0 0 0 f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2mod _null_ _null_ _null_ ) +insert ( 156 int4mod 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "23 23" _null_ _null_ _null_ _null_ _null_ int4mod _null_ _null_ _null_ ) +insert ( 157 textne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ textne _null_ _null_ _null_ ) +insert ( 158 int24eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "21 23" _null_ _null_ _null_ _null_ _null_ int24eq _null_ _null_ _null_ ) +insert ( 159 int42eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "23 21" _null_ _null_ _null_ _null_ _null_ int42eq _null_ _null_ _null_ ) +insert ( 160 int24lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "21 23" _null_ _null_ _null_ _null_ _null_ int24lt _null_ _null_ _null_ ) +insert ( 161 int42lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "23 21" _null_ _null_ _null_ _null_ _null_ int42lt _null_ _null_ _null_ ) +insert ( 162 int24gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "21 23" _null_ _null_ _null_ _null_ _null_ int24gt _null_ _null_ _null_ ) +insert ( 163 int42gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "23 21" _null_ _null_ _null_ _null_ _null_ int42gt _null_ _null_ _null_ ) +insert ( 164 int24ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "21 23" _null_ _null_ _null_ _null_ _null_ int24ne _null_ _null_ _null_ ) +insert ( 165 int42ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "23 21" _null_ _null_ _null_ _null_ _null_ int42ne _null_ _null_ _null_ ) +insert ( 166 int24le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "21 23" _null_ _null_ _null_ _null_ _null_ int24le _null_ _null_ _null_ ) +insert ( 167 int42le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "23 21" _null_ _null_ _null_ _null_ _null_ int42le _null_ _null_ _null_ ) +insert ( 168 int24ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "21 23" _null_ _null_ _null_ _null_ _null_ int24ge _null_ _null_ _null_ ) +insert ( 169 int42ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "23 21" _null_ _null_ _null_ _null_ _null_ int42ge _null_ _null_ _null_ ) +insert ( 170 int24mul 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "21 23" _null_ _null_ _null_ _null_ _null_ int24mul _null_ _null_ _null_ ) +insert ( 171 int42mul 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "23 21" _null_ _null_ _null_ _null_ _null_ int42mul _null_ _null_ _null_ ) +insert ( 172 int24div 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "21 23" _null_ _null_ _null_ _null_ _null_ int24div _null_ _null_ _null_ ) +insert ( 173 int42div 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "23 21" _null_ _null_ _null_ _null_ _null_ int42div _null_ _null_ _null_ ) +insert ( 176 int2pl 11 10 12 1 0 0 0 f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2pl _null_ _null_ _null_ ) +insert ( 177 int4pl 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "23 23" _null_ _null_ _null_ _null_ _null_ int4pl _null_ _null_ _null_ ) +insert ( 178 int24pl 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "21 23" _null_ _null_ _null_ _null_ _null_ int24pl _null_ _null_ _null_ ) +insert ( 179 int42pl 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "23 21" _null_ _null_ _null_ _null_ _null_ int42pl _null_ _null_ _null_ ) +insert ( 180 int2mi 11 10 12 1 0 0 0 f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2mi _null_ _null_ _null_ ) +insert ( 181 int4mi 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "23 23" _null_ _null_ _null_ _null_ _null_ int4mi _null_ _null_ _null_ ) +insert ( 182 int24mi 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "21 23" _null_ _null_ _null_ _null_ _null_ int24mi _null_ _null_ _null_ ) +insert ( 183 int42mi 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "23 21" _null_ _null_ _null_ _null_ _null_ int42mi _null_ _null_ _null_ ) +insert ( 184 oideq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "26 26" _null_ _null_ _null_ _null_ _null_ oideq _null_ _null_ _null_ ) +insert ( 185 oidne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "26 26" _null_ _null_ _null_ _null_ _null_ oidne _null_ _null_ _null_ ) +insert ( 186 box_same 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_same _null_ _null_ _null_ ) +insert ( 187 box_contain 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_contain _null_ _null_ _null_ ) +insert ( 188 box_left 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_left _null_ _null_ _null_ ) +insert ( 189 box_overleft 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_overleft _null_ _null_ _null_ ) +insert ( 190 box_overright 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_overright _null_ _null_ _null_ ) +insert ( 191 box_right 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_right _null_ _null_ _null_ ) +insert ( 192 box_contained 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_contained _null_ _null_ _null_ ) +insert ( 193 box_contain_pt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "603 600" _null_ _null_ _null_ _null_ _null_ box_contain_pt _null_ _null_ _null_ ) +insert ( 195 pg_node_tree_in 11 10 12 1 0 0 0 f f f t f i s 1 0 194 2275 _null_ _null_ _null_ _null_ _null_ pg_node_tree_in _null_ _null_ _null_ ) +insert ( 196 pg_node_tree_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 194 _null_ _null_ _null_ _null_ _null_ pg_node_tree_out _null_ _null_ _null_ ) +insert ( 197 pg_node_tree_recv 11 10 12 1 0 0 0 f f f t f s s 1 0 194 2281 _null_ _null_ _null_ _null_ _null_ pg_node_tree_recv _null_ _null_ _null_ ) +insert ( 198 pg_node_tree_send 11 10 12 1 0 0 0 f f f t f s s 1 0 17 194 _null_ _null_ _null_ _null_ _null_ pg_node_tree_send _null_ _null_ _null_ ) +insert ( 200 float4in 11 10 12 1 0 0 0 f f f t f i s 1 0 700 2275 _null_ _null_ _null_ _null_ _null_ float4in _null_ _null_ _null_ ) +insert ( 201 float4out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 700 _null_ _null_ _null_ _null_ _null_ float4out _null_ _null_ _null_ ) +insert ( 202 float4mul 11 10 12 1 0 0 0 f f f t f i s 2 0 700 "700 700" _null_ _null_ _null_ _null_ _null_ float4mul _null_ _null_ _null_ ) +insert ( 203 float4div 11 10 12 1 0 0 0 f f f t f i s 2 0 700 "700 700" _null_ _null_ _null_ _null_ _null_ float4div _null_ _null_ _null_ ) +insert ( 204 float4pl 11 10 12 1 0 0 0 f f f t f i s 2 0 700 "700 700" _null_ _null_ _null_ _null_ _null_ float4pl _null_ _null_ _null_ ) +insert ( 205 float4mi 11 10 12 1 0 0 0 f f f t f i s 2 0 700 "700 700" _null_ _null_ _null_ _null_ _null_ float4mi _null_ _null_ _null_ ) +insert ( 206 float4um 11 10 12 1 0 0 0 f f f t f i s 1 0 700 700 _null_ _null_ _null_ _null_ _null_ float4um _null_ _null_ _null_ ) +insert ( 207 float4abs 11 10 12 1 0 0 0 f f f t f i s 1 0 700 700 _null_ _null_ _null_ _null_ _null_ float4abs _null_ _null_ _null_ ) +insert ( 208 float4_accum 11 10 12 1 0 0 0 f f f t f i s 2 0 1022 "1022 700" _null_ _null_ _null_ _null_ _null_ float4_accum _null_ _null_ _null_ ) +insert ( 209 float4larger 11 10 12 1 0 0 0 f f f t f i s 2 0 700 "700 700" _null_ _null_ _null_ _null_ _null_ float4larger _null_ _null_ _null_ ) +insert ( 211 float4smaller 11 10 12 1 0 0 0 f f f t f i s 2 0 700 "700 700" _null_ _null_ _null_ _null_ _null_ float4smaller _null_ _null_ _null_ ) +insert ( 212 int4um 11 10 12 1 0 0 0 f f f t f i s 1 0 23 23 _null_ _null_ _null_ _null_ _null_ int4um _null_ _null_ _null_ ) +insert ( 213 int2um 11 10 12 1 0 0 0 f f f t f i s 1 0 21 21 _null_ _null_ _null_ _null_ _null_ int2um _null_ _null_ _null_ ) +insert ( 214 float8in 11 10 12 1 0 0 0 f f f t f i s 1 0 701 2275 _null_ _null_ _null_ _null_ _null_ float8in _null_ _null_ _null_ ) +insert ( 215 float8out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 701 _null_ _null_ _null_ _null_ _null_ float8out _null_ _null_ _null_ ) +insert ( 216 float8mul 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ float8mul _null_ _null_ _null_ ) +insert ( 217 float8div 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ float8div _null_ _null_ _null_ ) +insert ( 218 float8pl 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ float8pl _null_ _null_ _null_ ) +insert ( 219 float8mi 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ float8mi _null_ _null_ _null_ ) +insert ( 220 float8um 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ float8um _null_ _null_ _null_ ) +insert ( 221 float8abs 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ float8abs _null_ _null_ _null_ ) +insert ( 222 float8_accum 11 10 12 1 0 0 0 f f f t f i s 2 0 1022 "1022 701" _null_ _null_ _null_ _null_ _null_ float8_accum _null_ _null_ _null_ ) +insert ( 276 float8_combine 11 10 12 1 0 0 0 f f f t f i s 2 0 1022 "1022 1022" _null_ _null_ _null_ _null_ _null_ float8_combine _null_ _null_ _null_ ) +insert ( 223 float8larger 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ float8larger _null_ _null_ _null_ ) +insert ( 224 float8smaller 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ float8smaller _null_ _null_ _null_ ) +insert ( 225 lseg_center 11 10 12 1 0 0 0 f f f t f i s 1 0 600 601 _null_ _null_ _null_ _null_ _null_ lseg_center _null_ _null_ _null_ ) +insert ( 226 path_center 11 10 12 1 0 0 0 f f f t f i s 1 0 600 602 _null_ _null_ _null_ _null_ _null_ path_center _null_ _null_ _null_ ) +insert ( 227 poly_center 11 10 12 1 0 0 0 f f f t f i s 1 0 600 604 _null_ _null_ _null_ _null_ _null_ poly_center _null_ _null_ _null_ ) +insert ( 228 dround 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dround _null_ _null_ _null_ ) +insert ( 229 dtrunc 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dtrunc _null_ _null_ _null_ ) +insert ( 2308 ceil 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dceil _null_ _null_ _null_ ) +insert ( 2320 ceiling 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dceil _null_ _null_ _null_ ) +insert ( 2309 floor 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dfloor _null_ _null_ _null_ ) +insert ( 2310 sign 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dsign _null_ _null_ _null_ ) +insert ( 230 dsqrt 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dsqrt _null_ _null_ _null_ ) +insert ( 231 dcbrt 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dcbrt _null_ _null_ _null_ ) +insert ( 232 dpow 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ dpow _null_ _null_ _null_ ) +insert ( 233 dexp 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dexp _null_ _null_ _null_ ) +insert ( 234 dlog1 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dlog1 _null_ _null_ _null_ ) +insert ( 235 float8 11 10 12 1 0 0 0 f f f t f i s 1 0 701 21 _null_ _null_ _null_ _null_ _null_ i2tod _null_ _null_ _null_ ) +insert ( 236 float4 11 10 12 1 0 0 0 f f f t f i s 1 0 700 21 _null_ _null_ _null_ _null_ _null_ i2tof _null_ _null_ _null_ ) +insert ( 237 int2 11 10 12 1 0 0 0 f f f t f i s 1 0 21 701 _null_ _null_ _null_ _null_ _null_ dtoi2 _null_ _null_ _null_ ) +insert ( 238 int2 11 10 12 1 0 0 0 f f f t f i s 1 0 21 700 _null_ _null_ _null_ _null_ _null_ ftoi2 _null_ _null_ _null_ ) +insert ( 239 line_distance 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "628 628" _null_ _null_ _null_ _null_ _null_ line_distance _null_ _null_ _null_ ) +insert ( 240 nameeqtext 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "19 25" _null_ _null_ _null_ _null_ _null_ nameeqtext _null_ _null_ _null_ ) +insert ( 241 namelttext 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "19 25" _null_ _null_ _null_ _null_ _null_ namelttext _null_ _null_ _null_ ) +insert ( 242 nameletext 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "19 25" _null_ _null_ _null_ _null_ _null_ nameletext _null_ _null_ _null_ ) +insert ( 243 namegetext 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "19 25" _null_ _null_ _null_ _null_ _null_ namegetext _null_ _null_ _null_ ) +insert ( 244 namegttext 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "19 25" _null_ _null_ _null_ _null_ _null_ namegttext _null_ _null_ _null_ ) +insert ( 245 namenetext 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "19 25" _null_ _null_ _null_ _null_ _null_ namenetext _null_ _null_ _null_ ) +insert ( 246 btnametextcmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "19 25" _null_ _null_ _null_ _null_ _null_ btnametextcmp _null_ _null_ _null_ ) +insert ( 247 texteqname 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "25 19" _null_ _null_ _null_ _null_ _null_ texteqname _null_ _null_ _null_ ) +insert ( 248 textltname 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "25 19" _null_ _null_ _null_ _null_ _null_ textltname _null_ _null_ _null_ ) +insert ( 249 textlename 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "25 19" _null_ _null_ _null_ _null_ _null_ textlename _null_ _null_ _null_ ) +insert ( 250 textgename 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "25 19" _null_ _null_ _null_ _null_ _null_ textgename _null_ _null_ _null_ ) +insert ( 251 textgtname 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "25 19" _null_ _null_ _null_ _null_ _null_ textgtname _null_ _null_ _null_ ) +insert ( 252 textnename 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "25 19" _null_ _null_ _null_ _null_ _null_ textnename _null_ _null_ _null_ ) +insert ( 253 bttextnamecmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "25 19" _null_ _null_ _null_ _null_ _null_ bttextnamecmp _null_ _null_ _null_ ) +insert ( 266 nameconcatoid 11 10 12 1 0 0 0 f f f t f i s 2 0 19 "19 26" _null_ _null_ _null_ _null_ _null_ nameconcatoid _null_ _null_ _null_ ) +insert ( 274 timeofday 11 10 12 1 0 0 0 f f f t f v s 0 0 25 "" _null_ _null_ _null_ _null_ _null_ timeofday _null_ _null_ _null_ ) +insert ( 277 inter_sl 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "601 628" _null_ _null_ _null_ _null_ _null_ inter_sl _null_ _null_ _null_ ) +insert ( 278 inter_lb 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "628 603" _null_ _null_ _null_ _null_ _null_ inter_lb _null_ _null_ _null_ ) +insert ( 279 float48mul 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "700 701" _null_ _null_ _null_ _null_ _null_ float48mul _null_ _null_ _null_ ) +insert ( 280 float48div 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "700 701" _null_ _null_ _null_ _null_ _null_ float48div _null_ _null_ _null_ ) +insert ( 281 float48pl 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "700 701" _null_ _null_ _null_ _null_ _null_ float48pl _null_ _null_ _null_ ) +insert ( 282 float48mi 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "700 701" _null_ _null_ _null_ _null_ _null_ float48mi _null_ _null_ _null_ ) +insert ( 283 float84mul 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "701 700" _null_ _null_ _null_ _null_ _null_ float84mul _null_ _null_ _null_ ) +insert ( 284 float84div 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "701 700" _null_ _null_ _null_ _null_ _null_ float84div _null_ _null_ _null_ ) +insert ( 285 float84pl 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "701 700" _null_ _null_ _null_ _null_ _null_ float84pl _null_ _null_ _null_ ) +insert ( 286 float84mi 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "701 700" _null_ _null_ _null_ _null_ _null_ float84mi _null_ _null_ _null_ ) +insert ( 287 float4eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "700 700" _null_ _null_ _null_ _null_ _null_ float4eq _null_ _null_ _null_ ) +insert ( 288 float4ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "700 700" _null_ _null_ _null_ _null_ _null_ float4ne _null_ _null_ _null_ ) +insert ( 289 float4lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "700 700" _null_ _null_ _null_ _null_ _null_ float4lt _null_ _null_ _null_ ) +insert ( 290 float4le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "700 700" _null_ _null_ _null_ _null_ _null_ float4le _null_ _null_ _null_ ) +insert ( 291 float4gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "700 700" _null_ _null_ _null_ _null_ _null_ float4gt _null_ _null_ _null_ ) +insert ( 292 float4ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "700 700" _null_ _null_ _null_ _null_ _null_ float4ge _null_ _null_ _null_ ) +insert ( 293 float8eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "701 701" _null_ _null_ _null_ _null_ _null_ float8eq _null_ _null_ _null_ ) +insert ( 294 float8ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "701 701" _null_ _null_ _null_ _null_ _null_ float8ne _null_ _null_ _null_ ) +insert ( 295 float8lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "701 701" _null_ _null_ _null_ _null_ _null_ float8lt _null_ _null_ _null_ ) +insert ( 296 float8le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "701 701" _null_ _null_ _null_ _null_ _null_ float8le _null_ _null_ _null_ ) +insert ( 297 float8gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "701 701" _null_ _null_ _null_ _null_ _null_ float8gt _null_ _null_ _null_ ) +insert ( 298 float8ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "701 701" _null_ _null_ _null_ _null_ _null_ float8ge _null_ _null_ _null_ ) +insert ( 299 float48eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "700 701" _null_ _null_ _null_ _null_ _null_ float48eq _null_ _null_ _null_ ) +insert ( 300 float48ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "700 701" _null_ _null_ _null_ _null_ _null_ float48ne _null_ _null_ _null_ ) +insert ( 301 float48lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "700 701" _null_ _null_ _null_ _null_ _null_ float48lt _null_ _null_ _null_ ) +insert ( 302 float48le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "700 701" _null_ _null_ _null_ _null_ _null_ float48le _null_ _null_ _null_ ) +insert ( 303 float48gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "700 701" _null_ _null_ _null_ _null_ _null_ float48gt _null_ _null_ _null_ ) +insert ( 304 float48ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "700 701" _null_ _null_ _null_ _null_ _null_ float48ge _null_ _null_ _null_ ) +insert ( 305 float84eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "701 700" _null_ _null_ _null_ _null_ _null_ float84eq _null_ _null_ _null_ ) +insert ( 306 float84ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "701 700" _null_ _null_ _null_ _null_ _null_ float84ne _null_ _null_ _null_ ) +insert ( 307 float84lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "701 700" _null_ _null_ _null_ _null_ _null_ float84lt _null_ _null_ _null_ ) +insert ( 308 float84le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "701 700" _null_ _null_ _null_ _null_ _null_ float84le _null_ _null_ _null_ ) +insert ( 309 float84gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "701 700" _null_ _null_ _null_ _null_ _null_ float84gt _null_ _null_ _null_ ) +insert ( 310 float84ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "701 700" _null_ _null_ _null_ _null_ _null_ float84ge _null_ _null_ _null_ ) +insert ( 320 width_bucket 11 10 12 1 0 0 0 f f f t f i s 4 0 23 "701 701 701 23" _null_ _null_ _null_ _null_ _null_ width_bucket_float8 _null_ _null_ _null_ ) +insert ( 311 float8 11 10 12 1 0 0 0 f f f t f i s 1 0 701 700 _null_ _null_ _null_ _null_ _null_ ftod _null_ _null_ _null_ ) +insert ( 312 float4 11 10 12 1 0 0 0 f f f t f i s 1 0 700 701 _null_ _null_ _null_ _null_ _null_ dtof _null_ _null_ _null_ ) +insert ( 313 int4 11 10 12 1 0 0 0 f f f t f i s 1 0 23 21 _null_ _null_ _null_ _null_ _null_ i2toi4 _null_ _null_ _null_ ) +insert ( 314 int2 11 10 12 1 0 0 0 f f f t f i s 1 0 21 23 _null_ _null_ _null_ _null_ _null_ i4toi2 _null_ _null_ _null_ ) +insert ( 316 float8 11 10 12 1 0 0 0 f f f t f i s 1 0 701 23 _null_ _null_ _null_ _null_ _null_ i4tod _null_ _null_ _null_ ) +insert ( 317 int4 11 10 12 1 0 0 0 f f f t f i s 1 0 23 701 _null_ _null_ _null_ _null_ _null_ dtoi4 _null_ _null_ _null_ ) +insert ( 318 float4 11 10 12 1 0 0 0 f f f t f i s 1 0 700 23 _null_ _null_ _null_ _null_ _null_ i4tof _null_ _null_ _null_ ) +insert ( 319 int4 11 10 12 1 0 0 0 f f f t f i s 1 0 23 700 _null_ _null_ _null_ _null_ _null_ ftoi4 _null_ _null_ _null_ ) +insert ( 3 heap_tableam_handler 11 10 12 1 0 0 0 f f f t f v s 1 0 269 2281 _null_ _null_ _null_ _null_ _null_ heap_tableam_handler _null_ _null_ _null_ ) +insert ( 330 bthandler 11 10 12 1 0 0 0 f f f t f v s 1 0 325 2281 _null_ _null_ _null_ _null_ _null_ bthandler _null_ _null_ _null_ ) +insert ( 331 hashhandler 11 10 12 1 0 0 0 f f f t f v s 1 0 325 2281 _null_ _null_ _null_ _null_ _null_ hashhandler _null_ _null_ _null_ ) +insert ( 332 gisthandler 11 10 12 1 0 0 0 f f f t f v s 1 0 325 2281 _null_ _null_ _null_ _null_ _null_ gisthandler _null_ _null_ _null_ ) +insert ( 333 ginhandler 11 10 12 1 0 0 0 f f f t f v s 1 0 325 2281 _null_ _null_ _null_ _null_ _null_ ginhandler _null_ _null_ _null_ ) +insert ( 334 spghandler 11 10 12 1 0 0 0 f f f t f v s 1 0 325 2281 _null_ _null_ _null_ _null_ _null_ spghandler _null_ _null_ _null_ ) +insert ( 335 brinhandler 11 10 12 1 0 0 0 f f f t f v s 1 0 325 2281 _null_ _null_ _null_ _null_ _null_ brinhandler _null_ _null_ _null_ ) +insert ( 3952 brin_summarize_new_values 11 10 12 1 0 0 0 f f f t f v u 1 0 23 2205 _null_ _null_ _null_ _null_ _null_ brin_summarize_new_values _null_ _null_ _null_ ) +insert ( 3999 brin_summarize_range 11 10 12 1 0 0 0 f f f t f v u 2 0 23 "2205 20" _null_ _null_ _null_ _null_ _null_ brin_summarize_range _null_ _null_ _null_ ) +insert ( 4014 brin_desummarize_range 11 10 12 1 0 0 0 f f f t f v u 2 0 2278 "2205 20" _null_ _null_ _null_ _null_ _null_ brin_desummarize_range _null_ _null_ _null_ ) +insert ( 338 amvalidate 11 10 12 1 0 0 0 f f f t f v s 1 0 16 26 _null_ _null_ _null_ _null_ _null_ amvalidate _null_ _null_ _null_ ) +insert ( 636 pg_indexam_has_property 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "26 25" _null_ _null_ _null_ _null_ _null_ pg_indexam_has_property _null_ _null_ _null_ ) +insert ( 637 pg_index_has_property 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "2205 25" _null_ _null_ _null_ _null_ _null_ pg_index_has_property _null_ _null_ _null_ ) +insert ( 638 pg_index_column_has_property 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "2205 23 25" _null_ _null_ _null_ _null_ _null_ pg_index_column_has_property _null_ _null_ _null_ ) +insert ( 676 pg_indexam_progress_phasename 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "26 20" _null_ _null_ _null_ _null_ _null_ pg_indexam_progress_phasename _null_ _null_ _null_ ) +insert ( 339 poly_same 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "604 604" _null_ _null_ _null_ _null_ _null_ poly_same _null_ _null_ _null_ ) +insert ( 340 poly_contain 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "604 604" _null_ _null_ _null_ _null_ _null_ poly_contain _null_ _null_ _null_ ) +insert ( 341 poly_left 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "604 604" _null_ _null_ _null_ _null_ _null_ poly_left _null_ _null_ _null_ ) +insert ( 342 poly_overleft 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "604 604" _null_ _null_ _null_ _null_ _null_ poly_overleft _null_ _null_ _null_ ) +insert ( 343 poly_overright 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "604 604" _null_ _null_ _null_ _null_ _null_ poly_overright _null_ _null_ _null_ ) +insert ( 344 poly_right 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "604 604" _null_ _null_ _null_ _null_ _null_ poly_right _null_ _null_ _null_ ) +insert ( 345 poly_contained 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "604 604" _null_ _null_ _null_ _null_ _null_ poly_contained _null_ _null_ _null_ ) +insert ( 346 poly_overlap 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "604 604" _null_ _null_ _null_ _null_ _null_ poly_overlap _null_ _null_ _null_ ) +insert ( 347 poly_in 11 10 12 1 0 0 0 f f f t f i s 1 0 604 2275 _null_ _null_ _null_ _null_ _null_ poly_in _null_ _null_ _null_ ) +insert ( 348 poly_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 604 _null_ _null_ _null_ _null_ _null_ poly_out _null_ _null_ _null_ ) +insert ( 350 btint2cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "21 21" _null_ _null_ _null_ _null_ _null_ btint2cmp _null_ _null_ _null_ ) +insert ( 3129 btint2sortsupport 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ btint2sortsupport _null_ _null_ _null_ ) +insert ( 351 btint4cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "23 23" _null_ _null_ _null_ _null_ _null_ btint4cmp _null_ _null_ _null_ ) +insert ( 3130 btint4sortsupport 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ btint4sortsupport _null_ _null_ _null_ ) +insert ( 842 btint8cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "20 20" _null_ _null_ _null_ _null_ _null_ btint8cmp _null_ _null_ _null_ ) +insert ( 3131 btint8sortsupport 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ btint8sortsupport _null_ _null_ _null_ ) +insert ( 354 btfloat4cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "700 700" _null_ _null_ _null_ _null_ _null_ btfloat4cmp _null_ _null_ _null_ ) +insert ( 3132 btfloat4sortsupport 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ btfloat4sortsupport _null_ _null_ _null_ ) +insert ( 355 btfloat8cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "701 701" _null_ _null_ _null_ _null_ _null_ btfloat8cmp _null_ _null_ _null_ ) +insert ( 3133 btfloat8sortsupport 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ btfloat8sortsupport _null_ _null_ _null_ ) +insert ( 356 btoidcmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "26 26" _null_ _null_ _null_ _null_ _null_ btoidcmp _null_ _null_ _null_ ) +insert ( 3134 btoidsortsupport 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ btoidsortsupport _null_ _null_ _null_ ) +insert ( 404 btoidvectorcmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "30 30" _null_ _null_ _null_ _null_ _null_ btoidvectorcmp _null_ _null_ _null_ ) +insert ( 358 btcharcmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "18 18" _null_ _null_ _null_ _null_ _null_ btcharcmp _null_ _null_ _null_ ) +insert ( 359 btnamecmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "19 19" _null_ _null_ _null_ _null_ _null_ btnamecmp _null_ _null_ _null_ ) +insert ( 3135 btnamesortsupport 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ btnamesortsupport _null_ _null_ _null_ ) +insert ( 360 bttextcmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "25 25" _null_ _null_ _null_ _null_ _null_ bttextcmp _null_ _null_ _null_ ) +insert ( 3255 bttextsortsupport 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ bttextsortsupport _null_ _null_ _null_ ) +insert ( 5050 btvarstrequalimage 11 10 12 1 0 0 0 f f f t f i s 1 0 16 26 _null_ _null_ _null_ _null_ _null_ btvarstrequalimage _null_ _null_ _null_ ) +insert ( 377 cash_cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "790 790" _null_ _null_ _null_ _null_ _null_ cash_cmp _null_ _null_ _null_ ) +insert ( 382 btarraycmp 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "2277 2277" _null_ _null_ _null_ _null_ _null_ btarraycmp _null_ _null_ _null_ ) +insert ( 4126 in_range 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "20 20 20 16 16" _null_ _null_ _null_ _null_ _null_ in_range_int8_int8 _null_ _null_ _null_ ) +insert ( 4127 in_range 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "23 23 20 16 16" _null_ _null_ _null_ _null_ _null_ in_range_int4_int8 _null_ _null_ _null_ ) +insert ( 4128 in_range 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "23 23 23 16 16" _null_ _null_ _null_ _null_ _null_ in_range_int4_int4 _null_ _null_ _null_ ) +insert ( 4129 in_range 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "23 23 21 16 16" _null_ _null_ _null_ _null_ _null_ in_range_int4_int2 _null_ _null_ _null_ ) +insert ( 4130 in_range 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "21 21 20 16 16" _null_ _null_ _null_ _null_ _null_ in_range_int2_int8 _null_ _null_ _null_ ) +insert ( 4131 in_range 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "21 21 23 16 16" _null_ _null_ _null_ _null_ _null_ in_range_int2_int4 _null_ _null_ _null_ ) +insert ( 4132 in_range 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "21 21 21 16 16" _null_ _null_ _null_ _null_ _null_ in_range_int2_int2 _null_ _null_ _null_ ) +insert ( 4139 in_range 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "701 701 701 16 16" _null_ _null_ _null_ _null_ _null_ in_range_float8_float8 _null_ _null_ _null_ ) +insert ( 4140 in_range 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "700 700 701 16 16" _null_ _null_ _null_ _null_ _null_ in_range_float4_float8 _null_ _null_ _null_ ) +insert ( 4141 in_range 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "1700 1700 1700 16 16" _null_ _null_ _null_ _null_ _null_ in_range_numeric_numeric _null_ _null_ _null_ ) +insert ( 361 lseg_distance 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "601 601" _null_ _null_ _null_ _null_ _null_ lseg_distance _null_ _null_ _null_ ) +insert ( 362 lseg_interpt 11 10 12 1 0 0 0 f f f t f i s 2 0 600 "601 601" _null_ _null_ _null_ _null_ _null_ lseg_interpt _null_ _null_ _null_ ) +insert ( 363 dist_ps 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "600 601" _null_ _null_ _null_ _null_ _null_ dist_ps _null_ _null_ _null_ ) +insert ( 380 dist_sp 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "601 600" _null_ _null_ _null_ _null_ _null_ dist_sp _null_ _null_ _null_ ) +insert ( 364 dist_pb 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "600 603" _null_ _null_ _null_ _null_ _null_ dist_pb _null_ _null_ _null_ ) +insert ( 357 dist_bp 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "603 600" _null_ _null_ _null_ _null_ _null_ dist_bp _null_ _null_ _null_ ) +insert ( 365 dist_sb 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "601 603" _null_ _null_ _null_ _null_ _null_ dist_sb _null_ _null_ _null_ ) +insert ( 381 dist_bs 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "603 601" _null_ _null_ _null_ _null_ _null_ dist_bs _null_ _null_ _null_ ) +insert ( 366 close_ps 11 10 12 1 0 0 0 f f f t f i s 2 0 600 "600 601" _null_ _null_ _null_ _null_ _null_ close_ps _null_ _null_ _null_ ) +insert ( 367 close_pb 11 10 12 1 0 0 0 f f f t f i s 2 0 600 "600 603" _null_ _null_ _null_ _null_ _null_ close_pb _null_ _null_ _null_ ) +insert ( 368 close_sb 11 10 12 1 0 0 0 f f f t f i s 2 0 600 "601 603" _null_ _null_ _null_ _null_ _null_ close_sb _null_ _null_ _null_ ) +insert ( 369 on_ps 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "600 601" _null_ _null_ _null_ _null_ _null_ on_ps _null_ _null_ _null_ ) +insert ( 370 path_distance 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "602 602" _null_ _null_ _null_ _null_ _null_ path_distance _null_ _null_ _null_ ) +insert ( 371 dist_ppath 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "600 602" _null_ _null_ _null_ _null_ _null_ dist_ppath _null_ _null_ _null_ ) +insert ( 421 dist_pathp 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "602 600" _null_ _null_ _null_ _null_ _null_ dist_pathp _null_ _null_ _null_ ) +insert ( 372 on_sb 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "601 603" _null_ _null_ _null_ _null_ _null_ on_sb _null_ _null_ _null_ ) +insert ( 373 inter_sb 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "601 603" _null_ _null_ _null_ _null_ _null_ inter_sb _null_ _null_ _null_ ) +insert ( 401 text 11 10 12 1 0 0 0 f f f t f i s 1 0 25 1042 _null_ _null_ _null_ _null_ _null_ rtrim1 _null_ _null_ _null_ ) +insert ( 406 text 11 10 12 1 0 0 0 f f f t f i s 1 0 25 19 _null_ _null_ _null_ _null_ _null_ name_text _null_ _null_ _null_ ) +insert ( 407 name 11 10 12 1 0 0 0 f f f t f i s 1 0 19 25 _null_ _null_ _null_ _null_ _null_ text_name _null_ _null_ _null_ ) +insert ( 408 bpchar 11 10 12 1 0 0 0 f f f t f i s 1 0 1042 19 _null_ _null_ _null_ _null_ _null_ name_bpchar _null_ _null_ _null_ ) +insert ( 409 name 11 10 12 1 0 0 0 f f f t f i s 1 0 19 1042 _null_ _null_ _null_ _null_ _null_ bpchar_name _null_ _null_ _null_ ) +insert ( 449 hashint2 11 10 12 1 0 0 0 f f f t f i s 1 0 23 21 _null_ _null_ _null_ _null_ _null_ hashint2 _null_ _null_ _null_ ) +insert ( 441 hashint2extended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "21 20" _null_ _null_ _null_ _null_ _null_ hashint2extended _null_ _null_ _null_ ) +insert ( 450 hashint4 11 10 12 1 0 0 0 f f f t f i s 1 0 23 23 _null_ _null_ _null_ _null_ _null_ hashint4 _null_ _null_ _null_ ) +insert ( 425 hashint4extended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "23 20" _null_ _null_ _null_ _null_ _null_ hashint4extended _null_ _null_ _null_ ) +insert ( 949 hashint8 11 10 12 1 0 0 0 f f f t f i s 1 0 23 20 _null_ _null_ _null_ _null_ _null_ hashint8 _null_ _null_ _null_ ) +insert ( 442 hashint8extended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 20" _null_ _null_ _null_ _null_ _null_ hashint8extended _null_ _null_ _null_ ) +insert ( 451 hashfloat4 11 10 12 1 0 0 0 f f f t f i s 1 0 23 700 _null_ _null_ _null_ _null_ _null_ hashfloat4 _null_ _null_ _null_ ) +insert ( 443 hashfloat4extended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "700 20" _null_ _null_ _null_ _null_ _null_ hashfloat4extended _null_ _null_ _null_ ) +insert ( 452 hashfloat8 11 10 12 1 0 0 0 f f f t f i s 1 0 23 701 _null_ _null_ _null_ _null_ _null_ hashfloat8 _null_ _null_ _null_ ) +insert ( 444 hashfloat8extended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "701 20" _null_ _null_ _null_ _null_ _null_ hashfloat8extended _null_ _null_ _null_ ) +insert ( 453 hashoid 11 10 12 1 0 0 0 f f f t f i s 1 0 23 26 _null_ _null_ _null_ _null_ _null_ hashoid _null_ _null_ _null_ ) +insert ( 445 hashoidextended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "26 20" _null_ _null_ _null_ _null_ _null_ hashoidextended _null_ _null_ _null_ ) +insert ( 454 hashchar 11 10 12 1 0 0 0 f f f t f i s 1 0 23 18 _null_ _null_ _null_ _null_ _null_ hashchar _null_ _null_ _null_ ) +insert ( 446 hashcharextended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "18 20" _null_ _null_ _null_ _null_ _null_ hashcharextended _null_ _null_ _null_ ) +insert ( 455 hashname 11 10 12 1 0 0 0 f f f t f i s 1 0 23 19 _null_ _null_ _null_ _null_ _null_ hashname _null_ _null_ _null_ ) +insert ( 447 hashnameextended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "19 20" _null_ _null_ _null_ _null_ _null_ hashnameextended _null_ _null_ _null_ ) +insert ( 400 hashtext 11 10 12 1 0 0 0 f f f t f i s 1 0 23 25 _null_ _null_ _null_ _null_ _null_ hashtext _null_ _null_ _null_ ) +insert ( 448 hashtextextended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "25 20" _null_ _null_ _null_ _null_ _null_ hashtextextended _null_ _null_ _null_ ) +insert ( 456 hashvarlena 11 10 12 1 0 0 0 f f f t f i s 1 0 23 2281 _null_ _null_ _null_ _null_ _null_ hashvarlena _null_ _null_ _null_ ) +insert ( 772 hashvarlenaextended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "2281 20" _null_ _null_ _null_ _null_ _null_ hashvarlenaextended _null_ _null_ _null_ ) +insert ( 457 hashoidvector 11 10 12 1 0 0 0 f f f t f i s 1 0 23 30 _null_ _null_ _null_ _null_ _null_ hashoidvector _null_ _null_ _null_ ) +insert ( 776 hashoidvectorextended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "30 20" _null_ _null_ _null_ _null_ _null_ hashoidvectorextended _null_ _null_ _null_ ) +insert ( 329 hash_aclitem 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1033 _null_ _null_ _null_ _null_ _null_ hash_aclitem _null_ _null_ _null_ ) +insert ( 777 hash_aclitem_extended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "1033 20" _null_ _null_ _null_ _null_ _null_ hash_aclitem_extended _null_ _null_ _null_ ) +insert ( 399 hashmacaddr 11 10 12 1 0 0 0 f f f t f i s 1 0 23 829 _null_ _null_ _null_ _null_ _null_ hashmacaddr _null_ _null_ _null_ ) +insert ( 778 hashmacaddrextended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "829 20" _null_ _null_ _null_ _null_ _null_ hashmacaddrextended _null_ _null_ _null_ ) +insert ( 422 hashinet 11 10 12 1 0 0 0 f f f t f i s 1 0 23 869 _null_ _null_ _null_ _null_ _null_ hashinet _null_ _null_ _null_ ) +insert ( 779 hashinetextended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "869 20" _null_ _null_ _null_ _null_ _null_ hashinetextended _null_ _null_ _null_ ) +insert ( 432 hash_numeric 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1700 _null_ _null_ _null_ _null_ _null_ hash_numeric _null_ _null_ _null_ ) +insert ( 780 hash_numeric_extended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "1700 20" _null_ _null_ _null_ _null_ _null_ hash_numeric_extended _null_ _null_ _null_ ) +insert ( 328 hashmacaddr8 11 10 12 1 0 0 0 f f f t f i s 1 0 23 774 _null_ _null_ _null_ _null_ _null_ hashmacaddr8 _null_ _null_ _null_ ) +insert ( 781 hashmacaddr8extended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "774 20" _null_ _null_ _null_ _null_ _null_ hashmacaddr8extended _null_ _null_ _null_ ) +insert ( 438 num_nulls 11 10 12 1 0 2276 0 f f f f f i s 1 0 23 2276 "{2276}" "{v}" _null_ _null_ _null_ pg_num_nulls _null_ _null_ _null_ ) +insert ( 440 num_nonnulls 11 10 12 1 0 2276 0 f f f f f i s 1 0 23 2276 "{2276}" "{v}" _null_ _null_ _null_ pg_num_nonnulls _null_ _null_ _null_ ) +insert ( 458 text_larger 11 10 12 1 0 0 0 f f t t f i s 2 0 25 "25 25" _null_ _null_ _null_ _null_ _null_ text_larger _null_ _null_ _null_ ) +insert ( 459 text_smaller 11 10 12 1 0 0 0 f f t t f i s 2 0 25 "25 25" _null_ _null_ _null_ _null_ _null_ text_smaller _null_ _null_ _null_ ) +insert ( 460 int8in 11 10 12 1 0 0 0 f f f t f i s 1 0 20 2275 _null_ _null_ _null_ _null_ _null_ int8in _null_ _null_ _null_ ) +insert ( 461 int8out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 20 _null_ _null_ _null_ _null_ _null_ int8out _null_ _null_ _null_ ) +insert ( 462 int8um 11 10 12 1 0 0 0 f f f t f i s 1 0 20 20 _null_ _null_ _null_ _null_ _null_ int8um _null_ _null_ _null_ ) +insert ( 463 int8pl 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 20" _null_ _null_ _null_ _null_ _null_ int8pl _null_ _null_ _null_ ) +insert ( 464 int8mi 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 20" _null_ _null_ _null_ _null_ _null_ int8mi _null_ _null_ _null_ ) +insert ( 465 int8mul 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 20" _null_ _null_ _null_ _null_ _null_ int8mul _null_ _null_ _null_ ) +insert ( 466 int8div 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 20" _null_ _null_ _null_ _null_ _null_ int8div _null_ _null_ _null_ ) +insert ( 467 int8eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "20 20" _null_ _null_ _null_ _null_ _null_ int8eq _null_ _null_ _null_ ) +insert ( 468 int8ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "20 20" _null_ _null_ _null_ _null_ _null_ int8ne _null_ _null_ _null_ ) +insert ( 469 int8lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "20 20" _null_ _null_ _null_ _null_ _null_ int8lt _null_ _null_ _null_ ) +insert ( 470 int8gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "20 20" _null_ _null_ _null_ _null_ _null_ int8gt _null_ _null_ _null_ ) +insert ( 471 int8le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "20 20" _null_ _null_ _null_ _null_ _null_ int8le _null_ _null_ _null_ ) +insert ( 472 int8ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "20 20" _null_ _null_ _null_ _null_ _null_ int8ge _null_ _null_ _null_ ) +insert ( 474 int84eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "20 23" _null_ _null_ _null_ _null_ _null_ int84eq _null_ _null_ _null_ ) +insert ( 475 int84ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "20 23" _null_ _null_ _null_ _null_ _null_ int84ne _null_ _null_ _null_ ) +insert ( 476 int84lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "20 23" _null_ _null_ _null_ _null_ _null_ int84lt _null_ _null_ _null_ ) +insert ( 477 int84gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "20 23" _null_ _null_ _null_ _null_ _null_ int84gt _null_ _null_ _null_ ) +insert ( 478 int84le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "20 23" _null_ _null_ _null_ _null_ _null_ int84le _null_ _null_ _null_ ) +insert ( 479 int84ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "20 23" _null_ _null_ _null_ _null_ _null_ int84ge _null_ _null_ _null_ ) +insert ( 480 int4 11 10 12 1 0 0 0 f f f t f i s 1 0 23 20 _null_ _null_ _null_ _null_ _null_ int84 _null_ _null_ _null_ ) +insert ( 481 int8 11 10 12 1 0 0 0 f f f t f i s 1 0 20 23 _null_ _null_ _null_ _null_ _null_ int48 _null_ _null_ _null_ ) +insert ( 482 float8 11 10 12 1 0 0 0 f f f t f i s 1 0 701 20 _null_ _null_ _null_ _null_ _null_ i8tod _null_ _null_ _null_ ) +insert ( 483 int8 11 10 12 1 0 0 0 f f f t f i s 1 0 20 701 _null_ _null_ _null_ _null_ _null_ dtoi8 _null_ _null_ _null_ ) +insert ( 626 hash_array 11 10 12 1 0 0 0 f f f t f i s 1 0 23 2277 _null_ _null_ _null_ _null_ _null_ hash_array _null_ _null_ _null_ ) +insert ( 782 hash_array_extended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "2277 20" _null_ _null_ _null_ _null_ _null_ hash_array_extended _null_ _null_ _null_ ) +insert ( 652 float4 11 10 12 1 0 0 0 f f f t f i s 1 0 700 20 _null_ _null_ _null_ _null_ _null_ i8tof _null_ _null_ _null_ ) +insert ( 653 int8 11 10 12 1 0 0 0 f f f t f i s 1 0 20 700 _null_ _null_ _null_ _null_ _null_ ftoi8 _null_ _null_ _null_ ) +insert ( 714 int2 11 10 12 1 0 0 0 f f f t f i s 1 0 21 20 _null_ _null_ _null_ _null_ _null_ int82 _null_ _null_ _null_ ) +insert ( 754 int8 11 10 12 1 0 0 0 f f f t f i s 1 0 20 21 _null_ _null_ _null_ _null_ _null_ int28 _null_ _null_ _null_ ) +insert ( 655 namelt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "19 19" _null_ _null_ _null_ _null_ _null_ namelt _null_ _null_ _null_ ) +insert ( 656 namele 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "19 19" _null_ _null_ _null_ _null_ _null_ namele _null_ _null_ _null_ ) +insert ( 657 namegt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "19 19" _null_ _null_ _null_ _null_ _null_ namegt _null_ _null_ _null_ ) +insert ( 658 namege 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "19 19" _null_ _null_ _null_ _null_ _null_ namege _null_ _null_ _null_ ) +insert ( 659 namene 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "19 19" _null_ _null_ _null_ _null_ _null_ namene _null_ _null_ _null_ ) +insert ( 668 bpchar 11 10 12 1 0 0 0 f f f t f i s 3 0 1042 "1042 23 16" _null_ _null_ _null_ _null_ _null_ bpchar _null_ _null_ _null_ ) +insert ( 3097 varchar_support 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ varchar_support _null_ _null_ _null_ ) +insert ( 669 varchar 11 10 12 1 0 0 3097 f f f t f i s 3 0 1043 "1043 23 16" _null_ _null_ _null_ _null_ _null_ varchar _null_ _null_ _null_ ) +insert ( 619 oidvectorne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "30 30" _null_ _null_ _null_ _null_ _null_ oidvectorne _null_ _null_ _null_ ) +insert ( 677 oidvectorlt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "30 30" _null_ _null_ _null_ _null_ _null_ oidvectorlt _null_ _null_ _null_ ) +insert ( 678 oidvectorle 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "30 30" _null_ _null_ _null_ _null_ _null_ oidvectorle _null_ _null_ _null_ ) +insert ( 679 oidvectoreq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "30 30" _null_ _null_ _null_ _null_ _null_ oidvectoreq _null_ _null_ _null_ ) +insert ( 680 oidvectorge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "30 30" _null_ _null_ _null_ _null_ _null_ oidvectorge _null_ _null_ _null_ ) +insert ( 681 oidvectorgt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "30 30" _null_ _null_ _null_ _null_ _null_ oidvectorgt _null_ _null_ _null_ ) +insert ( 710 getpgusername 11 10 12 1 0 0 0 f f f t f s s 0 0 19 "" _null_ _null_ _null_ _null_ _null_ current_user _null_ _null_ _null_ ) +insert ( 716 oidlt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "26 26" _null_ _null_ _null_ _null_ _null_ oidlt _null_ _null_ _null_ ) +insert ( 717 oidle 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "26 26" _null_ _null_ _null_ _null_ _null_ oidle _null_ _null_ _null_ ) +insert ( 720 octet_length 11 10 12 1 0 0 0 f f f t f i s 1 0 23 17 _null_ _null_ _null_ _null_ _null_ byteaoctetlen _null_ _null_ _null_ ) +insert ( 721 get_byte 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "17 23" _null_ _null_ _null_ _null_ _null_ byteaGetByte _null_ _null_ _null_ ) +insert ( 722 set_byte 11 10 12 1 0 0 0 f f f t f i s 3 0 17 "17 23 23" _null_ _null_ _null_ _null_ _null_ byteaSetByte _null_ _null_ _null_ ) +insert ( 723 get_bit 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "17 20" _null_ _null_ _null_ _null_ _null_ byteaGetBit _null_ _null_ _null_ ) +insert ( 724 set_bit 11 10 12 1 0 0 0 f f f t f i s 3 0 17 "17 20 23" _null_ _null_ _null_ _null_ _null_ byteaSetBit _null_ _null_ _null_ ) +insert ( 749 overlay 11 10 12 1 0 0 0 f f f t f i s 4 0 17 "17 17 23 23" _null_ _null_ _null_ _null_ _null_ byteaoverlay _null_ _null_ _null_ ) +insert ( 752 overlay 11 10 12 1 0 0 0 f f f t f i s 3 0 17 "17 17 23" _null_ _null_ _null_ _null_ _null_ byteaoverlay_no_len _null_ _null_ _null_ ) +insert ( 725 dist_pl 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "600 628" _null_ _null_ _null_ _null_ _null_ dist_pl _null_ _null_ _null_ ) +insert ( 702 dist_lp 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "628 600" _null_ _null_ _null_ _null_ _null_ dist_lp _null_ _null_ _null_ ) +insert ( 726 dist_lb 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "628 603" _null_ _null_ _null_ _null_ _null_ dist_lb _null_ _null_ _null_ ) +insert ( 703 dist_bl 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "603 628" _null_ _null_ _null_ _null_ _null_ dist_bl _null_ _null_ _null_ ) +insert ( 727 dist_sl 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "601 628" _null_ _null_ _null_ _null_ _null_ dist_sl _null_ _null_ _null_ ) +insert ( 704 dist_ls 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "628 601" _null_ _null_ _null_ _null_ _null_ dist_ls _null_ _null_ _null_ ) +insert ( 728 dist_cpoly 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "718 604" _null_ _null_ _null_ _null_ _null_ dist_cpoly _null_ _null_ _null_ ) +insert ( 785 dist_polyc 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "604 718" _null_ _null_ _null_ _null_ _null_ dist_polyc _null_ _null_ _null_ ) +insert ( 729 poly_distance 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "604 604" _null_ _null_ _null_ _null_ _null_ poly_distance _null_ _null_ _null_ ) +insert ( 3275 dist_ppoly 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "600 604" _null_ _null_ _null_ _null_ _null_ dist_ppoly _null_ _null_ _null_ ) +insert ( 3292 dist_polyp 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "604 600" _null_ _null_ _null_ _null_ _null_ dist_polyp _null_ _null_ _null_ ) +insert ( 3290 dist_cpoint 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "718 600" _null_ _null_ _null_ _null_ _null_ dist_cpoint _null_ _null_ _null_ ) +insert ( 740 text_lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ text_lt _null_ _null_ _null_ ) +insert ( 741 text_le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ text_le _null_ _null_ _null_ ) +insert ( 742 text_gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ text_gt _null_ _null_ _null_ ) +insert ( 743 text_ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ text_ge _null_ _null_ _null_ ) +insert ( 745 current_user 11 10 12 1 0 0 0 f f f t f s s 0 0 19 "" _null_ _null_ _null_ _null_ _null_ current_user _null_ _null_ _null_ ) +insert ( 746 session_user 11 10 12 1 0 0 0 f f f t f s s 0 0 19 "" _null_ _null_ _null_ _null_ _null_ session_user _null_ _null_ _null_ ) +insert ( 744 array_eq 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2277 2277" _null_ _null_ _null_ _null_ _null_ array_eq _null_ _null_ _null_ ) +insert ( 390 array_ne 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2277 2277" _null_ _null_ _null_ _null_ _null_ array_ne _null_ _null_ _null_ ) +insert ( 391 array_lt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2277 2277" _null_ _null_ _null_ _null_ _null_ array_lt _null_ _null_ _null_ ) +insert ( 392 array_gt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2277 2277" _null_ _null_ _null_ _null_ _null_ array_gt _null_ _null_ _null_ ) +insert ( 393 array_le 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2277 2277" _null_ _null_ _null_ _null_ _null_ array_le _null_ _null_ _null_ ) +insert ( 396 array_ge 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2277 2277" _null_ _null_ _null_ _null_ _null_ array_ge _null_ _null_ _null_ ) +insert ( 747 array_dims 11 10 12 1 0 0 0 f f f t f i s 1 0 25 2277 _null_ _null_ _null_ _null_ _null_ array_dims _null_ _null_ _null_ ) +insert ( 748 array_ndims 11 10 12 1 0 0 0 f f f t f i s 1 0 23 2277 _null_ _null_ _null_ _null_ _null_ array_ndims _null_ _null_ _null_ ) +insert ( 750 array_in 11 10 12 1 0 0 0 f f f t f s s 3 0 2277 "2275 26 23" _null_ _null_ _null_ _null_ _null_ array_in _null_ _null_ _null_ ) +insert ( 751 array_out 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 2277 _null_ _null_ _null_ _null_ _null_ array_out _null_ _null_ _null_ ) +insert ( 2091 array_lower 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "2277 23" _null_ _null_ _null_ _null_ _null_ array_lower _null_ _null_ _null_ ) +insert ( 2092 array_upper 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "2277 23" _null_ _null_ _null_ _null_ _null_ array_upper _null_ _null_ _null_ ) +insert ( 2176 array_length 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "2277 23" _null_ _null_ _null_ _null_ _null_ array_length _null_ _null_ _null_ ) +insert ( 3179 cardinality 11 10 12 1 0 0 0 f f f t f i s 1 0 23 2277 _null_ _null_ _null_ _null_ _null_ array_cardinality _null_ _null_ _null_ ) +insert ( 378 array_append 11 10 12 1 0 0 0 f f f f f i s 2 0 2277 "2277 2283" _null_ _null_ _null_ _null_ _null_ array_append _null_ _null_ _null_ ) +insert ( 379 array_prepend 11 10 12 1 0 0 0 f f f f f i s 2 0 2277 "2283 2277" _null_ _null_ _null_ _null_ _null_ array_prepend _null_ _null_ _null_ ) +insert ( 383 array_cat 11 10 12 1 0 0 0 f f f f f i s 2 0 2277 "2277 2277" _null_ _null_ _null_ _null_ _null_ array_cat _null_ _null_ _null_ ) +insert ( 394 string_to_array 11 10 12 1 0 0 0 f f f f f i s 2 0 1009 "25 25" _null_ _null_ _null_ _null_ _null_ text_to_array _null_ _null_ _null_ ) +insert ( 395 array_to_string 11 10 12 1 0 0 0 f f f t f s s 2 0 25 "2277 25" _null_ _null_ _null_ _null_ _null_ array_to_text _null_ _null_ _null_ ) +insert ( 376 string_to_array 11 10 12 1 0 0 0 f f f f f i s 3 0 1009 "25 25 25" _null_ _null_ _null_ _null_ _null_ text_to_array_null _null_ _null_ _null_ ) +insert ( 384 array_to_string 11 10 12 1 0 0 0 f f f f f s s 3 0 25 "2277 25 25" _null_ _null_ _null_ _null_ _null_ array_to_text_null _null_ _null_ _null_ ) +insert ( 515 array_larger 11 10 12 1 0 0 0 f f f t f i s 2 0 2277 "2277 2277" _null_ _null_ _null_ _null_ _null_ array_larger _null_ _null_ _null_ ) +insert ( 516 array_smaller 11 10 12 1 0 0 0 f f f t f i s 2 0 2277 "2277 2277" _null_ _null_ _null_ _null_ _null_ array_smaller _null_ _null_ _null_ ) +insert ( 3277 array_position 11 10 12 1 0 0 0 f f f f f i s 2 0 23 "2277 2283" _null_ _null_ _null_ _null_ _null_ array_position _null_ _null_ _null_ ) +insert ( 3278 array_position 11 10 12 1 0 0 0 f f f f f i s 3 0 23 "2277 2283 23" _null_ _null_ _null_ _null_ _null_ array_position_start _null_ _null_ _null_ ) +insert ( 3279 array_positions 11 10 12 1 0 0 0 f f f f f i s 2 0 1007 "2277 2283" _null_ _null_ _null_ _null_ _null_ array_positions _null_ _null_ _null_ ) +insert ( 1191 generate_subscripts 11 10 12 1 1000 0 0 f f f t t i s 3 0 23 "2277 23 16" _null_ _null_ _null_ _null_ _null_ generate_subscripts _null_ _null_ _null_ ) +insert ( 1192 generate_subscripts 11 10 12 1 1000 0 0 f f f t t i s 2 0 23 "2277 23" _null_ _null_ _null_ _null_ _null_ generate_subscripts_nodir _null_ _null_ _null_ ) +insert ( 1193 array_fill 11 10 12 1 0 0 0 f f f f f i s 2 0 2277 "2283 1007" _null_ _null_ _null_ _null_ _null_ array_fill _null_ _null_ _null_ ) +insert ( 1286 array_fill 11 10 12 1 0 0 0 f f f f f i s 3 0 2277 "2283 1007 1007" _null_ _null_ _null_ _null_ _null_ array_fill_with_lower_bounds _null_ _null_ _null_ ) +insert ( 2331 unnest 11 10 12 1 100 0 3996 f f f t t i s 1 0 2283 2277 _null_ _null_ _null_ _null_ _null_ array_unnest _null_ _null_ _null_ ) +insert ( 3996 array_unnest_support 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ array_unnest_support _null_ _null_ _null_ ) +insert ( 3167 array_remove 11 10 12 1 0 0 0 f f f f f i s 2 0 2277 "2277 2283" _null_ _null_ _null_ _null_ _null_ array_remove _null_ _null_ _null_ ) +insert ( 3168 array_replace 11 10 12 1 0 0 0 f f f f f i s 3 0 2277 "2277 2283 2283" _null_ _null_ _null_ _null_ _null_ array_replace _null_ _null_ _null_ ) +insert ( 2333 array_agg_transfn 11 10 12 1 0 0 0 f f f f f i s 2 0 2281 "2281 2776" _null_ _null_ _null_ _null_ _null_ array_agg_transfn _null_ _null_ _null_ ) +insert ( 2334 array_agg_finalfn 11 10 12 1 0 0 0 f f f f f i s 2 0 2277 "2281 2776" _null_ _null_ _null_ _null_ _null_ array_agg_finalfn _null_ _null_ _null_ ) +insert ( 2335 array_agg 11 10 12 1 0 0 0 a f f f f i s 1 0 2277 2776 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 4051 array_agg_array_transfn 11 10 12 1 0 0 0 f f f f f i s 2 0 2281 "2281 2277" _null_ _null_ _null_ _null_ _null_ array_agg_array_transfn _null_ _null_ _null_ ) +insert ( 4052 array_agg_array_finalfn 11 10 12 1 0 0 0 f f f f f i s 2 0 2277 "2281 2277" _null_ _null_ _null_ _null_ _null_ array_agg_array_finalfn _null_ _null_ _null_ ) +insert ( 4053 array_agg 11 10 12 1 0 0 0 a f f f f i s 1 0 2277 2277 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3218 width_bucket 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "2283 2277" _null_ _null_ _null_ _null_ _null_ width_bucket_array _null_ _null_ _null_ ) +insert ( 3816 array_typanalyze 11 10 12 1 0 0 0 f f f t f s s 1 0 16 2281 _null_ _null_ _null_ _null_ _null_ array_typanalyze _null_ _null_ _null_ ) +insert ( 3817 arraycontsel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ arraycontsel _null_ _null_ _null_ ) +insert ( 3818 arraycontjoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ arraycontjoinsel _null_ _null_ _null_ ) +insert ( 764 lo_import 11 10 12 1 0 0 0 f f f t f v u 1 0 26 25 _null_ _null_ _null_ _null_ _null_ be_lo_import _null_ _null_ _null_ ) +insert ( 767 lo_import 11 10 12 1 0 0 0 f f f t f v u 2 0 26 "25 26" _null_ _null_ _null_ _null_ _null_ be_lo_import_with_oid _null_ _null_ _null_ ) +insert ( 765 lo_export 11 10 12 1 0 0 0 f f f t f v u 2 0 23 "26 25" _null_ _null_ _null_ _null_ _null_ be_lo_export _null_ _null_ _null_ ) +insert ( 766 int4inc 11 10 12 1 0 0 0 f f f t f i s 1 0 23 23 _null_ _null_ _null_ _null_ _null_ int4inc _null_ _null_ _null_ ) +insert ( 768 int4larger 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "23 23" _null_ _null_ _null_ _null_ _null_ int4larger _null_ _null_ _null_ ) +insert ( 769 int4smaller 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "23 23" _null_ _null_ _null_ _null_ _null_ int4smaller _null_ _null_ _null_ ) +insert ( 770 int2larger 11 10 12 1 0 0 0 f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2larger _null_ _null_ _null_ ) +insert ( 771 int2smaller 11 10 12 1 0 0 0 f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2smaller _null_ _null_ _null_ ) +insert ( 846 cash_mul_flt4 11 10 12 1 0 0 0 f f f t f i s 2 0 790 "790 700" _null_ _null_ _null_ _null_ _null_ cash_mul_flt4 _null_ _null_ _null_ ) +insert ( 847 cash_div_flt4 11 10 12 1 0 0 0 f f f t f i s 2 0 790 "790 700" _null_ _null_ _null_ _null_ _null_ cash_div_flt4 _null_ _null_ _null_ ) +insert ( 848 flt4_mul_cash 11 10 12 1 0 0 0 f f f t f i s 2 0 790 "700 790" _null_ _null_ _null_ _null_ _null_ flt4_mul_cash _null_ _null_ _null_ ) +insert ( 849 position 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "25 25" _null_ _null_ _null_ _null_ _null_ textpos _null_ _null_ _null_ ) +insert ( 850 textlike 11 10 12 1 0 0 1023 f f f t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ textlike _null_ _null_ _null_ ) +insert ( 1023 textlike_support 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ textlike_support _null_ _null_ _null_ ) +insert ( 851 textnlike 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ textnlike _null_ _null_ _null_ ) +insert ( 852 int48eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "23 20" _null_ _null_ _null_ _null_ _null_ int48eq _null_ _null_ _null_ ) +insert ( 853 int48ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "23 20" _null_ _null_ _null_ _null_ _null_ int48ne _null_ _null_ _null_ ) +insert ( 854 int48lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "23 20" _null_ _null_ _null_ _null_ _null_ int48lt _null_ _null_ _null_ ) +insert ( 855 int48gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "23 20" _null_ _null_ _null_ _null_ _null_ int48gt _null_ _null_ _null_ ) +insert ( 856 int48le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "23 20" _null_ _null_ _null_ _null_ _null_ int48le _null_ _null_ _null_ ) +insert ( 857 int48ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "23 20" _null_ _null_ _null_ _null_ _null_ int48ge _null_ _null_ _null_ ) +insert ( 858 namelike 11 10 12 1 0 0 1023 f f f t f i s 2 0 16 "19 25" _null_ _null_ _null_ _null_ _null_ namelike _null_ _null_ _null_ ) +insert ( 859 namenlike 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "19 25" _null_ _null_ _null_ _null_ _null_ namenlike _null_ _null_ _null_ ) +insert ( 860 bpchar 11 10 12 1 0 0 0 f f f t f i s 1 0 1042 18 _null_ _null_ _null_ _null_ _null_ char_bpchar _null_ _null_ _null_ ) +insert ( 861 current_database 11 10 12 1 0 0 0 f f f t f s s 0 0 19 "" _null_ _null_ _null_ _null_ _null_ current_database _null_ _null_ _null_ ) +insert ( 817 current_query 11 10 12 1 0 0 0 f f f f f v r 0 0 25 "" _null_ _null_ _null_ _null_ _null_ current_query _null_ _null_ _null_ ) +insert ( 3399 int8_mul_cash 11 10 12 1 0 0 0 f f f t f i s 2 0 790 "20 790" _null_ _null_ _null_ _null_ _null_ int8_mul_cash _null_ _null_ _null_ ) +insert ( 862 int4_mul_cash 11 10 12 1 0 0 0 f f f t f i s 2 0 790 "23 790" _null_ _null_ _null_ _null_ _null_ int4_mul_cash _null_ _null_ _null_ ) +insert ( 863 int2_mul_cash 11 10 12 1 0 0 0 f f f t f i s 2 0 790 "21 790" _null_ _null_ _null_ _null_ _null_ int2_mul_cash _null_ _null_ _null_ ) +insert ( 3344 cash_mul_int8 11 10 12 1 0 0 0 f f f t f i s 2 0 790 "790 20" _null_ _null_ _null_ _null_ _null_ cash_mul_int8 _null_ _null_ _null_ ) +insert ( 3345 cash_div_int8 11 10 12 1 0 0 0 f f f t f i s 2 0 790 "790 20" _null_ _null_ _null_ _null_ _null_ cash_div_int8 _null_ _null_ _null_ ) +insert ( 864 cash_mul_int4 11 10 12 1 0 0 0 f f f t f i s 2 0 790 "790 23" _null_ _null_ _null_ _null_ _null_ cash_mul_int4 _null_ _null_ _null_ ) +insert ( 865 cash_div_int4 11 10 12 1 0 0 0 f f f t f i s 2 0 790 "790 23" _null_ _null_ _null_ _null_ _null_ cash_div_int4 _null_ _null_ _null_ ) +insert ( 866 cash_mul_int2 11 10 12 1 0 0 0 f f f t f i s 2 0 790 "790 21" _null_ _null_ _null_ _null_ _null_ cash_mul_int2 _null_ _null_ _null_ ) +insert ( 867 cash_div_int2 11 10 12 1 0 0 0 f f f t f i s 2 0 790 "790 21" _null_ _null_ _null_ _null_ _null_ cash_div_int2 _null_ _null_ _null_ ) +insert ( 886 cash_in 11 10 12 1 0 0 0 f f f t f s s 1 0 790 2275 _null_ _null_ _null_ _null_ _null_ cash_in _null_ _null_ _null_ ) +insert ( 887 cash_out 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 790 _null_ _null_ _null_ _null_ _null_ cash_out _null_ _null_ _null_ ) +insert ( 888 cash_eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "790 790" _null_ _null_ _null_ _null_ _null_ cash_eq _null_ _null_ _null_ ) +insert ( 889 cash_ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "790 790" _null_ _null_ _null_ _null_ _null_ cash_ne _null_ _null_ _null_ ) +insert ( 890 cash_lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "790 790" _null_ _null_ _null_ _null_ _null_ cash_lt _null_ _null_ _null_ ) +insert ( 891 cash_le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "790 790" _null_ _null_ _null_ _null_ _null_ cash_le _null_ _null_ _null_ ) +insert ( 892 cash_gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "790 790" _null_ _null_ _null_ _null_ _null_ cash_gt _null_ _null_ _null_ ) +insert ( 893 cash_ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "790 790" _null_ _null_ _null_ _null_ _null_ cash_ge _null_ _null_ _null_ ) +insert ( 894 cash_pl 11 10 12 1 0 0 0 f f f t f i s 2 0 790 "790 790" _null_ _null_ _null_ _null_ _null_ cash_pl _null_ _null_ _null_ ) +insert ( 895 cash_mi 11 10 12 1 0 0 0 f f f t f i s 2 0 790 "790 790" _null_ _null_ _null_ _null_ _null_ cash_mi _null_ _null_ _null_ ) +insert ( 896 cash_mul_flt8 11 10 12 1 0 0 0 f f f t f i s 2 0 790 "790 701" _null_ _null_ _null_ _null_ _null_ cash_mul_flt8 _null_ _null_ _null_ ) +insert ( 897 cash_div_flt8 11 10 12 1 0 0 0 f f f t f i s 2 0 790 "790 701" _null_ _null_ _null_ _null_ _null_ cash_div_flt8 _null_ _null_ _null_ ) +insert ( 898 cashlarger 11 10 12 1 0 0 0 f f f t f i s 2 0 790 "790 790" _null_ _null_ _null_ _null_ _null_ cashlarger _null_ _null_ _null_ ) +insert ( 899 cashsmaller 11 10 12 1 0 0 0 f f f t f i s 2 0 790 "790 790" _null_ _null_ _null_ _null_ _null_ cashsmaller _null_ _null_ _null_ ) +insert ( 919 flt8_mul_cash 11 10 12 1 0 0 0 f f f t f i s 2 0 790 "701 790" _null_ _null_ _null_ _null_ _null_ flt8_mul_cash _null_ _null_ _null_ ) +insert ( 935 cash_words 11 10 12 1 0 0 0 f f f t f i s 1 0 25 790 _null_ _null_ _null_ _null_ _null_ cash_words _null_ _null_ _null_ ) +insert ( 3822 cash_div_cash 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "790 790" _null_ _null_ _null_ _null_ _null_ cash_div_cash _null_ _null_ _null_ ) +insert ( 3823 numeric 11 10 12 1 0 0 0 f f f t f s s 1 0 1700 790 _null_ _null_ _null_ _null_ _null_ cash_numeric _null_ _null_ _null_ ) +insert ( 3824 money 11 10 12 1 0 0 0 f f f t f s s 1 0 790 1700 _null_ _null_ _null_ _null_ _null_ numeric_cash _null_ _null_ _null_ ) +insert ( 3811 money 11 10 12 1 0 0 0 f f f t f s s 1 0 790 23 _null_ _null_ _null_ _null_ _null_ int4_cash _null_ _null_ _null_ ) +insert ( 3812 money 11 10 12 1 0 0 0 f f f t f s s 1 0 790 20 _null_ _null_ _null_ _null_ _null_ int8_cash _null_ _null_ _null_ ) +insert ( 940 mod 11 10 12 1 0 0 0 f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2mod _null_ _null_ _null_ ) +insert ( 941 mod 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "23 23" _null_ _null_ _null_ _null_ _null_ int4mod _null_ _null_ _null_ ) +insert ( 945 int8mod 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 20" _null_ _null_ _null_ _null_ _null_ int8mod _null_ _null_ _null_ ) +insert ( 947 mod 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 20" _null_ _null_ _null_ _null_ _null_ int8mod _null_ _null_ _null_ ) +insert ( 5044 gcd 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "23 23" _null_ _null_ _null_ _null_ _null_ int4gcd _null_ _null_ _null_ ) +insert ( 5045 gcd 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 20" _null_ _null_ _null_ _null_ _null_ int8gcd _null_ _null_ _null_ ) +insert ( 5046 lcm 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "23 23" _null_ _null_ _null_ _null_ _null_ int4lcm _null_ _null_ _null_ ) +insert ( 5047 lcm 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 20" _null_ _null_ _null_ _null_ _null_ int8lcm _null_ _null_ _null_ ) +insert ( 944 char 11 10 12 1 0 0 0 f f f t f i s 1 0 18 25 _null_ _null_ _null_ _null_ _null_ text_char _null_ _null_ _null_ ) +insert ( 946 text 11 10 12 1 0 0 0 f f f t f i s 1 0 25 18 _null_ _null_ _null_ _null_ _null_ char_text _null_ _null_ _null_ ) +insert ( 952 lo_open 11 10 12 1 0 0 0 f f f t f v u 2 0 23 "26 23" _null_ _null_ _null_ _null_ _null_ be_lo_open _null_ _null_ _null_ ) +insert ( 953 lo_close 11 10 12 1 0 0 0 f f f t f v u 1 0 23 23 _null_ _null_ _null_ _null_ _null_ be_lo_close _null_ _null_ _null_ ) +insert ( 954 loread 11 10 12 1 0 0 0 f f f t f v u 2 0 17 "23 23" _null_ _null_ _null_ _null_ _null_ be_loread _null_ _null_ _null_ ) +insert ( 955 lowrite 11 10 12 1 0 0 0 f f f t f v u 2 0 23 "23 17" _null_ _null_ _null_ _null_ _null_ be_lowrite _null_ _null_ _null_ ) +insert ( 956 lo_lseek 11 10 12 1 0 0 0 f f f t f v u 3 0 23 "23 23 23" _null_ _null_ _null_ _null_ _null_ be_lo_lseek _null_ _null_ _null_ ) +insert ( 3170 lo_lseek64 11 10 12 1 0 0 0 f f f t f v u 3 0 20 "23 20 23" _null_ _null_ _null_ _null_ _null_ be_lo_lseek64 _null_ _null_ _null_ ) +insert ( 957 lo_creat 11 10 12 1 0 0 0 f f f t f v u 1 0 26 23 _null_ _null_ _null_ _null_ _null_ be_lo_creat _null_ _null_ _null_ ) +insert ( 715 lo_create 11 10 12 1 0 0 0 f f f t f v u 1 0 26 26 _null_ _null_ _null_ _null_ _null_ be_lo_create _null_ _null_ _null_ ) +insert ( 958 lo_tell 11 10 12 1 0 0 0 f f f t f v u 1 0 23 23 _null_ _null_ _null_ _null_ _null_ be_lo_tell _null_ _null_ _null_ ) +insert ( 3171 lo_tell64 11 10 12 1 0 0 0 f f f t f v u 1 0 20 23 _null_ _null_ _null_ _null_ _null_ be_lo_tell64 _null_ _null_ _null_ ) +insert ( 1004 lo_truncate 11 10 12 1 0 0 0 f f f t f v u 2 0 23 "23 23" _null_ _null_ _null_ _null_ _null_ be_lo_truncate _null_ _null_ _null_ ) +insert ( 3172 lo_truncate64 11 10 12 1 0 0 0 f f f t f v u 2 0 23 "23 20" _null_ _null_ _null_ _null_ _null_ be_lo_truncate64 _null_ _null_ _null_ ) +insert ( 3457 lo_from_bytea 11 10 12 1 0 0 0 f f f t f v u 2 0 26 "26 17" _null_ _null_ _null_ _null_ _null_ be_lo_from_bytea _null_ _null_ _null_ ) +insert ( 3458 lo_get 11 10 12 1 0 0 0 f f f t f v u 1 0 17 26 _null_ _null_ _null_ _null_ _null_ be_lo_get _null_ _null_ _null_ ) +insert ( 3459 lo_get 11 10 12 1 0 0 0 f f f t f v u 3 0 17 "26 20 23" _null_ _null_ _null_ _null_ _null_ be_lo_get_fragment _null_ _null_ _null_ ) +insert ( 3460 lo_put 11 10 12 1 0 0 0 f f f t f v u 3 0 2278 "26 20 17" _null_ _null_ _null_ _null_ _null_ be_lo_put _null_ _null_ _null_ ) +insert ( 959 on_pl 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "600 628" _null_ _null_ _null_ _null_ _null_ on_pl _null_ _null_ _null_ ) +insert ( 960 on_sl 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "601 628" _null_ _null_ _null_ _null_ _null_ on_sl _null_ _null_ _null_ ) +insert ( 961 close_pl 11 10 12 1 0 0 0 f f f t f i s 2 0 600 "600 628" _null_ _null_ _null_ _null_ _null_ close_pl _null_ _null_ _null_ ) +insert ( 962 close_sl 11 10 12 1 0 0 0 f f f t f i s 2 0 600 "601 628" _null_ _null_ _null_ _null_ _null_ close_sl _null_ _null_ _null_ ) +insert ( 963 close_lb 11 10 12 1 0 0 0 f f f t f i s 2 0 600 "628 603" _null_ _null_ _null_ _null_ _null_ close_lb _null_ _null_ _null_ ) +insert ( 964 lo_unlink 11 10 12 1 0 0 0 f f f t f v u 1 0 23 26 _null_ _null_ _null_ _null_ _null_ be_lo_unlink _null_ _null_ _null_ ) +insert ( 973 path_inter 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "602 602" _null_ _null_ _null_ _null_ _null_ path_inter _null_ _null_ _null_ ) +insert ( 975 area 11 10 12 1 0 0 0 f f f t f i s 1 0 701 603 _null_ _null_ _null_ _null_ _null_ box_area _null_ _null_ _null_ ) +insert ( 976 width 11 10 12 1 0 0 0 f f f t f i s 1 0 701 603 _null_ _null_ _null_ _null_ _null_ box_width _null_ _null_ _null_ ) +insert ( 977 height 11 10 12 1 0 0 0 f f f t f i s 1 0 701 603 _null_ _null_ _null_ _null_ _null_ box_height _null_ _null_ _null_ ) +insert ( 978 box_distance 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "603 603" _null_ _null_ _null_ _null_ _null_ box_distance _null_ _null_ _null_ ) +insert ( 979 area 11 10 12 1 0 0 0 f f f t f i s 1 0 701 602 _null_ _null_ _null_ _null_ _null_ path_area _null_ _null_ _null_ ) +insert ( 980 box_intersect 11 10 12 1 0 0 0 f f f t f i s 2 0 603 "603 603" _null_ _null_ _null_ _null_ _null_ box_intersect _null_ _null_ _null_ ) +insert ( 4067 bound_box 11 10 12 1 0 0 0 f f f t f i s 2 0 603 "603 603" _null_ _null_ _null_ _null_ _null_ boxes_bound_box _null_ _null_ _null_ ) +insert ( 981 diagonal 11 10 12 1 0 0 0 f f f t f i s 1 0 601 603 _null_ _null_ _null_ _null_ _null_ box_diagonal _null_ _null_ _null_ ) +insert ( 982 path_n_lt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "602 602" _null_ _null_ _null_ _null_ _null_ path_n_lt _null_ _null_ _null_ ) +insert ( 983 path_n_gt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "602 602" _null_ _null_ _null_ _null_ _null_ path_n_gt _null_ _null_ _null_ ) +insert ( 984 path_n_eq 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "602 602" _null_ _null_ _null_ _null_ _null_ path_n_eq _null_ _null_ _null_ ) +insert ( 985 path_n_le 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "602 602" _null_ _null_ _null_ _null_ _null_ path_n_le _null_ _null_ _null_ ) +insert ( 986 path_n_ge 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "602 602" _null_ _null_ _null_ _null_ _null_ path_n_ge _null_ _null_ _null_ ) +insert ( 987 path_length 11 10 12 1 0 0 0 f f f t f i s 1 0 701 602 _null_ _null_ _null_ _null_ _null_ path_length _null_ _null_ _null_ ) +insert ( 988 point_ne 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "600 600" _null_ _null_ _null_ _null_ _null_ point_ne _null_ _null_ _null_ ) +insert ( 989 point_vert 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "600 600" _null_ _null_ _null_ _null_ _null_ point_vert _null_ _null_ _null_ ) +insert ( 990 point_horiz 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "600 600" _null_ _null_ _null_ _null_ _null_ point_horiz _null_ _null_ _null_ ) +insert ( 991 point_distance 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "600 600" _null_ _null_ _null_ _null_ _null_ point_distance _null_ _null_ _null_ ) +insert ( 992 slope 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "600 600" _null_ _null_ _null_ _null_ _null_ point_slope _null_ _null_ _null_ ) +insert ( 993 lseg 11 10 12 1 0 0 0 f f f t f i s 2 0 601 "600 600" _null_ _null_ _null_ _null_ _null_ lseg_construct _null_ _null_ _null_ ) +insert ( 994 lseg_intersect 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "601 601" _null_ _null_ _null_ _null_ _null_ lseg_intersect _null_ _null_ _null_ ) +insert ( 995 lseg_parallel 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "601 601" _null_ _null_ _null_ _null_ _null_ lseg_parallel _null_ _null_ _null_ ) +insert ( 996 lseg_perp 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "601 601" _null_ _null_ _null_ _null_ _null_ lseg_perp _null_ _null_ _null_ ) +insert ( 997 lseg_vertical 11 10 12 1 0 0 0 f f f t f i s 1 0 16 601 _null_ _null_ _null_ _null_ _null_ lseg_vertical _null_ _null_ _null_ ) +insert ( 998 lseg_horizontal 11 10 12 1 0 0 0 f f f t f i s 1 0 16 601 _null_ _null_ _null_ _null_ _null_ lseg_horizontal _null_ _null_ _null_ ) +insert ( 999 lseg_eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "601 601" _null_ _null_ _null_ _null_ _null_ lseg_eq _null_ _null_ _null_ ) +insert ( 1026 timezone 11 10 12 1 0 0 0 f f f t f i s 2 0 1114 "1186 1184" _null_ _null_ _null_ _null_ _null_ timestamptz_izone _null_ _null_ _null_ ) +insert ( 1031 aclitemin 11 10 12 1 0 0 0 f f f t f s s 1 0 1033 2275 _null_ _null_ _null_ _null_ _null_ aclitemin _null_ _null_ _null_ ) +insert ( 1032 aclitemout 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 1033 _null_ _null_ _null_ _null_ _null_ aclitemout _null_ _null_ _null_ ) +insert ( 1035 aclinsert 11 10 12 1 0 0 0 f f f t f i s 2 0 1034 "1034 1033" _null_ _null_ _null_ _null_ _null_ aclinsert _null_ _null_ _null_ ) +insert ( 1036 aclremove 11 10 12 1 0 0 0 f f f t f i s 2 0 1034 "1034 1033" _null_ _null_ _null_ _null_ _null_ aclremove _null_ _null_ _null_ ) +insert ( 1037 aclcontains 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1034 1033" _null_ _null_ _null_ _null_ _null_ aclcontains _null_ _null_ _null_ ) +insert ( 1062 aclitemeq 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1033 1033" _null_ _null_ _null_ _null_ _null_ aclitem_eq _null_ _null_ _null_ ) +insert ( 1365 makeaclitem 11 10 12 1 0 0 0 f f f t f i s 4 0 1033 "26 26 25 16" _null_ _null_ _null_ _null_ _null_ makeaclitem _null_ _null_ _null_ ) +insert ( 3943 acldefault 11 10 12 1 0 0 0 f f f t f i s 2 0 1034 "18 26" _null_ _null_ _null_ _null_ _null_ acldefault_sql _null_ _null_ _null_ ) +insert ( 1689 aclexplode 11 10 12 1 10 0 0 f f f t t s s 1 0 2249 1034 "{1034,26,26,25,16}" "{i,o,o,o,o}" "{acl,grantor,grantee,privilege_type,is_grantable}" _null_ _null_ aclexplode _null_ _null_ _null_ ) +insert ( 1044 bpcharin 11 10 12 1 0 0 0 f f f t f i s 3 0 1042 "2275 26 23" _null_ _null_ _null_ _null_ _null_ bpcharin _null_ _null_ _null_ ) +insert ( 1045 bpcharout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 1042 _null_ _null_ _null_ _null_ _null_ bpcharout _null_ _null_ _null_ ) +insert ( 2913 bpchartypmodin 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1263 _null_ _null_ _null_ _null_ _null_ bpchartypmodin _null_ _null_ _null_ ) +insert ( 2914 bpchartypmodout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 23 _null_ _null_ _null_ _null_ _null_ bpchartypmodout _null_ _null_ _null_ ) +insert ( 1046 varcharin 11 10 12 1 0 0 0 f f f t f i s 3 0 1043 "2275 26 23" _null_ _null_ _null_ _null_ _null_ varcharin _null_ _null_ _null_ ) +insert ( 1047 varcharout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 1043 _null_ _null_ _null_ _null_ _null_ varcharout _null_ _null_ _null_ ) +insert ( 2915 varchartypmodin 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1263 _null_ _null_ _null_ _null_ _null_ varchartypmodin _null_ _null_ _null_ ) +insert ( 2916 varchartypmodout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 23 _null_ _null_ _null_ _null_ _null_ varchartypmodout _null_ _null_ _null_ ) +insert ( 1048 bpchareq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1042 1042" _null_ _null_ _null_ _null_ _null_ bpchareq _null_ _null_ _null_ ) +insert ( 1049 bpcharlt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1042 1042" _null_ _null_ _null_ _null_ _null_ bpcharlt _null_ _null_ _null_ ) +insert ( 1050 bpcharle 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1042 1042" _null_ _null_ _null_ _null_ _null_ bpcharle _null_ _null_ _null_ ) +insert ( 1051 bpchargt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1042 1042" _null_ _null_ _null_ _null_ _null_ bpchargt _null_ _null_ _null_ ) +insert ( 1052 bpcharge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1042 1042" _null_ _null_ _null_ _null_ _null_ bpcharge _null_ _null_ _null_ ) +insert ( 1053 bpcharne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1042 1042" _null_ _null_ _null_ _null_ _null_ bpcharne _null_ _null_ _null_ ) +insert ( 1063 bpchar_larger 11 10 12 1 0 0 0 f f t t f i s 2 0 1042 "1042 1042" _null_ _null_ _null_ _null_ _null_ bpchar_larger _null_ _null_ _null_ ) +insert ( 1064 bpchar_smaller 11 10 12 1 0 0 0 f f t t f i s 2 0 1042 "1042 1042" _null_ _null_ _null_ _null_ _null_ bpchar_smaller _null_ _null_ _null_ ) +insert ( 1078 bpcharcmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "1042 1042" _null_ _null_ _null_ _null_ _null_ bpcharcmp _null_ _null_ _null_ ) +insert ( 3328 bpchar_sortsupport 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ bpchar_sortsupport _null_ _null_ _null_ ) +insert ( 1080 hashbpchar 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1042 _null_ _null_ _null_ _null_ _null_ hashbpchar _null_ _null_ _null_ ) +insert ( 972 hashbpcharextended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "1042 20" _null_ _null_ _null_ _null_ _null_ hashbpcharextended _null_ _null_ _null_ ) +insert ( 1081 format_type 11 10 12 1 0 0 0 f f f f f s s 2 0 25 "26 23" _null_ _null_ _null_ _null_ _null_ format_type _null_ _null_ _null_ ) +insert ( 1084 date_in 11 10 12 1 0 0 0 f f f t f s s 1 0 1082 2275 _null_ _null_ _null_ _null_ _null_ date_in _null_ _null_ _null_ ) +insert ( 1085 date_out 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 1082 _null_ _null_ _null_ _null_ _null_ date_out _null_ _null_ _null_ ) +insert ( 1086 date_eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1082 1082" _null_ _null_ _null_ _null_ _null_ date_eq _null_ _null_ _null_ ) +insert ( 1087 date_lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1082 1082" _null_ _null_ _null_ _null_ _null_ date_lt _null_ _null_ _null_ ) +insert ( 1088 date_le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1082 1082" _null_ _null_ _null_ _null_ _null_ date_le _null_ _null_ _null_ ) +insert ( 1089 date_gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1082 1082" _null_ _null_ _null_ _null_ _null_ date_gt _null_ _null_ _null_ ) +insert ( 1090 date_ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1082 1082" _null_ _null_ _null_ _null_ _null_ date_ge _null_ _null_ _null_ ) +insert ( 1091 date_ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1082 1082" _null_ _null_ _null_ _null_ _null_ date_ne _null_ _null_ _null_ ) +insert ( 1092 date_cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "1082 1082" _null_ _null_ _null_ _null_ _null_ date_cmp _null_ _null_ _null_ ) +insert ( 3136 date_sortsupport 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ date_sortsupport _null_ _null_ _null_ ) +insert ( 4133 in_range 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "1082 1082 1186 16 16" _null_ _null_ _null_ _null_ _null_ in_range_date_interval _null_ _null_ _null_ ) +insert ( 1102 time_lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1083 1083" _null_ _null_ _null_ _null_ _null_ time_lt _null_ _null_ _null_ ) +insert ( 1103 time_le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1083 1083" _null_ _null_ _null_ _null_ _null_ time_le _null_ _null_ _null_ ) +insert ( 1104 time_gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1083 1083" _null_ _null_ _null_ _null_ _null_ time_gt _null_ _null_ _null_ ) +insert ( 1105 time_ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1083 1083" _null_ _null_ _null_ _null_ _null_ time_ge _null_ _null_ _null_ ) +insert ( 1106 time_ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1083 1083" _null_ _null_ _null_ _null_ _null_ time_ne _null_ _null_ _null_ ) +insert ( 1107 time_cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "1083 1083" _null_ _null_ _null_ _null_ _null_ time_cmp _null_ _null_ _null_ ) +insert ( 1138 date_larger 11 10 12 1 0 0 0 f f f t f i s 2 0 1082 "1082 1082" _null_ _null_ _null_ _null_ _null_ date_larger _null_ _null_ _null_ ) +insert ( 1139 date_smaller 11 10 12 1 0 0 0 f f f t f i s 2 0 1082 "1082 1082" _null_ _null_ _null_ _null_ _null_ date_smaller _null_ _null_ _null_ ) +insert ( 1140 date_mi 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "1082 1082" _null_ _null_ _null_ _null_ _null_ date_mi _null_ _null_ _null_ ) +insert ( 1141 date_pli 11 10 12 1 0 0 0 f f f t f i s 2 0 1082 "1082 23" _null_ _null_ _null_ _null_ _null_ date_pli _null_ _null_ _null_ ) +insert ( 1142 date_mii 11 10 12 1 0 0 0 f f f t f i s 2 0 1082 "1082 23" _null_ _null_ _null_ _null_ _null_ date_mii _null_ _null_ _null_ ) +insert ( 1143 time_in 11 10 12 1 0 0 0 f f f t f s s 3 0 1083 "2275 26 23" _null_ _null_ _null_ _null_ _null_ time_in _null_ _null_ _null_ ) +insert ( 1144 time_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 1083 _null_ _null_ _null_ _null_ _null_ time_out _null_ _null_ _null_ ) +insert ( 2909 timetypmodin 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1263 _null_ _null_ _null_ _null_ _null_ timetypmodin _null_ _null_ _null_ ) +insert ( 2910 timetypmodout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 23 _null_ _null_ _null_ _null_ _null_ timetypmodout _null_ _null_ _null_ ) +insert ( 1145 time_eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1083 1083" _null_ _null_ _null_ _null_ _null_ time_eq _null_ _null_ _null_ ) +insert ( 1146 circle_add_pt 11 10 12 1 0 0 0 f f f t f i s 2 0 718 "718 600" _null_ _null_ _null_ _null_ _null_ circle_add_pt _null_ _null_ _null_ ) +insert ( 1147 circle_sub_pt 11 10 12 1 0 0 0 f f f t f i s 2 0 718 "718 600" _null_ _null_ _null_ _null_ _null_ circle_sub_pt _null_ _null_ _null_ ) +insert ( 1148 circle_mul_pt 11 10 12 1 0 0 0 f f f t f i s 2 0 718 "718 600" _null_ _null_ _null_ _null_ _null_ circle_mul_pt _null_ _null_ _null_ ) +insert ( 1149 circle_div_pt 11 10 12 1 0 0 0 f f f t f i s 2 0 718 "718 600" _null_ _null_ _null_ _null_ _null_ circle_div_pt _null_ _null_ _null_ ) +insert ( 1150 timestamptz_in 11 10 12 1 0 0 0 f f f t f s s 3 0 1184 "2275 26 23" _null_ _null_ _null_ _null_ _null_ timestamptz_in _null_ _null_ _null_ ) +insert ( 1151 timestamptz_out 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 1184 _null_ _null_ _null_ _null_ _null_ timestamptz_out _null_ _null_ _null_ ) +insert ( 2907 timestamptztypmodin 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1263 _null_ _null_ _null_ _null_ _null_ timestamptztypmodin _null_ _null_ _null_ ) +insert ( 2908 timestamptztypmodout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 23 _null_ _null_ _null_ _null_ _null_ timestamptztypmodout _null_ _null_ _null_ ) +insert ( 1152 timestamptz_eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1184 1184" _null_ _null_ _null_ _null_ _null_ timestamp_eq _null_ _null_ _null_ ) +insert ( 1153 timestamptz_ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1184 1184" _null_ _null_ _null_ _null_ _null_ timestamp_ne _null_ _null_ _null_ ) +insert ( 1154 timestamptz_lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1184 1184" _null_ _null_ _null_ _null_ _null_ timestamp_lt _null_ _null_ _null_ ) +insert ( 1155 timestamptz_le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1184 1184" _null_ _null_ _null_ _null_ _null_ timestamp_le _null_ _null_ _null_ ) +insert ( 1156 timestamptz_ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1184 1184" _null_ _null_ _null_ _null_ _null_ timestamp_ge _null_ _null_ _null_ ) +insert ( 1157 timestamptz_gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1184 1184" _null_ _null_ _null_ _null_ _null_ timestamp_gt _null_ _null_ _null_ ) +insert ( 1158 to_timestamp 11 10 12 1 0 0 0 f f f t f i s 1 0 1184 701 _null_ _null_ _null_ _null_ _null_ float8_timestamptz _null_ _null_ _null_ ) +insert ( 1159 timezone 11 10 12 1 0 0 0 f f f t f i s 2 0 1114 "25 1184" _null_ _null_ _null_ _null_ _null_ timestamptz_zone _null_ _null_ _null_ ) +insert ( 1160 interval_in 11 10 12 1 0 0 0 f f f t f s s 3 0 1186 "2275 26 23" _null_ _null_ _null_ _null_ _null_ interval_in _null_ _null_ _null_ ) +insert ( 1161 interval_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 1186 _null_ _null_ _null_ _null_ _null_ interval_out _null_ _null_ _null_ ) +insert ( 2903 intervaltypmodin 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1263 _null_ _null_ _null_ _null_ _null_ intervaltypmodin _null_ _null_ _null_ ) +insert ( 2904 intervaltypmodout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 23 _null_ _null_ _null_ _null_ _null_ intervaltypmodout _null_ _null_ _null_ ) +insert ( 1162 interval_eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1186 1186" _null_ _null_ _null_ _null_ _null_ interval_eq _null_ _null_ _null_ ) +insert ( 1163 interval_ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1186 1186" _null_ _null_ _null_ _null_ _null_ interval_ne _null_ _null_ _null_ ) +insert ( 1164 interval_lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1186 1186" _null_ _null_ _null_ _null_ _null_ interval_lt _null_ _null_ _null_ ) +insert ( 1165 interval_le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1186 1186" _null_ _null_ _null_ _null_ _null_ interval_le _null_ _null_ _null_ ) +insert ( 1166 interval_ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1186 1186" _null_ _null_ _null_ _null_ _null_ interval_ge _null_ _null_ _null_ ) +insert ( 1167 interval_gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1186 1186" _null_ _null_ _null_ _null_ _null_ interval_gt _null_ _null_ _null_ ) +insert ( 1168 interval_um 11 10 12 1 0 0 0 f f f t f i s 1 0 1186 1186 _null_ _null_ _null_ _null_ _null_ interval_um _null_ _null_ _null_ ) +insert ( 1169 interval_pl 11 10 12 1 0 0 0 f f f t f i s 2 0 1186 "1186 1186" _null_ _null_ _null_ _null_ _null_ interval_pl _null_ _null_ _null_ ) +insert ( 1170 interval_mi 11 10 12 1 0 0 0 f f f t f i s 2 0 1186 "1186 1186" _null_ _null_ _null_ _null_ _null_ interval_mi _null_ _null_ _null_ ) +insert ( 1171 date_part 11 10 12 1 0 0 0 f f f t f s s 2 0 701 "25 1184" _null_ _null_ _null_ _null_ _null_ timestamptz_part _null_ _null_ _null_ ) +insert ( 1172 date_part 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "25 1186" _null_ _null_ _null_ _null_ _null_ interval_part _null_ _null_ _null_ ) +insert ( 1174 timestamptz 11 10 12 1 0 0 0 f f f t f s s 1 0 1184 1082 _null_ _null_ _null_ _null_ _null_ date_timestamptz _null_ _null_ _null_ ) +insert ( 2711 justify_interval 11 10 12 1 0 0 0 f f f t f i s 1 0 1186 1186 _null_ _null_ _null_ _null_ _null_ interval_justify_interval _null_ _null_ _null_ ) +insert ( 1175 justify_hours 11 10 12 1 0 0 0 f f f t f i s 1 0 1186 1186 _null_ _null_ _null_ _null_ _null_ interval_justify_hours _null_ _null_ _null_ ) +insert ( 1295 justify_days 11 10 12 1 0 0 0 f f f t f i s 1 0 1186 1186 _null_ _null_ _null_ _null_ _null_ interval_justify_days _null_ _null_ _null_ ) +insert ( 1176 timestamptz 11 10 14 1 0 0 0 f f f t f s s 2 0 1184 "1082 1083" _null_ _null_ _null_ _null_ _null_ "select cast(($1 + $2) as timestamp with time zone)" _null_ _null_ _null_ ) +insert ( 1178 date 11 10 12 1 0 0 0 f f f t f s s 1 0 1082 1184 _null_ _null_ _null_ _null_ _null_ timestamptz_date _null_ _null_ _null_ ) +insert ( 1181 age 11 10 12 1 0 0 0 f f f t f s r 1 0 23 28 _null_ _null_ _null_ _null_ _null_ xid_age _null_ _null_ _null_ ) +insert ( 3939 mxid_age 11 10 12 1 0 0 0 f f f t f s s 1 0 23 28 _null_ _null_ _null_ _null_ _null_ mxid_age _null_ _null_ _null_ ) +insert ( 1188 timestamptz_mi 11 10 12 1 0 0 0 f f f t f i s 2 0 1186 "1184 1184" _null_ _null_ _null_ _null_ _null_ timestamp_mi _null_ _null_ _null_ ) +insert ( 1189 timestamptz_pl_interval 11 10 12 1 0 0 0 f f f t f s s 2 0 1184 "1184 1186" _null_ _null_ _null_ _null_ _null_ timestamptz_pl_interval _null_ _null_ _null_ ) +insert ( 1190 timestamptz_mi_interval 11 10 12 1 0 0 0 f f f t f s s 2 0 1184 "1184 1186" _null_ _null_ _null_ _null_ _null_ timestamptz_mi_interval _null_ _null_ _null_ ) +insert ( 1195 timestamptz_smaller 11 10 12 1 0 0 0 f f f t f i s 2 0 1184 "1184 1184" _null_ _null_ _null_ _null_ _null_ timestamp_smaller _null_ _null_ _null_ ) +insert ( 1196 timestamptz_larger 11 10 12 1 0 0 0 f f f t f i s 2 0 1184 "1184 1184" _null_ _null_ _null_ _null_ _null_ timestamp_larger _null_ _null_ _null_ ) +insert ( 1197 interval_smaller 11 10 12 1 0 0 0 f f f t f i s 2 0 1186 "1186 1186" _null_ _null_ _null_ _null_ _null_ interval_smaller _null_ _null_ _null_ ) +insert ( 1198 interval_larger 11 10 12 1 0 0 0 f f f t f i s 2 0 1186 "1186 1186" _null_ _null_ _null_ _null_ _null_ interval_larger _null_ _null_ _null_ ) +insert ( 1199 age 11 10 12 1 0 0 0 f f f t f i s 2 0 1186 "1184 1184" _null_ _null_ _null_ _null_ _null_ timestamptz_age _null_ _null_ _null_ ) +insert ( 3918 interval_support 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ interval_support _null_ _null_ _null_ ) +insert ( 1200 interval 11 10 12 1 0 0 3918 f f f t f i s 2 0 1186 "1186 23" _null_ _null_ _null_ _null_ _null_ interval_scale _null_ _null_ _null_ ) +insert ( 1215 obj_description 11 10 14 100 0 0 0 f f f t f s s 2 0 25 "26 19" _null_ _null_ _null_ _null_ _null_ "select description from pg_catalog.pg_description where objoid = $1 and classoid = (select oid from pg_catalog.pg_class where relname = $2 and relnamespace = 11) and objsubid = 0" _null_ _null_ _null_ ) +insert ( 1216 col_description 11 10 14 100 0 0 0 f f f t f s s 2 0 25 "26 23" _null_ _null_ _null_ _null_ _null_ "select description from pg_catalog.pg_description where objoid = $1 and classoid = ''pg_catalog.pg_class''::pg_catalog.regclass and objsubid = $2" _null_ _null_ _null_ ) +insert ( 1993 shobj_description 11 10 14 100 0 0 0 f f f t f s s 2 0 25 "26 19" _null_ _null_ _null_ _null_ _null_ "select description from pg_catalog.pg_shdescription where objoid = $1 and classoid = (select oid from pg_catalog.pg_class where relname = $2 and relnamespace = 11)" _null_ _null_ _null_ ) +insert ( 1217 date_trunc 11 10 12 1 0 0 0 f f f t f s s 2 0 1184 "25 1184" _null_ _null_ _null_ _null_ _null_ timestamptz_trunc _null_ _null_ _null_ ) +insert ( 1284 date_trunc 11 10 12 1 0 0 0 f f f t f s s 3 0 1184 "25 1184 25" _null_ _null_ _null_ _null_ _null_ timestamptz_trunc_zone _null_ _null_ _null_ ) +insert ( 1218 date_trunc 11 10 12 1 0 0 0 f f f t f i s 2 0 1186 "25 1186" _null_ _null_ _null_ _null_ _null_ interval_trunc _null_ _null_ _null_ ) +insert ( 1219 int8inc 11 10 12 1 0 0 0 f f f t f i s 1 0 20 20 _null_ _null_ _null_ _null_ _null_ int8inc _null_ _null_ _null_ ) +insert ( 3546 int8dec 11 10 12 1 0 0 0 f f f t f i s 1 0 20 20 _null_ _null_ _null_ _null_ _null_ int8dec _null_ _null_ _null_ ) +insert ( 2804 int8inc_any 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 2276" _null_ _null_ _null_ _null_ _null_ int8inc_any _null_ _null_ _null_ ) +insert ( 3547 int8dec_any 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 2276" _null_ _null_ _null_ _null_ _null_ int8dec_any _null_ _null_ _null_ ) +insert ( 1230 int8abs 11 10 12 1 0 0 0 f f f t f i s 1 0 20 20 _null_ _null_ _null_ _null_ _null_ int8abs _null_ _null_ _null_ ) +insert ( 1236 int8larger 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 20" _null_ _null_ _null_ _null_ _null_ int8larger _null_ _null_ _null_ ) +insert ( 1237 int8smaller 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 20" _null_ _null_ _null_ _null_ _null_ int8smaller _null_ _null_ _null_ ) +insert ( 1238 texticregexeq 11 10 12 1 0 0 1024 f f f t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ texticregexeq _null_ _null_ _null_ ) +insert ( 1024 texticregexeq_support 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ texticregexeq_support _null_ _null_ _null_ ) +insert ( 1239 texticregexne 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ texticregexne _null_ _null_ _null_ ) +insert ( 1240 nameicregexeq 11 10 12 1 0 0 1024 f f f t f i s 2 0 16 "19 25" _null_ _null_ _null_ _null_ _null_ nameicregexeq _null_ _null_ _null_ ) +insert ( 1241 nameicregexne 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "19 25" _null_ _null_ _null_ _null_ _null_ nameicregexne _null_ _null_ _null_ ) +insert ( 1251 int4abs 11 10 12 1 0 0 0 f f f t f i s 1 0 23 23 _null_ _null_ _null_ _null_ _null_ int4abs _null_ _null_ _null_ ) +insert ( 1253 int2abs 11 10 12 1 0 0 0 f f f t f i s 1 0 21 21 _null_ _null_ _null_ _null_ _null_ int2abs _null_ _null_ _null_ ) +insert ( 1271 overlaps 11 10 12 1 0 0 0 f f f f f i s 4 0 16 "1266 1266 1266 1266" _null_ _null_ _null_ _null_ _null_ overlaps_timetz _null_ _null_ _null_ ) +insert ( 1272 datetime_pl 11 10 12 1 0 0 0 f f f t f i s 2 0 1114 "1082 1083" _null_ _null_ _null_ _null_ _null_ datetime_timestamp _null_ _null_ _null_ ) +insert ( 1273 date_part 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "25 1266" _null_ _null_ _null_ _null_ _null_ timetz_part _null_ _null_ _null_ ) +insert ( 1274 int84pl 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 23" _null_ _null_ _null_ _null_ _null_ int84pl _null_ _null_ _null_ ) +insert ( 1275 int84mi 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 23" _null_ _null_ _null_ _null_ _null_ int84mi _null_ _null_ _null_ ) +insert ( 1276 int84mul 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 23" _null_ _null_ _null_ _null_ _null_ int84mul _null_ _null_ _null_ ) +insert ( 1277 int84div 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 23" _null_ _null_ _null_ _null_ _null_ int84div _null_ _null_ _null_ ) +insert ( 1278 int48pl 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "23 20" _null_ _null_ _null_ _null_ _null_ int48pl _null_ _null_ _null_ ) +insert ( 1279 int48mi 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "23 20" _null_ _null_ _null_ _null_ _null_ int48mi _null_ _null_ _null_ ) +insert ( 1280 int48mul 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "23 20" _null_ _null_ _null_ _null_ _null_ int48mul _null_ _null_ _null_ ) +insert ( 1281 int48div 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "23 20" _null_ _null_ _null_ _null_ _null_ int48div _null_ _null_ _null_ ) +insert ( 837 int82pl 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 21" _null_ _null_ _null_ _null_ _null_ int82pl _null_ _null_ _null_ ) +insert ( 838 int82mi 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 21" _null_ _null_ _null_ _null_ _null_ int82mi _null_ _null_ _null_ ) +insert ( 839 int82mul 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 21" _null_ _null_ _null_ _null_ _null_ int82mul _null_ _null_ _null_ ) +insert ( 840 int82div 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 21" _null_ _null_ _null_ _null_ _null_ int82div _null_ _null_ _null_ ) +insert ( 841 int28pl 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "21 20" _null_ _null_ _null_ _null_ _null_ int28pl _null_ _null_ _null_ ) +insert ( 942 int28mi 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "21 20" _null_ _null_ _null_ _null_ _null_ int28mi _null_ _null_ _null_ ) +insert ( 943 int28mul 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "21 20" _null_ _null_ _null_ _null_ _null_ int28mul _null_ _null_ _null_ ) +insert ( 948 int28div 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "21 20" _null_ _null_ _null_ _null_ _null_ int28div _null_ _null_ _null_ ) +insert ( 1287 oid 11 10 12 1 0 0 0 f f f t f i s 1 0 26 20 _null_ _null_ _null_ _null_ _null_ i8tooid _null_ _null_ _null_ ) +insert ( 1288 int8 11 10 12 1 0 0 0 f f f t f i s 1 0 20 26 _null_ _null_ _null_ _null_ _null_ oidtoi8 _null_ _null_ _null_ ) +insert ( 1291 suppress_redundant_updates_trigger 11 10 12 1 0 0 0 f f f t f v s 0 0 2279 "" _null_ _null_ _null_ _null_ _null_ suppress_redundant_updates_trigger _null_ _null_ _null_ ) +insert ( 1292 tideq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "27 27" _null_ _null_ _null_ _null_ _null_ tideq _null_ _null_ _null_ ) +insert ( 1293 currtid 11 10 12 1 0 0 0 f f f t f v u 2 0 27 "26 27" _null_ _null_ _null_ _null_ _null_ currtid_byreloid _null_ _null_ _null_ ) +insert ( 1294 currtid2 11 10 12 1 0 0 0 f f f t f v u 2 0 27 "25 27" _null_ _null_ _null_ _null_ _null_ currtid_byrelname _null_ _null_ _null_ ) +insert ( 1265 tidne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "27 27" _null_ _null_ _null_ _null_ _null_ tidne _null_ _null_ _null_ ) +insert ( 2790 tidgt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "27 27" _null_ _null_ _null_ _null_ _null_ tidgt _null_ _null_ _null_ ) +insert ( 2791 tidlt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "27 27" _null_ _null_ _null_ _null_ _null_ tidlt _null_ _null_ _null_ ) +insert ( 2792 tidge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "27 27" _null_ _null_ _null_ _null_ _null_ tidge _null_ _null_ _null_ ) +insert ( 2793 tidle 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "27 27" _null_ _null_ _null_ _null_ _null_ tidle _null_ _null_ _null_ ) +insert ( 2794 bttidcmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "27 27" _null_ _null_ _null_ _null_ _null_ bttidcmp _null_ _null_ _null_ ) +insert ( 2795 tidlarger 11 10 12 1 0 0 0 f f f t f i s 2 0 27 "27 27" _null_ _null_ _null_ _null_ _null_ tidlarger _null_ _null_ _null_ ) +insert ( 2796 tidsmaller 11 10 12 1 0 0 0 f f f t f i s 2 0 27 "27 27" _null_ _null_ _null_ _null_ _null_ tidsmaller _null_ _null_ _null_ ) +insert ( 2233 hashtid 11 10 12 1 0 0 0 f f f t f i s 1 0 23 27 _null_ _null_ _null_ _null_ _null_ hashtid _null_ _null_ _null_ ) +insert ( 2234 hashtidextended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "27 20" _null_ _null_ _null_ _null_ _null_ hashtidextended _null_ _null_ _null_ ) +insert ( 1296 timedate_pl 11 10 14 1 0 0 0 f f f t f i s 2 0 1114 "1083 1082" _null_ _null_ _null_ _null_ _null_ "select ($2 + $1)" _null_ _null_ _null_ ) +insert ( 1297 datetimetz_pl 11 10 12 1 0 0 0 f f f t f i s 2 0 1184 "1082 1266" _null_ _null_ _null_ _null_ _null_ datetimetz_timestamptz _null_ _null_ _null_ ) +insert ( 1298 timetzdate_pl 11 10 14 1 0 0 0 f f f t f i s 2 0 1184 "1266 1082" _null_ _null_ _null_ _null_ _null_ "select ($2 + $1)" _null_ _null_ _null_ ) +insert ( 1299 now 11 10 12 1 0 0 0 f f f t f s s 0 0 1184 "" _null_ _null_ _null_ _null_ _null_ now _null_ _null_ _null_ ) +insert ( 2647 transaction_timestamp 11 10 12 1 0 0 0 f f f t f s s 0 0 1184 "" _null_ _null_ _null_ _null_ _null_ now _null_ _null_ _null_ ) +insert ( 2648 statement_timestamp 11 10 12 1 0 0 0 f f f t f s s 0 0 1184 "" _null_ _null_ _null_ _null_ _null_ statement_timestamp _null_ _null_ _null_ ) +insert ( 2649 clock_timestamp 11 10 12 1 0 0 0 f f f t f v s 0 0 1184 "" _null_ _null_ _null_ _null_ _null_ clock_timestamp _null_ _null_ _null_ ) +insert ( 1300 positionsel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ positionsel _null_ _null_ _null_ ) +insert ( 1301 positionjoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ positionjoinsel _null_ _null_ _null_ ) +insert ( 1302 contsel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ contsel _null_ _null_ _null_ ) +insert ( 1303 contjoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ contjoinsel _null_ _null_ _null_ ) +insert ( 1304 overlaps 11 10 12 1 0 0 0 f f f f f i s 4 0 16 "1184 1184 1184 1184" _null_ _null_ _null_ _null_ _null_ overlaps_timestamp _null_ _null_ _null_ ) +insert ( 1305 overlaps 11 10 14 1 0 0 0 f f f f f s s 4 0 16 "1184 1186 1184 1186" _null_ _null_ _null_ _null_ _null_ "select ($1, ($1 + $2)) overlaps ($3, ($3 + $4))" _null_ _null_ _null_ ) +insert ( 1306 overlaps 11 10 14 1 0 0 0 f f f f f s s 4 0 16 "1184 1184 1184 1186" _null_ _null_ _null_ _null_ _null_ "select ($1, $2) overlaps ($3, ($3 + $4))" _null_ _null_ _null_ ) +insert ( 1307 overlaps 11 10 14 1 0 0 0 f f f f f s s 4 0 16 "1184 1186 1184 1184" _null_ _null_ _null_ _null_ _null_ "select ($1, ($1 + $2)) overlaps ($3, $4)" _null_ _null_ _null_ ) +insert ( 1308 overlaps 11 10 12 1 0 0 0 f f f f f i s 4 0 16 "1083 1083 1083 1083" _null_ _null_ _null_ _null_ _null_ overlaps_time _null_ _null_ _null_ ) +insert ( 1309 overlaps 11 10 14 1 0 0 0 f f f f f i s 4 0 16 "1083 1186 1083 1186" _null_ _null_ _null_ _null_ _null_ "select ($1, ($1 + $2)) overlaps ($3, ($3 + $4))" _null_ _null_ _null_ ) +insert ( 1310 overlaps 11 10 14 1 0 0 0 f f f f f i s 4 0 16 "1083 1083 1083 1186" _null_ _null_ _null_ _null_ _null_ "select ($1, $2) overlaps ($3, ($3 + $4))" _null_ _null_ _null_ ) +insert ( 1311 overlaps 11 10 14 1 0 0 0 f f f f f i s 4 0 16 "1083 1186 1083 1083" _null_ _null_ _null_ _null_ _null_ "select ($1, ($1 + $2)) overlaps ($3, $4)" _null_ _null_ _null_ ) +insert ( 1312 timestamp_in 11 10 12 1 0 0 0 f f f t f s s 3 0 1114 "2275 26 23" _null_ _null_ _null_ _null_ _null_ timestamp_in _null_ _null_ _null_ ) +insert ( 1313 timestamp_out 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 1114 _null_ _null_ _null_ _null_ _null_ timestamp_out _null_ _null_ _null_ ) +insert ( 2905 timestamptypmodin 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1263 _null_ _null_ _null_ _null_ _null_ timestamptypmodin _null_ _null_ _null_ ) +insert ( 2906 timestamptypmodout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 23 _null_ _null_ _null_ _null_ _null_ timestamptypmodout _null_ _null_ _null_ ) +insert ( 1314 timestamptz_cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "1184 1184" _null_ _null_ _null_ _null_ _null_ timestamp_cmp _null_ _null_ _null_ ) +insert ( 1315 interval_cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "1186 1186" _null_ _null_ _null_ _null_ _null_ interval_cmp _null_ _null_ _null_ ) +insert ( 1316 time 11 10 12 1 0 0 0 f f f t f i s 1 0 1083 1114 _null_ _null_ _null_ _null_ _null_ timestamp_time _null_ _null_ _null_ ) +insert ( 1317 length 11 10 12 1 0 0 0 f f f t f i s 1 0 23 25 _null_ _null_ _null_ _null_ _null_ textlen _null_ _null_ _null_ ) +insert ( 1318 length 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1042 _null_ _null_ _null_ _null_ _null_ bpcharlen _null_ _null_ _null_ ) +insert ( 1319 xideqint4 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "28 23" _null_ _null_ _null_ _null_ _null_ xideq _null_ _null_ _null_ ) +insert ( 3309 xidneqint4 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "28 23" _null_ _null_ _null_ _null_ _null_ xidneq _null_ _null_ _null_ ) +insert ( 1326 interval_div 11 10 12 1 0 0 0 f f f t f i s 2 0 1186 "1186 701" _null_ _null_ _null_ _null_ _null_ interval_div _null_ _null_ _null_ ) +insert ( 1339 dlog10 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dlog10 _null_ _null_ _null_ ) +insert ( 1340 log 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dlog10 _null_ _null_ _null_ ) +insert ( 1194 log10 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dlog10 _null_ _null_ _null_ ) +insert ( 1341 ln 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dlog1 _null_ _null_ _null_ ) +insert ( 1342 round 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dround _null_ _null_ _null_ ) +insert ( 1343 trunc 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dtrunc _null_ _null_ _null_ ) +insert ( 1344 sqrt 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dsqrt _null_ _null_ _null_ ) +insert ( 1345 cbrt 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dcbrt _null_ _null_ _null_ ) +insert ( 1346 pow 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ dpow _null_ _null_ _null_ ) +insert ( 1368 power 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ dpow _null_ _null_ _null_ ) +insert ( 1347 exp 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dexp _null_ _null_ _null_ ) +insert ( 1348 obj_description 11 10 14 100 0 0 0 f f f t f s s 1 0 25 26 _null_ _null_ _null_ _null_ _null_ "select description from pg_catalog.pg_description where objoid = $1 and objsubid = 0" _null_ _null_ _null_ ) +insert ( 1349 oidvectortypes 11 10 12 1 0 0 0 f f f t f s s 1 0 25 30 _null_ _null_ _null_ _null_ _null_ oidvectortypes _null_ _null_ _null_ ) +insert ( 1350 timetz_in 11 10 12 1 0 0 0 f f f t f s s 3 0 1266 "2275 26 23" _null_ _null_ _null_ _null_ _null_ timetz_in _null_ _null_ _null_ ) +insert ( 1351 timetz_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 1266 _null_ _null_ _null_ _null_ _null_ timetz_out _null_ _null_ _null_ ) +insert ( 2911 timetztypmodin 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1263 _null_ _null_ _null_ _null_ _null_ timetztypmodin _null_ _null_ _null_ ) +insert ( 2912 timetztypmodout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 23 _null_ _null_ _null_ _null_ _null_ timetztypmodout _null_ _null_ _null_ ) +insert ( 1352 timetz_eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1266 1266" _null_ _null_ _null_ _null_ _null_ timetz_eq _null_ _null_ _null_ ) +insert ( 1353 timetz_ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1266 1266" _null_ _null_ _null_ _null_ _null_ timetz_ne _null_ _null_ _null_ ) +insert ( 1354 timetz_lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1266 1266" _null_ _null_ _null_ _null_ _null_ timetz_lt _null_ _null_ _null_ ) +insert ( 1355 timetz_le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1266 1266" _null_ _null_ _null_ _null_ _null_ timetz_le _null_ _null_ _null_ ) +insert ( 1356 timetz_ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1266 1266" _null_ _null_ _null_ _null_ _null_ timetz_ge _null_ _null_ _null_ ) +insert ( 1357 timetz_gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1266 1266" _null_ _null_ _null_ _null_ _null_ timetz_gt _null_ _null_ _null_ ) +insert ( 1358 timetz_cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "1266 1266" _null_ _null_ _null_ _null_ _null_ timetz_cmp _null_ _null_ _null_ ) +insert ( 1359 timestamptz 11 10 12 1 0 0 0 f f f t f i s 2 0 1184 "1082 1266" _null_ _null_ _null_ _null_ _null_ datetimetz_timestamptz _null_ _null_ _null_ ) +insert ( 1367 character_length 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1042 _null_ _null_ _null_ _null_ _null_ bpcharlen _null_ _null_ _null_ ) +insert ( 1369 character_length 11 10 12 1 0 0 0 f f f t f i s 1 0 23 25 _null_ _null_ _null_ _null_ _null_ textlen _null_ _null_ _null_ ) +insert ( 1370 interval 11 10 12 1 0 0 0 f f f t f i s 1 0 1186 1083 _null_ _null_ _null_ _null_ _null_ time_interval _null_ _null_ _null_ ) +insert ( 1372 char_length 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1042 _null_ _null_ _null_ _null_ _null_ bpcharlen _null_ _null_ _null_ ) +insert ( 1374 octet_length 11 10 12 1 0 0 0 f f f t f i s 1 0 23 25 _null_ _null_ _null_ _null_ _null_ textoctetlen _null_ _null_ _null_ ) +insert ( 1375 octet_length 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1042 _null_ _null_ _null_ _null_ _null_ bpcharoctetlen _null_ _null_ _null_ ) +insert ( 1377 time_larger 11 10 12 1 0 0 0 f f f t f i s 2 0 1083 "1083 1083" _null_ _null_ _null_ _null_ _null_ time_larger _null_ _null_ _null_ ) +insert ( 1378 time_smaller 11 10 12 1 0 0 0 f f f t f i s 2 0 1083 "1083 1083" _null_ _null_ _null_ _null_ _null_ time_smaller _null_ _null_ _null_ ) +insert ( 1379 timetz_larger 11 10 12 1 0 0 0 f f f t f i s 2 0 1266 "1266 1266" _null_ _null_ _null_ _null_ _null_ timetz_larger _null_ _null_ _null_ ) +insert ( 1380 timetz_smaller 11 10 12 1 0 0 0 f f f t f i s 2 0 1266 "1266 1266" _null_ _null_ _null_ _null_ _null_ timetz_smaller _null_ _null_ _null_ ) +insert ( 1381 char_length 11 10 12 1 0 0 0 f f f t f i s 1 0 23 25 _null_ _null_ _null_ _null_ _null_ textlen _null_ _null_ _null_ ) +insert ( 1384 date_part 11 10 14 1 0 0 0 f f f t f i s 2 0 701 "25 1082" _null_ _null_ _null_ _null_ _null_ "select pg_catalog.date_part($1, cast($2 as timestamp without time zone))" _null_ _null_ _null_ ) +insert ( 1385 date_part 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "25 1083" _null_ _null_ _null_ _null_ _null_ time_part _null_ _null_ _null_ ) +insert ( 1386 age 11 10 14 1 0 0 0 f f f t f s s 1 0 1186 1184 _null_ _null_ _null_ _null_ _null_ "select pg_catalog.age(cast(current_date as timestamp with time zone), $1)" _null_ _null_ _null_ ) +insert ( 1388 timetz 11 10 12 1 0 0 0 f f f t f s s 1 0 1266 1184 _null_ _null_ _null_ _null_ _null_ timestamptz_timetz _null_ _null_ _null_ ) +insert ( 1373 isfinite 11 10 12 1 0 0 0 f f f t f i s 1 0 16 1082 _null_ _null_ _null_ _null_ _null_ date_finite _null_ _null_ _null_ ) +insert ( 1389 isfinite 11 10 12 1 0 0 0 f f f t f i s 1 0 16 1184 _null_ _null_ _null_ _null_ _null_ timestamp_finite _null_ _null_ _null_ ) +insert ( 1390 isfinite 11 10 12 1 0 0 0 f f f t f i s 1 0 16 1186 _null_ _null_ _null_ _null_ _null_ interval_finite _null_ _null_ _null_ ) +insert ( 1376 factorial 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 20 _null_ _null_ _null_ _null_ _null_ numeric_fac _null_ _null_ _null_ ) +insert ( 1394 abs 11 10 12 1 0 0 0 f f f t f i s 1 0 700 700 _null_ _null_ _null_ _null_ _null_ float4abs _null_ _null_ _null_ ) +insert ( 1395 abs 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ float8abs _null_ _null_ _null_ ) +insert ( 1396 abs 11 10 12 1 0 0 0 f f f t f i s 1 0 20 20 _null_ _null_ _null_ _null_ _null_ int8abs _null_ _null_ _null_ ) +insert ( 1397 abs 11 10 12 1 0 0 0 f f f t f i s 1 0 23 23 _null_ _null_ _null_ _null_ _null_ int4abs _null_ _null_ _null_ ) +insert ( 1398 abs 11 10 12 1 0 0 0 f f f t f i s 1 0 21 21 _null_ _null_ _null_ _null_ _null_ int2abs _null_ _null_ _null_ ) +insert ( 1400 name 11 10 12 1 0 0 0 f f f t f i s 1 0 19 1043 _null_ _null_ _null_ _null_ _null_ text_name _null_ _null_ _null_ ) +insert ( 1401 varchar 11 10 12 1 0 0 0 f f f t f i s 1 0 1043 19 _null_ _null_ _null_ _null_ _null_ name_text _null_ _null_ _null_ ) +insert ( 1402 current_schema 11 10 12 1 0 0 0 f f f t f s u 0 0 19 "" _null_ _null_ _null_ _null_ _null_ current_schema _null_ _null_ _null_ ) +insert ( 1403 current_schemas 11 10 12 1 0 0 0 f f f t f s u 1 0 1003 16 _null_ _null_ _null_ _null_ _null_ current_schemas _null_ _null_ _null_ ) +insert ( 1404 overlay 11 10 12 1 0 0 0 f f f t f i s 4 0 25 "25 25 23 23" _null_ _null_ _null_ _null_ _null_ textoverlay _null_ _null_ _null_ ) +insert ( 1405 overlay 11 10 12 1 0 0 0 f f f t f i s 3 0 25 "25 25 23" _null_ _null_ _null_ _null_ _null_ textoverlay_no_len _null_ _null_ _null_ ) +insert ( 1406 isvertical 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "600 600" _null_ _null_ _null_ _null_ _null_ point_vert _null_ _null_ _null_ ) +insert ( 1407 ishorizontal 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "600 600" _null_ _null_ _null_ _null_ _null_ point_horiz _null_ _null_ _null_ ) +insert ( 1408 isparallel 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "601 601" _null_ _null_ _null_ _null_ _null_ lseg_parallel _null_ _null_ _null_ ) +insert ( 1409 isperp 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "601 601" _null_ _null_ _null_ _null_ _null_ lseg_perp _null_ _null_ _null_ ) +insert ( 1410 isvertical 11 10 12 1 0 0 0 f f f t f i s 1 0 16 601 _null_ _null_ _null_ _null_ _null_ lseg_vertical _null_ _null_ _null_ ) +insert ( 1411 ishorizontal 11 10 12 1 0 0 0 f f f t f i s 1 0 16 601 _null_ _null_ _null_ _null_ _null_ lseg_horizontal _null_ _null_ _null_ ) +insert ( 1412 isparallel 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "628 628" _null_ _null_ _null_ _null_ _null_ line_parallel _null_ _null_ _null_ ) +insert ( 1413 isperp 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "628 628" _null_ _null_ _null_ _null_ _null_ line_perp _null_ _null_ _null_ ) +insert ( 1414 isvertical 11 10 12 1 0 0 0 f f f t f i s 1 0 16 628 _null_ _null_ _null_ _null_ _null_ line_vertical _null_ _null_ _null_ ) +insert ( 1415 ishorizontal 11 10 12 1 0 0 0 f f f t f i s 1 0 16 628 _null_ _null_ _null_ _null_ _null_ line_horizontal _null_ _null_ _null_ ) +insert ( 1416 point 11 10 12 1 0 0 0 f f f t f i s 1 0 600 718 _null_ _null_ _null_ _null_ _null_ circle_center _null_ _null_ _null_ ) +insert ( 1419 time 11 10 12 1 0 0 0 f f f t f i s 1 0 1083 1186 _null_ _null_ _null_ _null_ _null_ interval_time _null_ _null_ _null_ ) +insert ( 1421 box 11 10 12 1 0 0 0 f f f t f i s 2 0 603 "600 600" _null_ _null_ _null_ _null_ _null_ points_box _null_ _null_ _null_ ) +insert ( 1422 box_add 11 10 12 1 0 0 0 f f f t f i s 2 0 603 "603 600" _null_ _null_ _null_ _null_ _null_ box_add _null_ _null_ _null_ ) +insert ( 1423 box_sub 11 10 12 1 0 0 0 f f f t f i s 2 0 603 "603 600" _null_ _null_ _null_ _null_ _null_ box_sub _null_ _null_ _null_ ) +insert ( 1424 box_mul 11 10 12 1 0 0 0 f f f t f i s 2 0 603 "603 600" _null_ _null_ _null_ _null_ _null_ box_mul _null_ _null_ _null_ ) +insert ( 1425 box_div 11 10 12 1 0 0 0 f f f t f i s 2 0 603 "603 600" _null_ _null_ _null_ _null_ _null_ box_div _null_ _null_ _null_ ) +insert ( 1426 path_contain_pt 11 10 14 1 0 0 0 f f f t f i s 2 0 16 "602 600" _null_ _null_ _null_ _null_ _null_ "select pg_catalog.on_ppath($2, $1)" _null_ _null_ _null_ ) +insert ( 1428 poly_contain_pt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "604 600" _null_ _null_ _null_ _null_ _null_ poly_contain_pt _null_ _null_ _null_ ) +insert ( 1429 pt_contained_poly 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "600 604" _null_ _null_ _null_ _null_ _null_ pt_contained_poly _null_ _null_ _null_ ) +insert ( 1430 isclosed 11 10 12 1 0 0 0 f f f t f i s 1 0 16 602 _null_ _null_ _null_ _null_ _null_ path_isclosed _null_ _null_ _null_ ) +insert ( 1431 isopen 11 10 12 1 0 0 0 f f f t f i s 1 0 16 602 _null_ _null_ _null_ _null_ _null_ path_isopen _null_ _null_ _null_ ) +insert ( 1432 path_npoints 11 10 12 1 0 0 0 f f f t f i s 1 0 23 602 _null_ _null_ _null_ _null_ _null_ path_npoints _null_ _null_ _null_ ) +insert ( 1433 pclose 11 10 12 1 0 0 0 f f f t f i s 1 0 602 602 _null_ _null_ _null_ _null_ _null_ path_close _null_ _null_ _null_ ) +insert ( 1434 popen 11 10 12 1 0 0 0 f f f t f i s 1 0 602 602 _null_ _null_ _null_ _null_ _null_ path_open _null_ _null_ _null_ ) +insert ( 1435 path_add 11 10 12 1 0 0 0 f f f t f i s 2 0 602 "602 602" _null_ _null_ _null_ _null_ _null_ path_add _null_ _null_ _null_ ) +insert ( 1436 path_add_pt 11 10 12 1 0 0 0 f f f t f i s 2 0 602 "602 600" _null_ _null_ _null_ _null_ _null_ path_add_pt _null_ _null_ _null_ ) +insert ( 1437 path_sub_pt 11 10 12 1 0 0 0 f f f t f i s 2 0 602 "602 600" _null_ _null_ _null_ _null_ _null_ path_sub_pt _null_ _null_ _null_ ) +insert ( 1438 path_mul_pt 11 10 12 1 0 0 0 f f f t f i s 2 0 602 "602 600" _null_ _null_ _null_ _null_ _null_ path_mul_pt _null_ _null_ _null_ ) +insert ( 1439 path_div_pt 11 10 12 1 0 0 0 f f f t f i s 2 0 602 "602 600" _null_ _null_ _null_ _null_ _null_ path_div_pt _null_ _null_ _null_ ) +insert ( 1440 point 11 10 12 1 0 0 0 f f f t f i s 2 0 600 "701 701" _null_ _null_ _null_ _null_ _null_ construct_point _null_ _null_ _null_ ) +insert ( 1441 point_add 11 10 12 1 0 0 0 f f f t f i s 2 0 600 "600 600" _null_ _null_ _null_ _null_ _null_ point_add _null_ _null_ _null_ ) +insert ( 1442 point_sub 11 10 12 1 0 0 0 f f f t f i s 2 0 600 "600 600" _null_ _null_ _null_ _null_ _null_ point_sub _null_ _null_ _null_ ) +insert ( 1443 point_mul 11 10 12 1 0 0 0 f f f t f i s 2 0 600 "600 600" _null_ _null_ _null_ _null_ _null_ point_mul _null_ _null_ _null_ ) +insert ( 1444 point_div 11 10 12 1 0 0 0 f f f t f i s 2 0 600 "600 600" _null_ _null_ _null_ _null_ _null_ point_div _null_ _null_ _null_ ) +insert ( 1445 poly_npoints 11 10 12 1 0 0 0 f f f t f i s 1 0 23 604 _null_ _null_ _null_ _null_ _null_ poly_npoints _null_ _null_ _null_ ) +insert ( 1446 box 11 10 12 1 0 0 0 f f f t f i s 1 0 603 604 _null_ _null_ _null_ _null_ _null_ poly_box _null_ _null_ _null_ ) +insert ( 1447 path 11 10 12 1 0 0 0 f f f t f i s 1 0 602 604 _null_ _null_ _null_ _null_ _null_ poly_path _null_ _null_ _null_ ) +insert ( 1448 polygon 11 10 12 1 0 0 0 f f f t f i s 1 0 604 603 _null_ _null_ _null_ _null_ _null_ box_poly _null_ _null_ _null_ ) +insert ( 1449 polygon 11 10 12 1 0 0 0 f f f t f i s 1 0 604 602 _null_ _null_ _null_ _null_ _null_ path_poly _null_ _null_ _null_ ) +insert ( 1450 circle_in 11 10 12 1 0 0 0 f f f t f i s 1 0 718 2275 _null_ _null_ _null_ _null_ _null_ circle_in _null_ _null_ _null_ ) +insert ( 1451 circle_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 718 _null_ _null_ _null_ _null_ _null_ circle_out _null_ _null_ _null_ ) +insert ( 1452 circle_same 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "718 718" _null_ _null_ _null_ _null_ _null_ circle_same _null_ _null_ _null_ ) +insert ( 1453 circle_contain 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "718 718" _null_ _null_ _null_ _null_ _null_ circle_contain _null_ _null_ _null_ ) +insert ( 1454 circle_left 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "718 718" _null_ _null_ _null_ _null_ _null_ circle_left _null_ _null_ _null_ ) +insert ( 1455 circle_overleft 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "718 718" _null_ _null_ _null_ _null_ _null_ circle_overleft _null_ _null_ _null_ ) +insert ( 1456 circle_overright 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "718 718" _null_ _null_ _null_ _null_ _null_ circle_overright _null_ _null_ _null_ ) +insert ( 1457 circle_right 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "718 718" _null_ _null_ _null_ _null_ _null_ circle_right _null_ _null_ _null_ ) +insert ( 1458 circle_contained 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "718 718" _null_ _null_ _null_ _null_ _null_ circle_contained _null_ _null_ _null_ ) +insert ( 1459 circle_overlap 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "718 718" _null_ _null_ _null_ _null_ _null_ circle_overlap _null_ _null_ _null_ ) +insert ( 1460 circle_below 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "718 718" _null_ _null_ _null_ _null_ _null_ circle_below _null_ _null_ _null_ ) +insert ( 1461 circle_above 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "718 718" _null_ _null_ _null_ _null_ _null_ circle_above _null_ _null_ _null_ ) +insert ( 1462 circle_eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "718 718" _null_ _null_ _null_ _null_ _null_ circle_eq _null_ _null_ _null_ ) +insert ( 1463 circle_ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "718 718" _null_ _null_ _null_ _null_ _null_ circle_ne _null_ _null_ _null_ ) +insert ( 1464 circle_lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "718 718" _null_ _null_ _null_ _null_ _null_ circle_lt _null_ _null_ _null_ ) +insert ( 1465 circle_gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "718 718" _null_ _null_ _null_ _null_ _null_ circle_gt _null_ _null_ _null_ ) +insert ( 1466 circle_le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "718 718" _null_ _null_ _null_ _null_ _null_ circle_le _null_ _null_ _null_ ) +insert ( 1467 circle_ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "718 718" _null_ _null_ _null_ _null_ _null_ circle_ge _null_ _null_ _null_ ) +insert ( 1468 area 11 10 12 1 0 0 0 f f f t f i s 1 0 701 718 _null_ _null_ _null_ _null_ _null_ circle_area _null_ _null_ _null_ ) +insert ( 1469 diameter 11 10 12 1 0 0 0 f f f t f i s 1 0 701 718 _null_ _null_ _null_ _null_ _null_ circle_diameter _null_ _null_ _null_ ) +insert ( 1470 radius 11 10 12 1 0 0 0 f f f t f i s 1 0 701 718 _null_ _null_ _null_ _null_ _null_ circle_radius _null_ _null_ _null_ ) +insert ( 1471 circle_distance 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "718 718" _null_ _null_ _null_ _null_ _null_ circle_distance _null_ _null_ _null_ ) +insert ( 1472 circle_center 11 10 12 1 0 0 0 f f f t f i s 1 0 600 718 _null_ _null_ _null_ _null_ _null_ circle_center _null_ _null_ _null_ ) +insert ( 1473 circle 11 10 12 1 0 0 0 f f f t f i s 2 0 718 "600 701" _null_ _null_ _null_ _null_ _null_ cr_circle _null_ _null_ _null_ ) +insert ( 1474 circle 11 10 12 1 0 0 0 f f f t f i s 1 0 718 604 _null_ _null_ _null_ _null_ _null_ poly_circle _null_ _null_ _null_ ) +insert ( 1475 polygon 11 10 12 1 0 0 0 f f f t f i s 2 0 604 "23 718" _null_ _null_ _null_ _null_ _null_ circle_poly _null_ _null_ _null_ ) +insert ( 1476 dist_pc 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "600 718" _null_ _null_ _null_ _null_ _null_ dist_pc _null_ _null_ _null_ ) +insert ( 1477 circle_contain_pt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "718 600" _null_ _null_ _null_ _null_ _null_ circle_contain_pt _null_ _null_ _null_ ) +insert ( 1478 pt_contained_circle 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "600 718" _null_ _null_ _null_ _null_ _null_ pt_contained_circle _null_ _null_ _null_ ) +insert ( 4091 box 11 10 12 1 0 0 0 f f f t f i s 1 0 603 600 _null_ _null_ _null_ _null_ _null_ point_box _null_ _null_ _null_ ) +insert ( 1479 circle 11 10 12 1 0 0 0 f f f t f i s 1 0 718 603 _null_ _null_ _null_ _null_ _null_ box_circle _null_ _null_ _null_ ) +insert ( 1480 box 11 10 12 1 0 0 0 f f f t f i s 1 0 603 718 _null_ _null_ _null_ _null_ _null_ circle_box _null_ _null_ _null_ ) +insert ( 1482 lseg_ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "601 601" _null_ _null_ _null_ _null_ _null_ lseg_ne _null_ _null_ _null_ ) +insert ( 1483 lseg_lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "601 601" _null_ _null_ _null_ _null_ _null_ lseg_lt _null_ _null_ _null_ ) +insert ( 1484 lseg_le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "601 601" _null_ _null_ _null_ _null_ _null_ lseg_le _null_ _null_ _null_ ) +insert ( 1485 lseg_gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "601 601" _null_ _null_ _null_ _null_ _null_ lseg_gt _null_ _null_ _null_ ) +insert ( 1486 lseg_ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "601 601" _null_ _null_ _null_ _null_ _null_ lseg_ge _null_ _null_ _null_ ) +insert ( 1487 lseg_length 11 10 12 1 0 0 0 f f f t f i s 1 0 701 601 _null_ _null_ _null_ _null_ _null_ lseg_length _null_ _null_ _null_ ) +insert ( 1488 close_ls 11 10 12 1 0 0 0 f f f t f i s 2 0 600 "628 601" _null_ _null_ _null_ _null_ _null_ close_ls _null_ _null_ _null_ ) +insert ( 1489 close_lseg 11 10 12 1 0 0 0 f f f t f i s 2 0 600 "601 601" _null_ _null_ _null_ _null_ _null_ close_lseg _null_ _null_ _null_ ) +insert ( 1490 line_in 11 10 12 1 0 0 0 f f f t f i s 1 0 628 2275 _null_ _null_ _null_ _null_ _null_ line_in _null_ _null_ _null_ ) +insert ( 1491 line_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 628 _null_ _null_ _null_ _null_ _null_ line_out _null_ _null_ _null_ ) +insert ( 1492 line_eq 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "628 628" _null_ _null_ _null_ _null_ _null_ line_eq _null_ _null_ _null_ ) +insert ( 1493 line 11 10 12 1 0 0 0 f f f t f i s 2 0 628 "600 600" _null_ _null_ _null_ _null_ _null_ line_construct_pp _null_ _null_ _null_ ) +insert ( 1494 line_interpt 11 10 12 1 0 0 0 f f f t f i s 2 0 600 "628 628" _null_ _null_ _null_ _null_ _null_ line_interpt _null_ _null_ _null_ ) +insert ( 1495 line_intersect 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "628 628" _null_ _null_ _null_ _null_ _null_ line_intersect _null_ _null_ _null_ ) +insert ( 1496 line_parallel 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "628 628" _null_ _null_ _null_ _null_ _null_ line_parallel _null_ _null_ _null_ ) +insert ( 1497 line_perp 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "628 628" _null_ _null_ _null_ _null_ _null_ line_perp _null_ _null_ _null_ ) +insert ( 1498 line_vertical 11 10 12 1 0 0 0 f f f t f i s 1 0 16 628 _null_ _null_ _null_ _null_ _null_ line_vertical _null_ _null_ _null_ ) +insert ( 1499 line_horizontal 11 10 12 1 0 0 0 f f f t f i s 1 0 16 628 _null_ _null_ _null_ _null_ _null_ line_horizontal _null_ _null_ _null_ ) +insert ( 1530 length 11 10 12 1 0 0 0 f f f t f i s 1 0 701 601 _null_ _null_ _null_ _null_ _null_ lseg_length _null_ _null_ _null_ ) +insert ( 1531 length 11 10 12 1 0 0 0 f f f t f i s 1 0 701 602 _null_ _null_ _null_ _null_ _null_ path_length _null_ _null_ _null_ ) +insert ( 1532 point 11 10 12 1 0 0 0 f f f t f i s 1 0 600 601 _null_ _null_ _null_ _null_ _null_ lseg_center _null_ _null_ _null_ ) +insert ( 1533 point 11 10 12 1 0 0 0 f f f t f i s 1 0 600 602 _null_ _null_ _null_ _null_ _null_ path_center _null_ _null_ _null_ ) +insert ( 1534 point 11 10 12 1 0 0 0 f f f t f i s 1 0 600 603 _null_ _null_ _null_ _null_ _null_ box_center _null_ _null_ _null_ ) +insert ( 1540 point 11 10 12 1 0 0 0 f f f t f i s 1 0 600 604 _null_ _null_ _null_ _null_ _null_ poly_center _null_ _null_ _null_ ) +insert ( 1541 lseg 11 10 12 1 0 0 0 f f f t f i s 1 0 601 603 _null_ _null_ _null_ _null_ _null_ box_diagonal _null_ _null_ _null_ ) +insert ( 1542 center 11 10 12 1 0 0 0 f f f t f i s 1 0 600 603 _null_ _null_ _null_ _null_ _null_ box_center _null_ _null_ _null_ ) +insert ( 1543 center 11 10 12 1 0 0 0 f f f t f i s 1 0 600 718 _null_ _null_ _null_ _null_ _null_ circle_center _null_ _null_ _null_ ) +insert ( 1544 polygon 11 10 14 1 0 0 0 f f f t f i s 1 0 604 718 _null_ _null_ _null_ _null_ _null_ "select pg_catalog.polygon(12, $1)" _null_ _null_ _null_ ) +insert ( 1545 npoints 11 10 12 1 0 0 0 f f f t f i s 1 0 23 602 _null_ _null_ _null_ _null_ _null_ path_npoints _null_ _null_ _null_ ) +insert ( 1556 npoints 11 10 12 1 0 0 0 f f f t f i s 1 0 23 604 _null_ _null_ _null_ _null_ _null_ poly_npoints _null_ _null_ _null_ ) +insert ( 1564 bit_in 11 10 12 1 0 0 0 f f f t f i s 3 0 1560 "2275 26 23" _null_ _null_ _null_ _null_ _null_ bit_in _null_ _null_ _null_ ) +insert ( 1565 bit_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 1560 _null_ _null_ _null_ _null_ _null_ bit_out _null_ _null_ _null_ ) +insert ( 2919 bittypmodin 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1263 _null_ _null_ _null_ _null_ _null_ bittypmodin _null_ _null_ _null_ ) +insert ( 2920 bittypmodout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 23 _null_ _null_ _null_ _null_ _null_ bittypmodout _null_ _null_ _null_ ) +insert ( 1569 like 11 10 12 1 0 0 1023 f f f t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ textlike _null_ _null_ _null_ ) +insert ( 1570 notlike 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ textnlike _null_ _null_ _null_ ) +insert ( 1571 like 11 10 12 1 0 0 1023 f f f t f i s 2 0 16 "19 25" _null_ _null_ _null_ _null_ _null_ namelike _null_ _null_ _null_ ) +insert ( 1572 notlike 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "19 25" _null_ _null_ _null_ _null_ _null_ namenlike _null_ _null_ _null_ ) +insert ( 1574 nextval 11 10 12 1 0 0 0 f f f t f v u 1 0 20 2205 _null_ _null_ _null_ _null_ _null_ nextval_oid _null_ _null_ _null_ ) +insert ( 1575 currval 11 10 12 1 0 0 0 f f f t f v u 1 0 20 2205 _null_ _null_ _null_ _null_ _null_ currval_oid _null_ _null_ _null_ ) +insert ( 1576 setval 11 10 12 1 0 0 0 f f f t f v u 2 0 20 "2205 20" _null_ _null_ _null_ _null_ _null_ setval_oid _null_ _null_ _null_ ) +insert ( 1765 setval 11 10 12 1 0 0 0 f f f t f v u 3 0 20 "2205 20 16" _null_ _null_ _null_ _null_ _null_ setval3_oid _null_ _null_ _null_ ) +insert ( 3078 pg_sequence_parameters 11 10 12 1 0 0 0 f f f t f s s 1 0 2249 26 "{26,20,20,20,20,16,20,26}" "{i,o,o,o,o,o,o,o}" "{sequence_oid,start_value,minimum_value,maximum_value,increment,cycle_option,cache_size,data_type}" _null_ _null_ pg_sequence_parameters _null_ _null_ _null_ ) +insert ( 4032 pg_sequence_last_value 11 10 12 1 0 0 0 f f f t f v u 1 0 20 2205 _null_ _null_ _null_ _null_ _null_ pg_sequence_last_value _null_ _null_ _null_ ) +insert ( 275 pg_nextoid 11 10 12 1 0 0 0 f f f t f v u 3 0 26 "2205 19 2205" _null_ _null_ _null_ _null_ _null_ pg_nextoid _null_ _null_ _null_ ) +insert ( 1579 varbit_in 11 10 12 1 0 0 0 f f f t f i s 3 0 1562 "2275 26 23" _null_ _null_ _null_ _null_ _null_ varbit_in _null_ _null_ _null_ ) +insert ( 1580 varbit_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 1562 _null_ _null_ _null_ _null_ _null_ varbit_out _null_ _null_ _null_ ) +insert ( 2902 varbittypmodin 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1263 _null_ _null_ _null_ _null_ _null_ varbittypmodin _null_ _null_ _null_ ) +insert ( 2921 varbittypmodout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 23 _null_ _null_ _null_ _null_ _null_ varbittypmodout _null_ _null_ _null_ ) +insert ( 1581 biteq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1560 1560" _null_ _null_ _null_ _null_ _null_ biteq _null_ _null_ _null_ ) +insert ( 1582 bitne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1560 1560" _null_ _null_ _null_ _null_ _null_ bitne _null_ _null_ _null_ ) +insert ( 1592 bitge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1560 1560" _null_ _null_ _null_ _null_ _null_ bitge _null_ _null_ _null_ ) +insert ( 1593 bitgt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1560 1560" _null_ _null_ _null_ _null_ _null_ bitgt _null_ _null_ _null_ ) +insert ( 1594 bitle 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1560 1560" _null_ _null_ _null_ _null_ _null_ bitle _null_ _null_ _null_ ) +insert ( 1595 bitlt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1560 1560" _null_ _null_ _null_ _null_ _null_ bitlt _null_ _null_ _null_ ) +insert ( 1596 bitcmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "1560 1560" _null_ _null_ _null_ _null_ _null_ bitcmp _null_ _null_ _null_ ) +insert ( 1598 random 11 10 12 1 0 0 0 f f f t f v r 0 0 701 "" _null_ _null_ _null_ _null_ _null_ drandom _null_ _null_ _null_ ) +insert ( 1599 setseed 11 10 12 1 0 0 0 f f f t f v r 1 0 2278 701 _null_ _null_ _null_ _null_ _null_ setseed _null_ _null_ _null_ ) +insert ( 1600 asin 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dasin _null_ _null_ _null_ ) +insert ( 1601 acos 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dacos _null_ _null_ _null_ ) +insert ( 1602 atan 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ datan _null_ _null_ _null_ ) +insert ( 1603 atan2 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ datan2 _null_ _null_ _null_ ) +insert ( 1604 sin 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dsin _null_ _null_ _null_ ) +insert ( 1605 cos 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dcos _null_ _null_ _null_ ) +insert ( 1606 tan 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dtan _null_ _null_ _null_ ) +insert ( 1607 cot 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dcot _null_ _null_ _null_ ) +insert ( 2731 asind 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dasind _null_ _null_ _null_ ) +insert ( 2732 acosd 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dacosd _null_ _null_ _null_ ) +insert ( 2733 atand 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ datand _null_ _null_ _null_ ) +insert ( 2734 atan2d 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ datan2d _null_ _null_ _null_ ) +insert ( 2735 sind 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dsind _null_ _null_ _null_ ) +insert ( 2736 cosd 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dcosd _null_ _null_ _null_ ) +insert ( 2737 tand 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dtand _null_ _null_ _null_ ) +insert ( 2738 cotd 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dcotd _null_ _null_ _null_ ) +insert ( 1608 degrees 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ degrees _null_ _null_ _null_ ) +insert ( 1609 radians 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ radians _null_ _null_ _null_ ) +insert ( 1610 pi 11 10 12 1 0 0 0 f f f t f i s 0 0 701 "" _null_ _null_ _null_ _null_ _null_ dpi _null_ _null_ _null_ ) +insert ( 2462 sinh 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dsinh _null_ _null_ _null_ ) +insert ( 2463 cosh 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dcosh _null_ _null_ _null_ ) +insert ( 2464 tanh 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dtanh _null_ _null_ _null_ ) +insert ( 2465 asinh 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dasinh _null_ _null_ _null_ ) +insert ( 2466 acosh 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ dacosh _null_ _null_ _null_ ) +insert ( 2467 atanh 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ datanh _null_ _null_ _null_ ) +insert ( 1618 interval_mul 11 10 12 1 0 0 0 f f f t f i s 2 0 1186 "1186 701" _null_ _null_ _null_ _null_ _null_ interval_mul _null_ _null_ _null_ ) +insert ( 1620 ascii 11 10 12 1 0 0 0 f f f t f i s 1 0 23 25 _null_ _null_ _null_ _null_ _null_ ascii _null_ _null_ _null_ ) +insert ( 1621 chr 11 10 12 1 0 0 0 f f f t f i s 1 0 25 23 _null_ _null_ _null_ _null_ _null_ chr _null_ _null_ _null_ ) +insert ( 1622 repeat 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "25 23" _null_ _null_ _null_ _null_ _null_ repeat _null_ _null_ _null_ ) +insert ( 1623 similar_escape 11 10 12 1 0 0 0 f f f f f i s 2 0 25 "25 25" _null_ _null_ _null_ _null_ _null_ similar_escape _null_ _null_ _null_ ) +insert ( 1986 similar_to_escape 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "25 25" _null_ _null_ _null_ _null_ _null_ similar_to_escape_2 _null_ _null_ _null_ ) +insert ( 1987 similar_to_escape 11 10 12 1 0 0 0 f f f t f i s 1 0 25 25 _null_ _null_ _null_ _null_ _null_ similar_to_escape_1 _null_ _null_ _null_ ) +insert ( 1624 mul_d_interval 11 10 12 1 0 0 0 f f f t f i s 2 0 1186 "701 1186" _null_ _null_ _null_ _null_ _null_ mul_d_interval _null_ _null_ _null_ ) +insert ( 1631 bpcharlike 11 10 12 1 0 0 1023 f f f t f i s 2 0 16 "1042 25" _null_ _null_ _null_ _null_ _null_ textlike _null_ _null_ _null_ ) +insert ( 1632 bpcharnlike 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1042 25" _null_ _null_ _null_ _null_ _null_ textnlike _null_ _null_ _null_ ) +insert ( 1633 texticlike 11 10 12 1 0 0 1025 f f f t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ texticlike _null_ _null_ _null_ ) +insert ( 1025 texticlike_support 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ texticlike_support _null_ _null_ _null_ ) +insert ( 1634 texticnlike 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ texticnlike _null_ _null_ _null_ ) +insert ( 1635 nameiclike 11 10 12 1 0 0 1025 f f f t f i s 2 0 16 "19 25" _null_ _null_ _null_ _null_ _null_ nameiclike _null_ _null_ _null_ ) +insert ( 1636 nameicnlike 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "19 25" _null_ _null_ _null_ _null_ _null_ nameicnlike _null_ _null_ _null_ ) +insert ( 1637 like_escape 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "25 25" _null_ _null_ _null_ _null_ _null_ like_escape _null_ _null_ _null_ ) +insert ( 1656 bpcharicregexeq 11 10 12 1 0 0 1024 f f f t f i s 2 0 16 "1042 25" _null_ _null_ _null_ _null_ _null_ texticregexeq _null_ _null_ _null_ ) +insert ( 1657 bpcharicregexne 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1042 25" _null_ _null_ _null_ _null_ _null_ texticregexne _null_ _null_ _null_ ) +insert ( 1658 bpcharregexeq 11 10 12 1 0 0 1364 f f f t f i s 2 0 16 "1042 25" _null_ _null_ _null_ _null_ _null_ textregexeq _null_ _null_ _null_ ) +insert ( 1659 bpcharregexne 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1042 25" _null_ _null_ _null_ _null_ _null_ textregexne _null_ _null_ _null_ ) +insert ( 1660 bpchariclike 11 10 12 1 0 0 1025 f f f t f i s 2 0 16 "1042 25" _null_ _null_ _null_ _null_ _null_ texticlike _null_ _null_ _null_ ) +insert ( 1661 bpcharicnlike 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1042 25" _null_ _null_ _null_ _null_ _null_ texticnlike _null_ _null_ _null_ ) +insert ( 868 strpos 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "25 25" _null_ _null_ _null_ _null_ _null_ textpos _null_ _null_ _null_ ) +insert ( 870 lower 11 10 12 1 0 0 0 f f f t f i s 1 0 25 25 _null_ _null_ _null_ _null_ _null_ lower _null_ _null_ _null_ ) +insert ( 871 upper 11 10 12 1 0 0 0 f f f t f i s 1 0 25 25 _null_ _null_ _null_ _null_ _null_ upper _null_ _null_ _null_ ) +insert ( 872 initcap 11 10 12 1 0 0 0 f f f t f i s 1 0 25 25 _null_ _null_ _null_ _null_ _null_ initcap _null_ _null_ _null_ ) +insert ( 873 lpad 11 10 12 1 0 0 0 f f f t f i s 3 0 25 "25 23 25" _null_ _null_ _null_ _null_ _null_ lpad _null_ _null_ _null_ ) +insert ( 874 rpad 11 10 12 1 0 0 0 f f f t f i s 3 0 25 "25 23 25" _null_ _null_ _null_ _null_ _null_ rpad _null_ _null_ _null_ ) +insert ( 875 ltrim 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "25 25" _null_ _null_ _null_ _null_ _null_ ltrim _null_ _null_ _null_ ) +insert ( 876 rtrim 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "25 25" _null_ _null_ _null_ _null_ _null_ rtrim _null_ _null_ _null_ ) +insert ( 877 substr 11 10 12 1 0 0 0 f f f t f i s 3 0 25 "25 23 23" _null_ _null_ _null_ _null_ _null_ text_substr _null_ _null_ _null_ ) +insert ( 878 translate 11 10 12 1 0 0 0 f f f t f i s 3 0 25 "25 25 25" _null_ _null_ _null_ _null_ _null_ translate _null_ _null_ _null_ ) +insert ( 879 lpad 11 10 14 1 0 0 0 f f f t f i s 2 0 25 "25 23" _null_ _null_ _null_ _null_ _null_ "select pg_catalog.lpad($1, $2, '' '')" _null_ _null_ _null_ ) +insert ( 880 rpad 11 10 14 1 0 0 0 f f f t f i s 2 0 25 "25 23" _null_ _null_ _null_ _null_ _null_ "select pg_catalog.rpad($1, $2, '' '')" _null_ _null_ _null_ ) +insert ( 881 ltrim 11 10 12 1 0 0 0 f f f t f i s 1 0 25 25 _null_ _null_ _null_ _null_ _null_ ltrim1 _null_ _null_ _null_ ) +insert ( 882 rtrim 11 10 12 1 0 0 0 f f f t f i s 1 0 25 25 _null_ _null_ _null_ _null_ _null_ rtrim1 _null_ _null_ _null_ ) +insert ( 883 substr 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "25 23" _null_ _null_ _null_ _null_ _null_ text_substr_no_len _null_ _null_ _null_ ) +insert ( 884 btrim 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "25 25" _null_ _null_ _null_ _null_ _null_ btrim _null_ _null_ _null_ ) +insert ( 885 btrim 11 10 12 1 0 0 0 f f f t f i s 1 0 25 25 _null_ _null_ _null_ _null_ _null_ btrim1 _null_ _null_ _null_ ) +insert ( 936 substring 11 10 12 1 0 0 0 f f f t f i s 3 0 25 "25 23 23" _null_ _null_ _null_ _null_ _null_ text_substr _null_ _null_ _null_ ) +insert ( 937 substring 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "25 23" _null_ _null_ _null_ _null_ _null_ text_substr_no_len _null_ _null_ _null_ ) +insert ( 2087 replace 11 10 12 1 0 0 0 f f f t f i s 3 0 25 "25 25 25" _null_ _null_ _null_ _null_ _null_ replace_text _null_ _null_ _null_ ) +insert ( 2284 regexp_replace 11 10 12 1 0 0 0 f f f t f i s 3 0 25 "25 25 25" _null_ _null_ _null_ _null_ _null_ textregexreplace_noopt _null_ _null_ _null_ ) +insert ( 2285 regexp_replace 11 10 12 1 0 0 0 f f f t f i s 4 0 25 "25 25 25 25" _null_ _null_ _null_ _null_ _null_ textregexreplace _null_ _null_ _null_ ) +insert ( 3396 regexp_match 11 10 12 1 0 0 0 f f f t f i s 2 0 1009 "25 25" _null_ _null_ _null_ _null_ _null_ regexp_match_no_flags _null_ _null_ _null_ ) +insert ( 3397 regexp_match 11 10 12 1 0 0 0 f f f t f i s 3 0 1009 "25 25 25" _null_ _null_ _null_ _null_ _null_ regexp_match _null_ _null_ _null_ ) +insert ( 2763 regexp_matches 11 10 12 1 1 0 0 f f f t t i s 2 0 1009 "25 25" _null_ _null_ _null_ _null_ _null_ regexp_matches_no_flags _null_ _null_ _null_ ) +insert ( 2764 regexp_matches 11 10 12 1 10 0 0 f f f t t i s 3 0 1009 "25 25 25" _null_ _null_ _null_ _null_ _null_ regexp_matches _null_ _null_ _null_ ) +insert ( 2088 split_part 11 10 12 1 0 0 0 f f f t f i s 3 0 25 "25 25 23" _null_ _null_ _null_ _null_ _null_ split_text _null_ _null_ _null_ ) +insert ( 2765 regexp_split_to_table 11 10 12 1 1000 0 0 f f f t t i s 2 0 25 "25 25" _null_ _null_ _null_ _null_ _null_ regexp_split_to_table_no_flags _null_ _null_ _null_ ) +insert ( 2766 regexp_split_to_table 11 10 12 1 1000 0 0 f f f t t i s 3 0 25 "25 25 25" _null_ _null_ _null_ _null_ _null_ regexp_split_to_table _null_ _null_ _null_ ) +insert ( 2767 regexp_split_to_array 11 10 12 1 0 0 0 f f f t f i s 2 0 1009 "25 25" _null_ _null_ _null_ _null_ _null_ regexp_split_to_array_no_flags _null_ _null_ _null_ ) +insert ( 2768 regexp_split_to_array 11 10 12 1 0 0 0 f f f t f i s 3 0 1009 "25 25 25" _null_ _null_ _null_ _null_ _null_ regexp_split_to_array _null_ _null_ _null_ ) +insert ( 2089 to_hex 11 10 12 1 0 0 0 f f f t f i s 1 0 25 23 _null_ _null_ _null_ _null_ _null_ to_hex32 _null_ _null_ _null_ ) +insert ( 2090 to_hex 11 10 12 1 0 0 0 f f f t f i s 1 0 25 20 _null_ _null_ _null_ _null_ _null_ to_hex64 _null_ _null_ _null_ ) +insert ( 1039 getdatabaseencoding 11 10 12 1 0 0 0 f f f t f s s 0 0 19 "" _null_ _null_ _null_ _null_ _null_ getdatabaseencoding _null_ _null_ _null_ ) +insert ( 810 pg_client_encoding 11 10 12 1 0 0 0 f f f t f s s 0 0 19 "" _null_ _null_ _null_ _null_ _null_ pg_client_encoding _null_ _null_ _null_ ) +insert ( 1713 length 11 10 12 1 0 0 0 f f f t f s s 2 0 23 "17 19" _null_ _null_ _null_ _null_ _null_ length_in_encoding _null_ _null_ _null_ ) +insert ( 1714 convert_from 11 10 12 1 0 0 0 f f f t f s s 2 0 25 "17 19" _null_ _null_ _null_ _null_ _null_ pg_convert_from _null_ _null_ _null_ ) +insert ( 1717 convert_to 11 10 12 1 0 0 0 f f f t f s s 2 0 17 "25 19" _null_ _null_ _null_ _null_ _null_ pg_convert_to _null_ _null_ _null_ ) +insert ( 1813 convert 11 10 12 1 0 0 0 f f f t f s s 3 0 17 "17 19 19" _null_ _null_ _null_ _null_ _null_ pg_convert _null_ _null_ _null_ ) +insert ( 1264 pg_char_to_encoding 11 10 12 1 0 0 0 f f f t f s s 1 0 23 19 _null_ _null_ _null_ _null_ _null_ PG_char_to_encoding _null_ _null_ _null_ ) +insert ( 1597 pg_encoding_to_char 11 10 12 1 0 0 0 f f f t f s s 1 0 19 23 _null_ _null_ _null_ _null_ _null_ PG_encoding_to_char _null_ _null_ _null_ ) +insert ( 2319 pg_encoding_max_length 11 10 12 1 0 0 0 f f f t f i s 1 0 23 23 _null_ _null_ _null_ _null_ _null_ pg_encoding_max_length_sql _null_ _null_ _null_ ) +insert ( 1638 oidgt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "26 26" _null_ _null_ _null_ _null_ _null_ oidgt _null_ _null_ _null_ ) +insert ( 1639 oidge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "26 26" _null_ _null_ _null_ _null_ _null_ oidge _null_ _null_ _null_ ) +insert ( 1573 pg_get_ruledef 11 10 12 1 0 0 0 f f f t f s s 1 0 25 26 _null_ _null_ _null_ _null_ _null_ pg_get_ruledef _null_ _null_ _null_ ) +insert ( 1640 pg_get_viewdef 11 10 12 1 0 0 0 f f f t f s r 1 0 25 25 _null_ _null_ _null_ _null_ _null_ pg_get_viewdef_name _null_ _null_ _null_ ) +insert ( 1641 pg_get_viewdef 11 10 12 1 0 0 0 f f f t f s r 1 0 25 26 _null_ _null_ _null_ _null_ _null_ pg_get_viewdef _null_ _null_ _null_ ) +insert ( 1642 pg_get_userbyid 11 10 12 1 0 0 0 f f f t f s s 1 0 19 26 _null_ _null_ _null_ _null_ _null_ pg_get_userbyid _null_ _null_ _null_ ) +insert ( 1643 pg_get_indexdef 11 10 12 1 0 0 0 f f f t f s s 1 0 25 26 _null_ _null_ _null_ _null_ _null_ pg_get_indexdef _null_ _null_ _null_ ) +insert ( 3415 pg_get_statisticsobjdef 11 10 12 1 0 0 0 f f f t f s s 1 0 25 26 _null_ _null_ _null_ _null_ _null_ pg_get_statisticsobjdef _null_ _null_ _null_ ) +insert ( 3352 pg_get_partkeydef 11 10 12 1 0 0 0 f f f t f s s 1 0 25 26 _null_ _null_ _null_ _null_ _null_ pg_get_partkeydef _null_ _null_ _null_ ) +insert ( 3408 pg_get_partition_constraintdef 11 10 12 1 0 0 0 f f f t f s s 1 0 25 26 _null_ _null_ _null_ _null_ _null_ pg_get_partition_constraintdef _null_ _null_ _null_ ) +insert ( 1662 pg_get_triggerdef 11 10 12 1 0 0 0 f f f t f s s 1 0 25 26 _null_ _null_ _null_ _null_ _null_ pg_get_triggerdef _null_ _null_ _null_ ) +insert ( 1387 pg_get_constraintdef 11 10 12 1 0 0 0 f f f t f s s 1 0 25 26 _null_ _null_ _null_ _null_ _null_ pg_get_constraintdef _null_ _null_ _null_ ) +insert ( 1716 pg_get_expr 11 10 12 1 0 0 0 f f f t f s s 2 0 25 "194 26" _null_ _null_ _null_ _null_ _null_ pg_get_expr _null_ _null_ _null_ ) +insert ( 1665 pg_get_serial_sequence 11 10 12 1 0 0 0 f f f t f s s 2 0 25 "25 25" _null_ _null_ _null_ _null_ _null_ pg_get_serial_sequence _null_ _null_ _null_ ) +insert ( 2098 pg_get_functiondef 11 10 12 1 0 0 0 f f f t f s s 1 0 25 26 _null_ _null_ _null_ _null_ _null_ pg_get_functiondef _null_ _null_ _null_ ) +insert ( 2162 pg_get_function_arguments 11 10 12 1 0 0 0 f f f t f s s 1 0 25 26 _null_ _null_ _null_ _null_ _null_ pg_get_function_arguments _null_ _null_ _null_ ) +insert ( 2232 pg_get_function_identity_arguments 11 10 12 1 0 0 0 f f f t f s s 1 0 25 26 _null_ _null_ _null_ _null_ _null_ pg_get_function_identity_arguments _null_ _null_ _null_ ) +insert ( 2165 pg_get_function_result 11 10 12 1 0 0 0 f f f t f s s 1 0 25 26 _null_ _null_ _null_ _null_ _null_ pg_get_function_result _null_ _null_ _null_ ) +insert ( 3808 pg_get_function_arg_default 11 10 12 1 0 0 0 f f f t f s s 2 0 25 "26 23" _null_ _null_ _null_ _null_ _null_ pg_get_function_arg_default _null_ _null_ _null_ ) +insert ( 1686 pg_get_keywords 11 10 12 10 400 0 0 f f f t t s s 0 0 2249 "" "{25,18,25}" "{o,o,o}" "{word,catcode,catdesc}" _null_ _null_ pg_get_keywords _null_ _null_ _null_ ) +insert ( 2289 pg_options_to_table 11 10 12 1 3 0 0 f f f t t s s 1 0 2249 1009 "{1009,25,25}" "{i,o,o}" "{options_array,option_name,option_value}" _null_ _null_ pg_options_to_table _null_ _null_ _null_ ) +insert ( 1619 pg_typeof 11 10 12 1 0 0 0 f f f f f s s 1 0 2206 2276 _null_ _null_ _null_ _null_ _null_ pg_typeof _null_ _null_ _null_ ) +insert ( 3162 pg_collation_for 11 10 12 1 0 0 0 f f f f f s s 1 0 25 2276 _null_ _null_ _null_ _null_ _null_ pg_collation_for _null_ _null_ _null_ ) +insert ( 3842 pg_relation_is_updatable 11 10 12 10 0 0 0 f f f t f s s 2 0 23 "2205 16" _null_ _null_ _null_ _null_ _null_ pg_relation_is_updatable _null_ _null_ _null_ ) +insert ( 3843 pg_column_is_updatable 11 10 12 10 0 0 0 f f f t f s s 3 0 16 "2205 21 16" _null_ _null_ _null_ _null_ _null_ pg_column_is_updatable _null_ _null_ _null_ ) +insert ( 6120 pg_get_replica_identity_index 11 10 12 10 0 0 0 f f f t f s s 1 0 2205 2205 _null_ _null_ _null_ _null_ _null_ pg_get_replica_identity_index _null_ _null_ _null_ ) +insert ( 1250 unique_key_recheck 11 10 12 1 0 0 0 f f f t f v s 0 0 2279 "" _null_ _null_ _null_ _null_ _null_ unique_key_recheck _null_ _null_ _null_ ) +insert ( 1644 RI_FKey_check_ins 11 10 12 1 0 0 0 f f f t f v s 0 0 2279 "" _null_ _null_ _null_ _null_ _null_ RI_FKey_check_ins _null_ _null_ _null_ ) +insert ( 1645 RI_FKey_check_upd 11 10 12 1 0 0 0 f f f t f v s 0 0 2279 "" _null_ _null_ _null_ _null_ _null_ RI_FKey_check_upd _null_ _null_ _null_ ) +insert ( 1646 RI_FKey_cascade_del 11 10 12 1 0 0 0 f f f t f v s 0 0 2279 "" _null_ _null_ _null_ _null_ _null_ RI_FKey_cascade_del _null_ _null_ _null_ ) +insert ( 1647 RI_FKey_cascade_upd 11 10 12 1 0 0 0 f f f t f v s 0 0 2279 "" _null_ _null_ _null_ _null_ _null_ RI_FKey_cascade_upd _null_ _null_ _null_ ) +insert ( 1648 RI_FKey_restrict_del 11 10 12 1 0 0 0 f f f t f v s 0 0 2279 "" _null_ _null_ _null_ _null_ _null_ RI_FKey_restrict_del _null_ _null_ _null_ ) +insert ( 1649 RI_FKey_restrict_upd 11 10 12 1 0 0 0 f f f t f v s 0 0 2279 "" _null_ _null_ _null_ _null_ _null_ RI_FKey_restrict_upd _null_ _null_ _null_ ) +insert ( 1650 RI_FKey_setnull_del 11 10 12 1 0 0 0 f f f t f v s 0 0 2279 "" _null_ _null_ _null_ _null_ _null_ RI_FKey_setnull_del _null_ _null_ _null_ ) +insert ( 1651 RI_FKey_setnull_upd 11 10 12 1 0 0 0 f f f t f v s 0 0 2279 "" _null_ _null_ _null_ _null_ _null_ RI_FKey_setnull_upd _null_ _null_ _null_ ) +insert ( 1652 RI_FKey_setdefault_del 11 10 12 1 0 0 0 f f f t f v s 0 0 2279 "" _null_ _null_ _null_ _null_ _null_ RI_FKey_setdefault_del _null_ _null_ _null_ ) +insert ( 1653 RI_FKey_setdefault_upd 11 10 12 1 0 0 0 f f f t f v s 0 0 2279 "" _null_ _null_ _null_ _null_ _null_ RI_FKey_setdefault_upd _null_ _null_ _null_ ) +insert ( 1654 RI_FKey_noaction_del 11 10 12 1 0 0 0 f f f t f v s 0 0 2279 "" _null_ _null_ _null_ _null_ _null_ RI_FKey_noaction_del _null_ _null_ _null_ ) +insert ( 1655 RI_FKey_noaction_upd 11 10 12 1 0 0 0 f f f t f v s 0 0 2279 "" _null_ _null_ _null_ _null_ _null_ RI_FKey_noaction_upd _null_ _null_ _null_ ) +insert ( 1666 varbiteq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1562 1562" _null_ _null_ _null_ _null_ _null_ biteq _null_ _null_ _null_ ) +insert ( 1667 varbitne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1562 1562" _null_ _null_ _null_ _null_ _null_ bitne _null_ _null_ _null_ ) +insert ( 1668 varbitge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1562 1562" _null_ _null_ _null_ _null_ _null_ bitge _null_ _null_ _null_ ) +insert ( 1669 varbitgt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1562 1562" _null_ _null_ _null_ _null_ _null_ bitgt _null_ _null_ _null_ ) +insert ( 1670 varbitle 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1562 1562" _null_ _null_ _null_ _null_ _null_ bitle _null_ _null_ _null_ ) +insert ( 1671 varbitlt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1562 1562" _null_ _null_ _null_ _null_ _null_ bitlt _null_ _null_ _null_ ) +insert ( 1672 varbitcmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "1562 1562" _null_ _null_ _null_ _null_ _null_ bitcmp _null_ _null_ _null_ ) +insert ( 1673 bitand 11 10 12 1 0 0 0 f f f t f i s 2 0 1560 "1560 1560" _null_ _null_ _null_ _null_ _null_ bit_and _null_ _null_ _null_ ) +insert ( 1674 bitor 11 10 12 1 0 0 0 f f f t f i s 2 0 1560 "1560 1560" _null_ _null_ _null_ _null_ _null_ bit_or _null_ _null_ _null_ ) +insert ( 1675 bitxor 11 10 12 1 0 0 0 f f f t f i s 2 0 1560 "1560 1560" _null_ _null_ _null_ _null_ _null_ bitxor _null_ _null_ _null_ ) +insert ( 1676 bitnot 11 10 12 1 0 0 0 f f f t f i s 1 0 1560 1560 _null_ _null_ _null_ _null_ _null_ bitnot _null_ _null_ _null_ ) +insert ( 1677 bitshiftleft 11 10 12 1 0 0 0 f f f t f i s 2 0 1560 "1560 23" _null_ _null_ _null_ _null_ _null_ bitshiftleft _null_ _null_ _null_ ) +insert ( 1678 bitshiftright 11 10 12 1 0 0 0 f f f t f i s 2 0 1560 "1560 23" _null_ _null_ _null_ _null_ _null_ bitshiftright _null_ _null_ _null_ ) +insert ( 1679 bitcat 11 10 12 1 0 0 0 f f f t f i s 2 0 1562 "1562 1562" _null_ _null_ _null_ _null_ _null_ bitcat _null_ _null_ _null_ ) +insert ( 1680 substring 11 10 12 1 0 0 0 f f f t f i s 3 0 1560 "1560 23 23" _null_ _null_ _null_ _null_ _null_ bitsubstr _null_ _null_ _null_ ) +insert ( 1681 length 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1560 _null_ _null_ _null_ _null_ _null_ bitlength _null_ _null_ _null_ ) +insert ( 1682 octet_length 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1560 _null_ _null_ _null_ _null_ _null_ bitoctetlength _null_ _null_ _null_ ) +insert ( 1683 bit 11 10 12 1 0 0 0 f f f t f i s 2 0 1560 "23 23" _null_ _null_ _null_ _null_ _null_ bitfromint4 _null_ _null_ _null_ ) +insert ( 1684 int4 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1560 _null_ _null_ _null_ _null_ _null_ bittoint4 _null_ _null_ _null_ ) +insert ( 1685 bit 11 10 12 1 0 0 0 f f f t f i s 3 0 1560 "1560 23 16" _null_ _null_ _null_ _null_ _null_ bit _null_ _null_ _null_ ) +insert ( 3158 varbit_support 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ varbit_support _null_ _null_ _null_ ) +insert ( 1687 varbit 11 10 12 1 0 0 3158 f f f t f i s 3 0 1562 "1562 23 16" _null_ _null_ _null_ _null_ _null_ varbit _null_ _null_ _null_ ) +insert ( 1698 position 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "1560 1560" _null_ _null_ _null_ _null_ _null_ bitposition _null_ _null_ _null_ ) +insert ( 1699 substring 11 10 12 1 0 0 0 f f f t f i s 2 0 1560 "1560 23" _null_ _null_ _null_ _null_ _null_ bitsubstr_no_len _null_ _null_ _null_ ) +insert ( 3030 overlay 11 10 12 1 0 0 0 f f f t f i s 4 0 1560 "1560 1560 23 23" _null_ _null_ _null_ _null_ _null_ bitoverlay _null_ _null_ _null_ ) +insert ( 3031 overlay 11 10 12 1 0 0 0 f f f t f i s 3 0 1560 "1560 1560 23" _null_ _null_ _null_ _null_ _null_ bitoverlay_no_len _null_ _null_ _null_ ) +insert ( 3032 get_bit 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "1560 23" _null_ _null_ _null_ _null_ _null_ bitgetbit _null_ _null_ _null_ ) +insert ( 3033 set_bit 11 10 12 1 0 0 0 f f f t f i s 3 0 1560 "1560 23 23" _null_ _null_ _null_ _null_ _null_ bitsetbit _null_ _null_ _null_ ) +insert ( 436 macaddr_in 11 10 12 1 0 0 0 f f f t f i s 1 0 829 2275 _null_ _null_ _null_ _null_ _null_ macaddr_in _null_ _null_ _null_ ) +insert ( 437 macaddr_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 829 _null_ _null_ _null_ _null_ _null_ macaddr_out _null_ _null_ _null_ ) +insert ( 753 trunc 11 10 12 1 0 0 0 f f f t f i s 1 0 829 829 _null_ _null_ _null_ _null_ _null_ macaddr_trunc _null_ _null_ _null_ ) +insert ( 830 macaddr_eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_eq _null_ _null_ _null_ ) +insert ( 831 macaddr_lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_lt _null_ _null_ _null_ ) +insert ( 832 macaddr_le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_le _null_ _null_ _null_ ) +insert ( 833 macaddr_gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_gt _null_ _null_ _null_ ) +insert ( 834 macaddr_ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_ge _null_ _null_ _null_ ) +insert ( 835 macaddr_ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_ne _null_ _null_ _null_ ) +insert ( 836 macaddr_cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_cmp _null_ _null_ _null_ ) +insert ( 3144 macaddr_not 11 10 12 1 0 0 0 f f f t f i s 1 0 829 829 _null_ _null_ _null_ _null_ _null_ macaddr_not _null_ _null_ _null_ ) +insert ( 3145 macaddr_and 11 10 12 1 0 0 0 f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_and _null_ _null_ _null_ ) +insert ( 3146 macaddr_or 11 10 12 1 0 0 0 f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_or _null_ _null_ _null_ ) +insert ( 3359 macaddr_sortsupport 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ macaddr_sortsupport _null_ _null_ _null_ ) +insert ( 4110 macaddr8_in 11 10 12 1 0 0 0 f f f t f i s 1 0 774 2275 _null_ _null_ _null_ _null_ _null_ macaddr8_in _null_ _null_ _null_ ) +insert ( 4111 macaddr8_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 774 _null_ _null_ _null_ _null_ _null_ macaddr8_out _null_ _null_ _null_ ) +insert ( 4112 trunc 11 10 12 1 0 0 0 f f f t f i s 1 0 774 774 _null_ _null_ _null_ _null_ _null_ macaddr8_trunc _null_ _null_ _null_ ) +insert ( 4113 macaddr8_eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_eq _null_ _null_ _null_ ) +insert ( 4114 macaddr8_lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_lt _null_ _null_ _null_ ) +insert ( 4115 macaddr8_le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_le _null_ _null_ _null_ ) +insert ( 4116 macaddr8_gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_gt _null_ _null_ _null_ ) +insert ( 4117 macaddr8_ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_ge _null_ _null_ _null_ ) +insert ( 4118 macaddr8_ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_ne _null_ _null_ _null_ ) +insert ( 4119 macaddr8_cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_cmp _null_ _null_ _null_ ) +insert ( 4120 macaddr8_not 11 10 12 1 0 0 0 f f f t f i s 1 0 774 774 _null_ _null_ _null_ _null_ _null_ macaddr8_not _null_ _null_ _null_ ) +insert ( 4121 macaddr8_and 11 10 12 1 0 0 0 f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_and _null_ _null_ _null_ ) +insert ( 4122 macaddr8_or 11 10 12 1 0 0 0 f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_or _null_ _null_ _null_ ) +insert ( 4123 macaddr8 11 10 12 1 0 0 0 f f f t f i s 1 0 774 829 _null_ _null_ _null_ _null_ _null_ macaddrtomacaddr8 _null_ _null_ _null_ ) +insert ( 4124 macaddr 11 10 12 1 0 0 0 f f f t f i s 1 0 829 774 _null_ _null_ _null_ _null_ _null_ macaddr8tomacaddr _null_ _null_ _null_ ) +insert ( 4125 macaddr8_set7bit 11 10 12 1 0 0 0 f f f t f i s 1 0 774 774 _null_ _null_ _null_ _null_ _null_ macaddr8_set7bit _null_ _null_ _null_ ) +insert ( 910 inet_in 11 10 12 1 0 0 0 f f f t f i s 1 0 869 2275 _null_ _null_ _null_ _null_ _null_ inet_in _null_ _null_ _null_ ) +insert ( 911 inet_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 869 _null_ _null_ _null_ _null_ _null_ inet_out _null_ _null_ _null_ ) +insert ( 1267 cidr_in 11 10 12 1 0 0 0 f f f t f i s 1 0 650 2275 _null_ _null_ _null_ _null_ _null_ cidr_in _null_ _null_ _null_ ) +insert ( 1427 cidr_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 650 _null_ _null_ _null_ _null_ _null_ cidr_out _null_ _null_ _null_ ) +insert ( 920 network_eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "869 869" _null_ _null_ _null_ _null_ _null_ network_eq _null_ _null_ _null_ ) +insert ( 921 network_lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "869 869" _null_ _null_ _null_ _null_ _null_ network_lt _null_ _null_ _null_ ) +insert ( 922 network_le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "869 869" _null_ _null_ _null_ _null_ _null_ network_le _null_ _null_ _null_ ) +insert ( 923 network_gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "869 869" _null_ _null_ _null_ _null_ _null_ network_gt _null_ _null_ _null_ ) +insert ( 924 network_ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "869 869" _null_ _null_ _null_ _null_ _null_ network_ge _null_ _null_ _null_ ) +insert ( 925 network_ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "869 869" _null_ _null_ _null_ _null_ _null_ network_ne _null_ _null_ _null_ ) +insert ( 3562 network_larger 11 10 12 1 0 0 0 f f f t f i s 2 0 869 "869 869" _null_ _null_ _null_ _null_ _null_ network_larger _null_ _null_ _null_ ) +insert ( 3563 network_smaller 11 10 12 1 0 0 0 f f f t f i s 2 0 869 "869 869" _null_ _null_ _null_ _null_ _null_ network_smaller _null_ _null_ _null_ ) +insert ( 926 network_cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "869 869" _null_ _null_ _null_ _null_ _null_ network_cmp _null_ _null_ _null_ ) +insert ( 927 network_sub 11 10 12 1 0 0 1173 f f f t f i s 2 0 16 "869 869" _null_ _null_ _null_ _null_ _null_ network_sub _null_ _null_ _null_ ) +insert ( 928 network_subeq 11 10 12 1 0 0 1173 f f f t f i s 2 0 16 "869 869" _null_ _null_ _null_ _null_ _null_ network_subeq _null_ _null_ _null_ ) +insert ( 929 network_sup 11 10 12 1 0 0 1173 f f f t f i s 2 0 16 "869 869" _null_ _null_ _null_ _null_ _null_ network_sup _null_ _null_ _null_ ) +insert ( 930 network_supeq 11 10 12 1 0 0 1173 f f f t f i s 2 0 16 "869 869" _null_ _null_ _null_ _null_ _null_ network_supeq _null_ _null_ _null_ ) +insert ( 1173 network_subset_support 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ network_subset_support _null_ _null_ _null_ ) +insert ( 3551 network_overlap 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "869 869" _null_ _null_ _null_ _null_ _null_ network_overlap _null_ _null_ _null_ ) +insert ( 5033 network_sortsupport 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ network_sortsupport _null_ _null_ _null_ ) +insert ( 598 abbrev 11 10 12 1 0 0 0 f f f t f i s 1 0 25 869 _null_ _null_ _null_ _null_ _null_ inet_abbrev _null_ _null_ _null_ ) +insert ( 599 abbrev 11 10 12 1 0 0 0 f f f t f i s 1 0 25 650 _null_ _null_ _null_ _null_ _null_ cidr_abbrev _null_ _null_ _null_ ) +insert ( 605 set_masklen 11 10 12 1 0 0 0 f f f t f i s 2 0 869 "869 23" _null_ _null_ _null_ _null_ _null_ inet_set_masklen _null_ _null_ _null_ ) +insert ( 635 set_masklen 11 10 12 1 0 0 0 f f f t f i s 2 0 650 "650 23" _null_ _null_ _null_ _null_ _null_ cidr_set_masklen _null_ _null_ _null_ ) +insert ( 711 family 11 10 12 1 0 0 0 f f f t f i s 1 0 23 869 _null_ _null_ _null_ _null_ _null_ network_family _null_ _null_ _null_ ) +insert ( 683 network 11 10 12 1 0 0 0 f f f t f i s 1 0 650 869 _null_ _null_ _null_ _null_ _null_ network_network _null_ _null_ _null_ ) +insert ( 696 netmask 11 10 12 1 0 0 0 f f f t f i s 1 0 869 869 _null_ _null_ _null_ _null_ _null_ network_netmask _null_ _null_ _null_ ) +insert ( 697 masklen 11 10 12 1 0 0 0 f f f t f i s 1 0 23 869 _null_ _null_ _null_ _null_ _null_ network_masklen _null_ _null_ _null_ ) +insert ( 698 broadcast 11 10 12 1 0 0 0 f f f t f i s 1 0 869 869 _null_ _null_ _null_ _null_ _null_ network_broadcast _null_ _null_ _null_ ) +insert ( 699 host 11 10 12 1 0 0 0 f f f t f i s 1 0 25 869 _null_ _null_ _null_ _null_ _null_ network_host _null_ _null_ _null_ ) +insert ( 730 text 11 10 12 1 0 0 0 f f f t f i s 1 0 25 869 _null_ _null_ _null_ _null_ _null_ network_show _null_ _null_ _null_ ) +insert ( 1362 hostmask 11 10 12 1 0 0 0 f f f t f i s 1 0 869 869 _null_ _null_ _null_ _null_ _null_ network_hostmask _null_ _null_ _null_ ) +insert ( 1715 cidr 11 10 12 1 0 0 0 f f f t f i s 1 0 650 869 _null_ _null_ _null_ _null_ _null_ inet_to_cidr _null_ _null_ _null_ ) +insert ( 2196 inet_client_addr 11 10 12 1 0 0 0 f f f f f s r 0 0 869 "" _null_ _null_ _null_ _null_ _null_ inet_client_addr _null_ _null_ _null_ ) +insert ( 2197 inet_client_port 11 10 12 1 0 0 0 f f f f f s r 0 0 23 "" _null_ _null_ _null_ _null_ _null_ inet_client_port _null_ _null_ _null_ ) +insert ( 2198 inet_server_addr 11 10 12 1 0 0 0 f f f f f s s 0 0 869 "" _null_ _null_ _null_ _null_ _null_ inet_server_addr _null_ _null_ _null_ ) +insert ( 2199 inet_server_port 11 10 12 1 0 0 0 f f f f f s s 0 0 23 "" _null_ _null_ _null_ _null_ _null_ inet_server_port _null_ _null_ _null_ ) +insert ( 2627 inetnot 11 10 12 1 0 0 0 f f f t f i s 1 0 869 869 _null_ _null_ _null_ _null_ _null_ inetnot _null_ _null_ _null_ ) +insert ( 2628 inetand 11 10 12 1 0 0 0 f f f t f i s 2 0 869 "869 869" _null_ _null_ _null_ _null_ _null_ inetand _null_ _null_ _null_ ) +insert ( 2629 inetor 11 10 12 1 0 0 0 f f f t f i s 2 0 869 "869 869" _null_ _null_ _null_ _null_ _null_ inetor _null_ _null_ _null_ ) +insert ( 2630 inetpl 11 10 12 1 0 0 0 f f f t f i s 2 0 869 "869 20" _null_ _null_ _null_ _null_ _null_ inetpl _null_ _null_ _null_ ) +insert ( 2631 int8pl_inet 11 10 14 1 0 0 0 f f f t f i s 2 0 869 "20 869" _null_ _null_ _null_ _null_ _null_ "select $2 + $1" _null_ _null_ _null_ ) +insert ( 2632 inetmi_int8 11 10 12 1 0 0 0 f f f t f i s 2 0 869 "869 20" _null_ _null_ _null_ _null_ _null_ inetmi_int8 _null_ _null_ _null_ ) +insert ( 2633 inetmi 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "869 869" _null_ _null_ _null_ _null_ _null_ inetmi _null_ _null_ _null_ ) +insert ( 4071 inet_same_family 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "869 869" _null_ _null_ _null_ _null_ _null_ inet_same_family _null_ _null_ _null_ ) +insert ( 4063 inet_merge 11 10 12 1 0 0 0 f f f t f i s 2 0 650 "869 869" _null_ _null_ _null_ _null_ _null_ inet_merge _null_ _null_ _null_ ) +insert ( 3553 inet_gist_consistent 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "2281 869 21 26 2281" _null_ _null_ _null_ _null_ _null_ inet_gist_consistent _null_ _null_ _null_ ) +insert ( 3554 inet_gist_union 11 10 12 1 0 0 0 f f f t f i s 2 0 869 "2281 2281" _null_ _null_ _null_ _null_ _null_ inet_gist_union _null_ _null_ _null_ ) +insert ( 3555 inet_gist_compress 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ inet_gist_compress _null_ _null_ _null_ ) +insert ( 3573 inet_gist_fetch 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ inet_gist_fetch _null_ _null_ _null_ ) +insert ( 3557 inet_gist_penalty 11 10 12 1 0 0 0 f f f t f i s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ inet_gist_penalty _null_ _null_ _null_ ) +insert ( 3558 inet_gist_picksplit 11 10 12 1 0 0 0 f f f t f i s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ inet_gist_picksplit _null_ _null_ _null_ ) +insert ( 3559 inet_gist_same 11 10 12 1 0 0 0 f f f t f i s 3 0 2281 "869 869 2281" _null_ _null_ _null_ _null_ _null_ inet_gist_same _null_ _null_ _null_ ) +insert ( 3795 inet_spg_config 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ inet_spg_config _null_ _null_ _null_ ) +insert ( 3796 inet_spg_choose 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ inet_spg_choose _null_ _null_ _null_ ) +insert ( 3797 inet_spg_picksplit 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ inet_spg_picksplit _null_ _null_ _null_ ) +insert ( 3798 inet_spg_inner_consistent 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ inet_spg_inner_consistent _null_ _null_ _null_ ) +insert ( 3799 inet_spg_leaf_consistent 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ inet_spg_leaf_consistent _null_ _null_ _null_ ) +insert ( 3560 networksel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ networksel _null_ _null_ _null_ ) +insert ( 3561 networkjoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ networkjoinsel _null_ _null_ _null_ ) +insert ( 1690 time_mi_time 11 10 12 1 0 0 0 f f f t f i s 2 0 1186 "1083 1083" _null_ _null_ _null_ _null_ _null_ time_mi_time _null_ _null_ _null_ ) +insert ( 1691 boolle 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "16 16" _null_ _null_ _null_ _null_ _null_ boolle _null_ _null_ _null_ ) +insert ( 1692 boolge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "16 16" _null_ _null_ _null_ _null_ _null_ boolge _null_ _null_ _null_ ) +insert ( 1693 btboolcmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "16 16" _null_ _null_ _null_ _null_ _null_ btboolcmp _null_ _null_ _null_ ) +insert ( 1688 time_hash 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1083 _null_ _null_ _null_ _null_ _null_ time_hash _null_ _null_ _null_ ) +insert ( 3409 time_hash_extended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "1083 20" _null_ _null_ _null_ _null_ _null_ time_hash_extended _null_ _null_ _null_ ) +insert ( 1696 timetz_hash 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1266 _null_ _null_ _null_ _null_ _null_ timetz_hash _null_ _null_ _null_ ) +insert ( 3410 timetz_hash_extended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "1266 20" _null_ _null_ _null_ _null_ _null_ timetz_hash_extended _null_ _null_ _null_ ) +insert ( 1697 interval_hash 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1186 _null_ _null_ _null_ _null_ _null_ interval_hash _null_ _null_ _null_ ) +insert ( 3418 interval_hash_extended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "1186 20" _null_ _null_ _null_ _null_ _null_ interval_hash_extended _null_ _null_ _null_ ) +insert ( 1701 numeric_in 11 10 12 1 0 0 0 f f f t f i s 3 0 1700 "2275 26 23" _null_ _null_ _null_ _null_ _null_ numeric_in _null_ _null_ _null_ ) +insert ( 1702 numeric_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 1700 _null_ _null_ _null_ _null_ _null_ numeric_out _null_ _null_ _null_ ) +insert ( 2917 numerictypmodin 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1263 _null_ _null_ _null_ _null_ _null_ numerictypmodin _null_ _null_ _null_ ) +insert ( 2918 numerictypmodout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 23 _null_ _null_ _null_ _null_ _null_ numerictypmodout _null_ _null_ _null_ ) +insert ( 3157 numeric_support 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ numeric_support _null_ _null_ _null_ ) +insert ( 1703 numeric 11 10 12 1 0 0 3157 f f f t f i s 2 0 1700 "1700 23" _null_ _null_ _null_ _null_ _null_ numeric _null_ _null_ _null_ ) +insert ( 1704 numeric_abs 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ numeric_abs _null_ _null_ _null_ ) +insert ( 1705 abs 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ numeric_abs _null_ _null_ _null_ ) +insert ( 1706 sign 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ numeric_sign _null_ _null_ _null_ ) +insert ( 1707 round 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "1700 23" _null_ _null_ _null_ _null_ _null_ numeric_round _null_ _null_ _null_ ) +insert ( 1708 round 11 10 14 1 0 0 0 f f f t f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ "select pg_catalog.round($1,0)" _null_ _null_ _null_ ) +insert ( 1709 trunc 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "1700 23" _null_ _null_ _null_ _null_ _null_ numeric_trunc _null_ _null_ _null_ ) +insert ( 1710 trunc 11 10 14 1 0 0 0 f f f t f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ "select pg_catalog.trunc($1,0)" _null_ _null_ _null_ ) +insert ( 1711 ceil 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ numeric_ceil _null_ _null_ _null_ ) +insert ( 2167 ceiling 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ numeric_ceil _null_ _null_ _null_ ) +insert ( 1712 floor 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ numeric_floor _null_ _null_ _null_ ) +insert ( 1718 numeric_eq 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_eq _null_ _null_ _null_ ) +insert ( 1719 numeric_ne 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_ne _null_ _null_ _null_ ) +insert ( 1720 numeric_gt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_gt _null_ _null_ _null_ ) +insert ( 1721 numeric_ge 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_ge _null_ _null_ _null_ ) +insert ( 1722 numeric_lt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_lt _null_ _null_ _null_ ) +insert ( 1723 numeric_le 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_le _null_ _null_ _null_ ) +insert ( 1724 numeric_add 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_add _null_ _null_ _null_ ) +insert ( 1725 numeric_sub 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_sub _null_ _null_ _null_ ) +insert ( 1726 numeric_mul 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_mul _null_ _null_ _null_ ) +insert ( 1727 numeric_div 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_div _null_ _null_ _null_ ) +insert ( 1728 mod 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_mod _null_ _null_ _null_ ) +insert ( 1729 numeric_mod 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_mod _null_ _null_ _null_ ) +insert ( 5048 gcd 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_gcd _null_ _null_ _null_ ) +insert ( 5049 lcm 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_lcm _null_ _null_ _null_ ) +insert ( 1730 sqrt 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ numeric_sqrt _null_ _null_ _null_ ) +insert ( 1731 numeric_sqrt 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ numeric_sqrt _null_ _null_ _null_ ) +insert ( 1732 exp 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ numeric_exp _null_ _null_ _null_ ) +insert ( 1733 numeric_exp 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ numeric_exp _null_ _null_ _null_ ) +insert ( 1734 ln 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ numeric_ln _null_ _null_ _null_ ) +insert ( 1735 numeric_ln 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ numeric_ln _null_ _null_ _null_ ) +insert ( 1736 log 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_log _null_ _null_ _null_ ) +insert ( 1737 numeric_log 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_log _null_ _null_ _null_ ) +insert ( 1738 pow 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_power _null_ _null_ _null_ ) +insert ( 2169 power 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_power _null_ _null_ _null_ ) +insert ( 1739 numeric_power 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_power _null_ _null_ _null_ ) +insert ( 3281 scale 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1700 _null_ _null_ _null_ _null_ _null_ numeric_scale _null_ _null_ _null_ ) +insert ( 5042 min_scale 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1700 _null_ _null_ _null_ _null_ _null_ numeric_min_scale _null_ _null_ _null_ ) +insert ( 5043 trim_scale 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ numeric_trim_scale _null_ _null_ _null_ ) +insert ( 1740 numeric 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 23 _null_ _null_ _null_ _null_ _null_ int4_numeric _null_ _null_ _null_ ) +insert ( 1741 log 11 10 14 1 0 0 0 f f f t f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ "select pg_catalog.log(10, $1)" _null_ _null_ _null_ ) +insert ( 1481 log10 11 10 14 1 0 0 0 f f f t f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ "select pg_catalog.log(10, $1)" _null_ _null_ _null_ ) +insert ( 1742 numeric 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 700 _null_ _null_ _null_ _null_ _null_ float4_numeric _null_ _null_ _null_ ) +insert ( 1743 numeric 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 701 _null_ _null_ _null_ _null_ _null_ float8_numeric _null_ _null_ _null_ ) +insert ( 1744 int4 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1700 _null_ _null_ _null_ _null_ _null_ numeric_int4 _null_ _null_ _null_ ) +insert ( 1745 float4 11 10 12 1 0 0 0 f f f t f i s 1 0 700 1700 _null_ _null_ _null_ _null_ _null_ numeric_float4 _null_ _null_ _null_ ) +insert ( 1746 float8 11 10 12 1 0 0 0 f f f t f i s 1 0 701 1700 _null_ _null_ _null_ _null_ _null_ numeric_float8 _null_ _null_ _null_ ) +insert ( 1973 div 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_div_trunc _null_ _null_ _null_ ) +insert ( 1980 numeric_div_trunc 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_div_trunc _null_ _null_ _null_ ) +insert ( 2170 width_bucket 11 10 12 1 0 0 0 f f f t f i s 4 0 23 "1700 1700 1700 23" _null_ _null_ _null_ _null_ _null_ width_bucket_numeric _null_ _null_ _null_ ) +insert ( 1747 time_pl_interval 11 10 12 1 0 0 0 f f f t f i s 2 0 1083 "1083 1186" _null_ _null_ _null_ _null_ _null_ time_pl_interval _null_ _null_ _null_ ) +insert ( 1748 time_mi_interval 11 10 12 1 0 0 0 f f f t f i s 2 0 1083 "1083 1186" _null_ _null_ _null_ _null_ _null_ time_mi_interval _null_ _null_ _null_ ) +insert ( 1749 timetz_pl_interval 11 10 12 1 0 0 0 f f f t f i s 2 0 1266 "1266 1186" _null_ _null_ _null_ _null_ _null_ timetz_pl_interval _null_ _null_ _null_ ) +insert ( 1750 timetz_mi_interval 11 10 12 1 0 0 0 f f f t f i s 2 0 1266 "1266 1186" _null_ _null_ _null_ _null_ _null_ timetz_mi_interval _null_ _null_ _null_ ) +insert ( 1764 numeric_inc 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ numeric_inc _null_ _null_ _null_ ) +insert ( 1766 numeric_smaller 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_smaller _null_ _null_ _null_ ) +insert ( 1767 numeric_larger 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_larger _null_ _null_ _null_ ) +insert ( 1769 numeric_cmp 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_cmp _null_ _null_ _null_ ) +insert ( 3283 numeric_sortsupport 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ numeric_sortsupport _null_ _null_ _null_ ) +insert ( 1771 numeric_uminus 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ numeric_uminus _null_ _null_ _null_ ) +insert ( 1779 int8 11 10 12 1 0 0 0 f f f t f i s 1 0 20 1700 _null_ _null_ _null_ _null_ _null_ numeric_int8 _null_ _null_ _null_ ) +insert ( 1781 numeric 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 20 _null_ _null_ _null_ _null_ _null_ int8_numeric _null_ _null_ _null_ ) +insert ( 1782 numeric 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 21 _null_ _null_ _null_ _null_ _null_ int2_numeric _null_ _null_ _null_ ) +insert ( 1783 int2 11 10 12 1 0 0 0 f f f t f i s 1 0 21 1700 _null_ _null_ _null_ _null_ _null_ numeric_int2 _null_ _null_ _null_ ) +insert ( 3556 bool 11 10 12 1 0 0 0 f f f t f i s 1 0 16 3802 _null_ _null_ _null_ _null_ _null_ jsonb_bool _null_ _null_ _null_ ) +insert ( 3449 numeric 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 3802 _null_ _null_ _null_ _null_ _null_ jsonb_numeric _null_ _null_ _null_ ) +insert ( 3450 int2 11 10 12 1 0 0 0 f f f t f i s 1 0 21 3802 _null_ _null_ _null_ _null_ _null_ jsonb_int2 _null_ _null_ _null_ ) +insert ( 3451 int4 11 10 12 1 0 0 0 f f f t f i s 1 0 23 3802 _null_ _null_ _null_ _null_ _null_ jsonb_int4 _null_ _null_ _null_ ) +insert ( 3452 int8 11 10 12 1 0 0 0 f f f t f i s 1 0 20 3802 _null_ _null_ _null_ _null_ _null_ jsonb_int8 _null_ _null_ _null_ ) +insert ( 3453 float4 11 10 12 1 0 0 0 f f f t f i s 1 0 700 3802 _null_ _null_ _null_ _null_ _null_ jsonb_float4 _null_ _null_ _null_ ) +insert ( 2580 float8 11 10 12 1 0 0 0 f f f t f i s 1 0 701 3802 _null_ _null_ _null_ _null_ _null_ jsonb_float8 _null_ _null_ _null_ ) +insert ( 1770 to_char 11 10 12 1 0 0 0 f f f t f s s 2 0 25 "1184 25" _null_ _null_ _null_ _null_ _null_ timestamptz_to_char _null_ _null_ _null_ ) +insert ( 1772 to_char 11 10 12 1 0 0 0 f f f t f s s 2 0 25 "1700 25" _null_ _null_ _null_ _null_ _null_ numeric_to_char _null_ _null_ _null_ ) +insert ( 1773 to_char 11 10 12 1 0 0 0 f f f t f s s 2 0 25 "23 25" _null_ _null_ _null_ _null_ _null_ int4_to_char _null_ _null_ _null_ ) +insert ( 1774 to_char 11 10 12 1 0 0 0 f f f t f s s 2 0 25 "20 25" _null_ _null_ _null_ _null_ _null_ int8_to_char _null_ _null_ _null_ ) +insert ( 1775 to_char 11 10 12 1 0 0 0 f f f t f s s 2 0 25 "700 25" _null_ _null_ _null_ _null_ _null_ float4_to_char _null_ _null_ _null_ ) +insert ( 1776 to_char 11 10 12 1 0 0 0 f f f t f s s 2 0 25 "701 25" _null_ _null_ _null_ _null_ _null_ float8_to_char _null_ _null_ _null_ ) +insert ( 1777 to_number 11 10 12 1 0 0 0 f f f t f s s 2 0 1700 "25 25" _null_ _null_ _null_ _null_ _null_ numeric_to_number _null_ _null_ _null_ ) +insert ( 1778 to_timestamp 11 10 12 1 0 0 0 f f f t f s s 2 0 1184 "25 25" _null_ _null_ _null_ _null_ _null_ to_timestamp _null_ _null_ _null_ ) +insert ( 1780 to_date 11 10 12 1 0 0 0 f f f t f s s 2 0 1082 "25 25" _null_ _null_ _null_ _null_ _null_ to_date _null_ _null_ _null_ ) +insert ( 1768 to_char 11 10 12 1 0 0 0 f f f t f s s 2 0 25 "1186 25" _null_ _null_ _null_ _null_ _null_ interval_to_char _null_ _null_ _null_ ) +insert ( 1282 quote_ident 11 10 12 1 0 0 0 f f f t f i s 1 0 25 25 _null_ _null_ _null_ _null_ _null_ quote_ident _null_ _null_ _null_ ) +insert ( 1283 quote_literal 11 10 12 1 0 0 0 f f f t f i s 1 0 25 25 _null_ _null_ _null_ _null_ _null_ quote_literal _null_ _null_ _null_ ) +insert ( 1285 quote_literal 11 10 14 1 0 0 0 f f f t f s s 1 0 25 2283 _null_ _null_ _null_ _null_ _null_ "select pg_catalog.quote_literal($1::pg_catalog.text)" _null_ _null_ _null_ ) +insert ( 1289 quote_nullable 11 10 12 1 0 0 0 f f f f f i s 1 0 25 25 _null_ _null_ _null_ _null_ _null_ quote_nullable _null_ _null_ _null_ ) +insert ( 1290 quote_nullable 11 10 14 1 0 0 0 f f f f f s s 1 0 25 2283 _null_ _null_ _null_ _null_ _null_ "select pg_catalog.quote_nullable($1::pg_catalog.text)" _null_ _null_ _null_ ) +insert ( 1798 oidin 11 10 12 1 0 0 0 f f f t f i s 1 0 26 2275 _null_ _null_ _null_ _null_ _null_ oidin _null_ _null_ _null_ ) +insert ( 1799 oidout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 26 _null_ _null_ _null_ _null_ _null_ oidout _null_ _null_ _null_ ) +insert ( 3058 concat 11 10 12 1 0 2276 0 f f f f f s s 1 0 25 2276 "{2276}" "{v}" _null_ _null_ _null_ text_concat _null_ _null_ _null_ ) +insert ( 3059 concat_ws 11 10 12 1 0 2276 0 f f f f f s s 2 0 25 "25 2276" "{25,2276}" "{i,v}" _null_ _null_ _null_ text_concat_ws _null_ _null_ _null_ ) +insert ( 3060 left 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "25 23" _null_ _null_ _null_ _null_ _null_ text_left _null_ _null_ _null_ ) +insert ( 3061 right 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "25 23" _null_ _null_ _null_ _null_ _null_ text_right _null_ _null_ _null_ ) +insert ( 3062 reverse 11 10 12 1 0 0 0 f f f t f i s 1 0 25 25 _null_ _null_ _null_ _null_ _null_ text_reverse _null_ _null_ _null_ ) +insert ( 3539 format 11 10 12 1 0 2276 0 f f f f f s s 2 0 25 "25 2276" "{25,2276}" "{i,v}" _null_ _null_ _null_ text_format _null_ _null_ _null_ ) +insert ( 3540 format 11 10 12 1 0 0 0 f f f f f s s 1 0 25 25 _null_ _null_ _null_ _null_ _null_ text_format_nv _null_ _null_ _null_ ) +insert ( 1810 bit_length 11 10 14 1 0 0 0 f f f t f i s 1 0 23 17 _null_ _null_ _null_ _null_ _null_ "select pg_catalog.octet_length($1) * 8" _null_ _null_ _null_ ) +insert ( 1811 bit_length 11 10 14 1 0 0 0 f f f t f i s 1 0 23 25 _null_ _null_ _null_ _null_ _null_ "select pg_catalog.octet_length($1) * 8" _null_ _null_ _null_ ) +insert ( 1812 bit_length 11 10 14 1 0 0 0 f f f t f i s 1 0 23 1560 _null_ _null_ _null_ _null_ _null_ "select pg_catalog.length($1)" _null_ _null_ _null_ ) +insert ( 1814 iclikesel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ iclikesel _null_ _null_ _null_ ) +insert ( 1815 icnlikesel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ icnlikesel _null_ _null_ _null_ ) +insert ( 1816 iclikejoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ iclikejoinsel _null_ _null_ _null_ ) +insert ( 1817 icnlikejoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ icnlikejoinsel _null_ _null_ _null_ ) +insert ( 1818 regexeqsel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ regexeqsel _null_ _null_ _null_ ) +insert ( 1819 likesel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ likesel _null_ _null_ _null_ ) +insert ( 1820 icregexeqsel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ icregexeqsel _null_ _null_ _null_ ) +insert ( 1821 regexnesel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ regexnesel _null_ _null_ _null_ ) +insert ( 1822 nlikesel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ nlikesel _null_ _null_ _null_ ) +insert ( 1823 icregexnesel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ icregexnesel _null_ _null_ _null_ ) +insert ( 1824 regexeqjoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ regexeqjoinsel _null_ _null_ _null_ ) +insert ( 1825 likejoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ likejoinsel _null_ _null_ _null_ ) +insert ( 1826 icregexeqjoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ icregexeqjoinsel _null_ _null_ _null_ ) +insert ( 1827 regexnejoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ regexnejoinsel _null_ _null_ _null_ ) +insert ( 1828 nlikejoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ nlikejoinsel _null_ _null_ _null_ ) +insert ( 1829 icregexnejoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ icregexnejoinsel _null_ _null_ _null_ ) +insert ( 3437 prefixsel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ prefixsel _null_ _null_ _null_ ) +insert ( 3438 prefixjoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ prefixjoinsel _null_ _null_ _null_ ) +insert ( 1830 float8_avg 11 10 12 1 0 0 0 f f f t f i s 1 0 701 1022 _null_ _null_ _null_ _null_ _null_ float8_avg _null_ _null_ _null_ ) +insert ( 2512 float8_var_pop 11 10 12 1 0 0 0 f f f t f i s 1 0 701 1022 _null_ _null_ _null_ _null_ _null_ float8_var_pop _null_ _null_ _null_ ) +insert ( 1831 float8_var_samp 11 10 12 1 0 0 0 f f f t f i s 1 0 701 1022 _null_ _null_ _null_ _null_ _null_ float8_var_samp _null_ _null_ _null_ ) +insert ( 2513 float8_stddev_pop 11 10 12 1 0 0 0 f f f t f i s 1 0 701 1022 _null_ _null_ _null_ _null_ _null_ float8_stddev_pop _null_ _null_ _null_ ) +insert ( 1832 float8_stddev_samp 11 10 12 1 0 0 0 f f f t f i s 1 0 701 1022 _null_ _null_ _null_ _null_ _null_ float8_stddev_samp _null_ _null_ _null_ ) +insert ( 1833 numeric_accum 11 10 12 1 0 0 0 f f f f f i s 2 0 2281 "2281 1700" _null_ _null_ _null_ _null_ _null_ numeric_accum _null_ _null_ _null_ ) +insert ( 3341 numeric_combine 11 10 12 1 0 0 0 f f f f f i s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ numeric_combine _null_ _null_ _null_ ) +insert ( 2858 numeric_avg_accum 11 10 12 1 0 0 0 f f f f f i s 2 0 2281 "2281 1700" _null_ _null_ _null_ _null_ _null_ numeric_avg_accum _null_ _null_ _null_ ) +insert ( 3337 numeric_avg_combine 11 10 12 1 0 0 0 f f f f f i s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ numeric_avg_combine _null_ _null_ _null_ ) +insert ( 2740 numeric_avg_serialize 11 10 12 1 0 0 0 f f f t f i s 1 0 17 2281 _null_ _null_ _null_ _null_ _null_ numeric_avg_serialize _null_ _null_ _null_ ) +insert ( 2741 numeric_avg_deserialize 11 10 12 1 0 0 0 f f f t f i s 2 0 2281 "17 2281" _null_ _null_ _null_ _null_ _null_ numeric_avg_deserialize _null_ _null_ _null_ ) +insert ( 3335 numeric_serialize 11 10 12 1 0 0 0 f f f t f i s 1 0 17 2281 _null_ _null_ _null_ _null_ _null_ numeric_serialize _null_ _null_ _null_ ) +insert ( 3336 numeric_deserialize 11 10 12 1 0 0 0 f f f t f i s 2 0 2281 "17 2281" _null_ _null_ _null_ _null_ _null_ numeric_deserialize _null_ _null_ _null_ ) +insert ( 3548 numeric_accum_inv 11 10 12 1 0 0 0 f f f f f i s 2 0 2281 "2281 1700" _null_ _null_ _null_ _null_ _null_ numeric_accum_inv _null_ _null_ _null_ ) +insert ( 1834 int2_accum 11 10 12 1 0 0 0 f f f f f i s 2 0 2281 "2281 21" _null_ _null_ _null_ _null_ _null_ int2_accum _null_ _null_ _null_ ) +insert ( 1835 int4_accum 11 10 12 1 0 0 0 f f f f f i s 2 0 2281 "2281 23" _null_ _null_ _null_ _null_ _null_ int4_accum _null_ _null_ _null_ ) +insert ( 1836 int8_accum 11 10 12 1 0 0 0 f f f f f i s 2 0 2281 "2281 20" _null_ _null_ _null_ _null_ _null_ int8_accum _null_ _null_ _null_ ) +insert ( 3338 numeric_poly_combine 11 10 12 1 0 0 0 f f f f f i s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ numeric_poly_combine _null_ _null_ _null_ ) +insert ( 3339 numeric_poly_serialize 11 10 12 1 0 0 0 f f f t f i s 1 0 17 2281 _null_ _null_ _null_ _null_ _null_ numeric_poly_serialize _null_ _null_ _null_ ) +insert ( 3340 numeric_poly_deserialize 11 10 12 1 0 0 0 f f f t f i s 2 0 2281 "17 2281" _null_ _null_ _null_ _null_ _null_ numeric_poly_deserialize _null_ _null_ _null_ ) +insert ( 2746 int8_avg_accum 11 10 12 1 0 0 0 f f f f f i s 2 0 2281 "2281 20" _null_ _null_ _null_ _null_ _null_ int8_avg_accum _null_ _null_ _null_ ) +insert ( 3567 int2_accum_inv 11 10 12 1 0 0 0 f f f f f i s 2 0 2281 "2281 21" _null_ _null_ _null_ _null_ _null_ int2_accum_inv _null_ _null_ _null_ ) +insert ( 3568 int4_accum_inv 11 10 12 1 0 0 0 f f f f f i s 2 0 2281 "2281 23" _null_ _null_ _null_ _null_ _null_ int4_accum_inv _null_ _null_ _null_ ) +insert ( 3569 int8_accum_inv 11 10 12 1 0 0 0 f f f f f i s 2 0 2281 "2281 20" _null_ _null_ _null_ _null_ _null_ int8_accum_inv _null_ _null_ _null_ ) +insert ( 3387 int8_avg_accum_inv 11 10 12 1 0 0 0 f f f f f i s 2 0 2281 "2281 20" _null_ _null_ _null_ _null_ _null_ int8_avg_accum_inv _null_ _null_ _null_ ) +insert ( 2785 int8_avg_combine 11 10 12 1 0 0 0 f f f f f i s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ int8_avg_combine _null_ _null_ _null_ ) +insert ( 2786 int8_avg_serialize 11 10 12 1 0 0 0 f f f t f i s 1 0 17 2281 _null_ _null_ _null_ _null_ _null_ int8_avg_serialize _null_ _null_ _null_ ) +insert ( 2787 int8_avg_deserialize 11 10 12 1 0 0 0 f f f t f i s 2 0 2281 "17 2281" _null_ _null_ _null_ _null_ _null_ int8_avg_deserialize _null_ _null_ _null_ ) +insert ( 3324 int4_avg_combine 11 10 12 1 0 0 0 f f f t f i s 2 0 1016 "1016 1016" _null_ _null_ _null_ _null_ _null_ int4_avg_combine _null_ _null_ _null_ ) +insert ( 3178 numeric_sum 11 10 12 1 0 0 0 f f f f f i s 1 0 1700 2281 _null_ _null_ _null_ _null_ _null_ numeric_sum _null_ _null_ _null_ ) +insert ( 1837 numeric_avg 11 10 12 1 0 0 0 f f f f f i s 1 0 1700 2281 _null_ _null_ _null_ _null_ _null_ numeric_avg _null_ _null_ _null_ ) +insert ( 2514 numeric_var_pop 11 10 12 1 0 0 0 f f f f f i s 1 0 1700 2281 _null_ _null_ _null_ _null_ _null_ numeric_var_pop _null_ _null_ _null_ ) +insert ( 1838 numeric_var_samp 11 10 12 1 0 0 0 f f f f f i s 1 0 1700 2281 _null_ _null_ _null_ _null_ _null_ numeric_var_samp _null_ _null_ _null_ ) +insert ( 2596 numeric_stddev_pop 11 10 12 1 0 0 0 f f f f f i s 1 0 1700 2281 _null_ _null_ _null_ _null_ _null_ numeric_stddev_pop _null_ _null_ _null_ ) +insert ( 1839 numeric_stddev_samp 11 10 12 1 0 0 0 f f f f f i s 1 0 1700 2281 _null_ _null_ _null_ _null_ _null_ numeric_stddev_samp _null_ _null_ _null_ ) +insert ( 1840 int2_sum 11 10 12 1 0 0 0 f f f f f i s 2 0 20 "20 21" _null_ _null_ _null_ _null_ _null_ int2_sum _null_ _null_ _null_ ) +insert ( 1841 int4_sum 11 10 12 1 0 0 0 f f f f f i s 2 0 20 "20 23" _null_ _null_ _null_ _null_ _null_ int4_sum _null_ _null_ _null_ ) +insert ( 1842 int8_sum 11 10 12 1 0 0 0 f f f f f i s 2 0 1700 "1700 20" _null_ _null_ _null_ _null_ _null_ int8_sum _null_ _null_ _null_ ) +insert ( 3388 numeric_poly_sum 11 10 12 1 0 0 0 f f f f f i s 1 0 1700 2281 _null_ _null_ _null_ _null_ _null_ numeric_poly_sum _null_ _null_ _null_ ) +insert ( 3389 numeric_poly_avg 11 10 12 1 0 0 0 f f f f f i s 1 0 1700 2281 _null_ _null_ _null_ _null_ _null_ numeric_poly_avg _null_ _null_ _null_ ) +insert ( 3390 numeric_poly_var_pop 11 10 12 1 0 0 0 f f f f f i s 1 0 1700 2281 _null_ _null_ _null_ _null_ _null_ numeric_poly_var_pop _null_ _null_ _null_ ) +insert ( 3391 numeric_poly_var_samp 11 10 12 1 0 0 0 f f f f f i s 1 0 1700 2281 _null_ _null_ _null_ _null_ _null_ numeric_poly_var_samp _null_ _null_ _null_ ) +insert ( 3392 numeric_poly_stddev_pop 11 10 12 1 0 0 0 f f f f f i s 1 0 1700 2281 _null_ _null_ _null_ _null_ _null_ numeric_poly_stddev_pop _null_ _null_ _null_ ) +insert ( 3393 numeric_poly_stddev_samp 11 10 12 1 0 0 0 f f f f f i s 1 0 1700 2281 _null_ _null_ _null_ _null_ _null_ numeric_poly_stddev_samp _null_ _null_ _null_ ) +insert ( 1843 interval_accum 11 10 12 1 0 0 0 f f f t f i s 2 0 1187 "1187 1186" _null_ _null_ _null_ _null_ _null_ interval_accum _null_ _null_ _null_ ) +insert ( 3325 interval_combine 11 10 12 1 0 0 0 f f f t f i s 2 0 1187 "1187 1187" _null_ _null_ _null_ _null_ _null_ interval_combine _null_ _null_ _null_ ) +insert ( 3549 interval_accum_inv 11 10 12 1 0 0 0 f f f t f i s 2 0 1187 "1187 1186" _null_ _null_ _null_ _null_ _null_ interval_accum_inv _null_ _null_ _null_ ) +insert ( 1844 interval_avg 11 10 12 1 0 0 0 f f f t f i s 1 0 1186 1187 _null_ _null_ _null_ _null_ _null_ interval_avg _null_ _null_ _null_ ) +insert ( 1962 int2_avg_accum 11 10 12 1 0 0 0 f f f t f i s 2 0 1016 "1016 21" _null_ _null_ _null_ _null_ _null_ int2_avg_accum _null_ _null_ _null_ ) +insert ( 1963 int4_avg_accum 11 10 12 1 0 0 0 f f f t f i s 2 0 1016 "1016 23" _null_ _null_ _null_ _null_ _null_ int4_avg_accum _null_ _null_ _null_ ) +insert ( 3570 int2_avg_accum_inv 11 10 12 1 0 0 0 f f f t f i s 2 0 1016 "1016 21" _null_ _null_ _null_ _null_ _null_ int2_avg_accum_inv _null_ _null_ _null_ ) +insert ( 3571 int4_avg_accum_inv 11 10 12 1 0 0 0 f f f t f i s 2 0 1016 "1016 23" _null_ _null_ _null_ _null_ _null_ int4_avg_accum_inv _null_ _null_ _null_ ) +insert ( 1964 int8_avg 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 1016 _null_ _null_ _null_ _null_ _null_ int8_avg _null_ _null_ _null_ ) +insert ( 3572 int2int4_sum 11 10 12 1 0 0 0 f f f t f i s 1 0 20 1016 _null_ _null_ _null_ _null_ _null_ int2int4_sum _null_ _null_ _null_ ) +insert ( 2805 int8inc_float8_float8 11 10 12 1 0 0 0 f f f t f i s 3 0 20 "20 701 701" _null_ _null_ _null_ _null_ _null_ int8inc_float8_float8 _null_ _null_ _null_ ) +insert ( 2806 float8_regr_accum 11 10 12 1 0 0 0 f f f t f i s 3 0 1022 "1022 701 701" _null_ _null_ _null_ _null_ _null_ float8_regr_accum _null_ _null_ _null_ ) +insert ( 3342 float8_regr_combine 11 10 12 1 0 0 0 f f f t f i s 2 0 1022 "1022 1022" _null_ _null_ _null_ _null_ _null_ float8_regr_combine _null_ _null_ _null_ ) +insert ( 2807 float8_regr_sxx 11 10 12 1 0 0 0 f f f t f i s 1 0 701 1022 _null_ _null_ _null_ _null_ _null_ float8_regr_sxx _null_ _null_ _null_ ) +insert ( 2808 float8_regr_syy 11 10 12 1 0 0 0 f f f t f i s 1 0 701 1022 _null_ _null_ _null_ _null_ _null_ float8_regr_syy _null_ _null_ _null_ ) +insert ( 2809 float8_regr_sxy 11 10 12 1 0 0 0 f f f t f i s 1 0 701 1022 _null_ _null_ _null_ _null_ _null_ float8_regr_sxy _null_ _null_ _null_ ) +insert ( 2810 float8_regr_avgx 11 10 12 1 0 0 0 f f f t f i s 1 0 701 1022 _null_ _null_ _null_ _null_ _null_ float8_regr_avgx _null_ _null_ _null_ ) +insert ( 2811 float8_regr_avgy 11 10 12 1 0 0 0 f f f t f i s 1 0 701 1022 _null_ _null_ _null_ _null_ _null_ float8_regr_avgy _null_ _null_ _null_ ) +insert ( 2812 float8_regr_r2 11 10 12 1 0 0 0 f f f t f i s 1 0 701 1022 _null_ _null_ _null_ _null_ _null_ float8_regr_r2 _null_ _null_ _null_ ) +insert ( 2813 float8_regr_slope 11 10 12 1 0 0 0 f f f t f i s 1 0 701 1022 _null_ _null_ _null_ _null_ _null_ float8_regr_slope _null_ _null_ _null_ ) +insert ( 2814 float8_regr_intercept 11 10 12 1 0 0 0 f f f t f i s 1 0 701 1022 _null_ _null_ _null_ _null_ _null_ float8_regr_intercept _null_ _null_ _null_ ) +insert ( 2815 float8_covar_pop 11 10 12 1 0 0 0 f f f t f i s 1 0 701 1022 _null_ _null_ _null_ _null_ _null_ float8_covar_pop _null_ _null_ _null_ ) +insert ( 2816 float8_covar_samp 11 10 12 1 0 0 0 f f f t f i s 1 0 701 1022 _null_ _null_ _null_ _null_ _null_ float8_covar_samp _null_ _null_ _null_ ) +insert ( 2817 float8_corr 11 10 12 1 0 0 0 f f f t f i s 1 0 701 1022 _null_ _null_ _null_ _null_ _null_ float8_corr _null_ _null_ _null_ ) +insert ( 3535 string_agg_transfn 11 10 12 1 0 0 0 f f f f f i s 3 0 2281 "2281 25 25" _null_ _null_ _null_ _null_ _null_ string_agg_transfn _null_ _null_ _null_ ) +insert ( 3536 string_agg_finalfn 11 10 12 1 0 0 0 f f f f f i s 1 0 25 2281 _null_ _null_ _null_ _null_ _null_ string_agg_finalfn _null_ _null_ _null_ ) +insert ( 3538 string_agg 11 10 12 1 0 0 0 a f f f f i s 2 0 25 "25 25" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3543 bytea_string_agg_transfn 11 10 12 1 0 0 0 f f f f f i s 3 0 2281 "2281 17 17" _null_ _null_ _null_ _null_ _null_ bytea_string_agg_transfn _null_ _null_ _null_ ) +insert ( 3544 bytea_string_agg_finalfn 11 10 12 1 0 0 0 f f f f f i s 1 0 17 2281 _null_ _null_ _null_ _null_ _null_ bytea_string_agg_finalfn _null_ _null_ _null_ ) +insert ( 3545 string_agg 11 10 12 1 0 0 0 a f f f f i s 2 0 17 "17 17" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 1845 to_ascii 11 10 12 1 0 0 0 f f f t f i s 1 0 25 25 _null_ _null_ _null_ _null_ _null_ to_ascii_default _null_ _null_ _null_ ) +insert ( 1846 to_ascii 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "25 23" _null_ _null_ _null_ _null_ _null_ to_ascii_enc _null_ _null_ _null_ ) +insert ( 1847 to_ascii 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "25 19" _null_ _null_ _null_ _null_ _null_ to_ascii_encname _null_ _null_ _null_ ) +insert ( 1848 interval_pl_time 11 10 14 1 0 0 0 f f f t f i s 2 0 1083 "1186 1083" _null_ _null_ _null_ _null_ _null_ "select $2 + $1" _null_ _null_ _null_ ) +insert ( 1850 int28eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "21 20" _null_ _null_ _null_ _null_ _null_ int28eq _null_ _null_ _null_ ) +insert ( 1851 int28ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "21 20" _null_ _null_ _null_ _null_ _null_ int28ne _null_ _null_ _null_ ) +insert ( 1852 int28lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "21 20" _null_ _null_ _null_ _null_ _null_ int28lt _null_ _null_ _null_ ) +insert ( 1853 int28gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "21 20" _null_ _null_ _null_ _null_ _null_ int28gt _null_ _null_ _null_ ) +insert ( 1854 int28le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "21 20" _null_ _null_ _null_ _null_ _null_ int28le _null_ _null_ _null_ ) +insert ( 1855 int28ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "21 20" _null_ _null_ _null_ _null_ _null_ int28ge _null_ _null_ _null_ ) +insert ( 1856 int82eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "20 21" _null_ _null_ _null_ _null_ _null_ int82eq _null_ _null_ _null_ ) +insert ( 1857 int82ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "20 21" _null_ _null_ _null_ _null_ _null_ int82ne _null_ _null_ _null_ ) +insert ( 1858 int82lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "20 21" _null_ _null_ _null_ _null_ _null_ int82lt _null_ _null_ _null_ ) +insert ( 1859 int82gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "20 21" _null_ _null_ _null_ _null_ _null_ int82gt _null_ _null_ _null_ ) +insert ( 1860 int82le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "20 21" _null_ _null_ _null_ _null_ _null_ int82le _null_ _null_ _null_ ) +insert ( 1861 int82ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "20 21" _null_ _null_ _null_ _null_ _null_ int82ge _null_ _null_ _null_ ) +insert ( 1892 int2and 11 10 12 1 0 0 0 f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2and _null_ _null_ _null_ ) +insert ( 1893 int2or 11 10 12 1 0 0 0 f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2or _null_ _null_ _null_ ) +insert ( 1894 int2xor 11 10 12 1 0 0 0 f f f t f i s 2 0 21 "21 21" _null_ _null_ _null_ _null_ _null_ int2xor _null_ _null_ _null_ ) +insert ( 1895 int2not 11 10 12 1 0 0 0 f f f t f i s 1 0 21 21 _null_ _null_ _null_ _null_ _null_ int2not _null_ _null_ _null_ ) +insert ( 1896 int2shl 11 10 12 1 0 0 0 f f f t f i s 2 0 21 "21 23" _null_ _null_ _null_ _null_ _null_ int2shl _null_ _null_ _null_ ) +insert ( 1897 int2shr 11 10 12 1 0 0 0 f f f t f i s 2 0 21 "21 23" _null_ _null_ _null_ _null_ _null_ int2shr _null_ _null_ _null_ ) +insert ( 1898 int4and 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "23 23" _null_ _null_ _null_ _null_ _null_ int4and _null_ _null_ _null_ ) +insert ( 1899 int4or 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "23 23" _null_ _null_ _null_ _null_ _null_ int4or _null_ _null_ _null_ ) +insert ( 1900 int4xor 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "23 23" _null_ _null_ _null_ _null_ _null_ int4xor _null_ _null_ _null_ ) +insert ( 1901 int4not 11 10 12 1 0 0 0 f f f t f i s 1 0 23 23 _null_ _null_ _null_ _null_ _null_ int4not _null_ _null_ _null_ ) +insert ( 1902 int4shl 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "23 23" _null_ _null_ _null_ _null_ _null_ int4shl _null_ _null_ _null_ ) +insert ( 1903 int4shr 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "23 23" _null_ _null_ _null_ _null_ _null_ int4shr _null_ _null_ _null_ ) +insert ( 1904 int8and 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 20" _null_ _null_ _null_ _null_ _null_ int8and _null_ _null_ _null_ ) +insert ( 1905 int8or 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 20" _null_ _null_ _null_ _null_ _null_ int8or _null_ _null_ _null_ ) +insert ( 1906 int8xor 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 20" _null_ _null_ _null_ _null_ _null_ int8xor _null_ _null_ _null_ ) +insert ( 1907 int8not 11 10 12 1 0 0 0 f f f t f i s 1 0 20 20 _null_ _null_ _null_ _null_ _null_ int8not _null_ _null_ _null_ ) +insert ( 1908 int8shl 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 23" _null_ _null_ _null_ _null_ _null_ int8shl _null_ _null_ _null_ ) +insert ( 1909 int8shr 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "20 23" _null_ _null_ _null_ _null_ _null_ int8shr _null_ _null_ _null_ ) +insert ( 1910 int8up 11 10 12 1 0 0 0 f f f t f i s 1 0 20 20 _null_ _null_ _null_ _null_ _null_ int8up _null_ _null_ _null_ ) +insert ( 1911 int2up 11 10 12 1 0 0 0 f f f t f i s 1 0 21 21 _null_ _null_ _null_ _null_ _null_ int2up _null_ _null_ _null_ ) +insert ( 1912 int4up 11 10 12 1 0 0 0 f f f t f i s 1 0 23 23 _null_ _null_ _null_ _null_ _null_ int4up _null_ _null_ _null_ ) +insert ( 1913 float4up 11 10 12 1 0 0 0 f f f t f i s 1 0 700 700 _null_ _null_ _null_ _null_ _null_ float4up _null_ _null_ _null_ ) +insert ( 1914 float8up 11 10 12 1 0 0 0 f f f t f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ float8up _null_ _null_ _null_ ) +insert ( 1915 numeric_uplus 11 10 12 1 0 0 0 f f f t f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ numeric_uplus _null_ _null_ _null_ ) +insert ( 1922 has_table_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 25 25" _null_ _null_ _null_ _null_ _null_ has_table_privilege_name_name _null_ _null_ _null_ ) +insert ( 1923 has_table_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ _null_ has_table_privilege_name_id _null_ _null_ _null_ ) +insert ( 1924 has_table_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 25 25" _null_ _null_ _null_ _null_ _null_ has_table_privilege_id_name _null_ _null_ _null_ ) +insert ( 1925 has_table_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 26 25" _null_ _null_ _null_ _null_ _null_ has_table_privilege_id_id _null_ _null_ _null_ ) +insert ( 1926 has_table_privilege 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ has_table_privilege_name _null_ _null_ _null_ ) +insert ( 1927 has_table_privilege 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "26 25" _null_ _null_ _null_ _null_ _null_ has_table_privilege_id _null_ _null_ _null_ ) +insert ( 2181 has_sequence_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 25 25" _null_ _null_ _null_ _null_ _null_ has_sequence_privilege_name_name _null_ _null_ _null_ ) +insert ( 2182 has_sequence_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ _null_ has_sequence_privilege_name_id _null_ _null_ _null_ ) +insert ( 2183 has_sequence_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 25 25" _null_ _null_ _null_ _null_ _null_ has_sequence_privilege_id_name _null_ _null_ _null_ ) +insert ( 2184 has_sequence_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 26 25" _null_ _null_ _null_ _null_ _null_ has_sequence_privilege_id_id _null_ _null_ _null_ ) +insert ( 2185 has_sequence_privilege 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ has_sequence_privilege_name _null_ _null_ _null_ ) +insert ( 2186 has_sequence_privilege 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "26 25" _null_ _null_ _null_ _null_ _null_ has_sequence_privilege_id _null_ _null_ _null_ ) +insert ( 3012 has_column_privilege 11 10 12 1 0 0 0 f f f t f s s 4 0 16 "19 25 25 25" _null_ _null_ _null_ _null_ _null_ has_column_privilege_name_name_name _null_ _null_ _null_ ) +insert ( 3013 has_column_privilege 11 10 12 1 0 0 0 f f f t f s s 4 0 16 "19 25 21 25" _null_ _null_ _null_ _null_ _null_ has_column_privilege_name_name_attnum _null_ _null_ _null_ ) +insert ( 3014 has_column_privilege 11 10 12 1 0 0 0 f f f t f s s 4 0 16 "19 26 25 25" _null_ _null_ _null_ _null_ _null_ has_column_privilege_name_id_name _null_ _null_ _null_ ) +insert ( 3015 has_column_privilege 11 10 12 1 0 0 0 f f f t f s s 4 0 16 "19 26 21 25" _null_ _null_ _null_ _null_ _null_ has_column_privilege_name_id_attnum _null_ _null_ _null_ ) +insert ( 3016 has_column_privilege 11 10 12 1 0 0 0 f f f t f s s 4 0 16 "26 25 25 25" _null_ _null_ _null_ _null_ _null_ has_column_privilege_id_name_name _null_ _null_ _null_ ) +insert ( 3017 has_column_privilege 11 10 12 1 0 0 0 f f f t f s s 4 0 16 "26 25 21 25" _null_ _null_ _null_ _null_ _null_ has_column_privilege_id_name_attnum _null_ _null_ _null_ ) +insert ( 3018 has_column_privilege 11 10 12 1 0 0 0 f f f t f s s 4 0 16 "26 26 25 25" _null_ _null_ _null_ _null_ _null_ has_column_privilege_id_id_name _null_ _null_ _null_ ) +insert ( 3019 has_column_privilege 11 10 12 1 0 0 0 f f f t f s s 4 0 16 "26 26 21 25" _null_ _null_ _null_ _null_ _null_ has_column_privilege_id_id_attnum _null_ _null_ _null_ ) +insert ( 3020 has_column_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "25 25 25" _null_ _null_ _null_ _null_ _null_ has_column_privilege_name_name _null_ _null_ _null_ ) +insert ( 3021 has_column_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "25 21 25" _null_ _null_ _null_ _null_ _null_ has_column_privilege_name_attnum _null_ _null_ _null_ ) +insert ( 3022 has_column_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 25 25" _null_ _null_ _null_ _null_ _null_ has_column_privilege_id_name _null_ _null_ _null_ ) +insert ( 3023 has_column_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 21 25" _null_ _null_ _null_ _null_ _null_ has_column_privilege_id_attnum _null_ _null_ _null_ ) +insert ( 3024 has_any_column_privilege 11 10 12 10 0 0 0 f f f t f s s 3 0 16 "19 25 25" _null_ _null_ _null_ _null_ _null_ has_any_column_privilege_name_name _null_ _null_ _null_ ) +insert ( 3025 has_any_column_privilege 11 10 12 10 0 0 0 f f f t f s s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ _null_ has_any_column_privilege_name_id _null_ _null_ _null_ ) +insert ( 3026 has_any_column_privilege 11 10 12 10 0 0 0 f f f t f s s 3 0 16 "26 25 25" _null_ _null_ _null_ _null_ _null_ has_any_column_privilege_id_name _null_ _null_ _null_ ) +insert ( 3027 has_any_column_privilege 11 10 12 10 0 0 0 f f f t f s s 3 0 16 "26 26 25" _null_ _null_ _null_ _null_ _null_ has_any_column_privilege_id_id _null_ _null_ _null_ ) +insert ( 3028 has_any_column_privilege 11 10 12 10 0 0 0 f f f t f s s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ has_any_column_privilege_name _null_ _null_ _null_ ) +insert ( 3029 has_any_column_privilege 11 10 12 10 0 0 0 f f f t f s s 2 0 16 "26 25" _null_ _null_ _null_ _null_ _null_ has_any_column_privilege_id _null_ _null_ _null_ ) +insert ( 3355 pg_ndistinct_in 11 10 12 1 0 0 0 f f f t f i s 1 0 3361 2275 _null_ _null_ _null_ _null_ _null_ pg_ndistinct_in _null_ _null_ _null_ ) +insert ( 3356 pg_ndistinct_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 3361 _null_ _null_ _null_ _null_ _null_ pg_ndistinct_out _null_ _null_ _null_ ) +insert ( 3357 pg_ndistinct_recv 11 10 12 1 0 0 0 f f f t f s s 1 0 3361 2281 _null_ _null_ _null_ _null_ _null_ pg_ndistinct_recv _null_ _null_ _null_ ) +insert ( 3358 pg_ndistinct_send 11 10 12 1 0 0 0 f f f t f s s 1 0 17 3361 _null_ _null_ _null_ _null_ _null_ pg_ndistinct_send _null_ _null_ _null_ ) +insert ( 3404 pg_dependencies_in 11 10 12 1 0 0 0 f f f t f i s 1 0 3402 2275 _null_ _null_ _null_ _null_ _null_ pg_dependencies_in _null_ _null_ _null_ ) +insert ( 3405 pg_dependencies_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 3402 _null_ _null_ _null_ _null_ _null_ pg_dependencies_out _null_ _null_ _null_ ) +insert ( 3406 pg_dependencies_recv 11 10 12 1 0 0 0 f f f t f s s 1 0 3402 2281 _null_ _null_ _null_ _null_ _null_ pg_dependencies_recv _null_ _null_ _null_ ) +insert ( 3407 pg_dependencies_send 11 10 12 1 0 0 0 f f f t f s s 1 0 17 3402 _null_ _null_ _null_ _null_ _null_ pg_dependencies_send _null_ _null_ _null_ ) +insert ( 5018 pg_mcv_list_in 11 10 12 1 0 0 0 f f f t f i s 1 0 5017 2275 _null_ _null_ _null_ _null_ _null_ pg_mcv_list_in _null_ _null_ _null_ ) +insert ( 5019 pg_mcv_list_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 5017 _null_ _null_ _null_ _null_ _null_ pg_mcv_list_out _null_ _null_ _null_ ) +insert ( 5020 pg_mcv_list_recv 11 10 12 1 0 0 0 f f f t f s s 1 0 5017 2281 _null_ _null_ _null_ _null_ _null_ pg_mcv_list_recv _null_ _null_ _null_ ) +insert ( 5021 pg_mcv_list_send 11 10 12 1 0 0 0 f f f t f s s 1 0 17 5017 _null_ _null_ _null_ _null_ _null_ pg_mcv_list_send _null_ _null_ _null_ ) +insert ( 3427 pg_mcv_list_items 11 10 12 1 1000 0 0 f f f t t s s 1 0 2249 5017 "{5017,23,1009,1000,701,701}" "{i,o,o,o,o,o}" "{mcv_list,index,values,nulls,frequency,base_frequency}" _null_ _null_ pg_stats_ext_mcvlist_items _null_ _null_ _null_ ) +insert ( 1928 pg_stat_get_numscans 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_numscans _null_ _null_ _null_ ) +insert ( 1929 pg_stat_get_tuples_returned 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_tuples_returned _null_ _null_ _null_ ) +insert ( 1930 pg_stat_get_tuples_fetched 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_tuples_fetched _null_ _null_ _null_ ) +insert ( 1931 pg_stat_get_tuples_inserted 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_tuples_inserted _null_ _null_ _null_ ) +insert ( 1932 pg_stat_get_tuples_updated 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_tuples_updated _null_ _null_ _null_ ) +insert ( 1933 pg_stat_get_tuples_deleted 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_tuples_deleted _null_ _null_ _null_ ) +insert ( 1972 pg_stat_get_tuples_hot_updated 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_tuples_hot_updated _null_ _null_ _null_ ) +insert ( 2878 pg_stat_get_live_tuples 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_live_tuples _null_ _null_ _null_ ) +insert ( 2879 pg_stat_get_dead_tuples 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_dead_tuples _null_ _null_ _null_ ) +insert ( 3177 pg_stat_get_mod_since_analyze 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_mod_since_analyze _null_ _null_ _null_ ) +insert ( 5053 pg_stat_get_ins_since_vacuum 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_ins_since_vacuum _null_ _null_ _null_ ) +insert ( 1934 pg_stat_get_blocks_fetched 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_blocks_fetched _null_ _null_ _null_ ) +insert ( 1935 pg_stat_get_blocks_hit 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_blocks_hit _null_ _null_ _null_ ) +insert ( 2781 pg_stat_get_last_vacuum_time 11 10 12 1 0 0 0 f f f t f s r 1 0 1184 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_last_vacuum_time _null_ _null_ _null_ ) +insert ( 2782 pg_stat_get_last_autovacuum_time 11 10 12 1 0 0 0 f f f t f s r 1 0 1184 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_last_autovacuum_time _null_ _null_ _null_ ) +insert ( 2783 pg_stat_get_last_analyze_time 11 10 12 1 0 0 0 f f f t f s r 1 0 1184 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_last_analyze_time _null_ _null_ _null_ ) +insert ( 2784 pg_stat_get_last_autoanalyze_time 11 10 12 1 0 0 0 f f f t f s r 1 0 1184 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_last_autoanalyze_time _null_ _null_ _null_ ) +insert ( 3054 pg_stat_get_vacuum_count 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_vacuum_count _null_ _null_ _null_ ) +insert ( 3055 pg_stat_get_autovacuum_count 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_autovacuum_count _null_ _null_ _null_ ) +insert ( 3056 pg_stat_get_analyze_count 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_analyze_count _null_ _null_ _null_ ) +insert ( 3057 pg_stat_get_autoanalyze_count 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_autoanalyze_count _null_ _null_ _null_ ) +insert ( 1936 pg_stat_get_backend_idset 11 10 12 1 100 0 0 f f f t t s r 0 0 23 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_idset _null_ _null_ _null_ ) +insert ( 2022 pg_stat_get_activity 11 10 12 1 100 0 0 f f f f t s r 1 0 2249 23 "{23,26,23,26,25,25,25,25,25,1184,1184,1184,1184,869,25,23,28,28,25,16,25,25,23,16,25,1700,25,16,25,16,23}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,backend_type,ssl,sslversion,sslcipher,sslbits,sslcompression,ssl_client_dn,ssl_client_serial,ssl_issuer_dn,gss_auth,gss_princ,gss_enc,leader_pid}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ ) +insert ( 3318 pg_stat_get_progress_info 11 10 12 1 100 0 0 f f f t t s r 1 0 2249 25 "{25,23,26,26,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{cmdtype,pid,datid,relid,param1,param2,param3,param4,param5,param6,param7,param8,param9,param10,param11,param12,param13,param14,param15,param16,param17,param18,param19,param20}" _null_ _null_ pg_stat_get_progress_info _null_ _null_ _null_ ) +insert ( 3099 pg_stat_get_wal_senders 11 10 12 1 10 0 0 f f f f t s r 0 0 2249 "" "{23,25,3220,3220,3220,3220,1186,1186,1186,23,25,1184}" "{o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,state,sent_lsn,write_lsn,flush_lsn,replay_lsn,write_lag,flush_lag,replay_lag,sync_priority,sync_state,reply_time}" _null_ _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ) +insert ( 3317 pg_stat_get_wal_receiver 11 10 12 1 0 0 0 f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,3220,23,1184,1184,3220,1184,25,25,23,25}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,written_lsn,flushed_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,sender_host,sender_port,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ) +insert ( 6118 pg_stat_get_subscription 11 10 12 1 0 0 0 f f f f f s r 1 0 2249 26 "{26,26,26,23,3220,1184,1184,3220,1184}" "{i,o,o,o,o,o,o,o,o}" "{subid,subid,relid,pid,received_lsn,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time}" _null_ _null_ pg_stat_get_subscription _null_ _null_ _null_ ) +insert ( 2026 pg_backend_pid 11 10 12 1 0 0 0 f f f t f s r 0 0 23 "" _null_ _null_ _null_ _null_ _null_ pg_backend_pid _null_ _null_ _null_ ) +insert ( 1937 pg_stat_get_backend_pid 11 10 12 1 0 0 0 f f f t f s r 1 0 23 23 _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_pid _null_ _null_ _null_ ) +insert ( 1938 pg_stat_get_backend_dbid 11 10 12 1 0 0 0 f f f t f s r 1 0 26 23 _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_dbid _null_ _null_ _null_ ) +insert ( 1939 pg_stat_get_backend_userid 11 10 12 1 0 0 0 f f f t f s r 1 0 26 23 _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_userid _null_ _null_ _null_ ) +insert ( 1940 pg_stat_get_backend_activity 11 10 12 1 0 0 0 f f f t f s r 1 0 25 23 _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_activity _null_ _null_ _null_ ) +insert ( 2788 pg_stat_get_backend_wait_event_type 11 10 12 1 0 0 0 f f f t f s r 1 0 25 23 _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_wait_event_type _null_ _null_ _null_ ) +insert ( 2853 pg_stat_get_backend_wait_event 11 10 12 1 0 0 0 f f f t f s r 1 0 25 23 _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_wait_event _null_ _null_ _null_ ) +insert ( 2094 pg_stat_get_backend_activity_start 11 10 12 1 0 0 0 f f f t f s r 1 0 1184 23 _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_activity_start _null_ _null_ _null_ ) +insert ( 2857 pg_stat_get_backend_xact_start 11 10 12 1 0 0 0 f f f t f s r 1 0 1184 23 _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_xact_start _null_ _null_ _null_ ) +insert ( 1391 pg_stat_get_backend_start 11 10 12 1 0 0 0 f f f t f s r 1 0 1184 23 _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_start _null_ _null_ _null_ ) +insert ( 1392 pg_stat_get_backend_client_addr 11 10 12 1 0 0 0 f f f t f s r 1 0 869 23 _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_client_addr _null_ _null_ _null_ ) +insert ( 1393 pg_stat_get_backend_client_port 11 10 12 1 0 0 0 f f f t f s r 1 0 23 23 _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_client_port _null_ _null_ _null_ ) +insert ( 1941 pg_stat_get_db_numbackends 11 10 12 1 0 0 0 f f f t f s r 1 0 23 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_numbackends _null_ _null_ _null_ ) +insert ( 1942 pg_stat_get_db_xact_commit 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_xact_commit _null_ _null_ _null_ ) +insert ( 1943 pg_stat_get_db_xact_rollback 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_xact_rollback _null_ _null_ _null_ ) +insert ( 1944 pg_stat_get_db_blocks_fetched 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_blocks_fetched _null_ _null_ _null_ ) +insert ( 1945 pg_stat_get_db_blocks_hit 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_blocks_hit _null_ _null_ _null_ ) +insert ( 2758 pg_stat_get_db_tuples_returned 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_tuples_returned _null_ _null_ _null_ ) +insert ( 2759 pg_stat_get_db_tuples_fetched 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_tuples_fetched _null_ _null_ _null_ ) +insert ( 2760 pg_stat_get_db_tuples_inserted 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_tuples_inserted _null_ _null_ _null_ ) +insert ( 2761 pg_stat_get_db_tuples_updated 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_tuples_updated _null_ _null_ _null_ ) +insert ( 2762 pg_stat_get_db_tuples_deleted 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_tuples_deleted _null_ _null_ _null_ ) +insert ( 3065 pg_stat_get_db_conflict_tablespace 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_conflict_tablespace _null_ _null_ _null_ ) +insert ( 3066 pg_stat_get_db_conflict_lock 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_conflict_lock _null_ _null_ _null_ ) +insert ( 3067 pg_stat_get_db_conflict_snapshot 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_conflict_snapshot _null_ _null_ _null_ ) +insert ( 3068 pg_stat_get_db_conflict_bufferpin 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_conflict_bufferpin _null_ _null_ _null_ ) +insert ( 3069 pg_stat_get_db_conflict_startup_deadlock 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_conflict_startup_deadlock _null_ _null_ _null_ ) +insert ( 3070 pg_stat_get_db_conflict_all 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_conflict_all _null_ _null_ _null_ ) +insert ( 3152 pg_stat_get_db_deadlocks 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_deadlocks _null_ _null_ _null_ ) +insert ( 3426 pg_stat_get_db_checksum_failures 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_checksum_failures _null_ _null_ _null_ ) +insert ( 3428 pg_stat_get_db_checksum_last_failure 11 10 12 1 0 0 0 f f f t f s r 1 0 1184 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_checksum_last_failure _null_ _null_ _null_ ) +insert ( 3074 pg_stat_get_db_stat_reset_time 11 10 12 1 0 0 0 f f f t f s r 1 0 1184 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_stat_reset_time _null_ _null_ _null_ ) +insert ( 3150 pg_stat_get_db_temp_files 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_temp_files _null_ _null_ _null_ ) +insert ( 3151 pg_stat_get_db_temp_bytes 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_temp_bytes _null_ _null_ _null_ ) +insert ( 2844 pg_stat_get_db_blk_read_time 11 10 12 1 0 0 0 f f f t f s r 1 0 701 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_blk_read_time _null_ _null_ _null_ ) +insert ( 2845 pg_stat_get_db_blk_write_time 11 10 12 1 0 0 0 f f f t f s r 1 0 701 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_db_blk_write_time _null_ _null_ _null_ ) +insert ( 3195 pg_stat_get_archiver 11 10 12 1 0 0 0 f f f f f s r 0 0 2249 "" "{20,25,1184,20,25,1184,1184}" "{o,o,o,o,o,o,o}" "{archived_count,last_archived_wal,last_archived_time,failed_count,last_failed_wal,last_failed_time,stats_reset}" _null_ _null_ pg_stat_get_archiver _null_ _null_ _null_ ) +insert ( 2769 pg_stat_get_bgwriter_timed_checkpoints 11 10 12 1 0 0 0 f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_timed_checkpoints _null_ _null_ _null_ ) +insert ( 2770 pg_stat_get_bgwriter_requested_checkpoints 11 10 12 1 0 0 0 f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_requested_checkpoints _null_ _null_ _null_ ) +insert ( 2771 pg_stat_get_bgwriter_buf_written_checkpoints 11 10 12 1 0 0 0 f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_buf_written_checkpoints _null_ _null_ _null_ ) +insert ( 2772 pg_stat_get_bgwriter_buf_written_clean 11 10 12 1 0 0 0 f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_buf_written_clean _null_ _null_ _null_ ) +insert ( 2773 pg_stat_get_bgwriter_maxwritten_clean 11 10 12 1 0 0 0 f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_maxwritten_clean _null_ _null_ _null_ ) +insert ( 3075 pg_stat_get_bgwriter_stat_reset_time 11 10 12 1 0 0 0 f f f t f s r 0 0 1184 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_stat_reset_time _null_ _null_ _null_ ) +insert ( 3160 pg_stat_get_checkpoint_write_time 11 10 12 1 0 0 0 f f f t f s r 0 0 701 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_checkpoint_write_time _null_ _null_ _null_ ) +insert ( 3161 pg_stat_get_checkpoint_sync_time 11 10 12 1 0 0 0 f f f t f s r 0 0 701 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_checkpoint_sync_time _null_ _null_ _null_ ) +insert ( 2775 pg_stat_get_buf_written_backend 11 10 12 1 0 0 0 f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_buf_written_backend _null_ _null_ _null_ ) +insert ( 3063 pg_stat_get_buf_fsync_backend 11 10 12 1 0 0 0 f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_buf_fsync_backend _null_ _null_ _null_ ) +insert ( 2859 pg_stat_get_buf_alloc 11 10 12 1 0 0 0 f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_buf_alloc _null_ _null_ _null_ ) +insert ( 2306 pg_stat_get_slru 11 10 12 1 100 0 0 f f f f t s r 0 0 2249 "" "{25,20,20,20,20,20,20,20,1184}" "{o,o,o,o,o,o,o,o,o}" "{name,blks_zeroed,blks_hit,blks_read,blks_written,blks_exists,flushes,truncates,stats_reset}" _null_ _null_ pg_stat_get_slru _null_ _null_ _null_ ) +insert ( 2978 pg_stat_get_function_calls 11 10 12 1 0 0 0 f f f t f s r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_function_calls _null_ _null_ _null_ ) +insert ( 2979 pg_stat_get_function_total_time 11 10 12 1 0 0 0 f f f t f s r 1 0 701 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_function_total_time _null_ _null_ _null_ ) +insert ( 2980 pg_stat_get_function_self_time 11 10 12 1 0 0 0 f f f t f s r 1 0 701 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_function_self_time _null_ _null_ _null_ ) +insert ( 3037 pg_stat_get_xact_numscans 11 10 12 1 0 0 0 f f f t f v r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_xact_numscans _null_ _null_ _null_ ) +insert ( 3038 pg_stat_get_xact_tuples_returned 11 10 12 1 0 0 0 f f f t f v r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_xact_tuples_returned _null_ _null_ _null_ ) +insert ( 3039 pg_stat_get_xact_tuples_fetched 11 10 12 1 0 0 0 f f f t f v r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_xact_tuples_fetched _null_ _null_ _null_ ) +insert ( 3040 pg_stat_get_xact_tuples_inserted 11 10 12 1 0 0 0 f f f t f v r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_xact_tuples_inserted _null_ _null_ _null_ ) +insert ( 3041 pg_stat_get_xact_tuples_updated 11 10 12 1 0 0 0 f f f t f v r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_xact_tuples_updated _null_ _null_ _null_ ) +insert ( 3042 pg_stat_get_xact_tuples_deleted 11 10 12 1 0 0 0 f f f t f v r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_xact_tuples_deleted _null_ _null_ _null_ ) +insert ( 3043 pg_stat_get_xact_tuples_hot_updated 11 10 12 1 0 0 0 f f f t f v r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_xact_tuples_hot_updated _null_ _null_ _null_ ) +insert ( 3044 pg_stat_get_xact_blocks_fetched 11 10 12 1 0 0 0 f f f t f v r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_xact_blocks_fetched _null_ _null_ _null_ ) +insert ( 3045 pg_stat_get_xact_blocks_hit 11 10 12 1 0 0 0 f f f t f v r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_xact_blocks_hit _null_ _null_ _null_ ) +insert ( 3046 pg_stat_get_xact_function_calls 11 10 12 1 0 0 0 f f f t f v r 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_xact_function_calls _null_ _null_ _null_ ) +insert ( 3047 pg_stat_get_xact_function_total_time 11 10 12 1 0 0 0 f f f t f v r 1 0 701 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_xact_function_total_time _null_ _null_ _null_ ) +insert ( 3048 pg_stat_get_xact_function_self_time 11 10 12 1 0 0 0 f f f t f v r 1 0 701 26 _null_ _null_ _null_ _null_ _null_ pg_stat_get_xact_function_self_time _null_ _null_ _null_ ) +insert ( 3788 pg_stat_get_snapshot_timestamp 11 10 12 1 0 0 0 f f f t f s r 0 0 1184 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_snapshot_timestamp _null_ _null_ _null_ ) +insert ( 2230 pg_stat_clear_snapshot 11 10 12 1 0 0 0 f f f f f v r 0 0 2278 "" _null_ _null_ _null_ _null_ _null_ pg_stat_clear_snapshot _null_ _null_ _null_ ) +insert ( 2274 pg_stat_reset 11 10 12 1 0 0 0 f f f f f v s 0 0 2278 "" _null_ _null_ _null_ _null_ _null_ pg_stat_reset _null_ _null_ _null_ ) +insert ( 3775 pg_stat_reset_shared 11 10 12 1 0 0 0 f f f t f v s 1 0 2278 25 _null_ _null_ _null_ _null_ _null_ pg_stat_reset_shared _null_ _null_ _null_ ) +insert ( 3776 pg_stat_reset_single_table_counters 11 10 12 1 0 0 0 f f f t f v s 1 0 2278 26 _null_ _null_ _null_ _null_ _null_ pg_stat_reset_single_table_counters _null_ _null_ _null_ ) +insert ( 3777 pg_stat_reset_single_function_counters 11 10 12 1 0 0 0 f f f t f v s 1 0 2278 26 _null_ _null_ _null_ _null_ _null_ pg_stat_reset_single_function_counters _null_ _null_ _null_ ) +insert ( 2307 pg_stat_reset_slru 11 10 12 1 0 0 0 f f f f f v s 1 0 2278 25 _null_ _null_ _null_ _null_ _null_ pg_stat_reset_slru _null_ _null_ _null_ ) +insert ( 3163 pg_trigger_depth 11 10 12 1 0 0 0 f f f t f s r 0 0 23 "" _null_ _null_ _null_ _null_ _null_ pg_trigger_depth _null_ _null_ _null_ ) +insert ( 3778 pg_tablespace_location 11 10 12 1 0 0 0 f f f t f s s 1 0 25 26 _null_ _null_ _null_ _null_ _null_ pg_tablespace_location _null_ _null_ _null_ ) +insert ( 1946 encode 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "17 25" _null_ _null_ _null_ _null_ _null_ binary_encode _null_ _null_ _null_ ) +insert ( 1947 decode 11 10 12 1 0 0 0 f f f t f i s 2 0 17 "25 25" _null_ _null_ _null_ _null_ _null_ binary_decode _null_ _null_ _null_ ) +insert ( 1948 byteaeq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "17 17" _null_ _null_ _null_ _null_ _null_ byteaeq _null_ _null_ _null_ ) +insert ( 1949 bytealt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "17 17" _null_ _null_ _null_ _null_ _null_ bytealt _null_ _null_ _null_ ) +insert ( 1950 byteale 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "17 17" _null_ _null_ _null_ _null_ _null_ byteale _null_ _null_ _null_ ) +insert ( 1951 byteagt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "17 17" _null_ _null_ _null_ _null_ _null_ byteagt _null_ _null_ _null_ ) +insert ( 1952 byteage 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "17 17" _null_ _null_ _null_ _null_ _null_ byteage _null_ _null_ _null_ ) +insert ( 1953 byteane 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "17 17" _null_ _null_ _null_ _null_ _null_ byteane _null_ _null_ _null_ ) +insert ( 1954 byteacmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "17 17" _null_ _null_ _null_ _null_ _null_ byteacmp _null_ _null_ _null_ ) +insert ( 3331 bytea_sortsupport 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ bytea_sortsupport _null_ _null_ _null_ ) +insert ( 3917 timestamp_support 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ timestamp_support _null_ _null_ _null_ ) +insert ( 3944 time_support 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ time_support _null_ _null_ _null_ ) +insert ( 1961 timestamp 11 10 12 1 0 0 3917 f f f t f i s 2 0 1114 "1114 23" _null_ _null_ _null_ _null_ _null_ timestamp_scale _null_ _null_ _null_ ) +insert ( 1965 oidlarger 11 10 12 1 0 0 0 f f f t f i s 2 0 26 "26 26" _null_ _null_ _null_ _null_ _null_ oidlarger _null_ _null_ _null_ ) +insert ( 1966 oidsmaller 11 10 12 1 0 0 0 f f f t f i s 2 0 26 "26 26" _null_ _null_ _null_ _null_ _null_ oidsmaller _null_ _null_ _null_ ) +insert ( 1967 timestamptz 11 10 12 1 0 0 3917 f f f t f i s 2 0 1184 "1184 23" _null_ _null_ _null_ _null_ _null_ timestamptz_scale _null_ _null_ _null_ ) +insert ( 1968 time 11 10 12 1 0 0 3944 f f f t f i s 2 0 1083 "1083 23" _null_ _null_ _null_ _null_ _null_ time_scale _null_ _null_ _null_ ) +insert ( 1969 timetz 11 10 12 1 0 0 3944 f f f t f i s 2 0 1266 "1266 23" _null_ _null_ _null_ _null_ _null_ timetz_scale _null_ _null_ _null_ ) +insert ( 2003 textanycat 11 10 14 1 0 0 0 f f f t f s s 2 0 25 "25 2776" _null_ _null_ _null_ _null_ _null_ "select $1 || $2::pg_catalog.text" _null_ _null_ _null_ ) +insert ( 2004 anytextcat 11 10 14 1 0 0 0 f f f t f s s 2 0 25 "2776 25" _null_ _null_ _null_ _null_ _null_ "select $1::pg_catalog.text || $2" _null_ _null_ _null_ ) +insert ( 2005 bytealike 11 10 12 1 0 0 1023 f f f t f i s 2 0 16 "17 17" _null_ _null_ _null_ _null_ _null_ bytealike _null_ _null_ _null_ ) +insert ( 2006 byteanlike 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "17 17" _null_ _null_ _null_ _null_ _null_ byteanlike _null_ _null_ _null_ ) +insert ( 2007 like 11 10 12 1 0 0 1023 f f f t f i s 2 0 16 "17 17" _null_ _null_ _null_ _null_ _null_ bytealike _null_ _null_ _null_ ) +insert ( 2008 notlike 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "17 17" _null_ _null_ _null_ _null_ _null_ byteanlike _null_ _null_ _null_ ) +insert ( 2009 like_escape 11 10 12 1 0 0 0 f f f t f i s 2 0 17 "17 17" _null_ _null_ _null_ _null_ _null_ like_escape_bytea _null_ _null_ _null_ ) +insert ( 2010 length 11 10 12 1 0 0 0 f f f t f i s 1 0 23 17 _null_ _null_ _null_ _null_ _null_ byteaoctetlen _null_ _null_ _null_ ) +insert ( 2011 byteacat 11 10 12 1 0 0 0 f f f t f i s 2 0 17 "17 17" _null_ _null_ _null_ _null_ _null_ byteacat _null_ _null_ _null_ ) +insert ( 2012 substring 11 10 12 1 0 0 0 f f f t f i s 3 0 17 "17 23 23" _null_ _null_ _null_ _null_ _null_ bytea_substr _null_ _null_ _null_ ) +insert ( 2013 substring 11 10 12 1 0 0 0 f f f t f i s 2 0 17 "17 23" _null_ _null_ _null_ _null_ _null_ bytea_substr_no_len _null_ _null_ _null_ ) +insert ( 2085 substr 11 10 12 1 0 0 0 f f f t f i s 3 0 17 "17 23 23" _null_ _null_ _null_ _null_ _null_ bytea_substr _null_ _null_ _null_ ) +insert ( 2086 substr 11 10 12 1 0 0 0 f f f t f i s 2 0 17 "17 23" _null_ _null_ _null_ _null_ _null_ bytea_substr_no_len _null_ _null_ _null_ ) +insert ( 2014 position 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "17 17" _null_ _null_ _null_ _null_ _null_ byteapos _null_ _null_ _null_ ) +insert ( 2015 btrim 11 10 12 1 0 0 0 f f f t f i s 2 0 17 "17 17" _null_ _null_ _null_ _null_ _null_ byteatrim _null_ _null_ _null_ ) +insert ( 2019 time 11 10 12 1 0 0 0 f f f t f s s 1 0 1083 1184 _null_ _null_ _null_ _null_ _null_ timestamptz_time _null_ _null_ _null_ ) +insert ( 2020 date_trunc 11 10 12 1 0 0 0 f f f t f i s 2 0 1114 "25 1114" _null_ _null_ _null_ _null_ _null_ timestamp_trunc _null_ _null_ _null_ ) +insert ( 2021 date_part 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "25 1114" _null_ _null_ _null_ _null_ _null_ timestamp_part _null_ _null_ _null_ ) +insert ( 2024 timestamp 11 10 12 1 0 0 0 f f f t f i s 1 0 1114 1082 _null_ _null_ _null_ _null_ _null_ date_timestamp _null_ _null_ _null_ ) +insert ( 2025 timestamp 11 10 12 1 0 0 0 f f f t f i s 2 0 1114 "1082 1083" _null_ _null_ _null_ _null_ _null_ datetime_timestamp _null_ _null_ _null_ ) +insert ( 2027 timestamp 11 10 12 1 0 0 0 f f f t f s s 1 0 1114 1184 _null_ _null_ _null_ _null_ _null_ timestamptz_timestamp _null_ _null_ _null_ ) +insert ( 2028 timestamptz 11 10 12 1 0 0 0 f f f t f s s 1 0 1184 1114 _null_ _null_ _null_ _null_ _null_ timestamp_timestamptz _null_ _null_ _null_ ) +insert ( 2029 date 11 10 12 1 0 0 0 f f f t f i s 1 0 1082 1114 _null_ _null_ _null_ _null_ _null_ timestamp_date _null_ _null_ _null_ ) +insert ( 2031 timestamp_mi 11 10 12 1 0 0 0 f f f t f i s 2 0 1186 "1114 1114" _null_ _null_ _null_ _null_ _null_ timestamp_mi _null_ _null_ _null_ ) +insert ( 2032 timestamp_pl_interval 11 10 12 1 0 0 0 f f f t f i s 2 0 1114 "1114 1186" _null_ _null_ _null_ _null_ _null_ timestamp_pl_interval _null_ _null_ _null_ ) +insert ( 2033 timestamp_mi_interval 11 10 12 1 0 0 0 f f f t f i s 2 0 1114 "1114 1186" _null_ _null_ _null_ _null_ _null_ timestamp_mi_interval _null_ _null_ _null_ ) +insert ( 2035 timestamp_smaller 11 10 12 1 0 0 0 f f f t f i s 2 0 1114 "1114 1114" _null_ _null_ _null_ _null_ _null_ timestamp_smaller _null_ _null_ _null_ ) +insert ( 2036 timestamp_larger 11 10 12 1 0 0 0 f f f t f i s 2 0 1114 "1114 1114" _null_ _null_ _null_ _null_ _null_ timestamp_larger _null_ _null_ _null_ ) +insert ( 2037 timezone 11 10 12 1 0 0 0 f f f t f v s 2 0 1266 "25 1266" _null_ _null_ _null_ _null_ _null_ timetz_zone _null_ _null_ _null_ ) +insert ( 2038 timezone 11 10 12 1 0 0 0 f f f t f i s 2 0 1266 "1186 1266" _null_ _null_ _null_ _null_ _null_ timetz_izone _null_ _null_ _null_ ) +insert ( 2039 timestamp_hash 11 10 12 1 0 0 0 f f f t f i s 1 0 23 1114 _null_ _null_ _null_ _null_ _null_ timestamp_hash _null_ _null_ _null_ ) +insert ( 3411 timestamp_hash_extended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "1114 20" _null_ _null_ _null_ _null_ _null_ timestamp_hash_extended _null_ _null_ _null_ ) +insert ( 2041 overlaps 11 10 12 1 0 0 0 f f f f f i s 4 0 16 "1114 1114 1114 1114" _null_ _null_ _null_ _null_ _null_ overlaps_timestamp _null_ _null_ _null_ ) +insert ( 2042 overlaps 11 10 14 1 0 0 0 f f f f f i s 4 0 16 "1114 1186 1114 1186" _null_ _null_ _null_ _null_ _null_ "select ($1, ($1 + $2)) overlaps ($3, ($3 + $4))" _null_ _null_ _null_ ) +insert ( 2043 overlaps 11 10 14 1 0 0 0 f f f f f i s 4 0 16 "1114 1114 1114 1186" _null_ _null_ _null_ _null_ _null_ "select ($1, $2) overlaps ($3, ($3 + $4))" _null_ _null_ _null_ ) +insert ( 2044 overlaps 11 10 14 1 0 0 0 f f f f f i s 4 0 16 "1114 1186 1114 1114" _null_ _null_ _null_ _null_ _null_ "select ($1, ($1 + $2)) overlaps ($3, $4)" _null_ _null_ _null_ ) +insert ( 2045 timestamp_cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "1114 1114" _null_ _null_ _null_ _null_ _null_ timestamp_cmp _null_ _null_ _null_ ) +insert ( 3137 timestamp_sortsupport 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ timestamp_sortsupport _null_ _null_ _null_ ) +insert ( 4134 in_range 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "1114 1114 1186 16 16" _null_ _null_ _null_ _null_ _null_ in_range_timestamp_interval _null_ _null_ _null_ ) +insert ( 4135 in_range 11 10 12 1 0 0 0 f f f t f s s 5 0 16 "1184 1184 1186 16 16" _null_ _null_ _null_ _null_ _null_ in_range_timestamptz_interval _null_ _null_ _null_ ) +insert ( 4136 in_range 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "1186 1186 1186 16 16" _null_ _null_ _null_ _null_ _null_ in_range_interval_interval _null_ _null_ _null_ ) +insert ( 4137 in_range 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "1083 1083 1186 16 16" _null_ _null_ _null_ _null_ _null_ in_range_time_interval _null_ _null_ _null_ ) +insert ( 4138 in_range 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "1266 1266 1186 16 16" _null_ _null_ _null_ _null_ _null_ in_range_timetz_interval _null_ _null_ _null_ ) +insert ( 2046 time 11 10 12 1 0 0 0 f f f t f i s 1 0 1083 1266 _null_ _null_ _null_ _null_ _null_ timetz_time _null_ _null_ _null_ ) +insert ( 2047 timetz 11 10 12 1 0 0 0 f f f t f s s 1 0 1266 1083 _null_ _null_ _null_ _null_ _null_ time_timetz _null_ _null_ _null_ ) +insert ( 2048 isfinite 11 10 12 1 0 0 0 f f f t f i s 1 0 16 1114 _null_ _null_ _null_ _null_ _null_ timestamp_finite _null_ _null_ _null_ ) +insert ( 2049 to_char 11 10 12 1 0 0 0 f f f t f s s 2 0 25 "1114 25" _null_ _null_ _null_ _null_ _null_ timestamp_to_char _null_ _null_ _null_ ) +insert ( 2052 timestamp_eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1114 1114" _null_ _null_ _null_ _null_ _null_ timestamp_eq _null_ _null_ _null_ ) +insert ( 2053 timestamp_ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1114 1114" _null_ _null_ _null_ _null_ _null_ timestamp_ne _null_ _null_ _null_ ) +insert ( 2054 timestamp_lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1114 1114" _null_ _null_ _null_ _null_ _null_ timestamp_lt _null_ _null_ _null_ ) +insert ( 2055 timestamp_le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1114 1114" _null_ _null_ _null_ _null_ _null_ timestamp_le _null_ _null_ _null_ ) +insert ( 2056 timestamp_ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1114 1114" _null_ _null_ _null_ _null_ _null_ timestamp_ge _null_ _null_ _null_ ) +insert ( 2057 timestamp_gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1114 1114" _null_ _null_ _null_ _null_ _null_ timestamp_gt _null_ _null_ _null_ ) +insert ( 2058 age 11 10 12 1 0 0 0 f f f t f i s 2 0 1186 "1114 1114" _null_ _null_ _null_ _null_ _null_ timestamp_age _null_ _null_ _null_ ) +insert ( 2059 age 11 10 14 1 0 0 0 f f f t f s s 1 0 1186 1114 _null_ _null_ _null_ _null_ _null_ "select pg_catalog.age(cast(current_date as timestamp without time zone), $1)" _null_ _null_ _null_ ) +insert ( 2069 timezone 11 10 12 1 0 0 0 f f f t f i s 2 0 1184 "25 1114" _null_ _null_ _null_ _null_ _null_ timestamp_zone _null_ _null_ _null_ ) +insert ( 2070 timezone 11 10 12 1 0 0 0 f f f t f i s 2 0 1184 "1186 1114" _null_ _null_ _null_ _null_ _null_ timestamp_izone _null_ _null_ _null_ ) +insert ( 2071 date_pl_interval 11 10 12 1 0 0 0 f f f t f i s 2 0 1114 "1082 1186" _null_ _null_ _null_ _null_ _null_ date_pl_interval _null_ _null_ _null_ ) +insert ( 2072 date_mi_interval 11 10 12 1 0 0 0 f f f t f i s 2 0 1114 "1082 1186" _null_ _null_ _null_ _null_ _null_ date_mi_interval _null_ _null_ _null_ ) +insert ( 2073 substring 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "25 25" _null_ _null_ _null_ _null_ _null_ textregexsubstr _null_ _null_ _null_ ) +insert ( 2074 substring 11 10 14 1 0 0 0 f f f t f i s 3 0 25 "25 25 25" _null_ _null_ _null_ _null_ _null_ "select pg_catalog.substring($1, pg_catalog.similar_to_escape($2, $3))" _null_ _null_ _null_ ) +insert ( 2075 bit 11 10 12 1 0 0 0 f f f t f i s 2 0 1560 "20 23" _null_ _null_ _null_ _null_ _null_ bitfromint8 _null_ _null_ _null_ ) +insert ( 2076 int8 11 10 12 1 0 0 0 f f f t f i s 1 0 20 1560 _null_ _null_ _null_ _null_ _null_ bittoint8 _null_ _null_ _null_ ) +insert ( 2077 current_setting 11 10 12 1 0 0 0 f f f t f s s 1 0 25 25 _null_ _null_ _null_ _null_ _null_ show_config_by_name _null_ _null_ _null_ ) +insert ( 3294 current_setting 11 10 12 1 0 0 0 f f f t f s s 2 0 25 "25 16" _null_ _null_ _null_ _null_ _null_ show_config_by_name_missing_ok _null_ _null_ _null_ ) +insert ( 2078 set_config 11 10 12 1 0 0 0 f f f f f v u 3 0 25 "25 25 16" _null_ _null_ _null_ _null_ _null_ set_config_by_name _null_ _null_ _null_ ) +insert ( 2084 pg_show_all_settings 11 10 12 1 1000 0 0 f f f t t s s 0 0 2249 "" "{25,25,25,25,25,25,25,25,25,25,25,1009,25,25,25,23,16}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{name,setting,unit,category,short_desc,extra_desc,context,vartype,source,min_val,max_val,enumvals,boot_val,reset_val,sourcefile,sourceline,pending_restart}" _null_ _null_ show_all_settings _null_ _null_ _null_ ) +insert ( 3329 pg_show_all_file_settings 11 10 12 1 1000 0 0 f f f t t v s 0 0 2249 "" "{25,23,23,25,25,16,25}" "{o,o,o,o,o,o,o}" "{sourcefile,sourceline,seqno,name,setting,applied,error}" _null_ _null_ show_all_file_settings _null_ _null_ _null_ ) +insert ( 3401 pg_hba_file_rules 11 10 12 1 1000 0 0 f f f t t v s 0 0 2249 "" "{23,25,1009,1009,25,25,25,1009,25}" "{o,o,o,o,o,o,o,o,o}" "{line_number,type,database,user_name,address,netmask,auth_method,options,error}" _null_ _null_ pg_hba_file_rules _null_ _null_ _null_ ) +insert ( 1371 pg_lock_status 11 10 12 1 1000 0 0 f f f t t v s 0 0 2249 "" "{25,26,26,23,21,25,28,26,26,21,25,23,25,16,16}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{locktype,database,relation,page,tuple,virtualxid,transactionid,classid,objid,objsubid,virtualtransaction,pid,mode,granted,fastpath}" _null_ _null_ pg_lock_status _null_ _null_ _null_ ) +insert ( 2561 pg_blocking_pids 11 10 12 1 0 0 0 f f f t f v s 1 0 1007 23 _null_ _null_ _null_ _null_ _null_ pg_blocking_pids _null_ _null_ _null_ ) +insert ( 3376 pg_safe_snapshot_blocking_pids 11 10 12 1 0 0 0 f f f t f v s 1 0 1007 23 _null_ _null_ _null_ _null_ _null_ pg_safe_snapshot_blocking_pids _null_ _null_ _null_ ) +insert ( 3378 pg_isolation_test_session_is_blocked 11 10 12 1 0 0 0 f f f t f v s 2 0 16 "23 1007" _null_ _null_ _null_ _null_ _null_ pg_isolation_test_session_is_blocked _null_ _null_ _null_ ) +insert ( 1065 pg_prepared_xact 11 10 12 1 1000 0 0 f f f t t v s 0 0 2249 "" "{28,25,1184,26,26}" "{o,o,o,o,o}" "{transaction,gid,prepared,ownerid,dbid}" _null_ _null_ pg_prepared_xact _null_ _null_ _null_ ) +insert ( 3819 pg_get_multixact_members 11 10 12 1 1000 0 0 f f f t t v s 1 0 2249 28 "{28,28,25}" "{i,o,o}" "{multixid,xid,mode}" _null_ _null_ pg_get_multixact_members _null_ _null_ _null_ ) +insert ( 3581 pg_xact_commit_timestamp 11 10 12 1 0 0 0 f f f t f v s 1 0 1184 28 _null_ _null_ _null_ _null_ _null_ pg_xact_commit_timestamp _null_ _null_ _null_ ) +insert ( 3583 pg_last_committed_xact 11 10 12 1 0 0 0 f f f t f v s 0 0 2249 "" "{28,1184}" "{o,o}" "{xid,timestamp}" _null_ _null_ pg_last_committed_xact _null_ _null_ _null_ ) +insert ( 3537 pg_describe_object 11 10 12 1 0 0 0 f f f t f s s 3 0 25 "26 26 23" _null_ _null_ _null_ _null_ _null_ pg_describe_object _null_ _null_ _null_ ) +insert ( 3839 pg_identify_object 11 10 12 1 0 0 0 f f f t f s s 3 0 2249 "26 26 23" "{26,26,23,25,25,25,25}" "{i,i,i,o,o,o,o}" "{classid,objid,objsubid,type,schema,name,identity}" _null_ _null_ pg_identify_object _null_ _null_ _null_ ) +insert ( 3382 pg_identify_object_as_address 11 10 12 1 0 0 0 f f f t f s s 3 0 2249 "26 26 23" "{26,26,23,25,1009,1009}" "{i,i,i,o,o,o}" "{classid,objid,objsubid,type,object_names,object_args}" _null_ _null_ pg_identify_object_as_address _null_ _null_ _null_ ) +insert ( 3954 pg_get_object_address 11 10 12 1 0 0 0 f f f t f s s 3 0 2249 "25 1009 1009" "{25,1009,1009,26,26,23}" "{i,i,i,o,o,o}" "{type,object_names,object_args,classid,objid,objsubid}" _null_ _null_ pg_get_object_address _null_ _null_ _null_ ) +insert ( 2079 pg_table_is_visible 11 10 12 10 0 0 0 f f f t f s s 1 0 16 26 _null_ _null_ _null_ _null_ _null_ pg_table_is_visible _null_ _null_ _null_ ) +insert ( 2080 pg_type_is_visible 11 10 12 10 0 0 0 f f f t f s s 1 0 16 26 _null_ _null_ _null_ _null_ _null_ pg_type_is_visible _null_ _null_ _null_ ) +insert ( 2081 pg_function_is_visible 11 10 12 10 0 0 0 f f f t f s s 1 0 16 26 _null_ _null_ _null_ _null_ _null_ pg_function_is_visible _null_ _null_ _null_ ) +insert ( 2082 pg_operator_is_visible 11 10 12 10 0 0 0 f f f t f s s 1 0 16 26 _null_ _null_ _null_ _null_ _null_ pg_operator_is_visible _null_ _null_ _null_ ) +insert ( 2083 pg_opclass_is_visible 11 10 12 10 0 0 0 f f f t f s s 1 0 16 26 _null_ _null_ _null_ _null_ _null_ pg_opclass_is_visible _null_ _null_ _null_ ) +insert ( 3829 pg_opfamily_is_visible 11 10 12 10 0 0 0 f f f t f s s 1 0 16 26 _null_ _null_ _null_ _null_ _null_ pg_opfamily_is_visible _null_ _null_ _null_ ) +insert ( 2093 pg_conversion_is_visible 11 10 12 10 0 0 0 f f f t f s s 1 0 16 26 _null_ _null_ _null_ _null_ _null_ pg_conversion_is_visible _null_ _null_ _null_ ) +insert ( 3403 pg_statistics_obj_is_visible 11 10 12 10 0 0 0 f f f t f s s 1 0 16 26 _null_ _null_ _null_ _null_ _null_ pg_statistics_obj_is_visible _null_ _null_ _null_ ) +insert ( 3756 pg_ts_parser_is_visible 11 10 12 10 0 0 0 f f f t f s s 1 0 16 26 _null_ _null_ _null_ _null_ _null_ pg_ts_parser_is_visible _null_ _null_ _null_ ) +insert ( 3757 pg_ts_dict_is_visible 11 10 12 10 0 0 0 f f f t f s s 1 0 16 26 _null_ _null_ _null_ _null_ _null_ pg_ts_dict_is_visible _null_ _null_ _null_ ) +insert ( 3768 pg_ts_template_is_visible 11 10 12 10 0 0 0 f f f t f s s 1 0 16 26 _null_ _null_ _null_ _null_ _null_ pg_ts_template_is_visible _null_ _null_ _null_ ) +insert ( 3758 pg_ts_config_is_visible 11 10 12 10 0 0 0 f f f t f s s 1 0 16 26 _null_ _null_ _null_ _null_ _null_ pg_ts_config_is_visible _null_ _null_ _null_ ) +insert ( 3815 pg_collation_is_visible 11 10 12 10 0 0 0 f f f t f s s 1 0 16 26 _null_ _null_ _null_ _null_ _null_ pg_collation_is_visible _null_ _null_ _null_ ) +insert ( 2854 pg_my_temp_schema 11 10 12 1 0 0 0 f f f t f s r 0 0 26 "" _null_ _null_ _null_ _null_ _null_ pg_my_temp_schema _null_ _null_ _null_ ) +insert ( 2855 pg_is_other_temp_schema 11 10 12 1 0 0 0 f f f t f s s 1 0 16 26 _null_ _null_ _null_ _null_ _null_ pg_is_other_temp_schema _null_ _null_ _null_ ) +insert ( 2171 pg_cancel_backend 11 10 12 1 0 0 0 f f f t f v s 1 0 16 23 _null_ _null_ _null_ _null_ _null_ pg_cancel_backend _null_ _null_ _null_ ) +insert ( 2096 pg_terminate_backend 11 10 12 1 0 0 0 f f f t f v s 1 0 16 23 _null_ _null_ _null_ _null_ _null_ pg_terminate_backend _null_ _null_ _null_ ) +insert ( 2172 pg_start_backup 11 10 12 1 0 0 0 f f f t f v r 3 0 3220 "25 16 16" _null_ _null_ _null_ _null_ _null_ pg_start_backup _null_ _null_ _null_ ) +insert ( 2173 pg_stop_backup 11 10 12 1 0 0 0 f f f t f v r 0 0 3220 "" _null_ _null_ _null_ _null_ _null_ pg_stop_backup _null_ _null_ _null_ ) +insert ( 2739 pg_stop_backup 11 10 12 1 1 0 0 f f f t t v r 2 0 2249 "16 16" "{16,16,3220,25,25}" "{i,i,o,o,o}" "{exclusive,wait_for_archive,lsn,labelfile,spcmapfile}" _null_ _null_ pg_stop_backup_v2 _null_ _null_ _null_ ) +insert ( 3813 pg_is_in_backup 11 10 12 1 0 0 0 f f f t f v s 0 0 16 "" _null_ _null_ _null_ _null_ _null_ pg_is_in_backup _null_ _null_ _null_ ) +insert ( 3814 pg_backup_start_time 11 10 12 1 0 0 0 f f f t f s s 0 0 1184 "" _null_ _null_ _null_ _null_ _null_ pg_backup_start_time _null_ _null_ _null_ ) +insert ( 3436 pg_promote 11 10 12 1 0 0 0 f f f t f v s 2 0 16 "16 23" _null_ _null_ "{wait,wait_seconds}" _null_ _null_ pg_promote _null_ _null_ _null_ ) +insert ( 2848 pg_switch_wal 11 10 12 1 0 0 0 f f f t f v s 0 0 3220 "" _null_ _null_ _null_ _null_ _null_ pg_switch_wal _null_ _null_ _null_ ) +insert ( 3098 pg_create_restore_point 11 10 12 1 0 0 0 f f f t f v s 1 0 3220 25 _null_ _null_ _null_ _null_ _null_ pg_create_restore_point _null_ _null_ _null_ ) +insert ( 2849 pg_current_wal_lsn 11 10 12 1 0 0 0 f f f t f v s 0 0 3220 "" _null_ _null_ _null_ _null_ _null_ pg_current_wal_lsn _null_ _null_ _null_ ) +insert ( 2852 pg_current_wal_insert_lsn 11 10 12 1 0 0 0 f f f t f v s 0 0 3220 "" _null_ _null_ _null_ _null_ _null_ pg_current_wal_insert_lsn _null_ _null_ _null_ ) +insert ( 3330 pg_current_wal_flush_lsn 11 10 12 1 0 0 0 f f f t f v s 0 0 3220 "" _null_ _null_ _null_ _null_ _null_ pg_current_wal_flush_lsn _null_ _null_ _null_ ) +insert ( 2850 pg_walfile_name_offset 11 10 12 1 0 0 0 f f f t f i s 1 0 2249 3220 "{3220,25,23}" "{i,o,o}" "{lsn,file_name,file_offset}" _null_ _null_ pg_walfile_name_offset _null_ _null_ _null_ ) +insert ( 2851 pg_walfile_name 11 10 12 1 0 0 0 f f f t f i s 1 0 25 3220 _null_ _null_ _null_ _null_ _null_ pg_walfile_name _null_ _null_ _null_ ) +insert ( 3165 pg_wal_lsn_diff 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "3220 3220" _null_ _null_ _null_ _null_ _null_ pg_wal_lsn_diff _null_ _null_ _null_ ) +insert ( 3809 pg_export_snapshot 11 10 12 1 0 0 0 f f f t f v u 0 0 25 "" _null_ _null_ _null_ _null_ _null_ pg_export_snapshot _null_ _null_ _null_ ) +insert ( 3810 pg_is_in_recovery 11 10 12 1 0 0 0 f f f t f v s 0 0 16 "" _null_ _null_ _null_ _null_ _null_ pg_is_in_recovery _null_ _null_ _null_ ) +insert ( 3820 pg_last_wal_receive_lsn 11 10 12 1 0 0 0 f f f t f v s 0 0 3220 "" _null_ _null_ _null_ _null_ _null_ pg_last_wal_receive_lsn _null_ _null_ _null_ ) +insert ( 3821 pg_last_wal_replay_lsn 11 10 12 1 0 0 0 f f f t f v s 0 0 3220 "" _null_ _null_ _null_ _null_ _null_ pg_last_wal_replay_lsn _null_ _null_ _null_ ) +insert ( 3830 pg_last_xact_replay_timestamp 11 10 12 1 0 0 0 f f f t f v s 0 0 1184 "" _null_ _null_ _null_ _null_ _null_ pg_last_xact_replay_timestamp _null_ _null_ _null_ ) +insert ( 3071 pg_wal_replay_pause 11 10 12 1 0 0 0 f f f t f v s 0 0 2278 "" _null_ _null_ _null_ _null_ _null_ pg_wal_replay_pause _null_ _null_ _null_ ) +insert ( 3072 pg_wal_replay_resume 11 10 12 1 0 0 0 f f f t f v s 0 0 2278 "" _null_ _null_ _null_ _null_ _null_ pg_wal_replay_resume _null_ _null_ _null_ ) +insert ( 3073 pg_is_wal_replay_paused 11 10 12 1 0 0 0 f f f t f v s 0 0 16 "" _null_ _null_ _null_ _null_ _null_ pg_is_wal_replay_paused _null_ _null_ _null_ ) +insert ( 2621 pg_reload_conf 11 10 12 1 0 0 0 f f f t f v s 0 0 16 "" _null_ _null_ _null_ _null_ _null_ pg_reload_conf _null_ _null_ _null_ ) +insert ( 2622 pg_rotate_logfile 11 10 12 1 0 0 0 f f f t f v s 0 0 16 "" _null_ _null_ _null_ _null_ _null_ pg_rotate_logfile_v2 _null_ _null_ _null_ ) +insert ( 4099 pg_rotate_logfile_old 11 10 12 1 0 0 0 f f f t f v s 0 0 16 "" _null_ _null_ _null_ _null_ _null_ pg_rotate_logfile _null_ _null_ _null_ ) +insert ( 3800 pg_current_logfile 11 10 12 1 0 0 0 f f f f f v s 0 0 25 "" _null_ _null_ _null_ _null_ _null_ pg_current_logfile _null_ _null_ _null_ ) +insert ( 3801 pg_current_logfile 11 10 12 1 0 0 0 f f f f f v s 1 0 25 25 _null_ _null_ _null_ _null_ _null_ pg_current_logfile_1arg _null_ _null_ _null_ ) +insert ( 2623 pg_stat_file 11 10 12 1 0 0 0 f f f t f v s 1 0 2249 25 "{25,20,1184,1184,1184,1184,16}" "{i,o,o,o,o,o,o}" "{filename,size,access,modification,change,creation,isdir}" _null_ _null_ pg_stat_file_1arg _null_ _null_ _null_ ) +insert ( 3307 pg_stat_file 11 10 12 1 0 0 0 f f f t f v s 2 0 2249 "25 16" "{25,16,20,1184,1184,1184,1184,16}" "{i,i,o,o,o,o,o,o}" "{filename,missing_ok,size,access,modification,change,creation,isdir}" _null_ _null_ pg_stat_file _null_ _null_ _null_ ) +insert ( 2624 pg_read_file 11 10 12 1 0 0 0 f f f t f v s 3 0 25 "25 20 20" _null_ _null_ _null_ _null_ _null_ pg_read_file_off_len _null_ _null_ _null_ ) +insert ( 3293 pg_read_file 11 10 12 1 0 0 0 f f f t f v s 4 0 25 "25 20 20 16" _null_ _null_ _null_ _null_ _null_ pg_read_file_v2 _null_ _null_ _null_ ) +insert ( 4100 pg_read_file_old 11 10 12 1 0 0 0 f f f t f v s 3 0 25 "25 20 20" _null_ _null_ _null_ _null_ _null_ pg_read_file _null_ _null_ _null_ ) +insert ( 3826 pg_read_file 11 10 12 1 0 0 0 f f f t f v s 1 0 25 25 _null_ _null_ _null_ _null_ _null_ pg_read_file_all _null_ _null_ _null_ ) +insert ( 3827 pg_read_binary_file 11 10 12 1 0 0 0 f f f t f v s 3 0 17 "25 20 20" _null_ _null_ _null_ _null_ _null_ pg_read_binary_file_off_len _null_ _null_ _null_ ) +insert ( 3295 pg_read_binary_file 11 10 12 1 0 0 0 f f f t f v s 4 0 17 "25 20 20 16" _null_ _null_ _null_ _null_ _null_ pg_read_binary_file _null_ _null_ _null_ ) +insert ( 3828 pg_read_binary_file 11 10 12 1 0 0 0 f f f t f v s 1 0 17 25 _null_ _null_ _null_ _null_ _null_ pg_read_binary_file_all _null_ _null_ _null_ ) +insert ( 2625 pg_ls_dir 11 10 12 1 1000 0 0 f f f t t v s 1 0 25 25 _null_ _null_ _null_ _null_ _null_ pg_ls_dir_1arg _null_ _null_ _null_ ) +insert ( 3297 pg_ls_dir 11 10 12 1 1000 0 0 f f f t t v s 3 0 25 "25 16 16" _null_ _null_ _null_ _null_ _null_ pg_ls_dir _null_ _null_ _null_ ) +insert ( 2626 pg_sleep 11 10 12 1 0 0 0 f f f t f v s 1 0 2278 701 _null_ _null_ _null_ _null_ _null_ pg_sleep _null_ _null_ _null_ ) +insert ( 3935 pg_sleep_for 11 10 14 1 0 0 0 f f f t f v s 1 0 2278 1186 _null_ _null_ _null_ _null_ _null_ "select pg_catalog.pg_sleep(extract(epoch from pg_catalog.clock_timestamp() operator(pg_catalog.+) $1) operator(pg_catalog.-) extract(epoch from pg_catalog.clock_timestamp()))" _null_ _null_ _null_ ) +insert ( 3936 pg_sleep_until 11 10 14 1 0 0 0 f f f t f v s 1 0 2278 1184 _null_ _null_ _null_ _null_ _null_ "select pg_catalog.pg_sleep(extract(epoch from $1) operator(pg_catalog.-) extract(epoch from pg_catalog.clock_timestamp()))" _null_ _null_ _null_ ) +insert ( 315 pg_jit_available 11 10 12 1 0 0 0 f f f t f v s 0 0 16 "" _null_ _null_ _null_ _null_ _null_ pg_jit_available _null_ _null_ _null_ ) +insert ( 2971 text 11 10 12 1 0 0 0 f f f t f i s 1 0 25 16 _null_ _null_ _null_ _null_ _null_ booltext _null_ _null_ _null_ ) +insert ( 2100 avg 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 20 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2101 avg 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 23 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2102 avg 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 21 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2103 avg 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2104 avg 11 10 12 1 0 0 0 a f f f f i s 1 0 701 700 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2105 avg 11 10 12 1 0 0 0 a f f f f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2106 avg 11 10 12 1 0 0 0 a f f f f i s 1 0 1186 1186 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2107 sum 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 20 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2108 sum 11 10 12 1 0 0 0 a f f f f i s 1 0 20 23 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2109 sum 11 10 12 1 0 0 0 a f f f f i s 1 0 20 21 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2110 sum 11 10 12 1 0 0 0 a f f f f i s 1 0 700 700 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2111 sum 11 10 12 1 0 0 0 a f f f f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2112 sum 11 10 12 1 0 0 0 a f f f f i s 1 0 790 790 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2113 sum 11 10 12 1 0 0 0 a f f f f i s 1 0 1186 1186 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2114 sum 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2115 max 11 10 12 1 0 0 0 a f f f f i s 1 0 20 20 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2116 max 11 10 12 1 0 0 0 a f f f f i s 1 0 23 23 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2117 max 11 10 12 1 0 0 0 a f f f f i s 1 0 21 21 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2118 max 11 10 12 1 0 0 0 a f f f f i s 1 0 26 26 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2119 max 11 10 12 1 0 0 0 a f f f f i s 1 0 700 700 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2120 max 11 10 12 1 0 0 0 a f f f f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2122 max 11 10 12 1 0 0 0 a f f f f i s 1 0 1082 1082 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2123 max 11 10 12 1 0 0 0 a f f f f i s 1 0 1083 1083 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2124 max 11 10 12 1 0 0 0 a f f f f i s 1 0 1266 1266 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2125 max 11 10 12 1 0 0 0 a f f f f i s 1 0 790 790 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2126 max 11 10 12 1 0 0 0 a f f f f i s 1 0 1114 1114 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2127 max 11 10 12 1 0 0 0 a f f f f i s 1 0 1184 1184 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2128 max 11 10 12 1 0 0 0 a f f f f i s 1 0 1186 1186 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2129 max 11 10 12 1 0 0 0 a f f f f i s 1 0 25 25 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2130 max 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2050 max 11 10 12 1 0 0 0 a f f f f i s 1 0 2277 2277 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2244 max 11 10 12 1 0 0 0 a f f f f i s 1 0 1042 1042 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2797 max 11 10 12 1 0 0 0 a f f f f i s 1 0 27 27 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3564 max 11 10 12 1 0 0 0 a f f f f i s 1 0 869 869 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 4189 max 11 10 12 1 0 0 0 a f f f f i s 1 0 3220 3220 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2131 min 11 10 12 1 0 0 0 a f f f f i s 1 0 20 20 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2132 min 11 10 12 1 0 0 0 a f f f f i s 1 0 23 23 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2133 min 11 10 12 1 0 0 0 a f f f f i s 1 0 21 21 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2134 min 11 10 12 1 0 0 0 a f f f f i s 1 0 26 26 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2135 min 11 10 12 1 0 0 0 a f f f f i s 1 0 700 700 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2136 min 11 10 12 1 0 0 0 a f f f f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2138 min 11 10 12 1 0 0 0 a f f f f i s 1 0 1082 1082 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2139 min 11 10 12 1 0 0 0 a f f f f i s 1 0 1083 1083 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2140 min 11 10 12 1 0 0 0 a f f f f i s 1 0 1266 1266 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2141 min 11 10 12 1 0 0 0 a f f f f i s 1 0 790 790 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2142 min 11 10 12 1 0 0 0 a f f f f i s 1 0 1114 1114 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2143 min 11 10 12 1 0 0 0 a f f f f i s 1 0 1184 1184 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2144 min 11 10 12 1 0 0 0 a f f f f i s 1 0 1186 1186 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2145 min 11 10 12 1 0 0 0 a f f f f i s 1 0 25 25 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2146 min 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2051 min 11 10 12 1 0 0 0 a f f f f i s 1 0 2277 2277 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2245 min 11 10 12 1 0 0 0 a f f f f i s 1 0 1042 1042 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2798 min 11 10 12 1 0 0 0 a f f f f i s 1 0 27 27 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3565 min 11 10 12 1 0 0 0 a f f f f i s 1 0 869 869 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 4190 min 11 10 12 1 0 0 0 a f f f f i s 1 0 3220 3220 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2147 count 11 10 12 1 0 0 0 a f f f f i s 1 0 20 2276 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2803 count 11 10 12 1 0 0 0 a f f f f i s 0 0 20 "" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2718 var_pop 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 20 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2719 var_pop 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 23 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2720 var_pop 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 21 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2721 var_pop 11 10 12 1 0 0 0 a f f f f i s 1 0 701 700 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2722 var_pop 11 10 12 1 0 0 0 a f f f f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2723 var_pop 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2641 var_samp 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 20 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2642 var_samp 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 23 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2643 var_samp 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 21 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2644 var_samp 11 10 12 1 0 0 0 a f f f f i s 1 0 701 700 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2645 var_samp 11 10 12 1 0 0 0 a f f f f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2646 var_samp 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2148 variance 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 20 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2149 variance 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 23 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2150 variance 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 21 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2151 variance 11 10 12 1 0 0 0 a f f f f i s 1 0 701 700 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2152 variance 11 10 12 1 0 0 0 a f f f f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2153 variance 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2724 stddev_pop 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 20 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2725 stddev_pop 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 23 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2726 stddev_pop 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 21 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2727 stddev_pop 11 10 12 1 0 0 0 a f f f f i s 1 0 701 700 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2728 stddev_pop 11 10 12 1 0 0 0 a f f f f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2729 stddev_pop 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2712 stddev_samp 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 20 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2713 stddev_samp 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 23 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2714 stddev_samp 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 21 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2715 stddev_samp 11 10 12 1 0 0 0 a f f f f i s 1 0 701 700 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2716 stddev_samp 11 10 12 1 0 0 0 a f f f f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2717 stddev_samp 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2154 stddev 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 20 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2155 stddev 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 23 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2156 stddev 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 21 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2157 stddev 11 10 12 1 0 0 0 a f f f f i s 1 0 701 700 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2158 stddev 11 10 12 1 0 0 0 a f f f f i s 1 0 701 701 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2159 stddev 11 10 12 1 0 0 0 a f f f f i s 1 0 1700 1700 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2818 regr_count 11 10 12 1 0 0 0 a f f f f i s 2 0 20 "701 701" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2819 regr_sxx 11 10 12 1 0 0 0 a f f f f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2820 regr_syy 11 10 12 1 0 0 0 a f f f f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2821 regr_sxy 11 10 12 1 0 0 0 a f f f f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2822 regr_avgx 11 10 12 1 0 0 0 a f f f f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2823 regr_avgy 11 10 12 1 0 0 0 a f f f f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2824 regr_r2 11 10 12 1 0 0 0 a f f f f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2825 regr_slope 11 10 12 1 0 0 0 a f f f f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2826 regr_intercept 11 10 12 1 0 0 0 a f f f f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2827 covar_pop 11 10 12 1 0 0 0 a f f f f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2828 covar_samp 11 10 12 1 0 0 0 a f f f f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2829 corr 11 10 12 1 0 0 0 a f f f f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2160 text_pattern_lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ text_pattern_lt _null_ _null_ _null_ ) +insert ( 2161 text_pattern_le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ text_pattern_le _null_ _null_ _null_ ) +insert ( 2163 text_pattern_ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ text_pattern_ge _null_ _null_ _null_ ) +insert ( 2164 text_pattern_gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ text_pattern_gt _null_ _null_ _null_ ) +insert ( 2166 bttext_pattern_cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "25 25" _null_ _null_ _null_ _null_ _null_ bttext_pattern_cmp _null_ _null_ _null_ ) +insert ( 3332 bttext_pattern_sortsupport 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ bttext_pattern_sortsupport _null_ _null_ _null_ ) +insert ( 2174 bpchar_pattern_lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1042 1042" _null_ _null_ _null_ _null_ _null_ bpchar_pattern_lt _null_ _null_ _null_ ) +insert ( 2175 bpchar_pattern_le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1042 1042" _null_ _null_ _null_ _null_ _null_ bpchar_pattern_le _null_ _null_ _null_ ) +insert ( 2177 bpchar_pattern_ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1042 1042" _null_ _null_ _null_ _null_ _null_ bpchar_pattern_ge _null_ _null_ _null_ ) +insert ( 2178 bpchar_pattern_gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "1042 1042" _null_ _null_ _null_ _null_ _null_ bpchar_pattern_gt _null_ _null_ _null_ ) +insert ( 2180 btbpchar_pattern_cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "1042 1042" _null_ _null_ _null_ _null_ _null_ btbpchar_pattern_cmp _null_ _null_ _null_ ) +insert ( 3333 btbpchar_pattern_sortsupport 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ btbpchar_pattern_sortsupport _null_ _null_ _null_ ) +insert ( 2188 btint48cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "23 20" _null_ _null_ _null_ _null_ _null_ btint48cmp _null_ _null_ _null_ ) +insert ( 2189 btint84cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "20 23" _null_ _null_ _null_ _null_ _null_ btint84cmp _null_ _null_ _null_ ) +insert ( 2190 btint24cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "21 23" _null_ _null_ _null_ _null_ _null_ btint24cmp _null_ _null_ _null_ ) +insert ( 2191 btint42cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "23 21" _null_ _null_ _null_ _null_ _null_ btint42cmp _null_ _null_ _null_ ) +insert ( 2192 btint28cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "21 20" _null_ _null_ _null_ _null_ _null_ btint28cmp _null_ _null_ _null_ ) +insert ( 2193 btint82cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "20 21" _null_ _null_ _null_ _null_ _null_ btint82cmp _null_ _null_ _null_ ) +insert ( 2194 btfloat48cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "700 701" _null_ _null_ _null_ _null_ _null_ btfloat48cmp _null_ _null_ _null_ ) +insert ( 2195 btfloat84cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "701 700" _null_ _null_ _null_ _null_ _null_ btfloat84cmp _null_ _null_ _null_ ) +insert ( 2212 regprocedurein 11 10 12 1 0 0 0 f f f t f s s 1 0 2202 2275 _null_ _null_ _null_ _null_ _null_ regprocedurein _null_ _null_ _null_ ) +insert ( 2213 regprocedureout 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 2202 _null_ _null_ _null_ _null_ _null_ regprocedureout _null_ _null_ _null_ ) +insert ( 2214 regoperin 11 10 12 1 0 0 0 f f f t f s s 1 0 2203 2275 _null_ _null_ _null_ _null_ _null_ regoperin _null_ _null_ _null_ ) +insert ( 2215 regoperout 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 2203 _null_ _null_ _null_ _null_ _null_ regoperout _null_ _null_ _null_ ) +insert ( 3492 to_regoper 11 10 12 1 0 0 0 f f f t f s s 1 0 2203 25 _null_ _null_ _null_ _null_ _null_ to_regoper _null_ _null_ _null_ ) +insert ( 3476 to_regoperator 11 10 12 1 0 0 0 f f f t f s s 1 0 2204 25 _null_ _null_ _null_ _null_ _null_ to_regoperator _null_ _null_ _null_ ) +insert ( 2216 regoperatorin 11 10 12 1 0 0 0 f f f t f s s 1 0 2204 2275 _null_ _null_ _null_ _null_ _null_ regoperatorin _null_ _null_ _null_ ) +insert ( 2217 regoperatorout 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 2204 _null_ _null_ _null_ _null_ _null_ regoperatorout _null_ _null_ _null_ ) +insert ( 2218 regclassin 11 10 12 1 0 0 0 f f f t f s s 1 0 2205 2275 _null_ _null_ _null_ _null_ _null_ regclassin _null_ _null_ _null_ ) +insert ( 2219 regclassout 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 2205 _null_ _null_ _null_ _null_ _null_ regclassout _null_ _null_ _null_ ) +insert ( 3495 to_regclass 11 10 12 1 0 0 0 f f f t f s s 1 0 2205 25 _null_ _null_ _null_ _null_ _null_ to_regclass _null_ _null_ _null_ ) +insert ( 4193 regcollationin 11 10 12 1 0 0 0 f f f t f s s 1 0 4191 2275 _null_ _null_ _null_ _null_ _null_ regcollationin _null_ _null_ _null_ ) +insert ( 4194 regcollationout 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 4191 _null_ _null_ _null_ _null_ _null_ regcollationout _null_ _null_ _null_ ) +insert ( 4195 to_regcollation 11 10 12 1 0 0 0 f f f t f s s 1 0 4191 25 _null_ _null_ _null_ _null_ _null_ to_regcollation _null_ _null_ _null_ ) +insert ( 2220 regtypein 11 10 12 1 0 0 0 f f f t f s s 1 0 2206 2275 _null_ _null_ _null_ _null_ _null_ regtypein _null_ _null_ _null_ ) +insert ( 2221 regtypeout 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 2206 _null_ _null_ _null_ _null_ _null_ regtypeout _null_ _null_ _null_ ) +insert ( 3493 to_regtype 11 10 12 1 0 0 0 f f f t f s s 1 0 2206 25 _null_ _null_ _null_ _null_ _null_ to_regtype _null_ _null_ _null_ ) +insert ( 1079 regclass 11 10 12 1 0 0 0 f f f t f s s 1 0 2205 25 _null_ _null_ _null_ _null_ _null_ text_regclass _null_ _null_ _null_ ) +insert ( 4098 regrolein 11 10 12 1 0 0 0 f f f t f s s 1 0 4096 2275 _null_ _null_ _null_ _null_ _null_ regrolein _null_ _null_ _null_ ) +insert ( 4092 regroleout 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 4096 _null_ _null_ _null_ _null_ _null_ regroleout _null_ _null_ _null_ ) +insert ( 4093 to_regrole 11 10 12 1 0 0 0 f f f t f s s 1 0 4096 25 _null_ _null_ _null_ _null_ _null_ to_regrole _null_ _null_ _null_ ) +insert ( 4084 regnamespacein 11 10 12 1 0 0 0 f f f t f s s 1 0 4089 2275 _null_ _null_ _null_ _null_ _null_ regnamespacein _null_ _null_ _null_ ) +insert ( 4085 regnamespaceout 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 4089 _null_ _null_ _null_ _null_ _null_ regnamespaceout _null_ _null_ _null_ ) +insert ( 4086 to_regnamespace 11 10 12 1 0 0 0 f f f t f s s 1 0 4089 25 _null_ _null_ _null_ _null_ _null_ to_regnamespace _null_ _null_ _null_ ) +insert ( 1268 parse_ident 11 10 12 1 0 0 0 f f f t f i s 2 0 1009 "25 16" _null_ _null_ "{str,strict}" _null_ _null_ parse_ident _null_ _null_ _null_ ) +insert ( 2246 fmgr_internal_validator 11 10 12 1 0 0 0 f f f t f s s 1 0 2278 26 _null_ _null_ _null_ _null_ _null_ fmgr_internal_validator _null_ _null_ _null_ ) +insert ( 2247 fmgr_c_validator 11 10 12 1 0 0 0 f f f t f s s 1 0 2278 26 _null_ _null_ _null_ _null_ _null_ fmgr_c_validator _null_ _null_ _null_ ) +insert ( 2248 fmgr_sql_validator 11 10 12 1 0 0 0 f f f t f s s 1 0 2278 26 _null_ _null_ _null_ _null_ _null_ fmgr_sql_validator _null_ _null_ _null_ ) +insert ( 2250 has_database_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 25 25" _null_ _null_ _null_ _null_ _null_ has_database_privilege_name_name _null_ _null_ _null_ ) +insert ( 2251 has_database_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ _null_ has_database_privilege_name_id _null_ _null_ _null_ ) +insert ( 2252 has_database_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 25 25" _null_ _null_ _null_ _null_ _null_ has_database_privilege_id_name _null_ _null_ _null_ ) +insert ( 2253 has_database_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 26 25" _null_ _null_ _null_ _null_ _null_ has_database_privilege_id_id _null_ _null_ _null_ ) +insert ( 2254 has_database_privilege 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ has_database_privilege_name _null_ _null_ _null_ ) +insert ( 2255 has_database_privilege 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "26 25" _null_ _null_ _null_ _null_ _null_ has_database_privilege_id _null_ _null_ _null_ ) +insert ( 2256 has_function_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 25 25" _null_ _null_ _null_ _null_ _null_ has_function_privilege_name_name _null_ _null_ _null_ ) +insert ( 2257 has_function_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ _null_ has_function_privilege_name_id _null_ _null_ _null_ ) +insert ( 2258 has_function_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 25 25" _null_ _null_ _null_ _null_ _null_ has_function_privilege_id_name _null_ _null_ _null_ ) +insert ( 2259 has_function_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 26 25" _null_ _null_ _null_ _null_ _null_ has_function_privilege_id_id _null_ _null_ _null_ ) +insert ( 2260 has_function_privilege 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ has_function_privilege_name _null_ _null_ _null_ ) +insert ( 2261 has_function_privilege 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "26 25" _null_ _null_ _null_ _null_ _null_ has_function_privilege_id _null_ _null_ _null_ ) +insert ( 2262 has_language_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 25 25" _null_ _null_ _null_ _null_ _null_ has_language_privilege_name_name _null_ _null_ _null_ ) +insert ( 2263 has_language_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ _null_ has_language_privilege_name_id _null_ _null_ _null_ ) +insert ( 2264 has_language_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 25 25" _null_ _null_ _null_ _null_ _null_ has_language_privilege_id_name _null_ _null_ _null_ ) +insert ( 2265 has_language_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 26 25" _null_ _null_ _null_ _null_ _null_ has_language_privilege_id_id _null_ _null_ _null_ ) +insert ( 2266 has_language_privilege 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ has_language_privilege_name _null_ _null_ _null_ ) +insert ( 2267 has_language_privilege 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "26 25" _null_ _null_ _null_ _null_ _null_ has_language_privilege_id _null_ _null_ _null_ ) +insert ( 2268 has_schema_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 25 25" _null_ _null_ _null_ _null_ _null_ has_schema_privilege_name_name _null_ _null_ _null_ ) +insert ( 2269 has_schema_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ _null_ has_schema_privilege_name_id _null_ _null_ _null_ ) +insert ( 2270 has_schema_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 25 25" _null_ _null_ _null_ _null_ _null_ has_schema_privilege_id_name _null_ _null_ _null_ ) +insert ( 2271 has_schema_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 26 25" _null_ _null_ _null_ _null_ _null_ has_schema_privilege_id_id _null_ _null_ _null_ ) +insert ( 2272 has_schema_privilege 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ has_schema_privilege_name _null_ _null_ _null_ ) +insert ( 2273 has_schema_privilege 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "26 25" _null_ _null_ _null_ _null_ _null_ has_schema_privilege_id _null_ _null_ _null_ ) +insert ( 2390 has_tablespace_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 25 25" _null_ _null_ _null_ _null_ _null_ has_tablespace_privilege_name_name _null_ _null_ _null_ ) +insert ( 2391 has_tablespace_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ _null_ has_tablespace_privilege_name_id _null_ _null_ _null_ ) +insert ( 2392 has_tablespace_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 25 25" _null_ _null_ _null_ _null_ _null_ has_tablespace_privilege_id_name _null_ _null_ _null_ ) +insert ( 2393 has_tablespace_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 26 25" _null_ _null_ _null_ _null_ _null_ has_tablespace_privilege_id_id _null_ _null_ _null_ ) +insert ( 2394 has_tablespace_privilege 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ has_tablespace_privilege_name _null_ _null_ _null_ ) +insert ( 2395 has_tablespace_privilege 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "26 25" _null_ _null_ _null_ _null_ _null_ has_tablespace_privilege_id _null_ _null_ _null_ ) +insert ( 3000 has_foreign_data_wrapper_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 25 25" _null_ _null_ _null_ _null_ _null_ has_foreign_data_wrapper_privilege_name_name _null_ _null_ _null_ ) +insert ( 3001 has_foreign_data_wrapper_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ _null_ has_foreign_data_wrapper_privilege_name_id _null_ _null_ _null_ ) +insert ( 3002 has_foreign_data_wrapper_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 25 25" _null_ _null_ _null_ _null_ _null_ has_foreign_data_wrapper_privilege_id_name _null_ _null_ _null_ ) +insert ( 3003 has_foreign_data_wrapper_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 26 25" _null_ _null_ _null_ _null_ _null_ has_foreign_data_wrapper_privilege_id_id _null_ _null_ _null_ ) +insert ( 3004 has_foreign_data_wrapper_privilege 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ has_foreign_data_wrapper_privilege_name _null_ _null_ _null_ ) +insert ( 3005 has_foreign_data_wrapper_privilege 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "26 25" _null_ _null_ _null_ _null_ _null_ has_foreign_data_wrapper_privilege_id _null_ _null_ _null_ ) +insert ( 3006 has_server_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 25 25" _null_ _null_ _null_ _null_ _null_ has_server_privilege_name_name _null_ _null_ _null_ ) +insert ( 3007 has_server_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ _null_ has_server_privilege_name_id _null_ _null_ _null_ ) +insert ( 3008 has_server_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 25 25" _null_ _null_ _null_ _null_ _null_ has_server_privilege_id_name _null_ _null_ _null_ ) +insert ( 3009 has_server_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 26 25" _null_ _null_ _null_ _null_ _null_ has_server_privilege_id_id _null_ _null_ _null_ ) +insert ( 3010 has_server_privilege 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ has_server_privilege_name _null_ _null_ _null_ ) +insert ( 3011 has_server_privilege 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "26 25" _null_ _null_ _null_ _null_ _null_ has_server_privilege_id _null_ _null_ _null_ ) +insert ( 3138 has_type_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 25 25" _null_ _null_ _null_ _null_ _null_ has_type_privilege_name_name _null_ _null_ _null_ ) +insert ( 3139 has_type_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ _null_ has_type_privilege_name_id _null_ _null_ _null_ ) +insert ( 3140 has_type_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 25 25" _null_ _null_ _null_ _null_ _null_ has_type_privilege_id_name _null_ _null_ _null_ ) +insert ( 3141 has_type_privilege 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 26 25" _null_ _null_ _null_ _null_ _null_ has_type_privilege_id_id _null_ _null_ _null_ ) +insert ( 3142 has_type_privilege 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ has_type_privilege_name _null_ _null_ _null_ ) +insert ( 3143 has_type_privilege 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "26 25" _null_ _null_ _null_ _null_ _null_ has_type_privilege_id _null_ _null_ _null_ ) +insert ( 2705 pg_has_role 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 19 25" _null_ _null_ _null_ _null_ _null_ pg_has_role_name_name _null_ _null_ _null_ ) +insert ( 2706 pg_has_role 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ _null_ pg_has_role_name_id _null_ _null_ _null_ ) +insert ( 2707 pg_has_role 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 19 25" _null_ _null_ _null_ _null_ _null_ pg_has_role_id_name _null_ _null_ _null_ ) +insert ( 2708 pg_has_role 11 10 12 1 0 0 0 f f f t f s s 3 0 16 "26 26 25" _null_ _null_ _null_ _null_ _null_ pg_has_role_id_id _null_ _null_ _null_ ) +insert ( 2709 pg_has_role 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "19 25" _null_ _null_ _null_ _null_ _null_ pg_has_role_name _null_ _null_ _null_ ) +insert ( 2710 pg_has_role 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "26 25" _null_ _null_ _null_ _null_ _null_ pg_has_role_id _null_ _null_ _null_ ) +insert ( 1269 pg_column_size 11 10 12 1 0 0 0 f f f t f s s 1 0 23 2276 _null_ _null_ _null_ _null_ _null_ pg_column_size _null_ _null_ _null_ ) +insert ( 2322 pg_tablespace_size 11 10 12 1 0 0 0 f f f t f v s 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_tablespace_size_oid _null_ _null_ _null_ ) +insert ( 2323 pg_tablespace_size 11 10 12 1 0 0 0 f f f t f v s 1 0 20 19 _null_ _null_ _null_ _null_ _null_ pg_tablespace_size_name _null_ _null_ _null_ ) +insert ( 2324 pg_database_size 11 10 12 1 0 0 0 f f f t f v s 1 0 20 26 _null_ _null_ _null_ _null_ _null_ pg_database_size_oid _null_ _null_ _null_ ) +insert ( 2168 pg_database_size 11 10 12 1 0 0 0 f f f t f v s 1 0 20 19 _null_ _null_ _null_ _null_ _null_ pg_database_size_name _null_ _null_ _null_ ) +insert ( 2325 pg_relation_size 11 10 14 1 0 0 0 f f f t f v s 1 0 20 2205 _null_ _null_ _null_ _null_ _null_ "select pg_catalog.pg_relation_size($1, ''main'')" _null_ _null_ _null_ ) +insert ( 2332 pg_relation_size 11 10 12 1 0 0 0 f f f t f v s 2 0 20 "2205 25" _null_ _null_ _null_ _null_ _null_ pg_relation_size _null_ _null_ _null_ ) +insert ( 2286 pg_total_relation_size 11 10 12 1 0 0 0 f f f t f v s 1 0 20 2205 _null_ _null_ _null_ _null_ _null_ pg_total_relation_size _null_ _null_ _null_ ) +insert ( 2288 pg_size_pretty 11 10 12 1 0 0 0 f f f t f i s 1 0 25 20 _null_ _null_ _null_ _null_ _null_ pg_size_pretty _null_ _null_ _null_ ) +insert ( 3166 pg_size_pretty 11 10 12 1 0 0 0 f f f t f i s 1 0 25 1700 _null_ _null_ _null_ _null_ _null_ pg_size_pretty_numeric _null_ _null_ _null_ ) +insert ( 3334 pg_size_bytes 11 10 12 1 0 0 0 f f f t f i s 1 0 20 25 _null_ _null_ _null_ _null_ _null_ pg_size_bytes _null_ _null_ _null_ ) +insert ( 2997 pg_table_size 11 10 12 1 0 0 0 f f f t f v s 1 0 20 2205 _null_ _null_ _null_ _null_ _null_ pg_table_size _null_ _null_ _null_ ) +insert ( 2998 pg_indexes_size 11 10 12 1 0 0 0 f f f t f v s 1 0 20 2205 _null_ _null_ _null_ _null_ _null_ pg_indexes_size _null_ _null_ _null_ ) +insert ( 2999 pg_relation_filenode 11 10 12 1 0 0 0 f f f t f s s 1 0 26 2205 _null_ _null_ _null_ _null_ _null_ pg_relation_filenode _null_ _null_ _null_ ) +insert ( 3454 pg_filenode_relation 11 10 12 1 0 0 0 f f f t f s s 2 0 2205 "26 26" _null_ _null_ _null_ _null_ _null_ pg_filenode_relation _null_ _null_ _null_ ) +insert ( 3034 pg_relation_filepath 11 10 12 1 0 0 0 f f f t f s s 1 0 25 2205 _null_ _null_ _null_ _null_ _null_ pg_relation_filepath _null_ _null_ _null_ ) +insert ( 2316 postgresql_fdw_validator 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1009 26" _null_ _null_ _null_ _null_ _null_ postgresql_fdw_validator _null_ _null_ _null_ ) +insert ( 2290 record_in 11 10 12 1 0 0 0 f f f t f s s 3 0 2249 "2275 26 23" _null_ _null_ _null_ _null_ _null_ record_in _null_ _null_ _null_ ) +insert ( 2291 record_out 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 2249 _null_ _null_ _null_ _null_ _null_ record_out _null_ _null_ _null_ ) +insert ( 2292 cstring_in 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 2275 _null_ _null_ _null_ _null_ _null_ cstring_in _null_ _null_ _null_ ) +insert ( 2293 cstring_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 2275 _null_ _null_ _null_ _null_ _null_ cstring_out _null_ _null_ _null_ ) +insert ( 2294 any_in 11 10 12 1 0 0 0 f f f t f i s 1 0 2276 2275 _null_ _null_ _null_ _null_ _null_ any_in _null_ _null_ _null_ ) +insert ( 2295 any_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 2276 _null_ _null_ _null_ _null_ _null_ any_out _null_ _null_ _null_ ) +insert ( 2296 anyarray_in 11 10 12 1 0 0 0 f f f t f i s 1 0 2277 2275 _null_ _null_ _null_ _null_ _null_ anyarray_in _null_ _null_ _null_ ) +insert ( 2297 anyarray_out 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 2277 _null_ _null_ _null_ _null_ _null_ anyarray_out _null_ _null_ _null_ ) +insert ( 2298 void_in 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2275 _null_ _null_ _null_ _null_ _null_ void_in _null_ _null_ _null_ ) +insert ( 2299 void_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 2278 _null_ _null_ _null_ _null_ _null_ void_out _null_ _null_ _null_ ) +insert ( 2300 trigger_in 11 10 12 1 0 0 0 f f f f f i s 1 0 2279 2275 _null_ _null_ _null_ _null_ _null_ trigger_in _null_ _null_ _null_ ) +insert ( 2301 trigger_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 2279 _null_ _null_ _null_ _null_ _null_ trigger_out _null_ _null_ _null_ ) +insert ( 3594 event_trigger_in 11 10 12 1 0 0 0 f f f f f i s 1 0 3838 2275 _null_ _null_ _null_ _null_ _null_ event_trigger_in _null_ _null_ _null_ ) +insert ( 3595 event_trigger_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 3838 _null_ _null_ _null_ _null_ _null_ event_trigger_out _null_ _null_ _null_ ) +insert ( 2302 language_handler_in 11 10 12 1 0 0 0 f f f f f i s 1 0 2280 2275 _null_ _null_ _null_ _null_ _null_ language_handler_in _null_ _null_ _null_ ) +insert ( 2303 language_handler_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 2280 _null_ _null_ _null_ _null_ _null_ language_handler_out _null_ _null_ _null_ ) +insert ( 2304 internal_in 11 10 12 1 0 0 0 f f f f f i s 1 0 2281 2275 _null_ _null_ _null_ _null_ _null_ internal_in _null_ _null_ _null_ ) +insert ( 2305 internal_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 2281 _null_ _null_ _null_ _null_ _null_ internal_out _null_ _null_ _null_ ) +insert ( 2312 anyelement_in 11 10 12 1 0 0 0 f f f t f i s 1 0 2283 2275 _null_ _null_ _null_ _null_ _null_ anyelement_in _null_ _null_ _null_ ) +insert ( 2313 anyelement_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 2283 _null_ _null_ _null_ _null_ _null_ anyelement_out _null_ _null_ _null_ ) +insert ( 2398 shell_in 11 10 12 1 0 0 0 f f f f f i s 1 0 2278 2275 _null_ _null_ _null_ _null_ _null_ shell_in _null_ _null_ _null_ ) +insert ( 2399 shell_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 2278 _null_ _null_ _null_ _null_ _null_ shell_out _null_ _null_ _null_ ) +insert ( 2597 domain_in 11 10 12 1 0 0 0 f f f f f s s 3 0 2276 "2275 26 23" _null_ _null_ _null_ _null_ _null_ domain_in _null_ _null_ _null_ ) +insert ( 2598 domain_recv 11 10 12 1 0 0 0 f f f f f s s 3 0 2276 "2281 26 23" _null_ _null_ _null_ _null_ _null_ domain_recv _null_ _null_ _null_ ) +insert ( 2777 anynonarray_in 11 10 12 1 0 0 0 f f f t f i s 1 0 2776 2275 _null_ _null_ _null_ _null_ _null_ anynonarray_in _null_ _null_ _null_ ) +insert ( 2778 anynonarray_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 2776 _null_ _null_ _null_ _null_ _null_ anynonarray_out _null_ _null_ _null_ ) +insert ( 3116 fdw_handler_in 11 10 12 1 0 0 0 f f f f f i s 1 0 3115 2275 _null_ _null_ _null_ _null_ _null_ fdw_handler_in _null_ _null_ _null_ ) +insert ( 3117 fdw_handler_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 3115 _null_ _null_ _null_ _null_ _null_ fdw_handler_out _null_ _null_ _null_ ) +insert ( 326 index_am_handler_in 11 10 12 1 0 0 0 f f f f f i s 1 0 325 2275 _null_ _null_ _null_ _null_ _null_ index_am_handler_in _null_ _null_ _null_ ) +insert ( 327 index_am_handler_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 325 _null_ _null_ _null_ _null_ _null_ index_am_handler_out _null_ _null_ _null_ ) +insert ( 3311 tsm_handler_in 11 10 12 1 0 0 0 f f f f f i s 1 0 3310 2275 _null_ _null_ _null_ _null_ _null_ tsm_handler_in _null_ _null_ _null_ ) +insert ( 3312 tsm_handler_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 3310 _null_ _null_ _null_ _null_ _null_ tsm_handler_out _null_ _null_ _null_ ) +insert ( 267 table_am_handler_in 11 10 12 1 0 0 0 f f f f f i s 1 0 269 2275 _null_ _null_ _null_ _null_ _null_ table_am_handler_in _null_ _null_ _null_ ) +insert ( 268 table_am_handler_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 269 _null_ _null_ _null_ _null_ _null_ table_am_handler_out _null_ _null_ _null_ ) +insert ( 5086 anycompatible_in 11 10 12 1 0 0 0 f f f t f i s 1 0 5077 2275 _null_ _null_ _null_ _null_ _null_ anycompatible_in _null_ _null_ _null_ ) +insert ( 5087 anycompatible_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 5077 _null_ _null_ _null_ _null_ _null_ anycompatible_out _null_ _null_ _null_ ) +insert ( 5088 anycompatiblearray_in 11 10 12 1 0 0 0 f f f t f i s 1 0 5078 2275 _null_ _null_ _null_ _null_ _null_ anycompatiblearray_in _null_ _null_ _null_ ) +insert ( 5089 anycompatiblearray_out 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 5078 _null_ _null_ _null_ _null_ _null_ anycompatiblearray_out _null_ _null_ _null_ ) +insert ( 5090 anycompatiblearray_recv 11 10 12 1 0 0 0 f f f t f s s 1 0 5078 2281 _null_ _null_ _null_ _null_ _null_ anycompatiblearray_recv _null_ _null_ _null_ ) +insert ( 5091 anycompatiblearray_send 11 10 12 1 0 0 0 f f f t f s s 1 0 17 5078 _null_ _null_ _null_ _null_ _null_ anycompatiblearray_send _null_ _null_ _null_ ) +insert ( 5092 anycompatiblenonarray_in 11 10 12 1 0 0 0 f f f t f i s 1 0 5079 2275 _null_ _null_ _null_ _null_ _null_ anycompatiblenonarray_in _null_ _null_ _null_ ) +insert ( 5093 anycompatiblenonarray_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 5079 _null_ _null_ _null_ _null_ _null_ anycompatiblenonarray_out _null_ _null_ _null_ ) +insert ( 5094 anycompatiblerange_in 11 10 12 1 0 0 0 f f f t f s s 3 0 5080 "2275 26 23" _null_ _null_ _null_ _null_ _null_ anycompatiblerange_in _null_ _null_ _null_ ) +insert ( 5095 anycompatiblerange_out 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 5080 _null_ _null_ _null_ _null_ _null_ anycompatiblerange_out _null_ _null_ _null_ ) +insert ( 3313 bernoulli 11 10 12 1 0 0 0 f f f t f v s 1 0 3310 2281 _null_ _null_ _null_ _null_ _null_ tsm_bernoulli_handler _null_ _null_ _null_ ) +insert ( 3314 system 11 10 12 1 0 0 0 f f f t f v s 1 0 3310 2281 _null_ _null_ _null_ _null_ _null_ tsm_system_handler _null_ _null_ _null_ ) +insert ( 2311 md5 11 10 12 1 0 0 0 f f t t f i s 1 0 25 25 _null_ _null_ _null_ _null_ _null_ md5_text _null_ _null_ _null_ ) +insert ( 2321 md5 11 10 12 1 0 0 0 f f t t f i s 1 0 25 17 _null_ _null_ _null_ _null_ _null_ md5_bytea _null_ _null_ _null_ ) +insert ( 3419 sha224 11 10 12 1 0 0 0 f f t t f i s 1 0 17 17 _null_ _null_ _null_ _null_ _null_ sha224_bytea _null_ _null_ _null_ ) +insert ( 3420 sha256 11 10 12 1 0 0 0 f f t t f i s 1 0 17 17 _null_ _null_ _null_ _null_ _null_ sha256_bytea _null_ _null_ _null_ ) +insert ( 3421 sha384 11 10 12 1 0 0 0 f f t t f i s 1 0 17 17 _null_ _null_ _null_ _null_ _null_ sha384_bytea _null_ _null_ _null_ ) +insert ( 3422 sha512 11 10 12 1 0 0 0 f f t t f i s 1 0 17 17 _null_ _null_ _null_ _null_ _null_ sha512_bytea _null_ _null_ _null_ ) +insert ( 2338 date_lt_timestamp 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1082 1114" _null_ _null_ _null_ _null_ _null_ date_lt_timestamp _null_ _null_ _null_ ) +insert ( 2339 date_le_timestamp 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1082 1114" _null_ _null_ _null_ _null_ _null_ date_le_timestamp _null_ _null_ _null_ ) +insert ( 2340 date_eq_timestamp 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1082 1114" _null_ _null_ _null_ _null_ _null_ date_eq_timestamp _null_ _null_ _null_ ) +insert ( 2341 date_gt_timestamp 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1082 1114" _null_ _null_ _null_ _null_ _null_ date_gt_timestamp _null_ _null_ _null_ ) +insert ( 2342 date_ge_timestamp 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1082 1114" _null_ _null_ _null_ _null_ _null_ date_ge_timestamp _null_ _null_ _null_ ) +insert ( 2343 date_ne_timestamp 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1082 1114" _null_ _null_ _null_ _null_ _null_ date_ne_timestamp _null_ _null_ _null_ ) +insert ( 2344 date_cmp_timestamp 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "1082 1114" _null_ _null_ _null_ _null_ _null_ date_cmp_timestamp _null_ _null_ _null_ ) +insert ( 2351 date_lt_timestamptz 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1082 1184" _null_ _null_ _null_ _null_ _null_ date_lt_timestamptz _null_ _null_ _null_ ) +insert ( 2352 date_le_timestamptz 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1082 1184" _null_ _null_ _null_ _null_ _null_ date_le_timestamptz _null_ _null_ _null_ ) +insert ( 2353 date_eq_timestamptz 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1082 1184" _null_ _null_ _null_ _null_ _null_ date_eq_timestamptz _null_ _null_ _null_ ) +insert ( 2354 date_gt_timestamptz 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1082 1184" _null_ _null_ _null_ _null_ _null_ date_gt_timestamptz _null_ _null_ _null_ ) +insert ( 2355 date_ge_timestamptz 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1082 1184" _null_ _null_ _null_ _null_ _null_ date_ge_timestamptz _null_ _null_ _null_ ) +insert ( 2356 date_ne_timestamptz 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1082 1184" _null_ _null_ _null_ _null_ _null_ date_ne_timestamptz _null_ _null_ _null_ ) +insert ( 2357 date_cmp_timestamptz 11 10 12 1 0 0 0 f f f t f s s 2 0 23 "1082 1184" _null_ _null_ _null_ _null_ _null_ date_cmp_timestamptz _null_ _null_ _null_ ) +insert ( 2364 timestamp_lt_date 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1114 1082" _null_ _null_ _null_ _null_ _null_ timestamp_lt_date _null_ _null_ _null_ ) +insert ( 2365 timestamp_le_date 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1114 1082" _null_ _null_ _null_ _null_ _null_ timestamp_le_date _null_ _null_ _null_ ) +insert ( 2366 timestamp_eq_date 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1114 1082" _null_ _null_ _null_ _null_ _null_ timestamp_eq_date _null_ _null_ _null_ ) +insert ( 2367 timestamp_gt_date 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1114 1082" _null_ _null_ _null_ _null_ _null_ timestamp_gt_date _null_ _null_ _null_ ) +insert ( 2368 timestamp_ge_date 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1114 1082" _null_ _null_ _null_ _null_ _null_ timestamp_ge_date _null_ _null_ _null_ ) +insert ( 2369 timestamp_ne_date 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "1114 1082" _null_ _null_ _null_ _null_ _null_ timestamp_ne_date _null_ _null_ _null_ ) +insert ( 2370 timestamp_cmp_date 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "1114 1082" _null_ _null_ _null_ _null_ _null_ timestamp_cmp_date _null_ _null_ _null_ ) +insert ( 2377 timestamptz_lt_date 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1184 1082" _null_ _null_ _null_ _null_ _null_ timestamptz_lt_date _null_ _null_ _null_ ) +insert ( 2378 timestamptz_le_date 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1184 1082" _null_ _null_ _null_ _null_ _null_ timestamptz_le_date _null_ _null_ _null_ ) +insert ( 2379 timestamptz_eq_date 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1184 1082" _null_ _null_ _null_ _null_ _null_ timestamptz_eq_date _null_ _null_ _null_ ) +insert ( 2380 timestamptz_gt_date 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1184 1082" _null_ _null_ _null_ _null_ _null_ timestamptz_gt_date _null_ _null_ _null_ ) +insert ( 2381 timestamptz_ge_date 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1184 1082" _null_ _null_ _null_ _null_ _null_ timestamptz_ge_date _null_ _null_ _null_ ) +insert ( 2382 timestamptz_ne_date 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1184 1082" _null_ _null_ _null_ _null_ _null_ timestamptz_ne_date _null_ _null_ _null_ ) +insert ( 2383 timestamptz_cmp_date 11 10 12 1 0 0 0 f f f t f s s 2 0 23 "1184 1082" _null_ _null_ _null_ _null_ _null_ timestamptz_cmp_date _null_ _null_ _null_ ) +insert ( 2520 timestamp_lt_timestamptz 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1114 1184" _null_ _null_ _null_ _null_ _null_ timestamp_lt_timestamptz _null_ _null_ _null_ ) +insert ( 2521 timestamp_le_timestamptz 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1114 1184" _null_ _null_ _null_ _null_ _null_ timestamp_le_timestamptz _null_ _null_ _null_ ) +insert ( 2522 timestamp_eq_timestamptz 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1114 1184" _null_ _null_ _null_ _null_ _null_ timestamp_eq_timestamptz _null_ _null_ _null_ ) +insert ( 2523 timestamp_gt_timestamptz 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1114 1184" _null_ _null_ _null_ _null_ _null_ timestamp_gt_timestamptz _null_ _null_ _null_ ) +insert ( 2524 timestamp_ge_timestamptz 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1114 1184" _null_ _null_ _null_ _null_ _null_ timestamp_ge_timestamptz _null_ _null_ _null_ ) +insert ( 2525 timestamp_ne_timestamptz 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1114 1184" _null_ _null_ _null_ _null_ _null_ timestamp_ne_timestamptz _null_ _null_ _null_ ) +insert ( 2526 timestamp_cmp_timestamptz 11 10 12 1 0 0 0 f f f t f s s 2 0 23 "1114 1184" _null_ _null_ _null_ _null_ _null_ timestamp_cmp_timestamptz _null_ _null_ _null_ ) +insert ( 2527 timestamptz_lt_timestamp 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1184 1114" _null_ _null_ _null_ _null_ _null_ timestamptz_lt_timestamp _null_ _null_ _null_ ) +insert ( 2528 timestamptz_le_timestamp 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1184 1114" _null_ _null_ _null_ _null_ _null_ timestamptz_le_timestamp _null_ _null_ _null_ ) +insert ( 2529 timestamptz_eq_timestamp 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1184 1114" _null_ _null_ _null_ _null_ _null_ timestamptz_eq_timestamp _null_ _null_ _null_ ) +insert ( 2530 timestamptz_gt_timestamp 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1184 1114" _null_ _null_ _null_ _null_ _null_ timestamptz_gt_timestamp _null_ _null_ _null_ ) +insert ( 2531 timestamptz_ge_timestamp 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1184 1114" _null_ _null_ _null_ _null_ _null_ timestamptz_ge_timestamp _null_ _null_ _null_ ) +insert ( 2532 timestamptz_ne_timestamp 11 10 12 1 0 0 0 f f f t f s s 2 0 16 "1184 1114" _null_ _null_ _null_ _null_ _null_ timestamptz_ne_timestamp _null_ _null_ _null_ ) +insert ( 2533 timestamptz_cmp_timestamp 11 10 12 1 0 0 0 f f f t f s s 2 0 23 "1184 1114" _null_ _null_ _null_ _null_ _null_ timestamptz_cmp_timestamp _null_ _null_ _null_ ) +insert ( 2400 array_recv 11 10 12 1 0 0 0 f f f t f s s 3 0 2277 "2281 26 23" _null_ _null_ _null_ _null_ _null_ array_recv _null_ _null_ _null_ ) +insert ( 2401 array_send 11 10 12 1 0 0 0 f f f t f s s 1 0 17 2277 _null_ _null_ _null_ _null_ _null_ array_send _null_ _null_ _null_ ) +insert ( 2402 record_recv 11 10 12 1 0 0 0 f f f t f s s 3 0 2249 "2281 26 23" _null_ _null_ _null_ _null_ _null_ record_recv _null_ _null_ _null_ ) +insert ( 2403 record_send 11 10 12 1 0 0 0 f f f t f s s 1 0 17 2249 _null_ _null_ _null_ _null_ _null_ record_send _null_ _null_ _null_ ) +insert ( 2404 int2recv 11 10 12 1 0 0 0 f f f t f i s 1 0 21 2281 _null_ _null_ _null_ _null_ _null_ int2recv _null_ _null_ _null_ ) +insert ( 2405 int2send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 21 _null_ _null_ _null_ _null_ _null_ int2send _null_ _null_ _null_ ) +insert ( 2406 int4recv 11 10 12 1 0 0 0 f f f t f i s 1 0 23 2281 _null_ _null_ _null_ _null_ _null_ int4recv _null_ _null_ _null_ ) +insert ( 2407 int4send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 23 _null_ _null_ _null_ _null_ _null_ int4send _null_ _null_ _null_ ) +insert ( 2408 int8recv 11 10 12 1 0 0 0 f f f t f i s 1 0 20 2281 _null_ _null_ _null_ _null_ _null_ int8recv _null_ _null_ _null_ ) +insert ( 2409 int8send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 20 _null_ _null_ _null_ _null_ _null_ int8send _null_ _null_ _null_ ) +insert ( 2410 int2vectorrecv 11 10 12 1 0 0 0 f f f t f i s 1 0 22 2281 _null_ _null_ _null_ _null_ _null_ int2vectorrecv _null_ _null_ _null_ ) +insert ( 2411 int2vectorsend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 22 _null_ _null_ _null_ _null_ _null_ int2vectorsend _null_ _null_ _null_ ) +insert ( 2412 bytearecv 11 10 12 1 0 0 0 f f f t f i s 1 0 17 2281 _null_ _null_ _null_ _null_ _null_ bytearecv _null_ _null_ _null_ ) +insert ( 2413 byteasend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 17 _null_ _null_ _null_ _null_ _null_ byteasend _null_ _null_ _null_ ) +insert ( 2414 textrecv 11 10 12 1 0 0 0 f f f t f s s 1 0 25 2281 _null_ _null_ _null_ _null_ _null_ textrecv _null_ _null_ _null_ ) +insert ( 2415 textsend 11 10 12 1 0 0 0 f f f t f s s 1 0 17 25 _null_ _null_ _null_ _null_ _null_ textsend _null_ _null_ _null_ ) +insert ( 2416 unknownrecv 11 10 12 1 0 0 0 f f f t f i s 1 0 705 2281 _null_ _null_ _null_ _null_ _null_ unknownrecv _null_ _null_ _null_ ) +insert ( 2417 unknownsend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 705 _null_ _null_ _null_ _null_ _null_ unknownsend _null_ _null_ _null_ ) +insert ( 2418 oidrecv 11 10 12 1 0 0 0 f f f t f i s 1 0 26 2281 _null_ _null_ _null_ _null_ _null_ oidrecv _null_ _null_ _null_ ) +insert ( 2419 oidsend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 26 _null_ _null_ _null_ _null_ _null_ oidsend _null_ _null_ _null_ ) +insert ( 2420 oidvectorrecv 11 10 12 1 0 0 0 f f f t f i s 1 0 30 2281 _null_ _null_ _null_ _null_ _null_ oidvectorrecv _null_ _null_ _null_ ) +insert ( 2421 oidvectorsend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 30 _null_ _null_ _null_ _null_ _null_ oidvectorsend _null_ _null_ _null_ ) +insert ( 2422 namerecv 11 10 12 1 0 0 0 f f f t f s s 1 0 19 2281 _null_ _null_ _null_ _null_ _null_ namerecv _null_ _null_ _null_ ) +insert ( 2423 namesend 11 10 12 1 0 0 0 f f f t f s s 1 0 17 19 _null_ _null_ _null_ _null_ _null_ namesend _null_ _null_ _null_ ) +insert ( 2424 float4recv 11 10 12 1 0 0 0 f f f t f i s 1 0 700 2281 _null_ _null_ _null_ _null_ _null_ float4recv _null_ _null_ _null_ ) +insert ( 2425 float4send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 700 _null_ _null_ _null_ _null_ _null_ float4send _null_ _null_ _null_ ) +insert ( 2426 float8recv 11 10 12 1 0 0 0 f f f t f i s 1 0 701 2281 _null_ _null_ _null_ _null_ _null_ float8recv _null_ _null_ _null_ ) +insert ( 2427 float8send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 701 _null_ _null_ _null_ _null_ _null_ float8send _null_ _null_ _null_ ) +insert ( 2428 point_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 600 2281 _null_ _null_ _null_ _null_ _null_ point_recv _null_ _null_ _null_ ) +insert ( 2429 point_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 600 _null_ _null_ _null_ _null_ _null_ point_send _null_ _null_ _null_ ) +insert ( 2430 bpcharrecv 11 10 12 1 0 0 0 f f f t f s s 3 0 1042 "2281 26 23" _null_ _null_ _null_ _null_ _null_ bpcharrecv _null_ _null_ _null_ ) +insert ( 2431 bpcharsend 11 10 12 1 0 0 0 f f f t f s s 1 0 17 1042 _null_ _null_ _null_ _null_ _null_ bpcharsend _null_ _null_ _null_ ) +insert ( 2432 varcharrecv 11 10 12 1 0 0 0 f f f t f s s 3 0 1043 "2281 26 23" _null_ _null_ _null_ _null_ _null_ varcharrecv _null_ _null_ _null_ ) +insert ( 2433 varcharsend 11 10 12 1 0 0 0 f f f t f s s 1 0 17 1043 _null_ _null_ _null_ _null_ _null_ varcharsend _null_ _null_ _null_ ) +insert ( 2434 charrecv 11 10 12 1 0 0 0 f f f t f i s 1 0 18 2281 _null_ _null_ _null_ _null_ _null_ charrecv _null_ _null_ _null_ ) +insert ( 2435 charsend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 18 _null_ _null_ _null_ _null_ _null_ charsend _null_ _null_ _null_ ) +insert ( 2436 boolrecv 11 10 12 1 0 0 0 f f f t f i s 1 0 16 2281 _null_ _null_ _null_ _null_ _null_ boolrecv _null_ _null_ _null_ ) +insert ( 2437 boolsend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 16 _null_ _null_ _null_ _null_ _null_ boolsend _null_ _null_ _null_ ) +insert ( 2438 tidrecv 11 10 12 1 0 0 0 f f f t f i s 1 0 27 2281 _null_ _null_ _null_ _null_ _null_ tidrecv _null_ _null_ _null_ ) +insert ( 2439 tidsend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 27 _null_ _null_ _null_ _null_ _null_ tidsend _null_ _null_ _null_ ) +insert ( 2440 xidrecv 11 10 12 1 0 0 0 f f f t f i s 1 0 28 2281 _null_ _null_ _null_ _null_ _null_ xidrecv _null_ _null_ _null_ ) +insert ( 2441 xidsend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 28 _null_ _null_ _null_ _null_ _null_ xidsend _null_ _null_ _null_ ) +insert ( 2442 cidrecv 11 10 12 1 0 0 0 f f f t f i s 1 0 29 2281 _null_ _null_ _null_ _null_ _null_ cidrecv _null_ _null_ _null_ ) +insert ( 2443 cidsend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 29 _null_ _null_ _null_ _null_ _null_ cidsend _null_ _null_ _null_ ) +insert ( 2444 regprocrecv 11 10 12 1 0 0 0 f f f t f i s 1 0 24 2281 _null_ _null_ _null_ _null_ _null_ regprocrecv _null_ _null_ _null_ ) +insert ( 2445 regprocsend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 24 _null_ _null_ _null_ _null_ _null_ regprocsend _null_ _null_ _null_ ) +insert ( 2446 regprocedurerecv 11 10 12 1 0 0 0 f f f t f i s 1 0 2202 2281 _null_ _null_ _null_ _null_ _null_ regprocedurerecv _null_ _null_ _null_ ) +insert ( 2447 regproceduresend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 2202 _null_ _null_ _null_ _null_ _null_ regproceduresend _null_ _null_ _null_ ) +insert ( 2448 regoperrecv 11 10 12 1 0 0 0 f f f t f i s 1 0 2203 2281 _null_ _null_ _null_ _null_ _null_ regoperrecv _null_ _null_ _null_ ) +insert ( 2449 regopersend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 2203 _null_ _null_ _null_ _null_ _null_ regopersend _null_ _null_ _null_ ) +insert ( 2450 regoperatorrecv 11 10 12 1 0 0 0 f f f t f i s 1 0 2204 2281 _null_ _null_ _null_ _null_ _null_ regoperatorrecv _null_ _null_ _null_ ) +insert ( 2451 regoperatorsend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 2204 _null_ _null_ _null_ _null_ _null_ regoperatorsend _null_ _null_ _null_ ) +insert ( 2452 regclassrecv 11 10 12 1 0 0 0 f f f t f i s 1 0 2205 2281 _null_ _null_ _null_ _null_ _null_ regclassrecv _null_ _null_ _null_ ) +insert ( 2453 regclasssend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 2205 _null_ _null_ _null_ _null_ _null_ regclasssend _null_ _null_ _null_ ) +insert ( 4196 regcollationrecv 11 10 12 1 0 0 0 f f f t f i s 1 0 4191 2281 _null_ _null_ _null_ _null_ _null_ regcollationrecv _null_ _null_ _null_ ) +insert ( 4197 regcollationsend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 4191 _null_ _null_ _null_ _null_ _null_ regcollationsend _null_ _null_ _null_ ) +insert ( 2454 regtyperecv 11 10 12 1 0 0 0 f f f t f i s 1 0 2206 2281 _null_ _null_ _null_ _null_ _null_ regtyperecv _null_ _null_ _null_ ) +insert ( 2455 regtypesend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 2206 _null_ _null_ _null_ _null_ _null_ regtypesend _null_ _null_ _null_ ) +insert ( 4094 regrolerecv 11 10 12 1 0 0 0 f f f t f i s 1 0 4096 2281 _null_ _null_ _null_ _null_ _null_ regrolerecv _null_ _null_ _null_ ) +insert ( 4095 regrolesend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 4096 _null_ _null_ _null_ _null_ _null_ regrolesend _null_ _null_ _null_ ) +insert ( 4087 regnamespacerecv 11 10 12 1 0 0 0 f f f t f i s 1 0 4089 2281 _null_ _null_ _null_ _null_ _null_ regnamespacerecv _null_ _null_ _null_ ) +insert ( 4088 regnamespacesend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 4089 _null_ _null_ _null_ _null_ _null_ regnamespacesend _null_ _null_ _null_ ) +insert ( 2456 bit_recv 11 10 12 1 0 0 0 f f f t f i s 3 0 1560 "2281 26 23" _null_ _null_ _null_ _null_ _null_ bit_recv _null_ _null_ _null_ ) +insert ( 2457 bit_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 1560 _null_ _null_ _null_ _null_ _null_ bit_send _null_ _null_ _null_ ) +insert ( 2458 varbit_recv 11 10 12 1 0 0 0 f f f t f i s 3 0 1562 "2281 26 23" _null_ _null_ _null_ _null_ _null_ varbit_recv _null_ _null_ _null_ ) +insert ( 2459 varbit_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 1562 _null_ _null_ _null_ _null_ _null_ varbit_send _null_ _null_ _null_ ) +insert ( 2460 numeric_recv 11 10 12 1 0 0 0 f f f t f i s 3 0 1700 "2281 26 23" _null_ _null_ _null_ _null_ _null_ numeric_recv _null_ _null_ _null_ ) +insert ( 2461 numeric_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 1700 _null_ _null_ _null_ _null_ _null_ numeric_send _null_ _null_ _null_ ) +insert ( 2468 date_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 1082 2281 _null_ _null_ _null_ _null_ _null_ date_recv _null_ _null_ _null_ ) +insert ( 2469 date_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 1082 _null_ _null_ _null_ _null_ _null_ date_send _null_ _null_ _null_ ) +insert ( 2470 time_recv 11 10 12 1 0 0 0 f f f t f i s 3 0 1083 "2281 26 23" _null_ _null_ _null_ _null_ _null_ time_recv _null_ _null_ _null_ ) +insert ( 2471 time_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 1083 _null_ _null_ _null_ _null_ _null_ time_send _null_ _null_ _null_ ) +insert ( 2472 timetz_recv 11 10 12 1 0 0 0 f f f t f i s 3 0 1266 "2281 26 23" _null_ _null_ _null_ _null_ _null_ timetz_recv _null_ _null_ _null_ ) +insert ( 2473 timetz_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 1266 _null_ _null_ _null_ _null_ _null_ timetz_send _null_ _null_ _null_ ) +insert ( 2474 timestamp_recv 11 10 12 1 0 0 0 f f f t f i s 3 0 1114 "2281 26 23" _null_ _null_ _null_ _null_ _null_ timestamp_recv _null_ _null_ _null_ ) +insert ( 2475 timestamp_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 1114 _null_ _null_ _null_ _null_ _null_ timestamp_send _null_ _null_ _null_ ) +insert ( 2476 timestamptz_recv 11 10 12 1 0 0 0 f f f t f i s 3 0 1184 "2281 26 23" _null_ _null_ _null_ _null_ _null_ timestamptz_recv _null_ _null_ _null_ ) +insert ( 2477 timestamptz_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 1184 _null_ _null_ _null_ _null_ _null_ timestamptz_send _null_ _null_ _null_ ) +insert ( 2478 interval_recv 11 10 12 1 0 0 0 f f f t f i s 3 0 1186 "2281 26 23" _null_ _null_ _null_ _null_ _null_ interval_recv _null_ _null_ _null_ ) +insert ( 2479 interval_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 1186 _null_ _null_ _null_ _null_ _null_ interval_send _null_ _null_ _null_ ) +insert ( 2480 lseg_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 601 2281 _null_ _null_ _null_ _null_ _null_ lseg_recv _null_ _null_ _null_ ) +insert ( 2481 lseg_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 601 _null_ _null_ _null_ _null_ _null_ lseg_send _null_ _null_ _null_ ) +insert ( 2482 path_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 602 2281 _null_ _null_ _null_ _null_ _null_ path_recv _null_ _null_ _null_ ) +insert ( 2483 path_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 602 _null_ _null_ _null_ _null_ _null_ path_send _null_ _null_ _null_ ) +insert ( 2484 box_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 603 2281 _null_ _null_ _null_ _null_ _null_ box_recv _null_ _null_ _null_ ) +insert ( 2485 box_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 603 _null_ _null_ _null_ _null_ _null_ box_send _null_ _null_ _null_ ) +insert ( 2486 poly_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 604 2281 _null_ _null_ _null_ _null_ _null_ poly_recv _null_ _null_ _null_ ) +insert ( 2487 poly_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 604 _null_ _null_ _null_ _null_ _null_ poly_send _null_ _null_ _null_ ) +insert ( 2488 line_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 628 2281 _null_ _null_ _null_ _null_ _null_ line_recv _null_ _null_ _null_ ) +insert ( 2489 line_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 628 _null_ _null_ _null_ _null_ _null_ line_send _null_ _null_ _null_ ) +insert ( 2490 circle_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 718 2281 _null_ _null_ _null_ _null_ _null_ circle_recv _null_ _null_ _null_ ) +insert ( 2491 circle_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 718 _null_ _null_ _null_ _null_ _null_ circle_send _null_ _null_ _null_ ) +insert ( 2492 cash_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 790 2281 _null_ _null_ _null_ _null_ _null_ cash_recv _null_ _null_ _null_ ) +insert ( 2493 cash_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 790 _null_ _null_ _null_ _null_ _null_ cash_send _null_ _null_ _null_ ) +insert ( 2494 macaddr_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 829 2281 _null_ _null_ _null_ _null_ _null_ macaddr_recv _null_ _null_ _null_ ) +insert ( 2495 macaddr_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 829 _null_ _null_ _null_ _null_ _null_ macaddr_send _null_ _null_ _null_ ) +insert ( 2496 inet_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 869 2281 _null_ _null_ _null_ _null_ _null_ inet_recv _null_ _null_ _null_ ) +insert ( 2497 inet_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 869 _null_ _null_ _null_ _null_ _null_ inet_send _null_ _null_ _null_ ) +insert ( 2498 cidr_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 650 2281 _null_ _null_ _null_ _null_ _null_ cidr_recv _null_ _null_ _null_ ) +insert ( 2499 cidr_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 650 _null_ _null_ _null_ _null_ _null_ cidr_send _null_ _null_ _null_ ) +insert ( 2500 cstring_recv 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 2281 _null_ _null_ _null_ _null_ _null_ cstring_recv _null_ _null_ _null_ ) +insert ( 2501 cstring_send 11 10 12 1 0 0 0 f f f t f s s 1 0 17 2275 _null_ _null_ _null_ _null_ _null_ cstring_send _null_ _null_ _null_ ) +insert ( 2502 anyarray_recv 11 10 12 1 0 0 0 f f f t f s s 1 0 2277 2281 _null_ _null_ _null_ _null_ _null_ anyarray_recv _null_ _null_ _null_ ) +insert ( 2503 anyarray_send 11 10 12 1 0 0 0 f f f t f s s 1 0 17 2277 _null_ _null_ _null_ _null_ _null_ anyarray_send _null_ _null_ _null_ ) +insert ( 3120 void_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ void_recv _null_ _null_ _null_ ) +insert ( 3121 void_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 2278 _null_ _null_ _null_ _null_ _null_ void_send _null_ _null_ _null_ ) +insert ( 3446 macaddr8_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 774 2281 _null_ _null_ _null_ _null_ _null_ macaddr8_recv _null_ _null_ _null_ ) +insert ( 3447 macaddr8_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 774 _null_ _null_ _null_ _null_ _null_ macaddr8_send _null_ _null_ _null_ ) +insert ( 2504 pg_get_ruledef 11 10 12 1 0 0 0 f f f t f s s 2 0 25 "26 16" _null_ _null_ _null_ _null_ _null_ pg_get_ruledef_ext _null_ _null_ _null_ ) +insert ( 2505 pg_get_viewdef 11 10 12 1 0 0 0 f f f t f s r 2 0 25 "25 16" _null_ _null_ _null_ _null_ _null_ pg_get_viewdef_name_ext _null_ _null_ _null_ ) +insert ( 2506 pg_get_viewdef 11 10 12 1 0 0 0 f f f t f s r 2 0 25 "26 16" _null_ _null_ _null_ _null_ _null_ pg_get_viewdef_ext _null_ _null_ _null_ ) +insert ( 3159 pg_get_viewdef 11 10 12 1 0 0 0 f f f t f s r 2 0 25 "26 23" _null_ _null_ _null_ _null_ _null_ pg_get_viewdef_wrap _null_ _null_ _null_ ) +insert ( 2507 pg_get_indexdef 11 10 12 1 0 0 0 f f f t f s s 3 0 25 "26 23 16" _null_ _null_ _null_ _null_ _null_ pg_get_indexdef_ext _null_ _null_ _null_ ) +insert ( 2508 pg_get_constraintdef 11 10 12 1 0 0 0 f f f t f s s 2 0 25 "26 16" _null_ _null_ _null_ _null_ _null_ pg_get_constraintdef_ext _null_ _null_ _null_ ) +insert ( 2509 pg_get_expr 11 10 12 1 0 0 0 f f f t f s s 3 0 25 "194 26 16" _null_ _null_ _null_ _null_ _null_ pg_get_expr_ext _null_ _null_ _null_ ) +insert ( 2510 pg_prepared_statement 11 10 12 1 1000 0 0 f f f t t s r 0 0 2249 "" "{25,25,1184,2211,16}" "{o,o,o,o,o}" "{name,statement,prepare_time,parameter_types,from_sql}" _null_ _null_ pg_prepared_statement _null_ _null_ _null_ ) +insert ( 2511 pg_cursor 11 10 12 1 1000 0 0 f f f t t s r 0 0 2249 "" "{25,25,16,16,16,1184}" "{o,o,o,o,o,o}" "{name,statement,is_holdable,is_binary,is_scrollable,creation_time}" _null_ _null_ pg_cursor _null_ _null_ _null_ ) +insert ( 2599 pg_timezone_abbrevs 11 10 12 1 1000 0 0 f f f t t s s 0 0 2249 "" "{25,1186,16}" "{o,o,o}" "{abbrev,utc_offset,is_dst}" _null_ _null_ pg_timezone_abbrevs _null_ _null_ _null_ ) +insert ( 2856 pg_timezone_names 11 10 12 1 1000 0 0 f f f t t s s 0 0 2249 "" "{25,25,1186,16}" "{o,o,o,o}" "{name,abbrev,utc_offset,is_dst}" _null_ _null_ pg_timezone_names _null_ _null_ _null_ ) +insert ( 2730 pg_get_triggerdef 11 10 12 1 0 0 0 f f f t f s s 2 0 25 "26 16" _null_ _null_ _null_ _null_ _null_ pg_get_triggerdef_ext _null_ _null_ _null_ ) +insert ( 3035 pg_listening_channels 11 10 12 1 10 0 0 f f f t t s r 0 0 25 "" _null_ _null_ _null_ _null_ _null_ pg_listening_channels _null_ _null_ _null_ ) +insert ( 3036 pg_notify 11 10 12 1 0 0 0 f f f f f v r 2 0 2278 "25 25" _null_ _null_ _null_ _null_ _null_ pg_notify _null_ _null_ _null_ ) +insert ( 3296 pg_notification_queue_usage 11 10 12 1 0 0 0 f f f t f v r 0 0 701 "" _null_ _null_ _null_ _null_ _null_ pg_notification_queue_usage _null_ _null_ _null_ ) +insert ( 5052 pg_get_shmem_allocations 11 10 12 1 50 0 0 f f f t t v s 0 0 2249 "" "{25,20,20,20}" "{o,o,o,o}" "{name,off,size,allocated_size}" _null_ _null_ pg_get_shmem_allocations _null_ _null_ _null_ ) +insert ( 1066 generate_series 11 10 12 1 1000 0 3994 f f f t t i s 3 0 23 "23 23 23" _null_ _null_ _null_ _null_ _null_ generate_series_step_int4 _null_ _null_ _null_ ) +insert ( 1067 generate_series 11 10 12 1 1000 0 3994 f f f t t i s 2 0 23 "23 23" _null_ _null_ _null_ _null_ _null_ generate_series_int4 _null_ _null_ _null_ ) +insert ( 3994 generate_series_int4_support 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ generate_series_int4_support _null_ _null_ _null_ ) +insert ( 1068 generate_series 11 10 12 1 1000 0 3995 f f f t t i s 3 0 20 "20 20 20" _null_ _null_ _null_ _null_ _null_ generate_series_step_int8 _null_ _null_ _null_ ) +insert ( 1069 generate_series 11 10 12 1 1000 0 3995 f f f t t i s 2 0 20 "20 20" _null_ _null_ _null_ _null_ _null_ generate_series_int8 _null_ _null_ _null_ ) +insert ( 3995 generate_series_int8_support 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ generate_series_int8_support _null_ _null_ _null_ ) +insert ( 3259 generate_series 11 10 12 1 1000 0 0 f f f t t i s 3 0 1700 "1700 1700 1700" _null_ _null_ _null_ _null_ _null_ generate_series_step_numeric _null_ _null_ _null_ ) +insert ( 3260 generate_series 11 10 12 1 1000 0 0 f f f t t i s 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ _null_ generate_series_numeric _null_ _null_ _null_ ) +insert ( 938 generate_series 11 10 12 1 1000 0 0 f f f t t i s 3 0 1114 "1114 1114 1186" _null_ _null_ _null_ _null_ _null_ generate_series_timestamp _null_ _null_ _null_ ) +insert ( 939 generate_series 11 10 12 1 1000 0 0 f f f t t s s 3 0 1184 "1184 1184 1186" _null_ _null_ _null_ _null_ _null_ generate_series_timestamptz _null_ _null_ _null_ ) +insert ( 2515 booland_statefunc 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "16 16" _null_ _null_ _null_ _null_ _null_ booland_statefunc _null_ _null_ _null_ ) +insert ( 2516 boolor_statefunc 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "16 16" _null_ _null_ _null_ _null_ _null_ boolor_statefunc _null_ _null_ _null_ ) +insert ( 3496 bool_accum 11 10 12 1 0 0 0 f f f f f i s 2 0 2281 "2281 16" _null_ _null_ _null_ _null_ _null_ bool_accum _null_ _null_ _null_ ) +insert ( 3497 bool_accum_inv 11 10 12 1 0 0 0 f f f f f i s 2 0 2281 "2281 16" _null_ _null_ _null_ _null_ _null_ bool_accum_inv _null_ _null_ _null_ ) +insert ( 3498 bool_alltrue 11 10 12 1 0 0 0 f f f t f i s 1 0 16 2281 _null_ _null_ _null_ _null_ _null_ bool_alltrue _null_ _null_ _null_ ) +insert ( 3499 bool_anytrue 11 10 12 1 0 0 0 f f f t f i s 1 0 16 2281 _null_ _null_ _null_ _null_ _null_ bool_anytrue _null_ _null_ _null_ ) +insert ( 2517 bool_and 11 10 12 1 0 0 0 a f f f f i s 1 0 16 16 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2518 bool_or 11 10 12 1 0 0 0 a f f f f i s 1 0 16 16 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2519 every 11 10 12 1 0 0 0 a f f f f i s 1 0 16 16 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2236 bit_and 11 10 12 1 0 0 0 a f f f f i s 1 0 21 21 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2237 bit_or 11 10 12 1 0 0 0 a f f f f i s 1 0 21 21 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2238 bit_and 11 10 12 1 0 0 0 a f f f f i s 1 0 23 23 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2239 bit_or 11 10 12 1 0 0 0 a f f f f i s 1 0 23 23 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2240 bit_and 11 10 12 1 0 0 0 a f f f f i s 1 0 20 20 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2241 bit_or 11 10 12 1 0 0 0 a f f f f i s 1 0 20 20 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2242 bit_and 11 10 12 1 0 0 0 a f f f f i s 1 0 1560 1560 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2243 bit_or 11 10 12 1 0 0 0 a f f f f i s 1 0 1560 1560 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2546 interval_pl_date 11 10 14 1 0 0 0 f f f t f i s 2 0 1114 "1186 1082" _null_ _null_ _null_ _null_ _null_ "select $2 + $1" _null_ _null_ _null_ ) +insert ( 2547 interval_pl_timetz 11 10 14 1 0 0 0 f f f t f i s 2 0 1266 "1186 1266" _null_ _null_ _null_ _null_ _null_ "select $2 + $1" _null_ _null_ _null_ ) +insert ( 2548 interval_pl_timestamp 11 10 14 1 0 0 0 f f f t f i s 2 0 1114 "1186 1114" _null_ _null_ _null_ _null_ _null_ "select $2 + $1" _null_ _null_ _null_ ) +insert ( 2549 interval_pl_timestamptz 11 10 14 1 0 0 0 f f f t f s s 2 0 1184 "1186 1184" _null_ _null_ _null_ _null_ _null_ "select $2 + $1" _null_ _null_ _null_ ) +insert ( 2550 integer_pl_date 11 10 14 1 0 0 0 f f f t f i s 2 0 1082 "23 1082" _null_ _null_ _null_ _null_ _null_ "select $2 + $1" _null_ _null_ _null_ ) +insert ( 2556 pg_tablespace_databases 11 10 12 1 1000 0 0 f f f t t s s 1 0 26 26 _null_ _null_ _null_ _null_ _null_ pg_tablespace_databases _null_ _null_ _null_ ) +insert ( 2557 bool 11 10 12 1 0 0 0 f f f t f i s 1 0 16 23 _null_ _null_ _null_ _null_ _null_ int4_bool _null_ _null_ _null_ ) +insert ( 2558 int4 11 10 12 1 0 0 0 f f f t f i s 1 0 23 16 _null_ _null_ _null_ _null_ _null_ bool_int4 _null_ _null_ _null_ ) +insert ( 2559 lastval 11 10 12 1 0 0 0 f f f t f v u 0 0 20 "" _null_ _null_ _null_ _null_ _null_ lastval _null_ _null_ _null_ ) +insert ( 2560 pg_postmaster_start_time 11 10 12 1 0 0 0 f f f t f s s 0 0 1184 "" _null_ _null_ _null_ _null_ _null_ pg_postmaster_start_time _null_ _null_ _null_ ) +insert ( 2034 pg_conf_load_time 11 10 12 1 0 0 0 f f f t f s r 0 0 1184 "" _null_ _null_ _null_ _null_ _null_ pg_conf_load_time _null_ _null_ _null_ ) +insert ( 2562 box_below 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_below _null_ _null_ _null_ ) +insert ( 2563 box_overbelow 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_overbelow _null_ _null_ _null_ ) +insert ( 2564 box_overabove 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_overabove _null_ _null_ _null_ ) +insert ( 2565 box_above 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "603 603" _null_ _null_ _null_ _null_ _null_ box_above _null_ _null_ _null_ ) +insert ( 2566 poly_below 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "604 604" _null_ _null_ _null_ _null_ _null_ poly_below _null_ _null_ _null_ ) +insert ( 2567 poly_overbelow 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "604 604" _null_ _null_ _null_ _null_ _null_ poly_overbelow _null_ _null_ _null_ ) +insert ( 2568 poly_overabove 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "604 604" _null_ _null_ _null_ _null_ _null_ poly_overabove _null_ _null_ _null_ ) +insert ( 2569 poly_above 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "604 604" _null_ _null_ _null_ _null_ _null_ poly_above _null_ _null_ _null_ ) +insert ( 2587 circle_overbelow 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "718 718" _null_ _null_ _null_ _null_ _null_ circle_overbelow _null_ _null_ _null_ ) +insert ( 2588 circle_overabove 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "718 718" _null_ _null_ _null_ _null_ _null_ circle_overabove _null_ _null_ _null_ ) +insert ( 2578 gist_box_consistent 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "2281 603 21 26 2281" _null_ _null_ _null_ _null_ _null_ gist_box_consistent _null_ _null_ _null_ ) +insert ( 2581 gist_box_penalty 11 10 12 1 0 0 0 f f f t f i s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gist_box_penalty _null_ _null_ _null_ ) +insert ( 2582 gist_box_picksplit 11 10 12 1 0 0 0 f f f t f i s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ gist_box_picksplit _null_ _null_ _null_ ) +insert ( 2583 gist_box_union 11 10 12 1 0 0 0 f f f t f i s 2 0 603 "2281 2281" _null_ _null_ _null_ _null_ _null_ gist_box_union _null_ _null_ _null_ ) +insert ( 2584 gist_box_same 11 10 12 1 0 0 0 f f f t f i s 3 0 2281 "603 603 2281" _null_ _null_ _null_ _null_ _null_ gist_box_same _null_ _null_ _null_ ) +insert ( 3998 gist_box_distance 11 10 12 1 0 0 0 f f f t f i s 5 0 701 "2281 603 21 26 2281" _null_ _null_ _null_ _null_ _null_ gist_box_distance _null_ _null_ _null_ ) +insert ( 2585 gist_poly_consistent 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "2281 604 21 26 2281" _null_ _null_ _null_ _null_ _null_ gist_poly_consistent _null_ _null_ _null_ ) +insert ( 2586 gist_poly_compress 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ gist_poly_compress _null_ _null_ _null_ ) +insert ( 2591 gist_circle_consistent 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "2281 718 21 26 2281" _null_ _null_ _null_ _null_ _null_ gist_circle_consistent _null_ _null_ _null_ ) +insert ( 2592 gist_circle_compress 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ gist_circle_compress _null_ _null_ _null_ ) +insert ( 1030 gist_point_compress 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ gist_point_compress _null_ _null_ _null_ ) +insert ( 3282 gist_point_fetch 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ gist_point_fetch _null_ _null_ _null_ ) +insert ( 2179 gist_point_consistent 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "2281 600 21 26 2281" _null_ _null_ _null_ _null_ _null_ gist_point_consistent _null_ _null_ _null_ ) +insert ( 3064 gist_point_distance 11 10 12 1 0 0 0 f f f t f i s 5 0 701 "2281 600 21 26 2281" _null_ _null_ _null_ _null_ _null_ gist_point_distance _null_ _null_ _null_ ) +insert ( 3280 gist_circle_distance 11 10 12 1 0 0 0 f f f t f i s 5 0 701 "2281 718 21 26 2281" _null_ _null_ _null_ _null_ _null_ gist_circle_distance _null_ _null_ _null_ ) +insert ( 3288 gist_poly_distance 11 10 12 1 0 0 0 f f f t f i s 5 0 701 "2281 604 21 26 2281" _null_ _null_ _null_ _null_ _null_ gist_poly_distance _null_ _null_ _null_ ) +insert ( 2743 ginarrayextract 11 10 12 1 0 0 0 f f f t f i s 3 0 2281 "2277 2281 2281" _null_ _null_ _null_ _null_ _null_ ginarrayextract _null_ _null_ _null_ ) +insert ( 2774 ginqueryarrayextract 11 10 12 1 0 0 0 f f f t f i s 7 0 2281 "2277 2281 21 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginqueryarrayextract _null_ _null_ _null_ ) +insert ( 2744 ginarrayconsistent 11 10 12 1 0 0 0 f f f t f i s 8 0 16 "2281 21 2277 23 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginarrayconsistent _null_ _null_ _null_ ) +insert ( 3920 ginarraytriconsistent 11 10 12 1 0 0 0 f f f t f i s 7 0 18 "2281 21 2277 23 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ ginarraytriconsistent _null_ _null_ _null_ ) +insert ( 3076 ginarrayextract 11 10 12 1 0 0 0 f f f t f i s 2 0 2281 "2277 2281" _null_ _null_ _null_ _null_ _null_ ginarrayextract_2args _null_ _null_ _null_ ) +insert ( 2747 arrayoverlap 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2277 2277" _null_ _null_ _null_ _null_ _null_ arrayoverlap _null_ _null_ _null_ ) +insert ( 2748 arraycontains 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2277 2277" _null_ _null_ _null_ _null_ _null_ arraycontains _null_ _null_ _null_ ) +insert ( 2749 arraycontained 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2277 2277" _null_ _null_ _null_ _null_ _null_ arraycontained _null_ _null_ _null_ ) +insert ( 3383 brin_minmax_opcinfo 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ brin_minmax_opcinfo _null_ _null_ _null_ ) +insert ( 3384 brin_minmax_add_value 11 10 12 1 0 0 0 f f f t f i s 4 0 16 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brin_minmax_add_value _null_ _null_ _null_ ) +insert ( 3385 brin_minmax_consistent 11 10 12 1 0 0 0 f f f t f i s 3 0 16 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brin_minmax_consistent _null_ _null_ _null_ ) +insert ( 3386 brin_minmax_union 11 10 12 1 0 0 0 f f f t f i s 3 0 16 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brin_minmax_union _null_ _null_ _null_ ) +insert ( 4105 brin_inclusion_opcinfo 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ brin_inclusion_opcinfo _null_ _null_ _null_ ) +insert ( 4106 brin_inclusion_add_value 11 10 12 1 0 0 0 f f f t f i s 4 0 16 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brin_inclusion_add_value _null_ _null_ _null_ ) +insert ( 4107 brin_inclusion_consistent 11 10 12 1 0 0 0 f f f t f i s 3 0 16 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brin_inclusion_consistent _null_ _null_ _null_ ) +insert ( 4108 brin_inclusion_union 11 10 12 1 0 0 0 f f f t f i s 3 0 16 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brin_inclusion_union _null_ _null_ _null_ ) +insert ( 2880 pg_advisory_lock 11 10 12 1 0 0 0 f f f t f v r 1 0 2278 20 _null_ _null_ _null_ _null_ _null_ pg_advisory_lock_int8 _null_ _null_ _null_ ) +insert ( 3089 pg_advisory_xact_lock 11 10 12 1 0 0 0 f f f t f v r 1 0 2278 20 _null_ _null_ _null_ _null_ _null_ pg_advisory_xact_lock_int8 _null_ _null_ _null_ ) +insert ( 2881 pg_advisory_lock_shared 11 10 12 1 0 0 0 f f f t f v r 1 0 2278 20 _null_ _null_ _null_ _null_ _null_ pg_advisory_lock_shared_int8 _null_ _null_ _null_ ) +insert ( 3090 pg_advisory_xact_lock_shared 11 10 12 1 0 0 0 f f f t f v r 1 0 2278 20 _null_ _null_ _null_ _null_ _null_ pg_advisory_xact_lock_shared_int8 _null_ _null_ _null_ ) +insert ( 2882 pg_try_advisory_lock 11 10 12 1 0 0 0 f f f t f v r 1 0 16 20 _null_ _null_ _null_ _null_ _null_ pg_try_advisory_lock_int8 _null_ _null_ _null_ ) +insert ( 3091 pg_try_advisory_xact_lock 11 10 12 1 0 0 0 f f f t f v r 1 0 16 20 _null_ _null_ _null_ _null_ _null_ pg_try_advisory_xact_lock_int8 _null_ _null_ _null_ ) +insert ( 2883 pg_try_advisory_lock_shared 11 10 12 1 0 0 0 f f f t f v r 1 0 16 20 _null_ _null_ _null_ _null_ _null_ pg_try_advisory_lock_shared_int8 _null_ _null_ _null_ ) +insert ( 3092 pg_try_advisory_xact_lock_shared 11 10 12 1 0 0 0 f f f t f v r 1 0 16 20 _null_ _null_ _null_ _null_ _null_ pg_try_advisory_xact_lock_shared_int8 _null_ _null_ _null_ ) +insert ( 2884 pg_advisory_unlock 11 10 12 1 0 0 0 f f f t f v r 1 0 16 20 _null_ _null_ _null_ _null_ _null_ pg_advisory_unlock_int8 _null_ _null_ _null_ ) +insert ( 2885 pg_advisory_unlock_shared 11 10 12 1 0 0 0 f f f t f v r 1 0 16 20 _null_ _null_ _null_ _null_ _null_ pg_advisory_unlock_shared_int8 _null_ _null_ _null_ ) +insert ( 2886 pg_advisory_lock 11 10 12 1 0 0 0 f f f t f v r 2 0 2278 "23 23" _null_ _null_ _null_ _null_ _null_ pg_advisory_lock_int4 _null_ _null_ _null_ ) +insert ( 3093 pg_advisory_xact_lock 11 10 12 1 0 0 0 f f f t f v r 2 0 2278 "23 23" _null_ _null_ _null_ _null_ _null_ pg_advisory_xact_lock_int4 _null_ _null_ _null_ ) +insert ( 2887 pg_advisory_lock_shared 11 10 12 1 0 0 0 f f f t f v r 2 0 2278 "23 23" _null_ _null_ _null_ _null_ _null_ pg_advisory_lock_shared_int4 _null_ _null_ _null_ ) +insert ( 3094 pg_advisory_xact_lock_shared 11 10 12 1 0 0 0 f f f t f v r 2 0 2278 "23 23" _null_ _null_ _null_ _null_ _null_ pg_advisory_xact_lock_shared_int4 _null_ _null_ _null_ ) +insert ( 2888 pg_try_advisory_lock 11 10 12 1 0 0 0 f f f t f v r 2 0 16 "23 23" _null_ _null_ _null_ _null_ _null_ pg_try_advisory_lock_int4 _null_ _null_ _null_ ) +insert ( 3095 pg_try_advisory_xact_lock 11 10 12 1 0 0 0 f f f t f v r 2 0 16 "23 23" _null_ _null_ _null_ _null_ _null_ pg_try_advisory_xact_lock_int4 _null_ _null_ _null_ ) +insert ( 2889 pg_try_advisory_lock_shared 11 10 12 1 0 0 0 f f f t f v r 2 0 16 "23 23" _null_ _null_ _null_ _null_ _null_ pg_try_advisory_lock_shared_int4 _null_ _null_ _null_ ) +insert ( 3096 pg_try_advisory_xact_lock_shared 11 10 12 1 0 0 0 f f f t f v r 2 0 16 "23 23" _null_ _null_ _null_ _null_ _null_ pg_try_advisory_xact_lock_shared_int4 _null_ _null_ _null_ ) +insert ( 2890 pg_advisory_unlock 11 10 12 1 0 0 0 f f f t f v r 2 0 16 "23 23" _null_ _null_ _null_ _null_ _null_ pg_advisory_unlock_int4 _null_ _null_ _null_ ) +insert ( 2891 pg_advisory_unlock_shared 11 10 12 1 0 0 0 f f f t f v r 2 0 16 "23 23" _null_ _null_ _null_ _null_ _null_ pg_advisory_unlock_shared_int4 _null_ _null_ _null_ ) +insert ( 2892 pg_advisory_unlock_all 11 10 12 1 0 0 0 f f f t f v r 0 0 2278 "" _null_ _null_ _null_ _null_ _null_ pg_advisory_unlock_all _null_ _null_ _null_ ) +insert ( 2893 xml_in 11 10 12 1 0 0 0 f f f t f s s 1 0 142 2275 _null_ _null_ _null_ _null_ _null_ xml_in _null_ _null_ _null_ ) +insert ( 2894 xml_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 142 _null_ _null_ _null_ _null_ _null_ xml_out _null_ _null_ _null_ ) +insert ( 2895 xmlcomment 11 10 12 1 0 0 0 f f f t f i s 1 0 142 25 _null_ _null_ _null_ _null_ _null_ xmlcomment _null_ _null_ _null_ ) +insert ( 2896 xml 11 10 12 1 0 0 0 f f f t f s s 1 0 142 25 _null_ _null_ _null_ _null_ _null_ texttoxml _null_ _null_ _null_ ) +insert ( 2897 xmlvalidate 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "142 25" _null_ _null_ _null_ _null_ _null_ xmlvalidate _null_ _null_ _null_ ) +insert ( 2898 xml_recv 11 10 12 1 0 0 0 f f f t f s s 1 0 142 2281 _null_ _null_ _null_ _null_ _null_ xml_recv _null_ _null_ _null_ ) +insert ( 2899 xml_send 11 10 12 1 0 0 0 f f f t f s s 1 0 17 142 _null_ _null_ _null_ _null_ _null_ xml_send _null_ _null_ _null_ ) +insert ( 2900 xmlconcat2 11 10 12 1 0 0 0 f f f f f i s 2 0 142 "142 142" _null_ _null_ _null_ _null_ _null_ xmlconcat2 _null_ _null_ _null_ ) +insert ( 2901 xmlagg 11 10 12 1 0 0 0 a f f f f i s 1 0 142 142 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 2922 text 11 10 12 1 0 0 0 f f f t f i s 1 0 25 142 _null_ _null_ _null_ _null_ _null_ xmltotext _null_ _null_ _null_ ) +insert ( 2923 table_to_xml 11 10 12 100 0 0 0 f f f t f s r 4 0 142 "2205 16 16 25" _null_ _null_ "{tbl,nulls,tableforest,targetns}" _null_ _null_ table_to_xml _null_ _null_ _null_ ) +insert ( 2924 query_to_xml 11 10 12 100 0 0 0 f f f t f v u 4 0 142 "25 16 16 25" _null_ _null_ "{query,nulls,tableforest,targetns}" _null_ _null_ query_to_xml _null_ _null_ _null_ ) +insert ( 2925 cursor_to_xml 11 10 12 100 0 0 0 f f f t f v u 5 0 142 "1790 23 16 16 25" _null_ _null_ "{cursor,count,nulls,tableforest,targetns}" _null_ _null_ cursor_to_xml _null_ _null_ _null_ ) +insert ( 2926 table_to_xmlschema 11 10 12 100 0 0 0 f f f t f s r 4 0 142 "2205 16 16 25" _null_ _null_ "{tbl,nulls,tableforest,targetns}" _null_ _null_ table_to_xmlschema _null_ _null_ _null_ ) +insert ( 2927 query_to_xmlschema 11 10 12 100 0 0 0 f f f t f v u 4 0 142 "25 16 16 25" _null_ _null_ "{query,nulls,tableforest,targetns}" _null_ _null_ query_to_xmlschema _null_ _null_ _null_ ) +insert ( 2928 cursor_to_xmlschema 11 10 12 100 0 0 0 f f f t f v u 4 0 142 "1790 16 16 25" _null_ _null_ "{cursor,nulls,tableforest,targetns}" _null_ _null_ cursor_to_xmlschema _null_ _null_ _null_ ) +insert ( 2929 table_to_xml_and_xmlschema 11 10 12 100 0 0 0 f f f t f s r 4 0 142 "2205 16 16 25" _null_ _null_ "{tbl,nulls,tableforest,targetns}" _null_ _null_ table_to_xml_and_xmlschema _null_ _null_ _null_ ) +insert ( 2930 query_to_xml_and_xmlschema 11 10 12 100 0 0 0 f f f t f v u 4 0 142 "25 16 16 25" _null_ _null_ "{query,nulls,tableforest,targetns}" _null_ _null_ query_to_xml_and_xmlschema _null_ _null_ _null_ ) +insert ( 2933 schema_to_xml 11 10 12 100 0 0 0 f f f t f s r 4 0 142 "19 16 16 25" _null_ _null_ "{schema,nulls,tableforest,targetns}" _null_ _null_ schema_to_xml _null_ _null_ _null_ ) +insert ( 2934 schema_to_xmlschema 11 10 12 100 0 0 0 f f f t f s r 4 0 142 "19 16 16 25" _null_ _null_ "{schema,nulls,tableforest,targetns}" _null_ _null_ schema_to_xmlschema _null_ _null_ _null_ ) +insert ( 2935 schema_to_xml_and_xmlschema 11 10 12 100 0 0 0 f f f t f s r 4 0 142 "19 16 16 25" _null_ _null_ "{schema,nulls,tableforest,targetns}" _null_ _null_ schema_to_xml_and_xmlschema _null_ _null_ _null_ ) +insert ( 2936 database_to_xml 11 10 12 100 0 0 0 f f f t f s r 3 0 142 "16 16 25" _null_ _null_ "{nulls,tableforest,targetns}" _null_ _null_ database_to_xml _null_ _null_ _null_ ) +insert ( 2937 database_to_xmlschema 11 10 12 100 0 0 0 f f f t f s r 3 0 142 "16 16 25" _null_ _null_ "{nulls,tableforest,targetns}" _null_ _null_ database_to_xmlschema _null_ _null_ _null_ ) +insert ( 2938 database_to_xml_and_xmlschema 11 10 12 100 0 0 0 f f f t f s r 3 0 142 "16 16 25" _null_ _null_ "{nulls,tableforest,targetns}" _null_ _null_ database_to_xml_and_xmlschema _null_ _null_ _null_ ) +insert ( 2931 xpath 11 10 12 1 0 0 0 f f f t f i s 3 0 143 "25 142 1009" _null_ _null_ _null_ _null_ _null_ xpath _null_ _null_ _null_ ) +insert ( 2932 xpath 11 10 14 1 0 0 0 f f f t f i s 2 0 143 "25 142" _null_ _null_ _null_ _null_ _null_ "select pg_catalog.xpath($1, $2, ''{}''::pg_catalog.text[])" _null_ _null_ _null_ ) +insert ( 2614 xmlexists 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "25 142" _null_ _null_ _null_ _null_ _null_ xmlexists _null_ _null_ _null_ ) +insert ( 3049 xpath_exists 11 10 12 1 0 0 0 f f f t f i s 3 0 16 "25 142 1009" _null_ _null_ _null_ _null_ _null_ xpath_exists _null_ _null_ _null_ ) +insert ( 3050 xpath_exists 11 10 14 1 0 0 0 f f f t f i s 2 0 16 "25 142" _null_ _null_ _null_ _null_ _null_ "select pg_catalog.xpath_exists($1, $2, ''{}''::pg_catalog.text[])" _null_ _null_ _null_ ) +insert ( 3051 xml_is_well_formed 11 10 12 1 0 0 0 f f f t f s s 1 0 16 25 _null_ _null_ _null_ _null_ _null_ xml_is_well_formed _null_ _null_ _null_ ) +insert ( 3052 xml_is_well_formed_document 11 10 12 1 0 0 0 f f f t f i s 1 0 16 25 _null_ _null_ _null_ _null_ _null_ xml_is_well_formed_document _null_ _null_ _null_ ) +insert ( 3053 xml_is_well_formed_content 11 10 12 1 0 0 0 f f f t f i s 1 0 16 25 _null_ _null_ _null_ _null_ _null_ xml_is_well_formed_content _null_ _null_ _null_ ) +insert ( 321 json_in 11 10 12 1 0 0 0 f f f t f i s 1 0 114 2275 _null_ _null_ _null_ _null_ _null_ json_in _null_ _null_ _null_ ) +insert ( 322 json_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 114 _null_ _null_ _null_ _null_ _null_ json_out _null_ _null_ _null_ ) +insert ( 323 json_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 114 2281 _null_ _null_ _null_ _null_ _null_ json_recv _null_ _null_ _null_ ) +insert ( 324 json_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 114 _null_ _null_ _null_ _null_ _null_ json_send _null_ _null_ _null_ ) +insert ( 3153 array_to_json 11 10 12 1 0 0 0 f f f t f s s 1 0 114 2277 _null_ _null_ _null_ _null_ _null_ array_to_json _null_ _null_ _null_ ) +insert ( 3154 array_to_json 11 10 12 1 0 0 0 f f f t f s s 2 0 114 "2277 16" _null_ _null_ _null_ _null_ _null_ array_to_json_pretty _null_ _null_ _null_ ) +insert ( 3155 row_to_json 11 10 12 1 0 0 0 f f f t f s s 1 0 114 2249 _null_ _null_ _null_ _null_ _null_ row_to_json _null_ _null_ _null_ ) +insert ( 3156 row_to_json 11 10 12 1 0 0 0 f f f t f s s 2 0 114 "2249 16" _null_ _null_ _null_ _null_ _null_ row_to_json_pretty _null_ _null_ _null_ ) +insert ( 3173 json_agg_transfn 11 10 12 1 0 0 0 f f f f f s s 2 0 2281 "2281 2283" _null_ _null_ _null_ _null_ _null_ json_agg_transfn _null_ _null_ _null_ ) +insert ( 3174 json_agg_finalfn 11 10 12 1 0 0 0 f f f f f i s 1 0 114 2281 _null_ _null_ _null_ _null_ _null_ json_agg_finalfn _null_ _null_ _null_ ) +insert ( 3175 json_agg 11 10 12 1 0 0 0 a f f f f s s 1 0 114 2283 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3180 json_object_agg_transfn 11 10 12 1 0 0 0 f f f f f s s 3 0 2281 "2281 2276 2276" _null_ _null_ _null_ _null_ _null_ json_object_agg_transfn _null_ _null_ _null_ ) +insert ( 3196 json_object_agg_finalfn 11 10 12 1 0 0 0 f f f f f i s 1 0 114 2281 _null_ _null_ _null_ _null_ _null_ json_object_agg_finalfn _null_ _null_ _null_ ) +insert ( 3197 json_object_agg 11 10 12 1 0 0 0 a f f f f s s 2 0 114 "2276 2276" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3198 json_build_array 11 10 12 1 0 2276 0 f f f f f s s 1 0 114 2276 "{2276}" "{v}" _null_ _null_ _null_ json_build_array _null_ _null_ _null_ ) +insert ( 3199 json_build_array 11 10 12 1 0 0 0 f f f f f s s 0 0 114 "" _null_ _null_ _null_ _null_ _null_ json_build_array_noargs _null_ _null_ _null_ ) +insert ( 3200 json_build_object 11 10 12 1 0 2276 0 f f f f f s s 1 0 114 2276 "{2276}" "{v}" _null_ _null_ _null_ json_build_object _null_ _null_ _null_ ) +insert ( 3201 json_build_object 11 10 12 1 0 0 0 f f f f f s s 0 0 114 "" _null_ _null_ _null_ _null_ _null_ json_build_object_noargs _null_ _null_ _null_ ) +insert ( 3202 json_object 11 10 12 1 0 0 0 f f f t f i s 1 0 114 1009 _null_ _null_ _null_ _null_ _null_ json_object _null_ _null_ _null_ ) +insert ( 3203 json_object 11 10 12 1 0 0 0 f f f t f i s 2 0 114 "1009 1009" _null_ _null_ _null_ _null_ _null_ json_object_two_arg _null_ _null_ _null_ ) +insert ( 3176 to_json 11 10 12 1 0 0 0 f f f t f s s 1 0 114 2283 _null_ _null_ _null_ _null_ _null_ to_json _null_ _null_ _null_ ) +insert ( 3261 json_strip_nulls 11 10 12 1 0 0 0 f f f t f i s 1 0 114 114 _null_ _null_ _null_ _null_ _null_ json_strip_nulls _null_ _null_ _null_ ) +insert ( 3947 json_object_field 11 10 12 1 0 0 0 f f f t f i s 2 0 114 "114 25" _null_ _null_ "{from_json, field_name}" _null_ _null_ json_object_field _null_ _null_ _null_ ) +insert ( 3948 json_object_field_text 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "114 25" _null_ _null_ "{from_json, field_name}" _null_ _null_ json_object_field_text _null_ _null_ _null_ ) +insert ( 3949 json_array_element 11 10 12 1 0 0 0 f f f t f i s 2 0 114 "114 23" _null_ _null_ "{from_json, element_index}" _null_ _null_ json_array_element _null_ _null_ _null_ ) +insert ( 3950 json_array_element_text 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "114 23" _null_ _null_ "{from_json, element_index}" _null_ _null_ json_array_element_text _null_ _null_ _null_ ) +insert ( 3951 json_extract_path 11 10 12 1 0 25 0 f f f t f i s 2 0 114 "114 1009" "{114,1009}" "{i,v}" "{from_json,path_elems}" _null_ _null_ json_extract_path _null_ _null_ _null_ ) +insert ( 3953 json_extract_path_text 11 10 12 1 0 25 0 f f f t f i s 2 0 25 "114 1009" "{114,1009}" "{i,v}" "{from_json,path_elems}" _null_ _null_ json_extract_path_text _null_ _null_ _null_ ) +insert ( 3955 json_array_elements 11 10 12 1 100 0 0 f f f t t i s 1 0 114 114 "{114,114}" "{i,o}" "{from_json,value}" _null_ _null_ json_array_elements _null_ _null_ _null_ ) +insert ( 3969 json_array_elements_text 11 10 12 1 100 0 0 f f f t t i s 1 0 25 114 "{114,25}" "{i,o}" "{from_json,value}" _null_ _null_ json_array_elements_text _null_ _null_ _null_ ) +insert ( 3956 json_array_length 11 10 12 1 0 0 0 f f f t f i s 1 0 23 114 _null_ _null_ _null_ _null_ _null_ json_array_length _null_ _null_ _null_ ) +insert ( 3957 json_object_keys 11 10 12 1 100 0 0 f f f t t i s 1 0 25 114 _null_ _null_ _null_ _null_ _null_ json_object_keys _null_ _null_ _null_ ) +insert ( 3958 json_each 11 10 12 1 100 0 0 f f f t t i s 1 0 2249 114 "{114,25,114}" "{i,o,o}" "{from_json,key,value}" _null_ _null_ json_each _null_ _null_ _null_ ) +insert ( 3959 json_each_text 11 10 12 1 100 0 0 f f f t t i s 1 0 2249 114 "{114,25,25}" "{i,o,o}" "{from_json,key,value}" _null_ _null_ json_each_text _null_ _null_ _null_ ) +insert ( 3960 json_populate_record 11 10 12 1 0 0 0 f f f f f s s 3 0 2283 "2283 114 16" _null_ _null_ _null_ _null_ _null_ json_populate_record _null_ _null_ _null_ ) +insert ( 3961 json_populate_recordset 11 10 12 1 100 0 0 f f f f t s s 3 0 2283 "2283 114 16" _null_ _null_ _null_ _null_ _null_ json_populate_recordset _null_ _null_ _null_ ) +insert ( 3204 json_to_record 11 10 12 1 0 0 0 f f f t f s s 1 0 2249 114 _null_ _null_ _null_ _null_ _null_ json_to_record _null_ _null_ _null_ ) +insert ( 3205 json_to_recordset 11 10 12 1 100 0 0 f f f f t s s 1 0 2249 114 _null_ _null_ _null_ _null_ _null_ json_to_recordset _null_ _null_ _null_ ) +insert ( 3968 json_typeof 11 10 12 1 0 0 0 f f f t f i s 1 0 25 114 _null_ _null_ _null_ _null_ _null_ json_typeof _null_ _null_ _null_ ) +insert ( 2952 uuid_in 11 10 12 1 0 0 0 f f f t f i s 1 0 2950 2275 _null_ _null_ _null_ _null_ _null_ uuid_in _null_ _null_ _null_ ) +insert ( 2953 uuid_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 2950 _null_ _null_ _null_ _null_ _null_ uuid_out _null_ _null_ _null_ ) +insert ( 2954 uuid_lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "2950 2950" _null_ _null_ _null_ _null_ _null_ uuid_lt _null_ _null_ _null_ ) +insert ( 2955 uuid_le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "2950 2950" _null_ _null_ _null_ _null_ _null_ uuid_le _null_ _null_ _null_ ) +insert ( 2956 uuid_eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "2950 2950" _null_ _null_ _null_ _null_ _null_ uuid_eq _null_ _null_ _null_ ) +insert ( 2957 uuid_ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "2950 2950" _null_ _null_ _null_ _null_ _null_ uuid_ge _null_ _null_ _null_ ) +insert ( 2958 uuid_gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "2950 2950" _null_ _null_ _null_ _null_ _null_ uuid_gt _null_ _null_ _null_ ) +insert ( 2959 uuid_ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "2950 2950" _null_ _null_ _null_ _null_ _null_ uuid_ne _null_ _null_ _null_ ) +insert ( 2960 uuid_cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "2950 2950" _null_ _null_ _null_ _null_ _null_ uuid_cmp _null_ _null_ _null_ ) +insert ( 3300 uuid_sortsupport 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ uuid_sortsupport _null_ _null_ _null_ ) +insert ( 2961 uuid_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 2950 2281 _null_ _null_ _null_ _null_ _null_ uuid_recv _null_ _null_ _null_ ) +insert ( 2962 uuid_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 2950 _null_ _null_ _null_ _null_ _null_ uuid_send _null_ _null_ _null_ ) +insert ( 2963 uuid_hash 11 10 12 1 0 0 0 f f f t f i s 1 0 23 2950 _null_ _null_ _null_ _null_ _null_ uuid_hash _null_ _null_ _null_ ) +insert ( 3412 uuid_hash_extended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "2950 20" _null_ _null_ _null_ _null_ _null_ uuid_hash_extended _null_ _null_ _null_ ) +insert ( 3432 gen_random_uuid 11 10 12 1 0 0 0 f f t t f v s 0 0 2950 "" _null_ _null_ _null_ _null_ _null_ gen_random_uuid _null_ _null_ _null_ ) +insert ( 3229 pg_lsn_in 11 10 12 1 0 0 0 f f f t f i s 1 0 3220 2275 _null_ _null_ _null_ _null_ _null_ pg_lsn_in _null_ _null_ _null_ ) +insert ( 3230 pg_lsn_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 3220 _null_ _null_ _null_ _null_ _null_ pg_lsn_out _null_ _null_ _null_ ) +insert ( 3231 pg_lsn_lt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "3220 3220" _null_ _null_ _null_ _null_ _null_ pg_lsn_lt _null_ _null_ _null_ ) +insert ( 3232 pg_lsn_le 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "3220 3220" _null_ _null_ _null_ _null_ _null_ pg_lsn_le _null_ _null_ _null_ ) +insert ( 3233 pg_lsn_eq 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "3220 3220" _null_ _null_ _null_ _null_ _null_ pg_lsn_eq _null_ _null_ _null_ ) +insert ( 3234 pg_lsn_ge 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "3220 3220" _null_ _null_ _null_ _null_ _null_ pg_lsn_ge _null_ _null_ _null_ ) +insert ( 3235 pg_lsn_gt 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "3220 3220" _null_ _null_ _null_ _null_ _null_ pg_lsn_gt _null_ _null_ _null_ ) +insert ( 3236 pg_lsn_ne 11 10 12 1 0 0 0 f f t t f i s 2 0 16 "3220 3220" _null_ _null_ _null_ _null_ _null_ pg_lsn_ne _null_ _null_ _null_ ) +insert ( 3237 pg_lsn_mi 11 10 12 1 0 0 0 f f f t f i s 2 0 1700 "3220 3220" _null_ _null_ _null_ _null_ _null_ pg_lsn_mi _null_ _null_ _null_ ) +insert ( 3238 pg_lsn_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 3220 2281 _null_ _null_ _null_ _null_ _null_ pg_lsn_recv _null_ _null_ _null_ ) +insert ( 3239 pg_lsn_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 3220 _null_ _null_ _null_ _null_ _null_ pg_lsn_send _null_ _null_ _null_ ) +insert ( 3251 pg_lsn_cmp 11 10 12 1 0 0 0 f f t t f i s 2 0 23 "3220 3220" _null_ _null_ _null_ _null_ _null_ pg_lsn_cmp _null_ _null_ _null_ ) +insert ( 3252 pg_lsn_hash 11 10 12 1 0 0 0 f f f t f i s 1 0 23 3220 _null_ _null_ _null_ _null_ _null_ pg_lsn_hash _null_ _null_ _null_ ) +insert ( 3413 pg_lsn_hash_extended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "3220 20" _null_ _null_ _null_ _null_ _null_ pg_lsn_hash_extended _null_ _null_ _null_ ) +insert ( 4187 pg_lsn_larger 11 10 12 1 0 0 0 f f f t f i s 2 0 3220 "3220 3220" _null_ _null_ _null_ _null_ _null_ pg_lsn_larger _null_ _null_ _null_ ) +insert ( 4188 pg_lsn_smaller 11 10 12 1 0 0 0 f f f t f i s 2 0 3220 "3220 3220" _null_ _null_ _null_ _null_ _null_ pg_lsn_smaller _null_ _null_ _null_ ) +insert ( 3504 anyenum_in 11 10 12 1 0 0 0 f f f t f i s 1 0 3500 2275 _null_ _null_ _null_ _null_ _null_ anyenum_in _null_ _null_ _null_ ) +insert ( 3505 anyenum_out 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 3500 _null_ _null_ _null_ _null_ _null_ anyenum_out _null_ _null_ _null_ ) +insert ( 3506 enum_in 11 10 12 1 0 0 0 f f f t f s s 2 0 3500 "2275 26" _null_ _null_ _null_ _null_ _null_ enum_in _null_ _null_ _null_ ) +insert ( 3507 enum_out 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 3500 _null_ _null_ _null_ _null_ _null_ enum_out _null_ _null_ _null_ ) +insert ( 3508 enum_eq 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3500 3500" _null_ _null_ _null_ _null_ _null_ enum_eq _null_ _null_ _null_ ) +insert ( 3509 enum_ne 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3500 3500" _null_ _null_ _null_ _null_ _null_ enum_ne _null_ _null_ _null_ ) +insert ( 3510 enum_lt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3500 3500" _null_ _null_ _null_ _null_ _null_ enum_lt _null_ _null_ _null_ ) +insert ( 3511 enum_gt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3500 3500" _null_ _null_ _null_ _null_ _null_ enum_gt _null_ _null_ _null_ ) +insert ( 3512 enum_le 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3500 3500" _null_ _null_ _null_ _null_ _null_ enum_le _null_ _null_ _null_ ) +insert ( 3513 enum_ge 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3500 3500" _null_ _null_ _null_ _null_ _null_ enum_ge _null_ _null_ _null_ ) +insert ( 3514 enum_cmp 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "3500 3500" _null_ _null_ _null_ _null_ _null_ enum_cmp _null_ _null_ _null_ ) +insert ( 3515 hashenum 11 10 12 1 0 0 0 f f f t f i s 1 0 23 3500 _null_ _null_ _null_ _null_ _null_ hashenum _null_ _null_ _null_ ) +insert ( 3414 hashenumextended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "3500 20" _null_ _null_ _null_ _null_ _null_ hashenumextended _null_ _null_ _null_ ) +insert ( 3524 enum_smaller 11 10 12 1 0 0 0 f f f t f i s 2 0 3500 "3500 3500" _null_ _null_ _null_ _null_ _null_ enum_smaller _null_ _null_ _null_ ) +insert ( 3525 enum_larger 11 10 12 1 0 0 0 f f f t f i s 2 0 3500 "3500 3500" _null_ _null_ _null_ _null_ _null_ enum_larger _null_ _null_ _null_ ) +insert ( 3526 max 11 10 12 1 0 0 0 a f f f f i s 1 0 3500 3500 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3527 min 11 10 12 1 0 0 0 a f f f f i s 1 0 3500 3500 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3528 enum_first 11 10 12 1 0 0 0 f f f f f s s 1 0 3500 3500 _null_ _null_ _null_ _null_ _null_ enum_first _null_ _null_ _null_ ) +insert ( 3529 enum_last 11 10 12 1 0 0 0 f f f f f s s 1 0 3500 3500 _null_ _null_ _null_ _null_ _null_ enum_last _null_ _null_ _null_ ) +insert ( 3530 enum_range 11 10 12 1 0 0 0 f f f f f s s 2 0 2277 "3500 3500" _null_ _null_ _null_ _null_ _null_ enum_range_bounds _null_ _null_ _null_ ) +insert ( 3531 enum_range 11 10 12 1 0 0 0 f f f f f s s 1 0 2277 3500 _null_ _null_ _null_ _null_ _null_ enum_range_all _null_ _null_ _null_ ) +insert ( 3532 enum_recv 11 10 12 1 0 0 0 f f f t f s s 2 0 3500 "2281 26" _null_ _null_ _null_ _null_ _null_ enum_recv _null_ _null_ _null_ ) +insert ( 3533 enum_send 11 10 12 1 0 0 0 f f f t f s s 1 0 17 3500 _null_ _null_ _null_ _null_ _null_ enum_send _null_ _null_ _null_ ) +insert ( 3610 tsvectorin 11 10 12 1 0 0 0 f f f t f i s 1 0 3614 2275 _null_ _null_ _null_ _null_ _null_ tsvectorin _null_ _null_ _null_ ) +insert ( 3639 tsvectorrecv 11 10 12 1 0 0 0 f f f t f i s 1 0 3614 2281 _null_ _null_ _null_ _null_ _null_ tsvectorrecv _null_ _null_ _null_ ) +insert ( 3611 tsvectorout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 3614 _null_ _null_ _null_ _null_ _null_ tsvectorout _null_ _null_ _null_ ) +insert ( 3638 tsvectorsend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 3614 _null_ _null_ _null_ _null_ _null_ tsvectorsend _null_ _null_ _null_ ) +insert ( 3612 tsqueryin 11 10 12 1 0 0 0 f f f t f i s 1 0 3615 2275 _null_ _null_ _null_ _null_ _null_ tsqueryin _null_ _null_ _null_ ) +insert ( 3641 tsqueryrecv 11 10 12 1 0 0 0 f f f t f i s 1 0 3615 2281 _null_ _null_ _null_ _null_ _null_ tsqueryrecv _null_ _null_ _null_ ) +insert ( 3613 tsqueryout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 3615 _null_ _null_ _null_ _null_ _null_ tsqueryout _null_ _null_ _null_ ) +insert ( 3640 tsquerysend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 3615 _null_ _null_ _null_ _null_ _null_ tsquerysend _null_ _null_ _null_ ) +insert ( 3646 gtsvectorin 11 10 12 1 0 0 0 f f f t f i s 1 0 3642 2275 _null_ _null_ _null_ _null_ _null_ gtsvectorin _null_ _null_ _null_ ) +insert ( 3647 gtsvectorout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 3642 _null_ _null_ _null_ _null_ _null_ gtsvectorout _null_ _null_ _null_ ) +insert ( 3616 tsvector_lt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3614 3614" _null_ _null_ _null_ _null_ _null_ tsvector_lt _null_ _null_ _null_ ) +insert ( 3617 tsvector_le 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3614 3614" _null_ _null_ _null_ _null_ _null_ tsvector_le _null_ _null_ _null_ ) +insert ( 3618 tsvector_eq 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3614 3614" _null_ _null_ _null_ _null_ _null_ tsvector_eq _null_ _null_ _null_ ) +insert ( 3619 tsvector_ne 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3614 3614" _null_ _null_ _null_ _null_ _null_ tsvector_ne _null_ _null_ _null_ ) +insert ( 3620 tsvector_ge 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3614 3614" _null_ _null_ _null_ _null_ _null_ tsvector_ge _null_ _null_ _null_ ) +insert ( 3621 tsvector_gt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3614 3614" _null_ _null_ _null_ _null_ _null_ tsvector_gt _null_ _null_ _null_ ) +insert ( 3622 tsvector_cmp 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "3614 3614" _null_ _null_ _null_ _null_ _null_ tsvector_cmp _null_ _null_ _null_ ) +insert ( 3711 length 11 10 12 1 0 0 0 f f f t f i s 1 0 23 3614 _null_ _null_ _null_ _null_ _null_ tsvector_length _null_ _null_ _null_ ) +insert ( 3623 strip 11 10 12 1 0 0 0 f f f t f i s 1 0 3614 3614 _null_ _null_ _null_ _null_ _null_ tsvector_strip _null_ _null_ _null_ ) +insert ( 3624 setweight 11 10 12 1 0 0 0 f f f t f i s 2 0 3614 "3614 18" _null_ _null_ _null_ _null_ _null_ tsvector_setweight _null_ _null_ _null_ ) +insert ( 3320 setweight 11 10 12 1 0 0 0 f f f t f i s 3 0 3614 "3614 18 1009" _null_ _null_ _null_ _null_ _null_ tsvector_setweight_by_filter _null_ _null_ _null_ ) +insert ( 3625 tsvector_concat 11 10 12 1 0 0 0 f f f t f i s 2 0 3614 "3614 3614" _null_ _null_ _null_ _null_ _null_ tsvector_concat _null_ _null_ _null_ ) +insert ( 3321 ts_delete 11 10 12 1 0 0 0 f f f t f i s 2 0 3614 "3614 25" _null_ _null_ _null_ _null_ _null_ tsvector_delete_str _null_ _null_ _null_ ) +insert ( 3323 ts_delete 11 10 12 1 0 0 0 f f f t f i s 2 0 3614 "3614 1009" _null_ _null_ _null_ _null_ _null_ tsvector_delete_arr _null_ _null_ _null_ ) +insert ( 3322 unnest 11 10 12 1 10 0 0 f f f t t i s 1 0 2249 3614 "{3614,25,1005,1009}" "{i,o,o,o}" "{tsvector,lexeme,positions,weights}" _null_ _null_ tsvector_unnest _null_ _null_ _null_ ) +insert ( 3326 tsvector_to_array 11 10 12 1 0 0 0 f f f t f i s 1 0 1009 3614 _null_ _null_ _null_ _null_ _null_ tsvector_to_array _null_ _null_ _null_ ) +insert ( 3327 array_to_tsvector 11 10 12 1 0 0 0 f f f t f i s 1 0 3614 1009 _null_ _null_ _null_ _null_ _null_ array_to_tsvector _null_ _null_ _null_ ) +insert ( 3319 ts_filter 11 10 12 1 0 0 0 f f f t f i s 2 0 3614 "3614 1002" _null_ _null_ _null_ _null_ _null_ tsvector_filter _null_ _null_ _null_ ) +insert ( 3634 ts_match_vq 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3614 3615" _null_ _null_ _null_ _null_ _null_ ts_match_vq _null_ _null_ _null_ ) +insert ( 3635 ts_match_qv 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3615 3614" _null_ _null_ _null_ _null_ _null_ ts_match_qv _null_ _null_ _null_ ) +insert ( 3760 ts_match_tt 11 10 12 100 0 0 0 f f f t f s s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ ts_match_tt _null_ _null_ _null_ ) +insert ( 3761 ts_match_tq 11 10 12 100 0 0 0 f f f t f s s 2 0 16 "25 3615" _null_ _null_ _null_ _null_ _null_ ts_match_tq _null_ _null_ _null_ ) +insert ( 3648 gtsvector_compress 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ gtsvector_compress _null_ _null_ _null_ ) +insert ( 3649 gtsvector_decompress 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ gtsvector_decompress _null_ _null_ _null_ ) +insert ( 3650 gtsvector_picksplit 11 10 12 1 0 0 0 f f f t f i s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ gtsvector_picksplit _null_ _null_ _null_ ) +insert ( 3651 gtsvector_union 11 10 12 1 0 0 0 f f f t f i s 2 0 3642 "2281 2281" _null_ _null_ _null_ _null_ _null_ gtsvector_union _null_ _null_ _null_ ) +insert ( 3652 gtsvector_same 11 10 12 1 0 0 0 f f f t f i s 3 0 2281 "3642 3642 2281" _null_ _null_ _null_ _null_ _null_ gtsvector_same _null_ _null_ _null_ ) +insert ( 3653 gtsvector_penalty 11 10 12 1 0 0 0 f f f t f i s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gtsvector_penalty _null_ _null_ _null_ ) +insert ( 3654 gtsvector_consistent 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "2281 3614 21 26 2281" _null_ _null_ _null_ _null_ _null_ gtsvector_consistent _null_ _null_ _null_ ) +insert ( 3790 gtsvector_consistent 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "2281 3642 23 26 2281" _null_ _null_ _null_ _null_ _null_ gtsvector_consistent_oldsig _null_ _null_ _null_ ) +insert ( 3434 gtsvector_options 11 10 12 1 0 0 0 f f f f f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ gtsvector_options _null_ _null_ _null_ ) +insert ( 3656 gin_extract_tsvector 11 10 12 1 0 0 0 f f f t f i s 3 0 2281 "3614 2281 2281" _null_ _null_ _null_ _null_ _null_ gin_extract_tsvector _null_ _null_ _null_ ) +insert ( 3657 gin_extract_tsquery 11 10 12 1 0 0 0 f f f t f i s 7 0 2281 "3614 2281 21 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gin_extract_tsquery _null_ _null_ _null_ ) +insert ( 3658 gin_tsquery_consistent 11 10 12 1 0 0 0 f f f t f i s 8 0 16 "2281 21 3614 23 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gin_tsquery_consistent _null_ _null_ _null_ ) +insert ( 3921 gin_tsquery_triconsistent 11 10 12 1 0 0 0 f f f t f i s 7 0 18 "2281 21 3614 23 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gin_tsquery_triconsistent _null_ _null_ _null_ ) +insert ( 3724 gin_cmp_tslexeme 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "25 25" _null_ _null_ _null_ _null_ _null_ gin_cmp_tslexeme _null_ _null_ _null_ ) +insert ( 2700 gin_cmp_prefix 11 10 12 1 0 0 0 f f f t f i s 4 0 23 "25 25 21 2281" _null_ _null_ _null_ _null_ _null_ gin_cmp_prefix _null_ _null_ _null_ ) +insert ( 3077 gin_extract_tsvector 11 10 12 1 0 0 0 f f f t f i s 2 0 2281 "3614 2281" _null_ _null_ _null_ _null_ _null_ gin_extract_tsvector_2args _null_ _null_ _null_ ) +insert ( 3087 gin_extract_tsquery 11 10 12 1 0 0 0 f f f t f i s 5 0 2281 "3615 2281 21 2281 2281" _null_ _null_ _null_ _null_ _null_ gin_extract_tsquery_5args _null_ _null_ _null_ ) +insert ( 3088 gin_tsquery_consistent 11 10 12 1 0 0 0 f f f t f i s 6 0 16 "2281 21 3615 23 2281 2281" _null_ _null_ _null_ _null_ _null_ gin_tsquery_consistent_6args _null_ _null_ _null_ ) +insert ( 3791 gin_extract_tsquery 11 10 12 1 0 0 0 f f f t f i s 7 0 2281 "3615 2281 21 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gin_extract_tsquery_oldsig _null_ _null_ _null_ ) +insert ( 3792 gin_tsquery_consistent 11 10 12 1 0 0 0 f f f t f i s 8 0 16 "2281 21 3615 23 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gin_tsquery_consistent_oldsig _null_ _null_ _null_ ) +insert ( 3789 gin_clean_pending_list 11 10 12 1 0 0 0 f f f t f v u 1 0 20 2205 _null_ _null_ _null_ _null_ _null_ gin_clean_pending_list _null_ _null_ _null_ ) +insert ( 3662 tsquery_lt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3615 3615" _null_ _null_ _null_ _null_ _null_ tsquery_lt _null_ _null_ _null_ ) +insert ( 3663 tsquery_le 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3615 3615" _null_ _null_ _null_ _null_ _null_ tsquery_le _null_ _null_ _null_ ) +insert ( 3664 tsquery_eq 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3615 3615" _null_ _null_ _null_ _null_ _null_ tsquery_eq _null_ _null_ _null_ ) +insert ( 3665 tsquery_ne 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3615 3615" _null_ _null_ _null_ _null_ _null_ tsquery_ne _null_ _null_ _null_ ) +insert ( 3666 tsquery_ge 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3615 3615" _null_ _null_ _null_ _null_ _null_ tsquery_ge _null_ _null_ _null_ ) +insert ( 3667 tsquery_gt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3615 3615" _null_ _null_ _null_ _null_ _null_ tsquery_gt _null_ _null_ _null_ ) +insert ( 3668 tsquery_cmp 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "3615 3615" _null_ _null_ _null_ _null_ _null_ tsquery_cmp _null_ _null_ _null_ ) +insert ( 3669 tsquery_and 11 10 12 1 0 0 0 f f f t f i s 2 0 3615 "3615 3615" _null_ _null_ _null_ _null_ _null_ tsquery_and _null_ _null_ _null_ ) +insert ( 3670 tsquery_or 11 10 12 1 0 0 0 f f f t f i s 2 0 3615 "3615 3615" _null_ _null_ _null_ _null_ _null_ tsquery_or _null_ _null_ _null_ ) +insert ( 5003 tsquery_phrase 11 10 12 1 0 0 0 f f f t f i s 2 0 3615 "3615 3615" _null_ _null_ _null_ _null_ _null_ tsquery_phrase _null_ _null_ _null_ ) +insert ( 5004 tsquery_phrase 11 10 12 1 0 0 0 f f f t f i s 3 0 3615 "3615 3615 23" _null_ _null_ _null_ _null_ _null_ tsquery_phrase_distance _null_ _null_ _null_ ) +insert ( 3671 tsquery_not 11 10 12 1 0 0 0 f f f t f i s 1 0 3615 3615 _null_ _null_ _null_ _null_ _null_ tsquery_not _null_ _null_ _null_ ) +insert ( 3691 tsq_mcontains 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3615 3615" _null_ _null_ _null_ _null_ _null_ tsq_mcontains _null_ _null_ _null_ ) +insert ( 3692 tsq_mcontained 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3615 3615" _null_ _null_ _null_ _null_ _null_ tsq_mcontained _null_ _null_ _null_ ) +insert ( 3672 numnode 11 10 12 1 0 0 0 f f f t f i s 1 0 23 3615 _null_ _null_ _null_ _null_ _null_ tsquery_numnode _null_ _null_ _null_ ) +insert ( 3673 querytree 11 10 12 1 0 0 0 f f f t f i s 1 0 25 3615 _null_ _null_ _null_ _null_ _null_ tsquerytree _null_ _null_ _null_ ) +insert ( 3684 ts_rewrite 11 10 12 1 0 0 0 f f f t f i s 3 0 3615 "3615 3615 3615" _null_ _null_ _null_ _null_ _null_ tsquery_rewrite _null_ _null_ _null_ ) +insert ( 3685 ts_rewrite 11 10 12 100 0 0 0 f f f t f v u 2 0 3615 "3615 25" _null_ _null_ _null_ _null_ _null_ tsquery_rewrite_query _null_ _null_ _null_ ) +insert ( 3695 gtsquery_compress 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ gtsquery_compress _null_ _null_ _null_ ) +insert ( 3697 gtsquery_picksplit 11 10 12 1 0 0 0 f f f t f i s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ gtsquery_picksplit _null_ _null_ _null_ ) +insert ( 3698 gtsquery_union 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "2281 2281" _null_ _null_ _null_ _null_ _null_ gtsquery_union _null_ _null_ _null_ ) +insert ( 3699 gtsquery_same 11 10 12 1 0 0 0 f f f t f i s 3 0 2281 "20 20 2281" _null_ _null_ _null_ _null_ _null_ gtsquery_same _null_ _null_ _null_ ) +insert ( 3700 gtsquery_penalty 11 10 12 1 0 0 0 f f f t f i s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gtsquery_penalty _null_ _null_ _null_ ) +insert ( 3701 gtsquery_consistent 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "2281 3615 21 26 2281" _null_ _null_ _null_ _null_ _null_ gtsquery_consistent _null_ _null_ _null_ ) +insert ( 3793 gtsquery_consistent 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "2281 2281 23 26 2281" _null_ _null_ _null_ _null_ _null_ gtsquery_consistent_oldsig _null_ _null_ _null_ ) +insert ( 3686 tsmatchsel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ tsmatchsel _null_ _null_ _null_ ) +insert ( 3687 tsmatchjoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ tsmatchjoinsel _null_ _null_ _null_ ) +insert ( 3688 ts_typanalyze 11 10 12 1 0 0 0 f f f t f s s 1 0 16 2281 _null_ _null_ _null_ _null_ _null_ ts_typanalyze _null_ _null_ _null_ ) +insert ( 3689 ts_stat 11 10 12 10 10000 0 0 f f f t t v u 1 0 2249 25 "{25,25,23,23}" "{i,o,o,o}" "{query,word,ndoc,nentry}" _null_ _null_ ts_stat1 _null_ _null_ _null_ ) +insert ( 3690 ts_stat 11 10 12 10 10000 0 0 f f f t t v u 2 0 2249 "25 25" "{25,25,25,23,23}" "{i,i,o,o,o}" "{query,weights,word,ndoc,nentry}" _null_ _null_ ts_stat2 _null_ _null_ _null_ ) +insert ( 3703 ts_rank 11 10 12 1 0 0 0 f f f t f i s 4 0 700 "1021 3614 3615 23" _null_ _null_ _null_ _null_ _null_ ts_rank_wttf _null_ _null_ _null_ ) +insert ( 3704 ts_rank 11 10 12 1 0 0 0 f f f t f i s 3 0 700 "1021 3614 3615" _null_ _null_ _null_ _null_ _null_ ts_rank_wtt _null_ _null_ _null_ ) +insert ( 3705 ts_rank 11 10 12 1 0 0 0 f f f t f i s 3 0 700 "3614 3615 23" _null_ _null_ _null_ _null_ _null_ ts_rank_ttf _null_ _null_ _null_ ) +insert ( 3706 ts_rank 11 10 12 1 0 0 0 f f f t f i s 2 0 700 "3614 3615" _null_ _null_ _null_ _null_ _null_ ts_rank_tt _null_ _null_ _null_ ) +insert ( 3707 ts_rank_cd 11 10 12 1 0 0 0 f f f t f i s 4 0 700 "1021 3614 3615 23" _null_ _null_ _null_ _null_ _null_ ts_rankcd_wttf _null_ _null_ _null_ ) +insert ( 3708 ts_rank_cd 11 10 12 1 0 0 0 f f f t f i s 3 0 700 "1021 3614 3615" _null_ _null_ _null_ _null_ _null_ ts_rankcd_wtt _null_ _null_ _null_ ) +insert ( 3709 ts_rank_cd 11 10 12 1 0 0 0 f f f t f i s 3 0 700 "3614 3615 23" _null_ _null_ _null_ _null_ _null_ ts_rankcd_ttf _null_ _null_ _null_ ) +insert ( 3710 ts_rank_cd 11 10 12 1 0 0 0 f f f t f i s 2 0 700 "3614 3615" _null_ _null_ _null_ _null_ _null_ ts_rankcd_tt _null_ _null_ _null_ ) +insert ( 3713 ts_token_type 11 10 12 1 16 0 0 f f f t t i s 1 0 2249 26 "{26,23,25,25}" "{i,o,o,o}" "{parser_oid,tokid,alias,description}" _null_ _null_ ts_token_type_byid _null_ _null_ _null_ ) +insert ( 3714 ts_token_type 11 10 12 1 16 0 0 f f f t t s s 1 0 2249 25 "{25,23,25,25}" "{i,o,o,o}" "{parser_name,tokid,alias,description}" _null_ _null_ ts_token_type_byname _null_ _null_ _null_ ) +insert ( 3715 ts_parse 11 10 12 1 1000 0 0 f f f t t i s 2 0 2249 "26 25" "{26,25,23,25}" "{i,i,o,o}" "{parser_oid,txt,tokid,token}" _null_ _null_ ts_parse_byid _null_ _null_ _null_ ) +insert ( 3716 ts_parse 11 10 12 1 1000 0 0 f f f t t s s 2 0 2249 "25 25" "{25,25,23,25}" "{i,i,o,o}" "{parser_name,txt,tokid,token}" _null_ _null_ ts_parse_byname _null_ _null_ _null_ ) +insert ( 3717 prsd_start 11 10 12 1 0 0 0 f f f t f i s 2 0 2281 "2281 23" _null_ _null_ _null_ _null_ _null_ prsd_start _null_ _null_ _null_ ) +insert ( 3718 prsd_nexttoken 11 10 12 1 0 0 0 f f f t f i s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ prsd_nexttoken _null_ _null_ _null_ ) +insert ( 3719 prsd_end 11 10 12 1 0 0 0 f f f t f i s 1 0 2278 2281 _null_ _null_ _null_ _null_ _null_ prsd_end _null_ _null_ _null_ ) +insert ( 3720 prsd_headline 11 10 12 1 0 0 0 f f f t f i s 3 0 2281 "2281 2281 3615" _null_ _null_ _null_ _null_ _null_ prsd_headline _null_ _null_ _null_ ) +insert ( 3721 prsd_lextype 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ prsd_lextype _null_ _null_ _null_ ) +insert ( 3723 ts_lexize 11 10 12 1 0 0 0 f f f t f i s 2 0 1009 "3769 25" _null_ _null_ _null_ _null_ _null_ ts_lexize _null_ _null_ _null_ ) +insert ( 3725 dsimple_init 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ dsimple_init _null_ _null_ _null_ ) +insert ( 3726 dsimple_lexize 11 10 12 1 0 0 0 f f f t f i s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ dsimple_lexize _null_ _null_ _null_ ) +insert ( 3728 dsynonym_init 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ dsynonym_init _null_ _null_ _null_ ) +insert ( 3729 dsynonym_lexize 11 10 12 1 0 0 0 f f f t f i s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ dsynonym_lexize _null_ _null_ _null_ ) +insert ( 3731 dispell_init 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ dispell_init _null_ _null_ _null_ ) +insert ( 3732 dispell_lexize 11 10 12 1 0 0 0 f f f t f i s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ dispell_lexize _null_ _null_ _null_ ) +insert ( 3740 thesaurus_init 11 10 12 1 0 0 0 f f f t f i s 1 0 2281 2281 _null_ _null_ _null_ _null_ _null_ thesaurus_init _null_ _null_ _null_ ) +insert ( 3741 thesaurus_lexize 11 10 12 1 0 0 0 f f f t f i s 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ thesaurus_lexize _null_ _null_ _null_ ) +insert ( 3743 ts_headline 11 10 12 100 0 0 0 f f f t f i s 4 0 25 "3734 25 3615 25" _null_ _null_ _null_ _null_ _null_ ts_headline_byid_opt _null_ _null_ _null_ ) +insert ( 3744 ts_headline 11 10 12 100 0 0 0 f f f t f i s 3 0 25 "3734 25 3615" _null_ _null_ _null_ _null_ _null_ ts_headline_byid _null_ _null_ _null_ ) +insert ( 3754 ts_headline 11 10 12 100 0 0 0 f f f t f s s 3 0 25 "25 3615 25" _null_ _null_ _null_ _null_ _null_ ts_headline_opt _null_ _null_ _null_ ) +insert ( 3755 ts_headline 11 10 12 100 0 0 0 f f f t f s s 2 0 25 "25 3615" _null_ _null_ _null_ _null_ _null_ ts_headline _null_ _null_ _null_ ) +insert ( 4201 ts_headline 11 10 12 100 0 0 0 f f f t f i s 4 0 3802 "3734 3802 3615 25" _null_ _null_ _null_ _null_ _null_ ts_headline_jsonb_byid_opt _null_ _null_ _null_ ) +insert ( 4202 ts_headline 11 10 12 100 0 0 0 f f f t f i s 3 0 3802 "3734 3802 3615" _null_ _null_ _null_ _null_ _null_ ts_headline_jsonb_byid _null_ _null_ _null_ ) +insert ( 4203 ts_headline 11 10 12 100 0 0 0 f f f t f s s 3 0 3802 "3802 3615 25" _null_ _null_ _null_ _null_ _null_ ts_headline_jsonb_opt _null_ _null_ _null_ ) +insert ( 4204 ts_headline 11 10 12 100 0 0 0 f f f t f s s 2 0 3802 "3802 3615" _null_ _null_ _null_ _null_ _null_ ts_headline_jsonb _null_ _null_ _null_ ) +insert ( 4205 ts_headline 11 10 12 100 0 0 0 f f f t f i s 4 0 114 "3734 114 3615 25" _null_ _null_ _null_ _null_ _null_ ts_headline_json_byid_opt _null_ _null_ _null_ ) +insert ( 4206 ts_headline 11 10 12 100 0 0 0 f f f t f i s 3 0 114 "3734 114 3615" _null_ _null_ _null_ _null_ _null_ ts_headline_json_byid _null_ _null_ _null_ ) +insert ( 4207 ts_headline 11 10 12 100 0 0 0 f f f t f s s 3 0 114 "114 3615 25" _null_ _null_ _null_ _null_ _null_ ts_headline_json_opt _null_ _null_ _null_ ) +insert ( 4208 ts_headline 11 10 12 100 0 0 0 f f f t f s s 2 0 114 "114 3615" _null_ _null_ _null_ _null_ _null_ ts_headline_json _null_ _null_ _null_ ) +insert ( 3745 to_tsvector 11 10 12 100 0 0 0 f f f t f i s 2 0 3614 "3734 25" _null_ _null_ _null_ _null_ _null_ to_tsvector_byid _null_ _null_ _null_ ) +insert ( 3746 to_tsquery 11 10 12 100 0 0 0 f f f t f i s 2 0 3615 "3734 25" _null_ _null_ _null_ _null_ _null_ to_tsquery_byid _null_ _null_ _null_ ) +insert ( 3747 plainto_tsquery 11 10 12 100 0 0 0 f f f t f i s 2 0 3615 "3734 25" _null_ _null_ _null_ _null_ _null_ plainto_tsquery_byid _null_ _null_ _null_ ) +insert ( 5006 phraseto_tsquery 11 10 12 100 0 0 0 f f f t f i s 2 0 3615 "3734 25" _null_ _null_ _null_ _null_ _null_ phraseto_tsquery_byid _null_ _null_ _null_ ) +insert ( 5007 websearch_to_tsquery 11 10 12 100 0 0 0 f f f t f i s 2 0 3615 "3734 25" _null_ _null_ _null_ _null_ _null_ websearch_to_tsquery_byid _null_ _null_ _null_ ) +insert ( 3749 to_tsvector 11 10 12 100 0 0 0 f f f t f s s 1 0 3614 25 _null_ _null_ _null_ _null_ _null_ to_tsvector _null_ _null_ _null_ ) +insert ( 3750 to_tsquery 11 10 12 100 0 0 0 f f f t f s s 1 0 3615 25 _null_ _null_ _null_ _null_ _null_ to_tsquery _null_ _null_ _null_ ) +insert ( 3751 plainto_tsquery 11 10 12 100 0 0 0 f f f t f s s 1 0 3615 25 _null_ _null_ _null_ _null_ _null_ plainto_tsquery _null_ _null_ _null_ ) +insert ( 5001 phraseto_tsquery 11 10 12 100 0 0 0 f f f t f s s 1 0 3615 25 _null_ _null_ _null_ _null_ _null_ phraseto_tsquery _null_ _null_ _null_ ) +insert ( 5009 websearch_to_tsquery 11 10 12 100 0 0 0 f f f t f s s 1 0 3615 25 _null_ _null_ _null_ _null_ _null_ websearch_to_tsquery _null_ _null_ _null_ ) +insert ( 4209 to_tsvector 11 10 12 100 0 0 0 f f f t f s s 1 0 3614 3802 _null_ _null_ _null_ _null_ _null_ jsonb_string_to_tsvector _null_ _null_ _null_ ) +insert ( 4213 jsonb_to_tsvector 11 10 12 100 0 0 0 f f f t f s s 2 0 3614 "3802 3802" _null_ _null_ _null_ _null_ _null_ jsonb_to_tsvector _null_ _null_ _null_ ) +insert ( 4210 to_tsvector 11 10 12 100 0 0 0 f f f t f s s 1 0 3614 114 _null_ _null_ _null_ _null_ _null_ json_string_to_tsvector _null_ _null_ _null_ ) +insert ( 4215 json_to_tsvector 11 10 12 100 0 0 0 f f f t f s s 2 0 3614 "114 3802" _null_ _null_ _null_ _null_ _null_ json_to_tsvector _null_ _null_ _null_ ) +insert ( 4211 to_tsvector 11 10 12 100 0 0 0 f f f t f i s 2 0 3614 "3734 3802" _null_ _null_ _null_ _null_ _null_ jsonb_string_to_tsvector_byid _null_ _null_ _null_ ) +insert ( 4214 jsonb_to_tsvector 11 10 12 100 0 0 0 f f f t f i s 3 0 3614 "3734 3802 3802" _null_ _null_ _null_ _null_ _null_ jsonb_to_tsvector_byid _null_ _null_ _null_ ) +insert ( 4212 to_tsvector 11 10 12 100 0 0 0 f f f t f i s 2 0 3614 "3734 114" _null_ _null_ _null_ _null_ _null_ json_string_to_tsvector_byid _null_ _null_ _null_ ) +insert ( 4216 json_to_tsvector 11 10 12 100 0 0 0 f f f t f i s 3 0 3614 "3734 114 3802" _null_ _null_ _null_ _null_ _null_ json_to_tsvector_byid _null_ _null_ _null_ ) +insert ( 3752 tsvector_update_trigger 11 10 12 1 0 0 0 f f f f f v s 0 0 2279 "" _null_ _null_ _null_ _null_ _null_ tsvector_update_trigger_byid _null_ _null_ _null_ ) +insert ( 3753 tsvector_update_trigger_column 11 10 12 1 0 0 0 f f f f f v s 0 0 2279 "" _null_ _null_ _null_ _null_ _null_ tsvector_update_trigger_bycolumn _null_ _null_ _null_ ) +insert ( 3759 get_current_ts_config 11 10 12 1 0 0 0 f f f t f s s 0 0 3734 "" _null_ _null_ _null_ _null_ _null_ get_current_ts_config _null_ _null_ _null_ ) +insert ( 3736 regconfigin 11 10 12 1 0 0 0 f f f t f s s 1 0 3734 2275 _null_ _null_ _null_ _null_ _null_ regconfigin _null_ _null_ _null_ ) +insert ( 3737 regconfigout 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 3734 _null_ _null_ _null_ _null_ _null_ regconfigout _null_ _null_ _null_ ) +insert ( 3738 regconfigrecv 11 10 12 1 0 0 0 f f f t f i s 1 0 3734 2281 _null_ _null_ _null_ _null_ _null_ regconfigrecv _null_ _null_ _null_ ) +insert ( 3739 regconfigsend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 3734 _null_ _null_ _null_ _null_ _null_ regconfigsend _null_ _null_ _null_ ) +insert ( 3771 regdictionaryin 11 10 12 1 0 0 0 f f f t f s s 1 0 3769 2275 _null_ _null_ _null_ _null_ _null_ regdictionaryin _null_ _null_ _null_ ) +insert ( 3772 regdictionaryout 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 3769 _null_ _null_ _null_ _null_ _null_ regdictionaryout _null_ _null_ _null_ ) +insert ( 3773 regdictionaryrecv 11 10 12 1 0 0 0 f f f t f i s 1 0 3769 2281 _null_ _null_ _null_ _null_ _null_ regdictionaryrecv _null_ _null_ _null_ ) +insert ( 3774 regdictionarysend 11 10 12 1 0 0 0 f f f t f i s 1 0 17 3769 _null_ _null_ _null_ _null_ _null_ regdictionarysend _null_ _null_ _null_ ) +insert ( 3806 jsonb_in 11 10 12 1 0 0 0 f f f t f i s 1 0 3802 2275 _null_ _null_ _null_ _null_ _null_ jsonb_in _null_ _null_ _null_ ) +insert ( 3805 jsonb_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 3802 2281 _null_ _null_ _null_ _null_ _null_ jsonb_recv _null_ _null_ _null_ ) +insert ( 3804 jsonb_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 3802 _null_ _null_ _null_ _null_ _null_ jsonb_out _null_ _null_ _null_ ) +insert ( 3803 jsonb_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 3802 _null_ _null_ _null_ _null_ _null_ jsonb_send _null_ _null_ _null_ ) +insert ( 3263 jsonb_object 11 10 12 1 0 0 0 f f f t f i s 1 0 3802 1009 _null_ _null_ _null_ _null_ _null_ jsonb_object _null_ _null_ _null_ ) +insert ( 3264 jsonb_object 11 10 12 1 0 0 0 f f f t f i s 2 0 3802 "1009 1009" _null_ _null_ _null_ _null_ _null_ jsonb_object_two_arg _null_ _null_ _null_ ) +insert ( 3787 to_jsonb 11 10 12 1 0 0 0 f f f t f s s 1 0 3802 2283 _null_ _null_ _null_ _null_ _null_ to_jsonb _null_ _null_ _null_ ) +insert ( 3265 jsonb_agg_transfn 11 10 12 1 0 0 0 f f f f f s s 2 0 2281 "2281 2283" _null_ _null_ _null_ _null_ _null_ jsonb_agg_transfn _null_ _null_ _null_ ) +insert ( 3266 jsonb_agg_finalfn 11 10 12 1 0 0 0 f f f f f s s 1 0 3802 2281 _null_ _null_ _null_ _null_ _null_ jsonb_agg_finalfn _null_ _null_ _null_ ) +insert ( 3267 jsonb_agg 11 10 12 1 0 0 0 a f f f f s s 1 0 3802 2283 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3268 jsonb_object_agg_transfn 11 10 12 1 0 0 0 f f f f f s s 3 0 2281 "2281 2276 2276" _null_ _null_ _null_ _null_ _null_ jsonb_object_agg_transfn _null_ _null_ _null_ ) +insert ( 3269 jsonb_object_agg_finalfn 11 10 12 1 0 0 0 f f f f f s s 1 0 3802 2281 _null_ _null_ _null_ _null_ _null_ jsonb_object_agg_finalfn _null_ _null_ _null_ ) +insert ( 3270 jsonb_object_agg 11 10 12 1 0 0 0 a f f f f i s 2 0 3802 "2276 2276" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3271 jsonb_build_array 11 10 12 1 0 2276 0 f f f f f s s 1 0 3802 2276 "{2276}" "{v}" _null_ _null_ _null_ jsonb_build_array _null_ _null_ _null_ ) +insert ( 3272 jsonb_build_array 11 10 12 1 0 0 0 f f f f f s s 0 0 3802 "" _null_ _null_ _null_ _null_ _null_ jsonb_build_array_noargs _null_ _null_ _null_ ) +insert ( 3273 jsonb_build_object 11 10 12 1 0 2276 0 f f f f f s s 1 0 3802 2276 "{2276}" "{v}" _null_ _null_ _null_ jsonb_build_object _null_ _null_ _null_ ) +insert ( 3274 jsonb_build_object 11 10 12 1 0 0 0 f f f f f s s 0 0 3802 "" _null_ _null_ _null_ _null_ _null_ jsonb_build_object_noargs _null_ _null_ _null_ ) +insert ( 3262 jsonb_strip_nulls 11 10 12 1 0 0 0 f f f t f i s 1 0 3802 3802 _null_ _null_ _null_ _null_ _null_ jsonb_strip_nulls _null_ _null_ _null_ ) +insert ( 3478 jsonb_object_field 11 10 12 1 0 0 0 f f f t f i s 2 0 3802 "3802 25" _null_ _null_ "{from_json, field_name}" _null_ _null_ jsonb_object_field _null_ _null_ _null_ ) +insert ( 3214 jsonb_object_field_text 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "3802 25" _null_ _null_ "{from_json, field_name}" _null_ _null_ jsonb_object_field_text _null_ _null_ _null_ ) +insert ( 3215 jsonb_array_element 11 10 12 1 0 0 0 f f f t f i s 2 0 3802 "3802 23" _null_ _null_ "{from_json, element_index}" _null_ _null_ jsonb_array_element _null_ _null_ _null_ ) +insert ( 3216 jsonb_array_element_text 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "3802 23" _null_ _null_ "{from_json, element_index}" _null_ _null_ jsonb_array_element_text _null_ _null_ _null_ ) +insert ( 3217 jsonb_extract_path 11 10 12 1 0 25 0 f f f t f i s 2 0 3802 "3802 1009" "{3802,1009}" "{i,v}" "{from_json,path_elems}" _null_ _null_ jsonb_extract_path _null_ _null_ _null_ ) +insert ( 3940 jsonb_extract_path_text 11 10 12 1 0 25 0 f f f t f i s 2 0 25 "3802 1009" "{3802,1009}" "{i,v}" "{from_json,path_elems}" _null_ _null_ jsonb_extract_path_text _null_ _null_ _null_ ) +insert ( 3219 jsonb_array_elements 11 10 12 1 100 0 0 f f f t t i s 1 0 3802 3802 "{3802,3802}" "{i,o}" "{from_json,value}" _null_ _null_ jsonb_array_elements _null_ _null_ _null_ ) +insert ( 3465 jsonb_array_elements_text 11 10 12 1 100 0 0 f f f t t i s 1 0 25 3802 "{3802,25}" "{i,o}" "{from_json,value}" _null_ _null_ jsonb_array_elements_text _null_ _null_ _null_ ) +insert ( 3207 jsonb_array_length 11 10 12 1 0 0 0 f f f t f i s 1 0 23 3802 _null_ _null_ _null_ _null_ _null_ jsonb_array_length _null_ _null_ _null_ ) +insert ( 3931 jsonb_object_keys 11 10 12 1 100 0 0 f f f t t i s 1 0 25 3802 _null_ _null_ _null_ _null_ _null_ jsonb_object_keys _null_ _null_ _null_ ) +insert ( 3208 jsonb_each 11 10 12 1 100 0 0 f f f t t i s 1 0 2249 3802 "{3802,25,3802}" "{i,o,o}" "{from_json,key,value}" _null_ _null_ jsonb_each _null_ _null_ _null_ ) +insert ( 3932 jsonb_each_text 11 10 12 1 100 0 0 f f f t t i s 1 0 2249 3802 "{3802,25,25}" "{i,o,o}" "{from_json,key,value}" _null_ _null_ jsonb_each_text _null_ _null_ _null_ ) +insert ( 3209 jsonb_populate_record 11 10 12 1 0 0 0 f f f f f s s 2 0 2283 "2283 3802" _null_ _null_ _null_ _null_ _null_ jsonb_populate_record _null_ _null_ _null_ ) +insert ( 3475 jsonb_populate_recordset 11 10 12 1 100 0 0 f f f f t s s 2 0 2283 "2283 3802" _null_ _null_ _null_ _null_ _null_ jsonb_populate_recordset _null_ _null_ _null_ ) +insert ( 3490 jsonb_to_record 11 10 12 1 0 0 0 f f f t f s s 1 0 2249 3802 _null_ _null_ _null_ _null_ _null_ jsonb_to_record _null_ _null_ _null_ ) +insert ( 3491 jsonb_to_recordset 11 10 12 1 100 0 0 f f f f t s s 1 0 2249 3802 _null_ _null_ _null_ _null_ _null_ jsonb_to_recordset _null_ _null_ _null_ ) +insert ( 3210 jsonb_typeof 11 10 12 1 0 0 0 f f f t f i s 1 0 25 3802 _null_ _null_ _null_ _null_ _null_ jsonb_typeof _null_ _null_ _null_ ) +insert ( 4038 jsonb_ne 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3802 3802" _null_ _null_ _null_ _null_ _null_ jsonb_ne _null_ _null_ _null_ ) +insert ( 4039 jsonb_lt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3802 3802" _null_ _null_ _null_ _null_ _null_ jsonb_lt _null_ _null_ _null_ ) +insert ( 4040 jsonb_gt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3802 3802" _null_ _null_ _null_ _null_ _null_ jsonb_gt _null_ _null_ _null_ ) +insert ( 4041 jsonb_le 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3802 3802" _null_ _null_ _null_ _null_ _null_ jsonb_le _null_ _null_ _null_ ) +insert ( 4042 jsonb_ge 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3802 3802" _null_ _null_ _null_ _null_ _null_ jsonb_ge _null_ _null_ _null_ ) +insert ( 4043 jsonb_eq 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3802 3802" _null_ _null_ _null_ _null_ _null_ jsonb_eq _null_ _null_ _null_ ) +insert ( 4044 jsonb_cmp 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "3802 3802" _null_ _null_ _null_ _null_ _null_ jsonb_cmp _null_ _null_ _null_ ) +insert ( 4045 jsonb_hash 11 10 12 1 0 0 0 f f f t f i s 1 0 23 3802 _null_ _null_ _null_ _null_ _null_ jsonb_hash _null_ _null_ _null_ ) +insert ( 3416 jsonb_hash_extended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "3802 20" _null_ _null_ _null_ _null_ _null_ jsonb_hash_extended _null_ _null_ _null_ ) +insert ( 4046 jsonb_contains 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3802 3802" _null_ _null_ _null_ _null_ _null_ jsonb_contains _null_ _null_ _null_ ) +insert ( 4047 jsonb_exists 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3802 25" _null_ _null_ _null_ _null_ _null_ jsonb_exists _null_ _null_ _null_ ) +insert ( 4048 jsonb_exists_any 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3802 1009" _null_ _null_ _null_ _null_ _null_ jsonb_exists_any _null_ _null_ _null_ ) +insert ( 4049 jsonb_exists_all 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3802 1009" _null_ _null_ _null_ _null_ _null_ jsonb_exists_all _null_ _null_ _null_ ) +insert ( 4050 jsonb_contained 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3802 3802" _null_ _null_ _null_ _null_ _null_ jsonb_contained _null_ _null_ _null_ ) +insert ( 3480 gin_compare_jsonb 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "25 25" _null_ _null_ _null_ _null_ _null_ gin_compare_jsonb _null_ _null_ _null_ ) +insert ( 3482 gin_extract_jsonb 11 10 12 1 0 0 0 f f f t f i s 3 0 2281 "3802 2281 2281" _null_ _null_ _null_ _null_ _null_ gin_extract_jsonb _null_ _null_ _null_ ) +insert ( 3483 gin_extract_jsonb_query 11 10 12 1 0 0 0 f f f t f i s 7 0 2281 "3802 2281 21 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gin_extract_jsonb_query _null_ _null_ _null_ ) +insert ( 3484 gin_consistent_jsonb 11 10 12 1 0 0 0 f f f t f i s 8 0 16 "2281 21 3802 23 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gin_consistent_jsonb _null_ _null_ _null_ ) +insert ( 3488 gin_triconsistent_jsonb 11 10 12 1 0 0 0 f f f t f i s 7 0 18 "2281 21 3802 23 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gin_triconsistent_jsonb _null_ _null_ _null_ ) +insert ( 3485 gin_extract_jsonb_path 11 10 12 1 0 0 0 f f f t f i s 3 0 2281 "3802 2281 2281" _null_ _null_ _null_ _null_ _null_ gin_extract_jsonb_path _null_ _null_ _null_ ) +insert ( 3486 gin_extract_jsonb_query_path 11 10 12 1 0 0 0 f f f t f i s 7 0 2281 "3802 2281 21 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gin_extract_jsonb_query_path _null_ _null_ _null_ ) +insert ( 3487 gin_consistent_jsonb_path 11 10 12 1 0 0 0 f f f t f i s 8 0 16 "2281 21 3802 23 2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gin_consistent_jsonb_path _null_ _null_ _null_ ) +insert ( 3489 gin_triconsistent_jsonb_path 11 10 12 1 0 0 0 f f f t f i s 7 0 18 "2281 21 3802 23 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ gin_triconsistent_jsonb_path _null_ _null_ _null_ ) +insert ( 3301 jsonb_concat 11 10 12 1 0 0 0 f f f t f i s 2 0 3802 "3802 3802" _null_ _null_ _null_ _null_ _null_ jsonb_concat _null_ _null_ _null_ ) +insert ( 3302 jsonb_delete 11 10 12 1 0 0 0 f f f t f i s 2 0 3802 "3802 25" _null_ _null_ _null_ _null_ _null_ jsonb_delete _null_ _null_ _null_ ) +insert ( 3303 jsonb_delete 11 10 12 1 0 0 0 f f f t f i s 2 0 3802 "3802 23" _null_ _null_ _null_ _null_ _null_ jsonb_delete_idx _null_ _null_ _null_ ) +insert ( 3343 jsonb_delete 11 10 12 1 0 25 0 f f f t f i s 2 0 3802 "3802 1009" "{3802,1009}" "{i,v}" "{from_json,path_elems}" _null_ _null_ jsonb_delete_array _null_ _null_ _null_ ) +insert ( 3304 jsonb_delete_path 11 10 12 1 0 0 0 f f f t f i s 2 0 3802 "3802 1009" _null_ _null_ _null_ _null_ _null_ jsonb_delete_path _null_ _null_ _null_ ) +insert ( 5054 jsonb_set_lax 11 10 12 1 0 0 0 f f f f f i s 5 0 3802 "3802 1009 3802 16 25" _null_ _null_ _null_ _null_ _null_ jsonb_set_lax _null_ _null_ _null_ ) +insert ( 3305 jsonb_set 11 10 12 1 0 0 0 f f f t f i s 4 0 3802 "3802 1009 3802 16" _null_ _null_ _null_ _null_ _null_ jsonb_set _null_ _null_ _null_ ) +insert ( 3306 jsonb_pretty 11 10 12 1 0 0 0 f f f t f i s 1 0 25 3802 _null_ _null_ _null_ _null_ _null_ jsonb_pretty _null_ _null_ _null_ ) +insert ( 3579 jsonb_insert 11 10 12 1 0 0 0 f f f t f i s 4 0 3802 "3802 1009 3802 16" _null_ _null_ _null_ _null_ _null_ jsonb_insert _null_ _null_ _null_ ) +insert ( 4001 jsonpath_in 11 10 12 1 0 0 0 f f f t f i s 1 0 4072 2275 _null_ _null_ _null_ _null_ _null_ jsonpath_in _null_ _null_ _null_ ) +insert ( 4002 jsonpath_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 4072 2281 _null_ _null_ _null_ _null_ _null_ jsonpath_recv _null_ _null_ _null_ ) +insert ( 4003 jsonpath_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 4072 _null_ _null_ _null_ _null_ _null_ jsonpath_out _null_ _null_ _null_ ) +insert ( 4004 jsonpath_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 4072 _null_ _null_ _null_ _null_ _null_ jsonpath_send _null_ _null_ _null_ ) +insert ( 4005 jsonb_path_exists 11 10 12 1 0 0 0 f f f t f i s 4 0 16 "3802 4072 3802 16" _null_ _null_ _null_ _null_ _null_ jsonb_path_exists _null_ _null_ _null_ ) +insert ( 4006 jsonb_path_query 11 10 12 1 1000 0 0 f f f t t i s 4 0 3802 "3802 4072 3802 16" _null_ _null_ _null_ _null_ _null_ jsonb_path_query _null_ _null_ _null_ ) +insert ( 4007 jsonb_path_query_array 11 10 12 1 0 0 0 f f f t f i s 4 0 3802 "3802 4072 3802 16" _null_ _null_ _null_ _null_ _null_ jsonb_path_query_array _null_ _null_ _null_ ) +insert ( 4008 jsonb_path_query_first 11 10 12 1 0 0 0 f f f t f i s 4 0 3802 "3802 4072 3802 16" _null_ _null_ _null_ _null_ _null_ jsonb_path_query_first _null_ _null_ _null_ ) +insert ( 4009 jsonb_path_match 11 10 12 1 0 0 0 f f f t f i s 4 0 16 "3802 4072 3802 16" _null_ _null_ _null_ _null_ _null_ jsonb_path_match _null_ _null_ _null_ ) +insert ( 1177 jsonb_path_exists_tz 11 10 12 1 0 0 0 f f f t f s s 4 0 16 "3802 4072 3802 16" _null_ _null_ _null_ _null_ _null_ jsonb_path_exists_tz _null_ _null_ _null_ ) +insert ( 1179 jsonb_path_query_tz 11 10 12 1 1000 0 0 f f f t t s s 4 0 3802 "3802 4072 3802 16" _null_ _null_ _null_ _null_ _null_ jsonb_path_query_tz _null_ _null_ _null_ ) +insert ( 1180 jsonb_path_query_array_tz 11 10 12 1 0 0 0 f f f t f s s 4 0 3802 "3802 4072 3802 16" _null_ _null_ _null_ _null_ _null_ jsonb_path_query_array_tz _null_ _null_ _null_ ) +insert ( 2023 jsonb_path_query_first_tz 11 10 12 1 0 0 0 f f f t f s s 4 0 3802 "3802 4072 3802 16" _null_ _null_ _null_ _null_ _null_ jsonb_path_query_first_tz _null_ _null_ _null_ ) +insert ( 2030 jsonb_path_match_tz 11 10 12 1 0 0 0 f f f t f s s 4 0 16 "3802 4072 3802 16" _null_ _null_ _null_ _null_ _null_ jsonb_path_match_tz _null_ _null_ _null_ ) +insert ( 4010 jsonb_path_exists_opr 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3802 4072" _null_ _null_ _null_ _null_ _null_ jsonb_path_exists_opr _null_ _null_ _null_ ) +insert ( 4011 jsonb_path_match_opr 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3802 4072" _null_ _null_ _null_ _null_ _null_ jsonb_path_match_opr _null_ _null_ _null_ ) +insert ( 2939 txid_snapshot_in 11 10 12 1 0 0 0 f f f t f i s 1 0 2970 2275 _null_ _null_ _null_ _null_ _null_ pg_snapshot_in _null_ _null_ _null_ ) +insert ( 2940 txid_snapshot_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 2970 _null_ _null_ _null_ _null_ _null_ pg_snapshot_out _null_ _null_ _null_ ) +insert ( 2941 txid_snapshot_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 2970 2281 _null_ _null_ _null_ _null_ _null_ pg_snapshot_recv _null_ _null_ _null_ ) +insert ( 2942 txid_snapshot_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 2970 _null_ _null_ _null_ _null_ _null_ pg_snapshot_send _null_ _null_ _null_ ) +insert ( 2943 txid_current 11 10 12 1 0 0 0 f f f t f s u 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_current_xact_id _null_ _null_ _null_ ) +insert ( 3348 txid_current_if_assigned 11 10 12 1 0 0 0 f f f t f s u 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_current_xact_id_if_assigned _null_ _null_ _null_ ) +insert ( 2944 txid_current_snapshot 11 10 12 1 0 0 0 f f f t f s s 0 0 2970 "" _null_ _null_ _null_ _null_ _null_ pg_current_snapshot _null_ _null_ _null_ ) +insert ( 2945 txid_snapshot_xmin 11 10 12 1 0 0 0 f f f t f i s 1 0 20 2970 _null_ _null_ _null_ _null_ _null_ pg_snapshot_xmin _null_ _null_ _null_ ) +insert ( 2946 txid_snapshot_xmax 11 10 12 1 0 0 0 f f f t f i s 1 0 20 2970 _null_ _null_ _null_ _null_ _null_ pg_snapshot_xmax _null_ _null_ _null_ ) +insert ( 2947 txid_snapshot_xip 11 10 12 1 50 0 0 f f f t t i s 1 0 20 2970 _null_ _null_ _null_ _null_ _null_ pg_snapshot_xip _null_ _null_ _null_ ) +insert ( 2948 txid_visible_in_snapshot 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "20 2970" _null_ _null_ _null_ _null_ _null_ pg_visible_in_snapshot _null_ _null_ _null_ ) +insert ( 3360 txid_status 11 10 12 1 0 0 0 f f f t f v s 1 0 25 20 _null_ _null_ _null_ _null_ _null_ pg_xact_status _null_ _null_ _null_ ) +insert ( 5055 pg_snapshot_in 11 10 12 1 0 0 0 f f f t f i s 1 0 5038 2275 _null_ _null_ _null_ _null_ _null_ pg_snapshot_in _null_ _null_ _null_ ) +insert ( 5056 pg_snapshot_out 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 5038 _null_ _null_ _null_ _null_ _null_ pg_snapshot_out _null_ _null_ _null_ ) +insert ( 5057 pg_snapshot_recv 11 10 12 1 0 0 0 f f f t f i s 1 0 5038 2281 _null_ _null_ _null_ _null_ _null_ pg_snapshot_recv _null_ _null_ _null_ ) +insert ( 5058 pg_snapshot_send 11 10 12 1 0 0 0 f f f t f i s 1 0 17 5038 _null_ _null_ _null_ _null_ _null_ pg_snapshot_send _null_ _null_ _null_ ) +insert ( 5061 pg_current_snapshot 11 10 12 1 0 0 0 f f f t f s s 0 0 5038 "" _null_ _null_ _null_ _null_ _null_ pg_current_snapshot _null_ _null_ _null_ ) +insert ( 5062 pg_snapshot_xmin 11 10 12 1 0 0 0 f f f t f i s 1 0 5069 5038 _null_ _null_ _null_ _null_ _null_ pg_snapshot_xmin _null_ _null_ _null_ ) +insert ( 5063 pg_snapshot_xmax 11 10 12 1 0 0 0 f f f t f i s 1 0 5069 5038 _null_ _null_ _null_ _null_ _null_ pg_snapshot_xmax _null_ _null_ _null_ ) +insert ( 5064 pg_snapshot_xip 11 10 12 1 50 0 0 f f f t t i s 1 0 5069 5038 _null_ _null_ _null_ _null_ _null_ pg_snapshot_xip _null_ _null_ _null_ ) +insert ( 5065 pg_visible_in_snapshot 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "5069 5038" _null_ _null_ _null_ _null_ _null_ pg_visible_in_snapshot _null_ _null_ _null_ ) +insert ( 5059 pg_current_xact_id 11 10 12 1 0 0 0 f f f t f s u 0 0 5069 "" _null_ _null_ _null_ _null_ _null_ pg_current_xact_id _null_ _null_ _null_ ) +insert ( 5060 pg_current_xact_id_if_assigned 11 10 12 1 0 0 0 f f f t f s u 0 0 5069 "" _null_ _null_ _null_ _null_ _null_ pg_current_xact_id_if_assigned _null_ _null_ _null_ ) +insert ( 5066 pg_xact_status 11 10 12 1 0 0 0 f f f t f v s 1 0 25 5069 _null_ _null_ _null_ _null_ _null_ pg_xact_status _null_ _null_ _null_ ) +insert ( 2981 record_eq 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2249 2249" _null_ _null_ _null_ _null_ _null_ record_eq _null_ _null_ _null_ ) +insert ( 2982 record_ne 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2249 2249" _null_ _null_ _null_ _null_ _null_ record_ne _null_ _null_ _null_ ) +insert ( 2983 record_lt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2249 2249" _null_ _null_ _null_ _null_ _null_ record_lt _null_ _null_ _null_ ) +insert ( 2984 record_gt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2249 2249" _null_ _null_ _null_ _null_ _null_ record_gt _null_ _null_ _null_ ) +insert ( 2985 record_le 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2249 2249" _null_ _null_ _null_ _null_ _null_ record_le _null_ _null_ _null_ ) +insert ( 2986 record_ge 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2249 2249" _null_ _null_ _null_ _null_ _null_ record_ge _null_ _null_ _null_ ) +insert ( 2987 btrecordcmp 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "2249 2249" _null_ _null_ _null_ _null_ _null_ btrecordcmp _null_ _null_ _null_ ) +insert ( 3181 record_image_eq 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2249 2249" _null_ _null_ _null_ _null_ _null_ record_image_eq _null_ _null_ _null_ ) +insert ( 3182 record_image_ne 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2249 2249" _null_ _null_ _null_ _null_ _null_ record_image_ne _null_ _null_ _null_ ) +insert ( 3183 record_image_lt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2249 2249" _null_ _null_ _null_ _null_ _null_ record_image_lt _null_ _null_ _null_ ) +insert ( 3184 record_image_gt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2249 2249" _null_ _null_ _null_ _null_ _null_ record_image_gt _null_ _null_ _null_ ) +insert ( 3185 record_image_le 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2249 2249" _null_ _null_ _null_ _null_ _null_ record_image_le _null_ _null_ _null_ ) +insert ( 3186 record_image_ge 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2249 2249" _null_ _null_ _null_ _null_ _null_ record_image_ge _null_ _null_ _null_ ) +insert ( 3187 btrecordimagecmp 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "2249 2249" _null_ _null_ _null_ _null_ _null_ btrecordimagecmp _null_ _null_ _null_ ) +insert ( 5051 btequalimage 11 10 12 1 0 0 0 f f f t f i s 1 0 16 26 _null_ _null_ _null_ _null_ _null_ btequalimage _null_ _null_ _null_ ) +insert ( 3082 pg_available_extensions 11 10 12 10 100 0 0 f f f t t s s 0 0 2249 "" "{19,25,25}" "{o,o,o}" "{name,default_version,comment}" _null_ _null_ pg_available_extensions _null_ _null_ _null_ ) +insert ( 3083 pg_available_extension_versions 11 10 12 10 100 0 0 f f f t t s s 0 0 2249 "" "{19,25,16,16,16,19,1003,25}" "{o,o,o,o,o,o,o,o}" "{name,version,superuser,trusted,relocatable,schema,requires,comment}" _null_ _null_ pg_available_extension_versions _null_ _null_ _null_ ) +insert ( 3084 pg_extension_update_paths 11 10 12 10 100 0 0 f f f t t s s 1 0 2249 19 "{19,25,25,25}" "{i,o,o,o}" "{name,source,target,path}" _null_ _null_ pg_extension_update_paths _null_ _null_ _null_ ) +insert ( 3086 pg_extension_config_dump 11 10 12 1 0 0 0 f f f t f v u 2 0 2278 "2205 25" _null_ _null_ _null_ _null_ _null_ pg_extension_config_dump _null_ _null_ _null_ ) +insert ( 3100 row_number 11 10 12 1 0 0 0 w f f f f i s 0 0 20 "" _null_ _null_ _null_ _null_ _null_ window_row_number _null_ _null_ _null_ ) +insert ( 3101 rank 11 10 12 1 0 0 0 w f f f f i s 0 0 20 "" _null_ _null_ _null_ _null_ _null_ window_rank _null_ _null_ _null_ ) +insert ( 3102 dense_rank 11 10 12 1 0 0 0 w f f f f i s 0 0 20 "" _null_ _null_ _null_ _null_ _null_ window_dense_rank _null_ _null_ _null_ ) +insert ( 3103 percent_rank 11 10 12 1 0 0 0 w f f f f i s 0 0 701 "" _null_ _null_ _null_ _null_ _null_ window_percent_rank _null_ _null_ _null_ ) +insert ( 3104 cume_dist 11 10 12 1 0 0 0 w f f f f i s 0 0 701 "" _null_ _null_ _null_ _null_ _null_ window_cume_dist _null_ _null_ _null_ ) +insert ( 3105 ntile 11 10 12 1 0 0 0 w f f t f i s 1 0 23 23 _null_ _null_ _null_ _null_ _null_ window_ntile _null_ _null_ _null_ ) +insert ( 3106 lag 11 10 12 1 0 0 0 w f f t f i s 1 0 2283 2283 _null_ _null_ _null_ _null_ _null_ window_lag _null_ _null_ _null_ ) +insert ( 3107 lag 11 10 12 1 0 0 0 w f f t f i s 2 0 2283 "2283 23" _null_ _null_ _null_ _null_ _null_ window_lag_with_offset _null_ _null_ _null_ ) +insert ( 3108 lag 11 10 12 1 0 0 0 w f f t f i s 3 0 2283 "2283 23 2283" _null_ _null_ _null_ _null_ _null_ window_lag_with_offset_and_default _null_ _null_ _null_ ) +insert ( 3109 lead 11 10 12 1 0 0 0 w f f t f i s 1 0 2283 2283 _null_ _null_ _null_ _null_ _null_ window_lead _null_ _null_ _null_ ) +insert ( 3110 lead 11 10 12 1 0 0 0 w f f t f i s 2 0 2283 "2283 23" _null_ _null_ _null_ _null_ _null_ window_lead_with_offset _null_ _null_ _null_ ) +insert ( 3111 lead 11 10 12 1 0 0 0 w f f t f i s 3 0 2283 "2283 23 2283" _null_ _null_ _null_ _null_ _null_ window_lead_with_offset_and_default _null_ _null_ _null_ ) +insert ( 3112 first_value 11 10 12 1 0 0 0 w f f t f i s 1 0 2283 2283 _null_ _null_ _null_ _null_ _null_ window_first_value _null_ _null_ _null_ ) +insert ( 3113 last_value 11 10 12 1 0 0 0 w f f t f i s 1 0 2283 2283 _null_ _null_ _null_ _null_ _null_ window_last_value _null_ _null_ _null_ ) +insert ( 3114 nth_value 11 10 12 1 0 0 0 w f f t f i s 2 0 2283 "2283 23" _null_ _null_ _null_ _null_ _null_ window_nth_value _null_ _null_ _null_ ) +insert ( 3832 anyrange_in 11 10 12 1 0 0 0 f f f t f s s 3 0 3831 "2275 26 23" _null_ _null_ _null_ _null_ _null_ anyrange_in _null_ _null_ _null_ ) +insert ( 3833 anyrange_out 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 3831 _null_ _null_ _null_ _null_ _null_ anyrange_out _null_ _null_ _null_ ) +insert ( 3834 range_in 11 10 12 1 0 0 0 f f f t f s s 3 0 3831 "2275 26 23" _null_ _null_ _null_ _null_ _null_ range_in _null_ _null_ _null_ ) +insert ( 3835 range_out 11 10 12 1 0 0 0 f f f t f s s 1 0 2275 3831 _null_ _null_ _null_ _null_ _null_ range_out _null_ _null_ _null_ ) +insert ( 3836 range_recv 11 10 12 1 0 0 0 f f f t f s s 3 0 3831 "2281 26 23" _null_ _null_ _null_ _null_ _null_ range_recv _null_ _null_ _null_ ) +insert ( 3837 range_send 11 10 12 1 0 0 0 f f f t f s s 1 0 17 3831 _null_ _null_ _null_ _null_ _null_ range_send _null_ _null_ _null_ ) +insert ( 3848 lower 11 10 12 1 0 0 0 f f f t f i s 1 0 2283 3831 _null_ _null_ _null_ _null_ _null_ range_lower _null_ _null_ _null_ ) +insert ( 3849 upper 11 10 12 1 0 0 0 f f f t f i s 1 0 2283 3831 _null_ _null_ _null_ _null_ _null_ range_upper _null_ _null_ _null_ ) +insert ( 3850 isempty 11 10 12 1 0 0 0 f f f t f i s 1 0 16 3831 _null_ _null_ _null_ _null_ _null_ range_empty _null_ _null_ _null_ ) +insert ( 3851 lower_inc 11 10 12 1 0 0 0 f f f t f i s 1 0 16 3831 _null_ _null_ _null_ _null_ _null_ range_lower_inc _null_ _null_ _null_ ) +insert ( 3852 upper_inc 11 10 12 1 0 0 0 f f f t f i s 1 0 16 3831 _null_ _null_ _null_ _null_ _null_ range_upper_inc _null_ _null_ _null_ ) +insert ( 3853 lower_inf 11 10 12 1 0 0 0 f f f t f i s 1 0 16 3831 _null_ _null_ _null_ _null_ _null_ range_lower_inf _null_ _null_ _null_ ) +insert ( 3854 upper_inf 11 10 12 1 0 0 0 f f f t f i s 1 0 16 3831 _null_ _null_ _null_ _null_ _null_ range_upper_inf _null_ _null_ _null_ ) +insert ( 3855 range_eq 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_eq _null_ _null_ _null_ ) +insert ( 3856 range_ne 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_ne _null_ _null_ _null_ ) +insert ( 3857 range_overlaps 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_overlaps _null_ _null_ _null_ ) +insert ( 3858 range_contains_elem 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3831 2283" _null_ _null_ _null_ _null_ _null_ range_contains_elem _null_ _null_ _null_ ) +insert ( 3859 range_contains 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_contains _null_ _null_ _null_ ) +insert ( 3860 elem_contained_by_range 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2283 3831" _null_ _null_ _null_ _null_ _null_ elem_contained_by_range _null_ _null_ _null_ ) +insert ( 3861 range_contained_by 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_contained_by _null_ _null_ _null_ ) +insert ( 3862 range_adjacent 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_adjacent _null_ _null_ _null_ ) +insert ( 3863 range_before 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_before _null_ _null_ _null_ ) +insert ( 3864 range_after 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_after _null_ _null_ _null_ ) +insert ( 3865 range_overleft 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_overleft _null_ _null_ _null_ ) +insert ( 3866 range_overright 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_overright _null_ _null_ _null_ ) +insert ( 3867 range_union 11 10 12 1 0 0 0 f f f t f i s 2 0 3831 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_union _null_ _null_ _null_ ) +insert ( 4057 range_merge 11 10 12 1 0 0 0 f f f t f i s 2 0 3831 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_merge _null_ _null_ _null_ ) +insert ( 3868 range_intersect 11 10 12 1 0 0 0 f f f t f i s 2 0 3831 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_intersect _null_ _null_ _null_ ) +insert ( 3869 range_minus 11 10 12 1 0 0 0 f f f t f i s 2 0 3831 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_minus _null_ _null_ _null_ ) +insert ( 3870 range_cmp 11 10 12 1 0 0 0 f f f t f i s 2 0 23 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_cmp _null_ _null_ _null_ ) +insert ( 3871 range_lt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_lt _null_ _null_ _null_ ) +insert ( 3872 range_le 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_le _null_ _null_ _null_ ) +insert ( 3873 range_ge 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_ge _null_ _null_ _null_ ) +insert ( 3874 range_gt 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_gt _null_ _null_ _null_ ) +insert ( 3875 range_gist_consistent 11 10 12 1 0 0 0 f f f t f i s 5 0 16 "2281 3831 21 26 2281" _null_ _null_ _null_ _null_ _null_ range_gist_consistent _null_ _null_ _null_ ) +insert ( 3876 range_gist_union 11 10 12 1 0 0 0 f f f t f i s 2 0 3831 "2281 2281" _null_ _null_ _null_ _null_ _null_ range_gist_union _null_ _null_ _null_ ) +insert ( 3879 range_gist_penalty 11 10 12 1 0 0 0 f f f t f i s 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ range_gist_penalty _null_ _null_ _null_ ) +insert ( 3880 range_gist_picksplit 11 10 12 1 0 0 0 f f f t f i s 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ _null_ range_gist_picksplit _null_ _null_ _null_ ) +insert ( 3881 range_gist_same 11 10 12 1 0 0 0 f f f t f i s 3 0 2281 "3831 3831 2281" _null_ _null_ _null_ _null_ _null_ range_gist_same _null_ _null_ _null_ ) +insert ( 3902 hash_range 11 10 12 1 0 0 0 f f f t f i s 1 0 23 3831 _null_ _null_ _null_ _null_ _null_ hash_range _null_ _null_ _null_ ) +insert ( 3417 hash_range_extended 11 10 12 1 0 0 0 f f f t f i s 2 0 20 "3831 20" _null_ _null_ _null_ _null_ _null_ hash_range_extended _null_ _null_ _null_ ) +insert ( 3916 range_typanalyze 11 10 12 1 0 0 0 f f f t f s s 1 0 16 2281 _null_ _null_ _null_ _null_ _null_ range_typanalyze _null_ _null_ _null_ ) +insert ( 3169 rangesel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ rangesel _null_ _null_ _null_ ) +insert ( 3914 int4range_canonical 11 10 12 1 0 0 0 f f f t f i s 1 0 3904 3904 _null_ _null_ _null_ _null_ _null_ int4range_canonical _null_ _null_ _null_ ) +insert ( 3928 int8range_canonical 11 10 12 1 0 0 0 f f f t f i s 1 0 3926 3926 _null_ _null_ _null_ _null_ _null_ int8range_canonical _null_ _null_ _null_ ) +insert ( 3915 daterange_canonical 11 10 12 1 0 0 0 f f f t f i s 1 0 3912 3912 _null_ _null_ _null_ _null_ _null_ daterange_canonical _null_ _null_ _null_ ) +insert ( 3922 int4range_subdiff 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "23 23" _null_ _null_ _null_ _null_ _null_ int4range_subdiff _null_ _null_ _null_ ) +insert ( 3923 int8range_subdiff 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "20 20" _null_ _null_ _null_ _null_ _null_ int8range_subdiff _null_ _null_ _null_ ) +insert ( 3924 numrange_subdiff 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "1700 1700" _null_ _null_ _null_ _null_ _null_ numrange_subdiff _null_ _null_ _null_ ) +insert ( 3925 daterange_subdiff 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "1082 1082" _null_ _null_ _null_ _null_ _null_ daterange_subdiff _null_ _null_ _null_ ) +insert ( 3929 tsrange_subdiff 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "1114 1114" _null_ _null_ _null_ _null_ _null_ tsrange_subdiff _null_ _null_ _null_ ) +insert ( 3930 tstzrange_subdiff 11 10 12 1 0 0 0 f f f t f i s 2 0 701 "1184 1184" _null_ _null_ _null_ _null_ _null_ tstzrange_subdiff _null_ _null_ _null_ ) +insert ( 3840 int4range 11 10 12 1 0 0 0 f f f f f i s 2 0 3904 "23 23" _null_ _null_ _null_ _null_ _null_ range_constructor2 _null_ _null_ _null_ ) +insert ( 3841 int4range 11 10 12 1 0 0 0 f f f f f i s 3 0 3904 "23 23 25" _null_ _null_ _null_ _null_ _null_ range_constructor3 _null_ _null_ _null_ ) +insert ( 3844 numrange 11 10 12 1 0 0 0 f f f f f i s 2 0 3906 "1700 1700" _null_ _null_ _null_ _null_ _null_ range_constructor2 _null_ _null_ _null_ ) +insert ( 3845 numrange 11 10 12 1 0 0 0 f f f f f i s 3 0 3906 "1700 1700 25" _null_ _null_ _null_ _null_ _null_ range_constructor3 _null_ _null_ _null_ ) +insert ( 3933 tsrange 11 10 12 1 0 0 0 f f f f f i s 2 0 3908 "1114 1114" _null_ _null_ _null_ _null_ _null_ range_constructor2 _null_ _null_ _null_ ) +insert ( 3934 tsrange 11 10 12 1 0 0 0 f f f f f i s 3 0 3908 "1114 1114 25" _null_ _null_ _null_ _null_ _null_ range_constructor3 _null_ _null_ _null_ ) +insert ( 3937 tstzrange 11 10 12 1 0 0 0 f f f f f i s 2 0 3910 "1184 1184" _null_ _null_ _null_ _null_ _null_ range_constructor2 _null_ _null_ _null_ ) +insert ( 3938 tstzrange 11 10 12 1 0 0 0 f f f f f i s 3 0 3910 "1184 1184 25" _null_ _null_ _null_ _null_ _null_ range_constructor3 _null_ _null_ _null_ ) +insert ( 3941 daterange 11 10 12 1 0 0 0 f f f f f i s 2 0 3912 "1082 1082" _null_ _null_ _null_ _null_ _null_ range_constructor2 _null_ _null_ _null_ ) +insert ( 3942 daterange 11 10 12 1 0 0 0 f f f f f i s 3 0 3912 "1082 1082 25" _null_ _null_ _null_ _null_ _null_ range_constructor3 _null_ _null_ _null_ ) +insert ( 3945 int8range 11 10 12 1 0 0 0 f f f f f i s 2 0 3926 "20 20" _null_ _null_ _null_ _null_ _null_ range_constructor2 _null_ _null_ _null_ ) +insert ( 3946 int8range 11 10 12 1 0 0 0 f f f f f i s 3 0 3926 "20 20 25" _null_ _null_ _null_ _null_ _null_ range_constructor3 _null_ _null_ _null_ ) +insert ( 3846 make_date 11 10 12 1 0 0 0 f f f t f i s 3 0 1082 "23 23 23" _null_ _null_ "{year,month,day}" _null_ _null_ make_date _null_ _null_ _null_ ) +insert ( 3847 make_time 11 10 12 1 0 0 0 f f f t f i s 3 0 1083 "23 23 701" _null_ _null_ "{hour,min,sec}" _null_ _null_ make_time _null_ _null_ _null_ ) +insert ( 3461 make_timestamp 11 10 12 1 0 0 0 f f f t f i s 6 0 1114 "23 23 23 23 23 701" _null_ _null_ "{year,month,mday,hour,min,sec}" _null_ _null_ make_timestamp _null_ _null_ _null_ ) +insert ( 3462 make_timestamptz 11 10 12 1 0 0 0 f f f t f s s 6 0 1184 "23 23 23 23 23 701" _null_ _null_ "{year,month,mday,hour,min,sec}" _null_ _null_ make_timestamptz _null_ _null_ _null_ ) +insert ( 3463 make_timestamptz 11 10 12 1 0 0 0 f f f t f s s 7 0 1184 "23 23 23 23 23 701 25" _null_ _null_ "{year,month,mday,hour,min,sec,timezone}" _null_ _null_ make_timestamptz_at_timezone _null_ _null_ _null_ ) +insert ( 3464 make_interval 11 10 12 1 0 0 0 f f f t f i s 7 0 1186 "23 23 23 23 23 23 701" _null_ _null_ "{years,months,weeks,days,hours,mins,secs}" _null_ _null_ make_interval _null_ _null_ _null_ ) +insert ( 4018 spg_quad_config 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_quad_config _null_ _null_ _null_ ) +insert ( 4019 spg_quad_choose 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_quad_choose _null_ _null_ _null_ ) +insert ( 4020 spg_quad_picksplit 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_quad_picksplit _null_ _null_ _null_ ) +insert ( 4021 spg_quad_inner_consistent 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_quad_inner_consistent _null_ _null_ _null_ ) +insert ( 4022 spg_quad_leaf_consistent 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_quad_leaf_consistent _null_ _null_ _null_ ) +insert ( 4023 spg_kd_config 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_kd_config _null_ _null_ _null_ ) +insert ( 4024 spg_kd_choose 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_kd_choose _null_ _null_ _null_ ) +insert ( 4025 spg_kd_picksplit 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_kd_picksplit _null_ _null_ _null_ ) +insert ( 4026 spg_kd_inner_consistent 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_kd_inner_consistent _null_ _null_ _null_ ) +insert ( 4027 spg_text_config 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_text_config _null_ _null_ _null_ ) +insert ( 4028 spg_text_choose 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_text_choose _null_ _null_ _null_ ) +insert ( 4029 spg_text_picksplit 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_text_picksplit _null_ _null_ _null_ ) +insert ( 4030 spg_text_inner_consistent 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_text_inner_consistent _null_ _null_ _null_ ) +insert ( 4031 spg_text_leaf_consistent 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_text_leaf_consistent _null_ _null_ _null_ ) +insert ( 3469 spg_range_quad_config 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_range_quad_config _null_ _null_ _null_ ) +insert ( 3470 spg_range_quad_choose 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_range_quad_choose _null_ _null_ _null_ ) +insert ( 3471 spg_range_quad_picksplit 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_range_quad_picksplit _null_ _null_ _null_ ) +insert ( 3472 spg_range_quad_inner_consistent 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_range_quad_inner_consistent _null_ _null_ _null_ ) +insert ( 3473 spg_range_quad_leaf_consistent 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_range_quad_leaf_consistent _null_ _null_ _null_ ) +insert ( 5012 spg_box_quad_config 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_box_quad_config _null_ _null_ _null_ ) +insert ( 5013 spg_box_quad_choose 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_box_quad_choose _null_ _null_ _null_ ) +insert ( 5014 spg_box_quad_picksplit 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_box_quad_picksplit _null_ _null_ _null_ ) +insert ( 5015 spg_box_quad_inner_consistent 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_box_quad_inner_consistent _null_ _null_ _null_ ) +insert ( 5016 spg_box_quad_leaf_consistent 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_box_quad_leaf_consistent _null_ _null_ _null_ ) +insert ( 5010 spg_bbox_quad_config 11 10 12 1 0 0 0 f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_bbox_quad_config _null_ _null_ _null_ ) +insert ( 5011 spg_poly_quad_compress 11 10 12 1 0 0 0 f f f t f i s 1 0 603 604 _null_ _null_ _null_ _null_ _null_ spg_poly_quad_compress _null_ _null_ _null_ ) +insert ( 3779 pg_create_physical_replication_slot 11 10 12 1 0 0 0 f f f t f v u 3 0 2249 "19 16 16" "{19,16,16,19,3220}" "{i,i,i,o,o}" "{slot_name,immediately_reserve,temporary,slot_name,lsn}" _null_ _null_ pg_create_physical_replication_slot _null_ _null_ _null_ ) +insert ( 4220 pg_copy_physical_replication_slot 11 10 12 1 0 0 0 f f f t f v u 3 0 2249 "19 19 16" "{19,19,16,19,3220}" "{i,i,i,o,o}" "{src_slot_name,dst_slot_name,temporary,slot_name,lsn}" _null_ _null_ pg_copy_physical_replication_slot_a _null_ _null_ _null_ ) +insert ( 4221 pg_copy_physical_replication_slot 11 10 12 1 0 0 0 f f f t f v u 2 0 2249 "19 19" "{19,19,19,3220}" "{i,i,o,o}" "{src_slot_name,dst_slot_name,slot_name,lsn}" _null_ _null_ pg_copy_physical_replication_slot_b _null_ _null_ _null_ ) +insert ( 3780 pg_drop_replication_slot 11 10 12 1 0 0 0 f f f t f v u 1 0 2278 19 _null_ _null_ _null_ _null_ _null_ pg_drop_replication_slot _null_ _null_ _null_ ) +insert ( 3781 pg_get_replication_slots 11 10 12 1 10 0 0 f f f f t s s 0 0 2249 "" "{19,19,25,26,16,16,23,28,28,3220,3220,25,20}" "{o,o,o,o,o,o,o,o,o,o,o,o,o}" "{slot_name,plugin,slot_type,datoid,temporary,active,active_pid,xmin,catalog_xmin,restart_lsn,confirmed_flush_lsn,wal_status,safe_wal_size}" _null_ _null_ pg_get_replication_slots _null_ _null_ _null_ ) +insert ( 3786 pg_create_logical_replication_slot 11 10 12 1 0 0 0 f f f t f v u 3 0 2249 "19 19 16" "{19,19,16,19,3220}" "{i,i,i,o,o}" "{slot_name,plugin,temporary,slot_name,lsn}" _null_ _null_ pg_create_logical_replication_slot _null_ _null_ _null_ ) +insert ( 4222 pg_copy_logical_replication_slot 11 10 12 1 0 0 0 f f f t f v u 4 0 2249 "19 19 16 19" "{19,19,16,19,19,3220}" "{i,i,i,i,o,o}" "{src_slot_name,dst_slot_name,temporary,plugin,slot_name,lsn}" _null_ _null_ pg_copy_logical_replication_slot_a _null_ _null_ _null_ ) +insert ( 4223 pg_copy_logical_replication_slot 11 10 12 1 0 0 0 f f f t f v u 3 0 2249 "19 19 16" "{19,19,16,19,3220}" "{i,i,i,o,o}" "{src_slot_name,dst_slot_name,temporary,slot_name,lsn}" _null_ _null_ pg_copy_logical_replication_slot_b _null_ _null_ _null_ ) +insert ( 4224 pg_copy_logical_replication_slot 11 10 12 1 0 0 0 f f f t f v u 2 0 2249 "19 19" "{19,19,19,3220}" "{i,i,o,o}" "{src_slot_name,dst_slot_name,slot_name,lsn}" _null_ _null_ pg_copy_logical_replication_slot_c _null_ _null_ _null_ ) +insert ( 3782 pg_logical_slot_get_changes 11 10 12 1000 1000 25 0 f f f f t v u 4 0 2249 "19 3220 23 1009" "{19,3220,23,1009,3220,28,25}" "{i,i,i,v,o,o,o}" "{slot_name,upto_lsn,upto_nchanges,options,lsn,xid,data}" _null_ _null_ pg_logical_slot_get_changes _null_ _null_ _null_ ) +insert ( 3783 pg_logical_slot_get_binary_changes 11 10 12 1000 1000 25 0 f f f f t v u 4 0 2249 "19 3220 23 1009" "{19,3220,23,1009,3220,28,17}" "{i,i,i,v,o,o,o}" "{slot_name,upto_lsn,upto_nchanges,options,lsn,xid,data}" _null_ _null_ pg_logical_slot_get_binary_changes _null_ _null_ _null_ ) +insert ( 3784 pg_logical_slot_peek_changes 11 10 12 1000 1000 25 0 f f f f t v u 4 0 2249 "19 3220 23 1009" "{19,3220,23,1009,3220,28,25}" "{i,i,i,v,o,o,o}" "{slot_name,upto_lsn,upto_nchanges,options,lsn,xid,data}" _null_ _null_ pg_logical_slot_peek_changes _null_ _null_ _null_ ) +insert ( 3785 pg_logical_slot_peek_binary_changes 11 10 12 1000 1000 25 0 f f f f t v u 4 0 2249 "19 3220 23 1009" "{19,3220,23,1009,3220,28,17}" "{i,i,i,v,o,o,o}" "{slot_name,upto_lsn,upto_nchanges,options,lsn,xid,data}" _null_ _null_ pg_logical_slot_peek_binary_changes _null_ _null_ _null_ ) +insert ( 3878 pg_replication_slot_advance 11 10 12 1 0 0 0 f f f t f v u 2 0 2249 "19 3220" "{19,3220,19,3220}" "{i,i,o,o}" "{slot_name,upto_lsn,slot_name,end_lsn}" _null_ _null_ pg_replication_slot_advance _null_ _null_ _null_ ) +insert ( 3577 pg_logical_emit_message 11 10 12 1 0 0 0 f f f t f v u 3 0 3220 "16 25 25" _null_ _null_ _null_ _null_ _null_ pg_logical_emit_message_text _null_ _null_ _null_ ) +insert ( 3578 pg_logical_emit_message 11 10 12 1 0 0 0 f f f t f v u 3 0 3220 "16 25 17" _null_ _null_ _null_ _null_ _null_ pg_logical_emit_message_bytea _null_ _null_ _null_ ) +insert ( 3566 pg_event_trigger_dropped_objects 11 10 12 10 100 0 0 f f f t t s r 0 0 2249 "" "{26,26,23,16,16,16,25,25,25,25,1009,1009}" "{o,o,o,o,o,o,o,o,o,o,o,o}" "{classid, objid, objsubid, original, normal, is_temporary, object_type, schema_name, object_name, object_identity, address_names, address_args}" _null_ _null_ pg_event_trigger_dropped_objects _null_ _null_ _null_ ) +insert ( 4566 pg_event_trigger_table_rewrite_oid 11 10 12 1 0 0 0 f f f t f s r 0 0 26 "" "{26}" "{o}" "{oid}" _null_ _null_ pg_event_trigger_table_rewrite_oid _null_ _null_ _null_ ) +insert ( 4567 pg_event_trigger_table_rewrite_reason 11 10 12 1 0 0 0 f f f t f s r 0 0 23 "" _null_ _null_ _null_ _null_ _null_ pg_event_trigger_table_rewrite_reason _null_ _null_ _null_ ) +insert ( 4568 pg_event_trigger_ddl_commands 11 10 12 10 100 0 0 f f f t t s r 0 0 2249 "" "{26,26,23,25,25,25,25,16,32}" "{o,o,o,o,o,o,o,o,o}" "{classid, objid, objsubid, command_tag, object_type, schema_name, object_identity, in_extension, command}" _null_ _null_ pg_event_trigger_ddl_commands _null_ _null_ _null_ ) +insert ( 3970 ordered_set_transition 11 10 12 1 0 0 0 f f f f f i s 2 0 2281 "2281 2276" _null_ _null_ _null_ _null_ _null_ ordered_set_transition _null_ _null_ _null_ ) +insert ( 3971 ordered_set_transition_multi 11 10 12 1 0 2276 0 f f f f f i s 2 0 2281 "2281 2276" "{2281,2276}" "{i,v}" _null_ _null_ _null_ ordered_set_transition_multi _null_ _null_ _null_ ) +insert ( 3972 percentile_disc 11 10 12 1 0 0 0 a f f f f i s 2 0 2283 "701 2283" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3973 percentile_disc_final 11 10 12 1 0 0 0 f f f f f i s 3 0 2283 "2281 701 2283" _null_ _null_ _null_ _null_ _null_ percentile_disc_final _null_ _null_ _null_ ) +insert ( 3974 percentile_cont 11 10 12 1 0 0 0 a f f f f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3975 percentile_cont_float8_final 11 10 12 1 0 0 0 f f f f f i s 2 0 701 "2281 701" _null_ _null_ _null_ _null_ _null_ percentile_cont_float8_final _null_ _null_ _null_ ) +insert ( 3976 percentile_cont 11 10 12 1 0 0 0 a f f f f i s 2 0 1186 "701 1186" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3977 percentile_cont_interval_final 11 10 12 1 0 0 0 f f f f f i s 2 0 1186 "2281 701" _null_ _null_ _null_ _null_ _null_ percentile_cont_interval_final _null_ _null_ _null_ ) +insert ( 3978 percentile_disc 11 10 12 1 0 0 0 a f f f f i s 2 0 2277 "1022 2283" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3979 percentile_disc_multi_final 11 10 12 1 0 0 0 f f f f f i s 3 0 2277 "2281 1022 2283" _null_ _null_ _null_ _null_ _null_ percentile_disc_multi_final _null_ _null_ _null_ ) +insert ( 3980 percentile_cont 11 10 12 1 0 0 0 a f f f f i s 2 0 1022 "1022 701" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3981 percentile_cont_float8_multi_final 11 10 12 1 0 0 0 f f f f f i s 2 0 1022 "2281 1022" _null_ _null_ _null_ _null_ _null_ percentile_cont_float8_multi_final _null_ _null_ _null_ ) +insert ( 3982 percentile_cont 11 10 12 1 0 0 0 a f f f f i s 2 0 1187 "1022 1186" _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3983 percentile_cont_interval_multi_final 11 10 12 1 0 0 0 f f f f f i s 2 0 1187 "2281 1022" _null_ _null_ _null_ _null_ _null_ percentile_cont_interval_multi_final _null_ _null_ _null_ ) +insert ( 3984 mode 11 10 12 1 0 0 0 a f f f f i s 1 0 2283 2283 _null_ _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3985 mode_final 11 10 12 1 0 0 0 f f f f f i s 2 0 2283 "2281 2283" _null_ _null_ _null_ _null_ _null_ mode_final _null_ _null_ _null_ ) +insert ( 3986 rank 11 10 12 1 0 2276 0 a f f f f i s 1 0 20 2276 "{2276}" "{v}" _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3987 rank_final 11 10 12 1 0 2276 0 f f f f f i s 2 0 20 "2281 2276" "{2281,2276}" "{i,v}" _null_ _null_ _null_ hypothetical_rank_final _null_ _null_ _null_ ) +insert ( 3988 percent_rank 11 10 12 1 0 2276 0 a f f f f i s 1 0 701 2276 "{2276}" "{v}" _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3989 percent_rank_final 11 10 12 1 0 2276 0 f f f f f i s 2 0 701 "2281 2276" "{2281,2276}" "{i,v}" _null_ _null_ _null_ hypothetical_percent_rank_final _null_ _null_ _null_ ) +insert ( 3990 cume_dist 11 10 12 1 0 2276 0 a f f f f i s 1 0 701 2276 "{2276}" "{v}" _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3991 cume_dist_final 11 10 12 1 0 2276 0 f f f f f i s 2 0 701 "2281 2276" "{2281,2276}" "{i,v}" _null_ _null_ _null_ hypothetical_cume_dist_final _null_ _null_ _null_ ) +insert ( 3992 dense_rank 11 10 12 1 0 2276 0 a f f f f i s 1 0 20 2276 "{2276}" "{v}" _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ) +insert ( 3993 dense_rank_final 11 10 12 1 0 2276 0 f f f f f i s 2 0 20 "2281 2276" "{2281,2276}" "{i,v}" _null_ _null_ _null_ hypothetical_dense_rank_final _null_ _null_ _null_ ) +insert ( 3582 binary_upgrade_set_next_pg_type_oid 11 10 12 1 0 0 0 f f f t f v r 1 0 2278 26 _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_pg_type_oid _null_ _null_ _null_ ) +insert ( 3584 binary_upgrade_set_next_array_pg_type_oid 11 10 12 1 0 0 0 f f f t f v r 1 0 2278 26 _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_array_pg_type_oid _null_ _null_ _null_ ) +insert ( 3585 binary_upgrade_set_next_toast_pg_type_oid 11 10 12 1 0 0 0 f f f t f v r 1 0 2278 26 _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_toast_pg_type_oid _null_ _null_ _null_ ) +insert ( 3586 binary_upgrade_set_next_heap_pg_class_oid 11 10 12 1 0 0 0 f f f t f v r 1 0 2278 26 _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_heap_pg_class_oid _null_ _null_ _null_ ) +insert ( 3587 binary_upgrade_set_next_index_pg_class_oid 11 10 12 1 0 0 0 f f f t f v r 1 0 2278 26 _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_index_pg_class_oid _null_ _null_ _null_ ) +insert ( 3588 binary_upgrade_set_next_toast_pg_class_oid 11 10 12 1 0 0 0 f f f t f v r 1 0 2278 26 _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_toast_pg_class_oid _null_ _null_ _null_ ) +insert ( 3589 binary_upgrade_set_next_pg_enum_oid 11 10 12 1 0 0 0 f f f t f v r 1 0 2278 26 _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_pg_enum_oid _null_ _null_ _null_ ) +insert ( 3590 binary_upgrade_set_next_pg_authid_oid 11 10 12 1 0 0 0 f f f t f v r 1 0 2278 26 _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_next_pg_authid_oid _null_ _null_ _null_ ) +insert ( 3591 binary_upgrade_create_empty_extension 11 10 12 1 0 0 0 f f f f f v u 7 0 2278 "25 25 16 25 1028 1009 1009" _null_ _null_ _null_ _null_ _null_ binary_upgrade_create_empty_extension _null_ _null_ _null_ ) +insert ( 4083 binary_upgrade_set_record_init_privs 11 10 12 1 0 0 0 f f f t f v r 1 0 2278 16 _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_record_init_privs _null_ _null_ _null_ ) +insert ( 4101 binary_upgrade_set_missing_value 11 10 12 1 0 0 0 f f f t f v u 3 0 2278 "26 25 25" _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_missing_value _null_ _null_ _null_ ) +insert ( 4302 koi8r_to_mic 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ koi8r_to_mic "$libdir/cyrillic_and_mic" _null_ _null_ ) +insert ( 4303 mic_to_koi8r 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ mic_to_koi8r "$libdir/cyrillic_and_mic" _null_ _null_ ) +insert ( 4304 iso_to_mic 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ iso_to_mic "$libdir/cyrillic_and_mic" _null_ _null_ ) +insert ( 4305 mic_to_iso 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ mic_to_iso "$libdir/cyrillic_and_mic" _null_ _null_ ) +insert ( 4306 win1251_to_mic 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ win1251_to_mic "$libdir/cyrillic_and_mic" _null_ _null_ ) +insert ( 4307 mic_to_win1251 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ mic_to_win1251 "$libdir/cyrillic_and_mic" _null_ _null_ ) +insert ( 4308 win866_to_mic 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ win866_to_mic "$libdir/cyrillic_and_mic" _null_ _null_ ) +insert ( 4309 mic_to_win866 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ mic_to_win866 "$libdir/cyrillic_and_mic" _null_ _null_ ) +insert ( 4310 koi8r_to_win1251 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ koi8r_to_win1251 "$libdir/cyrillic_and_mic" _null_ _null_ ) +insert ( 4311 win1251_to_koi8r 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ win1251_to_koi8r "$libdir/cyrillic_and_mic" _null_ _null_ ) +insert ( 4312 koi8r_to_win866 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ koi8r_to_win866 "$libdir/cyrillic_and_mic" _null_ _null_ ) +insert ( 4313 win866_to_koi8r 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ win866_to_koi8r "$libdir/cyrillic_and_mic" _null_ _null_ ) +insert ( 4314 win866_to_win1251 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ win866_to_win1251 "$libdir/cyrillic_and_mic" _null_ _null_ ) +insert ( 4315 win1251_to_win866 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ win1251_to_win866 "$libdir/cyrillic_and_mic" _null_ _null_ ) +insert ( 4316 iso_to_koi8r 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ iso_to_koi8r "$libdir/cyrillic_and_mic" _null_ _null_ ) +insert ( 4317 koi8r_to_iso 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ koi8r_to_iso "$libdir/cyrillic_and_mic" _null_ _null_ ) +insert ( 4318 iso_to_win1251 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ iso_to_win1251 "$libdir/cyrillic_and_mic" _null_ _null_ ) +insert ( 4319 win1251_to_iso 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ win1251_to_iso "$libdir/cyrillic_and_mic" _null_ _null_ ) +insert ( 4320 iso_to_win866 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ iso_to_win866 "$libdir/cyrillic_and_mic" _null_ _null_ ) +insert ( 4321 win866_to_iso 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ win866_to_iso "$libdir/cyrillic_and_mic" _null_ _null_ ) +insert ( 4322 euc_cn_to_mic 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ euc_cn_to_mic "$libdir/euc_cn_and_mic" _null_ _null_ ) +insert ( 4323 mic_to_euc_cn 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ mic_to_euc_cn "$libdir/euc_cn_and_mic" _null_ _null_ ) +insert ( 4324 euc_jp_to_sjis 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ euc_jp_to_sjis "$libdir/euc_jp_and_sjis" _null_ _null_ ) +insert ( 4325 sjis_to_euc_jp 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ sjis_to_euc_jp "$libdir/euc_jp_and_sjis" _null_ _null_ ) +insert ( 4326 euc_jp_to_mic 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ euc_jp_to_mic "$libdir/euc_jp_and_sjis" _null_ _null_ ) +insert ( 4327 sjis_to_mic 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ sjis_to_mic "$libdir/euc_jp_and_sjis" _null_ _null_ ) +insert ( 4328 mic_to_euc_jp 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ mic_to_euc_jp "$libdir/euc_jp_and_sjis" _null_ _null_ ) +insert ( 4329 mic_to_sjis 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ mic_to_sjis "$libdir/euc_jp_and_sjis" _null_ _null_ ) +insert ( 4330 euc_kr_to_mic 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ euc_kr_to_mic "$libdir/euc_kr_and_mic" _null_ _null_ ) +insert ( 4331 mic_to_euc_kr 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ mic_to_euc_kr "$libdir/euc_kr_and_mic" _null_ _null_ ) +insert ( 4332 euc_tw_to_big5 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ euc_tw_to_big5 "$libdir/euc_tw_and_big5" _null_ _null_ ) +insert ( 4333 big5_to_euc_tw 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ big5_to_euc_tw "$libdir/euc_tw_and_big5" _null_ _null_ ) +insert ( 4334 euc_tw_to_mic 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ euc_tw_to_mic "$libdir/euc_tw_and_big5" _null_ _null_ ) +insert ( 4335 big5_to_mic 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ big5_to_mic "$libdir/euc_tw_and_big5" _null_ _null_ ) +insert ( 4336 mic_to_euc_tw 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ mic_to_euc_tw "$libdir/euc_tw_and_big5" _null_ _null_ ) +insert ( 4337 mic_to_big5 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ mic_to_big5 "$libdir/euc_tw_and_big5" _null_ _null_ ) +insert ( 4338 latin2_to_mic 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ latin2_to_mic "$libdir/latin2_and_win1250" _null_ _null_ ) +insert ( 4339 mic_to_latin2 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ mic_to_latin2 "$libdir/latin2_and_win1250" _null_ _null_ ) +insert ( 4340 win1250_to_mic 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ win1250_to_mic "$libdir/latin2_and_win1250" _null_ _null_ ) +insert ( 4341 mic_to_win1250 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ mic_to_win1250 "$libdir/latin2_and_win1250" _null_ _null_ ) +insert ( 4342 latin2_to_win1250 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ latin2_to_win1250 "$libdir/latin2_and_win1250" _null_ _null_ ) +insert ( 4343 win1250_to_latin2 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ win1250_to_latin2 "$libdir/latin2_and_win1250" _null_ _null_ ) +insert ( 4344 latin1_to_mic 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ latin1_to_mic "$libdir/latin_and_mic" _null_ _null_ ) +insert ( 4345 mic_to_latin1 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ mic_to_latin1 "$libdir/latin_and_mic" _null_ _null_ ) +insert ( 4346 latin3_to_mic 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ latin3_to_mic "$libdir/latin_and_mic" _null_ _null_ ) +insert ( 4347 mic_to_latin3 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ mic_to_latin3 "$libdir/latin_and_mic" _null_ _null_ ) +insert ( 4348 latin4_to_mic 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ latin4_to_mic "$libdir/latin_and_mic" _null_ _null_ ) +insert ( 4349 mic_to_latin4 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ mic_to_latin4 "$libdir/latin_and_mic" _null_ _null_ ) +insert ( 4352 big5_to_utf8 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ big5_to_utf8 "$libdir/utf8_and_big5" _null_ _null_ ) +insert ( 4353 utf8_to_big5 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ utf8_to_big5 "$libdir/utf8_and_big5" _null_ _null_ ) +insert ( 4354 utf8_to_koi8r 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ utf8_to_koi8r "$libdir/utf8_and_cyrillic" _null_ _null_ ) +insert ( 4355 koi8r_to_utf8 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ koi8r_to_utf8 "$libdir/utf8_and_cyrillic" _null_ _null_ ) +insert ( 4356 utf8_to_koi8u 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ utf8_to_koi8u "$libdir/utf8_and_cyrillic" _null_ _null_ ) +insert ( 4357 koi8u_to_utf8 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ koi8u_to_utf8 "$libdir/utf8_and_cyrillic" _null_ _null_ ) +insert ( 4358 utf8_to_win 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ utf8_to_win "$libdir/utf8_and_win" _null_ _null_ ) +insert ( 4359 win_to_utf8 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ win_to_utf8 "$libdir/utf8_and_win" _null_ _null_ ) +insert ( 4360 euc_cn_to_utf8 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ euc_cn_to_utf8 "$libdir/utf8_and_euc_cn" _null_ _null_ ) +insert ( 4361 utf8_to_euc_cn 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ utf8_to_euc_cn "$libdir/utf8_and_euc_cn" _null_ _null_ ) +insert ( 4362 euc_jp_to_utf8 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ euc_jp_to_utf8 "$libdir/utf8_and_euc_jp" _null_ _null_ ) +insert ( 4363 utf8_to_euc_jp 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ utf8_to_euc_jp "$libdir/utf8_and_euc_jp" _null_ _null_ ) +insert ( 4364 euc_kr_to_utf8 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ euc_kr_to_utf8 "$libdir/utf8_and_euc_kr" _null_ _null_ ) +insert ( 4365 utf8_to_euc_kr 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ utf8_to_euc_kr "$libdir/utf8_and_euc_kr" _null_ _null_ ) +insert ( 4366 euc_tw_to_utf8 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ euc_tw_to_utf8 "$libdir/utf8_and_euc_tw" _null_ _null_ ) +insert ( 4367 utf8_to_euc_tw 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ utf8_to_euc_tw "$libdir/utf8_and_euc_tw" _null_ _null_ ) +insert ( 4368 gb18030_to_utf8 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ gb18030_to_utf8 "$libdir/utf8_and_gb18030" _null_ _null_ ) +insert ( 4369 utf8_to_gb18030 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ utf8_to_gb18030 "$libdir/utf8_and_gb18030" _null_ _null_ ) +insert ( 4370 gbk_to_utf8 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ gbk_to_utf8 "$libdir/utf8_and_gbk" _null_ _null_ ) +insert ( 4371 utf8_to_gbk 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ utf8_to_gbk "$libdir/utf8_and_gbk" _null_ _null_ ) +insert ( 4372 utf8_to_iso8859 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ utf8_to_iso8859 "$libdir/utf8_and_iso8859" _null_ _null_ ) +insert ( 4373 iso8859_to_utf8 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ iso8859_to_utf8 "$libdir/utf8_and_iso8859" _null_ _null_ ) +insert ( 4374 iso8859_1_to_utf8 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ iso8859_1_to_utf8 "$libdir/utf8_and_iso8859_1" _null_ _null_ ) +insert ( 4375 utf8_to_iso8859_1 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ utf8_to_iso8859_1 "$libdir/utf8_and_iso8859_1" _null_ _null_ ) +insert ( 4376 johab_to_utf8 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ johab_to_utf8 "$libdir/utf8_and_johab" _null_ _null_ ) +insert ( 4377 utf8_to_johab 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ utf8_to_johab "$libdir/utf8_and_johab" _null_ _null_ ) +insert ( 4378 sjis_to_utf8 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ sjis_to_utf8 "$libdir/utf8_and_sjis" _null_ _null_ ) +insert ( 4379 utf8_to_sjis 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ utf8_to_sjis "$libdir/utf8_and_sjis" _null_ _null_ ) +insert ( 4380 uhc_to_utf8 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ uhc_to_utf8 "$libdir/utf8_and_uhc" _null_ _null_ ) +insert ( 4381 utf8_to_uhc 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ utf8_to_uhc "$libdir/utf8_and_uhc" _null_ _null_ ) +insert ( 4382 euc_jis_2004_to_utf8 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ euc_jis_2004_to_utf8 "$libdir/utf8_and_euc2004" _null_ _null_ ) +insert ( 4383 utf8_to_euc_jis_2004 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ utf8_to_euc_jis_2004 "$libdir/utf8_and_euc2004" _null_ _null_ ) +insert ( 4384 shift_jis_2004_to_utf8 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ shift_jis_2004_to_utf8 "$libdir/utf8_and_sjis2004" _null_ _null_ ) +insert ( 4385 utf8_to_shift_jis_2004 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ utf8_to_shift_jis_2004 "$libdir/utf8_and_sjis2004" _null_ _null_ ) +insert ( 4386 euc_jis_2004_to_shift_jis_2004 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ euc_jis_2004_to_shift_jis_2004 "$libdir/euc2004_sjis2004" _null_ _null_ ) +insert ( 4387 shift_jis_2004_to_euc_jis_2004 11 10 13 1 0 0 0 f f f t f i s 5 0 2278 "23 23 2275 2281 23" _null_ _null_ _null_ _null_ _null_ shift_jis_2004_to_euc_jis_2004 "$libdir/euc2004_sjis2004" _null_ _null_ ) +insert ( 5040 matchingsel 11 10 12 1 0 0 0 f f f t f s s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ matchingsel _null_ _null_ _null_ ) +insert ( 5041 matchingjoinsel 11 10 12 1 0 0 0 f f f t f s s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ _null_ matchingjoinsel _null_ _null_ _null_ ) +insert ( 6003 pg_replication_origin_create 11 10 12 1 0 0 0 f f f t f v u 1 0 26 25 _null_ _null_ _null_ _null_ _null_ pg_replication_origin_create _null_ _null_ _null_ ) +insert ( 6004 pg_replication_origin_drop 11 10 12 1 0 0 0 f f f t f v u 1 0 2278 25 _null_ _null_ _null_ _null_ _null_ pg_replication_origin_drop _null_ _null_ _null_ ) +insert ( 6005 pg_replication_origin_oid 11 10 12 1 0 0 0 f f f t f s s 1 0 26 25 _null_ _null_ _null_ _null_ _null_ pg_replication_origin_oid _null_ _null_ _null_ ) +insert ( 6006 pg_replication_origin_session_setup 11 10 12 1 0 0 0 f f f t f v u 1 0 2278 25 _null_ _null_ _null_ _null_ _null_ pg_replication_origin_session_setup _null_ _null_ _null_ ) +insert ( 6007 pg_replication_origin_session_reset 11 10 12 1 0 0 0 f f f t f v u 0 0 2278 "" _null_ _null_ _null_ _null_ _null_ pg_replication_origin_session_reset _null_ _null_ _null_ ) +insert ( 6008 pg_replication_origin_session_is_setup 11 10 12 1 0 0 0 f f f t f v r 0 0 16 "" _null_ _null_ _null_ _null_ _null_ pg_replication_origin_session_is_setup _null_ _null_ _null_ ) +insert ( 6009 pg_replication_origin_session_progress 11 10 12 1 0 0 0 f f f t f v u 1 0 3220 16 _null_ _null_ _null_ _null_ _null_ pg_replication_origin_session_progress _null_ _null_ _null_ ) +insert ( 6010 pg_replication_origin_xact_setup 11 10 12 1 0 0 0 f f f t f v r 2 0 2278 "3220 1184" _null_ _null_ _null_ _null_ _null_ pg_replication_origin_xact_setup _null_ _null_ _null_ ) +insert ( 6011 pg_replication_origin_xact_reset 11 10 12 1 0 0 0 f f f t f v r 0 0 2278 "" _null_ _null_ _null_ _null_ _null_ pg_replication_origin_xact_reset _null_ _null_ _null_ ) +insert ( 6012 pg_replication_origin_advance 11 10 12 1 0 0 0 f f f t f v u 2 0 2278 "25 3220" _null_ _null_ _null_ _null_ _null_ pg_replication_origin_advance _null_ _null_ _null_ ) +insert ( 6013 pg_replication_origin_progress 11 10 12 1 0 0 0 f f f t f v u 2 0 3220 "25 16" _null_ _null_ _null_ _null_ _null_ pg_replication_origin_progress _null_ _null_ _null_ ) +insert ( 6014 pg_show_replication_origin_status 11 10 12 1 100 0 0 f f f f t v r 0 0 2249 "" "{26,25,3220,3220}" "{o,o,o,o}" "{local_id, external_id, remote_lsn, local_lsn}" _null_ _null_ pg_show_replication_origin_status _null_ _null_ _null_ ) +insert ( 6119 pg_get_publication_tables 11 10 12 1 1000 0 0 f f f t t s s 1 0 26 25 "{25,26}" "{i,o}" "{pubname,relid}" _null_ _null_ pg_get_publication_tables _null_ _null_ _null_ ) +insert ( 6121 pg_relation_is_publishable 11 10 12 1 0 0 0 f f f t f s s 1 0 16 2205 _null_ _null_ _null_ _null_ _null_ pg_relation_is_publishable _null_ _null_ _null_ ) +insert ( 3298 row_security_active 11 10 12 1 0 0 0 f f f t f s s 1 0 16 26 _null_ _null_ _null_ _null_ _null_ row_security_active _null_ _null_ _null_ ) +insert ( 3299 row_security_active 11 10 12 1 0 0 0 f f f t f s s 1 0 16 25 _null_ _null_ _null_ _null_ _null_ row_security_active_name _null_ _null_ _null_ ) +insert ( 3400 pg_config 11 10 12 1 23 0 0 f f f t t s r 0 0 2249 "" "{25,25}" "{o,o}" "{name,setting}" _null_ _null_ pg_config _null_ _null_ _null_ ) +insert ( 3441 pg_control_system 11 10 12 1 0 0 0 f f f t f v s 0 0 2249 "" "{23,23,20,1184}" "{o,o,o,o}" "{pg_control_version,catalog_version_no,system_identifier,pg_control_last_modified}" _null_ _null_ pg_control_system _null_ _null_ _null_ ) +insert ( 3442 pg_control_checkpoint 11 10 12 1 0 0 0 f f f t f v s 0 0 2249 "" "{3220,3220,25,23,23,16,25,26,28,28,28,26,28,28,26,28,28,1184}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{checkpoint_lsn,redo_lsn,redo_wal_file,timeline_id,prev_timeline_id,full_page_writes,next_xid,next_oid,next_multixact_id,next_multi_offset,oldest_xid,oldest_xid_dbid,oldest_active_xid,oldest_multi_xid,oldest_multi_dbid,oldest_commit_ts_xid,newest_commit_ts_xid,checkpoint_time}" _null_ _null_ pg_control_checkpoint _null_ _null_ _null_ ) +insert ( 3443 pg_control_recovery 11 10 12 1 0 0 0 f f f t f v s 0 0 2249 "" "{3220,23,3220,3220,16}" "{o,o,o,o,o}" "{min_recovery_end_lsn,min_recovery_end_timeline,backup_start_lsn,backup_end_lsn,end_of_backup_record_required}" _null_ _null_ pg_control_recovery _null_ _null_ _null_ ) +insert ( 3444 pg_control_init 11 10 12 1 0 0 0 f f f t f v s 0 0 2249 "" "{23,23,23,23,23,23,23,23,23,16,23}" "{o,o,o,o,o,o,o,o,o,o,o}" "{max_data_alignment,database_block_size,blocks_per_segment,wal_block_size,bytes_per_wal_segment,max_identifier_length,max_index_columns,max_toast_chunk_size,large_object_chunk_size,float8_pass_by_value,data_page_checksum_version}" _null_ _null_ pg_control_init _null_ _null_ _null_ ) +insert ( 3445 pg_import_system_collations 11 10 12 100 0 0 0 f f f t f v u 1 0 23 4089 _null_ _null_ _null_ _null_ _null_ pg_import_system_collations _null_ _null_ _null_ ) +insert ( 3448 pg_collation_actual_version 11 10 12 100 0 0 0 f f f t f v s 1 0 25 26 _null_ _null_ _null_ _null_ _null_ pg_collation_actual_version _null_ _null_ _null_ ) +insert ( 3353 pg_ls_logdir 11 10 12 10 20 0 0 f f f t t v s 0 0 2249 "" "{25,20,1184}" "{o,o,o}" "{name,size,modification}" _null_ _null_ pg_ls_logdir _null_ _null_ _null_ ) +insert ( 3354 pg_ls_waldir 11 10 12 10 20 0 0 f f f t t v s 0 0 2249 "" "{25,20,1184}" "{o,o,o}" "{name,size,modification}" _null_ _null_ pg_ls_waldir _null_ _null_ _null_ ) +insert ( 5031 pg_ls_archive_statusdir 11 10 12 10 20 0 0 f f f t t v s 0 0 2249 "" "{25,20,1184}" "{o,o,o}" "{name,size,modification}" _null_ _null_ pg_ls_archive_statusdir _null_ _null_ _null_ ) +insert ( 5029 pg_ls_tmpdir 11 10 12 10 20 0 0 f f f t t v s 0 0 2249 "" "{25,20,1184}" "{o,o,o}" "{name,size,modification}" _null_ _null_ pg_ls_tmpdir_noargs _null_ _null_ _null_ ) +insert ( 5030 pg_ls_tmpdir 11 10 12 10 20 0 0 f f f t t v s 1 0 2249 26 "{26,25,20,1184}" "{i,o,o,o}" "{tablespace,name,size,modification}" _null_ _null_ pg_ls_tmpdir_1arg _null_ _null_ _null_ ) +insert ( 5028 satisfies_hash_partition 11 10 12 1 0 2276 0 f f f f f i s 4 0 16 "26 23 23 2276" _null_ "{i,i,i,v}" _null_ _null_ _null_ satisfies_hash_partition _null_ _null_ _null_ ) +insert ( 3423 pg_partition_tree 11 10 12 1 1000 0 0 f f f t t v s 1 0 2249 2205 "{2205,2205,2205,16,23}" "{i,o,o,o,o}" "{rootrelid,relid,parentrelid,isleaf,level}" _null_ _null_ pg_partition_tree _null_ _null_ _null_ ) +insert ( 3425 pg_partition_ancestors 11 10 12 1 10 0 0 f f f t t v s 1 0 2205 2205 "{2205,2205}" "{i,o}" "{partitionid,relid}" _null_ _null_ pg_partition_ancestors _null_ _null_ _null_ ) +insert ( 3424 pg_partition_root 11 10 12 1 0 0 0 f f f t f i s 1 0 2205 2205 _null_ _null_ _null_ _null_ _null_ pg_partition_root _null_ _null_ _null_ ) +insert ( 4350 normalize 11 10 12 1 0 0 0 f f f t f i s 2 0 25 "25 25" _null_ _null_ _null_ _null_ _null_ unicode_normalize_func _null_ _null_ _null_ ) +insert ( 4351 is_normalized 11 10 12 1 0 0 0 f f f t f i s 2 0 16 "25 25" _null_ _null_ _null_ _null_ _null_ unicode_is_normalized _null_ _null_ _null_ ) +close pg_proc +create pg_type 1247 bootstrap rowtype_oid 71 + ( + oid = oid , + typname = name , + typnamespace = oid , + typowner = oid , + typlen = int2 , + typbyval = bool , + typtype = char , + typcategory = char , + typispreferred = bool , + typisdefined = bool , + typdelim = char , + typrelid = oid , + typelem = oid , + typarray = oid , + typinput = regproc , + typoutput = regproc , + typreceive = regproc , + typsend = regproc , + typmodin = regproc , + typmodout = regproc , + typanalyze = regproc , + typalign = char , + typstorage = char , + typnotnull = bool , + typbasetype = oid , + typtypmod = int4 , + typndims = int4 , + typcollation = oid , + typdefaultbin = pg_node_tree , + typdefault = text , + typacl = _aclitem + ) +insert ( 16 bool 11 10 1 t b B t t "," 0 0 1000 1242 1243 2436 2437 - - - c p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 17 bytea 11 10 -1 f b U f t "," 0 0 1001 1244 31 2412 2413 - - - i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 18 char 11 10 1 t b S f t "," 0 0 1002 1245 33 2434 2435 - - - c p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 19 name 11 10 NAMEDATALEN f b S f t "," 0 18 1003 34 35 2422 2423 - - - c p f 0 -1 0 950 _null_ _null_ _null_ ) +insert ( 20 int8 11 10 8 FLOAT8PASSBYVAL b N f t "," 0 0 1016 460 461 2408 2409 - - - d p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 21 int2 11 10 2 t b N f t "," 0 0 1005 38 39 2404 2405 - - - s p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 22 int2vector 11 10 -1 f b A f t "," 0 21 1006 40 41 2410 2411 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 23 int4 11 10 4 t b N f t "," 0 0 1007 42 43 2406 2407 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 24 regproc 11 10 4 t b N f t "," 0 0 1008 44 45 2444 2445 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 25 text 11 10 -1 f b S t t "," 0 0 1009 46 47 2414 2415 - - - i x f 0 -1 0 100 _null_ _null_ _null_ ) +insert ( 26 oid 11 10 4 t b N t t "," 0 0 1028 1798 1799 2418 2419 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 27 tid 11 10 6 f b U f t "," 0 0 1010 48 49 2438 2439 - - - s p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 28 xid 11 10 4 t b U f t "," 0 0 1011 50 51 2440 2441 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 29 cid 11 10 4 t b U f t "," 0 0 1012 52 53 2442 2443 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 30 oidvector 11 10 -1 f b A f t "," 0 26 1013 54 55 2420 2421 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 71 pg_type 11 10 -1 f c C f t "," 1247 0 0 2290 2291 2402 2403 - - - d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 75 pg_attribute 11 10 -1 f c C f t "," 1249 0 0 2290 2291 2402 2403 - - - d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 81 pg_proc 11 10 -1 f c C f t "," 1255 0 0 2290 2291 2402 2403 - - - d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 83 pg_class 11 10 -1 f c C f t "," 1259 0 0 2290 2291 2402 2403 - - - d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 114 json 11 10 -1 f b U f t "," 0 0 199 321 322 323 324 - - - i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 142 xml 11 10 -1 f b U f t "," 0 0 143 2893 2894 2898 2899 - - - i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 194 pg_node_tree 11 10 -1 f b S f t "," 0 0 0 195 196 197 198 - - - i x f 0 -1 0 100 _null_ _null_ _null_ ) +insert ( 3361 pg_ndistinct 11 10 -1 f b S f t "," 0 0 0 3355 3356 3357 3358 - - - i x f 0 -1 0 100 _null_ _null_ _null_ ) +insert ( 3402 pg_dependencies 11 10 -1 f b S f t "," 0 0 0 3404 3405 3406 3407 - - - i x f 0 -1 0 100 _null_ _null_ _null_ ) +insert ( 5017 pg_mcv_list 11 10 -1 f b S f t "," 0 0 0 5018 5019 5020 5021 - - - i x f 0 -1 0 100 _null_ _null_ _null_ ) +insert ( 32 pg_ddl_command 11 10 SIZEOF_POINTER t p P f t "," 0 0 0 86 87 88 90 - - - ALIGNOF_POINTER p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 5069 xid8 11 10 8 FLOAT8PASSBYVAL b U f t "," 0 0 271 5070 5081 5082 5083 - - - d p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 600 point 11 10 16 f b G f t "," 0 701 1017 117 118 2428 2429 - - - d p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 601 lseg 11 10 32 f b G f t "," 0 600 1018 119 120 2480 2481 - - - d p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 602 path 11 10 -1 f b G f t "," 0 0 1019 121 122 2482 2483 - - - d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 603 box 11 10 32 f b G f t ";" 0 600 1020 123 124 2484 2485 - - - d p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 604 polygon 11 10 -1 f b G f t "," 0 0 1027 347 348 2486 2487 - - - d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 628 line 11 10 24 f b G f t "," 0 701 629 1490 1491 2488 2489 - - - d p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 700 float4 11 10 4 t b N f t "," 0 0 1021 200 201 2424 2425 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 701 float8 11 10 8 FLOAT8PASSBYVAL b N t t "," 0 0 1022 214 215 2426 2427 - - - d p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 705 unknown 11 10 -2 f p X f t "," 0 0 0 109 110 2416 2417 - - - c p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 718 circle 11 10 24 f b G f t "," 0 0 719 1450 1451 2490 2491 - - - d p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 790 money 11 10 8 FLOAT8PASSBYVAL b N f t "," 0 0 791 886 887 2492 2493 - - - d p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 829 macaddr 11 10 6 f b U f t "," 0 0 1040 436 437 2494 2495 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 869 inet 11 10 -1 f b I t t "," 0 0 1041 910 911 2496 2497 - - - i m f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 650 cidr 11 10 -1 f b I f t "," 0 0 651 1267 1427 2498 2499 - - - i m f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 774 macaddr8 11 10 8 f b U f t "," 0 0 775 4110 4111 3446 3447 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1033 aclitem 11 10 12 f b U f t "," 0 0 1034 1031 1032 - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1042 bpchar 11 10 -1 f b S f t "," 0 0 1014 1044 1045 2430 2431 2913 2914 - i x f 0 -1 0 100 _null_ _null_ _null_ ) +insert ( 1043 varchar 11 10 -1 f b S f t "," 0 0 1015 1046 1047 2432 2433 2915 2916 - i x f 0 -1 0 100 _null_ _null_ _null_ ) +insert ( 1082 date 11 10 4 t b D f t "," 0 0 1182 1084 1085 2468 2469 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1083 time 11 10 8 FLOAT8PASSBYVAL b D f t "," 0 0 1183 1143 1144 2470 2471 2909 2910 - d p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1114 timestamp 11 10 8 FLOAT8PASSBYVAL b D f t "," 0 0 1115 1312 1313 2474 2475 2905 2906 - d p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1184 timestamptz 11 10 8 FLOAT8PASSBYVAL b D t t "," 0 0 1185 1150 1151 2476 2477 2907 2908 - d p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1186 interval 11 10 16 f b T t t "," 0 0 1187 1160 1161 2478 2479 2903 2904 - d p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1266 timetz 11 10 12 f b D f t "," 0 0 1270 1350 1351 2472 2473 2911 2912 - d p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1560 bit 11 10 -1 f b V f t "," 0 0 1561 1564 1565 2456 2457 2919 2920 - i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1562 varbit 11 10 -1 f b V t t "," 0 0 1563 1579 1580 2458 2459 2902 2921 - i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1700 numeric 11 10 -1 f b N f t "," 0 0 1231 1701 1702 2460 2461 2917 2918 - i m f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1790 refcursor 11 10 -1 f b U f t "," 0 0 2201 46 47 2414 2415 - - - i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2202 regprocedure 11 10 4 t b N f t "," 0 0 2207 2212 2213 2446 2447 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2203 regoper 11 10 4 t b N f t "," 0 0 2208 2214 2215 2448 2449 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2204 regoperator 11 10 4 t b N f t "," 0 0 2209 2216 2217 2450 2451 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2205 regclass 11 10 4 t b N f t "," 0 0 2210 2218 2219 2452 2453 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 4191 regcollation 11 10 4 t b N f t "," 0 0 4192 4193 4194 4196 4197 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2206 regtype 11 10 4 t b N f t "," 0 0 2211 2220 2221 2454 2455 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 4096 regrole 11 10 4 t b N f t "," 0 0 4097 4098 4092 4094 4095 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 4089 regnamespace 11 10 4 t b N f t "," 0 0 4090 4084 4085 4087 4088 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2950 uuid 11 10 16 f b U f t "," 0 0 2951 2952 2953 2961 2962 - - - c p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3220 pg_lsn 11 10 8 FLOAT8PASSBYVAL b U f t "," 0 0 3221 3229 3230 3238 3239 - - - d p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3614 tsvector 11 10 -1 f b U f t "," 0 0 3643 3610 3611 3639 3638 - - 3688 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3642 gtsvector 11 10 -1 f b U f t "," 0 0 3644 3646 3647 - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3615 tsquery 11 10 -1 f b U f t "," 0 0 3645 3612 3613 3641 3640 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3734 regconfig 11 10 4 t b N f t "," 0 0 3735 3736 3737 3738 3739 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3769 regdictionary 11 10 4 t b N f t "," 0 0 3770 3771 3772 3773 3774 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3802 jsonb 11 10 -1 f b U f t "," 0 0 3807 3806 3804 3805 3803 - - - i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 4072 jsonpath 11 10 -1 f b U f t "," 0 0 4073 4001 4003 4002 4004 - - - i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2970 txid_snapshot 11 10 -1 f b U f t "," 0 0 2949 2939 2940 2941 2942 - - - d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 5038 pg_snapshot 11 10 -1 f b U f t "," 0 0 5039 5055 5056 5057 5058 - - - d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3904 int4range 11 10 -1 f r R f t "," 0 0 3905 3834 3835 3836 3837 - - 3916 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3906 numrange 11 10 -1 f r R f t "," 0 0 3907 3834 3835 3836 3837 - - 3916 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3908 tsrange 11 10 -1 f r R f t "," 0 0 3909 3834 3835 3836 3837 - - 3916 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3910 tstzrange 11 10 -1 f r R f t "," 0 0 3911 3834 3835 3836 3837 - - 3916 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3912 daterange 11 10 -1 f r R f t "," 0 0 3913 3834 3835 3836 3837 - - 3916 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3926 int8range 11 10 -1 f r R f t "," 0 0 3927 3834 3835 3836 3837 - - 3916 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2249 record 11 10 -1 f p P f t "," 0 0 2287 2290 2291 2402 2403 - - - d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2287 _record 11 10 -1 f p P f t "," 0 2249 0 750 751 2400 2401 - - 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2275 cstring 11 10 -2 f p P f t "," 0 0 1263 2292 2293 2500 2501 - - - c p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2276 any 11 10 4 t p P f t "," 0 0 0 2294 2295 - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2277 anyarray 11 10 -1 f p P f t "," 0 0 0 2296 2297 2502 2503 - - - d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2278 void 11 10 4 t p P f t "," 0 0 0 2298 2299 3120 3121 - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2279 trigger 11 10 4 t p P f t "," 0 0 0 2300 2301 - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3838 event_trigger 11 10 4 t p P f t "," 0 0 0 3594 3595 - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2280 language_handler 11 10 4 t p P f t "," 0 0 0 2302 2303 - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2281 internal 11 10 SIZEOF_POINTER t p P f t "," 0 0 0 2304 2305 - - - - - ALIGNOF_POINTER p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2283 anyelement 11 10 4 t p P f t "," 0 0 0 2312 2313 - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2776 anynonarray 11 10 4 t p P f t "," 0 0 0 2777 2778 - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3500 anyenum 11 10 4 t p P f t "," 0 0 0 3504 3505 - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3115 fdw_handler 11 10 4 t p P f t "," 0 0 0 3116 3117 - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 325 index_am_handler 11 10 4 t p P f t "," 0 0 0 326 327 - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3310 tsm_handler 11 10 4 t p P f t "," 0 0 0 3311 3312 - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 269 table_am_handler 11 10 4 t p P f t "," 0 0 0 267 268 - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3831 anyrange 11 10 -1 f p P f t "," 0 0 0 3832 3833 - - - - - d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 5077 anycompatible 11 10 4 t p P f t "," 0 0 0 5086 5087 - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 5078 anycompatiblearray 11 10 -1 f p P f t "," 0 0 0 5088 5089 5090 5091 - - - d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 5079 anycompatiblenonarray 11 10 4 t p P f t "," 0 0 0 5092 5093 - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 5080 anycompatiblerange 11 10 -1 f p P f t "," 0 0 0 5094 5095 - - - - - d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1000 _bool 11 10 -1 f b A f t "," 0 16 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1001 _bytea 11 10 -1 f b A f t "," 0 17 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1002 _char 11 10 -1 f b A f t "," 0 18 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1003 _name 11 10 -1 f b A f t "," 0 19 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 950 _null_ _null_ _null_ ) +insert ( 1016 _int8 11 10 -1 f b A f t "," 0 20 0 750 751 2400 2401 - - 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1005 _int2 11 10 -1 f b A f t "," 0 21 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1006 _int2vector 11 10 -1 f b A f t "," 0 22 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1007 _int4 11 10 -1 f b A f t "," 0 23 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1008 _regproc 11 10 -1 f b A f t "," 0 24 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1009 _text 11 10 -1 f b A f t "," 0 25 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 100 _null_ _null_ _null_ ) +insert ( 1028 _oid 11 10 -1 f b A f t "," 0 26 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1010 _tid 11 10 -1 f b A f t "," 0 27 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1011 _xid 11 10 -1 f b A f t "," 0 28 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1012 _cid 11 10 -1 f b A f t "," 0 29 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1013 _oidvector 11 10 -1 f b A f t "," 0 30 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 199 _json 11 10 -1 f b A f t "," 0 114 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 143 _xml 11 10 -1 f b A f t "," 0 142 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 271 _xid8 11 10 -1 f b A f t "," 0 5069 0 750 751 2400 2401 - - 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1017 _point 11 10 -1 f b A f t "," 0 600 0 750 751 2400 2401 - - 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1018 _lseg 11 10 -1 f b A f t "," 0 601 0 750 751 2400 2401 - - 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1019 _path 11 10 -1 f b A f t "," 0 602 0 750 751 2400 2401 - - 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1020 _box 11 10 -1 f b A f t ";" 0 603 0 750 751 2400 2401 - - 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1027 _polygon 11 10 -1 f b A f t "," 0 604 0 750 751 2400 2401 - - 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 629 _line 11 10 -1 f b A f t "," 0 628 0 750 751 2400 2401 - - 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1021 _float4 11 10 -1 f b A f t "," 0 700 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1022 _float8 11 10 -1 f b A f t "," 0 701 0 750 751 2400 2401 - - 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 719 _circle 11 10 -1 f b A f t "," 0 718 0 750 751 2400 2401 - - 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 791 _money 11 10 -1 f b A f t "," 0 790 0 750 751 2400 2401 - - 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1040 _macaddr 11 10 -1 f b A f t "," 0 829 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1041 _inet 11 10 -1 f b A f t "," 0 869 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 651 _cidr 11 10 -1 f b A f t "," 0 650 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 775 _macaddr8 11 10 -1 f b A f t "," 0 774 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1034 _aclitem 11 10 -1 f b A f t "," 0 1033 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1014 _bpchar 11 10 -1 f b A f t "," 0 1042 0 750 751 2400 2401 2913 2914 3816 i x f 0 -1 0 100 _null_ _null_ _null_ ) +insert ( 1015 _varchar 11 10 -1 f b A f t "," 0 1043 0 750 751 2400 2401 2915 2916 3816 i x f 0 -1 0 100 _null_ _null_ _null_ ) +insert ( 1182 _date 11 10 -1 f b A f t "," 0 1082 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1183 _time 11 10 -1 f b A f t "," 0 1083 0 750 751 2400 2401 2909 2910 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1115 _timestamp 11 10 -1 f b A f t "," 0 1114 0 750 751 2400 2401 2905 2906 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1185 _timestamptz 11 10 -1 f b A f t "," 0 1184 0 750 751 2400 2401 2907 2908 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1187 _interval 11 10 -1 f b A f t "," 0 1186 0 750 751 2400 2401 2903 2904 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1270 _timetz 11 10 -1 f b A f t "," 0 1266 0 750 751 2400 2401 2911 2912 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1561 _bit 11 10 -1 f b A f t "," 0 1560 0 750 751 2400 2401 2919 2920 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1563 _varbit 11 10 -1 f b A f t "," 0 1562 0 750 751 2400 2401 2902 2921 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1231 _numeric 11 10 -1 f b A f t "," 0 1700 0 750 751 2400 2401 2917 2918 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2201 _refcursor 11 10 -1 f b A f t "," 0 1790 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2207 _regprocedure 11 10 -1 f b A f t "," 0 2202 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2208 _regoper 11 10 -1 f b A f t "," 0 2203 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2209 _regoperator 11 10 -1 f b A f t "," 0 2204 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2210 _regclass 11 10 -1 f b A f t "," 0 2205 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 4192 _regcollation 11 10 -1 f b A f t "," 0 4191 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2211 _regtype 11 10 -1 f b A f t "," 0 2206 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 4097 _regrole 11 10 -1 f b A f t "," 0 4096 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 4090 _regnamespace 11 10 -1 f b A f t "," 0 4089 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2951 _uuid 11 10 -1 f b A f t "," 0 2950 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3221 _pg_lsn 11 10 -1 f b A f t "," 0 3220 0 750 751 2400 2401 - - 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3643 _tsvector 11 10 -1 f b A f t "," 0 3614 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3644 _gtsvector 11 10 -1 f b A f t "," 0 3642 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3645 _tsquery 11 10 -1 f b A f t "," 0 3615 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3735 _regconfig 11 10 -1 f b A f t "," 0 3734 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3770 _regdictionary 11 10 -1 f b A f t "," 0 3769 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3807 _jsonb 11 10 -1 f b A f t "," 0 3802 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 4073 _jsonpath 11 10 -1 f b A f t "," 0 4072 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 2949 _txid_snapshot 11 10 -1 f b A f t "," 0 2970 0 750 751 2400 2401 - - 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 5039 _pg_snapshot 11 10 -1 f b A f t "," 0 5038 0 750 751 2400 2401 - - 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3905 _int4range 11 10 -1 f b A f t "," 0 3904 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3907 _numrange 11 10 -1 f b A f t "," 0 3906 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3909 _tsrange 11 10 -1 f b A f t "," 0 3908 0 750 751 2400 2401 - - 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3911 _tstzrange 11 10 -1 f b A f t "," 0 3910 0 750 751 2400 2401 - - 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3913 _daterange 11 10 -1 f b A f t "," 0 3912 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 3927 _int8range 11 10 -1 f b A f t "," 0 3926 0 750 751 2400 2401 - - 3816 d x f 0 -1 0 0 _null_ _null_ _null_ ) +insert ( 1263 _cstring 11 10 -1 f b A f t "," 0 2275 0 750 751 2400 2401 - - 3816 i x f 0 -1 0 0 _null_ _null_ _null_ ) +close pg_type +create pg_attribute 1249 bootstrap rowtype_oid 75 + ( + attrelid = oid , + attname = name , + atttypid = oid , + attstattarget = int4 , + attlen = int2 , + attnum = int2 , + attndims = int4 , + attcacheoff = int4 , + atttypmod = int4 , + attbyval = bool , + attstorage = char , + attalign = char , + attnotnull = bool , + atthasdef = bool , + atthasmissing = bool , + attidentity = char , + attgenerated = char , + attisdropped = bool , + attislocal = bool , + attinhcount = int4 , + attcollation = oid , + attacl = _aclitem , + attoptions = _text , + attfdwoptions = _text , + attmissingval = anyarray + ) +insert ( 1255 oid 26 -1 4 1 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 proname 19 -1 NAMEDATALEN 2 0 -1 -1 f p c t f f "" "" f t 0 950 _null_ _null_ _null_ _null_ ) +insert ( 1255 pronamespace 26 -1 4 3 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 proowner 26 -1 4 4 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 prolang 26 -1 4 5 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 procost 700 -1 4 6 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 prorows 700 -1 4 7 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 provariadic 26 -1 4 8 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 prosupport 24 -1 4 9 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 prokind 18 -1 1 10 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 prosecdef 16 -1 1 11 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 proleakproof 16 -1 1 12 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 proisstrict 16 -1 1 13 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 proretset 16 -1 1 14 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 provolatile 18 -1 1 15 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 proparallel 18 -1 1 16 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 pronargs 21 -1 2 17 0 -1 -1 t p s t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 pronargdefaults 21 -1 2 18 0 -1 -1 t p s t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 prorettype 26 -1 4 19 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 proargtypes 30 -1 -1 20 1 -1 -1 f p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 proallargtypes 1028 -1 -1 21 1 -1 -1 f x i f f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 proargmodes 1002 -1 -1 22 1 -1 -1 f x i f f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 proargnames 1009 -1 -1 23 1 -1 -1 f x i f f f "" "" f t 0 950 _null_ _null_ _null_ _null_ ) +insert ( 1255 proargdefaults 194 -1 -1 24 0 -1 -1 f x i f f f "" "" f t 0 950 _null_ _null_ _null_ _null_ ) +insert ( 1255 protrftypes 1028 -1 -1 25 1 -1 -1 f x i f f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 prosrc 25 -1 -1 26 0 -1 -1 f x i t f f "" "" f t 0 950 _null_ _null_ _null_ _null_ ) +insert ( 1255 probin 25 -1 -1 27 0 -1 -1 f x i f f f "" "" f t 0 950 _null_ _null_ _null_ _null_ ) +insert ( 1255 proconfig 1009 -1 -1 28 1 -1 -1 f x i f f f "" "" f t 0 950 _null_ _null_ _null_ _null_ ) +insert ( 1255 proacl 1034 -1 -1 29 1 -1 -1 f x i f f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 ctid 27 0 6 -1 0 -1 -1 f p s t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 xmin 28 0 4 -2 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 cmin 29 0 4 -3 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 xmax 28 0 4 -4 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 cmax 29 0 4 -5 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1255 tableoid 26 0 4 -6 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 oid 26 -1 4 1 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typname 19 -1 NAMEDATALEN 2 0 -1 -1 f p c t f f "" "" f t 0 950 _null_ _null_ _null_ _null_ ) +insert ( 1247 typnamespace 26 -1 4 3 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typowner 26 -1 4 4 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typlen 21 -1 2 5 0 -1 -1 t p s t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typbyval 16 -1 1 6 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typtype 18 -1 1 7 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typcategory 18 -1 1 8 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typispreferred 16 -1 1 9 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typisdefined 16 -1 1 10 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typdelim 18 -1 1 11 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typrelid 26 -1 4 12 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typelem 26 -1 4 13 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typarray 26 -1 4 14 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typinput 24 -1 4 15 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typoutput 24 -1 4 16 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typreceive 24 -1 4 17 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typsend 24 -1 4 18 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typmodin 24 -1 4 19 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typmodout 24 -1 4 20 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typanalyze 24 -1 4 21 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typalign 18 -1 1 22 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typstorage 18 -1 1 23 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typnotnull 16 -1 1 24 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typbasetype 26 -1 4 25 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typtypmod 23 -1 4 26 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typndims 23 -1 4 27 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typcollation 26 -1 4 28 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 typdefaultbin 194 -1 -1 29 0 -1 -1 f x i f f f "" "" f t 0 950 _null_ _null_ _null_ _null_ ) +insert ( 1247 typdefault 25 -1 -1 30 0 -1 -1 f x i f f f "" "" f t 0 950 _null_ _null_ _null_ _null_ ) +insert ( 1247 typacl 1034 -1 -1 31 1 -1 -1 f x i f f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 ctid 27 0 6 -1 0 -1 -1 f p s t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 xmin 28 0 4 -2 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 cmin 29 0 4 -3 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 xmax 28 0 4 -4 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 cmax 29 0 4 -5 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1247 tableoid 26 0 4 -6 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 attrelid 26 -1 4 1 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 attname 19 -1 NAMEDATALEN 2 0 -1 -1 f p c t f f "" "" f t 0 950 _null_ _null_ _null_ _null_ ) +insert ( 1249 atttypid 26 -1 4 3 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 attstattarget 23 -1 4 4 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 attlen 21 -1 2 5 0 -1 -1 t p s t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 attnum 21 -1 2 6 0 -1 -1 t p s t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 attndims 23 -1 4 7 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 attcacheoff 23 -1 4 8 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 atttypmod 23 -1 4 9 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 attbyval 16 -1 1 10 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 attstorage 18 -1 1 11 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 attalign 18 -1 1 12 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 attnotnull 16 -1 1 13 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 atthasdef 16 -1 1 14 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 atthasmissing 16 -1 1 15 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 attidentity 18 -1 1 16 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 attgenerated 18 -1 1 17 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 attisdropped 16 -1 1 18 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 attislocal 16 -1 1 19 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 attinhcount 23 -1 4 20 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 attcollation 26 -1 4 21 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 attacl 1034 -1 -1 22 1 -1 -1 f x i f f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 attoptions 1009 -1 -1 23 1 -1 -1 f x i f f f "" "" f t 0 950 _null_ _null_ _null_ _null_ ) +insert ( 1249 attfdwoptions 1009 -1 -1 24 1 -1 -1 f x i f f f "" "" f t 0 950 _null_ _null_ _null_ _null_ ) +insert ( 1249 attmissingval 2277 -1 -1 25 0 -1 -1 f x d f f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 ctid 27 0 6 -1 0 -1 -1 f p s t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 xmin 28 0 4 -2 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 cmin 29 0 4 -3 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 xmax 28 0 4 -4 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 cmax 29 0 4 -5 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1249 tableoid 26 0 4 -6 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 oid 26 -1 4 1 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relname 19 -1 NAMEDATALEN 2 0 -1 -1 f p c t f f "" "" f t 0 950 _null_ _null_ _null_ _null_ ) +insert ( 1259 relnamespace 26 -1 4 3 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 reltype 26 -1 4 4 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 reloftype 26 -1 4 5 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relowner 26 -1 4 6 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relam 26 -1 4 7 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relfilenode 26 -1 4 8 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 reltablespace 26 -1 4 9 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relpages 23 -1 4 10 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 reltuples 700 -1 4 11 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relallvisible 23 -1 4 12 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 reltoastrelid 26 -1 4 13 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relhasindex 16 -1 1 14 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relisshared 16 -1 1 15 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relpersistence 18 -1 1 16 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relkind 18 -1 1 17 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relnatts 21 -1 2 18 0 -1 -1 t p s t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relchecks 21 -1 2 19 0 -1 -1 t p s t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relhasrules 16 -1 1 20 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relhastriggers 16 -1 1 21 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relhassubclass 16 -1 1 22 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relrowsecurity 16 -1 1 23 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relforcerowsecurity 16 -1 1 24 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relispopulated 16 -1 1 25 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relreplident 18 -1 1 26 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relispartition 16 -1 1 27 0 -1 -1 t p c t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relrewrite 26 -1 4 28 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relfrozenxid 28 -1 4 29 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relminmxid 28 -1 4 30 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 relacl 1034 -1 -1 31 1 -1 -1 f x i f f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 reloptions 1009 -1 -1 32 1 -1 -1 f x i f f f "" "" f t 0 950 _null_ _null_ _null_ _null_ ) +insert ( 1259 relpartbound 194 -1 -1 33 0 -1 -1 f x i f f f "" "" f t 0 950 _null_ _null_ _null_ _null_ ) +insert ( 1259 ctid 27 0 6 -1 0 -1 -1 f p s t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 xmin 28 0 4 -2 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 cmin 29 0 4 -3 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 xmax 28 0 4 -4 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 cmax 29 0 4 -5 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +insert ( 1259 tableoid 26 0 4 -6 0 -1 -1 t p i t f f "" "" f t 0 0 _null_ _null_ _null_ _null_ ) +close pg_attribute +create pg_class 1259 bootstrap rowtype_oid 83 + ( + oid = oid , + relname = name , + relnamespace = oid , + reltype = oid , + reloftype = oid , + relowner = oid , + relam = oid , + relfilenode = oid , + reltablespace = oid , + relpages = int4 , + reltuples = float4 , + relallvisible = int4 , + reltoastrelid = oid , + relhasindex = bool , + relisshared = bool , + relpersistence = char , + relkind = char , + relnatts = int2 , + relchecks = int2 , + relhasrules = bool , + relhastriggers = bool , + relhassubclass = bool , + relrowsecurity = bool , + relforcerowsecurity = bool , + relispopulated = bool , + relreplident = char , + relispartition = bool , + relrewrite = oid , + relfrozenxid = xid , + relminmxid = xid , + relacl = _aclitem , + reloptions = _text , + relpartbound = pg_node_tree + ) +insert ( 1247 pg_type 11 71 0 10 2 0 0 0 0 0 0 f f p r 31 0 f f f f f t n f 0 3 1 _null_ _null_ _null_ ) +insert ( 1249 pg_attribute 11 75 0 10 2 0 0 0 0 0 0 f f p r 25 0 f f f f f t n f 0 3 1 _null_ _null_ _null_ ) +insert ( 1255 pg_proc 11 81 0 10 2 0 0 0 0 0 0 f f p r 29 0 f f f f f t n f 0 3 1 _null_ _null_ _null_ ) +insert ( 1259 pg_class 11 83 0 10 2 0 0 0 0 0 0 f f p r 33 0 f f f f f t n f 0 3 1 _null_ _null_ _null_ ) +close pg_class +create pg_attrdef 2604 + ( + oid = oid , + adrelid = oid , + adnum = int2 , + adbin = pg_node_tree FORCE NOT NULL + ) +open pg_attrdef +close pg_attrdef +create pg_constraint 2606 + ( + oid = oid , + conname = name , + connamespace = oid , + contype = char , + condeferrable = bool , + condeferred = bool , + convalidated = bool , + conrelid = oid , + contypid = oid , + conindid = oid , + conparentid = oid , + confrelid = oid , + confupdtype = char , + confdeltype = char , + confmatchtype = char , + conislocal = bool , + coninhcount = int4 , + connoinherit = bool , + conkey = _int2 , + confkey = _int2 , + conpfeqop = _oid , + conppeqop = _oid , + conffeqop = _oid , + conexclop = _oid , + conbin = pg_node_tree + ) +open pg_constraint +close pg_constraint +create pg_inherits 2611 + ( + inhrelid = oid , + inhparent = oid , + inhseqno = int4 + ) +open pg_inherits +close pg_inherits +create pg_index 2610 + ( + indexrelid = oid , + indrelid = oid , + indnatts = int2 , + indnkeyatts = int2 , + indisunique = bool , + indisprimary = bool , + indisexclusion = bool , + indimmediate = bool , + indisclustered = bool , + indisvalid = bool , + indcheckxmin = bool , + indisready = bool , + indislive = bool , + indisreplident = bool , + indkey = int2vector , + indcollation = oidvector , + indclass = oidvector , + indoption = int2vector , + indexprs = pg_node_tree , + indpred = pg_node_tree + ) +open pg_index +close pg_index +create pg_operator 2617 + ( + oid = oid , + oprname = name , + oprnamespace = oid , + oprowner = oid , + oprkind = char , + oprcanmerge = bool , + oprcanhash = bool , + oprleft = oid , + oprright = oid , + oprresult = oid , + oprcom = oid , + oprnegate = oid , + oprcode = regproc , + oprrest = regproc , + oprjoin = regproc + ) +open pg_operator +insert ( 15 "=" 11 10 b t t 23 20 16 416 36 852 101 105 ) +insert ( 36 "<>" 11 10 b f f 23 20 16 417 15 853 102 106 ) +insert ( 37 "<" 11 10 b f f 23 20 16 419 82 854 103 107 ) +insert ( 76 ">" 11 10 b f f 23 20 16 418 80 855 104 108 ) +insert ( 80 "<=" 11 10 b f f 23 20 16 430 76 856 336 386 ) +insert ( 82 ">=" 11 10 b f f 23 20 16 420 37 857 337 398 ) +insert ( 58 "<" 11 10 b f f 16 16 16 59 1695 56 103 107 ) +insert ( 59 ">" 11 10 b f f 16 16 16 58 1694 57 104 108 ) +insert ( 85 "<>" 11 10 b f f 16 16 16 85 91 84 102 106 ) +insert ( 91 "=" 11 10 b t t 16 16 16 91 85 60 101 105 ) +insert ( 1694 "<=" 11 10 b f f 16 16 16 1695 59 1691 336 386 ) +insert ( 1695 ">=" 11 10 b f f 16 16 16 1694 58 1692 337 398 ) +insert ( 92 "=" 11 10 b t t 18 18 16 92 630 61 101 105 ) +insert ( 93 "=" 11 10 b t t 19 19 16 93 643 62 101 105 ) +insert ( 94 "=" 11 10 b t t 21 21 16 94 519 63 101 105 ) +insert ( 95 "<" 11 10 b f f 21 21 16 520 524 64 103 107 ) +insert ( 96 "=" 11 10 b t t 23 23 16 96 518 65 101 105 ) +insert ( 97 "<" 11 10 b f f 23 23 16 521 525 66 103 107 ) +insert ( 98 "=" 11 10 b t t 25 25 16 98 531 67 101 105 ) +insert ( 3877 "^@" 11 10 b f f 25 25 16 0 0 3696 3437 3438 ) +insert ( 254 "=" 11 10 b t t 19 25 16 260 259 240 101 105 ) +insert ( 255 "<" 11 10 b f f 19 25 16 264 257 241 103 107 ) +insert ( 256 "<=" 11 10 b f f 19 25 16 263 258 242 336 386 ) +insert ( 257 ">=" 11 10 b f f 19 25 16 262 255 243 337 398 ) +insert ( 258 ">" 11 10 b f f 19 25 16 261 256 244 104 108 ) +insert ( 259 "<>" 11 10 b f f 19 25 16 265 254 245 102 106 ) +insert ( 260 "=" 11 10 b t t 25 19 16 254 265 247 101 105 ) +insert ( 261 "<" 11 10 b f f 25 19 16 258 263 248 103 107 ) +insert ( 262 "<=" 11 10 b f f 25 19 16 257 264 249 336 386 ) +insert ( 263 ">=" 11 10 b f f 25 19 16 256 261 250 337 398 ) +insert ( 264 ">" 11 10 b f f 25 19 16 255 262 251 104 108 ) +insert ( 265 "<>" 11 10 b f f 25 19 16 259 260 252 102 106 ) +insert ( 349 "||" 11 10 b f f 2277 2283 2277 0 0 378 - - ) +insert ( 374 "||" 11 10 b f f 2283 2277 2277 0 0 379 - - ) +insert ( 375 "||" 11 10 b f f 2277 2277 2277 0 0 383 - - ) +insert ( 352 "=" 11 10 b f t 28 28 16 352 3315 68 101 105 ) +insert ( 353 "=" 11 10 b f f 28 23 16 0 3316 1319 101 105 ) +insert ( 3315 "<>" 11 10 b f f 28 28 16 3315 352 3308 102 106 ) +insert ( 3316 "<>" 11 10 b f f 28 23 16 0 353 3309 102 106 ) +insert ( 5068 "=" 11 10 b t t 5069 5069 16 5068 5072 5084 101 105 ) +insert ( 5072 "<>" 11 10 b f f 5069 5069 16 5072 5068 5085 102 106 ) +insert ( 5073 "<" 11 10 b f f 5069 5069 16 5074 5076 5034 103 107 ) +insert ( 5074 ">" 11 10 b f f 5069 5069 16 5073 5075 5035 104 108 ) +insert ( 5075 "<=" 11 10 b f f 5069 5069 16 5076 5074 5036 336 386 ) +insert ( 5076 ">=" 11 10 b f f 5069 5069 16 5075 5073 5037 337 398 ) +insert ( 388 "!" 11 10 r f f 20 0 1700 0 0 111 - - ) +insert ( 389 "!!" 11 10 l f f 0 20 1700 0 0 111 - - ) +insert ( 385 "=" 11 10 b f t 29 29 16 385 0 69 101 105 ) +insert ( 387 "=" 11 10 b t t 27 27 16 387 402 1292 101 105 ) +insert ( 402 "<>" 11 10 b f f 27 27 16 402 387 1265 102 106 ) +insert ( 2799 "<" 11 10 b f f 27 27 16 2800 2802 2791 103 107 ) +insert ( 2800 ">" 11 10 b f f 27 27 16 2799 2801 2790 104 108 ) +insert ( 2801 "<=" 11 10 b f f 27 27 16 2802 2800 2793 336 386 ) +insert ( 2802 ">=" 11 10 b f f 27 27 16 2801 2799 2792 337 398 ) +insert ( 410 "=" 11 10 b t t 20 20 16 410 411 467 101 105 ) +insert ( 411 "<>" 11 10 b f f 20 20 16 411 410 468 102 106 ) +insert ( 412 "<" 11 10 b f f 20 20 16 413 415 469 103 107 ) +insert ( 413 ">" 11 10 b f f 20 20 16 412 414 470 104 108 ) +insert ( 414 "<=" 11 10 b f f 20 20 16 415 413 471 336 386 ) +insert ( 415 ">=" 11 10 b f f 20 20 16 414 412 472 337 398 ) +insert ( 416 "=" 11 10 b t t 20 23 16 15 417 474 101 105 ) +insert ( 417 "<>" 11 10 b f f 20 23 16 36 416 475 102 106 ) +insert ( 418 "<" 11 10 b f f 20 23 16 76 430 476 103 107 ) +insert ( 419 ">" 11 10 b f f 20 23 16 37 420 477 104 108 ) +insert ( 420 "<=" 11 10 b f f 20 23 16 82 419 478 336 386 ) +insert ( 430 ">=" 11 10 b f f 20 23 16 80 418 479 337 398 ) +insert ( 439 "%" 11 10 b f f 20 20 20 0 0 945 - - ) +insert ( 473 "@" 11 10 l f f 0 20 20 0 0 1230 - - ) +insert ( 484 - 11 10 l f f 0 20 20 0 0 462 - - ) +insert ( 485 "<<" 11 10 b f f 604 604 16 0 0 341 1300 1301 ) +insert ( 486 "&<" 11 10 b f f 604 604 16 0 0 342 1300 1301 ) +insert ( 487 "&>" 11 10 b f f 604 604 16 0 0 343 1300 1301 ) +insert ( 488 ">>" 11 10 b f f 604 604 16 0 0 344 1300 1301 ) +insert ( 489 "<@" 11 10 b f f 604 604 16 490 0 345 1302 1303 ) +insert ( 490 "@>" 11 10 b f f 604 604 16 489 0 340 1302 1303 ) +insert ( 491 "~=" 11 10 b f f 604 604 16 491 0 339 101 105 ) +insert ( 492 "&&" 11 10 b f f 604 604 16 492 0 346 139 140 ) +insert ( 493 "<<" 11 10 b f f 603 603 16 0 0 188 1300 1301 ) +insert ( 494 "&<" 11 10 b f f 603 603 16 0 0 189 1300 1301 ) +insert ( 495 "&>" 11 10 b f f 603 603 16 0 0 190 1300 1301 ) +insert ( 496 ">>" 11 10 b f f 603 603 16 0 0 191 1300 1301 ) +insert ( 497 "<@" 11 10 b f f 603 603 16 498 0 192 1302 1303 ) +insert ( 498 "@>" 11 10 b f f 603 603 16 497 0 187 1302 1303 ) +insert ( 499 "~=" 11 10 b f f 603 603 16 499 0 186 101 105 ) +insert ( 500 "&&" 11 10 b f f 603 603 16 500 0 125 139 140 ) +insert ( 501 ">=" 11 10 b f f 603 603 16 505 504 126 139 140 ) +insert ( 502 ">" 11 10 b f f 603 603 16 504 505 127 139 140 ) +insert ( 503 "=" 11 10 b f f 603 603 16 503 0 128 101 105 ) +insert ( 504 "<" 11 10 b f f 603 603 16 502 501 129 139 140 ) +insert ( 505 "<=" 11 10 b f f 603 603 16 501 502 130 139 140 ) +insert ( 506 ">^" 11 10 b f f 600 600 16 0 0 131 1300 1301 ) +insert ( 507 "<<" 11 10 b f f 600 600 16 0 0 132 1300 1301 ) +insert ( 508 ">>" 11 10 b f f 600 600 16 0 0 133 1300 1301 ) +insert ( 509 "<^" 11 10 b f f 600 600 16 0 0 134 1300 1301 ) +insert ( 510 "~=" 11 10 b f f 600 600 16 510 713 135 101 105 ) +insert ( 511 "<@" 11 10 b f f 600 603 16 433 0 136 1302 1303 ) +insert ( 433 "@>" 11 10 b f f 603 600 16 511 0 193 1302 1303 ) +insert ( 512 "<@" 11 10 b f f 600 602 16 755 0 137 - - ) +insert ( 513 "@@" 11 10 l f f 0 603 600 0 0 138 - - ) +insert ( 514 "*" 11 10 b f f 23 23 23 514 0 141 - - ) +insert ( 517 "<->" 11 10 b f f 600 600 701 517 0 991 - - ) +insert ( 518 "<>" 11 10 b f f 23 23 16 518 96 144 102 106 ) +insert ( 519 "<>" 11 10 b f f 21 21 16 519 94 145 102 106 ) +insert ( 520 ">" 11 10 b f f 21 21 16 95 522 146 104 108 ) +insert ( 521 ">" 11 10 b f f 23 23 16 97 523 147 104 108 ) +insert ( 522 "<=" 11 10 b f f 21 21 16 524 520 148 336 386 ) +insert ( 523 "<=" 11 10 b f f 23 23 16 525 521 149 336 386 ) +insert ( 524 ">=" 11 10 b f f 21 21 16 522 95 151 337 398 ) +insert ( 525 ">=" 11 10 b f f 23 23 16 523 97 150 337 398 ) +insert ( 526 "*" 11 10 b f f 21 21 21 526 0 152 - - ) +insert ( 527 "/" 11 10 b f f 21 21 21 0 0 153 - - ) +insert ( 528 "/" 11 10 b f f 23 23 23 0 0 154 - - ) +insert ( 529 "%" 11 10 b f f 21 21 21 0 0 155 - - ) +insert ( 530 "%" 11 10 b f f 23 23 23 0 0 156 - - ) +insert ( 531 "<>" 11 10 b f f 25 25 16 531 98 157 102 106 ) +insert ( 532 "=" 11 10 b t t 21 23 16 533 538 158 101 105 ) +insert ( 533 "=" 11 10 b t t 23 21 16 532 539 159 101 105 ) +insert ( 534 "<" 11 10 b f f 21 23 16 537 542 160 103 107 ) +insert ( 535 "<" 11 10 b f f 23 21 16 536 543 161 103 107 ) +insert ( 536 ">" 11 10 b f f 21 23 16 535 540 162 104 108 ) +insert ( 537 ">" 11 10 b f f 23 21 16 534 541 163 104 108 ) +insert ( 538 "<>" 11 10 b f f 21 23 16 539 532 164 102 106 ) +insert ( 539 "<>" 11 10 b f f 23 21 16 538 533 165 102 106 ) +insert ( 540 "<=" 11 10 b f f 21 23 16 543 536 166 336 386 ) +insert ( 541 "<=" 11 10 b f f 23 21 16 542 537 167 336 386 ) +insert ( 542 ">=" 11 10 b f f 21 23 16 541 534 168 337 398 ) +insert ( 543 ">=" 11 10 b f f 23 21 16 540 535 169 337 398 ) +insert ( 544 "*" 11 10 b f f 21 23 23 545 0 170 - - ) +insert ( 545 "*" 11 10 b f f 23 21 23 544 0 171 - - ) +insert ( 546 "/" 11 10 b f f 21 23 23 0 0 172 - - ) +insert ( 547 "/" 11 10 b f f 23 21 23 0 0 173 - - ) +insert ( 550 "+" 11 10 b f f 21 21 21 550 0 176 - - ) +insert ( 551 "+" 11 10 b f f 23 23 23 551 0 177 - - ) +insert ( 552 "+" 11 10 b f f 21 23 23 553 0 178 - - ) +insert ( 553 "+" 11 10 b f f 23 21 23 552 0 179 - - ) +insert ( 554 - 11 10 b f f 21 21 21 0 0 180 - - ) +insert ( 555 - 11 10 b f f 23 23 23 0 0 181 - - ) +insert ( 556 - 11 10 b f f 21 23 23 0 0 182 - - ) +insert ( 557 - 11 10 b f f 23 21 23 0 0 183 - - ) +insert ( 558 - 11 10 l f f 0 23 23 0 0 212 - - ) +insert ( 559 - 11 10 l f f 0 21 21 0 0 213 - - ) +insert ( 584 - 11 10 l f f 0 700 700 0 0 206 - - ) +insert ( 585 - 11 10 l f f 0 701 701 0 0 220 - - ) +insert ( 586 "+" 11 10 b f f 700 700 700 586 0 204 - - ) +insert ( 587 - 11 10 b f f 700 700 700 0 0 205 - - ) +insert ( 588 "/" 11 10 b f f 700 700 700 0 0 203 - - ) +insert ( 589 "*" 11 10 b f f 700 700 700 589 0 202 - - ) +insert ( 590 "@" 11 10 l f f 0 700 700 0 0 207 - - ) +insert ( 591 "+" 11 10 b f f 701 701 701 591 0 218 - - ) +insert ( 592 - 11 10 b f f 701 701 701 0 0 219 - - ) +insert ( 593 "/" 11 10 b f f 701 701 701 0 0 217 - - ) +insert ( 594 "*" 11 10 b f f 701 701 701 594 0 216 - - ) +insert ( 595 "@" 11 10 l f f 0 701 701 0 0 221 - - ) +insert ( 596 "|/" 11 10 l f f 0 701 701 0 0 230 - - ) +insert ( 597 "||/" 11 10 l f f 0 701 701 0 0 231 - - ) +insert ( 607 "=" 11 10 b t t 26 26 16 607 608 184 101 105 ) +insert ( 608 "<>" 11 10 b f f 26 26 16 608 607 185 102 106 ) +insert ( 609 "<" 11 10 b f f 26 26 16 610 612 716 103 107 ) +insert ( 610 ">" 11 10 b f f 26 26 16 609 611 1638 104 108 ) +insert ( 611 "<=" 11 10 b f f 26 26 16 612 610 717 336 386 ) +insert ( 612 ">=" 11 10 b f f 26 26 16 611 609 1639 337 398 ) +insert ( 644 "<>" 11 10 b f f 30 30 16 644 649 619 102 106 ) +insert ( 645 "<" 11 10 b f f 30 30 16 646 648 677 103 107 ) +insert ( 646 ">" 11 10 b f f 30 30 16 645 647 681 104 108 ) +insert ( 647 "<=" 11 10 b f f 30 30 16 648 646 678 336 386 ) +insert ( 648 ">=" 11 10 b f f 30 30 16 647 645 680 337 398 ) +insert ( 649 "=" 11 10 b t t 30 30 16 649 644 679 101 105 ) +insert ( 613 "<->" 11 10 b f f 600 628 701 760 0 725 - - ) +insert ( 760 "<->" 11 10 b f f 628 600 701 613 0 702 - - ) +insert ( 614 "<->" 11 10 b f f 600 601 701 761 0 363 - - ) +insert ( 761 "<->" 11 10 b f f 601 600 701 614 0 380 - - ) +insert ( 615 "<->" 11 10 b f f 600 603 701 606 0 364 - - ) +insert ( 606 "<->" 11 10 b f f 603 600 701 615 0 357 - - ) +insert ( 616 "<->" 11 10 b f f 601 628 701 762 0 727 - - ) +insert ( 762 "<->" 11 10 b f f 628 601 701 616 0 704 - - ) +insert ( 617 "<->" 11 10 b f f 601 603 701 763 0 365 - - ) +insert ( 763 "<->" 11 10 b f f 603 601 701 617 0 381 - - ) +insert ( 618 "<->" 11 10 b f f 600 602 701 784 0 371 - - ) +insert ( 784 "<->" 11 10 b f f 602 600 701 618 0 421 - - ) +insert ( 620 "=" 11 10 b t t 700 700 16 620 621 287 101 105 ) +insert ( 621 "<>" 11 10 b f f 700 700 16 621 620 288 102 106 ) +insert ( 622 "<" 11 10 b f f 700 700 16 623 625 289 103 107 ) +insert ( 623 ">" 11 10 b f f 700 700 16 622 624 291 104 108 ) +insert ( 624 "<=" 11 10 b f f 700 700 16 625 623 290 336 386 ) +insert ( 625 ">=" 11 10 b f f 700 700 16 624 622 292 337 398 ) +insert ( 630 "<>" 11 10 b f f 18 18 16 630 92 70 102 106 ) +insert ( 631 "<" 11 10 b f f 18 18 16 633 634 1246 103 107 ) +insert ( 632 "<=" 11 10 b f f 18 18 16 634 633 72 336 386 ) +insert ( 633 ">" 11 10 b f f 18 18 16 631 632 73 104 108 ) +insert ( 634 ">=" 11 10 b f f 18 18 16 632 631 74 337 398 ) +insert ( 639 "~" 11 10 b f f 19 25 16 0 640 79 1818 1824 ) +insert ( 640 "!~" 11 10 b f f 19 25 16 0 639 1252 1821 1827 ) +insert ( 641 "~" 11 10 b f f 25 25 16 0 642 1254 1818 1824 ) +insert ( 642 "!~" 11 10 b f f 25 25 16 0 641 1256 1821 1827 ) +insert ( 643 "<>" 11 10 b f f 19 19 16 643 93 659 102 106 ) +insert ( 654 "||" 11 10 b f f 25 25 25 0 0 1258 - - ) +insert ( 660 "<" 11 10 b f f 19 19 16 662 663 655 103 107 ) +insert ( 661 "<=" 11 10 b f f 19 19 16 663 662 656 336 386 ) +insert ( 662 ">" 11 10 b f f 19 19 16 660 661 657 104 108 ) +insert ( 663 ">=" 11 10 b f f 19 19 16 661 660 658 337 398 ) +insert ( 664 "<" 11 10 b f f 25 25 16 666 667 740 103 107 ) +insert ( 665 "<=" 11 10 b f f 25 25 16 667 666 741 336 386 ) +insert ( 666 ">" 11 10 b f f 25 25 16 664 665 742 104 108 ) +insert ( 667 ">=" 11 10 b f f 25 25 16 665 664 743 337 398 ) +insert ( 670 "=" 11 10 b t t 701 701 16 670 671 293 101 105 ) +insert ( 671 "<>" 11 10 b f f 701 701 16 671 670 294 102 106 ) +insert ( 672 "<" 11 10 b f f 701 701 16 674 675 295 103 107 ) +insert ( 673 "<=" 11 10 b f f 701 701 16 675 674 296 336 386 ) +insert ( 674 ">" 11 10 b f f 701 701 16 672 673 297 104 108 ) +insert ( 675 ">=" 11 10 b f f 701 701 16 673 672 298 337 398 ) +insert ( 682 "@" 11 10 l f f 0 21 21 0 0 1253 - - ) +insert ( 684 "+" 11 10 b f f 20 20 20 684 0 463 - - ) +insert ( 685 - 11 10 b f f 20 20 20 0 0 464 - - ) +insert ( 686 "*" 11 10 b f f 20 20 20 686 0 465 - - ) +insert ( 687 "/" 11 10 b f f 20 20 20 0 0 466 - - ) +insert ( 688 "+" 11 10 b f f 20 23 20 692 0 1274 - - ) +insert ( 689 - 11 10 b f f 20 23 20 0 0 1275 - - ) +insert ( 690 "*" 11 10 b f f 20 23 20 694 0 1276 - - ) +insert ( 691 "/" 11 10 b f f 20 23 20 0 0 1277 - - ) +insert ( 692 "+" 11 10 b f f 23 20 20 688 0 1278 - - ) +insert ( 693 - 11 10 b f f 23 20 20 0 0 1279 - - ) +insert ( 694 "*" 11 10 b f f 23 20 20 690 0 1280 - - ) +insert ( 695 "/" 11 10 b f f 23 20 20 0 0 1281 - - ) +insert ( 818 "+" 11 10 b f f 20 21 20 822 0 837 - - ) +insert ( 819 - 11 10 b f f 20 21 20 0 0 838 - - ) +insert ( 820 "*" 11 10 b f f 20 21 20 824 0 839 - - ) +insert ( 821 "/" 11 10 b f f 20 21 20 0 0 840 - - ) +insert ( 822 "+" 11 10 b f f 21 20 20 818 0 841 - - ) +insert ( 823 - 11 10 b f f 21 20 20 0 0 942 - - ) +insert ( 824 "*" 11 10 b f f 21 20 20 820 0 943 - - ) +insert ( 825 "/" 11 10 b f f 21 20 20 0 0 948 - - ) +insert ( 706 "<->" 11 10 b f f 603 603 701 706 0 978 - - ) +insert ( 707 "<->" 11 10 b f f 602 602 701 707 0 370 - - ) +insert ( 708 "<->" 11 10 b f f 628 628 701 708 0 239 - - ) +insert ( 709 "<->" 11 10 b f f 601 601 701 709 0 361 - - ) +insert ( 712 "<->" 11 10 b f f 604 604 701 712 0 729 - - ) +insert ( 713 "<>" 11 10 b f f 600 600 16 713 510 988 102 106 ) +insert ( 731 "+" 11 10 b f f 600 600 600 731 0 1441 - - ) +insert ( 732 - 11 10 b f f 600 600 600 0 0 1442 - - ) +insert ( 733 "*" 11 10 b f f 600 600 600 733 0 1443 - - ) +insert ( 734 "/" 11 10 b f f 600 600 600 0 0 1444 - - ) +insert ( 735 "+" 11 10 b f f 602 602 602 735 0 1435 - - ) +insert ( 736 "+" 11 10 b f f 602 600 602 0 0 1436 - - ) +insert ( 737 - 11 10 b f f 602 600 602 0 0 1437 - - ) +insert ( 738 "*" 11 10 b f f 602 600 602 0 0 1438 - - ) +insert ( 739 "/" 11 10 b f f 602 600 602 0 0 1439 - - ) +insert ( 755 "@>" 11 10 b f f 602 600 16 512 0 1426 - - ) +insert ( 756 "<@" 11 10 b f f 600 604 16 757 0 1429 1302 1303 ) +insert ( 757 "@>" 11 10 b f f 604 600 16 756 0 1428 1302 1303 ) +insert ( 758 "<@" 11 10 b f f 600 718 16 759 0 1478 1302 1303 ) +insert ( 759 "@>" 11 10 b f f 718 600 16 758 0 1477 1302 1303 ) +insert ( 773 "@" 11 10 l f f 0 23 23 0 0 1251 - - ) +insert ( 792 "=" 11 10 b f f 602 602 16 792 0 984 101 105 ) +insert ( 793 "<" 11 10 b f f 602 602 16 794 0 982 - - ) +insert ( 794 ">" 11 10 b f f 602 602 16 793 0 983 - - ) +insert ( 795 "<=" 11 10 b f f 602 602 16 796 0 985 - - ) +insert ( 796 ">=" 11 10 b f f 602 602 16 795 0 986 - - ) +insert ( 797 "#" 11 10 l f f 0 602 23 0 0 1432 - - ) +insert ( 798 "?#" 11 10 b f f 602 602 16 0 0 973 - - ) +insert ( 799 "@-@" 11 10 l f f 0 602 701 0 0 987 - - ) +insert ( 800 ">^" 11 10 b f f 603 603 16 0 0 115 1300 1301 ) +insert ( 801 "<^" 11 10 b f f 603 603 16 0 0 116 1300 1301 ) +insert ( 802 "?#" 11 10 b f f 603 603 16 0 0 125 139 140 ) +insert ( 803 "#" 11 10 b f f 603 603 603 0 0 980 - - ) +insert ( 804 "+" 11 10 b f f 603 600 603 0 0 1422 - - ) +insert ( 805 - 11 10 b f f 603 600 603 0 0 1423 - - ) +insert ( 806 "*" 11 10 b f f 603 600 603 0 0 1424 - - ) +insert ( 807 "/" 11 10 b f f 603 600 603 0 0 1425 - - ) +insert ( 808 "?-" 11 10 b f f 600 600 16 808 0 990 - - ) +insert ( 809 "?|" 11 10 b f f 600 600 16 809 0 989 - - ) +insert ( 843 "*" 11 10 b f f 790 700 790 845 0 846 - - ) +insert ( 844 "/" 11 10 b f f 790 700 790 0 0 847 - - ) +insert ( 845 "*" 11 10 b f f 700 790 790 843 0 848 - - ) +insert ( 900 "=" 11 10 b t f 790 790 16 900 901 888 101 105 ) +insert ( 901 "<>" 11 10 b f f 790 790 16 901 900 889 102 106 ) +insert ( 902 "<" 11 10 b f f 790 790 16 903 905 890 103 107 ) +insert ( 903 ">" 11 10 b f f 790 790 16 902 904 892 104 108 ) +insert ( 904 "<=" 11 10 b f f 790 790 16 905 903 891 336 386 ) +insert ( 905 ">=" 11 10 b f f 790 790 16 904 902 893 337 398 ) +insert ( 906 "+" 11 10 b f f 790 790 790 906 0 894 - - ) +insert ( 907 - 11 10 b f f 790 790 790 0 0 895 - - ) +insert ( 908 "*" 11 10 b f f 790 701 790 916 0 896 - - ) +insert ( 909 "/" 11 10 b f f 790 701 790 0 0 897 - - ) +insert ( 3346 "*" 11 10 b f f 790 20 790 3349 0 3344 - - ) +insert ( 3347 "/" 11 10 b f f 790 20 790 0 0 3345 - - ) +insert ( 912 "*" 11 10 b f f 790 23 790 917 0 864 - - ) +insert ( 913 "/" 11 10 b f f 790 23 790 0 0 865 - - ) +insert ( 914 "*" 11 10 b f f 790 21 790 918 0 866 - - ) +insert ( 915 "/" 11 10 b f f 790 21 790 0 0 867 - - ) +insert ( 916 "*" 11 10 b f f 701 790 790 908 0 919 - - ) +insert ( 3349 "*" 11 10 b f f 20 790 790 3346 0 3399 - - ) +insert ( 917 "*" 11 10 b f f 23 790 790 912 0 862 - - ) +insert ( 918 "*" 11 10 b f f 21 790 790 914 0 863 - - ) +insert ( 3825 "/" 11 10 b f f 790 790 701 0 0 3822 - - ) +insert ( 965 "^" 11 10 b f f 701 701 701 0 0 232 - - ) +insert ( 966 "+" 11 10 b f f 1034 1033 1034 0 0 1035 - - ) +insert ( 967 - 11 10 b f f 1034 1033 1034 0 0 1036 - - ) +insert ( 968 "@>" 11 10 b f f 1034 1033 16 0 0 1037 - - ) +insert ( 974 "=" 11 10 b f t 1033 1033 16 974 0 1062 101 105 ) +insert ( 969 "@@" 11 10 l f f 0 601 600 0 0 225 - - ) +insert ( 970 "@@" 11 10 l f f 0 602 600 0 0 226 - - ) +insert ( 971 "@@" 11 10 l f f 0 604 600 0 0 227 - - ) +insert ( 1054 "=" 11 10 b t t 1042 1042 16 1054 1057 1048 101 105 ) +insert ( 1055 "~" 11 10 b f f 1042 25 16 0 1056 1658 1818 1824 ) +insert ( 1056 "!~" 11 10 b f f 1042 25 16 0 1055 1659 1821 1827 ) +insert ( 1057 "<>" 11 10 b f f 1042 1042 16 1057 1054 1053 102 106 ) +insert ( 1058 "<" 11 10 b f f 1042 1042 16 1060 1061 1049 103 107 ) +insert ( 1059 "<=" 11 10 b f f 1042 1042 16 1061 1060 1050 336 386 ) +insert ( 1060 ">" 11 10 b f f 1042 1042 16 1058 1059 1051 104 108 ) +insert ( 1061 ">=" 11 10 b f f 1042 1042 16 1059 1058 1052 337 398 ) +insert ( 1070 "=" 11 10 b t t 2277 2277 16 1070 1071 744 101 105 ) +insert ( 1071 "<>" 11 10 b f f 2277 2277 16 1071 1070 390 102 106 ) +insert ( 1072 "<" 11 10 b f f 2277 2277 16 1073 1075 391 103 107 ) +insert ( 1073 ">" 11 10 b f f 2277 2277 16 1072 1074 392 104 108 ) +insert ( 1074 "<=" 11 10 b f f 2277 2277 16 1075 1073 393 336 386 ) +insert ( 1075 ">=" 11 10 b f f 2277 2277 16 1074 1072 396 337 398 ) +insert ( 1076 "+" 11 10 b f f 1082 1186 1114 2551 0 2071 - - ) +insert ( 1077 - 11 10 b f f 1082 1186 1114 0 0 2072 - - ) +insert ( 1093 "=" 11 10 b t t 1082 1082 16 1093 1094 1086 101 105 ) +insert ( 1094 "<>" 11 10 b f f 1082 1082 16 1094 1093 1091 102 106 ) +insert ( 1095 "<" 11 10 b f f 1082 1082 16 1097 1098 1087 103 107 ) +insert ( 1096 "<=" 11 10 b f f 1082 1082 16 1098 1097 1088 336 386 ) +insert ( 1097 ">" 11 10 b f f 1082 1082 16 1095 1096 1089 104 108 ) +insert ( 1098 ">=" 11 10 b f f 1082 1082 16 1096 1095 1090 337 398 ) +insert ( 1099 - 11 10 b f f 1082 1082 23 0 0 1140 - - ) +insert ( 1100 "+" 11 10 b f f 1082 23 1082 2555 0 1141 - - ) +insert ( 1101 - 11 10 b f f 1082 23 1082 0 0 1142 - - ) +insert ( 1108 "=" 11 10 b t t 1083 1083 16 1108 1109 1145 101 105 ) +insert ( 1109 "<>" 11 10 b f f 1083 1083 16 1109 1108 1106 102 106 ) +insert ( 1110 "<" 11 10 b f f 1083 1083 16 1112 1113 1102 103 107 ) +insert ( 1111 "<=" 11 10 b f f 1083 1083 16 1113 1112 1103 336 386 ) +insert ( 1112 ">" 11 10 b f f 1083 1083 16 1110 1111 1104 104 108 ) +insert ( 1113 ">=" 11 10 b f f 1083 1083 16 1111 1110 1105 337 398 ) +insert ( 1550 "=" 11 10 b t t 1266 1266 16 1550 1551 1352 101 105 ) +insert ( 1551 "<>" 11 10 b f f 1266 1266 16 1551 1550 1353 102 106 ) +insert ( 1552 "<" 11 10 b f f 1266 1266 16 1554 1555 1354 103 107 ) +insert ( 1553 "<=" 11 10 b f f 1266 1266 16 1555 1554 1355 336 386 ) +insert ( 1554 ">" 11 10 b f f 1266 1266 16 1552 1553 1357 104 108 ) +insert ( 1555 ">=" 11 10 b f f 1266 1266 16 1553 1552 1356 337 398 ) +insert ( 1116 "+" 11 10 b f f 700 701 701 1126 0 281 - - ) +insert ( 1117 - 11 10 b f f 700 701 701 0 0 282 - - ) +insert ( 1118 "/" 11 10 b f f 700 701 701 0 0 280 - - ) +insert ( 1119 "*" 11 10 b f f 700 701 701 1129 0 279 - - ) +insert ( 1120 "=" 11 10 b t t 700 701 16 1130 1121 299 101 105 ) +insert ( 1121 "<>" 11 10 b f f 700 701 16 1131 1120 300 102 106 ) +insert ( 1122 "<" 11 10 b f f 700 701 16 1133 1125 301 103 107 ) +insert ( 1123 ">" 11 10 b f f 700 701 16 1132 1124 303 104 108 ) +insert ( 1124 "<=" 11 10 b f f 700 701 16 1135 1123 302 336 386 ) +insert ( 1125 ">=" 11 10 b f f 700 701 16 1134 1122 304 337 398 ) +insert ( 1126 "+" 11 10 b f f 701 700 701 1116 0 285 - - ) +insert ( 1127 - 11 10 b f f 701 700 701 0 0 286 - - ) +insert ( 1128 "/" 11 10 b f f 701 700 701 0 0 284 - - ) +insert ( 1129 "*" 11 10 b f f 701 700 701 1119 0 283 - - ) +insert ( 1130 "=" 11 10 b t t 701 700 16 1120 1131 305 101 105 ) +insert ( 1131 "<>" 11 10 b f f 701 700 16 1121 1130 306 102 106 ) +insert ( 1132 "<" 11 10 b f f 701 700 16 1123 1135 307 103 107 ) +insert ( 1133 ">" 11 10 b f f 701 700 16 1122 1134 309 104 108 ) +insert ( 1134 "<=" 11 10 b f f 701 700 16 1125 1133 308 336 386 ) +insert ( 1135 ">=" 11 10 b f f 701 700 16 1124 1132 310 337 398 ) +insert ( 1207 "~~" 11 10 b f f 19 25 16 0 1208 858 1819 1825 ) +insert ( 1208 "!~~" 11 10 b f f 19 25 16 0 1207 859 1822 1828 ) +insert ( 1209 "~~" 11 10 b f f 25 25 16 0 1210 850 1819 1825 ) +insert ( 1210 "!~~" 11 10 b f f 25 25 16 0 1209 851 1822 1828 ) +insert ( 1211 "~~" 11 10 b f f 1042 25 16 0 1212 1631 1819 1825 ) +insert ( 1212 "!~~" 11 10 b f f 1042 25 16 0 1211 1632 1822 1828 ) +insert ( 1226 "~*" 11 10 b f f 19 25 16 0 1227 1240 1820 1826 ) +insert ( 1227 "!~*" 11 10 b f f 19 25 16 0 1226 1241 1823 1829 ) +insert ( 1228 "~*" 11 10 b f f 25 25 16 0 1229 1238 1820 1826 ) +insert ( 1229 "!~*" 11 10 b f f 25 25 16 0 1228 1239 1823 1829 ) +insert ( 1234 "~*" 11 10 b f f 1042 25 16 0 1235 1656 1820 1826 ) +insert ( 1235 "!~*" 11 10 b f f 1042 25 16 0 1234 1657 1823 1829 ) +insert ( 1320 "=" 11 10 b t t 1184 1184 16 1320 1321 1152 101 105 ) +insert ( 1321 "<>" 11 10 b f f 1184 1184 16 1321 1320 1153 102 106 ) +insert ( 1322 "<" 11 10 b f f 1184 1184 16 1324 1325 1154 103 107 ) +insert ( 1323 "<=" 11 10 b f f 1184 1184 16 1325 1324 1155 336 386 ) +insert ( 1324 ">" 11 10 b f f 1184 1184 16 1322 1323 1157 104 108 ) +insert ( 1325 ">=" 11 10 b f f 1184 1184 16 1323 1322 1156 337 398 ) +insert ( 1327 "+" 11 10 b f f 1184 1186 1184 2554 0 1189 - - ) +insert ( 1328 - 11 10 b f f 1184 1184 1186 0 0 1188 - - ) +insert ( 1329 - 11 10 b f f 1184 1186 1184 0 0 1190 - - ) +insert ( 1330 "=" 11 10 b t t 1186 1186 16 1330 1331 1162 101 105 ) +insert ( 1331 "<>" 11 10 b f f 1186 1186 16 1331 1330 1163 102 106 ) +insert ( 1332 "<" 11 10 b f f 1186 1186 16 1334 1335 1164 103 107 ) +insert ( 1333 "<=" 11 10 b f f 1186 1186 16 1335 1334 1165 336 386 ) +insert ( 1334 ">" 11 10 b f f 1186 1186 16 1332 1333 1167 104 108 ) +insert ( 1335 ">=" 11 10 b f f 1186 1186 16 1333 1332 1166 337 398 ) +insert ( 1336 - 11 10 l f f 0 1186 1186 0 0 1168 - - ) +insert ( 1337 "+" 11 10 b f f 1186 1186 1186 1337 0 1169 - - ) +insert ( 1338 - 11 10 b f f 1186 1186 1186 0 0 1170 - - ) +insert ( 1360 "+" 11 10 b f f 1082 1083 1114 1363 0 1272 - - ) +insert ( 1361 "+" 11 10 b f f 1082 1266 1184 1366 0 1297 - - ) +insert ( 1363 "+" 11 10 b f f 1083 1082 1114 1360 0 1296 - - ) +insert ( 1366 "+" 11 10 b f f 1266 1082 1184 1361 0 1298 - - ) +insert ( 1399 - 11 10 b f f 1083 1083 1186 0 0 1690 - - ) +insert ( 1420 "@@" 11 10 l f f 0 718 600 0 0 1472 - - ) +insert ( 1500 "=" 11 10 b f f 718 718 16 1500 1501 1462 101 105 ) +insert ( 1501 "<>" 11 10 b f f 718 718 16 1501 1500 1463 102 106 ) +insert ( 1502 "<" 11 10 b f f 718 718 16 1503 1505 1464 139 140 ) +insert ( 1503 ">" 11 10 b f f 718 718 16 1502 1504 1465 139 140 ) +insert ( 1504 "<=" 11 10 b f f 718 718 16 1505 1503 1466 139 140 ) +insert ( 1505 ">=" 11 10 b f f 718 718 16 1504 1502 1467 139 140 ) +insert ( 1506 "<<" 11 10 b f f 718 718 16 0 0 1454 1300 1301 ) +insert ( 1507 "&<" 11 10 b f f 718 718 16 0 0 1455 1300 1301 ) +insert ( 1508 "&>" 11 10 b f f 718 718 16 0 0 1456 1300 1301 ) +insert ( 1509 ">>" 11 10 b f f 718 718 16 0 0 1457 1300 1301 ) +insert ( 1510 "<@" 11 10 b f f 718 718 16 1511 0 1458 1302 1303 ) +insert ( 1511 "@>" 11 10 b f f 718 718 16 1510 0 1453 1302 1303 ) +insert ( 1512 "~=" 11 10 b f f 718 718 16 1512 0 1452 101 105 ) +insert ( 1513 "&&" 11 10 b f f 718 718 16 1513 0 1459 139 140 ) +insert ( 1514 "|>>" 11 10 b f f 718 718 16 0 0 1461 1300 1301 ) +insert ( 1515 "<<|" 11 10 b f f 718 718 16 0 0 1460 1300 1301 ) +insert ( 1516 "+" 11 10 b f f 718 600 718 0 0 1146 - - ) +insert ( 1517 - 11 10 b f f 718 600 718 0 0 1147 - - ) +insert ( 1518 "*" 11 10 b f f 718 600 718 0 0 1148 - - ) +insert ( 1519 "/" 11 10 b f f 718 600 718 0 0 1149 - - ) +insert ( 1520 "<->" 11 10 b f f 718 718 701 1520 0 1471 - - ) +insert ( 1521 "#" 11 10 l f f 0 604 23 0 0 1445 - - ) +insert ( 1522 "<->" 11 10 b f f 600 718 701 3291 0 1476 - - ) +insert ( 3291 "<->" 11 10 b f f 718 600 701 1522 0 3290 - - ) +insert ( 3276 "<->" 11 10 b f f 600 604 701 3289 0 3275 - - ) +insert ( 3289 "<->" 11 10 b f f 604 600 701 3276 0 3292 - - ) +insert ( 1523 "<->" 11 10 b f f 718 604 701 1383 0 728 - - ) +insert ( 1383 "<->" 11 10 b f f 604 718 701 1523 0 785 - - ) +insert ( 1524 "<->" 11 10 b f f 628 603 701 1382 0 726 - - ) +insert ( 1382 "<->" 11 10 b f f 603 628 701 1524 0 703 - - ) +insert ( 1525 "?#" 11 10 b f f 601 601 16 1525 0 994 - - ) +insert ( 1526 "?||" 11 10 b f f 601 601 16 1526 0 995 - - ) +insert ( 1527 "?-|" 11 10 b f f 601 601 16 1527 0 996 - - ) +insert ( 1528 "?-" 11 10 l f f 0 601 16 0 0 998 - - ) +insert ( 1529 "?|" 11 10 l f f 0 601 16 0 0 997 - - ) +insert ( 1535 "=" 11 10 b f f 601 601 16 1535 1586 999 101 105 ) +insert ( 1536 "#" 11 10 b f f 601 601 600 1536 0 362 - - ) +insert ( 1537 "?#" 11 10 b f f 601 628 16 0 0 277 - - ) +insert ( 1538 "?#" 11 10 b f f 601 603 16 0 0 373 - - ) +insert ( 1539 "?#" 11 10 b f f 628 603 16 0 0 278 - - ) +insert ( 1546 "<@" 11 10 b f f 600 628 16 0 0 959 - - ) +insert ( 1547 "<@" 11 10 b f f 600 601 16 0 0 369 - - ) +insert ( 1548 "<@" 11 10 b f f 601 628 16 0 0 960 - - ) +insert ( 1549 "<@" 11 10 b f f 601 603 16 0 0 372 - - ) +insert ( 1557 "##" 11 10 b f f 600 628 600 0 0 961 - - ) +insert ( 1558 "##" 11 10 b f f 600 601 600 0 0 366 - - ) +insert ( 1559 "##" 11 10 b f f 600 603 600 0 0 367 - - ) +insert ( 1566 "##" 11 10 b f f 601 628 600 0 0 962 - - ) +insert ( 1567 "##" 11 10 b f f 601 603 600 0 0 368 - - ) +insert ( 1568 "##" 11 10 b f f 628 603 600 0 0 963 - - ) +insert ( 1577 "##" 11 10 b f f 628 601 600 0 0 1488 - - ) +insert ( 1578 "##" 11 10 b f f 601 601 600 0 0 1489 - - ) +insert ( 1583 "*" 11 10 b f f 1186 701 1186 1584 0 1618 - - ) +insert ( 1584 "*" 11 10 b f f 701 1186 1186 1583 0 1624 - - ) +insert ( 1585 "/" 11 10 b f f 1186 701 1186 0 0 1326 - - ) +insert ( 1586 "<>" 11 10 b f f 601 601 16 1586 1535 1482 102 106 ) +insert ( 1587 "<" 11 10 b f f 601 601 16 1589 1590 1483 - - ) +insert ( 1588 "<=" 11 10 b f f 601 601 16 1590 1589 1484 - - ) +insert ( 1589 ">" 11 10 b f f 601 601 16 1587 1588 1485 - - ) +insert ( 1590 ">=" 11 10 b f f 601 601 16 1588 1587 1486 - - ) +insert ( 1591 "@-@" 11 10 l f f 0 601 701 0 0 1487 - - ) +insert ( 1611 "?#" 11 10 b f f 628 628 16 1611 0 1495 - - ) +insert ( 1612 "?||" 11 10 b f f 628 628 16 1612 0 1496 - - ) +insert ( 1613 "?-|" 11 10 b f f 628 628 16 1613 0 1497 - - ) +insert ( 1614 "?-" 11 10 l f f 0 628 16 0 0 1499 - - ) +insert ( 1615 "?|" 11 10 l f f 0 628 16 0 0 1498 - - ) +insert ( 1616 "=" 11 10 b f f 628 628 16 1616 0 1492 101 105 ) +insert ( 1617 "#" 11 10 b f f 628 628 600 1617 0 1494 - - ) +insert ( 1220 "=" 11 10 b t t 829 829 16 1220 1221 830 101 105 ) +insert ( 1221 "<>" 11 10 b f f 829 829 16 1221 1220 835 102 106 ) +insert ( 1222 "<" 11 10 b f f 829 829 16 1224 1225 831 103 107 ) +insert ( 1223 "<=" 11 10 b f f 829 829 16 1225 1224 832 336 386 ) +insert ( 1224 ">" 11 10 b f f 829 829 16 1222 1223 833 104 108 ) +insert ( 1225 ">=" 11 10 b f f 829 829 16 1223 1222 834 337 398 ) +insert ( 3147 "~" 11 10 l f f 0 829 829 0 0 3144 - - ) +insert ( 3148 "&" 11 10 b f f 829 829 829 0 0 3145 - - ) +insert ( 3149 "|" 11 10 b f f 829 829 829 0 0 3146 - - ) +insert ( 3362 "=" 11 10 b t t 774 774 16 3362 3363 4113 101 105 ) +insert ( 3363 "<>" 11 10 b f f 774 774 16 3363 3362 4118 102 106 ) +insert ( 3364 "<" 11 10 b f f 774 774 16 3366 3367 4114 103 107 ) +insert ( 3365 "<=" 11 10 b f f 774 774 16 3367 3366 4115 336 386 ) +insert ( 3366 ">" 11 10 b f f 774 774 16 3364 3365 4116 104 108 ) +insert ( 3367 ">=" 11 10 b f f 774 774 16 3365 3364 4117 337 398 ) +insert ( 3368 "~" 11 10 l f f 0 774 774 0 0 4120 - - ) +insert ( 3369 "&" 11 10 b f f 774 774 774 0 0 4121 - - ) +insert ( 3370 "|" 11 10 b f f 774 774 774 0 0 4122 - - ) +insert ( 1201 "=" 11 10 b t t 869 869 16 1201 1202 920 101 105 ) +insert ( 1202 "<>" 11 10 b f f 869 869 16 1202 1201 925 102 106 ) +insert ( 1203 "<" 11 10 b f f 869 869 16 1205 1206 921 103 107 ) +insert ( 1204 "<=" 11 10 b f f 869 869 16 1206 1205 922 336 386 ) +insert ( 1205 ">" 11 10 b f f 869 869 16 1203 1204 923 104 108 ) +insert ( 1206 ">=" 11 10 b f f 869 869 16 1204 1203 924 337 398 ) +insert ( 931 "<<" 11 10 b f f 869 869 16 933 0 927 3560 3561 ) +insert ( 932 "<<=" 11 10 b f f 869 869 16 934 0 928 3560 3561 ) +insert ( 933 ">>" 11 10 b f f 869 869 16 931 0 929 3560 3561 ) +insert ( 934 ">>=" 11 10 b f f 869 869 16 932 0 930 3560 3561 ) +insert ( 3552 "&&" 11 10 b f f 869 869 16 3552 0 3551 3560 3561 ) +insert ( 2634 "~" 11 10 l f f 0 869 869 0 0 2627 - - ) +insert ( 2635 "&" 11 10 b f f 869 869 869 0 0 2628 - - ) +insert ( 2636 "|" 11 10 b f f 869 869 869 0 0 2629 - - ) +insert ( 2637 "+" 11 10 b f f 869 20 869 2638 0 2630 - - ) +insert ( 2638 "+" 11 10 b f f 20 869 869 2637 0 2631 - - ) +insert ( 2639 - 11 10 b f f 869 20 869 0 0 2632 - - ) +insert ( 2640 - 11 10 b f f 869 869 20 0 0 2633 - - ) +insert ( 1625 "~~*" 11 10 b f f 19 25 16 0 1626 1635 1814 1816 ) +insert ( 1626 "!~~*" 11 10 b f f 19 25 16 0 1625 1636 1815 1817 ) +insert ( 1627 "~~*" 11 10 b f f 25 25 16 0 1628 1633 1814 1816 ) +insert ( 1628 "!~~*" 11 10 b f f 25 25 16 0 1627 1634 1815 1817 ) +insert ( 1629 "~~*" 11 10 b f f 1042 25 16 0 1630 1660 1814 1816 ) +insert ( 1630 "!~~*" 11 10 b f f 1042 25 16 0 1629 1661 1815 1817 ) +insert ( 1751 - 11 10 l f f 0 1700 1700 0 0 1771 - - ) +insert ( 1752 "=" 11 10 b t t 1700 1700 16 1752 1753 1718 101 105 ) +insert ( 1753 "<>" 11 10 b f f 1700 1700 16 1753 1752 1719 102 106 ) +insert ( 1754 "<" 11 10 b f f 1700 1700 16 1756 1757 1722 103 107 ) +insert ( 1755 "<=" 11 10 b f f 1700 1700 16 1757 1756 1723 336 386 ) +insert ( 1756 ">" 11 10 b f f 1700 1700 16 1754 1755 1720 104 108 ) +insert ( 1757 ">=" 11 10 b f f 1700 1700 16 1755 1754 1721 337 398 ) +insert ( 1758 "+" 11 10 b f f 1700 1700 1700 1758 0 1724 - - ) +insert ( 1759 - 11 10 b f f 1700 1700 1700 0 0 1725 - - ) +insert ( 1760 "*" 11 10 b f f 1700 1700 1700 1760 0 1726 - - ) +insert ( 1761 "/" 11 10 b f f 1700 1700 1700 0 0 1727 - - ) +insert ( 1762 "%" 11 10 b f f 1700 1700 1700 0 0 1729 - - ) +insert ( 1038 "^" 11 10 b f f 1700 1700 1700 0 0 1739 - - ) +insert ( 1763 "@" 11 10 l f f 0 1700 1700 0 0 1704 - - ) +insert ( 1784 "=" 11 10 b t f 1560 1560 16 1784 1785 1581 101 105 ) +insert ( 1785 "<>" 11 10 b f f 1560 1560 16 1785 1784 1582 102 106 ) +insert ( 1786 "<" 11 10 b f f 1560 1560 16 1787 1789 1595 103 107 ) +insert ( 1787 ">" 11 10 b f f 1560 1560 16 1786 1788 1593 104 108 ) +insert ( 1788 "<=" 11 10 b f f 1560 1560 16 1789 1787 1594 336 386 ) +insert ( 1789 ">=" 11 10 b f f 1560 1560 16 1788 1786 1592 337 398 ) +insert ( 1791 "&" 11 10 b f f 1560 1560 1560 1791 0 1673 - - ) +insert ( 1792 "|" 11 10 b f f 1560 1560 1560 1792 0 1674 - - ) +insert ( 1793 "#" 11 10 b f f 1560 1560 1560 1793 0 1675 - - ) +insert ( 1794 "~" 11 10 l f f 0 1560 1560 0 0 1676 - - ) +insert ( 1795 "<<" 11 10 b f f 1560 23 1560 0 0 1677 - - ) +insert ( 1796 ">>" 11 10 b f f 1560 23 1560 0 0 1678 - - ) +insert ( 1797 "||" 11 10 b f f 1562 1562 1562 0 0 1679 - - ) +insert ( 1800 "+" 11 10 b f f 1083 1186 1083 1849 0 1747 - - ) +insert ( 1801 - 11 10 b f f 1083 1186 1083 0 0 1748 - - ) +insert ( 1802 "+" 11 10 b f f 1266 1186 1266 2552 0 1749 - - ) +insert ( 1803 - 11 10 b f f 1266 1186 1266 0 0 1750 - - ) +insert ( 1804 "=" 11 10 b t f 1562 1562 16 1804 1805 1666 101 105 ) +insert ( 1805 "<>" 11 10 b f f 1562 1562 16 1805 1804 1667 102 106 ) +insert ( 1806 "<" 11 10 b f f 1562 1562 16 1807 1809 1671 103 107 ) +insert ( 1807 ">" 11 10 b f f 1562 1562 16 1806 1808 1669 104 108 ) +insert ( 1808 "<=" 11 10 b f f 1562 1562 16 1809 1807 1670 336 386 ) +insert ( 1809 ">=" 11 10 b f f 1562 1562 16 1808 1806 1668 337 398 ) +insert ( 1849 "+" 11 10 b f f 1186 1083 1083 1800 0 1848 - - ) +insert ( 1862 "=" 11 10 b t t 21 20 16 1868 1863 1850 101 105 ) +insert ( 1863 "<>" 11 10 b f f 21 20 16 1869 1862 1851 102 106 ) +insert ( 1864 "<" 11 10 b f f 21 20 16 1871 1867 1852 103 107 ) +insert ( 1865 ">" 11 10 b f f 21 20 16 1870 1866 1853 104 108 ) +insert ( 1866 "<=" 11 10 b f f 21 20 16 1873 1865 1854 336 386 ) +insert ( 1867 ">=" 11 10 b f f 21 20 16 1872 1864 1855 337 398 ) +insert ( 1868 "=" 11 10 b t t 20 21 16 1862 1869 1856 101 105 ) +insert ( 1869 "<>" 11 10 b f f 20 21 16 1863 1868 1857 102 106 ) +insert ( 1870 "<" 11 10 b f f 20 21 16 1865 1873 1858 103 107 ) +insert ( 1871 ">" 11 10 b f f 20 21 16 1864 1872 1859 104 108 ) +insert ( 1872 "<=" 11 10 b f f 20 21 16 1867 1871 1860 336 386 ) +insert ( 1873 ">=" 11 10 b f f 20 21 16 1866 1870 1861 337 398 ) +insert ( 1874 "&" 11 10 b f f 21 21 21 1874 0 1892 - - ) +insert ( 1875 "|" 11 10 b f f 21 21 21 1875 0 1893 - - ) +insert ( 1876 "#" 11 10 b f f 21 21 21 1876 0 1894 - - ) +insert ( 1877 "~" 11 10 l f f 0 21 21 0 0 1895 - - ) +insert ( 1878 "<<" 11 10 b f f 21 23 21 0 0 1896 - - ) +insert ( 1879 ">>" 11 10 b f f 21 23 21 0 0 1897 - - ) +insert ( 1880 "&" 11 10 b f f 23 23 23 1880 0 1898 - - ) +insert ( 1881 "|" 11 10 b f f 23 23 23 1881 0 1899 - - ) +insert ( 1882 "#" 11 10 b f f 23 23 23 1882 0 1900 - - ) +insert ( 1883 "~" 11 10 l f f 0 23 23 0 0 1901 - - ) +insert ( 1884 "<<" 11 10 b f f 23 23 23 0 0 1902 - - ) +insert ( 1885 ">>" 11 10 b f f 23 23 23 0 0 1903 - - ) +insert ( 1886 "&" 11 10 b f f 20 20 20 1886 0 1904 - - ) +insert ( 1887 "|" 11 10 b f f 20 20 20 1887 0 1905 - - ) +insert ( 1888 "#" 11 10 b f f 20 20 20 1888 0 1906 - - ) +insert ( 1889 "~" 11 10 l f f 0 20 20 0 0 1907 - - ) +insert ( 1890 "<<" 11 10 b f f 20 23 20 0 0 1908 - - ) +insert ( 1891 ">>" 11 10 b f f 20 23 20 0 0 1909 - - ) +insert ( 1916 "+" 11 10 l f f 0 20 20 0 0 1910 - - ) +insert ( 1917 "+" 11 10 l f f 0 21 21 0 0 1911 - - ) +insert ( 1918 "+" 11 10 l f f 0 23 23 0 0 1912 - - ) +insert ( 1919 "+" 11 10 l f f 0 700 700 0 0 1913 - - ) +insert ( 1920 "+" 11 10 l f f 0 701 701 0 0 1914 - - ) +insert ( 1921 "+" 11 10 l f f 0 1700 1700 0 0 1915 - - ) +insert ( 1955 "=" 11 10 b t t 17 17 16 1955 1956 1948 101 105 ) +insert ( 1956 "<>" 11 10 b f f 17 17 16 1956 1955 1953 102 106 ) +insert ( 1957 "<" 11 10 b f f 17 17 16 1959 1960 1949 103 107 ) +insert ( 1958 "<=" 11 10 b f f 17 17 16 1960 1959 1950 336 386 ) +insert ( 1959 ">" 11 10 b f f 17 17 16 1957 1958 1951 104 108 ) +insert ( 1960 ">=" 11 10 b f f 17 17 16 1958 1957 1952 337 398 ) +insert ( 2016 "~~" 11 10 b f f 17 17 16 0 2017 2005 1819 1825 ) +insert ( 2017 "!~~" 11 10 b f f 17 17 16 0 2016 2006 1822 1828 ) +insert ( 2018 "||" 11 10 b f f 17 17 17 0 0 2011 - - ) +insert ( 2060 "=" 11 10 b t t 1114 1114 16 2060 2061 2052 101 105 ) +insert ( 2061 "<>" 11 10 b f f 1114 1114 16 2061 2060 2053 102 106 ) +insert ( 2062 "<" 11 10 b f f 1114 1114 16 2064 2065 2054 103 107 ) +insert ( 2063 "<=" 11 10 b f f 1114 1114 16 2065 2064 2055 336 386 ) +insert ( 2064 ">" 11 10 b f f 1114 1114 16 2062 2063 2057 104 108 ) +insert ( 2065 ">=" 11 10 b f f 1114 1114 16 2063 2062 2056 337 398 ) +insert ( 2066 "+" 11 10 b f f 1114 1186 1114 2553 0 2032 - - ) +insert ( 2067 - 11 10 b f f 1114 1114 1186 0 0 2031 - - ) +insert ( 2068 - 11 10 b f f 1114 1186 1114 0 0 2033 - - ) +insert ( 2314 "~<~" 11 10 b f f 25 25 16 2318 2317 2160 103 107 ) +insert ( 2315 "~<=~" 11 10 b f f 25 25 16 2317 2318 2161 336 386 ) +insert ( 2317 "~>=~" 11 10 b f f 25 25 16 2315 2314 2163 337 398 ) +insert ( 2318 "~>~" 11 10 b f f 25 25 16 2314 2315 2164 104 108 ) +insert ( 2326 "~<~" 11 10 b f f 1042 1042 16 2330 2329 2174 103 107 ) +insert ( 2327 "~<=~" 11 10 b f f 1042 1042 16 2329 2330 2175 336 386 ) +insert ( 2329 "~>=~" 11 10 b f f 1042 1042 16 2327 2326 2177 337 398 ) +insert ( 2330 "~>~" 11 10 b f f 1042 1042 16 2326 2327 2178 104 108 ) +insert ( 2345 "<" 11 10 b f f 1082 1114 16 2375 2348 2338 103 107 ) +insert ( 2346 "<=" 11 10 b f f 1082 1114 16 2374 2349 2339 336 386 ) +insert ( 2347 "=" 11 10 b t f 1082 1114 16 2373 2350 2340 101 105 ) +insert ( 2348 ">=" 11 10 b f f 1082 1114 16 2372 2345 2342 337 398 ) +insert ( 2349 ">" 11 10 b f f 1082 1114 16 2371 2346 2341 104 108 ) +insert ( 2350 "<>" 11 10 b f f 1082 1114 16 2376 2347 2343 102 106 ) +insert ( 2358 "<" 11 10 b f f 1082 1184 16 2388 2361 2351 103 107 ) +insert ( 2359 "<=" 11 10 b f f 1082 1184 16 2387 2362 2352 336 386 ) +insert ( 2360 "=" 11 10 b t f 1082 1184 16 2386 2363 2353 101 105 ) +insert ( 2361 ">=" 11 10 b f f 1082 1184 16 2385 2358 2355 337 398 ) +insert ( 2362 ">" 11 10 b f f 1082 1184 16 2384 2359 2354 104 108 ) +insert ( 2363 "<>" 11 10 b f f 1082 1184 16 2389 2360 2356 102 106 ) +insert ( 2371 "<" 11 10 b f f 1114 1082 16 2349 2374 2364 103 107 ) +insert ( 2372 "<=" 11 10 b f f 1114 1082 16 2348 2375 2365 336 386 ) +insert ( 2373 "=" 11 10 b t f 1114 1082 16 2347 2376 2366 101 105 ) +insert ( 2374 ">=" 11 10 b f f 1114 1082 16 2346 2371 2368 337 398 ) +insert ( 2375 ">" 11 10 b f f 1114 1082 16 2345 2372 2367 104 108 ) +insert ( 2376 "<>" 11 10 b f f 1114 1082 16 2350 2373 2369 102 106 ) +insert ( 2384 "<" 11 10 b f f 1184 1082 16 2362 2387 2377 103 107 ) +insert ( 2385 "<=" 11 10 b f f 1184 1082 16 2361 2388 2378 336 386 ) +insert ( 2386 "=" 11 10 b t f 1184 1082 16 2360 2389 2379 101 105 ) +insert ( 2387 ">=" 11 10 b f f 1184 1082 16 2359 2384 2381 337 398 ) +insert ( 2388 ">" 11 10 b f f 1184 1082 16 2358 2385 2380 104 108 ) +insert ( 2389 "<>" 11 10 b f f 1184 1082 16 2363 2386 2382 102 106 ) +insert ( 2534 "<" 11 10 b f f 1114 1184 16 2544 2537 2520 103 107 ) +insert ( 2535 "<=" 11 10 b f f 1114 1184 16 2543 2538 2521 336 386 ) +insert ( 2536 "=" 11 10 b t f 1114 1184 16 2542 2539 2522 101 105 ) +insert ( 2537 ">=" 11 10 b f f 1114 1184 16 2541 2534 2524 337 398 ) +insert ( 2538 ">" 11 10 b f f 1114 1184 16 2540 2535 2523 104 108 ) +insert ( 2539 "<>" 11 10 b f f 1114 1184 16 2545 2536 2525 102 106 ) +insert ( 2540 "<" 11 10 b f f 1184 1114 16 2538 2543 2527 103 107 ) +insert ( 2541 "<=" 11 10 b f f 1184 1114 16 2537 2544 2528 336 386 ) +insert ( 2542 "=" 11 10 b t f 1184 1114 16 2536 2545 2529 101 105 ) +insert ( 2543 ">=" 11 10 b f f 1184 1114 16 2535 2540 2531 337 398 ) +insert ( 2544 ">" 11 10 b f f 1184 1114 16 2534 2541 2530 104 108 ) +insert ( 2545 "<>" 11 10 b f f 1184 1114 16 2539 2542 2532 102 106 ) +insert ( 2551 "+" 11 10 b f f 1186 1082 1114 1076 0 2546 - - ) +insert ( 2552 "+" 11 10 b f f 1186 1266 1266 1802 0 2547 - - ) +insert ( 2553 "+" 11 10 b f f 1186 1114 1114 2066 0 2548 - - ) +insert ( 2554 "+" 11 10 b f f 1186 1184 1184 1327 0 2549 - - ) +insert ( 2555 "+" 11 10 b f f 23 1082 1082 1100 0 2550 - - ) +insert ( 2570 "<<|" 11 10 b f f 603 603 16 0 0 2562 1300 1301 ) +insert ( 2571 "&<|" 11 10 b f f 603 603 16 0 0 2563 1300 1301 ) +insert ( 2572 "|&>" 11 10 b f f 603 603 16 0 0 2564 1300 1301 ) +insert ( 2573 "|>>" 11 10 b f f 603 603 16 0 0 2565 1300 1301 ) +insert ( 2574 "<<|" 11 10 b f f 604 604 16 0 0 2566 1300 1301 ) +insert ( 2575 "&<|" 11 10 b f f 604 604 16 0 0 2567 1300 1301 ) +insert ( 2576 "|&>" 11 10 b f f 604 604 16 0 0 2568 1300 1301 ) +insert ( 2577 "|>>" 11 10 b f f 604 604 16 0 0 2569 1300 1301 ) +insert ( 2589 "&<|" 11 10 b f f 718 718 16 0 0 2587 1300 1301 ) +insert ( 2590 "|&>" 11 10 b f f 718 718 16 0 0 2588 1300 1301 ) +insert ( 2750 "&&" 11 10 b f f 2277 2277 16 2750 0 2747 3817 3818 ) +insert ( 2751 "@>" 11 10 b f f 2277 2277 16 2752 0 2748 3817 3818 ) +insert ( 2752 "<@" 11 10 b f f 2277 2277 16 2751 0 2749 3817 3818 ) +insert ( 2779 "||" 11 10 b f f 25 2776 25 0 0 2003 - - ) +insert ( 2780 "||" 11 10 b f f 2776 25 25 0 0 2004 - - ) +insert ( 2860 "@" 11 10 b f f 604 604 16 2861 0 345 1302 1303 ) +insert ( 2861 "~" 11 10 b f f 604 604 16 2860 0 340 1302 1303 ) +insert ( 2862 "@" 11 10 b f f 603 603 16 2863 0 192 1302 1303 ) +insert ( 2863 "~" 11 10 b f f 603 603 16 2862 0 187 1302 1303 ) +insert ( 2864 "@" 11 10 b f f 718 718 16 2865 0 1458 1302 1303 ) +insert ( 2865 "~" 11 10 b f f 718 718 16 2864 0 1453 1302 1303 ) +insert ( 2866 "@" 11 10 b f f 600 603 16 0 0 136 - - ) +insert ( 2867 "@" 11 10 b f f 600 602 16 2868 0 137 - - ) +insert ( 2868 "~" 11 10 b f f 602 600 16 2867 0 1426 - - ) +insert ( 2869 "@" 11 10 b f f 600 604 16 2870 0 1429 - - ) +insert ( 2870 "~" 11 10 b f f 604 600 16 2869 0 1428 - - ) +insert ( 2871 "@" 11 10 b f f 600 718 16 2872 0 1478 - - ) +insert ( 2872 "~" 11 10 b f f 718 600 16 2871 0 1477 - - ) +insert ( 2873 "@" 11 10 b f f 600 628 16 0 0 959 - - ) +insert ( 2874 "@" 11 10 b f f 600 601 16 0 0 369 - - ) +insert ( 2875 "@" 11 10 b f f 601 628 16 0 0 960 - - ) +insert ( 2876 "@" 11 10 b f f 601 603 16 0 0 372 - - ) +insert ( 2877 "~" 11 10 b f f 1034 1033 16 0 0 1037 - - ) +insert ( 2972 "=" 11 10 b t t 2950 2950 16 2972 2973 2956 101 105 ) +insert ( 2973 "<>" 11 10 b f f 2950 2950 16 2973 2972 2959 102 106 ) +insert ( 2974 "<" 11 10 b f f 2950 2950 16 2975 2977 2954 103 107 ) +insert ( 2975 ">" 11 10 b f f 2950 2950 16 2974 2976 2958 104 108 ) +insert ( 2976 "<=" 11 10 b f f 2950 2950 16 2977 2975 2955 336 386 ) +insert ( 2977 ">=" 11 10 b f f 2950 2950 16 2976 2974 2957 337 398 ) +insert ( 3222 "=" 11 10 b t t 3220 3220 16 3222 3223 3233 101 105 ) +insert ( 3223 "<>" 11 10 b f f 3220 3220 16 3223 3222 3236 102 106 ) +insert ( 3224 "<" 11 10 b f f 3220 3220 16 3225 3227 3231 103 107 ) +insert ( 3225 ">" 11 10 b f f 3220 3220 16 3224 3226 3235 104 108 ) +insert ( 3226 "<=" 11 10 b f f 3220 3220 16 3227 3225 3232 336 386 ) +insert ( 3227 ">=" 11 10 b f f 3220 3220 16 3226 3224 3234 337 398 ) +insert ( 3228 - 11 10 b f f 3220 3220 1700 0 0 3237 - - ) +insert ( 3516 "=" 11 10 b t t 3500 3500 16 3516 3517 3508 101 105 ) +insert ( 3517 "<>" 11 10 b f f 3500 3500 16 3517 3516 3509 102 106 ) +insert ( 3518 "<" 11 10 b f f 3500 3500 16 3519 3521 3510 103 107 ) +insert ( 3519 ">" 11 10 b f f 3500 3500 16 3518 3520 3511 104 108 ) +insert ( 3520 "<=" 11 10 b f f 3500 3500 16 3521 3519 3512 336 386 ) +insert ( 3521 ">=" 11 10 b f f 3500 3500 16 3520 3518 3513 337 398 ) +insert ( 3627 "<" 11 10 b f f 3614 3614 16 3632 3631 3616 103 107 ) +insert ( 3628 "<=" 11 10 b f f 3614 3614 16 3631 3632 3617 336 386 ) +insert ( 3629 "=" 11 10 b t f 3614 3614 16 3629 3630 3618 101 105 ) +insert ( 3630 "<>" 11 10 b f f 3614 3614 16 3630 3629 3619 102 106 ) +insert ( 3631 ">=" 11 10 b f f 3614 3614 16 3628 3627 3620 337 398 ) +insert ( 3632 ">" 11 10 b f f 3614 3614 16 3627 3628 3621 104 108 ) +insert ( 3633 "||" 11 10 b f f 3614 3614 3614 0 0 3625 - - ) +insert ( 3636 "@@" 11 10 b f f 3614 3615 16 3637 0 3634 3686 3687 ) +insert ( 3637 "@@" 11 10 b f f 3615 3614 16 3636 0 3635 3686 3687 ) +insert ( 3660 "@@@" 11 10 b f f 3614 3615 16 3661 0 3634 3686 3687 ) +insert ( 3661 "@@@" 11 10 b f f 3615 3614 16 3660 0 3635 3686 3687 ) +insert ( 3674 "<" 11 10 b f f 3615 3615 16 3679 3678 3662 103 107 ) +insert ( 3675 "<=" 11 10 b f f 3615 3615 16 3678 3679 3663 336 386 ) +insert ( 3676 "=" 11 10 b t f 3615 3615 16 3676 3677 3664 101 105 ) +insert ( 3677 "<>" 11 10 b f f 3615 3615 16 3677 3676 3665 102 106 ) +insert ( 3678 ">=" 11 10 b f f 3615 3615 16 3675 3674 3666 337 398 ) +insert ( 3679 ">" 11 10 b f f 3615 3615 16 3674 3675 3667 104 108 ) +insert ( 3680 "&&" 11 10 b f f 3615 3615 3615 0 0 3669 - - ) +insert ( 3681 "||" 11 10 b f f 3615 3615 3615 0 0 3670 - - ) +insert ( 5005 "<->" 11 10 b f f 3615 3615 3615 0 0 5003 - - ) +insert ( 3682 "!!" 11 10 l f f 0 3615 3615 0 0 3671 - - ) +insert ( 3693 "@>" 11 10 b f f 3615 3615 16 3694 0 3691 5040 5041 ) +insert ( 3694 "<@" 11 10 b f f 3615 3615 16 3693 0 3692 5040 5041 ) +insert ( 3762 "@@" 11 10 b f f 25 25 16 0 0 3760 5040 5041 ) +insert ( 3763 "@@" 11 10 b f f 25 3615 16 0 0 3761 5040 5041 ) +insert ( 2988 "=" 11 10 b t f 2249 2249 16 2988 2989 2981 101 105 ) +insert ( 2989 "<>" 11 10 b f f 2249 2249 16 2989 2988 2982 102 106 ) +insert ( 2990 "<" 11 10 b f f 2249 2249 16 2991 2993 2983 103 107 ) +insert ( 2991 ">" 11 10 b f f 2249 2249 16 2990 2992 2984 104 108 ) +insert ( 2992 "<=" 11 10 b f f 2249 2249 16 2993 2991 2985 336 386 ) +insert ( 2993 ">=" 11 10 b f f 2249 2249 16 2992 2990 2986 337 398 ) +insert ( 3188 "*=" 11 10 b t f 2249 2249 16 3188 3189 3181 101 105 ) +insert ( 3189 "*<>" 11 10 b f f 2249 2249 16 3189 3188 3182 102 106 ) +insert ( 3190 "*<" 11 10 b f f 2249 2249 16 3191 3193 3183 103 107 ) +insert ( 3191 "*>" 11 10 b f f 2249 2249 16 3190 3192 3184 104 108 ) +insert ( 3192 "*<=" 11 10 b f f 2249 2249 16 3193 3191 3185 336 386 ) +insert ( 3193 "*>=" 11 10 b f f 2249 2249 16 3192 3190 3186 337 398 ) +insert ( 3882 "=" 11 10 b t t 3831 3831 16 3882 3883 3855 101 105 ) +insert ( 3883 "<>" 11 10 b f f 3831 3831 16 3883 3882 3856 102 106 ) +insert ( 3884 "<" 11 10 b f f 3831 3831 16 3887 3886 3871 3169 107 ) +insert ( 3885 "<=" 11 10 b f f 3831 3831 16 3886 3887 3872 3169 386 ) +insert ( 3886 ">=" 11 10 b f f 3831 3831 16 3885 3884 3873 3169 398 ) +insert ( 3887 ">" 11 10 b f f 3831 3831 16 3884 3885 3874 3169 108 ) +insert ( 3888 "&&" 11 10 b f f 3831 3831 16 3888 0 3857 3169 140 ) +insert ( 3889 "@>" 11 10 b f f 3831 2283 16 3891 0 3858 3169 1303 ) +insert ( 3890 "@>" 11 10 b f f 3831 3831 16 3892 0 3859 3169 1303 ) +insert ( 3891 "<@" 11 10 b f f 2283 3831 16 3889 0 3860 3169 1303 ) +insert ( 3892 "<@" 11 10 b f f 3831 3831 16 3890 0 3861 3169 1303 ) +insert ( 3893 "<<" 11 10 b f f 3831 3831 16 3894 0 3863 3169 107 ) +insert ( 3894 ">>" 11 10 b f f 3831 3831 16 3893 0 3864 3169 108 ) +insert ( 3895 "&<" 11 10 b f f 3831 3831 16 0 0 3865 3169 107 ) +insert ( 3896 "&>" 11 10 b f f 3831 3831 16 0 0 3866 3169 108 ) +insert ( 3897 "-|-" 11 10 b f f 3831 3831 16 3897 0 3862 5040 5041 ) +insert ( 3898 "+" 11 10 b f f 3831 3831 3831 3898 0 3867 - - ) +insert ( 3899 - 11 10 b f f 3831 3831 3831 0 0 3869 - - ) +insert ( 3900 "*" 11 10 b f f 3831 3831 3831 3900 0 3868 - - ) +insert ( 3962 "->" 11 10 b f f 114 25 114 0 0 3947 - - ) +insert ( 3963 "->>" 11 10 b f f 114 25 25 0 0 3948 - - ) +insert ( 3964 "->" 11 10 b f f 114 23 114 0 0 3949 - - ) +insert ( 3965 "->>" 11 10 b f f 114 23 25 0 0 3950 - - ) +insert ( 3966 "#>" 11 10 b f f 114 1009 114 0 0 3951 - - ) +insert ( 3967 "#>>" 11 10 b f f 114 1009 25 0 0 3953 - - ) +insert ( 3211 "->" 11 10 b f f 3802 25 3802 0 0 3478 - - ) +insert ( 3477 "->>" 11 10 b f f 3802 25 25 0 0 3214 - - ) +insert ( 3212 "->" 11 10 b f f 3802 23 3802 0 0 3215 - - ) +insert ( 3481 "->>" 11 10 b f f 3802 23 25 0 0 3216 - - ) +insert ( 3213 "#>" 11 10 b f f 3802 1009 3802 0 0 3217 - - ) +insert ( 3206 "#>>" 11 10 b f f 3802 1009 25 0 0 3940 - - ) +insert ( 3240 "=" 11 10 b t t 3802 3802 16 3240 3241 4043 101 105 ) +insert ( 3241 "<>" 11 10 b f f 3802 3802 16 3241 3240 4038 102 106 ) +insert ( 3242 "<" 11 10 b f f 3802 3802 16 3243 3245 4039 103 107 ) +insert ( 3243 ">" 11 10 b f f 3802 3802 16 3242 3244 4040 104 108 ) +insert ( 3244 "<=" 11 10 b f f 3802 3802 16 3245 3243 4041 336 386 ) +insert ( 3245 ">=" 11 10 b f f 3802 3802 16 3244 3242 4042 337 398 ) +insert ( 3246 "@>" 11 10 b f f 3802 3802 16 3250 0 4046 5040 5041 ) +insert ( 3247 "?" 11 10 b f f 3802 25 16 0 0 4047 5040 5041 ) +insert ( 3248 "?|" 11 10 b f f 3802 1009 16 0 0 4048 5040 5041 ) +insert ( 3249 "?&" 11 10 b f f 3802 1009 16 0 0 4049 5040 5041 ) +insert ( 3250 "<@" 11 10 b f f 3802 3802 16 3246 0 4050 5040 5041 ) +insert ( 3284 "||" 11 10 b f f 3802 3802 3802 0 0 3301 - - ) +insert ( 3285 - 11 10 b f f 3802 25 3802 0 0 3302 - - ) +insert ( 3398 - 11 10 b f f 3802 1009 3802 0 0 3343 - - ) +insert ( 3286 - 11 10 b f f 3802 23 3802 0 0 3303 - - ) +insert ( 3287 "#-" 11 10 b f f 3802 1009 3802 0 0 3304 - - ) +insert ( 4012 "@?" 11 10 b f f 3802 4072 16 0 0 4010 5040 5041 ) +insert ( 4013 "@@" 11 10 b f f 3802 4072 16 0 0 4011 5040 5041 ) +close pg_operator +create pg_opfamily 2753 + ( + oid = oid , + opfmethod = oid , + opfname = name , + opfnamespace = oid , + opfowner = oid + ) +open pg_opfamily +insert ( 397 403 array_ops 11 10 ) +insert ( 627 405 array_ops 11 10 ) +insert ( 423 403 bit_ops 11 10 ) +insert ( 424 403 bool_ops 11 10 ) +insert ( 426 403 bpchar_ops 11 10 ) +insert ( 427 405 bpchar_ops 11 10 ) +insert ( 428 403 bytea_ops 11 10 ) +insert ( 429 403 char_ops 11 10 ) +insert ( 431 405 char_ops 11 10 ) +insert ( 434 403 datetime_ops 11 10 ) +insert ( 435 405 date_ops 11 10 ) +insert ( 1970 403 float_ops 11 10 ) +insert ( 1971 405 float_ops 11 10 ) +insert ( 1974 403 network_ops 11 10 ) +insert ( 1975 405 network_ops 11 10 ) +insert ( 3550 783 network_ops 11 10 ) +insert ( 3794 4000 network_ops 11 10 ) +insert ( 1976 403 integer_ops 11 10 ) +insert ( 1977 405 integer_ops 11 10 ) +insert ( 1982 403 interval_ops 11 10 ) +insert ( 1983 405 interval_ops 11 10 ) +insert ( 1984 403 macaddr_ops 11 10 ) +insert ( 1985 405 macaddr_ops 11 10 ) +insert ( 3371 403 macaddr8_ops 11 10 ) +insert ( 3372 405 macaddr8_ops 11 10 ) +insert ( 1988 403 numeric_ops 11 10 ) +insert ( 1998 405 numeric_ops 11 10 ) +insert ( 1989 403 oid_ops 11 10 ) +insert ( 1990 405 oid_ops 11 10 ) +insert ( 1991 403 oidvector_ops 11 10 ) +insert ( 1992 405 oidvector_ops 11 10 ) +insert ( 2994 403 record_ops 11 10 ) +insert ( 3194 403 record_image_ops 11 10 ) +insert ( 1994 403 text_ops 11 10 ) +insert ( 1995 405 text_ops 11 10 ) +insert ( 1996 403 time_ops 11 10 ) +insert ( 1997 405 time_ops 11 10 ) +insert ( 1999 405 timestamptz_ops 11 10 ) +insert ( 2000 403 timetz_ops 11 10 ) +insert ( 2001 405 timetz_ops 11 10 ) +insert ( 2002 403 varbit_ops 11 10 ) +insert ( 2040 405 timestamp_ops 11 10 ) +insert ( 2095 403 text_pattern_ops 11 10 ) +insert ( 2097 403 bpchar_pattern_ops 11 10 ) +insert ( 2099 403 money_ops 11 10 ) +insert ( 2222 405 bool_ops 11 10 ) +insert ( 2223 405 bytea_ops 11 10 ) +insert ( 2789 403 tid_ops 11 10 ) +insert ( 2225 405 xid_ops 11 10 ) +insert ( 5032 405 xid8_ops 11 10 ) +insert ( 5067 403 xid8_ops 11 10 ) +insert ( 2226 405 cid_ops 11 10 ) +insert ( 2227 405 tid_ops 11 10 ) +insert ( 2229 405 text_pattern_ops 11 10 ) +insert ( 2231 405 bpchar_pattern_ops 11 10 ) +insert ( 2235 405 aclitem_ops 11 10 ) +insert ( 2593 783 box_ops 11 10 ) +insert ( 2594 783 poly_ops 11 10 ) +insert ( 2595 783 circle_ops 11 10 ) +insert ( 1029 783 point_ops 11 10 ) +insert ( 2745 2742 array_ops 11 10 ) +insert ( 2968 403 uuid_ops 11 10 ) +insert ( 2969 405 uuid_ops 11 10 ) +insert ( 3253 403 pg_lsn_ops 11 10 ) +insert ( 3254 405 pg_lsn_ops 11 10 ) +insert ( 3522 403 enum_ops 11 10 ) +insert ( 3523 405 enum_ops 11 10 ) +insert ( 3626 403 tsvector_ops 11 10 ) +insert ( 3655 783 tsvector_ops 11 10 ) +insert ( 3659 2742 tsvector_ops 11 10 ) +insert ( 3683 403 tsquery_ops 11 10 ) +insert ( 3702 783 tsquery_ops 11 10 ) +insert ( 3901 403 range_ops 11 10 ) +insert ( 3903 405 range_ops 11 10 ) +insert ( 3919 783 range_ops 11 10 ) +insert ( 3474 4000 range_ops 11 10 ) +insert ( 4015 4000 quad_point_ops 11 10 ) +insert ( 4016 4000 kd_point_ops 11 10 ) +insert ( 4017 4000 text_ops 11 10 ) +insert ( 4033 403 jsonb_ops 11 10 ) +insert ( 4034 405 jsonb_ops 11 10 ) +insert ( 4036 2742 jsonb_ops 11 10 ) +insert ( 4037 2742 jsonb_path_ops 11 10 ) +insert ( 4054 3580 integer_minmax_ops 11 10 ) +insert ( 4055 3580 numeric_minmax_ops 11 10 ) +insert ( 4056 3580 text_minmax_ops 11 10 ) +insert ( 4058 3580 timetz_minmax_ops 11 10 ) +insert ( 4059 3580 datetime_minmax_ops 11 10 ) +insert ( 4062 3580 char_minmax_ops 11 10 ) +insert ( 4064 3580 bytea_minmax_ops 11 10 ) +insert ( 4065 3580 name_minmax_ops 11 10 ) +insert ( 4068 3580 oid_minmax_ops 11 10 ) +insert ( 4069 3580 tid_minmax_ops 11 10 ) +insert ( 4070 3580 float_minmax_ops 11 10 ) +insert ( 4074 3580 macaddr_minmax_ops 11 10 ) +insert ( 4109 3580 macaddr8_minmax_ops 11 10 ) +insert ( 4075 3580 network_minmax_ops 11 10 ) +insert ( 4102 3580 network_inclusion_ops 11 10 ) +insert ( 4076 3580 bpchar_minmax_ops 11 10 ) +insert ( 4077 3580 time_minmax_ops 11 10 ) +insert ( 4078 3580 interval_minmax_ops 11 10 ) +insert ( 4079 3580 bit_minmax_ops 11 10 ) +insert ( 4080 3580 varbit_minmax_ops 11 10 ) +insert ( 4081 3580 uuid_minmax_ops 11 10 ) +insert ( 4103 3580 range_inclusion_ops 11 10 ) +insert ( 4082 3580 pg_lsn_minmax_ops 11 10 ) +insert ( 4104 3580 box_inclusion_ops 11 10 ) +insert ( 5000 4000 box_ops 11 10 ) +insert ( 5008 4000 poly_ops 11 10 ) +close pg_opfamily +create pg_opclass 2616 + ( + oid = oid , + opcmethod = oid , + opcname = name , + opcnamespace = oid , + opcowner = oid , + opcfamily = oid , + opcintype = oid , + opcdefault = bool , + opckeytype = oid + ) +open pg_opclass +insert ( 10000 403 array_ops 11 10 397 2277 t 0 ) +insert ( 10001 405 array_ops 11 10 627 2277 t 0 ) +insert ( 10002 403 bit_ops 11 10 423 1560 t 0 ) +insert ( 10003 403 bool_ops 11 10 424 16 t 0 ) +insert ( 10004 403 bpchar_ops 11 10 426 1042 t 0 ) +insert ( 10005 405 bpchar_ops 11 10 427 1042 t 0 ) +insert ( 10006 403 bytea_ops 11 10 428 17 t 0 ) +insert ( 10007 403 char_ops 11 10 429 18 t 0 ) +insert ( 10008 405 char_ops 11 10 431 18 t 0 ) +insert ( 10009 403 cidr_ops 11 10 1974 869 f 0 ) +insert ( 10010 405 cidr_ops 11 10 1975 869 f 0 ) +insert ( 3122 403 date_ops 11 10 434 1082 t 0 ) +insert ( 10011 405 date_ops 11 10 435 1082 t 0 ) +insert ( 10012 403 float4_ops 11 10 1970 700 t 0 ) +insert ( 10013 405 float4_ops 11 10 1971 700 t 0 ) +insert ( 3123 403 float8_ops 11 10 1970 701 t 0 ) +insert ( 10014 405 float8_ops 11 10 1971 701 t 0 ) +insert ( 10015 403 inet_ops 11 10 1974 869 t 0 ) +insert ( 10016 405 inet_ops 11 10 1975 869 t 0 ) +insert ( 10017 783 inet_ops 11 10 3550 869 f 0 ) +insert ( 10018 4000 inet_ops 11 10 3794 869 t 0 ) +insert ( 1979 403 int2_ops 11 10 1976 21 t 0 ) +insert ( 10019 405 int2_ops 11 10 1977 21 t 0 ) +insert ( 1978 403 int4_ops 11 10 1976 23 t 0 ) +insert ( 10020 405 int4_ops 11 10 1977 23 t 0 ) +insert ( 3124 403 int8_ops 11 10 1976 20 t 0 ) +insert ( 10021 405 int8_ops 11 10 1977 20 t 0 ) +insert ( 10022 403 interval_ops 11 10 1982 1186 t 0 ) +insert ( 10023 405 interval_ops 11 10 1983 1186 t 0 ) +insert ( 10024 403 macaddr_ops 11 10 1984 829 t 0 ) +insert ( 10025 405 macaddr_ops 11 10 1985 829 t 0 ) +insert ( 10026 403 macaddr8_ops 11 10 3371 774 t 0 ) +insert ( 10027 405 macaddr8_ops 11 10 3372 774 t 0 ) +insert ( 10028 403 name_ops 11 10 1994 19 t 2275 ) +insert ( 10029 405 name_ops 11 10 1995 19 t 0 ) +insert ( 3125 403 numeric_ops 11 10 1988 1700 t 0 ) +insert ( 10030 405 numeric_ops 11 10 1998 1700 t 0 ) +insert ( 1981 403 oid_ops 11 10 1989 26 t 0 ) +insert ( 10031 405 oid_ops 11 10 1990 26 t 0 ) +insert ( 10032 403 oidvector_ops 11 10 1991 30 t 0 ) +insert ( 10033 405 oidvector_ops 11 10 1992 30 t 0 ) +insert ( 10034 403 record_ops 11 10 2994 2249 t 0 ) +insert ( 10035 403 record_image_ops 11 10 3194 2249 f 0 ) +insert ( 3126 403 text_ops 11 10 1994 25 t 0 ) +insert ( 10036 405 text_ops 11 10 1995 25 t 0 ) +insert ( 10037 403 time_ops 11 10 1996 1083 t 0 ) +insert ( 10038 405 time_ops 11 10 1997 1083 t 0 ) +insert ( 3127 403 timestamptz_ops 11 10 434 1184 t 0 ) +insert ( 10039 405 timestamptz_ops 11 10 1999 1184 t 0 ) +insert ( 10040 403 timetz_ops 11 10 2000 1266 t 0 ) +insert ( 10041 405 timetz_ops 11 10 2001 1266 t 0 ) +insert ( 10042 403 varbit_ops 11 10 2002 1562 t 0 ) +insert ( 10043 403 varchar_ops 11 10 1994 25 f 0 ) +insert ( 10044 405 varchar_ops 11 10 1995 25 f 0 ) +insert ( 3128 403 timestamp_ops 11 10 434 1114 t 0 ) +insert ( 10045 405 timestamp_ops 11 10 2040 1114 t 0 ) +insert ( 4217 403 text_pattern_ops 11 10 2095 25 f 0 ) +insert ( 4218 403 varchar_pattern_ops 11 10 2095 25 f 0 ) +insert ( 4219 403 bpchar_pattern_ops 11 10 2097 1042 f 0 ) +insert ( 10046 403 money_ops 11 10 2099 790 t 0 ) +insert ( 10047 405 bool_ops 11 10 2222 16 t 0 ) +insert ( 10048 405 bytea_ops 11 10 2223 17 t 0 ) +insert ( 10049 403 tid_ops 11 10 2789 27 t 0 ) +insert ( 10050 405 xid_ops 11 10 2225 28 t 0 ) +insert ( 10051 405 xid8_ops 11 10 5032 5069 t 0 ) +insert ( 10052 403 xid8_ops 11 10 5067 5069 t 0 ) +insert ( 10053 405 cid_ops 11 10 2226 29 t 0 ) +insert ( 10054 405 tid_ops 11 10 2227 27 t 0 ) +insert ( 10055 405 text_pattern_ops 11 10 2229 25 f 0 ) +insert ( 10056 405 varchar_pattern_ops 11 10 2229 25 f 0 ) +insert ( 10057 405 bpchar_pattern_ops 11 10 2231 1042 f 0 ) +insert ( 10058 405 aclitem_ops 11 10 2235 1033 t 0 ) +insert ( 10059 783 box_ops 11 10 2593 603 t 0 ) +insert ( 10060 783 point_ops 11 10 1029 600 t 603 ) +insert ( 10061 783 poly_ops 11 10 2594 604 t 603 ) +insert ( 10062 783 circle_ops 11 10 2595 718 t 603 ) +insert ( 10063 2742 array_ops 11 10 2745 2277 t 2283 ) +insert ( 10064 403 uuid_ops 11 10 2968 2950 t 0 ) +insert ( 10065 405 uuid_ops 11 10 2969 2950 t 0 ) +insert ( 10066 403 pg_lsn_ops 11 10 3253 3220 t 0 ) +insert ( 10067 405 pg_lsn_ops 11 10 3254 3220 t 0 ) +insert ( 10068 403 enum_ops 11 10 3522 3500 t 0 ) +insert ( 10069 405 enum_ops 11 10 3523 3500 t 0 ) +insert ( 10070 403 tsvector_ops 11 10 3626 3614 t 0 ) +insert ( 10071 783 tsvector_ops 11 10 3655 3614 t 3642 ) +insert ( 10072 2742 tsvector_ops 11 10 3659 3614 t 25 ) +insert ( 10073 403 tsquery_ops 11 10 3683 3615 t 0 ) +insert ( 10074 783 tsquery_ops 11 10 3702 3615 t 20 ) +insert ( 10075 403 range_ops 11 10 3901 3831 t 0 ) +insert ( 10076 405 range_ops 11 10 3903 3831 t 0 ) +insert ( 10077 783 range_ops 11 10 3919 3831 t 0 ) +insert ( 10078 4000 range_ops 11 10 3474 3831 t 0 ) +insert ( 10079 4000 box_ops 11 10 5000 603 t 0 ) +insert ( 10080 4000 quad_point_ops 11 10 4015 600 t 0 ) +insert ( 10081 4000 kd_point_ops 11 10 4016 600 f 0 ) +insert ( 10082 4000 text_ops 11 10 4017 25 t 0 ) +insert ( 10083 4000 poly_ops 11 10 5008 604 t 603 ) +insert ( 10084 403 jsonb_ops 11 10 4033 3802 t 0 ) +insert ( 10085 405 jsonb_ops 11 10 4034 3802 t 0 ) +insert ( 10086 2742 jsonb_ops 11 10 4036 3802 t 25 ) +insert ( 10087 2742 jsonb_path_ops 11 10 4037 3802 f 23 ) +insert ( 10088 3580 bytea_minmax_ops 11 10 4064 17 t 17 ) +insert ( 10089 3580 char_minmax_ops 11 10 4062 18 t 18 ) +insert ( 10090 3580 name_minmax_ops 11 10 4065 19 t 19 ) +insert ( 10091 3580 int8_minmax_ops 11 10 4054 20 t 20 ) +insert ( 10092 3580 int2_minmax_ops 11 10 4054 21 t 21 ) +insert ( 10093 3580 int4_minmax_ops 11 10 4054 23 t 23 ) +insert ( 10094 3580 text_minmax_ops 11 10 4056 25 t 25 ) +insert ( 10095 3580 oid_minmax_ops 11 10 4068 26 t 26 ) +insert ( 10096 3580 tid_minmax_ops 11 10 4069 27 t 27 ) +insert ( 10097 3580 float4_minmax_ops 11 10 4070 700 t 700 ) +insert ( 10098 3580 float8_minmax_ops 11 10 4070 701 t 701 ) +insert ( 10099 3580 macaddr_minmax_ops 11 10 4074 829 t 829 ) +insert ( 10100 3580 macaddr8_minmax_ops 11 10 4109 774 t 774 ) +insert ( 10101 3580 inet_minmax_ops 11 10 4075 869 f 869 ) +insert ( 10102 3580 inet_inclusion_ops 11 10 4102 869 t 869 ) +insert ( 10103 3580 bpchar_minmax_ops 11 10 4076 1042 t 1042 ) +insert ( 10104 3580 time_minmax_ops 11 10 4077 1083 t 1083 ) +insert ( 10105 3580 date_minmax_ops 11 10 4059 1082 t 1082 ) +insert ( 10106 3580 timestamp_minmax_ops 11 10 4059 1114 t 1114 ) +insert ( 10107 3580 timestamptz_minmax_ops 11 10 4059 1184 t 1184 ) +insert ( 10108 3580 interval_minmax_ops 11 10 4078 1186 t 1186 ) +insert ( 10109 3580 timetz_minmax_ops 11 10 4058 1266 t 1266 ) +insert ( 10110 3580 bit_minmax_ops 11 10 4079 1560 t 1560 ) +insert ( 10111 3580 varbit_minmax_ops 11 10 4080 1562 t 1562 ) +insert ( 10112 3580 numeric_minmax_ops 11 10 4055 1700 t 1700 ) +insert ( 10113 3580 uuid_minmax_ops 11 10 4081 2950 t 2950 ) +insert ( 10114 3580 range_inclusion_ops 11 10 4103 3831 t 3831 ) +insert ( 10115 3580 pg_lsn_minmax_ops 11 10 4082 3220 t 3220 ) +insert ( 10116 3580 box_inclusion_ops 11 10 4104 603 t 603 ) +close pg_opclass +create pg_am 2601 + ( + oid = oid , + amname = name , + amhandler = regproc , + amtype = char + ) +open pg_am +insert ( 2 heap 3 t ) +insert ( 403 btree 330 i ) +insert ( 405 hash 331 i ) +insert ( 783 gist 332 i ) +insert ( 2742 gin 333 i ) +insert ( 4000 spgist 334 i ) +insert ( 3580 brin 335 i ) +close pg_am +create pg_amop 2602 + ( + oid = oid , + amopfamily = oid , + amoplefttype = oid , + amoprighttype = oid , + amopstrategy = int2 , + amoppurpose = char , + amopopr = oid , + amopmethod = oid , + amopsortfamily = oid + ) +open pg_amop +insert ( 10117 1976 21 21 1 s 95 403 0 ) +insert ( 10118 1976 21 21 2 s 522 403 0 ) +insert ( 10119 1976 21 21 3 s 94 403 0 ) +insert ( 10120 1976 21 21 4 s 524 403 0 ) +insert ( 10121 1976 21 21 5 s 520 403 0 ) +insert ( 10122 1976 21 23 1 s 534 403 0 ) +insert ( 10123 1976 21 23 2 s 540 403 0 ) +insert ( 10124 1976 21 23 3 s 532 403 0 ) +insert ( 10125 1976 21 23 4 s 542 403 0 ) +insert ( 10126 1976 21 23 5 s 536 403 0 ) +insert ( 10127 1976 21 20 1 s 1864 403 0 ) +insert ( 10128 1976 21 20 2 s 1866 403 0 ) +insert ( 10129 1976 21 20 3 s 1862 403 0 ) +insert ( 10130 1976 21 20 4 s 1867 403 0 ) +insert ( 10131 1976 21 20 5 s 1865 403 0 ) +insert ( 10132 1976 23 23 1 s 97 403 0 ) +insert ( 10133 1976 23 23 2 s 523 403 0 ) +insert ( 10134 1976 23 23 3 s 96 403 0 ) +insert ( 10135 1976 23 23 4 s 525 403 0 ) +insert ( 10136 1976 23 23 5 s 521 403 0 ) +insert ( 10137 1976 23 21 1 s 535 403 0 ) +insert ( 10138 1976 23 21 2 s 541 403 0 ) +insert ( 10139 1976 23 21 3 s 533 403 0 ) +insert ( 10140 1976 23 21 4 s 543 403 0 ) +insert ( 10141 1976 23 21 5 s 537 403 0 ) +insert ( 10142 1976 23 20 1 s 37 403 0 ) +insert ( 10143 1976 23 20 2 s 80 403 0 ) +insert ( 10144 1976 23 20 3 s 15 403 0 ) +insert ( 10145 1976 23 20 4 s 82 403 0 ) +insert ( 10146 1976 23 20 5 s 76 403 0 ) +insert ( 10147 1976 20 20 1 s 412 403 0 ) +insert ( 10148 1976 20 20 2 s 414 403 0 ) +insert ( 10149 1976 20 20 3 s 410 403 0 ) +insert ( 10150 1976 20 20 4 s 415 403 0 ) +insert ( 10151 1976 20 20 5 s 413 403 0 ) +insert ( 10152 1976 20 21 1 s 1870 403 0 ) +insert ( 10153 1976 20 21 2 s 1872 403 0 ) +insert ( 10154 1976 20 21 3 s 1868 403 0 ) +insert ( 10155 1976 20 21 4 s 1873 403 0 ) +insert ( 10156 1976 20 21 5 s 1871 403 0 ) +insert ( 10157 1976 20 23 1 s 418 403 0 ) +insert ( 10158 1976 20 23 2 s 420 403 0 ) +insert ( 10159 1976 20 23 3 s 416 403 0 ) +insert ( 10160 1976 20 23 4 s 430 403 0 ) +insert ( 10161 1976 20 23 5 s 419 403 0 ) +insert ( 10162 1989 26 26 1 s 609 403 0 ) +insert ( 10163 1989 26 26 2 s 611 403 0 ) +insert ( 10164 1989 26 26 3 s 607 403 0 ) +insert ( 10165 1989 26 26 4 s 612 403 0 ) +insert ( 10166 1989 26 26 5 s 610 403 0 ) +insert ( 10167 5067 5069 5069 1 s 5073 403 0 ) +insert ( 10168 5067 5069 5069 2 s 5075 403 0 ) +insert ( 10169 5067 5069 5069 3 s 5068 403 0 ) +insert ( 10170 5067 5069 5069 4 s 5076 403 0 ) +insert ( 10171 5067 5069 5069 5 s 5074 403 0 ) +insert ( 10172 2789 27 27 1 s 2799 403 0 ) +insert ( 10173 2789 27 27 2 s 2801 403 0 ) +insert ( 10174 2789 27 27 3 s 387 403 0 ) +insert ( 10175 2789 27 27 4 s 2802 403 0 ) +insert ( 10176 2789 27 27 5 s 2800 403 0 ) +insert ( 10177 1991 30 30 1 s 645 403 0 ) +insert ( 10178 1991 30 30 2 s 647 403 0 ) +insert ( 10179 1991 30 30 3 s 649 403 0 ) +insert ( 10180 1991 30 30 4 s 648 403 0 ) +insert ( 10181 1991 30 30 5 s 646 403 0 ) +insert ( 10182 1970 700 700 1 s 622 403 0 ) +insert ( 10183 1970 700 700 2 s 624 403 0 ) +insert ( 10184 1970 700 700 3 s 620 403 0 ) +insert ( 10185 1970 700 700 4 s 625 403 0 ) +insert ( 10186 1970 700 700 5 s 623 403 0 ) +insert ( 10187 1970 700 701 1 s 1122 403 0 ) +insert ( 10188 1970 700 701 2 s 1124 403 0 ) +insert ( 10189 1970 700 701 3 s 1120 403 0 ) +insert ( 10190 1970 700 701 4 s 1125 403 0 ) +insert ( 10191 1970 700 701 5 s 1123 403 0 ) +insert ( 10192 1970 701 701 1 s 672 403 0 ) +insert ( 10193 1970 701 701 2 s 673 403 0 ) +insert ( 10194 1970 701 701 3 s 670 403 0 ) +insert ( 10195 1970 701 701 4 s 675 403 0 ) +insert ( 10196 1970 701 701 5 s 674 403 0 ) +insert ( 10197 1970 701 700 1 s 1132 403 0 ) +insert ( 10198 1970 701 700 2 s 1134 403 0 ) +insert ( 10199 1970 701 700 3 s 1130 403 0 ) +insert ( 10200 1970 701 700 4 s 1135 403 0 ) +insert ( 10201 1970 701 700 5 s 1133 403 0 ) +insert ( 10202 429 18 18 1 s 631 403 0 ) +insert ( 10203 429 18 18 2 s 632 403 0 ) +insert ( 10204 429 18 18 3 s 92 403 0 ) +insert ( 10205 429 18 18 4 s 634 403 0 ) +insert ( 10206 429 18 18 5 s 633 403 0 ) +insert ( 10207 1994 25 25 1 s 664 403 0 ) +insert ( 10208 1994 25 25 2 s 665 403 0 ) +insert ( 10209 1994 25 25 3 s 98 403 0 ) +insert ( 10210 1994 25 25 4 s 667 403 0 ) +insert ( 10211 1994 25 25 5 s 666 403 0 ) +insert ( 10212 1994 19 19 1 s 660 403 0 ) +insert ( 10213 1994 19 19 2 s 661 403 0 ) +insert ( 10214 1994 19 19 3 s 93 403 0 ) +insert ( 10215 1994 19 19 4 s 663 403 0 ) +insert ( 10216 1994 19 19 5 s 662 403 0 ) +insert ( 10217 1994 19 25 1 s 255 403 0 ) +insert ( 10218 1994 19 25 2 s 256 403 0 ) +insert ( 10219 1994 19 25 3 s 254 403 0 ) +insert ( 10220 1994 19 25 4 s 257 403 0 ) +insert ( 10221 1994 19 25 5 s 258 403 0 ) +insert ( 10222 1994 25 19 1 s 261 403 0 ) +insert ( 10223 1994 25 19 2 s 262 403 0 ) +insert ( 10224 1994 25 19 3 s 260 403 0 ) +insert ( 10225 1994 25 19 4 s 263 403 0 ) +insert ( 10226 1994 25 19 5 s 264 403 0 ) +insert ( 10227 426 1042 1042 1 s 1058 403 0 ) +insert ( 10228 426 1042 1042 2 s 1059 403 0 ) +insert ( 10229 426 1042 1042 3 s 1054 403 0 ) +insert ( 10230 426 1042 1042 4 s 1061 403 0 ) +insert ( 10231 426 1042 1042 5 s 1060 403 0 ) +insert ( 10232 428 17 17 1 s 1957 403 0 ) +insert ( 10233 428 17 17 2 s 1958 403 0 ) +insert ( 10234 428 17 17 3 s 1955 403 0 ) +insert ( 10235 428 17 17 4 s 1960 403 0 ) +insert ( 10236 428 17 17 5 s 1959 403 0 ) +insert ( 10237 434 1082 1082 1 s 1095 403 0 ) +insert ( 10238 434 1082 1082 2 s 1096 403 0 ) +insert ( 10239 434 1082 1082 3 s 1093 403 0 ) +insert ( 10240 434 1082 1082 4 s 1098 403 0 ) +insert ( 10241 434 1082 1082 5 s 1097 403 0 ) +insert ( 10242 434 1082 1114 1 s 2345 403 0 ) +insert ( 10243 434 1082 1114 2 s 2346 403 0 ) +insert ( 10244 434 1082 1114 3 s 2347 403 0 ) +insert ( 10245 434 1082 1114 4 s 2348 403 0 ) +insert ( 10246 434 1082 1114 5 s 2349 403 0 ) +insert ( 10247 434 1082 1184 1 s 2358 403 0 ) +insert ( 10248 434 1082 1184 2 s 2359 403 0 ) +insert ( 10249 434 1082 1184 3 s 2360 403 0 ) +insert ( 10250 434 1082 1184 4 s 2361 403 0 ) +insert ( 10251 434 1082 1184 5 s 2362 403 0 ) +insert ( 10252 434 1114 1114 1 s 2062 403 0 ) +insert ( 10253 434 1114 1114 2 s 2063 403 0 ) +insert ( 10254 434 1114 1114 3 s 2060 403 0 ) +insert ( 10255 434 1114 1114 4 s 2065 403 0 ) +insert ( 10256 434 1114 1114 5 s 2064 403 0 ) +insert ( 10257 434 1114 1082 1 s 2371 403 0 ) +insert ( 10258 434 1114 1082 2 s 2372 403 0 ) +insert ( 10259 434 1114 1082 3 s 2373 403 0 ) +insert ( 10260 434 1114 1082 4 s 2374 403 0 ) +insert ( 10261 434 1114 1082 5 s 2375 403 0 ) +insert ( 10262 434 1114 1184 1 s 2534 403 0 ) +insert ( 10263 434 1114 1184 2 s 2535 403 0 ) +insert ( 10264 434 1114 1184 3 s 2536 403 0 ) +insert ( 10265 434 1114 1184 4 s 2537 403 0 ) +insert ( 10266 434 1114 1184 5 s 2538 403 0 ) +insert ( 10267 434 1184 1184 1 s 1322 403 0 ) +insert ( 10268 434 1184 1184 2 s 1323 403 0 ) +insert ( 10269 434 1184 1184 3 s 1320 403 0 ) +insert ( 10270 434 1184 1184 4 s 1325 403 0 ) +insert ( 10271 434 1184 1184 5 s 1324 403 0 ) +insert ( 10272 434 1184 1082 1 s 2384 403 0 ) +insert ( 10273 434 1184 1082 2 s 2385 403 0 ) +insert ( 10274 434 1184 1082 3 s 2386 403 0 ) +insert ( 10275 434 1184 1082 4 s 2387 403 0 ) +insert ( 10276 434 1184 1082 5 s 2388 403 0 ) +insert ( 10277 434 1184 1114 1 s 2540 403 0 ) +insert ( 10278 434 1184 1114 2 s 2541 403 0 ) +insert ( 10279 434 1184 1114 3 s 2542 403 0 ) +insert ( 10280 434 1184 1114 4 s 2543 403 0 ) +insert ( 10281 434 1184 1114 5 s 2544 403 0 ) +insert ( 10282 1996 1083 1083 1 s 1110 403 0 ) +insert ( 10283 1996 1083 1083 2 s 1111 403 0 ) +insert ( 10284 1996 1083 1083 3 s 1108 403 0 ) +insert ( 10285 1996 1083 1083 4 s 1113 403 0 ) +insert ( 10286 1996 1083 1083 5 s 1112 403 0 ) +insert ( 10287 2000 1266 1266 1 s 1552 403 0 ) +insert ( 10288 2000 1266 1266 2 s 1553 403 0 ) +insert ( 10289 2000 1266 1266 3 s 1550 403 0 ) +insert ( 10290 2000 1266 1266 4 s 1555 403 0 ) +insert ( 10291 2000 1266 1266 5 s 1554 403 0 ) +insert ( 10292 1982 1186 1186 1 s 1332 403 0 ) +insert ( 10293 1982 1186 1186 2 s 1333 403 0 ) +insert ( 10294 1982 1186 1186 3 s 1330 403 0 ) +insert ( 10295 1982 1186 1186 4 s 1335 403 0 ) +insert ( 10296 1982 1186 1186 5 s 1334 403 0 ) +insert ( 10297 1984 829 829 1 s 1222 403 0 ) +insert ( 10298 1984 829 829 2 s 1223 403 0 ) +insert ( 10299 1984 829 829 3 s 1220 403 0 ) +insert ( 10300 1984 829 829 4 s 1225 403 0 ) +insert ( 10301 1984 829 829 5 s 1224 403 0 ) +insert ( 10302 3371 774 774 1 s 3364 403 0 ) +insert ( 10303 3371 774 774 2 s 3365 403 0 ) +insert ( 10304 3371 774 774 3 s 3362 403 0 ) +insert ( 10305 3371 774 774 4 s 3367 403 0 ) +insert ( 10306 3371 774 774 5 s 3366 403 0 ) +insert ( 10307 1974 869 869 1 s 1203 403 0 ) +insert ( 10308 1974 869 869 2 s 1204 403 0 ) +insert ( 10309 1974 869 869 3 s 1201 403 0 ) +insert ( 10310 1974 869 869 4 s 1206 403 0 ) +insert ( 10311 1974 869 869 5 s 1205 403 0 ) +insert ( 10312 1988 1700 1700 1 s 1754 403 0 ) +insert ( 10313 1988 1700 1700 2 s 1755 403 0 ) +insert ( 10314 1988 1700 1700 3 s 1752 403 0 ) +insert ( 10315 1988 1700 1700 4 s 1757 403 0 ) +insert ( 10316 1988 1700 1700 5 s 1756 403 0 ) +insert ( 10317 424 16 16 1 s 58 403 0 ) +insert ( 10318 424 16 16 2 s 1694 403 0 ) +insert ( 10319 424 16 16 3 s 91 403 0 ) +insert ( 10320 424 16 16 4 s 1695 403 0 ) +insert ( 10321 424 16 16 5 s 59 403 0 ) +insert ( 10322 423 1560 1560 1 s 1786 403 0 ) +insert ( 10323 423 1560 1560 2 s 1788 403 0 ) +insert ( 10324 423 1560 1560 3 s 1784 403 0 ) +insert ( 10325 423 1560 1560 4 s 1789 403 0 ) +insert ( 10326 423 1560 1560 5 s 1787 403 0 ) +insert ( 10327 2002 1562 1562 1 s 1806 403 0 ) +insert ( 10328 2002 1562 1562 2 s 1808 403 0 ) +insert ( 10329 2002 1562 1562 3 s 1804 403 0 ) +insert ( 10330 2002 1562 1562 4 s 1809 403 0 ) +insert ( 10331 2002 1562 1562 5 s 1807 403 0 ) +insert ( 10332 2095 25 25 1 s 2314 403 0 ) +insert ( 10333 2095 25 25 2 s 2315 403 0 ) +insert ( 10334 2095 25 25 3 s 98 403 0 ) +insert ( 10335 2095 25 25 4 s 2317 403 0 ) +insert ( 10336 2095 25 25 5 s 2318 403 0 ) +insert ( 10337 2097 1042 1042 1 s 2326 403 0 ) +insert ( 10338 2097 1042 1042 2 s 2327 403 0 ) +insert ( 10339 2097 1042 1042 3 s 1054 403 0 ) +insert ( 10340 2097 1042 1042 4 s 2329 403 0 ) +insert ( 10341 2097 1042 1042 5 s 2330 403 0 ) +insert ( 10342 2099 790 790 1 s 902 403 0 ) +insert ( 10343 2099 790 790 2 s 904 403 0 ) +insert ( 10344 2099 790 790 3 s 900 403 0 ) +insert ( 10345 2099 790 790 4 s 905 403 0 ) +insert ( 10346 2099 790 790 5 s 903 403 0 ) +insert ( 10347 397 2277 2277 1 s 1072 403 0 ) +insert ( 10348 397 2277 2277 2 s 1074 403 0 ) +insert ( 10349 397 2277 2277 3 s 1070 403 0 ) +insert ( 10350 397 2277 2277 4 s 1075 403 0 ) +insert ( 10351 397 2277 2277 5 s 1073 403 0 ) +insert ( 10352 2994 2249 2249 1 s 2990 403 0 ) +insert ( 10353 2994 2249 2249 2 s 2992 403 0 ) +insert ( 10354 2994 2249 2249 3 s 2988 403 0 ) +insert ( 10355 2994 2249 2249 4 s 2993 403 0 ) +insert ( 10356 2994 2249 2249 5 s 2991 403 0 ) +insert ( 10357 3194 2249 2249 1 s 3190 403 0 ) +insert ( 10358 3194 2249 2249 2 s 3192 403 0 ) +insert ( 10359 3194 2249 2249 3 s 3188 403 0 ) +insert ( 10360 3194 2249 2249 4 s 3193 403 0 ) +insert ( 10361 3194 2249 2249 5 s 3191 403 0 ) +insert ( 10362 2968 2950 2950 1 s 2974 403 0 ) +insert ( 10363 2968 2950 2950 2 s 2976 403 0 ) +insert ( 10364 2968 2950 2950 3 s 2972 403 0 ) +insert ( 10365 2968 2950 2950 4 s 2977 403 0 ) +insert ( 10366 2968 2950 2950 5 s 2975 403 0 ) +insert ( 10367 3253 3220 3220 1 s 3224 403 0 ) +insert ( 10368 3253 3220 3220 2 s 3226 403 0 ) +insert ( 10369 3253 3220 3220 3 s 3222 403 0 ) +insert ( 10370 3253 3220 3220 4 s 3227 403 0 ) +insert ( 10371 3253 3220 3220 5 s 3225 403 0 ) +insert ( 10372 427 1042 1042 1 s 1054 405 0 ) +insert ( 10373 431 18 18 1 s 92 405 0 ) +insert ( 10374 435 1082 1082 1 s 1093 405 0 ) +insert ( 10375 1971 700 700 1 s 620 405 0 ) +insert ( 10376 1971 701 701 1 s 670 405 0 ) +insert ( 10377 1971 700 701 1 s 1120 405 0 ) +insert ( 10378 1971 701 700 1 s 1130 405 0 ) +insert ( 10379 1975 869 869 1 s 1201 405 0 ) +insert ( 10380 1977 21 21 1 s 94 405 0 ) +insert ( 10381 1977 23 23 1 s 96 405 0 ) +insert ( 10382 1977 20 20 1 s 410 405 0 ) +insert ( 10383 1977 21 23 1 s 532 405 0 ) +insert ( 10384 1977 21 20 1 s 1862 405 0 ) +insert ( 10385 1977 23 21 1 s 533 405 0 ) +insert ( 10386 1977 23 20 1 s 15 405 0 ) +insert ( 10387 1977 20 21 1 s 1868 405 0 ) +insert ( 10388 1977 20 23 1 s 416 405 0 ) +insert ( 10389 1983 1186 1186 1 s 1330 405 0 ) +insert ( 10390 1985 829 829 1 s 1220 405 0 ) +insert ( 10391 3372 774 774 1 s 3362 405 0 ) +insert ( 10392 1990 26 26 1 s 607 405 0 ) +insert ( 10393 1992 30 30 1 s 649 405 0 ) +insert ( 10394 1995 25 25 1 s 98 405 0 ) +insert ( 10395 1995 19 19 1 s 93 405 0 ) +insert ( 10396 1995 19 25 1 s 254 405 0 ) +insert ( 10397 1995 25 19 1 s 260 405 0 ) +insert ( 10398 1997 1083 1083 1 s 1108 405 0 ) +insert ( 10399 1999 1184 1184 1 s 1320 405 0 ) +insert ( 10400 2001 1266 1266 1 s 1550 405 0 ) +insert ( 10401 2040 1114 1114 1 s 2060 405 0 ) +insert ( 10402 2222 16 16 1 s 91 405 0 ) +insert ( 10403 2223 17 17 1 s 1955 405 0 ) +insert ( 10404 2225 28 28 1 s 352 405 0 ) +insert ( 10405 5032 5069 5069 1 s 5068 405 0 ) +insert ( 10406 2226 29 29 1 s 385 405 0 ) +insert ( 10407 2227 27 27 1 s 387 405 0 ) +insert ( 10408 2229 25 25 1 s 98 405 0 ) +insert ( 10409 2231 1042 1042 1 s 1054 405 0 ) +insert ( 10410 2235 1033 1033 1 s 974 405 0 ) +insert ( 10411 2969 2950 2950 1 s 2972 405 0 ) +insert ( 10412 3254 3220 3220 1 s 3222 405 0 ) +insert ( 10413 1998 1700 1700 1 s 1752 405 0 ) +insert ( 10414 627 2277 2277 1 s 1070 405 0 ) +insert ( 10415 2593 603 603 1 s 493 783 0 ) +insert ( 10416 2593 603 603 2 s 494 783 0 ) +insert ( 10417 2593 603 603 3 s 500 783 0 ) +insert ( 10418 2593 603 603 4 s 495 783 0 ) +insert ( 10419 2593 603 603 5 s 496 783 0 ) +insert ( 10420 2593 603 603 6 s 499 783 0 ) +insert ( 10421 2593 603 603 7 s 498 783 0 ) +insert ( 10422 2593 603 603 8 s 497 783 0 ) +insert ( 10423 2593 603 603 9 s 2571 783 0 ) +insert ( 10424 2593 603 603 10 s 2570 783 0 ) +insert ( 10425 2593 603 603 11 s 2573 783 0 ) +insert ( 10426 2593 603 603 12 s 2572 783 0 ) +insert ( 10427 2593 603 603 13 s 2863 783 0 ) +insert ( 10428 2593 603 603 14 s 2862 783 0 ) +insert ( 10429 2593 603 600 15 o 606 783 1970 ) +insert ( 10430 1029 600 600 11 s 506 783 0 ) +insert ( 10431 1029 600 600 1 s 507 783 0 ) +insert ( 10432 1029 600 600 5 s 508 783 0 ) +insert ( 10433 1029 600 600 10 s 509 783 0 ) +insert ( 10434 1029 600 600 6 s 510 783 0 ) +insert ( 10435 1029 600 600 15 o 517 783 1970 ) +insert ( 10436 1029 600 603 28 s 511 783 0 ) +insert ( 10437 1029 600 604 48 s 756 783 0 ) +insert ( 10438 1029 600 718 68 s 758 783 0 ) +insert ( 10439 2594 604 604 1 s 485 783 0 ) +insert ( 10440 2594 604 604 2 s 486 783 0 ) +insert ( 10441 2594 604 604 3 s 492 783 0 ) +insert ( 10442 2594 604 604 4 s 487 783 0 ) +insert ( 10443 2594 604 604 5 s 488 783 0 ) +insert ( 10444 2594 604 604 6 s 491 783 0 ) +insert ( 10445 2594 604 604 7 s 490 783 0 ) +insert ( 10446 2594 604 604 8 s 489 783 0 ) +insert ( 10447 2594 604 604 9 s 2575 783 0 ) +insert ( 10448 2594 604 604 10 s 2574 783 0 ) +insert ( 10449 2594 604 604 11 s 2577 783 0 ) +insert ( 10450 2594 604 604 12 s 2576 783 0 ) +insert ( 10451 2594 604 604 13 s 2861 783 0 ) +insert ( 10452 2594 604 604 14 s 2860 783 0 ) +insert ( 10453 2594 604 600 15 o 3289 783 1970 ) +insert ( 10454 2595 718 718 1 s 1506 783 0 ) +insert ( 10455 2595 718 718 2 s 1507 783 0 ) +insert ( 10456 2595 718 718 3 s 1513 783 0 ) +insert ( 10457 2595 718 718 4 s 1508 783 0 ) +insert ( 10458 2595 718 718 5 s 1509 783 0 ) +insert ( 10459 2595 718 718 6 s 1512 783 0 ) +insert ( 10460 2595 718 718 7 s 1511 783 0 ) +insert ( 10461 2595 718 718 8 s 1510 783 0 ) +insert ( 10462 2595 718 718 9 s 2589 783 0 ) +insert ( 10463 2595 718 718 10 s 1515 783 0 ) +insert ( 10464 2595 718 718 11 s 1514 783 0 ) +insert ( 10465 2595 718 718 12 s 2590 783 0 ) +insert ( 10466 2595 718 718 13 s 2865 783 0 ) +insert ( 10467 2595 718 718 14 s 2864 783 0 ) +insert ( 10468 2595 718 600 15 o 3291 783 1970 ) +insert ( 10469 2745 2277 2277 1 s 2750 2742 0 ) +insert ( 10470 2745 2277 2277 2 s 2751 2742 0 ) +insert ( 10471 2745 2277 2277 3 s 2752 2742 0 ) +insert ( 10472 2745 2277 2277 4 s 1070 2742 0 ) +insert ( 10473 3522 3500 3500 1 s 3518 403 0 ) +insert ( 10474 3522 3500 3500 2 s 3520 403 0 ) +insert ( 10475 3522 3500 3500 3 s 3516 403 0 ) +insert ( 10476 3522 3500 3500 4 s 3521 403 0 ) +insert ( 10477 3522 3500 3500 5 s 3519 403 0 ) +insert ( 10478 3523 3500 3500 1 s 3516 405 0 ) +insert ( 10479 3626 3614 3614 1 s 3627 403 0 ) +insert ( 10480 3626 3614 3614 2 s 3628 403 0 ) +insert ( 10481 3626 3614 3614 3 s 3629 403 0 ) +insert ( 10482 3626 3614 3614 4 s 3631 403 0 ) +insert ( 10483 3626 3614 3614 5 s 3632 403 0 ) +insert ( 10484 3655 3614 3615 1 s 3636 783 0 ) +insert ( 10485 3659 3614 3615 1 s 3636 2742 0 ) +insert ( 10486 3659 3614 3615 2 s 3660 2742 0 ) +insert ( 10487 3683 3615 3615 1 s 3674 403 0 ) +insert ( 10488 3683 3615 3615 2 s 3675 403 0 ) +insert ( 10489 3683 3615 3615 3 s 3676 403 0 ) +insert ( 10490 3683 3615 3615 4 s 3678 403 0 ) +insert ( 10491 3683 3615 3615 5 s 3679 403 0 ) +insert ( 10492 3702 3615 3615 7 s 3693 783 0 ) +insert ( 10493 3702 3615 3615 8 s 3694 783 0 ) +insert ( 10494 3901 3831 3831 1 s 3884 403 0 ) +insert ( 10495 3901 3831 3831 2 s 3885 403 0 ) +insert ( 10496 3901 3831 3831 3 s 3882 403 0 ) +insert ( 10497 3901 3831 3831 4 s 3886 403 0 ) +insert ( 10498 3901 3831 3831 5 s 3887 403 0 ) +insert ( 10499 3903 3831 3831 1 s 3882 405 0 ) +insert ( 10500 3919 3831 3831 1 s 3893 783 0 ) +insert ( 10501 3919 3831 3831 2 s 3895 783 0 ) +insert ( 10502 3919 3831 3831 3 s 3888 783 0 ) +insert ( 10503 3919 3831 3831 4 s 3896 783 0 ) +insert ( 10504 3919 3831 3831 5 s 3894 783 0 ) +insert ( 10505 3919 3831 3831 6 s 3897 783 0 ) +insert ( 10506 3919 3831 3831 7 s 3890 783 0 ) +insert ( 10507 3919 3831 3831 8 s 3892 783 0 ) +insert ( 10508 3919 3831 2283 16 s 3889 783 0 ) +insert ( 10509 3919 3831 3831 18 s 3882 783 0 ) +insert ( 10510 4015 600 600 11 s 506 4000 0 ) +insert ( 10511 4015 600 600 1 s 507 4000 0 ) +insert ( 10512 4015 600 600 5 s 508 4000 0 ) +insert ( 10513 4015 600 600 10 s 509 4000 0 ) +insert ( 10514 4015 600 600 6 s 510 4000 0 ) +insert ( 10515 4015 600 603 8 s 511 4000 0 ) +insert ( 10516 4015 600 600 15 o 517 4000 1970 ) +insert ( 10517 4016 600 600 11 s 506 4000 0 ) +insert ( 10518 4016 600 600 1 s 507 4000 0 ) +insert ( 10519 4016 600 600 5 s 508 4000 0 ) +insert ( 10520 4016 600 600 10 s 509 4000 0 ) +insert ( 10521 4016 600 600 6 s 510 4000 0 ) +insert ( 10522 4016 600 603 8 s 511 4000 0 ) +insert ( 10523 4016 600 600 15 o 517 4000 1970 ) +insert ( 10524 4017 25 25 1 s 2314 4000 0 ) +insert ( 10525 4017 25 25 2 s 2315 4000 0 ) +insert ( 10526 4017 25 25 3 s 98 4000 0 ) +insert ( 10527 4017 25 25 4 s 2317 4000 0 ) +insert ( 10528 4017 25 25 5 s 2318 4000 0 ) +insert ( 10529 4017 25 25 11 s 664 4000 0 ) +insert ( 10530 4017 25 25 12 s 665 4000 0 ) +insert ( 10531 4017 25 25 14 s 667 4000 0 ) +insert ( 10532 4017 25 25 15 s 666 4000 0 ) +insert ( 10533 4017 25 25 28 s 3877 4000 0 ) +insert ( 10534 4033 3802 3802 1 s 3242 403 0 ) +insert ( 10535 4033 3802 3802 2 s 3244 403 0 ) +insert ( 10536 4033 3802 3802 3 s 3240 403 0 ) +insert ( 10537 4033 3802 3802 4 s 3245 403 0 ) +insert ( 10538 4033 3802 3802 5 s 3243 403 0 ) +insert ( 10539 4034 3802 3802 1 s 3240 405 0 ) +insert ( 10540 4036 3802 3802 7 s 3246 2742 0 ) +insert ( 10541 4036 3802 25 9 s 3247 2742 0 ) +insert ( 10542 4036 3802 1009 10 s 3248 2742 0 ) +insert ( 10543 4036 3802 1009 11 s 3249 2742 0 ) +insert ( 10544 4036 3802 4072 15 s 4012 2742 0 ) +insert ( 10545 4036 3802 4072 16 s 4013 2742 0 ) +insert ( 10546 4037 3802 3802 7 s 3246 2742 0 ) +insert ( 10547 4037 3802 4072 15 s 4012 2742 0 ) +insert ( 10548 4037 3802 4072 16 s 4013 2742 0 ) +insert ( 10549 3474 3831 3831 1 s 3893 4000 0 ) +insert ( 10550 3474 3831 3831 2 s 3895 4000 0 ) +insert ( 10551 3474 3831 3831 3 s 3888 4000 0 ) +insert ( 10552 3474 3831 3831 4 s 3896 4000 0 ) +insert ( 10553 3474 3831 3831 5 s 3894 4000 0 ) +insert ( 10554 3474 3831 3831 6 s 3897 4000 0 ) +insert ( 10555 3474 3831 3831 7 s 3890 4000 0 ) +insert ( 10556 3474 3831 3831 8 s 3892 4000 0 ) +insert ( 10557 3474 3831 2283 16 s 3889 4000 0 ) +insert ( 10558 3474 3831 3831 18 s 3882 4000 0 ) +insert ( 10559 5000 603 603 1 s 493 4000 0 ) +insert ( 10560 5000 603 603 2 s 494 4000 0 ) +insert ( 10561 5000 603 603 3 s 500 4000 0 ) +insert ( 10562 5000 603 603 4 s 495 4000 0 ) +insert ( 10563 5000 603 603 5 s 496 4000 0 ) +insert ( 10564 5000 603 603 6 s 499 4000 0 ) +insert ( 10565 5000 603 603 7 s 498 4000 0 ) +insert ( 10566 5000 603 603 8 s 497 4000 0 ) +insert ( 10567 5000 603 603 9 s 2571 4000 0 ) +insert ( 10568 5000 603 603 10 s 2570 4000 0 ) +insert ( 10569 5000 603 603 11 s 2573 4000 0 ) +insert ( 10570 5000 603 603 12 s 2572 4000 0 ) +insert ( 10571 5000 603 600 15 o 606 4000 1970 ) +insert ( 10572 5008 604 604 1 s 485 4000 0 ) +insert ( 10573 5008 604 604 2 s 486 4000 0 ) +insert ( 10574 5008 604 604 3 s 492 4000 0 ) +insert ( 10575 5008 604 604 4 s 487 4000 0 ) +insert ( 10576 5008 604 604 5 s 488 4000 0 ) +insert ( 10577 5008 604 604 6 s 491 4000 0 ) +insert ( 10578 5008 604 604 7 s 490 4000 0 ) +insert ( 10579 5008 604 604 8 s 489 4000 0 ) +insert ( 10580 5008 604 604 9 s 2575 4000 0 ) +insert ( 10581 5008 604 604 10 s 2574 4000 0 ) +insert ( 10582 5008 604 604 11 s 2577 4000 0 ) +insert ( 10583 5008 604 604 12 s 2576 4000 0 ) +insert ( 10584 5008 604 600 15 o 3289 4000 1970 ) +insert ( 10585 3550 869 869 3 s 3552 783 0 ) +insert ( 10586 3550 869 869 18 s 1201 783 0 ) +insert ( 10587 3550 869 869 19 s 1202 783 0 ) +insert ( 10588 3550 869 869 20 s 1203 783 0 ) +insert ( 10589 3550 869 869 21 s 1204 783 0 ) +insert ( 10590 3550 869 869 22 s 1205 783 0 ) +insert ( 10591 3550 869 869 23 s 1206 783 0 ) +insert ( 10592 3550 869 869 24 s 931 783 0 ) +insert ( 10593 3550 869 869 25 s 932 783 0 ) +insert ( 10594 3550 869 869 26 s 933 783 0 ) +insert ( 10595 3550 869 869 27 s 934 783 0 ) +insert ( 10596 3794 869 869 3 s 3552 4000 0 ) +insert ( 10597 3794 869 869 18 s 1201 4000 0 ) +insert ( 10598 3794 869 869 19 s 1202 4000 0 ) +insert ( 10599 3794 869 869 20 s 1203 4000 0 ) +insert ( 10600 3794 869 869 21 s 1204 4000 0 ) +insert ( 10601 3794 869 869 22 s 1205 4000 0 ) +insert ( 10602 3794 869 869 23 s 1206 4000 0 ) +insert ( 10603 3794 869 869 24 s 931 4000 0 ) +insert ( 10604 3794 869 869 25 s 932 4000 0 ) +insert ( 10605 3794 869 869 26 s 933 4000 0 ) +insert ( 10606 3794 869 869 27 s 934 4000 0 ) +insert ( 10607 4064 17 17 1 s 1957 3580 0 ) +insert ( 10608 4064 17 17 2 s 1958 3580 0 ) +insert ( 10609 4064 17 17 3 s 1955 3580 0 ) +insert ( 10610 4064 17 17 4 s 1960 3580 0 ) +insert ( 10611 4064 17 17 5 s 1959 3580 0 ) +insert ( 10612 4062 18 18 1 s 631 3580 0 ) +insert ( 10613 4062 18 18 2 s 632 3580 0 ) +insert ( 10614 4062 18 18 3 s 92 3580 0 ) +insert ( 10615 4062 18 18 4 s 634 3580 0 ) +insert ( 10616 4062 18 18 5 s 633 3580 0 ) +insert ( 10617 4065 19 19 1 s 660 3580 0 ) +insert ( 10618 4065 19 19 2 s 661 3580 0 ) +insert ( 10619 4065 19 19 3 s 93 3580 0 ) +insert ( 10620 4065 19 19 4 s 663 3580 0 ) +insert ( 10621 4065 19 19 5 s 662 3580 0 ) +insert ( 10622 4054 20 20 1 s 412 3580 0 ) +insert ( 10623 4054 20 20 2 s 414 3580 0 ) +insert ( 10624 4054 20 20 3 s 410 3580 0 ) +insert ( 10625 4054 20 20 4 s 415 3580 0 ) +insert ( 10626 4054 20 20 5 s 413 3580 0 ) +insert ( 10627 4054 20 21 1 s 1870 3580 0 ) +insert ( 10628 4054 20 21 2 s 1872 3580 0 ) +insert ( 10629 4054 20 21 3 s 1868 3580 0 ) +insert ( 10630 4054 20 21 4 s 1873 3580 0 ) +insert ( 10631 4054 20 21 5 s 1871 3580 0 ) +insert ( 10632 4054 20 23 1 s 418 3580 0 ) +insert ( 10633 4054 20 23 2 s 420 3580 0 ) +insert ( 10634 4054 20 23 3 s 416 3580 0 ) +insert ( 10635 4054 20 23 4 s 430 3580 0 ) +insert ( 10636 4054 20 23 5 s 419 3580 0 ) +insert ( 10637 4054 21 21 1 s 95 3580 0 ) +insert ( 10638 4054 21 21 2 s 522 3580 0 ) +insert ( 10639 4054 21 21 3 s 94 3580 0 ) +insert ( 10640 4054 21 21 4 s 524 3580 0 ) +insert ( 10641 4054 21 21 5 s 520 3580 0 ) +insert ( 10642 4054 21 20 1 s 1864 3580 0 ) +insert ( 10643 4054 21 20 2 s 1866 3580 0 ) +insert ( 10644 4054 21 20 3 s 1862 3580 0 ) +insert ( 10645 4054 21 20 4 s 1867 3580 0 ) +insert ( 10646 4054 21 20 5 s 1865 3580 0 ) +insert ( 10647 4054 21 23 1 s 534 3580 0 ) +insert ( 10648 4054 21 23 2 s 540 3580 0 ) +insert ( 10649 4054 21 23 3 s 532 3580 0 ) +insert ( 10650 4054 21 23 4 s 542 3580 0 ) +insert ( 10651 4054 21 23 5 s 536 3580 0 ) +insert ( 10652 4054 23 23 1 s 97 3580 0 ) +insert ( 10653 4054 23 23 2 s 523 3580 0 ) +insert ( 10654 4054 23 23 3 s 96 3580 0 ) +insert ( 10655 4054 23 23 4 s 525 3580 0 ) +insert ( 10656 4054 23 23 5 s 521 3580 0 ) +insert ( 10657 4054 23 21 1 s 535 3580 0 ) +insert ( 10658 4054 23 21 2 s 541 3580 0 ) +insert ( 10659 4054 23 21 3 s 533 3580 0 ) +insert ( 10660 4054 23 21 4 s 543 3580 0 ) +insert ( 10661 4054 23 21 5 s 537 3580 0 ) +insert ( 10662 4054 23 20 1 s 37 3580 0 ) +insert ( 10663 4054 23 20 2 s 80 3580 0 ) +insert ( 10664 4054 23 20 3 s 15 3580 0 ) +insert ( 10665 4054 23 20 4 s 82 3580 0 ) +insert ( 10666 4054 23 20 5 s 76 3580 0 ) +insert ( 10667 4056 25 25 1 s 664 3580 0 ) +insert ( 10668 4056 25 25 2 s 665 3580 0 ) +insert ( 10669 4056 25 25 3 s 98 3580 0 ) +insert ( 10670 4056 25 25 4 s 667 3580 0 ) +insert ( 10671 4056 25 25 5 s 666 3580 0 ) +insert ( 10672 4068 26 26 1 s 609 3580 0 ) +insert ( 10673 4068 26 26 2 s 611 3580 0 ) +insert ( 10674 4068 26 26 3 s 607 3580 0 ) +insert ( 10675 4068 26 26 4 s 612 3580 0 ) +insert ( 10676 4068 26 26 5 s 610 3580 0 ) +insert ( 10677 4069 27 27 1 s 2799 3580 0 ) +insert ( 10678 4069 27 27 2 s 2801 3580 0 ) +insert ( 10679 4069 27 27 3 s 387 3580 0 ) +insert ( 10680 4069 27 27 4 s 2802 3580 0 ) +insert ( 10681 4069 27 27 5 s 2800 3580 0 ) +insert ( 10682 4070 700 700 1 s 622 3580 0 ) +insert ( 10683 4070 700 700 2 s 624 3580 0 ) +insert ( 10684 4070 700 700 3 s 620 3580 0 ) +insert ( 10685 4070 700 700 4 s 625 3580 0 ) +insert ( 10686 4070 700 700 5 s 623 3580 0 ) +insert ( 10687 4070 700 701 1 s 1122 3580 0 ) +insert ( 10688 4070 700 701 2 s 1124 3580 0 ) +insert ( 10689 4070 700 701 3 s 1120 3580 0 ) +insert ( 10690 4070 700 701 4 s 1125 3580 0 ) +insert ( 10691 4070 700 701 5 s 1123 3580 0 ) +insert ( 10692 4070 701 700 1 s 1132 3580 0 ) +insert ( 10693 4070 701 700 2 s 1134 3580 0 ) +insert ( 10694 4070 701 700 3 s 1130 3580 0 ) +insert ( 10695 4070 701 700 4 s 1135 3580 0 ) +insert ( 10696 4070 701 700 5 s 1133 3580 0 ) +insert ( 10697 4070 701 701 1 s 672 3580 0 ) +insert ( 10698 4070 701 701 2 s 673 3580 0 ) +insert ( 10699 4070 701 701 3 s 670 3580 0 ) +insert ( 10700 4070 701 701 4 s 675 3580 0 ) +insert ( 10701 4070 701 701 5 s 674 3580 0 ) +insert ( 10702 4074 829 829 1 s 1222 3580 0 ) +insert ( 10703 4074 829 829 2 s 1223 3580 0 ) +insert ( 10704 4074 829 829 3 s 1220 3580 0 ) +insert ( 10705 4074 829 829 4 s 1225 3580 0 ) +insert ( 10706 4074 829 829 5 s 1224 3580 0 ) +insert ( 10707 4109 774 774 1 s 3364 3580 0 ) +insert ( 10708 4109 774 774 2 s 3365 3580 0 ) +insert ( 10709 4109 774 774 3 s 3362 3580 0 ) +insert ( 10710 4109 774 774 4 s 3367 3580 0 ) +insert ( 10711 4109 774 774 5 s 3366 3580 0 ) +insert ( 10712 4075 869 869 1 s 1203 3580 0 ) +insert ( 10713 4075 869 869 2 s 1204 3580 0 ) +insert ( 10714 4075 869 869 3 s 1201 3580 0 ) +insert ( 10715 4075 869 869 4 s 1206 3580 0 ) +insert ( 10716 4075 869 869 5 s 1205 3580 0 ) +insert ( 10717 4102 869 869 3 s 3552 3580 0 ) +insert ( 10718 4102 869 869 7 s 934 3580 0 ) +insert ( 10719 4102 869 869 8 s 932 3580 0 ) +insert ( 10720 4102 869 869 18 s 1201 3580 0 ) +insert ( 10721 4102 869 869 24 s 933 3580 0 ) +insert ( 10722 4102 869 869 26 s 931 3580 0 ) +insert ( 10723 4076 1042 1042 1 s 1058 3580 0 ) +insert ( 10724 4076 1042 1042 2 s 1059 3580 0 ) +insert ( 10725 4076 1042 1042 3 s 1054 3580 0 ) +insert ( 10726 4076 1042 1042 4 s 1061 3580 0 ) +insert ( 10727 4076 1042 1042 5 s 1060 3580 0 ) +insert ( 10728 4077 1083 1083 1 s 1110 3580 0 ) +insert ( 10729 4077 1083 1083 2 s 1111 3580 0 ) +insert ( 10730 4077 1083 1083 3 s 1108 3580 0 ) +insert ( 10731 4077 1083 1083 4 s 1113 3580 0 ) +insert ( 10732 4077 1083 1083 5 s 1112 3580 0 ) +insert ( 10733 4059 1114 1114 1 s 2062 3580 0 ) +insert ( 10734 4059 1114 1114 2 s 2063 3580 0 ) +insert ( 10735 4059 1114 1114 3 s 2060 3580 0 ) +insert ( 10736 4059 1114 1114 4 s 2065 3580 0 ) +insert ( 10737 4059 1114 1114 5 s 2064 3580 0 ) +insert ( 10738 4059 1114 1082 1 s 2371 3580 0 ) +insert ( 10739 4059 1114 1082 2 s 2372 3580 0 ) +insert ( 10740 4059 1114 1082 3 s 2373 3580 0 ) +insert ( 10741 4059 1114 1082 4 s 2374 3580 0 ) +insert ( 10742 4059 1114 1082 5 s 2375 3580 0 ) +insert ( 10743 4059 1114 1184 1 s 2534 3580 0 ) +insert ( 10744 4059 1114 1184 2 s 2535 3580 0 ) +insert ( 10745 4059 1114 1184 3 s 2536 3580 0 ) +insert ( 10746 4059 1114 1184 4 s 2537 3580 0 ) +insert ( 10747 4059 1114 1184 5 s 2538 3580 0 ) +insert ( 10748 4059 1082 1082 1 s 1095 3580 0 ) +insert ( 10749 4059 1082 1082 2 s 1096 3580 0 ) +insert ( 10750 4059 1082 1082 3 s 1093 3580 0 ) +insert ( 10751 4059 1082 1082 4 s 1098 3580 0 ) +insert ( 10752 4059 1082 1082 5 s 1097 3580 0 ) +insert ( 10753 4059 1082 1114 1 s 2345 3580 0 ) +insert ( 10754 4059 1082 1114 2 s 2346 3580 0 ) +insert ( 10755 4059 1082 1114 3 s 2347 3580 0 ) +insert ( 10756 4059 1082 1114 4 s 2348 3580 0 ) +insert ( 10757 4059 1082 1114 5 s 2349 3580 0 ) +insert ( 10758 4059 1082 1184 1 s 2358 3580 0 ) +insert ( 10759 4059 1082 1184 2 s 2359 3580 0 ) +insert ( 10760 4059 1082 1184 3 s 2360 3580 0 ) +insert ( 10761 4059 1082 1184 4 s 2361 3580 0 ) +insert ( 10762 4059 1082 1184 5 s 2362 3580 0 ) +insert ( 10763 4059 1184 1082 1 s 2384 3580 0 ) +insert ( 10764 4059 1184 1082 2 s 2385 3580 0 ) +insert ( 10765 4059 1184 1082 3 s 2386 3580 0 ) +insert ( 10766 4059 1184 1082 4 s 2387 3580 0 ) +insert ( 10767 4059 1184 1082 5 s 2388 3580 0 ) +insert ( 10768 4059 1184 1114 1 s 2540 3580 0 ) +insert ( 10769 4059 1184 1114 2 s 2541 3580 0 ) +insert ( 10770 4059 1184 1114 3 s 2542 3580 0 ) +insert ( 10771 4059 1184 1114 4 s 2543 3580 0 ) +insert ( 10772 4059 1184 1114 5 s 2544 3580 0 ) +insert ( 10773 4059 1184 1184 1 s 1322 3580 0 ) +insert ( 10774 4059 1184 1184 2 s 1323 3580 0 ) +insert ( 10775 4059 1184 1184 3 s 1320 3580 0 ) +insert ( 10776 4059 1184 1184 4 s 1325 3580 0 ) +insert ( 10777 4059 1184 1184 5 s 1324 3580 0 ) +insert ( 10778 4078 1186 1186 1 s 1332 3580 0 ) +insert ( 10779 4078 1186 1186 2 s 1333 3580 0 ) +insert ( 10780 4078 1186 1186 3 s 1330 3580 0 ) +insert ( 10781 4078 1186 1186 4 s 1335 3580 0 ) +insert ( 10782 4078 1186 1186 5 s 1334 3580 0 ) +insert ( 10783 4058 1266 1266 1 s 1552 3580 0 ) +insert ( 10784 4058 1266 1266 2 s 1553 3580 0 ) +insert ( 10785 4058 1266 1266 3 s 1550 3580 0 ) +insert ( 10786 4058 1266 1266 4 s 1555 3580 0 ) +insert ( 10787 4058 1266 1266 5 s 1554 3580 0 ) +insert ( 10788 4079 1560 1560 1 s 1786 3580 0 ) +insert ( 10789 4079 1560 1560 2 s 1788 3580 0 ) +insert ( 10790 4079 1560 1560 3 s 1784 3580 0 ) +insert ( 10791 4079 1560 1560 4 s 1789 3580 0 ) +insert ( 10792 4079 1560 1560 5 s 1787 3580 0 ) +insert ( 10793 4080 1562 1562 1 s 1806 3580 0 ) +insert ( 10794 4080 1562 1562 2 s 1808 3580 0 ) +insert ( 10795 4080 1562 1562 3 s 1804 3580 0 ) +insert ( 10796 4080 1562 1562 4 s 1809 3580 0 ) +insert ( 10797 4080 1562 1562 5 s 1807 3580 0 ) +insert ( 10798 4055 1700 1700 1 s 1754 3580 0 ) +insert ( 10799 4055 1700 1700 2 s 1755 3580 0 ) +insert ( 10800 4055 1700 1700 3 s 1752 3580 0 ) +insert ( 10801 4055 1700 1700 4 s 1757 3580 0 ) +insert ( 10802 4055 1700 1700 5 s 1756 3580 0 ) +insert ( 10803 4081 2950 2950 1 s 2974 3580 0 ) +insert ( 10804 4081 2950 2950 2 s 2976 3580 0 ) +insert ( 10805 4081 2950 2950 3 s 2972 3580 0 ) +insert ( 10806 4081 2950 2950 4 s 2977 3580 0 ) +insert ( 10807 4081 2950 2950 5 s 2975 3580 0 ) +insert ( 10808 4103 3831 3831 1 s 3893 3580 0 ) +insert ( 10809 4103 3831 3831 2 s 3895 3580 0 ) +insert ( 10810 4103 3831 3831 3 s 3888 3580 0 ) +insert ( 10811 4103 3831 3831 4 s 3896 3580 0 ) +insert ( 10812 4103 3831 3831 5 s 3894 3580 0 ) +insert ( 10813 4103 3831 3831 7 s 3890 3580 0 ) +insert ( 10814 4103 3831 3831 8 s 3892 3580 0 ) +insert ( 10815 4103 3831 2283 16 s 3889 3580 0 ) +insert ( 10816 4103 3831 3831 17 s 3897 3580 0 ) +insert ( 10817 4103 3831 3831 18 s 3882 3580 0 ) +insert ( 10818 4103 3831 3831 20 s 3884 3580 0 ) +insert ( 10819 4103 3831 3831 21 s 3885 3580 0 ) +insert ( 10820 4103 3831 3831 22 s 3887 3580 0 ) +insert ( 10821 4103 3831 3831 23 s 3886 3580 0 ) +insert ( 10822 4082 3220 3220 1 s 3224 3580 0 ) +insert ( 10823 4082 3220 3220 2 s 3226 3580 0 ) +insert ( 10824 4082 3220 3220 3 s 3222 3580 0 ) +insert ( 10825 4082 3220 3220 4 s 3227 3580 0 ) +insert ( 10826 4082 3220 3220 5 s 3225 3580 0 ) +insert ( 10827 4104 603 603 1 s 493 3580 0 ) +insert ( 10828 4104 603 603 2 s 494 3580 0 ) +insert ( 10829 4104 603 603 3 s 500 3580 0 ) +insert ( 10830 4104 603 603 4 s 495 3580 0 ) +insert ( 10831 4104 603 603 5 s 496 3580 0 ) +insert ( 10832 4104 603 603 6 s 499 3580 0 ) +insert ( 10833 4104 603 603 7 s 498 3580 0 ) +insert ( 10834 4104 603 603 8 s 497 3580 0 ) +insert ( 10835 4104 603 603 9 s 2571 3580 0 ) +insert ( 10836 4104 603 603 10 s 2570 3580 0 ) +insert ( 10837 4104 603 603 11 s 2573 3580 0 ) +insert ( 10838 4104 603 603 12 s 2572 3580 0 ) +insert ( 10839 4104 603 600 7 s 433 3580 0 ) +close pg_amop +create pg_amproc 2603 + ( + oid = oid , + amprocfamily = oid , + amproclefttype = oid , + amprocrighttype = oid , + amprocnum = int2 , + amproc = regproc + ) +open pg_amproc +insert ( 10840 397 2277 2277 1 382 ) +insert ( 10841 423 1560 1560 1 1596 ) +insert ( 10842 423 1560 1560 4 5051 ) +insert ( 10843 424 16 16 1 1693 ) +insert ( 10844 424 16 16 4 5051 ) +insert ( 10845 426 1042 1042 1 1078 ) +insert ( 10846 426 1042 1042 2 3328 ) +insert ( 10847 426 1042 1042 4 5050 ) +insert ( 10848 428 17 17 1 1954 ) +insert ( 10849 428 17 17 2 3331 ) +insert ( 10850 428 17 17 4 5051 ) +insert ( 10851 429 18 18 1 358 ) +insert ( 10852 429 18 18 4 5051 ) +insert ( 10853 434 1082 1082 1 1092 ) +insert ( 10854 434 1082 1082 2 3136 ) +insert ( 10855 434 1082 1082 4 5051 ) +insert ( 10856 434 1082 1114 1 2344 ) +insert ( 10857 434 1082 1184 1 2357 ) +insert ( 10858 434 1114 1114 1 2045 ) +insert ( 10859 434 1114 1114 2 3137 ) +insert ( 10860 434 1114 1114 4 5051 ) +insert ( 10861 434 1114 1082 1 2370 ) +insert ( 10862 434 1114 1184 1 2526 ) +insert ( 10863 434 1184 1184 1 1314 ) +insert ( 10864 434 1184 1184 2 3137 ) +insert ( 10865 434 1184 1184 4 5051 ) +insert ( 10866 434 1184 1082 1 2383 ) +insert ( 10867 434 1184 1114 1 2533 ) +insert ( 10868 434 1082 1186 3 4133 ) +insert ( 10869 434 1114 1186 3 4134 ) +insert ( 10870 434 1184 1186 3 4135 ) +insert ( 10871 1970 700 700 1 354 ) +insert ( 10872 1970 700 700 2 3132 ) +insert ( 10873 1970 700 701 1 2194 ) +insert ( 10874 1970 701 701 1 355 ) +insert ( 10875 1970 701 701 2 3133 ) +insert ( 10876 1970 701 700 1 2195 ) +insert ( 10877 1970 701 701 3 4139 ) +insert ( 10878 1970 700 701 3 4140 ) +insert ( 10879 1974 869 869 1 926 ) +insert ( 10880 1974 869 869 2 5033 ) +insert ( 10881 1974 869 869 4 5051 ) +insert ( 10882 1976 21 21 1 350 ) +insert ( 10883 1976 21 21 2 3129 ) +insert ( 10884 1976 21 21 4 5051 ) +insert ( 10885 1976 21 23 1 2190 ) +insert ( 10886 1976 21 20 1 2192 ) +insert ( 10887 1976 21 20 3 4130 ) +insert ( 10888 1976 21 23 3 4131 ) +insert ( 10889 1976 21 21 3 4132 ) +insert ( 10890 1976 23 23 1 351 ) +insert ( 10891 1976 23 23 2 3130 ) +insert ( 10892 1976 23 23 4 5051 ) +insert ( 10893 1976 23 20 1 2188 ) +insert ( 10894 1976 23 21 1 2191 ) +insert ( 10895 1976 23 20 3 4127 ) +insert ( 10896 1976 23 23 3 4128 ) +insert ( 10897 1976 23 21 3 4129 ) +insert ( 10898 1976 20 20 1 842 ) +insert ( 10899 1976 20 20 2 3131 ) +insert ( 10900 1976 20 20 4 5051 ) +insert ( 10901 1976 20 23 1 2189 ) +insert ( 10902 1976 20 21 1 2193 ) +insert ( 10903 1976 20 20 3 4126 ) +insert ( 10904 1982 1186 1186 1 1315 ) +insert ( 10905 1982 1186 1186 3 4136 ) +insert ( 10906 1982 1186 1186 4 5051 ) +insert ( 10907 1984 829 829 1 836 ) +insert ( 10908 1984 829 829 2 3359 ) +insert ( 10909 1984 829 829 4 5051 ) +insert ( 10910 1988 1700 1700 1 1769 ) +insert ( 10911 1988 1700 1700 2 3283 ) +insert ( 10912 1988 1700 1700 3 4141 ) +insert ( 10913 1989 26 26 1 356 ) +insert ( 10914 1989 26 26 2 3134 ) +insert ( 10915 1989 26 26 4 5051 ) +insert ( 10916 1991 30 30 1 404 ) +insert ( 10917 1991 30 30 4 5051 ) +insert ( 10918 1994 25 25 1 360 ) +insert ( 10919 1994 25 25 2 3255 ) +insert ( 10920 1994 25 25 4 5050 ) +insert ( 10921 1994 19 19 1 359 ) +insert ( 10922 1994 19 19 2 3135 ) +insert ( 10923 1994 19 19 4 5050 ) +insert ( 10924 1994 19 25 1 246 ) +insert ( 10925 1994 25 19 1 253 ) +insert ( 10926 1996 1083 1083 1 1107 ) +insert ( 10927 1996 1083 1083 4 5051 ) +insert ( 10928 1996 1083 1186 3 4137 ) +insert ( 10929 2000 1266 1266 1 1358 ) +insert ( 10930 2000 1266 1266 4 5051 ) +insert ( 10931 2000 1266 1186 3 4138 ) +insert ( 10932 2002 1562 1562 1 1672 ) +insert ( 10933 2002 1562 1562 4 5051 ) +insert ( 10934 2095 25 25 1 2166 ) +insert ( 10935 2095 25 25 2 3332 ) +insert ( 10936 2095 25 25 4 5051 ) +insert ( 10937 2097 1042 1042 1 2180 ) +insert ( 10938 2097 1042 1042 2 3333 ) +insert ( 10939 2097 1042 1042 4 5051 ) +insert ( 10940 2099 790 790 1 377 ) +insert ( 10941 2099 790 790 4 5051 ) +insert ( 10942 2789 27 27 1 2794 ) +insert ( 10943 2789 27 27 4 5051 ) +insert ( 10944 2968 2950 2950 1 2960 ) +insert ( 10945 2968 2950 2950 2 3300 ) +insert ( 10946 2968 2950 2950 4 5051 ) +insert ( 10947 2994 2249 2249 1 2987 ) +insert ( 10948 3194 2249 2249 1 3187 ) +insert ( 10949 3253 3220 3220 1 3251 ) +insert ( 10950 3253 3220 3220 4 5051 ) +insert ( 10951 3371 774 774 1 4119 ) +insert ( 10952 3371 774 774 4 5051 ) +insert ( 10953 3522 3500 3500 1 3514 ) +insert ( 10954 3522 3500 3500 4 5051 ) +insert ( 10955 3626 3614 3614 1 3622 ) +insert ( 10956 3683 3615 3615 1 3668 ) +insert ( 10957 3901 3831 3831 1 3870 ) +insert ( 10958 4033 3802 3802 1 4044 ) +insert ( 10959 5067 5069 5069 1 5096 ) +insert ( 10960 5067 5069 5069 4 5051 ) +insert ( 10961 427 1042 1042 1 1080 ) +insert ( 10962 427 1042 1042 2 972 ) +insert ( 10963 431 18 18 1 454 ) +insert ( 10964 431 18 18 2 446 ) +insert ( 10965 435 1082 1082 1 450 ) +insert ( 10966 435 1082 1082 2 425 ) +insert ( 10967 627 2277 2277 1 626 ) +insert ( 10968 627 2277 2277 2 782 ) +insert ( 10969 1971 700 700 1 451 ) +insert ( 10970 1971 700 700 2 443 ) +insert ( 10971 1971 701 701 1 452 ) +insert ( 10972 1971 701 701 2 444 ) +insert ( 10973 1975 869 869 1 422 ) +insert ( 10974 1975 869 869 2 779 ) +insert ( 10975 1977 21 21 1 449 ) +insert ( 10976 1977 21 21 2 441 ) +insert ( 10977 1977 23 23 1 450 ) +insert ( 10978 1977 23 23 2 425 ) +insert ( 10979 1977 20 20 1 949 ) +insert ( 10980 1977 20 20 2 442 ) +insert ( 10981 1983 1186 1186 1 1697 ) +insert ( 10982 1983 1186 1186 2 3418 ) +insert ( 10983 1985 829 829 1 399 ) +insert ( 10984 1985 829 829 2 778 ) +insert ( 10985 1990 26 26 1 453 ) +insert ( 10986 1990 26 26 2 445 ) +insert ( 10987 1992 30 30 1 457 ) +insert ( 10988 1992 30 30 2 776 ) +insert ( 10989 1995 25 25 1 400 ) +insert ( 10990 1995 25 25 2 448 ) +insert ( 10991 1995 19 19 1 455 ) +insert ( 10992 1995 19 19 2 447 ) +insert ( 10993 1997 1083 1083 1 1688 ) +insert ( 10994 1997 1083 1083 2 3409 ) +insert ( 10995 1998 1700 1700 1 432 ) +insert ( 10996 1998 1700 1700 2 780 ) +insert ( 10997 1999 1184 1184 1 2039 ) +insert ( 10998 1999 1184 1184 2 3411 ) +insert ( 10999 2001 1266 1266 1 1696 ) +insert ( 11000 2001 1266 1266 2 3410 ) +insert ( 11001 2040 1114 1114 1 2039 ) +insert ( 11002 2040 1114 1114 2 3411 ) +insert ( 11003 2222 16 16 1 454 ) +insert ( 11004 2222 16 16 2 446 ) +insert ( 11005 2223 17 17 1 456 ) +insert ( 11006 2223 17 17 2 772 ) +insert ( 11007 2225 28 28 1 450 ) +insert ( 11008 2225 28 28 2 425 ) +insert ( 11009 5032 5069 5069 1 949 ) +insert ( 11010 5032 5069 5069 2 442 ) +insert ( 11011 2226 29 29 1 450 ) +insert ( 11012 2226 29 29 2 425 ) +insert ( 11013 2227 27 27 1 2233 ) +insert ( 11014 2227 27 27 2 2234 ) +insert ( 11015 2229 25 25 1 400 ) +insert ( 11016 2229 25 25 2 448 ) +insert ( 11017 2231 1042 1042 1 1080 ) +insert ( 11018 2231 1042 1042 2 972 ) +insert ( 11019 2235 1033 1033 1 329 ) +insert ( 11020 2235 1033 1033 2 777 ) +insert ( 11021 2969 2950 2950 1 2963 ) +insert ( 11022 2969 2950 2950 2 3412 ) +insert ( 11023 3254 3220 3220 1 3252 ) +insert ( 11024 3254 3220 3220 2 3413 ) +insert ( 11025 3372 774 774 1 328 ) +insert ( 11026 3372 774 774 2 781 ) +insert ( 11027 3523 3500 3500 1 3515 ) +insert ( 11028 3523 3500 3500 2 3414 ) +insert ( 11029 3903 3831 3831 1 3902 ) +insert ( 11030 3903 3831 3831 2 3417 ) +insert ( 11031 4034 3802 3802 1 4045 ) +insert ( 11032 4034 3802 3802 2 3416 ) +insert ( 11033 1029 600 600 1 2179 ) +insert ( 11034 1029 600 600 2 2583 ) +insert ( 11035 1029 600 600 3 1030 ) +insert ( 11036 1029 600 600 5 2581 ) +insert ( 11037 1029 600 600 6 2582 ) +insert ( 11038 1029 600 600 7 2584 ) +insert ( 11039 1029 600 600 8 3064 ) +insert ( 11040 1029 600 600 9 3282 ) +insert ( 11041 2593 603 603 1 2578 ) +insert ( 11042 2593 603 603 2 2583 ) +insert ( 11043 2593 603 603 5 2581 ) +insert ( 11044 2593 603 603 6 2582 ) +insert ( 11045 2593 603 603 7 2584 ) +insert ( 11046 2593 603 603 8 3998 ) +insert ( 11047 2594 604 604 1 2585 ) +insert ( 11048 2594 604 604 2 2583 ) +insert ( 11049 2594 604 604 3 2586 ) +insert ( 11050 2594 604 604 5 2581 ) +insert ( 11051 2594 604 604 6 2582 ) +insert ( 11052 2594 604 604 7 2584 ) +insert ( 11053 2594 604 604 8 3288 ) +insert ( 11054 2595 718 718 1 2591 ) +insert ( 11055 2595 718 718 2 2583 ) +insert ( 11056 2595 718 718 3 2592 ) +insert ( 11057 2595 718 718 5 2581 ) +insert ( 11058 2595 718 718 6 2582 ) +insert ( 11059 2595 718 718 7 2584 ) +insert ( 11060 2595 718 718 8 3280 ) +insert ( 11061 3655 3614 3614 1 3654 ) +insert ( 11062 3655 3614 3614 2 3651 ) +insert ( 11063 3655 3614 3614 3 3648 ) +insert ( 11064 3655 3614 3614 4 3649 ) +insert ( 11065 3655 3614 3614 5 3653 ) +insert ( 11066 3655 3614 3614 6 3650 ) +insert ( 11067 3655 3614 3614 7 3652 ) +insert ( 11068 3655 3614 3614 10 3434 ) +insert ( 11069 3702 3615 3615 1 3701 ) +insert ( 11070 3702 3615 3615 2 3698 ) +insert ( 11071 3702 3615 3615 3 3695 ) +insert ( 11072 3702 3615 3615 5 3700 ) +insert ( 11073 3702 3615 3615 6 3697 ) +insert ( 11074 3702 3615 3615 7 3699 ) +insert ( 11075 3919 3831 3831 1 3875 ) +insert ( 11076 3919 3831 3831 2 3876 ) +insert ( 11077 3919 3831 3831 5 3879 ) +insert ( 11078 3919 3831 3831 6 3880 ) +insert ( 11079 3919 3831 3831 7 3881 ) +insert ( 11080 3550 869 869 1 3553 ) +insert ( 11081 3550 869 869 2 3554 ) +insert ( 11082 3550 869 869 3 3555 ) +insert ( 11083 3550 869 869 5 3557 ) +insert ( 11084 3550 869 869 6 3558 ) +insert ( 11085 3550 869 869 7 3559 ) +insert ( 11086 3550 869 869 9 3573 ) +insert ( 11087 2745 2277 2277 2 2743 ) +insert ( 11088 2745 2277 2277 3 2774 ) +insert ( 11089 2745 2277 2277 4 2744 ) +insert ( 11090 2745 2277 2277 6 3920 ) +insert ( 11091 3659 3614 3614 1 3724 ) +insert ( 11092 3659 3614 3614 2 3656 ) +insert ( 11093 3659 3614 3614 3 3657 ) +insert ( 11094 3659 3614 3614 4 3658 ) +insert ( 11095 3659 3614 3614 5 2700 ) +insert ( 11096 3659 3614 3614 6 3921 ) +insert ( 11097 4036 3802 3802 1 3480 ) +insert ( 11098 4036 3802 3802 2 3482 ) +insert ( 11099 4036 3802 3802 3 3483 ) +insert ( 11100 4036 3802 3802 4 3484 ) +insert ( 11101 4036 3802 3802 6 3488 ) +insert ( 11102 4037 3802 3802 1 351 ) +insert ( 11103 4037 3802 3802 2 3485 ) +insert ( 11104 4037 3802 3802 3 3486 ) +insert ( 11105 4037 3802 3802 4 3487 ) +insert ( 11106 4037 3802 3802 6 3489 ) +insert ( 11107 3474 3831 3831 1 3469 ) +insert ( 11108 3474 3831 3831 2 3470 ) +insert ( 11109 3474 3831 3831 3 3471 ) +insert ( 11110 3474 3831 3831 4 3472 ) +insert ( 11111 3474 3831 3831 5 3473 ) +insert ( 11112 3794 869 869 1 3795 ) +insert ( 11113 3794 869 869 2 3796 ) +insert ( 11114 3794 869 869 3 3797 ) +insert ( 11115 3794 869 869 4 3798 ) +insert ( 11116 3794 869 869 5 3799 ) +insert ( 11117 4015 600 600 1 4018 ) +insert ( 11118 4015 600 600 2 4019 ) +insert ( 11119 4015 600 600 3 4020 ) +insert ( 11120 4015 600 600 4 4021 ) +insert ( 11121 4015 600 600 5 4022 ) +insert ( 11122 4016 600 600 1 4023 ) +insert ( 11123 4016 600 600 2 4024 ) +insert ( 11124 4016 600 600 3 4025 ) +insert ( 11125 4016 600 600 4 4026 ) +insert ( 11126 4016 600 600 5 4022 ) +insert ( 11127 4017 25 25 1 4027 ) +insert ( 11128 4017 25 25 2 4028 ) +insert ( 11129 4017 25 25 3 4029 ) +insert ( 11130 4017 25 25 4 4030 ) +insert ( 11131 4017 25 25 5 4031 ) +insert ( 11132 5000 603 603 1 5012 ) +insert ( 11133 5000 603 603 2 5013 ) +insert ( 11134 5000 603 603 3 5014 ) +insert ( 11135 5000 603 603 4 5015 ) +insert ( 11136 5000 603 603 5 5016 ) +insert ( 11137 5008 604 604 1 5010 ) +insert ( 11138 5008 604 604 2 5013 ) +insert ( 11139 5008 604 604 3 5014 ) +insert ( 11140 5008 604 604 4 5015 ) +insert ( 11141 5008 604 604 5 5016 ) +insert ( 11142 5008 604 604 6 5011 ) +insert ( 11143 4064 17 17 1 3383 ) +insert ( 11144 4064 17 17 2 3384 ) +insert ( 11145 4064 17 17 3 3385 ) +insert ( 11146 4064 17 17 4 3386 ) +insert ( 11147 4062 18 18 1 3383 ) +insert ( 11148 4062 18 18 2 3384 ) +insert ( 11149 4062 18 18 3 3385 ) +insert ( 11150 4062 18 18 4 3386 ) +insert ( 11151 4065 19 19 1 3383 ) +insert ( 11152 4065 19 19 2 3384 ) +insert ( 11153 4065 19 19 3 3385 ) +insert ( 11154 4065 19 19 4 3386 ) +insert ( 11155 4054 20 20 1 3383 ) +insert ( 11156 4054 20 20 2 3384 ) +insert ( 11157 4054 20 20 3 3385 ) +insert ( 11158 4054 20 20 4 3386 ) +insert ( 11159 4054 20 21 1 3383 ) +insert ( 11160 4054 20 21 2 3384 ) +insert ( 11161 4054 20 21 3 3385 ) +insert ( 11162 4054 20 21 4 3386 ) +insert ( 11163 4054 20 23 1 3383 ) +insert ( 11164 4054 20 23 2 3384 ) +insert ( 11165 4054 20 23 3 3385 ) +insert ( 11166 4054 20 23 4 3386 ) +insert ( 11167 4054 21 21 1 3383 ) +insert ( 11168 4054 21 21 2 3384 ) +insert ( 11169 4054 21 21 3 3385 ) +insert ( 11170 4054 21 21 4 3386 ) +insert ( 11171 4054 21 20 1 3383 ) +insert ( 11172 4054 21 20 2 3384 ) +insert ( 11173 4054 21 20 3 3385 ) +insert ( 11174 4054 21 20 4 3386 ) +insert ( 11175 4054 21 23 1 3383 ) +insert ( 11176 4054 21 23 2 3384 ) +insert ( 11177 4054 21 23 3 3385 ) +insert ( 11178 4054 21 23 4 3386 ) +insert ( 11179 4054 23 23 1 3383 ) +insert ( 11180 4054 23 23 2 3384 ) +insert ( 11181 4054 23 23 3 3385 ) +insert ( 11182 4054 23 23 4 3386 ) +insert ( 11183 4054 23 20 1 3383 ) +insert ( 11184 4054 23 20 2 3384 ) +insert ( 11185 4054 23 20 3 3385 ) +insert ( 11186 4054 23 20 4 3386 ) +insert ( 11187 4054 23 21 1 3383 ) +insert ( 11188 4054 23 21 2 3384 ) +insert ( 11189 4054 23 21 3 3385 ) +insert ( 11190 4054 23 21 4 3386 ) +insert ( 11191 4056 25 25 1 3383 ) +insert ( 11192 4056 25 25 2 3384 ) +insert ( 11193 4056 25 25 3 3385 ) +insert ( 11194 4056 25 25 4 3386 ) +insert ( 11195 4068 26 26 1 3383 ) +insert ( 11196 4068 26 26 2 3384 ) +insert ( 11197 4068 26 26 3 3385 ) +insert ( 11198 4068 26 26 4 3386 ) +insert ( 11199 4069 27 27 1 3383 ) +insert ( 11200 4069 27 27 2 3384 ) +insert ( 11201 4069 27 27 3 3385 ) +insert ( 11202 4069 27 27 4 3386 ) +insert ( 11203 4070 700 700 1 3383 ) +insert ( 11204 4070 700 700 2 3384 ) +insert ( 11205 4070 700 700 3 3385 ) +insert ( 11206 4070 700 700 4 3386 ) +insert ( 11207 4070 700 701 1 3383 ) +insert ( 11208 4070 700 701 2 3384 ) +insert ( 11209 4070 700 701 3 3385 ) +insert ( 11210 4070 700 701 4 3386 ) +insert ( 11211 4070 701 701 1 3383 ) +insert ( 11212 4070 701 701 2 3384 ) +insert ( 11213 4070 701 701 3 3385 ) +insert ( 11214 4070 701 701 4 3386 ) +insert ( 11215 4070 701 700 1 3383 ) +insert ( 11216 4070 701 700 2 3384 ) +insert ( 11217 4070 701 700 3 3385 ) +insert ( 11218 4070 701 700 4 3386 ) +insert ( 11219 4074 829 829 1 3383 ) +insert ( 11220 4074 829 829 2 3384 ) +insert ( 11221 4074 829 829 3 3385 ) +insert ( 11222 4074 829 829 4 3386 ) +insert ( 11223 4109 774 774 1 3383 ) +insert ( 11224 4109 774 774 2 3384 ) +insert ( 11225 4109 774 774 3 3385 ) +insert ( 11226 4109 774 774 4 3386 ) +insert ( 11227 4075 869 869 1 3383 ) +insert ( 11228 4075 869 869 2 3384 ) +insert ( 11229 4075 869 869 3 3385 ) +insert ( 11230 4075 869 869 4 3386 ) +insert ( 11231 4102 869 869 1 4105 ) +insert ( 11232 4102 869 869 2 4106 ) +insert ( 11233 4102 869 869 3 4107 ) +insert ( 11234 4102 869 869 4 4108 ) +insert ( 11235 4102 869 869 11 4063 ) +insert ( 11236 4102 869 869 12 4071 ) +insert ( 11237 4102 869 869 13 930 ) +insert ( 11238 4076 1042 1042 1 3383 ) +insert ( 11239 4076 1042 1042 2 3384 ) +insert ( 11240 4076 1042 1042 3 3385 ) +insert ( 11241 4076 1042 1042 4 3386 ) +insert ( 11242 4077 1083 1083 1 3383 ) +insert ( 11243 4077 1083 1083 2 3384 ) +insert ( 11244 4077 1083 1083 3 3385 ) +insert ( 11245 4077 1083 1083 4 3386 ) +insert ( 11246 4059 1114 1114 1 3383 ) +insert ( 11247 4059 1114 1114 2 3384 ) +insert ( 11248 4059 1114 1114 3 3385 ) +insert ( 11249 4059 1114 1114 4 3386 ) +insert ( 11250 4059 1114 1184 1 3383 ) +insert ( 11251 4059 1114 1184 2 3384 ) +insert ( 11252 4059 1114 1184 3 3385 ) +insert ( 11253 4059 1114 1184 4 3386 ) +insert ( 11254 4059 1114 1082 1 3383 ) +insert ( 11255 4059 1114 1082 2 3384 ) +insert ( 11256 4059 1114 1082 3 3385 ) +insert ( 11257 4059 1114 1082 4 3386 ) +insert ( 11258 4059 1184 1184 1 3383 ) +insert ( 11259 4059 1184 1184 2 3384 ) +insert ( 11260 4059 1184 1184 3 3385 ) +insert ( 11261 4059 1184 1184 4 3386 ) +insert ( 11262 4059 1184 1114 1 3383 ) +insert ( 11263 4059 1184 1114 2 3384 ) +insert ( 11264 4059 1184 1114 3 3385 ) +insert ( 11265 4059 1184 1114 4 3386 ) +insert ( 11266 4059 1184 1082 1 3383 ) +insert ( 11267 4059 1184 1082 2 3384 ) +insert ( 11268 4059 1184 1082 3 3385 ) +insert ( 11269 4059 1184 1082 4 3386 ) +insert ( 11270 4059 1082 1082 1 3383 ) +insert ( 11271 4059 1082 1082 2 3384 ) +insert ( 11272 4059 1082 1082 3 3385 ) +insert ( 11273 4059 1082 1082 4 3386 ) +insert ( 11274 4059 1082 1114 1 3383 ) +insert ( 11275 4059 1082 1114 2 3384 ) +insert ( 11276 4059 1082 1114 3 3385 ) +insert ( 11277 4059 1082 1114 4 3386 ) +insert ( 11278 4059 1082 1184 1 3383 ) +insert ( 11279 4059 1082 1184 2 3384 ) +insert ( 11280 4059 1082 1184 3 3385 ) +insert ( 11281 4059 1082 1184 4 3386 ) +insert ( 11282 4078 1186 1186 1 3383 ) +insert ( 11283 4078 1186 1186 2 3384 ) +insert ( 11284 4078 1186 1186 3 3385 ) +insert ( 11285 4078 1186 1186 4 3386 ) +insert ( 11286 4058 1266 1266 1 3383 ) +insert ( 11287 4058 1266 1266 2 3384 ) +insert ( 11288 4058 1266 1266 3 3385 ) +insert ( 11289 4058 1266 1266 4 3386 ) +insert ( 11290 4079 1560 1560 1 3383 ) +insert ( 11291 4079 1560 1560 2 3384 ) +insert ( 11292 4079 1560 1560 3 3385 ) +insert ( 11293 4079 1560 1560 4 3386 ) +insert ( 11294 4080 1562 1562 1 3383 ) +insert ( 11295 4080 1562 1562 2 3384 ) +insert ( 11296 4080 1562 1562 3 3385 ) +insert ( 11297 4080 1562 1562 4 3386 ) +insert ( 11298 4055 1700 1700 1 3383 ) +insert ( 11299 4055 1700 1700 2 3384 ) +insert ( 11300 4055 1700 1700 3 3385 ) +insert ( 11301 4055 1700 1700 4 3386 ) +insert ( 11302 4081 2950 2950 1 3383 ) +insert ( 11303 4081 2950 2950 2 3384 ) +insert ( 11304 4081 2950 2950 3 3385 ) +insert ( 11305 4081 2950 2950 4 3386 ) +insert ( 11306 4103 3831 3831 1 4105 ) +insert ( 11307 4103 3831 3831 2 4106 ) +insert ( 11308 4103 3831 3831 3 4107 ) +insert ( 11309 4103 3831 3831 4 4108 ) +insert ( 11310 4103 3831 3831 11 4057 ) +insert ( 11311 4103 3831 3831 13 3859 ) +insert ( 11312 4103 3831 3831 14 3850 ) +insert ( 11313 4082 3220 3220 1 3383 ) +insert ( 11314 4082 3220 3220 2 3384 ) +insert ( 11315 4082 3220 3220 3 3385 ) +insert ( 11316 4082 3220 3220 4 3386 ) +insert ( 11317 4104 603 603 1 4105 ) +insert ( 11318 4104 603 603 2 4106 ) +insert ( 11319 4104 603 603 3 4107 ) +insert ( 11320 4104 603 603 4 4108 ) +insert ( 11321 4104 603 603 11 4067 ) +insert ( 11322 4104 603 603 13 187 ) +close pg_amproc +create pg_language 2612 + ( + oid = oid , + lanname = name , + lanowner = oid , + lanispl = bool , + lanpltrusted = bool , + lanplcallfoid = oid , + laninline = oid , + lanvalidator = oid , + lanacl = _aclitem + ) +open pg_language +insert ( 12 internal 10 f f 0 0 2246 _null_ ) +insert ( 13 c 10 f f 0 0 2247 _null_ ) +insert ( 14 sql 10 f t 0 0 2248 _null_ ) +close pg_language +create pg_largeobject_metadata 2995 + ( + oid = oid , + lomowner = oid , + lomacl = _aclitem + ) +open pg_largeobject_metadata +close pg_largeobject_metadata +create pg_largeobject 2613 + ( + loid = oid , + pageno = int4 , + data = bytea FORCE NOT NULL + ) +open pg_largeobject +close pg_largeobject +create pg_aggregate 2600 + ( + aggfnoid = regproc , + aggkind = char , + aggnumdirectargs = int2 , + aggtransfn = regproc , + aggfinalfn = regproc , + aggcombinefn = regproc , + aggserialfn = regproc , + aggdeserialfn = regproc , + aggmtransfn = regproc , + aggminvtransfn = regproc , + aggmfinalfn = regproc , + aggfinalextra = bool , + aggmfinalextra = bool , + aggfinalmodify = char , + aggmfinalmodify = char , + aggsortop = oid , + aggtranstype = oid , + aggtransspace = int4 , + aggmtranstype = oid , + aggmtransspace = int4 , + agginitval = text , + aggminitval = text + ) +open pg_aggregate +insert ( 2100 n 0 2746 3389 2785 2786 2787 2746 3387 3389 f f r r 0 2281 48 2281 48 _null_ _null_ ) +insert ( 2101 n 0 1963 1964 3324 - - 1963 3571 1964 f f r r 0 1016 0 1016 0 "{0,0}" "{0,0}" ) +insert ( 2102 n 0 1962 1964 3324 - - 1962 3570 1964 f f r r 0 1016 0 1016 0 "{0,0}" "{0,0}" ) +insert ( 2103 n 0 2858 1837 3337 2740 2741 2858 3548 1837 f f r r 0 2281 128 2281 128 _null_ _null_ ) +insert ( 2104 n 0 208 1830 276 - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ ) +insert ( 2105 n 0 222 1830 276 - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ ) +insert ( 2106 n 0 1843 1844 3325 - - 1843 3549 1844 f f r r 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ) +insert ( 2107 n 0 2746 3388 2785 2786 2787 2746 3387 3388 f f r r 0 2281 48 2281 48 _null_ _null_ ) +insert ( 2108 n 0 1841 - 463 - - 1963 3571 3572 f f r r 0 20 0 1016 0 _null_ "{0,0}" ) +insert ( 2109 n 0 1840 - 463 - - 1962 3570 3572 f f r r 0 20 0 1016 0 _null_ "{0,0}" ) +insert ( 2110 n 0 204 - 204 - - - - - f f r r 0 700 0 0 0 _null_ _null_ ) +insert ( 2111 n 0 218 - 218 - - - - - f f r r 0 701 0 0 0 _null_ _null_ ) +insert ( 2112 n 0 894 - 894 - - 894 895 - f f r r 0 790 0 790 0 _null_ _null_ ) +insert ( 2113 n 0 1169 - 1169 - - 1169 1170 - f f r r 0 1186 0 1186 0 _null_ _null_ ) +insert ( 2114 n 0 2858 3178 3337 2740 2741 2858 3548 3178 f f r r 0 2281 128 2281 128 _null_ _null_ ) +insert ( 2115 n 0 1236 - 1236 - - - - - f f r r 413 20 0 0 0 _null_ _null_ ) +insert ( 2116 n 0 768 - 768 - - - - - f f r r 521 23 0 0 0 _null_ _null_ ) +insert ( 2117 n 0 770 - 770 - - - - - f f r r 520 21 0 0 0 _null_ _null_ ) +insert ( 2118 n 0 1965 - 1965 - - - - - f f r r 610 26 0 0 0 _null_ _null_ ) +insert ( 2119 n 0 209 - 209 - - - - - f f r r 623 700 0 0 0 _null_ _null_ ) +insert ( 2120 n 0 223 - 223 - - - - - f f r r 674 701 0 0 0 _null_ _null_ ) +insert ( 2122 n 0 1138 - 1138 - - - - - f f r r 1097 1082 0 0 0 _null_ _null_ ) +insert ( 2123 n 0 1377 - 1377 - - - - - f f r r 1112 1083 0 0 0 _null_ _null_ ) +insert ( 2124 n 0 1379 - 1379 - - - - - f f r r 1554 1266 0 0 0 _null_ _null_ ) +insert ( 2125 n 0 898 - 898 - - - - - f f r r 903 790 0 0 0 _null_ _null_ ) +insert ( 2126 n 0 2036 - 2036 - - - - - f f r r 2064 1114 0 0 0 _null_ _null_ ) +insert ( 2127 n 0 1196 - 1196 - - - - - f f r r 1324 1184 0 0 0 _null_ _null_ ) +insert ( 2128 n 0 1198 - 1198 - - - - - f f r r 1334 1186 0 0 0 _null_ _null_ ) +insert ( 2129 n 0 458 - 458 - - - - - f f r r 666 25 0 0 0 _null_ _null_ ) +insert ( 2130 n 0 1767 - 1767 - - - - - f f r r 1756 1700 0 0 0 _null_ _null_ ) +insert ( 2050 n 0 515 - 515 - - - - - f f r r 1073 2277 0 0 0 _null_ _null_ ) +insert ( 2244 n 0 1063 - 1063 - - - - - f f r r 1060 1042 0 0 0 _null_ _null_ ) +insert ( 2797 n 0 2795 - 2795 - - - - - f f r r 2800 27 0 0 0 _null_ _null_ ) +insert ( 3526 n 0 3525 - 3525 - - - - - f f r r 3519 3500 0 0 0 _null_ _null_ ) +insert ( 3564 n 0 3562 - 3562 - - - - - f f r r 1205 869 0 0 0 _null_ _null_ ) +insert ( 4189 n 0 4187 - 4187 - - - - - f f r r 3225 3220 0 0 0 _null_ _null_ ) +insert ( 2131 n 0 1237 - 1237 - - - - - f f r r 412 20 0 0 0 _null_ _null_ ) +insert ( 2132 n 0 769 - 769 - - - - - f f r r 97 23 0 0 0 _null_ _null_ ) +insert ( 2133 n 0 771 - 771 - - - - - f f r r 95 21 0 0 0 _null_ _null_ ) +insert ( 2134 n 0 1966 - 1966 - - - - - f f r r 609 26 0 0 0 _null_ _null_ ) +insert ( 2135 n 0 211 - 211 - - - - - f f r r 622 700 0 0 0 _null_ _null_ ) +insert ( 2136 n 0 224 - 224 - - - - - f f r r 672 701 0 0 0 _null_ _null_ ) +insert ( 2138 n 0 1139 - 1139 - - - - - f f r r 1095 1082 0 0 0 _null_ _null_ ) +insert ( 2139 n 0 1378 - 1378 - - - - - f f r r 1110 1083 0 0 0 _null_ _null_ ) +insert ( 2140 n 0 1380 - 1380 - - - - - f f r r 1552 1266 0 0 0 _null_ _null_ ) +insert ( 2141 n 0 899 - 899 - - - - - f f r r 902 790 0 0 0 _null_ _null_ ) +insert ( 2142 n 0 2035 - 2035 - - - - - f f r r 2062 1114 0 0 0 _null_ _null_ ) +insert ( 2143 n 0 1195 - 1195 - - - - - f f r r 1322 1184 0 0 0 _null_ _null_ ) +insert ( 2144 n 0 1197 - 1197 - - - - - f f r r 1332 1186 0 0 0 _null_ _null_ ) +insert ( 2145 n 0 459 - 459 - - - - - f f r r 664 25 0 0 0 _null_ _null_ ) +insert ( 2146 n 0 1766 - 1766 - - - - - f f r r 1754 1700 0 0 0 _null_ _null_ ) +insert ( 2051 n 0 516 - 516 - - - - - f f r r 1072 2277 0 0 0 _null_ _null_ ) +insert ( 2245 n 0 1064 - 1064 - - - - - f f r r 1058 1042 0 0 0 _null_ _null_ ) +insert ( 2798 n 0 2796 - 2796 - - - - - f f r r 2799 27 0 0 0 _null_ _null_ ) +insert ( 3527 n 0 3524 - 3524 - - - - - f f r r 3518 3500 0 0 0 _null_ _null_ ) +insert ( 3565 n 0 3563 - 3563 - - - - - f f r r 1203 869 0 0 0 _null_ _null_ ) +insert ( 4190 n 0 4188 - 4188 - - - - - f f r r 3224 3220 0 0 0 _null_ _null_ ) +insert ( 2147 n 0 2804 - 463 - - 2804 3547 - f f r r 0 20 0 20 0 0 0 ) +insert ( 2803 n 0 1219 - 463 - - 1219 3546 - f f r r 0 20 0 20 0 0 0 ) +insert ( 2718 n 0 1836 2514 3341 3335 3336 1836 3569 2514 f f r r 0 2281 128 2281 128 _null_ _null_ ) +insert ( 2719 n 0 1835 3390 3338 3339 3340 1835 3568 3390 f f r r 0 2281 48 2281 48 _null_ _null_ ) +insert ( 2720 n 0 1834 3390 3338 3339 3340 1834 3567 3390 f f r r 0 2281 48 2281 48 _null_ _null_ ) +insert ( 2721 n 0 208 2512 276 - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ ) +insert ( 2722 n 0 222 2512 276 - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ ) +insert ( 2723 n 0 1833 2514 3341 3335 3336 1833 3548 2514 f f r r 0 2281 128 2281 128 _null_ _null_ ) +insert ( 2641 n 0 1836 1838 3341 3335 3336 1836 3569 1838 f f r r 0 2281 128 2281 128 _null_ _null_ ) +insert ( 2642 n 0 1835 3391 3338 3339 3340 1835 3568 3391 f f r r 0 2281 48 2281 48 _null_ _null_ ) +insert ( 2643 n 0 1834 3391 3338 3339 3340 1834 3567 3391 f f r r 0 2281 48 2281 48 _null_ _null_ ) +insert ( 2644 n 0 208 1831 276 - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ ) +insert ( 2645 n 0 222 1831 276 - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ ) +insert ( 2646 n 0 1833 1838 3341 3335 3336 1833 3548 1838 f f r r 0 2281 128 2281 128 _null_ _null_ ) +insert ( 2148 n 0 1836 1838 3341 3335 3336 1836 3569 1838 f f r r 0 2281 128 2281 128 _null_ _null_ ) +insert ( 2149 n 0 1835 3391 3338 3339 3340 1835 3568 3391 f f r r 0 2281 48 2281 48 _null_ _null_ ) +insert ( 2150 n 0 1834 3391 3338 3339 3340 1834 3567 3391 f f r r 0 2281 48 2281 48 _null_ _null_ ) +insert ( 2151 n 0 208 1831 276 - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ ) +insert ( 2152 n 0 222 1831 276 - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ ) +insert ( 2153 n 0 1833 1838 3341 3335 3336 1833 3548 1838 f f r r 0 2281 128 2281 128 _null_ _null_ ) +insert ( 2724 n 0 1836 2596 3341 3335 3336 1836 3569 2596 f f r r 0 2281 128 2281 128 _null_ _null_ ) +insert ( 2725 n 0 1835 3392 3338 3339 3340 1835 3568 3392 f f r r 0 2281 48 2281 48 _null_ _null_ ) +insert ( 2726 n 0 1834 3392 3338 3339 3340 1834 3567 3392 f f r r 0 2281 48 2281 48 _null_ _null_ ) +insert ( 2727 n 0 208 2513 276 - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ ) +insert ( 2728 n 0 222 2513 276 - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ ) +insert ( 2729 n 0 1833 2596 3341 3335 3336 1833 3548 2596 f f r r 0 2281 128 2281 128 _null_ _null_ ) +insert ( 2712 n 0 1836 1839 3341 3335 3336 1836 3569 1839 f f r r 0 2281 128 2281 128 _null_ _null_ ) +insert ( 2713 n 0 1835 3393 3338 3339 3340 1835 3568 3393 f f r r 0 2281 48 2281 48 _null_ _null_ ) +insert ( 2714 n 0 1834 3393 3338 3339 3340 1834 3567 3393 f f r r 0 2281 48 2281 48 _null_ _null_ ) +insert ( 2715 n 0 208 1832 276 - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ ) +insert ( 2716 n 0 222 1832 276 - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ ) +insert ( 2717 n 0 1833 1839 3341 3335 3336 1833 3548 1839 f f r r 0 2281 128 2281 128 _null_ _null_ ) +insert ( 2154 n 0 1836 1839 3341 3335 3336 1836 3569 1839 f f r r 0 2281 128 2281 128 _null_ _null_ ) +insert ( 2155 n 0 1835 3393 3338 3339 3340 1835 3568 3393 f f r r 0 2281 48 2281 48 _null_ _null_ ) +insert ( 2156 n 0 1834 3393 3338 3339 3340 1834 3567 3393 f f r r 0 2281 48 2281 48 _null_ _null_ ) +insert ( 2157 n 0 208 1832 276 - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ ) +insert ( 2158 n 0 222 1832 276 - - - - - f f r r 0 1022 0 0 0 "{0,0,0}" _null_ ) +insert ( 2159 n 0 1833 1839 3341 3335 3336 1833 3548 1839 f f r r 0 2281 128 2281 128 _null_ _null_ ) +insert ( 2818 n 0 2805 - 463 - - - - - f f r r 0 20 0 0 0 0 _null_ ) +insert ( 2819 n 0 2806 2807 3342 - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ) +insert ( 2820 n 0 2806 2808 3342 - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ) +insert ( 2821 n 0 2806 2809 3342 - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ) +insert ( 2822 n 0 2806 2810 3342 - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ) +insert ( 2823 n 0 2806 2811 3342 - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ) +insert ( 2824 n 0 2806 2812 3342 - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ) +insert ( 2825 n 0 2806 2813 3342 - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ) +insert ( 2826 n 0 2806 2814 3342 - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ) +insert ( 2827 n 0 2806 2815 3342 - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ) +insert ( 2828 n 0 2806 2816 3342 - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ) +insert ( 2829 n 0 2806 2817 3342 - - - - - f f r r 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ ) +insert ( 2517 n 0 2515 - 2515 - - 3496 3497 3498 f f r r 58 16 0 2281 16 _null_ _null_ ) +insert ( 2518 n 0 2516 - 2516 - - 3496 3497 3499 f f r r 59 16 0 2281 16 _null_ _null_ ) +insert ( 2519 n 0 2515 - 2515 - - 3496 3497 3498 f f r r 58 16 0 2281 16 _null_ _null_ ) +insert ( 2236 n 0 1892 - 1892 - - - - - f f r r 0 21 0 0 0 _null_ _null_ ) +insert ( 2237 n 0 1893 - 1893 - - - - - f f r r 0 21 0 0 0 _null_ _null_ ) +insert ( 2238 n 0 1898 - 1898 - - - - - f f r r 0 23 0 0 0 _null_ _null_ ) +insert ( 2239 n 0 1899 - 1899 - - - - - f f r r 0 23 0 0 0 _null_ _null_ ) +insert ( 2240 n 0 1904 - 1904 - - - - - f f r r 0 20 0 0 0 _null_ _null_ ) +insert ( 2241 n 0 1905 - 1905 - - - - - f f r r 0 20 0 0 0 _null_ _null_ ) +insert ( 2242 n 0 1673 - 1673 - - - - - f f r r 0 1560 0 0 0 _null_ _null_ ) +insert ( 2243 n 0 1674 - 1674 - - - - - f f r r 0 1560 0 0 0 _null_ _null_ ) +insert ( 2901 n 0 2900 - - - - - - - f f r r 0 142 0 0 0 _null_ _null_ ) +insert ( 2335 n 0 2333 2334 - - - - - - t f r r 0 2281 0 0 0 _null_ _null_ ) +insert ( 4053 n 0 4051 4052 - - - - - - t f r r 0 2281 0 0 0 _null_ _null_ ) +insert ( 3538 n 0 3535 3536 - - - - - - f f r r 0 2281 0 0 0 _null_ _null_ ) +insert ( 3545 n 0 3543 3544 - - - - - - f f r r 0 2281 0 0 0 _null_ _null_ ) +insert ( 3175 n 0 3173 3174 - - - - - - f f r r 0 2281 0 0 0 _null_ _null_ ) +insert ( 3197 n 0 3180 3196 - - - - - - f f r r 0 2281 0 0 0 _null_ _null_ ) +insert ( 3267 n 0 3265 3266 - - - - - - f f r r 0 2281 0 0 0 _null_ _null_ ) +insert ( 3270 n 0 3268 3269 - - - - - - f f r r 0 2281 0 0 0 _null_ _null_ ) +insert ( 3972 o 1 3970 3973 - - - - - - t f s s 0 2281 0 0 0 _null_ _null_ ) +insert ( 3974 o 1 3970 3975 - - - - - - f f s s 0 2281 0 0 0 _null_ _null_ ) +insert ( 3976 o 1 3970 3977 - - - - - - f f s s 0 2281 0 0 0 _null_ _null_ ) +insert ( 3978 o 1 3970 3979 - - - - - - t f s s 0 2281 0 0 0 _null_ _null_ ) +insert ( 3980 o 1 3970 3981 - - - - - - f f s s 0 2281 0 0 0 _null_ _null_ ) +insert ( 3982 o 1 3970 3983 - - - - - - f f s s 0 2281 0 0 0 _null_ _null_ ) +insert ( 3984 o 0 3970 3985 - - - - - - t f s s 0 2281 0 0 0 _null_ _null_ ) +insert ( 3986 h 1 3971 3987 - - - - - - t f w w 0 2281 0 0 0 _null_ _null_ ) +insert ( 3988 h 1 3971 3989 - - - - - - t f w w 0 2281 0 0 0 _null_ _null_ ) +insert ( 3990 h 1 3971 3991 - - - - - - t f w w 0 2281 0 0 0 _null_ _null_ ) +insert ( 3992 h 1 3971 3993 - - - - - - t f w w 0 2281 0 0 0 _null_ _null_ ) +close pg_aggregate +create pg_statistic_ext 3381 + ( + oid = oid , + stxrelid = oid , + stxname = name , + stxnamespace = oid , + stxowner = oid , + stxstattarget = int4 , + stxkeys = int2vector , + stxkind = _char FORCE NOT NULL + ) +open pg_statistic_ext +close pg_statistic_ext +create pg_statistic_ext_data 3429 + ( + stxoid = oid , + stxdndistinct = pg_ndistinct , + stxddependencies = pg_dependencies , + stxdmcv = pg_mcv_list + ) +open pg_statistic_ext_data +close pg_statistic_ext_data +create pg_statistic 2619 + ( + starelid = oid , + staattnum = int2 , + stainherit = bool , + stanullfrac = float4 , + stawidth = int4 , + stadistinct = float4 , + stakind1 = int2 , + stakind2 = int2 , + stakind3 = int2 , + stakind4 = int2 , + stakind5 = int2 , + staop1 = oid , + staop2 = oid , + staop3 = oid , + staop4 = oid , + staop5 = oid , + stacoll1 = oid , + stacoll2 = oid , + stacoll3 = oid , + stacoll4 = oid , + stacoll5 = oid , + stanumbers1 = _float4 , + stanumbers2 = _float4 , + stanumbers3 = _float4 , + stanumbers4 = _float4 , + stanumbers5 = _float4 , + stavalues1 = anyarray , + stavalues2 = anyarray , + stavalues3 = anyarray , + stavalues4 = anyarray , + stavalues5 = anyarray + ) +open pg_statistic +close pg_statistic +create pg_rewrite 2618 + ( + oid = oid , + rulename = name , + ev_class = oid , + ev_type = char , + ev_enabled = char , + is_instead = bool , + ev_qual = pg_node_tree FORCE NOT NULL , + ev_action = pg_node_tree FORCE NOT NULL + ) +open pg_rewrite +close pg_rewrite +create pg_trigger 2620 + ( + oid = oid , + tgrelid = oid , + tgparentid = oid , + tgname = name , + tgfoid = oid , + tgtype = int2 , + tgenabled = char , + tgisinternal = bool , + tgconstrrelid = oid , + tgconstrindid = oid , + tgconstraint = oid , + tgdeferrable = bool , + tginitdeferred = bool , + tgnargs = int2 , + tgattr = int2vector , + tgargs = bytea FORCE NOT NULL , + tgqual = pg_node_tree , + tgoldtable = name , + tgnewtable = name + ) +open pg_trigger +close pg_trigger +create pg_event_trigger 3466 + ( + oid = oid , + evtname = name , + evtevent = name , + evtowner = oid , + evtfoid = oid , + evtenabled = char , + evttags = _text + ) +open pg_event_trigger +close pg_event_trigger +create pg_description 2609 + ( + objoid = oid , + classoid = oid , + objsubid = int4 , + description = text FORCE NOT NULL + ) +open pg_description +insert ( 1242 1255 0 "I/O" ) +insert ( 1243 1255 0 "I/O" ) +insert ( 1244 1255 0 "I/O" ) +insert ( 31 1255 0 "I/O" ) +insert ( 1245 1255 0 "I/O" ) +insert ( 33 1255 0 "I/O" ) +insert ( 34 1255 0 "I/O" ) +insert ( 35 1255 0 "I/O" ) +insert ( 38 1255 0 "I/O" ) +insert ( 39 1255 0 "I/O" ) +insert ( 40 1255 0 "I/O" ) +insert ( 41 1255 0 "I/O" ) +insert ( 42 1255 0 "I/O" ) +insert ( 43 1255 0 "I/O" ) +insert ( 44 1255 0 "I/O" ) +insert ( 45 1255 0 "I/O" ) +insert ( 3494 1255 0 "convert proname to regproc" ) +insert ( 3479 1255 0 "convert proname to regprocedure" ) +insert ( 46 1255 0 "I/O" ) +insert ( 47 1255 0 "I/O" ) +insert ( 48 1255 0 "I/O" ) +insert ( 49 1255 0 "I/O" ) +insert ( 50 1255 0 "I/O" ) +insert ( 51 1255 0 "I/O" ) +insert ( 5070 1255 0 "I/O" ) +insert ( 5081 1255 0 "I/O" ) +insert ( 5082 1255 0 "I/O" ) +insert ( 5083 1255 0 "I/O" ) +insert ( 52 1255 0 "I/O" ) +insert ( 53 1255 0 "I/O" ) +insert ( 54 1255 0 "I/O" ) +insert ( 55 1255 0 "I/O" ) +insert ( 5096 1255 0 less-equal-greater ) +insert ( 5071 1255 0 "convert xid8 to xid" ) +insert ( 77 1255 0 "convert char to int4" ) +insert ( 78 1255 0 "convert int4 to char" ) +insert ( 1364 1255 0 "planner support for textregexeq" ) +insert ( 1257 1255 0 length ) +insert ( 89 1255 0 "PostgreSQL version string" ) +insert ( 86 1255 0 "I/O" ) +insert ( 87 1255 0 "I/O" ) +insert ( 88 1255 0 "I/O" ) +insert ( 90 1255 0 "I/O" ) +insert ( 101 1255 0 "restriction selectivity of = and related operators" ) +insert ( 102 1255 0 "restriction selectivity of <> and related operators" ) +insert ( 103 1255 0 "restriction selectivity of < and related operators on scalar datatypes" ) +insert ( 104 1255 0 "restriction selectivity of > and related operators on scalar datatypes" ) +insert ( 105 1255 0 "join selectivity of = and related operators" ) +insert ( 106 1255 0 "join selectivity of <> and related operators" ) +insert ( 107 1255 0 "join selectivity of < and related operators on scalar datatypes" ) +insert ( 108 1255 0 "join selectivity of > and related operators on scalar datatypes" ) +insert ( 336 1255 0 "restriction selectivity of <= and related operators on scalar datatypes" ) +insert ( 337 1255 0 "restriction selectivity of >= and related operators on scalar datatypes" ) +insert ( 386 1255 0 "join selectivity of <= and related operators on scalar datatypes" ) +insert ( 398 1255 0 "join selectivity of >= and related operators on scalar datatypes" ) +insert ( 109 1255 0 "I/O" ) +insert ( 110 1255 0 "I/O" ) +insert ( 111 1255 0 "implementation of deprecated ! and !! factorial operators" ) +insert ( 117 1255 0 "I/O" ) +insert ( 118 1255 0 "I/O" ) +insert ( 119 1255 0 "I/O" ) +insert ( 120 1255 0 "I/O" ) +insert ( 121 1255 0 "I/O" ) +insert ( 122 1255 0 "I/O" ) +insert ( 123 1255 0 "I/O" ) +insert ( 124 1255 0 "I/O" ) +insert ( 139 1255 0 "restriction selectivity for area-comparison operators" ) +insert ( 140 1255 0 "join selectivity for area-comparison operators" ) +insert ( 195 1255 0 "I/O" ) +insert ( 196 1255 0 "I/O" ) +insert ( 197 1255 0 "I/O" ) +insert ( 198 1255 0 "I/O" ) +insert ( 200 1255 0 "I/O" ) +insert ( 201 1255 0 "I/O" ) +insert ( 208 1255 0 "aggregate transition function" ) +insert ( 209 1255 0 "larger of two" ) +insert ( 211 1255 0 "smaller of two" ) +insert ( 214 1255 0 "I/O" ) +insert ( 215 1255 0 "I/O" ) +insert ( 222 1255 0 "aggregate transition function" ) +insert ( 276 1255 0 "aggregate combine function" ) +insert ( 223 1255 0 "larger of two" ) +insert ( 224 1255 0 "smaller of two" ) +insert ( 228 1255 0 "round to nearest integer" ) +insert ( 229 1255 0 "truncate to integer" ) +insert ( 2308 1255 0 "nearest integer >= value" ) +insert ( 2320 1255 0 "nearest integer >= value" ) +insert ( 2309 1255 0 "nearest integer <= value" ) +insert ( 2310 1255 0 "sign of value" ) +insert ( 233 1255 0 "natural exponential (e^x)" ) +insert ( 234 1255 0 "natural logarithm" ) +insert ( 235 1255 0 "convert int2 to float8" ) +insert ( 236 1255 0 "convert int2 to float4" ) +insert ( 237 1255 0 "convert float8 to int2" ) +insert ( 238 1255 0 "convert float4 to int2" ) +insert ( 246 1255 0 less-equal-greater ) +insert ( 253 1255 0 less-equal-greater ) +insert ( 266 1255 0 "concatenate name and oid" ) +insert ( 274 1255 0 "current date and time - increments during transactions" ) +insert ( 320 1255 0 "bucket number of operand in equal-width histogram" ) +insert ( 311 1255 0 "convert float4 to float8" ) +insert ( 312 1255 0 "convert float8 to float4" ) +insert ( 313 1255 0 "convert int2 to int4" ) +insert ( 314 1255 0 "convert int4 to int2" ) +insert ( 316 1255 0 "convert int4 to float8" ) +insert ( 317 1255 0 "convert float8 to int4" ) +insert ( 318 1255 0 "convert int4 to float4" ) +insert ( 319 1255 0 "convert float4 to int4" ) +insert ( 3 1255 0 "row-oriented heap table access method handler" ) +insert ( 330 1255 0 "btree index access method handler" ) +insert ( 331 1255 0 "hash index access method handler" ) +insert ( 332 1255 0 "gist index access method handler" ) +insert ( 333 1255 0 "gin index access method handler" ) +insert ( 334 1255 0 "spgist index access method handler" ) +insert ( 335 1255 0 "brin index access method handler" ) +insert ( 3952 1255 0 "brin: standalone scan new table pages" ) +insert ( 3999 1255 0 "brin: standalone scan new table pages" ) +insert ( 4014 1255 0 "brin: desummarize page range" ) +insert ( 338 1255 0 "validate an operator class" ) +insert ( 636 1255 0 "test property of an index access method" ) +insert ( 637 1255 0 "test property of an index" ) +insert ( 638 1255 0 "test property of an index column" ) +insert ( 676 1255 0 "return name of given index build phase" ) +insert ( 347 1255 0 "I/O" ) +insert ( 348 1255 0 "I/O" ) +insert ( 350 1255 0 less-equal-greater ) +insert ( 3129 1255 0 "sort support" ) +insert ( 351 1255 0 less-equal-greater ) +insert ( 3130 1255 0 "sort support" ) +insert ( 842 1255 0 less-equal-greater ) +insert ( 3131 1255 0 "sort support" ) +insert ( 354 1255 0 less-equal-greater ) +insert ( 3132 1255 0 "sort support" ) +insert ( 355 1255 0 less-equal-greater ) +insert ( 3133 1255 0 "sort support" ) +insert ( 356 1255 0 less-equal-greater ) +insert ( 3134 1255 0 "sort support" ) +insert ( 404 1255 0 less-equal-greater ) +insert ( 358 1255 0 less-equal-greater ) +insert ( 359 1255 0 less-equal-greater ) +insert ( 3135 1255 0 "sort support" ) +insert ( 360 1255 0 less-equal-greater ) +insert ( 3255 1255 0 "sort support" ) +insert ( 5050 1255 0 "equal image" ) +insert ( 377 1255 0 less-equal-greater ) +insert ( 382 1255 0 less-equal-greater ) +insert ( 4126 1255 0 "window RANGE support" ) +insert ( 4127 1255 0 "window RANGE support" ) +insert ( 4128 1255 0 "window RANGE support" ) +insert ( 4129 1255 0 "window RANGE support" ) +insert ( 4130 1255 0 "window RANGE support" ) +insert ( 4131 1255 0 "window RANGE support" ) +insert ( 4132 1255 0 "window RANGE support" ) +insert ( 4139 1255 0 "window RANGE support" ) +insert ( 4140 1255 0 "window RANGE support" ) +insert ( 4141 1255 0 "window RANGE support" ) +insert ( 401 1255 0 "convert char(n) to text" ) +insert ( 406 1255 0 "convert name to text" ) +insert ( 407 1255 0 "convert text to name" ) +insert ( 408 1255 0 "convert name to char(n)" ) +insert ( 409 1255 0 "convert char(n) to name" ) +insert ( 449 1255 0 hash ) +insert ( 441 1255 0 hash ) +insert ( 450 1255 0 hash ) +insert ( 425 1255 0 hash ) +insert ( 949 1255 0 hash ) +insert ( 442 1255 0 hash ) +insert ( 451 1255 0 hash ) +insert ( 443 1255 0 hash ) +insert ( 452 1255 0 hash ) +insert ( 444 1255 0 hash ) +insert ( 453 1255 0 hash ) +insert ( 445 1255 0 hash ) +insert ( 454 1255 0 hash ) +insert ( 446 1255 0 hash ) +insert ( 455 1255 0 hash ) +insert ( 447 1255 0 hash ) +insert ( 400 1255 0 hash ) +insert ( 448 1255 0 hash ) +insert ( 456 1255 0 hash ) +insert ( 772 1255 0 hash ) +insert ( 457 1255 0 hash ) +insert ( 776 1255 0 hash ) +insert ( 329 1255 0 hash ) +insert ( 777 1255 0 hash ) +insert ( 399 1255 0 hash ) +insert ( 778 1255 0 hash ) +insert ( 422 1255 0 hash ) +insert ( 779 1255 0 hash ) +insert ( 432 1255 0 hash ) +insert ( 780 1255 0 hash ) +insert ( 328 1255 0 hash ) +insert ( 781 1255 0 hash ) +insert ( 438 1255 0 "count the number of NULL arguments" ) +insert ( 440 1255 0 "count the number of non-NULL arguments" ) +insert ( 458 1255 0 "larger of two" ) +insert ( 459 1255 0 "smaller of two" ) +insert ( 460 1255 0 "I/O" ) +insert ( 461 1255 0 "I/O" ) +insert ( 480 1255 0 "convert int8 to int4" ) +insert ( 481 1255 0 "convert int4 to int8" ) +insert ( 482 1255 0 "convert int8 to float8" ) +insert ( 483 1255 0 "convert float8 to int8" ) +insert ( 626 1255 0 hash ) +insert ( 782 1255 0 hash ) +insert ( 652 1255 0 "convert int8 to float4" ) +insert ( 653 1255 0 "convert float4 to int8" ) +insert ( 714 1255 0 "convert int8 to int2" ) +insert ( 754 1255 0 "convert int2 to int8" ) +insert ( 668 1255 0 "adjust char() to typmod length" ) +insert ( 3097 1255 0 "planner support for varchar length coercion" ) +insert ( 669 1255 0 "adjust varchar() to typmod length" ) +insert ( 710 1255 0 "deprecated, use current_user instead" ) +insert ( 720 1255 0 "octet length" ) +insert ( 721 1255 0 "get byte" ) +insert ( 722 1255 0 "set byte" ) +insert ( 723 1255 0 "get bit" ) +insert ( 724 1255 0 "set bit" ) +insert ( 749 1255 0 "substitute portion of string" ) +insert ( 752 1255 0 "substitute portion of string" ) +insert ( 745 1255 0 "current user name" ) +insert ( 746 1255 0 "session user name" ) +insert ( 747 1255 0 "array dimensions" ) +insert ( 748 1255 0 "number of array dimensions" ) +insert ( 750 1255 0 "I/O" ) +insert ( 751 1255 0 "I/O" ) +insert ( 2091 1255 0 "array lower dimension" ) +insert ( 2092 1255 0 "array upper dimension" ) +insert ( 2176 1255 0 "array length" ) +insert ( 3179 1255 0 "array cardinality" ) +insert ( 378 1255 0 "append element onto end of array" ) +insert ( 379 1255 0 "prepend element onto front of array" ) +insert ( 394 1255 0 "split delimited text into text[]" ) +insert ( 395 1255 0 "concatenate array elements, using delimiter, into text" ) +insert ( 376 1255 0 "split delimited text into text[], with null string" ) +insert ( 384 1255 0 "concatenate array elements, using delimiter and null string, into text" ) +insert ( 515 1255 0 "larger of two" ) +insert ( 516 1255 0 "smaller of two" ) +insert ( 3277 1255 0 "returns an offset of value in array" ) +insert ( 3278 1255 0 "returns an offset of value in array with start index" ) +insert ( 3279 1255 0 "returns an array of offsets of some value in array" ) +insert ( 1191 1255 0 "array subscripts generator" ) +insert ( 1192 1255 0 "array subscripts generator" ) +insert ( 1193 1255 0 "array constructor with value" ) +insert ( 1286 1255 0 "array constructor with value" ) +insert ( 2331 1255 0 "expand array to set of rows" ) +insert ( 3996 1255 0 "planner support for array_unnest" ) +insert ( 3167 1255 0 "remove any occurrences of an element from an array" ) +insert ( 3168 1255 0 "replace any occurrences of an element in an array" ) +insert ( 2333 1255 0 "aggregate transition function" ) +insert ( 2334 1255 0 "aggregate final function" ) +insert ( 2335 1255 0 "concatenate aggregate input into an array" ) +insert ( 4051 1255 0 "aggregate transition function" ) +insert ( 4052 1255 0 "aggregate final function" ) +insert ( 4053 1255 0 "concatenate aggregate input into an array" ) +insert ( 3218 1255 0 "bucket number of operand given a sorted array of bucket lower bounds" ) +insert ( 3816 1255 0 "array typanalyze" ) +insert ( 3817 1255 0 "restriction selectivity for array-containment operators" ) +insert ( 3818 1255 0 "join selectivity for array-containment operators" ) +insert ( 764 1255 0 "large object import" ) +insert ( 767 1255 0 "large object import" ) +insert ( 765 1255 0 "large object export" ) +insert ( 766 1255 0 increment ) +insert ( 768 1255 0 "larger of two" ) +insert ( 769 1255 0 "smaller of two" ) +insert ( 770 1255 0 "larger of two" ) +insert ( 771 1255 0 "smaller of two" ) +insert ( 849 1255 0 "position of substring" ) +insert ( 1023 1255 0 "planner support for textlike" ) +insert ( 860 1255 0 "convert char to char(n)" ) +insert ( 861 1255 0 "name of the current database" ) +insert ( 817 1255 0 "get the currently executing query" ) +insert ( 886 1255 0 "I/O" ) +insert ( 887 1255 0 "I/O" ) +insert ( 898 1255 0 "larger of two" ) +insert ( 899 1255 0 "smaller of two" ) +insert ( 935 1255 0 "output money amount as words" ) +insert ( 3823 1255 0 "convert money to numeric" ) +insert ( 3824 1255 0 "convert numeric to money" ) +insert ( 3811 1255 0 "convert int4 to money" ) +insert ( 3812 1255 0 "convert int8 to money" ) +insert ( 940 1255 0 modulus ) +insert ( 941 1255 0 modulus ) +insert ( 947 1255 0 modulus ) +insert ( 5044 1255 0 "greatest common divisor" ) +insert ( 5045 1255 0 "greatest common divisor" ) +insert ( 5046 1255 0 "least common multiple" ) +insert ( 5047 1255 0 "least common multiple" ) +insert ( 944 1255 0 "convert text to char" ) +insert ( 946 1255 0 "convert char to text" ) +insert ( 952 1255 0 "large object open" ) +insert ( 953 1255 0 "large object close" ) +insert ( 954 1255 0 "large object read" ) +insert ( 955 1255 0 "large object write" ) +insert ( 956 1255 0 "large object seek" ) +insert ( 3170 1255 0 "large object seek (64 bit)" ) +insert ( 957 1255 0 "large object create" ) +insert ( 715 1255 0 "large object create" ) +insert ( 958 1255 0 "large object position" ) +insert ( 3171 1255 0 "large object position (64 bit)" ) +insert ( 1004 1255 0 "truncate large object" ) +insert ( 3172 1255 0 "truncate large object (64 bit)" ) +insert ( 3457 1255 0 "create new large object with given content" ) +insert ( 3458 1255 0 "read entire large object" ) +insert ( 3459 1255 0 "read large object from offset for length" ) +insert ( 3460 1255 0 "write data at offset" ) +insert ( 964 1255 0 "large object unlink (delete)" ) +insert ( 975 1255 0 "box area" ) +insert ( 976 1255 0 "box width" ) +insert ( 977 1255 0 "box height" ) +insert ( 979 1255 0 "area of a closed path" ) +insert ( 4067 1255 0 "bounding box of two boxes" ) +insert ( 981 1255 0 "box diagonal" ) +insert ( 992 1255 0 "slope between points" ) +insert ( 993 1255 0 "convert points to line segment" ) +insert ( 1026 1255 0 "adjust timestamp to new time zone" ) +insert ( 1031 1255 0 "I/O" ) +insert ( 1032 1255 0 "I/O" ) +insert ( 1035 1255 0 "add/update ACL item" ) +insert ( 1036 1255 0 "remove ACL item" ) +insert ( 1037 1255 0 contains ) +insert ( 1365 1255 0 "make ACL item" ) +insert ( 3943 1255 0 "show hardwired default privileges, primarily for use by the information schema" ) +insert ( 1689 1255 0 "convert ACL item array to table, primarily for use by information schema" ) +insert ( 1044 1255 0 "I/O" ) +insert ( 1045 1255 0 "I/O" ) +insert ( 2913 1255 0 "I/O typmod" ) +insert ( 2914 1255 0 "I/O typmod" ) +insert ( 1046 1255 0 "I/O" ) +insert ( 1047 1255 0 "I/O" ) +insert ( 2915 1255 0 "I/O typmod" ) +insert ( 2916 1255 0 "I/O typmod" ) +insert ( 1063 1255 0 "larger of two" ) +insert ( 1064 1255 0 "smaller of two" ) +insert ( 1078 1255 0 less-equal-greater ) +insert ( 3328 1255 0 "sort support" ) +insert ( 1080 1255 0 hash ) +insert ( 972 1255 0 hash ) +insert ( 1081 1255 0 "format a type oid and atttypmod to canonical SQL" ) +insert ( 1084 1255 0 "I/O" ) +insert ( 1085 1255 0 "I/O" ) +insert ( 1092 1255 0 less-equal-greater ) +insert ( 3136 1255 0 "sort support" ) +insert ( 4133 1255 0 "window RANGE support" ) +insert ( 1107 1255 0 less-equal-greater ) +insert ( 1138 1255 0 "larger of two" ) +insert ( 1139 1255 0 "smaller of two" ) +insert ( 1143 1255 0 "I/O" ) +insert ( 1144 1255 0 "I/O" ) +insert ( 2909 1255 0 "I/O typmod" ) +insert ( 2910 1255 0 "I/O typmod" ) +insert ( 1150 1255 0 "I/O" ) +insert ( 1151 1255 0 "I/O" ) +insert ( 2907 1255 0 "I/O typmod" ) +insert ( 2908 1255 0 "I/O typmod" ) +insert ( 1158 1255 0 "convert UNIX epoch to timestamptz" ) +insert ( 1159 1255 0 "adjust timestamp to new time zone" ) +insert ( 1160 1255 0 "I/O" ) +insert ( 1161 1255 0 "I/O" ) +insert ( 2903 1255 0 "I/O typmod" ) +insert ( 2904 1255 0 "I/O typmod" ) +insert ( 1171 1255 0 "extract field from timestamp with time zone" ) +insert ( 1172 1255 0 "extract field from interval" ) +insert ( 1174 1255 0 "convert date to timestamp with time zone" ) +insert ( 2711 1255 0 "promote groups of 24 hours to numbers of days and promote groups of 30 days to numbers of months" ) +insert ( 1175 1255 0 "promote groups of 24 hours to numbers of days" ) +insert ( 1295 1255 0 "promote groups of 30 days to numbers of months" ) +insert ( 1176 1255 0 "convert date and time to timestamp with time zone" ) +insert ( 1178 1255 0 "convert timestamp with time zone to date" ) +insert ( 1181 1255 0 "age of a transaction ID, in transactions before current transaction" ) +insert ( 3939 1255 0 "age of a multi-transaction ID, in multi-transactions before current multi-transaction" ) +insert ( 1195 1255 0 "smaller of two" ) +insert ( 1196 1255 0 "larger of two" ) +insert ( 1197 1255 0 "smaller of two" ) +insert ( 1198 1255 0 "larger of two" ) +insert ( 1199 1255 0 "date difference preserving months and years" ) +insert ( 3918 1255 0 "planner support for interval length coercion" ) +insert ( 1200 1255 0 "adjust interval precision" ) +insert ( 1215 1255 0 "get description for object id and catalog name" ) +insert ( 1216 1255 0 "get description for table column" ) +insert ( 1993 1255 0 "get description for object id and shared catalog name" ) +insert ( 1217 1255 0 "truncate timestamp with time zone to specified units" ) +insert ( 1284 1255 0 "truncate timestamp with time zone to specified units in specified time zone" ) +insert ( 1218 1255 0 "truncate interval to specified units" ) +insert ( 1219 1255 0 increment ) +insert ( 3546 1255 0 decrement ) +insert ( 2804 1255 0 "increment, ignores second argument" ) +insert ( 3547 1255 0 "decrement, ignores second argument" ) +insert ( 1236 1255 0 "larger of two" ) +insert ( 1237 1255 0 "smaller of two" ) +insert ( 1024 1255 0 "planner support for texticregexeq" ) +insert ( 1271 1255 0 "intervals overlap?" ) +insert ( 1273 1255 0 "extract field from time with time zone" ) +insert ( 1287 1255 0 "convert int8 to oid" ) +insert ( 1288 1255 0 "convert oid to int8" ) +insert ( 1291 1255 0 "trigger to suppress updates when new and old records match" ) +insert ( 1293 1255 0 "latest tid of a tuple" ) +insert ( 1294 1255 0 "latest tid of a tuple" ) +insert ( 2794 1255 0 less-equal-greater ) +insert ( 2795 1255 0 "larger of two" ) +insert ( 2796 1255 0 "smaller of two" ) +insert ( 2233 1255 0 hash ) +insert ( 2234 1255 0 hash ) +insert ( 1299 1255 0 "current transaction time" ) +insert ( 2647 1255 0 "current transaction time" ) +insert ( 2648 1255 0 "current statement time" ) +insert ( 2649 1255 0 "current clock time" ) +insert ( 1300 1255 0 "restriction selectivity for position-comparison operators" ) +insert ( 1301 1255 0 "join selectivity for position-comparison operators" ) +insert ( 1302 1255 0 "restriction selectivity for containment comparison operators" ) +insert ( 1303 1255 0 "join selectivity for containment comparison operators" ) +insert ( 1304 1255 0 "intervals overlap?" ) +insert ( 1305 1255 0 "intervals overlap?" ) +insert ( 1306 1255 0 "intervals overlap?" ) +insert ( 1307 1255 0 "intervals overlap?" ) +insert ( 1308 1255 0 "intervals overlap?" ) +insert ( 1309 1255 0 "intervals overlap?" ) +insert ( 1310 1255 0 "intervals overlap?" ) +insert ( 1311 1255 0 "intervals overlap?" ) +insert ( 1312 1255 0 "I/O" ) +insert ( 1313 1255 0 "I/O" ) +insert ( 2905 1255 0 "I/O typmod" ) +insert ( 2906 1255 0 "I/O typmod" ) +insert ( 1314 1255 0 less-equal-greater ) +insert ( 1315 1255 0 less-equal-greater ) +insert ( 1316 1255 0 "convert timestamp to time" ) +insert ( 1317 1255 0 length ) +insert ( 1318 1255 0 "character length" ) +insert ( 1339 1255 0 "base 10 logarithm" ) +insert ( 1340 1255 0 "base 10 logarithm" ) +insert ( 1194 1255 0 "base 10 logarithm" ) +insert ( 1341 1255 0 "natural logarithm" ) +insert ( 1342 1255 0 "round to nearest integer" ) +insert ( 1343 1255 0 "truncate to integer" ) +insert ( 1344 1255 0 "square root" ) +insert ( 1345 1255 0 "cube root" ) +insert ( 1346 1255 0 exponentiation ) +insert ( 1368 1255 0 exponentiation ) +insert ( 1347 1255 0 "natural exponential (e^x)" ) +insert ( 1348 1255 0 "deprecated, use two-argument form instead" ) +insert ( 1349 1255 0 "print type names of oidvector field" ) +insert ( 1350 1255 0 "I/O" ) +insert ( 1351 1255 0 "I/O" ) +insert ( 2911 1255 0 "I/O typmod" ) +insert ( 2912 1255 0 "I/O typmod" ) +insert ( 1358 1255 0 less-equal-greater ) +insert ( 1359 1255 0 "convert date and time with time zone to timestamp with time zone" ) +insert ( 1367 1255 0 "character length" ) +insert ( 1369 1255 0 "character length" ) +insert ( 1370 1255 0 "convert time to interval" ) +insert ( 1372 1255 0 "character length" ) +insert ( 1374 1255 0 "octet length" ) +insert ( 1375 1255 0 "octet length" ) +insert ( 1377 1255 0 "larger of two" ) +insert ( 1378 1255 0 "smaller of two" ) +insert ( 1379 1255 0 "larger of two" ) +insert ( 1380 1255 0 "smaller of two" ) +insert ( 1381 1255 0 "character length" ) +insert ( 1384 1255 0 "extract field from date" ) +insert ( 1385 1255 0 "extract field from time" ) +insert ( 1386 1255 0 "date difference from today preserving months and years" ) +insert ( 1388 1255 0 "convert timestamp with time zone to time with time zone" ) +insert ( 1373 1255 0 "finite date?" ) +insert ( 1389 1255 0 "finite timestamp?" ) +insert ( 1390 1255 0 "finite interval?" ) +insert ( 1376 1255 0 factorial ) +insert ( 1394 1255 0 "absolute value" ) +insert ( 1395 1255 0 "absolute value" ) +insert ( 1396 1255 0 "absolute value" ) +insert ( 1397 1255 0 "absolute value" ) +insert ( 1398 1255 0 "absolute value" ) +insert ( 1400 1255 0 "convert varchar to name" ) +insert ( 1401 1255 0 "convert name to varchar" ) +insert ( 1402 1255 0 "current schema name" ) +insert ( 1403 1255 0 "current schema search list" ) +insert ( 1404 1255 0 "substitute portion of string" ) +insert ( 1405 1255 0 "substitute portion of string" ) +insert ( 1406 1255 0 "vertically aligned" ) +insert ( 1407 1255 0 "horizontally aligned" ) +insert ( 1408 1255 0 parallel ) +insert ( 1409 1255 0 perpendicular ) +insert ( 1410 1255 0 vertical ) +insert ( 1411 1255 0 horizontal ) +insert ( 1412 1255 0 parallel ) +insert ( 1413 1255 0 perpendicular ) +insert ( 1414 1255 0 vertical ) +insert ( 1415 1255 0 horizontal ) +insert ( 1416 1255 0 "center of" ) +insert ( 1419 1255 0 "convert interval to time" ) +insert ( 1421 1255 0 "convert points to box" ) +insert ( 1430 1255 0 "path closed?" ) +insert ( 1431 1255 0 "path open?" ) +insert ( 1433 1255 0 "close path" ) +insert ( 1434 1255 0 "open path" ) +insert ( 1440 1255 0 "convert x, y to point" ) +insert ( 1446 1255 0 "convert polygon to bounding box" ) +insert ( 1447 1255 0 "convert polygon to path" ) +insert ( 1448 1255 0 "convert box to polygon" ) +insert ( 1449 1255 0 "convert path to polygon" ) +insert ( 1450 1255 0 "I/O" ) +insert ( 1451 1255 0 "I/O" ) +insert ( 1468 1255 0 "area of circle" ) +insert ( 1469 1255 0 "diameter of circle" ) +insert ( 1470 1255 0 "radius of circle" ) +insert ( 1473 1255 0 "convert point and radius to circle" ) +insert ( 1474 1255 0 "convert polygon to circle" ) +insert ( 1475 1255 0 "convert vertex count and circle to polygon" ) +insert ( 4091 1255 0 "convert point to empty box" ) +insert ( 1479 1255 0 "convert box to circle" ) +insert ( 1480 1255 0 "convert circle to box" ) +insert ( 1490 1255 0 "I/O" ) +insert ( 1491 1255 0 "I/O" ) +insert ( 1493 1255 0 "construct line from points" ) +insert ( 1530 1255 0 "distance between endpoints" ) +insert ( 1531 1255 0 "sum of path segments" ) +insert ( 1532 1255 0 "center of" ) +insert ( 1533 1255 0 "center of" ) +insert ( 1534 1255 0 "center of" ) +insert ( 1540 1255 0 "center of" ) +insert ( 1541 1255 0 "diagonal of" ) +insert ( 1542 1255 0 "center of" ) +insert ( 1543 1255 0 "center of" ) +insert ( 1544 1255 0 "convert circle to 12-vertex polygon" ) +insert ( 1545 1255 0 "number of points" ) +insert ( 1556 1255 0 "number of points" ) +insert ( 1564 1255 0 "I/O" ) +insert ( 1565 1255 0 "I/O" ) +insert ( 2919 1255 0 "I/O typmod" ) +insert ( 2920 1255 0 "I/O typmod" ) +insert ( 1569 1255 0 "matches LIKE expression" ) +insert ( 1570 1255 0 "does not match LIKE expression" ) +insert ( 1571 1255 0 "matches LIKE expression" ) +insert ( 1572 1255 0 "does not match LIKE expression" ) +insert ( 1574 1255 0 "sequence next value" ) +insert ( 1575 1255 0 "sequence current value" ) +insert ( 1576 1255 0 "set sequence value" ) +insert ( 1765 1255 0 "set sequence value and is_called status" ) +insert ( 3078 1255 0 "sequence parameters, for use by information schema" ) +insert ( 4032 1255 0 "sequence last value" ) +insert ( 275 1255 0 "return the next oid for a system table" ) +insert ( 1579 1255 0 "I/O" ) +insert ( 1580 1255 0 "I/O" ) +insert ( 2902 1255 0 "I/O typmod" ) +insert ( 2921 1255 0 "I/O typmod" ) +insert ( 1596 1255 0 less-equal-greater ) +insert ( 1598 1255 0 "random value" ) +insert ( 1599 1255 0 "set random seed" ) +insert ( 1600 1255 0 arcsine ) +insert ( 1601 1255 0 arccosine ) +insert ( 1602 1255 0 arctangent ) +insert ( 1603 1255 0 "arctangent, two arguments" ) +insert ( 1604 1255 0 sine ) +insert ( 1605 1255 0 cosine ) +insert ( 1606 1255 0 tangent ) +insert ( 1607 1255 0 cotangent ) +insert ( 2731 1255 0 "arcsine, degrees" ) +insert ( 2732 1255 0 "arccosine, degrees" ) +insert ( 2733 1255 0 "arctangent, degrees" ) +insert ( 2734 1255 0 "arctangent, two arguments, degrees" ) +insert ( 2735 1255 0 "sine, degrees" ) +insert ( 2736 1255 0 "cosine, degrees" ) +insert ( 2737 1255 0 "tangent, degrees" ) +insert ( 2738 1255 0 "cotangent, degrees" ) +insert ( 1608 1255 0 "radians to degrees" ) +insert ( 1609 1255 0 "degrees to radians" ) +insert ( 1610 1255 0 PI ) +insert ( 2462 1255 0 "hyperbolic sine" ) +insert ( 2463 1255 0 "hyperbolic cosine" ) +insert ( 2464 1255 0 "hyperbolic tangent" ) +insert ( 2465 1255 0 "inverse hyperbolic sine" ) +insert ( 2466 1255 0 "inverse hyperbolic cosine" ) +insert ( 2467 1255 0 "inverse hyperbolic tangent" ) +insert ( 1620 1255 0 "convert first char to int4" ) +insert ( 1621 1255 0 "convert int4 to char" ) +insert ( 1622 1255 0 "replicate string n times" ) +insert ( 1623 1255 0 "convert SQL regexp pattern to POSIX style" ) +insert ( 1986 1255 0 "convert SQL regexp pattern to POSIX style" ) +insert ( 1987 1255 0 "convert SQL regexp pattern to POSIX style" ) +insert ( 1025 1255 0 "planner support for texticlike" ) +insert ( 1637 1255 0 "convert LIKE pattern to use backslash escapes" ) +insert ( 868 1255 0 "position of substring" ) +insert ( 870 1255 0 lowercase ) +insert ( 871 1255 0 uppercase ) +insert ( 872 1255 0 "capitalize each word" ) +insert ( 873 1255 0 "left-pad string to length" ) +insert ( 874 1255 0 "right-pad string to length" ) +insert ( 875 1255 0 "trim selected characters from left end of string" ) +insert ( 876 1255 0 "trim selected characters from right end of string" ) +insert ( 877 1255 0 "extract portion of string" ) +insert ( 878 1255 0 "map a set of characters appearing in string" ) +insert ( 879 1255 0 "left-pad string to length" ) +insert ( 880 1255 0 "right-pad string to length" ) +insert ( 881 1255 0 "trim spaces from left end of string" ) +insert ( 882 1255 0 "trim spaces from right end of string" ) +insert ( 883 1255 0 "extract portion of string" ) +insert ( 884 1255 0 "trim selected characters from both ends of string" ) +insert ( 885 1255 0 "trim spaces from both ends of string" ) +insert ( 936 1255 0 "extract portion of string" ) +insert ( 937 1255 0 "extract portion of string" ) +insert ( 2087 1255 0 "replace all occurrences in string of old_substr with new_substr" ) +insert ( 2284 1255 0 "replace text using regexp" ) +insert ( 2285 1255 0 "replace text using regexp" ) +insert ( 3396 1255 0 "find first match for regexp" ) +insert ( 3397 1255 0 "find first match for regexp" ) +insert ( 2763 1255 0 "find match(es) for regexp" ) +insert ( 2764 1255 0 "find match(es) for regexp" ) +insert ( 2088 1255 0 "split string by field_sep and return field_num" ) +insert ( 2765 1255 0 "split string by pattern" ) +insert ( 2766 1255 0 "split string by pattern" ) +insert ( 2767 1255 0 "split string by pattern" ) +insert ( 2768 1255 0 "split string by pattern" ) +insert ( 2089 1255 0 "convert int4 number to hex" ) +insert ( 2090 1255 0 "convert int8 number to hex" ) +insert ( 1039 1255 0 "encoding name of current database" ) +insert ( 810 1255 0 "encoding name of current database" ) +insert ( 1713 1255 0 "length of string in specified encoding" ) +insert ( 1714 1255 0 "convert string with specified source encoding name" ) +insert ( 1717 1255 0 "convert string with specified destination encoding name" ) +insert ( 1813 1255 0 "convert string with specified encoding names" ) +insert ( 1264 1255 0 "convert encoding name to encoding id" ) +insert ( 1597 1255 0 "convert encoding id to encoding name" ) +insert ( 2319 1255 0 "maximum octet length of a character in given encoding" ) +insert ( 1573 1255 0 "source text of a rule" ) +insert ( 1640 1255 0 "select statement of a view" ) +insert ( 1641 1255 0 "select statement of a view" ) +insert ( 1642 1255 0 "role name by OID (with fallback)" ) +insert ( 1643 1255 0 "index description" ) +insert ( 3415 1255 0 "extended statistics object description" ) +insert ( 3352 1255 0 "partition key description" ) +insert ( 3408 1255 0 "partition constraint description" ) +insert ( 1662 1255 0 "trigger description" ) +insert ( 1387 1255 0 "constraint description" ) +insert ( 1716 1255 0 "deparse an encoded expression" ) +insert ( 1665 1255 0 "name of sequence for a serial column" ) +insert ( 2098 1255 0 "definition of a function" ) +insert ( 2162 1255 0 "argument list of a function" ) +insert ( 2232 1255 0 "identity argument list of a function" ) +insert ( 2165 1255 0 "result type of a function" ) +insert ( 3808 1255 0 "function argument default" ) +insert ( 1686 1255 0 "list of SQL keywords" ) +insert ( 2289 1255 0 "convert generic options array to name/value table" ) +insert ( 1619 1255 0 "type of the argument" ) +insert ( 3162 1255 0 "collation of the argument; implementation of the COLLATION FOR expression" ) +insert ( 3842 1255 0 "is a relation insertable/updatable/deletable" ) +insert ( 3843 1255 0 "is a column updatable" ) +insert ( 6120 1255 0 "oid of replica identity index if any" ) +insert ( 1250 1255 0 "deferred UNIQUE constraint check" ) +insert ( 1644 1255 0 "referential integrity FOREIGN KEY ... REFERENCES" ) +insert ( 1645 1255 0 "referential integrity FOREIGN KEY ... REFERENCES" ) +insert ( 1646 1255 0 "referential integrity ON DELETE CASCADE" ) +insert ( 1647 1255 0 "referential integrity ON UPDATE CASCADE" ) +insert ( 1648 1255 0 "referential integrity ON DELETE RESTRICT" ) +insert ( 1649 1255 0 "referential integrity ON UPDATE RESTRICT" ) +insert ( 1650 1255 0 "referential integrity ON DELETE SET NULL" ) +insert ( 1651 1255 0 "referential integrity ON UPDATE SET NULL" ) +insert ( 1652 1255 0 "referential integrity ON DELETE SET DEFAULT" ) +insert ( 1653 1255 0 "referential integrity ON UPDATE SET DEFAULT" ) +insert ( 1654 1255 0 "referential integrity ON DELETE NO ACTION" ) +insert ( 1655 1255 0 "referential integrity ON UPDATE NO ACTION" ) +insert ( 1672 1255 0 less-equal-greater ) +insert ( 1680 1255 0 "extract portion of bitstring" ) +insert ( 1681 1255 0 "bitstring length" ) +insert ( 1682 1255 0 "octet length" ) +insert ( 1683 1255 0 "convert int4 to bitstring" ) +insert ( 1684 1255 0 "convert bitstring to int4" ) +insert ( 1685 1255 0 "adjust bit() to typmod length" ) +insert ( 3158 1255 0 "planner support for varbit length coercion" ) +insert ( 1687 1255 0 "adjust varbit() to typmod length" ) +insert ( 1698 1255 0 "position of sub-bitstring" ) +insert ( 1699 1255 0 "extract portion of bitstring" ) +insert ( 3030 1255 0 "substitute portion of bitstring" ) +insert ( 3031 1255 0 "substitute portion of bitstring" ) +insert ( 3032 1255 0 "get bit" ) +insert ( 3033 1255 0 "set bit" ) +insert ( 436 1255 0 "I/O" ) +insert ( 437 1255 0 "I/O" ) +insert ( 753 1255 0 "MACADDR manufacturer fields" ) +insert ( 836 1255 0 less-equal-greater ) +insert ( 3359 1255 0 "sort support" ) +insert ( 4110 1255 0 "I/O" ) +insert ( 4111 1255 0 "I/O" ) +insert ( 4112 1255 0 "MACADDR8 manufacturer fields" ) +insert ( 4119 1255 0 less-equal-greater ) +insert ( 4123 1255 0 "convert macaddr to macaddr8" ) +insert ( 4124 1255 0 "convert macaddr8 to macaddr" ) +insert ( 4125 1255 0 "set 7th bit in macaddr8" ) +insert ( 910 1255 0 "I/O" ) +insert ( 911 1255 0 "I/O" ) +insert ( 1267 1255 0 "I/O" ) +insert ( 1427 1255 0 "I/O" ) +insert ( 3562 1255 0 "larger of two" ) +insert ( 3563 1255 0 "smaller of two" ) +insert ( 926 1255 0 less-equal-greater ) +insert ( 1173 1255 0 "planner support for network_sub/superset" ) +insert ( 5033 1255 0 "sort support" ) +insert ( 598 1255 0 "abbreviated display of inet value" ) +insert ( 599 1255 0 "abbreviated display of cidr value" ) +insert ( 605 1255 0 "change netmask of inet" ) +insert ( 635 1255 0 "change netmask of cidr" ) +insert ( 711 1255 0 "address family (4 for IPv4, 6 for IPv6)" ) +insert ( 683 1255 0 "network part of address" ) +insert ( 696 1255 0 "netmask of address" ) +insert ( 697 1255 0 "netmask length" ) +insert ( 698 1255 0 "broadcast address of network" ) +insert ( 699 1255 0 "show address octets only" ) +insert ( 730 1255 0 "show all parts of inet/cidr value" ) +insert ( 1362 1255 0 "hostmask of address" ) +insert ( 1715 1255 0 "convert inet to cidr" ) +insert ( 2196 1255 0 "inet address of the client" ) +insert ( 2197 1255 0 "client''s port number for this connection" ) +insert ( 2198 1255 0 "inet address of the server" ) +insert ( 2199 1255 0 "server''s port number for this connection" ) +insert ( 4071 1255 0 "are the addresses from the same family?" ) +insert ( 4063 1255 0 "the smallest network which includes both of the given networks" ) +insert ( 3553 1255 0 "GiST support" ) +insert ( 3554 1255 0 "GiST support" ) +insert ( 3555 1255 0 "GiST support" ) +insert ( 3573 1255 0 "GiST support" ) +insert ( 3557 1255 0 "GiST support" ) +insert ( 3558 1255 0 "GiST support" ) +insert ( 3559 1255 0 "GiST support" ) +insert ( 3795 1255 0 "SP-GiST support" ) +insert ( 3796 1255 0 "SP-GiST support" ) +insert ( 3797 1255 0 "SP-GiST support" ) +insert ( 3798 1255 0 "SP-GiST support" ) +insert ( 3799 1255 0 "SP-GiST support" ) +insert ( 3560 1255 0 "restriction selectivity for network operators" ) +insert ( 3561 1255 0 "join selectivity for network operators" ) +insert ( 1693 1255 0 less-equal-greater ) +insert ( 1688 1255 0 hash ) +insert ( 3409 1255 0 hash ) +insert ( 1696 1255 0 hash ) +insert ( 3410 1255 0 hash ) +insert ( 1697 1255 0 hash ) +insert ( 3418 1255 0 hash ) +insert ( 1701 1255 0 "I/O" ) +insert ( 1702 1255 0 "I/O" ) +insert ( 2917 1255 0 "I/O typmod" ) +insert ( 2918 1255 0 "I/O typmod" ) +insert ( 3157 1255 0 "planner support for numeric length coercion" ) +insert ( 1703 1255 0 "adjust numeric to typmod precision/scale" ) +insert ( 1705 1255 0 "absolute value" ) +insert ( 1706 1255 0 "sign of value" ) +insert ( 1707 1255 0 "value rounded to ''scale''" ) +insert ( 1708 1255 0 "value rounded to ''scale'' of zero" ) +insert ( 1709 1255 0 "value truncated to ''scale''" ) +insert ( 1710 1255 0 "value truncated to ''scale'' of zero" ) +insert ( 1711 1255 0 "nearest integer >= value" ) +insert ( 2167 1255 0 "nearest integer >= value" ) +insert ( 1712 1255 0 "nearest integer <= value" ) +insert ( 1728 1255 0 modulus ) +insert ( 5048 1255 0 "greatest common divisor" ) +insert ( 5049 1255 0 "least common multiple" ) +insert ( 1730 1255 0 "square root" ) +insert ( 1731 1255 0 "square root" ) +insert ( 1732 1255 0 "natural exponential (e^x)" ) +insert ( 1733 1255 0 "natural exponential (e^x)" ) +insert ( 1734 1255 0 "natural logarithm" ) +insert ( 1735 1255 0 "natural logarithm" ) +insert ( 1736 1255 0 "logarithm base m of n" ) +insert ( 1737 1255 0 "logarithm base m of n" ) +insert ( 1738 1255 0 exponentiation ) +insert ( 2169 1255 0 exponentiation ) +insert ( 3281 1255 0 "number of decimal digits in the fractional part" ) +insert ( 5042 1255 0 "minimum scale needed to represent the value" ) +insert ( 5043 1255 0 "numeric with minimum scale needed to represent the value" ) +insert ( 1740 1255 0 "convert int4 to numeric" ) +insert ( 1741 1255 0 "base 10 logarithm" ) +insert ( 1481 1255 0 "base 10 logarithm" ) +insert ( 1742 1255 0 "convert float4 to numeric" ) +insert ( 1743 1255 0 "convert float8 to numeric" ) +insert ( 1744 1255 0 "convert numeric to int4" ) +insert ( 1745 1255 0 "convert numeric to float4" ) +insert ( 1746 1255 0 "convert numeric to float8" ) +insert ( 1973 1255 0 "trunc(x/y)" ) +insert ( 1980 1255 0 "trunc(x/y)" ) +insert ( 2170 1255 0 "bucket number of operand in equal-width histogram" ) +insert ( 1764 1255 0 "increment by one" ) +insert ( 1766 1255 0 "smaller of two" ) +insert ( 1767 1255 0 "larger of two" ) +insert ( 1769 1255 0 less-equal-greater ) +insert ( 3283 1255 0 "sort support" ) +insert ( 1779 1255 0 "convert numeric to int8" ) +insert ( 1781 1255 0 "convert int8 to numeric" ) +insert ( 1782 1255 0 "convert int2 to numeric" ) +insert ( 1783 1255 0 "convert numeric to int2" ) +insert ( 3556 1255 0 "convert jsonb to boolean" ) +insert ( 3449 1255 0 "convert jsonb to numeric" ) +insert ( 3450 1255 0 "convert jsonb to int2" ) +insert ( 3451 1255 0 "convert jsonb to int4" ) +insert ( 3452 1255 0 "convert jsonb to int8" ) +insert ( 3453 1255 0 "convert jsonb to float4" ) +insert ( 2580 1255 0 "convert jsonb to float8" ) +insert ( 1770 1255 0 "format timestamp with time zone to text" ) +insert ( 1772 1255 0 "format numeric to text" ) +insert ( 1773 1255 0 "format int4 to text" ) +insert ( 1774 1255 0 "format int8 to text" ) +insert ( 1775 1255 0 "format float4 to text" ) +insert ( 1776 1255 0 "format float8 to text" ) +insert ( 1777 1255 0 "convert text to numeric" ) +insert ( 1778 1255 0 "convert text to timestamp with time zone" ) +insert ( 1780 1255 0 "convert text to date" ) +insert ( 1768 1255 0 "format interval to text" ) +insert ( 1282 1255 0 "quote an identifier for usage in a querystring" ) +insert ( 1283 1255 0 "quote a literal for usage in a querystring" ) +insert ( 1285 1255 0 "quote a data value for usage in a querystring" ) +insert ( 1289 1255 0 "quote a possibly-null literal for usage in a querystring" ) +insert ( 1290 1255 0 "quote a possibly-null data value for usage in a querystring" ) +insert ( 1798 1255 0 "I/O" ) +insert ( 1799 1255 0 "I/O" ) +insert ( 3058 1255 0 "concatenate values" ) +insert ( 3059 1255 0 "concatenate values with separators" ) +insert ( 3060 1255 0 "extract the first n characters" ) +insert ( 3061 1255 0 "extract the last n characters" ) +insert ( 3062 1255 0 "reverse text" ) +insert ( 3539 1255 0 "format text message" ) +insert ( 3540 1255 0 "format text message" ) +insert ( 1810 1255 0 "length in bits" ) +insert ( 1811 1255 0 "length in bits" ) +insert ( 1812 1255 0 "length in bits" ) +insert ( 1814 1255 0 "restriction selectivity of ILIKE" ) +insert ( 1815 1255 0 "restriction selectivity of NOT ILIKE" ) +insert ( 1816 1255 0 "join selectivity of ILIKE" ) +insert ( 1817 1255 0 "join selectivity of NOT ILIKE" ) +insert ( 1818 1255 0 "restriction selectivity of regex match" ) +insert ( 1819 1255 0 "restriction selectivity of LIKE" ) +insert ( 1820 1255 0 "restriction selectivity of case-insensitive regex match" ) +insert ( 1821 1255 0 "restriction selectivity of regex non-match" ) +insert ( 1822 1255 0 "restriction selectivity of NOT LIKE" ) +insert ( 1823 1255 0 "restriction selectivity of case-insensitive regex non-match" ) +insert ( 1824 1255 0 "join selectivity of regex match" ) +insert ( 1825 1255 0 "join selectivity of LIKE" ) +insert ( 1826 1255 0 "join selectivity of case-insensitive regex match" ) +insert ( 1827 1255 0 "join selectivity of regex non-match" ) +insert ( 1828 1255 0 "join selectivity of NOT LIKE" ) +insert ( 1829 1255 0 "join selectivity of case-insensitive regex non-match" ) +insert ( 3437 1255 0 "restriction selectivity of exact prefix" ) +insert ( 3438 1255 0 "join selectivity of exact prefix" ) +insert ( 1830 1255 0 "aggregate final function" ) +insert ( 2512 1255 0 "aggregate final function" ) +insert ( 1831 1255 0 "aggregate final function" ) +insert ( 2513 1255 0 "aggregate final function" ) +insert ( 1832 1255 0 "aggregate final function" ) +insert ( 1833 1255 0 "aggregate transition function" ) +insert ( 3341 1255 0 "aggregate combine function" ) +insert ( 2858 1255 0 "aggregate transition function" ) +insert ( 3337 1255 0 "aggregate combine function" ) +insert ( 2740 1255 0 "aggregate serial function" ) +insert ( 2741 1255 0 "aggregate deserial function" ) +insert ( 3335 1255 0 "aggregate serial function" ) +insert ( 3336 1255 0 "aggregate deserial function" ) +insert ( 3548 1255 0 "aggregate transition function" ) +insert ( 1834 1255 0 "aggregate transition function" ) +insert ( 1835 1255 0 "aggregate transition function" ) +insert ( 1836 1255 0 "aggregate transition function" ) +insert ( 3338 1255 0 "aggregate combine function" ) +insert ( 3339 1255 0 "aggregate serial function" ) +insert ( 3340 1255 0 "aggregate deserial function" ) +insert ( 2746 1255 0 "aggregate transition function" ) +insert ( 3567 1255 0 "aggregate transition function" ) +insert ( 3568 1255 0 "aggregate transition function" ) +insert ( 3569 1255 0 "aggregate transition function" ) +insert ( 3387 1255 0 "aggregate transition function" ) +insert ( 2785 1255 0 "aggregate combine function" ) +insert ( 2786 1255 0 "aggregate serial function" ) +insert ( 2787 1255 0 "aggregate deserial function" ) +insert ( 3324 1255 0 "aggregate combine function" ) +insert ( 3178 1255 0 "aggregate final function" ) +insert ( 1837 1255 0 "aggregate final function" ) +insert ( 2514 1255 0 "aggregate final function" ) +insert ( 1838 1255 0 "aggregate final function" ) +insert ( 2596 1255 0 "aggregate final function" ) +insert ( 1839 1255 0 "aggregate final function" ) +insert ( 1840 1255 0 "aggregate transition function" ) +insert ( 1841 1255 0 "aggregate transition function" ) +insert ( 1842 1255 0 "aggregate transition function" ) +insert ( 3388 1255 0 "aggregate final function" ) +insert ( 3389 1255 0 "aggregate final function" ) +insert ( 3390 1255 0 "aggregate final function" ) +insert ( 3391 1255 0 "aggregate final function" ) +insert ( 3392 1255 0 "aggregate final function" ) +insert ( 3393 1255 0 "aggregate final function" ) +insert ( 1843 1255 0 "aggregate transition function" ) +insert ( 3325 1255 0 "aggregate combine function" ) +insert ( 3549 1255 0 "aggregate transition function" ) +insert ( 1844 1255 0 "aggregate final function" ) +insert ( 1962 1255 0 "aggregate transition function" ) +insert ( 1963 1255 0 "aggregate transition function" ) +insert ( 3570 1255 0 "aggregate transition function" ) +insert ( 3571 1255 0 "aggregate transition function" ) +insert ( 1964 1255 0 "aggregate final function" ) +insert ( 3572 1255 0 "aggregate final function" ) +insert ( 2805 1255 0 "aggregate transition function" ) +insert ( 2806 1255 0 "aggregate transition function" ) +insert ( 3342 1255 0 "aggregate combine function" ) +insert ( 2807 1255 0 "aggregate final function" ) +insert ( 2808 1255 0 "aggregate final function" ) +insert ( 2809 1255 0 "aggregate final function" ) +insert ( 2810 1255 0 "aggregate final function" ) +insert ( 2811 1255 0 "aggregate final function" ) +insert ( 2812 1255 0 "aggregate final function" ) +insert ( 2813 1255 0 "aggregate final function" ) +insert ( 2814 1255 0 "aggregate final function" ) +insert ( 2815 1255 0 "aggregate final function" ) +insert ( 2816 1255 0 "aggregate final function" ) +insert ( 2817 1255 0 "aggregate final function" ) +insert ( 3535 1255 0 "aggregate transition function" ) +insert ( 3536 1255 0 "aggregate final function" ) +insert ( 3538 1255 0 "concatenate aggregate input into a string" ) +insert ( 3543 1255 0 "aggregate transition function" ) +insert ( 3544 1255 0 "aggregate final function" ) +insert ( 3545 1255 0 "concatenate aggregate input into a bytea" ) +insert ( 1845 1255 0 "encode text from DB encoding to ASCII text" ) +insert ( 1846 1255 0 "encode text from encoding to ASCII text" ) +insert ( 1847 1255 0 "encode text from encoding to ASCII text" ) +insert ( 1922 1255 0 "user privilege on relation by username, rel name" ) +insert ( 1923 1255 0 "user privilege on relation by username, rel oid" ) +insert ( 1924 1255 0 "user privilege on relation by user oid, rel name" ) +insert ( 1925 1255 0 "user privilege on relation by user oid, rel oid" ) +insert ( 1926 1255 0 "current user privilege on relation by rel name" ) +insert ( 1927 1255 0 "current user privilege on relation by rel oid" ) +insert ( 2181 1255 0 "user privilege on sequence by username, seq name" ) +insert ( 2182 1255 0 "user privilege on sequence by username, seq oid" ) +insert ( 2183 1255 0 "user privilege on sequence by user oid, seq name" ) +insert ( 2184 1255 0 "user privilege on sequence by user oid, seq oid" ) +insert ( 2185 1255 0 "current user privilege on sequence by seq name" ) +insert ( 2186 1255 0 "current user privilege on sequence by seq oid" ) +insert ( 3012 1255 0 "user privilege on column by username, rel name, col name" ) +insert ( 3013 1255 0 "user privilege on column by username, rel name, col attnum" ) +insert ( 3014 1255 0 "user privilege on column by username, rel oid, col name" ) +insert ( 3015 1255 0 "user privilege on column by username, rel oid, col attnum" ) +insert ( 3016 1255 0 "user privilege on column by user oid, rel name, col name" ) +insert ( 3017 1255 0 "user privilege on column by user oid, rel name, col attnum" ) +insert ( 3018 1255 0 "user privilege on column by user oid, rel oid, col name" ) +insert ( 3019 1255 0 "user privilege on column by user oid, rel oid, col attnum" ) +insert ( 3020 1255 0 "current user privilege on column by rel name, col name" ) +insert ( 3021 1255 0 "current user privilege on column by rel name, col attnum" ) +insert ( 3022 1255 0 "current user privilege on column by rel oid, col name" ) +insert ( 3023 1255 0 "current user privilege on column by rel oid, col attnum" ) +insert ( 3024 1255 0 "user privilege on any column by username, rel name" ) +insert ( 3025 1255 0 "user privilege on any column by username, rel oid" ) +insert ( 3026 1255 0 "user privilege on any column by user oid, rel name" ) +insert ( 3027 1255 0 "user privilege on any column by user oid, rel oid" ) +insert ( 3028 1255 0 "current user privilege on any column by rel name" ) +insert ( 3029 1255 0 "current user privilege on any column by rel oid" ) +insert ( 3355 1255 0 "I/O" ) +insert ( 3356 1255 0 "I/O" ) +insert ( 3357 1255 0 "I/O" ) +insert ( 3358 1255 0 "I/O" ) +insert ( 3404 1255 0 "I/O" ) +insert ( 3405 1255 0 "I/O" ) +insert ( 3406 1255 0 "I/O" ) +insert ( 3407 1255 0 "I/O" ) +insert ( 5018 1255 0 "I/O" ) +insert ( 5019 1255 0 "I/O" ) +insert ( 5020 1255 0 "I/O" ) +insert ( 5021 1255 0 "I/O" ) +insert ( 3427 1255 0 "details about MCV list items" ) +insert ( 1928 1255 0 "statistics: number of scans done for table/index" ) +insert ( 1929 1255 0 "statistics: number of tuples read by seqscan" ) +insert ( 1930 1255 0 "statistics: number of tuples fetched by idxscan" ) +insert ( 1931 1255 0 "statistics: number of tuples inserted" ) +insert ( 1932 1255 0 "statistics: number of tuples updated" ) +insert ( 1933 1255 0 "statistics: number of tuples deleted" ) +insert ( 1972 1255 0 "statistics: number of tuples hot updated" ) +insert ( 2878 1255 0 "statistics: number of live tuples" ) +insert ( 2879 1255 0 "statistics: number of dead tuples" ) +insert ( 3177 1255 0 "statistics: number of tuples changed since last analyze" ) +insert ( 5053 1255 0 "statistics: number of tuples inserted since last vacuum" ) +insert ( 1934 1255 0 "statistics: number of blocks fetched" ) +insert ( 1935 1255 0 "statistics: number of blocks found in cache" ) +insert ( 2781 1255 0 "statistics: last manual vacuum time for a table" ) +insert ( 2782 1255 0 "statistics: last auto vacuum time for a table" ) +insert ( 2783 1255 0 "statistics: last manual analyze time for a table" ) +insert ( 2784 1255 0 "statistics: last auto analyze time for a table" ) +insert ( 3054 1255 0 "statistics: number of manual vacuums for a table" ) +insert ( 3055 1255 0 "statistics: number of auto vacuums for a table" ) +insert ( 3056 1255 0 "statistics: number of manual analyzes for a table" ) +insert ( 3057 1255 0 "statistics: number of auto analyzes for a table" ) +insert ( 1936 1255 0 "statistics: currently active backend IDs" ) +insert ( 2022 1255 0 "statistics: information about currently active backends" ) +insert ( 3318 1255 0 "statistics: information about progress of backends running maintenance command" ) +insert ( 3099 1255 0 "statistics: information about currently active replication" ) +insert ( 3317 1255 0 "statistics: information about WAL receiver" ) +insert ( 6118 1255 0 "statistics: information about subscription" ) +insert ( 2026 1255 0 "statistics: current backend PID" ) +insert ( 1937 1255 0 "statistics: PID of backend" ) +insert ( 1938 1255 0 "statistics: database ID of backend" ) +insert ( 1939 1255 0 "statistics: user ID of backend" ) +insert ( 1940 1255 0 "statistics: current query of backend" ) +insert ( 2788 1255 0 "statistics: wait event type on which backend is currently waiting" ) +insert ( 2853 1255 0 "statistics: wait event on which backend is currently waiting" ) +insert ( 2094 1255 0 "statistics: start time for current query of backend" ) +insert ( 2857 1255 0 "statistics: start time for backend''s current transaction" ) +insert ( 1391 1255 0 "statistics: start time for current backend session" ) +insert ( 1392 1255 0 "statistics: address of client connected to backend" ) +insert ( 1393 1255 0 "statistics: port number of client connected to backend" ) +insert ( 1941 1255 0 "statistics: number of backends in database" ) +insert ( 1942 1255 0 "statistics: transactions committed" ) +insert ( 1943 1255 0 "statistics: transactions rolled back" ) +insert ( 1944 1255 0 "statistics: blocks fetched for database" ) +insert ( 1945 1255 0 "statistics: blocks found in cache for database" ) +insert ( 2758 1255 0 "statistics: tuples returned for database" ) +insert ( 2759 1255 0 "statistics: tuples fetched for database" ) +insert ( 2760 1255 0 "statistics: tuples inserted in database" ) +insert ( 2761 1255 0 "statistics: tuples updated in database" ) +insert ( 2762 1255 0 "statistics: tuples deleted in database" ) +insert ( 3065 1255 0 "statistics: recovery conflicts in database caused by drop tablespace" ) +insert ( 3066 1255 0 "statistics: recovery conflicts in database caused by relation lock" ) +insert ( 3067 1255 0 "statistics: recovery conflicts in database caused by snapshot expiry" ) +insert ( 3068 1255 0 "statistics: recovery conflicts in database caused by shared buffer pin" ) +insert ( 3069 1255 0 "statistics: recovery conflicts in database caused by buffer deadlock" ) +insert ( 3070 1255 0 "statistics: recovery conflicts in database" ) +insert ( 3152 1255 0 "statistics: deadlocks detected in database" ) +insert ( 3426 1255 0 "statistics: checksum failures detected in database" ) +insert ( 3428 1255 0 "statistics: when last checksum failure was detected in database" ) +insert ( 3074 1255 0 "statistics: last reset for a database" ) +insert ( 3150 1255 0 "statistics: number of temporary files written" ) +insert ( 3151 1255 0 "statistics: number of bytes in temporary files written" ) +insert ( 2844 1255 0 "statistics: block read time, in milliseconds" ) +insert ( 2845 1255 0 "statistics: block write time, in milliseconds" ) +insert ( 3195 1255 0 "statistics: information about WAL archiver" ) +insert ( 2769 1255 0 "statistics: number of timed checkpoints started by the bgwriter" ) +insert ( 2770 1255 0 "statistics: number of backend requested checkpoints started by the bgwriter" ) +insert ( 2771 1255 0 "statistics: number of buffers written by the bgwriter during checkpoints" ) +insert ( 2772 1255 0 "statistics: number of buffers written by the bgwriter for cleaning dirty buffers" ) +insert ( 2773 1255 0 "statistics: number of times the bgwriter stopped processing when it had written too many buffers while cleaning" ) +insert ( 3075 1255 0 "statistics: last reset for the bgwriter" ) +insert ( 3160 1255 0 "statistics: checkpoint time spent writing buffers to disk, in milliseconds" ) +insert ( 3161 1255 0 "statistics: checkpoint time spent synchronizing buffers to disk, in milliseconds" ) +insert ( 2775 1255 0 "statistics: number of buffers written by backends" ) +insert ( 3063 1255 0 "statistics: number of backend buffer writes that did their own fsync" ) +insert ( 2859 1255 0 "statistics: number of buffer allocations" ) +insert ( 2306 1255 0 "statistics: information about SLRU caches" ) +insert ( 2978 1255 0 "statistics: number of function calls" ) +insert ( 2979 1255 0 "statistics: total execution time of function, in milliseconds" ) +insert ( 2980 1255 0 "statistics: self execution time of function, in milliseconds" ) +insert ( 3037 1255 0 "statistics: number of scans done for table/index in current transaction" ) +insert ( 3038 1255 0 "statistics: number of tuples read by seqscan in current transaction" ) +insert ( 3039 1255 0 "statistics: number of tuples fetched by idxscan in current transaction" ) +insert ( 3040 1255 0 "statistics: number of tuples inserted in current transaction" ) +insert ( 3041 1255 0 "statistics: number of tuples updated in current transaction" ) +insert ( 3042 1255 0 "statistics: number of tuples deleted in current transaction" ) +insert ( 3043 1255 0 "statistics: number of tuples hot updated in current transaction" ) +insert ( 3044 1255 0 "statistics: number of blocks fetched in current transaction" ) +insert ( 3045 1255 0 "statistics: number of blocks found in cache in current transaction" ) +insert ( 3046 1255 0 "statistics: number of function calls in current transaction" ) +insert ( 3047 1255 0 "statistics: total execution time of function in current transaction, in milliseconds" ) +insert ( 3048 1255 0 "statistics: self execution time of function in current transaction, in milliseconds" ) +insert ( 3788 1255 0 "statistics: timestamp of the current statistics snapshot" ) +insert ( 2230 1255 0 "statistics: discard current transaction''s statistics snapshot" ) +insert ( 2274 1255 0 "statistics: reset collected statistics for current database" ) +insert ( 3775 1255 0 "statistics: reset collected statistics shared across the cluster" ) +insert ( 3776 1255 0 "statistics: reset collected statistics for a single table or index in the current database" ) +insert ( 3777 1255 0 "statistics: reset collected statistics for a single function in the current database" ) +insert ( 2307 1255 0 "statistics: reset collected statistics for a single SLRU" ) +insert ( 3163 1255 0 "current trigger depth" ) +insert ( 3778 1255 0 "tablespace location" ) +insert ( 1946 1255 0 "convert bytea value into some ascii-only text string" ) +insert ( 1947 1255 0 "convert ascii-encoded text string into bytea value" ) +insert ( 1954 1255 0 less-equal-greater ) +insert ( 3331 1255 0 "sort support" ) +insert ( 3917 1255 0 "planner support for timestamp length coercion" ) +insert ( 3944 1255 0 "planner support for time length coercion" ) +insert ( 1961 1255 0 "adjust timestamp precision" ) +insert ( 1965 1255 0 "larger of two" ) +insert ( 1966 1255 0 "smaller of two" ) +insert ( 1967 1255 0 "adjust timestamptz precision" ) +insert ( 1968 1255 0 "adjust time precision" ) +insert ( 1969 1255 0 "adjust time with time zone precision" ) +insert ( 2007 1255 0 "matches LIKE expression" ) +insert ( 2008 1255 0 "does not match LIKE expression" ) +insert ( 2009 1255 0 "convert LIKE pattern to use backslash escapes" ) +insert ( 2010 1255 0 "octet length" ) +insert ( 2012 1255 0 "extract portion of string" ) +insert ( 2013 1255 0 "extract portion of string" ) +insert ( 2085 1255 0 "extract portion of string" ) +insert ( 2086 1255 0 "extract portion of string" ) +insert ( 2014 1255 0 "position of substring" ) +insert ( 2015 1255 0 "trim both ends of string" ) +insert ( 2019 1255 0 "convert timestamp with time zone to time" ) +insert ( 2020 1255 0 "truncate timestamp to specified units" ) +insert ( 2021 1255 0 "extract field from timestamp" ) +insert ( 2024 1255 0 "convert date to timestamp" ) +insert ( 2025 1255 0 "convert date and time to timestamp" ) +insert ( 2027 1255 0 "convert timestamp with time zone to timestamp" ) +insert ( 2028 1255 0 "convert timestamp to timestamp with time zone" ) +insert ( 2029 1255 0 "convert timestamp to date" ) +insert ( 2035 1255 0 "smaller of two" ) +insert ( 2036 1255 0 "larger of two" ) +insert ( 2037 1255 0 "adjust time with time zone to new zone" ) +insert ( 2038 1255 0 "adjust time with time zone to new zone" ) +insert ( 2039 1255 0 hash ) +insert ( 3411 1255 0 hash ) +insert ( 2041 1255 0 "intervals overlap?" ) +insert ( 2042 1255 0 "intervals overlap?" ) +insert ( 2043 1255 0 "intervals overlap?" ) +insert ( 2044 1255 0 "intervals overlap?" ) +insert ( 2045 1255 0 less-equal-greater ) +insert ( 3137 1255 0 "sort support" ) +insert ( 4134 1255 0 "window RANGE support" ) +insert ( 4135 1255 0 "window RANGE support" ) +insert ( 4136 1255 0 "window RANGE support" ) +insert ( 4137 1255 0 "window RANGE support" ) +insert ( 4138 1255 0 "window RANGE support" ) +insert ( 2046 1255 0 "convert time with time zone to time" ) +insert ( 2047 1255 0 "convert time to time with time zone" ) +insert ( 2048 1255 0 "finite timestamp?" ) +insert ( 2049 1255 0 "format timestamp to text" ) +insert ( 2058 1255 0 "date difference preserving months and years" ) +insert ( 2059 1255 0 "date difference from today preserving months and years" ) +insert ( 2069 1255 0 "adjust timestamp to new time zone" ) +insert ( 2070 1255 0 "adjust timestamp to new time zone" ) +insert ( 2073 1255 0 "extract text matching regular expression" ) +insert ( 2074 1255 0 "extract text matching SQL regular expression" ) +insert ( 2075 1255 0 "convert int8 to bitstring" ) +insert ( 2076 1255 0 "convert bitstring to int8" ) +insert ( 2077 1255 0 "SHOW X as a function" ) +insert ( 3294 1255 0 "SHOW X as a function, optionally no error for missing variable" ) +insert ( 2078 1255 0 "SET X as a function" ) +insert ( 2084 1255 0 "SHOW ALL as a function" ) +insert ( 3329 1255 0 "show config file settings" ) +insert ( 3401 1255 0 "show pg_hba.conf rules" ) +insert ( 1371 1255 0 "view system lock information" ) +insert ( 2561 1255 0 "get array of PIDs of sessions blocking specified backend PID from acquiring a heavyweight lock" ) +insert ( 3376 1255 0 "get array of PIDs of sessions blocking specified backend PID from acquiring a safe snapshot" ) +insert ( 3378 1255 0 "isolationtester support function" ) +insert ( 1065 1255 0 "view two-phase transactions" ) +insert ( 3819 1255 0 "view members of a multixactid" ) +insert ( 3581 1255 0 "get commit timestamp of a transaction" ) +insert ( 3583 1255 0 "get transaction Id and commit timestamp of latest transaction commit" ) +insert ( 3537 1255 0 "get identification of SQL object" ) +insert ( 3839 1255 0 "get machine-parseable identification of SQL object" ) +insert ( 3382 1255 0 "get identification of SQL object for pg_get_object_address()" ) +insert ( 3954 1255 0 "get OID-based object address from name/args arrays" ) +insert ( 2079 1255 0 "is table visible in search path?" ) +insert ( 2080 1255 0 "is type visible in search path?" ) +insert ( 2081 1255 0 "is function visible in search path?" ) +insert ( 2082 1255 0 "is operator visible in search path?" ) +insert ( 2083 1255 0 "is opclass visible in search path?" ) +insert ( 3829 1255 0 "is opfamily visible in search path?" ) +insert ( 2093 1255 0 "is conversion visible in search path?" ) +insert ( 3403 1255 0 "is statistics object visible in search path?" ) +insert ( 3756 1255 0 "is text search parser visible in search path?" ) +insert ( 3757 1255 0 "is text search dictionary visible in search path?" ) +insert ( 3768 1255 0 "is text search template visible in search path?" ) +insert ( 3758 1255 0 "is text search configuration visible in search path?" ) +insert ( 3815 1255 0 "is collation visible in search path?" ) +insert ( 2854 1255 0 "get OID of current session''s temp schema, if any" ) +insert ( 2855 1255 0 "is schema another session''s temp schema?" ) +insert ( 2171 1255 0 "cancel a server process'' current query" ) +insert ( 2096 1255 0 "terminate a server process" ) +insert ( 2172 1255 0 "prepare for taking an online backup" ) +insert ( 2173 1255 0 "finish taking an online backup" ) +insert ( 2739 1255 0 "finish taking an online backup" ) +insert ( 3813 1255 0 "true if server is in online backup" ) +insert ( 3814 1255 0 "start time of an online backup" ) +insert ( 3436 1255 0 "promote standby server" ) +insert ( 2848 1255 0 "switch to new wal file" ) +insert ( 3098 1255 0 "create a named restore point" ) +insert ( 2849 1255 0 "current wal write location" ) +insert ( 2852 1255 0 "current wal insert location" ) +insert ( 3330 1255 0 "current wal flush location" ) +insert ( 2850 1255 0 "wal filename and byte offset, given a wal location" ) +insert ( 2851 1255 0 "wal filename, given a wal location" ) +insert ( 3165 1255 0 "difference in bytes, given two wal locations" ) +insert ( 3809 1255 0 "export a snapshot" ) +insert ( 3810 1255 0 "true if server is in recovery" ) +insert ( 3820 1255 0 "current wal flush location" ) +insert ( 3821 1255 0 "last wal replay location" ) +insert ( 3830 1255 0 "timestamp of last replay xact" ) +insert ( 3071 1255 0 "pause wal replay" ) +insert ( 3072 1255 0 "resume wal replay, if it was paused" ) +insert ( 3073 1255 0 "true if wal replay is paused" ) +insert ( 2621 1255 0 "reload configuration files" ) +insert ( 2622 1255 0 "rotate log file" ) +insert ( 4099 1255 0 "rotate log file - old version for adminpack 1.0" ) +insert ( 3800 1255 0 "current logging collector file location" ) +insert ( 3801 1255 0 "current logging collector file location" ) +insert ( 2623 1255 0 "get information about file" ) +insert ( 3307 1255 0 "get information about file" ) +insert ( 2624 1255 0 "read text from a file" ) +insert ( 3293 1255 0 "read text from a file" ) +insert ( 4100 1255 0 "read text from a file - old version for adminpack 1.0" ) +insert ( 3826 1255 0 "read text from a file" ) +insert ( 3827 1255 0 "read bytea from a file" ) +insert ( 3295 1255 0 "read bytea from a file" ) +insert ( 3828 1255 0 "read bytea from a file" ) +insert ( 2625 1255 0 "list all files in a directory" ) +insert ( 3297 1255 0 "list all files in a directory" ) +insert ( 2626 1255 0 "sleep for the specified time in seconds" ) +insert ( 3935 1255 0 "sleep for the specified interval" ) +insert ( 3936 1255 0 "sleep until the specified time" ) +insert ( 315 1255 0 "Is JIT compilation available in this session?" ) +insert ( 2971 1255 0 "convert boolean to text" ) +insert ( 2100 1255 0 "the average (arithmetic mean) as numeric of all bigint values" ) +insert ( 2101 1255 0 "the average (arithmetic mean) as numeric of all integer values" ) +insert ( 2102 1255 0 "the average (arithmetic mean) as numeric of all smallint values" ) +insert ( 2103 1255 0 "the average (arithmetic mean) as numeric of all numeric values" ) +insert ( 2104 1255 0 "the average (arithmetic mean) as float8 of all float4 values" ) +insert ( 2105 1255 0 "the average (arithmetic mean) as float8 of all float8 values" ) +insert ( 2106 1255 0 "the average (arithmetic mean) as interval of all interval values" ) +insert ( 2107 1255 0 "sum as numeric across all bigint input values" ) +insert ( 2108 1255 0 "sum as bigint across all integer input values" ) +insert ( 2109 1255 0 "sum as bigint across all smallint input values" ) +insert ( 2110 1255 0 "sum as float4 across all float4 input values" ) +insert ( 2111 1255 0 "sum as float8 across all float8 input values" ) +insert ( 2112 1255 0 "sum as money across all money input values" ) +insert ( 2113 1255 0 "sum as interval across all interval input values" ) +insert ( 2114 1255 0 "sum as numeric across all numeric input values" ) +insert ( 2115 1255 0 "maximum value of all bigint input values" ) +insert ( 2116 1255 0 "maximum value of all integer input values" ) +insert ( 2117 1255 0 "maximum value of all smallint input values" ) +insert ( 2118 1255 0 "maximum value of all oid input values" ) +insert ( 2119 1255 0 "maximum value of all float4 input values" ) +insert ( 2120 1255 0 "maximum value of all float8 input values" ) +insert ( 2122 1255 0 "maximum value of all date input values" ) +insert ( 2123 1255 0 "maximum value of all time input values" ) +insert ( 2124 1255 0 "maximum value of all time with time zone input values" ) +insert ( 2125 1255 0 "maximum value of all money input values" ) +insert ( 2126 1255 0 "maximum value of all timestamp input values" ) +insert ( 2127 1255 0 "maximum value of all timestamp with time zone input values" ) +insert ( 2128 1255 0 "maximum value of all interval input values" ) +insert ( 2129 1255 0 "maximum value of all text input values" ) +insert ( 2130 1255 0 "maximum value of all numeric input values" ) +insert ( 2050 1255 0 "maximum value of all anyarray input values" ) +insert ( 2244 1255 0 "maximum value of all bpchar input values" ) +insert ( 2797 1255 0 "maximum value of all tid input values" ) +insert ( 3564 1255 0 "maximum value of all inet input values" ) +insert ( 4189 1255 0 "maximum value of all pg_lsn input values" ) +insert ( 2131 1255 0 "minimum value of all bigint input values" ) +insert ( 2132 1255 0 "minimum value of all integer input values" ) +insert ( 2133 1255 0 "minimum value of all smallint input values" ) +insert ( 2134 1255 0 "minimum value of all oid input values" ) +insert ( 2135 1255 0 "minimum value of all float4 input values" ) +insert ( 2136 1255 0 "minimum value of all float8 input values" ) +insert ( 2138 1255 0 "minimum value of all date input values" ) +insert ( 2139 1255 0 "minimum value of all time input values" ) +insert ( 2140 1255 0 "minimum value of all time with time zone input values" ) +insert ( 2141 1255 0 "minimum value of all money input values" ) +insert ( 2142 1255 0 "minimum value of all timestamp input values" ) +insert ( 2143 1255 0 "minimum value of all timestamp with time zone input values" ) +insert ( 2144 1255 0 "minimum value of all interval input values" ) +insert ( 2145 1255 0 "minimum value of all text values" ) +insert ( 2146 1255 0 "minimum value of all numeric input values" ) +insert ( 2051 1255 0 "minimum value of all anyarray input values" ) +insert ( 2245 1255 0 "minimum value of all bpchar input values" ) +insert ( 2798 1255 0 "minimum value of all tid input values" ) +insert ( 3565 1255 0 "minimum value of all inet input values" ) +insert ( 4190 1255 0 "minimum value of all pg_lsn input values" ) +insert ( 2147 1255 0 "number of input rows for which the input expression is not null" ) +insert ( 2803 1255 0 "number of input rows" ) +insert ( 2718 1255 0 "population variance of bigint input values (square of the population standard deviation)" ) +insert ( 2719 1255 0 "population variance of integer input values (square of the population standard deviation)" ) +insert ( 2720 1255 0 "population variance of smallint input values (square of the population standard deviation)" ) +insert ( 2721 1255 0 "population variance of float4 input values (square of the population standard deviation)" ) +insert ( 2722 1255 0 "population variance of float8 input values (square of the population standard deviation)" ) +insert ( 2723 1255 0 "population variance of numeric input values (square of the population standard deviation)" ) +insert ( 2641 1255 0 "sample variance of bigint input values (square of the sample standard deviation)" ) +insert ( 2642 1255 0 "sample variance of integer input values (square of the sample standard deviation)" ) +insert ( 2643 1255 0 "sample variance of smallint input values (square of the sample standard deviation)" ) +insert ( 2644 1255 0 "sample variance of float4 input values (square of the sample standard deviation)" ) +insert ( 2645 1255 0 "sample variance of float8 input values (square of the sample standard deviation)" ) +insert ( 2646 1255 0 "sample variance of numeric input values (square of the sample standard deviation)" ) +insert ( 2148 1255 0 "historical alias for var_samp" ) +insert ( 2149 1255 0 "historical alias for var_samp" ) +insert ( 2150 1255 0 "historical alias for var_samp" ) +insert ( 2151 1255 0 "historical alias for var_samp" ) +insert ( 2152 1255 0 "historical alias for var_samp" ) +insert ( 2153 1255 0 "historical alias for var_samp" ) +insert ( 2724 1255 0 "population standard deviation of bigint input values" ) +insert ( 2725 1255 0 "population standard deviation of integer input values" ) +insert ( 2726 1255 0 "population standard deviation of smallint input values" ) +insert ( 2727 1255 0 "population standard deviation of float4 input values" ) +insert ( 2728 1255 0 "population standard deviation of float8 input values" ) +insert ( 2729 1255 0 "population standard deviation of numeric input values" ) +insert ( 2712 1255 0 "sample standard deviation of bigint input values" ) +insert ( 2713 1255 0 "sample standard deviation of integer input values" ) +insert ( 2714 1255 0 "sample standard deviation of smallint input values" ) +insert ( 2715 1255 0 "sample standard deviation of float4 input values" ) +insert ( 2716 1255 0 "sample standard deviation of float8 input values" ) +insert ( 2717 1255 0 "sample standard deviation of numeric input values" ) +insert ( 2154 1255 0 "historical alias for stddev_samp" ) +insert ( 2155 1255 0 "historical alias for stddev_samp" ) +insert ( 2156 1255 0 "historical alias for stddev_samp" ) +insert ( 2157 1255 0 "historical alias for stddev_samp" ) +insert ( 2158 1255 0 "historical alias for stddev_samp" ) +insert ( 2159 1255 0 "historical alias for stddev_samp" ) +insert ( 2818 1255 0 "number of input rows in which both expressions are not null" ) +insert ( 2819 1255 0 "sum of squares of the independent variable (sum(X^2) - sum(X)^2/N)" ) +insert ( 2820 1255 0 "sum of squares of the dependent variable (sum(Y^2) - sum(Y)^2/N)" ) +insert ( 2821 1255 0 "sum of products of independent times dependent variable (sum(X*Y) - sum(X) * sum(Y)/N)" ) +insert ( 2822 1255 0 "average of the independent variable (sum(X)/N)" ) +insert ( 2823 1255 0 "average of the dependent variable (sum(Y)/N)" ) +insert ( 2824 1255 0 "square of the correlation coefficient" ) +insert ( 2825 1255 0 "slope of the least-squares-fit linear equation determined by the (X, Y) pairs" ) +insert ( 2826 1255 0 "y-intercept of the least-squares-fit linear equation determined by the (X, Y) pairs" ) +insert ( 2827 1255 0 "population covariance" ) +insert ( 2828 1255 0 "sample covariance" ) +insert ( 2829 1255 0 "correlation coefficient" ) +insert ( 2166 1255 0 less-equal-greater ) +insert ( 3332 1255 0 "sort support" ) +insert ( 2180 1255 0 less-equal-greater ) +insert ( 3333 1255 0 "sort support" ) +insert ( 2188 1255 0 less-equal-greater ) +insert ( 2189 1255 0 less-equal-greater ) +insert ( 2190 1255 0 less-equal-greater ) +insert ( 2191 1255 0 less-equal-greater ) +insert ( 2192 1255 0 less-equal-greater ) +insert ( 2193 1255 0 less-equal-greater ) +insert ( 2194 1255 0 less-equal-greater ) +insert ( 2195 1255 0 less-equal-greater ) +insert ( 2212 1255 0 "I/O" ) +insert ( 2213 1255 0 "I/O" ) +insert ( 2214 1255 0 "I/O" ) +insert ( 2215 1255 0 "I/O" ) +insert ( 3492 1255 0 "convert operator name to regoper" ) +insert ( 3476 1255 0 "convert operator name to regoperator" ) +insert ( 2216 1255 0 "I/O" ) +insert ( 2217 1255 0 "I/O" ) +insert ( 2218 1255 0 "I/O" ) +insert ( 2219 1255 0 "I/O" ) +insert ( 3495 1255 0 "convert classname to regclass" ) +insert ( 4193 1255 0 "I/O" ) +insert ( 4194 1255 0 "I/O" ) +insert ( 4195 1255 0 "convert classname to regcollation" ) +insert ( 2220 1255 0 "I/O" ) +insert ( 2221 1255 0 "I/O" ) +insert ( 3493 1255 0 "convert type name to regtype" ) +insert ( 1079 1255 0 "convert text to regclass" ) +insert ( 4098 1255 0 "I/O" ) +insert ( 4092 1255 0 "I/O" ) +insert ( 4093 1255 0 "convert role name to regrole" ) +insert ( 4084 1255 0 "I/O" ) +insert ( 4085 1255 0 "I/O" ) +insert ( 4086 1255 0 "convert namespace name to regnamespace" ) +insert ( 1268 1255 0 "parse qualified identifier to array of identifiers" ) +insert ( 2246 1255 0 "(internal)" ) +insert ( 2247 1255 0 "(internal)" ) +insert ( 2248 1255 0 "(internal)" ) +insert ( 2250 1255 0 "user privilege on database by username, database name" ) +insert ( 2251 1255 0 "user privilege on database by username, database oid" ) +insert ( 2252 1255 0 "user privilege on database by user oid, database name" ) +insert ( 2253 1255 0 "user privilege on database by user oid, database oid" ) +insert ( 2254 1255 0 "current user privilege on database by database name" ) +insert ( 2255 1255 0 "current user privilege on database by database oid" ) +insert ( 2256 1255 0 "user privilege on function by username, function name" ) +insert ( 2257 1255 0 "user privilege on function by username, function oid" ) +insert ( 2258 1255 0 "user privilege on function by user oid, function name" ) +insert ( 2259 1255 0 "user privilege on function by user oid, function oid" ) +insert ( 2260 1255 0 "current user privilege on function by function name" ) +insert ( 2261 1255 0 "current user privilege on function by function oid" ) +insert ( 2262 1255 0 "user privilege on language by username, language name" ) +insert ( 2263 1255 0 "user privilege on language by username, language oid" ) +insert ( 2264 1255 0 "user privilege on language by user oid, language name" ) +insert ( 2265 1255 0 "user privilege on language by user oid, language oid" ) +insert ( 2266 1255 0 "current user privilege on language by language name" ) +insert ( 2267 1255 0 "current user privilege on language by language oid" ) +insert ( 2268 1255 0 "user privilege on schema by username, schema name" ) +insert ( 2269 1255 0 "user privilege on schema by username, schema oid" ) +insert ( 2270 1255 0 "user privilege on schema by user oid, schema name" ) +insert ( 2271 1255 0 "user privilege on schema by user oid, schema oid" ) +insert ( 2272 1255 0 "current user privilege on schema by schema name" ) +insert ( 2273 1255 0 "current user privilege on schema by schema oid" ) +insert ( 2390 1255 0 "user privilege on tablespace by username, tablespace name" ) +insert ( 2391 1255 0 "user privilege on tablespace by username, tablespace oid" ) +insert ( 2392 1255 0 "user privilege on tablespace by user oid, tablespace name" ) +insert ( 2393 1255 0 "user privilege on tablespace by user oid, tablespace oid" ) +insert ( 2394 1255 0 "current user privilege on tablespace by tablespace name" ) +insert ( 2395 1255 0 "current user privilege on tablespace by tablespace oid" ) +insert ( 3000 1255 0 "user privilege on foreign data wrapper by username, foreign data wrapper name" ) +insert ( 3001 1255 0 "user privilege on foreign data wrapper by username, foreign data wrapper oid" ) +insert ( 3002 1255 0 "user privilege on foreign data wrapper by user oid, foreign data wrapper name" ) +insert ( 3003 1255 0 "user privilege on foreign data wrapper by user oid, foreign data wrapper oid" ) +insert ( 3004 1255 0 "current user privilege on foreign data wrapper by foreign data wrapper name" ) +insert ( 3005 1255 0 "current user privilege on foreign data wrapper by foreign data wrapper oid" ) +insert ( 3006 1255 0 "user privilege on server by username, server name" ) +insert ( 3007 1255 0 "user privilege on server by username, server oid" ) +insert ( 3008 1255 0 "user privilege on server by user oid, server name" ) +insert ( 3009 1255 0 "user privilege on server by user oid, server oid" ) +insert ( 3010 1255 0 "current user privilege on server by server name" ) +insert ( 3011 1255 0 "current user privilege on server by server oid" ) +insert ( 3138 1255 0 "user privilege on type by username, type name" ) +insert ( 3139 1255 0 "user privilege on type by username, type oid" ) +insert ( 3140 1255 0 "user privilege on type by user oid, type name" ) +insert ( 3141 1255 0 "user privilege on type by user oid, type oid" ) +insert ( 3142 1255 0 "current user privilege on type by type name" ) +insert ( 3143 1255 0 "current user privilege on type by type oid" ) +insert ( 2705 1255 0 "user privilege on role by username, role name" ) +insert ( 2706 1255 0 "user privilege on role by username, role oid" ) +insert ( 2707 1255 0 "user privilege on role by user oid, role name" ) +insert ( 2708 1255 0 "user privilege on role by user oid, role oid" ) +insert ( 2709 1255 0 "current user privilege on role by role name" ) +insert ( 2710 1255 0 "current user privilege on role by role oid" ) +insert ( 1269 1255 0 "bytes required to store the value, perhaps with compression" ) +insert ( 2322 1255 0 "total disk space usage for the specified tablespace" ) +insert ( 2323 1255 0 "total disk space usage for the specified tablespace" ) +insert ( 2324 1255 0 "total disk space usage for the specified database" ) +insert ( 2168 1255 0 "total disk space usage for the specified database" ) +insert ( 2325 1255 0 "disk space usage for the main fork of the specified table or index" ) +insert ( 2332 1255 0 "disk space usage for the specified fork of a table or index" ) +insert ( 2286 1255 0 "total disk space usage for the specified table and associated indexes" ) +insert ( 2288 1255 0 "convert a long int to a human readable text using size units" ) +insert ( 3166 1255 0 "convert a numeric to a human readable text using size units" ) +insert ( 3334 1255 0 "convert a size in human-readable format with size units into bytes" ) +insert ( 2997 1255 0 "disk space usage for the specified table, including TOAST, free space and visibility map" ) +insert ( 2998 1255 0 "disk space usage for all indexes attached to the specified table" ) +insert ( 2999 1255 0 "filenode identifier of relation" ) +insert ( 3454 1255 0 "relation OID for filenode and tablespace" ) +insert ( 3034 1255 0 "file path of relation" ) +insert ( 2316 1255 0 "(internal)" ) +insert ( 2290 1255 0 "I/O" ) +insert ( 2291 1255 0 "I/O" ) +insert ( 2292 1255 0 "I/O" ) +insert ( 2293 1255 0 "I/O" ) +insert ( 2294 1255 0 "I/O" ) +insert ( 2295 1255 0 "I/O" ) +insert ( 2296 1255 0 "I/O" ) +insert ( 2297 1255 0 "I/O" ) +insert ( 2298 1255 0 "I/O" ) +insert ( 2299 1255 0 "I/O" ) +insert ( 2300 1255 0 "I/O" ) +insert ( 2301 1255 0 "I/O" ) +insert ( 3594 1255 0 "I/O" ) +insert ( 3595 1255 0 "I/O" ) +insert ( 2302 1255 0 "I/O" ) +insert ( 2303 1255 0 "I/O" ) +insert ( 2304 1255 0 "I/O" ) +insert ( 2305 1255 0 "I/O" ) +insert ( 2312 1255 0 "I/O" ) +insert ( 2313 1255 0 "I/O" ) +insert ( 2398 1255 0 "I/O" ) +insert ( 2399 1255 0 "I/O" ) +insert ( 2597 1255 0 "I/O" ) +insert ( 2598 1255 0 "I/O" ) +insert ( 2777 1255 0 "I/O" ) +insert ( 2778 1255 0 "I/O" ) +insert ( 3116 1255 0 "I/O" ) +insert ( 3117 1255 0 "I/O" ) +insert ( 326 1255 0 "I/O" ) +insert ( 327 1255 0 "I/O" ) +insert ( 3311 1255 0 "I/O" ) +insert ( 3312 1255 0 "I/O" ) +insert ( 267 1255 0 "I/O" ) +insert ( 268 1255 0 "I/O" ) +insert ( 5086 1255 0 "I/O" ) +insert ( 5087 1255 0 "I/O" ) +insert ( 5088 1255 0 "I/O" ) +insert ( 5089 1255 0 "I/O" ) +insert ( 5090 1255 0 "I/O" ) +insert ( 5091 1255 0 "I/O" ) +insert ( 5092 1255 0 "I/O" ) +insert ( 5093 1255 0 "I/O" ) +insert ( 5094 1255 0 "I/O" ) +insert ( 5095 1255 0 "I/O" ) +insert ( 3313 1255 0 "BERNOULLI tablesample method handler" ) +insert ( 3314 1255 0 "SYSTEM tablesample method handler" ) +insert ( 2311 1255 0 "MD5 hash" ) +insert ( 2321 1255 0 "MD5 hash" ) +insert ( 3419 1255 0 "SHA-224 hash" ) +insert ( 3420 1255 0 "SHA-256 hash" ) +insert ( 3421 1255 0 "SHA-384 hash" ) +insert ( 3422 1255 0 "SHA-512 hash" ) +insert ( 2344 1255 0 less-equal-greater ) +insert ( 2357 1255 0 less-equal-greater ) +insert ( 2370 1255 0 less-equal-greater ) +insert ( 2383 1255 0 less-equal-greater ) +insert ( 2526 1255 0 less-equal-greater ) +insert ( 2533 1255 0 less-equal-greater ) +insert ( 2400 1255 0 "I/O" ) +insert ( 2401 1255 0 "I/O" ) +insert ( 2402 1255 0 "I/O" ) +insert ( 2403 1255 0 "I/O" ) +insert ( 2404 1255 0 "I/O" ) +insert ( 2405 1255 0 "I/O" ) +insert ( 2406 1255 0 "I/O" ) +insert ( 2407 1255 0 "I/O" ) +insert ( 2408 1255 0 "I/O" ) +insert ( 2409 1255 0 "I/O" ) +insert ( 2410 1255 0 "I/O" ) +insert ( 2411 1255 0 "I/O" ) +insert ( 2412 1255 0 "I/O" ) +insert ( 2413 1255 0 "I/O" ) +insert ( 2414 1255 0 "I/O" ) +insert ( 2415 1255 0 "I/O" ) +insert ( 2416 1255 0 "I/O" ) +insert ( 2417 1255 0 "I/O" ) +insert ( 2418 1255 0 "I/O" ) +insert ( 2419 1255 0 "I/O" ) +insert ( 2420 1255 0 "I/O" ) +insert ( 2421 1255 0 "I/O" ) +insert ( 2422 1255 0 "I/O" ) +insert ( 2423 1255 0 "I/O" ) +insert ( 2424 1255 0 "I/O" ) +insert ( 2425 1255 0 "I/O" ) +insert ( 2426 1255 0 "I/O" ) +insert ( 2427 1255 0 "I/O" ) +insert ( 2428 1255 0 "I/O" ) +insert ( 2429 1255 0 "I/O" ) +insert ( 2430 1255 0 "I/O" ) +insert ( 2431 1255 0 "I/O" ) +insert ( 2432 1255 0 "I/O" ) +insert ( 2433 1255 0 "I/O" ) +insert ( 2434 1255 0 "I/O" ) +insert ( 2435 1255 0 "I/O" ) +insert ( 2436 1255 0 "I/O" ) +insert ( 2437 1255 0 "I/O" ) +insert ( 2438 1255 0 "I/O" ) +insert ( 2439 1255 0 "I/O" ) +insert ( 2440 1255 0 "I/O" ) +insert ( 2441 1255 0 "I/O" ) +insert ( 2442 1255 0 "I/O" ) +insert ( 2443 1255 0 "I/O" ) +insert ( 2444 1255 0 "I/O" ) +insert ( 2445 1255 0 "I/O" ) +insert ( 2446 1255 0 "I/O" ) +insert ( 2447 1255 0 "I/O" ) +insert ( 2448 1255 0 "I/O" ) +insert ( 2449 1255 0 "I/O" ) +insert ( 2450 1255 0 "I/O" ) +insert ( 2451 1255 0 "I/O" ) +insert ( 2452 1255 0 "I/O" ) +insert ( 2453 1255 0 "I/O" ) +insert ( 4196 1255 0 "I/O" ) +insert ( 4197 1255 0 "I/O" ) +insert ( 2454 1255 0 "I/O" ) +insert ( 2455 1255 0 "I/O" ) +insert ( 4094 1255 0 "I/O" ) +insert ( 4095 1255 0 "I/O" ) +insert ( 4087 1255 0 "I/O" ) +insert ( 4088 1255 0 "I/O" ) +insert ( 2456 1255 0 "I/O" ) +insert ( 2457 1255 0 "I/O" ) +insert ( 2458 1255 0 "I/O" ) +insert ( 2459 1255 0 "I/O" ) +insert ( 2460 1255 0 "I/O" ) +insert ( 2461 1255 0 "I/O" ) +insert ( 2468 1255 0 "I/O" ) +insert ( 2469 1255 0 "I/O" ) +insert ( 2470 1255 0 "I/O" ) +insert ( 2471 1255 0 "I/O" ) +insert ( 2472 1255 0 "I/O" ) +insert ( 2473 1255 0 "I/O" ) +insert ( 2474 1255 0 "I/O" ) +insert ( 2475 1255 0 "I/O" ) +insert ( 2476 1255 0 "I/O" ) +insert ( 2477 1255 0 "I/O" ) +insert ( 2478 1255 0 "I/O" ) +insert ( 2479 1255 0 "I/O" ) +insert ( 2480 1255 0 "I/O" ) +insert ( 2481 1255 0 "I/O" ) +insert ( 2482 1255 0 "I/O" ) +insert ( 2483 1255 0 "I/O" ) +insert ( 2484 1255 0 "I/O" ) +insert ( 2485 1255 0 "I/O" ) +insert ( 2486 1255 0 "I/O" ) +insert ( 2487 1255 0 "I/O" ) +insert ( 2488 1255 0 "I/O" ) +insert ( 2489 1255 0 "I/O" ) +insert ( 2490 1255 0 "I/O" ) +insert ( 2491 1255 0 "I/O" ) +insert ( 2492 1255 0 "I/O" ) +insert ( 2493 1255 0 "I/O" ) +insert ( 2494 1255 0 "I/O" ) +insert ( 2495 1255 0 "I/O" ) +insert ( 2496 1255 0 "I/O" ) +insert ( 2497 1255 0 "I/O" ) +insert ( 2498 1255 0 "I/O" ) +insert ( 2499 1255 0 "I/O" ) +insert ( 2500 1255 0 "I/O" ) +insert ( 2501 1255 0 "I/O" ) +insert ( 2502 1255 0 "I/O" ) +insert ( 2503 1255 0 "I/O" ) +insert ( 3120 1255 0 "I/O" ) +insert ( 3121 1255 0 "I/O" ) +insert ( 3446 1255 0 "I/O" ) +insert ( 3447 1255 0 "I/O" ) +insert ( 2504 1255 0 "source text of a rule with pretty-print option" ) +insert ( 2505 1255 0 "select statement of a view with pretty-print option" ) +insert ( 2506 1255 0 "select statement of a view with pretty-print option" ) +insert ( 3159 1255 0 "select statement of a view with pretty-printing and specified line wrapping" ) +insert ( 2507 1255 0 "index description (full create statement or single expression) with pretty-print option" ) +insert ( 2508 1255 0 "constraint description with pretty-print option" ) +insert ( 2509 1255 0 "deparse an encoded expression with pretty-print option" ) +insert ( 2510 1255 0 "get the prepared statements for this session" ) +insert ( 2511 1255 0 "get the open cursors for this session" ) +insert ( 2599 1255 0 "get the available time zone abbreviations" ) +insert ( 2856 1255 0 "get the available time zone names" ) +insert ( 2730 1255 0 "trigger description with pretty-print option" ) +insert ( 3035 1255 0 "get the channels that the current backend listens to" ) +insert ( 3036 1255 0 "send a notification event" ) +insert ( 3296 1255 0 "get the fraction of the asynchronous notification queue currently in use" ) +insert ( 5052 1255 0 "allocations from the main shared memory segment" ) +insert ( 1066 1255 0 "non-persistent series generator" ) +insert ( 1067 1255 0 "non-persistent series generator" ) +insert ( 3994 1255 0 "planner support for generate_series" ) +insert ( 1068 1255 0 "non-persistent series generator" ) +insert ( 1069 1255 0 "non-persistent series generator" ) +insert ( 3995 1255 0 "planner support for generate_series" ) +insert ( 3259 1255 0 "non-persistent series generator" ) +insert ( 3260 1255 0 "non-persistent series generator" ) +insert ( 938 1255 0 "non-persistent series generator" ) +insert ( 939 1255 0 "non-persistent series generator" ) +insert ( 2515 1255 0 "aggregate transition function" ) +insert ( 2516 1255 0 "aggregate transition function" ) +insert ( 3496 1255 0 "aggregate transition function" ) +insert ( 3497 1255 0 "aggregate transition function" ) +insert ( 3498 1255 0 "aggregate final function" ) +insert ( 3499 1255 0 "aggregate final function" ) +insert ( 2517 1255 0 "boolean-and aggregate" ) +insert ( 2518 1255 0 "boolean-or aggregate" ) +insert ( 2519 1255 0 "boolean-and aggregate" ) +insert ( 2236 1255 0 "bitwise-and smallint aggregate" ) +insert ( 2237 1255 0 "bitwise-or smallint aggregate" ) +insert ( 2238 1255 0 "bitwise-and integer aggregate" ) +insert ( 2239 1255 0 "bitwise-or integer aggregate" ) +insert ( 2240 1255 0 "bitwise-and bigint aggregate" ) +insert ( 2241 1255 0 "bitwise-or bigint aggregate" ) +insert ( 2242 1255 0 "bitwise-and bit aggregate" ) +insert ( 2243 1255 0 "bitwise-or bit aggregate" ) +insert ( 2556 1255 0 "get OIDs of databases in a tablespace" ) +insert ( 2557 1255 0 "convert int4 to boolean" ) +insert ( 2558 1255 0 "convert boolean to int4" ) +insert ( 2559 1255 0 "current value from last used sequence" ) +insert ( 2560 1255 0 "postmaster start time" ) +insert ( 2034 1255 0 "configuration load time" ) +insert ( 2578 1255 0 "GiST support" ) +insert ( 2581 1255 0 "GiST support" ) +insert ( 2582 1255 0 "GiST support" ) +insert ( 2583 1255 0 "GiST support" ) +insert ( 2584 1255 0 "GiST support" ) +insert ( 3998 1255 0 "GiST support" ) +insert ( 2585 1255 0 "GiST support" ) +insert ( 2586 1255 0 "GiST support" ) +insert ( 2591 1255 0 "GiST support" ) +insert ( 2592 1255 0 "GiST support" ) +insert ( 1030 1255 0 "GiST support" ) +insert ( 3282 1255 0 "GiST support" ) +insert ( 2179 1255 0 "GiST support" ) +insert ( 3064 1255 0 "GiST support" ) +insert ( 3280 1255 0 "GiST support" ) +insert ( 3288 1255 0 "GiST support" ) +insert ( 2743 1255 0 "GIN array support" ) +insert ( 2774 1255 0 "GIN array support" ) +insert ( 2744 1255 0 "GIN array support" ) +insert ( 3920 1255 0 "GIN array support" ) +insert ( 3076 1255 0 "GIN array support (obsolete)" ) +insert ( 3383 1255 0 "BRIN minmax support" ) +insert ( 3384 1255 0 "BRIN minmax support" ) +insert ( 3385 1255 0 "BRIN minmax support" ) +insert ( 3386 1255 0 "BRIN minmax support" ) +insert ( 4105 1255 0 "BRIN inclusion support" ) +insert ( 4106 1255 0 "BRIN inclusion support" ) +insert ( 4107 1255 0 "BRIN inclusion support" ) +insert ( 4108 1255 0 "BRIN inclusion support" ) +insert ( 2880 1255 0 "obtain exclusive advisory lock" ) +insert ( 3089 1255 0 "obtain exclusive advisory lock" ) +insert ( 2881 1255 0 "obtain shared advisory lock" ) +insert ( 3090 1255 0 "obtain shared advisory lock" ) +insert ( 2882 1255 0 "obtain exclusive advisory lock if available" ) +insert ( 3091 1255 0 "obtain exclusive advisory lock if available" ) +insert ( 2883 1255 0 "obtain shared advisory lock if available" ) +insert ( 3092 1255 0 "obtain shared advisory lock if available" ) +insert ( 2884 1255 0 "release exclusive advisory lock" ) +insert ( 2885 1255 0 "release shared advisory lock" ) +insert ( 2886 1255 0 "obtain exclusive advisory lock" ) +insert ( 3093 1255 0 "obtain exclusive advisory lock" ) +insert ( 2887 1255 0 "obtain shared advisory lock" ) +insert ( 3094 1255 0 "obtain shared advisory lock" ) +insert ( 2888 1255 0 "obtain exclusive advisory lock if available" ) +insert ( 3095 1255 0 "obtain exclusive advisory lock if available" ) +insert ( 2889 1255 0 "obtain shared advisory lock if available" ) +insert ( 3096 1255 0 "obtain shared advisory lock if available" ) +insert ( 2890 1255 0 "release exclusive advisory lock" ) +insert ( 2891 1255 0 "release shared advisory lock" ) +insert ( 2892 1255 0 "release all advisory locks" ) +insert ( 2893 1255 0 "I/O" ) +insert ( 2894 1255 0 "I/O" ) +insert ( 2895 1255 0 "generate XML comment" ) +insert ( 2896 1255 0 "perform a non-validating parse of a character string to produce an XML value" ) +insert ( 2897 1255 0 "validate an XML value" ) +insert ( 2898 1255 0 "I/O" ) +insert ( 2899 1255 0 "I/O" ) +insert ( 2900 1255 0 "aggregate transition function" ) +insert ( 2901 1255 0 "concatenate XML values" ) +insert ( 2922 1255 0 "serialize an XML value to a character string" ) +insert ( 2923 1255 0 "map table contents to XML" ) +insert ( 2924 1255 0 "map query result to XML" ) +insert ( 2925 1255 0 "map rows from cursor to XML" ) +insert ( 2926 1255 0 "map table structure to XML Schema" ) +insert ( 2927 1255 0 "map query result structure to XML Schema" ) +insert ( 2928 1255 0 "map cursor structure to XML Schema" ) +insert ( 2929 1255 0 "map table contents and structure to XML and XML Schema" ) +insert ( 2930 1255 0 "map query result and structure to XML and XML Schema" ) +insert ( 2933 1255 0 "map schema contents to XML" ) +insert ( 2934 1255 0 "map schema structure to XML Schema" ) +insert ( 2935 1255 0 "map schema contents and structure to XML and XML Schema" ) +insert ( 2936 1255 0 "map database contents to XML" ) +insert ( 2937 1255 0 "map database structure to XML Schema" ) +insert ( 2938 1255 0 "map database contents and structure to XML and XML Schema" ) +insert ( 2931 1255 0 "evaluate XPath expression, with namespaces support" ) +insert ( 2932 1255 0 "evaluate XPath expression" ) +insert ( 2614 1255 0 "test XML value against XPath expression" ) +insert ( 3049 1255 0 "test XML value against XPath expression, with namespace support" ) +insert ( 3050 1255 0 "test XML value against XPath expression" ) +insert ( 3051 1255 0 "determine if a string is well formed XML" ) +insert ( 3052 1255 0 "determine if a string is well formed XML document" ) +insert ( 3053 1255 0 "determine if a string is well formed XML content" ) +insert ( 321 1255 0 "I/O" ) +insert ( 322 1255 0 "I/O" ) +insert ( 323 1255 0 "I/O" ) +insert ( 324 1255 0 "I/O" ) +insert ( 3153 1255 0 "map array to json" ) +insert ( 3154 1255 0 "map array to json with optional pretty printing" ) +insert ( 3155 1255 0 "map row to json" ) +insert ( 3156 1255 0 "map row to json with optional pretty printing" ) +insert ( 3173 1255 0 "json aggregate transition function" ) +insert ( 3174 1255 0 "json aggregate final function" ) +insert ( 3175 1255 0 "aggregate input into json" ) +insert ( 3180 1255 0 "json object aggregate transition function" ) +insert ( 3196 1255 0 "json object aggregate final function" ) +insert ( 3197 1255 0 "aggregate input into a json object" ) +insert ( 3198 1255 0 "build a json array from any inputs" ) +insert ( 3199 1255 0 "build an empty json array" ) +insert ( 3200 1255 0 "build a json object from pairwise key/value inputs" ) +insert ( 3201 1255 0 "build an empty json object" ) +insert ( 3202 1255 0 "map text array of key value pairs to json object" ) +insert ( 3203 1255 0 "map text arrays of keys and values to json object" ) +insert ( 3176 1255 0 "map input to json" ) +insert ( 3261 1255 0 "remove object fields with null values from json" ) +insert ( 3951 1255 0 "get value from json with path elements" ) +insert ( 3953 1255 0 "get value from json as text with path elements" ) +insert ( 3955 1255 0 "key value pairs of a json object" ) +insert ( 3969 1255 0 "elements of json array" ) +insert ( 3956 1255 0 "length of json array" ) +insert ( 3957 1255 0 "get json object keys" ) +insert ( 3958 1255 0 "key value pairs of a json object" ) +insert ( 3959 1255 0 "key value pairs of a json object" ) +insert ( 3960 1255 0 "get record fields from a json object" ) +insert ( 3961 1255 0 "get set of records with fields from a json array of objects" ) +insert ( 3204 1255 0 "get record fields from a json object" ) +insert ( 3205 1255 0 "get set of records with fields from a json array of objects" ) +insert ( 3968 1255 0 "get the type of a json value" ) +insert ( 2952 1255 0 "I/O" ) +insert ( 2953 1255 0 "I/O" ) +insert ( 2960 1255 0 less-equal-greater ) +insert ( 3300 1255 0 "sort support" ) +insert ( 2961 1255 0 "I/O" ) +insert ( 2962 1255 0 "I/O" ) +insert ( 2963 1255 0 hash ) +insert ( 3412 1255 0 hash ) +insert ( 3432 1255 0 "generate random UUID" ) +insert ( 3229 1255 0 "I/O" ) +insert ( 3230 1255 0 "I/O" ) +insert ( 3238 1255 0 "I/O" ) +insert ( 3239 1255 0 "I/O" ) +insert ( 3251 1255 0 less-equal-greater ) +insert ( 3252 1255 0 hash ) +insert ( 3413 1255 0 hash ) +insert ( 4187 1255 0 "larger of two" ) +insert ( 4188 1255 0 "smaller of two" ) +insert ( 3504 1255 0 "I/O" ) +insert ( 3505 1255 0 "I/O" ) +insert ( 3506 1255 0 "I/O" ) +insert ( 3507 1255 0 "I/O" ) +insert ( 3514 1255 0 less-equal-greater ) +insert ( 3515 1255 0 hash ) +insert ( 3414 1255 0 hash ) +insert ( 3524 1255 0 "smaller of two" ) +insert ( 3525 1255 0 "larger of two" ) +insert ( 3526 1255 0 "maximum value of all enum input values" ) +insert ( 3527 1255 0 "minimum value of all enum input values" ) +insert ( 3528 1255 0 "first value of the input enum type" ) +insert ( 3529 1255 0 "last value of the input enum type" ) +insert ( 3530 1255 0 "range between the two given enum values, as an ordered array" ) +insert ( 3531 1255 0 "range of the given enum type, as an ordered array" ) +insert ( 3532 1255 0 "I/O" ) +insert ( 3533 1255 0 "I/O" ) +insert ( 3610 1255 0 "I/O" ) +insert ( 3639 1255 0 "I/O" ) +insert ( 3611 1255 0 "I/O" ) +insert ( 3638 1255 0 "I/O" ) +insert ( 3612 1255 0 "I/O" ) +insert ( 3641 1255 0 "I/O" ) +insert ( 3613 1255 0 "I/O" ) +insert ( 3640 1255 0 "I/O" ) +insert ( 3646 1255 0 "I/O" ) +insert ( 3647 1255 0 "I/O" ) +insert ( 3622 1255 0 less-equal-greater ) +insert ( 3711 1255 0 "number of lexemes" ) +insert ( 3623 1255 0 "strip position information" ) +insert ( 3624 1255 0 "set given weight for whole tsvector" ) +insert ( 3320 1255 0 "set given weight for given lexemes" ) +insert ( 3321 1255 0 "delete lexeme" ) +insert ( 3323 1255 0 "delete given lexemes" ) +insert ( 3322 1255 0 "expand tsvector to set of rows" ) +insert ( 3326 1255 0 "convert tsvector to array of lexemes" ) +insert ( 3327 1255 0 "build tsvector from array of lexemes" ) +insert ( 3319 1255 0 "delete lexemes that do not have one of the given weights" ) +insert ( 3648 1255 0 "GiST tsvector support" ) +insert ( 3649 1255 0 "GiST tsvector support" ) +insert ( 3650 1255 0 "GiST tsvector support" ) +insert ( 3651 1255 0 "GiST tsvector support" ) +insert ( 3652 1255 0 "GiST tsvector support" ) +insert ( 3653 1255 0 "GiST tsvector support" ) +insert ( 3654 1255 0 "GiST tsvector support" ) +insert ( 3790 1255 0 "GiST tsvector support (obsolete)" ) +insert ( 3434 1255 0 "GiST tsvector support" ) +insert ( 3656 1255 0 "GIN tsvector support" ) +insert ( 3657 1255 0 "GIN tsvector support" ) +insert ( 3658 1255 0 "GIN tsvector support" ) +insert ( 3921 1255 0 "GIN tsvector support" ) +insert ( 3724 1255 0 "GIN tsvector support" ) +insert ( 2700 1255 0 "GIN tsvector support" ) +insert ( 3077 1255 0 "GIN tsvector support (obsolete)" ) +insert ( 3087 1255 0 "GIN tsvector support (obsolete)" ) +insert ( 3088 1255 0 "GIN tsvector support (obsolete)" ) +insert ( 3791 1255 0 "GIN tsvector support (obsolete)" ) +insert ( 3792 1255 0 "GIN tsvector support (obsolete)" ) +insert ( 3789 1255 0 "clean up GIN pending list" ) +insert ( 3668 1255 0 less-equal-greater ) +insert ( 5004 1255 0 "phrase-concatenate with distance" ) +insert ( 3672 1255 0 "number of nodes" ) +insert ( 3673 1255 0 "show real useful query for GiST index" ) +insert ( 3684 1255 0 "rewrite tsquery" ) +insert ( 3685 1255 0 "rewrite tsquery" ) +insert ( 3695 1255 0 "GiST tsquery support" ) +insert ( 3697 1255 0 "GiST tsquery support" ) +insert ( 3698 1255 0 "GiST tsquery support" ) +insert ( 3699 1255 0 "GiST tsquery support" ) +insert ( 3700 1255 0 "GiST tsquery support" ) +insert ( 3701 1255 0 "GiST tsquery support" ) +insert ( 3793 1255 0 "GiST tsquery support (obsolete)" ) +insert ( 3686 1255 0 "restriction selectivity of tsvector @@ tsquery" ) +insert ( 3687 1255 0 "join selectivity of tsvector @@ tsquery" ) +insert ( 3688 1255 0 "tsvector typanalyze" ) +insert ( 3689 1255 0 "statistics of tsvector column" ) +insert ( 3690 1255 0 "statistics of tsvector column" ) +insert ( 3703 1255 0 relevance ) +insert ( 3704 1255 0 relevance ) +insert ( 3705 1255 0 relevance ) +insert ( 3706 1255 0 relevance ) +insert ( 3707 1255 0 relevance ) +insert ( 3708 1255 0 relevance ) +insert ( 3709 1255 0 relevance ) +insert ( 3710 1255 0 relevance ) +insert ( 3713 1255 0 "get parser''s token types" ) +insert ( 3714 1255 0 "get parser''s token types" ) +insert ( 3715 1255 0 "parse text to tokens" ) +insert ( 3716 1255 0 "parse text to tokens" ) +insert ( 3717 1255 0 "(internal)" ) +insert ( 3718 1255 0 "(internal)" ) +insert ( 3719 1255 0 "(internal)" ) +insert ( 3720 1255 0 "(internal)" ) +insert ( 3721 1255 0 "(internal)" ) +insert ( 3723 1255 0 "normalize one word by dictionary" ) +insert ( 3725 1255 0 "(internal)" ) +insert ( 3726 1255 0 "(internal)" ) +insert ( 3728 1255 0 "(internal)" ) +insert ( 3729 1255 0 "(internal)" ) +insert ( 3731 1255 0 "(internal)" ) +insert ( 3732 1255 0 "(internal)" ) +insert ( 3740 1255 0 "(internal)" ) +insert ( 3741 1255 0 "(internal)" ) +insert ( 3743 1255 0 "generate headline" ) +insert ( 3744 1255 0 "generate headline" ) +insert ( 3754 1255 0 "generate headline" ) +insert ( 3755 1255 0 "generate headline" ) +insert ( 4201 1255 0 "generate headline from jsonb" ) +insert ( 4202 1255 0 "generate headline from jsonb" ) +insert ( 4203 1255 0 "generate headline from jsonb" ) +insert ( 4204 1255 0 "generate headline from jsonb" ) +insert ( 4205 1255 0 "generate headline from json" ) +insert ( 4206 1255 0 "generate headline from json" ) +insert ( 4207 1255 0 "generate headline from json" ) +insert ( 4208 1255 0 "generate headline from json" ) +insert ( 3745 1255 0 "transform to tsvector" ) +insert ( 3746 1255 0 "make tsquery" ) +insert ( 3747 1255 0 "transform to tsquery" ) +insert ( 5006 1255 0 "transform to tsquery" ) +insert ( 5007 1255 0 "transform to tsquery" ) +insert ( 3749 1255 0 "transform to tsvector" ) +insert ( 3750 1255 0 "make tsquery" ) +insert ( 3751 1255 0 "transform to tsquery" ) +insert ( 5001 1255 0 "transform to tsquery" ) +insert ( 5009 1255 0 "transform to tsquery" ) +insert ( 4209 1255 0 "transform string values from jsonb to tsvector" ) +insert ( 4213 1255 0 "transform specified values from jsonb to tsvector" ) +insert ( 4210 1255 0 "transform string values from json to tsvector" ) +insert ( 4215 1255 0 "transform specified values from json to tsvector" ) +insert ( 4211 1255 0 "transform string values from jsonb to tsvector" ) +insert ( 4214 1255 0 "transform specified values from jsonb to tsvector" ) +insert ( 4212 1255 0 "transform string values from json to tsvector" ) +insert ( 4216 1255 0 "transform specified values from json to tsvector" ) +insert ( 3752 1255 0 "trigger for automatic update of tsvector column" ) +insert ( 3753 1255 0 "trigger for automatic update of tsvector column" ) +insert ( 3759 1255 0 "get current tsearch configuration" ) +insert ( 3736 1255 0 "I/O" ) +insert ( 3737 1255 0 "I/O" ) +insert ( 3738 1255 0 "I/O" ) +insert ( 3739 1255 0 "I/O" ) +insert ( 3771 1255 0 "I/O" ) +insert ( 3772 1255 0 "I/O" ) +insert ( 3773 1255 0 "I/O" ) +insert ( 3774 1255 0 "I/O" ) +insert ( 3806 1255 0 "I/O" ) +insert ( 3805 1255 0 "I/O" ) +insert ( 3804 1255 0 "I/O" ) +insert ( 3803 1255 0 "I/O" ) +insert ( 3263 1255 0 "map text array of key value pairs to jsonb object" ) +insert ( 3264 1255 0 "map text array of key value pairs to jsonb object" ) +insert ( 3787 1255 0 "map input to jsonb" ) +insert ( 3265 1255 0 "jsonb aggregate transition function" ) +insert ( 3266 1255 0 "jsonb aggregate final function" ) +insert ( 3267 1255 0 "aggregate input into jsonb" ) +insert ( 3268 1255 0 "jsonb object aggregate transition function" ) +insert ( 3269 1255 0 "jsonb object aggregate final function" ) +insert ( 3270 1255 0 "aggregate inputs into jsonb object" ) +insert ( 3271 1255 0 "build a jsonb array from any inputs" ) +insert ( 3272 1255 0 "build an empty jsonb array" ) +insert ( 3273 1255 0 "build a jsonb object from pairwise key/value inputs" ) +insert ( 3274 1255 0 "build an empty jsonb object" ) +insert ( 3262 1255 0 "remove object fields with null values from jsonb" ) +insert ( 3217 1255 0 "get value from jsonb with path elements" ) +insert ( 3940 1255 0 "get value from jsonb as text with path elements" ) +insert ( 3219 1255 0 "elements of a jsonb array" ) +insert ( 3465 1255 0 "elements of jsonb array" ) +insert ( 3207 1255 0 "length of jsonb array" ) +insert ( 3931 1255 0 "get jsonb object keys" ) +insert ( 3208 1255 0 "key value pairs of a jsonb object" ) +insert ( 3932 1255 0 "key value pairs of a jsonb object" ) +insert ( 3209 1255 0 "get record fields from a jsonb object" ) +insert ( 3475 1255 0 "get set of records with fields from a jsonb array of objects" ) +insert ( 3490 1255 0 "get record fields from a jsonb object" ) +insert ( 3491 1255 0 "get set of records with fields from a jsonb array of objects" ) +insert ( 3210 1255 0 "get the type of a jsonb value" ) +insert ( 4044 1255 0 less-equal-greater ) +insert ( 4045 1255 0 hash ) +insert ( 3416 1255 0 hash ) +insert ( 3480 1255 0 "GIN support" ) +insert ( 3482 1255 0 "GIN support" ) +insert ( 3483 1255 0 "GIN support" ) +insert ( 3484 1255 0 "GIN support" ) +insert ( 3488 1255 0 "GIN support" ) +insert ( 3485 1255 0 "GIN support" ) +insert ( 3486 1255 0 "GIN support" ) +insert ( 3487 1255 0 "GIN support" ) +insert ( 3489 1255 0 "GIN support" ) +insert ( 5054 1255 0 "Set part of a jsonb, handle NULL value" ) +insert ( 3305 1255 0 "Set part of a jsonb" ) +insert ( 3306 1255 0 "Indented text from jsonb" ) +insert ( 3579 1255 0 "Insert value into a jsonb" ) +insert ( 4001 1255 0 "I/O" ) +insert ( 4002 1255 0 "I/O" ) +insert ( 4003 1255 0 "I/O" ) +insert ( 4004 1255 0 "I/O" ) +insert ( 4005 1255 0 "jsonpath exists test" ) +insert ( 4006 1255 0 "jsonpath query" ) +insert ( 4007 1255 0 "jsonpath query wrapped into array" ) +insert ( 4008 1255 0 "jsonpath query first item" ) +insert ( 4009 1255 0 "jsonpath match" ) +insert ( 1177 1255 0 "jsonpath exists test with timezone" ) +insert ( 1179 1255 0 "jsonpath query with timezone" ) +insert ( 1180 1255 0 "jsonpath query wrapped into array with timezone" ) +insert ( 2023 1255 0 "jsonpath query first item with timezone" ) +insert ( 2030 1255 0 "jsonpath match with timezone" ) +insert ( 4010 1255 0 "implementation of @? operator" ) +insert ( 4011 1255 0 "implementation of @@ operator" ) +insert ( 2939 1255 0 "I/O" ) +insert ( 2940 1255 0 "I/O" ) +insert ( 2941 1255 0 "I/O" ) +insert ( 2942 1255 0 "I/O" ) +insert ( 2943 1255 0 "get current transaction ID" ) +insert ( 3348 1255 0 "get current transaction ID" ) +insert ( 2944 1255 0 "get current snapshot" ) +insert ( 2945 1255 0 "get xmin of snapshot" ) +insert ( 2946 1255 0 "get xmax of snapshot" ) +insert ( 2947 1255 0 "get set of in-progress txids in snapshot" ) +insert ( 2948 1255 0 "is txid visible in snapshot?" ) +insert ( 3360 1255 0 "commit status of transaction" ) +insert ( 5055 1255 0 "I/O" ) +insert ( 5056 1255 0 "I/O" ) +insert ( 5057 1255 0 "I/O" ) +insert ( 5058 1255 0 "I/O" ) +insert ( 5061 1255 0 "get current snapshot" ) +insert ( 5062 1255 0 "get xmin of snapshot" ) +insert ( 5063 1255 0 "get xmax of snapshot" ) +insert ( 5064 1255 0 "get set of in-progress transactions in snapshot" ) +insert ( 5065 1255 0 "is xid8 visible in snapshot?" ) +insert ( 5059 1255 0 "get current transaction ID" ) +insert ( 5060 1255 0 "get current transaction ID" ) +insert ( 5066 1255 0 "commit status of transaction" ) +insert ( 2987 1255 0 less-equal-greater ) +insert ( 3187 1255 0 "less-equal-greater based on byte images" ) +insert ( 5051 1255 0 "equal image" ) +insert ( 3082 1255 0 "list available extensions" ) +insert ( 3083 1255 0 "list available extension versions" ) +insert ( 3084 1255 0 "list an extension''s version update paths" ) +insert ( 3086 1255 0 "flag an extension''s table contents to be emitted by pg_dump" ) +insert ( 3100 1255 0 "row number within partition" ) +insert ( 3101 1255 0 "integer rank with gaps" ) +insert ( 3102 1255 0 "integer rank without gaps" ) +insert ( 3103 1255 0 "fractional rank within partition" ) +insert ( 3104 1255 0 "fractional row number within partition" ) +insert ( 3105 1255 0 "split rows into N groups" ) +insert ( 3106 1255 0 "fetch the preceding row value" ) +insert ( 3107 1255 0 "fetch the Nth preceding row value" ) +insert ( 3108 1255 0 "fetch the Nth preceding row value with default" ) +insert ( 3109 1255 0 "fetch the following row value" ) +insert ( 3110 1255 0 "fetch the Nth following row value" ) +insert ( 3111 1255 0 "fetch the Nth following row value with default" ) +insert ( 3112 1255 0 "fetch the first row value" ) +insert ( 3113 1255 0 "fetch the last row value" ) +insert ( 3114 1255 0 "fetch the Nth row value" ) +insert ( 3832 1255 0 "I/O" ) +insert ( 3833 1255 0 "I/O" ) +insert ( 3834 1255 0 "I/O" ) +insert ( 3835 1255 0 "I/O" ) +insert ( 3836 1255 0 "I/O" ) +insert ( 3837 1255 0 "I/O" ) +insert ( 3848 1255 0 "lower bound of range" ) +insert ( 3849 1255 0 "upper bound of range" ) +insert ( 3850 1255 0 "is the range empty?" ) +insert ( 3851 1255 0 "is the range''s lower bound inclusive?" ) +insert ( 3852 1255 0 "is the range''s upper bound inclusive?" ) +insert ( 3853 1255 0 "is the range''s lower bound infinite?" ) +insert ( 3854 1255 0 "is the range''s upper bound infinite?" ) +insert ( 4057 1255 0 "the smallest range which includes both of the given ranges" ) +insert ( 3870 1255 0 less-equal-greater ) +insert ( 3875 1255 0 "GiST support" ) +insert ( 3876 1255 0 "GiST support" ) +insert ( 3879 1255 0 "GiST support" ) +insert ( 3880 1255 0 "GiST support" ) +insert ( 3881 1255 0 "GiST support" ) +insert ( 3902 1255 0 "hash a range" ) +insert ( 3417 1255 0 "hash a range" ) +insert ( 3916 1255 0 "range typanalyze" ) +insert ( 3169 1255 0 "restriction selectivity for range operators" ) +insert ( 3914 1255 0 "convert an int4 range to canonical form" ) +insert ( 3928 1255 0 "convert an int8 range to canonical form" ) +insert ( 3915 1255 0 "convert a date range to canonical form" ) +insert ( 3922 1255 0 "float8 difference of two int4 values" ) +insert ( 3923 1255 0 "float8 difference of two int8 values" ) +insert ( 3924 1255 0 "float8 difference of two numeric values" ) +insert ( 3925 1255 0 "float8 difference of two date values" ) +insert ( 3929 1255 0 "float8 difference of two timestamp values" ) +insert ( 3930 1255 0 "float8 difference of two timestamp with time zone values" ) +insert ( 3840 1255 0 "int4range constructor" ) +insert ( 3841 1255 0 "int4range constructor" ) +insert ( 3844 1255 0 "numrange constructor" ) +insert ( 3845 1255 0 "numrange constructor" ) +insert ( 3933 1255 0 "tsrange constructor" ) +insert ( 3934 1255 0 "tsrange constructor" ) +insert ( 3937 1255 0 "tstzrange constructor" ) +insert ( 3938 1255 0 "tstzrange constructor" ) +insert ( 3941 1255 0 "daterange constructor" ) +insert ( 3942 1255 0 "daterange constructor" ) +insert ( 3945 1255 0 "int8range constructor" ) +insert ( 3946 1255 0 "int8range constructor" ) +insert ( 3846 1255 0 "construct date" ) +insert ( 3847 1255 0 "construct time" ) +insert ( 3461 1255 0 "construct timestamp" ) +insert ( 3462 1255 0 "construct timestamp with time zone" ) +insert ( 3463 1255 0 "construct timestamp with time zone" ) +insert ( 3464 1255 0 "construct interval" ) +insert ( 4018 1255 0 "SP-GiST support for quad tree over point" ) +insert ( 4019 1255 0 "SP-GiST support for quad tree over point" ) +insert ( 4020 1255 0 "SP-GiST support for quad tree over point" ) +insert ( 4021 1255 0 "SP-GiST support for quad tree over point" ) +insert ( 4022 1255 0 "SP-GiST support for quad tree and k-d tree over point" ) +insert ( 4023 1255 0 "SP-GiST support for k-d tree over point" ) +insert ( 4024 1255 0 "SP-GiST support for k-d tree over point" ) +insert ( 4025 1255 0 "SP-GiST support for k-d tree over point" ) +insert ( 4026 1255 0 "SP-GiST support for k-d tree over point" ) +insert ( 4027 1255 0 "SP-GiST support for radix tree over text" ) +insert ( 4028 1255 0 "SP-GiST support for radix tree over text" ) +insert ( 4029 1255 0 "SP-GiST support for radix tree over text" ) +insert ( 4030 1255 0 "SP-GiST support for radix tree over text" ) +insert ( 4031 1255 0 "SP-GiST support for radix tree over text" ) +insert ( 3469 1255 0 "SP-GiST support for quad tree over range" ) +insert ( 3470 1255 0 "SP-GiST support for quad tree over range" ) +insert ( 3471 1255 0 "SP-GiST support for quad tree over range" ) +insert ( 3472 1255 0 "SP-GiST support for quad tree over range" ) +insert ( 3473 1255 0 "SP-GiST support for quad tree over range" ) +insert ( 5012 1255 0 "SP-GiST support for quad tree over box" ) +insert ( 5013 1255 0 "SP-GiST support for quad tree over box" ) +insert ( 5014 1255 0 "SP-GiST support for quad tree over box" ) +insert ( 5015 1255 0 "SP-GiST support for quad tree over box" ) +insert ( 5016 1255 0 "SP-GiST support for quad tree over box" ) +insert ( 5010 1255 0 "SP-GiST support for quad tree over 2-D types represented by their bounding boxes" ) +insert ( 5011 1255 0 "SP-GiST support for quad tree over polygons" ) +insert ( 3779 1255 0 "create a physical replication slot" ) +insert ( 4220 1255 0 "copy a physical replication slot, changing temporality" ) +insert ( 4221 1255 0 "copy a physical replication slot" ) +insert ( 3780 1255 0 "drop a replication slot" ) +insert ( 3781 1255 0 "information about replication slots currently in use" ) +insert ( 3786 1255 0 "set up a logical replication slot" ) +insert ( 4222 1255 0 "copy a logical replication slot, changing temporality and plugin" ) +insert ( 4223 1255 0 "copy a logical replication slot, changing temporality" ) +insert ( 4224 1255 0 "copy a logical replication slot" ) +insert ( 3782 1255 0 "get changes from replication slot" ) +insert ( 3783 1255 0 "get binary changes from replication slot" ) +insert ( 3784 1255 0 "peek at changes from replication slot" ) +insert ( 3785 1255 0 "peek at binary changes from replication slot" ) +insert ( 3878 1255 0 "advance logical replication slot" ) +insert ( 3577 1255 0 "emit a textual logical decoding message" ) +insert ( 3578 1255 0 "emit a binary logical decoding message" ) +insert ( 3566 1255 0 "list objects dropped by the current command" ) +insert ( 4566 1255 0 "return Oid of the table getting rewritten" ) +insert ( 4567 1255 0 "return reason code for table getting rewritten" ) +insert ( 4568 1255 0 "list DDL actions being executed by the current command" ) +insert ( 3970 1255 0 "aggregate transition function" ) +insert ( 3971 1255 0 "aggregate transition function" ) +insert ( 3972 1255 0 "discrete percentile" ) +insert ( 3973 1255 0 "aggregate final function" ) +insert ( 3974 1255 0 "continuous distribution percentile" ) +insert ( 3975 1255 0 "aggregate final function" ) +insert ( 3976 1255 0 "continuous distribution percentile" ) +insert ( 3977 1255 0 "aggregate final function" ) +insert ( 3978 1255 0 "multiple discrete percentiles" ) +insert ( 3979 1255 0 "aggregate final function" ) +insert ( 3980 1255 0 "multiple continuous percentiles" ) +insert ( 3981 1255 0 "aggregate final function" ) +insert ( 3982 1255 0 "multiple continuous percentiles" ) +insert ( 3983 1255 0 "aggregate final function" ) +insert ( 3984 1255 0 "most common value" ) +insert ( 3985 1255 0 "aggregate final function" ) +insert ( 3986 1255 0 "rank of hypothetical row" ) +insert ( 3987 1255 0 "aggregate final function" ) +insert ( 3988 1255 0 "fractional rank of hypothetical row" ) +insert ( 3989 1255 0 "aggregate final function" ) +insert ( 3990 1255 0 "cumulative distribution of hypothetical row" ) +insert ( 3991 1255 0 "aggregate final function" ) +insert ( 3992 1255 0 "rank of hypothetical row without gaps" ) +insert ( 3993 1255 0 "aggregate final function" ) +insert ( 3582 1255 0 "for use by pg_upgrade" ) +insert ( 3584 1255 0 "for use by pg_upgrade" ) +insert ( 3585 1255 0 "for use by pg_upgrade" ) +insert ( 3586 1255 0 "for use by pg_upgrade" ) +insert ( 3587 1255 0 "for use by pg_upgrade" ) +insert ( 3588 1255 0 "for use by pg_upgrade" ) +insert ( 3589 1255 0 "for use by pg_upgrade" ) +insert ( 3590 1255 0 "for use by pg_upgrade" ) +insert ( 3591 1255 0 "for use by pg_upgrade" ) +insert ( 4083 1255 0 "for use by pg_upgrade" ) +insert ( 4101 1255 0 "for use by pg_upgrade" ) +insert ( 4302 1255 0 "internal conversion function for KOI8R to MULE_INTERNAL" ) +insert ( 4303 1255 0 "internal conversion function for MULE_INTERNAL to KOI8R" ) +insert ( 4304 1255 0 "internal conversion function for ISO-8859-5 to MULE_INTERNAL" ) +insert ( 4305 1255 0 "internal conversion function for MULE_INTERNAL to ISO-8859-5" ) +insert ( 4306 1255 0 "internal conversion function for WIN1251 to MULE_INTERNAL" ) +insert ( 4307 1255 0 "internal conversion function for MULE_INTERNAL to WIN1251" ) +insert ( 4308 1255 0 "internal conversion function for WIN866 to MULE_INTERNAL" ) +insert ( 4309 1255 0 "internal conversion function for MULE_INTERNAL to WIN866" ) +insert ( 4310 1255 0 "internal conversion function for KOI8R to WIN1251" ) +insert ( 4311 1255 0 "internal conversion function for WIN1251 to KOI8R" ) +insert ( 4312 1255 0 "internal conversion function for KOI8R to WIN866" ) +insert ( 4313 1255 0 "internal conversion function for WIN866 to KOI8R" ) +insert ( 4314 1255 0 "internal conversion function for WIN866 to WIN1251" ) +insert ( 4315 1255 0 "internal conversion function for WIN1251 to WIN866" ) +insert ( 4316 1255 0 "internal conversion function for ISO-8859-5 to KOI8R" ) +insert ( 4317 1255 0 "internal conversion function for KOI8R to ISO-8859-5" ) +insert ( 4318 1255 0 "internal conversion function for ISO-8859-5 to WIN1251" ) +insert ( 4319 1255 0 "internal conversion function for WIN1251 to ISO-8859-5" ) +insert ( 4320 1255 0 "internal conversion function for ISO-8859-5 to WIN866" ) +insert ( 4321 1255 0 "internal conversion function for WIN866 to ISO-8859-5" ) +insert ( 4322 1255 0 "internal conversion function for EUC_CN to MULE_INTERNAL" ) +insert ( 4323 1255 0 "internal conversion function for MULE_INTERNAL to EUC_CN" ) +insert ( 4324 1255 0 "internal conversion function for EUC_JP to SJIS" ) +insert ( 4325 1255 0 "internal conversion function for SJIS to EUC_JP" ) +insert ( 4326 1255 0 "internal conversion function for EUC_JP to MULE_INTERNAL" ) +insert ( 4327 1255 0 "internal conversion function for SJIS to MULE_INTERNAL" ) +insert ( 4328 1255 0 "internal conversion function for MULE_INTERNAL to EUC_JP" ) +insert ( 4329 1255 0 "internal conversion function for MULE_INTERNAL to SJIS" ) +insert ( 4330 1255 0 "internal conversion function for EUC_KR to MULE_INTERNAL" ) +insert ( 4331 1255 0 "internal conversion function for MULE_INTERNAL to EUC_KR" ) +insert ( 4332 1255 0 "internal conversion function for EUC_TW to BIG5" ) +insert ( 4333 1255 0 "internal conversion function for BIG5 to EUC_TW" ) +insert ( 4334 1255 0 "internal conversion function for EUC_TW to MULE_INTERNAL" ) +insert ( 4335 1255 0 "internal conversion function for BIG5 to MULE_INTERNAL" ) +insert ( 4336 1255 0 "internal conversion function for MULE_INTERNAL to EUC_TW" ) +insert ( 4337 1255 0 "internal conversion function for MULE_INTERNAL to BIG5" ) +insert ( 4338 1255 0 "internal conversion function for LATIN2 to MULE_INTERNAL" ) +insert ( 4339 1255 0 "internal conversion function for MULE_INTERNAL to LATIN2" ) +insert ( 4340 1255 0 "internal conversion function for WIN1250 to MULE_INTERNAL" ) +insert ( 4341 1255 0 "internal conversion function for MULE_INTERNAL to WIN1250" ) +insert ( 4342 1255 0 "internal conversion function for LATIN2 to WIN1250" ) +insert ( 4343 1255 0 "internal conversion function for WIN1250 to LATIN2" ) +insert ( 4344 1255 0 "internal conversion function for LATIN1 to MULE_INTERNAL" ) +insert ( 4345 1255 0 "internal conversion function for MULE_INTERNAL to LATIN1" ) +insert ( 4346 1255 0 "internal conversion function for LATIN3 to MULE_INTERNAL" ) +insert ( 4347 1255 0 "internal conversion function for MULE_INTERNAL to LATIN3" ) +insert ( 4348 1255 0 "internal conversion function for LATIN4 to MULE_INTERNAL" ) +insert ( 4349 1255 0 "internal conversion function for MULE_INTERNAL to LATIN4" ) +insert ( 4352 1255 0 "internal conversion function for BIG5 to UTF8" ) +insert ( 4353 1255 0 "internal conversion function for UTF8 to BIG5" ) +insert ( 4354 1255 0 "internal conversion function for UTF8 to KOI8R" ) +insert ( 4355 1255 0 "internal conversion function for KOI8R to UTF8" ) +insert ( 4356 1255 0 "internal conversion function for UTF8 to KOI8U" ) +insert ( 4357 1255 0 "internal conversion function for KOI8U to UTF8" ) +insert ( 4358 1255 0 "internal conversion function for UTF8 to WIN" ) +insert ( 4359 1255 0 "internal conversion function for WIN to UTF8" ) +insert ( 4360 1255 0 "internal conversion function for EUC_CN to UTF8" ) +insert ( 4361 1255 0 "internal conversion function for UTF8 to EUC_CN" ) +insert ( 4362 1255 0 "internal conversion function for EUC_JP to UTF8" ) +insert ( 4363 1255 0 "internal conversion function for UTF8 to EUC_JP" ) +insert ( 4364 1255 0 "internal conversion function for EUC_KR to UTF8" ) +insert ( 4365 1255 0 "internal conversion function for UTF8 to EUC_KR" ) +insert ( 4366 1255 0 "internal conversion function for EUC_TW to UTF8" ) +insert ( 4367 1255 0 "internal conversion function for UTF8 to EUC_TW" ) +insert ( 4368 1255 0 "internal conversion function for GB18030 to UTF8" ) +insert ( 4369 1255 0 "internal conversion function for UTF8 to GB18030" ) +insert ( 4370 1255 0 "internal conversion function for GBK to UTF8" ) +insert ( 4371 1255 0 "internal conversion function for UTF8 to GBK" ) +insert ( 4372 1255 0 "internal conversion function for UTF8 to ISO-8859 2-16" ) +insert ( 4373 1255 0 "internal conversion function for ISO-8859 2-16 to UTF8" ) +insert ( 4374 1255 0 "internal conversion function for LATIN1 to UTF8" ) +insert ( 4375 1255 0 "internal conversion function for UTF8 to LATIN1" ) +insert ( 4376 1255 0 "internal conversion function for JOHAB to UTF8" ) +insert ( 4377 1255 0 "internal conversion function for UTF8 to JOHAB" ) +insert ( 4378 1255 0 "internal conversion function for SJIS to UTF8" ) +insert ( 4379 1255 0 "internal conversion function for UTF8 to SJIS" ) +insert ( 4380 1255 0 "internal conversion function for UHC to UTF8" ) +insert ( 4381 1255 0 "internal conversion function for UTF8 to UHC" ) +insert ( 4382 1255 0 "internal conversion function for EUC_JIS_2004 to UTF8" ) +insert ( 4383 1255 0 "internal conversion function for UTF8 to EUC_JIS_2004" ) +insert ( 4384 1255 0 "internal conversion function for SHIFT_JIS_2004 to UTF8" ) +insert ( 4385 1255 0 "internal conversion function for UTF8 to SHIFT_JIS_2004" ) +insert ( 4386 1255 0 "internal conversion function for EUC_JIS_2004 to SHIFT_JIS_2004" ) +insert ( 4387 1255 0 "internal conversion function for SHIFT_JIS_2004 to EUC_JIS_2004" ) +insert ( 5040 1255 0 "restriction selectivity for generic matching operators" ) +insert ( 5041 1255 0 "join selectivity for generic matching operators" ) +insert ( 6003 1255 0 "create a replication origin" ) +insert ( 6004 1255 0 "drop replication origin identified by its name" ) +insert ( 6005 1255 0 "translate the replication origin''s name to its id" ) +insert ( 6006 1255 0 "configure session to maintain replication progress tracking for the passed in origin" ) +insert ( 6007 1255 0 "teardown configured replication progress tracking" ) +insert ( 6008 1255 0 "is a replication origin configured in this session" ) +insert ( 6009 1255 0 "get the replication progress of the current session" ) +insert ( 6010 1255 0 "setup the transaction''s origin lsn and timestamp" ) +insert ( 6011 1255 0 "reset the transaction''s origin lsn and timestamp" ) +insert ( 6012 1255 0 "advance replication origin to specific location" ) +insert ( 6013 1255 0 "get an individual replication origin''s replication progress" ) +insert ( 6014 1255 0 "get progress for all replication origins" ) +insert ( 6119 1255 0 "get OIDs of tables in a publication" ) +insert ( 6121 1255 0 "returns whether a relation can be part of a publication" ) +insert ( 3298 1255 0 "row security for current context active on table by table oid" ) +insert ( 3299 1255 0 "row security for current context active on table by table name" ) +insert ( 3400 1255 0 "pg_config binary as a function" ) +insert ( 3441 1255 0 "pg_controldata general state information as a function" ) +insert ( 3442 1255 0 "pg_controldata checkpoint state information as a function" ) +insert ( 3443 1255 0 "pg_controldata recovery state information as a function" ) +insert ( 3444 1255 0 "pg_controldata init state information as a function" ) +insert ( 3445 1255 0 "import collations from operating system" ) +insert ( 3448 1255 0 "get actual version of collation from operating system" ) +insert ( 3353 1255 0 "list files in the log directory" ) +insert ( 3354 1255 0 "list of files in the WAL directory" ) +insert ( 5031 1255 0 "list of files in the archive_status directory" ) +insert ( 5029 1255 0 "list files in the pgsql_tmp directory" ) +insert ( 5030 1255 0 "list files in the pgsql_tmp directory" ) +insert ( 5028 1255 0 "hash partition CHECK constraint" ) +insert ( 3423 1255 0 "view partition tree tables" ) +insert ( 3425 1255 0 "view ancestors of the partition" ) +insert ( 3424 1255 0 "get top-most partition root parent" ) +insert ( 4350 1255 0 "Unicode normalization" ) +insert ( 4351 1255 0 "check Unicode normalization" ) +insert ( 16 1247 0 "boolean, ''true''/''false''" ) +insert ( 17 1247 0 "variable-length string, binary values escaped" ) +insert ( 18 1247 0 "single character" ) +insert ( 19 1247 0 "63-byte type for storing system identifiers" ) +insert ( 20 1247 0 "~18 digit integer, 8-byte storage" ) +insert ( 21 1247 0 "-32 thousand to 32 thousand, 2-byte storage" ) +insert ( 22 1247 0 "array of int2, used in system tables" ) +insert ( 23 1247 0 "-2 billion to 2 billion integer, 4-byte storage" ) +insert ( 24 1247 0 "registered procedure" ) +insert ( 25 1247 0 "variable-length string, no limit specified" ) +insert ( 26 1247 0 "object identifier(oid), maximum 4 billion" ) +insert ( 27 1247 0 "(block, offset), physical location of tuple" ) +insert ( 28 1247 0 "transaction id" ) +insert ( 29 1247 0 "command identifier type, sequence in transaction id" ) +insert ( 30 1247 0 "array of oids, used in system tables" ) +insert ( 114 1247 0 "JSON stored as text" ) +insert ( 142 1247 0 "XML content" ) +insert ( 194 1247 0 "string representing an internal node tree" ) +insert ( 3361 1247 0 "multivariate ndistinct coefficients" ) +insert ( 3402 1247 0 "multivariate dependencies" ) +insert ( 5017 1247 0 "multivariate MCV list" ) +insert ( 32 1247 0 "internal type for passing CollectedCommand" ) +insert ( 5069 1247 0 "full transaction id" ) +insert ( 600 1247 0 "geometric point ''(x, y)''" ) +insert ( 601 1247 0 "geometric line segment ''(pt1,pt2)''" ) +insert ( 602 1247 0 "geometric path ''(pt1,...)''" ) +insert ( 603 1247 0 "geometric box ''(lower left,upper right)''" ) +insert ( 604 1247 0 "geometric polygon ''(pt1,...)''" ) +insert ( 628 1247 0 "geometric line" ) +insert ( 700 1247 0 "single-precision floating point number, 4-byte storage" ) +insert ( 701 1247 0 "double-precision floating point number, 8-byte storage" ) +insert ( 705 1247 0 "pseudo-type representing an undetermined type" ) +insert ( 718 1247 0 "geometric circle ''(center,radius)''" ) +insert ( 790 1247 0 "monetary amounts, $d,ddd.cc" ) +insert ( 829 1247 0 "XX:XX:XX:XX:XX:XX, MAC address" ) +insert ( 869 1247 0 "IP address/netmask, host address, netmask optional" ) +insert ( 650 1247 0 "network IP address/netmask, network address" ) +insert ( 774 1247 0 "XX:XX:XX:XX:XX:XX:XX:XX, MAC address" ) +insert ( 1033 1247 0 "access control list" ) +insert ( 1042 1247 0 "char(length), blank-padded string, fixed storage length" ) +insert ( 1043 1247 0 "varchar(length), non-blank-padded string, variable storage length" ) +insert ( 1082 1247 0 date ) +insert ( 1083 1247 0 "time of day" ) +insert ( 1114 1247 0 "date and time" ) +insert ( 1184 1247 0 "date and time with time zone" ) +insert ( 1186 1247 0 "@ <number> <units>, time interval" ) +insert ( 1266 1247 0 "time of day with time zone" ) +insert ( 1560 1247 0 "fixed-length bit string" ) +insert ( 1562 1247 0 "variable-length bit string" ) +insert ( 1700 1247 0 "numeric(precision, decimal), arbitrary precision number" ) +insert ( 1790 1247 0 "reference to cursor (portal name)" ) +insert ( 2202 1247 0 "registered procedure (with args)" ) +insert ( 2203 1247 0 "registered operator" ) +insert ( 2204 1247 0 "registered operator (with args)" ) +insert ( 2205 1247 0 "registered class" ) +insert ( 4191 1247 0 "registered collation" ) +insert ( 2206 1247 0 "registered type" ) +insert ( 4096 1247 0 "registered role" ) +insert ( 4089 1247 0 "registered namespace" ) +insert ( 2950 1247 0 "UUID datatype" ) +insert ( 3220 1247 0 "PostgreSQL LSN datatype" ) +insert ( 3614 1247 0 "text representation for text search" ) +insert ( 3642 1247 0 "GiST index internal text representation for text search" ) +insert ( 3615 1247 0 "query representation for text search" ) +insert ( 3734 1247 0 "registered text search configuration" ) +insert ( 3769 1247 0 "registered text search dictionary" ) +insert ( 3802 1247 0 "Binary JSON" ) +insert ( 4072 1247 0 "JSON path" ) +insert ( 2970 1247 0 "txid snapshot" ) +insert ( 5038 1247 0 snapshot ) +insert ( 3904 1247 0 "range of integers" ) +insert ( 3906 1247 0 "range of numerics" ) +insert ( 3908 1247 0 "range of timestamps without time zone" ) +insert ( 3910 1247 0 "range of timestamps with time zone" ) +insert ( 3912 1247 0 "range of dates" ) +insert ( 3926 1247 0 "range of bigints" ) +insert ( 2249 1247 0 "pseudo-type representing any composite type" ) +insert ( 2275 1247 0 "C-style string" ) +insert ( 2276 1247 0 "pseudo-type representing any type" ) +insert ( 2277 1247 0 "pseudo-type representing a polymorphic array type" ) +insert ( 2278 1247 0 "pseudo-type for the result of a function with no real result" ) +insert ( 2279 1247 0 "pseudo-type for the result of a trigger function" ) +insert ( 3838 1247 0 "pseudo-type for the result of an event trigger function" ) +insert ( 2280 1247 0 "pseudo-type for the result of a language handler function" ) +insert ( 2281 1247 0 "pseudo-type representing an internal data structure" ) +insert ( 2283 1247 0 "pseudo-type representing a polymorphic base type" ) +insert ( 2776 1247 0 "pseudo-type representing a polymorphic base type that is not an array" ) +insert ( 3500 1247 0 "pseudo-type representing a polymorphic base type that is an enum" ) +insert ( 3115 1247 0 "pseudo-type for the result of an FDW handler function" ) +insert ( 325 1247 0 "pseudo-type for the result of an index AM handler function" ) +insert ( 3310 1247 0 "pseudo-type for the result of a tablesample method function" ) +insert ( 3831 1247 0 "pseudo-type representing a range over a polymorphic base type" ) +insert ( 5077 1247 0 "pseudo-type representing a polymorphic common type" ) +insert ( 5078 1247 0 "pseudo-type representing an array of polymorphic common type elements" ) +insert ( 5079 1247 0 "pseudo-type representing a polymorphic common type that is not an array" ) +insert ( 5080 1247 0 "pseudo-type representing a range over a polymorphic common type" ) +insert ( 15 2617 0 equal ) +insert ( 36 2617 0 "not equal" ) +insert ( 37 2617 0 "less than" ) +insert ( 76 2617 0 "greater than" ) +insert ( 80 2617 0 "less than or equal" ) +insert ( 82 2617 0 "greater than or equal" ) +insert ( 58 2617 0 "less than" ) +insert ( 59 2617 0 "greater than" ) +insert ( 85 2617 0 "not equal" ) +insert ( 91 2617 0 equal ) +insert ( 1694 2617 0 "less than or equal" ) +insert ( 1695 2617 0 "greater than or equal" ) +insert ( 92 2617 0 equal ) +insert ( 93 2617 0 equal ) +insert ( 94 2617 0 equal ) +insert ( 95 2617 0 "less than" ) +insert ( 96 2617 0 equal ) +insert ( 97 2617 0 "less than" ) +insert ( 98 2617 0 equal ) +insert ( 3877 2617 0 "starts with" ) +insert ( 254 2617 0 equal ) +insert ( 255 2617 0 "less than" ) +insert ( 256 2617 0 "less than or equal" ) +insert ( 257 2617 0 "greater than or equal" ) +insert ( 258 2617 0 "greater than" ) +insert ( 259 2617 0 "not equal" ) +insert ( 260 2617 0 equal ) +insert ( 261 2617 0 "less than" ) +insert ( 262 2617 0 "less than or equal" ) +insert ( 263 2617 0 "greater than or equal" ) +insert ( 264 2617 0 "greater than" ) +insert ( 265 2617 0 "not equal" ) +insert ( 349 2617 0 "append element onto end of array" ) +insert ( 374 2617 0 "prepend element onto front of array" ) +insert ( 375 2617 0 concatenate ) +insert ( 352 2617 0 equal ) +insert ( 353 2617 0 equal ) +insert ( 3315 2617 0 "not equal" ) +insert ( 3316 2617 0 "not equal" ) +insert ( 5068 2617 0 equal ) +insert ( 5072 2617 0 "not equal" ) +insert ( 5073 2617 0 "less than" ) +insert ( 5074 2617 0 "greater than" ) +insert ( 5075 2617 0 "less than or equal" ) +insert ( 5076 2617 0 "greater than or equal" ) +insert ( 388 2617 0 "deprecated, use factorial() instead" ) +insert ( 389 2617 0 "deprecated, use factorial() instead" ) +insert ( 385 2617 0 equal ) +insert ( 387 2617 0 equal ) +insert ( 402 2617 0 "not equal" ) +insert ( 2799 2617 0 "less than" ) +insert ( 2800 2617 0 "greater than" ) +insert ( 2801 2617 0 "less than or equal" ) +insert ( 2802 2617 0 "greater than or equal" ) +insert ( 410 2617 0 equal ) +insert ( 411 2617 0 "not equal" ) +insert ( 412 2617 0 "less than" ) +insert ( 413 2617 0 "greater than" ) +insert ( 414 2617 0 "less than or equal" ) +insert ( 415 2617 0 "greater than or equal" ) +insert ( 416 2617 0 equal ) +insert ( 417 2617 0 "not equal" ) +insert ( 418 2617 0 "less than" ) +insert ( 419 2617 0 "greater than" ) +insert ( 420 2617 0 "less than or equal" ) +insert ( 430 2617 0 "greater than or equal" ) +insert ( 439 2617 0 modulus ) +insert ( 473 2617 0 "absolute value" ) +insert ( 484 2617 0 negate ) +insert ( 485 2617 0 "is left of" ) +insert ( 486 2617 0 "overlaps or is left of" ) +insert ( 487 2617 0 "overlaps or is right of" ) +insert ( 488 2617 0 "is right of" ) +insert ( 489 2617 0 "is contained by" ) +insert ( 490 2617 0 contains ) +insert ( 491 2617 0 "same as" ) +insert ( 492 2617 0 overlaps ) +insert ( 493 2617 0 "is left of" ) +insert ( 494 2617 0 "overlaps or is left of" ) +insert ( 495 2617 0 "overlaps or is right of" ) +insert ( 496 2617 0 "is right of" ) +insert ( 497 2617 0 "is contained by" ) +insert ( 498 2617 0 contains ) +insert ( 499 2617 0 "same as" ) +insert ( 500 2617 0 overlaps ) +insert ( 501 2617 0 "greater than or equal by area" ) +insert ( 502 2617 0 "greater than by area" ) +insert ( 503 2617 0 "equal by area" ) +insert ( 504 2617 0 "less than by area" ) +insert ( 505 2617 0 "less than or equal by area" ) +insert ( 506 2617 0 "is above" ) +insert ( 507 2617 0 "is left of" ) +insert ( 508 2617 0 "is right of" ) +insert ( 509 2617 0 "is below" ) +insert ( 510 2617 0 "same as" ) +insert ( 511 2617 0 "point inside box" ) +insert ( 433 2617 0 contains ) +insert ( 512 2617 0 "point within closed path, or point on open path" ) +insert ( 513 2617 0 "center of" ) +insert ( 514 2617 0 multiply ) +insert ( 517 2617 0 "distance between" ) +insert ( 518 2617 0 "not equal" ) +insert ( 519 2617 0 "not equal" ) +insert ( 520 2617 0 "greater than" ) +insert ( 521 2617 0 "greater than" ) +insert ( 522 2617 0 "less than or equal" ) +insert ( 523 2617 0 "less than or equal" ) +insert ( 524 2617 0 "greater than or equal" ) +insert ( 525 2617 0 "greater than or equal" ) +insert ( 526 2617 0 multiply ) +insert ( 527 2617 0 divide ) +insert ( 528 2617 0 divide ) +insert ( 529 2617 0 modulus ) +insert ( 530 2617 0 modulus ) +insert ( 531 2617 0 "not equal" ) +insert ( 532 2617 0 equal ) +insert ( 533 2617 0 equal ) +insert ( 534 2617 0 "less than" ) +insert ( 535 2617 0 "less than" ) +insert ( 536 2617 0 "greater than" ) +insert ( 537 2617 0 "greater than" ) +insert ( 538 2617 0 "not equal" ) +insert ( 539 2617 0 "not equal" ) +insert ( 540 2617 0 "less than or equal" ) +insert ( 541 2617 0 "less than or equal" ) +insert ( 542 2617 0 "greater than or equal" ) +insert ( 543 2617 0 "greater than or equal" ) +insert ( 544 2617 0 multiply ) +insert ( 545 2617 0 multiply ) +insert ( 546 2617 0 divide ) +insert ( 547 2617 0 divide ) +insert ( 550 2617 0 add ) +insert ( 551 2617 0 add ) +insert ( 552 2617 0 add ) +insert ( 553 2617 0 add ) +insert ( 554 2617 0 subtract ) +insert ( 555 2617 0 subtract ) +insert ( 556 2617 0 subtract ) +insert ( 557 2617 0 subtract ) +insert ( 558 2617 0 negate ) +insert ( 559 2617 0 negate ) +insert ( 584 2617 0 negate ) +insert ( 585 2617 0 negate ) +insert ( 586 2617 0 add ) +insert ( 587 2617 0 subtract ) +insert ( 588 2617 0 divide ) +insert ( 589 2617 0 multiply ) +insert ( 590 2617 0 "absolute value" ) +insert ( 591 2617 0 add ) +insert ( 592 2617 0 subtract ) +insert ( 593 2617 0 divide ) +insert ( 594 2617 0 multiply ) +insert ( 595 2617 0 "absolute value" ) +insert ( 596 2617 0 "square root" ) +insert ( 597 2617 0 "cube root" ) +insert ( 607 2617 0 equal ) +insert ( 608 2617 0 "not equal" ) +insert ( 609 2617 0 "less than" ) +insert ( 610 2617 0 "greater than" ) +insert ( 611 2617 0 "less than or equal" ) +insert ( 612 2617 0 "greater than or equal" ) +insert ( 644 2617 0 "not equal" ) +insert ( 645 2617 0 "less than" ) +insert ( 646 2617 0 "greater than" ) +insert ( 647 2617 0 "less than or equal" ) +insert ( 648 2617 0 "greater than or equal" ) +insert ( 649 2617 0 equal ) +insert ( 613 2617 0 "distance between" ) +insert ( 760 2617 0 "distance between" ) +insert ( 614 2617 0 "distance between" ) +insert ( 761 2617 0 "distance between" ) +insert ( 615 2617 0 "distance between" ) +insert ( 606 2617 0 "distance between" ) +insert ( 616 2617 0 "distance between" ) +insert ( 762 2617 0 "distance between" ) +insert ( 617 2617 0 "distance between" ) +insert ( 763 2617 0 "distance between" ) +insert ( 618 2617 0 "distance between" ) +insert ( 784 2617 0 "distance between" ) +insert ( 620 2617 0 equal ) +insert ( 621 2617 0 "not equal" ) +insert ( 622 2617 0 "less than" ) +insert ( 623 2617 0 "greater than" ) +insert ( 624 2617 0 "less than or equal" ) +insert ( 625 2617 0 "greater than or equal" ) +insert ( 630 2617 0 "not equal" ) +insert ( 631 2617 0 "less than" ) +insert ( 632 2617 0 "less than or equal" ) +insert ( 633 2617 0 "greater than" ) +insert ( 634 2617 0 "greater than or equal" ) +insert ( 639 2617 0 "matches regular expression, case-sensitive" ) +insert ( 640 2617 0 "does not match regular expression, case-sensitive" ) +insert ( 641 2617 0 "matches regular expression, case-sensitive" ) +insert ( 642 2617 0 "does not match regular expression, case-sensitive" ) +insert ( 643 2617 0 "not equal" ) +insert ( 654 2617 0 concatenate ) +insert ( 660 2617 0 "less than" ) +insert ( 661 2617 0 "less than or equal" ) +insert ( 662 2617 0 "greater than" ) +insert ( 663 2617 0 "greater than or equal" ) +insert ( 664 2617 0 "less than" ) +insert ( 665 2617 0 "less than or equal" ) +insert ( 666 2617 0 "greater than" ) +insert ( 667 2617 0 "greater than or equal" ) +insert ( 670 2617 0 equal ) +insert ( 671 2617 0 "not equal" ) +insert ( 672 2617 0 "less than" ) +insert ( 673 2617 0 "less than or equal" ) +insert ( 674 2617 0 "greater than" ) +insert ( 675 2617 0 "greater than or equal" ) +insert ( 682 2617 0 "absolute value" ) +insert ( 684 2617 0 add ) +insert ( 685 2617 0 subtract ) +insert ( 686 2617 0 multiply ) +insert ( 687 2617 0 divide ) +insert ( 688 2617 0 add ) +insert ( 689 2617 0 subtract ) +insert ( 690 2617 0 multiply ) +insert ( 691 2617 0 divide ) +insert ( 692 2617 0 add ) +insert ( 693 2617 0 subtract ) +insert ( 694 2617 0 multiply ) +insert ( 695 2617 0 divide ) +insert ( 818 2617 0 add ) +insert ( 819 2617 0 subtract ) +insert ( 820 2617 0 multiply ) +insert ( 821 2617 0 divide ) +insert ( 822 2617 0 add ) +insert ( 823 2617 0 subtract ) +insert ( 824 2617 0 multiply ) +insert ( 825 2617 0 divide ) +insert ( 706 2617 0 "distance between" ) +insert ( 707 2617 0 "distance between" ) +insert ( 708 2617 0 "distance between" ) +insert ( 709 2617 0 "distance between" ) +insert ( 712 2617 0 "distance between" ) +insert ( 713 2617 0 "not equal" ) +insert ( 731 2617 0 "add points (translate)" ) +insert ( 732 2617 0 "subtract points (translate)" ) +insert ( 733 2617 0 "multiply points (scale/rotate)" ) +insert ( 734 2617 0 "divide points (scale/rotate)" ) +insert ( 735 2617 0 concatenate ) +insert ( 736 2617 0 "add (translate path)" ) +insert ( 737 2617 0 "subtract (translate path)" ) +insert ( 738 2617 0 "multiply (rotate/scale path)" ) +insert ( 739 2617 0 "divide (rotate/scale path)" ) +insert ( 755 2617 0 contains ) +insert ( 756 2617 0 "is contained by" ) +insert ( 757 2617 0 contains ) +insert ( 758 2617 0 "is contained by" ) +insert ( 759 2617 0 contains ) +insert ( 773 2617 0 "absolute value" ) +insert ( 792 2617 0 equal ) +insert ( 793 2617 0 "less than" ) +insert ( 794 2617 0 "greater than" ) +insert ( 795 2617 0 "less than or equal" ) +insert ( 796 2617 0 "greater than or equal" ) +insert ( 797 2617 0 "number of points" ) +insert ( 798 2617 0 intersect ) +insert ( 799 2617 0 "sum of path segment lengths" ) +insert ( 800 2617 0 "is above (allows touching)" ) +insert ( 801 2617 0 "is below (allows touching)" ) +insert ( 802 2617 0 "deprecated, use && instead" ) +insert ( 803 2617 0 "box intersection" ) +insert ( 804 2617 0 "add point to box (translate)" ) +insert ( 805 2617 0 "subtract point from box (translate)" ) +insert ( 806 2617 0 "multiply box by point (scale)" ) +insert ( 807 2617 0 "divide box by point (scale)" ) +insert ( 808 2617 0 "horizontally aligned" ) +insert ( 809 2617 0 "vertically aligned" ) +insert ( 843 2617 0 multiply ) +insert ( 844 2617 0 divide ) +insert ( 845 2617 0 multiply ) +insert ( 900 2617 0 equal ) +insert ( 901 2617 0 "not equal" ) +insert ( 902 2617 0 "less than" ) +insert ( 903 2617 0 "greater than" ) +insert ( 904 2617 0 "less than or equal" ) +insert ( 905 2617 0 "greater than or equal" ) +insert ( 906 2617 0 add ) +insert ( 907 2617 0 subtract ) +insert ( 908 2617 0 multiply ) +insert ( 909 2617 0 divide ) +insert ( 3346 2617 0 multiply ) +insert ( 3347 2617 0 divide ) +insert ( 912 2617 0 multiply ) +insert ( 913 2617 0 divide ) +insert ( 914 2617 0 multiply ) +insert ( 915 2617 0 divide ) +insert ( 916 2617 0 multiply ) +insert ( 3349 2617 0 multiply ) +insert ( 917 2617 0 multiply ) +insert ( 918 2617 0 multiply ) +insert ( 3825 2617 0 divide ) +insert ( 965 2617 0 exponentiation ) +insert ( 966 2617 0 "add/update ACL item" ) +insert ( 967 2617 0 "remove ACL item" ) +insert ( 968 2617 0 contains ) +insert ( 974 2617 0 equal ) +insert ( 969 2617 0 "center of" ) +insert ( 970 2617 0 "center of" ) +insert ( 971 2617 0 "center of" ) +insert ( 1054 2617 0 equal ) +insert ( 1055 2617 0 "matches regular expression, case-sensitive" ) +insert ( 1056 2617 0 "does not match regular expression, case-sensitive" ) +insert ( 1057 2617 0 "not equal" ) +insert ( 1058 2617 0 "less than" ) +insert ( 1059 2617 0 "less than or equal" ) +insert ( 1060 2617 0 "greater than" ) +insert ( 1061 2617 0 "greater than or equal" ) +insert ( 1070 2617 0 equal ) +insert ( 1071 2617 0 "not equal" ) +insert ( 1072 2617 0 "less than" ) +insert ( 1073 2617 0 "greater than" ) +insert ( 1074 2617 0 "less than or equal" ) +insert ( 1075 2617 0 "greater than or equal" ) +insert ( 1076 2617 0 add ) +insert ( 1077 2617 0 subtract ) +insert ( 1093 2617 0 equal ) +insert ( 1094 2617 0 "not equal" ) +insert ( 1095 2617 0 "less than" ) +insert ( 1096 2617 0 "less than or equal" ) +insert ( 1097 2617 0 "greater than" ) +insert ( 1098 2617 0 "greater than or equal" ) +insert ( 1099 2617 0 subtract ) +insert ( 1100 2617 0 add ) +insert ( 1101 2617 0 subtract ) +insert ( 1108 2617 0 equal ) +insert ( 1109 2617 0 "not equal" ) +insert ( 1110 2617 0 "less than" ) +insert ( 1111 2617 0 "less than or equal" ) +insert ( 1112 2617 0 "greater than" ) +insert ( 1113 2617 0 "greater than or equal" ) +insert ( 1550 2617 0 equal ) +insert ( 1551 2617 0 "not equal" ) +insert ( 1552 2617 0 "less than" ) +insert ( 1553 2617 0 "less than or equal" ) +insert ( 1554 2617 0 "greater than" ) +insert ( 1555 2617 0 "greater than or equal" ) +insert ( 1116 2617 0 add ) +insert ( 1117 2617 0 subtract ) +insert ( 1118 2617 0 divide ) +insert ( 1119 2617 0 multiply ) +insert ( 1120 2617 0 equal ) +insert ( 1121 2617 0 "not equal" ) +insert ( 1122 2617 0 "less than" ) +insert ( 1123 2617 0 "greater than" ) +insert ( 1124 2617 0 "less than or equal" ) +insert ( 1125 2617 0 "greater than or equal" ) +insert ( 1126 2617 0 add ) +insert ( 1127 2617 0 subtract ) +insert ( 1128 2617 0 divide ) +insert ( 1129 2617 0 multiply ) +insert ( 1130 2617 0 equal ) +insert ( 1131 2617 0 "not equal" ) +insert ( 1132 2617 0 "less than" ) +insert ( 1133 2617 0 "greater than" ) +insert ( 1134 2617 0 "less than or equal" ) +insert ( 1135 2617 0 "greater than or equal" ) +insert ( 1207 2617 0 "matches LIKE expression" ) +insert ( 1208 2617 0 "does not match LIKE expression" ) +insert ( 1209 2617 0 "matches LIKE expression" ) +insert ( 1210 2617 0 "does not match LIKE expression" ) +insert ( 1211 2617 0 "matches LIKE expression" ) +insert ( 1212 2617 0 "does not match LIKE expression" ) +insert ( 1226 2617 0 "matches regular expression, case-insensitive" ) +insert ( 1227 2617 0 "does not match regular expression, case-insensitive" ) +insert ( 1228 2617 0 "matches regular expression, case-insensitive" ) +insert ( 1229 2617 0 "does not match regular expression, case-insensitive" ) +insert ( 1234 2617 0 "matches regular expression, case-insensitive" ) +insert ( 1235 2617 0 "does not match regular expression, case-insensitive" ) +insert ( 1320 2617 0 equal ) +insert ( 1321 2617 0 "not equal" ) +insert ( 1322 2617 0 "less than" ) +insert ( 1323 2617 0 "less than or equal" ) +insert ( 1324 2617 0 "greater than" ) +insert ( 1325 2617 0 "greater than or equal" ) +insert ( 1327 2617 0 add ) +insert ( 1328 2617 0 subtract ) +insert ( 1329 2617 0 subtract ) +insert ( 1330 2617 0 equal ) +insert ( 1331 2617 0 "not equal" ) +insert ( 1332 2617 0 "less than" ) +insert ( 1333 2617 0 "less than or equal" ) +insert ( 1334 2617 0 "greater than" ) +insert ( 1335 2617 0 "greater than or equal" ) +insert ( 1336 2617 0 negate ) +insert ( 1337 2617 0 add ) +insert ( 1338 2617 0 subtract ) +insert ( 1360 2617 0 "convert date and time to timestamp" ) +insert ( 1361 2617 0 "convert date and time with time zone to timestamp with time zone" ) +insert ( 1363 2617 0 "convert time and date to timestamp" ) +insert ( 1366 2617 0 "convert time with time zone and date to timestamp with time zone" ) +insert ( 1399 2617 0 subtract ) +insert ( 1420 2617 0 "center of" ) +insert ( 1500 2617 0 "equal by area" ) +insert ( 1501 2617 0 "not equal by area" ) +insert ( 1502 2617 0 "less than by area" ) +insert ( 1503 2617 0 "greater than by area" ) +insert ( 1504 2617 0 "less than or equal by area" ) +insert ( 1505 2617 0 "greater than or equal by area" ) +insert ( 1506 2617 0 "is left of" ) +insert ( 1507 2617 0 "overlaps or is left of" ) +insert ( 1508 2617 0 "overlaps or is right of" ) +insert ( 1509 2617 0 "is right of" ) +insert ( 1510 2617 0 "is contained by" ) +insert ( 1511 2617 0 contains ) +insert ( 1512 2617 0 "same as" ) +insert ( 1513 2617 0 overlaps ) +insert ( 1514 2617 0 "is above" ) +insert ( 1515 2617 0 "is below" ) +insert ( 1516 2617 0 add ) +insert ( 1517 2617 0 subtract ) +insert ( 1518 2617 0 multiply ) +insert ( 1519 2617 0 divide ) +insert ( 1520 2617 0 "distance between" ) +insert ( 1521 2617 0 "number of points" ) +insert ( 1522 2617 0 "distance between" ) +insert ( 3291 2617 0 "distance between" ) +insert ( 3276 2617 0 "distance between" ) +insert ( 3289 2617 0 "distance between" ) +insert ( 1523 2617 0 "distance between" ) +insert ( 1383 2617 0 "distance between" ) +insert ( 1524 2617 0 "distance between" ) +insert ( 1382 2617 0 "distance between" ) +insert ( 1525 2617 0 intersect ) +insert ( 1526 2617 0 parallel ) +insert ( 1527 2617 0 perpendicular ) +insert ( 1528 2617 0 horizontal ) +insert ( 1529 2617 0 vertical ) +insert ( 1535 2617 0 equal ) +insert ( 1536 2617 0 "intersection point" ) +insert ( 1537 2617 0 intersect ) +insert ( 1538 2617 0 intersect ) +insert ( 1539 2617 0 intersect ) +insert ( 1546 2617 0 "point on line" ) +insert ( 1547 2617 0 "is contained by" ) +insert ( 1548 2617 0 "lseg on line" ) +insert ( 1549 2617 0 "is contained by" ) +insert ( 1557 2617 0 "closest point to A on B" ) +insert ( 1558 2617 0 "closest point to A on B" ) +insert ( 1559 2617 0 "closest point to A on B" ) +insert ( 1566 2617 0 "closest point to A on B" ) +insert ( 1567 2617 0 "closest point to A on B" ) +insert ( 1568 2617 0 "closest point to A on B" ) +insert ( 1577 2617 0 "closest point to A on B" ) +insert ( 1578 2617 0 "closest point to A on B" ) +insert ( 1583 2617 0 multiply ) +insert ( 1584 2617 0 multiply ) +insert ( 1585 2617 0 divide ) +insert ( 1586 2617 0 "not equal" ) +insert ( 1587 2617 0 "less than by length" ) +insert ( 1588 2617 0 "less than or equal by length" ) +insert ( 1589 2617 0 "greater than by length" ) +insert ( 1590 2617 0 "greater than or equal by length" ) +insert ( 1591 2617 0 "distance between endpoints" ) +insert ( 1611 2617 0 intersect ) +insert ( 1612 2617 0 parallel ) +insert ( 1613 2617 0 perpendicular ) +insert ( 1614 2617 0 horizontal ) +insert ( 1615 2617 0 vertical ) +insert ( 1616 2617 0 equal ) +insert ( 1617 2617 0 "intersection point" ) +insert ( 1220 2617 0 equal ) +insert ( 1221 2617 0 "not equal" ) +insert ( 1222 2617 0 "less than" ) +insert ( 1223 2617 0 "less than or equal" ) +insert ( 1224 2617 0 "greater than" ) +insert ( 1225 2617 0 "greater than or equal" ) +insert ( 3147 2617 0 "bitwise not" ) +insert ( 3148 2617 0 "bitwise and" ) +insert ( 3149 2617 0 "bitwise or" ) +insert ( 3362 2617 0 equal ) +insert ( 3363 2617 0 "not equal" ) +insert ( 3364 2617 0 "less than" ) +insert ( 3365 2617 0 "less than or equal" ) +insert ( 3366 2617 0 "greater than" ) +insert ( 3367 2617 0 "greater than or equal" ) +insert ( 3368 2617 0 "bitwise not" ) +insert ( 3369 2617 0 "bitwise and" ) +insert ( 3370 2617 0 "bitwise or" ) +insert ( 1201 2617 0 equal ) +insert ( 1202 2617 0 "not equal" ) +insert ( 1203 2617 0 "less than" ) +insert ( 1204 2617 0 "less than or equal" ) +insert ( 1205 2617 0 "greater than" ) +insert ( 1206 2617 0 "greater than or equal" ) +insert ( 931 2617 0 "is subnet" ) +insert ( 932 2617 0 "is subnet or equal" ) +insert ( 933 2617 0 "is supernet" ) +insert ( 934 2617 0 "is supernet or equal" ) +insert ( 3552 2617 0 "overlaps (is subnet or supernet)" ) +insert ( 2634 2617 0 "bitwise not" ) +insert ( 2635 2617 0 "bitwise and" ) +insert ( 2636 2617 0 "bitwise or" ) +insert ( 2637 2617 0 add ) +insert ( 2638 2617 0 add ) +insert ( 2639 2617 0 subtract ) +insert ( 2640 2617 0 subtract ) +insert ( 1625 2617 0 "matches LIKE expression, case-insensitive" ) +insert ( 1626 2617 0 "does not match LIKE expression, case-insensitive" ) +insert ( 1627 2617 0 "matches LIKE expression, case-insensitive" ) +insert ( 1628 2617 0 "does not match LIKE expression, case-insensitive" ) +insert ( 1629 2617 0 "matches LIKE expression, case-insensitive" ) +insert ( 1630 2617 0 "does not match LIKE expression, case-insensitive" ) +insert ( 1751 2617 0 negate ) +insert ( 1752 2617 0 equal ) +insert ( 1753 2617 0 "not equal" ) +insert ( 1754 2617 0 "less than" ) +insert ( 1755 2617 0 "less than or equal" ) +insert ( 1756 2617 0 "greater than" ) +insert ( 1757 2617 0 "greater than or equal" ) +insert ( 1758 2617 0 add ) +insert ( 1759 2617 0 subtract ) +insert ( 1760 2617 0 multiply ) +insert ( 1761 2617 0 divide ) +insert ( 1762 2617 0 modulus ) +insert ( 1038 2617 0 exponentiation ) +insert ( 1763 2617 0 "absolute value" ) +insert ( 1784 2617 0 equal ) +insert ( 1785 2617 0 "not equal" ) +insert ( 1786 2617 0 "less than" ) +insert ( 1787 2617 0 "greater than" ) +insert ( 1788 2617 0 "less than or equal" ) +insert ( 1789 2617 0 "greater than or equal" ) +insert ( 1791 2617 0 "bitwise and" ) +insert ( 1792 2617 0 "bitwise or" ) +insert ( 1793 2617 0 "bitwise exclusive or" ) +insert ( 1794 2617 0 "bitwise not" ) +insert ( 1795 2617 0 "bitwise shift left" ) +insert ( 1796 2617 0 "bitwise shift right" ) +insert ( 1797 2617 0 concatenate ) +insert ( 1800 2617 0 add ) +insert ( 1801 2617 0 subtract ) +insert ( 1802 2617 0 add ) +insert ( 1803 2617 0 subtract ) +insert ( 1804 2617 0 equal ) +insert ( 1805 2617 0 "not equal" ) +insert ( 1806 2617 0 "less than" ) +insert ( 1807 2617 0 "greater than" ) +insert ( 1808 2617 0 "less than or equal" ) +insert ( 1809 2617 0 "greater than or equal" ) +insert ( 1849 2617 0 add ) +insert ( 1862 2617 0 equal ) +insert ( 1863 2617 0 "not equal" ) +insert ( 1864 2617 0 "less than" ) +insert ( 1865 2617 0 "greater than" ) +insert ( 1866 2617 0 "less than or equal" ) +insert ( 1867 2617 0 "greater than or equal" ) +insert ( 1868 2617 0 equal ) +insert ( 1869 2617 0 "not equal" ) +insert ( 1870 2617 0 "less than" ) +insert ( 1871 2617 0 "greater than" ) +insert ( 1872 2617 0 "less than or equal" ) +insert ( 1873 2617 0 "greater than or equal" ) +insert ( 1874 2617 0 "bitwise and" ) +insert ( 1875 2617 0 "bitwise or" ) +insert ( 1876 2617 0 "bitwise exclusive or" ) +insert ( 1877 2617 0 "bitwise not" ) +insert ( 1878 2617 0 "bitwise shift left" ) +insert ( 1879 2617 0 "bitwise shift right" ) +insert ( 1880 2617 0 "bitwise and" ) +insert ( 1881 2617 0 "bitwise or" ) +insert ( 1882 2617 0 "bitwise exclusive or" ) +insert ( 1883 2617 0 "bitwise not" ) +insert ( 1884 2617 0 "bitwise shift left" ) +insert ( 1885 2617 0 "bitwise shift right" ) +insert ( 1886 2617 0 "bitwise and" ) +insert ( 1887 2617 0 "bitwise or" ) +insert ( 1888 2617 0 "bitwise exclusive or" ) +insert ( 1889 2617 0 "bitwise not" ) +insert ( 1890 2617 0 "bitwise shift left" ) +insert ( 1891 2617 0 "bitwise shift right" ) +insert ( 1916 2617 0 "unary plus" ) +insert ( 1917 2617 0 "unary plus" ) +insert ( 1918 2617 0 "unary plus" ) +insert ( 1919 2617 0 "unary plus" ) +insert ( 1920 2617 0 "unary plus" ) +insert ( 1921 2617 0 "unary plus" ) +insert ( 1955 2617 0 equal ) +insert ( 1956 2617 0 "not equal" ) +insert ( 1957 2617 0 "less than" ) +insert ( 1958 2617 0 "less than or equal" ) +insert ( 1959 2617 0 "greater than" ) +insert ( 1960 2617 0 "greater than or equal" ) +insert ( 2016 2617 0 "matches LIKE expression" ) +insert ( 2017 2617 0 "does not match LIKE expression" ) +insert ( 2018 2617 0 concatenate ) +insert ( 2060 2617 0 equal ) +insert ( 2061 2617 0 "not equal" ) +insert ( 2062 2617 0 "less than" ) +insert ( 2063 2617 0 "less than or equal" ) +insert ( 2064 2617 0 "greater than" ) +insert ( 2065 2617 0 "greater than or equal" ) +insert ( 2066 2617 0 add ) +insert ( 2067 2617 0 subtract ) +insert ( 2068 2617 0 subtract ) +insert ( 2314 2617 0 "less than" ) +insert ( 2315 2617 0 "less than or equal" ) +insert ( 2317 2617 0 "greater than or equal" ) +insert ( 2318 2617 0 "greater than" ) +insert ( 2326 2617 0 "less than" ) +insert ( 2327 2617 0 "less than or equal" ) +insert ( 2329 2617 0 "greater than or equal" ) +insert ( 2330 2617 0 "greater than" ) +insert ( 2345 2617 0 "less than" ) +insert ( 2346 2617 0 "less than or equal" ) +insert ( 2347 2617 0 equal ) +insert ( 2348 2617 0 "greater than or equal" ) +insert ( 2349 2617 0 "greater than" ) +insert ( 2350 2617 0 "not equal" ) +insert ( 2358 2617 0 "less than" ) +insert ( 2359 2617 0 "less than or equal" ) +insert ( 2360 2617 0 equal ) +insert ( 2361 2617 0 "greater than or equal" ) +insert ( 2362 2617 0 "greater than" ) +insert ( 2363 2617 0 "not equal" ) +insert ( 2371 2617 0 "less than" ) +insert ( 2372 2617 0 "less than or equal" ) +insert ( 2373 2617 0 equal ) +insert ( 2374 2617 0 "greater than or equal" ) +insert ( 2375 2617 0 "greater than" ) +insert ( 2376 2617 0 "not equal" ) +insert ( 2384 2617 0 "less than" ) +insert ( 2385 2617 0 "less than or equal" ) +insert ( 2386 2617 0 equal ) +insert ( 2387 2617 0 "greater than or equal" ) +insert ( 2388 2617 0 "greater than" ) +insert ( 2389 2617 0 "not equal" ) +insert ( 2534 2617 0 "less than" ) +insert ( 2535 2617 0 "less than or equal" ) +insert ( 2536 2617 0 equal ) +insert ( 2537 2617 0 "greater than or equal" ) +insert ( 2538 2617 0 "greater than" ) +insert ( 2539 2617 0 "not equal" ) +insert ( 2540 2617 0 "less than" ) +insert ( 2541 2617 0 "less than or equal" ) +insert ( 2542 2617 0 equal ) +insert ( 2543 2617 0 "greater than or equal" ) +insert ( 2544 2617 0 "greater than" ) +insert ( 2545 2617 0 "not equal" ) +insert ( 2551 2617 0 add ) +insert ( 2552 2617 0 add ) +insert ( 2553 2617 0 add ) +insert ( 2554 2617 0 add ) +insert ( 2555 2617 0 add ) +insert ( 2570 2617 0 "is below" ) +insert ( 2571 2617 0 "overlaps or is below" ) +insert ( 2572 2617 0 "overlaps or is above" ) +insert ( 2573 2617 0 "is above" ) +insert ( 2574 2617 0 "is below" ) +insert ( 2575 2617 0 "overlaps or is below" ) +insert ( 2576 2617 0 "overlaps or is above" ) +insert ( 2577 2617 0 "is above" ) +insert ( 2589 2617 0 "overlaps or is below" ) +insert ( 2590 2617 0 "overlaps or is above" ) +insert ( 2750 2617 0 overlaps ) +insert ( 2751 2617 0 contains ) +insert ( 2752 2617 0 "is contained by" ) +insert ( 2779 2617 0 concatenate ) +insert ( 2780 2617 0 concatenate ) +insert ( 2860 2617 0 "deprecated, use <@ instead" ) +insert ( 2861 2617 0 "deprecated, use @> instead" ) +insert ( 2862 2617 0 "deprecated, use <@ instead" ) +insert ( 2863 2617 0 "deprecated, use @> instead" ) +insert ( 2864 2617 0 "deprecated, use <@ instead" ) +insert ( 2865 2617 0 "deprecated, use @> instead" ) +insert ( 2866 2617 0 "deprecated, use <@ instead" ) +insert ( 2867 2617 0 "deprecated, use <@ instead" ) +insert ( 2868 2617 0 "deprecated, use @> instead" ) +insert ( 2869 2617 0 "deprecated, use <@ instead" ) +insert ( 2870 2617 0 "deprecated, use @> instead" ) +insert ( 2871 2617 0 "deprecated, use <@ instead" ) +insert ( 2872 2617 0 "deprecated, use @> instead" ) +insert ( 2873 2617 0 "deprecated, use <@ instead" ) +insert ( 2874 2617 0 "deprecated, use <@ instead" ) +insert ( 2875 2617 0 "deprecated, use <@ instead" ) +insert ( 2876 2617 0 "deprecated, use <@ instead" ) +insert ( 2877 2617 0 "deprecated, use @> instead" ) +insert ( 2972 2617 0 equal ) +insert ( 2973 2617 0 "not equal" ) +insert ( 2974 2617 0 "less than" ) +insert ( 2975 2617 0 "greater than" ) +insert ( 2976 2617 0 "less than or equal" ) +insert ( 2977 2617 0 "greater than or equal" ) +insert ( 3222 2617 0 equal ) +insert ( 3223 2617 0 "not equal" ) +insert ( 3224 2617 0 "less than" ) +insert ( 3225 2617 0 "greater than" ) +insert ( 3226 2617 0 "less than or equal" ) +insert ( 3227 2617 0 "greater than or equal" ) +insert ( 3228 2617 0 minus ) +insert ( 3516 2617 0 equal ) +insert ( 3517 2617 0 "not equal" ) +insert ( 3518 2617 0 "less than" ) +insert ( 3519 2617 0 "greater than" ) +insert ( 3520 2617 0 "less than or equal" ) +insert ( 3521 2617 0 "greater than or equal" ) +insert ( 3627 2617 0 "less than" ) +insert ( 3628 2617 0 "less than or equal" ) +insert ( 3629 2617 0 equal ) +insert ( 3630 2617 0 "not equal" ) +insert ( 3631 2617 0 "greater than or equal" ) +insert ( 3632 2617 0 "greater than" ) +insert ( 3633 2617 0 concatenate ) +insert ( 3636 2617 0 "text search match" ) +insert ( 3637 2617 0 "text search match" ) +insert ( 3660 2617 0 "deprecated, use @@ instead" ) +insert ( 3661 2617 0 "deprecated, use @@ instead" ) +insert ( 3674 2617 0 "less than" ) +insert ( 3675 2617 0 "less than or equal" ) +insert ( 3676 2617 0 equal ) +insert ( 3677 2617 0 "not equal" ) +insert ( 3678 2617 0 "greater than or equal" ) +insert ( 3679 2617 0 "greater than" ) +insert ( 3680 2617 0 AND-concatenate ) +insert ( 3681 2617 0 OR-concatenate ) +insert ( 5005 2617 0 phrase-concatenate ) +insert ( 3682 2617 0 "NOT tsquery" ) +insert ( 3693 2617 0 contains ) +insert ( 3694 2617 0 "is contained by" ) +insert ( 3762 2617 0 "text search match" ) +insert ( 3763 2617 0 "text search match" ) +insert ( 2988 2617 0 equal ) +insert ( 2989 2617 0 "not equal" ) +insert ( 2990 2617 0 "less than" ) +insert ( 2991 2617 0 "greater than" ) +insert ( 2992 2617 0 "less than or equal" ) +insert ( 2993 2617 0 "greater than or equal" ) +insert ( 3188 2617 0 identical ) +insert ( 3189 2617 0 "not identical" ) +insert ( 3190 2617 0 "less than" ) +insert ( 3191 2617 0 "greater than" ) +insert ( 3192 2617 0 "less than or equal" ) +insert ( 3193 2617 0 "greater than or equal" ) +insert ( 3882 2617 0 equal ) +insert ( 3883 2617 0 "not equal" ) +insert ( 3884 2617 0 "less than" ) +insert ( 3885 2617 0 "less than or equal" ) +insert ( 3886 2617 0 "greater than or equal" ) +insert ( 3887 2617 0 "greater than" ) +insert ( 3888 2617 0 overlaps ) +insert ( 3889 2617 0 contains ) +insert ( 3890 2617 0 contains ) +insert ( 3891 2617 0 "is contained by" ) +insert ( 3892 2617 0 "is contained by" ) +insert ( 3893 2617 0 "is left of" ) +insert ( 3894 2617 0 "is right of" ) +insert ( 3895 2617 0 "overlaps or is left of" ) +insert ( 3896 2617 0 "overlaps or is right of" ) +insert ( 3897 2617 0 "is adjacent to" ) +insert ( 3898 2617 0 "range union" ) +insert ( 3899 2617 0 "range difference" ) +insert ( 3900 2617 0 "range intersection" ) +insert ( 3962 2617 0 "get json object field" ) +insert ( 3963 2617 0 "get json object field as text" ) +insert ( 3964 2617 0 "get json array element" ) +insert ( 3965 2617 0 "get json array element as text" ) +insert ( 3966 2617 0 "get value from json with path elements" ) +insert ( 3967 2617 0 "get value from json as text with path elements" ) +insert ( 3211 2617 0 "get jsonb object field" ) +insert ( 3477 2617 0 "get jsonb object field as text" ) +insert ( 3212 2617 0 "get jsonb array element" ) +insert ( 3481 2617 0 "get jsonb array element as text" ) +insert ( 3213 2617 0 "get value from jsonb with path elements" ) +insert ( 3206 2617 0 "get value from jsonb as text with path elements" ) +insert ( 3240 2617 0 equal ) +insert ( 3241 2617 0 "not equal" ) +insert ( 3242 2617 0 "less than" ) +insert ( 3243 2617 0 "greater than" ) +insert ( 3244 2617 0 "less than or equal" ) +insert ( 3245 2617 0 "greater than or equal" ) +insert ( 3246 2617 0 contains ) +insert ( 3247 2617 0 "key exists" ) +insert ( 3248 2617 0 "any key exists" ) +insert ( 3249 2617 0 "all keys exist" ) +insert ( 3250 2617 0 "is contained by" ) +insert ( 3284 2617 0 concatenate ) +insert ( 3285 2617 0 "delete object field" ) +insert ( 3398 2617 0 "delete object fields" ) +insert ( 3286 2617 0 "delete array element" ) +insert ( 3287 2617 0 "delete path" ) +insert ( 4012 2617 0 "jsonpath exists" ) +insert ( 4013 2617 0 "jsonpath match" ) +insert ( 2 2601 0 "heap table access method" ) +insert ( 403 2601 0 "b-tree index access method" ) +insert ( 405 2601 0 "hash index access method" ) +insert ( 783 2601 0 "GiST index access method" ) +insert ( 2742 2601 0 "GIN index access method" ) +insert ( 4000 2601 0 "SP-GiST index access method" ) +insert ( 3580 2601 0 "block range index (BRIN) access method" ) +insert ( 12 2612 0 "built-in functions" ) +insert ( 13 2612 0 "dynamically-loaded C functions" ) +insert ( 14 2612 0 "SQL-language functions" ) +insert ( 11 2615 0 "system catalog schema" ) +insert ( 99 2615 0 "reserved schema for TOAST tables" ) +insert ( 2200 2615 0 "standard public schema" ) +insert ( 4402 2607 0 "conversion for KOI8R to MULE_INTERNAL" ) +insert ( 4403 2607 0 "conversion for MULE_INTERNAL to KOI8R" ) +insert ( 4404 2607 0 "conversion for ISO-8859-5 to MULE_INTERNAL" ) +insert ( 4405 2607 0 "conversion for MULE_INTERNAL to ISO-8859-5" ) +insert ( 4406 2607 0 "conversion for WIN1251 to MULE_INTERNAL" ) +insert ( 4407 2607 0 "conversion for MULE_INTERNAL to WIN1251" ) +insert ( 4408 2607 0 "conversion for WIN866 to MULE_INTERNAL" ) +insert ( 4409 2607 0 "conversion for MULE_INTERNAL to WIN866" ) +insert ( 4410 2607 0 "conversion for KOI8R to WIN1251" ) +insert ( 4411 2607 0 "conversion for WIN1251 to KOI8R" ) +insert ( 4412 2607 0 "conversion for KOI8R to WIN866" ) +insert ( 4413 2607 0 "conversion for WIN866 to KOI8R" ) +insert ( 4414 2607 0 "conversion for WIN866 to WIN1251" ) +insert ( 4415 2607 0 "conversion for WIN1251 to WIN866" ) +insert ( 4416 2607 0 "conversion for ISO-8859-5 to KOI8R" ) +insert ( 4417 2607 0 "conversion for KOI8R to ISO-8859-5" ) +insert ( 4418 2607 0 "conversion for ISO-8859-5 to WIN1251" ) +insert ( 4419 2607 0 "conversion for WIN1251 to ISO-8859-5" ) +insert ( 4420 2607 0 "conversion for ISO-8859-5 to WIN866" ) +insert ( 4421 2607 0 "conversion for WIN866 to ISO-8859-5" ) +insert ( 4422 2607 0 "conversion for EUC_CN to MULE_INTERNAL" ) +insert ( 4423 2607 0 "conversion for MULE_INTERNAL to EUC_CN" ) +insert ( 4424 2607 0 "conversion for EUC_JP to SJIS" ) +insert ( 4425 2607 0 "conversion for SJIS to EUC_JP" ) +insert ( 4426 2607 0 "conversion for EUC_JP to MULE_INTERNAL" ) +insert ( 4427 2607 0 "conversion for SJIS to MULE_INTERNAL" ) +insert ( 4428 2607 0 "conversion for MULE_INTERNAL to EUC_JP" ) +insert ( 4429 2607 0 "conversion for MULE_INTERNAL to SJIS" ) +insert ( 4430 2607 0 "conversion for EUC_KR to MULE_INTERNAL" ) +insert ( 4431 2607 0 "conversion for MULE_INTERNAL to EUC_KR" ) +insert ( 4432 2607 0 "conversion for EUC_TW to BIG5" ) +insert ( 4433 2607 0 "conversion for BIG5 to EUC_TW" ) +insert ( 4434 2607 0 "conversion for EUC_TW to MULE_INTERNAL" ) +insert ( 4435 2607 0 "conversion for BIG5 to MULE_INTERNAL" ) +insert ( 4436 2607 0 "conversion for MULE_INTERNAL to EUC_TW" ) +insert ( 4437 2607 0 "conversion for MULE_INTERNAL to BIG5" ) +insert ( 4438 2607 0 "conversion for LATIN2 to MULE_INTERNAL" ) +insert ( 4439 2607 0 "conversion for MULE_INTERNAL to LATIN2" ) +insert ( 4440 2607 0 "conversion for WIN1250 to MULE_INTERNAL" ) +insert ( 4441 2607 0 "conversion for MULE_INTERNAL to WIN1250" ) +insert ( 4442 2607 0 "conversion for LATIN2 to WIN1250" ) +insert ( 4443 2607 0 "conversion for WIN1250 to LATIN2" ) +insert ( 4444 2607 0 "conversion for LATIN1 to MULE_INTERNAL" ) +insert ( 4445 2607 0 "conversion for MULE_INTERNAL to LATIN1" ) +insert ( 4446 2607 0 "conversion for LATIN3 to MULE_INTERNAL" ) +insert ( 4447 2607 0 "conversion for MULE_INTERNAL to LATIN3" ) +insert ( 4448 2607 0 "conversion for LATIN4 to MULE_INTERNAL" ) +insert ( 4449 2607 0 "conversion for MULE_INTERNAL to LATIN4" ) +insert ( 4452 2607 0 "conversion for BIG5 to UTF8" ) +insert ( 4453 2607 0 "conversion for UTF8 to BIG5" ) +insert ( 4454 2607 0 "conversion for UTF8 to KOI8R" ) +insert ( 4455 2607 0 "conversion for KOI8R to UTF8" ) +insert ( 4456 2607 0 "conversion for UTF8 to KOI8U" ) +insert ( 4457 2607 0 "conversion for KOI8U to UTF8" ) +insert ( 4458 2607 0 "conversion for UTF8 to WIN866" ) +insert ( 4459 2607 0 "conversion for WIN866 to UTF8" ) +insert ( 4460 2607 0 "conversion for UTF8 to WIN874" ) +insert ( 4461 2607 0 "conversion for WIN874 to UTF8" ) +insert ( 4462 2607 0 "conversion for UTF8 to WIN1250" ) +insert ( 4463 2607 0 "conversion for WIN1250 to UTF8" ) +insert ( 4464 2607 0 "conversion for UTF8 to WIN1251" ) +insert ( 4465 2607 0 "conversion for WIN1251 to UTF8" ) +insert ( 4466 2607 0 "conversion for UTF8 to WIN1252" ) +insert ( 4467 2607 0 "conversion for WIN1252 to UTF8" ) +insert ( 4468 2607 0 "conversion for UTF8 to WIN1253" ) +insert ( 4469 2607 0 "conversion for WIN1253 to UTF8" ) +insert ( 4470 2607 0 "conversion for UTF8 to WIN1254" ) +insert ( 4471 2607 0 "conversion for WIN1254 to UTF8" ) +insert ( 4472 2607 0 "conversion for UTF8 to WIN1255" ) +insert ( 4473 2607 0 "conversion for WIN1255 to UTF8" ) +insert ( 4474 2607 0 "conversion for UTF8 to WIN1256" ) +insert ( 4475 2607 0 "conversion for WIN1256 to UTF8" ) +insert ( 4476 2607 0 "conversion for UTF8 to WIN1257" ) +insert ( 4477 2607 0 "conversion for WIN1257 to UTF8" ) +insert ( 4478 2607 0 "conversion for UTF8 to WIN1258" ) +insert ( 4479 2607 0 "conversion for WIN1258 to UTF8" ) +insert ( 4480 2607 0 "conversion for EUC_CN to UTF8" ) +insert ( 4481 2607 0 "conversion for UTF8 to EUC_CN" ) +insert ( 4482 2607 0 "conversion for EUC_JP to UTF8" ) +insert ( 4483 2607 0 "conversion for UTF8 to EUC_JP" ) +insert ( 4484 2607 0 "conversion for EUC_KR to UTF8" ) +insert ( 4485 2607 0 "conversion for UTF8 to EUC_KR" ) +insert ( 4486 2607 0 "conversion for EUC_TW to UTF8" ) +insert ( 4487 2607 0 "conversion for UTF8 to EUC_TW" ) +insert ( 4488 2607 0 "conversion for GB18030 to UTF8" ) +insert ( 4489 2607 0 "conversion for UTF8 to GB18030" ) +insert ( 4490 2607 0 "conversion for GBK to UTF8" ) +insert ( 4491 2607 0 "conversion for UTF8 to GBK" ) +insert ( 4492 2607 0 "conversion for UTF8 to LATIN2" ) +insert ( 4493 2607 0 "conversion for LATIN2 to UTF8" ) +insert ( 4494 2607 0 "conversion for UTF8 to LATIN3" ) +insert ( 4495 2607 0 "conversion for LATIN3 to UTF8" ) +insert ( 4496 2607 0 "conversion for UTF8 to LATIN4" ) +insert ( 4497 2607 0 "conversion for LATIN4 to UTF8" ) +insert ( 4498 2607 0 "conversion for UTF8 to LATIN5" ) +insert ( 4499 2607 0 "conversion for LATIN5 to UTF8" ) +insert ( 4500 2607 0 "conversion for UTF8 to LATIN6" ) +insert ( 4501 2607 0 "conversion for LATIN6 to UTF8" ) +insert ( 4502 2607 0 "conversion for UTF8 to LATIN7" ) +insert ( 4503 2607 0 "conversion for LATIN7 to UTF8" ) +insert ( 4504 2607 0 "conversion for UTF8 to LATIN8" ) +insert ( 4505 2607 0 "conversion for LATIN8 to UTF8" ) +insert ( 4506 2607 0 "conversion for UTF8 to LATIN9" ) +insert ( 4507 2607 0 "conversion for LATIN9 to UTF8" ) +insert ( 4508 2607 0 "conversion for UTF8 to LATIN10" ) +insert ( 4509 2607 0 "conversion for LATIN10 to UTF8" ) +insert ( 4510 2607 0 "conversion for UTF8 to ISO-8859-5" ) +insert ( 4511 2607 0 "conversion for ISO-8859-5 to UTF8" ) +insert ( 4512 2607 0 "conversion for UTF8 to ISO-8859-6" ) +insert ( 4513 2607 0 "conversion for ISO-8859-6 to UTF8" ) +insert ( 4514 2607 0 "conversion for UTF8 to ISO-8859-7" ) +insert ( 4515 2607 0 "conversion for ISO-8859-7 to UTF8" ) +insert ( 4516 2607 0 "conversion for UTF8 to ISO-8859-8" ) +insert ( 4517 2607 0 "conversion for ISO-8859-8 to UTF8" ) +insert ( 4518 2607 0 "conversion for LATIN1 to UTF8" ) +insert ( 4519 2607 0 "conversion for UTF8 to LATIN1" ) +insert ( 4520 2607 0 "conversion for JOHAB to UTF8" ) +insert ( 4521 2607 0 "conversion for UTF8 to JOHAB" ) +insert ( 4522 2607 0 "conversion for SJIS to UTF8" ) +insert ( 4523 2607 0 "conversion for UTF8 to SJIS" ) +insert ( 4524 2607 0 "conversion for UHC to UTF8" ) +insert ( 4525 2607 0 "conversion for UTF8 to UHC" ) +insert ( 4526 2607 0 "conversion for EUC_JIS_2004 to UTF8" ) +insert ( 4527 2607 0 "conversion for UTF8 to EUC_JIS_2004" ) +insert ( 4528 2607 0 "conversion for SHIFT_JIS_2004 to UTF8" ) +insert ( 4529 2607 0 "conversion for UTF8 to SHIFT_JIS_2004" ) +insert ( 4530 2607 0 "conversion for EUC_JIS_2004 to SHIFT_JIS_2004" ) +insert ( 4531 2607 0 "conversion for SHIFT_JIS_2004 to EUC_JIS_2004" ) +insert ( 3748 3602 0 "simple configuration" ) +insert ( 3765 3600 0 "simple dictionary: just lower case and check for stopword" ) +insert ( 3722 3601 0 "default word parser" ) +insert ( 3727 3764 0 "simple dictionary: just lower case and check for stopword" ) +insert ( 3730 3764 0 "synonym dictionary: replace word by its synonym" ) +insert ( 3733 3764 0 "ispell dictionary" ) +insert ( 3742 3764 0 "thesaurus dictionary: phrase by phrase substitution" ) +insert ( 100 3456 0 "database''s default collation" ) +insert ( 950 3456 0 "standard C collation" ) +insert ( 951 3456 0 "standard POSIX collation" ) +close pg_description +create pg_cast 2605 + ( + oid = oid , + castsource = oid , + casttarget = oid , + castfunc = oid , + castcontext = char , + castmethod = char + ) +open pg_cast +insert ( 11323 20 21 714 a f ) +insert ( 11324 20 23 480 a f ) +insert ( 11325 20 700 652 i f ) +insert ( 11326 20 701 482 i f ) +insert ( 11327 20 1700 1781 i f ) +insert ( 11328 21 20 754 i f ) +insert ( 11329 21 23 313 i f ) +insert ( 11330 21 700 236 i f ) +insert ( 11331 21 701 235 i f ) +insert ( 11332 21 1700 1782 i f ) +insert ( 11333 23 20 481 i f ) +insert ( 11334 23 21 314 a f ) +insert ( 11335 23 700 318 i f ) +insert ( 11336 23 701 316 i f ) +insert ( 11337 23 1700 1740 i f ) +insert ( 11338 700 20 653 a f ) +insert ( 11339 700 21 238 a f ) +insert ( 11340 700 23 319 a f ) +insert ( 11341 700 701 311 i f ) +insert ( 11342 700 1700 1742 a f ) +insert ( 11343 701 20 483 a f ) +insert ( 11344 701 21 237 a f ) +insert ( 11345 701 23 317 a f ) +insert ( 11346 701 700 312 a f ) +insert ( 11347 701 1700 1743 a f ) +insert ( 11348 1700 20 1779 a f ) +insert ( 11349 1700 21 1783 a f ) +insert ( 11350 1700 23 1744 a f ) +insert ( 11351 1700 700 1745 i f ) +insert ( 11352 1700 701 1746 i f ) +insert ( 11353 790 1700 3823 a f ) +insert ( 11354 1700 790 3824 a f ) +insert ( 11355 23 790 3811 a f ) +insert ( 11356 20 790 3812 a f ) +insert ( 11357 23 16 2557 e f ) +insert ( 11358 16 23 2558 e f ) +insert ( 11359 5069 28 5071 e f ) +insert ( 11360 20 26 1287 i f ) +insert ( 11361 21 26 313 i f ) +insert ( 11362 23 26 0 i b ) +insert ( 11363 26 20 1288 a f ) +insert ( 11364 26 23 0 a b ) +insert ( 11365 26 24 0 i b ) +insert ( 11366 24 26 0 i b ) +insert ( 11367 20 24 1287 i f ) +insert ( 11368 21 24 313 i f ) +insert ( 11369 23 24 0 i b ) +insert ( 11370 24 20 1288 a f ) +insert ( 11371 24 23 0 a b ) +insert ( 11372 24 2202 0 i b ) +insert ( 11373 2202 24 0 i b ) +insert ( 11374 26 2202 0 i b ) +insert ( 11375 2202 26 0 i b ) +insert ( 11376 20 2202 1287 i f ) +insert ( 11377 21 2202 313 i f ) +insert ( 11378 23 2202 0 i b ) +insert ( 11379 2202 20 1288 a f ) +insert ( 11380 2202 23 0 a b ) +insert ( 11381 26 2203 0 i b ) +insert ( 11382 2203 26 0 i b ) +insert ( 11383 20 2203 1287 i f ) +insert ( 11384 21 2203 313 i f ) +insert ( 11385 23 2203 0 i b ) +insert ( 11386 2203 20 1288 a f ) +insert ( 11387 2203 23 0 a b ) +insert ( 11388 2203 2204 0 i b ) +insert ( 11389 2204 2203 0 i b ) +insert ( 11390 26 2204 0 i b ) +insert ( 11391 2204 26 0 i b ) +insert ( 11392 20 2204 1287 i f ) +insert ( 11393 21 2204 313 i f ) +insert ( 11394 23 2204 0 i b ) +insert ( 11395 2204 20 1288 a f ) +insert ( 11396 2204 23 0 a b ) +insert ( 11397 26 2205 0 i b ) +insert ( 11398 2205 26 0 i b ) +insert ( 11399 20 2205 1287 i f ) +insert ( 11400 21 2205 313 i f ) +insert ( 11401 23 2205 0 i b ) +insert ( 11402 2205 20 1288 a f ) +insert ( 11403 2205 23 0 a b ) +insert ( 11404 26 4191 0 i b ) +insert ( 11405 4191 26 0 i b ) +insert ( 11406 20 4191 1287 i f ) +insert ( 11407 21 4191 313 i f ) +insert ( 11408 23 4191 0 i b ) +insert ( 11409 4191 20 1288 a f ) +insert ( 11410 4191 23 0 a b ) +insert ( 11411 26 2206 0 i b ) +insert ( 11412 2206 26 0 i b ) +insert ( 11413 20 2206 1287 i f ) +insert ( 11414 21 2206 313 i f ) +insert ( 11415 23 2206 0 i b ) +insert ( 11416 2206 20 1288 a f ) +insert ( 11417 2206 23 0 a b ) +insert ( 11418 26 3734 0 i b ) +insert ( 11419 3734 26 0 i b ) +insert ( 11420 20 3734 1287 i f ) +insert ( 11421 21 3734 313 i f ) +insert ( 11422 23 3734 0 i b ) +insert ( 11423 3734 20 1288 a f ) +insert ( 11424 3734 23 0 a b ) +insert ( 11425 26 3769 0 i b ) +insert ( 11426 3769 26 0 i b ) +insert ( 11427 20 3769 1287 i f ) +insert ( 11428 21 3769 313 i f ) +insert ( 11429 23 3769 0 i b ) +insert ( 11430 3769 20 1288 a f ) +insert ( 11431 3769 23 0 a b ) +insert ( 11432 25 2205 1079 i f ) +insert ( 11433 1043 2205 1079 i f ) +insert ( 11434 26 4096 0 i b ) +insert ( 11435 4096 26 0 i b ) +insert ( 11436 20 4096 1287 i f ) +insert ( 11437 21 4096 313 i f ) +insert ( 11438 23 4096 0 i b ) +insert ( 11439 4096 20 1288 a f ) +insert ( 11440 4096 23 0 a b ) +insert ( 11441 26 4089 0 i b ) +insert ( 11442 4089 26 0 i b ) +insert ( 11443 20 4089 1287 i f ) +insert ( 11444 21 4089 313 i f ) +insert ( 11445 23 4089 0 i b ) +insert ( 11446 4089 20 1288 a f ) +insert ( 11447 4089 23 0 a b ) +insert ( 11448 25 1042 0 i b ) +insert ( 11449 25 1043 0 i b ) +insert ( 11450 1042 25 401 i f ) +insert ( 11451 1042 1043 401 i f ) +insert ( 11452 1043 25 0 i b ) +insert ( 11453 1043 1042 0 i b ) +insert ( 11454 18 25 946 i f ) +insert ( 11455 18 1042 860 a f ) +insert ( 11456 18 1043 946 a f ) +insert ( 11457 19 25 406 i f ) +insert ( 11458 19 1042 408 a f ) +insert ( 11459 19 1043 1401 a f ) +insert ( 11460 25 18 944 a f ) +insert ( 11461 1042 18 944 a f ) +insert ( 11462 1043 18 944 a f ) +insert ( 11463 25 19 407 i f ) +insert ( 11464 1042 19 409 i f ) +insert ( 11465 1043 19 1400 i f ) +insert ( 11466 18 23 77 e f ) +insert ( 11467 23 18 78 e f ) +insert ( 11468 194 25 0 i b ) +insert ( 11469 3361 17 0 i b ) +insert ( 11470 3361 25 0 i i ) +insert ( 11471 3402 17 0 i b ) +insert ( 11472 3402 25 0 i i ) +insert ( 11473 5017 17 0 i b ) +insert ( 11474 5017 25 0 i i ) +insert ( 11475 1082 1114 2024 i f ) +insert ( 11476 1082 1184 1174 i f ) +insert ( 11477 1083 1186 1370 i f ) +insert ( 11478 1083 1266 2047 i f ) +insert ( 11479 1114 1082 2029 a f ) +insert ( 11480 1114 1083 1316 a f ) +insert ( 11481 1114 1184 2028 i f ) +insert ( 11482 1184 1082 1178 a f ) +insert ( 11483 1184 1083 2019 a f ) +insert ( 11484 1184 1114 2027 a f ) +insert ( 11485 1184 1266 1388 a f ) +insert ( 11486 1186 1083 1419 a f ) +insert ( 11487 1266 1083 2046 a f ) +insert ( 11488 600 603 4091 a f ) +insert ( 11489 601 600 1532 e f ) +insert ( 11490 602 600 1533 e f ) +insert ( 11491 602 604 1449 a f ) +insert ( 11492 603 600 1534 e f ) +insert ( 11493 603 601 1541 e f ) +insert ( 11494 603 604 1448 a f ) +insert ( 11495 603 718 1479 e f ) +insert ( 11496 604 600 1540 e f ) +insert ( 11497 604 602 1447 a f ) +insert ( 11498 604 603 1446 e f ) +insert ( 11499 604 718 1474 e f ) +insert ( 11500 718 600 1416 e f ) +insert ( 11501 718 603 1480 e f ) +insert ( 11502 718 604 1544 e f ) +insert ( 11503 829 774 4123 i f ) +insert ( 11504 774 829 4124 i f ) +insert ( 11505 650 869 0 i b ) +insert ( 11506 869 650 1715 a f ) +insert ( 11507 1560 1562 0 i b ) +insert ( 11508 1562 1560 0 i b ) +insert ( 11509 20 1560 2075 e f ) +insert ( 11510 23 1560 1683 e f ) +insert ( 11511 1560 20 2076 e f ) +insert ( 11512 1560 23 1684 e f ) +insert ( 11513 650 25 730 a f ) +insert ( 11514 869 25 730 a f ) +insert ( 11515 16 25 2971 a f ) +insert ( 11516 142 25 0 a b ) +insert ( 11517 25 142 2896 e f ) +insert ( 11518 650 1043 730 a f ) +insert ( 11519 869 1043 730 a f ) +insert ( 11520 16 1043 2971 a f ) +insert ( 11521 142 1043 0 a b ) +insert ( 11522 1043 142 2896 e f ) +insert ( 11523 650 1042 730 a f ) +insert ( 11524 869 1042 730 a f ) +insert ( 11525 16 1042 2971 a f ) +insert ( 11526 142 1042 0 a b ) +insert ( 11527 1042 142 2896 e f ) +insert ( 11528 1042 1042 668 i f ) +insert ( 11529 1043 1043 669 i f ) +insert ( 11530 1083 1083 1968 i f ) +insert ( 11531 1114 1114 1961 i f ) +insert ( 11532 1184 1184 1967 i f ) +insert ( 11533 1186 1186 1200 i f ) +insert ( 11534 1266 1266 1969 i f ) +insert ( 11535 1560 1560 1685 i f ) +insert ( 11536 1562 1562 1687 i f ) +insert ( 11537 1700 1700 1703 i f ) +insert ( 11538 114 3802 0 a i ) +insert ( 11539 3802 114 0 a i ) +insert ( 11540 3802 16 3556 e f ) +insert ( 11541 3802 1700 3449 e f ) +insert ( 11542 3802 21 3450 e f ) +insert ( 11543 3802 23 3451 e f ) +insert ( 11544 3802 20 3452 e f ) +insert ( 11545 3802 700 3453 e f ) +insert ( 11546 3802 701 2580 e f ) +close pg_cast +create pg_enum 3501 + ( + oid = oid , + enumtypid = oid , + enumsortorder = float4 , + enumlabel = name + ) +open pg_enum +close pg_enum +create pg_namespace 2615 + ( + oid = oid , + nspname = name , + nspowner = oid , + nspacl = _aclitem + ) +open pg_namespace +insert ( 11 pg_catalog 10 _null_ ) +insert ( 99 pg_toast 10 _null_ ) +insert ( 2200 public 10 _null_ ) +close pg_namespace +create pg_conversion 2607 + ( + oid = oid , + conname = name , + connamespace = oid , + conowner = oid , + conforencoding = int4 , + contoencoding = int4 , + conproc = regproc , + condefault = bool + ) +open pg_conversion +insert ( 4402 koi8_r_to_mic 11 10 22 7 4302 t ) +insert ( 4403 mic_to_koi8_r 11 10 7 22 4303 t ) +insert ( 4404 iso_8859_5_to_mic 11 10 25 7 4304 t ) +insert ( 4405 mic_to_iso_8859_5 11 10 7 25 4305 t ) +insert ( 4406 windows_1251_to_mic 11 10 23 7 4306 t ) +insert ( 4407 mic_to_windows_1251 11 10 7 23 4307 t ) +insert ( 4408 windows_866_to_mic 11 10 20 7 4308 t ) +insert ( 4409 mic_to_windows_866 11 10 7 20 4309 t ) +insert ( 4410 koi8_r_to_windows_1251 11 10 22 23 4310 t ) +insert ( 4411 windows_1251_to_koi8_r 11 10 23 22 4311 t ) +insert ( 4412 koi8_r_to_windows_866 11 10 22 20 4312 t ) +insert ( 4413 windows_866_to_koi8_r 11 10 20 22 4313 t ) +insert ( 4414 windows_866_to_windows_1251 11 10 20 23 4314 t ) +insert ( 4415 windows_1251_to_windows_866 11 10 23 20 4315 t ) +insert ( 4416 iso_8859_5_to_koi8_r 11 10 25 22 4316 t ) +insert ( 4417 koi8_r_to_iso_8859_5 11 10 22 25 4317 t ) +insert ( 4418 iso_8859_5_to_windows_1251 11 10 25 23 4318 t ) +insert ( 4419 windows_1251_to_iso_8859_5 11 10 23 25 4319 t ) +insert ( 4420 iso_8859_5_to_windows_866 11 10 25 20 4320 t ) +insert ( 4421 windows_866_to_iso_8859_5 11 10 20 25 4321 t ) +insert ( 4422 euc_cn_to_mic 11 10 2 7 4322 t ) +insert ( 4423 mic_to_euc_cn 11 10 7 2 4323 t ) +insert ( 4424 euc_jp_to_sjis 11 10 1 35 4324 t ) +insert ( 4425 sjis_to_euc_jp 11 10 35 1 4325 t ) +insert ( 4426 euc_jp_to_mic 11 10 1 7 4326 t ) +insert ( 4427 sjis_to_mic 11 10 35 7 4327 t ) +insert ( 4428 mic_to_euc_jp 11 10 7 1 4328 t ) +insert ( 4429 mic_to_sjis 11 10 7 35 4329 t ) +insert ( 4430 euc_kr_to_mic 11 10 3 7 4330 t ) +insert ( 4431 mic_to_euc_kr 11 10 7 3 4331 t ) +insert ( 4432 euc_tw_to_big5 11 10 4 36 4332 t ) +insert ( 4433 big5_to_euc_tw 11 10 36 4 4333 t ) +insert ( 4434 euc_tw_to_mic 11 10 4 7 4334 t ) +insert ( 4435 big5_to_mic 11 10 36 7 4335 t ) +insert ( 4436 mic_to_euc_tw 11 10 7 4 4336 t ) +insert ( 4437 mic_to_big5 11 10 7 36 4337 t ) +insert ( 4438 iso_8859_2_to_mic 11 10 9 7 4338 t ) +insert ( 4439 mic_to_iso_8859_2 11 10 7 9 4339 t ) +insert ( 4440 windows_1250_to_mic 11 10 29 7 4340 t ) +insert ( 4441 mic_to_windows_1250 11 10 7 29 4341 t ) +insert ( 4442 iso_8859_2_to_windows_1250 11 10 9 29 4342 t ) +insert ( 4443 windows_1250_to_iso_8859_2 11 10 29 9 4343 t ) +insert ( 4444 iso_8859_1_to_mic 11 10 8 7 4344 t ) +insert ( 4445 mic_to_iso_8859_1 11 10 7 8 4345 t ) +insert ( 4446 iso_8859_3_to_mic 11 10 10 7 4346 t ) +insert ( 4447 mic_to_iso_8859_3 11 10 7 10 4347 t ) +insert ( 4448 iso_8859_4_to_mic 11 10 11 7 4348 t ) +insert ( 4449 mic_to_iso_8859_4 11 10 7 11 4349 t ) +insert ( 4452 big5_to_utf8 11 10 36 6 4352 t ) +insert ( 4453 utf8_to_big5 11 10 6 36 4353 t ) +insert ( 4454 utf8_to_koi8_r 11 10 6 22 4354 t ) +insert ( 4455 koi8_r_to_utf8 11 10 22 6 4355 t ) +insert ( 4456 utf8_to_koi8_u 11 10 6 34 4356 t ) +insert ( 4457 koi8_u_to_utf8 11 10 34 6 4357 t ) +insert ( 4458 utf8_to_windows_866 11 10 6 20 4358 t ) +insert ( 4459 windows_866_to_utf8 11 10 20 6 4359 t ) +insert ( 4460 utf8_to_windows_874 11 10 6 21 4358 t ) +insert ( 4461 windows_874_to_utf8 11 10 21 6 4359 t ) +insert ( 4462 utf8_to_windows_1250 11 10 6 29 4358 t ) +insert ( 4463 windows_1250_to_utf8 11 10 29 6 4359 t ) +insert ( 4464 utf8_to_windows_1251 11 10 6 23 4358 t ) +insert ( 4465 windows_1251_to_utf8 11 10 23 6 4359 t ) +insert ( 4466 utf8_to_windows_1252 11 10 6 24 4358 t ) +insert ( 4467 windows_1252_to_utf8 11 10 24 6 4359 t ) +insert ( 4468 utf8_to_windows_1253 11 10 6 30 4358 t ) +insert ( 4469 windows_1253_to_utf8 11 10 30 6 4359 t ) +insert ( 4470 utf8_to_windows_1254 11 10 6 31 4358 t ) +insert ( 4471 windows_1254_to_utf8 11 10 31 6 4359 t ) +insert ( 4472 utf8_to_windows_1255 11 10 6 32 4358 t ) +insert ( 4473 windows_1255_to_utf8 11 10 32 6 4359 t ) +insert ( 4474 utf8_to_windows_1256 11 10 6 18 4358 t ) +insert ( 4475 windows_1256_to_utf8 11 10 18 6 4359 t ) +insert ( 4476 utf8_to_windows_1257 11 10 6 33 4358 t ) +insert ( 4477 windows_1257_to_utf8 11 10 33 6 4359 t ) +insert ( 4478 utf8_to_windows_1258 11 10 6 19 4358 t ) +insert ( 4479 windows_1258_to_utf8 11 10 19 6 4359 t ) +insert ( 4480 euc_cn_to_utf8 11 10 2 6 4360 t ) +insert ( 4481 utf8_to_euc_cn 11 10 6 2 4361 t ) +insert ( 4482 euc_jp_to_utf8 11 10 1 6 4362 t ) +insert ( 4483 utf8_to_euc_jp 11 10 6 1 4363 t ) +insert ( 4484 euc_kr_to_utf8 11 10 3 6 4364 t ) +insert ( 4485 utf8_to_euc_kr 11 10 6 3 4365 t ) +insert ( 4486 euc_tw_to_utf8 11 10 4 6 4366 t ) +insert ( 4487 utf8_to_euc_tw 11 10 6 4 4367 t ) +insert ( 4488 gb18030_to_utf8 11 10 39 6 4368 t ) +insert ( 4489 utf8_to_gb18030 11 10 6 39 4369 t ) +insert ( 4490 gbk_to_utf8 11 10 37 6 4370 t ) +insert ( 4491 utf8_to_gbk 11 10 6 37 4371 t ) +insert ( 4492 utf8_to_iso_8859_2 11 10 6 9 4372 t ) +insert ( 4493 iso_8859_2_to_utf8 11 10 9 6 4373 t ) +insert ( 4494 utf8_to_iso_8859_3 11 10 6 10 4372 t ) +insert ( 4495 iso_8859_3_to_utf8 11 10 10 6 4373 t ) +insert ( 4496 utf8_to_iso_8859_4 11 10 6 11 4372 t ) +insert ( 4497 iso_8859_4_to_utf8 11 10 11 6 4373 t ) +insert ( 4498 utf8_to_iso_8859_9 11 10 6 12 4372 t ) +insert ( 4499 iso_8859_9_to_utf8 11 10 12 6 4373 t ) +insert ( 4500 utf8_to_iso_8859_10 11 10 6 13 4372 t ) +insert ( 4501 iso_8859_10_to_utf8 11 10 13 6 4373 t ) +insert ( 4502 utf8_to_iso_8859_13 11 10 6 14 4372 t ) +insert ( 4503 iso_8859_13_to_utf8 11 10 14 6 4373 t ) +insert ( 4504 utf8_to_iso_8859_14 11 10 6 15 4372 t ) +insert ( 4505 iso_8859_14_to_utf8 11 10 15 6 4373 t ) +insert ( 4506 utf8_to_iso_8859_15 11 10 6 16 4372 t ) +insert ( 4507 iso_8859_15_to_utf8 11 10 16 6 4373 t ) +insert ( 4508 utf8_to_iso_8859_16 11 10 6 17 4372 t ) +insert ( 4509 iso_8859_16_to_utf8 11 10 17 6 4373 t ) +insert ( 4510 utf8_to_iso_8859_5 11 10 6 25 4372 t ) +insert ( 4511 iso_8859_5_to_utf8 11 10 25 6 4373 t ) +insert ( 4512 utf8_to_iso_8859_6 11 10 6 26 4372 t ) +insert ( 4513 iso_8859_6_to_utf8 11 10 26 6 4373 t ) +insert ( 4514 utf8_to_iso_8859_7 11 10 6 27 4372 t ) +insert ( 4515 iso_8859_7_to_utf8 11 10 27 6 4373 t ) +insert ( 4516 utf8_to_iso_8859_8 11 10 6 28 4372 t ) +insert ( 4517 iso_8859_8_to_utf8 11 10 28 6 4373 t ) +insert ( 4518 iso_8859_1_to_utf8 11 10 8 6 4374 t ) +insert ( 4519 utf8_to_iso_8859_1 11 10 6 8 4375 t ) +insert ( 4520 johab_to_utf8 11 10 40 6 4376 t ) +insert ( 4521 utf8_to_johab 11 10 6 40 4377 t ) +insert ( 4522 sjis_to_utf8 11 10 35 6 4378 t ) +insert ( 4523 utf8_to_sjis 11 10 6 35 4379 t ) +insert ( 4524 uhc_to_utf8 11 10 38 6 4380 t ) +insert ( 4525 utf8_to_uhc 11 10 6 38 4381 t ) +insert ( 4526 euc_jis_2004_to_utf8 11 10 5 6 4382 t ) +insert ( 4527 utf8_to_euc_jis_2004 11 10 6 5 4383 t ) +insert ( 4528 shift_jis_2004_to_utf8 11 10 41 6 4384 t ) +insert ( 4529 utf8_to_shift_jis_2004 11 10 6 41 4385 t ) +insert ( 4530 euc_jis_2004_to_shift_jis_2004 11 10 5 41 4386 t ) +insert ( 4531 shift_jis_2004_to_euc_jis_2004 11 10 41 5 4387 t ) +close pg_conversion +create pg_depend 2608 + ( + classid = oid , + objid = oid , + objsubid = int4 , + refclassid = oid , + refobjid = oid , + refobjsubid = int4 , + deptype = char + ) +open pg_depend +close pg_depend +create pg_database 1262 shared_relation rowtype_oid 1248 + ( + oid = oid , + datname = name , + datdba = oid , + encoding = int4 , + datcollate = name , + datctype = name , + datistemplate = bool , + datallowconn = bool , + datconnlimit = int4 , + datlastsysoid = oid , + datfrozenxid = xid , + datminmxid = xid , + dattablespace = oid , + datacl = _aclitem + ) +open pg_database +insert ( 1 template1 10 ENCODING LC_COLLATE LC_CTYPE t t -1 0 0 1 1663 _null_ ) +close pg_database +create pg_db_role_setting 2964 shared_relation + ( + setdatabase = oid , + setrole = oid , + setconfig = _text + ) +open pg_db_role_setting +close pg_db_role_setting +create pg_tablespace 1213 shared_relation + ( + oid = oid , + spcname = name , + spcowner = oid , + spcacl = _aclitem , + spcoptions = _text + ) +open pg_tablespace +insert ( 1663 pg_default 10 _null_ _null_ ) +insert ( 1664 pg_global 10 _null_ _null_ ) +close pg_tablespace +create pg_authid 1260 shared_relation rowtype_oid 2842 + ( + oid = oid , + rolname = name , + rolsuper = bool , + rolinherit = bool , + rolcreaterole = bool , + rolcreatedb = bool , + rolcanlogin = bool , + rolreplication = bool , + rolbypassrls = bool , + rolconnlimit = int4 , + rolpassword = text , + rolvaliduntil = timestamptz + ) +open pg_authid +insert ( 10 POSTGRES t t t t t t t -1 _null_ _null_ ) +insert ( 3373 pg_monitor f t f f f f f -1 _null_ _null_ ) +insert ( 3374 pg_read_all_settings f t f f f f f -1 _null_ _null_ ) +insert ( 3375 pg_read_all_stats f t f f f f f -1 _null_ _null_ ) +insert ( 3377 pg_stat_scan_tables f t f f f f f -1 _null_ _null_ ) +insert ( 4569 pg_read_server_files f t f f f f f -1 _null_ _null_ ) +insert ( 4570 pg_write_server_files f t f f f f f -1 _null_ _null_ ) +insert ( 4571 pg_execute_server_program f t f f f f f -1 _null_ _null_ ) +insert ( 4200 pg_signal_backend f t f f f f f -1 _null_ _null_ ) +close pg_authid +create pg_auth_members 1261 shared_relation rowtype_oid 2843 + ( + roleid = oid , + member = oid , + grantor = oid , + admin_option = bool + ) +open pg_auth_members +close pg_auth_members +create pg_shdepend 1214 shared_relation + ( + dbid = oid , + classid = oid , + objid = oid , + objsubid = int4 , + refclassid = oid , + refobjid = oid , + deptype = char + ) +open pg_shdepend +close pg_shdepend +create pg_shdescription 2396 shared_relation + ( + objoid = oid , + classoid = oid , + description = text FORCE NOT NULL + ) +open pg_shdescription +insert ( 1 1262 "default template for new databases" ) +close pg_shdescription +create pg_ts_config 3602 + ( + oid = oid , + cfgname = name , + cfgnamespace = oid , + cfgowner = oid , + cfgparser = oid + ) +open pg_ts_config +insert ( 3748 simple 11 10 3722 ) +close pg_ts_config +create pg_ts_config_map 3603 + ( + mapcfg = oid , + maptokentype = int4 , + mapseqno = int4 , + mapdict = oid + ) +open pg_ts_config_map +insert ( 3748 1 1 3765 ) +insert ( 3748 2 1 3765 ) +insert ( 3748 3 1 3765 ) +insert ( 3748 4 1 3765 ) +insert ( 3748 5 1 3765 ) +insert ( 3748 6 1 3765 ) +insert ( 3748 7 1 3765 ) +insert ( 3748 8 1 3765 ) +insert ( 3748 9 1 3765 ) +insert ( 3748 10 1 3765 ) +insert ( 3748 11 1 3765 ) +insert ( 3748 15 1 3765 ) +insert ( 3748 16 1 3765 ) +insert ( 3748 17 1 3765 ) +insert ( 3748 18 1 3765 ) +insert ( 3748 19 1 3765 ) +insert ( 3748 20 1 3765 ) +insert ( 3748 21 1 3765 ) +insert ( 3748 22 1 3765 ) +close pg_ts_config_map +create pg_ts_dict 3600 + ( + oid = oid , + dictname = name , + dictnamespace = oid , + dictowner = oid , + dicttemplate = oid , + dictinitoption = text + ) +open pg_ts_dict +insert ( 3765 simple 11 10 3727 _null_ ) +close pg_ts_dict +create pg_ts_parser 3601 + ( + oid = oid , + prsname = name , + prsnamespace = oid , + prsstart = regproc , + prstoken = regproc , + prsend = regproc , + prsheadline = regproc , + prslextype = regproc + ) +open pg_ts_parser +insert ( 3722 default 11 3717 3718 3719 3720 3721 ) +close pg_ts_parser +create pg_ts_template 3764 + ( + oid = oid , + tmplname = name , + tmplnamespace = oid , + tmplinit = regproc , + tmpllexize = regproc + ) +open pg_ts_template +insert ( 3727 simple 11 3725 3726 ) +insert ( 3730 synonym 11 3728 3729 ) +insert ( 3733 ispell 11 3731 3732 ) +insert ( 3742 thesaurus 11 3740 3741 ) +close pg_ts_template +create pg_extension 3079 + ( + oid = oid , + extname = name , + extowner = oid , + extnamespace = oid , + extrelocatable = bool , + extversion = text FORCE NOT NULL , + extconfig = _oid , + extcondition = _text + ) +open pg_extension +close pg_extension +create pg_foreign_data_wrapper 2328 + ( + oid = oid , + fdwname = name , + fdwowner = oid , + fdwhandler = oid , + fdwvalidator = oid , + fdwacl = _aclitem , + fdwoptions = _text + ) +open pg_foreign_data_wrapper +close pg_foreign_data_wrapper +create pg_foreign_server 1417 + ( + oid = oid , + srvname = name , + srvowner = oid , + srvfdw = oid , + srvtype = text , + srvversion = text , + srvacl = _aclitem , + srvoptions = _text + ) +open pg_foreign_server +close pg_foreign_server +create pg_user_mapping 1418 + ( + oid = oid , + umuser = oid , + umserver = oid , + umoptions = _text + ) +open pg_user_mapping +close pg_user_mapping +create pg_foreign_table 3118 + ( + ftrelid = oid , + ftserver = oid , + ftoptions = _text + ) +open pg_foreign_table +close pg_foreign_table +create pg_policy 3256 + ( + oid = oid , + polname = name , + polrelid = oid , + polcmd = char , + polpermissive = bool , + polroles = _oid FORCE NOT NULL , + polqual = pg_node_tree , + polwithcheck = pg_node_tree + ) +open pg_policy +close pg_policy +create pg_replication_origin 6000 shared_relation + ( + roident = oid , + roname = text FORCE NOT NULL + ) +open pg_replication_origin +close pg_replication_origin +create pg_default_acl 826 + ( + oid = oid , + defaclrole = oid , + defaclnamespace = oid , + defaclobjtype = char , + defaclacl = _aclitem FORCE NOT NULL + ) +open pg_default_acl +close pg_default_acl +create pg_init_privs 3394 + ( + objoid = oid , + classoid = oid , + objsubid = int4 , + privtype = char , + initprivs = _aclitem FORCE NOT NULL + ) +open pg_init_privs +close pg_init_privs +create pg_seclabel 3596 + ( + objoid = oid , + classoid = oid , + objsubid = int4 , + provider = text FORCE NOT NULL , + label = text FORCE NOT NULL + ) +open pg_seclabel +close pg_seclabel +create pg_shseclabel 3592 shared_relation rowtype_oid 4066 + ( + objoid = oid , + classoid = oid , + provider = text FORCE NOT NULL , + label = text FORCE NOT NULL + ) +open pg_shseclabel +close pg_shseclabel +create pg_collation 3456 + ( + oid = oid , + collname = name , + collnamespace = oid , + collowner = oid , + collprovider = char , + collisdeterministic = bool , + collencoding = int4 , + collcollate = name , + collctype = name , + collversion = text + ) +open pg_collation +insert ( 100 default 11 10 d t -1 "" "" _null_ ) +insert ( 950 C 11 10 c t -1 C C _null_ ) +insert ( 951 POSIX 11 10 c t -1 POSIX POSIX _null_ ) +close pg_collation +create pg_partitioned_table 3350 + ( + partrelid = oid , + partstrat = char , + partnatts = int2 , + partdefid = oid , + partattrs = int2vector , + partclass = oidvector , + partcollation = oidvector , + partexprs = pg_node_tree + ) +open pg_partitioned_table +close pg_partitioned_table +create pg_range 3541 + ( + rngtypid = oid , + rngsubtype = oid , + rngcollation = oid , + rngsubopc = oid , + rngcanonical = regproc , + rngsubdiff = regproc + ) +open pg_range +insert ( 3904 23 0 1978 3914 3922 ) +insert ( 3906 1700 0 3125 - 3924 ) +insert ( 3908 1114 0 3128 - 3929 ) +insert ( 3910 1184 0 3127 - 3930 ) +insert ( 3912 1082 0 3122 3915 3925 ) +insert ( 3926 20 0 3124 3928 3923 ) +close pg_range +create pg_transform 3576 + ( + oid = oid , + trftype = oid , + trflang = oid , + trffromsql = regproc , + trftosql = regproc + ) +open pg_transform +close pg_transform +create pg_sequence 2224 + ( + seqrelid = oid , + seqtypid = oid , + seqstart = int8 , + seqincrement = int8 , + seqmax = int8 , + seqmin = int8 , + seqcache = int8 , + seqcycle = bool + ) +open pg_sequence +close pg_sequence +create pg_publication 6104 + ( + oid = oid , + pubname = name , + pubowner = oid , + puballtables = bool , + pubinsert = bool , + pubupdate = bool , + pubdelete = bool , + pubtruncate = bool , + pubviaroot = bool + ) +open pg_publication +close pg_publication +create pg_publication_rel 6106 + ( + oid = oid , + prpubid = oid , + prrelid = oid + ) +open pg_publication_rel +close pg_publication_rel +create pg_subscription 6100 shared_relation rowtype_oid 6101 + ( + oid = oid , + subdbid = oid , + subname = name , + subowner = oid , + subenabled = bool , + subconninfo = text FORCE NOT NULL , + subslotname = name FORCE NULL , + subsynccommit = text FORCE NOT NULL , + subpublications = _text FORCE NOT NULL + ) +open pg_subscription +close pg_subscription +create pg_subscription_rel 6102 + ( + srsubid = oid , + srrelid = oid , + srsubstate = char , + srsublsn = pg_lsn FORCE NULL + ) +open pg_subscription_rel +close pg_subscription_rel +declare toast 4159 4160 on pg_aggregate +declare toast 2830 2831 on pg_attrdef +declare toast 4161 4162 on pg_collation +declare toast 2832 2833 on pg_constraint +declare toast 4143 4144 on pg_default_acl +declare toast 2834 2835 on pg_description +declare toast 4145 4146 on pg_event_trigger +declare toast 4147 4148 on pg_extension +declare toast 4149 4150 on pg_foreign_data_wrapper +declare toast 4151 4152 on pg_foreign_server +declare toast 4153 4154 on pg_foreign_table +declare toast 4155 4156 on pg_init_privs +declare toast 4157 4158 on pg_language +declare toast 4163 4164 on pg_namespace +declare toast 4165 4166 on pg_partitioned_table +declare toast 4167 4168 on pg_policy +declare toast 2836 2837 on pg_proc +declare toast 2838 2839 on pg_rewrite +declare toast 3598 3599 on pg_seclabel +declare toast 2840 2841 on pg_statistic +declare toast 3439 3440 on pg_statistic_ext +declare toast 3430 3431 on pg_statistic_ext_data +declare toast 2336 2337 on pg_trigger +declare toast 4169 4170 on pg_ts_dict +declare toast 4171 4172 on pg_type +declare toast 4173 4174 on pg_user_mapping +declare toast 4175 4176 on pg_authid +declare toast 4177 4178 on pg_database +declare toast 2966 2967 on pg_db_role_setting +declare toast 4181 4182 on pg_replication_origin +declare toast 2846 2847 on pg_shdescription +declare toast 4060 4061 on pg_shseclabel +declare toast 4183 4184 on pg_subscription +declare toast 4185 4186 on pg_tablespace +declare unique index pg_aggregate_fnoid_index 2650 on pg_aggregate using btree(aggfnoid oid_ops) +declare unique index pg_am_name_index 2651 on pg_am using btree(amname name_ops) +declare unique index pg_am_oid_index 2652 on pg_am using btree(oid oid_ops) +declare unique index pg_amop_fam_strat_index 2653 on pg_amop using btree(amopfamily oid_ops, amoplefttype oid_ops, amoprighttype oid_ops, amopstrategy int2_ops) +declare unique index pg_amop_opr_fam_index 2654 on pg_amop using btree(amopopr oid_ops, amoppurpose char_ops, amopfamily oid_ops) +declare unique index pg_amop_oid_index 2756 on pg_amop using btree(oid oid_ops) +declare unique index pg_amproc_fam_proc_index 2655 on pg_amproc using btree(amprocfamily oid_ops, amproclefttype oid_ops, amprocrighttype oid_ops, amprocnum int2_ops) +declare unique index pg_amproc_oid_index 2757 on pg_amproc using btree(oid oid_ops) +declare unique index pg_attrdef_adrelid_adnum_index 2656 on pg_attrdef using btree(adrelid oid_ops, adnum int2_ops) +declare unique index pg_attrdef_oid_index 2657 on pg_attrdef using btree(oid oid_ops) +declare unique index pg_attribute_relid_attnam_index 2658 on pg_attribute using btree(attrelid oid_ops, attname name_ops) +declare unique index pg_attribute_relid_attnum_index 2659 on pg_attribute using btree(attrelid oid_ops, attnum int2_ops) +declare unique index pg_authid_rolname_index 2676 on pg_authid using btree(rolname name_ops) +declare unique index pg_authid_oid_index 2677 on pg_authid using btree(oid oid_ops) +declare unique index pg_auth_members_role_member_index 2694 on pg_auth_members using btree(roleid oid_ops, member oid_ops) +declare unique index pg_auth_members_member_role_index 2695 on pg_auth_members using btree(member oid_ops, roleid oid_ops) +declare unique index pg_cast_oid_index 2660 on pg_cast using btree(oid oid_ops) +declare unique index pg_cast_source_target_index 2661 on pg_cast using btree(castsource oid_ops, casttarget oid_ops) +declare unique index pg_class_oid_index 2662 on pg_class using btree(oid oid_ops) +declare unique index pg_class_relname_nsp_index 2663 on pg_class using btree(relname name_ops, relnamespace oid_ops) +declare index pg_class_tblspc_relfilenode_index 3455 on pg_class using btree(reltablespace oid_ops, relfilenode oid_ops) +declare unique index pg_collation_name_enc_nsp_index 3164 on pg_collation using btree(collname name_ops, collencoding int4_ops, collnamespace oid_ops) +declare unique index pg_collation_oid_index 3085 on pg_collation using btree(oid oid_ops) +declare index pg_constraint_conname_nsp_index 2664 on pg_constraint using btree(conname name_ops, connamespace oid_ops) +declare unique index pg_constraint_conrelid_contypid_conname_index 2665 on pg_constraint using btree(conrelid oid_ops, contypid oid_ops, conname name_ops) +declare index pg_constraint_contypid_index 2666 on pg_constraint using btree(contypid oid_ops) +declare unique index pg_constraint_oid_index 2667 on pg_constraint using btree(oid oid_ops) +declare index pg_constraint_conparentid_index 2579 on pg_constraint using btree(conparentid oid_ops) +declare unique index pg_conversion_default_index 2668 on pg_conversion using btree(connamespace oid_ops, conforencoding int4_ops, contoencoding int4_ops, oid oid_ops) +declare unique index pg_conversion_name_nsp_index 2669 on pg_conversion using btree(conname name_ops, connamespace oid_ops) +declare unique index pg_conversion_oid_index 2670 on pg_conversion using btree(oid oid_ops) +declare unique index pg_database_datname_index 2671 on pg_database using btree(datname name_ops) +declare unique index pg_database_oid_index 2672 on pg_database using btree(oid oid_ops) +declare index pg_depend_depender_index 2673 on pg_depend using btree(classid oid_ops, objid oid_ops, objsubid int4_ops) +declare index pg_depend_reference_index 2674 on pg_depend using btree(refclassid oid_ops, refobjid oid_ops, refobjsubid int4_ops) +declare unique index pg_description_o_c_o_index 2675 on pg_description using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops) +declare unique index pg_shdescription_o_c_index 2397 on pg_shdescription using btree(objoid oid_ops, classoid oid_ops) +declare unique index pg_enum_oid_index 3502 on pg_enum using btree(oid oid_ops) +declare unique index pg_enum_typid_label_index 3503 on pg_enum using btree(enumtypid oid_ops, enumlabel name_ops) +declare unique index pg_enum_typid_sortorder_index 3534 on pg_enum using btree(enumtypid oid_ops, enumsortorder float4_ops) +declare index pg_index_indrelid_index 2678 on pg_index using btree(indrelid oid_ops) +declare unique index pg_index_indexrelid_index 2679 on pg_index using btree(indexrelid oid_ops) +declare unique index pg_inherits_relid_seqno_index 2680 on pg_inherits using btree(inhrelid oid_ops, inhseqno int4_ops) +declare index pg_inherits_parent_index 2187 on pg_inherits using btree(inhparent oid_ops) +declare unique index pg_init_privs_o_c_o_index 3395 on pg_init_privs using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops) +declare unique index pg_language_name_index 2681 on pg_language using btree(lanname name_ops) +declare unique index pg_language_oid_index 2682 on pg_language using btree(oid oid_ops) +declare unique index pg_largeobject_loid_pn_index 2683 on pg_largeobject using btree(loid oid_ops, pageno int4_ops) +declare unique index pg_largeobject_metadata_oid_index 2996 on pg_largeobject_metadata using btree(oid oid_ops) +declare unique index pg_namespace_nspname_index 2684 on pg_namespace using btree(nspname name_ops) +declare unique index pg_namespace_oid_index 2685 on pg_namespace using btree(oid oid_ops) +declare unique index pg_opclass_am_name_nsp_index 2686 on pg_opclass using btree(opcmethod oid_ops, opcname name_ops, opcnamespace oid_ops) +declare unique index pg_opclass_oid_index 2687 on pg_opclass using btree(oid oid_ops) +declare unique index pg_operator_oid_index 2688 on pg_operator using btree(oid oid_ops) +declare unique index pg_operator_oprname_l_r_n_index 2689 on pg_operator using btree(oprname name_ops, oprleft oid_ops, oprright oid_ops, oprnamespace oid_ops) +declare unique index pg_opfamily_am_name_nsp_index 2754 on pg_opfamily using btree(opfmethod oid_ops, opfname name_ops, opfnamespace oid_ops) +declare unique index pg_opfamily_oid_index 2755 on pg_opfamily using btree(oid oid_ops) +declare unique index pg_proc_oid_index 2690 on pg_proc using btree(oid oid_ops) +declare unique index pg_proc_proname_args_nsp_index 2691 on pg_proc using btree(proname name_ops, proargtypes oidvector_ops, pronamespace oid_ops) +declare unique index pg_rewrite_oid_index 2692 on pg_rewrite using btree(oid oid_ops) +declare unique index pg_rewrite_rel_rulename_index 2693 on pg_rewrite using btree(ev_class oid_ops, rulename name_ops) +declare unique index pg_sequence_seqrelid_index 5002 on pg_sequence using btree(seqrelid oid_ops) +declare index pg_shdepend_depender_index 1232 on pg_shdepend using btree(dbid oid_ops, classid oid_ops, objid oid_ops, objsubid int4_ops) +declare index pg_shdepend_reference_index 1233 on pg_shdepend using btree(refclassid oid_ops, refobjid oid_ops) +declare unique index pg_statistic_relid_att_inh_index 2696 on pg_statistic using btree(starelid oid_ops, staattnum int2_ops, stainherit bool_ops) +declare unique index pg_statistic_ext_oid_index 3380 on pg_statistic_ext using btree(oid oid_ops) +declare unique index pg_statistic_ext_name_index 3997 on pg_statistic_ext using btree(stxname name_ops, stxnamespace oid_ops) +declare index pg_statistic_ext_relid_index 3379 on pg_statistic_ext using btree(stxrelid oid_ops) +declare unique index pg_statistic_ext_data_stxoid_index 3433 on pg_statistic_ext_data using btree(stxoid oid_ops) +declare unique index pg_tablespace_oid_index 2697 on pg_tablespace using btree(oid oid_ops) +declare unique index pg_tablespace_spcname_index 2698 on pg_tablespace using btree(spcname name_ops) +declare unique index pg_transform_oid_index 3574 on pg_transform using btree(oid oid_ops) +declare unique index pg_transform_type_lang_index 3575 on pg_transform using btree(trftype oid_ops, trflang oid_ops) +declare index pg_trigger_tgconstraint_index 2699 on pg_trigger using btree(tgconstraint oid_ops) +declare unique index pg_trigger_tgrelid_tgname_index 2701 on pg_trigger using btree(tgrelid oid_ops, tgname name_ops) +declare unique index pg_trigger_oid_index 2702 on pg_trigger using btree(oid oid_ops) +declare unique index pg_event_trigger_evtname_index 3467 on pg_event_trigger using btree(evtname name_ops) +declare unique index pg_event_trigger_oid_index 3468 on pg_event_trigger using btree(oid oid_ops) +declare unique index pg_ts_config_cfgname_index 3608 on pg_ts_config using btree(cfgname name_ops, cfgnamespace oid_ops) +declare unique index pg_ts_config_oid_index 3712 on pg_ts_config using btree(oid oid_ops) +declare unique index pg_ts_config_map_index 3609 on pg_ts_config_map using btree(mapcfg oid_ops, maptokentype int4_ops, mapseqno int4_ops) +declare unique index pg_ts_dict_dictname_index 3604 on pg_ts_dict using btree(dictname name_ops, dictnamespace oid_ops) +declare unique index pg_ts_dict_oid_index 3605 on pg_ts_dict using btree(oid oid_ops) +declare unique index pg_ts_parser_prsname_index 3606 on pg_ts_parser using btree(prsname name_ops, prsnamespace oid_ops) +declare unique index pg_ts_parser_oid_index 3607 on pg_ts_parser using btree(oid oid_ops) +declare unique index pg_ts_template_tmplname_index 3766 on pg_ts_template using btree(tmplname name_ops, tmplnamespace oid_ops) +declare unique index pg_ts_template_oid_index 3767 on pg_ts_template using btree(oid oid_ops) +declare unique index pg_type_oid_index 2703 on pg_type using btree(oid oid_ops) +declare unique index pg_type_typname_nsp_index 2704 on pg_type using btree(typname name_ops, typnamespace oid_ops) +declare unique index pg_foreign_data_wrapper_oid_index 112 on pg_foreign_data_wrapper using btree(oid oid_ops) +declare unique index pg_foreign_data_wrapper_name_index 548 on pg_foreign_data_wrapper using btree(fdwname name_ops) +declare unique index pg_foreign_server_oid_index 113 on pg_foreign_server using btree(oid oid_ops) +declare unique index pg_foreign_server_name_index 549 on pg_foreign_server using btree(srvname name_ops) +declare unique index pg_user_mapping_oid_index 174 on pg_user_mapping using btree(oid oid_ops) +declare unique index pg_user_mapping_user_server_index 175 on pg_user_mapping using btree(umuser oid_ops, umserver oid_ops) +declare unique index pg_foreign_table_relid_index 3119 on pg_foreign_table using btree(ftrelid oid_ops) +declare unique index pg_default_acl_role_nsp_obj_index 827 on pg_default_acl using btree(defaclrole oid_ops, defaclnamespace oid_ops, defaclobjtype char_ops) +declare unique index pg_default_acl_oid_index 828 on pg_default_acl using btree(oid oid_ops) +declare unique index pg_db_role_setting_databaseid_rol_index 2965 on pg_db_role_setting using btree(setdatabase oid_ops, setrole oid_ops) +declare unique index pg_seclabel_object_index 3597 on pg_seclabel using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops, provider text_ops) +declare unique index pg_shseclabel_object_index 3593 on pg_shseclabel using btree(objoid oid_ops, classoid oid_ops, provider text_ops) +declare unique index pg_extension_oid_index 3080 on pg_extension using btree(oid oid_ops) +declare unique index pg_extension_name_index 3081 on pg_extension using btree(extname name_ops) +declare unique index pg_range_rngtypid_index 3542 on pg_range using btree(rngtypid oid_ops) +declare unique index pg_policy_oid_index 3257 on pg_policy using btree(oid oid_ops) +declare unique index pg_policy_polrelid_polname_index 3258 on pg_policy using btree(polrelid oid_ops, polname name_ops) +declare unique index pg_replication_origin_roiident_index 6001 on pg_replication_origin using btree(roident oid_ops) +declare unique index pg_replication_origin_roname_index 6002 on pg_replication_origin using btree(roname text_ops) +declare unique index pg_partitioned_table_partrelid_index 3351 on pg_partitioned_table using btree(partrelid oid_ops) +declare unique index pg_publication_oid_index 6110 on pg_publication using btree(oid oid_ops) +declare unique index pg_publication_pubname_index 6111 on pg_publication using btree(pubname name_ops) +declare unique index pg_publication_rel_oid_index 6112 on pg_publication_rel using btree(oid oid_ops) +declare unique index pg_publication_rel_prrelid_prpubid_index 6113 on pg_publication_rel using btree(prrelid oid_ops, prpubid oid_ops) +declare unique index pg_subscription_oid_index 6114 on pg_subscription using btree(oid oid_ops) +declare unique index pg_subscription_subname_index 6115 on pg_subscription using btree(subdbid oid_ops, subname name_ops) +declare unique index pg_subscription_rel_srrelid_srsubid_index 6117 on pg_subscription_rel using btree(srrelid oid_ops, srsubid oid_ops) +build indices diff --git a/src/backend/catalog/schemapg.h b/src/backend/catalog/schemapg.h new file mode 100644 index 0000000..0069a35 --- /dev/null +++ b/src/backend/catalog/schemapg.h @@ -0,0 +1,222 @@ +/*------------------------------------------------------------------------- + * + * schemapg.h + * Schema_pg_xxx macros for use by relcache.c + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef SCHEMAPG_H +#define SCHEMAPG_H + +#define Schema_pg_proc \ +{ 1255, {"oid"}, 26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"proname"}, 19, -1, NAMEDATALEN, 2, 0, -1, -1, false, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 1255, {"pronamespace"}, 26, -1, 4, 3, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"proowner"}, 26, -1, 4, 4, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"prolang"}, 26, -1, 4, 5, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"procost"}, 700, -1, 4, 6, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"prorows"}, 700, -1, 4, 7, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"provariadic"}, 26, -1, 4, 8, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"prosupport"}, 24, -1, 4, 9, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"prokind"}, 18, -1, 1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"prosecdef"}, 16, -1, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"proleakproof"}, 16, -1, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"proisstrict"}, 16, -1, 1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"proretset"}, 16, -1, 1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"provolatile"}, 18, -1, 1, 15, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"proparallel"}, 18, -1, 1, 16, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"pronargs"}, 21, -1, 2, 17, 0, -1, -1, true, 'p', 's', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"pronargdefaults"}, 21, -1, 2, 18, 0, -1, -1, true, 'p', 's', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"prorettype"}, 26, -1, 4, 19, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"proargtypes"}, 30, -1, -1, 20, 1, -1, -1, false, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"proallargtypes"}, 1028, -1, -1, 21, 1, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"proargmodes"}, 1002, -1, -1, 22, 1, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"proargnames"}, 1009, -1, -1, 23, 1, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 1255, {"proargdefaults"}, 194, -1, -1, 24, 0, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 1255, {"protrftypes"}, 1028, -1, -1, 25, 1, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1255, {"prosrc"}, 25, -1, -1, 26, 0, -1, -1, false, 'x', 'i', true, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 1255, {"probin"}, 25, -1, -1, 27, 0, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 1255, {"proconfig"}, 1009, -1, -1, 28, 1, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 1255, {"proacl"}, 1034, -1, -1, 29, 1, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 0 } + +#define Schema_pg_type \ +{ 1247, {"oid"}, 26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typname"}, 19, -1, NAMEDATALEN, 2, 0, -1, -1, false, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 1247, {"typnamespace"}, 26, -1, 4, 3, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typowner"}, 26, -1, 4, 4, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typlen"}, 21, -1, 2, 5, 0, -1, -1, true, 'p', 's', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typbyval"}, 16, -1, 1, 6, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typtype"}, 18, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typcategory"}, 18, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typispreferred"}, 16, -1, 1, 9, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typisdefined"}, 16, -1, 1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typdelim"}, 18, -1, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typrelid"}, 26, -1, 4, 12, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typelem"}, 26, -1, 4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typarray"}, 26, -1, 4, 14, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typinput"}, 24, -1, 4, 15, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typoutput"}, 24, -1, 4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typreceive"}, 24, -1, 4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typsend"}, 24, -1, 4, 18, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typmodin"}, 24, -1, 4, 19, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typmodout"}, 24, -1, 4, 20, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typanalyze"}, 24, -1, 4, 21, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typalign"}, 18, -1, 1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typstorage"}, 18, -1, 1, 23, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typnotnull"}, 16, -1, 1, 24, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typbasetype"}, 26, -1, 4, 25, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typtypmod"}, 23, -1, 4, 26, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typndims"}, 23, -1, 4, 27, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typcollation"}, 26, -1, 4, 28, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1247, {"typdefaultbin"}, 194, -1, -1, 29, 0, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 1247, {"typdefault"}, 25, -1, -1, 30, 0, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 1247, {"typacl"}, 1034, -1, -1, 31, 1, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 0 } + +#define Schema_pg_attribute \ +{ 1249, {"attrelid"}, 26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"attname"}, 19, -1, NAMEDATALEN, 2, 0, -1, -1, false, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 1249, {"atttypid"}, 26, -1, 4, 3, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"attstattarget"}, 23, -1, 4, 4, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"attlen"}, 21, -1, 2, 5, 0, -1, -1, true, 'p', 's', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"attnum"}, 21, -1, 2, 6, 0, -1, -1, true, 'p', 's', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"attndims"}, 23, -1, 4, 7, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"attcacheoff"}, 23, -1, 4, 8, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"atttypmod"}, 23, -1, 4, 9, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"attbyval"}, 16, -1, 1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"attstorage"}, 18, -1, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"attalign"}, 18, -1, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"attnotnull"}, 16, -1, 1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"atthasdef"}, 16, -1, 1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"atthasmissing"}, 16, -1, 1, 15, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"attidentity"}, 18, -1, 1, 16, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"attgenerated"}, 18, -1, 1, 17, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"attisdropped"}, 16, -1, 1, 18, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"attislocal"}, 16, -1, 1, 19, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"attinhcount"}, 23, -1, 4, 20, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"attcollation"}, 26, -1, 4, 21, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"attacl"}, 1034, -1, -1, 22, 1, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1249, {"attoptions"}, 1009, -1, -1, 23, 1, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 1249, {"attfdwoptions"}, 1009, -1, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 1249, {"attmissingval"}, 2277, -1, -1, 25, 0, -1, -1, false, 'x', 'd', false, false, false, '\0', '\0', false, true, 0, 0 } + +#define Schema_pg_class \ +{ 1259, {"oid"}, 26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relname"}, 19, -1, NAMEDATALEN, 2, 0, -1, -1, false, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 1259, {"relnamespace"}, 26, -1, 4, 3, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"reltype"}, 26, -1, 4, 4, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"reloftype"}, 26, -1, 4, 5, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relowner"}, 26, -1, 4, 6, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relam"}, 26, -1, 4, 7, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relfilenode"}, 26, -1, 4, 8, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"reltablespace"}, 26, -1, 4, 9, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relpages"}, 23, -1, 4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"reltuples"}, 700, -1, 4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relallvisible"}, 23, -1, 4, 12, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"reltoastrelid"}, 26, -1, 4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relhasindex"}, 16, -1, 1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relisshared"}, 16, -1, 1, 15, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relpersistence"}, 18, -1, 1, 16, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relkind"}, 18, -1, 1, 17, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relnatts"}, 21, -1, 2, 18, 0, -1, -1, true, 'p', 's', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relchecks"}, 21, -1, 2, 19, 0, -1, -1, true, 'p', 's', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relhasrules"}, 16, -1, 1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relhastriggers"}, 16, -1, 1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relhassubclass"}, 16, -1, 1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relrowsecurity"}, 16, -1, 1, 23, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relforcerowsecurity"}, 16, -1, 1, 24, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relispopulated"}, 16, -1, 1, 25, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relreplident"}, 18, -1, 1, 26, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relispartition"}, 16, -1, 1, 27, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relrewrite"}, 26, -1, 4, 28, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relfrozenxid"}, 28, -1, 4, 29, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relminmxid"}, 28, -1, 4, 30, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"relacl"}, 1034, -1, -1, 31, 1, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1259, {"reloptions"}, 1009, -1, -1, 32, 1, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 1259, {"relpartbound"}, 194, -1, -1, 33, 0, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 950 } + +#define Schema_pg_index \ +{ 2610, {"indexrelid"}, 26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 2610, {"indrelid"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 2610, {"indnatts"}, 21, -1, 2, 3, 0, -1, -1, true, 'p', 's', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 2610, {"indnkeyatts"}, 21, -1, 2, 4, 0, -1, -1, true, 'p', 's', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 2610, {"indisunique"}, 16, -1, 1, 5, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 2610, {"indisprimary"}, 16, -1, 1, 6, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 2610, {"indisexclusion"}, 16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 2610, {"indimmediate"}, 16, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 2610, {"indisclustered"}, 16, -1, 1, 9, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 2610, {"indisvalid"}, 16, -1, 1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 2610, {"indcheckxmin"}, 16, -1, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 2610, {"indisready"}, 16, -1, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 2610, {"indislive"}, 16, -1, 1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 2610, {"indisreplident"}, 16, -1, 1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 2610, {"indkey"}, 22, -1, -1, 15, 1, -1, -1, false, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 2610, {"indcollation"}, 30, -1, -1, 16, 1, -1, -1, false, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 2610, {"indclass"}, 30, -1, -1, 17, 1, -1, -1, false, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 2610, {"indoption"}, 22, -1, -1, 18, 1, -1, -1, false, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 2610, {"indexprs"}, 194, -1, -1, 19, 0, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 2610, {"indpred"}, 194, -1, -1, 20, 0, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 950 } + +#define Schema_pg_database \ +{ 1262, {"oid"}, 26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1262, {"datname"}, 19, -1, NAMEDATALEN, 2, 0, -1, -1, false, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 1262, {"datdba"}, 26, -1, 4, 3, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1262, {"encoding"}, 23, -1, 4, 4, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1262, {"datcollate"}, 19, -1, NAMEDATALEN, 5, 0, -1, -1, false, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 1262, {"datctype"}, 19, -1, NAMEDATALEN, 6, 0, -1, -1, false, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 1262, {"datistemplate"}, 16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1262, {"datallowconn"}, 16, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1262, {"datconnlimit"}, 23, -1, 4, 9, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1262, {"datlastsysoid"}, 26, -1, 4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1262, {"datfrozenxid"}, 28, -1, 4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1262, {"datminmxid"}, 28, -1, 4, 12, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1262, {"dattablespace"}, 26, -1, 4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1262, {"datacl"}, 1034, -1, -1, 14, 1, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 0 } + +#define Schema_pg_authid \ +{ 1260, {"oid"}, 26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1260, {"rolname"}, 19, -1, NAMEDATALEN, 2, 0, -1, -1, false, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 1260, {"rolsuper"}, 16, -1, 1, 3, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1260, {"rolinherit"}, 16, -1, 1, 4, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1260, {"rolcreaterole"}, 16, -1, 1, 5, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1260, {"rolcreatedb"}, 16, -1, 1, 6, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1260, {"rolcanlogin"}, 16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1260, {"rolreplication"}, 16, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1260, {"rolbypassrls"}, 16, -1, 1, 9, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1260, {"rolconnlimit"}, 23, -1, 4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1260, {"rolpassword"}, 25, -1, -1, 11, 0, -1, -1, false, 'x', 'i', false, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 1260, {"rolvaliduntil"}, 1184, -1, 8, 12, 0, -1, -1, FLOAT8PASSBYVAL, 'p', 'd', false, false, false, '\0', '\0', false, true, 0, 0 } + +#define Schema_pg_auth_members \ +{ 1261, {"roleid"}, 26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1261, {"member"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1261, {"grantor"}, 26, -1, 4, 3, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 1261, {"admin_option"}, 16, -1, 1, 4, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 } + +#define Schema_pg_shseclabel \ +{ 3592, {"objoid"}, 26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 3592, {"classoid"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 3592, {"provider"}, 25, -1, -1, 3, 0, -1, -1, false, 'x', 'i', true, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 3592, {"label"}, 25, -1, -1, 4, 0, -1, -1, false, 'x', 'i', true, false, false, '\0', '\0', false, true, 0, 950 } + +#define Schema_pg_subscription \ +{ 6100, {"oid"}, 26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 6100, {"subdbid"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 6100, {"subname"}, 19, -1, NAMEDATALEN, 3, 0, -1, -1, false, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 6100, {"subowner"}, 26, -1, 4, 4, 0, -1, -1, true, 'p', 'i', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 6100, {"subenabled"}, 16, -1, 1, 5, 0, -1, -1, true, 'p', 'c', true, false, false, '\0', '\0', false, true, 0, 0 }, \ +{ 6100, {"subconninfo"}, 25, -1, -1, 6, 0, -1, -1, false, 'x', 'i', true, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 6100, {"subslotname"}, 19, -1, NAMEDATALEN, 7, 0, -1, -1, false, 'p', 'c', false, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 6100, {"subsynccommit"}, 25, -1, -1, 8, 0, -1, -1, false, 'x', 'i', true, false, false, '\0', '\0', false, true, 0, 950 }, \ +{ 6100, {"subpublications"}, 1009, -1, -1, 9, 1, -1, -1, false, 'x', 'i', true, false, false, '\0', '\0', false, true, 0, 950 } + +#endif /* SCHEMAPG_H */ diff --git a/src/backend/catalog/sql_feature_packages.txt b/src/backend/catalog/sql_feature_packages.txt new file mode 100644 index 0000000..7c22145 --- /dev/null +++ b/src/backend/catalog/sql_feature_packages.txt @@ -0,0 +1,37 @@ +E011 Core +E021 Core +E031 Core +E051 Core +E061 Core +E071 Core +E081 Core +E091 Core +E101 Core +E111 Core +E121 Core +E131 Core +E141 Core +E151 Core +E152 Core +E153 Core +E161 Core +E171 Core +E182 Core +F021 Core +F031 Core +F041 Core +F051 Core +F081 Core +F131 Core +F181 Core +F201 Core +F221 Core +F261 Core +F311 Core +F471 Core +F481 Core +F501 Core +F812 Core +S011 Core +T321 Core +T631 Core diff --git a/src/backend/catalog/sql_features.txt b/src/backend/catalog/sql_features.txt new file mode 100644 index 0000000..b6e58e8 --- /dev/null +++ b/src/backend/catalog/sql_features.txt @@ -0,0 +1,712 @@ +B011 Embedded Ada NO +B012 Embedded C YES +B013 Embedded COBOL NO +B014 Embedded Fortran NO +B015 Embedded MUMPS NO +B016 Embedded Pascal NO +B017 Embedded PL/I NO +B021 Direct SQL YES +B031 Basic dynamic SQL NO +B032 Extended dynamic SQL NO +B032 Extended dynamic SQL 01 <describe input statement> NO +B033 Untyped SQL-invoked function arguments NO +B034 Dynamic specification of cursor attributes NO +B035 Non-extended descriptor names NO +B041 Extensions to embedded SQL exception declarations NO +B051 Enhanced execution rights NO +B111 Module language Ada NO +B112 Module language C NO +B113 Module language COBOL NO +B114 Module language Fortran NO +B115 Module language MUMPS NO +B116 Module language Pascal NO +B117 Module language PL/I NO +B121 Routine language Ada NO +B122 Routine language C NO +B123 Routine language COBOL NO +B124 Routine language Fortran NO +B125 Routine language MUMPS NO +B126 Routine language Pascal NO +B127 Routine language PL/I NO +B128 Routine language SQL NO +B200 Polymorphic table functions NO +B201 More than one PTF generic table parameter NO +B202 PTF Copartitioning NO +B203 More than one copartition specification NO +B204 PRUNE WHEN EMPTY NO +B205 Pass-through columns NO +B206 PTF descriptor parameters NO +B207 Cross products of partitionings NO +B208 PTF component procedure interface NO +B209 PTF extended names NO +B211 Module language Ada: VARCHAR and NUMERIC support NO +B221 Routine language Ada: VARCHAR and NUMERIC support NO +E011 Numeric data types YES +E011 Numeric data types 01 INTEGER and SMALLINT data types YES +E011 Numeric data types 02 REAL, DOUBLE PRECISION, and FLOAT data types YES +E011 Numeric data types 03 DECIMAL and NUMERIC data types YES +E011 Numeric data types 04 Arithmetic operators YES +E011 Numeric data types 05 Numeric comparison YES +E011 Numeric data types 06 Implicit casting among the numeric data types YES +E021 Character data types YES +E021 Character string types 01 CHARACTER data type YES +E021 Character string types 02 CHARACTER VARYING data type YES +E021 Character string types 03 Character literals YES +E021 Character string types 04 CHARACTER_LENGTH function YES trims trailing spaces from CHARACTER values before counting +E021 Character string types 05 OCTET_LENGTH function YES +E021 Character string types 06 SUBSTRING function YES +E021 Character string types 07 Character concatenation YES +E021 Character string types 08 UPPER and LOWER functions YES +E021 Character string types 09 TRIM function YES +E021 Character string types 10 Implicit casting among the character string types YES +E021 Character string types 11 POSITION function YES +E021 Character string types 12 Character comparison YES +E031 Identifiers YES +E031 Identifiers 01 Delimited identifiers YES +E031 Identifiers 02 Lower case identifiers YES +E031 Identifiers 03 Trailing underscore YES +E051 Basic query specification YES +E051 Basic query specification 01 SELECT DISTINCT YES +E051 Basic query specification 02 GROUP BY clause YES +E051 Basic query specification 04 GROUP BY can contain columns not in <select list> YES +E051 Basic query specification 05 Select list items can be renamed YES +E051 Basic query specification 06 HAVING clause YES +E051 Basic query specification 07 Qualified * in select list YES +E051 Basic query specification 08 Correlation names in the FROM clause YES +E051 Basic query specification 09 Rename columns in the FROM clause YES +E061 Basic predicates and search conditions YES +E061 Basic predicates and search conditions 01 Comparison predicate YES +E061 Basic predicates and search conditions 02 BETWEEN predicate YES +E061 Basic predicates and search conditions 03 IN predicate with list of values YES +E061 Basic predicates and search conditions 04 LIKE predicate YES +E061 Basic predicates and search conditions 05 LIKE predicate ESCAPE clause YES +E061 Basic predicates and search conditions 06 NULL predicate YES +E061 Basic predicates and search conditions 07 Quantified comparison predicate YES +E061 Basic predicates and search conditions 08 EXISTS predicate YES +E061 Basic predicates and search conditions 09 Subqueries in comparison predicate YES +E061 Basic predicates and search conditions 11 Subqueries in IN predicate YES +E061 Basic predicates and search conditions 12 Subqueries in quantified comparison predicate YES +E061 Basic predicates and search conditions 13 Correlated subqueries YES +E061 Basic predicates and search conditions 14 Search condition YES +E071 Basic query expressions YES +E071 Basic query expressions 01 UNION DISTINCT table operator YES +E071 Basic query expressions 02 UNION ALL table operator YES +E071 Basic query expressions 03 EXCEPT DISTINCT table operator YES +E071 Basic query expressions 05 Columns combined via table operators need not have exactly the same data type YES +E071 Basic query expressions 06 Table operators in subqueries YES +E081 Basic Privileges YES +E081 Basic Privileges 01 SELECT privilege YES +E081 Basic Privileges 02 DELETE privilege YES +E081 Basic Privileges 03 INSERT privilege at the table level YES +E081 Basic Privileges 04 UPDATE privilege at the table level YES +E081 Basic Privileges 05 UPDATE privilege at the column level YES +E081 Basic Privileges 06 REFERENCES privilege at the table level YES +E081 Basic Privileges 07 REFERENCES privilege at the column level YES +E081 Basic Privileges 08 WITH GRANT OPTION YES +E081 Basic Privileges 09 USAGE privilege YES +E081 Basic Privileges 10 EXECUTE privilege YES +E091 Set functions YES +E091 Set functions 01 AVG YES +E091 Set functions 02 COUNT YES +E091 Set functions 03 MAX YES +E091 Set functions 04 MIN YES +E091 Set functions 05 SUM YES +E091 Set functions 06 ALL quantifier YES +E091 Set functions 07 DISTINCT quantifier YES +E101 Basic data manipulation YES +E101 Basic data manipulation 01 INSERT statement YES +E101 Basic data manipulation 03 Searched UPDATE statement YES +E101 Basic data manipulation 04 Searched DELETE statement YES +E111 Single row SELECT statement YES +E121 Basic cursor support YES +E121 Basic cursor support 01 DECLARE CURSOR YES +E121 Basic cursor support 02 ORDER BY columns need not be in select list YES +E121 Basic cursor support 03 Value expressions in ORDER BY clause YES +E121 Basic cursor support 04 OPEN statement YES +E121 Basic cursor support 06 Positioned UPDATE statement YES +E121 Basic cursor support 07 Positioned DELETE statement YES +E121 Basic cursor support 08 CLOSE statement YES +E121 Basic cursor support 10 FETCH statement implicit NEXT YES +E121 Basic cursor support 17 WITH HOLD cursors YES +E131 Null value support (nulls in lieu of values) YES +E141 Basic integrity constraints YES +E141 Basic integrity constraints 01 NOT NULL constraints YES +E141 Basic integrity constraints 02 UNIQUE constraints of NOT NULL columns YES +E141 Basic integrity constraints 03 PRIMARY KEY constraints YES +E141 Basic integrity constraints 04 Basic FOREIGN KEY constraint with the NO ACTION default for both referential delete action and referential update action YES +E141 Basic integrity constraints 06 CHECK constraints YES +E141 Basic integrity constraints 07 Column defaults YES +E141 Basic integrity constraints 08 NOT NULL inferred on PRIMARY KEY YES +E141 Basic integrity constraints 10 Names in a foreign key can be specified in any order YES +E151 Transaction support YES +E151 Transaction support 01 COMMIT statement YES +E151 Transaction support 02 ROLLBACK statement YES +E152 Basic SET TRANSACTION statement YES +E152 Basic SET TRANSACTION statement 01 SET TRANSACTION statement: ISOLATION LEVEL SERIALIZABLE clause YES +E152 Basic SET TRANSACTION statement 02 SET TRANSACTION statement: READ ONLY and READ WRITE clauses YES +E153 Updatable queries with subqueries YES +E161 SQL comments using leading double minus YES +E171 SQLSTATE support YES +E182 Host language binding YES +F021 Basic information schema YES +F021 Basic information schema 01 COLUMNS view YES +F021 Basic information schema 02 TABLES view YES +F021 Basic information schema 03 VIEWS view YES +F021 Basic information schema 04 TABLE_CONSTRAINTS view YES +F021 Basic information schema 05 REFERENTIAL_CONSTRAINTS view YES +F021 Basic information schema 06 CHECK_CONSTRAINTS view YES +F031 Basic schema manipulation YES +F031 Basic schema manipulation 01 CREATE TABLE statement to create persistent base tables YES +F031 Basic schema manipulation 02 CREATE VIEW statement YES +F031 Basic schema manipulation 03 GRANT statement YES +F031 Basic schema manipulation 04 ALTER TABLE statement: ADD COLUMN clause YES +F031 Basic schema manipulation 13 DROP TABLE statement: RESTRICT clause YES +F031 Basic schema manipulation 16 DROP VIEW statement: RESTRICT clause YES +F031 Basic schema manipulation 19 REVOKE statement: RESTRICT clause YES +F032 CASCADE drop behavior YES +F033 ALTER TABLE statement: DROP COLUMN clause YES +F034 Extended REVOKE statement YES +F034 Extended REVOKE statement 01 REVOKE statement performed by other than the owner of a schema object YES +F034 Extended REVOKE statement 02 REVOKE statement: GRANT OPTION FOR clause YES +F034 Extended REVOKE statement 03 REVOKE statement to revoke a privilege that the grantee has WITH GRANT OPTION YES +F041 Basic joined table YES +F041 Basic joined table 01 Inner join (but not necessarily the INNER keyword) YES +F041 Basic joined table 02 INNER keyword YES +F041 Basic joined table 03 LEFT OUTER JOIN YES +F041 Basic joined table 04 RIGHT OUTER JOIN YES +F041 Basic joined table 05 Outer joins can be nested YES +F041 Basic joined table 07 The inner table in a left or right outer join can also be used in an inner join YES +F041 Basic joined table 08 All comparison operators are supported (rather than just =) YES +F051 Basic date and time YES +F051 Basic date and time 01 DATE data type (including support of DATE literal) YES +F051 Basic date and time 02 TIME data type (including support of TIME literal) with fractional seconds precision of at least 0 YES +F051 Basic date and time 03 TIMESTAMP data type (including support of TIMESTAMP literal) with fractional seconds precision of at least 0 and 6 YES +F051 Basic date and time 04 Comparison predicate on DATE, TIME, and TIMESTAMP data types YES +F051 Basic date and time 05 Explicit CAST between datetime types and character string types YES +F051 Basic date and time 06 CURRENT_DATE YES +F051 Basic date and time 07 LOCALTIME YES +F051 Basic date and time 08 LOCALTIMESTAMP YES +F052 Intervals and datetime arithmetic YES +F053 OVERLAPS predicate YES +F054 TIMESTAMP in DATE type precedence list NO +F081 UNION and EXCEPT in views YES +F111 Isolation levels other than SERIALIZABLE YES +F111 Isolation levels other than SERIALIZABLE 01 READ UNCOMMITTED isolation level YES +F111 Isolation levels other than SERIALIZABLE 02 READ COMMITTED isolation level YES +F111 Isolation levels other than SERIALIZABLE 03 REPEATABLE READ isolation level YES +F121 Basic diagnostics management NO +F121 Basic diagnostics management 01 GET DIAGNOSTICS statement NO +F121 Basic diagnostics management 02 SET TRANSACTION statement: DIAGNOSTICS SIZE clause NO +F122 Enhanced diagnostics management NO +F123 All diagnostics NO +F131 Grouped operations YES +F131 Grouped operations 01 WHERE, GROUP BY, and HAVING clauses supported in queries with grouped views YES +F131 Grouped operations 02 Multiple tables supported in queries with grouped views YES +F131 Grouped operations 03 Set functions supported in queries with grouped views YES +F131 Grouped operations 04 Subqueries with GROUP BY and HAVING clauses and grouped views YES +F131 Grouped operations 05 Single row SELECT with GROUP BY and HAVING clauses and grouped views YES +F171 Multiple schemas per user YES +F181 Multiple module support YES +F191 Referential delete actions YES +F200 TRUNCATE TABLE statement YES +F201 CAST function YES +F202 TRUNCATE TABLE: identity column restart option YES +F221 Explicit defaults YES +F222 INSERT statement: DEFAULT VALUES clause YES +F231 Privilege tables YES +F231 Privilege tables 01 TABLE_PRIVILEGES view YES +F231 Privilege tables 02 COLUMN_PRIVILEGES view YES +F231 Privilege tables 03 USAGE_PRIVILEGES view YES +F251 Domain support YES +F261 CASE expression YES +F261 CASE expression 01 Simple CASE YES +F261 CASE expression 02 Searched CASE YES +F261 CASE expression 03 NULLIF YES +F261 CASE expression 04 COALESCE YES +F262 Extended CASE expression YES +F263 Comma-separated predicates in simple CASE expression NO +F271 Compound character literals YES +F281 LIKE enhancements YES +F291 UNIQUE predicate NO +F301 CORRESPONDING in query expressions NO +F302 INTERSECT table operator YES +F302 INTERSECT table operator 01 INTERSECT DISTINCT table operator YES +F302 INTERSECT table operator 02 INTERSECT ALL table operator YES +F304 EXCEPT ALL table operator YES +F311 Schema definition statement YES +F311 Schema definition statement 01 CREATE SCHEMA YES +F311 Schema definition statement 02 CREATE TABLE for persistent base tables YES +F311 Schema definition statement 03 CREATE VIEW YES +F311 Schema definition statement 04 CREATE VIEW: WITH CHECK OPTION YES +F311 Schema definition statement 05 GRANT statement YES +F312 MERGE statement NO consider INSERT ... ON CONFLICT DO UPDATE +F313 Enhanced MERGE statement NO +F314 MERGE statement with DELETE branch NO +F321 User authorization YES +F341 Usage tables NO no ROUTINE_*_USAGE tables +F361 Subprogram support YES +F381 Extended schema manipulation YES +F381 Extended schema manipulation 01 ALTER TABLE statement: ALTER COLUMN clause YES +F381 Extended schema manipulation 02 ALTER TABLE statement: ADD CONSTRAINT clause YES +F381 Extended schema manipulation 03 ALTER TABLE statement: DROP CONSTRAINT clause YES +F382 Alter column data type YES +F383 Set column not null clause YES +F384 Drop identity property clause YES +F385 Drop column generation expression clause YES +F386 Set identity column generation clause YES +F391 Long identifiers YES +F392 Unicode escapes in identifiers YES +F393 Unicode escapes in literals YES +F394 Optional normal form specification YES +F401 Extended joined table YES +F401 Extended joined table 01 NATURAL JOIN YES +F401 Extended joined table 02 FULL OUTER JOIN YES +F401 Extended joined table 04 CROSS JOIN YES +F402 Named column joins for LOBs, arrays, and multisets YES +F403 Partitioned joined tables NO +F404 Range variable for common column names NO +F411 Time zone specification YES differences regarding literal interpretation +F421 National character YES +F431 Read-only scrollable cursors YES +F431 Read-only scrollable cursors 01 FETCH with explicit NEXT YES +F431 Read-only scrollable cursors 02 FETCH FIRST YES +F431 Read-only scrollable cursors 03 FETCH LAST YES +F431 Read-only scrollable cursors 04 FETCH PRIOR YES +F431 Read-only scrollable cursors 05 FETCH ABSOLUTE YES +F431 Read-only scrollable cursors 06 FETCH RELATIVE YES +F441 Extended set function support YES +F442 Mixed column references in set functions YES +F451 Character set definition NO +F461 Named character sets NO +F471 Scalar subquery values YES +F481 Expanded NULL predicate YES +F491 Constraint management YES +F492 Optional table constraint enforcement NO +F501 Features and conformance views YES +F501 Features and conformance views 01 SQL_FEATURES view YES +F501 Features and conformance views 02 SQL_SIZING view YES +F502 Enhanced documentation tables YES +F521 Assertions NO +F531 Temporary tables YES +F555 Enhanced seconds precision YES +F561 Full value expressions YES +F571 Truth value tests YES +F591 Derived tables YES +F611 Indicator data types YES +F641 Row and table constructors YES +F651 Catalog name qualifiers YES +F661 Simple tables YES +F671 Subqueries in CHECK NO intentionally omitted +F672 Retrospective check constraints YES +F673 Reads SQL-data routine invocations in CHECK constraints NO +F690 Collation support YES but no character set support +F692 Extended collation support YES +F693 SQL-session and client module collations NO +F695 Translation support NO +F696 Additional translation documentation NO +F701 Referential update actions YES +F711 ALTER domain YES +F721 Deferrable constraints NO foreign and unique keys only +F731 INSERT column privileges YES +F741 Referential MATCH types NO no partial match yet +F751 View CHECK enhancements YES +F761 Session management YES +F762 CURRENT_CATALOG YES +F763 CURRENT_SCHEMA YES +F771 Connection management YES +F781 Self-referencing operations YES +F791 Insensitive cursors YES +F801 Full set function YES +F812 Basic flagging NO +F813 Extended flagging NO +F821 Local table references NO +F831 Full cursor update NO +F831 Full cursor update 01 Updatable scrollable cursors NO +F831 Full cursor update 02 Updatable ordered cursors NO +F841 LIKE_REGEX predicate NO +F842 OCCURRENCES_REGEX function NO +F843 POSITION_REGEX function NO +F844 SUBSTRING_REGEX function NO +F845 TRANSLATE_REGEX function NO +F846 Octet support in regular expression operators NO +F847 Nonconstant regular expressions NO +F850 Top-level <order by clause> in <query expression> YES +F851 <order by clause> in subqueries YES +F852 Top-level <order by clause> in views YES +F855 Nested <order by clause> in <query expression> YES +F856 Nested <fetch first clause> in <query expression> YES +F857 Top-level <fetch first clause> in <query expression> YES +F858 <fetch first clause> in subqueries YES +F859 Top-level <fetch first clause> in views YES +F860 <fetch first row count> in <fetch first clause> YES +F861 Top-level <result offset clause> in <query expression> YES +F862 <result offset clause> in subqueries YES +F863 Nested <result offset clause> in <query expression> YES +F864 Top-level <result offset clause> in views YES +F865 <offset row count> in <result offset clause> YES +F866 FETCH FIRST clause: PERCENT option NO +F867 FETCH FIRST clause: WITH TIES option YES +R010 Row pattern recognition: FROM clause NO +R020 Row pattern recognition: WINDOW clause NO +R030 Row pattern recognition: full aggregate support NO +S011 Distinct data types NO +S011 Distinct data types 01 USER_DEFINED_TYPES view NO +S023 Basic structured types NO +S024 Enhanced structured types NO +S025 Final structured types NO +S026 Self-referencing structured types NO +S027 Create method by specific method name NO +S028 Permutable UDT options list NO +S041 Basic reference types NO +S043 Enhanced reference types NO +S051 Create table of type NO partially supported +S071 SQL paths in function and type name resolution YES +S081 Subtables NO +S091 Basic array support NO partially supported +S091 Basic array support 01 Arrays of built-in data types NO +S091 Basic array support 02 Arrays of distinct types NO +S091 Basic array support 03 Array expressions NO +S092 Arrays of user-defined types YES +S094 Arrays of reference types NO +S095 Array constructors by query YES +S096 Optional array bounds YES +S097 Array element assignment NO +S098 ARRAY_AGG YES +S111 ONLY in query expressions YES +S151 Type predicate NO +S161 Subtype treatment NO +S162 Subtype treatment for references NO +S201 SQL-invoked routines on arrays YES +S201 SQL-invoked routines on arrays 01 Array parameters YES +S201 SQL-invoked routines on arrays 02 Array as result type of functions YES +S202 SQL-invoked routines on multisets NO +S211 User-defined cast functions YES +S231 Structured type locators NO +S232 Array locators NO +S233 Multiset locators NO +S241 Transform functions NO +S242 Alter transform statement NO +S251 User-defined orderings NO +S261 Specific type method NO +S271 Basic multiset support NO +S272 Multisets of user-defined types NO +S274 Multisets of reference types NO +S275 Advanced multiset support NO +S281 Nested collection types NO +S291 Unique constraint on entire row NO +S301 Enhanced UNNEST YES +S401 Distinct types based on array types NO +S402 Distinct types based on distinct types NO +S403 ARRAY_MAX_CARDINALITY NO +S404 TRIM_ARRAY NO +T011 Timestamp in Information Schema NO +T021 BINARY and VARBINARY data types NO +T022 Advanced support for BINARY and VARBINARY data types NO +T023 Compound binary literal NO +T024 Spaces in binary literals NO +T031 BOOLEAN data type YES +T041 Basic LOB data type support NO +T041 Basic LOB data type support 01 BLOB data type NO +T041 Basic LOB data type support 02 CLOB data type NO +T041 Basic LOB data type support 03 POSITION, LENGTH, LOWER, TRIM, UPPER, and SUBSTRING functions for LOB data types NO +T041 Basic LOB data type support 04 Concatenation of LOB data types NO +T041 Basic LOB data type support 05 LOB locator: non-holdable NO +T042 Extended LOB data type support NO +T043 Multiplier T NO +T044 Multiplier P NO +T051 Row types NO +T053 Explicit aliases for all-fields reference NO +T061 UCS support NO +T071 BIGINT data type YES +T076 DECFLOAT data type NO +T101 Enhanced nullability determination NO +T111 Updatable joins, unions, and columns NO +T121 WITH (excluding RECURSIVE) in query expression YES +T122 WITH (excluding RECURSIVE) in subquery YES +T131 Recursive query YES +T132 Recursive query in subquery YES +T141 SIMILAR predicate YES +T151 DISTINCT predicate YES +T152 DISTINCT predicate with negation YES +T171 LIKE clause in table definition YES +T172 AS subquery clause in table definition YES +T173 Extended LIKE clause in table definition YES +T174 Identity columns YES +T175 Generated columns NO mostly supported +T176 Sequence generator support NO supported except for NEXT VALUE FOR +T177 Sequence generator support: simple restart option YES +T178 Identity columns: simple restart option YES +T180 System-versioned tables NO +T181 Application-time period tables NO +T191 Referential action RESTRICT YES +T201 Comparable data types for referential constraints YES +T211 Basic trigger capability NO +T211 Basic trigger capability 01 Triggers activated on UPDATE, INSERT, or DELETE of one base table YES +T211 Basic trigger capability 02 BEFORE triggers YES +T211 Basic trigger capability 03 AFTER triggers YES +T211 Basic trigger capability 04 FOR EACH ROW triggers YES +T211 Basic trigger capability 05 Ability to specify a search condition that must be true before the trigger is invoked YES +T211 Basic trigger capability 06 Support for run-time rules for the interaction of triggers and constraints NO +T211 Basic trigger capability 07 TRIGGER privilege YES +T211 Basic trigger capability 08 Multiple triggers for the same event are executed in the order in which they were created in the catalog NO intentionally omitted +T212 Enhanced trigger capability YES +T213 INSTEAD OF triggers YES +T231 Sensitive cursors YES +T241 START TRANSACTION statement YES +T251 SET TRANSACTION statement: LOCAL option NO +T261 Chained transactions YES +T271 Savepoints YES +T272 Enhanced savepoint management NO +T281 SELECT privilege with column granularity YES +T285 Enhanced derived column names YES +T301 Functional dependencies NO partially supported +T312 OVERLAY function YES +T321 Basic SQL-invoked routines NO +T321 Basic SQL-invoked routines 01 User-defined functions with no overloading YES +T321 Basic SQL-invoked routines 02 User-defined stored procedures with no overloading YES +T321 Basic SQL-invoked routines 03 Function invocation YES +T321 Basic SQL-invoked routines 04 CALL statement YES +T321 Basic SQL-invoked routines 05 RETURN statement NO +T321 Basic SQL-invoked routines 06 ROUTINES view YES +T321 Basic SQL-invoked routines 07 PARAMETERS view YES +T322 Declared data type attributes NO +T323 Explicit security for external routines YES +T324 Explicit security for SQL routines NO +T325 Qualified SQL parameter references YES +T326 Table functions NO +T331 Basic roles YES +T332 Extended roles NO mostly supported +T341 Overloading of SQL-invoked functions and procedures YES +T351 Bracketed SQL comments (/*...*/ comments) YES +T431 Extended grouping capabilities YES +T432 Nested and concatenated GROUPING SETS YES +T433 Multiargument GROUPING function YES +T434 GROUP BY DISTINCT NO +T441 ABS and MOD functions YES +T461 Symmetric BETWEEN predicate YES +T471 Result sets return value NO +T472 DESCRIBE CURSOR NO +T491 LATERAL derived table YES +T495 Combined data change and retrieval NO different syntax +T501 Enhanced EXISTS predicate YES +T502 Period predicates NO +T511 Transaction counts NO +T521 Named arguments in CALL statement YES +T522 Default values for IN parameters of SQL-invoked procedures NO supported except DEFAULT key word in invocation +T523 Default values for INOUT parameters of SQL-invoked procedures YES +T524 Named arguments in routine invocations other than a CALL statement YES +T525 Default values for parameters of SQL-invoked functions YES +T551 Optional key words for default syntax YES +T561 Holdable locators NO +T571 Array-returning external SQL-invoked functions NO +T572 Multiset-returning external SQL-invoked functions NO +T581 Regular expression substring function YES +T591 UNIQUE constraints of possibly null columns YES +T601 Local cursor references NO +T611 Elementary OLAP operations YES +T612 Advanced OLAP operations YES +T613 Sampling YES +T614 NTILE function YES +T615 LEAD and LAG functions YES +T616 Null treatment option for LEAD and LAG functions NO +T617 FIRST_VALUE and LAST_VALUE function YES +T618 NTH_VALUE function NO function exists, but some options missing +T619 Nested window functions NO +T620 WINDOW clause: GROUPS option YES +T621 Enhanced numeric functions YES +T622 Trigonometric functions YES +T623 General logarithm functions YES +T624 Common logarithm functions YES +T625 LISTAGG NO +T631 IN predicate with one list element YES +T641 Multiple column assignment NO only some syntax variants supported +T651 SQL-schema statements in SQL routines YES +T652 SQL-dynamic statements in SQL routines NO +T653 SQL-schema statements in external routines YES +T654 SQL-dynamic statements in external routines NO +T655 Cyclically dependent routines YES +T811 Basic SQL/JSON constructor functions NO +T812 SQL/JSON: JSON_OBJECTAGG NO +T813 SQL/JSON: JSON_ARRAYAGG with ORDER BY NO +T814 Colon in JSON_OBJECT or JSON_OBJECTAGG NO +T821 Basic SQL/JSON query operators NO +T822 SQL/JSON: IS JSON WITH UNIQUE KEYS predicate NO +T823 SQL/JSON: PASSING clause NO +T824 JSON_TABLE: specific PLAN clause NO +T825 SQL/JSON: ON EMPTY and ON ERROR clauses NO +T826 General value expression in ON ERROR or ON EMPTY clauses NO +T827 JSON_TABLE: sibling NESTED COLUMNS clauses NO +T828 JSON_QUERY NO +T829 JSON_QUERY: array wrapper options NO +T830 Enforcing unique keys in SQL/JSON constructor functions NO +T831 SQL/JSON path language: strict mode YES +T832 SQL/JSON path language: item method YES +T833 SQL/JSON path language: multiple subscripts YES +T834 SQL/JSON path language: wildcard member accessor YES +T835 SQL/JSON path language: filter expressions YES +T836 SQL/JSON path language: starts with predicate YES +T837 SQL/JSON path language: regex_like predicate YES +T838 JSON_TABLE: PLAN DEFAULT clause NO +T839 Formatted cast of datetimes to/from character strings NO +M001 Datalinks NO +M002 Datalinks via SQL/CLI NO +M003 Datalinks via Embedded SQL NO +M004 Foreign data support NO partially supported +M005 Foreign schema support NO +M006 GetSQLString routine NO +M007 TransmitRequest NO +M009 GetOpts and GetStatistics routines NO +M010 Foreign data wrapper support NO different API +M011 Datalinks via Ada NO +M012 Datalinks via C NO +M013 Datalinks via COBOL NO +M014 Datalinks via Fortran NO +M015 Datalinks via M NO +M016 Datalinks via Pascal NO +M017 Datalinks via PL/I NO +M018 Foreign data wrapper interface routines in Ada NO +M019 Foreign data wrapper interface routines in C NO different API +M020 Foreign data wrapper interface routines in COBOL NO +M021 Foreign data wrapper interface routines in Fortran NO +M022 Foreign data wrapper interface routines in MUMPS NO +M023 Foreign data wrapper interface routines in Pascal NO +M024 Foreign data wrapper interface routines in PL/I NO +M030 SQL-server foreign data support NO +M031 Foreign data wrapper general routines NO +X010 XML type YES +X011 Arrays of XML type YES +X012 Multisets of XML type NO +X013 Distinct types of XML type NO +X014 Attributes of XML type YES +X015 Fields of XML type NO +X016 Persistent XML values YES +X020 XMLConcat YES +X025 XMLCast NO +X030 XMLDocument NO +X031 XMLElement YES +X032 XMLForest YES +X034 XMLAgg YES +X035 XMLAgg: ORDER BY option YES +X036 XMLComment YES +X037 XMLPI YES +X038 XMLText NO +X040 Basic table mapping YES +X041 Basic table mapping: nulls absent YES +X042 Basic table mapping: null as nil YES +X043 Basic table mapping: table as forest YES +X044 Basic table mapping: table as element YES +X045 Basic table mapping: with target namespace YES +X046 Basic table mapping: data mapping YES +X047 Basic table mapping: metadata mapping YES +X048 Basic table mapping: base64 encoding of binary strings YES +X049 Basic table mapping: hex encoding of binary strings YES +X050 Advanced table mapping YES +X051 Advanced table mapping: nulls absent YES +X052 Advanced table mapping: null as nil YES +X053 Advanced table mapping: table as forest YES +X054 Advanced table mapping: table as element YES +X055 Advanced table mapping: with target namespace YES +X056 Advanced table mapping: data mapping YES +X057 Advanced table mapping: metadata mapping YES +X058 Advanced table mapping: base64 encoding of binary strings YES +X059 Advanced table mapping: hex encoding of binary strings YES +X060 XMLParse: character string input and CONTENT option YES +X061 XMLParse: character string input and DOCUMENT option YES +X065 XMLParse: BLOB input and CONTENT option NO +X066 XMLParse: BLOB input and DOCUMENT option NO +X068 XMLSerialize: BOM NO +X069 XMLSerialize: INDENT NO +X070 XMLSerialize: character string serialization and CONTENT option YES +X071 XMLSerialize: character string serialization and DOCUMENT option YES +X072 XMLSerialize: character string serialization YES +X073 XMLSerialize: BLOB serialization and CONTENT option NO +X074 XMLSerialize: BLOB serialization and DOCUMENT option NO +X075 XMLSerialize: BLOB serialization NO +X076 XMLSerialize: VERSION NO +X077 XMLSerialize: explicit ENCODING option NO +X078 XMLSerialize: explicit XML declaration NO +X080 Namespaces in XML publishing NO +X081 Query-level XML namespace declarations NO +X082 XML namespace declarations in DML NO +X083 XML namespace declarations in DDL NO +X084 XML namespace declarations in compound statements NO +X085 Predefined namespace prefixes NO +X086 XML namespace declarations in XMLTable NO +X090 XML document predicate YES +X091 XML content predicate NO +X096 XMLExists NO XPath 1.0 only +X100 Host language support for XML: CONTENT option NO +X101 Host language support for XML: DOCUMENT option NO +X110 Host language support for XML: VARCHAR mapping NO +X111 Host language support for XML: CLOB mapping NO +X112 Host language support for XML: BLOB mapping NO +X113 Host language support for XML: STRIP WHITESPACE option NO +X114 Host language support for XML: PRESERVE WHITESPACE option NO +X120 XML parameters in SQL routines YES +X121 XML parameters in external routines YES +X131 Query-level XMLBINARY clause NO +X132 XMLBINARY clause in DML NO +X133 XMLBINARY clause in DDL NO +X134 XMLBINARY clause in compound statements NO +X135 XMLBINARY clause in subqueries NO +X141 IS VALID predicate: data-driven case NO +X142 IS VALID predicate: ACCORDING TO clause NO +X143 IS VALID predicate: ELEMENT clause NO +X144 IS VALID predicate: schema location NO +X145 IS VALID predicate outside check constraints NO +X151 IS VALID predicate with DOCUMENT option NO +X152 IS VALID predicate with CONTENT option NO +X153 IS VALID predicate with SEQUENCE option NO +X155 IS VALID predicate: NAMESPACE without ELEMENT clause NO +X157 IS VALID predicate: NO NAMESPACE with ELEMENT clause NO +X160 Basic Information Schema for registered XML Schemas NO +X161 Advanced Information Schema for registered XML Schemas NO +X170 XML null handling options NO +X171 NIL ON NO CONTENT option NO +X181 XML(DOCUMENT(UNTYPED)) type NO +X182 XML(DOCUMENT(ANY)) type NO +X190 XML(SEQUENCE) type NO +X191 XML(DOCUMENT(XMLSCHEMA)) type NO +X192 XML(CONTENT(XMLSCHEMA)) type NO +X200 XMLQuery NO +X201 XMLQuery: RETURNING CONTENT NO +X202 XMLQuery: RETURNING SEQUENCE NO +X203 XMLQuery: passing a context item NO +X204 XMLQuery: initializing an XQuery variable NO +X205 XMLQuery: EMPTY ON EMPTY option NO +X206 XMLQuery: NULL ON EMPTY option NO +X211 XML 1.1 support NO +X221 XML passing mechanism BY VALUE YES +X222 XML passing mechanism BY REF NO parser accepts BY REF but ignores it; passing is always BY VALUE +X231 XML(CONTENT(UNTYPED)) type NO +X232 XML(CONTENT(ANY)) type NO +X241 RETURNING CONTENT in XML publishing NO +X242 RETURNING SEQUENCE in XML publishing NO +X251 Persistent XML values of XML(DOCUMENT(UNTYPED)) type NO +X252 Persistent XML values of XML(DOCUMENT(ANY)) type NO +X253 Persistent XML values of XML(CONTENT(UNTYPED)) type NO +X254 Persistent XML values of XML(CONTENT(ANY)) type NO +X255 Persistent XML values of XML(SEQUENCE) type NO +X256 Persistent XML values of XML(DOCUMENT(XMLSCHEMA)) type NO +X257 Persistent XML values of XML(CONTENT(XMLSCHEMA)) type NO +X260 XML type: ELEMENT clause NO +X261 XML type: NAMESPACE without ELEMENT clause NO +X263 XML type: NO NAMESPACE with ELEMENT clause NO +X264 XML type: schema location NO +X271 XMLValidate: data-driven case NO +X272 XMLValidate: ACCORDING TO clause NO +X273 XMLValidate: ELEMENT clause NO +X274 XMLValidate: schema location NO +X281 XMLValidate with DOCUMENT option NO +X282 XMLValidate with CONTENT option NO +X283 XMLValidate with SEQUENCE option NO +X284 XMLValidate: NAMESPACE without ELEMENT clause NO +X286 XMLValidate: NO NAMESPACE with ELEMENT clause NO +X300 XMLTable NO XPath 1.0 only +X301 XMLTable: derived column list option YES +X302 XMLTable: ordinality column option YES +X303 XMLTable: column default option YES +X304 XMLTable: passing a context item YES must be XML DOCUMENT +X305 XMLTable: initializing an XQuery variable NO +X400 Name and identifier mapping YES +X410 Alter column data type: XML type YES diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c new file mode 100644 index 0000000..7421678 --- /dev/null +++ b/src/backend/catalog/storage.c @@ -0,0 +1,1011 @@ +/*------------------------------------------------------------------------- + * + * storage.c + * code to create and destroy physical storage for relations + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/storage.c + * + * NOTES + * Some of this code used to be in storage/smgr/smgr.c, and the + * function names still reflect that. + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/parallel.h" +#include "access/visibilitymap.h" +#include "access/xact.h" +#include "access/xlog.h" +#include "access/xloginsert.h" +#include "access/xlogutils.h" +#include "catalog/storage.h" +#include "catalog/storage_xlog.h" +#include "miscadmin.h" +#include "storage/freespace.h" +#include "storage/smgr.h" +#include "utils/hsearch.h" +#include "utils/memutils.h" +#include "utils/rel.h" + +/* GUC variables */ +int wal_skip_threshold = 2048; /* in kilobytes */ + +/* + * We keep a list of all relations (represented as RelFileNode values) + * that have been created or deleted in the current transaction. When + * a relation is created, we create the physical file immediately, but + * remember it so that we can delete the file again if the current + * transaction is aborted. Conversely, a deletion request is NOT + * executed immediately, but is just entered in the list. When and if + * the transaction commits, we can delete the physical file. + * + * To handle subtransactions, every entry is marked with its transaction + * nesting level. At subtransaction commit, we reassign the subtransaction's + * entries to the parent nesting level. At subtransaction abort, we can + * immediately execute the abort-time actions for all entries of the current + * nesting level. + * + * NOTE: the list is kept in TopMemoryContext to be sure it won't disappear + * unbetimes. It'd probably be OK to keep it in TopTransactionContext, + * but I'm being paranoid. + */ + +typedef struct PendingRelDelete +{ + RelFileNode relnode; /* relation that may need to be deleted */ + BackendId backend; /* InvalidBackendId if not a temp rel */ + bool atCommit; /* T=delete at commit; F=delete at abort */ + int nestLevel; /* xact nesting level of request */ + struct PendingRelDelete *next; /* linked-list link */ +} PendingRelDelete; + +typedef struct PendingRelSync +{ + RelFileNode rnode; + bool is_truncated; /* Has the file experienced truncation? */ +} PendingRelSync; + +static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */ +HTAB *pendingSyncHash = NULL; + + +/* + * AddPendingSync + * Queue an at-commit fsync. + */ +static void +AddPendingSync(const RelFileNode *rnode) +{ + PendingRelSync *pending; + bool found; + + /* create the hash if not yet */ + if (!pendingSyncHash) + { + HASHCTL ctl; + + ctl.keysize = sizeof(RelFileNode); + ctl.entrysize = sizeof(PendingRelSync); + ctl.hcxt = TopTransactionContext; + pendingSyncHash = hash_create("pending sync hash", 16, &ctl, + HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); + } + + pending = hash_search(pendingSyncHash, rnode, HASH_ENTER, &found); + Assert(!found); + pending->is_truncated = false; +} + +/* + * RelationCreateStorage + * Create physical storage for a relation. + * + * Create the underlying disk file storage for the relation. This only + * creates the main fork; additional forks are created lazily by the + * modules that need them. + * + * This function is transactional. The creation is WAL-logged, and if the + * transaction aborts later on, the storage will be destroyed. + */ +SMgrRelation +RelationCreateStorage(RelFileNode rnode, char relpersistence) +{ + PendingRelDelete *pending; + SMgrRelation srel; + BackendId backend; + bool needs_wal; + + Assert(!IsInParallelMode()); /* couldn't update pendingSyncHash */ + + switch (relpersistence) + { + case RELPERSISTENCE_TEMP: + backend = BackendIdForTempRelations(); + needs_wal = false; + break; + case RELPERSISTENCE_UNLOGGED: + backend = InvalidBackendId; + needs_wal = false; + break; + case RELPERSISTENCE_PERMANENT: + backend = InvalidBackendId; + needs_wal = true; + break; + default: + elog(ERROR, "invalid relpersistence: %c", relpersistence); + return NULL; /* placate compiler */ + } + + srel = smgropen(rnode, backend); + smgrcreate(srel, MAIN_FORKNUM, false); + + if (needs_wal) + log_smgrcreate(&srel->smgr_rnode.node, MAIN_FORKNUM); + + /* Add the relation to the list of stuff to delete at abort */ + pending = (PendingRelDelete *) + MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete)); + pending->relnode = rnode; + pending->backend = backend; + pending->atCommit = false; /* delete if abort */ + pending->nestLevel = GetCurrentTransactionNestLevel(); + pending->next = pendingDeletes; + pendingDeletes = pending; + + if (relpersistence == RELPERSISTENCE_PERMANENT && !XLogIsNeeded()) + { + Assert(backend == InvalidBackendId); + AddPendingSync(&rnode); + } + + return srel; +} + +/* + * Perform XLogInsert of an XLOG_SMGR_CREATE record to WAL. + */ +void +log_smgrcreate(const RelFileNode *rnode, ForkNumber forkNum) +{ + xl_smgr_create xlrec; + + /* + * Make an XLOG entry reporting the file creation. + */ + xlrec.rnode = *rnode; + xlrec.forkNum = forkNum; + + XLogBeginInsert(); + XLogRegisterData((char *) &xlrec, sizeof(xlrec)); + XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE | XLR_SPECIAL_REL_UPDATE); +} + +/* + * RelationDropStorage + * Schedule unlinking of physical storage at transaction commit. + */ +void +RelationDropStorage(Relation rel) +{ + PendingRelDelete *pending; + + /* Add the relation to the list of stuff to delete at commit */ + pending = (PendingRelDelete *) + MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete)); + pending->relnode = rel->rd_node; + pending->backend = rel->rd_backend; + pending->atCommit = true; /* delete if commit */ + pending->nestLevel = GetCurrentTransactionNestLevel(); + pending->next = pendingDeletes; + pendingDeletes = pending; + + /* + * NOTE: if the relation was created in this transaction, it will now be + * present in the pending-delete list twice, once with atCommit true and + * once with atCommit false. Hence, it will be physically deleted at end + * of xact in either case (and the other entry will be ignored by + * smgrDoPendingDeletes, so no error will occur). We could instead remove + * the existing list entry and delete the physical file immediately, but + * for now I'll keep the logic simple. + */ + + RelationCloseSmgr(rel); +} + +/* + * RelationPreserveStorage + * Mark a relation as not to be deleted after all. + * + * We need this function because relation mapping changes are committed + * separately from commit of the whole transaction, so it's still possible + * for the transaction to abort after the mapping update is done. + * When a new physical relation is installed in the map, it would be + * scheduled for delete-on-abort, so we'd delete it, and be in trouble. + * The relation mapper fixes this by telling us to not delete such relations + * after all as part of its commit. + * + * We also use this to reuse an old build of an index during ALTER TABLE, this + * time removing the delete-at-commit entry. + * + * No-op if the relation is not among those scheduled for deletion. + */ +void +RelationPreserveStorage(RelFileNode rnode, bool atCommit) +{ + PendingRelDelete *pending; + PendingRelDelete *prev; + PendingRelDelete *next; + + prev = NULL; + for (pending = pendingDeletes; pending != NULL; pending = next) + { + next = pending->next; + if (RelFileNodeEquals(rnode, pending->relnode) + && pending->atCommit == atCommit) + { + /* unlink and delete list entry */ + if (prev) + prev->next = next; + else + pendingDeletes = next; + pfree(pending); + /* prev does not change */ + } + else + { + /* unrelated entry, don't touch it */ + prev = pending; + } + } +} + +/* + * RelationTruncate + * Physically truncate a relation to the specified number of blocks. + * + * This includes getting rid of any buffers for the blocks that are to be + * dropped. + */ +void +RelationTruncate(Relation rel, BlockNumber nblocks) +{ + bool fsm; + bool vm; + bool need_fsm_vacuum = false; + ForkNumber forks[MAX_FORKNUM]; + BlockNumber blocks[MAX_FORKNUM]; + int nforks = 0; + + /* Open it at the smgr level if not already done */ + RelationOpenSmgr(rel); + + /* + * Make sure smgr_targblock etc aren't pointing somewhere past new end + */ + rel->rd_smgr->smgr_targblock = InvalidBlockNumber; + rel->rd_smgr->smgr_fsm_nblocks = InvalidBlockNumber; + rel->rd_smgr->smgr_vm_nblocks = InvalidBlockNumber; + + /* Prepare for truncation of MAIN fork of the relation */ + forks[nforks] = MAIN_FORKNUM; + blocks[nforks] = nblocks; + nforks++; + + /* Prepare for truncation of the FSM if it exists */ + fsm = smgrexists(rel->rd_smgr, FSM_FORKNUM); + if (fsm) + { + blocks[nforks] = FreeSpaceMapPrepareTruncateRel(rel, nblocks); + if (BlockNumberIsValid(blocks[nforks])) + { + forks[nforks] = FSM_FORKNUM; + nforks++; + need_fsm_vacuum = true; + } + } + + /* Prepare for truncation of the visibility map too if it exists */ + vm = smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM); + if (vm) + { + blocks[nforks] = visibilitymap_prepare_truncate(rel, nblocks); + if (BlockNumberIsValid(blocks[nforks])) + { + forks[nforks] = VISIBILITYMAP_FORKNUM; + nforks++; + } + } + + RelationPreTruncate(rel); + + /* + * We WAL-log the truncation before actually truncating, which means + * trouble if the truncation fails. If we then crash, the WAL replay + * likely isn't going to succeed in the truncation either, and cause a + * PANIC. It's tempting to put a critical section here, but that cure + * would be worse than the disease. It would turn a usually harmless + * failure to truncate, that might spell trouble at WAL replay, into a + * certain PANIC. + */ + if (RelationNeedsWAL(rel)) + { + /* + * Make an XLOG entry reporting the file truncation. + */ + XLogRecPtr lsn; + xl_smgr_truncate xlrec; + + xlrec.blkno = nblocks; + xlrec.rnode = rel->rd_node; + xlrec.flags = SMGR_TRUNCATE_ALL; + + XLogBeginInsert(); + XLogRegisterData((char *) &xlrec, sizeof(xlrec)); + + lsn = XLogInsert(RM_SMGR_ID, + XLOG_SMGR_TRUNCATE | XLR_SPECIAL_REL_UPDATE); + + /* + * Flush, because otherwise the truncation of the main relation might + * hit the disk before the WAL record, and the truncation of the FSM + * or visibility map. If we crashed during that window, we'd be left + * with a truncated heap, but the FSM or visibility map would still + * contain entries for the non-existent heap pages. + */ + if (fsm || vm) + XLogFlush(lsn); + } + + /* Do the real work to truncate relation forks */ + smgrtruncate(rel->rd_smgr, forks, nforks, blocks); + + /* + * Update upper-level FSM pages to account for the truncation. This is + * important because the just-truncated pages were likely marked as + * all-free, and would be preferentially selected. + */ + if (need_fsm_vacuum) + FreeSpaceMapVacuumRange(rel, nblocks, InvalidBlockNumber); +} + +/* + * RelationPreTruncate + * Perform AM-independent work before a physical truncation. + * + * If an access method's relation_nontransactional_truncate does not call + * RelationTruncate(), it must call this before decreasing the table size. + */ +void +RelationPreTruncate(Relation rel) +{ + PendingRelSync *pending; + + if (!pendingSyncHash) + return; + RelationOpenSmgr(rel); + + pending = hash_search(pendingSyncHash, &(rel->rd_smgr->smgr_rnode.node), + HASH_FIND, NULL); + if (pending) + pending->is_truncated = true; +} + +/* + * Copy a fork's data, block by block. + * + * Note that this requires that there is no dirty data in shared buffers. If + * it's possible that there are, callers need to flush those using + * e.g. FlushRelationBuffers(rel). + */ +void +RelationCopyStorage(SMgrRelation src, SMgrRelation dst, + ForkNumber forkNum, char relpersistence) +{ + PGAlignedBlock buf; + Page page; + bool use_wal; + bool copying_initfork; + BlockNumber nblocks; + BlockNumber blkno; + + page = (Page) buf.data; + + /* + * The init fork for an unlogged relation in many respects has to be + * treated the same as normal relation, changes need to be WAL logged and + * it needs to be synced to disk. + */ + copying_initfork = relpersistence == RELPERSISTENCE_UNLOGGED && + forkNum == INIT_FORKNUM; + + /* + * We need to log the copied data in WAL iff WAL archiving/streaming is + * enabled AND it's a permanent relation. This gives the same answer as + * "RelationNeedsWAL(rel) || copying_initfork", because we know the + * current operation created a new relfilenode. + */ + use_wal = XLogIsNeeded() && + (relpersistence == RELPERSISTENCE_PERMANENT || copying_initfork); + + nblocks = smgrnblocks(src, forkNum); + + for (blkno = 0; blkno < nblocks; blkno++) + { + /* If we got a cancel signal during the copy of the data, quit */ + CHECK_FOR_INTERRUPTS(); + + smgrread(src, forkNum, blkno, buf.data); + + if (!PageIsVerifiedExtended(page, blkno, + PIV_LOG_WARNING | PIV_REPORT_STAT)) + ereport(ERROR, + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg("invalid page in block %u of relation %s", + blkno, + relpathbackend(src->smgr_rnode.node, + src->smgr_rnode.backend, + forkNum)))); + + /* + * WAL-log the copied page. Unfortunately we don't know what kind of a + * page this is, so we have to log the full page including any unused + * space. + */ + if (use_wal) + log_newpage(&dst->smgr_rnode.node, forkNum, blkno, page, false); + + PageSetChecksumInplace(page, blkno); + + /* + * Now write the page. We say skipFsync = true because there's no + * need for smgr to schedule an fsync for this write; we'll do it + * ourselves below. + */ + smgrextend(dst, forkNum, blkno, buf.data, true); + } + + /* + * When we WAL-logged rel pages, we must nonetheless fsync them. The + * reason is that since we're copying outside shared buffers, a CHECKPOINT + * occurring during the copy has no way to flush the previously written + * data to disk (indeed it won't know the new rel even exists). A crash + * later on would replay WAL from the checkpoint, therefore it wouldn't + * replay our earlier WAL entries. If we do not fsync those pages here, + * they might still not be on disk when the crash occurs. + */ + if (use_wal || copying_initfork) + smgrimmedsync(dst, forkNum); +} + +/* + * RelFileNodeSkippingWAL + * Check if a BM_PERMANENT relfilenode is using WAL. + * + * Changes of certain relfilenodes must not write WAL; see "Skipping WAL for + * New RelFileNode" in src/backend/access/transam/README. Though it is known + * from Relation efficiently, this function is intended for the code paths not + * having access to Relation. + */ +bool +RelFileNodeSkippingWAL(RelFileNode rnode) +{ + if (!pendingSyncHash || + hash_search(pendingSyncHash, &rnode, HASH_FIND, NULL) == NULL) + return false; + + return true; +} + +/* + * EstimatePendingSyncsSpace + * Estimate space needed to pass syncs to parallel workers. + */ +Size +EstimatePendingSyncsSpace(void) +{ + long entries; + + entries = pendingSyncHash ? hash_get_num_entries(pendingSyncHash) : 0; + return mul_size(1 + entries, sizeof(RelFileNode)); +} + +/* + * SerializePendingSyncs + * Serialize syncs for parallel workers. + */ +void +SerializePendingSyncs(Size maxSize, char *startAddress) +{ + HTAB *tmphash; + HASHCTL ctl; + HASH_SEQ_STATUS scan; + PendingRelSync *sync; + PendingRelDelete *delete; + RelFileNode *src; + RelFileNode *dest = (RelFileNode *) startAddress; + + if (!pendingSyncHash) + goto terminate; + + /* Create temporary hash to collect active relfilenodes */ + ctl.keysize = sizeof(RelFileNode); + ctl.entrysize = sizeof(RelFileNode); + ctl.hcxt = CurrentMemoryContext; + tmphash = hash_create("tmp relfilenodes", + hash_get_num_entries(pendingSyncHash), &ctl, + HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); + + /* collect all rnodes from pending syncs */ + hash_seq_init(&scan, pendingSyncHash); + while ((sync = (PendingRelSync *) hash_seq_search(&scan))) + (void) hash_search(tmphash, &sync->rnode, HASH_ENTER, NULL); + + /* remove deleted rnodes */ + for (delete = pendingDeletes; delete != NULL; delete = delete->next) + if (delete->atCommit) + (void) hash_search(tmphash, (void *) &delete->relnode, + HASH_REMOVE, NULL); + + hash_seq_init(&scan, tmphash); + while ((src = (RelFileNode *) hash_seq_search(&scan))) + *dest++ = *src; + + hash_destroy(tmphash); + +terminate: + MemSet(dest, 0, sizeof(RelFileNode)); +} + +/* + * RestorePendingSyncs + * Restore syncs within a parallel worker. + * + * RelationNeedsWAL() and RelFileNodeSkippingWAL() must offer the correct + * answer to parallel workers. Only smgrDoPendingSyncs() reads the + * is_truncated field, at end of transaction. Hence, don't restore it. + */ +void +RestorePendingSyncs(char *startAddress) +{ + RelFileNode *rnode; + + Assert(pendingSyncHash == NULL); + for (rnode = (RelFileNode *) startAddress; rnode->relNode != 0; rnode++) + AddPendingSync(rnode); +} + +/* + * smgrDoPendingDeletes() -- Take care of relation deletes at end of xact. + * + * This also runs when aborting a subxact; we want to clean up a failed + * subxact immediately. + * + * Note: It's possible that we're being asked to remove a relation that has + * no physical storage in any fork. In particular, it's possible that we're + * cleaning up an old temporary relation for which RemovePgTempFiles has + * already recovered the physical storage. + */ +void +smgrDoPendingDeletes(bool isCommit) +{ + int nestLevel = GetCurrentTransactionNestLevel(); + PendingRelDelete *pending; + PendingRelDelete *prev; + PendingRelDelete *next; + int nrels = 0, + i = 0, + maxrels = 0; + SMgrRelation *srels = NULL; + + prev = NULL; + for (pending = pendingDeletes; pending != NULL; pending = next) + { + next = pending->next; + if (pending->nestLevel < nestLevel) + { + /* outer-level entries should not be processed yet */ + prev = pending; + } + else + { + /* unlink list entry first, so we don't retry on failure */ + if (prev) + prev->next = next; + else + pendingDeletes = next; + /* do deletion if called for */ + if (pending->atCommit == isCommit) + { + SMgrRelation srel; + + srel = smgropen(pending->relnode, pending->backend); + + /* allocate the initial array, or extend it, if needed */ + if (maxrels == 0) + { + maxrels = 8; + srels = palloc(sizeof(SMgrRelation) * maxrels); + } + else if (maxrels <= nrels) + { + maxrels *= 2; + srels = repalloc(srels, sizeof(SMgrRelation) * maxrels); + } + + srels[nrels++] = srel; + } + /* must explicitly free the list entry */ + pfree(pending); + /* prev does not change */ + } + } + + if (nrels > 0) + { + smgrdounlinkall(srels, nrels, false); + + for (i = 0; i < nrels; i++) + smgrclose(srels[i]); + + pfree(srels); + } +} + +/* + * smgrDoPendingSyncs() -- Take care of relation syncs at end of xact. + */ +void +smgrDoPendingSyncs(bool isCommit, bool isParallelWorker) +{ + PendingRelDelete *pending; + int nrels = 0, + maxrels = 0; + SMgrRelation *srels = NULL; + HASH_SEQ_STATUS scan; + PendingRelSync *pendingsync; + + Assert(GetCurrentTransactionNestLevel() == 1); + + if (!pendingSyncHash) + return; /* no relation needs sync */ + + /* Abort -- just throw away all pending syncs */ + if (!isCommit) + { + pendingSyncHash = NULL; + return; + } + + AssertPendingSyncs_RelationCache(); + + /* Parallel worker -- just throw away all pending syncs */ + if (isParallelWorker) + { + pendingSyncHash = NULL; + return; + } + + /* Skip syncing nodes that smgrDoPendingDeletes() will delete. */ + for (pending = pendingDeletes; pending != NULL; pending = pending->next) + if (pending->atCommit) + (void) hash_search(pendingSyncHash, (void *) &pending->relnode, + HASH_REMOVE, NULL); + + hash_seq_init(&scan, pendingSyncHash); + while ((pendingsync = (PendingRelSync *) hash_seq_search(&scan))) + { + ForkNumber fork; + BlockNumber nblocks[MAX_FORKNUM + 1]; + BlockNumber total_blocks = 0; + SMgrRelation srel; + + srel = smgropen(pendingsync->rnode, InvalidBackendId); + + /* + * We emit newpage WAL records for smaller relations. + * + * Small WAL records have a chance to be emitted along with other + * backends' WAL records. We emit WAL records instead of syncing for + * files that are smaller than a certain threshold, expecting faster + * commit. The threshold is defined by the GUC wal_skip_threshold. + */ + if (!pendingsync->is_truncated) + { + for (fork = 0; fork <= MAX_FORKNUM; fork++) + { + if (smgrexists(srel, fork)) + { + BlockNumber n = smgrnblocks(srel, fork); + + /* we shouldn't come here for unlogged relations */ + Assert(fork != INIT_FORKNUM); + nblocks[fork] = n; + total_blocks += n; + } + else + nblocks[fork] = InvalidBlockNumber; + } + } + + /* + * Sync file or emit WAL records for its contents. + * + * Although we emit WAL record if the file is small enough, do file + * sync regardless of the size if the file has experienced a + * truncation. It is because the file would be followed by trailing + * garbage blocks after a crash recovery if, while a past longer file + * had been flushed out, we omitted syncing-out of the file and + * emitted WAL instead. You might think that we could choose WAL if + * the current main fork is longer than ever, but there's a case where + * main fork is longer than ever but FSM fork gets shorter. + */ + if (pendingsync->is_truncated || + total_blocks * BLCKSZ / 1024 >= wal_skip_threshold) + { + /* allocate the initial array, or extend it, if needed */ + if (maxrels == 0) + { + maxrels = 8; + srels = palloc(sizeof(SMgrRelation) * maxrels); + } + else if (maxrels <= nrels) + { + maxrels *= 2; + srels = repalloc(srels, sizeof(SMgrRelation) * maxrels); + } + + srels[nrels++] = srel; + } + else + { + /* Emit WAL records for all blocks. The file is small enough. */ + for (fork = 0; fork <= MAX_FORKNUM; fork++) + { + int n = nblocks[fork]; + Relation rel; + + if (!BlockNumberIsValid(n)) + continue; + + /* + * Emit WAL for the whole file. Unfortunately we don't know + * what kind of a page this is, so we have to log the full + * page including any unused space. ReadBufferExtended() + * counts some pgstat events; unfortunately, we discard them. + */ + rel = CreateFakeRelcacheEntry(srel->smgr_rnode.node); + log_newpage_range(rel, fork, 0, n, false); + FreeFakeRelcacheEntry(rel); + } + } + } + + pendingSyncHash = NULL; + + if (nrels > 0) + { + smgrdosyncall(srels, nrels); + pfree(srels); + } +} + +/* + * smgrGetPendingDeletes() -- Get a list of non-temp relations to be deleted. + * + * The return value is the number of relations scheduled for termination. + * *ptr is set to point to a freshly-palloc'd array of RelFileNodes. + * If there are no relations to be deleted, *ptr is set to NULL. + * + * Only non-temporary relations are included in the returned list. This is OK + * because the list is used only in contexts where temporary relations don't + * matter: we're either writing to the two-phase state file (and transactions + * that have touched temp tables can't be prepared) or we're writing to xlog + * (and all temporary files will be zapped if we restart anyway, so no need + * for redo to do it also). + * + * Note that the list does not include anything scheduled for termination + * by upper-level transactions. + */ +int +smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr) +{ + int nestLevel = GetCurrentTransactionNestLevel(); + int nrels; + RelFileNode *rptr; + PendingRelDelete *pending; + + nrels = 0; + for (pending = pendingDeletes; pending != NULL; pending = pending->next) + { + if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit + && pending->backend == InvalidBackendId) + nrels++; + } + if (nrels == 0) + { + *ptr = NULL; + return 0; + } + rptr = (RelFileNode *) palloc(nrels * sizeof(RelFileNode)); + *ptr = rptr; + for (pending = pendingDeletes; pending != NULL; pending = pending->next) + { + if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit + && pending->backend == InvalidBackendId) + { + *rptr = pending->relnode; + rptr++; + } + } + return nrels; +} + +/* + * PostPrepare_smgr -- Clean up after a successful PREPARE + * + * What we have to do here is throw away the in-memory state about pending + * relation deletes. It's all been recorded in the 2PC state file and + * it's no longer smgr's job to worry about it. + */ +void +PostPrepare_smgr(void) +{ + PendingRelDelete *pending; + PendingRelDelete *next; + + for (pending = pendingDeletes; pending != NULL; pending = next) + { + next = pending->next; + pendingDeletes = next; + /* must explicitly free the list entry */ + pfree(pending); + } +} + + +/* + * AtSubCommit_smgr() --- Take care of subtransaction commit. + * + * Reassign all items in the pending-deletes list to the parent transaction. + */ +void +AtSubCommit_smgr(void) +{ + int nestLevel = GetCurrentTransactionNestLevel(); + PendingRelDelete *pending; + + for (pending = pendingDeletes; pending != NULL; pending = pending->next) + { + if (pending->nestLevel >= nestLevel) + pending->nestLevel = nestLevel - 1; + } +} + +/* + * AtSubAbort_smgr() --- Take care of subtransaction abort. + * + * Delete created relations and forget about deleted relations. + * We can execute these operations immediately because we know this + * subtransaction will not commit. + */ +void +AtSubAbort_smgr(void) +{ + smgrDoPendingDeletes(false); +} + +void +smgr_redo(XLogReaderState *record) +{ + XLogRecPtr lsn = record->EndRecPtr; + uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; + + /* Backup blocks are not used in smgr records */ + Assert(!XLogRecHasAnyBlockRefs(record)); + + if (info == XLOG_SMGR_CREATE) + { + xl_smgr_create *xlrec = (xl_smgr_create *) XLogRecGetData(record); + SMgrRelation reln; + + reln = smgropen(xlrec->rnode, InvalidBackendId); + smgrcreate(reln, xlrec->forkNum, true); + } + else if (info == XLOG_SMGR_TRUNCATE) + { + xl_smgr_truncate *xlrec = (xl_smgr_truncate *) XLogRecGetData(record); + SMgrRelation reln; + Relation rel; + ForkNumber forks[MAX_FORKNUM]; + BlockNumber blocks[MAX_FORKNUM]; + int nforks = 0; + bool need_fsm_vacuum = false; + + reln = smgropen(xlrec->rnode, InvalidBackendId); + + /* + * Forcibly create relation if it doesn't exist (which suggests that + * it was dropped somewhere later in the WAL sequence). As in + * XLogReadBufferForRedo, we prefer to recreate the rel and replay the + * log as best we can until the drop is seen. + */ + smgrcreate(reln, MAIN_FORKNUM, true); + + /* + * Before we perform the truncation, update minimum recovery point to + * cover this WAL record. Once the relation is truncated, there's no + * going back. The buffer manager enforces the WAL-first rule for + * normal updates to relation files, so that the minimum recovery + * point is always updated before the corresponding change in the data + * file is flushed to disk. We have to do the same manually here. + * + * Doing this before the truncation means that if the truncation fails + * for some reason, you cannot start up the system even after restart, + * until you fix the underlying situation so that the truncation will + * succeed. Alternatively, we could update the minimum recovery point + * after truncation, but that would leave a small window where the + * WAL-first rule could be violated. + */ + XLogFlush(lsn); + + /* Prepare for truncation of MAIN fork */ + if ((xlrec->flags & SMGR_TRUNCATE_HEAP) != 0) + { + forks[nforks] = MAIN_FORKNUM; + blocks[nforks] = xlrec->blkno; + nforks++; + + /* Also tell xlogutils.c about it */ + XLogTruncateRelation(xlrec->rnode, MAIN_FORKNUM, xlrec->blkno); + } + + /* Prepare for truncation of FSM and VM too */ + rel = CreateFakeRelcacheEntry(xlrec->rnode); + + if ((xlrec->flags & SMGR_TRUNCATE_FSM) != 0 && + smgrexists(reln, FSM_FORKNUM)) + { + blocks[nforks] = FreeSpaceMapPrepareTruncateRel(rel, xlrec->blkno); + if (BlockNumberIsValid(blocks[nforks])) + { + forks[nforks] = FSM_FORKNUM; + nforks++; + need_fsm_vacuum = true; + } + } + if ((xlrec->flags & SMGR_TRUNCATE_VM) != 0 && + smgrexists(reln, VISIBILITYMAP_FORKNUM)) + { + blocks[nforks] = visibilitymap_prepare_truncate(rel, xlrec->blkno); + if (BlockNumberIsValid(blocks[nforks])) + { + forks[nforks] = VISIBILITYMAP_FORKNUM; + nforks++; + } + } + + /* Do the real work to truncate relation forks */ + if (nforks > 0) + smgrtruncate(reln, forks, nforks, blocks); + + /* + * Update upper-level FSM pages to account for the truncation. This is + * important because the just-truncated pages were likely marked as + * all-free, and would be preferentially selected. + */ + if (need_fsm_vacuum) + FreeSpaceMapVacuumRange(rel, xlrec->blkno, + InvalidBlockNumber); + + FreeFakeRelcacheEntry(rel); + } + else + elog(PANIC, "smgr_redo: unknown op code %u", info); +} diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql new file mode 100644 index 0000000..51d738c --- /dev/null +++ b/src/backend/catalog/system_views.sql @@ -0,0 +1,1480 @@ +/* + * PostgreSQL System Views + * + * Copyright (c) 1996-2020, PostgreSQL Global Development Group + * + * src/backend/catalog/system_views.sql + * + * Note: this file is read in single-user -j mode, which means that the + * command terminator is semicolon-newline-newline; whenever the backend + * sees that, it stops and executes what it's got. If you write a lot of + * statements without empty lines between, they'll all get quoted to you + * in any error message about one of them, so don't do that. Also, you + * cannot write a semicolon immediately followed by an empty line in a + * string literal (including a function body!) or a multiline comment. + */ + +CREATE VIEW pg_roles AS + SELECT + rolname, + rolsuper, + rolinherit, + rolcreaterole, + rolcreatedb, + rolcanlogin, + rolreplication, + rolconnlimit, + '********'::text as rolpassword, + rolvaliduntil, + rolbypassrls, + setconfig as rolconfig, + pg_authid.oid + FROM pg_authid LEFT JOIN pg_db_role_setting s + ON (pg_authid.oid = setrole AND setdatabase = 0); + +CREATE VIEW pg_shadow AS + SELECT + rolname AS usename, + pg_authid.oid AS usesysid, + rolcreatedb AS usecreatedb, + rolsuper AS usesuper, + rolreplication AS userepl, + rolbypassrls AS usebypassrls, + rolpassword AS passwd, + rolvaliduntil AS valuntil, + setconfig AS useconfig + FROM pg_authid LEFT JOIN pg_db_role_setting s + ON (pg_authid.oid = setrole AND setdatabase = 0) + WHERE rolcanlogin; + +REVOKE ALL on pg_shadow FROM public; + +CREATE VIEW pg_group AS + SELECT + rolname AS groname, + oid AS grosysid, + ARRAY(SELECT member FROM pg_auth_members WHERE roleid = oid) AS grolist + FROM pg_authid + WHERE NOT rolcanlogin; + +CREATE VIEW pg_user AS + SELECT + usename, + usesysid, + usecreatedb, + usesuper, + userepl, + usebypassrls, + '********'::text as passwd, + valuntil, + useconfig + FROM pg_shadow; + +CREATE VIEW pg_policies AS + SELECT + N.nspname AS schemaname, + C.relname AS tablename, + pol.polname AS policyname, + CASE + WHEN pol.polpermissive THEN + 'PERMISSIVE' + ELSE + 'RESTRICTIVE' + END AS permissive, + CASE + WHEN pol.polroles = '{0}' THEN + string_to_array('public', '') + ELSE + ARRAY + ( + SELECT rolname + FROM pg_catalog.pg_authid + WHERE oid = ANY (pol.polroles) ORDER BY 1 + ) + END AS roles, + CASE pol.polcmd + WHEN 'r' THEN 'SELECT' + WHEN 'a' THEN 'INSERT' + WHEN 'w' THEN 'UPDATE' + WHEN 'd' THEN 'DELETE' + WHEN '*' THEN 'ALL' + END AS cmd, + pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS qual, + pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS with_check + FROM pg_catalog.pg_policy pol + JOIN pg_catalog.pg_class C ON (C.oid = pol.polrelid) + LEFT JOIN pg_catalog.pg_namespace N ON (N.oid = C.relnamespace); + +CREATE VIEW pg_rules AS + SELECT + N.nspname AS schemaname, + C.relname AS tablename, + R.rulename AS rulename, + pg_get_ruledef(R.oid) AS definition + FROM (pg_rewrite R JOIN pg_class C ON (C.oid = R.ev_class)) + LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) + WHERE R.rulename != '_RETURN'; + +CREATE VIEW pg_views AS + SELECT + N.nspname AS schemaname, + C.relname AS viewname, + pg_get_userbyid(C.relowner) AS viewowner, + pg_get_viewdef(C.oid) AS definition + FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) + WHERE C.relkind = 'v'; + +CREATE VIEW pg_tables AS + SELECT + N.nspname AS schemaname, + C.relname AS tablename, + pg_get_userbyid(C.relowner) AS tableowner, + T.spcname AS tablespace, + C.relhasindex AS hasindexes, + C.relhasrules AS hasrules, + C.relhastriggers AS hastriggers, + C.relrowsecurity AS rowsecurity + FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) + LEFT JOIN pg_tablespace T ON (T.oid = C.reltablespace) + WHERE C.relkind IN ('r', 'p'); + +CREATE VIEW pg_matviews AS + SELECT + N.nspname AS schemaname, + C.relname AS matviewname, + pg_get_userbyid(C.relowner) AS matviewowner, + T.spcname AS tablespace, + C.relhasindex AS hasindexes, + C.relispopulated AS ispopulated, + pg_get_viewdef(C.oid) AS definition + FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) + LEFT JOIN pg_tablespace T ON (T.oid = C.reltablespace) + WHERE C.relkind = 'm'; + +CREATE VIEW pg_indexes AS + SELECT + N.nspname AS schemaname, + C.relname AS tablename, + I.relname AS indexname, + T.spcname AS tablespace, + pg_get_indexdef(I.oid) AS indexdef + FROM pg_index X JOIN pg_class C ON (C.oid = X.indrelid) + JOIN pg_class I ON (I.oid = X.indexrelid) + LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) + LEFT JOIN pg_tablespace T ON (T.oid = I.reltablespace) + WHERE C.relkind IN ('r', 'm', 'p') AND I.relkind IN ('i', 'I'); + +CREATE OR REPLACE VIEW pg_sequences AS + SELECT + N.nspname AS schemaname, + C.relname AS sequencename, + pg_get_userbyid(C.relowner) AS sequenceowner, + S.seqtypid::regtype AS data_type, + S.seqstart AS start_value, + S.seqmin AS min_value, + S.seqmax AS max_value, + S.seqincrement AS increment_by, + S.seqcycle AS cycle, + S.seqcache AS cache_size, + CASE + WHEN has_sequence_privilege(C.oid, 'SELECT,USAGE'::text) + THEN pg_sequence_last_value(C.oid) + ELSE NULL + END AS last_value + FROM pg_sequence S JOIN pg_class C ON (C.oid = S.seqrelid) + LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) + WHERE NOT pg_is_other_temp_schema(N.oid) + AND relkind = 'S'; + +CREATE VIEW pg_stats WITH (security_barrier) AS + SELECT + nspname AS schemaname, + relname AS tablename, + attname AS attname, + stainherit AS inherited, + stanullfrac AS null_frac, + stawidth AS avg_width, + stadistinct AS n_distinct, + CASE + WHEN stakind1 = 1 THEN stavalues1 + WHEN stakind2 = 1 THEN stavalues2 + WHEN stakind3 = 1 THEN stavalues3 + WHEN stakind4 = 1 THEN stavalues4 + WHEN stakind5 = 1 THEN stavalues5 + END AS most_common_vals, + CASE + WHEN stakind1 = 1 THEN stanumbers1 + WHEN stakind2 = 1 THEN stanumbers2 + WHEN stakind3 = 1 THEN stanumbers3 + WHEN stakind4 = 1 THEN stanumbers4 + WHEN stakind5 = 1 THEN stanumbers5 + END AS most_common_freqs, + CASE + WHEN stakind1 = 2 THEN stavalues1 + WHEN stakind2 = 2 THEN stavalues2 + WHEN stakind3 = 2 THEN stavalues3 + WHEN stakind4 = 2 THEN stavalues4 + WHEN stakind5 = 2 THEN stavalues5 + END AS histogram_bounds, + CASE + WHEN stakind1 = 3 THEN stanumbers1[1] + WHEN stakind2 = 3 THEN stanumbers2[1] + WHEN stakind3 = 3 THEN stanumbers3[1] + WHEN stakind4 = 3 THEN stanumbers4[1] + WHEN stakind5 = 3 THEN stanumbers5[1] + END AS correlation, + CASE + WHEN stakind1 = 4 THEN stavalues1 + WHEN stakind2 = 4 THEN stavalues2 + WHEN stakind3 = 4 THEN stavalues3 + WHEN stakind4 = 4 THEN stavalues4 + WHEN stakind5 = 4 THEN stavalues5 + END AS most_common_elems, + CASE + WHEN stakind1 = 4 THEN stanumbers1 + WHEN stakind2 = 4 THEN stanumbers2 + WHEN stakind3 = 4 THEN stanumbers3 + WHEN stakind4 = 4 THEN stanumbers4 + WHEN stakind5 = 4 THEN stanumbers5 + END AS most_common_elem_freqs, + CASE + WHEN stakind1 = 5 THEN stanumbers1 + WHEN stakind2 = 5 THEN stanumbers2 + WHEN stakind3 = 5 THEN stanumbers3 + WHEN stakind4 = 5 THEN stanumbers4 + WHEN stakind5 = 5 THEN stanumbers5 + END AS elem_count_histogram + FROM pg_statistic s JOIN pg_class c ON (c.oid = s.starelid) + JOIN pg_attribute a ON (c.oid = attrelid AND attnum = s.staattnum) + LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace) + WHERE NOT attisdropped + AND has_column_privilege(c.oid, a.attnum, 'select') + AND (c.relrowsecurity = false OR NOT row_security_active(c.oid)); + +REVOKE ALL on pg_statistic FROM public; + +CREATE VIEW pg_stats_ext WITH (security_barrier) AS + SELECT cn.nspname AS schemaname, + c.relname AS tablename, + sn.nspname AS statistics_schemaname, + s.stxname AS statistics_name, + pg_get_userbyid(s.stxowner) AS statistics_owner, + ( SELECT array_agg(a.attname ORDER BY a.attnum) + FROM unnest(s.stxkeys) k + JOIN pg_attribute a + ON (a.attrelid = s.stxrelid AND a.attnum = k) + ) AS attnames, + s.stxkind AS kinds, + sd.stxdndistinct AS n_distinct, + sd.stxddependencies AS dependencies, + m.most_common_vals, + m.most_common_val_nulls, + m.most_common_freqs, + m.most_common_base_freqs + FROM pg_statistic_ext s JOIN pg_class c ON (c.oid = s.stxrelid) + JOIN pg_statistic_ext_data sd ON (s.oid = sd.stxoid) + LEFT JOIN pg_namespace cn ON (cn.oid = c.relnamespace) + LEFT JOIN pg_namespace sn ON (sn.oid = s.stxnamespace) + LEFT JOIN LATERAL + ( SELECT array_agg(values) AS most_common_vals, + array_agg(nulls) AS most_common_val_nulls, + array_agg(frequency) AS most_common_freqs, + array_agg(base_frequency) AS most_common_base_freqs + FROM pg_mcv_list_items(sd.stxdmcv) + ) m ON sd.stxdmcv IS NOT NULL + WHERE NOT EXISTS + ( SELECT 1 + FROM unnest(stxkeys) k + JOIN pg_attribute a + ON (a.attrelid = s.stxrelid AND a.attnum = k) + WHERE NOT has_column_privilege(c.oid, a.attnum, 'select') ) + AND (c.relrowsecurity = false OR NOT row_security_active(c.oid)); + +-- unprivileged users may read pg_statistic_ext but not pg_statistic_ext_data +REVOKE ALL on pg_statistic_ext_data FROM public; + +CREATE VIEW pg_publication_tables AS + SELECT + P.pubname AS pubname, + N.nspname AS schemaname, + C.relname AS tablename + FROM pg_publication P, + LATERAL pg_get_publication_tables(P.pubname) GPT, + pg_class C JOIN pg_namespace N ON (N.oid = C.relnamespace) + WHERE C.oid = GPT.relid; + +CREATE VIEW pg_locks AS + SELECT * FROM pg_lock_status() AS L; + +CREATE VIEW pg_cursors AS + SELECT * FROM pg_cursor() AS C; + +CREATE VIEW pg_available_extensions AS + SELECT E.name, E.default_version, X.extversion AS installed_version, + E.comment + FROM pg_available_extensions() AS E + LEFT JOIN pg_extension AS X ON E.name = X.extname; + +CREATE VIEW pg_available_extension_versions AS + SELECT E.name, E.version, (X.extname IS NOT NULL) AS installed, + E.superuser, E.trusted, E.relocatable, + E.schema, E.requires, E.comment + FROM pg_available_extension_versions() AS E + LEFT JOIN pg_extension AS X + ON E.name = X.extname AND E.version = X.extversion; + +CREATE VIEW pg_prepared_xacts AS + SELECT P.transaction, P.gid, P.prepared, + U.rolname AS owner, D.datname AS database + FROM pg_prepared_xact() AS P + LEFT JOIN pg_authid U ON P.ownerid = U.oid + LEFT JOIN pg_database D ON P.dbid = D.oid; + +CREATE VIEW pg_prepared_statements AS + SELECT * FROM pg_prepared_statement() AS P; + +CREATE VIEW pg_seclabels AS +SELECT + l.objoid, l.classoid, l.objsubid, + CASE WHEN rel.relkind IN ('r', 'p') THEN 'table'::text + WHEN rel.relkind = 'v' THEN 'view'::text + WHEN rel.relkind = 'm' THEN 'materialized view'::text + WHEN rel.relkind = 'S' THEN 'sequence'::text + WHEN rel.relkind = 'f' THEN 'foreign table'::text END AS objtype, + rel.relnamespace AS objnamespace, + CASE WHEN pg_table_is_visible(rel.oid) + THEN quote_ident(rel.relname) + ELSE quote_ident(nsp.nspname) || '.' || quote_ident(rel.relname) + END AS objname, + l.provider, l.label +FROM + pg_seclabel l + JOIN pg_class rel ON l.classoid = rel.tableoid AND l.objoid = rel.oid + JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid +WHERE + l.objsubid = 0 +UNION ALL +SELECT + l.objoid, l.classoid, l.objsubid, + 'column'::text AS objtype, + rel.relnamespace AS objnamespace, + CASE WHEN pg_table_is_visible(rel.oid) + THEN quote_ident(rel.relname) + ELSE quote_ident(nsp.nspname) || '.' || quote_ident(rel.relname) + END || '.' || att.attname AS objname, + l.provider, l.label +FROM + pg_seclabel l + JOIN pg_class rel ON l.classoid = rel.tableoid AND l.objoid = rel.oid + JOIN pg_attribute att + ON rel.oid = att.attrelid AND l.objsubid = att.attnum + JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid +WHERE + l.objsubid != 0 +UNION ALL +SELECT + l.objoid, l.classoid, l.objsubid, + CASE pro.prokind + WHEN 'a' THEN 'aggregate'::text + WHEN 'f' THEN 'function'::text + WHEN 'p' THEN 'procedure'::text + WHEN 'w' THEN 'window'::text END AS objtype, + pro.pronamespace AS objnamespace, + CASE WHEN pg_function_is_visible(pro.oid) + THEN quote_ident(pro.proname) + ELSE quote_ident(nsp.nspname) || '.' || quote_ident(pro.proname) + END || '(' || pg_catalog.pg_get_function_arguments(pro.oid) || ')' AS objname, + l.provider, l.label +FROM + pg_seclabel l + JOIN pg_proc pro ON l.classoid = pro.tableoid AND l.objoid = pro.oid + JOIN pg_namespace nsp ON pro.pronamespace = nsp.oid +WHERE + l.objsubid = 0 +UNION ALL +SELECT + l.objoid, l.classoid, l.objsubid, + CASE WHEN typ.typtype = 'd' THEN 'domain'::text + ELSE 'type'::text END AS objtype, + typ.typnamespace AS objnamespace, + CASE WHEN pg_type_is_visible(typ.oid) + THEN quote_ident(typ.typname) + ELSE quote_ident(nsp.nspname) || '.' || quote_ident(typ.typname) + END AS objname, + l.provider, l.label +FROM + pg_seclabel l + JOIN pg_type typ ON l.classoid = typ.tableoid AND l.objoid = typ.oid + JOIN pg_namespace nsp ON typ.typnamespace = nsp.oid +WHERE + l.objsubid = 0 +UNION ALL +SELECT + l.objoid, l.classoid, l.objsubid, + 'large object'::text AS objtype, + NULL::oid AS objnamespace, + l.objoid::text AS objname, + l.provider, l.label +FROM + pg_seclabel l + JOIN pg_largeobject_metadata lom ON l.objoid = lom.oid +WHERE + l.classoid = 'pg_catalog.pg_largeobject'::regclass AND l.objsubid = 0 +UNION ALL +SELECT + l.objoid, l.classoid, l.objsubid, + 'language'::text AS objtype, + NULL::oid AS objnamespace, + quote_ident(lan.lanname) AS objname, + l.provider, l.label +FROM + pg_seclabel l + JOIN pg_language lan ON l.classoid = lan.tableoid AND l.objoid = lan.oid +WHERE + l.objsubid = 0 +UNION ALL +SELECT + l.objoid, l.classoid, l.objsubid, + 'schema'::text AS objtype, + nsp.oid AS objnamespace, + quote_ident(nsp.nspname) AS objname, + l.provider, l.label +FROM + pg_seclabel l + JOIN pg_namespace nsp ON l.classoid = nsp.tableoid AND l.objoid = nsp.oid +WHERE + l.objsubid = 0 +UNION ALL +SELECT + l.objoid, l.classoid, l.objsubid, + 'event trigger'::text AS objtype, + NULL::oid AS objnamespace, + quote_ident(evt.evtname) AS objname, + l.provider, l.label +FROM + pg_seclabel l + JOIN pg_event_trigger evt ON l.classoid = evt.tableoid + AND l.objoid = evt.oid +WHERE + l.objsubid = 0 +UNION ALL +SELECT + l.objoid, l.classoid, l.objsubid, + 'publication'::text AS objtype, + NULL::oid AS objnamespace, + quote_ident(p.pubname) AS objname, + l.provider, l.label +FROM + pg_seclabel l + JOIN pg_publication p ON l.classoid = p.tableoid AND l.objoid = p.oid +WHERE + l.objsubid = 0 +UNION ALL +SELECT + l.objoid, l.classoid, 0::int4 AS objsubid, + 'subscription'::text AS objtype, + NULL::oid AS objnamespace, + quote_ident(s.subname) AS objname, + l.provider, l.label +FROM + pg_shseclabel l + JOIN pg_subscription s ON l.classoid = s.tableoid AND l.objoid = s.oid +UNION ALL +SELECT + l.objoid, l.classoid, 0::int4 AS objsubid, + 'database'::text AS objtype, + NULL::oid AS objnamespace, + quote_ident(dat.datname) AS objname, + l.provider, l.label +FROM + pg_shseclabel l + JOIN pg_database dat ON l.classoid = dat.tableoid AND l.objoid = dat.oid +UNION ALL +SELECT + l.objoid, l.classoid, 0::int4 AS objsubid, + 'tablespace'::text AS objtype, + NULL::oid AS objnamespace, + quote_ident(spc.spcname) AS objname, + l.provider, l.label +FROM + pg_shseclabel l + JOIN pg_tablespace spc ON l.classoid = spc.tableoid AND l.objoid = spc.oid +UNION ALL +SELECT + l.objoid, l.classoid, 0::int4 AS objsubid, + 'role'::text AS objtype, + NULL::oid AS objnamespace, + quote_ident(rol.rolname) AS objname, + l.provider, l.label +FROM + pg_shseclabel l + JOIN pg_authid rol ON l.classoid = rol.tableoid AND l.objoid = rol.oid; + +CREATE VIEW pg_settings AS + SELECT * FROM pg_show_all_settings() AS A; + +CREATE RULE pg_settings_u AS + ON UPDATE TO pg_settings + WHERE new.name = old.name DO + SELECT set_config(old.name, new.setting, 'f'); + +CREATE RULE pg_settings_n AS + ON UPDATE TO pg_settings + DO INSTEAD NOTHING; + +GRANT SELECT, UPDATE ON pg_settings TO PUBLIC; + +CREATE VIEW pg_file_settings AS + SELECT * FROM pg_show_all_file_settings() AS A; + +REVOKE ALL on pg_file_settings FROM PUBLIC; +REVOKE EXECUTE ON FUNCTION pg_show_all_file_settings() FROM PUBLIC; + +CREATE VIEW pg_hba_file_rules AS + SELECT * FROM pg_hba_file_rules() AS A; + +REVOKE ALL on pg_hba_file_rules FROM PUBLIC; +REVOKE EXECUTE ON FUNCTION pg_hba_file_rules() FROM PUBLIC; + +CREATE VIEW pg_timezone_abbrevs AS + SELECT * FROM pg_timezone_abbrevs(); + +CREATE VIEW pg_timezone_names AS + SELECT * FROM pg_timezone_names(); + +CREATE VIEW pg_config AS + SELECT * FROM pg_config(); + +REVOKE ALL on pg_config FROM PUBLIC; +REVOKE EXECUTE ON FUNCTION pg_config() FROM PUBLIC; + +CREATE VIEW pg_shmem_allocations AS + SELECT * FROM pg_get_shmem_allocations(); + +REVOKE ALL ON pg_shmem_allocations FROM PUBLIC; +REVOKE EXECUTE ON FUNCTION pg_get_shmem_allocations() FROM PUBLIC; + +-- Statistics views + +CREATE VIEW pg_stat_all_tables AS + SELECT + C.oid AS relid, + N.nspname AS schemaname, + C.relname AS relname, + pg_stat_get_numscans(C.oid) AS seq_scan, + pg_stat_get_tuples_returned(C.oid) AS seq_tup_read, + sum(pg_stat_get_numscans(I.indexrelid))::bigint AS idx_scan, + sum(pg_stat_get_tuples_fetched(I.indexrelid))::bigint + + pg_stat_get_tuples_fetched(C.oid) AS idx_tup_fetch, + pg_stat_get_tuples_inserted(C.oid) AS n_tup_ins, + pg_stat_get_tuples_updated(C.oid) AS n_tup_upd, + pg_stat_get_tuples_deleted(C.oid) AS n_tup_del, + pg_stat_get_tuples_hot_updated(C.oid) AS n_tup_hot_upd, + pg_stat_get_live_tuples(C.oid) AS n_live_tup, + pg_stat_get_dead_tuples(C.oid) AS n_dead_tup, + pg_stat_get_mod_since_analyze(C.oid) AS n_mod_since_analyze, + pg_stat_get_ins_since_vacuum(C.oid) AS n_ins_since_vacuum, + pg_stat_get_last_vacuum_time(C.oid) as last_vacuum, + pg_stat_get_last_autovacuum_time(C.oid) as last_autovacuum, + pg_stat_get_last_analyze_time(C.oid) as last_analyze, + pg_stat_get_last_autoanalyze_time(C.oid) as last_autoanalyze, + pg_stat_get_vacuum_count(C.oid) AS vacuum_count, + pg_stat_get_autovacuum_count(C.oid) AS autovacuum_count, + pg_stat_get_analyze_count(C.oid) AS analyze_count, + pg_stat_get_autoanalyze_count(C.oid) AS autoanalyze_count + FROM pg_class C LEFT JOIN + pg_index I ON C.oid = I.indrelid + LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) + WHERE C.relkind IN ('r', 't', 'm') + GROUP BY C.oid, N.nspname, C.relname; + +CREATE VIEW pg_stat_xact_all_tables AS + SELECT + C.oid AS relid, + N.nspname AS schemaname, + C.relname AS relname, + pg_stat_get_xact_numscans(C.oid) AS seq_scan, + pg_stat_get_xact_tuples_returned(C.oid) AS seq_tup_read, + sum(pg_stat_get_xact_numscans(I.indexrelid))::bigint AS idx_scan, + sum(pg_stat_get_xact_tuples_fetched(I.indexrelid))::bigint + + pg_stat_get_xact_tuples_fetched(C.oid) AS idx_tup_fetch, + pg_stat_get_xact_tuples_inserted(C.oid) AS n_tup_ins, + pg_stat_get_xact_tuples_updated(C.oid) AS n_tup_upd, + pg_stat_get_xact_tuples_deleted(C.oid) AS n_tup_del, + pg_stat_get_xact_tuples_hot_updated(C.oid) AS n_tup_hot_upd + FROM pg_class C LEFT JOIN + pg_index I ON C.oid = I.indrelid + LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) + WHERE C.relkind IN ('r', 't', 'm') + GROUP BY C.oid, N.nspname, C.relname; + +CREATE VIEW pg_stat_sys_tables AS + SELECT * FROM pg_stat_all_tables + WHERE schemaname IN ('pg_catalog', 'information_schema') OR + schemaname ~ '^pg_toast'; + +CREATE VIEW pg_stat_xact_sys_tables AS + SELECT * FROM pg_stat_xact_all_tables + WHERE schemaname IN ('pg_catalog', 'information_schema') OR + schemaname ~ '^pg_toast'; + +CREATE VIEW pg_stat_user_tables AS + SELECT * FROM pg_stat_all_tables + WHERE schemaname NOT IN ('pg_catalog', 'information_schema') AND + schemaname !~ '^pg_toast'; + +CREATE VIEW pg_stat_xact_user_tables AS + SELECT * FROM pg_stat_xact_all_tables + WHERE schemaname NOT IN ('pg_catalog', 'information_schema') AND + schemaname !~ '^pg_toast'; + +CREATE VIEW pg_statio_all_tables AS + SELECT + C.oid AS relid, + N.nspname AS schemaname, + C.relname AS relname, + pg_stat_get_blocks_fetched(C.oid) - + pg_stat_get_blocks_hit(C.oid) AS heap_blks_read, + pg_stat_get_blocks_hit(C.oid) AS heap_blks_hit, + sum(pg_stat_get_blocks_fetched(I.indexrelid) - + pg_stat_get_blocks_hit(I.indexrelid))::bigint AS idx_blks_read, + sum(pg_stat_get_blocks_hit(I.indexrelid))::bigint AS idx_blks_hit, + pg_stat_get_blocks_fetched(T.oid) - + pg_stat_get_blocks_hit(T.oid) AS toast_blks_read, + pg_stat_get_blocks_hit(T.oid) AS toast_blks_hit, + pg_stat_get_blocks_fetched(X.indexrelid) - + pg_stat_get_blocks_hit(X.indexrelid) AS tidx_blks_read, + pg_stat_get_blocks_hit(X.indexrelid) AS tidx_blks_hit + FROM pg_class C LEFT JOIN + pg_index I ON C.oid = I.indrelid LEFT JOIN + pg_class T ON C.reltoastrelid = T.oid LEFT JOIN + pg_index X ON T.oid = X.indrelid + LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) + WHERE C.relkind IN ('r', 't', 'm') + GROUP BY C.oid, N.nspname, C.relname, T.oid, X.indexrelid; + +CREATE VIEW pg_statio_sys_tables AS + SELECT * FROM pg_statio_all_tables + WHERE schemaname IN ('pg_catalog', 'information_schema') OR + schemaname ~ '^pg_toast'; + +CREATE VIEW pg_statio_user_tables AS + SELECT * FROM pg_statio_all_tables + WHERE schemaname NOT IN ('pg_catalog', 'information_schema') AND + schemaname !~ '^pg_toast'; + +CREATE VIEW pg_stat_all_indexes AS + SELECT + C.oid AS relid, + I.oid AS indexrelid, + N.nspname AS schemaname, + C.relname AS relname, + I.relname AS indexrelname, + pg_stat_get_numscans(I.oid) AS idx_scan, + pg_stat_get_tuples_returned(I.oid) AS idx_tup_read, + pg_stat_get_tuples_fetched(I.oid) AS idx_tup_fetch + FROM pg_class C JOIN + pg_index X ON C.oid = X.indrelid JOIN + pg_class I ON I.oid = X.indexrelid + LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) + WHERE C.relkind IN ('r', 't', 'm'); + +CREATE VIEW pg_stat_sys_indexes AS + SELECT * FROM pg_stat_all_indexes + WHERE schemaname IN ('pg_catalog', 'information_schema') OR + schemaname ~ '^pg_toast'; + +CREATE VIEW pg_stat_user_indexes AS + SELECT * FROM pg_stat_all_indexes + WHERE schemaname NOT IN ('pg_catalog', 'information_schema') AND + schemaname !~ '^pg_toast'; + +CREATE VIEW pg_statio_all_indexes AS + SELECT + C.oid AS relid, + I.oid AS indexrelid, + N.nspname AS schemaname, + C.relname AS relname, + I.relname AS indexrelname, + pg_stat_get_blocks_fetched(I.oid) - + pg_stat_get_blocks_hit(I.oid) AS idx_blks_read, + pg_stat_get_blocks_hit(I.oid) AS idx_blks_hit + FROM pg_class C JOIN + pg_index X ON C.oid = X.indrelid JOIN + pg_class I ON I.oid = X.indexrelid + LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) + WHERE C.relkind IN ('r', 't', 'm'); + +CREATE VIEW pg_statio_sys_indexes AS + SELECT * FROM pg_statio_all_indexes + WHERE schemaname IN ('pg_catalog', 'information_schema') OR + schemaname ~ '^pg_toast'; + +CREATE VIEW pg_statio_user_indexes AS + SELECT * FROM pg_statio_all_indexes + WHERE schemaname NOT IN ('pg_catalog', 'information_schema') AND + schemaname !~ '^pg_toast'; + +CREATE VIEW pg_statio_all_sequences AS + SELECT + C.oid AS relid, + N.nspname AS schemaname, + C.relname AS relname, + pg_stat_get_blocks_fetched(C.oid) - + pg_stat_get_blocks_hit(C.oid) AS blks_read, + pg_stat_get_blocks_hit(C.oid) AS blks_hit + FROM pg_class C + LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) + WHERE C.relkind = 'S'; + +CREATE VIEW pg_statio_sys_sequences AS + SELECT * FROM pg_statio_all_sequences + WHERE schemaname IN ('pg_catalog', 'information_schema') OR + schemaname ~ '^pg_toast'; + +CREATE VIEW pg_statio_user_sequences AS + SELECT * FROM pg_statio_all_sequences + WHERE schemaname NOT IN ('pg_catalog', 'information_schema') AND + schemaname !~ '^pg_toast'; + +CREATE VIEW pg_stat_activity AS + SELECT + S.datid AS datid, + D.datname AS datname, + S.pid, + S.leader_pid, + S.usesysid, + U.rolname AS usename, + S.application_name, + S.client_addr, + S.client_hostname, + S.client_port, + S.backend_start, + S.xact_start, + S.query_start, + S.state_change, + S.wait_event_type, + S.wait_event, + S.state, + S.backend_xid, + s.backend_xmin, + S.query, + S.backend_type + FROM pg_stat_get_activity(NULL) AS S + LEFT JOIN pg_database AS D ON (S.datid = D.oid) + LEFT JOIN pg_authid AS U ON (S.usesysid = U.oid); + +CREATE VIEW pg_stat_replication AS + SELECT + S.pid, + S.usesysid, + U.rolname AS usename, + S.application_name, + S.client_addr, + S.client_hostname, + S.client_port, + S.backend_start, + S.backend_xmin, + W.state, + W.sent_lsn, + W.write_lsn, + W.flush_lsn, + W.replay_lsn, + W.write_lag, + W.flush_lag, + W.replay_lag, + W.sync_priority, + W.sync_state, + W.reply_time + FROM pg_stat_get_activity(NULL) AS S + JOIN pg_stat_get_wal_senders() AS W ON (S.pid = W.pid) + LEFT JOIN pg_authid AS U ON (S.usesysid = U.oid); + +CREATE VIEW pg_stat_slru AS + SELECT + s.name, + s.blks_zeroed, + s.blks_hit, + s.blks_read, + s.blks_written, + s.blks_exists, + s.flushes, + s.truncates, + s.stats_reset + FROM pg_stat_get_slru() s; + +CREATE VIEW pg_stat_wal_receiver AS + SELECT + s.pid, + s.status, + s.receive_start_lsn, + s.receive_start_tli, + s.written_lsn, + s.flushed_lsn, + s.received_tli, + s.last_msg_send_time, + s.last_msg_receipt_time, + s.latest_end_lsn, + s.latest_end_time, + s.slot_name, + s.sender_host, + s.sender_port, + s.conninfo + FROM pg_stat_get_wal_receiver() s + WHERE s.pid IS NOT NULL; + +CREATE VIEW pg_stat_subscription AS + SELECT + su.oid AS subid, + su.subname, + st.pid, + st.relid, + st.received_lsn, + st.last_msg_send_time, + st.last_msg_receipt_time, + st.latest_end_lsn, + st.latest_end_time + FROM pg_subscription su + LEFT JOIN pg_stat_get_subscription(NULL) st + ON (st.subid = su.oid); + +CREATE VIEW pg_stat_ssl AS + SELECT + S.pid, + S.ssl, + S.sslversion AS version, + S.sslcipher AS cipher, + S.sslbits AS bits, + S.sslcompression AS compression, + S.ssl_client_dn AS client_dn, + S.ssl_client_serial AS client_serial, + S.ssl_issuer_dn AS issuer_dn + FROM pg_stat_get_activity(NULL) AS S + WHERE S.client_port IS NOT NULL; + +CREATE VIEW pg_stat_gssapi AS + SELECT + S.pid, + S.gss_auth AS gss_authenticated, + S.gss_princ AS principal, + S.gss_enc AS encrypted + FROM pg_stat_get_activity(NULL) AS S + WHERE S.client_port IS NOT NULL; + +CREATE VIEW pg_replication_slots AS + SELECT + L.slot_name, + L.plugin, + L.slot_type, + L.datoid, + D.datname AS database, + L.temporary, + L.active, + L.active_pid, + L.xmin, + L.catalog_xmin, + L.restart_lsn, + L.confirmed_flush_lsn, + L.wal_status, + L.safe_wal_size + FROM pg_get_replication_slots() AS L + LEFT JOIN pg_database D ON (L.datoid = D.oid); + +CREATE VIEW pg_stat_database AS + SELECT + D.oid AS datid, + D.datname AS datname, + CASE + WHEN (D.oid = (0)::oid) THEN 0 + ELSE pg_stat_get_db_numbackends(D.oid) + END AS numbackends, + pg_stat_get_db_xact_commit(D.oid) AS xact_commit, + pg_stat_get_db_xact_rollback(D.oid) AS xact_rollback, + pg_stat_get_db_blocks_fetched(D.oid) - + pg_stat_get_db_blocks_hit(D.oid) AS blks_read, + pg_stat_get_db_blocks_hit(D.oid) AS blks_hit, + pg_stat_get_db_tuples_returned(D.oid) AS tup_returned, + pg_stat_get_db_tuples_fetched(D.oid) AS tup_fetched, + pg_stat_get_db_tuples_inserted(D.oid) AS tup_inserted, + pg_stat_get_db_tuples_updated(D.oid) AS tup_updated, + pg_stat_get_db_tuples_deleted(D.oid) AS tup_deleted, + pg_stat_get_db_conflict_all(D.oid) AS conflicts, + pg_stat_get_db_temp_files(D.oid) AS temp_files, + pg_stat_get_db_temp_bytes(D.oid) AS temp_bytes, + pg_stat_get_db_deadlocks(D.oid) AS deadlocks, + pg_stat_get_db_checksum_failures(D.oid) AS checksum_failures, + pg_stat_get_db_checksum_last_failure(D.oid) AS checksum_last_failure, + pg_stat_get_db_blk_read_time(D.oid) AS blk_read_time, + pg_stat_get_db_blk_write_time(D.oid) AS blk_write_time, + pg_stat_get_db_stat_reset_time(D.oid) AS stats_reset + FROM ( + SELECT 0 AS oid, NULL::name AS datname + UNION ALL + SELECT oid, datname FROM pg_database + ) D; + +CREATE VIEW pg_stat_database_conflicts AS + SELECT + D.oid AS datid, + D.datname AS datname, + pg_stat_get_db_conflict_tablespace(D.oid) AS confl_tablespace, + pg_stat_get_db_conflict_lock(D.oid) AS confl_lock, + pg_stat_get_db_conflict_snapshot(D.oid) AS confl_snapshot, + pg_stat_get_db_conflict_bufferpin(D.oid) AS confl_bufferpin, + pg_stat_get_db_conflict_startup_deadlock(D.oid) AS confl_deadlock + FROM pg_database D; + +CREATE VIEW pg_stat_user_functions AS + SELECT + P.oid AS funcid, + N.nspname AS schemaname, + P.proname AS funcname, + pg_stat_get_function_calls(P.oid) AS calls, + pg_stat_get_function_total_time(P.oid) AS total_time, + pg_stat_get_function_self_time(P.oid) AS self_time + FROM pg_proc P LEFT JOIN pg_namespace N ON (N.oid = P.pronamespace) + WHERE P.prolang != 12 -- fast check to eliminate built-in functions + AND pg_stat_get_function_calls(P.oid) IS NOT NULL; + +CREATE VIEW pg_stat_xact_user_functions AS + SELECT + P.oid AS funcid, + N.nspname AS schemaname, + P.proname AS funcname, + pg_stat_get_xact_function_calls(P.oid) AS calls, + pg_stat_get_xact_function_total_time(P.oid) AS total_time, + pg_stat_get_xact_function_self_time(P.oid) AS self_time + FROM pg_proc P LEFT JOIN pg_namespace N ON (N.oid = P.pronamespace) + WHERE P.prolang != 12 -- fast check to eliminate built-in functions + AND pg_stat_get_xact_function_calls(P.oid) IS NOT NULL; + +CREATE VIEW pg_stat_archiver AS + SELECT + s.archived_count, + s.last_archived_wal, + s.last_archived_time, + s.failed_count, + s.last_failed_wal, + s.last_failed_time, + s.stats_reset + FROM pg_stat_get_archiver() s; + +CREATE VIEW pg_stat_bgwriter AS + SELECT + pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed, + pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req, + pg_stat_get_checkpoint_write_time() AS checkpoint_write_time, + pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time, + pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint, + pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean, + pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean, + pg_stat_get_buf_written_backend() AS buffers_backend, + pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync, + pg_stat_get_buf_alloc() AS buffers_alloc, + pg_stat_get_bgwriter_stat_reset_time() AS stats_reset; + +CREATE VIEW pg_stat_progress_analyze AS + SELECT + S.pid AS pid, S.datid AS datid, D.datname AS datname, + CAST(S.relid AS oid) AS relid, + CASE S.param1 WHEN 0 THEN 'initializing' + WHEN 1 THEN 'acquiring sample rows' + WHEN 2 THEN 'acquiring inherited sample rows' + WHEN 3 THEN 'computing statistics' + WHEN 4 THEN 'computing extended statistics' + WHEN 5 THEN 'finalizing analyze' + END AS phase, + S.param2 AS sample_blks_total, + S.param3 AS sample_blks_scanned, + S.param4 AS ext_stats_total, + S.param5 AS ext_stats_computed, + S.param6 AS child_tables_total, + S.param7 AS child_tables_done, + CAST(S.param8 AS oid) AS current_child_table_relid + FROM pg_stat_get_progress_info('ANALYZE') AS S + LEFT JOIN pg_database D ON S.datid = D.oid; + +CREATE VIEW pg_stat_progress_vacuum AS + SELECT + S.pid AS pid, S.datid AS datid, D.datname AS datname, + S.relid AS relid, + CASE S.param1 WHEN 0 THEN 'initializing' + WHEN 1 THEN 'scanning heap' + WHEN 2 THEN 'vacuuming indexes' + WHEN 3 THEN 'vacuuming heap' + WHEN 4 THEN 'cleaning up indexes' + WHEN 5 THEN 'truncating heap' + WHEN 6 THEN 'performing final cleanup' + END AS phase, + S.param2 AS heap_blks_total, S.param3 AS heap_blks_scanned, + S.param4 AS heap_blks_vacuumed, S.param5 AS index_vacuum_count, + S.param6 AS max_dead_tuples, S.param7 AS num_dead_tuples + FROM pg_stat_get_progress_info('VACUUM') AS S + LEFT JOIN pg_database D ON S.datid = D.oid; + +CREATE VIEW pg_stat_progress_cluster AS + SELECT + S.pid AS pid, + S.datid AS datid, + D.datname AS datname, + S.relid AS relid, + CASE S.param1 WHEN 1 THEN 'CLUSTER' + WHEN 2 THEN 'VACUUM FULL' + END AS command, + CASE S.param2 WHEN 0 THEN 'initializing' + WHEN 1 THEN 'seq scanning heap' + WHEN 2 THEN 'index scanning heap' + WHEN 3 THEN 'sorting tuples' + WHEN 4 THEN 'writing new heap' + WHEN 5 THEN 'swapping relation files' + WHEN 6 THEN 'rebuilding index' + WHEN 7 THEN 'performing final cleanup' + END AS phase, + CAST(S.param3 AS oid) AS cluster_index_relid, + S.param4 AS heap_tuples_scanned, + S.param5 AS heap_tuples_written, + S.param6 AS heap_blks_total, + S.param7 AS heap_blks_scanned, + S.param8 AS index_rebuild_count + FROM pg_stat_get_progress_info('CLUSTER') AS S + LEFT JOIN pg_database D ON S.datid = D.oid; + +CREATE VIEW pg_stat_progress_create_index AS + SELECT + S.pid AS pid, S.datid AS datid, D.datname AS datname, + S.relid AS relid, + CAST(S.param7 AS oid) AS index_relid, + CASE S.param1 WHEN 1 THEN 'CREATE INDEX' + WHEN 2 THEN 'CREATE INDEX CONCURRENTLY' + WHEN 3 THEN 'REINDEX' + WHEN 4 THEN 'REINDEX CONCURRENTLY' + END AS command, + CASE S.param10 WHEN 0 THEN 'initializing' + WHEN 1 THEN 'waiting for writers before build' + WHEN 2 THEN 'building index' || + COALESCE((': ' || pg_indexam_progress_phasename(S.param9::oid, S.param11)), + '') + WHEN 3 THEN 'waiting for writers before validation' + WHEN 4 THEN 'index validation: scanning index' + WHEN 5 THEN 'index validation: sorting tuples' + WHEN 6 THEN 'index validation: scanning table' + WHEN 7 THEN 'waiting for old snapshots' + WHEN 8 THEN 'waiting for readers before marking dead' + WHEN 9 THEN 'waiting for readers before dropping' + END as phase, + S.param4 AS lockers_total, + S.param5 AS lockers_done, + S.param6 AS current_locker_pid, + S.param16 AS blocks_total, + S.param17 AS blocks_done, + S.param12 AS tuples_total, + S.param13 AS tuples_done, + S.param14 AS partitions_total, + S.param15 AS partitions_done + FROM pg_stat_get_progress_info('CREATE INDEX') AS S + LEFT JOIN pg_database D ON S.datid = D.oid; + +CREATE VIEW pg_stat_progress_basebackup AS + SELECT + S.pid AS pid, + CASE S.param1 WHEN 0 THEN 'initializing' + WHEN 1 THEN 'waiting for checkpoint to finish' + WHEN 2 THEN 'estimating backup size' + WHEN 3 THEN 'streaming database files' + WHEN 4 THEN 'waiting for wal archiving to finish' + WHEN 5 THEN 'transferring wal files' + END AS phase, + CASE S.param2 WHEN -1 THEN NULL ELSE S.param2 END AS backup_total, + S.param3 AS backup_streamed, + S.param4 AS tablespaces_total, + S.param5 AS tablespaces_streamed + FROM pg_stat_get_progress_info('BASEBACKUP') AS S; + +CREATE VIEW pg_user_mappings AS + SELECT + U.oid AS umid, + S.oid AS srvid, + S.srvname AS srvname, + U.umuser AS umuser, + CASE WHEN U.umuser = 0 THEN + 'public' + ELSE + A.rolname + END AS usename, + CASE WHEN (U.umuser <> 0 AND A.rolname = current_user + AND (pg_has_role(S.srvowner, 'USAGE') + OR has_server_privilege(S.oid, 'USAGE'))) + OR (U.umuser = 0 AND pg_has_role(S.srvowner, 'USAGE')) + OR (SELECT rolsuper FROM pg_authid WHERE rolname = current_user) + THEN U.umoptions + ELSE NULL END AS umoptions + FROM pg_user_mapping U + JOIN pg_foreign_server S ON (U.umserver = S.oid) + LEFT JOIN pg_authid A ON (A.oid = U.umuser); + +REVOKE ALL on pg_user_mapping FROM public; + +CREATE VIEW pg_replication_origin_status AS + SELECT * + FROM pg_show_replication_origin_status(); + +REVOKE ALL ON pg_replication_origin_status FROM public; + +-- All columns of pg_subscription except subconninfo are readable. +REVOKE ALL ON pg_subscription FROM public; +GRANT SELECT (subdbid, subname, subowner, subenabled, subslotname, subpublications) + ON pg_subscription TO public; + + +-- +-- We have a few function definitions in here, too. +-- At some point there might be enough to justify breaking them out into +-- a separate "system_functions.sql" file. +-- + +-- Tsearch debug function. Defined here because it'd be pretty unwieldy +-- to put it into pg_proc.h + +CREATE FUNCTION ts_debug(IN config regconfig, IN document text, + OUT alias text, + OUT description text, + OUT token text, + OUT dictionaries regdictionary[], + OUT dictionary regdictionary, + OUT lexemes text[]) +RETURNS SETOF record AS +$$ +SELECT + tt.alias AS alias, + tt.description AS description, + parse.token AS token, + ARRAY ( SELECT m.mapdict::pg_catalog.regdictionary + FROM pg_catalog.pg_ts_config_map AS m + WHERE m.mapcfg = $1 AND m.maptokentype = parse.tokid + ORDER BY m.mapseqno ) + AS dictionaries, + ( SELECT mapdict::pg_catalog.regdictionary + FROM pg_catalog.pg_ts_config_map AS m + WHERE m.mapcfg = $1 AND m.maptokentype = parse.tokid + ORDER BY pg_catalog.ts_lexize(mapdict, parse.token) IS NULL, m.mapseqno + LIMIT 1 + ) AS dictionary, + ( SELECT pg_catalog.ts_lexize(mapdict, parse.token) + FROM pg_catalog.pg_ts_config_map AS m + WHERE m.mapcfg = $1 AND m.maptokentype = parse.tokid + ORDER BY pg_catalog.ts_lexize(mapdict, parse.token) IS NULL, m.mapseqno + LIMIT 1 + ) AS lexemes +FROM pg_catalog.ts_parse( + (SELECT cfgparser FROM pg_catalog.pg_ts_config WHERE oid = $1 ), $2 + ) AS parse, + pg_catalog.ts_token_type( + (SELECT cfgparser FROM pg_catalog.pg_ts_config WHERE oid = $1 ) + ) AS tt +WHERE tt.tokid = parse.tokid +$$ +LANGUAGE SQL STRICT STABLE PARALLEL SAFE; + +COMMENT ON FUNCTION ts_debug(regconfig,text) IS + 'debug function for text search configuration'; + +CREATE FUNCTION ts_debug(IN document text, + OUT alias text, + OUT description text, + OUT token text, + OUT dictionaries regdictionary[], + OUT dictionary regdictionary, + OUT lexemes text[]) +RETURNS SETOF record AS +$$ + SELECT * FROM pg_catalog.ts_debug( pg_catalog.get_current_ts_config(), $1); +$$ +LANGUAGE SQL STRICT STABLE PARALLEL SAFE; + +COMMENT ON FUNCTION ts_debug(text) IS + 'debug function for current text search configuration'; + +-- +-- Redeclare built-in functions that need default values attached to their +-- arguments. It's impractical to set those up directly in pg_proc.h because +-- of the complexity and platform-dependency of the expression tree +-- representation. (Note that internal functions still have to have entries +-- in pg_proc.h; we are merely causing their proargnames and proargdefaults +-- to get filled in.) +-- + +CREATE OR REPLACE FUNCTION + pg_start_backup(label text, fast boolean DEFAULT false, exclusive boolean DEFAULT true) + RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup' + PARALLEL RESTRICTED; + +CREATE OR REPLACE FUNCTION pg_stop_backup ( + exclusive boolean, wait_for_archive boolean DEFAULT true, + OUT lsn pg_lsn, OUT labelfile text, OUT spcmapfile text) + RETURNS SETOF record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup_v2' + 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; + +-- 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_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, + 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'; + +-- 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'; + +-- +-- The default permissions for functions mean that anyone can execute them. +-- A number of functions shouldn't be executable by just anyone, but rather +-- than use explicit 'superuser()' checks in those functions, we use the GRANT +-- system to REVOKE access to those functions at initdb time. Administrators +-- can later change who can access these functions, or leave them as only +-- available to superuser / cluster owner, if they choose. +-- +REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean, boolean) FROM public; +REVOKE EXECUTE ON FUNCTION pg_stop_backup() FROM public; +REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean, boolean) FROM public; +REVOKE EXECUTE ON FUNCTION pg_create_restore_point(text) FROM public; +REVOKE EXECUTE ON FUNCTION pg_switch_wal() FROM public; +REVOKE EXECUTE ON FUNCTION pg_wal_replay_pause() FROM public; +REVOKE EXECUTE ON FUNCTION pg_wal_replay_resume() FROM public; +REVOKE EXECUTE ON FUNCTION pg_rotate_logfile() FROM public; +REVOKE EXECUTE ON FUNCTION pg_reload_conf() FROM public; +REVOKE EXECUTE ON FUNCTION pg_current_logfile() FROM public; +REVOKE EXECUTE ON FUNCTION pg_current_logfile(text) FROM public; +REVOKE EXECUTE ON FUNCTION pg_promote(boolean, integer) FROM public; + +REVOKE EXECUTE ON FUNCTION pg_stat_reset() FROM public; +REVOKE EXECUTE ON FUNCTION pg_stat_reset_shared(text) FROM public; +REVOKE EXECUTE ON FUNCTION pg_stat_reset_slru(text) FROM public; +REVOKE EXECUTE ON FUNCTION pg_stat_reset_single_table_counters(oid) FROM public; +REVOKE EXECUTE ON FUNCTION pg_stat_reset_single_function_counters(oid) FROM public; + +REVOKE EXECUTE ON FUNCTION lo_import(text) FROM public; +REVOKE EXECUTE ON FUNCTION lo_import(text, oid) FROM public; +REVOKE EXECUTE ON FUNCTION lo_export(oid, text) FROM public; + +REVOKE EXECUTE ON FUNCTION pg_ls_logdir() FROM public; +REVOKE EXECUTE ON FUNCTION pg_ls_waldir() FROM public; +REVOKE EXECUTE ON FUNCTION pg_ls_archive_statusdir() FROM public; +REVOKE EXECUTE ON FUNCTION pg_ls_tmpdir() FROM public; +REVOKE EXECUTE ON FUNCTION pg_ls_tmpdir(oid) FROM public; + +REVOKE EXECUTE ON FUNCTION pg_read_file(text) FROM public; +REVOKE EXECUTE ON FUNCTION pg_read_file(text,bigint,bigint) FROM public; +REVOKE EXECUTE ON FUNCTION pg_read_file(text,bigint,bigint,boolean) FROM public; + +REVOKE EXECUTE ON FUNCTION pg_read_binary_file(text) FROM public; +REVOKE EXECUTE ON FUNCTION pg_read_binary_file(text,bigint,bigint) FROM public; +REVOKE EXECUTE ON FUNCTION pg_read_binary_file(text,bigint,bigint,boolean) FROM public; + +REVOKE EXECUTE ON FUNCTION pg_stat_file(text) FROM public; +REVOKE EXECUTE ON FUNCTION pg_stat_file(text,boolean) FROM public; + +REVOKE EXECUTE ON FUNCTION pg_ls_dir(text) FROM public; +REVOKE EXECUTE ON FUNCTION pg_ls_dir(text,boolean,boolean) FROM public; + +-- +-- We also set up some things as accessible to standard roles. +-- +GRANT EXECUTE ON FUNCTION pg_ls_logdir() TO pg_monitor; +GRANT EXECUTE ON FUNCTION pg_ls_waldir() TO pg_monitor; +GRANT EXECUTE ON FUNCTION pg_ls_archive_statusdir() TO pg_monitor; +GRANT EXECUTE ON FUNCTION pg_ls_tmpdir() TO pg_monitor; +GRANT EXECUTE ON FUNCTION pg_ls_tmpdir(oid) TO pg_monitor; + +GRANT pg_read_all_settings TO pg_monitor; +GRANT pg_read_all_stats TO pg_monitor; +GRANT pg_stat_scan_tables TO pg_monitor; diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c new file mode 100644 index 0000000..3f7ab8d --- /dev/null +++ b/src/backend/catalog/toasting.c @@ -0,0 +1,418 @@ +/*------------------------------------------------------------------------- + * + * toasting.c + * This file contains routines to support creation of toast tables + * + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/catalog/toasting.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/heapam.h" +#include "access/xact.h" +#include "catalog/binary_upgrade.h" +#include "catalog/catalog.h" +#include "catalog/dependency.h" +#include "catalog/heap.h" +#include "catalog/index.h" +#include "catalog/namespace.h" +#include "catalog/pg_am.h" +#include "catalog/pg_namespace.h" +#include "catalog/pg_opclass.h" +#include "catalog/pg_type.h" +#include "catalog/toasting.h" +#include "miscadmin.h" +#include "nodes/makefuncs.h" +#include "storage/lock.h" +#include "utils/builtins.h" +#include "utils/rel.h" +#include "utils/syscache.h" + +/* Potentially set by pg_upgrade_support functions */ +Oid binary_upgrade_next_toast_pg_type_oid = InvalidOid; + +static void CheckAndCreateToastTable(Oid relOid, Datum reloptions, + LOCKMODE lockmode, bool check); +static bool create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, + Datum reloptions, LOCKMODE lockmode, bool check); +static bool needs_toast_table(Relation rel); + + +/* + * CreateToastTable variants + * If the table needs a toast table, and doesn't already have one, + * then create a toast table for it. + * + * reloptions for the toast table can be passed, too. Pass (Datum) 0 + * for default reloptions. + * + * We expect the caller to have verified that the relation is a table and have + * already done any necessary permission checks. Callers expect this function + * to end with CommandCounterIncrement if it makes any changes. + */ +void +AlterTableCreateToastTable(Oid relOid, Datum reloptions, LOCKMODE lockmode) +{ + CheckAndCreateToastTable(relOid, reloptions, lockmode, true); +} + +void +NewHeapCreateToastTable(Oid relOid, Datum reloptions, LOCKMODE lockmode) +{ + CheckAndCreateToastTable(relOid, reloptions, lockmode, false); +} + +void +NewRelationCreateToastTable(Oid relOid, Datum reloptions) +{ + CheckAndCreateToastTable(relOid, reloptions, AccessExclusiveLock, false); +} + +static void +CheckAndCreateToastTable(Oid relOid, Datum reloptions, LOCKMODE lockmode, bool check) +{ + Relation rel; + + rel = table_open(relOid, lockmode); + + /* create_toast_table does all the work */ + (void) create_toast_table(rel, InvalidOid, InvalidOid, reloptions, lockmode, check); + + table_close(rel, NoLock); +} + +/* + * Create a toast table during bootstrap + * + * Here we need to prespecify the OIDs of the toast table and its index + */ +void +BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid) +{ + Relation rel; + + rel = table_openrv(makeRangeVar(NULL, relName, -1), AccessExclusiveLock); + + if (rel->rd_rel->relkind != RELKIND_RELATION && + rel->rd_rel->relkind != RELKIND_MATVIEW) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not a table or materialized view", + relName))); + + /* create_toast_table does all the work */ + if (!create_toast_table(rel, toastOid, toastIndexOid, (Datum) 0, + AccessExclusiveLock, false)) + elog(ERROR, "\"%s\" does not require a toast table", + relName); + + table_close(rel, NoLock); +} + + +/* + * create_toast_table --- internal workhorse + * + * rel is already opened and locked + * toastOid and toastIndexOid are normally InvalidOid, but during + * bootstrap they can be nonzero to specify hand-assigned OIDs + */ +static bool +create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, + Datum reloptions, LOCKMODE lockmode, bool check) +{ + Oid relOid = RelationGetRelid(rel); + HeapTuple reltup; + TupleDesc tupdesc; + bool shared_relation; + bool mapped_relation; + Relation toast_rel; + Relation class_rel; + Oid toast_relid; + Oid toast_typid = InvalidOid; + Oid namespaceid; + char toast_relname[NAMEDATALEN]; + char toast_idxname[NAMEDATALEN]; + IndexInfo *indexInfo; + Oid collationObjectId[2]; + Oid classObjectId[2]; + int16 coloptions[2]; + ObjectAddress baseobject, + toastobject; + + /* + * Is it already toasted? + */ + if (rel->rd_rel->reltoastrelid != InvalidOid) + return false; + + /* + * Check to see whether the table actually needs a TOAST table. + */ + if (!IsBinaryUpgrade) + { + /* Normal mode, normal check */ + if (!needs_toast_table(rel)) + return false; + } + else + { + /* + * In binary-upgrade mode, create a TOAST table if and only if + * pg_upgrade told us to (ie, a TOAST table OID has been provided). + * + * This indicates that the old cluster had a TOAST table for the + * current table. We must create a TOAST table to receive the old + * TOAST file, even if the table seems not to need one. + * + * Contrariwise, if the old cluster did not have a TOAST table, we + * should be able to get along without one even if the new version's + * needs_toast_table rules suggest we should have one. There is a lot + * of daylight between where we will create a TOAST table and where + * one is really necessary to avoid failures, so small cross-version + * differences in the when-to-create heuristic shouldn't be a problem. + * If we tried to create a TOAST table anyway, we would have the + * problem that it might take up an OID that will conflict with some + * old-cluster table we haven't seen yet. + */ + if (!OidIsValid(binary_upgrade_next_toast_pg_class_oid) || + !OidIsValid(binary_upgrade_next_toast_pg_type_oid)) + return false; + } + + /* + * If requested check lockmode is sufficient. This is a cross check in + * case of errors or conflicting decisions in earlier code. + */ + if (check && lockmode != AccessExclusiveLock) + elog(ERROR, "AccessExclusiveLock required to add toast table."); + + /* + * Create the toast table and its index + */ + snprintf(toast_relname, sizeof(toast_relname), + "pg_toast_%u", relOid); + snprintf(toast_idxname, sizeof(toast_idxname), + "pg_toast_%u_index", relOid); + + /* this is pretty painful... need a tuple descriptor */ + tupdesc = CreateTemplateTupleDesc(3); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, + "chunk_id", + OIDOID, + -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, + "chunk_seq", + INT4OID, + -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, + "chunk_data", + BYTEAOID, + -1, 0); + + /* + * Ensure that the toast table doesn't itself get toasted, or we'll be + * toast :-(. This is essential for chunk_data because type bytea is + * toastable; hit the other two just to be sure. + */ + TupleDescAttr(tupdesc, 0)->attstorage = TYPSTORAGE_PLAIN; + TupleDescAttr(tupdesc, 1)->attstorage = TYPSTORAGE_PLAIN; + TupleDescAttr(tupdesc, 2)->attstorage = TYPSTORAGE_PLAIN; + + /* + * Toast tables for regular relations go in pg_toast; those for temp + * relations go into the per-backend temp-toast-table namespace. + */ + if (isTempOrTempToastNamespace(rel->rd_rel->relnamespace)) + namespaceid = GetTempToastNamespace(); + else + namespaceid = PG_TOAST_NAMESPACE; + + /* + * Use binary-upgrade override for pg_type.oid, if supplied. We might be + * in the post-schema-restore phase where we are doing ALTER TABLE to + * create TOAST tables that didn't exist in the old cluster. + */ + if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_toast_pg_type_oid)) + { + toast_typid = binary_upgrade_next_toast_pg_type_oid; + binary_upgrade_next_toast_pg_type_oid = InvalidOid; + } + + /* Toast table is shared if and only if its parent is. */ + shared_relation = rel->rd_rel->relisshared; + + /* It's mapped if and only if its parent is, too */ + mapped_relation = RelationIsMapped(rel); + + toast_relid = heap_create_with_catalog(toast_relname, + namespaceid, + rel->rd_rel->reltablespace, + toastOid, + toast_typid, + InvalidOid, + rel->rd_rel->relowner, + table_relation_toast_am(rel), + tupdesc, + NIL, + RELKIND_TOASTVALUE, + rel->rd_rel->relpersistence, + shared_relation, + mapped_relation, + ONCOMMIT_NOOP, + reloptions, + false, + true, + true, + InvalidOid, + NULL); + Assert(toast_relid != InvalidOid); + + /* make the toast relation visible, else table_open will fail */ + CommandCounterIncrement(); + + /* ShareLock is not really needed here, but take it anyway */ + toast_rel = table_open(toast_relid, ShareLock); + + /* + * Create unique index on chunk_id, chunk_seq. + * + * NOTE: the normal TOAST access routines could actually function with a + * single-column index on chunk_id only. However, the slice access + * routines use both columns for faster access to an individual chunk. In + * addition, we want it to be unique as a check against the possibility of + * duplicate TOAST chunk OIDs. The index might also be a little more + * efficient this way, since btree isn't all that happy with large numbers + * of equal keys. + */ + + indexInfo = makeNode(IndexInfo); + indexInfo->ii_NumIndexAttrs = 2; + indexInfo->ii_NumIndexKeyAttrs = 2; + indexInfo->ii_IndexAttrNumbers[0] = 1; + indexInfo->ii_IndexAttrNumbers[1] = 2; + indexInfo->ii_Expressions = NIL; + indexInfo->ii_ExpressionsState = NIL; + indexInfo->ii_Predicate = NIL; + indexInfo->ii_PredicateState = NULL; + indexInfo->ii_ExclusionOps = NULL; + indexInfo->ii_ExclusionProcs = NULL; + indexInfo->ii_ExclusionStrats = NULL; + indexInfo->ii_OpclassOptions = NULL; + indexInfo->ii_Unique = true; + indexInfo->ii_ReadyForInserts = true; + indexInfo->ii_Concurrent = false; + indexInfo->ii_BrokenHotChain = false; + indexInfo->ii_ParallelWorkers = 0; + indexInfo->ii_Am = BTREE_AM_OID; + indexInfo->ii_AmCache = NULL; + indexInfo->ii_Context = CurrentMemoryContext; + + collationObjectId[0] = InvalidOid; + collationObjectId[1] = InvalidOid; + + classObjectId[0] = OID_BTREE_OPS_OID; + classObjectId[1] = INT4_BTREE_OPS_OID; + + coloptions[0] = 0; + coloptions[1] = 0; + + index_create(toast_rel, toast_idxname, toastIndexOid, InvalidOid, + InvalidOid, InvalidOid, + indexInfo, + list_make2("chunk_id", "chunk_seq"), + BTREE_AM_OID, + rel->rd_rel->reltablespace, + collationObjectId, classObjectId, coloptions, (Datum) 0, + INDEX_CREATE_IS_PRIMARY, 0, true, true, NULL); + + table_close(toast_rel, NoLock); + + /* + * Store the toast table's OID in the parent relation's pg_class row + */ + class_rel = table_open(RelationRelationId, RowExclusiveLock); + + reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid)); + if (!HeapTupleIsValid(reltup)) + elog(ERROR, "cache lookup failed for relation %u", relOid); + + ((Form_pg_class) GETSTRUCT(reltup))->reltoastrelid = toast_relid; + + if (!IsBootstrapProcessingMode()) + { + /* normal case, use a transactional update */ + CatalogTupleUpdate(class_rel, &reltup->t_self, reltup); + } + else + { + /* While bootstrapping, we cannot UPDATE, so overwrite in-place */ + heap_inplace_update(class_rel, reltup); + } + + heap_freetuple(reltup); + + table_close(class_rel, RowExclusiveLock); + + /* + * Register dependency from the toast table to the master, so that the + * toast table will be deleted if the master is. Skip this in bootstrap + * mode. + */ + if (!IsBootstrapProcessingMode()) + { + baseobject.classId = RelationRelationId; + baseobject.objectId = relOid; + baseobject.objectSubId = 0; + toastobject.classId = RelationRelationId; + toastobject.objectId = toast_relid; + toastobject.objectSubId = 0; + + recordDependencyOn(&toastobject, &baseobject, DEPENDENCY_INTERNAL); + } + + /* + * Make changes visible + */ + CommandCounterIncrement(); + + return true; +} + +/* + * Check to see whether the table needs a TOAST table. + */ +static bool +needs_toast_table(Relation rel) +{ + /* + * No need to create a TOAST table for partitioned tables. + */ + if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + return false; + + /* + * We cannot allow toasting a shared relation after initdb (because + * there's no way to mark it toasted in other databases' pg_class). + */ + if (rel->rd_rel->relisshared && !IsBootstrapProcessingMode()) + return false; + + /* + * Ignore attempts to create toast tables on catalog tables after initdb. + * Which catalogs get toast tables is explicitly chosen in + * catalog/toasting.h. (We could get here via some ALTER TABLE command if + * the catalog doesn't have a toast table.) + */ + if (IsCatalogRelation(rel) && !IsBootstrapProcessingMode()) + return false; + + /* Otherwise, let the AM decide. */ + return table_relation_needs_toast_table(rel); +} |