Commit 42ce74bf authored by Tom Lane's avatar Tom Lane

COMMENT ON casts, conversions, languages, operator classes, and

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
parent 0a97cb37
<!-- <!--
$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 PostgreSQL documentation
--> -->
...@@ -25,12 +25,17 @@ COMMENT ON ...@@ -25,12 +25,17 @@ COMMENT ON
TABLE <replaceable class="PARAMETER">object_name</replaceable> | TABLE <replaceable class="PARAMETER">object_name</replaceable> |
COLUMN <replaceable class="PARAMETER">table_name</replaceable>.<replaceable class="PARAMETER">column_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>) | 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> | 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> | DATABASE <replaceable class="PARAMETER">object_name</replaceable> |
DOMAIN <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>, ...) | 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> | 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 <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> | RULE <replaceable class="PARAMETER">rule_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> |
SCHEMA <replaceable class="PARAMETER">object_name</replaceable> | SCHEMA <replaceable class="PARAMETER">object_name</replaceable> |
SEQUENCE <replaceable class="PARAMETER">object_name</replaceable> | SEQUENCE <replaceable class="PARAMETER">object_name</replaceable> |
...@@ -70,7 +75,7 @@ COMMENT ON ...@@ -70,7 +75,7 @@ COMMENT ON
<varlistentry> <varlistentry>
<term><replaceable class="parameter">object_name</replaceable></term> <term><replaceable class="parameter">object_name</replaceable></term>
<term><replaceable class="parameter">table_name.column_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">constraint_name</replaceable></term>
<term><replaceable class="parameter">func_name</replaceable></term> <term><replaceable class="parameter">func_name</replaceable></term>
<term><replaceable class="parameter">op</replaceable></term> <term><replaceable class="parameter">op</replaceable></term>
...@@ -78,13 +83,60 @@ COMMENT ON ...@@ -78,13 +83,60 @@ COMMENT ON
<term><replaceable class="parameter">trigger_name</replaceable></term> <term><replaceable class="parameter">trigger_name</replaceable></term>
<listitem> <listitem>
<para> <para>
The name of the object to be be commented. Names of tables, The name of the object to be commented. Names of tables,
aggregates, domains, functions, indexes, operators, sequences, aggregates, domains, functions, indexes, operators, operator classes,
types, and views may be schema-qualified. sequences, types, and views may be schema-qualified.
</para> </para>
</listitem> </listitem>
</varlistentry> </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> <varlistentry>
<term><replaceable class="parameter">text</replaceable></term> <term><replaceable class="parameter">text</replaceable></term>
<listitem> <listitem>
...@@ -93,12 +145,18 @@ COMMENT ON ...@@ -93,12 +145,18 @@ COMMENT ON
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>
<refsect1> <refsect1>
<title>Notes</title> <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> <para>
There is presently no security mechanism for comments: any user There is presently no security mechanism for comments: any user
connected to a database can see all the comments for objects in connected to a database can see all the comments for objects in
...@@ -130,13 +188,18 @@ COMMENT ON TABLE mytable IS NULL; ...@@ -130,13 +188,18 @@ COMMENT ON TABLE mytable IS NULL;
<programlisting> <programlisting>
COMMENT ON AGGREGATE my_aggregate (double precision) IS 'Computes sample variance'; 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 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 DATABASE my_database IS 'Development Database';
COMMENT ON DOMAIN my_domain IS 'Email Address Domain'; COMMENT ON DOMAIN my_domain IS 'Email Address Domain';
COMMENT ON FUNCTION my_function (timestamp) IS 'Returns Roman Numeral'; COMMENT ON FUNCTION my_function (timestamp) IS 'Returns Roman Numeral';
COMMENT ON INDEX my_index IS 'Enforces uniqueness on employee ID'; 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 ^ (text, text) IS 'Performs intersection of two texts';
COMMENT ON OPERATOR ^ (NONE, text) IS 'This is a prefix operator on text'; 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 RULE my_rule ON my_table IS 'Logs updates of employee records';
COMMENT ON SCHEMA my_schema IS 'Departmental data'; COMMENT ON SCHEMA my_schema IS 'Departmental data';
COMMENT ON SEQUENCE my_sequence IS 'Used to generate primary keys'; COMMENT ON SEQUENCE my_sequence IS 'Used to generate primary keys';
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* See acl.h. * See acl.h.
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "catalog/catname.h" #include "catalog/catname.h"
#include "catalog/indexing.h" #include "catalog/indexing.h"
#include "catalog/namespace.h" #include "catalog/namespace.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h" #include "catalog/pg_database.h"
#include "catalog/pg_group.h" #include "catalog/pg_group.h"
#include "catalog/pg_language.h" #include "catalog/pg_language.h"
...@@ -1551,3 +1552,31 @@ pg_database_ownercheck(Oid db_oid, AclId userid) ...@@ -1551,3 +1552,31 @@ pg_database_ownercheck(Oid db_oid, AclId userid)
return userid == dba; 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;
}
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Copyright (c) 1996-2003, PostgreSQL Global Development Group * Copyright (c) 1996-2003, PostgreSQL Global Development Group
* *
* IDENTIFICATION * 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 @@ ...@@ -21,6 +21,7 @@
#include "catalog/namespace.h" #include "catalog/namespace.h"
#include "catalog/pg_constraint.h" #include "catalog/pg_constraint.h"
#include "catalog/pg_description.h" #include "catalog/pg_description.h"
#include "catalog/pg_largeobject.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_rewrite.h" #include "catalog/pg_rewrite.h"
#include "catalog/pg_trigger.h" #include "catalog/pg_trigger.h"
...@@ -58,6 +59,11 @@ static void CommentProc(List *function, List *arguments, char *comment); ...@@ -58,6 +59,11 @@ static void CommentProc(List *function, List *arguments, char *comment);
static void CommentOperator(List *opername, List *arguments, char *comment); static void CommentOperator(List *opername, List *arguments, char *comment);
static void CommentTrigger(List *qualname, char *comment); static void CommentTrigger(List *qualname, char *comment);
static void CommentConstraint(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) ...@@ -107,6 +113,21 @@ CommentObject(CommentStmt *stmt)
case OBJECT_CONSTRAINT: case OBJECT_CONSTRAINT:
CommentConstraint(stmt->objname, stmt->comment); CommentConstraint(stmt->objname, stmt->comment);
break; 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: default:
elog(ERROR, "unrecognized object type: %d", elog(ERROR, "unrecognized object type: %d",
(int) stmt->objtype); (int) stmt->objtype);
...@@ -592,7 +613,10 @@ CommentRule(List *qualname, char *comment) ...@@ -592,7 +613,10 @@ CommentRule(List *qualname, char *comment)
PointerGetDatum(rulename), PointerGetDatum(rulename),
0, 0); 0, 0);
if (!HeapTupleIsValid(tuple)) 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); Assert(reloid == ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_class);
ruleoid = HeapTupleGetOid(tuple); ruleoid = HeapTupleGetOid(tuple);
ReleaseSysCache(tuple); ReleaseSysCache(tuple);
...@@ -910,3 +934,297 @@ CommentConstraint(List *qualname, char *comment) ...@@ -910,3 +934,297 @@ CommentConstraint(List *qualname, char *comment)
heap_close(pg_constraint, AccessShareLock); heap_close(pg_constraint, AccessShareLock);
heap_close(relation, NoLock); 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);
}
...@@ -2,14 +2,15 @@ ...@@ -2,14 +2,15 @@
* *
* functioncmds.c * 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) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* *
* IDENTIFICATION * 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 * DESCRIPTION
* These routines take the parse tree and pick out the * These routines take the parse tree and pick out the
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * 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 * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -363,7 +363,7 @@ static void doNegateFloat(Value *v); ...@@ -363,7 +363,7 @@ static void doNegateFloat(Value *v);
KEY 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 LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
LOCK_P LOCK_P
...@@ -373,7 +373,7 @@ static void doNegateFloat(Value *v); ...@@ -373,7 +373,7 @@ static void doNegateFloat(Value *v);
NOCREATEUSER NONE NOT NOTHING NOTIFY NOTNULL NULL_P NOCREATEUSER NONE NOT NOTHING NOTIFY NOTNULL NULL_P
NULLIF NUMERIC 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 ORDER OUT_P OUTER_P OVERLAPS OVERLAY OWNER
PARTIAL PASSWORD PATH_P PENDANT PLACING POSITION PARTIAL PASSWORD PATH_P PENDANT PLACING POSITION
...@@ -2519,11 +2519,15 @@ TruncateStmt: ...@@ -2519,11 +2519,15 @@ TruncateStmt:
* The COMMENT ON statement can take different forms based upon the type of * 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: * the object associated with the comment. The form of the statement is:
* *
* COMMENT ON [ [ DATABASE | DOMAIN | INDEX | SEQUENCE | TABLE | TYPE | VIEW ] * COMMENT ON [ [ DATABASE | DOMAIN | INDEX | SEQUENCE | TABLE | TYPE | VIEW |
* <objname> | AGGREGATE <aggname> (<aggtype>) | FUNCTION * CONVERSION | LANGUAGE | OPERATOR CLASS | LARGE OBJECT |
* <funcname> (arg1, arg2, ...) | OPERATOR <op> * CAST ] <objname> |
* (leftoperand_typ rightoperand_typ) | TRIGGER <triggername> ON * AGGREGATE <aggname> (<aggtype>) |
* <relname> | RULE <rulename> ON <relname> ] IS 'text' * 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: ...@@ -2603,6 +2607,42 @@ CommentStmt:
n->comment = $8; n->comment = $8;
$$ = (Node *) n; $$ = (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: comment_type:
...@@ -2615,6 +2655,7 @@ comment_type: ...@@ -2615,6 +2655,7 @@ comment_type:
| DOMAIN_P { $$ = OBJECT_TYPE; } | DOMAIN_P { $$ = OBJECT_TYPE; }
| TYPE_P { $$ = OBJECT_TYPE; } | TYPE_P { $$ = OBJECT_TYPE; }
| VIEW { $$ = OBJECT_VIEW; } | VIEW { $$ = OBJECT_VIEW; }
| CONVERSION_P { $$ = OBJECT_CONVERSION; }
; ;
comment_text: comment_text:
...@@ -7365,6 +7406,7 @@ unreserved_keyword: ...@@ -7365,6 +7406,7 @@ unreserved_keyword:
| KEY | KEY
| LANCOMPILER | LANCOMPILER
| LANGUAGE | LANGUAGE
| LARGE_P
| LAST_P | LAST_P
| LEVEL | LEVEL
| LISTEN | LISTEN
...@@ -7387,6 +7429,7 @@ unreserved_keyword: ...@@ -7387,6 +7429,7 @@ unreserved_keyword:
| NOCREATEUSER | NOCREATEUSER
| NOTHING | NOTHING
| NOTIFY | NOTIFY
| OBJECT_P
| OF | OF
| OIDS | OIDS
| OPERATOR | OPERATOR
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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[] = { ...@@ -177,6 +177,7 @@ static const ScanKeyword ScanKeywords[] = {
{"key", KEY}, {"key", KEY},
{"lancompiler", LANCOMPILER}, {"lancompiler", LANCOMPILER},
{"language", LANGUAGE}, {"language", LANGUAGE},
{"large", LARGE_P},
{"last", LAST_P}, {"last", LAST_P},
{"leading", LEADING}, {"leading", LEADING},
{"left", LEFT}, {"left", LEFT},
...@@ -214,6 +215,7 @@ static const ScanKeyword ScanKeywords[] = { ...@@ -214,6 +215,7 @@ static const ScanKeyword ScanKeywords[] = {
{"null", NULL_P}, {"null", NULL_P},
{"nullif", NULLIF}, {"nullif", NULLIF},
{"numeric", NUMERIC}, {"numeric", NUMERIC},
{"object", OBJECT_P},
{"of", OF}, {"of", OF},
{"off", OFF}, {"off", OFF},
{"offset", OFFSET}, {"offset", OFFSET},
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -31,12 +31,14 @@ ...@@ -31,12 +31,14 @@
#include "catalog/pg_opclass.h" #include "catalog/pg_opclass.h"
#include "catalog/pg_largeobject.h" #include "catalog/pg_largeobject.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "commands/comment.h"
#include "libpq/libpq-fs.h" #include "libpq/libpq-fs.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "storage/large_object.h" #include "storage/large_object.h"
#include "storage/smgr.h" #include "storage/smgr.h"
#include "utils/fmgroids.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
static int32 static int32
...@@ -174,8 +176,16 @@ inv_close(LargeObjectDesc *obj_desc) ...@@ -174,8 +176,16 @@ inv_close(LargeObjectDesc *obj_desc)
int int
inv_drop(Oid lobjId) inv_drop(Oid lobjId)
{ {
Oid classoid;
LargeObjectDrop(lobjId); 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 * Advance command counter so that tuple removal will be seen by later
* large-object operations in this transaction. * large-object operations in this transaction.
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -61,6 +61,7 @@ dumpSchema(Archive *fout,
int numAggregates; int numAggregates;
int numOperators; int numOperators;
int numOpclasses; int numOpclasses;
int numConversions;
NamespaceInfo *nsinfo; NamespaceInfo *nsinfo;
TypeInfo *tinfo; TypeInfo *tinfo;
FuncInfo *finfo; FuncInfo *finfo;
...@@ -69,6 +70,7 @@ dumpSchema(Archive *fout, ...@@ -69,6 +70,7 @@ dumpSchema(Archive *fout,
InhInfo *inhinfo; InhInfo *inhinfo;
OprInfo *oprinfo; OprInfo *oprinfo;
OpclassInfo *opcinfo; OpclassInfo *opcinfo;
ConvInfo *convinfo;
if (g_verbose) if (g_verbose)
write_msg(NULL, "reading schemas\n"); write_msg(NULL, "reading schemas\n");
...@@ -94,6 +96,10 @@ dumpSchema(Archive *fout, ...@@ -94,6 +96,10 @@ dumpSchema(Archive *fout,
write_msg(NULL, "reading user-defined operator classes\n"); write_msg(NULL, "reading user-defined operator classes\n");
opcinfo = getOpclasses(&numOpclasses); opcinfo = getOpclasses(&numOpclasses);
if (g_verbose)
write_msg(NULL, "reading user-defined conversions\n");
convinfo = getConversions(&numConversions);
if (g_verbose) if (g_verbose)
write_msg(NULL, "reading user-defined tables\n"); write_msg(NULL, "reading user-defined tables\n");
tblinfo = getTables(&numTables); tblinfo = getTables(&numTables);
...@@ -190,6 +196,13 @@ dumpSchema(Archive *fout, ...@@ -190,6 +196,13 @@ dumpSchema(Archive *fout,
dumpCasts(fout, finfo, numFuncs, tinfo, numTypes); 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; *numTablesPtr = numTables;
return tblinfo; return tblinfo;
} }
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* by PostgreSQL * by PostgreSQL
* *
* IDENTIFICATION * 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); ...@@ -105,6 +105,7 @@ static const char *convertRegProcReference(const char *proc);
static const char *convertOperatorReference(const char *opr, static const char *convertOperatorReference(const char *opr,
OprInfo *g_oprinfo, int numOperators); OprInfo *g_oprinfo, int numOperators);
static void dumpOneOpclass(Archive *fout, OpclassInfo *opcinfo); static void dumpOneOpclass(Archive *fout, OpclassInfo *opcinfo);
static void dumpOneConversion(Archive *fout, ConvInfo *convinfo);
static void dumpOneAgg(Archive *fout, AggInfo *agginfo); static void dumpOneAgg(Archive *fout, AggInfo *agginfo);
static Oid findLastBuiltinOid_V71(const char *); static Oid findLastBuiltinOid_V71(const char *);
static Oid findLastBuiltinOid_V70(void); static Oid findLastBuiltinOid_V70(void);
...@@ -1689,6 +1690,79 @@ getOperators(int *numOprs) ...@@ -1689,6 +1690,79 @@ getOperators(int *numOprs)
return oprinfo; 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: * getOpclasses:
* read all opclasses in the system catalogs and return them in the * read all opclasses in the system catalogs and return them in the
...@@ -3414,6 +3488,7 @@ dumpOneCompositeType(Archive *fout, TypeInfo *tinfo) ...@@ -3414,6 +3488,7 @@ dumpOneCompositeType(Archive *fout, TypeInfo *tinfo)
tinfo->usename, "TYPE", NULL, tinfo->usename, "TYPE", NULL,
q->data, delq->data, NULL, NULL, NULL); q->data, delq->data, NULL, NULL, NULL);
/* Dump Type Comments */ /* Dump Type Comments */
resetPQExpBuffer(q); resetPQExpBuffer(q);
...@@ -3614,6 +3689,14 @@ dumpProcLangs(Archive *fout, FuncInfo finfo[], int numFuncs) ...@@ -3614,6 +3689,14 @@ dumpProcLangs(Archive *fout, FuncInfo finfo[], int numFuncs)
NULL, lanacl, lanoid); NULL, lanacl, lanoid);
free(tmp); 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); PQclear(res);
...@@ -4019,6 +4102,16 @@ dumpCasts(Archive *fout, ...@@ -4019,6 +4102,16 @@ dumpCasts(Archive *fout,
"CAST", deps, "CAST", deps,
defqry->data, delqry->data, defqry->data, delqry->data,
NULL, NULL, NULL); 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); PQclear(res);
...@@ -4490,7 +4583,8 @@ dumpOneOpclass(Archive *fout, OpclassInfo *opcinfo) ...@@ -4490,7 +4583,8 @@ dumpOneOpclass(Archive *fout, OpclassInfo *opcinfo)
opcintype = PQgetvalue(res, 0, i_opcintype); opcintype = PQgetvalue(res, 0, i_opcintype);
opckeytype = PQgetvalue(res, 0, i_opckeytype); opckeytype = PQgetvalue(res, 0, i_opckeytype);
opcdefault = PQgetvalue(res, 0, i_opcdefault); 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 * DROP must be fully qualified in case same name appears in
...@@ -4617,11 +4711,145 @@ dumpOneOpclass(Archive *fout, OpclassInfo *opcinfo) ...@@ -4617,11 +4711,145 @@ dumpOneOpclass(Archive *fout, OpclassInfo *opcinfo)
q->data, delq->data, q->data, delq->data,
NULL, NULL, NULL); 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(query);
destroyPQExpBuffer(q); destroyPQExpBuffer(q);
destroyPQExpBuffer(delq); 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 * dumpAggs
...@@ -6573,8 +6801,10 @@ dumpRules(Archive *fout, TableInfo *tblinfo, int numTables) ...@@ -6573,8 +6801,10 @@ dumpRules(Archive *fout, TableInfo *tblinfo, int numTables)
/* Dump rule comments */ /* Dump rule comments */
resetPQExpBuffer(query); resetPQExpBuffer(query);
appendPQExpBuffer(query, "RULE %s", fmtId(PQgetvalue(res, i, i_rulename))); appendPQExpBuffer(query, "RULE %s",
appendPQExpBuffer(query, " ON %s", fmtId(tbinfo->relname)); fmtId(PQgetvalue(res, i, i_rulename)));
appendPQExpBuffer(query, " ON %s",
fmtId(tbinfo->relname));
dumpComment(fout, query->data, dumpComment(fout, query->data,
tbinfo->relnamespace->nspname, tbinfo->relnamespace->nspname,
tbinfo->usename, tbinfo->usename,
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 ...@@ -95,6 +95,14 @@ typedef struct _opclassInfo
char *usename; char *usename;
} OpclassInfo; } OpclassInfo;
typedef struct _convInfo
{
char *oid;
char *conname;
NamespaceInfo *connamespace; /* link to containing namespace */
char *usename;
} ConvInfo;
typedef struct _tableInfo typedef struct _tableInfo
{ {
/* /*
...@@ -213,6 +221,7 @@ extern FuncInfo *getFuncs(int *numFuncs); ...@@ -213,6 +221,7 @@ extern FuncInfo *getFuncs(int *numFuncs);
extern AggInfo *getAggregates(int *numAggregates); extern AggInfo *getAggregates(int *numAggregates);
extern OprInfo *getOperators(int *numOperators); extern OprInfo *getOperators(int *numOperators);
extern OpclassInfo *getOpclasses(int *numOpclasses); extern OpclassInfo *getOpclasses(int *numOpclasses);
extern ConvInfo *getConversions(int *numConversions);
extern TableInfo *getTables(int *numTables); extern TableInfo *getTables(int *numTables);
extern InhInfo *getInherits(int *numInherits); extern InhInfo *getInherits(int *numInherits);
...@@ -230,6 +239,8 @@ extern void dumpAggs(Archive *fout, AggInfo agginfo[], int numAggregates); ...@@ -230,6 +239,8 @@ extern void dumpAggs(Archive *fout, AggInfo agginfo[], int numAggregates);
extern void dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators); extern void dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators);
extern void dumpOpclasses(Archive *fout, extern void dumpOpclasses(Archive *fout,
OpclassInfo *opcinfo, int numOpclasses); OpclassInfo *opcinfo, int numOpclasses);
extern void dumpConversions(Archive *fout,
ConvInfo *coninfo, int numConversions);
extern void dumpTables(Archive *fout, TableInfo tblinfo[], int numTables, extern void dumpTables(Archive *fout, TableInfo tblinfo[], int numTables,
const bool aclsSkip, const bool aclsSkip,
const bool schemaOnly, const bool dataOnly); const bool schemaOnly, const bool dataOnly);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright (c) 2000-2003, PostgreSQL Global Development Group * 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 "postgres_fe.h"
#include "large_obj.h" #include "large_obj.h"
...@@ -165,9 +165,7 @@ do_lo_import(const char *filename_arg, const char *comment_arg) ...@@ -165,9 +165,7 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
} }
/* insert description if given */ /* insert description if given */
/* XXX don't try to hack pg_description if not superuser */ if (comment_arg)
/* XXX ought to replace this with some kind of COMMENT command */
if (comment_arg && is_superuser())
{ {
char *cmdbuf; char *cmdbuf;
char *bufptr; char *bufptr;
...@@ -177,9 +175,7 @@ do_lo_import(const char *filename_arg, const char *comment_arg) ...@@ -177,9 +175,7 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
if (!cmdbuf) if (!cmdbuf)
return fail_lo_xact("\\lo_import", own_transaction); return fail_lo_xact("\\lo_import", own_transaction);
sprintf(cmdbuf, sprintf(cmdbuf,
"INSERT INTO pg_catalog.pg_description VALUES ('%u', " "COMMENT ON LARGE OBJECT %u IS '",
"'pg_catalog.pg_largeobject'::regclass, "
"0, '",
loid); loid);
bufptr = cmdbuf + strlen(cmdbuf); bufptr = cmdbuf + strlen(cmdbuf);
for (i = 0; i < slen; i++) for (i = 0; i < slen; i++)
...@@ -188,7 +184,7 @@ do_lo_import(const char *filename_arg, const char *comment_arg) ...@@ -188,7 +184,7 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
*bufptr++ = '\\'; *bufptr++ = '\\';
*bufptr++ = comment_arg[i]; *bufptr++ = comment_arg[i];
} }
strcpy(bufptr, "')"); strcpy(bufptr, "'");
if (!(res = PSQLexec(cmdbuf, false))) if (!(res = PSQLexec(cmdbuf, false)))
{ {
...@@ -219,10 +215,8 @@ do_lo_import(const char *filename_arg, const char *comment_arg) ...@@ -219,10 +215,8 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
bool bool
do_lo_unlink(const char *loid_arg) do_lo_unlink(const char *loid_arg)
{ {
PGresult *res;
int status; int status;
Oid loid = atooid(loid_arg); Oid loid = atooid(loid_arg);
char buf[256];
bool own_transaction; bool own_transaction;
if (!start_lo_xact("\\lo_unlink", &own_transaction)) if (!start_lo_xact("\\lo_unlink", &own_transaction))
...@@ -235,20 +229,6 @@ do_lo_unlink(const char *loid_arg) ...@@ -235,20 +229,6 @@ do_lo_unlink(const char *loid_arg)
return fail_lo_xact("\\lo_unlink", own_transaction); 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)) if (!finish_lo_xact("\\lo_unlink", own_transaction))
return false; return false;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 ...@@ -686,6 +686,7 @@ typedef enum ObjectType
OBJECT_GROUP, OBJECT_GROUP,
OBJECT_INDEX, OBJECT_INDEX,
OBJECT_LANGUAGE, OBJECT_LANGUAGE,
OBJECT_LARGEOBJECT,
OBJECT_OPCLASS, OBJECT_OPCLASS,
OBJECT_OPERATOR, OBJECT_OPERATOR,
OBJECT_RULE, OBJECT_RULE,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* An ACL array is simply an array of AclItems, representing the union * 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); ...@@ -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_namespace_ownercheck(Oid nsp_oid, AclId userid);
extern bool pg_opclass_ownercheck(Oid opc_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_database_ownercheck(Oid db_oid, AclId userid);
extern bool pg_conversion_ownercheck(Oid conv_oid, AclId userid);
#endif /* ACL_H */ #endif /* ACL_H */
...@@ -3,6 +3,10 @@ ...@@ -3,6 +3,10 @@
-- add attribute -- add attribute
-- --
CREATE TABLE tmp (initial int4); 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 a int4;
ALTER TABLE tmp ADD COLUMN b name; ALTER TABLE tmp ADD COLUMN b name;
ALTER TABLE tmp ADD COLUMN c text; ALTER TABLE tmp ADD COLUMN c text;
......
...@@ -18,6 +18,11 @@ CREATE DEFAULT CONVERSION public.mydef FOR 'LATIN1' TO 'UNICODE' FROM iso8859_1_ ...@@ -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; CREATE DEFAULT CONVERSION public.mydef2 FOR 'LATIN1' TO 'UNICODE' FROM iso8859_1_to_utf8;
ERROR: default conversion for LATIN1 to UNICODE already exists 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 -- drop user defined conversion
-- --
......
...@@ -7,6 +7,11 @@ CREATE AGGREGATE newavg ( ...@@ -7,6 +7,11 @@ CREATE AGGREGATE newavg (
finalfunc = numeric_avg, finalfunc = numeric_avg,
initcond1 = '{0,0,0}' 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 -- without finalfunc; test obsolete spellings 'sfunc1' etc
CREATE AGGREGATE newsum ( CREATE AGGREGATE newsum (
sfunc1 = int4pl, basetype = int4, stype1 = int4, sfunc1 = int4pl, basetype = int4, stype1 = int4,
...@@ -17,3 +22,7 @@ CREATE AGGREGATE newcnt ( ...@@ -17,3 +22,7 @@ CREATE AGGREGATE newcnt (
sfunc = int4inc, basetype = 'any', stype = int4, sfunc = int4inc, basetype = 'any', stype = int4,
initcond = '0' 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;
...@@ -18,6 +18,11 @@ CREATE INDEX tenk2_hundred ON tenk2 USING btree(hundred int4_ops); ...@@ -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 rix ON road USING btree (name text_ops);
CREATE INDEX iix ON ihighway 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); 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 -- BTREE ascending/descending cases
-- --
......
...@@ -26,3 +26,8 @@ CREATE OPERATOR #%# ( ...@@ -26,3 +26,8 @@ CREATE OPERATOR #%# (
leftarg = int4, -- right unary leftarg = int4, -- right unary
procedure = int4fac 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;
...@@ -71,6 +71,11 @@ SELECT * FROM get_default_test(); ...@@ -71,6 +71,11 @@ SELECT * FROM get_default_test();
zippo | 42 zippo | 42
(1 row) (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; DROP TYPE default_test_row CASCADE;
NOTICE: drop cascades to function get_default_test() NOTICE: drop cascades to function get_default_test()
DROP TABLE default_test; DROP TABLE default_test;
...@@ -15,6 +15,11 @@ CREATE VIEW iexit AS ...@@ -15,6 +15,11 @@ CREATE VIEW iexit AS
CREATE VIEW toyemp AS CREATE VIEW toyemp AS
SELECT name, age, location, 12*salary AS annualsal SELECT name, age, location, 12*salary AS annualsal
FROM emp; 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 -- CREATE OR REPLACE VIEW
-- --
......
...@@ -64,6 +64,11 @@ CREATE TABLE PKTABLE ( ptest1 int, ptest2 int, ptest3 text, PRIMARY KEY(ptest1, ...@@ -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" 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) 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); 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 test data into PKTABLE
INSERT INTO PKTABLE VALUES (1, 2, 'Test1'); INSERT INTO PKTABLE VALUES (1, 2, 'Test1');
INSERT INTO PKTABLE VALUES (1, 3, 'Test1-2'); INSERT INTO PKTABLE VALUES (1, 3, 'Test1-2');
......
...@@ -264,6 +264,11 @@ begin ...@@ -264,6 +264,11 @@ begin
return 0; return 0;
end; end;
' language 'plpgsql'; ' 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 -- * BEFORE INSERT or UPDATE on HSlot
-- * - prevent from manual manipulation -- * - prevent from manual manipulation
......
...@@ -17,6 +17,11 @@ create rule rtest_v1_upd as on update to rtest_v1 do instead ...@@ -17,6 +17,11 @@ create rule rtest_v1_upd as on update to rtest_v1 do instead
where a = old.a; where a = old.a;
create rule rtest_v1_del as on delete to rtest_v1 do instead create rule rtest_v1_del as on delete to rtest_v1 do instead
delete from rtest_t1 where a = old.a; 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 -- Tables and rules for the constraint update/delete test
-- --
......
...@@ -71,3 +71,8 @@ SELECT nextval('sequence_test2'); ...@@ -71,3 +71,8 @@ SELECT nextval('sequence_test2');
5 5
(1 row) (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;
...@@ -37,6 +37,11 @@ create trigger check_fkeys2_pkey_exist ...@@ -37,6 +37,11 @@ create trigger check_fkeys2_pkey_exist
for each row for each row
execute procedure execute procedure
check_primary_key ('fkey21', 'fkey22', 'pkeys', 'pkey1', 'pkey2'); 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: -- For pkeys:
-- ON DELETE/UPDATE (pkey1, pkey2) CASCADE: -- ON DELETE/UPDATE (pkey1, pkey2) CASCADE:
......
...@@ -5,6 +5,10 @@ ...@@ -5,6 +5,10 @@
CREATE TABLE tmp (initial int4); 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 a int4;
ALTER TABLE tmp ADD COLUMN b name; ALTER TABLE tmp ADD COLUMN b name;
......
...@@ -16,6 +16,10 @@ CREATE DEFAULT CONVERSION public.mydef FOR 'LATIN1' TO 'UNICODE' FROM iso8859_1_ ...@@ -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 -- 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; 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 -- drop user defined conversion
-- --
......
...@@ -9,6 +9,11 @@ CREATE AGGREGATE newavg ( ...@@ -9,6 +9,11 @@ CREATE AGGREGATE newavg (
initcond1 = '{0,0,0}' 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 -- without finalfunc; test obsolete spellings 'sfunc1' etc
CREATE AGGREGATE newsum ( CREATE AGGREGATE newsum (
sfunc1 = int4pl, basetype = int4, stype1 = int4, sfunc1 = int4pl, basetype = int4, stype1 = int4,
...@@ -21,3 +26,6 @@ CREATE AGGREGATE newcnt ( ...@@ -21,3 +26,6 @@ CREATE AGGREGATE newcnt (
initcond = '0' initcond = '0'
); );
COMMENT ON AGGREGATE nosuchagg (*) IS 'should fail';
COMMENT ON AGGREGATE newcnt (*) IS 'an any agg comment';
COMMENT ON AGGREGATE newcnt (*) IS NULL;
...@@ -32,6 +32,11 @@ CREATE INDEX iix ON ihighway USING btree (name text_ops); ...@@ -32,6 +32,11 @@ CREATE INDEX iix ON ihighway USING btree (name text_ops);
CREATE INDEX six ON shighway 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 -- BTREE ascending/descending cases
-- --
......
...@@ -32,3 +32,9 @@ CREATE OPERATOR #%# ( ...@@ -32,3 +32,9 @@ CREATE OPERATOR #%# (
procedure = int4fac 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;
...@@ -69,6 +69,11 @@ CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS ' ...@@ -69,6 +69,11 @@ CREATE FUNCTION get_default_test() RETURNS SETOF default_test_row AS '
SELECT * FROM get_default_test(); 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 TYPE default_test_row CASCADE;
DROP TABLE default_test; DROP TABLE default_test;
...@@ -19,6 +19,11 @@ CREATE VIEW toyemp AS ...@@ -19,6 +19,11 @@ CREATE VIEW toyemp AS
SELECT name, age, location, 12*salary AS annualsal SELECT name, age, location, 12*salary AS annualsal
FROM emp; 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 -- CREATE OR REPLACE VIEW
-- --
......
...@@ -50,6 +50,11 @@ CREATE TABLE PKTABLE ( ptest1 int, ptest2 int, ptest3 text, PRIMARY KEY(ptest1, ...@@ -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) 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); 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 test data into PKTABLE
INSERT INTO PKTABLE VALUES (1, 2, 'Test1'); INSERT INTO PKTABLE VALUES (1, 2, 'Test1');
INSERT INTO PKTABLE VALUES (1, 3, 'Test1-2'); INSERT INTO PKTABLE VALUES (1, 3, 'Test1-2');
......
...@@ -326,6 +326,10 @@ begin ...@@ -326,6 +326,10 @@ begin
end; end;
' language 'plpgsql'; ' 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 -- * BEFORE INSERT or UPDATE on HSlot
...@@ -1603,4 +1607,4 @@ END;' language 'plpgsql'; ...@@ -1603,4 +1607,4 @@ END;' language 'plpgsql';
SELECT perform_test_func(); SELECT perform_test_func();
SELECT * FROM perform_test; SELECT * FROM perform_test;
drop table perform_test; drop table perform_test;
\ No newline at end of file
...@@ -19,7 +19,10 @@ create rule rtest_v1_upd as on update to rtest_v1 do instead ...@@ -19,7 +19,10 @@ create rule rtest_v1_upd as on update to rtest_v1 do instead
where a = old.a; where a = old.a;
create rule rtest_v1_del as on delete to rtest_v1 do instead create rule rtest_v1_del as on delete to rtest_v1 do instead
delete from rtest_t1 where a = old.a; 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 -- Tables and rules for the constraint update/delete test
-- --
......
...@@ -37,3 +37,8 @@ SELECT nextval('sequence_test2'); ...@@ -37,3 +37,8 @@ SELECT nextval('sequence_test2');
SELECT nextval('sequence_test2'); 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;
...@@ -44,6 +44,11 @@ create trigger check_fkeys2_pkey_exist ...@@ -44,6 +44,11 @@ create trigger check_fkeys2_pkey_exist
execute procedure execute procedure
check_primary_key ('fkey21', 'fkey22', 'pkeys', 'pkey1', 'pkey2'); 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: -- For pkeys:
-- ON DELETE/UPDATE (pkey1, pkey2) CASCADE: -- ON DELETE/UPDATE (pkey1, pkey2) CASCADE:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment