]> granicus.if.org Git - postgresql/commitdiff
COMMENT ON casts, conversions, languages, operator classes, and
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 21 Nov 2003 22:32:49 +0000 (22:32 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 21 Nov 2003 22:32:49 +0000 (22:32 +0000)
large objects.  Dump all these in pg_dump; also add code to pg_dump
user-defined conversions.  Make psql's large object code rely on
the backend for inserting/deleting LOB comments, instead of trying to
hack pg_description directly.  Documentation and regression tests added.

Christopher Kings-Lynne, code reviewed by Tom

37 files changed:
doc/src/sgml/ref/comment.sgml
src/backend/catalog/aclchk.c
src/backend/commands/comment.c
src/backend/commands/functioncmds.c
src/backend/parser/gram.y
src/backend/parser/keywords.c
src/backend/storage/large_object/inv_api.c
src/bin/pg_dump/common.c
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h
src/bin/psql/large_obj.c
src/include/nodes/parsenodes.h
src/include/utils/acl.h
src/test/regress/expected/alter_table.out
src/test/regress/expected/conversion.out
src/test/regress/expected/create_aggregate.out
src/test/regress/expected/create_index.out
src/test/regress/expected/create_operator.out
src/test/regress/expected/create_type.out
src/test/regress/expected/create_view.out
src/test/regress/expected/foreign_key.out
src/test/regress/expected/plpgsql.out
src/test/regress/expected/rules.out
src/test/regress/expected/sequence.out
src/test/regress/expected/triggers.out
src/test/regress/sql/alter_table.sql
src/test/regress/sql/conversion.sql
src/test/regress/sql/create_aggregate.sql
src/test/regress/sql/create_index.sql
src/test/regress/sql/create_operator.sql
src/test/regress/sql/create_type.sql
src/test/regress/sql/create_view.sql
src/test/regress/sql/foreign_key.sql
src/test/regress/sql/plpgsql.sql
src/test/regress/sql/rules.sql
src/test/regress/sql/sequence.sql
src/test/regress/sql/triggers.sql

index 7e0f4318bfd034bcca5df8c098ee215530c5139b..7e1ff18d5e4bbcff459054920d7badf9aa0c8d63 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/comment.sgml,v 1.23 2003/09/09 18:28:52 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/comment.sgml,v 1.24 2003/11/21 22:32:48 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -25,12 +25,17 @@ COMMENT ON
   TABLE <replaceable class="PARAMETER">object_name</replaceable> |
   COLUMN <replaceable class="PARAMETER">table_name</replaceable>.<replaceable class="PARAMETER">column_name</replaceable> |
   AGGREGATE <replaceable class="PARAMETER">agg_name</replaceable> (<replaceable class="PARAMETER">agg_type</replaceable>) |
+  CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</replaceable>) |
   CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> |
+  CONVERSION <replaceable class="PARAMETER">object_name</replaceable> |
   DATABASE <replaceable class="PARAMETER">object_name</replaceable> |
   DOMAIN <replaceable class="PARAMETER">object_name</replaceable> |
   FUNCTION <replaceable class="PARAMETER">func_name</replaceable> (<replaceable class="PARAMETER">arg1_type</replaceable>, <replaceable class="PARAMETER">arg2_type</replaceable>, ...) |
   INDEX <replaceable class="PARAMETER">object_name</replaceable> |
+  LARGE OBJECT <replaceable class="PARAMETER">large_object_oid</replaceable> |
   OPERATOR <replaceable class="PARAMETER">op</replaceable> (<replaceable class="PARAMETER">leftoperand_type</replaceable>, <replaceable class="PARAMETER">rightoperand_type</replaceable>) |
+  OPERATOR CLASS <replaceable class="PARAMETER">object_name</replaceable> USING <replaceable class="parameter">index_method</replaceable> |
+  [ PROCEDURAL ] LANGUAGE <replaceable class="PARAMETER">object_name</replaceable> |
   RULE <replaceable class="PARAMETER">rule_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> |
   SCHEMA <replaceable class="PARAMETER">object_name</replaceable> |
   SEQUENCE <replaceable class="PARAMETER">object_name</replaceable> |
@@ -70,7 +75,7 @@ COMMENT ON
    <varlistentry>
     <term><replaceable class="parameter">object_name</replaceable></term>
     <term><replaceable class="parameter">table_name.column_name</replaceable></term>
-    <term><replaceable class="parameter">aggname</replaceable></term>
+    <term><replaceable class="parameter">agg_name</replaceable></term>
     <term><replaceable class="parameter">constraint_name</replaceable></term>
     <term><replaceable class="parameter">func_name</replaceable></term>
     <term><replaceable class="parameter">op</replaceable></term>
@@ -78,13 +83,60 @@ COMMENT ON
     <term><replaceable class="parameter">trigger_name</replaceable></term>
     <listitem>
      <para>
-      The name of the object to be be commented.  Names of tables,
-      aggregates, domains, functions, indexes, operators, sequences,
-      types, and views may be schema-qualified.
+      The name of the object to be commented.  Names of tables,
+      aggregates, domains, functions, indexes, operators, operator classes,
+      sequences, types, and views may be schema-qualified.
      </para>
     </listitem>
    </varlistentry>
 
+   <varlistentry>
+    <term><replaceable class="parameter">agg_type</replaceable></term>
+    <listitem>
+     <para>
+      The argument data type of the aggregate function, or
+      <literal>*</literal> if the function accepts any data type.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><replaceable class="parameter">large_object_oid</replaceable></term>
+    <listitem>
+     <para>
+      The OID of the large object.
+     </para>
+    </listitem>
+   </varlistentry>
+
+    <varlistentry>
+     <term><literal>PROCEDURAL</literal></term>
+
+     <listitem>
+      <para>
+       This is a noise word.
+      </para>
+     </listitem>
+    </varlistentry>
+   
+   <varlistentry>
+     <term><replaceable>sourcetype</replaceable></term>
+     <listitem>
+      <para>
+       The name of the source data type of the cast.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term><replaceable>targettype</replaceable></term>
+     <listitem>
+      <para>
+       The name of the target data type of the cast.
+      </para>
+     </listitem>
+    </varlistentry>
+
    <varlistentry>
     <term><replaceable class="parameter">text</replaceable></term>
     <listitem>
@@ -93,12 +145,18 @@ COMMENT ON
      </para>
     </listitem>
    </varlistentry>
+    
   </variablelist>
  </refsect1>
 
  <refsect1>
   <title>Notes</title>
 
+  <para>
+   A comment for a database can only be created in that database,
+   and will only be visible in that database, not in other databases.
+  </para>
+
   <para>
    There is presently no security mechanism for comments: any user
    connected to a database can see all the comments for objects in
@@ -130,13 +188,18 @@ COMMENT ON TABLE mytable IS NULL;
 
 <programlisting>
 COMMENT ON AGGREGATE my_aggregate (double precision) IS 'Computes sample variance';
+COMMENT ON CAST (text AS int4) IS 'Allow casts from text to int4';
 COMMENT ON COLUMN my_table.my_column IS 'Employee ID number';
+COMMENT ON CONVERSION my_conv IS 'Conversion to Unicode';
 COMMENT ON DATABASE my_database IS 'Development Database';
 COMMENT ON DOMAIN my_domain IS 'Email Address Domain';
 COMMENT ON FUNCTION my_function (timestamp) IS 'Returns Roman Numeral';
 COMMENT ON INDEX my_index IS 'Enforces uniqueness on employee ID';
+COMMENT ON LANGUAGE plpython IS 'Python support for stored procedures';
+COMMENT ON LARGE OBJECT 346344 IS 'Planning document';
 COMMENT ON OPERATOR ^ (text, text) IS 'Performs intersection of two texts';
 COMMENT ON OPERATOR ^ (NONE, text) IS 'This is a prefix operator on text';
+COMMENT ON OPERATOR CLASS int4ops USING btree IS '4 byte integer operators for btrees';
 COMMENT ON RULE my_rule ON my_table IS 'Logs updates of employee records';
 COMMENT ON SCHEMA my_schema IS 'Departmental data';
 COMMENT ON SEQUENCE my_sequence IS 'Used to generate primary keys';
index 7534750c99eb2051b4c3c83d8eb798bb15529ca4..93103c16f898d9c1330e7f89b231414aa8d588fd 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.93 2003/11/12 21:15:48 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.94 2003/11/21 22:32:48 tgl Exp $
  *
  * NOTES
  *       See acl.h.
@@ -22,6 +22,7 @@
 #include "catalog/catname.h"
 #include "catalog/indexing.h"
 #include "catalog/namespace.h"
+#include "catalog/pg_conversion.h"
 #include "catalog/pg_database.h"
 #include "catalog/pg_group.h"
 #include "catalog/pg_language.h"
@@ -1551,3 +1552,31 @@ pg_database_ownercheck(Oid db_oid, AclId userid)
 
        return userid == dba;
 }
+
+/*
+ * Ownership check for a conversion (specified by OID).
+ */
+bool
+pg_conversion_ownercheck(Oid conv_oid, AclId userid)
+{
+       HeapTuple       tuple;
+       AclId           owner_id;
+
+       /* Superusers bypass all permission checking. */
+       if (superuser_arg(userid))
+               return true;
+
+       tuple = SearchSysCache(CONOID,
+                                                  ObjectIdGetDatum(conv_oid),
+                                                  0, 0, 0);
+       if (!HeapTupleIsValid(tuple))
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                errmsg("conversion with OID %u does not exist", conv_oid)));
+
+       owner_id = ((Form_pg_conversion) GETSTRUCT(tuple))->conowner;
+
+       ReleaseSysCache(tuple);
+
+       return userid == owner_id;
+}
index 62765a96e0a2f313f58b56814e9dd7514dc34ee9..2283c563790bc0644fd08f02992ebf9b14feb02c 100644 (file)
@@ -7,7 +7,7 @@
  * Copyright (c) 1996-2003, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.73 2003/11/12 21:15:49 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.74 2003/11/21 22:32:48 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,6 +21,7 @@
 #include "catalog/namespace.h"
 #include "catalog/pg_constraint.h"
 #include "catalog/pg_description.h"
+#include "catalog/pg_largeobject.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_rewrite.h"
 #include "catalog/pg_trigger.h"
@@ -58,6 +59,11 @@ static void CommentProc(List *function, List *arguments, char *comment);
 static void CommentOperator(List *opername, List *arguments, char *comment);
 static void CommentTrigger(List *qualname, char *comment);
 static void CommentConstraint(List *qualname, char *comment);
+static void CommentConversion(List *qualname, char *comment);
+static void CommentLanguage(List *qualname, char *comment);
+static void CommentOpClass(List *qualname, List *arguments, char *comment);
+static void CommentLargeObject(List *qualname, char *comment);
+static void CommentCast(List *qualname, List *arguments, char *comment);
 
 
 /*
@@ -107,6 +113,21 @@ CommentObject(CommentStmt *stmt)
                case OBJECT_CONSTRAINT:
                        CommentConstraint(stmt->objname, stmt->comment);
                        break;
+               case OBJECT_CONVERSION:
+                       CommentConversion(stmt->objname, stmt->comment);
+                       break;
+               case OBJECT_LANGUAGE:
+                       CommentLanguage(stmt->objname, stmt->comment);
+                       break;
+               case OBJECT_OPCLASS:
+                       CommentOpClass(stmt->objname, stmt->objargs, stmt->comment);
+                       break;
+               case OBJECT_LARGEOBJECT:
+                       CommentLargeObject(stmt->objname,  stmt->comment);
+                       break;
+               case OBJECT_CAST:
+                       CommentCast(stmt->objname, stmt->objargs,  stmt->comment);
+                       break;
                default:
                        elog(ERROR, "unrecognized object type: %d",
                                 (int) stmt->objtype);
@@ -592,7 +613,10 @@ CommentRule(List *qualname, char *comment)
                                                           PointerGetDatum(rulename),
                                                           0, 0);
                if (!HeapTupleIsValid(tuple))
-                       elog(ERROR, "cache lookup failed for rule \"%s\"", rulename);
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                        errmsg("rule \"%s\" for relation \"%s\" does not exist",
+                                                       rulename, RelationGetRelationName(relation))));
                Assert(reloid == ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_class);
                ruleoid = HeapTupleGetOid(tuple);
                ReleaseSysCache(tuple);
@@ -910,3 +934,297 @@ CommentConstraint(List *qualname, char *comment)
        heap_close(pg_constraint, AccessShareLock);
        heap_close(relation, NoLock);
 }
+
+/*
+ * CommentConversion --
+ *
+ * This routine is used to add/drop any user-comments a user might
+ * have regarding a CONVERSION. The conversion is specified by name
+ * and, if found, and the user has appropriate permissions, a
+ * comment will be added/dropped using the CreateComments() routine.
+ * The conversion's name and the comment are the parameters to this routine.
+ */
+static void
+CommentConversion(List *qualname, char *comment)
+{
+       Oid                     conversionOid;
+       Oid                     classoid;
+
+       conversionOid = FindConversionByName(qualname);
+       if (!OidIsValid(conversionOid))
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                errmsg("conversion \"%s\" does not exist",
+                                               NameListToString(qualname))));
+
+       /* Check object security */
+       if (!pg_conversion_ownercheck(conversionOid, GetUserId()))
+               aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
+                                          NameListToString(qualname));
+
+       /* pg_conversion doesn't have a hard-coded OID, so must look it up */
+       classoid = get_system_catalog_relid(ConversionRelationName);
+
+       /* Call CreateComments() to create/drop the comments */
+       CreateComments(conversionOid, classoid, 0, comment);
+}
+
+/*
+ * CommentLanguage --
+ *
+ * This routine is used to add/drop any user-comments a user might
+ * have regarding a LANGUAGE. The language is specified by name
+ * and, if found, and the user has appropriate permissions, a
+ * comment will be added/dropped using the CreateComments() routine.
+ * The language's name and the comment are the parameters to this routine.
+ */
+static void
+CommentLanguage(List *qualname, char *comment)
+{
+       Oid                     oid;
+       Oid                     classoid;
+       char       *language;
+
+       if (length(qualname) != 1)
+               ereport(ERROR,
+                               (errcode(ERRCODE_SYNTAX_ERROR),
+                                errmsg("language name may not be qualified")));
+       language = strVal(lfirst(qualname));
+
+       oid = GetSysCacheOid(LANGNAME,
+                                                CStringGetDatum(language),
+                                                0, 0, 0);
+       if (!OidIsValid(oid))
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_SCHEMA),
+                                errmsg("language \"%s\" does not exist", language)));
+
+       /* Check object security */
+       if (!superuser())
+               ereport(ERROR,
+                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                          errmsg("must be superuser to comment on procedural language")));
+
+       /* pg_language doesn't have a hard-coded OID, so must look it up */
+       classoid = get_system_catalog_relid(LanguageRelationName);
+
+       /* Call CreateComments() to create/drop the comments */
+       CreateComments(oid, classoid, 0, comment);
+}
+
+/*
+ * CommentOpClass --
+ *
+ * This routine is used to allow a user to provide comments on an
+ * operator class. The operator class for commenting is determined by both
+ * its name and its argument list which defines the index method
+ * the operator class is used for. The argument list is expected to contain
+ * a single name (represented as a string Value node).
+ */
+static void
+CommentOpClass(List *qualname, List *arguments, char *comment)
+{
+       char       *amname;
+       char       *schemaname;
+       char       *opcname;
+       Oid                     amID;
+       Oid                     opcID;
+       Oid                     classoid;
+       HeapTuple       tuple;
+
+       Assert(length(arguments) == 1);
+       amname = strVal(lfirst(arguments));
+
+       /*
+        * Get the access method's OID.
+        */
+       amID = GetSysCacheOid(AMNAME,
+                                                 CStringGetDatum(amname),
+                                                 0, 0, 0);
+       if (!OidIsValid(amID))
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                errmsg("access method \"%s\" does not exist",
+                                               amname)));
+
+       /*
+        * Look up the opclass.
+        */
+
+       /* deconstruct the name list */
+       DeconstructQualifiedName(qualname, &schemaname, &opcname);
+
+       if (schemaname)
+       {
+               /* Look in specific schema only */
+               Oid                     namespaceId;
+
+               namespaceId = LookupExplicitNamespace(schemaname);
+               tuple = SearchSysCache(CLAAMNAMENSP,
+                                                          ObjectIdGetDatum(amID),
+                                                          PointerGetDatum(opcname),
+                                                          ObjectIdGetDatum(namespaceId),
+                                                          0);
+       }
+       else
+       {
+               /* Unqualified opclass name, so search the search path */
+               opcID = OpclassnameGetOpcid(amID, opcname);
+               if (!OidIsValid(opcID))
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                        errmsg("operator class \"%s\" does not exist for access method \"%s\"",
+                                                       opcname, amname)));
+               tuple = SearchSysCache(CLAOID,
+                                                          ObjectIdGetDatum(opcID),
+                                                          0, 0, 0);
+       }
+
+       if (!HeapTupleIsValid(tuple))
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                errmsg("operator class \"%s\" does not exist for access method \"%s\"",
+                                       NameListToString(qualname), amname)));
+
+       opcID = HeapTupleGetOid(tuple);
+
+       /* Permission check: must own opclass */
+       if (!pg_opclass_ownercheck(opcID, GetUserId()))
+               aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
+                                          NameListToString(qualname));
+
+       ReleaseSysCache(tuple);
+
+       /* pg_opclass doesn't have a hard-coded OID, so must look it up */
+       classoid = get_system_catalog_relid(OperatorClassRelationName);
+
+       /* Call CreateComments() to create/drop the comments */
+       CreateComments(opcID, classoid, 0, comment);
+}
+
+/*
+ * CommentLargeObject --
+ *
+ * This routine is used to add/drop any user-comments a user might
+ * have regarding a LARGE OBJECT. The large object is specified by OID
+ * and, if found, and the user has appropriate permissions, a
+ * comment will be added/dropped using the CreateComments() routine.
+ * The large object's OID and the comment are the parameters to this routine.
+ */
+static void
+CommentLargeObject(List *qualname, char *comment)
+{
+       Oid                     loid;
+       Oid                     classoid;
+       Node       *node; 
+
+       Assert(length(qualname) == 1);
+       node = (Node *) lfirst(qualname);
+
+       switch (nodeTag(node))
+       {
+               case T_Integer:
+                       loid = intVal(node);
+                       break;
+               case T_Float:
+                       /*
+                        * Values too large for int4 will be represented as Float
+                        * constants by the lexer.  Accept these if they are valid
+                        * OID strings.
+                        */
+                       loid = DatumGetObjectId(DirectFunctionCall1(oidin,
+                                                                               CStringGetDatum(strVal(node))));
+                       break;
+               default:
+                       elog(ERROR, "unrecognized node type: %d",
+                                (int) nodeTag(node));
+                       /* keep compiler quiet */
+                       loid = InvalidOid; 
+       }
+
+       /* check that the large object exists */
+       if (!LargeObjectExists(loid))
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                errmsg("large object %u does not exist", loid)));
+
+       /* pg_largeobject doesn't have a hard-coded OID, so must look it up */
+       classoid = get_system_catalog_relid(LargeObjectRelationName);
+
+       /* Call CreateComments() to create/drop the comments */
+       CreateComments(loid, classoid, 0, comment);     
+}
+
+/*
+ * CommentCast --
+ *
+ * This routine is used to add/drop any user-comments a user might
+ * have regarding a CAST. The cast is specified by source and destination types
+ * and, if found, and the user has appropriate permissions, a
+ * comment will be added/dropped using the CreateComments() routine.
+ * The cast's source type is passed as the "name", the destination type
+ * as the "arguments".
+ */
+static void
+CommentCast(List *qualname, List *arguments, char *comment)
+{
+       TypeName   *sourcetype;
+       TypeName   *targettype;
+       Oid                     sourcetypeid;
+       Oid                     targettypeid;
+       HeapTuple       tuple;
+       Oid                     castOid;
+       Oid                     classoid;
+
+       Assert(length(qualname) == 1);
+       sourcetype = (TypeName *) lfirst(qualname);
+       Assert(IsA(sourcetype, TypeName));
+       Assert(length(arguments) == 1);
+       targettype = (TypeName *) lfirst(arguments);
+       Assert(IsA(targettype, TypeName));
+       
+       sourcetypeid = typenameTypeId(sourcetype);
+       if (!OidIsValid(sourcetypeid))
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                errmsg("source data type %s does not exist",
+                                               TypeNameToString(sourcetype))));
+
+       targettypeid = typenameTypeId(targettype);
+       if (!OidIsValid(targettypeid))
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                errmsg("target data type %s does not exist",
+                                               TypeNameToString(targettype))));
+
+       tuple = SearchSysCache(CASTSOURCETARGET,
+                                                  ObjectIdGetDatum(sourcetypeid),
+                                                  ObjectIdGetDatum(targettypeid),
+                                                  0, 0);
+       if (!HeapTupleIsValid(tuple))
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                errmsg("cast from type %s to type %s does not exist",
+                                               TypeNameToString(sourcetype),
+                                               TypeNameToString(targettype))));
+
+       /* Get the OID of the cast */
+       castOid = HeapTupleGetOid(tuple);
+       
+       /* Permission check */
+       if (!pg_type_ownercheck(sourcetypeid, GetUserId())
+               && !pg_type_ownercheck(targettypeid, GetUserId()))
+               ereport(ERROR,
+                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                                errmsg("must be owner of type %s or type %s",
+                                               TypeNameToString(sourcetype),
+                                               TypeNameToString(targettype))));
+
+       ReleaseSysCache(tuple);
+
+       /* pg_cast doesn't have a hard-coded OID, so must look it up */
+       classoid = get_system_catalog_relid(CastRelationName);
+
+       /* Call CreateComments() to create/drop the comments */
+       CreateComments(castOid, classoid, 0, comment);  
+}
index 7e3c7410a10462aa1841ab0a0d697bddb2dbb6f5..417220df9d43d3e2f44ed3e1ae42d6d0e343c563 100644 (file)
@@ -2,14 +2,15 @@
  *
  * functioncmds.c
  *
- *       Routines for CREATE and DROP FUNCTION commands
+ *       Routines for CREATE and DROP FUNCTION commands and CREATE and DROP
+ *        CAST commands.
  *
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.40 2003/11/12 21:15:50 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.41 2003/11/21 22:32:48 tgl Exp $
  *
  * DESCRIPTION
  *       These routines take the parse tree and pick out the
index 5f0b0f4e5da4034a0d5e7c145db6d567dd84e7fb..337eef4480c8d52d4bde79bb2babf93b7ef11a74 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.437 2003/11/06 22:08:14 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.438 2003/11/21 22:32:49 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -363,7 +363,7 @@ static void doNegateFloat(Value *v);
 
        KEY
 
-       LANCOMPILER LANGUAGE LAST_P LEADING LEFT LEVEL LIKE LIMIT
+       LANCOMPILER LANGUAGE LARGE_P LAST_P LEADING LEFT LEVEL LIKE LIMIT
        LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
        LOCK_P
 
@@ -373,7 +373,7 @@ static void doNegateFloat(Value *v);
        NOCREATEUSER NONE NOT NOTHING NOTIFY NOTNULL NULL_P
        NULLIF NUMERIC
 
-       OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OR
+       OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OR
        ORDER OUT_P OUTER_P OVERLAPS OVERLAY OWNER
 
        PARTIAL PASSWORD PATH_P PENDANT PLACING POSITION
@@ -2519,11 +2519,15 @@ TruncateStmt:
  *     The COMMENT ON statement can take different forms based upon the type of
  *     the object associated with the comment. The form of the statement is:
  *
- *     COMMENT ON [ [ DATABASE | DOMAIN | INDEX | SEQUENCE | TABLE | TYPE | VIEW ]
- *                              <objname> | AGGREGATE <aggname> (<aggtype>) | FUNCTION
- *              <funcname> (arg1, arg2, ...) | OPERATOR <op>
- *              (leftoperand_typ rightoperand_typ) | TRIGGER <triggername> ON
- *              <relname> | RULE <rulename> ON <relname> ] IS 'text'
+ *     COMMENT ON [ [ DATABASE | DOMAIN | INDEX | SEQUENCE | TABLE | TYPE | VIEW |
+ *                                CONVERSION | LANGUAGE | OPERATOR CLASS | LARGE OBJECT |
+ *                                CAST ] <objname> |
+ *                              AGGREGATE <aggname> (<aggtype>) |
+ *                              FUNCTION <funcname> (arg1, arg2, ...) |
+ *                              OPERATOR <op> (leftoperand_typ, rightoperand_typ) |
+ *                              TRIGGER <triggername> ON <relname> |
+ *                              RULE <rulename> ON <relname> ]
+ *                        IS 'text'
  *
  *****************************************************************************/
 
@@ -2603,6 +2607,42 @@ CommentStmt:
                                        n->comment = $8;
                                        $$ = (Node *) n;
                                }
+                       | COMMENT ON OPERATOR CLASS any_name USING access_method IS comment_text
+                               {
+                                       CommentStmt *n = makeNode(CommentStmt);
+                                       n->objtype = OBJECT_OPCLASS;
+                                       n->objname = $5;
+                                       n->objargs = makeList1(makeString($7));
+                                       n->comment = $9;
+                                       $$ = (Node *) n;
+                               }
+                       | COMMENT ON LARGE_P OBJECT_P NumericOnly IS comment_text
+                               {
+                                       CommentStmt *n = makeNode(CommentStmt);
+                                       n->objtype = OBJECT_LARGEOBJECT;
+                                       n->objname = makeList1($5);
+                                       n->objargs = NIL;
+                                       n->comment = $7;
+                                       $$ = (Node *) n;
+                               }
+                       | COMMENT ON CAST '(' Typename AS Typename ')' IS comment_text
+                               {
+                                       CommentStmt *n = makeNode(CommentStmt);
+                                       n->objtype = OBJECT_CAST;
+                                       n->objname = makeList1($5);
+                                       n->objargs = makeList1($7);
+                                       n->comment = $10;
+                                       $$ = (Node *) n;
+                               }
+                       | COMMENT ON opt_procedural LANGUAGE any_name IS comment_text
+                               {
+                                       CommentStmt *n = makeNode(CommentStmt);
+                                       n->objtype = OBJECT_LANGUAGE;
+                                       n->objname = $5;
+                                       n->objargs = NIL;
+                                       n->comment = $7;
+                                       $$ = (Node *) n;
+                               }                               
                ;
 
 comment_type:
@@ -2615,6 +2655,7 @@ comment_type:
                        | DOMAIN_P                                                      { $$ = OBJECT_TYPE; }
                        | TYPE_P                                                        { $$ = OBJECT_TYPE; }
                        | VIEW                                                          { $$ = OBJECT_VIEW; }
+                       | CONVERSION_P                                          { $$ = OBJECT_CONVERSION; }
                ;
 
 comment_text:
@@ -7365,6 +7406,7 @@ unreserved_keyword:
                        | KEY
                        | LANCOMPILER
                        | LANGUAGE
+                       | LARGE_P
                        | LAST_P
                        | LEVEL
                        | LISTEN
@@ -7387,6 +7429,7 @@ unreserved_keyword:
                        | NOCREATEUSER
                        | NOTHING
                        | NOTIFY
+                       | OBJECT_P
                        | OF
                        | OIDS
                        | OPERATOR
index 6d42a13ef87046153df0eb9acd4ec26fc52a904b..c4e5058078075d9ff2f74e3e0c156445b40d9af3 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.142 2003/11/06 22:08:15 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.143 2003/11/21 22:32:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -177,6 +177,7 @@ static const ScanKeyword ScanKeywords[] = {
        {"key", KEY},
        {"lancompiler", LANCOMPILER},
        {"language", LANGUAGE},
+       {"large", LARGE_P},
        {"last", LAST_P},
        {"leading", LEADING},
        {"left", LEFT},
@@ -214,6 +215,7 @@ static const ScanKeyword ScanKeywords[] = {
        {"null", NULL_P},
        {"nullif", NULLIF},
        {"numeric", NUMERIC},
+       {"object", OBJECT_P},
        {"of", OF},
        {"off", OFF},
        {"offset", OFFSET},
index f777fb33b95a776a957a1d6bc20f95672975e17b..65a4602806dfffb9fb9508a3c83ece6fa0175d02 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.100 2003/11/12 21:15:54 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.101 2003/11/21 22:32:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_largeobject.h"
 #include "catalog/pg_type.h"
+#include "commands/comment.h"
 #include "libpq/libpq-fs.h"
 #include "miscadmin.h"
 #include "storage/large_object.h"
 #include "storage/smgr.h"
-#include "utils/fmgroids.h"
 #include "utils/builtins.h"
+#include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
 
 
 static int32
@@ -174,8 +176,16 @@ inv_close(LargeObjectDesc *obj_desc)
 int
 inv_drop(Oid lobjId)
 {
+       Oid classoid;
+
        LargeObjectDrop(lobjId);
 
+       /* pg_largeobject doesn't have a hard-coded OID, so must look it up */
+       classoid = get_system_catalog_relid(LargeObjectRelationName);
+
+       /* Delete any comments on the large object */
+       DeleteComments(lobjId, classoid, 0);
+
        /*
         * Advance command counter so that tuple removal will be seen by later
         * large-object operations in this transaction.
index 98b43f5cceb72fa37847f7f134da80643c3802b8..fb4979b453ecaaaf6f1c8399242776f312cf7a99 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.75 2003/08/04 02:40:09 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.76 2003/11/21 22:32:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -61,6 +61,7 @@ dumpSchema(Archive *fout,
        int                     numAggregates;
        int                     numOperators;
        int                     numOpclasses;
+       int                     numConversions;
        NamespaceInfo *nsinfo;
        TypeInfo   *tinfo;
        FuncInfo   *finfo;
@@ -69,6 +70,7 @@ dumpSchema(Archive *fout,
        InhInfo    *inhinfo;
        OprInfo    *oprinfo;
        OpclassInfo *opcinfo;
+       ConvInfo *convinfo;
 
        if (g_verbose)
                write_msg(NULL, "reading schemas\n");
@@ -94,6 +96,10 @@ dumpSchema(Archive *fout,
                write_msg(NULL, "reading user-defined operator classes\n");
        opcinfo = getOpclasses(&numOpclasses);
 
+       if (g_verbose)
+               write_msg(NULL, "reading user-defined conversions\n");
+       convinfo = getConversions(&numConversions);
+
        if (g_verbose)
                write_msg(NULL, "reading user-defined tables\n");
        tblinfo = getTables(&numTables);
@@ -190,6 +196,13 @@ dumpSchema(Archive *fout,
                dumpCasts(fout, finfo, numFuncs, tinfo, numTypes);
        }
 
+       if (!dataOnly)
+       {
+               if (g_verbose)
+                       write_msg(NULL, "dumping out user-defined conversions\n");
+               dumpConversions(fout, convinfo, numConversions);
+       }
+
        *numTablesPtr = numTables;
        return tblinfo;
 }
index 134e9522a379c3fc73de282bd30af17452c24d3c..f74cd30b5a01bb9dd6bc885c7de67eee3c82e476 100644 (file)
@@ -12,7 +12,7 @@
  *     by PostgreSQL
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.355 2003/10/28 21:05:29 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.356 2003/11/21 22:32:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -105,6 +105,7 @@ static const char *convertRegProcReference(const char *proc);
 static const char *convertOperatorReference(const char *opr,
                                                 OprInfo *g_oprinfo, int numOperators);
 static void dumpOneOpclass(Archive *fout, OpclassInfo *opcinfo);
+static void dumpOneConversion(Archive *fout, ConvInfo *convinfo);
 static void dumpOneAgg(Archive *fout, AggInfo *agginfo);
 static Oid     findLastBuiltinOid_V71(const char *);
 static Oid     findLastBuiltinOid_V70(void);
@@ -1689,6 +1690,79 @@ getOperators(int *numOprs)
        return oprinfo;
 }
 
+/*
+ * getConversions:
+ *       read all conversions in the system catalogs and return them in the
+ * ConvInfo* structure
+ *
+ *     numConversions is set to the number of conversions read in
+ */
+ConvInfo *
+getConversions(int *numConversions)
+{
+       PGresult   *res;
+       int                     ntups;
+       int                     i;
+       PQExpBuffer query = createPQExpBuffer();
+       ConvInfo *convinfo;
+       int                     i_oid;
+       int                     i_conname;
+       int                     i_connamespace;
+       int                     i_usename;
+
+       /* Conversions didn't exist pre-7.3 */
+       if (g_fout->remoteVersion < 70300) {
+               *numConversions = 0;
+               return NULL;
+       }
+
+       /*
+        * find all conversions, including builtin conversions; we filter out
+        * system-defined conversions at dump-out time.
+        */
+
+       /* Make sure we are in proper schema */
+       selectSourceSchema("pg_catalog");
+
+       appendPQExpBuffer(query, "SELECT pg_conversion.oid, conname, "
+                                         "connamespace, "
+                                         "(select usename from pg_user where conowner = usesysid) as usename "
+                                         "from pg_conversion");
+
+       res = PQexec(g_conn, query->data);
+       if (!res ||
+               PQresultStatus(res) != PGRES_TUPLES_OK)
+       {
+               write_msg(NULL, "query to obtain list of conversions failed: %s", PQerrorMessage(g_conn));
+               exit_nicely();
+       }
+
+       ntups = PQntuples(res);
+       *numConversions = ntups;
+
+       convinfo = (ConvInfo *) malloc(ntups * sizeof(ConvInfo));
+
+       i_oid = PQfnumber(res, "oid");
+       i_conname = PQfnumber(res, "conname");
+       i_connamespace = PQfnumber(res, "connamespace");
+       i_usename = PQfnumber(res, "usename");
+
+       for (i = 0; i < ntups; i++)
+       {
+               convinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
+               convinfo[i].conname = strdup(PQgetvalue(res, i, i_conname));
+               convinfo[i].connamespace = findNamespace(PQgetvalue(res, i, i_connamespace),
+                                                                                               convinfo[i].oid);
+               convinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
+       }
+
+       PQclear(res);
+
+       destroyPQExpBuffer(query);
+
+       return convinfo;
+}
+
 /*
  * getOpclasses:
  *       read all opclasses in the system catalogs and return them in the
@@ -3414,6 +3488,7 @@ dumpOneCompositeType(Archive *fout, TypeInfo *tinfo)
                                 tinfo->usename, "TYPE", NULL,
                                 q->data, delq->data, NULL, NULL, NULL);
 
+
        /* Dump Type Comments */
        resetPQExpBuffer(q);
 
@@ -3614,6 +3689,14 @@ dumpProcLangs(Archive *fout, FuncInfo finfo[], int numFuncs)
                                        NULL, lanacl, lanoid);
                        free(tmp);
                }
+
+               /* Dump Proc Lang Comments */
+               resetPQExpBuffer(defqry);
+
+               appendPQExpBuffer(defqry, "LANGUAGE %s", fmtId(lanname));
+               dumpComment(fout, defqry->data,
+                                       NULL, "",
+                                       lanoid, "pg_language", 0, NULL);
        }
 
        PQclear(res);
@@ -4019,6 +4102,16 @@ dumpCasts(Archive *fout,
                                         "CAST", deps,
                                         defqry->data, delqry->data,
                                         NULL, NULL, NULL);
+
+               /* Dump Cast Comments */
+               resetPQExpBuffer(defqry);
+               appendPQExpBuffer(defqry, "CAST (%s AS %s)",
+                                                 getFormattedTypeName(castsource, zeroAsNone),
+                                                 getFormattedTypeName(casttarget, zeroAsNone));
+               dumpComment(fout, defqry->data,
+                                       NULL, "",
+                                       castoid, "pg_cast", 0, NULL);
+
        }
 
        PQclear(res);
@@ -4490,7 +4583,8 @@ dumpOneOpclass(Archive *fout, OpclassInfo *opcinfo)
        opcintype = PQgetvalue(res, 0, i_opcintype);
        opckeytype = PQgetvalue(res, 0, i_opckeytype);
        opcdefault = PQgetvalue(res, 0, i_opcdefault);
-       amname = PQgetvalue(res, 0, i_amname);
+       /* amname will still be needed after we PQclear res */
+       amname = strdup(PQgetvalue(res, 0, i_amname));
 
        /*
         * DROP must be fully qualified in case same name appears in
@@ -4617,11 +4711,145 @@ dumpOneOpclass(Archive *fout, OpclassInfo *opcinfo)
                                 q->data, delq->data,
                                 NULL, NULL, NULL);
 
+       /* Dump Operator Class Comments */
+       resetPQExpBuffer(q);
+       appendPQExpBuffer(q, "OPERATOR CLASS %s",
+                                         fmtId(opcinfo->opcname));
+       appendPQExpBuffer(q, " USING %s",
+                                         fmtId(amname));
+       dumpComment(fout, q->data,
+                               NULL, opcinfo->usename,
+                               opcinfo->oid, "pg_opclass", 0, NULL);
+
+       free(amname);
        destroyPQExpBuffer(query);
        destroyPQExpBuffer(q);
        destroyPQExpBuffer(delq);
 }
 
+/*
+ * dumpConversions
+ *       writes out to fout the queries to create all the user-defined conversions
+ */
+void
+dumpConversions(Archive *fout, ConvInfo convinfo[], int numConvs)
+{
+       int                     i;
+
+       for (i = 0; i < numConvs; i++)
+       {
+               /* Dump only conversions in dumpable namespaces */
+               if (!convinfo[i].connamespace->dump)
+                       continue;
+
+               dumpOneConversion(fout, &convinfo[i]);
+       }
+}
+
+/*
+ * dumpOneConversion
+ *       write out a single conversion definition
+ */
+static void
+dumpOneConversion(Archive *fout, ConvInfo *convinfo)
+{
+       PQExpBuffer query = createPQExpBuffer();
+       PQExpBuffer q = createPQExpBuffer();
+       PQExpBuffer delq = createPQExpBuffer();
+       PQExpBuffer details = createPQExpBuffer();
+       PGresult   *res;
+       int                     ntups;
+       int                     i_conname;
+       int                     i_conforencoding;
+       int                     i_contoencoding;
+       int                     i_conproc;
+       int                     i_condefault;
+       const char *conname;
+       const char *conforencoding;
+       const char *contoencoding;
+       const char *conproc;
+       bool            condefault;
+
+       /* Make sure we are in proper schema */
+       selectSourceSchema(convinfo->connamespace->nspname);
+
+       /* Get conversion-specific details */
+       appendPQExpBuffer(query, "SELECT conname,
+                                       pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding,
+                                       pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding,
+                                       conproc, condefault
+                               FROM pg_catalog.pg_conversion c
+                               WHERE c.oid = '%s'::pg_catalog.oid",
+                                       convinfo->oid);
+
+       res = PQexec(g_conn, query->data);
+       if (!res ||
+               PQresultStatus(res) != PGRES_TUPLES_OK)
+       {
+               write_msg(NULL, "query to obtain conversion failed: %s",
+                                 PQerrorMessage(g_conn));
+               exit_nicely();
+       }
+
+       /* Expecting a single result only */
+       ntups = PQntuples(res);
+       if (ntups != 1)
+       {
+               write_msg(NULL, "Got %d rows instead of one from: %s",
+                                 ntups, query->data);
+               exit_nicely();
+       }
+
+       i_conname = PQfnumber(res, "conname");
+       i_conforencoding = PQfnumber(res, "conforencoding");
+       i_contoencoding = PQfnumber(res, "contoencoding");
+       i_conproc = PQfnumber(res, "conproc");
+       i_condefault = PQfnumber(res, "condefault");
+
+       conname = PQgetvalue(res, 0, i_conname);
+       conforencoding = PQgetvalue(res, 0, i_conforencoding);
+       contoencoding = PQgetvalue(res, 0, i_contoencoding);
+       conproc = PQgetvalue(res, 0, i_conproc);
+       condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
+
+       /*
+        * DROP must be fully qualified in case same name appears in
+        * pg_catalog
+        */
+       appendPQExpBuffer(delq, "DROP CONVERSION %s",
+                                         fmtId(convinfo->connamespace->nspname));
+       appendPQExpBuffer(delq, ".%s;\n",
+                                         fmtId(convinfo->conname));
+
+       appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
+                                       (condefault) ? "DEFAULT " : "", 
+                                       fmtId(convinfo->conname));
+       appendStringLiteral(q, conforencoding, true);
+       appendPQExpBuffer(q, " TO ");
+       appendStringLiteral(q, contoencoding, true);
+       /* regproc is automatically quoted in 7.3 and above */
+       appendPQExpBuffer(q, " FROM %s;\n", conproc);
+       
+       ArchiveEntry(fout, convinfo->oid, convinfo->conname,
+                                convinfo->connamespace->nspname, convinfo->usename,
+                                "CONVERSION", NULL,
+                                q->data, delq->data,
+                                NULL, NULL, NULL);
+
+       /* Dump Conversion Comments */
+       resetPQExpBuffer(q);
+       appendPQExpBuffer(q, "CONVERSION %s", fmtId(convinfo->conname));
+       dumpComment(fout, q->data,
+                               convinfo->connamespace->nspname, convinfo->usename,
+                               convinfo->oid, "pg_conversion", 0, NULL);
+
+       PQclear(res);
+
+       destroyPQExpBuffer(query);
+       destroyPQExpBuffer(q);
+       destroyPQExpBuffer(delq);
+       destroyPQExpBuffer(details);
+}
 
 /*
  * dumpAggs
@@ -6573,8 +6801,10 @@ dumpRules(Archive *fout, TableInfo *tblinfo, int numTables)
                        /* Dump rule comments */
 
                        resetPQExpBuffer(query);
-                       appendPQExpBuffer(query, "RULE %s", fmtId(PQgetvalue(res, i, i_rulename)));
-                       appendPQExpBuffer(query, " ON %s", fmtId(tbinfo->relname));
+                       appendPQExpBuffer(query, "RULE %s",
+                                                         fmtId(PQgetvalue(res, i, i_rulename)));
+                       appendPQExpBuffer(query, " ON %s",
+                                                         fmtId(tbinfo->relname));
                        dumpComment(fout, query->data,
                                                tbinfo->relnamespace->nspname,
                                                tbinfo->usename,
index a68a99ade07a86e0ffd1e2ee1aa67389b5c78cbe..1e6e2fbe112360964c1e6ddf359b4f8379664a6a 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_dump.h,v 1.104 2003/08/08 04:52:21 momjian Exp $
+ * $Id: pg_dump.h,v 1.105 2003/11/21 22:32:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -95,6 +95,14 @@ typedef struct _opclassInfo
        char       *usename;
 } OpclassInfo;
 
+typedef struct _convInfo
+{
+       char       *oid;
+       char       *conname;
+       NamespaceInfo *connamespace;    /* link to containing namespace */
+       char       *usename;
+} ConvInfo;
+
 typedef struct _tableInfo
 {
        /*
@@ -213,6 +221,7 @@ extern FuncInfo *getFuncs(int *numFuncs);
 extern AggInfo *getAggregates(int *numAggregates);
 extern OprInfo *getOperators(int *numOperators);
 extern OpclassInfo *getOpclasses(int *numOpclasses);
+extern ConvInfo *getConversions(int *numConversions);
 extern TableInfo *getTables(int *numTables);
 extern InhInfo *getInherits(int *numInherits);
 
@@ -230,6 +239,8 @@ extern void dumpAggs(Archive *fout, AggInfo agginfo[], int numAggregates);
 extern void dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators);
 extern void dumpOpclasses(Archive *fout,
                          OpclassInfo *opcinfo, int numOpclasses);
+extern void dumpConversions(Archive *fout,
+                         ConvInfo *coninfo, int numConversions);
 extern void dumpTables(Archive *fout, TableInfo tblinfo[], int numTables,
                   const bool aclsSkip,
                   const bool schemaOnly, const bool dataOnly);
index 53235b423ae1387998ab1dbca6d0f8254939700f..16cb1b947a73b169518ae52014aaeeb374733080 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2003, PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/large_obj.c,v 1.29 2003/08/04 23:59:40 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/large_obj.c,v 1.30 2003/11/21 22:32:49 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "large_obj.h"
@@ -165,9 +165,7 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
        }
 
        /* insert description if given */
-       /* XXX don't try to hack pg_description if not superuser */
-       /* XXX ought to replace this with some kind of COMMENT command */
-       if (comment_arg && is_superuser())
+       if (comment_arg)
        {
                char       *cmdbuf;
                char       *bufptr;
@@ -177,9 +175,7 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
                if (!cmdbuf)
                        return fail_lo_xact("\\lo_import", own_transaction);
                sprintf(cmdbuf,
-                               "INSERT INTO pg_catalog.pg_description VALUES ('%u', "
-                               "'pg_catalog.pg_largeobject'::regclass, "
-                               "0, '",
+                               "COMMENT ON LARGE OBJECT %u IS '",
                                loid);
                bufptr = cmdbuf + strlen(cmdbuf);
                for (i = 0; i < slen; i++)
@@ -188,7 +184,7 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
                                *bufptr++ = '\\';
                        *bufptr++ = comment_arg[i];
                }
-               strcpy(bufptr, "')");
+               strcpy(bufptr, "'");
 
                if (!(res = PSQLexec(cmdbuf, false)))
                {
@@ -219,10 +215,8 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
 bool
 do_lo_unlink(const char *loid_arg)
 {
-       PGresult   *res;
        int                     status;
        Oid                     loid = atooid(loid_arg);
-       char            buf[256];
        bool            own_transaction;
 
        if (!start_lo_xact("\\lo_unlink", &own_transaction))
@@ -235,20 +229,6 @@ do_lo_unlink(const char *loid_arg)
                return fail_lo_xact("\\lo_unlink", own_transaction);
        }
 
-       /* remove the comment as well */
-       /* XXX don't try to hack pg_description if not superuser */
-       /* XXX ought to replace this with some kind of COMMENT command */
-       if (is_superuser())
-       {
-               snprintf(buf, sizeof(buf),
-                        "DELETE FROM pg_catalog.pg_description WHERE objoid = '%u' "
-                                "AND classoid = 'pg_catalog.pg_largeobject'::regclass",
-                                loid);
-               if (!(res = PSQLexec(buf, false)))
-                       return fail_lo_xact("\\lo_unlink", own_transaction);
-               PQclear(res);
-       }
-
        if (!finish_lo_xact("\\lo_unlink", own_transaction))
                return false;
 
index 2aec3b7b7ac34b5c2c2cbeae61686845cd614f10..e0fada5dbef36b8d27eee346f7305ebec53f90e7 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.248 2003/09/17 04:25:29 ishii Exp $
+ * $Id: parsenodes.h,v 1.249 2003/11/21 22:32:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -686,6 +686,7 @@ typedef enum ObjectType
        OBJECT_GROUP,
        OBJECT_INDEX,
        OBJECT_LANGUAGE,
+       OBJECT_LARGEOBJECT,
        OBJECT_OPCLASS,
        OBJECT_OPERATOR,
        OBJECT_RULE,
index 8a4c235cea45c51c8a5d8082bab871eefdc011da..53fb98df9341221a1b2df4855a2d107952c9b010 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: acl.h,v 1.63 2003/10/29 22:20:54 tgl Exp $
+ * $Id: acl.h,v 1.64 2003/11/21 22:32:49 tgl Exp $
  *
  * NOTES
  *       An ACL array is simply an array of AclItems, representing the union
@@ -245,5 +245,6 @@ extern bool pg_proc_ownercheck(Oid proc_oid, AclId userid);
 extern bool pg_namespace_ownercheck(Oid nsp_oid, AclId userid);
 extern bool pg_opclass_ownercheck(Oid opc_oid, AclId userid);
 extern bool pg_database_ownercheck(Oid db_oid, AclId userid);
+extern bool pg_conversion_ownercheck(Oid conv_oid, AclId userid);
 
 #endif   /* ACL_H */
index 61a3965fe59e177d851b14389579cb71188dc75f..cc50cb86daea95f312708e9bb1dd462c20ba2187 100644 (file)
@@ -3,6 +3,10 @@
 -- add attribute
 --
 CREATE TABLE tmp (initial int4);
+COMMENT ON TABLE tmp_wrong IS 'table comment';
+ERROR:  relation "tmp_wrong" does not exist
+COMMENT ON TABLE tmp IS 'table comment';
+COMMENT ON TABLE tmp IS NULL;
 ALTER TABLE tmp ADD COLUMN a int4;
 ALTER TABLE tmp ADD COLUMN b name;
 ALTER TABLE tmp ADD COLUMN c text;
index 289bd0a27f10bf15ed8ffa9108b536717396652a..c0e85b85a1d8454c4f2bb3154365ae32195ee11b 100644 (file)
@@ -18,6 +18,11 @@ CREATE DEFAULT CONVERSION public.mydef FOR 'LATIN1' TO 'UNICODE' FROM iso8859_1_
 --
 CREATE DEFAULT CONVERSION public.mydef2 FOR 'LATIN1' TO 'UNICODE' FROM iso8859_1_to_utf8;
 ERROR:  default conversion for LATIN1 to UNICODE already exists
+-- test comments
+COMMENT ON CONVERSION myconv_bad IS 'foo';
+ERROR:  conversion "myconv_bad" does not exist
+COMMENT ON CONVERSION myconv IS 'bar';
+COMMENT ON CONVERSION myconv IS NULL;
 --
 -- drop user defined conversion
 --
index ef83c886a11454511cff793b2458e83fde3263f3..b0fec460cbb39d556668a497d34670bf9390440a 100644 (file)
@@ -7,6 +7,11 @@ CREATE AGGREGATE newavg (
    finalfunc = numeric_avg,
    initcond1 = '{0,0,0}'
 );
+-- test comments
+COMMENT ON AGGREGATE newavg_wrong (int4) IS 'an agg comment';
+ERROR:  aggregate newavg_wrong(integer) does not exist
+COMMENT ON AGGREGATE newavg (int4) IS 'an agg comment';
+COMMENT ON AGGREGATE newavg (int4) IS NULL;
 -- without finalfunc; test obsolete spellings 'sfunc1' etc
 CREATE AGGREGATE newsum (
    sfunc1 = int4pl, basetype = int4, stype1 = int4, 
@@ -17,3 +22,7 @@ CREATE AGGREGATE newcnt (
    sfunc = int4inc, basetype = 'any', stype = int4,
    initcond = '0'
 );
+COMMENT ON AGGREGATE nosuchagg (*) IS 'should fail';
+ERROR:  aggregate nosuchagg(*) does not exist
+COMMENT ON AGGREGATE newcnt (*) IS 'an any agg comment';
+COMMENT ON AGGREGATE newcnt (*) IS NULL;
index 46d2657d015fc796dbf595c4cabc3990bceaedbe..6643070e71700d75a633caef11b9d3c4f8e14a44 100644 (file)
@@ -18,6 +18,11 @@ CREATE INDEX tenk2_hundred ON tenk2 USING btree(hundred int4_ops);
 CREATE INDEX rix ON road USING btree (name text_ops);
 CREATE INDEX iix ON ihighway USING btree (name text_ops);
 CREATE INDEX six ON shighway USING btree (name text_ops);
+-- test comments
+COMMENT ON INDEX six_wrong IS 'bad index';
+ERROR:  relation "six_wrong" does not exist
+COMMENT ON INDEX six IS 'good index';
+COMMENT ON INDEX six IS NULL;
 --
 -- BTREE ascending/descending cases
 --
index 2338b7c7108342b10e3c22edcc4b768d3b87740e..7685dbe802c74e7134bca5ac00aabe2aacce37ba 100644 (file)
@@ -26,3 +26,8 @@ CREATE OPERATOR #%# (
    leftarg = int4,             -- right unary 
    procedure = int4fac 
 );
+-- Test comments
+COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary';
+ERROR:  operator does not exist: integer ######
+COMMENT ON OPERATOR #%# (int4, NONE) IS 'right unary';
+COMMENT ON OPERATOR #%# (int4, NONE) IS NULL;
index 210da92cf2df9b7f3663cc7e14812366d04fa25f..101382e7392deacbe88ebf8cd78656f424a0f355 100644 (file)
@@ -71,6 +71,11 @@ SELECT * FROM get_default_test();
  zippo | 42
 (1 row)
 
+-- Test comments
+COMMENT ON TYPE bad IS 'bad comment';
+ERROR:  type "bad" does not exist
+COMMENT ON TYPE default_test_row IS 'good comment';
+COMMENT ON TYPE default_test_row IS NULL;
 DROP TYPE default_test_row CASCADE;
 NOTICE:  drop cascades to function get_default_test()
 DROP TABLE default_test;
index 630855ed37cbf25bbb33caefda0f0660bb243a0d..04e62f708462650a91a829aeffecc55f81334d71 100644 (file)
@@ -15,6 +15,11 @@ CREATE VIEW iexit AS
 CREATE VIEW toyemp AS
    SELECT name, age, location, 12*salary AS annualsal
    FROM emp;
+-- Test comments
+COMMENT ON VIEW noview IS 'no view';
+ERROR:  relation "noview" does not exist
+COMMENT ON VIEW toyemp IS 'is a view';
+COMMENT ON VIEW toyemp IS NULL;
 --
 -- CREATE OR REPLACE VIEW
 --
index bfb90979f68483ae55fcd4ff5cf6507ebddc1ca0..57a4ae16471adae7f5071106efd6cf77563db599 100644 (file)
@@ -64,6 +64,11 @@ CREATE TABLE PKTABLE ( ptest1 int, ptest2 int, ptest3 text, PRIMARY KEY(ptest1,
 NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "pktable_pkey" for table "pktable"
 CREATE TABLE FKTABLE ( ftest1 int, ftest2 int, ftest3 int, CONSTRAINT constrname FOREIGN KEY(ftest1, ftest2) 
                        REFERENCES PKTABLE MATCH FULL ON DELETE SET NULL ON UPDATE SET NULL);
+-- Test comments
+COMMENT ON CONSTRAINT constrname_wrong ON FKTABLE IS 'fk constraint comment';
+ERROR:  constraint "constrname_wrong" for table "fktable" does not exist
+COMMENT ON CONSTRAINT constrname ON FKTABLE IS 'fk constraint comment';
+COMMENT ON CONSTRAINT constrname ON FKTABLE IS NULL;
 -- Insert test data into PKTABLE
 INSERT INTO PKTABLE VALUES (1, 2, 'Test1');
 INSERT INTO PKTABLE VALUES (1, 3, 'Test1-2');
index a7a380b5c6c70b247005ee675401f5740efcfada..694165e506a1530a63793e1be418a405447b542b 100644 (file)
@@ -264,6 +264,11 @@ begin
     return 0;
 end;
 ' language 'plpgsql';
+-- Test comments
+COMMENT ON FUNCTION tg_hub_adjustslots_wrong(bpchar, integer, integer) IS 'function with args';
+ERROR:  function tg_hub_adjustslots_wrong(character, integer, integer) does not exist
+COMMENT ON FUNCTION tg_hub_adjustslots(bpchar, integer, integer) IS 'function with args';
+COMMENT ON FUNCTION tg_hub_adjustslots(bpchar, integer, integer) IS NULL;
 -- ************************************************************
 -- * BEFORE INSERT or UPDATE on HSlot
 -- *   - prevent from manual manipulation
index 7ae49e8b44298ad6deb761aa9dea085caa17f2e8..ae7d0feea6343e2caa4fef4d5f39600b625c5fa5 100644 (file)
@@ -17,6 +17,11 @@ create rule rtest_v1_upd as on update to rtest_v1 do instead
        where a = old.a;
 create rule rtest_v1_del as on delete to rtest_v1 do instead
        delete from rtest_t1 where a = old.a;
+-- Test comments
+COMMENT ON RULE rtest_v1_bad ON rtest_v1 IS 'bad rule';
+ERROR:  rule "rtest_v1_bad" for relation "rtest_v1" does not exist
+COMMENT ON RULE rtest_v1_del ON rtest_v1 IS 'delete rule';
+COMMENT ON RULE rtest_v1_del ON rtest_v1 IS NULL;
 --
 -- Tables and rules for the constraint update/delete test
 --
index 49b783a805a69f6d1c179d4f5cf05b12280bae82..d09e5db1701fc65a3d235e925405c90e637fd7b0 100644 (file)
@@ -71,3 +71,8 @@ SELECT nextval('sequence_test2');
        5
 (1 row)
 
+-- Test comments
+COMMENT ON SEQUENCE asdf IS 'won''t work';
+ERROR:  relation "asdf" does not exist
+COMMENT ON SEQUENCE sequence_test2 IS 'will work';
+COMMENT ON SEQUENCE sequence_test2 IS NULL;
index 086c9f602c8109d0acbdd790bfc4ff9c622723c0..c44a81a75f872cf67b7e6f3db38e0644a85c1abd 100644 (file)
@@ -37,6 +37,11 @@ create trigger check_fkeys2_pkey_exist
        for each row 
        execute procedure 
        check_primary_key ('fkey21', 'fkey22', 'pkeys', 'pkey1', 'pkey2');
+-- Test comments
+COMMENT ON TRIGGER check_fkeys2_pkey_bad ON fkeys2 IS 'wrong';
+ERROR:  trigger "check_fkeys2_pkey_bad" for table "fkeys2" does not exist
+COMMENT ON TRIGGER check_fkeys2_pkey_exist ON fkeys2 IS 'right';
+COMMENT ON TRIGGER check_fkeys2_pkey_exist ON fkeys2 IS NULL;
 --
 -- For pkeys:
 --     ON DELETE/UPDATE (pkey1, pkey2) CASCADE:
index 9bdc8cd1eafd0079303fd872826e8df465631932..33187c8352672096fb38fe466013714502228685 100644 (file)
@@ -5,6 +5,10 @@
 
 CREATE TABLE tmp (initial int4);
 
+COMMENT ON TABLE tmp_wrong IS 'table comment';
+COMMENT ON TABLE tmp IS 'table comment';
+COMMENT ON TABLE tmp IS NULL;
+
 ALTER TABLE tmp ADD COLUMN a int4;
 
 ALTER TABLE tmp ADD COLUMN b name;
index 979a7cc0fdd26fc125bd6f996ac0c608ded58229..c84ffee95fedd34a4cb38d9b143f51cf17ca3126 100644 (file)
@@ -16,6 +16,10 @@ CREATE DEFAULT CONVERSION public.mydef FOR 'LATIN1' TO 'UNICODE' FROM iso8859_1_
 -- cannot make default conversion with same shcema/for_encoding/to_encoding
 --
 CREATE DEFAULT CONVERSION public.mydef2 FOR 'LATIN1' TO 'UNICODE' FROM iso8859_1_to_utf8;
+-- test comments
+COMMENT ON CONVERSION myconv_bad IS 'foo';
+COMMENT ON CONVERSION myconv IS 'bar';
+COMMENT ON CONVERSION myconv IS NULL;
 --
 -- drop user defined conversion
 --
index 5d42ed057e3d9a9fb7c9d3f44bae4846d2579176..4188760c87c21ece71153a8115017ca3c7be32e4 100644 (file)
@@ -9,6 +9,11 @@ CREATE AGGREGATE newavg (
    initcond1 = '{0,0,0}'
 );
 
+-- test comments
+COMMENT ON AGGREGATE newavg_wrong (int4) IS 'an agg comment';
+COMMENT ON AGGREGATE newavg (int4) IS 'an agg comment';
+COMMENT ON AGGREGATE newavg (int4) IS NULL;
+
 -- without finalfunc; test obsolete spellings 'sfunc1' etc
 CREATE AGGREGATE newsum (
    sfunc1 = int4pl, basetype = int4, stype1 = int4, 
@@ -21,3 +26,6 @@ CREATE AGGREGATE newcnt (
    initcond = '0'
 );
 
+COMMENT ON AGGREGATE nosuchagg (*) IS 'should fail';
+COMMENT ON AGGREGATE newcnt (*) IS 'an any agg comment';
+COMMENT ON AGGREGATE newcnt (*) IS NULL;
index d904bacd66bc7cbe974ee7d0e739fab09edf3481..6fa0b91e83c96b62022d34e26df72ae017813c0f 100644 (file)
@@ -32,6 +32,11 @@ CREATE INDEX iix ON ihighway USING btree (name text_ops);
 
 CREATE INDEX six ON shighway USING btree (name text_ops);
 
+-- test comments
+COMMENT ON INDEX six_wrong IS 'bad index';
+COMMENT ON INDEX six IS 'good index';
+COMMENT ON INDEX six IS NULL;
+
 --
 -- BTREE ascending/descending cases
 --
index c4251144ca36b01a1d772e0617612f7ee5591ea5..4167bf3ab825a0d472df192d35071d0883083a61 100644 (file)
@@ -32,3 +32,9 @@ CREATE OPERATOR #%# (
    procedure = int4fac 
 );
 
+-- Test comments
+COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary';
+COMMENT ON OPERATOR #%# (int4, NONE) IS 'right unary';
+COMMENT ON OPERATOR #%# (int4, NONE) IS NULL;
+
+
index ddcba72624eedc8a5e3ca4d7c83523db959422ea..6e8fa84b7dc5ccfa3f97c67c7e10cdad0f87cd0d 100644 (file)
@@ -69,6 +69,11 @@ CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
 
 SELECT * FROM get_default_test();
 
+-- Test comments
+COMMENT ON TYPE bad IS 'bad comment';
+COMMENT ON TYPE default_test_row IS 'good comment';
+COMMENT ON TYPE default_test_row IS NULL;
+
 DROP TYPE default_test_row CASCADE;
 
 DROP TABLE default_test;
index 8c15fc12417f299dc73d3a197f1f5f1acd9286ab..acc82b3e0e0c759a8df555897353638582d2ba74 100644 (file)
@@ -19,6 +19,11 @@ CREATE VIEW toyemp AS
    SELECT name, age, location, 12*salary AS annualsal
    FROM emp;
 
+-- Test comments
+COMMENT ON VIEW noview IS 'no view';
+COMMENT ON VIEW toyemp IS 'is a view';
+COMMENT ON VIEW toyemp IS NULL;
+
 --
 -- CREATE OR REPLACE VIEW
 --
index 009588db065ac46ea0f101fc0a104858faf166f2..10e4da0baf08f4033a2e7c24ddf8f3be3f370698 100644 (file)
@@ -50,6 +50,11 @@ CREATE TABLE PKTABLE ( ptest1 int, ptest2 int, ptest3 text, PRIMARY KEY(ptest1,
 CREATE TABLE FKTABLE ( ftest1 int, ftest2 int, ftest3 int, CONSTRAINT constrname FOREIGN KEY(ftest1, ftest2) 
                        REFERENCES PKTABLE MATCH FULL ON DELETE SET NULL ON UPDATE SET NULL);
 
+-- Test comments
+COMMENT ON CONSTRAINT constrname_wrong ON FKTABLE IS 'fk constraint comment';
+COMMENT ON CONSTRAINT constrname ON FKTABLE IS 'fk constraint comment';
+COMMENT ON CONSTRAINT constrname ON FKTABLE IS NULL;
+
 -- Insert test data into PKTABLE
 INSERT INTO PKTABLE VALUES (1, 2, 'Test1');
 INSERT INTO PKTABLE VALUES (1, 3, 'Test1-2');
index b4d0186458dc56ac7438b9916712e0399f31f439..9cb7f7c9407cf12542647e1968ad72397f2d6b6b 100644 (file)
@@ -326,6 +326,10 @@ begin
 end;
 ' language 'plpgsql';
 
+-- Test comments
+COMMENT ON FUNCTION tg_hub_adjustslots_wrong(bpchar, integer, integer) IS 'function with args';
+COMMENT ON FUNCTION tg_hub_adjustslots(bpchar, integer, integer) IS 'function with args';
+COMMENT ON FUNCTION tg_hub_adjustslots(bpchar, integer, integer) IS NULL;
 
 -- ************************************************************
 -- * BEFORE INSERT or UPDATE on HSlot
@@ -1603,4 +1607,4 @@ END;' language 'plpgsql';
 SELECT perform_test_func();
 SELECT * FROM perform_test;
 
-drop table perform_test;
\ No newline at end of file
+drop table perform_test;
index d797144d9d109b7cd07f9faa41bb1137f367e7af..55c3805bd5f601ce07fcc2150f2678f15cc0d021 100644 (file)
@@ -19,7 +19,10 @@ create rule rtest_v1_upd as on update to rtest_v1 do instead
        where a = old.a;
 create rule rtest_v1_del as on delete to rtest_v1 do instead
        delete from rtest_t1 where a = old.a;
-
+-- Test comments
+COMMENT ON RULE rtest_v1_bad ON rtest_v1 IS 'bad rule';
+COMMENT ON RULE rtest_v1_del ON rtest_v1 IS 'delete rule';
+COMMENT ON RULE rtest_v1_del ON rtest_v1 IS NULL;
 --
 -- Tables and rules for the constraint update/delete test
 --
index 6f3c1f22ddbca9d969316927d99f2d25de8961be..07f5765faf28aa7a149b77b1c9960ee82d041704 100644 (file)
@@ -37,3 +37,8 @@ SELECT nextval('sequence_test2');
 SELECT nextval('sequence_test2');
 SELECT nextval('sequence_test2');
 
+-- Test comments
+COMMENT ON SEQUENCE asdf IS 'won''t work';
+COMMENT ON SEQUENCE sequence_test2 IS 'will work';
+COMMENT ON SEQUENCE sequence_test2 IS NULL;
+
index 37bfb3bfd57d32e92f9845296d7f623c4c411a0b..f766e62554510e3facdf5136c629f3fb6222d5fb 100644 (file)
@@ -44,6 +44,11 @@ create trigger check_fkeys2_pkey_exist
        execute procedure 
        check_primary_key ('fkey21', 'fkey22', 'pkeys', 'pkey1', 'pkey2');
 
+-- Test comments
+COMMENT ON TRIGGER check_fkeys2_pkey_bad ON fkeys2 IS 'wrong';
+COMMENT ON TRIGGER check_fkeys2_pkey_exist ON fkeys2 IS 'right';
+COMMENT ON TRIGGER check_fkeys2_pkey_exist ON fkeys2 IS NULL;
+
 --
 -- For pkeys:
 --     ON DELETE/UPDATE (pkey1, pkey2) CASCADE: