COMMENT ON casts, conversions, languages, operator classes, and
authorTom Lane
Fri, 21 Nov 2003 22:32:49 +0000 (22:32 +0000)
committerTom Lane
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 @@
 
 
@@ -25,12 +25,17 @@ COMMENT ON
   TABLE object_name |
   COLUMN table_name.column_name |
   AGGREGATE agg_name (agg_type) |
+  CAST (sourcetype AS targettype) |
   CONSTRAINT constraint_name ON table_name |
+  CONVERSION object_name |
   DATABASE object_name |
   DOMAIN object_name |
   FUNCTION func_name (arg1_type, arg2_type, ...) |
   INDEX object_name |
+  LARGE OBJECT large_object_oid |
   OPERATOR op (leftoperand_type, rightoperand_type) |
+  OPERATOR CLASS object_name USING index_method |
+  [ PROCEDURAL ] LANGUAGE object_name |
   RULE rule_name ON table_name |
   SCHEMA object_name |
   SEQUENCE object_name |
@@ -70,7 +75,7 @@ COMMENT ON
    
     object_name
     table_name.column_name
-    aggname
+    agg_name
     constraint_name
     func_name
     op
@@ -78,13 +83,60 @@ COMMENT ON
     trigger_name
     
      
-      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.
      
     
    
 
+   
+    agg_type
+    
+     
+      The argument data type of the aggregate function, or
+      * if the function accepts any data type.
+     
+    
+   
+
+   
+    large_object_oid
+    
+     
+      The OID of the large object.
+     
+    
+   
+
+    
+     PROCEDURAL
+
+     
+      
+       This is a noise word.
+      
+     
+    
+   
+   
+     sourcetype
+     
+      
+       The name of the source data type of the cast.
+      
+     
+    
+
+    
+     targettype
+     
+      
+       The name of the target data type of the cast.
+      
+     
+    
+
    
     text
     
@@ -93,12 +145,18 @@ COMMENT ON
      
     
    
+    
   
  
 
  
   Notes
 
+  
+   A comment for a database can only be created in that database,
+   and will only be visible in that database, not in other databases.
+  
+
   
    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;
 
 
 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 ]
- *               | AGGREGATE  () | FUNCTION
- *       (arg1, arg2, ...) | OPERATOR 
- *      (leftoperand_typ rightoperand_typ) | TRIGGER  ON
- *       | RULE  ON  ] IS 'text'
+ * COMMENT ON [ [ DATABASE | DOMAIN | INDEX | SEQUENCE | TABLE | TYPE | VIEW |
+ *                CONVERSION | LANGUAGE | OPERATOR CLASS | LARGE OBJECT |
+ *                CAST ]  |
+ *              AGGREGATE  () |
+ *              FUNCTION  (arg1, arg2, ...) |
+ *              OPERATOR  (leftoperand_typ, rightoperand_typ) |
+ *              TRIGGER  ON  |
+ *              RULE  ON  ]
+ *            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: