I've created a new shared catalog table pg_shdescription to store
comments on cluster global objects like databases, tablespaces, and roles. It touches a lot of places, but not much in the way of big changes. The only design decision I made was to duplicate the query and manipulation functions rather than to try and have them handle both shared and local comments. I believe this is simpler for the code and not an issue for callers because they know what type of object they are dealing with. This has resulted in a shobj_description function analagous to obj_description and backend functions [Create/Delete]SharedComments mirroring the existing [Create/Delete]Comments functions. pg_shdescription.h goes into src/include/catalog/ Kris Jurka
This commit is contained in:
parent
95dbf9c02f
commit
f9a726aa88
@ -1,6 +1,6 @@
|
||||
<!--
|
||||
Documentation of the system catalogs, directed toward PostgreSQL developers
|
||||
$PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.119 2006/01/21 19:05:59 tgl Exp $
|
||||
$PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.120 2006/02/12 03:22:16 momjian Exp $
|
||||
-->
|
||||
|
||||
<chapter id="catalogs">
|
||||
@ -188,6 +188,11 @@
|
||||
<entry>dependencies on shared objects</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><link linkend="catalog-pg-shdescription"><structname>pg_shdescription</structname></link></entry>
|
||||
<entry>comments on shared objects</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><link linkend="catalog-pg-statistic"><structname>pg_statistic</structname></link></entry>
|
||||
<entry>planner statistics</entry>
|
||||
@ -2230,6 +2235,12 @@
|
||||
contents of <structname>pg_description</structname>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
See also <link linkend="catalog-pg-shdescription"><structname>pg_shdescription</structname></link>,
|
||||
which performs a similar function for descriptions involving objects that
|
||||
are shared across a database cluster.
|
||||
</para>
|
||||
|
||||
<table>
|
||||
<title><structname>pg_description</> Columns</title>
|
||||
|
||||
@ -3612,6 +3623,73 @@
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="catalog-pg-shdescription">
|
||||
<title><structname>pg_shdescription</structname></title>
|
||||
|
||||
<indexterm zone="catalog-pg-shdescription">
|
||||
<primary>pg_shdescription</primary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
The catalog <structname>pg_shdescription</structname> stores optional
|
||||
descriptions (comments) for shared database objects. Descriptions can
|
||||
be manipulated with the <command>COMMENT</command> command and viewed
|
||||
with <application>psql</application>'s <literal>\d</literal> commands.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
See also <link linkend="catalog-pg-description"><structname>pg_description</structname></link>,
|
||||
which performs a similar function for descriptions involving objects
|
||||
within a single database.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Unlike most system catalogs, <structname>pg_shdescription</structname>
|
||||
is shared across all databases of a cluster: there is only one
|
||||
copy of <structname>pg_shdescription</structname> per cluster, not
|
||||
one per database.
|
||||
</para>
|
||||
|
||||
<table>
|
||||
<title><structname>pg_shdescription</> Columns</title>
|
||||
|
||||
<tgroup cols=4>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Name</entry>
|
||||
<entry>Type</entry>
|
||||
<entry>References</entry>
|
||||
<entry>Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><structfield>objoid</structfield></entry>
|
||||
<entry><type>oid</type></entry>
|
||||
<entry>any OID column</entry>
|
||||
<entry>The OID of the object this description pertains to</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><structfield>classoid</structfield></entry>
|
||||
<entry><type>oid</type></entry>
|
||||
<entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry>
|
||||
<entry>The OID of the system catalog this object appears in</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><structfield>description</structfield></entry>
|
||||
<entry><type>text</type></entry>
|
||||
<entry></entry>
|
||||
<entry>Arbitrary text that servers as the description of this object.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
<sect1 id="catalog-pg-statistic">
|
||||
<title><structname>pg_statistic</structname></title>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!--
|
||||
$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.304 2006/02/11 03:32:38 momjian Exp $
|
||||
$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.305 2006/02/12 03:22:16 momjian Exp $
|
||||
PostgreSQL documentation
|
||||
-->
|
||||
|
||||
@ -9463,6 +9463,10 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
|
||||
<primary>col_description</primary>
|
||||
</indexterm>
|
||||
|
||||
<indexterm zone="functions-info">
|
||||
<primary>shobj_description</primary>
|
||||
</indexterm>
|
||||
|
||||
<indexterm zone="functions-info">
|
||||
<primary>comment</primary>
|
||||
<secondary sortas="database objects">about database objects</secondary>
|
||||
@ -9499,6 +9503,11 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
|
||||
<entry><type>text</type></entry>
|
||||
<entry>get comment for a table column</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal><function>shobj_description</function>(<parameter>object_oid</parameter>, <parameter>catalog_name</parameter>)</literal></entry>
|
||||
<entry><type>text</type></entry>
|
||||
<entry>get comment for a shared database object</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
@ -9521,6 +9530,14 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
|
||||
<function>obj_description</function> cannot be used for table columns since
|
||||
columns do not have OIDs of their own.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<function>shobj_description</function> is used just like
|
||||
<function>obj_description</function> only that it is used for retrieving
|
||||
comments on shared objects. Some system catalogs are global to all
|
||||
databases within each cluster and their descriptions are stored globally
|
||||
as well.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="functions-admin">
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!--
|
||||
$PostgreSQL: pgsql/doc/src/sgml/ref/comment.sgml,v 1.29 2005/06/08 21:15:27 tgl Exp $
|
||||
$PostgreSQL: pgsql/doc/src/sgml/ref/comment.sgml,v 1.30 2006/02/12 03:22:17 momjian Exp $
|
||||
PostgreSQL documentation
|
||||
-->
|
||||
|
||||
@ -36,9 +36,11 @@ COMMENT ON
|
||||
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> |
|
||||
ROLE <replaceable class="PARAMETER">object_name</replaceable> |
|
||||
RULE <replaceable class="PARAMETER">rule_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> |
|
||||
SCHEMA <replaceable class="PARAMETER">object_name</replaceable> |
|
||||
SEQUENCE <replaceable class="PARAMETER">object_name</replaceable> |
|
||||
TABLESPACE <replaceable class="PARAMETER">object_name</replaceable> |
|
||||
TRIGGER <replaceable class="PARAMETER">trigger_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> |
|
||||
TYPE <replaceable class="PARAMETER">object_name</replaceable> |
|
||||
VIEW <replaceable class="PARAMETER">object_name</replaceable>
|
||||
@ -67,7 +69,8 @@ COMMENT ON
|
||||
<command>\dd</command>, <command>\d+</command>, and <command>\l+</command>.
|
||||
Other user interfaces to retrieve comments can be built atop
|
||||
the same built-in functions that <application>psql</application> uses, namely
|
||||
<function>obj_description</> and <function>col_description</>
|
||||
<function>obj_description</>, <function>col_description</>,
|
||||
and <function>shobj_description</>
|
||||
(see <xref linkend="functions-info-comment-table">).
|
||||
</para>
|
||||
</refsect1>
|
||||
@ -197,17 +200,15 @@ COMMENT ON
|
||||
<refsect1>
|
||||
<title>Notes</title>
|
||||
|
||||
<para>
|
||||
A comment for a database can only be created in that database,
|
||||
and will only be visible in that database, not in other databases.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
There is presently no security mechanism for comments: any user
|
||||
connected to a database can see all the comments for objects in
|
||||
that database (although only superusers can change comments for
|
||||
objects that they don't own). Therefore, don't put
|
||||
security-critical information in comments.
|
||||
objects that they don't own). For shared objects such as
|
||||
databases, roles, and tablespaces comments are stored gloablly
|
||||
and any user connected to any database can see all the comments
|
||||
for shared objects. Therefore, don't put security-critical
|
||||
information in comments.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
@ -245,10 +246,12 @@ 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 ROLE my_role IS 'Administration group for finance tables';
|
||||
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';
|
||||
COMMENT ON TABLE my_schema.my_table IS 'Employee Information';
|
||||
COMMENT ON TABLESPACE my_tablespace IS 'Tablespace for indexes';
|
||||
COMMENT ON TRIGGER my_trigger ON my_table IS 'Used for RI';
|
||||
COMMENT ON TYPE complex IS 'Complex number data type';
|
||||
COMMENT ON VIEW my_view IS 'View of departmental costs';
|
||||
|
@ -2,7 +2,7 @@
|
||||
#
|
||||
# Makefile for backend/catalog
|
||||
#
|
||||
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.58 2005/12/09 21:19:35 petere Exp $
|
||||
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.59 2006/02/12 03:22:17 momjian Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@ -15,7 +15,7 @@ OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
|
||||
pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_shdepend.o \
|
||||
pg_type.o
|
||||
|
||||
BKIFILES = postgres.bki postgres.description
|
||||
BKIFILES = postgres.bki postgres.description postgres.shdescription
|
||||
|
||||
all: SUBSYS.o $(BKIFILES)
|
||||
|
||||
@ -34,7 +34,7 @@ POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/,\
|
||||
pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
|
||||
pg_namespace.h pg_conversion.h pg_depend.h \
|
||||
pg_database.h pg_tablespace.h pg_pltemplate.h \
|
||||
pg_authid.h pg_auth_members.h pg_shdepend.h \
|
||||
pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
|
||||
indexing.h \
|
||||
)
|
||||
|
||||
@ -43,6 +43,8 @@ pg_includes := $(sort -I$(top_srcdir)/src/include -I$(top_builddir)/src/include)
|
||||
# see explanation in ../parser/Makefile
|
||||
postgres.description: postgres.bki ;
|
||||
|
||||
postgres.shdescription: postgres.bki ;
|
||||
|
||||
postgres.bki: genbki.sh $(POSTGRES_BKI_SRCS) \
|
||||
$(top_srcdir)/src/include/postgres_ext.h $(top_builddir)/src/include/pg_config_manual.h
|
||||
AWK='$(AWK)' $(SHELL) $< $(pg_includes) --set-version=$(VERSION) -o postgres $(POSTGRES_BKI_SRCS)
|
||||
@ -51,6 +53,7 @@ postgres.bki: genbki.sh $(POSTGRES_BKI_SRCS) \
|
||||
install-data: $(BKIFILES) installdirs
|
||||
$(INSTALL_DATA) postgres.bki '$(DESTDIR)$(datadir)/postgres.bki'
|
||||
$(INSTALL_DATA) postgres.description '$(DESTDIR)$(datadir)/postgres.description'
|
||||
$(INSTALL_DATA) postgres.shdescription '$(DESTDIR)$(datadir)/postgres.shdescription'
|
||||
$(INSTALL_DATA) $(srcdir)/system_views.sql '$(DESTDIR)$(datadir)/system_views.sql'
|
||||
$(INSTALL_DATA) $(srcdir)/information_schema.sql '$(DESTDIR)$(datadir)/information_schema.sql'
|
||||
$(INSTALL_DATA) $(srcdir)/sql_features.txt '$(DESTDIR)$(datadir)/sql_features.txt'
|
||||
|
@ -11,7 +11,7 @@
|
||||
#
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $PostgreSQL: pgsql/src/backend/catalog/genbki.sh,v 1.37 2005/06/28 05:08:52 tgl Exp $
|
||||
# $PostgreSQL: pgsql/src/backend/catalog/genbki.sh,v 1.38 2006/02/12 03:22:17 momjian Exp $
|
||||
#
|
||||
# NOTES
|
||||
# non-essential whitespace is removed from the generated file.
|
||||
@ -103,7 +103,7 @@ fi
|
||||
|
||||
TMPFILE="genbkitmp$$.c"
|
||||
|
||||
trap "rm -f $TMPFILE ${OUTPUT_PREFIX}.bki.$$ ${OUTPUT_PREFIX}.description.$$" 0 1 2 3 15
|
||||
trap "rm -f $TMPFILE ${OUTPUT_PREFIX}.bki.$$ ${OUTPUT_PREFIX}.description.$$ ${OUTPUT_PREFIX}.shdescription.$$" 0 1 2 3 15
|
||||
|
||||
|
||||
# Get NAMEDATALEN from postgres_ext.h
|
||||
@ -131,6 +131,7 @@ for dir in $INCLUDE_DIRS; do
|
||||
done
|
||||
|
||||
touch ${OUTPUT_PREFIX}.description.$$
|
||||
touch ${OUTPUT_PREFIX}.shdescription.$$
|
||||
|
||||
# ----------------
|
||||
# Strip comments and other trash from .h
|
||||
@ -201,7 +202,7 @@ comment_level > 0 { next; }
|
||||
# ----------------
|
||||
# DATA() statements are basically passed right through after
|
||||
# stripping off the DATA( and the ) on the end.
|
||||
# Remember the OID for use by DESCR().
|
||||
# Remember the OID for use by DESCR() and SHDESCR().
|
||||
# ----------------
|
||||
/^DATA\(/ {
|
||||
data = substr($0, 6, length($0) - 6);
|
||||
@ -225,6 +226,16 @@ comment_level > 0 { next; }
|
||||
next;
|
||||
}
|
||||
|
||||
/^SHDESCR\(/ {
|
||||
if (oid != 0)
|
||||
{
|
||||
data = substr($0, 10, length($0) - 11);
|
||||
if (data != "")
|
||||
printf "%d\t%s\t%s\n", oid, catalog, data >>shdescriptionfile;
|
||||
}
|
||||
next;
|
||||
}
|
||||
|
||||
/^DECLARE_INDEX\(/ {
|
||||
# ----
|
||||
# end any prior catalog data insertions before starting a define index
|
||||
@ -365,7 +376,7 @@ END {
|
||||
reln_open = 0;
|
||||
}
|
||||
}
|
||||
' "descriptionfile=${OUTPUT_PREFIX}.description.$$" > $TMPFILE || exit
|
||||
' "descriptionfile=${OUTPUT_PREFIX}.description.$$" "shdescriptionfile=${OUTPUT_PREFIX}.shdescription.$$" > $TMPFILE || exit
|
||||
|
||||
echo "# PostgreSQL $major_version" >${OUTPUT_PREFIX}.bki.$$
|
||||
|
||||
@ -386,10 +397,15 @@ if [ `wc -c < ${OUTPUT_PREFIX}.description.$$` -lt 10000 ]; then
|
||||
echo "$CMDNAME: something seems to be wrong with the .description file" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ `wc -c < ${OUTPUT_PREFIX}.shdescription.$$` -lt 10 ]; then
|
||||
echo "$CMDNAME: something seems to be wrong with the .shdescription file" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Looks good, commit ...
|
||||
|
||||
mv ${OUTPUT_PREFIX}.bki.$$ ${OUTPUT_PREFIX}.bki || exit
|
||||
mv ${OUTPUT_PREFIX}.description.$$ ${OUTPUT_PREFIX}.description || exit
|
||||
mv ${OUTPUT_PREFIX}.shdescription.$$ ${OUTPUT_PREFIX}.shdescription || exit
|
||||
|
||||
exit 0
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.85 2005/11/22 18:17:08 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.86 2006/02/12 03:22:17 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -18,6 +18,7 @@
|
||||
#include "access/heapam.h"
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_authid.h"
|
||||
#include "catalog/pg_cast.h"
|
||||
#include "catalog/pg_constraint.h"
|
||||
#include "catalog/pg_conversion.h"
|
||||
@ -30,10 +31,13 @@
|
||||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_rewrite.h"
|
||||
#include "catalog/pg_shdescription.h"
|
||||
#include "catalog/pg_tablespace.h"
|
||||
#include "catalog/pg_trigger.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "commands/comment.h"
|
||||
#include "commands/dbcommands.h"
|
||||
#include "commands/tablespace.h"
|
||||
#include "miscadmin.h"
|
||||
#include "parser/parse_func.h"
|
||||
#include "parser/parse_oper.h"
|
||||
@ -70,6 +74,8 @@ 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);
|
||||
static void CommentTablespace(List *qualname, char *comment);
|
||||
static void CommentRole(List *qualname, char *comment);
|
||||
|
||||
|
||||
/*
|
||||
@ -134,6 +140,12 @@ CommentObject(CommentStmt *stmt)
|
||||
case OBJECT_CAST:
|
||||
CommentCast(stmt->objname, stmt->objargs, stmt->comment);
|
||||
break;
|
||||
case OBJECT_TABLESPACE:
|
||||
CommentTablespace(stmt->objname, stmt->comment);
|
||||
break;
|
||||
case OBJECT_ROLE:
|
||||
CommentRole(stmt->objname, stmt->comment);
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized object type: %d",
|
||||
(int) stmt->objtype);
|
||||
@ -240,6 +252,100 @@ CreateComments(Oid oid, Oid classoid, int32 subid, char *comment)
|
||||
heap_close(description, NoLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* CreateSharedComments --
|
||||
*
|
||||
* Create a comment for the specified shared object descriptor. Inserts a
|
||||
* new pg_shdescription tuple, or replaces an existing one with the same key.
|
||||
*
|
||||
* If the comment given is null or an empty string, instead delete any
|
||||
* existing comment for the specified key.
|
||||
*/
|
||||
void CreateSharedComments(Oid oid, Oid classoid, char *comment)
|
||||
{
|
||||
Relation shdescription;
|
||||
ScanKeyData skey[2];
|
||||
SysScanDesc sd;
|
||||
HeapTuple oldtuple;
|
||||
HeapTuple newtuple = NULL;
|
||||
Datum values[Natts_pg_shdescription];
|
||||
char nulls[Natts_pg_shdescription];
|
||||
char replaces[Natts_pg_shdescription];
|
||||
int i;
|
||||
|
||||
/* Reduce empty-string to NULL case */
|
||||
if (comment != NULL && strlen(comment) == 0)
|
||||
comment = NULL;
|
||||
|
||||
/* Prepare to form or update a tuple, if necessary */
|
||||
if (comment != NULL)
|
||||
{
|
||||
for (i = 0; i < Natts_pg_shdescription; i++)
|
||||
{
|
||||
nulls[i] = ' ';
|
||||
replaces[i] = 'r';
|
||||
}
|
||||
i = 0;
|
||||
values[i++] = ObjectIdGetDatum(oid);
|
||||
values[i++] = ObjectIdGetDatum(classoid);
|
||||
values[i++] = DirectFunctionCall1(textin, CStringGetDatum(comment));
|
||||
}
|
||||
|
||||
/* Use the index to search for a matching old tuple */
|
||||
|
||||
ScanKeyInit(&skey[0],
|
||||
Anum_pg_shdescription_objoid,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(oid));
|
||||
ScanKeyInit(&skey[1],
|
||||
Anum_pg_shdescription_classoid,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(classoid));
|
||||
|
||||
shdescription = heap_open(SharedDescriptionRelationId, RowExclusiveLock);
|
||||
|
||||
sd = systable_beginscan(shdescription, SharedDescriptionObjIndexId, true,
|
||||
SnapshotNow, 2, skey);
|
||||
|
||||
while ((oldtuple = systable_getnext(sd)) != NULL)
|
||||
{
|
||||
/* Found the old tuple, so delete or update it */
|
||||
|
||||
if (comment == NULL)
|
||||
simple_heap_delete(shdescription, &oldtuple->t_self);
|
||||
else
|
||||
{
|
||||
newtuple = heap_modifytuple(oldtuple, RelationGetDescr(shdescription),
|
||||
values, nulls, replaces);
|
||||
simple_heap_update(shdescription, &oldtuple->t_self, newtuple);
|
||||
}
|
||||
|
||||
break; /* Assume there can be only one match */
|
||||
}
|
||||
|
||||
systable_endscan(sd);
|
||||
|
||||
/* If we didn't find an old tuple, insert a new one */
|
||||
|
||||
if (newtuple == NULL && comment != NULL)
|
||||
{
|
||||
newtuple = heap_formtuple(RelationGetDescr(shdescription),
|
||||
values, nulls);
|
||||
simple_heap_insert(shdescription, newtuple);
|
||||
}
|
||||
|
||||
/* Update indexes, if necessary */
|
||||
if (newtuple != NULL)
|
||||
{
|
||||
CatalogUpdateIndexes(shdescription, newtuple);
|
||||
heap_freetuple(newtuple);
|
||||
}
|
||||
|
||||
/* Done */
|
||||
|
||||
heap_close(shdescription, NoLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* DeleteComments -- remove comments for an object
|
||||
*
|
||||
@ -292,6 +398,42 @@ DeleteComments(Oid oid, Oid classoid, int32 subid)
|
||||
heap_close(description, RowExclusiveLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* DeleteSharedComments -- remove comments for a shared object
|
||||
*/
|
||||
void
|
||||
DeleteSharedComments(Oid oid, Oid classoid)
|
||||
{
|
||||
Relation shdescription;
|
||||
ScanKeyData skey[2];
|
||||
SysScanDesc sd;
|
||||
HeapTuple oldtuple;
|
||||
|
||||
/* Use the index to search for all matching old tuples */
|
||||
|
||||
ScanKeyInit(&skey[0],
|
||||
Anum_pg_shdescription_objoid,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(oid));
|
||||
ScanKeyInit(&skey[1],
|
||||
Anum_pg_shdescription_classoid,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(classoid));
|
||||
|
||||
shdescription = heap_open(SharedDescriptionRelationId, RowExclusiveLock);
|
||||
|
||||
sd = systable_beginscan(shdescription, SharedDescriptionObjIndexId, true,
|
||||
SnapshotNow, 2, skey);
|
||||
|
||||
while ((oldtuple = systable_getnext(sd)) != NULL)
|
||||
simple_heap_delete(shdescription, &oldtuple->t_self);
|
||||
|
||||
/* Done */
|
||||
|
||||
systable_endscan(sd);
|
||||
heap_close(shdescription, RowExclusiveLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* CommentRelation --
|
||||
*
|
||||
@ -425,7 +567,7 @@ CommentAttribute(List *qualname, char *comment)
|
||||
* have regarding the specified database. The routine will check
|
||||
* security for owner permissions, and, if successful, will then
|
||||
* attempt to find the oid of the database specified. Once found,
|
||||
* a comment is added/dropped using the CreateComments() routine.
|
||||
* a comment is added/dropped using the CreateSharedComments() routine.
|
||||
*/
|
||||
static void
|
||||
CommentDatabase(List *qualname, char *comment)
|
||||
@ -440,11 +582,6 @@ CommentDatabase(List *qualname, char *comment)
|
||||
database = strVal(linitial(qualname));
|
||||
|
||||
/*
|
||||
* We cannot currently support cross-database comments (since other DBs
|
||||
* cannot see pg_description of this database). So, we reject attempts to
|
||||
* comment on a database other than the current one. Someday this might be
|
||||
* improved, but it would take a redesigned infrastructure.
|
||||
*
|
||||
* When loading a dump, we may see a COMMENT ON DATABASE for the old name
|
||||
* of the database. Erroring out would prevent pg_restore from completing
|
||||
* (which is really pg_restore's fault, but for now we will work around
|
||||
@ -462,23 +599,83 @@ CommentDatabase(List *qualname, char *comment)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Only allow comments on the current database */
|
||||
if (oid != MyDatabaseId)
|
||||
{
|
||||
ereport(WARNING, /* throw just a warning so pg_restore doesn't
|
||||
* fail */
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("database comments may only be applied to the current database")));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check object security */
|
||||
if (!pg_database_ownercheck(oid, GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
|
||||
database);
|
||||
|
||||
/* Call CreateComments() to create/drop the comments */
|
||||
CreateComments(oid, DatabaseRelationId, 0, comment);
|
||||
/* Call CreateSharedComments() to create/drop the comments */
|
||||
CreateSharedComments(oid, DatabaseRelationId, comment);
|
||||
}
|
||||
|
||||
/*
|
||||
* CommentTablespace --
|
||||
*
|
||||
* This routine is used to add/drop any user-comments a user might
|
||||
* have regarding a tablespace. The tablepace is specified by name
|
||||
* and, if found, and the user has appropriate permissions, a
|
||||
* comment will be added/dropped using the CreateSharedComments() routine.
|
||||
*
|
||||
*/
|
||||
static void
|
||||
CommentTablespace(List *qualname, char *comment)
|
||||
{
|
||||
char *tablespace;
|
||||
Oid oid;
|
||||
|
||||
if (list_length(qualname) != 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("tablespace name may not be qualified")));
|
||||
tablespace = strVal(linitial(qualname));
|
||||
|
||||
oid = get_tablespace_oid(tablespace);
|
||||
if (!OidIsValid(oid))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("tablespace \"%s\" does not exist", tablespace)));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check object security */
|
||||
if (!pg_tablespace_ownercheck(oid, GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE, tablespace);
|
||||
|
||||
/* Call CreateSharedComments() to create/drop the comments */
|
||||
CreateSharedComments(oid, TableSpaceRelationId, comment);
|
||||
}
|
||||
|
||||
/*
|
||||
* CommentRole --
|
||||
*
|
||||
* This routine is used to add/drop any user-comments a user might
|
||||
* have regarding a role. The role is specified by name
|
||||
* and, if found, and the user has appropriate permissions, a
|
||||
* comment will be added/dropped using the CreateSharedComments() routine.
|
||||
*/
|
||||
static void
|
||||
CommentRole(List *qualname, char *comment)
|
||||
{
|
||||
char *role;
|
||||
Oid oid;
|
||||
|
||||
if (list_length(qualname) != 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("role name may not be qualified")));
|
||||
role = strVal(linitial(qualname));
|
||||
|
||||
oid = get_roleid_checked(role);
|
||||
|
||||
/* Check object security */
|
||||
if (!has_privs_of_role(GetUserId(), oid))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("must be member of role \"%s\" to comment upon it", role)));
|
||||
|
||||
/* Call CreateSharedComments() to create/drop the comments */
|
||||
CreateSharedComments(oid, AuthIdRelationId, comment);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -15,7 +15,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.175 2005/11/22 18:17:08 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.176 2006/02/12 03:22:17 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -658,10 +658,8 @@ dropdb(const char *dbname, bool missing_ok)
|
||||
/*
|
||||
* Delete any comments associated with the database
|
||||
*
|
||||
* NOTE: this is probably dead code since any such comments should have
|
||||
* been in that database, not mine.
|
||||
*/
|
||||
DeleteComments(db_id, DatabaseRelationId, 0);
|
||||
DeleteSharedComments(db_id, DatabaseRelationId);
|
||||
|
||||
/*
|
||||
* Remove shared dependency references for the database.
|
||||
|
@ -37,7 +37,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.29 2006/01/19 04:45:38 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.30 2006/02/12 03:22:17 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -54,6 +54,7 @@
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/pg_namespace.h"
|
||||
#include "catalog/pg_tablespace.h"
|
||||
#include "commands/comment.h"
|
||||
#include "commands/tablespace.h"
|
||||
#include "miscadmin.h"
|
||||
#include "storage/fd.h"
|
||||
@ -428,6 +429,11 @@ DropTableSpace(DropTableSpaceStmt *stmt)
|
||||
|
||||
heap_endscan(scandesc);
|
||||
|
||||
/*
|
||||
* Remove any comments on this tablespace.
|
||||
*/
|
||||
DeleteSharedComments(tablespaceoid, TableSpaceRelationId);
|
||||
|
||||
/*
|
||||
* Remove dependency on owner.
|
||||
*/
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.168 2006/02/04 19:06:46 adunstan Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.169 2006/02/12 03:22:17 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -18,6 +18,7 @@
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/pg_auth_members.h"
|
||||
#include "catalog/pg_authid.h"
|
||||
#include "commands/comment.h"
|
||||
#include "commands/user.h"
|
||||
#include "libpq/crypt.h"
|
||||
#include "miscadmin.h"
|
||||
@ -940,6 +941,11 @@ DropRole(DropRoleStmt *stmt)
|
||||
|
||||
systable_endscan(sscan);
|
||||
|
||||
/*
|
||||
* Remove any comments on this role.
|
||||
*/
|
||||
DeleteSharedComments(roleid, AuthIdRelationId);
|
||||
|
||||
/*
|
||||
* Advance command counter so that later iterations of this loop will
|
||||
* see the changes already made. This is essential if, for example,
|
||||
|
@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.527 2006/02/11 22:17:18 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.528 2006/02/12 03:22:17 momjian Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@ -2953,11 +2953,12 @@ TruncateStmt:
|
||||
*
|
||||
* COMMENT ON [ [ DATABASE | DOMAIN | INDEX | SEQUENCE | TABLE | TYPE | VIEW |
|
||||
* CONVERSION | LANGUAGE | OPERATOR CLASS | LARGE OBJECT |
|
||||
* CAST ] <objname> |
|
||||
* CAST | COLUMN | SCHEMA | TABLESPACE | ROLE ] <objname> |
|
||||
* AGGREGATE <aggname> (<aggtype>) |
|
||||
* FUNCTION <funcname> (arg1, arg2, ...) |
|
||||
* OPERATOR <op> (leftoperand_typ, rightoperand_typ) |
|
||||
* TRIGGER <triggername> ON <relname> |
|
||||
* CONSTRAINT <constraintname> ON <relname> |
|
||||
* RULE <rulename> ON <relname> ]
|
||||
* IS 'text'
|
||||
*
|
||||
@ -3088,6 +3089,8 @@ comment_type:
|
||||
| TYPE_P { $$ = OBJECT_TYPE; }
|
||||
| VIEW { $$ = OBJECT_VIEW; }
|
||||
| CONVERSION_P { $$ = OBJECT_CONVERSION; }
|
||||
| TABLESPACE { $$ = OBJECT_TABLESPACE; }
|
||||
| ROLE { $$ = OBJECT_ROLE; }
|
||||
;
|
||||
|
||||
comment_text:
|
||||
|
@ -42,7 +42,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
* Portions taken from FreeBSD.
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.108 2006/02/10 22:05:42 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.109 2006/02/12 03:22:18 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -105,6 +105,7 @@ static const char *progname;
|
||||
static char *encodingid = "0";
|
||||
static char *bki_file;
|
||||
static char *desc_file;
|
||||
static char *shdesc_file;
|
||||
static char *hba_file;
|
||||
static char *ident_file;
|
||||
static char *conf_file;
|
||||
@ -181,6 +182,7 @@ static void unlimit_systables(void);
|
||||
static void setup_depend(void);
|
||||
static void setup_sysviews(void);
|
||||
static void setup_description(void);
|
||||
static void setup_shared_description(void);
|
||||
static void setup_conversion(void);
|
||||
static void setup_privileges(void);
|
||||
static void set_info_version(void);
|
||||
@ -1574,6 +1576,7 @@ unlimit_systables(void)
|
||||
"ALTER TABLE pg_description CREATE TOAST TABLE;\n",
|
||||
"ALTER TABLE pg_proc CREATE TOAST TABLE;\n",
|
||||
"ALTER TABLE pg_rewrite CREATE TOAST TABLE;\n",
|
||||
"ALTER TABLE pg_shdescription CREATE TOAST TABLE;\n",
|
||||
"ALTER TABLE pg_statistic CREATE TOAST TABLE;\n",
|
||||
NULL
|
||||
};
|
||||
@ -1751,6 +1754,42 @@ setup_description(void)
|
||||
check_ok();
|
||||
}
|
||||
|
||||
/*
|
||||
* load shared description data
|
||||
*/
|
||||
static void
|
||||
setup_shared_description(void)
|
||||
{
|
||||
PG_CMD_DECL;
|
||||
|
||||
fputs(_("loading pg_shdescription ... "), stdout);
|
||||
fflush(stdout);
|
||||
|
||||
snprintf(cmd, sizeof(cmd),
|
||||
"\"%s\" %s template1 >%s",
|
||||
backend_exec, backend_options,
|
||||
DEVNULL);
|
||||
|
||||
PG_CMD_OPEN;
|
||||
|
||||
PG_CMD_PUTS("CREATE TEMP TABLE tmp_pg_shdescription ( "
|
||||
" objoid oid, "
|
||||
" classname name, "
|
||||
" description text) WITHOUT OIDS;\n");
|
||||
|
||||
PG_CMD_PRINTF1("COPY tmp_pg_shdescription FROM '%s';\n",
|
||||
shdesc_file);
|
||||
|
||||
PG_CMD_PUTS("INSERT INTO pg_shdescription "
|
||||
" SELECT t.objoid, c.oid, t.description "
|
||||
" FROM tmp_pg_shdescription t, pg_class c "
|
||||
" WHERE c.relname = t.classname;\n");
|
||||
|
||||
PG_CMD_CLOSE;
|
||||
|
||||
check_ok();
|
||||
}
|
||||
|
||||
/*
|
||||
* load conversion functions
|
||||
*/
|
||||
@ -2702,6 +2741,7 @@ main(int argc, char *argv[])
|
||||
|
||||
set_input(&bki_file, "postgres.bki");
|
||||
set_input(&desc_file, "postgres.description");
|
||||
set_input(&shdesc_file, "postgres.shdescription");
|
||||
set_input(&hba_file, "pg_hba.conf.sample");
|
||||
set_input(&ident_file, "pg_ident.conf.sample");
|
||||
set_input(&conf_file, "postgresql.conf.sample");
|
||||
@ -2718,12 +2758,14 @@ main(int argc, char *argv[])
|
||||
"VERSION=%s\n"
|
||||
"PGDATA=%s\nshare_path=%s\nPGPATH=%s\n"
|
||||
"POSTGRES_SUPERUSERNAME=%s\nPOSTGRES_BKI=%s\n"
|
||||
"POSTGRES_DESCR=%s\nPOSTGRESQL_CONF_SAMPLE=%s\n"
|
||||
"POSTGRES_DESCR=%s\nPOSTGRES_SHDESCR=%s\n"
|
||||
"POSTGRESQL_CONF_SAMPLE=%s\n"
|
||||
"PG_HBA_SAMPLE=%s\nPG_IDENT_SAMPLE=%s\n",
|
||||
PG_VERSION,
|
||||
pg_data, share_path, bin_path,
|
||||
effective_user, bki_file,
|
||||
desc_file, conf_file,
|
||||
desc_file, shdesc_file,
|
||||
conf_file,
|
||||
hba_file, ident_file);
|
||||
if (show_setting)
|
||||
exit(0);
|
||||
@ -2731,6 +2773,7 @@ main(int argc, char *argv[])
|
||||
|
||||
check_input(bki_file);
|
||||
check_input(desc_file);
|
||||
check_input(shdesc_file);
|
||||
check_input(hba_file);
|
||||
check_input(ident_file);
|
||||
check_input(conf_file);
|
||||
@ -2918,6 +2961,8 @@ main(int argc, char *argv[])
|
||||
|
||||
setup_description();
|
||||
|
||||
setup_shared_description();
|
||||
|
||||
setup_conversion();
|
||||
|
||||
setup_privileges();
|
||||
|
@ -12,7 +12,7 @@
|
||||
* by PostgreSQL
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.427 2006/01/21 02:16:20 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.428 2006/02/12 03:22:18 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -1185,7 +1185,20 @@ dumpDatabase(Archive *AH)
|
||||
selectSourceSchema("pg_catalog");
|
||||
|
||||
/* Get the database owner and parameters from pg_database */
|
||||
if (g_fout->remoteVersion >= 80000)
|
||||
if (g_fout->remoteVersion >= 80200)
|
||||
{
|
||||
appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
|
||||
"(%s datdba) as dba, "
|
||||
"pg_encoding_to_char(encoding) as encoding, "
|
||||
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) as tablespace, "
|
||||
"shobj_description(oid, 'pg_database') as description "
|
||||
|
||||
"FROM pg_database "
|
||||
"WHERE datname = ",
|
||||
username_subquery);
|
||||
appendStringLiteral(dbQry, datname, true);
|
||||
}
|
||||
else if (g_fout->remoteVersion >= 80000)
|
||||
{
|
||||
appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
|
||||
"(%s datdba) as dba, "
|
||||
@ -1287,10 +1300,28 @@ dumpDatabase(Archive *AH)
|
||||
NULL); /* Dumper Arg */
|
||||
|
||||
/* Dump DB comment if any */
|
||||
resetPQExpBuffer(dbQry);
|
||||
appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
|
||||
dumpComment(AH, dbQry->data, NULL, "",
|
||||
if (g_fout->remoteVersion >= 80200)
|
||||
{
|
||||
/* 8.2 keeps comments on shared objects in a shared table, so
|
||||
* we cannot use the dumpComment used for other database objects.
|
||||
*/
|
||||
char *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
|
||||
if (comment && strlen(comment)) {
|
||||
resetPQExpBuffer(dbQry);
|
||||
appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
|
||||
appendStringLiteral(dbQry, comment, false);
|
||||
appendPQExpBuffer(dbQry, ";\n");
|
||||
|
||||
ArchiveEntry(AH, dbCatId, createDumpId(), datname, NULL, NULL,
|
||||
dba, false, "COMMENT", dbQry->data, "", NULL,
|
||||
&dbDumpId, 1, NULL, NULL);
|
||||
}
|
||||
} else {
|
||||
resetPQExpBuffer(dbQry);
|
||||
appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
|
||||
dumpComment(AH, dbQry->data, NULL, "",
|
||||
dbCatId, 0, dbDumpId);
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.69 2005/10/15 02:49:39 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.70 2006/02/12 03:22:19 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -409,16 +409,25 @@ dumpRoles(PGconn *conn)
|
||||
i_rolcanlogin,
|
||||
i_rolconnlimit,
|
||||
i_rolpassword,
|
||||
i_rolvaliduntil;
|
||||
i_rolvaliduntil,
|
||||
i_rolcomment;
|
||||
int i;
|
||||
|
||||
/* note: rolconfig is dumped later */
|
||||
if (server_version >= 80100)
|
||||
if (server_version >= 80200)
|
||||
printfPQExpBuffer(buf,
|
||||
"SELECT rolname, rolsuper, rolinherit, "
|
||||
"rolcreaterole, rolcreatedb, rolcatupdate, "
|
||||
"rolcanlogin, rolconnlimit, rolpassword, "
|
||||
"rolvaliduntil "
|
||||
"rolvaliduntil, "
|
||||
"pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment "
|
||||
"FROM pg_authid");
|
||||
else if (server_version >= 80100)
|
||||
printfPQExpBuffer(buf,
|
||||
"SELECT rolname, rolsuper, rolinherit, "
|
||||
"rolcreaterole, rolcreatedb, rolcatupdate, "
|
||||
"rolcanlogin, rolconnlimit, rolpassword, "
|
||||
"rolvaliduntil, null as rolcomment "
|
||||
"FROM pg_authid");
|
||||
else
|
||||
printfPQExpBuffer(buf,
|
||||
@ -432,6 +441,7 @@ dumpRoles(PGconn *conn)
|
||||
"-1 as rolconnlimit, "
|
||||
"passwd as rolpassword, "
|
||||
"valuntil as rolvaliduntil "
|
||||
"null as rolcomment "
|
||||
"FROM pg_shadow "
|
||||
"UNION ALL "
|
||||
"SELECT groname as rolname, "
|
||||
@ -444,6 +454,7 @@ dumpRoles(PGconn *conn)
|
||||
"-1 as rolconnlimit, "
|
||||
"null::text as rolpassword, "
|
||||
"null::abstime as rolvaliduntil "
|
||||
"null "
|
||||
"FROM pg_group");
|
||||
|
||||
res = executeQuery(conn, buf->data);
|
||||
@ -458,6 +469,7 @@ dumpRoles(PGconn *conn)
|
||||
i_rolconnlimit = PQfnumber(res, "rolconnlimit");
|
||||
i_rolpassword = PQfnumber(res, "rolpassword");
|
||||
i_rolvaliduntil = PQfnumber(res, "rolvaliduntil");
|
||||
i_rolcomment = PQfnumber(res, "rolcomment");
|
||||
|
||||
if (PQntuples(res) > 0)
|
||||
printf("--\n-- Roles\n--\n\n");
|
||||
@ -523,6 +535,12 @@ dumpRoles(PGconn *conn)
|
||||
|
||||
appendPQExpBuffer(buf, ";\n");
|
||||
|
||||
if (!PQgetisnull(res, i, i_rolcomment)) {
|
||||
appendPQExpBuffer(buf, "COMMENT ON ROLE %s IS ", fmtId(rolename));
|
||||
appendStringLiteral(buf, PQgetvalue(res, i, i_rolcomment), true);
|
||||
appendPQExpBuffer(buf, ";\n");
|
||||
}
|
||||
|
||||
printf("%s", buf->data);
|
||||
|
||||
if (server_version >= 70300)
|
||||
@ -652,9 +670,18 @@ dumpTablespaces(PGconn *conn)
|
||||
* Get all tablespaces except built-in ones (which we assume are named
|
||||
* pg_xxx)
|
||||
*/
|
||||
res = executeQuery(conn, "SELECT spcname, "
|
||||
if (server_version >= 80200)
|
||||
res = executeQuery(conn, "SELECT spcname, "
|
||||
"pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
|
||||
"spclocation, spcacl "
|
||||
"spclocation, spcacl, "
|
||||
"pg_catalog.shobj_description(oid, 'pg_tablespace') "
|
||||
"FROM pg_catalog.pg_tablespace "
|
||||
"WHERE spcname NOT LIKE 'pg!_%' ESCAPE '!'");
|
||||
else
|
||||
res = executeQuery(conn, "SELECT spcname, "
|
||||
"pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
|
||||
"spclocation, spcacl, "
|
||||
"null "
|
||||
"FROM pg_catalog.pg_tablespace "
|
||||
"WHERE spcname NOT LIKE 'pg!_%' ESCAPE '!'");
|
||||
|
||||
@ -668,6 +695,7 @@ dumpTablespaces(PGconn *conn)
|
||||
char *spcowner = PQgetvalue(res, i, 1);
|
||||
char *spclocation = PQgetvalue(res, i, 2);
|
||||
char *spcacl = PQgetvalue(res, i, 3);
|
||||
char *spccomment = PQgetvalue(res, i, 4);
|
||||
char *fspcname;
|
||||
|
||||
/* needed for buildACLCommands() */
|
||||
@ -693,6 +721,12 @@ dumpTablespaces(PGconn *conn)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (spccomment && strlen(spccomment)) {
|
||||
appendPQExpBuffer(buf, "COMMENT ON TABLESPACE %s IS ", fspcname);
|
||||
appendStringLiteral(buf, spccomment, true);
|
||||
appendPQExpBuffer(buf, ";\n");
|
||||
}
|
||||
|
||||
printf("%s", buf->data);
|
||||
|
||||
free(fspcname);
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.159 2006/02/12 02:54:30 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.160 2006/02/12 03:22:19 momjian Exp $
|
||||
*/
|
||||
#include "postgres_fe.h"
|
||||
#include "command.h"
|
||||
@ -379,7 +379,7 @@ exec_command(const char *cmd,
|
||||
break;
|
||||
case 'g':
|
||||
/* no longer distinct from \du */
|
||||
success = describeRoles(pattern);
|
||||
success = describeRoles(pattern, show_verbose);
|
||||
break;
|
||||
case 'l':
|
||||
success = do_lo_list();
|
||||
@ -404,7 +404,7 @@ exec_command(const char *cmd,
|
||||
success = listTables(&cmd[1], pattern, show_verbose);
|
||||
break;
|
||||
case 'u':
|
||||
success = describeRoles(pattern);
|
||||
success = describeRoles(pattern, show_verbose);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.130 2005/11/22 18:17:29 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.131 2006/02/12 03:22:19 momjian Exp $
|
||||
*/
|
||||
#include "postgres_fe.h"
|
||||
#include "describe.h"
|
||||
@ -127,8 +127,9 @@ describeTablespaces(const char *pattern, bool verbose)
|
||||
|
||||
if (verbose)
|
||||
appendPQExpBuffer(&buf,
|
||||
",\n spcacl as \"%s\"",
|
||||
_("Access privileges"));
|
||||
",\n spcacl as \"%s\""
|
||||
",\n pg_catalog.shobj_description(oid, 'pg_tablespace') AS \"%s\"",
|
||||
_("Access privileges"), _("Description"));
|
||||
|
||||
appendPQExpBuffer(&buf,
|
||||
"\nFROM pg_catalog.pg_tablespace\n");
|
||||
@ -362,7 +363,7 @@ listAllDbs(bool verbose)
|
||||
_("Encoding"));
|
||||
if (verbose)
|
||||
appendPQExpBuffer(&buf,
|
||||
",\n pg_catalog.obj_description(d.oid, 'pg_database') as \"%s\"",
|
||||
",\n pg_catalog.shobj_description(d.oid, 'pg_database') as \"%s\"",
|
||||
_("Description"));
|
||||
appendPQExpBuffer(&buf,
|
||||
"\nFROM pg_catalog.pg_database d"
|
||||
@ -1382,7 +1383,7 @@ add_tablespace_footer(char relkind, Oid tablespace, char **footers,
|
||||
* Describes roles. Any schema portion of the pattern is ignored.
|
||||
*/
|
||||
bool
|
||||
describeRoles(const char *pattern)
|
||||
describeRoles(const char *pattern, bool verbose)
|
||||
{
|
||||
PQExpBufferData buf;
|
||||
PGresult *res;
|
||||
@ -1398,8 +1399,7 @@ describeRoles(const char *pattern)
|
||||
" CASE WHEN r.rolconnlimit < 0 THEN CAST('%s' AS pg_catalog.text)\n"
|
||||
" ELSE CAST(r.rolconnlimit AS pg_catalog.text)\n"
|
||||
" END AS \"%s\", \n"
|
||||
" ARRAY(SELECT b.rolname FROM pg_catalog.pg_auth_members m JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid) WHERE m.member = r.oid) as \"%s\"\n"
|
||||
"FROM pg_catalog.pg_roles r\n",
|
||||
" ARRAY(SELECT b.rolname FROM pg_catalog.pg_auth_members m JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid) WHERE m.member = r.oid) as \"%s\"",
|
||||
_("Role name"),
|
||||
_("yes"), _("no"), _("Superuser"),
|
||||
_("yes"), _("no"), _("Create role"),
|
||||
@ -1407,6 +1407,12 @@ describeRoles(const char *pattern)
|
||||
_("no limit"), _("Connections"),
|
||||
_("Member of"));
|
||||
|
||||
if (verbose)
|
||||
appendPQExpBuffer(&buf, "\n, pg_catalog.shobj_description(r.oid, 'pg_authid') AS \"%s\"",
|
||||
_("Description"));
|
||||
|
||||
appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_roles r\n");
|
||||
|
||||
processNamePattern(&buf, pattern, false, false,
|
||||
NULL, "r.rolname", NULL, NULL);
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/psql/describe.h,v 1.29 2005/08/14 18:49:30 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/psql/describe.h,v 1.30 2006/02/12 03:22:19 momjian Exp $
|
||||
*/
|
||||
#ifndef DESCRIBE_H
|
||||
#define DESCRIBE_H
|
||||
@ -26,7 +26,7 @@ extern bool describeTypes(const char *pattern, bool verbose);
|
||||
extern bool describeOperators(const char *pattern);
|
||||
|
||||
/* \du, \dg */
|
||||
extern bool describeRoles(const char *pattern);
|
||||
extern bool describeRoles(const char *pattern, bool verbose);
|
||||
|
||||
/* \z (or \dp) */
|
||||
extern bool permissionsList(const char *pattern);
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.145 2006/02/11 21:55:35 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.146 2006/02/12 03:22:19 momjian Exp $
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
@ -925,7 +925,8 @@ psql_completion(char *text, int start, int end)
|
||||
static const char *const list_COMMENT[] =
|
||||
{"CAST", "CONVERSION", "DATABASE", "INDEX", "LANGUAGE", "RULE", "SCHEMA",
|
||||
"SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
|
||||
"OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT", NULL};
|
||||
"OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT",
|
||||
"TABLESPACE", "ROLE", NULL};
|
||||
|
||||
COMPLETE_WITH_LIST(list_COMMENT);
|
||||
}
|
||||
|
@ -37,7 +37,7 @@
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.314 2006/02/11 16:28:56 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.315 2006/02/12 03:22:19 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -53,6 +53,6 @@
|
||||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 200602111
|
||||
#define CATALOG_VERSION_NO 200602112
|
||||
|
||||
#endif
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.92 2005/10/15 02:49:42 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.93 2006/02/12 03:22:19 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -139,6 +139,8 @@ DECLARE_INDEX(pg_depend_reference_index, 2674, on pg_depend using btree(refclass
|
||||
|
||||
DECLARE_UNIQUE_INDEX(pg_description_o_c_o_index, 2675, on pg_description using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops));
|
||||
#define DescriptionObjIndexId 2675
|
||||
DECLARE_UNIQUE_INDEX(pg_shdescription_o_c_index, 2397, on pg_shdescription using btree(objoid oid_ops, classoid oid_ops));
|
||||
#define SharedDescriptionObjIndexId 2397
|
||||
|
||||
/* This following index is not used for a cache and is not unique */
|
||||
DECLARE_INDEX(pg_index_indrelid_index, 2678, on pg_index using btree(indrelid oid_ops));
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/catalog/pg_database.h,v 1.38 2005/10/15 02:49:42 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/include/catalog/pg_database.h,v 1.39 2006/02/12 03:22:19 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* the genbki.sh script reads this file and generates .bki
|
||||
@ -75,7 +75,7 @@ typedef FormData_pg_database *Form_pg_database;
|
||||
#define Anum_pg_database_datacl 12
|
||||
|
||||
DATA(insert OID = 1 ( template1 PGUID ENCODING t t -1 0 0 0 1663 _null_ _null_ ));
|
||||
DESCR("Default template database");
|
||||
SHDESCR("Default template database");
|
||||
#define TemplateDbOid 1
|
||||
|
||||
#endif /* PG_DATABASE_H */
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.396 2006/02/11 20:39:58 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.397 2006/02/12 03:22:19 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* The script catalog/genbki.sh reads this file and generates .bki
|
||||
@ -1513,6 +1513,8 @@ DATA(insert OID = 1215 ( obj_description PGNSP PGUID 14 f f t f s 2 25 "26 19"
|
||||
DESCR("get description for object id and catalog name");
|
||||
DATA(insert OID = 1216 ( col_description PGNSP PGUID 14 f f t f s 2 25 "26 23" _null_ _null_ _null_ "select description from pg_catalog.pg_description where objoid = $1 and classoid = ''pg_catalog.pg_class''::regclass and objsubid = $2" - _null_ ));
|
||||
DESCR("get description for table column");
|
||||
DATA(insert OID = 1993 ( shobj_description PGNSP PGUID 14 f f t f s 2 25 "26 19" _null_ _null_ _null_ "select description from pg_catalog.pg_shdescription where objoid = $1 and classoid = (select oid from pg_catalog.pg_class where relname = $2 and relnamespace = PGNSP)" - _null_ ));
|
||||
DESCR("get description for object id and shared catalog name");
|
||||
|
||||
DATA(insert OID = 1217 ( date_trunc PGNSP PGUID 12 f f t f s 2 1184 "25 1184" _null_ _null_ _null_ timestamptz_trunc - _null_ ));
|
||||
DESCR("truncate timestamp with time zone to specified units");
|
||||
|
80
src/include/catalog/pg_shdescription.h
Normal file
80
src/include/catalog/pg_shdescription.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* pg_shdescription.h
|
||||
* definition of the system "shared description" relation
|
||||
* (pg_shdescription)
|
||||
*
|
||||
* NOTE: an object is identified by the OID of the row that primarily
|
||||
* defines the object, plus the OID of the table that that row appears in.
|
||||
* For example, a database is identified by the OID of its pg_database row
|
||||
* plus the pg_class OID of table pg_database. This allows unique
|
||||
* identification of objects without assuming that OIDs are unique
|
||||
* across tables.
|
||||
*
|
||||
*
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/catalog/pg_shdescription.h,v 1.1 2006/02/12 03:22:21 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* the genbki.sh script reads this file and generates .bki
|
||||
* information from the DATA() statements.
|
||||
*
|
||||
* XXX do NOT break up DATA() statements into multiple lines!
|
||||
* the scripts are not as smart as you might think...
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef PG_SHDESCRIPTION_H
|
||||
#define PG_SHDESCRIPTION_H
|
||||
|
||||
/* ----------------
|
||||
* postgres.h contains the system type definitions and the
|
||||
* CATALOG(), BKI_BOOTSTRAP and DATA() sugar words so this file
|
||||
* can be read by both genbki.sh and the C compiler.
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* pg_shdescription definition. cpp turns this into
|
||||
* typedef struct FormData_pg_shdescription
|
||||
* ----------------
|
||||
*/
|
||||
#define SharedDescriptionRelationId 2396
|
||||
|
||||
CATALOG(pg_shdescription,2396) BKI_SHARED_RELATION BKI_WITHOUT_OIDS
|
||||
{
|
||||
Oid objoid; /* OID of object itself */
|
||||
Oid classoid; /* OID of table containing object */
|
||||
text description; /* description of object */
|
||||
} FormData_pg_shdescription;
|
||||
|
||||
/* ----------------
|
||||
* Form_pg_shdescription corresponds to a pointer to a tuple with
|
||||
* the format of pg_shdescription relation.
|
||||
* ----------------
|
||||
*/
|
||||
typedef FormData_pg_shdescription *Form_pg_shdescription;
|
||||
|
||||
/* ----------------
|
||||
* compiler constants for pg_shdescription
|
||||
* ----------------
|
||||
*/
|
||||
#define Natts_pg_shdescription 3
|
||||
#define Anum_pg_shdescription_objoid 1
|
||||
#define Anum_pg_shdescription_classoid 2
|
||||
#define Anum_pg_shdescription_description 3
|
||||
|
||||
/* ----------------
|
||||
* initial contents of pg_shdescription
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* Because the contents of this table are taken from the other *.h files,
|
||||
* there is no initialization here. The initial contents are extracted
|
||||
* by genbki.sh and loaded during initdb.
|
||||
*/
|
||||
|
||||
#endif /* PG_SHDESCRIPTION_H */
|
@ -21,7 +21,8 @@
|
||||
* related routines. CommentObject() implements the SQL "COMMENT ON"
|
||||
* command. DeleteComments() deletes all comments for an object.
|
||||
* CreateComments creates (or deletes, if comment is NULL) a comment
|
||||
* for a specific key.
|
||||
* for a specific key. There are versions of these two methods for
|
||||
* both normal and shared objects.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@ -31,4 +32,8 @@ extern void DeleteComments(Oid oid, Oid classoid, int32 subid);
|
||||
|
||||
extern void CreateComments(Oid oid, Oid classoid, int32 subid, char *comment);
|
||||
|
||||
extern void DeleteSharedComments(Oid oid, Oid classoid);
|
||||
|
||||
extern void CreateSharedComments(Oid oid, Oid classoid, char *comment);
|
||||
|
||||
#endif /* COMMENT_H */
|
||||
|
@ -10,7 +10,7 @@
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1995, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/postgres.h,v 1.72 2006/01/08 21:24:37 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/postgres.h,v 1.73 2006/02/12 03:22:19 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -539,6 +539,7 @@ extern int ExceptionalCondition(char *conditionName, char *errorType,
|
||||
/* these need to expand into some harmless, repeatable declaration */
|
||||
#define DATA(x) extern int no_such_variable
|
||||
#define DESCR(x) extern int no_such_variable
|
||||
#define SHDESCR(x) extern int no_such_variable
|
||||
|
||||
typedef int4 aclitem; /* PHONY definition for catalog use only */
|
||||
|
||||
|
@ -59,6 +59,7 @@ SELECT relname, relhasindex
|
||||
pg_proc | t
|
||||
pg_rewrite | t
|
||||
pg_shdepend | t
|
||||
pg_shdescription | t
|
||||
pg_statistic | t
|
||||
pg_tablespace | t
|
||||
pg_trigger | t
|
||||
@ -68,7 +69,7 @@ SELECT relname, relhasindex
|
||||
shighway | t
|
||||
tenk1 | t
|
||||
tenk2 | t
|
||||
(58 rows)
|
||||
(59 rows)
|
||||
|
||||
--
|
||||
-- another sanity check: every system catalog that has OIDs should have
|
||||
|
Loading…
x
Reference in New Issue
Block a user