Skip to content
Browse files

Add support for privileges on types

This adds support for the more or less SQL-conforming USAGE privilege
on types and domains.  The intent is to be able restrict which users
can create dependencies on types, which restricts the way in which
owners can alter types.

reviewed by Yeb Havinga
  • Loading branch information...
1 parent 05e992e commit 729205571e81b4767efc42ad7beb53663e08d1ff @petere petere committed
Showing with 1,249 additions and 201 deletions.
  1. +20 −15 doc/src/sgml/information_schema.sgml
  2. +11 −1 doc/src/sgml/ref/alter_default_privileges.sgml
  3. +2 −0 doc/src/sgml/ref/alter_foreign_table.sgml
  4. +3 −0 doc/src/sgml/ref/alter_table.sgml
  5. +2 −0 doc/src/sgml/ref/alter_type.sgml
  6. +7 −0 doc/src/sgml/ref/create_aggregate.sgml
  7. +5 −4 doc/src/sgml/ref/create_cast.sgml
  8. +5 −0 doc/src/sgml/ref/create_domain.sgml
  9. +5 −0 doc/src/sgml/ref/create_foreign_table.sgml
  10. +5 −0 doc/src/sgml/ref/create_function.sgml
  11. +7 −0 doc/src/sgml/ref/create_operator.sgml
  12. +6 −0 doc/src/sgml/ref/create_table.sgml
  13. +5 −0 doc/src/sgml/ref/create_type.sgml
  14. +18 −1 doc/src/sgml/ref/grant.sgml
  15. +3 −3 doc/src/sgml/ref/psql-ref.sgml
  16. +12 −0 doc/src/sgml/ref/revoke.sgml
  17. +9 −0 src/backend/access/common/tupdesc.c
  18. +271 −0 src/backend/catalog/aclchk.c
  19. +63 −21 src/backend/catalog/information_schema.sql
  20. +23 −0 src/backend/catalog/pg_aggregate.c
  21. +9 −0 src/backend/catalog/pg_type.c
  22. +24 −0 src/backend/commands/functioncmds.c
  23. +24 −0 src/backend/commands/operatorcmds.c
  24. +22 −0 src/backend/commands/tablecmds.c
  25. +5 −0 src/backend/commands/typecmds.c
  26. +15 −0 src/backend/executor/execMain.c
  27. +18 −1 src/backend/parser/gram.y
  28. +207 −0 src/backend/utils/adt/acl.c
  29. +12 −0 src/bin/psql/describe.c
  30. +7 −1 src/bin/psql/tab-complete.c
  31. +1 −1 src/include/catalog/catversion.h
  32. +1 −1 src/include/catalog/pg_class.h
  33. +1 −0 src/include/catalog/pg_default_acl.h
  34. +13 −0 src/include/catalog/pg_proc.h
  35. +155 −150 src/include/catalog/pg_type.h
  36. +3 −1 src/include/nodes/parsenodes.h
  37. +1 −0 src/include/parser/kwlist.h
  38. +4 −0 src/include/utils/acl.h
  39. +6 −0 src/include/utils/builtins.h
  40. +115 −1 src/test/regress/expected/privileges.out
  41. +124 −0 src/test/regress/sql/privileges.sql
View
35 doc/src/sgml/information_schema.sgml
@@ -284,6 +284,8 @@
the attributes of composite data types defined in the database.
(Note that the view does not give information about table columns,
which are sometimes called attributes in PostgreSQL contexts.)
+ Only those attributes are shown that the current user has access to (by way
+ of being the owner of or having some privilege on the type).
</para>
<table>
@@ -1915,8 +1917,10 @@
<title><literal>domain_constraints</literal></title>
<para>
- The view <literal>domain_constraints</literal> contains all
- constraints belonging to domains defined in the current database.
+ The view <literal>domain_constraints</literal> contains all constraints
+ belonging to domains defined in the current database. Only those domains
+ are shown that the current user has access to (by way of being the owner or
+ having some privilege).
</para>
<table>
@@ -2052,8 +2056,9 @@
<title><literal>domains</literal></title>
<para>
- The view <literal>domains</literal> contains all domains defined in
- the current database.
+ The view <literal>domains</literal> contains all domains defined in the
+ current database. Only those domains are shown that the current user has
+ access to (by way of being the owner or having some privilege).
</para>
<table>
@@ -5778,15 +5783,13 @@ ORDER BY c.ordinal_position;
<title><literal>udt_privileges</literal></title>
<para>
- The view <literal>udt_privileges</literal> is intended to identify
- <literal>USAGE</literal> privileges granted on user-defined types
- to a currently enabled role or by a currently enabled role. Since
- data types do not have real privileges
- in <productname>PostgreSQL</productname>, this view shows implicit
- non-grantable <literal>USAGE</literal> privileges granted by the
- owner to <literal>PUBLIC</literal> for all types, including
- built-in ones (except domains,
- see <xref linkend="infoschema-usage-privileges"> for that).
+ The view <literal>udt_privileges</literal> identifies
+ <literal>USAGE</literal> privileges granted on user-defined types to a
+ currently enabled role or by a currently enabled role. There is one row for
+ each combination of column, grantor, and grantee. This view shows only
+ composite types (see under <xref linkend="infoschema-user-defined-types">
+ for why); see
+ <xref linkend="infoschema-usage-privileges"> for domain privileges.
</para>
<table>
@@ -5861,10 +5864,10 @@ ORDER BY c.ordinal_position;
</para>
<para>
- Since collations and domains do not have real privileges
+ Since collations do not have real privileges
in <productname>PostgreSQL</productname>, this view shows implicit
non-grantable <literal>USAGE</literal> privileges granted by the
- owner to <literal>PUBLIC</literal> for all collations and domains. The other
+ owner to <literal>PUBLIC</literal> for all collations. The other
object types, however, show real privileges.
</para>
@@ -5940,6 +5943,8 @@ ORDER BY c.ordinal_position;
<para>
The view <literal>user_defined_types</literal> currently contains
all composite types defined in the current database.
+ Only those types are shown that the current user has access to (by way
+ of being the owner or having some privilege).
</para>
<para>
View
12 doc/src/sgml/ref/alter_default_privileges.sgml
@@ -42,6 +42,10 @@ GRANT { EXECUTE | ALL [ PRIVILEGES ] }
ON FUNCTIONS
TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
+GRANT { USAGE | ALL [ PRIVILEGES ] }
+ ON TYPES
+ TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
+
REVOKE [ GRANT OPTION FOR ]
{ { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
[, ...] | ALL [ PRIVILEGES ] }
@@ -61,6 +65,12 @@ REVOKE [ GRANT OPTION FOR ]
ON FUNCTIONS
FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
+
+REVOKE [ GRANT OPTION FOR ]
+ { USAGE | ALL [ PRIVILEGES ] }
+ ON TYPES
+ FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
+ [ CASCADE | RESTRICT ]
</synopsis>
</refsynopsisdiv>
@@ -72,7 +82,7 @@ REVOKE [ GRANT OPTION FOR ]
that will be applied to objects created in the future. (It does not
affect privileges assigned to already-existing objects.) Currently,
only the privileges for tables (including views and foreign tables),
- sequences, and functions can be altered.
+ sequences, functions, and types (including domains) can be altered.
</para>
<para>
View
2 doc/src/sgml/ref/alter_foreign_table.sgml
@@ -157,6 +157,8 @@ ALTER FOREIGN TABLE <replaceable class="PARAMETER">name</replaceable>
the table's schema. (These restrictions enforce that altering the owner
doesn't do anything you couldn't do by dropping and recreating the table.
However, a superuser can alter ownership of any table anyway.)
+ To add a column or alter a column type, you must also
+ have <literal>USAGE</literal> privilege on the data type.
</para>
</refsect1>
View
3 doc/src/sgml/ref/alter_table.sgml
@@ -594,6 +594,9 @@ ALTER TABLE <replaceable class="PARAMETER">name</replaceable>
the table's schema. (These restrictions enforce that altering the owner
doesn't do anything you couldn't do by dropping and recreating the table.
However, a superuser can alter ownership of any table anyway.)
+ To add a column or alter a column type or use the <literal>OF</literal>
+ clause, you must also have <literal>USAGE</literal> privilege on the data
+ type.
</para>
</refsect1>
View
2 doc/src/sgml/ref/alter_type.sgml
@@ -156,6 +156,8 @@ ALTER TYPE <replaceable class="PARAMETER">name</replaceable> ADD VALUE <replacea
the type's schema. (These restrictions enforce that altering the owner
doesn't do anything you couldn't do by dropping and recreating the type.
However, a superuser can alter ownership of any type anyway.)
+ To add an attribute or alter an attribute type, you must also
+ have <literal>USAGE</literal> privilege on the data type.
</para>
</refsect1>
View
7 doc/src/sgml/ref/create_aggregate.sgml
@@ -163,6 +163,13 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
than</quote> or <quote>greater than</quote> strategy member of a B-tree
index operator class.
</para>
+
+ <para>
+ To be able to create an aggregate function, you must
+ have <literal>USAGE</literal> privilege on the argument types, the state
+ type, and the return type, as well as <literal>EXECUTE</literal> privilege
+ on the transition and final functions.
+ </para>
</refsect1>
<refsect1>
View
9 doc/src/sgml/ref/create_cast.sgml
@@ -159,10 +159,11 @@ SELECT CAST ( 2 AS numeric ) + 4.0;
</note>
<para>
- To be able to create a cast, you must own the source or the target
- data type. To create a binary-coercible cast, you must be superuser.
- (This restriction is made because an erroneous binary-coercible cast
- conversion can easily crash the server.)
+ To be able to create a cast, you must own the source or the target data type
+ and have <literal>USAGE</literal> privilege on the other type. To create a
+ binary-coercible cast, you must be superuser. (This restriction is made
+ because an erroneous binary-coercible cast conversion can easily crash the
+ server.)
</para>
</refsect1>
View
5 doc/src/sgml/ref/create_domain.sgml
@@ -59,6 +59,11 @@ CREATE DOMAIN <replaceable class="parameter">name</replaceable> [ AS ] <replacea
Define a domain rather than setting up each table's constraint
individually.
</para>
+
+ <para>
+ To be able to create a domain, you must have <literal>USAGE</literal>
+ privilege on the underlying type.
+ </para>
</refsect1>
<refsect1>
View
5 doc/src/sgml/ref/create_foreign_table.sgml
@@ -52,6 +52,11 @@ CREATE FOREIGN TABLE [ IF NOT EXISTS ] <replaceable class="PARAMETER">table_name
the foreign table. Therefore, foreign tables cannot have the same
name as any existing data type in the same schema.
</para>
+
+ <para>
+ To be able to create a table, you must have <literal>USAGE</literal>
+ privilege on all column types.
+ </para>
</refsect1>
<refsect1>
View
5 doc/src/sgml/ref/create_function.sgml
@@ -92,6 +92,11 @@ CREATE [ OR REPLACE ] FUNCTION
<para>
The user that creates the function becomes the owner of the function.
</para>
+
+ <para>
+ To be able to create a function, you must have <literal>USAGE</literal>
+ privilege on the argument types and the return type.
+ </para>
</refsect1>
<refsect1>
View
7 doc/src/sgml/ref/create_operator.sgml
@@ -103,6 +103,13 @@ CREATE OPERATOR <replaceable>name</replaceable> (
The other clauses specify optional operator optimization clauses.
Their meaning is detailed in <xref linkend="xoper-optimization">.
</para>
+
+ <para>
+ To be able to create an operator, you must have <literal>USAGE</literal>
+ privilege on the argument types and the return type, as well
+ as <literal>EXECUTE</literal> privilege on the underlying function. If a
+ commutator or negator operator is specified, you must own these operators.
+ </para>
</refsect1>
<refsect1>
View
6 doc/src/sgml/ref/create_table.sgml
@@ -124,6 +124,12 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
a column constraint is only a notational convenience for use when the
constraint only affects one column.
</para>
+
+ <para>
+ To be able to create a table, you must have <literal>USAGE</literal>
+ privilege on all column types or the type in the <literal>OF</literal>
+ clause, respectively.
+ </para>
</refsect1>
<refsect1>
View
5 doc/src/sgml/ref/create_type.sgml
@@ -104,6 +104,11 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
A stand-alone composite type is useful, for example, as the argument or
return type of a function.
</para>
+
+ <para>
+ To be able to create a composite type, you must
+ have <literal>USAGE</literal> privilege on all attribute types.
+ </para>
</refsect2>
<refsect2 id="SQL-CREATETYPE-enum">
View
19 doc/src/sgml/ref/grant.sgml
@@ -43,6 +43,10 @@ GRANT { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] }
TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
GRANT { USAGE | ALL [ PRIVILEGES ] }
+ ON DOMAIN <replaceable>domain_name</replaceable> [, ...]
+ TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
+
+GRANT { USAGE | ALL [ PRIVILEGES ] }
ON FOREIGN DATA WRAPPER <replaceable>fdw_name</replaceable> [, ...]
TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
@@ -71,6 +75,10 @@ GRANT { CREATE | ALL [ PRIVILEGES ] }
ON TABLESPACE <replaceable>tablespace_name</replaceable> [, ...]
TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
+GRANT { USAGE | ALL [ PRIVILEGES ] }
+ ON TYPE <replaceable>type_name</replaceable> [, ...]
+ TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
+
GRANT <replaceable class="PARAMETER">role_name</replaceable> [, ...] TO <replaceable class="PARAMETER">role_name</replaceable> [, ...] [ WITH ADMIN OPTION ]
</synopsis>
</refsynopsisdiv>
@@ -336,6 +344,15 @@ GRANT <replaceable class="PARAMETER">role_name</replaceable> [, ...] TO <replace
<function>currval</function> and <function>nextval</function> functions.
</para>
<para>
+ For types and domains, this privilege allow the use of the type or
+ domain in the creation of tables, functions, and other schema objects.
+ (Note that it does not control general <quote>usage</quote> of the type,
+ such as values of the type appearing in queries. It only prevents
+ objects from being created that depend on the type. The main purpose of
+ the privilege is controlling which users create dependencies on a type,
+ which could prevent the owner from changing the type later.)
+ </para>
+ <para>
For foreign-data wrappers, this privilege enables the grantee
to create new servers using that foreign-data wrapper.
</para>
@@ -616,7 +633,7 @@ GRANT admins TO joe;
<para>
The SQL standard provides for a <literal>USAGE</literal> privilege
on other kinds of objects: character sets, collations,
- translations, domains.
+ translations.
</para>
<para>
View
6 doc/src/sgml/ref/psql-ref.sgml
@@ -1048,7 +1048,7 @@ testdb=&gt;
pattern or the <literal>S</literal> modifier to include system
objects.
If <literal>+</literal> is appended to the command name, each object
- is listed with its associated description.
+ is listed with its associated permissions and description.
</para>
</listitem>
</varlistentry>
@@ -1387,8 +1387,8 @@ testdb=&gt;
If <replaceable class="parameter">pattern</replaceable> is
specified, only types whose names match the pattern are listed.
If <literal>+</literal> is appended to the command name, each type is
- listed with its internal name and size, as well as its allowed values
- if it is an <type>enum</> type.
+ listed with its internal name and size, its allowed values
+ if it is an <type>enum</> type, and its associated permissions.
By default, only user-created objects are shown; supply a
pattern or the <literal>S</literal> modifier to include system
objects.
View
12 doc/src/sgml/ref/revoke.sgml
@@ -52,6 +52,12 @@ REVOKE [ GRANT OPTION FOR ]
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
+ ON DOMAIN <replaceable>domain_name</replaceable> [, ...]
+ FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
+ [ CASCADE | RESTRICT ]
+
+REVOKE [ GRANT OPTION FOR ]
+ { USAGE | ALL [ PRIVILEGES ] }
ON FOREIGN DATA WRAPPER <replaceable>fdw_name</replaceable> [, ...]
FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
@@ -93,6 +99,12 @@ REVOKE [ GRANT OPTION FOR ]
FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
+REVOKE [ GRANT OPTION FOR ]
+ { USAGE | ALL [ PRIVILEGES ] }
+ ON TYPE <replaceable>type_name</replaceable> [, ...]
+ FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
+ [ CASCADE | RESTRICT ]
+
REVOKE [ ADMIN OPTION FOR ]
<replaceable class="PARAMETER">role_name</replaceable> [, ...] FROM <replaceable class="PARAMETER">role_name</replaceable> [, ...]
[ CASCADE | RESTRICT ]
View
9 src/backend/access/common/tupdesc.c
@@ -20,7 +20,9 @@
#include "postgres.h"
#include "catalog/pg_type.h"
+#include "miscadmin.h"
#include "parser/parse_type.h"
+#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/resowner.h"
#include "utils/syscache.h"
@@ -557,6 +559,7 @@ BuildDescForRelation(List *schema)
foreach(l, schema)
{
ColumnDef *entry = lfirst(l);
+ AclResult aclresult;
/*
* for each entry in the list, get the name and type information from
@@ -567,6 +570,12 @@ BuildDescForRelation(List *schema)
attname = entry->colname;
typenameTypeIdAndMod(NULL, entry->typeName, &atttypid, &atttypmod);
+
+ aclresult = pg_type_aclcheck(atttypid, GetUserId(), ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_TYPE,
+ format_type_be(atttypid));
+
attcollation = GetColumnDefCollation(NULL, entry, atttypid);
attdim = list_length(entry->typeName->arrayBounds);
View
271 src/backend/catalog/aclchk.c
@@ -49,7 +49,9 @@
#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/builtins.h"
#include "utils/fmgroids.h"
@@ -113,6 +115,7 @@ 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);
@@ -274,6 +277,9 @@ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
case ACL_KIND_FOREIGN_SERVER:
whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
break;
+ case ACL_KIND_TYPE:
+ whole_mask = ACL_ALL_RIGHTS_TYPE;
+ break;
default:
elog(ERROR, "unrecognized object kind: %d", objkind);
/* not reached, but keep compiler quiet */
@@ -449,6 +455,10 @@ ExecuteGrantStmt(GrantStmt *stmt)
all_privileges = ACL_ALL_RIGHTS_DATABASE;
errormsg = gettext_noop("invalid privilege type %s for database");
break;
+ case ACL_OBJECT_DOMAIN:
+ all_privileges = ACL_ALL_RIGHTS_TYPE;
+ errormsg = gettext_noop("invalid privilege type %s for domain");
+ break;
case ACL_OBJECT_FUNCTION:
all_privileges = ACL_ALL_RIGHTS_FUNCTION;
errormsg = gettext_noop("invalid privilege type %s for function");
@@ -469,6 +479,10 @@ ExecuteGrantStmt(GrantStmt *stmt)
all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
errormsg = gettext_noop("invalid privilege type %s for tablespace");
break;
+ case ACL_OBJECT_TYPE:
+ all_privileges = ACL_ALL_RIGHTS_TYPE;
+ errormsg = gettext_noop("invalid privilege type %s for type");
+ break;
case ACL_OBJECT_FDW:
all_privileges = ACL_ALL_RIGHTS_FDW;
errormsg = gettext_noop("invalid privilege type %s for foreign-data wrapper");
@@ -552,6 +566,10 @@ ExecGrantStmt_oids(InternalGrant *istmt)
case ACL_OBJECT_DATABASE:
ExecGrant_Database(istmt);
break;
+ case ACL_OBJECT_DOMAIN:
+ case ACL_OBJECT_TYPE:
+ ExecGrant_Type(istmt);
+ break;
case ACL_OBJECT_FDW:
ExecGrant_Fdw(istmt);
break;
@@ -620,6 +638,17 @@ objectNamesToOids(GrantObjectType objtype, List *objnames)
objects = lappend_oid(objects, dbid);
}
break;
+ case ACL_OBJECT_DOMAIN:
+ case ACL_OBJECT_TYPE:
+ foreach(cell, objnames)
+ {
+ List *typname = (List *) lfirst(cell);
+ Oid oid;
+
+ oid = typenameTypeId(NULL, makeTypeNameFromNameList(typname));
+ objects = lappend_oid(objects, oid);
+ }
+ break;
case ACL_OBJECT_FUNCTION:
foreach(cell, objnames)
{
@@ -903,6 +932,10 @@ ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt)
all_privileges = ACL_ALL_RIGHTS_FUNCTION;
errormsg = gettext_noop("invalid privilege type %s for function");
break;
+ case ACL_OBJECT_TYPE:
+ all_privileges = ACL_ALL_RIGHTS_TYPE;
+ errormsg = gettext_noop("invalid privilege type %s for type");
+ break;
default:
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
(int) action->objtype);
@@ -1085,6 +1118,12 @@ SetDefaultACL(InternalDefaultACL *iacls)
this_privileges = ACL_ALL_RIGHTS_FUNCTION;
break;
+ case ACL_OBJECT_TYPE:
+ objtype = DEFACLOBJ_TYPE;
+ if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
+ this_privileges = ACL_ALL_RIGHTS_TYPE;
+ break;
+
default:
elog(ERROR, "unrecognized objtype: %d",
(int) iacls->objtype);
@@ -1334,6 +1373,9 @@ RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
case DatabaseRelationId:
istmt.objtype = ACL_OBJECT_DATABASE;
break;
+ case TypeRelationId:
+ istmt.objtype = ACL_OBJECT_TYPE;
+ break;
case ProcedureRelationId:
istmt.objtype = ACL_OBJECT_FUNCTION;
break;
@@ -2987,6 +3029,143 @@ ExecGrant_Tablespace(InternalGrant *istmt)
heap_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 = heap_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 == ACL_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, ACL_KIND_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);
+
+ simple_heap_update(relation, &newtuple->t_self, newtuple);
+
+ /* keep the catalog indexes up to date */
+ CatalogUpdateIndexes(relation, newtuple);
+
+ /* 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();
+ }
+
+ heap_close(relation, RowExclusiveLock);
+}
+
static AclMode
string_to_privilege(const char *privname)
@@ -3263,6 +3442,8 @@ pg_aclmask(AclObjectKind objkind, Oid table_oid, AttrNumber attnum, Oid roleid,
return pg_foreign_data_wrapper_aclmask(table_oid, roleid, mask, how);
case ACL_KIND_FOREIGN_SERVER:
return pg_foreign_server_aclmask(table_oid, roleid, mask, how);
+ case ACL_KIND_TYPE:
+ return pg_type_aclmask(table_oid, roleid, mask, how);
default:
elog(ERROR, "unrecognized objkind: %d",
(int) objkind);
@@ -3972,6 +4153,80 @@ pg_foreign_server_aclmask(Oid srv_oid, Oid roleid,
}
/*
+ * 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,
+ (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 */
+ if (typeForm->typelem != 0 && typeForm->typlen == -1)
+ {
+ Oid elttype_oid = typeForm->typelem;
+
+ ReleaseSysCache(tuple);
+
+ tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errmsg("type with OID %u does not exist",
+ type_oid)));
+ typeForm = (Form_pg_type) GETSTRUCT(tuple);
+ }
+
+ /*
+ * Normal case: get the type's ACL from pg_type
+ */
+ ownerId = typeForm->typowner;
+
+ aclDatum = SysCacheGetAttr(TYPEOID, tuple,
+ Anum_pg_type_typacl, &isNull);
+ if (isNull)
+ {
+ /* No ACL, so build default ACL */
+ acl = acldefault(ACL_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
@@ -4205,6 +4460,18 @@ pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode)
}
/*
+ * 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
@@ -4813,6 +5080,10 @@ get_user_default_acl(GrantObjectType objtype, Oid ownerId, Oid nsp_oid)
defaclobjtype = DEFACLOBJ_FUNCTION;
break;
+ case ACL_OBJECT_TYPE:
+ defaclobjtype = DEFACLOBJ_TYPE;
+ break;
+
default:
return NULL;
}
View
84 src/backend/catalog/information_schema.sql
@@ -357,7 +357,9 @@ CREATE VIEW attributes AS
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 c.relkind in ('c')
+ AND (pg_has_role(c.relowner, 'USAGE')
+ OR has_type_privilege(c.reltype, 'USAGE'));
GRANT SELECT ON attributes TO PUBLIC;
@@ -868,7 +870,9 @@ CREATE VIEW domain_constraints AS
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 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;
@@ -978,7 +982,8 @@ CREATE VIEW domains AS
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;
@@ -2024,20 +2029,38 @@ GRANT SELECT ON triggers TO PUBLIC;
*/
CREATE VIEW udt_privileges AS
- SELECT CAST(null AS sql_identifier) AS grantor,
- CAST('PUBLIC' AS sql_identifier) AS grantee,
+ 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('NO' AS yes_or_no) AS is_grantable
+ 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 pg_authid u, pg_namespace n, pg_type t
+ FROM (
+ SELECT oid, typname, typnamespace, typtype, typowner, (aclexplode(typacl)).* 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 u.oid = t.typowner
- AND n.oid = t.typnamespace
- AND t.typtype <> 'd'
- AND NOT (t.typelem <> 0 AND t.typlen = -1);
+ 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;
@@ -2091,23 +2114,39 @@ CREATE VIEW usage_privileges AS
UNION ALL
/* domains */
- -- Domains have no real privileges, so we represent all domains with implicit usage privilege here.
- SELECT CAST(u.rolname AS sql_identifier) AS grantor,
- CAST('PUBLIC' AS sql_identifier) AS grantee,
+ 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('NO' AS yes_or_no) AS is_grantable
+ 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 pg_authid u,
+ FROM (
+ SELECT oid, typname, typnamespace, typtype, typowner, (aclexplode(typacl)).* FROM pg_type
+ ) AS t (oid, typname, typnamespace, typtype, typowner, grantor, grantee, prtype, grantable),
pg_namespace n,
- pg_type t
+ pg_authid u_grantor,
+ (
+ SELECT oid, rolname FROM pg_authid
+ UNION ALL
+ SELECT 0::oid, 'PUBLIC'
+ ) AS grantee (oid, rolname)
- WHERE u.oid = t.typowner
- AND t.typnamespace = n.oid
+ 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
@@ -2237,10 +2276,13 @@ CREATE VIEW user_defined_types AS
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
+ FROM pg_namespace n, pg_class c, pg_type t
WHERE n.oid = c.relnamespace
- AND c.relkind = 'c';
+ 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;
View
23 src/backend/catalog/pg_aggregate.c
@@ -71,6 +71,7 @@ AggregateCreate(const char *aggName,
int i;
ObjectAddress myself,
referenced;
+ AclResult aclresult;
/* sanity checks (caller should have caught these) */
if (!aggName)
@@ -201,6 +202,28 @@ AggregateCreate(const char *aggName,
}
/*
+ * 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(aclresult, ACL_KIND_TYPE,
+ format_type_be(aggArgTypes[i]));
+ }
+
+ aclresult = pg_type_aclcheck(aggTransType, GetUserId(), ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_TYPE,
+ format_type_be(aggTransType));
+
+ aclresult = pg_type_aclcheck(finaltype, GetUserId(), ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_TYPE,
+ format_type_be(finaltype));
+
+
+ /*
* Everything looks okay. Try to create the pg_proc entry for the
* aggregate. (This could fail if there's already a conflicting entry.)
*/
View
9 src/backend/catalog/pg_type.c
@@ -117,6 +117,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
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;
/*
* create a new type tuple
@@ -224,6 +225,7 @@ TypeCreate(Oid newTypeOid,
Datum values[Natts_pg_type];
NameData name;
int i;
+ Acl *typacl = NULL;
/*
* We assume that the caller validated the arguments individually, but did
@@ -369,6 +371,13 @@ TypeCreate(Oid newTypeOid,
else
nulls[Anum_pg_type_typdefault - 1] = true;
+ typacl = get_user_default_acl(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.
*
View
24 src/backend/commands/functioncmds.c
@@ -87,9 +87,11 @@ compute_return_type(TypeName *returnType, Oid languageOid,
{
Oid rettype;
Type typtup;
+ AclResult aclresult;
typtup = LookupTypeName(NULL, returnType, NULL);
+
if (typtup)
{
if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
@@ -150,6 +152,11 @@ compute_return_type(TypeName *returnType, Oid languageOid,
Assert(OidIsValid(rettype));
}
+ aclresult = pg_type_aclcheck(rettype, GetUserId(), ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_TYPE,
+ format_type_be(rettype));
+
*prorettype_p = rettype;
*returnsSet_p = returnType->setof;
}
@@ -207,6 +214,7 @@ examine_parameter_list(List *parameters, Oid languageOid,
bool isinput = false;
Oid toid;
Type typtup;
+ AclResult aclresult;
typtup = LookupTypeName(NULL, t, NULL);
if (typtup)
@@ -237,6 +245,11 @@ examine_parameter_list(List *parameters, Oid languageOid,
toid = InvalidOid; /* keep compiler quiet */
}
+ aclresult = pg_type_aclcheck(toid, GetUserId(), ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_TYPE,
+ format_type_be(toid));
+
if (t->setof)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
@@ -1429,6 +1442,7 @@ CreateCast(CreateCastStmt *stmt)
bool nulls[Natts_pg_cast];
ObjectAddress myself,
referenced;
+ AclResult aclresult;
sourcetypeid = typenameTypeId(NULL, stmt->sourcetype);
targettypeid = typenameTypeId(NULL, stmt->targettype);
@@ -1457,6 +1471,16 @@ CreateCast(CreateCastStmt *stmt)
format_type_be(sourcetypeid),
format_type_be(targettypeid))));
+ aclresult = pg_type_aclcheck(sourcetypeid, GetUserId(), ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_TYPE,
+ format_type_be(sourcetypeid));
+
+ aclresult = pg_type_aclcheck(targettypeid, GetUserId(), ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_TYPE,
+ format_type_be(targettypeid));
+
/* Detemine the cast method */
if (stmt->func != NULL)
castmethod = COERCION_METHOD_FUNCTION;
View
24 src/backend/commands/operatorcmds.c
@@ -45,6 +45,7 @@
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
+#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
@@ -73,6 +74,7 @@ DefineOperator(List *names, List *parameters)
TypeName *typeName2 = NULL; /* second type name */
Oid typeId1 = InvalidOid; /* types converted to OID */
Oid typeId2 = InvalidOid;
+ Oid rettype;
List *commutatorName = NIL; /* optional commutator operator name */
List *negatorName = NIL; /* optional negator operator name */
List *restrictionName = NIL; /* optional restrict. sel. procedure */
@@ -175,6 +177,22 @@ DefineOperator(List *names, List *parameters)
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("at least one of leftarg or rightarg must be specified")));
+ if (typeName1)
+ {
+ aclresult = pg_type_aclcheck(typeId1, GetUserId(), ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_TYPE,
+ format_type_be(typeId1));
+ }
+
+ if (typeName2)
+ {
+ aclresult = pg_type_aclcheck(typeId2, GetUserId(), ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_TYPE,
+ format_type_be(typeId2));
+ }
+
/*
* Look up the operator's underlying function.
*/
@@ -206,6 +224,12 @@ DefineOperator(List *names, List *parameters)
aclcheck_error(aclresult, ACL_KIND_PROC,
NameListToString(functionName));
+ rettype = get_func_rettype(functionOid);
+ aclresult = pg_type_aclcheck(rettype, GetUserId(), ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_TYPE,
+ format_type_be(rettype));
+
/*
* Look up restriction estimator if specified
*/
View
22 src/backend/commands/tablecmds.c
@@ -506,7 +506,16 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
(void) heap_reloptions(relkind, reloptions, true);
if (stmt->ofTypename)
+ {
+ AclResult aclresult;
+
ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
+
+ aclresult = pg_type_aclcheck(ofTypeId, GetUserId(), ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_TYPE,
+ format_type_be(ofTypeId));
+ }
else
ofTypeId = InvalidOid;
@@ -4326,6 +4335,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
Expr *defval;
List *children;
ListCell *child;
+ AclResult aclresult;
/* At top level, permission check was done in ATPrepCmd, else do it */
if (recursing)
@@ -4429,6 +4439,12 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
typeTuple = typenameType(NULL, colDef->typeName, &typmod);
tform = (Form_pg_type) GETSTRUCT(typeTuple);
typeOid = HeapTupleGetOid(typeTuple);
+
+ aclresult = pg_type_aclcheck(typeOid, GetUserId(), ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_TYPE,
+ format_type_be(typeOid));
+
collOid = GetColumnDefCollation(NULL, colDef, typeOid);
/* make sure datatype is legal for a column */
@@ -6973,6 +6989,7 @@ ATPrepAlterColumnType(List **wqueue,
Oid targetcollid;
NewColumnValue *newval;
ParseState *pstate = make_parsestate(NULL);
+ AclResult aclresult;
if (rel->rd_rel->reloftype && !recursing)
ereport(ERROR,
@@ -7006,6 +7023,11 @@ ATPrepAlterColumnType(List **wqueue,
/* Look up the target type */
typenameTypeIdAndMod(NULL, typeName, &targettype, &targettypmod);
+ aclresult = pg_type_aclcheck(targettype, GetUserId(), ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_TYPE,
+ format_type_be(targettype));
+
/* And the collation */
targetcollid = GetColumnDefCollation(NULL, def, targettype);
View
5 src/backend/commands/typecmds.c
@@ -756,6 +756,11 @@ DefineDomain(CreateDomainStmt *stmt)
errmsg("\"%s\" is not a valid base type for a domain",
TypeNameToString(stmt->typeName))));
+ aclresult = pg_type_aclcheck(basetypeoid, GetUserId(), ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_TYPE,
+ format_type_be(basetypeoid));
+
/*
* Identify the collation if any
*/
View
15 src/backend/executor/execMain.c
@@ -2490,6 +2490,21 @@ OpenIntoRel(QueryDesc *queryDesc)
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("ON COMMIT can only be used on temporary tables")));
+ {
+ AclResult aclresult;
+ int i;
+
+ for (i = 0; i < intoTupDesc->natts; i++)
+ {
+ Oid atttypid = intoTupDesc->attrs[i]->atttypid;
+
+ aclresult = pg_type_aclcheck(atttypid, GetUserId(), ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_TYPE,
+ format_type_be(atttypid));
+ }
+ }
+
/*
* If a column name list was specified in CREATE TABLE AS, override the
* column names derived from the query. (Too few column names are OK, too
View
19 src/backend/parser/gram.y
@@ -558,7 +558,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType,
TABLE TABLES TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN TIME TIMESTAMP
TO TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P
- TRUNCATE TRUSTED TYPE_P
+ TRUNCATE TRUSTED TYPE_P TYPES_P
UNBOUNDED UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNLOGGED
UNTIL UPDATE USER USING
@@ -5434,6 +5434,14 @@ privilege_target:
n->objs = $2;
$$ = n;
}
+ | DOMAIN_P any_name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_OBJECT;
+ n->objtype = ACL_OBJECT_DOMAIN;
+ n->objs = $2;
+ $$ = n;
+ }
| LANGUAGE name_list
{
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
@@ -5466,6 +5474,14 @@ privilege_target:
n->objs = $2;
$$ = n;
}
+ | TYPE_P any_name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_OBJECT;
+ n->objtype = ACL_OBJECT_TYPE;
+ n->objs = $2;
+ $$ = n;
+ }
| ALL TABLES IN_P SCHEMA name_list
{
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
@@ -5680,6 +5696,7 @@ defacl_privilege_target:
TABLES { $$ = ACL_OBJECT_RELATION; }
| FUNCTIONS { $$ = ACL_OBJECT_FUNCTION; }
| SEQUENCES { $$ = ACL_OBJECT_SEQUENCE; }
+ | TYPES_P { $$ = ACL_OBJECT_TYPE; }
;
View
207 src/backend/utils/adt/acl.c
@@ -109,6 +109,8 @@ static Oid convert_server_name(text *servername);
static AclMode convert_server_priv_string(text *priv_type_text);
static Oid convert_tablespace_name(text *tablespacename);
static AclMode convert_tablespace_priv_string(text *priv_type_text);
+static Oid convert_type_name(text *typename);
+static AclMode convert_type_priv_string(text *priv_type_text);
static AclMode convert_role_priv_string(text *priv_type_text);
static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
@@ -782,6 +784,11 @@ acldefault(GrantObjectType objtype, Oid ownerId)
world_default = ACL_NO_RIGHTS;
owner_default = ACL_ALL_RIGHTS_FOREIGN_SERVER;
break;
+ case ACL_OBJECT_DOMAIN:
+ case ACL_OBJECT_TYPE:
+ world_default = ACL_USAGE;
+ owner_default = ACL_ALL_RIGHTS_TYPE;
+ break;
default:
elog(ERROR, "unrecognized objtype: %d", (int) objtype);
world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
@@ -4127,6 +4134,206 @@ convert_tablespace_priv_string(text *priv_type_text)
}
/*
+ * has_type_privilege variants
+ * These are all named "has_type_privilege" at the SQL level.
+ * They take various combinations of type name, type OID,
+ * user name, user OID, or implicit user = current_user.
+ *
+ * The result is a boolean value: true if user has the indicated
+ * privilege, false if not, or NULL if object doesn't exist.
+ */
+
+/*
+ * has_type_privilege_name_name
+ * Check user privileges on a type given
+ * name username, text typename, and text priv name.
+ */
+Datum
+has_type_privilege_name_name(PG_FUNCTION_ARGS)
+{
+ Name username = PG_GETARG_NAME(0);
+ text *typename = PG_GETARG_TEXT_P(1);
+ text *priv_type_text = PG_GETARG_TEXT_P(2);
+ Oid roleid;
+ Oid typeoid;
+ AclMode mode;
+ AclResult aclresult;
+
+ roleid = get_role_oid_or_public(NameStr(*username));
+ typeoid = convert_type_name(typename);
+ mode = convert_type_priv_string(priv_type_text);
+
+ aclresult = pg_type_aclcheck(typeoid, roleid, mode);
+
+ PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_type_privilege_name
+ * Check user privileges on a type given
+ * text typename and text priv name.
+ * current_user is assumed
+ */
+Datum
+has_type_privilege_name(PG_FUNCTION_ARGS)
+{
+ text *typename = PG_GETARG_TEXT_P(0);
+ text *priv_type_text = PG_GETARG_TEXT_P(1);
+ Oid roleid;
+ Oid typeoid;
+ AclMode mode;
+ AclResult aclresult;
+
+ roleid = GetUserId();
+ typeoid = convert_type_name(typename);
+ mode = convert_type_priv_string(priv_type_text);
+
+ aclresult = pg_type_aclcheck(typeoid, roleid, mode);
+
+ PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_type_privilege_name_id
+ * Check user privileges on a type given
+ * name usename, type oid, and text priv name.
+ */
+Datum
+has_type_privilege_name_id(PG_FUNCTION_ARGS)
+{
+ Name username = PG_GETARG_NAME(0);
+ Oid typeoid = PG_GETARG_OID(1);
+ text *priv_type_text = PG_GETARG_TEXT_P(2);
+ Oid roleid;
+ AclMode mode;
+ AclResult aclresult;
+
+ roleid = get_role_oid_or_public(NameStr(*username));
+ mode = convert_type_priv_string(priv_type_text);
+
+ if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(typeoid)))
+ PG_RETURN_NULL();
+
+ aclresult = pg_type_aclcheck(typeoid, roleid, mode);
+
+ PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_type_privilege_id
+ * Check user privileges on a type given
+ * type oid, and text priv name.
+ * current_user is assumed
+ */
+Datum
+has_type_privilege_id(PG_FUNCTION_ARGS)
+{
+ Oid typeoid = PG_GETARG_OID(0);
+ text *priv_type_text = PG_GETARG_TEXT_P(1);
+ Oid roleid;
+ AclMode mode;
+ AclResult aclresult;
+
+ roleid = GetUserId();
+ mode = convert_type_priv_string(priv_type_text);
+
+ if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(typeoid)))
+ PG_RETURN_NULL();
+
+ aclresult = pg_type_aclcheck(typeoid, roleid, mode);
+
+ PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_type_privilege_id_name
+ * Check user privileges on a type given
+ * roleid, text typename, and text priv name.
+ */
+Datum
+has_type_privilege_id_name(PG_FUNCTION_ARGS)
+{
+ Oid roleid = PG_GETARG_OID(0);
+ text *typename = PG_GETARG_TEXT_P(1);
+ text *priv_type_text = PG_GETARG_TEXT_P(2);
+ Oid typeoid;
+ AclMode mode;
+ AclResult aclresult;
+
+ typeoid = convert_type_name(typename);
+ mode = convert_type_priv_string(priv_type_text);
+
+ aclresult = pg_type_aclcheck(typeoid, roleid, mode);
+
+ PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_type_privilege_id_id
+ * Check user privileges on a type given
+ * roleid, type oid, and text priv name.
+ */
+Datum
+has_type_privilege_id_id(PG_FUNCTION_ARGS)
+{
+ Oid roleid = PG_GETARG_OID(0);
+ Oid typeoid = PG_GETARG_OID(1);
+ text *priv_type_text = PG_GETARG_TEXT_P(2);
+ AclMode mode;
+ AclResult aclresult;
+
+ mode = convert_type_priv_string(priv_type_text);
+
+ if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(typeoid)))
+ PG_RETURN_NULL();
+
+ aclresult = pg_type_aclcheck(typeoid, roleid, mode);
+
+ PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * Support routines for has_type_privilege family.
+ */
+
+/*
+ * Given a type name expressed as a string, look it up and return Oid
+ */
+static Oid
+convert_type_name(text *typename)
+{
+ char *typname = text_to_cstring(typename);
+ Oid oid;
+
+ oid = DatumGetObjectId(DirectFunctionCall1(regtypein,
+ CStringGetDatum(typname)));
+
+ if (!OidIsValid(oid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("type \"%s\" does not exist", typname)));
+
+ return oid;
+}
+
+/*
+ * convert_type_priv_string
+ * Convert text string to AclMode value.
+ */
+static AclMode
+convert_type_priv_string(text *priv_type_text)
+{
+ static const priv_map type_priv_map[] = {
+ {"USAGE", ACL_USAGE},
+ {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
+ {NULL, 0}
+ };
+
+ return convert_any_priv_string(priv_type_text, type_priv_map);
+}
+
+
+/*
* pg_has_role variants
* These are all named "pg_has_role" at the SQL level.
* They take various combinations of role name, role OID,
View
12 src/bin/psql/describe.c
@@ -504,6 +504,11 @@ describeTypes(const char *pattern, bool verbose, bool showSystem)
" ) AS \"%s\",\n",
gettext_noop("Elements"));
}
+ if (verbose && pset.sversion >= 90200)
+ {
+ printACLColumn(&buf, "t.typacl");
+ appendPQExpBuffer(&buf, ",\n ");
+ }
appendPQExpBuffer(&buf,
" pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n",
@@ -2813,9 +2818,16 @@ listDomains(const char *pattern, bool verbose, bool showSystem)
gettext_noop("Check"));
if (verbose)
+ {
+ if (pset.sversion >= 90200)
+ {
+ appendPQExpBuffer(&buf, ",\n ");
+ printACLColumn(&buf, "t.typacl");
+ }
appendPQExpBuffer(&buf,
",\n d.description as \"%s\"",
gettext_noop("Description"));
+ }
appendPQExpBuffer(&buf,
"\nFROM pg_catalog.pg_type t\n"
View
8 src/bin/psql/tab-complete.c
@@ -2241,13 +2241,15 @@ psql_completion(char *text, int start, int end)
pg_strcasecmp(prev_wd, "ON") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf,
" UNION SELECT 'DATABASE'"
+ " UNION SELECT 'DOMAIN'"
" UNION SELECT 'FOREIGN DATA WRAPPER'"
" UNION SELECT 'FOREIGN SERVER'"
" UNION SELECT 'FUNCTION'"
" UNION SELECT 'LANGUAGE'"
" UNION SELECT 'LARGE OBJECT'"
" UNION SELECT 'SCHEMA'"
- " UNION SELECT 'TABLESPACE'");
+ " UNION SELECT 'TABLESPACE'"
+ " UNION SELECT 'TYPE'");
else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
pg_strcasecmp(prev2_wd, "ON") == 0 &&
@@ -2266,6 +2268,8 @@ psql_completion(char *text, int start, int end)
{
if (pg_strcasecmp(prev_wd, "DATABASE") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_databases);
+ else if (pg_strcasecmp(prev_wd, "DOMAIN") == 0)
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
else if (pg_strcasecmp(prev_wd, "FUNCTION") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
else if (pg_strcasecmp(prev_wd, "LANGUAGE") == 0)
@@ -2274,6 +2278,8 @@ psql_completion(char *text, int start, int end)
COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
+ else if (pg_strcasecmp(prev_wd, "TYPE") == 0)
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
else if (pg_strcasecmp(prev4_wd, "GRANT") == 0)
COMPLETE_WITH_CONST("TO");
else
View
2 src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201112191
+#define CATALOG_VERSION_NO 201112192
#endif
View
2 src/include/catalog/pg_class.h
@@ -133,7 +133,7 @@ typedef FormData_pg_class *Form_pg_class;
*/
/* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
-DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 0 f f p r 29 0 t f f f f 3 _null_ _null_ ));
+DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 0 f f p r 30 0 t f f f f 3 _null_ _null_ ));
DESCR("");
DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 0 f f p r 21 0 f f f f f 3 _null_ _null_ ));
DESCR("");
View
1 src/include/catalog/pg_default_acl.h
@@ -71,5 +71,6 @@ typedef FormData_pg_default_acl *Form_pg_default_acl;
#define DEFACLOBJ_RELATION 'r' /* table, view */
#define DEFACLOBJ_SEQUENCE 'S' /* sequence */
#define DEFACLOBJ_FUNCTION 'f' /* function */
+#define DEFACLOBJ_TYPE 'T' /* type */
#endif /* PG_DEFAULT_ACL_H */
View
13 src/include/catalog/pg_proc.h
@@ -3311,6 +3311,19 @@ DESCR("current user privilege on server by server name");
DATA(insert OID = 3011 ( has_server_privilege PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 16 "26 25" _null_ _null_ _null_ _null_ has_server_privilege_id _null_ _null_ _null_ ));
DESCR("current user privilege on server by server oid");
+DATA(insert OID = 3138 ( has_type_privilege PGNSP PGUID 12 1 0 0 0 f f f t f s 3 0 16 "19 25 25" _null_ _null_ _null_ _null_ has_type_privilege_name_name _null_ _null_ _null_ ));
+DESCR("user privilege on type by username, type name");
+DATA(insert OID = 3139 ( has_type_privilege PGNSP PGUID 12 1 0 0 0 f f f t f s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ has_type_privilege_name_id _null_ _null_ _null_ ));
+DESCR("user privilege on type by username, type oid");
+DATA(insert OID = 3140 ( has_type_privilege PGNSP PGUID 12 1 0 0 0 f f f t f s 3 0 16 "26 25 25" _null_ _null_ _null_ _null_ has_type_privilege_id_name _null_ _null_ _null_ ));
+DESCR("user privilege on type by user oid, type name");
+DATA(insert OID = 3141 ( has_type_privilege PGNSP PGUID 12 1 0 0 0 f f f t f s 3 0 16 "26 26 25" _null_ _null_ _null_ _null_ has_type_privilege_id_id _null_ _null_ _null_ ));
+DESCR("user privilege on type by user oid, type oid");
+DATA(insert OID = 3142 ( has_type_privilege PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 16 "25 25" _null_ _null_ _null_ _null_ has_type_privilege_name _null_ _null_ _null_ ));
+DESCR("current user privilege on type by type name");
+DATA(insert OID = 3143 ( has_type_privilege PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 16 "26 25" _null_ _null_ _null_ _null_ has_type_privilege_id _null_ _null_ _null_ ));
+DESCR("current user privilege on type by type oid");
+
DATA(insert OID = 2705 ( pg_has_role PGNSP PGUID 12 1 0 0 0 f f f t f s 3 0 16 "19 19 25" _null_ _null_ _null_ _null_ pg_has_role_name_name _null_ _null_ _null_ ));
DESCR("user privilege on role by username, role name");
DATA(insert OID = 2706 ( pg_has_role PGNSP PGUID 12 1 0 0 0 f f f t f s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ pg_has_role_name_id _null_ _null_ _null_ ));
View
305 src/include/catalog/pg_type.h
@@ -217,6 +217,10 @@ CATALOG(pg_type,1247) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71) BKI_SCHEMA_MACRO
*/
text typdefault; /* VARIABLE LENGTH FIELD */
+ /*
+ * Access permissions
+ */
+ aclitem typacl[1]; /* VARIABLE LENGTH FIELD */
} FormData_pg_type;
/* ----------------
@@ -230,7 +234,7 @@ typedef FormData_pg_type *Form_pg_type;
* compiler constants for pg_type
* ----------------
*/
-#define Natts_pg_type 29
+#define Natts_pg_type 30
#define Anum_pg_type_typname 1
#define Anum_pg_type_typnamespace 2
#define Anum_pg_type_typowner 3
@@ -260,6 +264,7 @@ typedef FormData_pg_type *Form_pg_type;
#define Anum_pg_type_typcollation 27
#define Anum_pg_type_typdefaultbin 28
#define Anum_pg_type_typdefault 29
+#define Anum_pg_type_typacl 30
/* ----------------
@@ -276,87 +281,87 @@ typedef FormData_pg_type *Form_pg_type;
*/
/* OIDS 1 - 99 */
-DATA(insert OID = 16 ( bool PGNSP PGUID 1 t b B t t \054 0 0 1000 boolin boolout boolrecv boolsend - - - c p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 16 ( bool PGNSP PGUID 1 t b B t t \054 0 0 1000 boolin boolout boolrecv boolsend - - - c p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("boolean, 'true'/'false'");
#define BOOLOID 16
-DATA(insert OID = 17 ( bytea PGNSP PGUID -1 f b U f t \054 0 0 1001 byteain byteaout bytearecv byteasend - - - i x f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 17 ( bytea PGNSP PGUID -1 f b U f t \054 0 0 1001 byteain byteaout bytearecv byteasend - - - i x f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("variable-length string, binary values escaped");
#define BYTEAOID 17
-DATA(insert OID = 18 ( char PGNSP PGUID 1 t b S f t \054 0 0 1002 charin charout charrecv charsend - - - c p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 18 ( char PGNSP PGUID 1 t b S f t \054 0 0 1002 charin charout charrecv charsend - - - c p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("single character");
#define CHAROID 18
-DATA(insert OID = 19 ( name PGNSP PGUID NAMEDATALEN f b S f t \054 0 18 1003 namein nameout namerecv namesend - - - c p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 19 ( name PGNSP PGUID NAMEDATALEN f b S f t \054 0 18 1003 namein nameout namerecv namesend - - - c p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("63-character type for storing system identifiers");
#define NAMEOID 19
-DATA(insert OID = 20 ( int8 PGNSP PGUID 8 FLOAT8PASSBYVAL b N f t \054 0 0 1016 int8in int8out int8recv int8send - - - d p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 20 ( int8 PGNSP PGUID 8 FLOAT8PASSBYVAL b N f t \054 0 0 1016 int8in int8out int8recv int8send - - - d p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("~18 digit integer, 8-byte storage");
#define INT8OID 20
-DATA(insert OID = 21 ( int2 PGNSP PGUID 2 t b N f t \054 0 0 1005 int2in int2out int2recv int2send - - - s p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 21 ( int2 PGNSP PGUID 2 t b N f t \054 0 0 1005 int2in int2out int2recv int2send - - - s p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("-32 thousand to 32 thousand, 2-byte storage");
#define INT2OID 21
-DATA(insert OID = 22 ( int2vector PGNSP PGUID -1 f b A f t \054 0 21 1006 int2vectorin int2vectorout int2vectorrecv int2vectorsend - - - i p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 22 ( int2vector PGNSP PGUID -1 f b A f t \054 0 21 1006 int2vectorin int2vectorout int2vectorrecv int2vectorsend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("array of int2, used in system tables");
#define INT2VECTOROID 22
-DATA(insert OID = 23 ( int4 PGNSP PGUID 4 t b N f t \054 0 0 1007 int4in int4out int4recv int4send - - - i p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 23 ( int4 PGNSP PGUID 4 t b N f t \054 0 0 1007 int4in int4out int4recv int4send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("-2 billion to 2 billion integer, 4-byte storage");
#define INT4OID 23
-DATA(insert OID = 24 ( regproc PGNSP PGUID 4 t b N f t \054 0 0 1008 regprocin regprocout regprocrecv regprocsend - - - i p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 24 ( regproc PGNSP PGUID 4 t b N f t \054 0 0 1008 regprocin regprocout regprocrecv regprocsend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("registered procedure");
#define REGPROCOID 24
-DATA(insert OID = 25 ( text PGNSP PGUID -1 f b S t t \054 0 0 1009 textin textout textrecv textsend - - - i x f 0 -1 0 100 _null_ _null_ ));
+DATA(insert OID = 25 ( text PGNSP PGUID -1 f b S t t \054 0 0 1009 textin textout textrecv textsend - - - i x f 0 -1 0 100 _null_ _null_ _null_ ));
DESCR("variable-length string, no limit specified");
#define TEXTOID 25
-DATA(insert OID = 26 ( oid PGNSP PGUID 4 t b N t t \054 0 0 1028 oidin oidout oidrecv oidsend - - - i p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 26 ( oid PGNSP PGUID 4 t b N t t \054 0 0 1028 oidin oidout oidrecv oidsend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("object identifier(oid), maximum 4 billion");
#define OIDOID 26
-DATA(insert OID = 27 ( tid PGNSP PGUID 6 f b U f t \054 0 0 1010 tidin tidout tidrecv tidsend - - - s p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 27 ( tid PGNSP PGUID 6 f b U f t \054 0 0 1010 tidin tidout tidrecv tidsend - - - s p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("(block, offset), physical location of tuple");
#define TIDOID 27
-DATA(insert OID = 28 ( xid PGNSP PGUID 4 t b U f t \054 0 0 1011 xidin xidout xidrecv xidsend - - - i p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 28 ( xid PGNSP PGUID 4 t b U f t \054 0 0 1011 xidin xidout xidrecv xidsend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("transaction id");
#define XIDOID 28
-DATA(insert OID = 29 ( cid PGNSP PGUID 4 t b U f t \054 0 0 1012 cidin cidout cidrecv cidsend - - - i p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 29 ( cid PGNSP PGUID 4 t b U f t \054 0 0 1012 cidin cidout cidrecv cidsend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("command identifier type, sequence in transaction id");
#define CIDOID 29
-DATA(insert OID = 30 ( oidvector PGNSP PGUID -1 f b A f t \054 0 26 1013 oidvectorin oidvectorout oidvectorrecv oidvectorsend - - - i p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 30 ( oidvector PGNSP PGUID -1 f b A f t \054 0 26 1013 oidvectorin oidvectorout oidvectorrecv oidvectorsend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("array of oids, used in system tables");
#define OIDVECTOROID 30
/* hand-built rowtype entries for bootstrapped catalogs */
/* NB: OIDs assigned here must match the BKI_ROWTYPE_OID declarations */
-DATA(insert OID = 71 ( pg_type PGNSP PGUID -1 f c C f t \054 1247 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 0 _null_ _null_ ));
-DATA(insert OID = 75 ( pg_attribute PGNSP PGUID -1 f c C f t \054 1249 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 0 _null_ _null_ ));
-DATA(insert OID = 81 ( pg_proc PGNSP PGUID -1 f c C f t \054 1255 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 0 _null_ _null_ ));
-DATA(insert OID = 83 ( pg_class PGNSP PGUID -1 f c C f t \054 1259 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 71 ( pg_type PGNSP PGUID -1 f c C f t \054 1247 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 75 ( pg_attribute PGNSP PGUID -1 f c C f t \054 1249 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 81 ( pg_proc PGNSP PGUID -1 f c C f t \054 1255 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 83 ( pg_class PGNSP PGUID -1 f c C f t \054 1259 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
/* OIDS 100 - 199 */
-DATA(insert OID = 142 ( xml PGNSP PGUID -1 f b U f t \054 0 0 143 xml_in xml_out xml_recv xml_send - - - i x f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 142 ( xml PGNSP PGUID -1 f b U f t \054 0 0 143 xml_in xml_out xml_recv xml_send - - - i x f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("XML content");
#define XMLOID 142
-DATA(insert OID = 143 ( _xml PGNSP PGUID -1 f b A f t \054 0 142 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 143 ( _xml PGNSP PGUID -1 f b A f t \054 0 142 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 194 ( pg_node_tree PGNSP PGUID -1 f b S f t \054 0 0 0 pg_node_tree_in pg_node_tree_out pg_node_tree_recv pg_node_tree_send - - - i x f 0 -1 0 100 _null_ _null_ ));
+DATA(insert OID = 194 ( pg_node_tree PGNSP PGUID -1 f b S f t \054 0 0 0 pg_node_tree_in pg_node_tree_out pg_node_tree_recv pg_node_tree_send - - - i x f 0 -1 0 100 _null_ _null_ _null_ ));
DESCR("string representing an internal node tree");
#define PGNODETREEOID 194
/* OIDS 200 - 299 */
-DATA(insert OID = 210 ( smgr PGNSP PGUID 2 t b U f t \054 0 0 0 smgrin smgrout - - - - - s p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 210 ( smgr PGNSP PGUID 2 t b U f t \054 0 0 0 smgrin smgrout - - - - - s p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("storage manager");
/* OIDS 300 - 399 */
@@ -366,252 +371,252 @@ DESCR("storage manager");
/* OIDS 500 - 599 */
/* OIDS 600 - 699 */
-DATA(insert OID = 600 ( point PGNSP PGUID 16 f b G f t \054 0 701 1017 point_in point_out point_recv point_send - - - d p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 600 ( point PGNSP PGUID 16 f b G f t \054 0 701 1017 point_in point_out point_recv point_send - - - d p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("geometric point '(x, y)'");
#define POINTOID 600
-DATA(insert OID = 601 ( lseg PGNSP PGUID 32 f b G f t \054 0 600 1018 lseg_in lseg_out lseg_recv lseg_send - - - d p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 601 ( lseg PGNSP PGUID 32 f b G f t \054 0 600 1018 lseg_in lseg_out lseg_recv lseg_send - - - d p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("geometric line segment '(pt1,pt2)'");
#define LSEGOID 601
-DATA(insert OID = 602 ( path PGNSP PGUID -1 f b G f t \054 0 0 1019 path_in path_out path_recv path_send - - - d x f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 602 ( path PGNSP PGUID -1 f b G f t \054 0 0 1019 path_in path_out path_recv path_send - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("geometric path '(pt1,...)'");
#define PATHOID 602
-DATA(insert OID = 603 ( box PGNSP PGUID 32 f b G f t \073 0 600 1020 box_in box_out box_recv box_send - - - d p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 603 ( box PGNSP PGUID 32 f b G f t \073 0 600 1020 box_in box_out box_recv box_send - - - d p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("geometric box '(lower left,upper right)'");
#define BOXOID 603
-DATA(insert OID = 604 ( polygon PGNSP PGUID -1 f b G f t \054 0 0 1027 poly_in poly_out poly_recv poly_send - - - d x f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 604 ( polygon PGNSP PGUID -1 f b G f t \054 0 0 1027 poly_in poly_out poly_recv poly_send - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("geometric polygon '(pt1,...)'");
#define POLYGONOID 604
-DATA(insert OID = 628 ( line PGNSP PGUID 32 f b G f t \054 0 701 629 line_in line_out line_recv line_send - - - d p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 628 ( line PGNSP PGUID 32 f b G f t \054 0 701 629 line_in line_out line_recv line_send - - - d p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("geometric line (not implemented)");
#define LINEOID 628
-DATA(insert OID = 629 ( _line PGNSP PGUID -1 f b A f t \054 0 628 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 629 ( _line PGNSP PGUID -1 f b A f t \054 0 628 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("");
/* OIDS 700 - 799 */
-DATA(insert OID = 700 ( float4 PGNSP PGUID 4 FLOAT4PASSBYVAL b N f t \054 0 0 1021 float4in float4out float4recv float4send - - - i p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 700 ( float4 PGNSP PGUID 4 FLOAT4PASSBYVAL b N f t \054 0 0 1021 float4in float4out float4recv float4send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("single-precision floating point number, 4-byte storage");
#define FLOAT4OID 700
-DATA(insert OID = 701 ( float8 PGNSP PGUID 8 FLOAT8PASSBYVAL b N t t \054 0 0 1022 float8in float8out float8recv float8send - - - d p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 701 ( float8 PGNSP PGUID 8 FLOAT8PASSBYVAL b N t t \054 0 0 1022 float8in float8out float8recv float8send - - - d p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("double-precision floating point number, 8-byte storage");
#define FLOAT8OID 701
-DATA(insert OID = 702 ( abstime PGNSP PGUID 4 t b D f t \054 0 0 1023 abstimein abstimeout abstimerecv abstimesend - - - i p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 702 ( abstime PGNSP PGUID 4 t b D f t \054 0 0 1023 abstimein abstimeout abstimerecv abstimesend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("absolute, limited-range date and time (Unix system time)");
#define ABSTIMEOID 702
-DATA(insert OID = 703 ( reltime PGNSP PGUID 4 t b T f t \054 0 0 1024 reltimein reltimeout reltimerecv reltimesend - - - i p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 703 ( reltime PGNSP PGUID 4 t b T f t \054 0 0 1024 reltimein reltimeout reltimerecv reltimesend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("relative, limited-range time interval (Unix delta time)");
#define RELTIMEOID 703
-DATA(insert OID = 704 ( tinterval PGNSP PGUID 12 f b T f t \054 0 0 1025 tintervalin tintervalout tintervalrecv tintervalsend - - - i p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 704 ( tinterval PGNSP PGUID 12 f b T f t \054 0 0 1025 tintervalin tintervalout tintervalrecv tintervalsend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("(abstime,abstime), time interval");
#define TINTERVALOID 704
-DATA(insert OID = 705 ( unknown PGNSP PGUID -2 f b X f t \054 0 0 0 unknownin unknownout unknownrecv unknownsend - - - c p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 705 ( unknown PGNSP PGUID -2 f b X f t \054 0 0 0 unknownin unknownout unknownrecv unknownsend - - - c p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("");
#define UNKNOWNOID 705
-DATA(insert OID = 718 ( circle PGNSP PGUID 24 f b G f t \054 0 0 719 circle_in circle_out circle_recv circle_send - - - d p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 718 ( circle PGNSP PGUID 24 f b G f t \054 0 0 719 circle_in circle_out circle_recv circle_send - - - d p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("geometric circle '(center,radius)'");
#define CIRCLEOID 718
-DATA(insert OID = 719 ( _circle PGNSP PGUID -1 f b A f t \054 0 718 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 0 _null_ _null_ ));
-DATA(insert OID = 790 ( money PGNSP PGUID 8 FLOAT8PASSBYVAL b N f t \054 0 0 791 cash_in cash_out cash_recv cash_send - - - d p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 719 ( _circle PGNSP PGUID -1 f b A f t \054 0 718 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 790 ( money PGNSP PGUID 8 FLOAT8PASSBYVAL b N f t \054 0 0 791 cash_in cash_out cash_recv cash_send - - - d p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("monetary amounts, $d,ddd.cc");
#define CASHOID 790
-DATA(insert OID = 791 ( _money PGNSP PGUID -1 f b A f t \054 0 790 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 791 ( _money PGNSP PGUID -1 f b A f t \054 0 790 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
/* OIDS 800 - 899 */
-DATA(insert OID = 829 ( macaddr PGNSP PGUID 6 f b U f t \054 0 0 1040 macaddr_in macaddr_out macaddr_recv macaddr_send - - - i p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 829 ( macaddr PGNSP PGUID 6 f b U f t \054 0 0 1040 macaddr_in macaddr_out macaddr_recv macaddr_send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("XX:XX:XX:XX:XX:XX, MAC address");
#define MACADDROID 829
-DATA(insert OID = 869 ( inet PGNSP PGUID -1 f b I t t \054 0 0 1041 inet_in inet_out inet_recv inet_send - - - i m f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 869 ( inet PGNSP PGUID -1 f b I t t \054 0 0 1041 inet_in inet_out inet_recv inet_send - - - i m f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("IP address/netmask, host address, netmask optional");
#define INETOID 869
-DATA(insert OID = 650 ( cidr PGNSP PGUID -1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 650 ( cidr PGNSP PGUID -1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("network IP address/netmask, network address");
#define CIDROID 650
/* OIDS 900 - 999 */
/* OIDS 1000 - 1099 */
-DATA(insert OID = 1000 ( _bool PGNSP PGUID -1 f b A f t \054 0 16 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
-DATA(insert OID = 1001 ( _bytea PGNSP PGUID -1 f b A f t \054 0 17 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
-DATA(insert OID = 1002 ( _char PGNSP PGUID -1 f b A f t \054 0 18 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
-DATA(insert OID = 1003 ( _name PGNSP PGUID -1 f b A f t \054 0 19 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
-DATA(insert OID = 1005 ( _int2 PGNSP PGUID -1 f b A f t \054 0 21 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
-DATA(insert OID = 1006 ( _int2vector PGNSP PGUID -1 f b A f t \054 0 22 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
-DATA(insert OID = 1007 ( _int4 PGNSP PGUID -1 f b A f t \054 0 23 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 1000 ( _bool PGNSP PGUID -1 f b A f t \054 0 16 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1001 ( _bytea PGNSP PGUID -1 f b A f t \054 0 17 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1002 ( _char PGNSP PGUID -1 f b A f t \054 0 18 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1003 ( _name PGNSP PGUID -1 f b A f t \054 0 19 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1005 ( _int2 PGNSP PGUID -1 f b A f t \054 0 21 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1006 ( _int2vector PGNSP PGUID -1 f b A f t \054 0 22 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1007 ( _int4 PGNSP PGUID -1 f b A f t \054 0 23 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ _null_ ));
#define INT4ARRAYOID 1007
-DATA(insert OID = 1008 ( _regproc PGNSP PGUID -1 f b A f t \054 0 24 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
-DATA(insert OID = 1009 ( _text PGNSP PGUID -1 f b A f t \054 0 25 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 100 _null_ _null_ ));
+DATA(insert OID = 1008 ( _regproc PGNSP PGUID -1 f b A f t \054 0 24 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1009 ( _text PGNSP PGUID -1 f b A f t \054 0 25 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 100 _null_ _null_ _null_ ));
#define TEXTARRAYOID 1009
-DATA(insert OID = 1028 ( _oid PGNSP PGUID -1 f b A f t \054 0 26 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
-DATA(insert OID = 1010 ( _tid PGNSP PGUID -1 f b A f t \054 0 27 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
-DATA(insert OID = 1011 ( _xid PGNSP PGUID -1 f b A f t \054 0 28 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
-DATA(insert OID = 1012 ( _cid PGNSP PGUID -1 f b A f t \054 0 29 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
-DATA(insert OID = 1013 ( _oidvector PGNSP PGUID -1 f b A f t \054 0 30 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
-DATA(insert OID = 1014 ( _bpchar PGNSP PGUID -1 f b A f t \054 0 1042 0 array_in array_out array_recv array_send bpchartypmodin bpchartypmodout - i x f 0 -1 0 100 _null_ _null_ ));
-DATA(insert OID = 1015 ( _varchar PGNSP PGUID -1 f b A f t \054 0 1043 0 array_in array_out array_recv array_send varchartypmodin varchartypmodout - i x f 0 -1 0 100 _null_ _null_ ));
-DATA(insert OID = 1016 ( _int8 PGNSP PGUID -1 f b A f t \054 0 20 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 0 _null_ _null_ ));
-DATA(insert OID = 1017 ( _point PGNSP PGUID -1 f b A f t \054 0 600 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 0 _null_ _null_ ));
-DATA(insert OID = 1018 ( _lseg PGNSP PGUID -1 f b A f t \054 0 601 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 0 _