Modify pg_dump to dump foreign-key constraints as constraints, not as
sets of triggers. Also modify psql \d command to show foreign key constraints as such and hide the triggers. pg_get_constraintdef() function added to backend to support these. From Rod Taylor, code review and some editorialization by Tom Lane.
This commit is contained in:
parent
8dabef838c
commit
a208ea72bc
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.111 2002/08/14 02:45:09 ishii Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.112 2002/08/16 23:01:18 tgl Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -5521,6 +5521,11 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
|
|||||||
<entry><type>text</type></entry>
|
<entry><type>text</type></entry>
|
||||||
<entry>Get CREATE INDEX command for index</entry>
|
<entry>Get CREATE INDEX command for index</entry>
|
||||||
</row>
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry><function>pg_get_constraintdef</function>(<parameter>constraintOID</parameter>)</entry>
|
||||||
|
<entry><type>text</type></entry>
|
||||||
|
<entry>Get definition of a constraint</entry>
|
||||||
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry><function>pg_get_userbyid</function>(<parameter>userid</parameter>)</entry>
|
<entry><function>pg_get_userbyid</function>(<parameter>userid</parameter>)</entry>
|
||||||
<entry><type>name</type></entry>
|
<entry><type>name</type></entry>
|
||||||
@ -5542,16 +5547,25 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
|
|||||||
<primary>pg_get_indexdef</primary>
|
<primary>pg_get_indexdef</primary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
|
<indexterm zone="functions-misc">
|
||||||
|
<primary>pg_get_constraintdef</primary>
|
||||||
|
</indexterm>
|
||||||
|
|
||||||
<indexterm zone="functions-misc">
|
<indexterm zone="functions-misc">
|
||||||
<primary>pg_get_userbyid</primary>
|
<primary>pg_get_userbyid</primary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
These functions extract information from the system catalogs.
|
These functions extract information from the system catalogs.
|
||||||
<function>pg_get_viewdef()</function>, <function>pg_get_ruledef()</function>, and
|
<function>pg_get_viewdef()</function>,
|
||||||
<function>pg_get_indexdef()</function> respectively reconstruct the creating
|
<function>pg_get_ruledef()</function>,
|
||||||
command for a view, rule, or index. (Note that this is a decompiled
|
<function>pg_get_indexdef()</function>, and
|
||||||
|
<function>pg_get_constraintdef()</function> respectively reconstruct the
|
||||||
|
creating command for a view, rule, index, or constraint.
|
||||||
|
(Note that this is a decompiled
|
||||||
reconstruction, not the verbatim text of the command.)
|
reconstruction, not the verbatim text of the command.)
|
||||||
|
At present <function>pg_get_constraintdef()</function> only works for
|
||||||
|
foreign-key constraints.
|
||||||
<function>pg_get_userbyid()</function> extracts a user's name given a
|
<function>pg_get_userbyid()</function> extracts a user's name given a
|
||||||
<structfield>usesysid</structfield> value.
|
<structfield>usesysid</structfield> value.
|
||||||
</para>
|
</para>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* back to source text
|
* back to source text
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.115 2002/08/16 20:55:09 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.116 2002/08/16 23:01:19 tgl Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -40,10 +40,14 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include "access/genam.h"
|
||||||
|
#include "catalog/catname.h"
|
||||||
#include "catalog/heap.h"
|
#include "catalog/heap.h"
|
||||||
#include "catalog/index.h"
|
#include "catalog/index.h"
|
||||||
|
#include "catalog/indexing.h"
|
||||||
#include "catalog/namespace.h"
|
#include "catalog/namespace.h"
|
||||||
#include "catalog/pg_cast.h"
|
#include "catalog/pg_cast.h"
|
||||||
|
#include "catalog/pg_constraint.h"
|
||||||
#include "catalog/pg_index.h"
|
#include "catalog/pg_index.h"
|
||||||
#include "catalog/pg_opclass.h"
|
#include "catalog/pg_opclass.h"
|
||||||
#include "catalog/pg_operator.h"
|
#include "catalog/pg_operator.h"
|
||||||
@ -60,6 +64,8 @@
|
|||||||
#include "parser/parsetree.h"
|
#include "parser/parsetree.h"
|
||||||
#include "rewrite/rewriteManip.h"
|
#include "rewrite/rewriteManip.h"
|
||||||
#include "rewrite/rewriteSupport.h"
|
#include "rewrite/rewriteSupport.h"
|
||||||
|
#include "utils/array.h"
|
||||||
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
|
|
||||||
|
|
||||||
@ -116,6 +122,8 @@ static char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_c
|
|||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
static text *pg_do_getviewdef(Oid viewoid);
|
static text *pg_do_getviewdef(Oid viewoid);
|
||||||
|
static void decompile_column_index_array(Datum column_index_array, Oid relId,
|
||||||
|
StringInfo buf);
|
||||||
static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
|
static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
|
||||||
static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
|
static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
|
||||||
static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
|
static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
|
||||||
@ -528,6 +536,214 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pg_get_constraintdef
|
||||||
|
*
|
||||||
|
* Returns the definition for the constraint, ie, everything that needs to
|
||||||
|
* appear after "ALTER TABLE ... ADD CONSTRAINT <constraintname>".
|
||||||
|
*
|
||||||
|
* XXX The present implementation only works for foreign-key constraints, but
|
||||||
|
* it could and should handle anything pg_constraint stores.
|
||||||
|
*/
|
||||||
|
Datum
|
||||||
|
pg_get_constraintdef(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid constraintId = PG_GETARG_OID(0);
|
||||||
|
text *result;
|
||||||
|
StringInfoData buf;
|
||||||
|
int len;
|
||||||
|
Relation conDesc;
|
||||||
|
SysScanDesc conscan;
|
||||||
|
ScanKeyData skey[1];
|
||||||
|
HeapTuple tup;
|
||||||
|
Form_pg_constraint conForm;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fetch the pg_constraint row. There's no syscache for pg_constraint
|
||||||
|
* so we must do it the hard way.
|
||||||
|
*/
|
||||||
|
conDesc = heap_openr(ConstraintRelationName, AccessShareLock);
|
||||||
|
|
||||||
|
ScanKeyEntryInitialize(&skey[0], 0x0,
|
||||||
|
ObjectIdAttributeNumber, F_OIDEQ,
|
||||||
|
ObjectIdGetDatum(constraintId));
|
||||||
|
|
||||||
|
conscan = systable_beginscan(conDesc, ConstraintOidIndex, true,
|
||||||
|
SnapshotNow, 1, skey);
|
||||||
|
|
||||||
|
tup = systable_getnext(conscan);
|
||||||
|
if (!HeapTupleIsValid(tup))
|
||||||
|
elog(ERROR, "Failed to find constraint with OID %u", constraintId);
|
||||||
|
conForm = (Form_pg_constraint) GETSTRUCT(tup);
|
||||||
|
|
||||||
|
initStringInfo(&buf);
|
||||||
|
|
||||||
|
switch (conForm->contype)
|
||||||
|
{
|
||||||
|
case CONSTRAINT_FOREIGN:
|
||||||
|
{
|
||||||
|
Datum val;
|
||||||
|
bool isnull;
|
||||||
|
const char *string;
|
||||||
|
|
||||||
|
/* Start off the constraint definition */
|
||||||
|
appendStringInfo(&buf, "FOREIGN KEY (");
|
||||||
|
|
||||||
|
/* Fetch and build referencing-column list */
|
||||||
|
val = heap_getattr(tup, Anum_pg_constraint_conkey,
|
||||||
|
RelationGetDescr(conDesc), &isnull);
|
||||||
|
if (isnull)
|
||||||
|
elog(ERROR, "pg_get_constraintdef: Null conkey for constraint %u",
|
||||||
|
constraintId);
|
||||||
|
|
||||||
|
decompile_column_index_array(val, conForm->conrelid, &buf);
|
||||||
|
|
||||||
|
/* add foreign relation name */
|
||||||
|
appendStringInfo(&buf, ") REFERENCES %s(",
|
||||||
|
generate_relation_name(conForm->confrelid));
|
||||||
|
|
||||||
|
/* Fetch and build referenced-column list */
|
||||||
|
val = heap_getattr(tup, Anum_pg_constraint_confkey,
|
||||||
|
RelationGetDescr(conDesc), &isnull);
|
||||||
|
if (isnull)
|
||||||
|
elog(ERROR, "pg_get_constraintdef: Null confkey for constraint %u",
|
||||||
|
constraintId);
|
||||||
|
|
||||||
|
decompile_column_index_array(val, conForm->confrelid, &buf);
|
||||||
|
|
||||||
|
appendStringInfo(&buf, ")");
|
||||||
|
|
||||||
|
/* Add match type */
|
||||||
|
switch (conForm->confmatchtype)
|
||||||
|
{
|
||||||
|
case FKCONSTR_MATCH_FULL:
|
||||||
|
string = " MATCH FULL";
|
||||||
|
break;
|
||||||
|
case FKCONSTR_MATCH_PARTIAL:
|
||||||
|
string = " MATCH PARTIAL";
|
||||||
|
break;
|
||||||
|
case FKCONSTR_MATCH_UNSPECIFIED:
|
||||||
|
string = "";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
elog(ERROR, "pg_get_constraintdef: Unknown confmatchtype '%c' for constraint %u",
|
||||||
|
conForm->confmatchtype, constraintId);
|
||||||
|
string = ""; /* keep compiler quiet */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
appendStringInfo(&buf, "%s", string);
|
||||||
|
|
||||||
|
/* Add ON UPDATE and ON DELETE clauses */
|
||||||
|
switch (conForm->confupdtype)
|
||||||
|
{
|
||||||
|
case FKCONSTR_ACTION_NOACTION:
|
||||||
|
string = "NO ACTION";
|
||||||
|
break;
|
||||||
|
case FKCONSTR_ACTION_RESTRICT:
|
||||||
|
string = "RESTRICT";
|
||||||
|
break;
|
||||||
|
case FKCONSTR_ACTION_CASCADE:
|
||||||
|
string = "CASCADE";
|
||||||
|
break;
|
||||||
|
case FKCONSTR_ACTION_SETNULL:
|
||||||
|
string = "SET NULL";
|
||||||
|
break;
|
||||||
|
case FKCONSTR_ACTION_SETDEFAULT:
|
||||||
|
string = "SET DEFAULT";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
elog(ERROR, "pg_get_constraintdef: Unknown confupdtype '%c' for constraint %u",
|
||||||
|
conForm->confupdtype, constraintId);
|
||||||
|
string = ""; /* keep compiler quiet */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
appendStringInfo(&buf, " ON UPDATE %s", string);
|
||||||
|
|
||||||
|
switch (conForm->confdeltype)
|
||||||
|
{
|
||||||
|
case FKCONSTR_ACTION_NOACTION:
|
||||||
|
string = "NO ACTION";
|
||||||
|
break;
|
||||||
|
case FKCONSTR_ACTION_RESTRICT:
|
||||||
|
string = "RESTRICT";
|
||||||
|
break;
|
||||||
|
case FKCONSTR_ACTION_CASCADE:
|
||||||
|
string = "CASCADE";
|
||||||
|
break;
|
||||||
|
case FKCONSTR_ACTION_SETNULL:
|
||||||
|
string = "SET NULL";
|
||||||
|
break;
|
||||||
|
case FKCONSTR_ACTION_SETDEFAULT:
|
||||||
|
string = "SET DEFAULT";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
elog(ERROR, "pg_get_constraintdef: Unknown confdeltype '%c' for constraint %u",
|
||||||
|
conForm->confdeltype, constraintId);
|
||||||
|
string = ""; /* keep compiler quiet */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
appendStringInfo(&buf, " ON DELETE %s", string);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX Add more code here for other contypes
|
||||||
|
*/
|
||||||
|
default:
|
||||||
|
elog(ERROR, "pg_get_constraintdef: unsupported constraint type '%c'",
|
||||||
|
conForm->contype);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Record the results */
|
||||||
|
len = buf.len + VARHDRSZ;
|
||||||
|
result = (text *) palloc(len);
|
||||||
|
VARATT_SIZEP(result) = len;
|
||||||
|
memcpy(VARDATA(result), buf.data, buf.len);
|
||||||
|
|
||||||
|
/* Cleanup */
|
||||||
|
pfree(buf.data);
|
||||||
|
systable_endscan(conscan);
|
||||||
|
heap_close(conDesc, AccessShareLock);
|
||||||
|
|
||||||
|
PG_RETURN_TEXT_P(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert an int16[] Datum into a comma-separated list of column names
|
||||||
|
* for the indicated relation; append the list to buf.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
decompile_column_index_array(Datum column_index_array, Oid relId,
|
||||||
|
StringInfo buf)
|
||||||
|
{
|
||||||
|
Datum *keys;
|
||||||
|
int nKeys;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
/* Extract data from array of int16 */
|
||||||
|
deconstruct_array(DatumGetArrayTypeP(column_index_array),
|
||||||
|
true, 2, 's',
|
||||||
|
&keys, &nKeys);
|
||||||
|
|
||||||
|
for (j = 0; j < nKeys; j++)
|
||||||
|
{
|
||||||
|
char *colName;
|
||||||
|
|
||||||
|
colName = get_attname(relId, DatumGetInt16(keys[j]));
|
||||||
|
|
||||||
|
if (j == 0)
|
||||||
|
appendStringInfo(buf, "%s",
|
||||||
|
quote_identifier(colName));
|
||||||
|
else
|
||||||
|
appendStringInfo(buf, ", %s",
|
||||||
|
quote_identifier(colName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* get_expr - Decompile an expression tree
|
* get_expr - Decompile an expression tree
|
||||||
*
|
*
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.283 2002/08/16 21:03:42 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.284 2002/08/16 23:01:19 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -108,6 +108,7 @@ static void dumpACL(Archive *fout, const char *type, const char *name,
|
|||||||
const char *tag, const char *nspname,
|
const char *tag, const char *nspname,
|
||||||
const char *usename, const char *acl, const char *objoid);
|
const char *usename, const char *acl, const char *objoid);
|
||||||
|
|
||||||
|
static void dumpConstraints(Archive *fout, TableInfo *tblinfo, int numTables);
|
||||||
static void dumpTriggers(Archive *fout, TableInfo *tblinfo, int numTables);
|
static void dumpTriggers(Archive *fout, TableInfo *tblinfo, int numTables);
|
||||||
static void dumpRules(Archive *fout, TableInfo *tblinfo, int numTables);
|
static void dumpRules(Archive *fout, TableInfo *tblinfo, int numTables);
|
||||||
static void formatStringLiteral(PQExpBuffer buf, const char *str,
|
static void formatStringLiteral(PQExpBuffer buf, const char *str,
|
||||||
@ -608,6 +609,7 @@ main(int argc, char **argv)
|
|||||||
if (!dataOnly) /* dump indexes and triggers at the end
|
if (!dataOnly) /* dump indexes and triggers at the end
|
||||||
* for performance */
|
* for performance */
|
||||||
{
|
{
|
||||||
|
dumpConstraints(g_fout, tblinfo, numTables);
|
||||||
dumpTriggers(g_fout, tblinfo, numTables);
|
dumpTriggers(g_fout, tblinfo, numTables);
|
||||||
dumpRules(g_fout, tblinfo, numTables);
|
dumpRules(g_fout, tblinfo, numTables);
|
||||||
}
|
}
|
||||||
@ -5814,6 +5816,117 @@ dumpOneSequence(Archive *fout, TableInfo *tbinfo,
|
|||||||
destroyPQExpBuffer(delqry);
|
destroyPQExpBuffer(delqry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dumpConstraints
|
||||||
|
*
|
||||||
|
* Dump out constraints after all table creation statements in
|
||||||
|
* an alter table format. Currently handles foreign keys only.
|
||||||
|
*
|
||||||
|
* XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that
|
||||||
|
* the current table data is not processed
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
dumpConstraints(Archive *fout, TableInfo *tblinfo, int numTables)
|
||||||
|
{
|
||||||
|
int i,
|
||||||
|
j;
|
||||||
|
PQExpBuffer query;
|
||||||
|
PQExpBuffer delqry;
|
||||||
|
PGresult *res;
|
||||||
|
int i_condef,
|
||||||
|
i_conoid,
|
||||||
|
i_conname;
|
||||||
|
int ntups;
|
||||||
|
|
||||||
|
/* pg_constraint was created in 7.3, so nothing to do if older */
|
||||||
|
if (g_fout->remoteVersion < 70300)
|
||||||
|
return;
|
||||||
|
|
||||||
|
query = createPQExpBuffer();
|
||||||
|
delqry = createPQExpBuffer();
|
||||||
|
|
||||||
|
for (i = 0; i < numTables; i++)
|
||||||
|
{
|
||||||
|
TableInfo *tbinfo = &tblinfo[i];
|
||||||
|
|
||||||
|
if (tbinfo->ntrig == 0 || !tbinfo->dump)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (g_verbose)
|
||||||
|
write_msg(NULL, "dumping triggers for table %s\n",
|
||||||
|
tbinfo->relname);
|
||||||
|
|
||||||
|
/* select table schema to ensure regproc name is qualified if needed */
|
||||||
|
selectSourceSchema(tbinfo->relnamespace->nspname);
|
||||||
|
|
||||||
|
resetPQExpBuffer(query);
|
||||||
|
appendPQExpBuffer(query,
|
||||||
|
"SELECT oid, conname, "
|
||||||
|
"pg_catalog.pg_get_constraintdef(oid) as condef "
|
||||||
|
"FROM pg_catalog.pg_constraint "
|
||||||
|
"WHERE conrelid = '%s'::pg_catalog.oid "
|
||||||
|
"AND contype = 'f'",
|
||||||
|
tbinfo->oid);
|
||||||
|
res = PQexec(g_conn, query->data);
|
||||||
|
if (!res ||
|
||||||
|
PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
|
{
|
||||||
|
write_msg(NULL, "query to obtain list of foreign key definitions failed: %s", PQerrorMessage(g_conn));
|
||||||
|
exit_nicely();
|
||||||
|
}
|
||||||
|
ntups = PQntuples(res);
|
||||||
|
|
||||||
|
i_conoid = PQfnumber(res, "oid");
|
||||||
|
i_conname = PQfnumber(res, "conname");
|
||||||
|
i_condef = PQfnumber(res, "condef");
|
||||||
|
|
||||||
|
for (j = 0; j < ntups; j++)
|
||||||
|
{
|
||||||
|
const char *conOid = PQgetvalue(res, j, i_conoid);
|
||||||
|
const char *conName = PQgetvalue(res, j, i_conname);
|
||||||
|
const char *conDef = PQgetvalue(res, j, i_condef);
|
||||||
|
|
||||||
|
resetPQExpBuffer(query);
|
||||||
|
appendPQExpBuffer(query, "ALTER TABLE ONLY %s ",
|
||||||
|
fmtId(tbinfo->relname, force_quotes));
|
||||||
|
appendPQExpBuffer(query, "ADD CONSTRAINT %s %s;\n",
|
||||||
|
fmtId(conName, force_quotes),
|
||||||
|
conDef);
|
||||||
|
|
||||||
|
/* DROP must be fully qualified in case same name appears in pg_catalog */
|
||||||
|
resetPQExpBuffer(delqry);
|
||||||
|
appendPQExpBuffer(delqry, "ALTER TABLE ONLY %s.",
|
||||||
|
fmtId(tbinfo->relnamespace->nspname, force_quotes));
|
||||||
|
appendPQExpBuffer(delqry, "%s ",
|
||||||
|
fmtId(tbinfo->relname, force_quotes));
|
||||||
|
appendPQExpBuffer(delqry, "DROP CONSTRAINT %s;\n",
|
||||||
|
fmtId(conName, force_quotes));
|
||||||
|
|
||||||
|
ArchiveEntry(fout, conOid,
|
||||||
|
conName,
|
||||||
|
tbinfo->relnamespace->nspname,
|
||||||
|
tbinfo->usename,
|
||||||
|
"CONSTRAINT", NULL,
|
||||||
|
query->data, delqry->data,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
|
||||||
|
resetPQExpBuffer(query);
|
||||||
|
appendPQExpBuffer(query, "CONSTRAINT %s ",
|
||||||
|
fmtId(conName, force_quotes));
|
||||||
|
appendPQExpBuffer(query, "ON %s",
|
||||||
|
fmtId(tbinfo->relname, force_quotes));
|
||||||
|
|
||||||
|
dumpComment(fout, query->data,
|
||||||
|
tbinfo->relnamespace->nspname, tbinfo->usename,
|
||||||
|
conOid, "pg_constraint", 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
PQclear(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
destroyPQExpBuffer(query);
|
||||||
|
destroyPQExpBuffer(delqry);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dumpTriggers(Archive *fout, TableInfo *tblinfo, int numTables)
|
dumpTriggers(Archive *fout, TableInfo *tblinfo, int numTables)
|
||||||
@ -5854,6 +5967,7 @@ dumpTriggers(Archive *fout, TableInfo *tblinfo, int numTables)
|
|||||||
resetPQExpBuffer(query);
|
resetPQExpBuffer(query);
|
||||||
if (g_fout->remoteVersion >= 70300)
|
if (g_fout->remoteVersion >= 70300)
|
||||||
{
|
{
|
||||||
|
/* We ignore triggers that are tied to a foreign-key constraint */
|
||||||
appendPQExpBuffer(query,
|
appendPQExpBuffer(query,
|
||||||
"SELECT tgname, "
|
"SELECT tgname, "
|
||||||
"tgfoid::pg_catalog.regproc as tgfname, "
|
"tgfoid::pg_catalog.regproc as tgfname, "
|
||||||
@ -5861,8 +5975,13 @@ dumpTriggers(Archive *fout, TableInfo *tblinfo, int numTables)
|
|||||||
"tgisconstraint, tgconstrname, tgdeferrable, "
|
"tgisconstraint, tgconstrname, tgdeferrable, "
|
||||||
"tgconstrrelid, tginitdeferred, oid, "
|
"tgconstrrelid, tginitdeferred, oid, "
|
||||||
"tgconstrrelid::pg_catalog.regclass as tgconstrrelname "
|
"tgconstrrelid::pg_catalog.regclass as tgconstrrelname "
|
||||||
"from pg_catalog.pg_trigger "
|
"from pg_catalog.pg_trigger t "
|
||||||
"where tgrelid = '%s'::pg_catalog.oid",
|
"where tgrelid = '%s'::pg_catalog.oid "
|
||||||
|
"and (not tgisconstraint "
|
||||||
|
" OR NOT EXISTS"
|
||||||
|
" (SELECT 1 FROM pg_catalog.pg_depend d "
|
||||||
|
" JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
|
||||||
|
" WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
|
||||||
tbinfo->oid);
|
tbinfo->oid);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -5886,7 +6005,11 @@ dumpTriggers(Archive *fout, TableInfo *tblinfo, int numTables)
|
|||||||
exit_nicely();
|
exit_nicely();
|
||||||
}
|
}
|
||||||
ntups = PQntuples(res);
|
ntups = PQntuples(res);
|
||||||
if (ntups != tbinfo->ntrig)
|
/*
|
||||||
|
* We may have less triggers than recorded due to constraint triggers
|
||||||
|
* which are dumped by dumpConstraints
|
||||||
|
*/
|
||||||
|
if (ntups > tbinfo->ntrig)
|
||||||
{
|
{
|
||||||
write_msg(NULL, "expected %d triggers on table \"%s\" but found %d\n",
|
write_msg(NULL, "expected %d triggers on table \"%s\" but found %d\n",
|
||||||
tbinfo->ntrig, tbinfo->relname, ntups);
|
tbinfo->ntrig, tbinfo->relname, ntups);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright 2000-2002 by PostgreSQL Global Development Group
|
* Copyright 2000-2002 by PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.61 2002/08/15 16:36:06 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.62 2002/08/16 23:01:19 tgl Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
#include "describe.h"
|
#include "describe.h"
|
||||||
@ -914,9 +914,11 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
PGresult *result1 = NULL,
|
PGresult *result1 = NULL,
|
||||||
*result2 = NULL,
|
*result2 = NULL,
|
||||||
*result3 = NULL,
|
*result3 = NULL,
|
||||||
*result4 = NULL;
|
*result4 = NULL,
|
||||||
int index_count = 0,
|
*result5 = NULL;
|
||||||
check_count = 0,
|
int check_count = 0,
|
||||||
|
index_count = 0,
|
||||||
|
foreignkey_count = 0,
|
||||||
rule_count = 0,
|
rule_count = 0,
|
||||||
trigger_count = 0;
|
trigger_count = 0;
|
||||||
int count_footers = 0;
|
int count_footers = 0;
|
||||||
@ -968,13 +970,18 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
rule_count = PQntuples(result3);
|
rule_count = PQntuples(result3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* count triggers */
|
/* count triggers (but ignore foreign-key triggers) */
|
||||||
if (tableinfo.triggers)
|
if (tableinfo.triggers)
|
||||||
{
|
{
|
||||||
printfPQExpBuffer(&buf,
|
printfPQExpBuffer(&buf,
|
||||||
"SELECT t.tgname\n"
|
"SELECT t.tgname\n"
|
||||||
"FROM pg_catalog.pg_trigger t\n"
|
"FROM pg_catalog.pg_trigger t\n"
|
||||||
"WHERE t.tgrelid = '%s'",
|
"WHERE t.tgrelid = '%s' "
|
||||||
|
"and (not tgisconstraint "
|
||||||
|
" OR NOT EXISTS"
|
||||||
|
" (SELECT 1 FROM pg_catalog.pg_depend d "
|
||||||
|
" JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
|
||||||
|
" WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
|
||||||
oid);
|
oid);
|
||||||
result4 = PSQLexec(buf.data);
|
result4 = PSQLexec(buf.data);
|
||||||
if (!result4)
|
if (!result4)
|
||||||
@ -983,7 +990,23 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
trigger_count = PQntuples(result4);
|
trigger_count = PQntuples(result4);
|
||||||
}
|
}
|
||||||
|
|
||||||
footers = xmalloc((index_count + check_count + rule_count + trigger_count + 1)
|
/* count foreign-key constraints (there are none if no triggers) */
|
||||||
|
if (tableinfo.triggers)
|
||||||
|
{
|
||||||
|
printfPQExpBuffer(&buf,
|
||||||
|
"SELECT conname,\n"
|
||||||
|
" pg_catalog.pg_get_constraintdef(oid) as condef\n"
|
||||||
|
"FROM pg_catalog.pg_constraint r\n"
|
||||||
|
"WHERE r.conrelid = '%s' AND r.contype = 'f'",
|
||||||
|
oid);
|
||||||
|
result5 = PSQLexec(buf.data);
|
||||||
|
if (!result5)
|
||||||
|
goto error_return;
|
||||||
|
else
|
||||||
|
foreignkey_count = PQntuples(result5);
|
||||||
|
}
|
||||||
|
|
||||||
|
footers = xmalloc((index_count + check_count + rule_count + trigger_count + foreignkey_count + 1)
|
||||||
* sizeof(*footers));
|
* sizeof(*footers));
|
||||||
|
|
||||||
/* print indexes */
|
/* print indexes */
|
||||||
@ -1041,6 +1064,27 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
footers[count_footers++] = xstrdup(buf.data);
|
footers[count_footers++] = xstrdup(buf.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* print foreign key constraints */
|
||||||
|
for (i = 0; i < foreignkey_count; i++)
|
||||||
|
{
|
||||||
|
char *s = _("Foreign Key constraints");
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
printfPQExpBuffer(&buf, _("%s: %s %s"),
|
||||||
|
s,
|
||||||
|
PQgetvalue(result5, i, 0),
|
||||||
|
PQgetvalue(result5, i, 1));
|
||||||
|
else
|
||||||
|
printfPQExpBuffer(&buf, _("%*s %s %s"),
|
||||||
|
(int) strlen(s), "",
|
||||||
|
PQgetvalue(result5, i, 0),
|
||||||
|
PQgetvalue(result5, i, 1));
|
||||||
|
if (i < foreignkey_count - 1)
|
||||||
|
appendPQExpBuffer(&buf, ",");
|
||||||
|
|
||||||
|
footers[count_footers++] = xstrdup(buf.data);
|
||||||
|
}
|
||||||
|
|
||||||
/* print rules */
|
/* print rules */
|
||||||
for (i = 0; i < rule_count; i++)
|
for (i = 0; i < rule_count; i++)
|
||||||
{
|
{
|
||||||
@ -1078,6 +1122,7 @@ describeOneTableDetails(const char *schemaname,
|
|||||||
PQclear(result2);
|
PQclear(result2);
|
||||||
PQclear(result3);
|
PQclear(result3);
|
||||||
PQclear(result4);
|
PQclear(result4);
|
||||||
|
PQclear(result5);
|
||||||
}
|
}
|
||||||
|
|
||||||
printTable(title.data, headers,
|
printTable(title.data, headers,
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, 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: catversion.h,v 1.148 2002/08/13 20:40:44 momjian Exp $
|
* $Id: catversion.h,v 1.149 2002/08/16 23:01:20 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 200208131
|
#define CATALOG_VERSION_NO 200208161
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, 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_proc.h,v 1.254 2002/08/15 02:51:27 momjian Exp $
|
* $Id: pg_proc.h,v 1.255 2002/08/16 23:01:20 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The script catalog/genbki.sh reads this file and generates .bki
|
* The script catalog/genbki.sh reads this file and generates .bki
|
||||||
@ -2174,6 +2174,8 @@ DATA(insert OID = 1642 ( pg_get_userbyid PGNSP PGUID 12 f f t f s 1 19 "23"
|
|||||||
DESCR("user name by UID (with fallback)");
|
DESCR("user name by UID (with fallback)");
|
||||||
DATA(insert OID = 1643 ( pg_get_indexdef PGNSP PGUID 12 f f t f s 1 25 "26" pg_get_indexdef - _null_ ));
|
DATA(insert OID = 1643 ( pg_get_indexdef PGNSP PGUID 12 f f t f s 1 25 "26" pg_get_indexdef - _null_ ));
|
||||||
DESCR("index description");
|
DESCR("index description");
|
||||||
|
DATA(insert OID = 1387 ( pg_get_constraintdef PGNSP PGUID 12 f f t f s 1 25 "26" pg_get_constraintdef - _null_ ));
|
||||||
|
DESCR("constraint description");
|
||||||
DATA(insert OID = 1716 ( pg_get_expr PGNSP PGUID 12 f f t f s 2 25 "25 26" pg_get_expr - _null_ ));
|
DATA(insert OID = 1716 ( pg_get_expr PGNSP PGUID 12 f f t f s 2 25 "25 26" pg_get_expr - _null_ ));
|
||||||
DESCR("deparse an encoded expression");
|
DESCR("deparse an encoded expression");
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, 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: builtins.h,v 1.191 2002/08/15 02:51:27 momjian Exp $
|
* $Id: builtins.h,v 1.192 2002/08/16 23:01:21 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -375,6 +375,7 @@ extern Datum pg_get_ruledef(PG_FUNCTION_ARGS);
|
|||||||
extern Datum pg_get_viewdef(PG_FUNCTION_ARGS);
|
extern Datum pg_get_viewdef(PG_FUNCTION_ARGS);
|
||||||
extern Datum pg_get_viewdef_name(PG_FUNCTION_ARGS);
|
extern Datum pg_get_viewdef_name(PG_FUNCTION_ARGS);
|
||||||
extern Datum pg_get_indexdef(PG_FUNCTION_ARGS);
|
extern Datum pg_get_indexdef(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum pg_get_constraintdef(PG_FUNCTION_ARGS);
|
||||||
extern Datum pg_get_userbyid(PG_FUNCTION_ARGS);
|
extern Datum pg_get_userbyid(PG_FUNCTION_ARGS);
|
||||||
extern Datum pg_get_expr(PG_FUNCTION_ARGS);
|
extern Datum pg_get_expr(PG_FUNCTION_ARGS);
|
||||||
extern char *deparse_expression(Node *expr, List *dpcontext,
|
extern char *deparse_expression(Node *expr, List *dpcontext,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user