mirror of
https://github.com/postgres/postgres.git
synced 2025-11-09 06:21:09 +03:00
pg_type has a typnamespace column; system now supports creating types
in different namespaces. Also, cleanup work on relation namespace support: drop, alter, rename commands work for tables in non-default namespaces.
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.73 2002/03/26 19:15:35 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.74 2002/03/29 19:06:03 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -129,7 +129,7 @@ cluster(RangeVar *oldrelation, char *oldindexname)
|
||||
CommandCounterIncrement();
|
||||
|
||||
/* Destroy old heap (along with its index) and rename new. */
|
||||
heap_drop_with_catalog(saveoldrelation->relname, allowSystemTableMods);
|
||||
heap_drop_with_catalog(OIDOldHeap, allowSystemTableMods);
|
||||
|
||||
CommandCounterIncrement();
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.166 2002/03/26 19:15:36 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.167 2002/03/29 19:06:03 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* The PerformAddAttribute() code, like most of the relation
|
||||
@@ -42,11 +42,12 @@
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/planmain.h"
|
||||
#include "optimizer/prep.h"
|
||||
#include "parser/analyze.h"
|
||||
#include "parser/parse.h"
|
||||
#include "parser/parse_expr.h"
|
||||
#include "parser/parse_oper.h"
|
||||
#include "parser/parse_relation.h"
|
||||
#include "parser/analyze.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "tcop/utility.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
@@ -58,9 +59,9 @@
|
||||
|
||||
static void drop_default(Oid relid, int16 attnum);
|
||||
static bool needs_toast_table(Relation rel);
|
||||
static void AlterTableOwnerId(Oid relationOid, int32 newOwnerSysId);
|
||||
static void CheckTupleType(Form_pg_class tuple_class);
|
||||
|
||||
|
||||
/* --------------------------------
|
||||
* PortalCleanup
|
||||
* --------------------------------
|
||||
@@ -309,13 +310,13 @@ PerformPortalClose(char *name, CommandDest dest)
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
AlterTableAddColumn(const char *relationName,
|
||||
AlterTableAddColumn(Oid myrelid,
|
||||
bool inherits,
|
||||
ColumnDef *colDef)
|
||||
{
|
||||
Relation rel,
|
||||
pgclass,
|
||||
attrdesc;
|
||||
Oid myrelid;
|
||||
HeapTuple reltup;
|
||||
HeapTuple newreltup;
|
||||
HeapTuple attributeTuple;
|
||||
@@ -326,19 +327,17 @@ AlterTableAddColumn(const char *relationName,
|
||||
maxatts;
|
||||
HeapTuple typeTuple;
|
||||
Form_pg_type tform;
|
||||
char *typename;
|
||||
int attndims;
|
||||
|
||||
/*
|
||||
* Grab an exclusive lock on the target table, which we will NOT
|
||||
* release until end of transaction.
|
||||
*/
|
||||
rel = heap_openr(relationName, AccessExclusiveLock);
|
||||
myrelid = RelationGetRelid(rel);
|
||||
rel = heap_open(myrelid, AccessExclusiveLock);
|
||||
|
||||
if (rel->rd_rel->relkind != RELKIND_RELATION)
|
||||
elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table",
|
||||
relationName);
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
/*
|
||||
* permissions checking. this would normally be done in utility.c,
|
||||
@@ -346,13 +345,13 @@ AlterTableAddColumn(const char *relationName,
|
||||
*
|
||||
* normally, only the owner of a class can change its schema.
|
||||
*/
|
||||
if (!allowSystemTableMods && IsSystemRelationName(relationName))
|
||||
if (!allowSystemTableMods
|
||||
&& IsSystemRelationName(RelationGetRelationName(rel)))
|
||||
elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
|
||||
relationName);
|
||||
RelationGetRelationName(rel));
|
||||
if (!pg_class_ownercheck(myrelid, GetUserId()))
|
||||
elog(ERROR, "ALTER TABLE: permission denied");
|
||||
|
||||
heap_close(rel, NoLock); /* close rel but keep lock! */
|
||||
elog(ERROR, "ALTER TABLE: \"%s\": permission denied",
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
/*
|
||||
* Recurse to add the column to child classes, if requested.
|
||||
@@ -377,17 +376,11 @@ AlterTableAddColumn(const char *relationName,
|
||||
foreach(child, children)
|
||||
{
|
||||
Oid childrelid = lfirsti(child);
|
||||
char *childrelname;
|
||||
|
||||
if (childrelid == myrelid)
|
||||
continue;
|
||||
rel = heap_open(childrelid, AccessExclusiveLock);
|
||||
childrelname = pstrdup(RelationGetRelationName(rel));
|
||||
heap_close(rel, AccessExclusiveLock);
|
||||
|
||||
AlterTableAddColumn(childrelname, false, colDef);
|
||||
|
||||
pfree(childrelname);
|
||||
AlterTableAddColumn(childrelid, false, colDef);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,23 +405,21 @@ AlterTableAddColumn(const char *relationName,
|
||||
elog(ERROR, "Adding NOT NULL columns is not implemented."
|
||||
"\n\tAdd the column, then use ALTER TABLE ADD CONSTRAINT.");
|
||||
|
||||
|
||||
rel = heap_openr(RelationRelationName, RowExclusiveLock);
|
||||
pgclass = heap_openr(RelationRelationName, RowExclusiveLock);
|
||||
|
||||
reltup = SearchSysCache(RELOID,
|
||||
ObjectIdGetDatum(myrelid),
|
||||
0, 0, 0);
|
||||
|
||||
if (!HeapTupleIsValid(reltup))
|
||||
elog(ERROR, "ALTER TABLE: relation \"%s\" not found",
|
||||
relationName);
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
if (SearchSysCacheExists(ATTNAME,
|
||||
ObjectIdGetDatum(myrelid),
|
||||
PointerGetDatum(colDef->colname),
|
||||
0, 0))
|
||||
elog(ERROR, "ALTER TABLE: column name \"%s\" already exists in table \"%s\"",
|
||||
colDef->colname, relationName);
|
||||
colDef->colname, RelationGetRelationName(rel));
|
||||
|
||||
minattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts;
|
||||
maxatts = minattnum + 1;
|
||||
@@ -440,21 +431,11 @@ AlterTableAddColumn(const char *relationName,
|
||||
attrdesc = heap_openr(AttributeRelationName, RowExclusiveLock);
|
||||
|
||||
if (colDef->typename->arrayBounds)
|
||||
{
|
||||
attndims = length(colDef->typename->arrayBounds);
|
||||
typename = makeArrayTypeName(colDef->typename->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
attndims = 0;
|
||||
typename = colDef->typename->name;
|
||||
}
|
||||
|
||||
typeTuple = SearchSysCache(TYPENAME,
|
||||
PointerGetDatum(typename),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(typeTuple))
|
||||
elog(ERROR, "ALTER TABLE: type \"%s\" does not exist", typename);
|
||||
typeTuple = typenameType(colDef->typename);
|
||||
tform = (Form_pg_type) GETSTRUCT(typeTuple);
|
||||
|
||||
attributeTuple = heap_addheader(Natts_pg_attribute,
|
||||
@@ -494,7 +475,7 @@ AlterTableAddColumn(const char *relationName,
|
||||
CatalogCloseIndices(Num_pg_attr_indices, idescs);
|
||||
}
|
||||
|
||||
heap_close(attrdesc, NoLock);
|
||||
heap_close(attrdesc, RowExclusiveLock);
|
||||
|
||||
/*
|
||||
* Update number of attributes in pg_class tuple
|
||||
@@ -502,22 +483,24 @@ AlterTableAddColumn(const char *relationName,
|
||||
newreltup = heap_copytuple(reltup);
|
||||
|
||||
((Form_pg_class) GETSTRUCT(newreltup))->relnatts = maxatts;
|
||||
simple_heap_update(rel, &newreltup->t_self, newreltup);
|
||||
simple_heap_update(pgclass, &newreltup->t_self, newreltup);
|
||||
|
||||
/* keep catalog indices current */
|
||||
if (RelationGetForm(rel)->relhasindex)
|
||||
if (RelationGetForm(pgclass)->relhasindex)
|
||||
{
|
||||
Relation ridescs[Num_pg_class_indices];
|
||||
|
||||
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
|
||||
CatalogIndexInsert(ridescs, Num_pg_class_indices, rel, newreltup);
|
||||
CatalogIndexInsert(ridescs, Num_pg_class_indices, pgclass, newreltup);
|
||||
CatalogCloseIndices(Num_pg_class_indices, ridescs);
|
||||
}
|
||||
|
||||
heap_freetuple(newreltup);
|
||||
ReleaseSysCache(reltup);
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
heap_close(pgclass, NoLock);
|
||||
|
||||
heap_close(rel, NoLock); /* close rel but keep lock! */
|
||||
|
||||
/*
|
||||
* Make our catalog updates visible for subsequent steps.
|
||||
@@ -549,29 +532,28 @@ AlterTableAddColumn(const char *relationName,
|
||||
* ALTER TABLE ALTER COLUMN SET/DROP DEFAULT
|
||||
*/
|
||||
void
|
||||
AlterTableAlterColumnDefault(const char *relationName,
|
||||
AlterTableAlterColumnDefault(Oid myrelid,
|
||||
bool inh, const char *colName,
|
||||
Node *newDefault)
|
||||
{
|
||||
Relation rel;
|
||||
HeapTuple tuple;
|
||||
int16 attnum;
|
||||
Oid myrelid;
|
||||
|
||||
rel = heap_openr(relationName, AccessExclusiveLock);
|
||||
myrelid = RelationGetRelid(rel);
|
||||
rel = heap_open(myrelid, AccessExclusiveLock);
|
||||
|
||||
if (rel->rd_rel->relkind != RELKIND_RELATION)
|
||||
elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table",
|
||||
relationName);
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
if (!allowSystemTableMods && IsSystemRelationName(relationName))
|
||||
if (!allowSystemTableMods
|
||||
&& IsSystemRelationName(RelationGetRelationName(rel)))
|
||||
elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
|
||||
relationName);
|
||||
if (!pg_class_ownercheck(myrelid, GetUserId()))
|
||||
elog(ERROR, "ALTER TABLE: permission denied");
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
if (!pg_class_ownercheck(myrelid, GetUserId()))
|
||||
elog(ERROR, "ALTER TABLE: \"%s\" permission denied",
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
/*
|
||||
* Propagate to children if desired
|
||||
@@ -595,18 +577,13 @@ AlterTableAlterColumnDefault(const char *relationName,
|
||||
|
||||
if (childrelid == myrelid)
|
||||
continue;
|
||||
rel = heap_open(childrelid, AccessExclusiveLock);
|
||||
AlterTableAlterColumnDefault(RelationGetRelationName(rel),
|
||||
AlterTableAlterColumnDefault(childrelid,
|
||||
false, colName, newDefault);
|
||||
heap_close(rel, AccessExclusiveLock);
|
||||
}
|
||||
}
|
||||
|
||||
/* -= now do the thing on this relation =- */
|
||||
|
||||
/* reopen the business */
|
||||
rel = heap_openr(relationName, AccessExclusiveLock);
|
||||
|
||||
/*
|
||||
* get the number of the attribute
|
||||
*/
|
||||
@@ -616,7 +593,7 @@ AlterTableAlterColumnDefault(const char *relationName,
|
||||
0, 0);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"",
|
||||
relationName, colName);
|
||||
RelationGetRelationName(rel), colName);
|
||||
|
||||
attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
|
||||
ReleaseSysCache(tuple);
|
||||
@@ -718,43 +695,42 @@ drop_default(Oid relid, int16 attnum)
|
||||
* ALTER TABLE ALTER COLUMN SET STATISTICS / STORAGE
|
||||
*/
|
||||
void
|
||||
AlterTableAlterColumnFlags(const char *relationName,
|
||||
AlterTableAlterColumnFlags(Oid myrelid,
|
||||
bool inh, const char *colName,
|
||||
Node *flagValue, const char *flagType)
|
||||
{
|
||||
Relation rel;
|
||||
Oid myrelid;
|
||||
int newtarget = 1;
|
||||
char newstorage = 'x';
|
||||
char *storagemode;
|
||||
Relation attrelation;
|
||||
HeapTuple tuple;
|
||||
|
||||
rel = heap_openr(relationName, AccessExclusiveLock);
|
||||
myrelid = RelationGetRelid(rel);
|
||||
rel = heap_open(myrelid, AccessExclusiveLock);
|
||||
|
||||
if (rel->rd_rel->relkind != RELKIND_RELATION)
|
||||
elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table",
|
||||
relationName);
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
/* we allow statistics case for system tables */
|
||||
if (*flagType == 'M' &&
|
||||
!allowSystemTableMods && IsSystemRelationName(relationName))
|
||||
/*
|
||||
* we allow statistics case for system tables
|
||||
*/
|
||||
if (*flagType != 'S' &&
|
||||
!allowSystemTableMods
|
||||
&& IsSystemRelationName(RelationGetRelationName(rel)))
|
||||
elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
|
||||
relationName);
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
if (!pg_class_ownercheck(myrelid, GetUserId()))
|
||||
elog(ERROR, "ALTER TABLE: permission denied");
|
||||
|
||||
heap_close(rel, NoLock); /* close rel, but keep lock! */
|
||||
|
||||
elog(ERROR, "ALTER TABLE: \"%s\" permission denied",
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
/*
|
||||
* Check the supplied parameters before anything else
|
||||
*/
|
||||
if (*flagType == 'S') /*
|
||||
* STATISTICS
|
||||
*/
|
||||
if (*flagType == 'S')
|
||||
{
|
||||
/* STATISTICS */
|
||||
Assert(IsA(flagValue, Integer));
|
||||
newtarget = intVal(flagValue);
|
||||
|
||||
@@ -766,10 +742,9 @@ AlterTableAlterColumnFlags(const char *relationName,
|
||||
else if (newtarget > 1000)
|
||||
newtarget = 1000;
|
||||
}
|
||||
else if (*flagType == 'M') /*
|
||||
* STORAGE
|
||||
*/
|
||||
else if (*flagType == 'M')
|
||||
{
|
||||
/* STORAGE */
|
||||
Assert(IsA(flagValue, Value));
|
||||
|
||||
storagemode = strVal(flagValue);
|
||||
@@ -813,10 +788,8 @@ AlterTableAlterColumnFlags(const char *relationName,
|
||||
|
||||
if (childrelid == myrelid)
|
||||
continue;
|
||||
rel = heap_open(childrelid, AccessExclusiveLock);
|
||||
AlterTableAlterColumnFlags(RelationGetRelationName(rel),
|
||||
false, colName, flagValue, flagType);
|
||||
heap_close(rel, AccessExclusiveLock);
|
||||
AlterTableAlterColumnFlags(childrelid,
|
||||
false, colName, flagValue, flagType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -830,7 +803,7 @@ AlterTableAlterColumnFlags(const char *relationName,
|
||||
0, 0);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"",
|
||||
relationName, colName);
|
||||
RelationGetRelationName(rel), colName);
|
||||
|
||||
if (((Form_pg_attribute) GETSTRUCT(tuple))->attnum < 0)
|
||||
elog(ERROR, "ALTER TABLE: cannot change system attribute \"%s\"",
|
||||
@@ -864,6 +837,7 @@ AlterTableAlterColumnFlags(const char *relationName,
|
||||
|
||||
heap_freetuple(tuple);
|
||||
heap_close(attrelation, NoLock);
|
||||
heap_close(rel, NoLock); /* close rel, but keep lock! */
|
||||
}
|
||||
|
||||
|
||||
@@ -1006,14 +980,13 @@ RemoveColumnReferences(Oid reloid, int attnum, bool checkonly, HeapTuple reltup)
|
||||
* ALTER TABLE DROP COLUMN
|
||||
*/
|
||||
void
|
||||
AlterTableDropColumn(const char *relationName,
|
||||
AlterTableDropColumn(Oid myrelid,
|
||||
bool inh, const char *colName,
|
||||
int behavior)
|
||||
{
|
||||
#ifdef _DROP_COLUMN_HACK__
|
||||
Relation rel,
|
||||
attrdesc;
|
||||
Oid myrelid;
|
||||
HeapTuple reltup;
|
||||
HeapTupleData classtuple;
|
||||
Buffer buffer;
|
||||
@@ -1031,12 +1004,16 @@ AlterTableDropColumn(const char *relationName,
|
||||
* Grab an exclusive lock on the target table, which we will NOT
|
||||
* release until end of transaction.
|
||||
*/
|
||||
rel = heap_openr(relationName, AccessExclusiveLock);
|
||||
myrelid = RelationGetRelid(rel);
|
||||
rel = heap_open(myrelid, AccessExclusiveLock);
|
||||
|
||||
if (rel->rd_rel->relkind != RELKIND_RELATION)
|
||||
elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table",
|
||||
relationName);
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
if (!allowSystemTableMods
|
||||
&& IsSystemRelationName(RelationGetRelationName(rel))
|
||||
elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
/*
|
||||
* permissions checking. this would normally be done in utility.c,
|
||||
@@ -1044,9 +1021,6 @@ AlterTableDropColumn(const char *relationName,
|
||||
*
|
||||
* normally, only the owner of a class can change its schema.
|
||||
*/
|
||||
if (!allowSystemTableMods && IsSystemRelationName(relationName))
|
||||
elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
|
||||
relationName);
|
||||
if (!pg_class_ownercheck(myrelid, GetUserId()))
|
||||
elog(ERROR, "ALTER TABLE: permission denied");
|
||||
|
||||
@@ -1066,8 +1040,17 @@ AlterTableDropColumn(const char *relationName,
|
||||
ObjectIdGetDatum(myrelid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(reltup))
|
||||
{
|
||||
Relation myrel;
|
||||
char *myrelname;
|
||||
|
||||
myrel = heap_open(myrelid, AccessExclusiveLock);
|
||||
myrelname = pstrdup(RelationGetRelationName(myrel));
|
||||
heap_close(myrel, AccessExclusiveLock);
|
||||
|
||||
elog(ERROR, "ALTER TABLE: relation \"%s\" not found",
|
||||
relationName);
|
||||
myrelname);
|
||||
}
|
||||
classtuple.t_self = reltup->t_self;
|
||||
ReleaseSysCache(reltup);
|
||||
|
||||
@@ -1092,8 +1075,17 @@ AlterTableDropColumn(const char *relationName,
|
||||
PointerGetDatum(colName),
|
||||
0, 0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
{
|
||||
Relation myrel;
|
||||
char *myrelname;
|
||||
|
||||
myrel = heap_open(myrelid, AccessExclusiveLock);
|
||||
myrelname = pstrdup(RelationGetRelationName(myrel));
|
||||
heap_close(myrel, AccessExclusiveLock);
|
||||
|
||||
elog(ERROR, "ALTER TABLE: column name \"%s\" doesn't exist in table \"%s\"",
|
||||
colName, relationName);
|
||||
colName, myrelname);
|
||||
}
|
||||
|
||||
attribute = (Form_pg_attribute) GETSTRUCT(tup);
|
||||
attnum = attribute->attnum;
|
||||
@@ -1164,29 +1156,30 @@ AlterTableDropColumn(const char *relationName,
|
||||
* ALTER TABLE ADD CONSTRAINT
|
||||
*/
|
||||
void
|
||||
AlterTableAddConstraint(char *relationName,
|
||||
AlterTableAddConstraint(Oid myrelid,
|
||||
bool inh, List *newConstraints)
|
||||
{
|
||||
Relation rel;
|
||||
Oid myrelid;
|
||||
List *listptr;
|
||||
|
||||
/*
|
||||
* Grab an exclusive lock on the target table, which we will NOT
|
||||
* release until end of transaction.
|
||||
*/
|
||||
rel = heap_openr(relationName, AccessExclusiveLock);
|
||||
myrelid = RelationGetRelid(rel);
|
||||
rel = heap_open(myrelid, AccessExclusiveLock);
|
||||
|
||||
if (rel->rd_rel->relkind != RELKIND_RELATION)
|
||||
elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table",
|
||||
relationName);
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
if (!allowSystemTableMods && IsSystemRelationName(relationName))
|
||||
if (!allowSystemTableMods
|
||||
&& IsSystemRelationName(RelationGetRelationName(rel)))
|
||||
elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
|
||||
relationName);
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
if (!pg_class_ownercheck(myrelid, GetUserId()))
|
||||
elog(ERROR, "ALTER TABLE: permission denied");
|
||||
elog(ERROR, "ALTER TABLE: \"%s\": permission denied",
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
if (inh)
|
||||
{
|
||||
@@ -1204,16 +1197,10 @@ AlterTableAddConstraint(char *relationName,
|
||||
foreach(child, children)
|
||||
{
|
||||
Oid childrelid = lfirsti(child);
|
||||
char *childrelname;
|
||||
Relation childrel;
|
||||
|
||||
if (childrelid == myrelid)
|
||||
continue;
|
||||
childrel = heap_open(childrelid, AccessExclusiveLock);
|
||||
childrelname = pstrdup(RelationGetRelationName(childrel));
|
||||
heap_close(childrel, AccessExclusiveLock);
|
||||
AlterTableAddConstraint(childrelname, false, newConstraints);
|
||||
pfree(childrelname);
|
||||
AlterTableAddConstraint(childrelid, false, newConstraints);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1262,7 +1249,7 @@ AlterTableAddConstraint(char *relationName,
|
||||
pstate = make_parsestate(NULL);
|
||||
rte = addRangeTableEntryForRelation(pstate,
|
||||
myrelid,
|
||||
makeAlias(relationName, NIL),
|
||||
makeAlias(RelationGetRelationName(rel), NIL),
|
||||
false,
|
||||
true);
|
||||
addRTEtoQuery(pstate, rte, true, true);
|
||||
@@ -1286,7 +1273,7 @@ AlterTableAddConstraint(char *relationName,
|
||||
*/
|
||||
if (length(pstate->p_rtable) != 1)
|
||||
elog(ERROR, "Only relation '%s' can be referenced in CHECK",
|
||||
relationName);
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
/*
|
||||
* Might as well try to reduce any
|
||||
@@ -1358,7 +1345,7 @@ AlterTableAddConstraint(char *relationName,
|
||||
int count;
|
||||
|
||||
if (is_temp_rel_name(fkconstraint->pktable->relname) &&
|
||||
!is_temp_rel_name(relationName))
|
||||
!is_temp_rel_name(RelationGetRelationName(rel)))
|
||||
elog(ERROR, "ALTER TABLE / ADD CONSTRAINT: Unable to reference temporary table from permanent table constraint.");
|
||||
|
||||
/*
|
||||
@@ -1408,7 +1395,7 @@ AlterTableAddConstraint(char *relationName,
|
||||
trig.tgargs[0] = fkconstraint->constr_name;
|
||||
else
|
||||
trig.tgargs[0] = "<unknown>";
|
||||
trig.tgargs[1] = (char *) relationName;
|
||||
trig.tgargs[1] = pstrdup(RelationGetRelationName(rel));
|
||||
trig.tgargs[2] = fkconstraint->pktable->relname;
|
||||
trig.tgargs[3] = fkconstraint->match_type;
|
||||
count = 4;
|
||||
@@ -1483,12 +1470,11 @@ AlterTableAddConstraint(char *relationName,
|
||||
* Christopher Kings-Lynne
|
||||
*/
|
||||
void
|
||||
AlterTableDropConstraint(const char *relationName,
|
||||
AlterTableDropConstraint(Oid myrelid,
|
||||
bool inh, const char *constrName,
|
||||
int behavior)
|
||||
{
|
||||
Relation rel;
|
||||
Oid myrelid;
|
||||
int deleted;
|
||||
|
||||
/*
|
||||
@@ -1502,19 +1488,21 @@ AlterTableDropConstraint(const char *relationName,
|
||||
* Acquire an exclusive lock on the target relation for the duration
|
||||
* of the operation.
|
||||
*/
|
||||
rel = heap_openr(relationName, AccessExclusiveLock);
|
||||
myrelid = RelationGetRelid(rel);
|
||||
rel = heap_open(myrelid, AccessExclusiveLock);
|
||||
|
||||
/* Disallow DROP CONSTRAINT on views, indexes, sequences, etc */
|
||||
if (rel->rd_rel->relkind != RELKIND_RELATION)
|
||||
elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table",
|
||||
relationName);
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
if (!allowSystemTableMods && IsSystemRelationName(relationName))
|
||||
if (!allowSystemTableMods
|
||||
&& IsSystemRelationName(RelationGetRelationName(rel)))
|
||||
elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
|
||||
relationName);
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
if (!pg_class_ownercheck(myrelid, GetUserId()))
|
||||
elog(ERROR, "ALTER TABLE: permission denied");
|
||||
elog(ERROR, "ALTER TABLE: \"%s\": permission denied",
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
/*
|
||||
* Since all we have is the name of the constraint, we have to look
|
||||
@@ -1554,30 +1542,7 @@ AlterTableDropConstraint(const char *relationName,
|
||||
* ALTER TABLE OWNER
|
||||
*/
|
||||
void
|
||||
AlterTableOwner(const RangeVar *tgtrel, const char *newOwnerName)
|
||||
{
|
||||
Relation rel;
|
||||
Oid myrelid;
|
||||
int32 newOwnerSysId;
|
||||
|
||||
/* check that we are the superuser */
|
||||
if (!superuser())
|
||||
elog(ERROR, "ALTER TABLE: permission denied");
|
||||
|
||||
/* lookup the OID of the target relation */
|
||||
rel = relation_openrv(tgtrel, AccessExclusiveLock);
|
||||
myrelid = RelationGetRelid(rel);
|
||||
heap_close(rel, NoLock); /* close rel but keep lock! */
|
||||
|
||||
/* lookup the sysid of the new owner */
|
||||
newOwnerSysId = get_usesysid(newOwnerName);
|
||||
|
||||
/* do all the actual work */
|
||||
AlterTableOwnerId(myrelid, newOwnerSysId);
|
||||
}
|
||||
|
||||
static void
|
||||
AlterTableOwnerId(Oid relationOid, int32 newOwnerSysId)
|
||||
AlterTableOwner(Oid relationOid, int32 newOwnerSysId)
|
||||
{
|
||||
Relation target_rel;
|
||||
Relation class_rel;
|
||||
@@ -1629,7 +1594,7 @@ AlterTableOwnerId(Oid relationOid, int32 newOwnerSysId)
|
||||
/* For each index, recursively change its ownership */
|
||||
foreach(i, index_oid_list)
|
||||
{
|
||||
AlterTableOwnerId(lfirsti(i), newOwnerSysId);
|
||||
AlterTableOwner(lfirsti(i), newOwnerSysId);
|
||||
}
|
||||
|
||||
freeList(index_oid_list);
|
||||
@@ -1640,7 +1605,7 @@ AlterTableOwnerId(Oid relationOid, int32 newOwnerSysId)
|
||||
/* If it has a toast table, recurse to change its ownership */
|
||||
if (tuple_class->reltoastrelid != InvalidOid)
|
||||
{
|
||||
AlterTableOwnerId(tuple_class->reltoastrelid, newOwnerSysId);
|
||||
AlterTableOwner(tuple_class->reltoastrelid, newOwnerSysId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Copyright (c) 1999-2001, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.37 2002/03/26 19:15:38 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.38 2002/03/29 19:06:04 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -27,9 +27,10 @@
|
||||
#include "catalog/pg_type.h"
|
||||
#include "commands/comment.h"
|
||||
#include "miscadmin.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "parser/parse_agg.h"
|
||||
#include "parser/parse_expr.h"
|
||||
#include "parser/parse_func.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "parser/parse.h"
|
||||
#include "rewrite/rewriteRemove.h"
|
||||
#include "utils/acl.h"
|
||||
@@ -51,14 +52,16 @@
|
||||
|
||||
static void CommentRelation(int objtype, char * schemaname, char *relation,
|
||||
char *comment);
|
||||
static void CommentAttribute(char *relation, char *attrib, char *comment);
|
||||
static void CommentAttribute(char * schemaname, char *relation,
|
||||
char *attrib, char *comment);
|
||||
static void CommentDatabase(char *database, char *comment);
|
||||
static void CommentRewrite(char *rule, char *comment);
|
||||
static void CommentType(char *type, char *comment);
|
||||
static void CommentAggregate(char *aggregate, List *arguments, char *comment);
|
||||
static void CommentProc(char *function, List *arguments, char *comment);
|
||||
static void CommentOperator(char *opname, List *arguments, char *comment);
|
||||
static void CommentTrigger(char *trigger, char *relation, char *comments);
|
||||
static void CommentTrigger(char *trigger, char *schemaname, char *relation,
|
||||
char *comments);
|
||||
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
@@ -88,7 +91,7 @@ CommentObject(int objtype, char *schemaname, char *objname, char *objproperty,
|
||||
CommentRelation(objtype, schemaname, objname, comment);
|
||||
break;
|
||||
case COLUMN:
|
||||
CommentAttribute(objname, objproperty, comment);
|
||||
CommentAttribute(schemaname, objname, objproperty, comment);
|
||||
break;
|
||||
case DATABASE:
|
||||
CommentDatabase(objname, comment);
|
||||
@@ -109,7 +112,7 @@ CommentObject(int objtype, char *schemaname, char *objname, char *objproperty,
|
||||
CommentOperator(objname, objlist, comment);
|
||||
break;
|
||||
case TRIGGER:
|
||||
CommentTrigger(objname, objproperty, comment);
|
||||
CommentTrigger(objname, schemaname, objproperty, comment);
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "An attempt was made to comment on a unknown type: %d",
|
||||
@@ -391,14 +394,18 @@ CommentRelation(int reltype, char *schemaname, char *relname, char *comment)
|
||||
*/
|
||||
|
||||
static void
|
||||
CommentAttribute(char *relname, char *attrname, char *comment)
|
||||
CommentAttribute(char *schemaname, char *relname, char *attrname, char *comment)
|
||||
{
|
||||
RangeVar *rel = makeNode(RangeVar);
|
||||
Relation relation;
|
||||
AttrNumber attnum;
|
||||
|
||||
/* Open the containing relation to ensure it won't go away meanwhile */
|
||||
|
||||
relation = heap_openr(relname, AccessShareLock);
|
||||
rel->relname = relname;
|
||||
rel->schemaname = schemaname;
|
||||
rel->istemp = false;
|
||||
relation = heap_openrv(rel, AccessShareLock);
|
||||
|
||||
/* Check object security */
|
||||
|
||||
@@ -539,11 +546,8 @@ CommentType(char *type, char *comment)
|
||||
|
||||
/* Find the type's oid */
|
||||
|
||||
oid = GetSysCacheOid(TYPENAME,
|
||||
PointerGetDatum(type),
|
||||
0, 0, 0);
|
||||
if (!OidIsValid(oid))
|
||||
elog(ERROR, "type '%s' does not exist", type);
|
||||
/* XXX WRONG: need to deal with qualified type names */
|
||||
oid = typenameTypeId(makeTypeName(type));
|
||||
|
||||
/* Check object security */
|
||||
|
||||
@@ -570,21 +574,13 @@ static void
|
||||
CommentAggregate(char *aggregate, List *arguments, char *comment)
|
||||
{
|
||||
TypeName *aggtype = (TypeName *) lfirst(arguments);
|
||||
char *aggtypename;
|
||||
Oid baseoid,
|
||||
oid;
|
||||
Oid classoid;
|
||||
bool defined;
|
||||
|
||||
/* First, attempt to determine the base aggregate oid */
|
||||
|
||||
if (aggtype)
|
||||
{
|
||||
aggtypename = TypeNameToInternalName(aggtype);
|
||||
baseoid = TypeGet(aggtypename, &defined);
|
||||
if (!OidIsValid(baseoid))
|
||||
elog(ERROR, "type '%s' does not exist", aggtypename);
|
||||
}
|
||||
baseoid = typenameTypeId(aggtype);
|
||||
else
|
||||
baseoid = InvalidOid;
|
||||
|
||||
@@ -648,20 +644,19 @@ CommentProc(char *function, List *arguments, char *comment)
|
||||
for (i = 0; i < argcount; i++)
|
||||
{
|
||||
TypeName *t = (TypeName *) lfirst(arguments);
|
||||
char *typnam = TypeNameToInternalName(t);
|
||||
|
||||
argoids[i] = LookupTypeName(t);
|
||||
if (!OidIsValid(argoids[i]))
|
||||
{
|
||||
char *typnam = TypeNameToString(t);
|
||||
|
||||
if (strcmp(typnam, "opaque") == 0)
|
||||
argoids[i] = InvalidOid;
|
||||
else
|
||||
elog(ERROR, "Type \"%s\" does not exist", typnam);
|
||||
}
|
||||
|
||||
arguments = lnext(arguments);
|
||||
|
||||
if (strcmp(typnam, "opaque") == 0)
|
||||
argoids[i] = InvalidOid;
|
||||
else
|
||||
{
|
||||
argoids[i] = GetSysCacheOid(TYPENAME,
|
||||
PointerGetDatum(typnam),
|
||||
0, 0, 0);
|
||||
if (!OidIsValid(argoids[i]))
|
||||
elog(ERROR, "CommentProc: type '%s' not found", typnam);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now, find the corresponding oid for this procedure */
|
||||
@@ -707,40 +702,20 @@ CommentOperator(char *opername, List *arguments, char *comment)
|
||||
{
|
||||
TypeName *typenode1 = (TypeName *) lfirst(arguments);
|
||||
TypeName *typenode2 = (TypeName *) lsecond(arguments);
|
||||
char oprtype = 0,
|
||||
*lefttype = NULL,
|
||||
*righttype = NULL;
|
||||
char oprtype = 0;
|
||||
Form_pg_operator data;
|
||||
HeapTuple optuple;
|
||||
Oid oid,
|
||||
leftoid = InvalidOid,
|
||||
rightoid = InvalidOid;
|
||||
bool defined;
|
||||
|
||||
/* Initialize our left and right argument types */
|
||||
|
||||
/* Attempt to fetch the left type oid, if specified */
|
||||
if (typenode1 != NULL)
|
||||
lefttype = TypeNameToInternalName(typenode1);
|
||||
leftoid = typenameTypeId(typenode1);
|
||||
|
||||
/* Attempt to fetch the right type oid, if specified */
|
||||
if (typenode2 != NULL)
|
||||
righttype = TypeNameToInternalName(typenode2);
|
||||
|
||||
/* Attempt to fetch the left oid, if specified */
|
||||
|
||||
if (lefttype != NULL)
|
||||
{
|
||||
leftoid = TypeGet(lefttype, &defined);
|
||||
if (!OidIsValid(leftoid))
|
||||
elog(ERROR, "left type '%s' does not exist", lefttype);
|
||||
}
|
||||
|
||||
/* Attempt to fetch the right oid, if specified */
|
||||
|
||||
if (righttype != NULL)
|
||||
{
|
||||
rightoid = TypeGet(righttype, &defined);
|
||||
if (!OidIsValid(rightoid))
|
||||
elog(ERROR, "right type '%s' does not exist", righttype);
|
||||
}
|
||||
rightoid = typenameTypeId(typenode2);
|
||||
|
||||
/* Determine operator type */
|
||||
|
||||
@@ -797,8 +772,9 @@ CommentOperator(char *opername, List *arguments, char *comment)
|
||||
*/
|
||||
|
||||
static void
|
||||
CommentTrigger(char *trigger, char *relname, char *comment)
|
||||
CommentTrigger(char *trigger, char *schemaname, char *relname, char *comment)
|
||||
{
|
||||
RangeVar *rel = makeNode(RangeVar);
|
||||
Relation pg_trigger,
|
||||
relation;
|
||||
HeapTuple triggertuple;
|
||||
@@ -808,7 +784,10 @@ CommentTrigger(char *trigger, char *relname, char *comment)
|
||||
|
||||
/* First, validate the user's action */
|
||||
|
||||
relation = heap_openr(relname, AccessShareLock);
|
||||
rel->relname = relname;
|
||||
rel->schemaname = schemaname;
|
||||
rel->istemp = false;
|
||||
relation = heap_openrv(rel, AccessShareLock);
|
||||
|
||||
if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
|
||||
elog(ERROR, "you are not permitted to comment on trigger '%s' %s '%s'",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.151 2002/03/21 23:27:20 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.152 2002/03/29 19:06:05 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "access/printtup.h"
|
||||
#include "catalog/catname.h"
|
||||
#include "catalog/index.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_index.h"
|
||||
#include "catalog/pg_shadow.h"
|
||||
#include "catalog/pg_type.h"
|
||||
@@ -228,7 +229,7 @@ CopyDonePeek(FILE *fp, int c, bool pickup)
|
||||
/*
|
||||
* DoCopy executes the SQL COPY statement.
|
||||
*
|
||||
* Either unload or reload contents of table <relname>, depending on <from>.
|
||||
* Either unload or reload contents of table <relation>, depending on <from>.
|
||||
* (<from> = TRUE means we are inserting into the table.)
|
||||
*
|
||||
* If <pipe> is false, transfer is between the table and the file named
|
||||
@@ -260,7 +261,7 @@ CopyDonePeek(FILE *fp, int c, bool pickup)
|
||||
* the table.
|
||||
*/
|
||||
void
|
||||
DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
|
||||
DoCopy(const RangeVar *relation, bool binary, bool oids, bool from, bool pipe,
|
||||
char *filename, char *delim, char *null_print)
|
||||
{
|
||||
FILE *fp;
|
||||
@@ -271,7 +272,7 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
|
||||
/*
|
||||
* Open and lock the relation, using the appropriate lock type.
|
||||
*/
|
||||
rel = heap_openr(relname, (from ? RowExclusiveLock : AccessShareLock));
|
||||
rel = heap_openrv(relation, (from ? RowExclusiveLock : AccessShareLock));
|
||||
|
||||
/* Check permissions. */
|
||||
aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
|
||||
@@ -312,11 +313,14 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
|
||||
if (rel->rd_rel->relkind != RELKIND_RELATION)
|
||||
{
|
||||
if (rel->rd_rel->relkind == RELKIND_VIEW)
|
||||
elog(ERROR, "You cannot copy view %s", relname);
|
||||
elog(ERROR, "You cannot copy view %s",
|
||||
RelationGetRelationName(rel));
|
||||
else if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
|
||||
elog(ERROR, "You cannot change sequence relation %s", relname);
|
||||
elog(ERROR, "You cannot change sequence relation %s",
|
||||
RelationGetRelationName(rel));
|
||||
else
|
||||
elog(ERROR, "You cannot copy object %s", relname);
|
||||
elog(ERROR, "You cannot copy object %s",
|
||||
RelationGetRelationName(rel));
|
||||
}
|
||||
if (pipe)
|
||||
{
|
||||
@@ -354,11 +358,14 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
|
||||
if (rel->rd_rel->relkind != RELKIND_RELATION)
|
||||
{
|
||||
if (rel->rd_rel->relkind == RELKIND_VIEW)
|
||||
elog(ERROR, "You cannot copy view %s", relname);
|
||||
elog(ERROR, "You cannot copy view %s",
|
||||
RelationGetRelationName(rel));
|
||||
else if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
|
||||
elog(ERROR, "You cannot copy sequence %s", relname);
|
||||
elog(ERROR, "You cannot copy sequence %s",
|
||||
RelationGetRelationName(rel));
|
||||
else
|
||||
elog(ERROR, "You cannot copy object %s", relname);
|
||||
elog(ERROR, "You cannot copy object %s",
|
||||
RelationGetRelationName(rel));
|
||||
}
|
||||
if (pipe)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.92 2002/03/26 19:15:40 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.93 2002/03/29 19:06:05 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "commands/creatinh.h"
|
||||
#include "miscadmin.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "utils/temprel.h"
|
||||
@@ -108,7 +109,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
|
||||
* (BuildDescForRelation takes care of the inherited defaults, but we
|
||||
* have to copy inherited constraints here.)
|
||||
*/
|
||||
descriptor = BuildDescForRelation(schema, relname);
|
||||
descriptor = BuildDescForRelation(schema);
|
||||
|
||||
if (old_constraints != NIL)
|
||||
{
|
||||
@@ -238,10 +239,12 @@ DefineRelation(CreateStmt *stmt, char relkind)
|
||||
* themselves will be destroyed, too.
|
||||
*/
|
||||
void
|
||||
RemoveRelation(const char *name)
|
||||
RemoveRelation(const RangeVar *relation)
|
||||
{
|
||||
AssertArg(name);
|
||||
heap_drop_with_catalog(name, allowSystemTableMods);
|
||||
Oid relOid;
|
||||
|
||||
relOid = RangeVarGetRelid(relation, false);
|
||||
heap_drop_with_catalog(relOid, allowSystemTableMods);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -255,34 +258,36 @@ RemoveRelation(const char *name)
|
||||
* Rows are removed, indices are truncated and reconstructed.
|
||||
*/
|
||||
void
|
||||
TruncateRelation(const char *relname)
|
||||
TruncateRelation(const RangeVar *relation)
|
||||
{
|
||||
Oid relid;
|
||||
Relation rel;
|
||||
|
||||
AssertArg(relname);
|
||||
relid = RangeVarGetRelid(relation, false);
|
||||
|
||||
/* Grab exclusive lock in preparation for truncate */
|
||||
rel = heap_openr(relname, AccessExclusiveLock);
|
||||
rel = heap_open(relid, AccessExclusiveLock);
|
||||
|
||||
if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
|
||||
elog(ERROR, "TRUNCATE cannot be used on sequences. '%s' is a sequence",
|
||||
relname);
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
if (rel->rd_rel->relkind == RELKIND_VIEW)
|
||||
elog(ERROR, "TRUNCATE cannot be used on views. '%s' is a view",
|
||||
relname);
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
if (!allowSystemTableMods && IsSystemRelationName(relname))
|
||||
if (!allowSystemTableMods && IsSystemRelationName(RelationGetRelationName(rel)))
|
||||
elog(ERROR, "TRUNCATE cannot be used on system tables. '%s' is a system table",
|
||||
relname);
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId()))
|
||||
elog(ERROR, "you do not own relation \"%s\"", relname);
|
||||
elog(ERROR, "you do not own relation \"%s\"",
|
||||
RelationGetRelationName(rel));
|
||||
|
||||
/* Keep the lock until transaction commit */
|
||||
heap_close(rel, NoLock);
|
||||
|
||||
heap_truncate(relname);
|
||||
heap_truncate(relid);
|
||||
}
|
||||
|
||||
|
||||
@@ -308,12 +313,7 @@ MergeDomainAttributes(List *schema)
|
||||
HeapTuple tuple;
|
||||
Form_pg_type typeTup;
|
||||
|
||||
tuple = SearchSysCache(TYPENAME,
|
||||
CStringGetDatum(coldef->typename->name),
|
||||
0,0,0);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
elog(ERROR, "MergeDomainAttributes: Type %s does not exist",
|
||||
coldef->typename->name);
|
||||
tuple = typenameType(coldef->typename);
|
||||
typeTup = (Form_pg_type) GETSTRUCT(tuple);
|
||||
|
||||
if (typeTup->typtype == 'd')
|
||||
@@ -486,26 +486,11 @@ MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
parent_attno++)
|
||||
{
|
||||
Form_pg_attribute attribute = tupleDesc->attrs[parent_attno - 1];
|
||||
char *attributeName;
|
||||
char *attributeType;
|
||||
HeapTuple tuple;
|
||||
char *attributeName = NameStr(attribute->attname);
|
||||
int exist_attno;
|
||||
ColumnDef *def;
|
||||
TypeName *typename;
|
||||
|
||||
/*
|
||||
* Get name and type name of attribute
|
||||
*/
|
||||
attributeName = NameStr(attribute->attname);
|
||||
tuple = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(attribute->atttypid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
elog(ERROR, "CREATE TABLE: cache lookup failed for type %u",
|
||||
attribute->atttypid);
|
||||
attributeType = pstrdup(NameStr(((Form_pg_type) GETSTRUCT(tuple))->typname));
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
/*
|
||||
* Does it conflict with some previously inherited column?
|
||||
*/
|
||||
@@ -519,10 +504,12 @@ MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
elog(NOTICE, "CREATE TABLE: merging multiple inherited definitions of attribute \"%s\"",
|
||||
attributeName);
|
||||
def = (ColumnDef *) nth(exist_attno - 1, inhSchema);
|
||||
if (strcmp(def->typename->name, attributeType) != 0 ||
|
||||
if (typenameTypeId(def->typename) != attribute->atttypid ||
|
||||
def->typename->typmod != attribute->atttypmod)
|
||||
elog(ERROR, "CREATE TABLE: inherited attribute \"%s\" type conflict (%s and %s)",
|
||||
attributeName, def->typename->name, attributeType);
|
||||
attributeName,
|
||||
TypeNameToString(def->typename),
|
||||
typeidTypeName(attribute->atttypid));
|
||||
/* Merge of NOT NULL constraints = OR 'em together */
|
||||
def->is_not_null |= attribute->attnotnull;
|
||||
/* Default and other constraints are handled below */
|
||||
@@ -536,7 +523,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
def = makeNode(ColumnDef);
|
||||
def->colname = pstrdup(attributeName);
|
||||
typename = makeNode(TypeName);
|
||||
typename->name = attributeType;
|
||||
typename->typeid = attribute->atttypid;
|
||||
typename->typmod = attribute->atttypmod;
|
||||
def->typename = typename;
|
||||
def->is_not_null = attribute->attnotnull;
|
||||
@@ -640,7 +627,6 @@ MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
{
|
||||
ColumnDef *newdef = lfirst(entry);
|
||||
char *attributeName = newdef->colname;
|
||||
char *attributeType = newdef->typename->name;
|
||||
int exist_attno;
|
||||
|
||||
/*
|
||||
@@ -658,10 +644,12 @@ MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
elog(NOTICE, "CREATE TABLE: merging attribute \"%s\" with inherited definition",
|
||||
attributeName);
|
||||
def = (ColumnDef *) nth(exist_attno - 1, inhSchema);
|
||||
if (strcmp(def->typename->name, attributeType) != 0 ||
|
||||
if (typenameTypeId(def->typename) != typenameTypeId(newdef->typename) ||
|
||||
def->typename->typmod != newdef->typename->typmod)
|
||||
elog(ERROR, "CREATE TABLE: attribute \"%s\" type conflict (%s and %s)",
|
||||
attributeName, def->typename->name, attributeType);
|
||||
attributeName,
|
||||
TypeNameToString(def->typename),
|
||||
TypeNameToString(newdef->typename));
|
||||
/* Merge of NOT NULL constraints = OR 'em together */
|
||||
def->is_not_null |= newdef->is_not_null;
|
||||
/* If new def has a default, override previous default */
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.71 2002/03/20 19:43:44 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.72 2002/03/29 19:06:06 tgl Exp $
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The "DefineFoo" routines take the parse tree and pick out the
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "access/heapam.h"
|
||||
#include "catalog/catname.h"
|
||||
#include "catalog/heap.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_aggregate.h"
|
||||
#include "catalog/pg_language.h"
|
||||
#include "catalog/pg_operator.h"
|
||||
@@ -50,13 +51,19 @@
|
||||
#include "fmgr.h"
|
||||
#include "miscadmin.h"
|
||||
#include "optimizer/cost.h"
|
||||
#include "parser/parse_expr.h"
|
||||
#include "parser/parse_func.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/fmgroids.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
static Oid findTypeIOFunction(const char *procname, bool isOutput);
|
||||
static char *defGetString(DefElem *def);
|
||||
static double defGetNumeric(DefElem *def);
|
||||
static TypeName *defGetTypeName(DefElem *def);
|
||||
static int defGetTypeLength(DefElem *def);
|
||||
|
||||
#define DEFAULT_TYPDELIM ','
|
||||
@@ -77,16 +84,59 @@ case_translate_language_name(const char *input, char *output)
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
compute_return_type(TypeName *returnType,
|
||||
char **prorettype_p, bool *returnsSet_p)
|
||||
{
|
||||
/*
|
||||
* Examine the "returns" clause returnType of the CREATE FUNCTION statement
|
||||
* and return information about it as *prorettype_p and *returnsSet.
|
||||
*
|
||||
* This is more complex than the average typename lookup because we want to
|
||||
* allow a shell type to be used, or even created if the specified return type
|
||||
* doesn't exist yet. (Without this, there's no way to define the I/O procs
|
||||
* for a new type.) But SQL function creation won't cope, so error out if
|
||||
* the target language is SQL.
|
||||
*/
|
||||
*prorettype_p = TypeNameToInternalName(returnType);
|
||||
static void
|
||||
compute_return_type(TypeName *returnType, Oid languageOid,
|
||||
Oid *prorettype_p, bool *returnsSet_p)
|
||||
{
|
||||
Oid rettype;
|
||||
|
||||
rettype = LookupTypeName(returnType);
|
||||
|
||||
if (OidIsValid(rettype))
|
||||
{
|
||||
if (!get_typisdefined(rettype))
|
||||
{
|
||||
if (languageOid == SQLlanguageId)
|
||||
elog(ERROR, "SQL functions cannot return shell types");
|
||||
else
|
||||
elog(WARNING, "Return type \"%s\" is only a shell",
|
||||
TypeNameToString(returnType));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char *typnam = TypeNameToString(returnType);
|
||||
|
||||
if (strcmp(typnam, "opaque") == 0)
|
||||
rettype = InvalidOid;
|
||||
else
|
||||
{
|
||||
Oid namespaceId;
|
||||
char *typname;
|
||||
|
||||
if (languageOid == SQLlanguageId)
|
||||
elog(ERROR, "Type \"%s\" does not exist", typnam);
|
||||
elog(WARNING, "ProcedureCreate: type %s is not yet defined",
|
||||
typnam);
|
||||
namespaceId = QualifiedNameGetCreationNamespace(returnType->names,
|
||||
&typname);
|
||||
rettype = TypeShellMake(typname, namespaceId);
|
||||
if (!OidIsValid(rettype))
|
||||
elog(ERROR, "could not create type %s", typnam);
|
||||
}
|
||||
}
|
||||
|
||||
*prorettype_p = rettype;
|
||||
*returnsSet_p = returnType->setof;
|
||||
}
|
||||
|
||||
@@ -211,34 +261,31 @@ interpret_AS_clause(Oid languageOid, const char *languageName, const List *as,
|
||||
void
|
||||
CreateFunction(ProcedureStmt *stmt)
|
||||
{
|
||||
/* pathname of executable file that executes this function, if any */
|
||||
char *probin_str;
|
||||
/* SQL that executes this function, if any */
|
||||
char *prosrc_str;
|
||||
/* Type of return value (or member of set of values) from function */
|
||||
char *prorettype;
|
||||
/* name of language of function, with case adjusted */
|
||||
char languageName[NAMEDATALEN];
|
||||
/* The function returns a set of values, as opposed to a singleton. */
|
||||
Oid prorettype;
|
||||
bool returnsSet;
|
||||
/*
|
||||
* The following are optional user-supplied attributes of the
|
||||
* function.
|
||||
*/
|
||||
char languageName[NAMEDATALEN];
|
||||
Oid languageOid;
|
||||
char *funcname;
|
||||
Oid namespaceId;
|
||||
int32 byte_pct,
|
||||
perbyte_cpu,
|
||||
percall_cpu,
|
||||
outin_ratio;
|
||||
bool canCache,
|
||||
isStrict;
|
||||
|
||||
HeapTuple languageTuple;
|
||||
Form_pg_language languageStruct;
|
||||
Oid languageOid;
|
||||
|
||||
/* Convert list of names to a name and namespace */
|
||||
namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
|
||||
&funcname);
|
||||
|
||||
/* Convert language name to canonical case */
|
||||
case_translate_language_name(stmt->language, languageName);
|
||||
|
||||
/* Look up the language and validate permissions */
|
||||
languageTuple = SearchSysCache(LANGNAME,
|
||||
PointerGetDatum(languageName),
|
||||
0, 0, 0);
|
||||
@@ -259,21 +306,22 @@ CreateFunction(ProcedureStmt *stmt)
|
||||
* Convert remaining parameters of CREATE to form wanted by
|
||||
* ProcedureCreate.
|
||||
*/
|
||||
Assert(IsA(stmt->returnType, TypeName));
|
||||
compute_return_type((TypeName *) stmt->returnType,
|
||||
compute_return_type(stmt->returnType, languageOid,
|
||||
&prorettype, &returnsSet);
|
||||
|
||||
compute_full_attributes(stmt->withClause,
|
||||
&byte_pct, &perbyte_cpu, &percall_cpu,
|
||||
&outin_ratio, &canCache, &isStrict);
|
||||
|
||||
interpret_AS_clause(languageOid, languageName, stmt->as, &prosrc_str, &probin_str);
|
||||
interpret_AS_clause(languageOid, languageName, stmt->as,
|
||||
&prosrc_str, &probin_str);
|
||||
|
||||
/*
|
||||
* And now that we have all the parameters, and know we're permitted
|
||||
* to do so, go ahead and create the function.
|
||||
*/
|
||||
ProcedureCreate(stmt->funcname,
|
||||
ProcedureCreate(funcname,
|
||||
namespaceId,
|
||||
stmt->replace,
|
||||
returnsSet,
|
||||
prorettype,
|
||||
@@ -292,27 +340,28 @@ CreateFunction(ProcedureStmt *stmt)
|
||||
|
||||
|
||||
|
||||
/* --------------------------------
|
||||
/*
|
||||
* DefineOperator
|
||||
*
|
||||
* this function extracts all the information from the
|
||||
* parameter list generated by the parser and then has
|
||||
* OperatorCreate() do all the actual work.
|
||||
*
|
||||
* 'parameters' is a list of DefElem
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
DefineOperator(char *oprName,
|
||||
List *parameters)
|
||||
DefineOperator(List *names, List *parameters)
|
||||
{
|
||||
char *oprName;
|
||||
Oid oprNamespace;
|
||||
uint16 precedence = 0; /* operator precedence */
|
||||
bool canHash = false; /* operator hashes */
|
||||
bool isLeftAssociative = true; /* operator is left
|
||||
* associative */
|
||||
char *functionName = NULL; /* function for operator */
|
||||
char *typeName1 = NULL; /* first type name */
|
||||
char *typeName2 = NULL; /* second type name */
|
||||
TypeName *typeName1 = NULL; /* first type name */
|
||||
TypeName *typeName2 = NULL; /* second type name */
|
||||
Oid typeId1 = InvalidOid; /* types converted to OID */
|
||||
Oid typeId2 = InvalidOid;
|
||||
char *commutatorName = NULL; /* optional commutator operator
|
||||
* name */
|
||||
char *negatorName = NULL; /* optional negator operator name */
|
||||
@@ -323,6 +372,9 @@ DefineOperator(char *oprName,
|
||||
char *sortName2 = NULL; /* optional second sort operator */
|
||||
List *pl;
|
||||
|
||||
/* Convert list of names to a name and namespace */
|
||||
oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
|
||||
|
||||
/*
|
||||
* loop over the definition list and extract the information we need.
|
||||
*/
|
||||
@@ -332,16 +384,14 @@ DefineOperator(char *oprName,
|
||||
|
||||
if (strcasecmp(defel->defname, "leftarg") == 0)
|
||||
{
|
||||
typeName1 = defGetString(defel);
|
||||
if (IsA(defel->arg, TypeName) &&
|
||||
((TypeName *) defel->arg)->setof)
|
||||
typeName1 = defGetTypeName(defel);
|
||||
if (typeName1->setof)
|
||||
elog(ERROR, "setof type not implemented for leftarg");
|
||||
}
|
||||
else if (strcasecmp(defel->defname, "rightarg") == 0)
|
||||
{
|
||||
typeName2 = defGetString(defel);
|
||||
if (IsA(defel->arg, TypeName) &&
|
||||
((TypeName *) defel->arg)->setof)
|
||||
typeName2 = defGetTypeName(defel);
|
||||
if (typeName2->setof)
|
||||
elog(ERROR, "setof type not implemented for rightarg");
|
||||
}
|
||||
else if (strcasecmp(defel->defname, "procedure") == 0)
|
||||
@@ -367,15 +417,7 @@ DefineOperator(char *oprName,
|
||||
else if (strcasecmp(defel->defname, "hashes") == 0)
|
||||
canHash = TRUE;
|
||||
else if (strcasecmp(defel->defname, "sort1") == 0)
|
||||
{
|
||||
/* ----------------
|
||||
* XXX ( ... [ , sort1 = oprname ] [ , sort2 = oprname ] ... )
|
||||
* XXX is undocumented in the reference manual source as of
|
||||
* 89/8/22.
|
||||
* ----------------
|
||||
*/
|
||||
sortName1 = defGetString(defel);
|
||||
}
|
||||
else if (strcasecmp(defel->defname, "sort2") == 0)
|
||||
sortName2 = defGetString(defel);
|
||||
else
|
||||
@@ -391,12 +433,18 @@ DefineOperator(char *oprName,
|
||||
if (functionName == NULL)
|
||||
elog(ERROR, "Define: \"procedure\" unspecified");
|
||||
|
||||
/* Transform type names to type OIDs */
|
||||
if (typeName1)
|
||||
typeId1 = typenameTypeId(typeName1);
|
||||
if (typeName2)
|
||||
typeId2 = typenameTypeId(typeName2);
|
||||
|
||||
/*
|
||||
* now have OperatorCreate do all the work..
|
||||
*/
|
||||
OperatorCreate(oprName, /* operator name */
|
||||
typeName1, /* first type name */
|
||||
typeName2, /* second type name */
|
||||
typeId1, /* left type id */
|
||||
typeId2, /* right type id */
|
||||
functionName, /* function for operator */
|
||||
precedence, /* operator precedence */
|
||||
isLeftAssociative, /* operator is left associative */
|
||||
@@ -412,20 +460,26 @@ DefineOperator(char *oprName,
|
||||
|
||||
}
|
||||
|
||||
/* -------------------
|
||||
/*
|
||||
* DefineAggregate
|
||||
* ------------------
|
||||
*/
|
||||
void
|
||||
DefineAggregate(char *aggName, List *parameters)
|
||||
DefineAggregate(List *names, List *parameters)
|
||||
{
|
||||
char *aggName;
|
||||
Oid aggNamespace;
|
||||
char *transfuncName = NULL;
|
||||
char *finalfuncName = NULL;
|
||||
char *baseType = NULL;
|
||||
char *transType = NULL;
|
||||
TypeName *baseType = NULL;
|
||||
TypeName *transType = NULL;
|
||||
char *initval = NULL;
|
||||
Oid baseTypeId;
|
||||
Oid transTypeId;
|
||||
List *pl;
|
||||
|
||||
/* Convert list of names to a name and namespace */
|
||||
aggNamespace = QualifiedNameGetCreationNamespace(names, &aggName);
|
||||
|
||||
foreach(pl, parameters)
|
||||
{
|
||||
DefElem *defel = (DefElem *) lfirst(pl);
|
||||
@@ -441,11 +495,11 @@ DefineAggregate(char *aggName, List *parameters)
|
||||
else if (strcasecmp(defel->defname, "finalfunc") == 0)
|
||||
finalfuncName = defGetString(defel);
|
||||
else if (strcasecmp(defel->defname, "basetype") == 0)
|
||||
baseType = defGetString(defel);
|
||||
baseType = defGetTypeName(defel);
|
||||
else if (strcasecmp(defel->defname, "stype") == 0)
|
||||
transType = defGetString(defel);
|
||||
transType = defGetTypeName(defel);
|
||||
else if (strcasecmp(defel->defname, "stype1") == 0)
|
||||
transType = defGetString(defel);
|
||||
transType = defGetTypeName(defel);
|
||||
else if (strcasecmp(defel->defname, "initcond") == 0)
|
||||
initval = defGetString(defel);
|
||||
else if (strcasecmp(defel->defname, "initcond1") == 0)
|
||||
@@ -465,14 +519,40 @@ DefineAggregate(char *aggName, List *parameters)
|
||||
if (transfuncName == NULL)
|
||||
elog(ERROR, "Define: \"sfunc\" unspecified");
|
||||
|
||||
/*
|
||||
* Handle the aggregate's base type (input data type). This can be
|
||||
* specified as 'ANY' for a data-independent transition function, such
|
||||
* as COUNT(*).
|
||||
*/
|
||||
baseTypeId = LookupTypeName(baseType);
|
||||
if (OidIsValid(baseTypeId))
|
||||
{
|
||||
/* no need to allow aggregates on as-yet-undefined types */
|
||||
if (!get_typisdefined(baseTypeId))
|
||||
elog(ERROR, "Type \"%s\" is only a shell",
|
||||
TypeNameToString(baseType));
|
||||
}
|
||||
else
|
||||
{
|
||||
char *typnam = TypeNameToString(baseType);
|
||||
|
||||
if (strcasecmp(typnam, "ANY") != 0)
|
||||
elog(ERROR, "Type \"%s\" does not exist", typnam);
|
||||
baseTypeId = InvalidOid;
|
||||
}
|
||||
|
||||
/* handle transtype --- no special cases here */
|
||||
transTypeId = typenameTypeId(transType);
|
||||
|
||||
/*
|
||||
* Most of the argument-checking is done inside of AggregateCreate
|
||||
*/
|
||||
AggregateCreate(aggName, /* aggregate name */
|
||||
aggNamespace, /* namespace */
|
||||
transfuncName, /* step function name */
|
||||
finalfuncName, /* final function name */
|
||||
baseType, /* type of data being aggregated */
|
||||
transType, /* transition data type */
|
||||
baseTypeId, /* type of data being aggregated */
|
||||
transTypeId, /* transition data type */
|
||||
initval); /* initial condition */
|
||||
}
|
||||
|
||||
@@ -483,12 +563,14 @@ DefineAggregate(char *aggName, List *parameters)
|
||||
void
|
||||
DefineDomain(CreateDomainStmt *stmt)
|
||||
{
|
||||
char *domainName;
|
||||
Oid domainNamespace;
|
||||
int16 internalLength;
|
||||
int16 externalLength;
|
||||
char *inputName;
|
||||
char *outputName;
|
||||
char *sendName;
|
||||
char *receiveName;
|
||||
Oid inputProcedure;
|
||||
Oid outputProcedure;
|
||||
Oid receiveProcedure;
|
||||
Oid sendProcedure;
|
||||
bool byValue;
|
||||
char delimiter;
|
||||
char alignment;
|
||||
@@ -500,46 +582,27 @@ DefineDomain(CreateDomainStmt *stmt)
|
||||
char *defaultValueBin = NULL;
|
||||
bool typNotNull = false;
|
||||
Oid basetypelem;
|
||||
char *elemName = NULL;
|
||||
int32 typNDims = 0; /* No array dimensions by default */
|
||||
int32 typNDims = length(stmt->typename->arrayBounds);
|
||||
HeapTuple typeTup;
|
||||
char *typeName = stmt->typename->name;
|
||||
List *schema = stmt->constraints;
|
||||
List *listptr;
|
||||
|
||||
/* Convert list of names to a name and namespace */
|
||||
domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
|
||||
&domainName);
|
||||
|
||||
/*
|
||||
* Domainnames, unlike typenames don't need to account for the '_'
|
||||
* prefix. So they can be one character longer.
|
||||
*/
|
||||
if (strlen(stmt->domainname) > (NAMEDATALEN - 1))
|
||||
if (strlen(domainName) > (NAMEDATALEN - 1))
|
||||
elog(ERROR, "CREATE DOMAIN: domain names must be %d characters or less",
|
||||
NAMEDATALEN - 1);
|
||||
|
||||
/* Test for existing Domain (or type) of that name */
|
||||
typeTup = SearchSysCache(TYPENAME,
|
||||
PointerGetDatum(stmt->domainname),
|
||||
0, 0, 0);
|
||||
if (HeapTupleIsValid(typeTup))
|
||||
elog(ERROR, "CREATE DOMAIN: domain or type %s already exists",
|
||||
stmt->domainname);
|
||||
|
||||
/*
|
||||
* When the type is an array for some reason we don't actually receive
|
||||
* the name here. We receive the base types name. Lets set Dims while
|
||||
* were at it.
|
||||
* Look up the base type.
|
||||
*/
|
||||
if (stmt->typename->arrayBounds > 0) {
|
||||
typeName = makeArrayTypeName(stmt->typename->name);
|
||||
|
||||
typNDims = length(stmt->typename->arrayBounds);
|
||||
}
|
||||
|
||||
typeTup = SearchSysCache(TYPENAME,
|
||||
PointerGetDatum(typeName),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(typeTup))
|
||||
elog(ERROR, "CREATE DOMAIN: type %s does not exist",
|
||||
stmt->typename->name);
|
||||
typeTup = typenameType(stmt->typename);
|
||||
|
||||
/*
|
||||
* What we really don't want is domains of domains. This could cause all sorts
|
||||
@@ -550,7 +613,7 @@ DefineDomain(CreateDomainStmt *stmt)
|
||||
typtype = ((Form_pg_type) GETSTRUCT(typeTup))->typtype;
|
||||
if (typtype != 'b')
|
||||
elog(ERROR, "DefineDomain: %s is not a basetype",
|
||||
stmt->typename->name);
|
||||
TypeNameToString(stmt->typename));
|
||||
|
||||
/* passed by value */
|
||||
byValue = ((Form_pg_type) GETSTRUCT(typeTup))->typbyval;
|
||||
@@ -570,43 +633,20 @@ DefineDomain(CreateDomainStmt *stmt)
|
||||
/* Array element Delimiter */
|
||||
delimiter = ((Form_pg_type) GETSTRUCT(typeTup))->typdelim;
|
||||
|
||||
/*
|
||||
* XXX this is pretty bogus: should be passing function OIDs to
|
||||
* TypeCreate, not names which aren't unique.
|
||||
*/
|
||||
|
||||
/* Input Function Name */
|
||||
datum = SysCacheGetAttr(TYPENAME, typeTup, Anum_pg_type_typinput, &isnull);
|
||||
Assert(!isnull);
|
||||
|
||||
inputName = DatumGetCString(DirectFunctionCall1(regprocout, datum));
|
||||
|
||||
/* Output Function Name */
|
||||
datum = SysCacheGetAttr(TYPENAME, typeTup, Anum_pg_type_typoutput, &isnull);
|
||||
Assert(!isnull);
|
||||
|
||||
outputName = DatumGetCString(DirectFunctionCall1(regprocout, datum));
|
||||
|
||||
/* ReceiveName */
|
||||
datum = SysCacheGetAttr(TYPENAME, typeTup, Anum_pg_type_typreceive, &isnull);
|
||||
Assert(!isnull);
|
||||
|
||||
receiveName = DatumGetCString(DirectFunctionCall1(regprocout, datum));
|
||||
|
||||
/* SendName */
|
||||
datum = SysCacheGetAttr(TYPENAME, typeTup, Anum_pg_type_typsend, &isnull);
|
||||
Assert(!isnull);
|
||||
|
||||
sendName = DatumGetCString(DirectFunctionCall1(regprocout, datum));
|
||||
/* I/O Functions */
|
||||
inputProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typinput;
|
||||
outputProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typoutput;
|
||||
receiveProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typreceive;
|
||||
sendProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typsend;
|
||||
|
||||
/* Inherited default value */
|
||||
datum = SysCacheGetAttr(TYPENAME, typeTup,
|
||||
datum = SysCacheGetAttr(TYPEOID, typeTup,
|
||||
Anum_pg_type_typdefault, &isnull);
|
||||
if (!isnull)
|
||||
defaultValue = DatumGetCString(DirectFunctionCall1(textout, datum));
|
||||
|
||||
/* Inherited default binary value */
|
||||
datum = SysCacheGetAttr(TYPENAME, typeTup,
|
||||
datum = SysCacheGetAttr(TYPEOID, typeTup,
|
||||
Anum_pg_type_typdefaultbin, &isnull);
|
||||
if (!isnull)
|
||||
defaultValueBin = DatumGetCString(DirectFunctionCall1(textout, datum));
|
||||
@@ -617,16 +657,6 @@ DefineDomain(CreateDomainStmt *stmt)
|
||||
* This is what enables us to make a domain of an array
|
||||
*/
|
||||
basetypelem = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
|
||||
if (basetypelem != InvalidOid)
|
||||
{
|
||||
HeapTuple tup;
|
||||
|
||||
tup = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(basetypelem),
|
||||
0, 0, 0);
|
||||
elemName = pstrdup(NameStr(((Form_pg_type) GETSTRUCT(tup))->typname));
|
||||
ReleaseSysCache(tup);
|
||||
}
|
||||
|
||||
/*
|
||||
* Run through constraints manually to avoid the additional
|
||||
@@ -661,14 +691,14 @@ DefineDomain(CreateDomainStmt *stmt)
|
||||
expr = cookDefault(pstate, colDef->raw_expr,
|
||||
typeTup->t_data->t_oid,
|
||||
stmt->typename->typmod,
|
||||
stmt->typename->name);
|
||||
domainName);
|
||||
/*
|
||||
* Expression must be stored as a nodeToString result,
|
||||
* but we also require a valid textual representation
|
||||
* (mainly to make life easier for pg_dump).
|
||||
*/
|
||||
defaultValue = deparse_expression(expr,
|
||||
deparse_context_for(stmt->domainname,
|
||||
deparse_context_for(domainName,
|
||||
InvalidOid),
|
||||
false);
|
||||
defaultValueBin = nodeToString(expr);
|
||||
@@ -723,19 +753,20 @@ DefineDomain(CreateDomainStmt *stmt)
|
||||
/*
|
||||
* Have TypeCreate do all the real work.
|
||||
*/
|
||||
TypeCreate(stmt->domainname, /* type name */
|
||||
TypeCreate(domainName, /* type name */
|
||||
domainNamespace, /* namespace */
|
||||
InvalidOid, /* preassigned type oid (not done here) */
|
||||
InvalidOid, /* relation oid (n/a here) */
|
||||
internalLength, /* internal size */
|
||||
externalLength, /* external size */
|
||||
'd', /* type-type (domain type) */
|
||||
delimiter, /* array element delimiter */
|
||||
inputName, /* input procedure */
|
||||
outputName, /* output procedure */
|
||||
receiveName, /* receive procedure */
|
||||
sendName, /* send procedure */
|
||||
elemName, /* element type name */
|
||||
typeName, /* base type name */
|
||||
inputProcedure, /* input procedure */
|
||||
outputProcedure, /* output procedure */
|
||||
receiveProcedure, /* receive procedure */
|
||||
sendProcedure, /* send procedure */
|
||||
basetypelem, /* element type ID */
|
||||
typeTup->t_data->t_oid, /* base type ID */
|
||||
defaultValue, /* default type value (text) */
|
||||
defaultValueBin, /* default type value (binary) */
|
||||
byValue, /* passed by value */
|
||||
@@ -743,7 +774,7 @@ DefineDomain(CreateDomainStmt *stmt)
|
||||
storage, /* TOAST strategy */
|
||||
stmt->typename->typmod, /* typeMod value */
|
||||
typNDims, /* Array dimensions for base type */
|
||||
typNotNull); /* Type NOT NULL */
|
||||
typNotNull); /* Type NOT NULL */
|
||||
|
||||
/*
|
||||
* Now we can clean up.
|
||||
@@ -756,11 +787,13 @@ DefineDomain(CreateDomainStmt *stmt)
|
||||
* Registers a new type.
|
||||
*/
|
||||
void
|
||||
DefineType(char *typeName, List *parameters)
|
||||
DefineType(List *names, List *parameters)
|
||||
{
|
||||
char *typeName;
|
||||
Oid typeNamespace;
|
||||
int16 internalLength = -1; /* int2 */
|
||||
int16 externalLength = -1; /* int2 */
|
||||
char *elemName = NULL;
|
||||
Oid elemType = InvalidOid;
|
||||
char *inputName = NULL;
|
||||
char *outputName = NULL;
|
||||
char *sendName = NULL;
|
||||
@@ -768,10 +801,18 @@ DefineType(char *typeName, List *parameters)
|
||||
char *defaultValue = NULL;
|
||||
bool byValue = false;
|
||||
char delimiter = DEFAULT_TYPDELIM;
|
||||
char *shadow_type;
|
||||
List *pl;
|
||||
char alignment = 'i'; /* default alignment */
|
||||
char storage = 'p'; /* default TOAST storage method */
|
||||
Oid inputOid;
|
||||
Oid outputOid;
|
||||
Oid sendOid;
|
||||
Oid receiveOid;
|
||||
char *shadow_type;
|
||||
List *pl;
|
||||
Oid typoid;
|
||||
|
||||
/* Convert list of names to a name and namespace */
|
||||
typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
|
||||
|
||||
/*
|
||||
* Type names must be one character shorter than other names, allowing
|
||||
@@ -796,16 +837,16 @@ DefineType(char *typeName, List *parameters)
|
||||
outputName = defGetString(defel);
|
||||
else if (strcasecmp(defel->defname, "send") == 0)
|
||||
sendName = defGetString(defel);
|
||||
else if (strcasecmp(defel->defname, "receive") == 0)
|
||||
receiveName = defGetString(defel);
|
||||
else if (strcasecmp(defel->defname, "delimiter") == 0)
|
||||
{
|
||||
char *p = defGetString(defel);
|
||||
|
||||
delimiter = p[0];
|
||||
}
|
||||
else if (strcasecmp(defel->defname, "receive") == 0)
|
||||
receiveName = defGetString(defel);
|
||||
else if (strcasecmp(defel->defname, "element") == 0)
|
||||
elemName = defGetString(defel);
|
||||
elemType = typenameTypeId(defGetTypeName(defel));
|
||||
else if (strcasecmp(defel->defname, "default") == 0)
|
||||
defaultValue = defGetString(defel);
|
||||
else if (strcasecmp(defel->defname, "passedbyvalue") == 0)
|
||||
@@ -867,30 +908,44 @@ DefineType(char *typeName, List *parameters)
|
||||
if (outputName == NULL)
|
||||
elog(ERROR, "Define: \"output\" unspecified");
|
||||
|
||||
/* Convert I/O proc names to OIDs */
|
||||
inputOid = findTypeIOFunction(inputName, false);
|
||||
outputOid = findTypeIOFunction(outputName, true);
|
||||
if (sendName)
|
||||
sendOid = findTypeIOFunction(sendName, true);
|
||||
else
|
||||
sendOid = outputOid;
|
||||
if (receiveName)
|
||||
receiveOid = findTypeIOFunction(receiveName, false);
|
||||
else
|
||||
receiveOid = inputOid;
|
||||
|
||||
/*
|
||||
* now have TypeCreate do all the real work.
|
||||
*/
|
||||
TypeCreate(typeName, /* type name */
|
||||
InvalidOid, /* preassigned type oid (not done here) */
|
||||
InvalidOid, /* relation oid (n/a here) */
|
||||
internalLength, /* internal size */
|
||||
externalLength, /* external size */
|
||||
'b', /* type-type (base type) */
|
||||
delimiter, /* array element delimiter */
|
||||
inputName, /* input procedure */
|
||||
outputName, /* output procedure */
|
||||
receiveName, /* receive procedure */
|
||||
sendName, /* send procedure */
|
||||
elemName, /* element type name */
|
||||
NULL, /* base type name (only for domains) */
|
||||
defaultValue, /* default type value */
|
||||
NULL, /* no binary form available */
|
||||
byValue, /* passed by value */
|
||||
alignment, /* required alignment */
|
||||
storage, /* TOAST strategy */
|
||||
-1, /* typMod (Domains only) */
|
||||
0, /* Array Dimensions of typbasetype */
|
||||
'f'); /* Type NOT NULL */
|
||||
typoid =
|
||||
TypeCreate(typeName, /* type name */
|
||||
typeNamespace, /* namespace */
|
||||
InvalidOid, /* preassigned type oid (not done here) */
|
||||
InvalidOid, /* relation oid (n/a here) */
|
||||
internalLength, /* internal size */
|
||||
externalLength, /* external size */
|
||||
'b', /* type-type (base type) */
|
||||
delimiter, /* array element delimiter */
|
||||
inputOid, /* input procedure */
|
||||
outputOid, /* output procedure */
|
||||
receiveOid, /* receive procedure */
|
||||
sendOid, /* send procedure */
|
||||
elemType, /* element type ID */
|
||||
InvalidOid, /* base type ID (only for domains) */
|
||||
defaultValue, /* default type value */
|
||||
NULL, /* no binary form available */
|
||||
byValue, /* passed by value */
|
||||
alignment, /* required alignment */
|
||||
storage, /* TOAST strategy */
|
||||
-1, /* typMod (Domains only) */
|
||||
0, /* Array Dimensions of typbasetype */
|
||||
false); /* Type NOT NULL */
|
||||
|
||||
/*
|
||||
* When we create a base type (as opposed to a complex type) we need
|
||||
@@ -902,18 +957,19 @@ DefineType(char *typeName, List *parameters)
|
||||
alignment = (alignment == 'd') ? 'd' : 'i';
|
||||
|
||||
TypeCreate(shadow_type, /* type name */
|
||||
typeNamespace, /* namespace */
|
||||
InvalidOid, /* preassigned type oid (not done here) */
|
||||
InvalidOid, /* relation oid (n/a here) */
|
||||
-1, /* internal size */
|
||||
-1, /* external size */
|
||||
'b', /* type-type (base type) */
|
||||
DEFAULT_TYPDELIM, /* array element delimiter */
|
||||
"array_in", /* input procedure */
|
||||
"array_out", /* output procedure */
|
||||
"array_in", /* receive procedure */
|
||||
"array_out", /* send procedure */
|
||||
typeName, /* element type name */
|
||||
NULL, /* base type name */
|
||||
F_ARRAY_IN, /* input procedure */
|
||||
F_ARRAY_OUT, /* output procedure */
|
||||
F_ARRAY_IN, /* receive procedure */
|
||||
F_ARRAY_OUT, /* send procedure */
|
||||
typoid, /* element type ID */
|
||||
InvalidOid, /* base type ID */
|
||||
NULL, /* never a default type value */
|
||||
NULL, /* binary default isn't sent either */
|
||||
false, /* never passed by value */
|
||||
@@ -921,11 +977,65 @@ DefineType(char *typeName, List *parameters)
|
||||
'x', /* ARRAY is always toastable */
|
||||
-1, /* typMod (Domains only) */
|
||||
0, /* Array dimensions of typbasetype */
|
||||
'f'); /* Type NOT NULL */
|
||||
false); /* Type NOT NULL */
|
||||
|
||||
pfree(shadow_type);
|
||||
}
|
||||
|
||||
static Oid
|
||||
findTypeIOFunction(const char *procname, bool isOutput)
|
||||
{
|
||||
Oid argList[FUNC_MAX_ARGS];
|
||||
int nargs;
|
||||
Oid procOid;
|
||||
|
||||
/*
|
||||
* First look for a 1-argument func with all argtypes 0. This is
|
||||
* valid for all kinds of procedure.
|
||||
*/
|
||||
MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||
|
||||
procOid = GetSysCacheOid(PROCNAME,
|
||||
PointerGetDatum(procname),
|
||||
Int32GetDatum(1),
|
||||
PointerGetDatum(argList),
|
||||
0);
|
||||
|
||||
if (!OidIsValid(procOid))
|
||||
{
|
||||
/*
|
||||
* Alternatively, input procedures may take 3 args (data
|
||||
* value, element OID, atttypmod); the pg_proc argtype
|
||||
* signature is 0,OIDOID,INT4OID. Output procedures may
|
||||
* take 2 args (data value, element OID).
|
||||
*/
|
||||
if (isOutput)
|
||||
{
|
||||
/* output proc */
|
||||
nargs = 2;
|
||||
argList[1] = OIDOID;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* input proc */
|
||||
nargs = 3;
|
||||
argList[1] = OIDOID;
|
||||
argList[2] = INT4OID;
|
||||
}
|
||||
procOid = GetSysCacheOid(PROCNAME,
|
||||
PointerGetDatum(procname),
|
||||
Int32GetDatum(nargs),
|
||||
PointerGetDatum(argList),
|
||||
0);
|
||||
|
||||
if (!OidIsValid(procOid))
|
||||
func_error("TypeCreate", procname, 1, argList, NULL);
|
||||
}
|
||||
|
||||
return procOid;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
defGetString(DefElem *def)
|
||||
{
|
||||
@@ -951,7 +1061,7 @@ defGetString(DefElem *def)
|
||||
case T_String:
|
||||
return strVal(def->arg);
|
||||
case T_TypeName:
|
||||
return TypeNameToInternalName((TypeName *) def->arg);
|
||||
return TypeNameToString((TypeName *) def->arg);
|
||||
default:
|
||||
elog(ERROR, "Define: cannot interpret argument of \"%s\"",
|
||||
def->defname);
|
||||
@@ -978,6 +1088,32 @@ defGetNumeric(DefElem *def)
|
||||
return 0; /* keep compiler quiet */
|
||||
}
|
||||
|
||||
static TypeName *
|
||||
defGetTypeName(DefElem *def)
|
||||
{
|
||||
if (def->arg == NULL)
|
||||
elog(ERROR, "Define: \"%s\" requires a parameter",
|
||||
def->defname);
|
||||
switch (nodeTag(def->arg))
|
||||
{
|
||||
case T_TypeName:
|
||||
return (TypeName *) def->arg;
|
||||
case T_String:
|
||||
{
|
||||
/* Allow quoted typename for backwards compatibility */
|
||||
TypeName *n = makeNode(TypeName);
|
||||
|
||||
n->names = makeList1(def->arg);
|
||||
n->typmod = -1;
|
||||
return n;
|
||||
}
|
||||
default:
|
||||
elog(ERROR, "Define: argument of \"%s\" must be a type name",
|
||||
def->defname);
|
||||
}
|
||||
return NULL; /* keep compiler quiet */
|
||||
}
|
||||
|
||||
static int
|
||||
defGetTypeLength(DefElem *def)
|
||||
{
|
||||
@@ -998,7 +1134,7 @@ defGetTypeLength(DefElem *def)
|
||||
break;
|
||||
case T_TypeName:
|
||||
/* cope if grammar chooses to believe "variable" is a typename */
|
||||
if (strcasecmp(TypeNameToInternalName((TypeName *) def->arg),
|
||||
if (strcasecmp(TypeNameToString((TypeName *) def->arg),
|
||||
"variable") == 0)
|
||||
return -1; /* variable length */
|
||||
break;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.71 2002/03/21 23:27:21 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.72 2002/03/29 19:06:06 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -24,8 +24,8 @@
|
||||
#include "miscadmin.h"
|
||||
#include "parser/parse.h"
|
||||
#include "parser/parse_agg.h"
|
||||
#include "parser/parse_expr.h"
|
||||
#include "parser/parse_func.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/syscache.h"
|
||||
@@ -43,29 +43,20 @@
|
||||
*/
|
||||
void
|
||||
RemoveOperator(char *operatorName, /* operator name */
|
||||
char *typeName1, /* left argument type name */
|
||||
char *typeName2) /* right argument type name */
|
||||
TypeName *typeName1, /* left argument type name */
|
||||
TypeName *typeName2) /* right argument type name */
|
||||
{
|
||||
Relation relation;
|
||||
HeapTuple tup;
|
||||
Oid typeId1 = InvalidOid;
|
||||
Oid typeId2 = InvalidOid;
|
||||
bool defined;
|
||||
char oprtype;
|
||||
|
||||
if (typeName1)
|
||||
{
|
||||
typeId1 = TypeGet(typeName1, &defined);
|
||||
if (!OidIsValid(typeId1))
|
||||
elog(ERROR, "RemoveOperator: type '%s' does not exist", typeName1);
|
||||
}
|
||||
typeId1 = typenameTypeId(typeName1);
|
||||
|
||||
if (typeName2)
|
||||
{
|
||||
typeId2 = TypeGet(typeName2, &defined);
|
||||
if (!OidIsValid(typeId2))
|
||||
elog(ERROR, "RemoveOperator: type '%s' does not exist", typeName2);
|
||||
}
|
||||
typeId2 = typenameTypeId(typeName2);
|
||||
|
||||
if (OidIsValid(typeId1) && OidIsValid(typeId2))
|
||||
oprtype = 'b';
|
||||
@@ -99,20 +90,20 @@ RemoveOperator(char *operatorName, /* operator name */
|
||||
{
|
||||
elog(ERROR, "RemoveOperator: binary operator '%s' taking '%s' and '%s' does not exist",
|
||||
operatorName,
|
||||
typeName1,
|
||||
typeName2);
|
||||
TypeNameToString(typeName1),
|
||||
TypeNameToString(typeName2));
|
||||
}
|
||||
else if (OidIsValid(typeId1))
|
||||
{
|
||||
elog(ERROR, "RemoveOperator: right unary operator '%s' taking '%s' does not exist",
|
||||
operatorName,
|
||||
typeName1);
|
||||
TypeNameToString(typeName1));
|
||||
}
|
||||
else
|
||||
{
|
||||
elog(ERROR, "RemoveOperator: left unary operator '%s' taking '%s' does not exist",
|
||||
operatorName,
|
||||
typeName2);
|
||||
TypeNameToString(typeName2));
|
||||
}
|
||||
}
|
||||
heap_freetuple(tup);
|
||||
@@ -213,16 +204,13 @@ AttributeAndRelationRemove(Oid typeOid)
|
||||
rel = heap_openr(RelationRelationName, RowExclusiveLock);
|
||||
while (PointerIsValid((char *) optr->next))
|
||||
{
|
||||
key[0].sk_argument = (Datum) (optr++)->reloid;
|
||||
Oid relOid = (optr++)->reloid;
|
||||
|
||||
key[0].sk_argument = ObjectIdGetDatum(relOid);
|
||||
scan = heap_beginscan(rel, 0, SnapshotNow, 1, key);
|
||||
tup = heap_getnext(scan, 0);
|
||||
if (HeapTupleIsValid(tup))
|
||||
{
|
||||
char *name;
|
||||
|
||||
name = NameStr(((Form_pg_class) GETSTRUCT(tup))->relname);
|
||||
heap_drop_with_catalog(name, allowSystemTableMods);
|
||||
}
|
||||
heap_drop_with_catalog(relOid, allowSystemTableMods);
|
||||
heap_endscan(scan);
|
||||
}
|
||||
heap_close(rel, RowExclusiveLock);
|
||||
@@ -231,42 +219,68 @@ AttributeAndRelationRemove(Oid typeOid)
|
||||
|
||||
/*
|
||||
* TypeRemove
|
||||
* Removes the type 'typeName' and all attributes and relations that
|
||||
* use it.
|
||||
* Removes a datatype.
|
||||
*
|
||||
* NOTE: since this tries to remove the associated array type too, it'll
|
||||
* only work on scalar types.
|
||||
*/
|
||||
void
|
||||
RemoveType(char *typeName) /* type name to be removed */
|
||||
RemoveType(List *names)
|
||||
{
|
||||
TypeName *typename;
|
||||
Relation relation;
|
||||
Oid typeoid;
|
||||
HeapTuple tup;
|
||||
char *shadow_type;
|
||||
|
||||
/* Make a TypeName so we can use standard type lookup machinery */
|
||||
typename = makeNode(TypeName);
|
||||
typename->names = names;
|
||||
typename->typmod = -1;
|
||||
typename->arrayBounds = NIL;
|
||||
|
||||
relation = heap_openr(TypeRelationName, RowExclusiveLock);
|
||||
|
||||
tup = SearchSysCache(TYPENAME,
|
||||
PointerGetDatum(typeName),
|
||||
/* Use LookupTypeName here so that shell types can be removed. */
|
||||
typeoid = LookupTypeName(typename);
|
||||
if (!OidIsValid(typeoid))
|
||||
elog(ERROR, "Type \"%s\" does not exist",
|
||||
TypeNameToString(typename));
|
||||
|
||||
tup = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(typeoid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(ERROR, "RemoveType: type '%s' does not exist", typeName);
|
||||
elog(ERROR, "Type \"%s\" does not exist",
|
||||
TypeNameToString(typename));
|
||||
|
||||
if (!pg_type_ownercheck(tup->t_data->t_oid, GetUserId()))
|
||||
if (!pg_type_ownercheck(typeoid, GetUserId()))
|
||||
elog(ERROR, "RemoveType: type '%s': permission denied",
|
||||
typeName);
|
||||
TypeNameToString(typename));
|
||||
|
||||
/* Delete any comments associated with this type */
|
||||
DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation));
|
||||
DeleteComments(typeoid, RelationGetRelid(relation));
|
||||
|
||||
/* Remove the type tuple from pg_type */
|
||||
simple_heap_delete(relation, &tup->t_self);
|
||||
|
||||
ReleaseSysCache(tup);
|
||||
|
||||
/* Also, delete the "array of" that type */
|
||||
shadow_type = makeArrayTypeName(typeName);
|
||||
tup = SearchSysCache(TYPENAME,
|
||||
PointerGetDatum(shadow_type),
|
||||
/* Now, delete the "array of" that type */
|
||||
typename->arrayBounds = makeList1(makeInteger(1));
|
||||
|
||||
typeoid = LookupTypeName(typename);
|
||||
if (!OidIsValid(typeoid))
|
||||
elog(ERROR, "Type \"%s\" does not exist",
|
||||
TypeNameToString(typename));
|
||||
|
||||
tup = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(typeoid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(ERROR, "RemoveType: type '%s' does not exist", shadow_type);
|
||||
elog(ERROR, "Type \"%s\" does not exist",
|
||||
TypeNameToString(typename));
|
||||
|
||||
DeleteComments(typeoid, RelationGetRelid(relation));
|
||||
|
||||
simple_heap_delete(relation, &tup->t_self);
|
||||
|
||||
@@ -277,13 +291,14 @@ RemoveType(char *typeName) /* type name to be removed */
|
||||
|
||||
/*
|
||||
* RemoveDomain
|
||||
* Removes the domain 'typeName' and all attributes and relations that
|
||||
* use it.
|
||||
* Removes a domain.
|
||||
*/
|
||||
void
|
||||
RemoveDomain(char *domainName, int behavior)
|
||||
RemoveDomain(List *names, int behavior)
|
||||
{
|
||||
TypeName *typename;
|
||||
Relation relation;
|
||||
Oid typeoid;
|
||||
HeapTuple tup;
|
||||
char typtype;
|
||||
|
||||
@@ -291,31 +306,44 @@ RemoveDomain(char *domainName, int behavior)
|
||||
if (behavior == CASCADE)
|
||||
elog(ERROR, "DROP DOMAIN does not support the CASCADE keyword");
|
||||
|
||||
/* Make a TypeName so we can use standard type lookup machinery */
|
||||
typename = makeNode(TypeName);
|
||||
typename->names = names;
|
||||
typename->typmod = -1;
|
||||
typename->arrayBounds = NIL;
|
||||
|
||||
relation = heap_openr(TypeRelationName, RowExclusiveLock);
|
||||
|
||||
tup = SearchSysCache(TYPENAME,
|
||||
PointerGetDatum(domainName),
|
||||
typeoid = typenameTypeId(typename);
|
||||
|
||||
tup = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(typeoid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(ERROR, "RemoveType: type '%s' does not exist", domainName);
|
||||
elog(ERROR, "RemoveDomain: type '%s' does not exist",
|
||||
TypeNameToString(typename));
|
||||
|
||||
if (!pg_type_ownercheck(tup->t_data->t_oid, GetUserId()))
|
||||
if (!pg_type_ownercheck(typeoid, GetUserId()))
|
||||
elog(ERROR, "RemoveDomain: type '%s': permission denied",
|
||||
domainName);
|
||||
TypeNameToString(typename));
|
||||
|
||||
/* Check that this is actually a domain */
|
||||
typtype = ((Form_pg_type) GETSTRUCT(tup))->typtype;
|
||||
|
||||
if (typtype != 'd')
|
||||
elog(ERROR, "%s is not a domain", domainName);
|
||||
elog(ERROR, "%s is not a domain",
|
||||
TypeNameToString(typename));
|
||||
|
||||
/* Delete any comments associated with this type */
|
||||
DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation));
|
||||
DeleteComments(typeoid, RelationGetRelid(relation));
|
||||
|
||||
/* Remove the type tuple from pg_type */
|
||||
simple_heap_delete(relation, &tup->t_self);
|
||||
|
||||
ReleaseSysCache(tup);
|
||||
|
||||
/* At present, domains don't have associated array types */
|
||||
|
||||
heap_close(relation, RowExclusiveLock);
|
||||
}
|
||||
|
||||
@@ -345,20 +373,19 @@ RemoveFunction(char *functionName, /* function name to be removed */
|
||||
for (i = 0; i < nargs; i++)
|
||||
{
|
||||
TypeName *t = (TypeName *) lfirst(argTypes);
|
||||
char *typnam = TypeNameToInternalName(t);
|
||||
|
||||
argList[i] = LookupTypeName(t);
|
||||
if (!OidIsValid(argList[i]))
|
||||
{
|
||||
char *typnam = TypeNameToString(t);
|
||||
|
||||
if (strcmp(typnam, "opaque") == 0)
|
||||
argList[i] = InvalidOid;
|
||||
else
|
||||
elog(ERROR, "Type \"%s\" does not exist", typnam);
|
||||
}
|
||||
|
||||
argTypes = lnext(argTypes);
|
||||
|
||||
if (strcmp(typnam, "opaque") == 0)
|
||||
argList[i] = InvalidOid;
|
||||
else
|
||||
{
|
||||
argList[i] = GetSysCacheOid(TYPENAME,
|
||||
PointerGetDatum(typnam),
|
||||
0, 0, 0);
|
||||
if (!OidIsValid(argList[i]))
|
||||
elog(ERROR, "RemoveFunction: type '%s' not found", typnam);
|
||||
}
|
||||
}
|
||||
|
||||
relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
|
||||
@@ -393,12 +420,11 @@ RemoveFunction(char *functionName, /* function name to be removed */
|
||||
}
|
||||
|
||||
void
|
||||
RemoveAggregate(char *aggName, char *aggType)
|
||||
RemoveAggregate(char *aggName, TypeName *aggType)
|
||||
{
|
||||
Relation relation;
|
||||
HeapTuple tup;
|
||||
Oid basetypeID;
|
||||
bool defined;
|
||||
|
||||
/*
|
||||
* if a basetype is passed in, then attempt to find an aggregate for
|
||||
@@ -410,11 +436,7 @@ RemoveAggregate(char *aggName, char *aggType)
|
||||
*/
|
||||
|
||||
if (aggType)
|
||||
{
|
||||
basetypeID = TypeGet(aggType, &defined);
|
||||
if (!OidIsValid(basetypeID))
|
||||
elog(ERROR, "RemoveAggregate: type '%s' does not exist", aggType);
|
||||
}
|
||||
basetypeID = typenameTypeId(aggType);
|
||||
else
|
||||
basetypeID = InvalidOid;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.65 2002/03/26 19:15:43 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.66 2002/03/29 19:06:07 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -69,16 +69,14 @@ static void update_ri_trigger_args(Oid relid,
|
||||
* delete original attribute from attribute catalog
|
||||
*/
|
||||
void
|
||||
renameatt(char *relname,
|
||||
renameatt(Oid relid,
|
||||
char *oldattname,
|
||||
char *newattname,
|
||||
int recurse)
|
||||
bool recurse)
|
||||
{
|
||||
Relation targetrelation;
|
||||
Relation attrelation;
|
||||
HeapTuple reltup,
|
||||
atttup;
|
||||
Oid relid;
|
||||
HeapTuple atttup;
|
||||
List *indexoidlist;
|
||||
List *indexoidscan;
|
||||
|
||||
@@ -86,8 +84,7 @@ renameatt(char *relname,
|
||||
* Grab an exclusive lock on the target table, which we will NOT
|
||||
* release until end of transaction.
|
||||
*/
|
||||
targetrelation = heap_openr(relname, AccessExclusiveLock);
|
||||
relid = RelationGetRelid(targetrelation);
|
||||
targetrelation = heap_open(relid, AccessExclusiveLock);
|
||||
|
||||
/*
|
||||
* permissions checking. this would normally be done in utility.c,
|
||||
@@ -95,12 +92,13 @@ renameatt(char *relname,
|
||||
*
|
||||
* normally, only the owner of a class can change its schema.
|
||||
*/
|
||||
if (!allowSystemTableMods && IsSystemRelationName(relname))
|
||||
if (!allowSystemTableMods
|
||||
&& IsSystemRelationName(RelationGetRelationName(targetrelation)))
|
||||
elog(ERROR, "renameatt: class \"%s\" is a system catalog",
|
||||
relname);
|
||||
RelationGetRelationName(targetrelation));
|
||||
if (!pg_class_ownercheck(relid, GetUserId()))
|
||||
elog(ERROR, "renameatt: you do not own class \"%s\"",
|
||||
relname);
|
||||
RelationGetRelationName(targetrelation));
|
||||
|
||||
/*
|
||||
* if the 'recurse' flag is set then we are supposed to rename this
|
||||
@@ -127,25 +125,11 @@ renameatt(char *relname,
|
||||
foreach(child, children)
|
||||
{
|
||||
Oid childrelid = lfirsti(child);
|
||||
char childname[NAMEDATALEN];
|
||||
|
||||
if (childrelid == relid)
|
||||
continue;
|
||||
reltup = SearchSysCache(RELOID,
|
||||
ObjectIdGetDatum(childrelid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(reltup))
|
||||
{
|
||||
elog(ERROR, "renameatt: can't find catalog entry for inheriting class with oid %u",
|
||||
childrelid);
|
||||
}
|
||||
/* make copy of cache value, could disappear in call */
|
||||
StrNCpy(childname,
|
||||
NameStr(((Form_pg_class) GETSTRUCT(reltup))->relname),
|
||||
NAMEDATALEN);
|
||||
ReleaseSysCache(reltup);
|
||||
/* note we need not recurse again! */
|
||||
renameatt(childname, oldattname, newattname, 0);
|
||||
renameatt(childrelid, oldattname, newattname, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,7 +340,7 @@ renamerel(const RangeVar *relation, const char *newrelname)
|
||||
* Also rename the associated type, if any.
|
||||
*/
|
||||
if (relkind != RELKIND_INDEX)
|
||||
TypeRename(relation->relname, newrelname);
|
||||
TypeRename(relation->relname, namespaceId, newrelname);
|
||||
|
||||
/*
|
||||
* If it's a view, must also rename the associated ON SELECT rule.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.74 2002/03/22 02:56:31 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.75 2002/03/29 19:06:07 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <ctype.h>
|
||||
|
||||
#include "access/heapam.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "commands/creatinh.h"
|
||||
#include "commands/sequence.h"
|
||||
#include "miscadmin.h"
|
||||
@@ -85,8 +86,6 @@ DefineSequence(CreateSeqStmt *seq)
|
||||
{
|
||||
FormData_pg_sequence new;
|
||||
CreateStmt *stmt = makeNode(CreateStmt);
|
||||
ColumnDef *coldef;
|
||||
TypeName *typnam;
|
||||
Oid seqoid;
|
||||
Relation rel;
|
||||
Buffer buf;
|
||||
@@ -108,9 +107,12 @@ DefineSequence(CreateSeqStmt *seq)
|
||||
stmt->tableElts = NIL;
|
||||
for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
|
||||
{
|
||||
ColumnDef *coldef;
|
||||
TypeName *typnam;
|
||||
|
||||
typnam = makeNode(TypeName);
|
||||
typnam->setof = FALSE;
|
||||
typnam->arrayBounds = NULL;
|
||||
typnam->arrayBounds = NIL;
|
||||
typnam->typmod = -1;
|
||||
coldef = makeNode(ColumnDef);
|
||||
coldef->typename = typnam;
|
||||
@@ -122,48 +124,48 @@ DefineSequence(CreateSeqStmt *seq)
|
||||
switch (i)
|
||||
{
|
||||
case SEQ_COL_NAME:
|
||||
typnam->name = "name";
|
||||
typnam->typeid = NAMEOID;
|
||||
coldef->colname = "sequence_name";
|
||||
namestrcpy(&name, seq->sequence->relname);
|
||||
value[i - 1] = NameGetDatum(&name);
|
||||
break;
|
||||
case SEQ_COL_LASTVAL:
|
||||
typnam->name = "int8";
|
||||
typnam->typeid = INT8OID;
|
||||
coldef->colname = "last_value";
|
||||
value[i - 1] = Int64GetDatumFast(new.last_value);
|
||||
break;
|
||||
case SEQ_COL_INCBY:
|
||||
typnam->name = "int8";
|
||||
typnam->typeid = INT8OID;
|
||||
coldef->colname = "increment_by";
|
||||
value[i - 1] = Int64GetDatumFast(new.increment_by);
|
||||
break;
|
||||
case SEQ_COL_MAXVALUE:
|
||||
typnam->name = "int8";
|
||||
typnam->typeid = INT8OID;
|
||||
coldef->colname = "max_value";
|
||||
value[i - 1] = Int64GetDatumFast(new.max_value);
|
||||
break;
|
||||
case SEQ_COL_MINVALUE:
|
||||
typnam->name = "int8";
|
||||
typnam->typeid = INT8OID;
|
||||
coldef->colname = "min_value";
|
||||
value[i - 1] = Int64GetDatumFast(new.min_value);
|
||||
break;
|
||||
case SEQ_COL_CACHE:
|
||||
typnam->name = "int8";
|
||||
typnam->typeid = INT8OID;
|
||||
coldef->colname = "cache_value";
|
||||
value[i - 1] = Int64GetDatumFast(new.cache_value);
|
||||
break;
|
||||
case SEQ_COL_LOG:
|
||||
typnam->name = "int8";
|
||||
typnam->typeid = INT8OID;
|
||||
coldef->colname = "log_cnt";
|
||||
value[i - 1] = Int64GetDatum((int64) 1);
|
||||
break;
|
||||
case SEQ_COL_CYCLE:
|
||||
typnam->name = "bool";
|
||||
typnam->typeid = BOOLOID;
|
||||
coldef->colname = "is_cycled";
|
||||
value[i - 1] = BoolGetDatum(new.is_cycled);
|
||||
break;
|
||||
case SEQ_COL_CALLED:
|
||||
typnam->name = "bool";
|
||||
typnam->typeid = BOOLOID;
|
||||
coldef->colname = "is_called";
|
||||
value[i - 1] = BoolGetDatum(false);
|
||||
break;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.60 2002/03/06 06:09:39 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.61 2002/03/29 19:06:07 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -21,11 +21,12 @@
|
||||
|
||||
#include "access/xact.h"
|
||||
#include "catalog/pg_shadow.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "commands/variable.h"
|
||||
#include "miscadmin.h"
|
||||
#include "optimizer/cost.h"
|
||||
#include "optimizer/paths.h"
|
||||
#include "parser/parse_expr.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/date.h"
|
||||
#include "utils/guc.h"
|
||||
@@ -390,7 +391,9 @@ parse_timezone(List *args)
|
||||
type = p->typename;
|
||||
if (type != NULL)
|
||||
{
|
||||
if (strcmp(type->name, "interval") == 0)
|
||||
Oid typeOid = typenameTypeId(type);
|
||||
|
||||
if (typeOid == INTERVALOID)
|
||||
{
|
||||
Interval *interval;
|
||||
|
||||
@@ -402,7 +405,7 @@ parse_timezone(List *args)
|
||||
elog(ERROR, "SET TIME ZONE illegal INTERVAL; month not allowed");
|
||||
CTimeZone = interval->time;
|
||||
}
|
||||
else if (strcmp(type->name, "float8") == 0)
|
||||
else if (typeOid == FLOAT8OID)
|
||||
{
|
||||
float8 time;
|
||||
|
||||
@@ -414,7 +417,7 @@ parse_timezone(List *args)
|
||||
* We do not actually generate an integer constant in gram.y
|
||||
* so this is not used...
|
||||
*/
|
||||
else if (strcmp(type->name, "int4") == 0)
|
||||
else if (typeOid == INT4OID)
|
||||
{
|
||||
int32 time;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: view.c,v 1.60 2002/03/22 02:56:31 tgl Exp $
|
||||
* $Id: view.c,v 1.61 2002/03/29 19:06:08 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "access/xact.h"
|
||||
#include "catalog/heap.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "commands/creatinh.h"
|
||||
#include "commands/view.h"
|
||||
#include "miscadmin.h"
|
||||
@@ -24,6 +25,7 @@
|
||||
#include "rewrite/rewriteManip.h"
|
||||
#include "rewrite/rewriteRemove.h"
|
||||
#include "rewrite/rewriteSupport.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
@@ -38,10 +40,9 @@
|
||||
*---------------------------------------------------------------------
|
||||
*/
|
||||
static Oid
|
||||
DefineVirtualRelation(char *relname, List *tlist)
|
||||
DefineVirtualRelation(const RangeVar *relation, List *tlist)
|
||||
{
|
||||
CreateStmt *createStmt = makeNode(CreateStmt);
|
||||
RangeVar *rel = makeNode(RangeVar);
|
||||
List *attrList,
|
||||
*t;
|
||||
|
||||
@@ -57,14 +58,12 @@ DefineVirtualRelation(char *relname, List *tlist)
|
||||
|
||||
if (!res->resjunk)
|
||||
{
|
||||
char *resname = res->resname;
|
||||
char *restypename = typeidTypeName(res->restype);
|
||||
ColumnDef *def = makeNode(ColumnDef);
|
||||
TypeName *typename = makeNode(TypeName);
|
||||
|
||||
def->colname = pstrdup(resname);
|
||||
def->colname = pstrdup(res->resname);
|
||||
|
||||
typename->name = pstrdup(restypename);
|
||||
typename->typeid = res->restype;
|
||||
typename->typmod = res->restypmod;
|
||||
def->typename = typename;
|
||||
|
||||
@@ -84,10 +83,7 @@ DefineVirtualRelation(char *relname, List *tlist)
|
||||
* now create the parameters for keys/inheritance etc. All of them are
|
||||
* nil...
|
||||
*/
|
||||
rel->relname = relname;
|
||||
rel->schemaname = NULL; /* XXX wrong */
|
||||
rel->istemp = false;
|
||||
createStmt->relation = rel;
|
||||
createStmt->relation = (RangeVar *) relation;
|
||||
createStmt->tableElts = attrList;
|
||||
createStmt->inhRelations = NIL;
|
||||
createStmt->constraints = NIL;
|
||||
@@ -100,25 +96,19 @@ DefineVirtualRelation(char *relname, List *tlist)
|
||||
}
|
||||
|
||||
static RuleStmt *
|
||||
FormViewRetrieveRule(char *viewName, Query *viewParse)
|
||||
FormViewRetrieveRule(const RangeVar *view, Query *viewParse)
|
||||
{
|
||||
RuleStmt *rule;
|
||||
char *rname;
|
||||
RangeVar *rel;
|
||||
|
||||
/*
|
||||
* Create a RuleStmt that corresponds to the suitable rewrite rule
|
||||
* args for DefineQueryRewrite();
|
||||
*/
|
||||
rname = MakeRetrieveViewRuleName(viewName);
|
||||
|
||||
rel = makeNode(RangeVar);
|
||||
rel->relname = pstrdup(viewName);
|
||||
rel->inhOpt = INH_NO;
|
||||
rel->alias = NULL;
|
||||
rname = MakeRetrieveViewRuleName(view->relname);
|
||||
|
||||
rule = makeNode(RuleStmt);
|
||||
rule->relation = rel;
|
||||
rule->relation = copyObject((RangeVar *) view);
|
||||
rule->rulename = pstrdup(rname);
|
||||
rule->whereClause = NULL;
|
||||
rule->event = CMD_SELECT;
|
||||
@@ -129,7 +119,7 @@ FormViewRetrieveRule(char *viewName, Query *viewParse)
|
||||
}
|
||||
|
||||
static void
|
||||
DefineViewRules(char *viewName, Query *viewParse)
|
||||
DefineViewRules(const RangeVar *view, Query *viewParse)
|
||||
{
|
||||
RuleStmt *retrieve_rule;
|
||||
|
||||
@@ -139,13 +129,13 @@ DefineViewRules(char *viewName, Query *viewParse)
|
||||
RuleStmt *delete_rule;
|
||||
#endif
|
||||
|
||||
retrieve_rule = FormViewRetrieveRule(viewName, viewParse);
|
||||
retrieve_rule = FormViewRetrieveRule(view, viewParse);
|
||||
|
||||
#ifdef NOTYET
|
||||
|
||||
replace_rule = FormViewReplaceRule(viewName, viewParse);
|
||||
append_rule = FormViewAppendRule(viewName, viewParse);
|
||||
delete_rule = FormViewDeleteRule(viewName, viewParse);
|
||||
replace_rule = FormViewReplaceRule(view, viewParse);
|
||||
append_rule = FormViewAppendRule(view, viewParse);
|
||||
delete_rule = FormViewDeleteRule(view, viewParse);
|
||||
#endif
|
||||
|
||||
DefineQueryRewrite(retrieve_rule);
|
||||
@@ -231,7 +221,7 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
|
||||
*-------------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
DefineView(char *viewName, Query *viewParse)
|
||||
DefineView(const RangeVar *view, Query *viewParse)
|
||||
{
|
||||
Oid viewOid;
|
||||
|
||||
@@ -240,7 +230,7 @@ DefineView(char *viewName, Query *viewParse)
|
||||
*
|
||||
* NOTE: if it already exists, the xact will be aborted.
|
||||
*/
|
||||
viewOid = DefineVirtualRelation(viewName, viewParse->targetList);
|
||||
viewOid = DefineVirtualRelation(view, viewParse->targetList);
|
||||
|
||||
/*
|
||||
* The relation we have just created is not visible to any other
|
||||
@@ -258,7 +248,7 @@ DefineView(char *viewName, Query *viewParse)
|
||||
/*
|
||||
* Now create the rules associated with the view.
|
||||
*/
|
||||
DefineViewRules(viewName, viewParse);
|
||||
DefineViewRules(view, viewParse);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
@@ -268,11 +258,14 @@ DefineView(char *viewName, Query *viewParse)
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
RemoveView(char *viewName)
|
||||
RemoveView(const RangeVar *view)
|
||||
{
|
||||
Oid viewOid;
|
||||
|
||||
viewOid = RangeVarGetRelid(view, false);
|
||||
/*
|
||||
* We just have to drop the relation; the associated rules will be
|
||||
* cleaned up automatically.
|
||||
*/
|
||||
heap_drop_with_catalog(viewName, allowSystemTableMods);
|
||||
heap_drop_with_catalog(viewOid, allowSystemTableMods);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user