The contents of command.c, creatinh.c, define.c, remove.c and rename.c

have been divided according to the type of object manipulated - so ALTER
TABLE code is in tablecmds.c, aggregate commands in aggregatecmds.c and
so on.

A few common support routines remain in define.c (prototypes in
src/include/commands/defrem.h).

No code has been changed except for includes to reflect the new files.
The prototypes for aggregatecmds.c, functioncmds.c, operatorcmds.c,
and typecmds.c remain in src/include/commands/defrem.h.

From John Gray <jgray@azuli.co.uk>
This commit is contained in:
Tom Lane 2002-04-15 05:22:04 +00:00
parent ab1ead6b97
commit 71dc300a37
29 changed files with 3620 additions and 3578 deletions

View File

@ -1,10 +1,10 @@
#-------------------------------------------------------------------------
#
# Makefile--
# Makefile for commands
# Makefile for backend/commands
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.27 2001/07/13 22:55:59 tgl Exp $
# $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.28 2002/04/15 05:22:03 tgl Exp $
#
#-------------------------------------------------------------------------
@ -12,10 +12,11 @@ subdir = src/backend/commands
top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
OBJS = async.o creatinh.o command.o comment.o copy.o indexcmds.o define.o \
remove.o rename.o vacuum.o vacuumlazy.o analyze.o view.o cluster.o \
explain.o sequence.o trigger.o user.o proclang.o \
dbcommands.o variable.o
OBJS = aggregatecmds.o analyze.o async.o cluster.o comment.o copy.o \
dbcommands.o define.o explain.o functioncmds.o \
indexcmds.o lockcmds.o operatorcmds.o portalcmds.o proclang.o \
schemacmds.o sequence.o tablecmds.o trigger.o typecmds.o user.o \
vacuum.o vacuumlazy.o variable.o view.o
all: SUBSYS.o

View File

@ -0,0 +1,208 @@
/*-------------------------------------------------------------------------
*
* aggregatecmds.c
*
* Routines for aggregate-manipulation commands
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.1 2002/04/15 05:22:03 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
* appropriate arguments/flags, passing the results to the
* corresponding "FooDefine" routines (in src/catalog) that do
* the actual catalog-munging. These routines also verify permission
* of the user to execute the command.
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/namespace.h"
#include "catalog/pg_aggregate.h"
#include "commands/comment.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
#include "parser/parse_type.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
/*
* DefineAggregate
*/
void
DefineAggregate(List *names, List *parameters)
{
char *aggName;
Oid aggNamespace;
List *transfuncName = NIL;
List *finalfuncName = NIL;
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);
/*
* sfunc1, stype1, and initcond1 are accepted as obsolete
* spellings for sfunc, stype, initcond.
*/
if (strcasecmp(defel->defname, "sfunc") == 0)
transfuncName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "sfunc1") == 0)
transfuncName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "finalfunc") == 0)
finalfuncName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "basetype") == 0)
baseType = defGetTypeName(defel);
else if (strcasecmp(defel->defname, "stype") == 0)
transType = defGetTypeName(defel);
else if (strcasecmp(defel->defname, "stype1") == 0)
transType = defGetTypeName(defel);
else if (strcasecmp(defel->defname, "initcond") == 0)
initval = defGetString(defel);
else if (strcasecmp(defel->defname, "initcond1") == 0)
initval = defGetString(defel);
else
elog(WARNING, "DefineAggregate: attribute \"%s\" not recognized",
defel->defname);
}
/*
* make sure we have our required definitions
*/
if (baseType == NULL)
elog(ERROR, "Define: \"basetype\" unspecified");
if (transType == NULL)
elog(ERROR, "Define: \"stype\" unspecified");
if (transfuncName == NIL)
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 */
baseTypeId, /* type of data being aggregated */
transTypeId, /* transition data type */
initval); /* initial condition */
}
void
RemoveAggregate(List *aggName, TypeName *aggType)
{
Relation relation;
HeapTuple tup;
Oid basetypeID;
Oid procOid;
/*
* if a basetype is passed in, then attempt to find an aggregate for
* that specific type.
*
* else if the basetype is blank, then attempt to find an aggregate with
* a basetype of zero. This is valid. It means that the aggregate is
* to apply to all basetypes (eg, COUNT).
*/
if (aggType)
basetypeID = typenameTypeId(aggType);
else
basetypeID = InvalidOid;
procOid = find_aggregate_func("RemoveAggregate", aggName, basetypeID);
/* Permission check */
if (!pg_proc_ownercheck(procOid, GetUserId()))
{
if (basetypeID == InvalidOid)
elog(ERROR, "RemoveAggregate: aggregate %s for all types: permission denied",
NameListToString(aggName));
else
elog(ERROR, "RemoveAggregate: aggregate %s for type %s: permission denied",
NameListToString(aggName), format_type_be(basetypeID));
}
/* Remove the pg_proc tuple */
relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
tup = SearchSysCache(PROCOID,
ObjectIdGetDatum(procOid),
0, 0, 0);
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "RemoveAggregate: couldn't find pg_proc tuple for %s",
NameListToString(aggName));
/* Delete any comments associated with this function */
DeleteComments(procOid, RelationGetRelid(relation));
simple_heap_delete(relation, &tup->t_self);
ReleaseSysCache(tup);
heap_close(relation, RowExclusiveLock);
/* Remove the pg_aggregate tuple */
relation = heap_openr(AggregateRelationName, RowExclusiveLock);
tup = SearchSysCache(AGGFNOID,
ObjectIdGetDatum(procOid),
0, 0, 0);
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "RemoveAggregate: couldn't find pg_aggregate tuple for %s",
NameListToString(aggName));
simple_heap_delete(relation, &tup->t_self);
ReleaseSysCache(tup);
heap_close(relation, RowExclusiveLock);
}

View File

@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.77 2002/03/31 07:49:30 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.78 2002/04/15 05:22:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -29,8 +29,7 @@
#include "catalog/pg_index.h"
#include "catalog/pg_proc.h"
#include "commands/cluster.h"
#include "commands/command.h"
#include "commands/rename.h"
#include "commands/tablecmds.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"

View File

@ -1,932 +0,0 @@
/*-------------------------------------------------------------------------
*
* creatinh.c
* POSTGRES create/destroy relation with inheritance utility code.
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.96 2002/04/12 20:38:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/heapam.h"
#include "catalog/catalog.h"
#include "catalog/catname.h"
#include "catalog/heap.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_type.h"
#include "commands/creatinh.h"
#include "miscadmin.h"
#include "optimizer/clauses.h"
#include "parser/parse_type.h"
#include "utils/acl.h"
#include "utils/syscache.h"
/* ----------------
* local stuff
* ----------------
*/
static List *MergeAttributes(List *schema, List *supers, bool istemp,
List **supOids, List **supconstr, bool *supHasOids);
static bool change_varattnos_of_a_node(Node *node, const AttrNumber *newattno);
static void StoreCatalogInheritance(Oid relationId, List *supers);
static int findAttrByName(const char *attributeName, List *schema);
static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
static List *MergeDomainAttributes(List *schema);
/* ----------------------------------------------------------------
* DefineRelation
* Creates a new relation.
*
* If successful, returns the OID of the new relation.
* ----------------------------------------------------------------
*/
Oid
DefineRelation(CreateStmt *stmt, char relkind)
{
char *relname = palloc(NAMEDATALEN);
Oid namespaceId;
List *schema = stmt->tableElts;
int numberOfAttributes;
Oid relationId;
Relation rel;
TupleDesc descriptor;
List *inheritOids;
List *old_constraints;
bool parentHasOids;
List *rawDefaults;
List *listptr;
int i;
AttrNumber attnum;
/*
* Truncate relname to appropriate length (probably a waste of time,
* as parser should have done this already).
*/
StrNCpy(relname, (stmt->relation)->relname, NAMEDATALEN);
/*
* Look up the namespace in which we are supposed to create the
* relation.
*/
namespaceId = RangeVarGetCreationNamespace(stmt->relation);
/*
* Merge domain attributes into the known columns before processing table
* inheritance. Otherwise we risk adding double constraints to a
* domain-type column that's inherited.
*/
schema = MergeDomainAttributes(schema);
/*
* Look up inheritance ancestors and generate relation schema,
* including inherited attributes.
*/
schema = MergeAttributes(schema, stmt->inhRelations,
stmt->relation->istemp,
&inheritOids, &old_constraints, &parentHasOids);
numberOfAttributes = length(schema);
if (numberOfAttributes <= 0)
elog(ERROR, "DefineRelation: please inherit from a relation or define an attribute");
/*
* Create a relation descriptor from the relation schema and create
* the relation. Note that in this stage only inherited (pre-cooked)
* defaults and constraints will be included into the new relation.
* (BuildDescForRelation takes care of the inherited defaults, but we
* have to copy inherited constraints here.)
*/
descriptor = BuildDescForRelation(schema);
if (old_constraints != NIL)
{
ConstrCheck *check = (ConstrCheck *) palloc(length(old_constraints) *
sizeof(ConstrCheck));
int ncheck = 0;
foreach(listptr, old_constraints)
{
Constraint *cdef = (Constraint *) lfirst(listptr);
if (cdef->contype != CONSTR_CHECK)
continue;
if (cdef->name != NULL)
{
for (i = 0; i < ncheck; i++)
{
if (strcmp(check[i].ccname, cdef->name) == 0)
elog(ERROR, "Duplicate CHECK constraint name: '%s'",
cdef->name);
}
check[ncheck].ccname = cdef->name;
}
else
{
check[ncheck].ccname = (char *) palloc(NAMEDATALEN);
snprintf(check[ncheck].ccname, NAMEDATALEN, "$%d", ncheck + 1);
}
Assert(cdef->raw_expr == NULL && cdef->cooked_expr != NULL);
check[ncheck].ccbin = pstrdup(cdef->cooked_expr);
ncheck++;
}
if (ncheck > 0)
{
if (descriptor->constr == NULL)
{
descriptor->constr = (TupleConstr *) palloc(sizeof(TupleConstr));
descriptor->constr->defval = NULL;
descriptor->constr->num_defval = 0;
descriptor->constr->has_not_null = false;
}
descriptor->constr->num_check = ncheck;
descriptor->constr->check = check;
}
}
relationId = heap_create_with_catalog(relname,
namespaceId,
descriptor,
relkind,
stmt->hasoids || parentHasOids,
allowSystemTableMods);
StoreCatalogInheritance(relationId, inheritOids);
/*
* We must bump the command counter to make the newly-created relation
* tuple visible for opening.
*/
CommandCounterIncrement();
/*
* Open the new relation and acquire exclusive lock on it. This isn't
* really necessary for locking out other backends (since they can't
* see the new rel anyway until we commit), but it keeps the lock
* manager from complaining about deadlock risks.
*/
rel = heap_open(relationId, AccessExclusiveLock);
/*
* Now add any newly specified column default values and CHECK
* constraints to the new relation. These are passed to us in the
* form of raw parsetrees; we need to transform them to executable
* expression trees before they can be added. The most convenient way
* to do that is to apply the parser's transformExpr routine, but
* transformExpr doesn't work unless we have a pre-existing relation.
* So, the transformation has to be postponed to this final step of
* CREATE TABLE.
*
* First, scan schema to find new column defaults.
*/
rawDefaults = NIL;
attnum = 0;
foreach(listptr, schema)
{
ColumnDef *colDef = lfirst(listptr);
RawColumnDefault *rawEnt;
attnum++;
if (colDef->raw_default == NULL)
continue;
Assert(colDef->cooked_default == NULL);
rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
rawEnt->attnum = attnum;
rawEnt->raw_default = colDef->raw_default;
rawDefaults = lappend(rawDefaults, rawEnt);
}
/*
* Parse and add the defaults/constraints, if any.
*/
if (rawDefaults || stmt->constraints)
AddRelationRawConstraints(rel, rawDefaults, stmt->constraints);
/*
* Clean up. We keep lock on new relation (although it shouldn't be
* visible to anyone else anyway, until commit).
*/
heap_close(rel, NoLock);
return relationId;
}
/*
* RemoveRelation
* Deletes a relation.
*
* Exceptions:
* BadArg if name is invalid.
*
* Note:
* If the relation has indices defined on it, then the index relations
* themselves will be destroyed, too.
*/
void
RemoveRelation(const RangeVar *relation)
{
Oid relOid;
relOid = RangeVarGetRelid(relation, false);
heap_drop_with_catalog(relOid, allowSystemTableMods);
}
/*
* TruncateRelation
* Removes all the rows from a relation
*
* Exceptions:
* BadArg if name is invalid
*
* Note:
* Rows are removed, indices are truncated and reconstructed.
*/
void
TruncateRelation(const RangeVar *relation)
{
Relation rel;
Oid relid;
/* Grab exclusive lock in preparation for truncate */
rel = heap_openrv(relation, AccessExclusiveLock);
relid = RelationGetRelid(rel);
if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
elog(ERROR, "TRUNCATE cannot be used on sequences. '%s' is a sequence",
RelationGetRelationName(rel));
if (rel->rd_rel->relkind == RELKIND_VIEW)
elog(ERROR, "TRUNCATE cannot be used on views. '%s' is a view",
RelationGetRelationName(rel));
if (!allowSystemTableMods && IsSystemRelation(rel))
elog(ERROR, "TRUNCATE cannot be used on system tables. '%s' is a system table",
RelationGetRelationName(rel));
if (!pg_class_ownercheck(relid, GetUserId()))
elog(ERROR, "you do not own relation \"%s\"",
RelationGetRelationName(rel));
/* Keep the lock until transaction commit */
heap_close(rel, NoLock);
heap_truncate(relid);
}
/*
* MergeDomainAttributes
* Returns a new table schema with the constraints, types, and other
* attributes of domains resolved for fields using a domain as
* their type.
*/
static List *
MergeDomainAttributes(List *schema)
{
List *entry;
/*
* Loop through the table elements supplied. These should
* never include inherited domains else they'll be
* double (or more) processed.
*/
foreach(entry, schema)
{
ColumnDef *coldef = lfirst(entry);
HeapTuple tuple;
Form_pg_type typeTup;
tuple = typenameType(coldef->typename);
typeTup = (Form_pg_type) GETSTRUCT(tuple);
if (typeTup->typtype == 'd')
{
/* Force the column to have the correct typmod. */
coldef->typename->typmod = typeTup->typtypmod;
/* XXX more to do here? */
}
/* Enforce type NOT NULL || column definition NOT NULL -> NOT NULL */
/* Currently only used for domains, but could be valid for all */
coldef->is_not_null |= typeTup->typnotnull;
ReleaseSysCache(tuple);
}
return schema;
}
/*----------
* MergeAttributes
* Returns new schema given initial schema and superclasses.
*
* Input arguments:
* 'schema' is the column/attribute definition for the table. (It's a list
* of ColumnDef's.) It is destructively changed.
* 'supers' is a list of names (as RangeVar nodes) of parent relations.
* 'istemp' is TRUE if we are creating a temp relation.
*
* Output arguments:
* 'supOids' receives an integer list of the OIDs of the parent relations.
* 'supconstr' receives a list of constraints belonging to the parents,
* updated as necessary to be valid for the child.
* 'supHasOids' is set TRUE if any parent has OIDs, else it is set FALSE.
*
* Return value:
* Completed schema list.
*
* Notes:
* The order in which the attributes are inherited is very important.
* Intuitively, the inherited attributes should come first. If a table
* inherits from multiple parents, the order of those attributes are
* according to the order of the parents specified in CREATE TABLE.
*
* Here's an example:
*
* create table person (name text, age int4, location point);
* create table emp (salary int4, manager text) inherits(person);
* create table student (gpa float8) inherits (person);
* create table stud_emp (percent int4) inherits (emp, student);
*
* The order of the attributes of stud_emp is:
*
* person {1:name, 2:age, 3:location}
* / \
* {6:gpa} student emp {4:salary, 5:manager}
* \ /
* stud_emp {7:percent}
*
* If the same attribute name appears multiple times, then it appears
* in the result table in the proper location for its first appearance.
*
* Constraints (including NOT NULL constraints) for the child table
* are the union of all relevant constraints, from both the child schema
* and parent tables.
*
* The default value for a child column is defined as:
* (1) If the child schema specifies a default, that value is used.
* (2) If neither the child nor any parent specifies a default, then
* the column will not have a default.
* (3) If conflicting defaults are inherited from different parents
* (and not overridden by the child), an error is raised.
* (4) Otherwise the inherited default is used.
* Rule (3) is new in Postgres 7.1; in earlier releases you got a
* rather arbitrary choice of which parent default to use.
*----------
*/
static List *
MergeAttributes(List *schema, List *supers, bool istemp,
List **supOids, List **supconstr, bool *supHasOids)
{
List *entry;
List *inhSchema = NIL;
List *parentOids = NIL;
List *constraints = NIL;
bool parentHasOids = false;
bool have_bogus_defaults = false;
char *bogus_marker = "Bogus!"; /* marks conflicting
* defaults */
int child_attno;
/*
* Check for duplicate names in the explicit list of attributes.
*
* Although we might consider merging such entries in the same way that
* we handle name conflicts for inherited attributes, it seems to make
* more sense to assume such conflicts are errors.
*/
foreach(entry, schema)
{
ColumnDef *coldef = lfirst(entry);
List *rest;
foreach(rest, lnext(entry))
{
ColumnDef *restdef = lfirst(rest);
if (strcmp(coldef->colname, restdef->colname) == 0)
elog(ERROR, "CREATE TABLE: attribute \"%s\" duplicated",
coldef->colname);
}
}
/*
* Scan the parents left-to-right, and merge their attributes to form
* a list of inherited attributes (inhSchema). Also check to see if
* we need to inherit an OID column.
*/
child_attno = 0;
foreach(entry, supers)
{
RangeVar *parent = (RangeVar *) lfirst(entry);
Relation relation;
TupleDesc tupleDesc;
TupleConstr *constr;
AttrNumber *newattno;
AttrNumber parent_attno;
relation = heap_openrv(parent, AccessShareLock);
if (relation->rd_rel->relkind != RELKIND_RELATION)
elog(ERROR, "CREATE TABLE: inherited relation \"%s\" is not a table",
parent->relname);
/* Permanent rels cannot inherit from temporary ones */
if (!istemp && isTempNamespace(RelationGetNamespace(relation)))
elog(ERROR, "CREATE TABLE: cannot inherit from temp relation \"%s\"",
parent->relname);
/*
* We should have an UNDER permission flag for this, but for now,
* demand that creator of a child table own the parent.
*/
if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
elog(ERROR, "you do not own table \"%s\"",
parent->relname);
/*
* Reject duplications in the list of parents.
*/
if (intMember(RelationGetRelid(relation), parentOids))
elog(ERROR, "CREATE TABLE: inherited relation \"%s\" duplicated",
parent->relname);
parentOids = lappendi(parentOids, RelationGetRelid(relation));
setRelhassubclassInRelation(RelationGetRelid(relation), true);
parentHasOids |= relation->rd_rel->relhasoids;
tupleDesc = RelationGetDescr(relation);
constr = tupleDesc->constr;
/*
* newattno[] will contain the child-table attribute numbers for
* the attributes of this parent table. (They are not the same
* for parents after the first one.)
*/
newattno = (AttrNumber *) palloc(tupleDesc->natts * sizeof(AttrNumber));
for (parent_attno = 1; parent_attno <= tupleDesc->natts;
parent_attno++)
{
Form_pg_attribute attribute = tupleDesc->attrs[parent_attno - 1];
char *attributeName = NameStr(attribute->attname);
int exist_attno;
ColumnDef *def;
TypeName *typename;
/*
* Does it conflict with some previously inherited column?
*/
exist_attno = findAttrByName(attributeName, inhSchema);
if (exist_attno > 0)
{
/*
* Yes, try to merge the two column definitions. They must
* have the same type and typmod.
*/
elog(NOTICE, "CREATE TABLE: merging multiple inherited definitions of attribute \"%s\"",
attributeName);
def = (ColumnDef *) nth(exist_attno - 1, inhSchema);
if (typenameTypeId(def->typename) != attribute->atttypid ||
def->typename->typmod != attribute->atttypmod)
elog(ERROR, "CREATE TABLE: inherited attribute \"%s\" type conflict (%s and %s)",
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 */
newattno[parent_attno - 1] = exist_attno;
}
else
{
/*
* No, create a new inherited column
*/
def = makeNode(ColumnDef);
def->colname = pstrdup(attributeName);
typename = makeNode(TypeName);
typename->typeid = attribute->atttypid;
typename->typmod = attribute->atttypmod;
def->typename = typename;
def->is_not_null = attribute->attnotnull;
def->raw_default = NULL;
def->cooked_default = NULL;
def->constraints = NIL;
inhSchema = lappend(inhSchema, def);
newattno[parent_attno - 1] = ++child_attno;
}
/*
* Copy default if any
*/
if (attribute->atthasdef)
{
char *this_default = NULL;
AttrDefault *attrdef;
int i;
/* Find default in constraint structure */
Assert(constr != NULL);
attrdef = constr->defval;
for (i = 0; i < constr->num_defval; i++)
{
if (attrdef[i].adnum == parent_attno)
{
this_default = attrdef[i].adbin;
break;
}
}
Assert(this_default != NULL);
/*
* If default expr could contain any vars, we'd need to
* fix 'em, but it can't; so default is ready to apply to
* child.
*
* If we already had a default from some prior parent, check
* to see if they are the same. If so, no problem; if
* not, mark the column as having a bogus default. Below,
* we will complain if the bogus default isn't overridden
* by the child schema.
*/
Assert(def->raw_default == NULL);
if (def->cooked_default == NULL)
def->cooked_default = pstrdup(this_default);
else if (strcmp(def->cooked_default, this_default) != 0)
{
def->cooked_default = bogus_marker;
have_bogus_defaults = true;
}
}
}
/*
* Now copy the constraints of this parent, adjusting attnos using
* the completed newattno[] map
*/
if (constr && constr->num_check > 0)
{
ConstrCheck *check = constr->check;
int i;
for (i = 0; i < constr->num_check; i++)
{
Constraint *cdef = makeNode(Constraint);
Node *expr;
cdef->contype = CONSTR_CHECK;
if (check[i].ccname[0] == '$')
cdef->name = NULL;
else
cdef->name = pstrdup(check[i].ccname);
cdef->raw_expr = NULL;
/* adjust varattnos of ccbin here */
expr = stringToNode(check[i].ccbin);
change_varattnos_of_a_node(expr, newattno);
cdef->cooked_expr = nodeToString(expr);
constraints = lappend(constraints, cdef);
}
}
pfree(newattno);
/*
* Close the parent rel, but keep our AccessShareLock on it until
* xact commit. That will prevent someone else from deleting or
* ALTERing the parent before the child is committed.
*/
heap_close(relation, NoLock);
}
/*
* If we had no inherited attributes, the result schema is just the
* explicitly declared columns. Otherwise, we need to merge the
* declared columns into the inherited schema list.
*/
if (inhSchema != NIL)
{
foreach(entry, schema)
{
ColumnDef *newdef = lfirst(entry);
char *attributeName = newdef->colname;
int exist_attno;
/*
* Does it conflict with some previously inherited column?
*/
exist_attno = findAttrByName(attributeName, inhSchema);
if (exist_attno > 0)
{
ColumnDef *def;
/*
* Yes, try to merge the two column definitions. They must
* have the same type and typmod.
*/
elog(NOTICE, "CREATE TABLE: merging attribute \"%s\" with inherited definition",
attributeName);
def = (ColumnDef *) nth(exist_attno - 1, inhSchema);
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,
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 */
if (newdef->raw_default != NULL)
{
def->raw_default = newdef->raw_default;
def->cooked_default = newdef->cooked_default;
}
}
else
{
/*
* No, attach new column to result schema
*/
inhSchema = lappend(inhSchema, newdef);
}
}
schema = inhSchema;
}
/*
* If we found any conflicting parent default values, check to make
* sure they were overridden by the child.
*/
if (have_bogus_defaults)
{
foreach(entry, schema)
{
ColumnDef *def = lfirst(entry);
if (def->cooked_default == bogus_marker)
elog(ERROR, "CREATE TABLE: attribute \"%s\" inherits conflicting default values"
"\n\tTo resolve the conflict, specify a default explicitly",
def->colname);
}
}
*supOids = parentOids;
*supconstr = constraints;
*supHasOids = parentHasOids;
return schema;
}
/*
* complementary static functions for MergeAttributes().
*
* Varattnos of pg_relcheck.rcbin must be rewritten when subclasses inherit
* constraints from parent classes, since the inherited attributes could
* be given different column numbers in multiple-inheritance cases.
*
* Note that the passed node tree is modified in place!
*/
static bool
change_varattnos_walker(Node *node, const AttrNumber *newattno)
{
if (node == NULL)
return false;
if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varlevelsup == 0 && var->varno == 1 &&
var->varattno > 0)
{
/*
* ??? the following may be a problem when the node is
* multiply referenced though stringToNode() doesn't create
* such a node currently.
*/
Assert(newattno[var->varattno - 1] > 0);
var->varattno = newattno[var->varattno - 1];
}
return false;
}
return expression_tree_walker(node, change_varattnos_walker,
(void *) newattno);
}
static bool
change_varattnos_of_a_node(Node *node, const AttrNumber *newattno)
{
return change_varattnos_walker(node, newattno);
}
/*
* StoreCatalogInheritance
* Updates the system catalogs with proper inheritance information.
*
* supers is an integer list of the OIDs of the new relation's direct
* ancestors. NB: it is destructively changed to include indirect ancestors.
*/
static void
StoreCatalogInheritance(Oid relationId, List *supers)
{
Relation relation;
TupleDesc desc;
int16 seqNumber;
List *entry;
HeapTuple tuple;
/*
* sanity checks
*/
AssertArg(OidIsValid(relationId));
if (supers == NIL)
return;
/*
* Catalog INHERITS information using direct ancestors only.
*/
relation = heap_openr(InheritsRelationName, RowExclusiveLock);
desc = RelationGetDescr(relation);
seqNumber = 1;
foreach(entry, supers)
{
Oid entryOid = lfirsti(entry);
Datum datum[Natts_pg_inherits];
char nullarr[Natts_pg_inherits];
datum[0] = ObjectIdGetDatum(relationId); /* inhrel */
datum[1] = ObjectIdGetDatum(entryOid); /* inhparent */
datum[2] = Int16GetDatum(seqNumber); /* inhseqno */
nullarr[0] = ' ';
nullarr[1] = ' ';
nullarr[2] = ' ';
tuple = heap_formtuple(desc, datum, nullarr);
heap_insert(relation, tuple);
if (RelationGetForm(relation)->relhasindex)
{
Relation idescs[Num_pg_inherits_indices];
CatalogOpenIndices(Num_pg_inherits_indices, Name_pg_inherits_indices, idescs);
CatalogIndexInsert(idescs, Num_pg_inherits_indices, relation, tuple);
CatalogCloseIndices(Num_pg_inherits_indices, idescs);
}
heap_freetuple(tuple);
seqNumber += 1;
}
heap_close(relation, RowExclusiveLock);
/* ----------------
* Expand supers list to include indirect ancestors as well.
*
* Algorithm:
* 0. begin with list of direct superclasses.
* 1. append after each relationId, its superclasses, recursively.
* 2. remove all but last of duplicates.
* ----------------
*/
/*
* 1. append after each relationId, its superclasses, recursively.
*/
foreach(entry, supers)
{
HeapTuple tuple;
Oid id;
int16 number;
List *next;
List *current;
id = (Oid) lfirsti(entry);
current = entry;
next = lnext(entry);
for (number = 1;; number += 1)
{
tuple = SearchSysCache(INHRELID,
ObjectIdGetDatum(id),
Int16GetDatum(number),
0, 0);
if (!HeapTupleIsValid(tuple))
break;
lnext(current) = lconsi(((Form_pg_inherits)
GETSTRUCT(tuple))->inhparent,
NIL);
ReleaseSysCache(tuple);
current = lnext(current);
}
lnext(current) = next;
}
/*
* 2. remove all but last of duplicates.
*/
foreach(entry, supers)
{
Oid thisone;
bool found;
List *rest;
again:
thisone = lfirsti(entry);
found = false;
foreach(rest, lnext(entry))
{
if (thisone == lfirsti(rest))
{
found = true;
break;
}
}
if (found)
{
/*
* found a later duplicate, so remove this entry.
*/
lfirsti(entry) = lfirsti(lnext(entry));
lnext(entry) = lnext(lnext(entry));
goto again;
}
}
}
/*
* Look for an existing schema entry with the given name.
*
* Returns the index (starting with 1) if attribute already exists in schema,
* 0 if it doesn't.
*/
static int
findAttrByName(const char *attributeName, List *schema)
{
List *s;
int i = 0;
foreach(s, schema)
{
ColumnDef *def = lfirst(s);
++i;
if (strcmp(attributeName, def->colname) == 0)
return i;
}
return 0;
}
/*
* Update a relation's pg_class.relhassubclass entry to the given value
*/
static void
setRelhassubclassInRelation(Oid relationId, bool relhassubclass)
{
Relation relationRelation;
HeapTuple tuple;
Relation idescs[Num_pg_class_indices];
/*
* Fetch a modifiable copy of the tuple, modify it, update pg_class.
*/
relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
tuple = SearchSysCacheCopy(RELOID,
ObjectIdGetDatum(relationId),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "setRelhassubclassInRelation: cache lookup failed for relation %u", relationId);
((Form_pg_class) GETSTRUCT(tuple))->relhassubclass = relhassubclass;
simple_heap_update(relationRelation, &tuple->t_self, tuple);
/* keep the catalog indices up to date */
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
CatalogIndexInsert(idescs, Num_pg_class_indices, relationRelation, tuple);
CatalogCloseIndices(Num_pg_class_indices, idescs);
heap_freetuple(tuple);
heap_close(relationRelation, RowExclusiveLock);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,431 @@
/*-------------------------------------------------------------------------
*
* functioncmds.c
*
* Routines for CREATE and DROP FUNCTION commands
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.1 2002/04/15 05:22:03 tgl Exp $
*
* DESCRIPTION
* These routines take the parse tree and pick out the
* appropriate arguments/flags, and pass the results to the
* corresponding "FooDefine" routines (in src/catalog) that do
* the actual catalog-munging. These routines also verify permission
* of the user to execute the command.
*
* NOTES
* These things must be defined and committed in the following order:
* "create function":
* input/output, recv/send procedures
* "create type":
* type
* "create operator":
* operators
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/namespace.h"
#include "catalog/pg_language.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/comment.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "optimizer/cost.h"
#include "parser/parse_func.h"
#include "parser/parse_type.h"
#include "utils/acl.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
/*
* 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.
*/
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;
}
/*
* Interpret the argument-types list of the CREATE FUNCTION statement.
*/
static int
compute_parameter_types(List *argTypes, Oid languageOid,
Oid *parameterTypes)
{
int parameterCount = 0;
List *x;
MemSet(parameterTypes, 0, FUNC_MAX_ARGS * sizeof(Oid));
foreach(x, argTypes)
{
TypeName *t = (TypeName *) lfirst(x);
Oid toid;
if (parameterCount >= FUNC_MAX_ARGS)
elog(ERROR, "functions cannot have more than %d arguments",
FUNC_MAX_ARGS);
toid = LookupTypeName(t);
if (OidIsValid(toid))
{
if (!get_typisdefined(toid))
elog(WARNING, "Argument type \"%s\" is only a shell",
TypeNameToString(t));
}
else
{
char *typnam = TypeNameToString(t);
if (strcmp(typnam, "opaque") == 0)
{
if (languageOid == SQLlanguageId)
elog(ERROR, "SQL functions cannot have arguments of type \"opaque\"");
toid = InvalidOid;
}
else
elog(ERROR, "Type \"%s\" does not exist", typnam);
}
if (t->setof)
elog(ERROR, "functions cannot accept set arguments");
parameterTypes[parameterCount++] = toid;
}
return parameterCount;
}
/*-------------
* Interpret the parameters *parameters and return their contents as
* *byte_pct_p, etc.
*
* These parameters supply optional information about a function.
* All have defaults if not specified.
*
* Note: currently, only three of these parameters actually do anything:
*
* * isImplicit means the function may be used as an implicit type
* coercion.
*
* * isStrict means the function should not be called when any NULL
* inputs are present; instead a NULL result value should be assumed.
*
* * volatility tells the optimizer whether the function's result can
* be assumed to be repeatable over multiple evaluations.
*
* The other four parameters are not used anywhere. They used to be
* used in the "expensive functions" optimizer, but that's been dead code
* for a long time.
*------------
*/
static void
compute_full_attributes(List *parameters,
int32 *byte_pct_p, int32 *perbyte_cpu_p,
int32 *percall_cpu_p, int32 *outin_ratio_p,
bool *isImplicit_p, bool *isStrict_p,
char *volatility_p)
{
List *pl;
/* the defaults */
*byte_pct_p = BYTE_PCT;
*perbyte_cpu_p = PERBYTE_CPU;
*percall_cpu_p = PERCALL_CPU;
*outin_ratio_p = OUTIN_RATIO;
*isImplicit_p = false;
*isStrict_p = false;
*volatility_p = PROVOLATILE_VOLATILE;
foreach(pl, parameters)
{
DefElem *param = (DefElem *) lfirst(pl);
if (strcasecmp(param->defname, "implicitcoercion") == 0)
*isImplicit_p = true;
else if (strcasecmp(param->defname, "isstrict") == 0)
*isStrict_p = true;
else if (strcasecmp(param->defname, "isimmutable") == 0)
*volatility_p = PROVOLATILE_IMMUTABLE;
else if (strcasecmp(param->defname, "isstable") == 0)
*volatility_p = PROVOLATILE_STABLE;
else if (strcasecmp(param->defname, "isvolatile") == 0)
*volatility_p = PROVOLATILE_VOLATILE;
else if (strcasecmp(param->defname, "iscachable") == 0)
{
/* obsolete spelling of isImmutable */
*volatility_p = PROVOLATILE_IMMUTABLE;
}
else if (strcasecmp(param->defname, "trusted") == 0)
{
/*
* we don't have untrusted functions any more. The 4.2
* implementation is lousy anyway so I took it out. -ay 10/94
*/
elog(ERROR, "untrusted function has been decommissioned.");
}
else if (strcasecmp(param->defname, "byte_pct") == 0)
*byte_pct_p = (int) defGetNumeric(param);
else if (strcasecmp(param->defname, "perbyte_cpu") == 0)
*perbyte_cpu_p = (int) defGetNumeric(param);
else if (strcasecmp(param->defname, "percall_cpu") == 0)
*percall_cpu_p = (int) defGetNumeric(param);
else if (strcasecmp(param->defname, "outin_ratio") == 0)
*outin_ratio_p = (int) defGetNumeric(param);
else
elog(WARNING, "Unrecognized function attribute '%s' ignored",
param->defname);
}
}
/*
* For a dynamically linked C language object, the form of the clause is
*
* AS <object file name> [, <link symbol name> ]
*
* In all other cases
*
* AS <object reference, or sql code>
*
*/
static void
interpret_AS_clause(Oid languageOid, const char *languageName, const List *as,
char **prosrc_str_p, char **probin_str_p)
{
Assert(as != NIL);
if (languageOid == ClanguageId)
{
/*
* For "C" language, store the file name in probin and, when
* given, the link symbol name in prosrc.
*/
*probin_str_p = strVal(lfirst(as));
if (lnext(as) == NULL)
*prosrc_str_p = "-";
else
*prosrc_str_p = strVal(lsecond(as));
}
else
{
/* Everything else wants the given string in prosrc. */
*prosrc_str_p = strVal(lfirst(as));
*probin_str_p = "-";
if (lnext(as) != NIL)
elog(ERROR, "CREATE FUNCTION: only one AS item needed for %s language",
languageName);
}
}
/*
* CreateFunction
* Execute a CREATE FUNCTION utility statement.
*/
void
CreateFunction(ProcedureStmt *stmt)
{
char *probin_str;
char *prosrc_str;
Oid prorettype;
bool returnsSet;
char languageName[NAMEDATALEN];
Oid languageOid;
char *funcname;
Oid namespaceId;
int parameterCount;
Oid parameterTypes[FUNC_MAX_ARGS];
int32 byte_pct,
perbyte_cpu,
percall_cpu,
outin_ratio;
bool isImplicit,
isStrict;
char volatility;
HeapTuple languageTuple;
Form_pg_language languageStruct;
/* 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);
if (!HeapTupleIsValid(languageTuple))
elog(ERROR, "language \"%s\" does not exist", languageName);
languageOid = languageTuple->t_data->t_oid;
languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
if (!((languageStruct->lanpltrusted
&& pg_language_aclcheck(languageOid, GetUserId()) == ACLCHECK_OK)
|| superuser()))
elog(ERROR, "permission denied");
ReleaseSysCache(languageTuple);
/*
* Convert remaining parameters of CREATE to form wanted by
* ProcedureCreate.
*/
compute_return_type(stmt->returnType, languageOid,
&prorettype, &returnsSet);
parameterCount = compute_parameter_types(stmt->argTypes, languageOid,
parameterTypes);
compute_full_attributes(stmt->withClause,
&byte_pct, &perbyte_cpu, &percall_cpu,
&outin_ratio, &isImplicit, &isStrict,
&volatility);
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(funcname,
namespaceId,
stmt->replace,
returnsSet,
prorettype,
languageOid,
prosrc_str, /* converted to text later */
probin_str, /* converted to text later */
false, /* not an aggregate */
true, /* (obsolete "trusted") */
isImplicit,
isStrict,
volatility,
byte_pct,
perbyte_cpu,
percall_cpu,
outin_ratio,
parameterCount,
parameterTypes);
}
/*
* RemoveFunction
* Deletes a function.
*
* Exceptions:
* BadArg if name is invalid.
* "ERROR" if function nonexistent.
* ...
*/
void
RemoveFunction(List *functionName, /* function name to be removed */
List *argTypes) /* list of TypeName nodes */
{
Oid funcOid;
Relation relation;
HeapTuple tup;
funcOid = LookupFuncNameTypeNames(functionName, argTypes,
true, "RemoveFunction");
relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
tup = SearchSysCache(PROCOID,
ObjectIdGetDatum(funcOid),
0, 0, 0);
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "RemoveFunction: couldn't find tuple for function %s",
NameListToString(functionName));
if (!pg_proc_ownercheck(funcOid, GetUserId()))
elog(ERROR, "RemoveFunction: function '%s': permission denied",
NameListToString(functionName));
if (((Form_pg_proc) GETSTRUCT(tup))->proisagg)
elog(ERROR, "RemoveFunction: function '%s' is an aggregate"
"\n\tUse DROP AGGREGATE to remove it",
NameListToString(functionName));
if (((Form_pg_proc) GETSTRUCT(tup))->prolang == INTERNALlanguageId)
{
/* "Helpful" WARNING when removing a builtin function ... */
elog(WARNING, "Removing built-in function \"%s\"",
NameListToString(functionName));
}
/* Delete any comments associated with this function */
DeleteComments(funcOid, RelationGetRelid(relation));
simple_heap_delete(relation, &tup->t_self);
ReleaseSysCache(tup);
heap_close(relation, RowExclusiveLock);
}

View File

@ -0,0 +1,69 @@
/*-------------------------------------------------------------------------
*
* lockcmds.c
* Lock command support code
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/lockcmds.c,v 1.1 2002/04/15 05:22:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/heapam.h"
#include "catalog/namespace.h"
#include "commands/lockcmds.h"
#include "miscadmin.h"
#include "utils/acl.h"
/*
* LOCK TABLE
*/
void
LockTableCommand(LockStmt *lockstmt)
{
List *p;
/*
* Iterate over the list and open, lock, and close the relations one
* at a time
*/
foreach(p, lockstmt->relations)
{
RangeVar *relation = lfirst(p);
Oid reloid;
int32 aclresult;
Relation rel;
/*
* We don't want to open the relation until we've checked privilege.
* So, manually get the relation OID.
*/
reloid = RangeVarGetRelid(relation, false);
if (lockstmt->mode == AccessShareLock)
aclresult = pg_class_aclcheck(reloid, GetUserId(),
ACL_SELECT);
else
aclresult = pg_class_aclcheck(reloid, GetUserId(),
ACL_UPDATE | ACL_DELETE);
if (aclresult != ACLCHECK_OK)
elog(ERROR, "LOCK TABLE: permission denied");
rel = relation_open(reloid, lockstmt->mode);
/* Currently, we only allow plain tables to be locked */
if (rel->rd_rel->relkind != RELKIND_RELATION)
elog(ERROR, "LOCK TABLE: %s is not a table",
relation->relname);
relation_close(rel, NoLock); /* close rel, keep lock */
}
}

View File

@ -0,0 +1,247 @@
/*-------------------------------------------------------------------------
*
* operatorcmds.c
*
* Routines for operator manipulation commands
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/operatorcmds.c,v 1.1 2002/04/15 05:22:03 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
* appropriate arguments/flags, passing the results to the
* corresponding "FooDefine" routines (in src/catalog) that do
* the actual catalog-munging. These routines also verify permission
* of the user to execute the command.
*
* NOTES
* These things must be defined and committed in the following order:
* "create function":
* input/output, recv/send procedures
* "create type":
* type
* "create operator":
* operators
*
* Most of the parse-tree manipulation routines are defined in
* commands/manip.c.
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/namespace.h"
#include "catalog/pg_operator.h"
#include "commands/comment.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "parser/parse_type.h"
#include "utils/acl.h"
#include "utils/syscache.h"
/*
* 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(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 */
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 */
char *restrictionName = NULL; /* optional restrict. sel.
* procedure */
char *joinName = NULL; /* optional join sel. procedure name */
char *sortName1 = NULL; /* optional first sort operator */
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.
*/
foreach(pl, parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
if (strcasecmp(defel->defname, "leftarg") == 0)
{
typeName1 = defGetTypeName(defel);
if (typeName1->setof)
elog(ERROR, "setof type not implemented for leftarg");
}
else if (strcasecmp(defel->defname, "rightarg") == 0)
{
typeName2 = defGetTypeName(defel);
if (typeName2->setof)
elog(ERROR, "setof type not implemented for rightarg");
}
else if (strcasecmp(defel->defname, "procedure") == 0)
functionName = defGetString(defel);
else if (strcasecmp(defel->defname, "precedence") == 0)
{
/* NOT IMPLEMENTED (never worked in v4.2) */
elog(NOTICE, "CREATE OPERATOR: precedence not implemented");
}
else if (strcasecmp(defel->defname, "associativity") == 0)
{
/* NOT IMPLEMENTED (never worked in v4.2) */
elog(NOTICE, "CREATE OPERATOR: associativity not implemented");
}
else if (strcasecmp(defel->defname, "commutator") == 0)
commutatorName = defGetString(defel);
else if (strcasecmp(defel->defname, "negator") == 0)
negatorName = defGetString(defel);
else if (strcasecmp(defel->defname, "restrict") == 0)
restrictionName = defGetString(defel);
else if (strcasecmp(defel->defname, "join") == 0)
joinName = defGetString(defel);
else if (strcasecmp(defel->defname, "hashes") == 0)
canHash = TRUE;
else if (strcasecmp(defel->defname, "sort1") == 0)
sortName1 = defGetString(defel);
else if (strcasecmp(defel->defname, "sort2") == 0)
sortName2 = defGetString(defel);
else
{
elog(WARNING, "DefineOperator: attribute \"%s\" not recognized",
defel->defname);
}
}
/*
* make sure we have our required definitions
*/
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 */
typeId1, /* left type id */
typeId2, /* right type id */
functionName, /* function for operator */
precedence, /* operator precedence */
isLeftAssociative, /* operator is left associative */
commutatorName, /* optional commutator operator
* name */
negatorName, /* optional negator operator name */
restrictionName, /* optional restrict. sel.
* procedure */
joinName, /* optional join sel. procedure name */
canHash, /* operator hashes */
sortName1, /* optional first sort operator */
sortName2); /* optional second sort operator */
}
/*
* RemoveOperator
* Deletes an operator.
*
* Exceptions:
* BadArg if name is invalid.
* BadArg if type1 is invalid.
* "ERROR" if operator nonexistent.
* ...
*/
void
RemoveOperator(char *operatorName, /* operator name */
TypeName *typeName1, /* left argument type name */
TypeName *typeName2) /* right argument type name */
{
Relation relation;
HeapTuple tup;
Oid typeId1 = InvalidOid;
Oid typeId2 = InvalidOid;
char oprtype;
if (typeName1)
typeId1 = typenameTypeId(typeName1);
if (typeName2)
typeId2 = typenameTypeId(typeName2);
if (OidIsValid(typeId1) && OidIsValid(typeId2))
oprtype = 'b';
else if (OidIsValid(typeId1))
oprtype = 'r';
else
oprtype = 'l';
relation = heap_openr(OperatorRelationName, RowExclusiveLock);
tup = SearchSysCacheCopy(OPERNAME,
PointerGetDatum(operatorName),
ObjectIdGetDatum(typeId1),
ObjectIdGetDatum(typeId2),
CharGetDatum(oprtype));
if (HeapTupleIsValid(tup))
{
if (!pg_oper_ownercheck(tup->t_data->t_oid, GetUserId()))
elog(ERROR, "RemoveOperator: operator '%s': permission denied",
operatorName);
/* Delete any comments associated with this operator */
DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation));
simple_heap_delete(relation, &tup->t_self);
}
else
{
if (OidIsValid(typeId1) && OidIsValid(typeId2))
{
elog(ERROR, "RemoveOperator: binary operator '%s' taking '%s' and '%s' does not exist",
operatorName,
TypeNameToString(typeName1),
TypeNameToString(typeName2));
}
else if (OidIsValid(typeId1))
{
elog(ERROR, "RemoveOperator: right unary operator '%s' taking '%s' does not exist",
operatorName,
TypeNameToString(typeName1));
}
else
{
elog(ERROR, "RemoveOperator: left unary operator '%s' taking '%s' does not exist",
operatorName,
TypeNameToString(typeName2));
}
}
heap_freetuple(tup);
heap_close(relation, RowExclusiveLock);
}

View File

@ -0,0 +1,234 @@
/*-------------------------------------------------------------------------
*
* portalcmds.c
* portal support code
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.1 2002/04/15 05:22:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "commands/portalcmds.h"
#include "executor/executor.h"
/*
* PortalCleanup
*/
void
PortalCleanup(Portal portal)
{
MemoryContext oldcontext;
/*
* sanity checks
*/
AssertArg(PortalIsValid(portal));
AssertArg(portal->cleanup == PortalCleanup);
/*
* set proper portal-executor context before calling ExecMain.
*/
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
/*
* tell the executor to shutdown the query
*/
ExecutorEnd(PortalGetQueryDesc(portal), PortalGetState(portal));
/*
* switch back to previous context
*/
MemoryContextSwitchTo(oldcontext);
}
/*
* PerformPortalFetch
*
* name: name of portal
* forward: forward or backward fetch?
* count: # of tuples to fetch (0 implies all)
* dest: where to send results
* completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
* in which to store a command completion status string.
*
* completionTag may be NULL if caller doesn't want a status string.
*/
void
PerformPortalFetch(char *name,
bool forward,
int count,
CommandDest dest,
char *completionTag)
{
Portal portal;
QueryDesc *queryDesc;
EState *estate;
MemoryContext oldcontext;
ScanDirection direction;
CommandId savedId;
bool temp_desc = false;
/* initialize completion status in case of early exit */
if (completionTag)
strcpy(completionTag, (dest == None) ? "MOVE 0" : "FETCH 0");
/*
* sanity checks
*/
if (name == NULL)
{
elog(WARNING, "PerformPortalFetch: missing portal name");
return;
}
/*
* get the portal from the portal name
*/
portal = GetPortalByName(name);
if (!PortalIsValid(portal))
{
elog(WARNING, "PerformPortalFetch: portal \"%s\" not found",
name);
return;
}
/*
* switch into the portal context
*/
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
queryDesc = PortalGetQueryDesc(portal);
estate = PortalGetState(portal);
/*
* If the requested destination is not the same as the query's
* original destination, make a temporary QueryDesc with the proper
* destination. This supports MOVE, for example, which will pass in
* dest = None.
*
* EXCEPTION: if the query's original dest is RemoteInternal (ie, it's a
* binary cursor) and the request is Remote, we do NOT override the
* original dest. This is necessary since a FETCH command will pass
* dest = Remote, not knowing whether the cursor is binary or not.
*/
if (dest != queryDesc->dest &&
!(queryDesc->dest == RemoteInternal && dest == Remote))
{
QueryDesc *qdesc = (QueryDesc *) palloc(sizeof(QueryDesc));
memcpy(qdesc, queryDesc, sizeof(QueryDesc));
qdesc->dest = dest;
queryDesc = qdesc;
temp_desc = true;
}
/*
* Restore the scanCommandId that was current when the cursor was
* opened. This ensures that we see the same tuples throughout the
* execution of the cursor.
*/
savedId = GetScanCommandId();
SetScanCommandId(PortalGetCommandId(portal));
/*
* Determine which direction to go in, and check to see if we're
* already at the end of the available tuples in that direction. If
* so, set the direction to NoMovement to avoid trying to fetch any
* tuples. (This check exists because not all plan node types
* are robust about being called again if they've already returned
* NULL once.) Then call the executor (we must not skip this, because
* the destination needs to see a setup and shutdown even if no tuples
* are available). Finally, update the atStart/atEnd state depending
* on the number of tuples that were retrieved.
*/
if (forward)
{
if (portal->atEnd)
direction = NoMovementScanDirection;
else
direction = ForwardScanDirection;
ExecutorRun(queryDesc, estate, direction, (long) count);
if (estate->es_processed > 0)
portal->atStart = false; /* OK to back up now */
if (count <= 0 || (int) estate->es_processed < count)
portal->atEnd = true; /* we retrieved 'em all */
}
else
{
if (portal->atStart)
direction = NoMovementScanDirection;
else
direction = BackwardScanDirection;
ExecutorRun(queryDesc, estate, direction, (long) count);
if (estate->es_processed > 0)
portal->atEnd = false; /* OK to go forward now */
if (count <= 0 || (int) estate->es_processed < count)
portal->atStart = true; /* we retrieved 'em all */
}
/* Return command status if wanted */
if (completionTag)
snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u",
(dest == None) ? "MOVE" : "FETCH",
estate->es_processed);
/*
* Restore outer command ID.
*/
SetScanCommandId(savedId);
/*
* Clean up and switch back to old context.
*/
if (temp_desc)
pfree(queryDesc);
MemoryContextSwitchTo(oldcontext);
}
/*
* PerformPortalClose
*/
void
PerformPortalClose(char *name, CommandDest dest)
{
Portal portal;
/*
* sanity checks
*/
if (name == NULL)
{
elog(WARNING, "PerformPortalClose: missing portal name");
return;
}
/*
* get the portal from the portal name
*/
portal = GetPortalByName(name);
if (!PortalIsValid(portal))
{
elog(WARNING, "PerformPortalClose: portal \"%s\" not found",
name);
return;
}
/*
* Note: PortalCleanup is called as a side-effect
*/
PortalDrop(portal);
}

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.30 2002/04/09 20:35:48 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.31 2002/04/15 05:22:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -22,6 +22,7 @@
#include "catalog/pg_language.h"
#include "catalog/pg_proc.h"
#include "commands/proclang.h"
#include "commands/defrem.h"
#include "fmgr.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
@ -30,21 +31,6 @@
#include "utils/syscache.h"
/*
* Translate the input language name to lower case.
*/
static void
case_translate_language_name(const char *input, char *output)
{
int i;
for (i = 0; i < NAMEDATALEN && input[i]; ++i)
output[i] = tolower((unsigned char) input[i]);
output[i] = '\0';
}
/* ---------------------------------------------------------------------
* CREATE PROCEDURAL LANGUAGE
* ---------------------------------------------------------------------

View File

@ -1,476 +0,0 @@
/*-------------------------------------------------------------------------
*
* remove.c
* POSTGRES remove (domain | function | type | operator ) utilty code.
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.74 2002/04/11 19:59:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/namespace.h"
#include "catalog/pg_language.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/comment.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "parser/parse.h"
#include "parser/parse_func.h"
#include "parser/parse_type.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/syscache.h"
/*
* RemoveOperator
* Deletes an operator.
*
* Exceptions:
* BadArg if name is invalid.
* BadArg if type1 is invalid.
* "ERROR" if operator nonexistent.
* ...
*/
void
RemoveOperator(char *operatorName, /* operator name */
TypeName *typeName1, /* left argument type name */
TypeName *typeName2) /* right argument type name */
{
Relation relation;
HeapTuple tup;
Oid typeId1 = InvalidOid;
Oid typeId2 = InvalidOid;
char oprtype;
if (typeName1)
typeId1 = typenameTypeId(typeName1);
if (typeName2)
typeId2 = typenameTypeId(typeName2);
if (OidIsValid(typeId1) && OidIsValid(typeId2))
oprtype = 'b';
else if (OidIsValid(typeId1))
oprtype = 'r';
else
oprtype = 'l';
relation = heap_openr(OperatorRelationName, RowExclusiveLock);
tup = SearchSysCacheCopy(OPERNAME,
PointerGetDatum(operatorName),
ObjectIdGetDatum(typeId1),
ObjectIdGetDatum(typeId2),
CharGetDatum(oprtype));
if (HeapTupleIsValid(tup))
{
if (!pg_oper_ownercheck(tup->t_data->t_oid, GetUserId()))
elog(ERROR, "RemoveOperator: operator '%s': permission denied",
operatorName);
/* Delete any comments associated with this operator */
DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation));
simple_heap_delete(relation, &tup->t_self);
}
else
{
if (OidIsValid(typeId1) && OidIsValid(typeId2))
{
elog(ERROR, "RemoveOperator: binary operator '%s' taking '%s' and '%s' does not exist",
operatorName,
TypeNameToString(typeName1),
TypeNameToString(typeName2));
}
else if (OidIsValid(typeId1))
{
elog(ERROR, "RemoveOperator: right unary operator '%s' taking '%s' does not exist",
operatorName,
TypeNameToString(typeName1));
}
else
{
elog(ERROR, "RemoveOperator: left unary operator '%s' taking '%s' does not exist",
operatorName,
TypeNameToString(typeName2));
}
}
heap_freetuple(tup);
heap_close(relation, RowExclusiveLock);
}
#ifdef NOTYET
/*
* this stuff is to support removing all reference to a type
* don't use it - pma 2/1/94
*/
/*
* SingleOpOperatorRemove
* Removes all operators that have operands or a result of type 'typeOid'.
*/
static void
SingleOpOperatorRemove(Oid typeOid)
{
Relation rel;
ScanKeyData key[3];
HeapScanDesc scan;
HeapTuple tup;
static attnums[3] = {7, 8, 9}; /* left, right, return */
int i;
ScanKeyEntryInitialize(&key[0],
0, 0, F_OIDEQ, (Datum) typeOid);
rel = heap_openr(OperatorRelationName, RowExclusiveLock);
for (i = 0; i < 3; ++i)
{
key[0].sk_attno = attnums[i];
scan = heap_beginscan(rel, 0, SnapshotNow, 1, key);
while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
{
/* Delete any comments associated with this operator */
DeleteComments(tup->t_data->t_oid, RelationGetRelid(rel));
simple_heap_delete(rel, &tup->t_self);
}
heap_endscan(scan);
}
heap_close(rel, RowExclusiveLock);
}
/*
* AttributeAndRelationRemove
* Removes all entries in the attribute and relation relations
* that contain entries of type 'typeOid'.
* Currently nothing calls this code, it is untested.
*/
static void
AttributeAndRelationRemove(Oid typeOid)
{
struct oidlist
{
Oid reloid;
struct oidlist *next;
};
struct oidlist *oidptr,
*optr;
Relation rel;
ScanKeyData key[1];
HeapScanDesc scan;
HeapTuple tup;
/*
* Get the oid's of the relations to be removed by scanning the entire
* attribute relation. We don't need to remove the attributes here,
* because amdestroy will remove all attributes of the relation. XXX
* should check for duplicate relations
*/
ScanKeyEntryInitialize(&key[0],
0, 3, F_OIDEQ, (Datum) typeOid);
oidptr = (struct oidlist *) palloc(sizeof(*oidptr));
oidptr->next = NULL;
optr = oidptr;
rel = heap_openr(AttributeRelationName, AccessShareLock);
scan = heap_beginscan(rel, 0, SnapshotNow, 1, key);
while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
{
optr->reloid = ((Form_pg_attribute) GETSTRUCT(tup))->attrelid;
optr->next = (struct oidlist *) palloc(sizeof(*oidptr));
optr = optr->next;
}
optr->next = NULL;
heap_endscan(scan);
heap_close(rel, AccessShareLock);
optr = oidptr;
ScanKeyEntryInitialize(&key[0], 0,
ObjectIdAttributeNumber,
F_OIDEQ, (Datum) 0);
/* get RowExclusiveLock because heap_destroy will need it */
rel = heap_openr(RelationRelationName, RowExclusiveLock);
while (PointerIsValid((char *) optr->next))
{
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))
heap_drop_with_catalog(relOid, allowSystemTableMods);
heap_endscan(scan);
}
heap_close(rel, RowExclusiveLock);
}
#endif /* NOTYET */
/*
* TypeRemove
* Removes a datatype.
*
* NOTE: since this tries to remove the associated array type too, it'll
* only work on scalar types.
*/
void
RemoveType(List *names)
{
TypeName *typename;
Relation relation;
Oid typeoid;
HeapTuple tup;
/* 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);
/* 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, "Type \"%s\" does not exist",
TypeNameToString(typename));
if (!pg_type_ownercheck(typeoid, GetUserId()))
elog(ERROR, "RemoveType: type '%s': permission denied",
TypeNameToString(typename));
/* Delete any comments associated with this type */
DeleteComments(typeoid, RelationGetRelid(relation));
/* Remove the type tuple from pg_type */
simple_heap_delete(relation, &tup->t_self);
ReleaseSysCache(tup);
/* 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, "Type \"%s\" does not exist",
TypeNameToString(typename));
DeleteComments(typeoid, RelationGetRelid(relation));
simple_heap_delete(relation, &tup->t_self);
ReleaseSysCache(tup);
heap_close(relation, RowExclusiveLock);
}
/*
* RemoveDomain
* Removes a domain.
*/
void
RemoveDomain(List *names, int behavior)
{
TypeName *typename;
Relation relation;
Oid typeoid;
HeapTuple tup;
char typtype;
/* CASCADE unsupported */
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);
typeoid = typenameTypeId(typename);
tup = SearchSysCache(TYPEOID,
ObjectIdGetDatum(typeoid),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "RemoveDomain: type '%s' does not exist",
TypeNameToString(typename));
if (!pg_type_ownercheck(typeoid, GetUserId()))
elog(ERROR, "RemoveDomain: type '%s': permission denied",
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",
TypeNameToString(typename));
/* Delete any comments associated with this type */
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);
}
/*
* RemoveFunction
* Deletes a function.
*
* Exceptions:
* BadArg if name is invalid.
* "ERROR" if function nonexistent.
* ...
*/
void
RemoveFunction(List *functionName, /* function name to be removed */
List *argTypes) /* list of TypeName nodes */
{
Oid funcOid;
Relation relation;
HeapTuple tup;
funcOid = LookupFuncNameTypeNames(functionName, argTypes,
true, "RemoveFunction");
relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
tup = SearchSysCache(PROCOID,
ObjectIdGetDatum(funcOid),
0, 0, 0);
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "RemoveFunction: couldn't find tuple for function %s",
NameListToString(functionName));
if (!pg_proc_ownercheck(funcOid, GetUserId()))
elog(ERROR, "RemoveFunction: function '%s': permission denied",
NameListToString(functionName));
if (((Form_pg_proc) GETSTRUCT(tup))->proisagg)
elog(ERROR, "RemoveFunction: function '%s' is an aggregate"
"\n\tUse DROP AGGREGATE to remove it",
NameListToString(functionName));
if (((Form_pg_proc) GETSTRUCT(tup))->prolang == INTERNALlanguageId)
{
/* "Helpful" WARNING when removing a builtin function ... */
elog(WARNING, "Removing built-in function \"%s\"",
NameListToString(functionName));
}
/* Delete any comments associated with this function */
DeleteComments(funcOid, RelationGetRelid(relation));
simple_heap_delete(relation, &tup->t_self);
ReleaseSysCache(tup);
heap_close(relation, RowExclusiveLock);
}
void
RemoveAggregate(List *aggName, TypeName *aggType)
{
Relation relation;
HeapTuple tup;
Oid basetypeID;
Oid procOid;
/*
* if a basetype is passed in, then attempt to find an aggregate for
* that specific type.
*
* else if the basetype is blank, then attempt to find an aggregate with
* a basetype of zero. This is valid. It means that the aggregate is
* to apply to all basetypes (eg, COUNT).
*/
if (aggType)
basetypeID = typenameTypeId(aggType);
else
basetypeID = InvalidOid;
procOid = find_aggregate_func("RemoveAggregate", aggName, basetypeID);
/* Permission check */
if (!pg_proc_ownercheck(procOid, GetUserId()))
{
if (basetypeID == InvalidOid)
elog(ERROR, "RemoveAggregate: aggregate %s for all types: permission denied",
NameListToString(aggName));
else
elog(ERROR, "RemoveAggregate: aggregate %s for type %s: permission denied",
NameListToString(aggName), format_type_be(basetypeID));
}
/* Remove the pg_proc tuple */
relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
tup = SearchSysCache(PROCOID,
ObjectIdGetDatum(procOid),
0, 0, 0);
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "RemoveAggregate: couldn't find pg_proc tuple for %s",
NameListToString(aggName));
/* Delete any comments associated with this function */
DeleteComments(procOid, RelationGetRelid(relation));
simple_heap_delete(relation, &tup->t_self);
ReleaseSysCache(tup);
heap_close(relation, RowExclusiveLock);
/* Remove the pg_aggregate tuple */
relation = heap_openr(AggregateRelationName, RowExclusiveLock);
tup = SearchSysCache(AGGFNOID,
ObjectIdGetDatum(procOid),
0, 0, 0);
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "RemoveAggregate: couldn't find pg_aggregate tuple for %s",
NameListToString(aggName));
simple_heap_delete(relation, &tup->t_self);
ReleaseSysCache(tup);
heap_close(relation, RowExclusiveLock);
}

View File

@ -1,591 +0,0 @@
/*-------------------------------------------------------------------------
*
* rename.c
* renameatt() and renamerel() reside here.
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.70 2002/04/12 20:38:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <errno.h>
#include "access/genam.h"
#include "access/heapam.h"
#include "access/itup.h"
#include "catalog/catname.h"
#include "catalog/pg_index.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "catalog/heap.h"
#include "catalog/indexing.h"
#include "catalog/catalog.h"
#include "commands/rename.h"
#include "commands/trigger.h"
#include "miscadmin.h"
#include "storage/smgr.h"
#include "optimizer/prep.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteSupport.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/relcache.h"
#include "utils/syscache.h"
#define RI_TRIGGER_PK 1 /* is a trigger on the PK relation */
#define RI_TRIGGER_FK 2 /* is a trigger on the FK relation */
#define RI_TRIGGER_NONE 0 /* is not an RI trigger function */
static int ri_trigger_type(Oid tgfoid);
static void update_ri_trigger_args(Oid relid,
const char *oldname,
const char *newname,
bool fk_scan,
bool update_relname);
/*
* renameatt - changes the name of a attribute in a relation
*
* Attname attribute is changed in attribute catalog.
* No record of the previous attname is kept (correct?).
*
* get proper relrelation from relation catalog (if not arg)
* scan attribute catalog
* for name conflict (within rel)
* for original attribute (if not arg)
* modify attname in attribute tuple
* insert modified attribute in attribute catalog
* delete original attribute from attribute catalog
*/
void
renameatt(Oid relid,
const char *oldattname,
const char *newattname,
bool recurse)
{
Relation targetrelation;
Relation attrelation;
HeapTuple atttup;
List *indexoidlist;
List *indexoidscan;
/*
* Grab an exclusive lock on the target table, which we will NOT
* release until end of transaction.
*/
targetrelation = heap_open(relid, AccessExclusiveLock);
/*
* permissions checking. this would normally be done in utility.c,
* but this particular routine is recursive.
*
* normally, only the owner of a class can change its schema.
*/
if (!allowSystemTableMods
&& IsSystemRelation(targetrelation))
elog(ERROR, "renameatt: class \"%s\" is a system catalog",
RelationGetRelationName(targetrelation));
if (!pg_class_ownercheck(relid, GetUserId()))
elog(ERROR, "renameatt: you do not own class \"%s\"",
RelationGetRelationName(targetrelation));
/*
* if the 'recurse' flag is set then we are supposed to rename this
* attribute in all classes that inherit from 'relname' (as well as in
* 'relname').
*
* any permissions or problems with duplicate attributes will cause the
* whole transaction to abort, which is what we want -- all or
* nothing.
*/
if (recurse)
{
List *child,
*children;
/* this routine is actually in the planner */
children = find_all_inheritors(relid);
/*
* find_all_inheritors does the recursive search of the
* inheritance hierarchy, so all we have to do is process all of
* the relids in the list that it returns.
*/
foreach(child, children)
{
Oid childrelid = lfirsti(child);
if (childrelid == relid)
continue;
/* note we need not recurse again! */
renameatt(childrelid, oldattname, newattname, false);
}
}
attrelation = heap_openr(AttributeRelationName, RowExclusiveLock);
atttup = SearchSysCacheCopy(ATTNAME,
ObjectIdGetDatum(relid),
PointerGetDatum(oldattname),
0, 0);
if (!HeapTupleIsValid(atttup))
elog(ERROR, "renameatt: attribute \"%s\" does not exist", oldattname);
if (((Form_pg_attribute) GETSTRUCT(atttup))->attnum < 0)
elog(ERROR, "renameatt: system attribute \"%s\" not renamed", oldattname);
/* should not already exist */
if (SearchSysCacheExists(ATTNAME,
ObjectIdGetDatum(relid),
PointerGetDatum(newattname),
0, 0))
elog(ERROR, "renameatt: attribute \"%s\" exists", newattname);
StrNCpy(NameStr(((Form_pg_attribute) GETSTRUCT(atttup))->attname),
newattname, NAMEDATALEN);
simple_heap_update(attrelation, &atttup->t_self, atttup);
/* keep system catalog indices current */
{
Relation irelations[Num_pg_attr_indices];
CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, irelations);
CatalogIndexInsert(irelations, Num_pg_attr_indices, attrelation, atttup);
CatalogCloseIndices(Num_pg_attr_indices, irelations);
}
heap_freetuple(atttup);
/*
* Update column names of indexes that refer to the column being
* renamed.
*/
indexoidlist = RelationGetIndexList(targetrelation);
foreach(indexoidscan, indexoidlist)
{
Oid indexoid = lfirsti(indexoidscan);
HeapTuple indextup;
/*
* First check to see if index is a functional index. If so, its
* column name is a function name and shouldn't be renamed here.
*/
indextup = SearchSysCache(INDEXRELID,
ObjectIdGetDatum(indexoid),
0, 0, 0);
if (!HeapTupleIsValid(indextup))
elog(ERROR, "renameatt: can't find index id %u", indexoid);
if (OidIsValid(((Form_pg_index) GETSTRUCT(indextup))->indproc))
{
ReleaseSysCache(indextup);
continue;
}
ReleaseSysCache(indextup);
/*
* Okay, look to see if any column name of the index matches the
* old attribute name.
*/
atttup = SearchSysCacheCopy(ATTNAME,
ObjectIdGetDatum(indexoid),
PointerGetDatum(oldattname),
0, 0);
if (!HeapTupleIsValid(atttup))
continue; /* Nope, so ignore it */
/*
* Update the (copied) attribute tuple.
*/
StrNCpy(NameStr(((Form_pg_attribute) GETSTRUCT(atttup))->attname),
newattname, NAMEDATALEN);
simple_heap_update(attrelation, &atttup->t_self, atttup);
/* keep system catalog indices current */
{
Relation irelations[Num_pg_attr_indices];
CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, irelations);
CatalogIndexInsert(irelations, Num_pg_attr_indices, attrelation, atttup);
CatalogCloseIndices(Num_pg_attr_indices, irelations);
}
heap_freetuple(atttup);
}
freeList(indexoidlist);
heap_close(attrelation, RowExclusiveLock);
/*
* Update att name in any RI triggers associated with the relation.
*/
if (targetrelation->rd_rel->reltriggers > 0)
{
/* update tgargs column reference where att is primary key */
update_ri_trigger_args(RelationGetRelid(targetrelation),
oldattname, newattname,
false, false);
/* update tgargs column reference where att is foreign key */
update_ri_trigger_args(RelationGetRelid(targetrelation),
oldattname, newattname,
true, false);
}
heap_close(targetrelation, NoLock); /* close rel but keep lock! */
}
/*
* renamerel - change the name of a relation
*
* XXX - When renaming sequences, we don't bother to modify the
* sequence name that is stored within the sequence itself
* (this would cause problems with MVCC). In the future,
* the sequence name should probably be removed from the
* sequence, AFAIK there's no need for it to be there.
*/
void
renamerel(Oid relid, const char *newrelname)
{
Relation targetrelation;
Relation relrelation; /* for RELATION relation */
HeapTuple reltup;
Oid namespaceId;
char relkind;
bool relhastriggers;
Relation irelations[Num_pg_class_indices];
/*
* Grab an exclusive lock on the target table or index, which we will
* NOT release until end of transaction.
*/
targetrelation = relation_open(relid, AccessExclusiveLock);
namespaceId = RelationGetNamespace(targetrelation);
/* Validity checks */
if (!allowSystemTableMods &&
IsSystemRelation(targetrelation))
elog(ERROR, "renamerel: system relation \"%s\" may not be renamed",
RelationGetRelationName(targetrelation));
relkind = targetrelation->rd_rel->relkind;
relhastriggers = (targetrelation->rd_rel->reltriggers > 0);
/*
* Find relation's pg_class tuple, and make sure newrelname isn't in
* use.
*/
relrelation = heap_openr(RelationRelationName, RowExclusiveLock);
reltup = SearchSysCacheCopy(RELOID,
PointerGetDatum(relid),
0, 0, 0);
if (!HeapTupleIsValid(reltup))
elog(ERROR, "renamerel: relation \"%s\" does not exist",
RelationGetRelationName(targetrelation));
if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
elog(ERROR, "renamerel: relation \"%s\" exists", newrelname);
/*
* Update pg_class tuple with new relname. (Scribbling on reltup is
* OK because it's a copy...)
*/
StrNCpy(NameStr(((Form_pg_class) GETSTRUCT(reltup))->relname),
newrelname, NAMEDATALEN);
simple_heap_update(relrelation, &reltup->t_self, reltup);
/* keep the system catalog indices current */
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, irelations);
CatalogIndexInsert(irelations, Num_pg_class_indices, relrelation, reltup);
CatalogCloseIndices(Num_pg_class_indices, irelations);
heap_close(relrelation, NoLock);
heap_freetuple(reltup);
/*
* Also rename the associated type, if any.
*/
if (relkind != RELKIND_INDEX)
TypeRename(RelationGetRelationName(targetrelation), namespaceId,
newrelname);
/*
* If it's a view, must also rename the associated ON SELECT rule.
*/
if (relkind == RELKIND_VIEW)
{
char *oldrulename,
*newrulename;
oldrulename = MakeRetrieveViewRuleName(RelationGetRelationName(targetrelation));
newrulename = MakeRetrieveViewRuleName(newrelname);
RenameRewriteRule(oldrulename, newrulename);
}
/*
* Update rel name in any RI triggers associated with the relation.
*/
if (relhastriggers)
{
/* update tgargs where relname is primary key */
update_ri_trigger_args(relid,
RelationGetRelationName(targetrelation),
newrelname,
false, true);
/* update tgargs where relname is foreign key */
update_ri_trigger_args(relid,
RelationGetRelationName(targetrelation),
newrelname,
true, true);
}
/*
* Close rel, but keep exclusive lock!
*/
relation_close(targetrelation, NoLock);
}
/*
* Given a trigger function OID, determine whether it is an RI trigger,
* and if so whether it is attached to PK or FK relation.
*
* XXX this probably doesn't belong here; should be exported by
* ri_triggers.c
*/
static int
ri_trigger_type(Oid tgfoid)
{
switch (tgfoid)
{
case F_RI_FKEY_CASCADE_DEL:
case F_RI_FKEY_CASCADE_UPD:
case F_RI_FKEY_RESTRICT_DEL:
case F_RI_FKEY_RESTRICT_UPD:
case F_RI_FKEY_SETNULL_DEL:
case F_RI_FKEY_SETNULL_UPD:
case F_RI_FKEY_SETDEFAULT_DEL:
case F_RI_FKEY_SETDEFAULT_UPD:
case F_RI_FKEY_NOACTION_DEL:
case F_RI_FKEY_NOACTION_UPD:
return RI_TRIGGER_PK;
case F_RI_FKEY_CHECK_INS:
case F_RI_FKEY_CHECK_UPD:
return RI_TRIGGER_FK;
}
return RI_TRIGGER_NONE;
}
/*
* Scan pg_trigger for RI triggers that are on the specified relation
* (if fk_scan is false) or have it as the tgconstrrel (if fk_scan
* is true). Update RI trigger args fields matching oldname to contain
* newname instead. If update_relname is true, examine the relname
* fields; otherwise examine the attname fields.
*/
static void
update_ri_trigger_args(Oid relid,
const char *oldname,
const char *newname,
bool fk_scan,
bool update_relname)
{
Relation tgrel;
Relation irel;
ScanKeyData skey[1];
IndexScanDesc idxtgscan;
RetrieveIndexResult idxres;
Datum values[Natts_pg_trigger];
char nulls[Natts_pg_trigger];
char replaces[Natts_pg_trigger];
tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
if (fk_scan)
irel = index_openr(TriggerConstrRelidIndex);
else
irel = index_openr(TriggerRelidIndex);
ScanKeyEntryInitialize(&skey[0], 0x0,
1, /* always column 1 of index */
F_OIDEQ,
ObjectIdGetDatum(relid));
idxtgscan = index_beginscan(irel, false, 1, skey);
while ((idxres = index_getnext(idxtgscan, ForwardScanDirection)) != NULL)
{
HeapTupleData tupledata;
Buffer buffer;
HeapTuple tuple;
Form_pg_trigger pg_trigger;
bytea *val;
bytea *newtgargs;
bool isnull;
int tg_type;
bool examine_pk;
bool changed;
int tgnargs;
int i;
int newlen;
const char *arga[RI_MAX_ARGUMENTS];
const char *argp;
tupledata.t_self = idxres->heap_iptr;
heap_fetch(tgrel, SnapshotNow, &tupledata, &buffer, idxtgscan);
pfree(idxres);
if (!tupledata.t_data)
continue;
tuple = &tupledata;
pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
tg_type = ri_trigger_type(pg_trigger->tgfoid);
if (tg_type == RI_TRIGGER_NONE)
{
/* Not an RI trigger, forget it */
ReleaseBuffer(buffer);
continue;
}
/*
* It is an RI trigger, so parse the tgargs bytea.
*
* NB: we assume the field will never be compressed or moved out of
* line; so does trigger.c ...
*/
tgnargs = pg_trigger->tgnargs;
val = (bytea *) fastgetattr(tuple,
Anum_pg_trigger_tgargs,
tgrel->rd_att, &isnull);
if (isnull || tgnargs < RI_FIRST_ATTNAME_ARGNO ||
tgnargs > RI_MAX_ARGUMENTS)
{
/* This probably shouldn't happen, but ignore busted triggers */
ReleaseBuffer(buffer);
continue;
}
argp = (const char *) VARDATA(val);
for (i = 0; i < tgnargs; i++)
{
arga[i] = argp;
argp += strlen(argp) + 1;
}
/*
* Figure out which item(s) to look at. If the trigger is
* primary-key type and attached to my rel, I should look at the
* PK fields; if it is foreign-key type and attached to my rel, I
* should look at the FK fields. But the opposite rule holds when
* examining triggers found by tgconstrrel search.
*/
examine_pk = (tg_type == RI_TRIGGER_PK) == (!fk_scan);
changed = false;
if (update_relname)
{
/* Change the relname if needed */
i = examine_pk ? RI_PK_RELNAME_ARGNO : RI_FK_RELNAME_ARGNO;
if (strcmp(arga[i], oldname) == 0)
{
arga[i] = newname;
changed = true;
}
}
else
{
/* Change attname(s) if needed */
i = examine_pk ? RI_FIRST_ATTNAME_ARGNO + RI_KEYPAIR_PK_IDX :
RI_FIRST_ATTNAME_ARGNO + RI_KEYPAIR_FK_IDX;
for (; i < tgnargs; i += 2)
{
if (strcmp(arga[i], oldname) == 0)
{
arga[i] = newname;
changed = true;
}
}
}
if (!changed)
{
/* Don't need to update this tuple */
ReleaseBuffer(buffer);
continue;
}
/*
* Construct modified tgargs bytea.
*/
newlen = VARHDRSZ;
for (i = 0; i < tgnargs; i++)
newlen += strlen(arga[i]) + 1;
newtgargs = (bytea *) palloc(newlen);
VARATT_SIZEP(newtgargs) = newlen;
newlen = VARHDRSZ;
for (i = 0; i < tgnargs; i++)
{
strcpy(((char *) newtgargs) + newlen, arga[i]);
newlen += strlen(arga[i]) + 1;
}
/*
* Build modified tuple.
*/
for (i = 0; i < Natts_pg_trigger; i++)
{
values[i] = (Datum) 0;
replaces[i] = ' ';
nulls[i] = ' ';
}
values[Anum_pg_trigger_tgargs - 1] = PointerGetDatum(newtgargs);
replaces[Anum_pg_trigger_tgargs - 1] = 'r';
tuple = heap_modifytuple(tuple, tgrel, values, nulls, replaces);
/*
* Now we can release hold on original tuple.
*/
ReleaseBuffer(buffer);
/*
* Update pg_trigger and its indexes
*/
simple_heap_update(tgrel, &tuple->t_self, tuple);
{
Relation irelations[Num_pg_attr_indices];
CatalogOpenIndices(Num_pg_trigger_indices, Name_pg_trigger_indices, irelations);
CatalogIndexInsert(irelations, Num_pg_trigger_indices, tgrel, tuple);
CatalogCloseIndices(Num_pg_trigger_indices, irelations);
}
/* free up our scratch memory */
pfree(newtgargs);
heap_freetuple(tuple);
}
index_endscan(idxtgscan);
index_close(irel);
heap_close(tgrel, RowExclusiveLock);
/*
* Increment cmd counter to make updates visible; this is needed in
* case the same tuple has to be updated again by next pass (can
* happen in case of a self-referential FK relationship).
*/
CommandCounterIncrement();
}

View File

@ -0,0 +1,116 @@
/*-------------------------------------------------------------------------
*
* schemacmds.c
* schema creation command support code
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/schemacmds.c,v 1.1 2002/04/15 05:22:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "catalog/catalog.h"
#include "catalog/pg_namespace.h"
#include "commands/schemacmds.h"
#include "miscadmin.h"
#include "parser/analyze.h"
#include "tcop/utility.h"
#include "utils/lsyscache.h"
/*
* CREATE SCHEMA
*/
void
CreateSchemaCommand(CreateSchemaStmt *stmt)
{
const char *schemaName = stmt->schemaname;
const char *authId = stmt->authid;
List *parsetree_list;
List *parsetree_item;
const char *owner_name;
Oid owner_userid;
Oid saved_userid;
saved_userid = GetUserId();
if (!authId)
{
owner_userid = saved_userid;
owner_name = GetUserName(owner_userid);
}
else if (superuser())
{
owner_name = authId;
/* The following will error out if user does not exist */
owner_userid = get_usesysid(owner_name);
/*
* Set the current user to the requested authorization so
* that objects created in the statement have the requested
* owner. (This will revert to session user on error or at
* the end of this routine.)
*/
SetUserId(owner_userid);
}
else /* not superuser */
{
owner_userid = saved_userid;
owner_name = GetUserName(owner_userid);
if (strcmp(authId, owner_name) != 0)
elog(ERROR, "CREATE SCHEMA: permission denied"
"\n\t\"%s\" is not a superuser, so cannot create a schema for \"%s\"",
owner_name, authId);
}
if (!allowSystemTableMods && IsReservedName(schemaName))
elog(ERROR, "CREATE SCHEMA: Illegal schema name: \"%s\" -- pg_ is reserved for system schemas",
schemaName);
/* Create the schema's namespace */
NamespaceCreate(schemaName, owner_userid);
/* Let commands in the schema-element-list know about the schema */
CommandCounterIncrement();
/*
* Examine the list of commands embedded in the CREATE SCHEMA command,
* and reorganize them into a sequentially executable order with no
* forward references. Note that the result is still a list of raw
* parsetrees in need of parse analysis --- we cannot, in general,
* run analyze.c on one statement until we have actually executed the
* prior ones.
*/
parsetree_list = analyzeCreateSchemaStmt(stmt);
/*
* Analyze and execute each command contained in the CREATE SCHEMA
*/
foreach(parsetree_item, parsetree_list)
{
Node *parsetree = (Node *) lfirst(parsetree_item);
List *querytree_list,
*querytree_item;
querytree_list = parse_analyze(parsetree, NULL);
foreach(querytree_item, querytree_list)
{
Query *querytree = (Query *) lfirst(querytree_item);
/* schemas should contain only utility stmts */
Assert(querytree->commandType == CMD_UTILITY);
/* do this step */
ProcessUtility(querytree->utilityStmt, None, NULL);
/* make sure later steps can see the object created here */
CommandCounterIncrement();
}
}
/* Reset current user */
SetUserId(saved_userid);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.76 2002/03/30 01:02:41 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.77 2002/04/15 05:22:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -17,7 +17,7 @@
#include "access/heapam.h"
#include "catalog/namespace.h"
#include "catalog/pg_type.h"
#include "commands/creatinh.h"
#include "commands/tablecmds.h"
#include "commands/sequence.h"
#include "miscadmin.h"
#include "utils/acl.h"

View File

@ -0,0 +1,660 @@
/*-------------------------------------------------------------------------
*
* typecmds.c
* Routines for SQL commands that manipulate types (and domains).
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.1 2002/04/15 05:22:03 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
* appropriate arguments/flags, passing the results to the
* corresponding "FooDefine" routines (in src/catalog) that do
* the actual catalog-munging. These routines also verify permission
* of the user to execute the command.
*
* NOTES
* These things must be defined and committed in the following order:
* "create function":
* input/output, recv/send procedures
* "create type":
* type
* "create operator":
* operators
*
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/heap.h"
#include "catalog/namespace.h"
#include "catalog/pg_type.h"
#include "commands/comment.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "parser/parse.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/syscache.h"
static Oid findTypeIOFunction(List *procname, bool isOutput);
/*
* DefineType
* Registers a new type.
*/
void
DefineType(List *names, List *parameters)
{
char *typeName;
Oid typeNamespace;
int16 internalLength = -1; /* int2 */
int16 externalLength = -1; /* int2 */
Oid elemType = InvalidOid;
List *inputName = NIL;
List *outputName = NIL;
List *sendName = NIL;
List *receiveName = NIL;
char *defaultValue = NULL;
bool byValue = false;
char delimiter = DEFAULT_TYPDELIM;
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
* room to create the corresponding array type name with prepended
* "_".
*/
if (strlen(typeName) > (NAMEDATALEN - 2))
elog(ERROR, "DefineType: type names must be %d characters or less",
NAMEDATALEN - 2);
foreach(pl, parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
if (strcasecmp(defel->defname, "internallength") == 0)
internalLength = defGetTypeLength(defel);
else if (strcasecmp(defel->defname, "externallength") == 0)
externalLength = defGetTypeLength(defel);
else if (strcasecmp(defel->defname, "input") == 0)
inputName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "output") == 0)
outputName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "send") == 0)
sendName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "receive") == 0)
receiveName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "delimiter") == 0)
{
char *p = defGetString(defel);
delimiter = p[0];
}
else if (strcasecmp(defel->defname, "element") == 0)
elemType = typenameTypeId(defGetTypeName(defel));
else if (strcasecmp(defel->defname, "default") == 0)
defaultValue = defGetString(defel);
else if (strcasecmp(defel->defname, "passedbyvalue") == 0)
byValue = true;
else if (strcasecmp(defel->defname, "alignment") == 0)
{
char *a = defGetString(defel);
/*
* Note: if argument was an unquoted identifier, parser will
* have applied xlateSqlType() to it, so be prepared to
* recognize translated type names as well as the nominal
* form.
*/
if (strcasecmp(a, "double") == 0)
alignment = 'd';
else if (strcasecmp(a, "float8") == 0)
alignment = 'd';
else if (strcasecmp(a, "int4") == 0)
alignment = 'i';
else if (strcasecmp(a, "int2") == 0)
alignment = 's';
else if (strcasecmp(a, "char") == 0)
alignment = 'c';
else if (strcasecmp(a, "bpchar") == 0)
alignment = 'c';
else
elog(ERROR, "DefineType: \"%s\" alignment not recognized",
a);
}
else if (strcasecmp(defel->defname, "storage") == 0)
{
char *a = defGetString(defel);
if (strcasecmp(a, "plain") == 0)
storage = 'p';
else if (strcasecmp(a, "external") == 0)
storage = 'e';
else if (strcasecmp(a, "extended") == 0)
storage = 'x';
else if (strcasecmp(a, "main") == 0)
storage = 'm';
else
elog(ERROR, "DefineType: \"%s\" storage not recognized",
a);
}
else
{
elog(WARNING, "DefineType: attribute \"%s\" not recognized",
defel->defname);
}
}
/*
* make sure we have our required definitions
*/
if (inputName == NIL)
elog(ERROR, "Define: \"input\" unspecified");
if (outputName == NIL)
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.
*/
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
* to have an array entry for it in pg_type as well.
*/
shadow_type = makeArrayTypeName(typeName);
/* alignment must be 'i' or 'd' for arrays */
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 */
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 */
alignment, /* see above */
'x', /* ARRAY is always toastable */
-1, /* typMod (Domains only) */
0, /* Array dimensions of typbasetype */
false); /* Type NOT NULL */
pfree(shadow_type);
}
/*
* RemoveType
* Removes a datatype.
*
* NOTE: since this tries to remove the associated array type too, it'll
* only work on scalar types.
*/
void
RemoveType(List *names)
{
TypeName *typename;
Relation relation;
Oid typeoid;
HeapTuple tup;
/* 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);
/* 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, "Type \"%s\" does not exist",
TypeNameToString(typename));
if (!pg_type_ownercheck(typeoid, GetUserId()))
elog(ERROR, "RemoveType: type '%s': permission denied",
TypeNameToString(typename));
/* Delete any comments associated with this type */
DeleteComments(typeoid, RelationGetRelid(relation));
/* Remove the type tuple from pg_type */
simple_heap_delete(relation, &tup->t_self);
ReleaseSysCache(tup);
/* 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, "Type \"%s\" does not exist",
TypeNameToString(typename));
DeleteComments(typeoid, RelationGetRelid(relation));
simple_heap_delete(relation, &tup->t_self);
ReleaseSysCache(tup);
heap_close(relation, RowExclusiveLock);
}
/*
* DefineDomain
* Registers a new domain.
*/
void
DefineDomain(CreateDomainStmt *stmt)
{
char *domainName;
Oid domainNamespace;
int16 internalLength;
int16 externalLength;
Oid inputProcedure;
Oid outputProcedure;
Oid receiveProcedure;
Oid sendProcedure;
bool byValue;
char delimiter;
char alignment;
char storage;
char typtype;
Datum datum;
bool isnull;
char *defaultValue = NULL;
char *defaultValueBin = NULL;
bool typNotNull = false;
Oid basetypelem;
int32 typNDims = length(stmt->typename->arrayBounds);
HeapTuple typeTup;
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(domainName) > (NAMEDATALEN - 1))
elog(ERROR, "CREATE DOMAIN: domain names must be %d characters or less",
NAMEDATALEN - 1);
/*
* Look up the base type.
*/
typeTup = typenameType(stmt->typename);
/*
* What we really don't want is domains of domains. This could cause all sorts
* of neat issues if we allow that.
*
* With testing, we may determine complex types should be allowed
*/
typtype = ((Form_pg_type) GETSTRUCT(typeTup))->typtype;
if (typtype != 'b')
elog(ERROR, "DefineDomain: %s is not a basetype",
TypeNameToString(stmt->typename));
/* passed by value */
byValue = ((Form_pg_type) GETSTRUCT(typeTup))->typbyval;
/* Required Alignment */
alignment = ((Form_pg_type) GETSTRUCT(typeTup))->typalign;
/* TOAST Strategy */
storage = ((Form_pg_type) GETSTRUCT(typeTup))->typstorage;
/* Storage Length */
internalLength = ((Form_pg_type) GETSTRUCT(typeTup))->typlen;
/* External Length (unused) */
externalLength = ((Form_pg_type) GETSTRUCT(typeTup))->typprtlen;
/* Array element Delimiter */
delimiter = ((Form_pg_type) GETSTRUCT(typeTup))->typdelim;
/* 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(TYPEOID, typeTup,
Anum_pg_type_typdefault, &isnull);
if (!isnull)
defaultValue = DatumGetCString(DirectFunctionCall1(textout, datum));
/* Inherited default binary value */
datum = SysCacheGetAttr(TYPEOID, typeTup,
Anum_pg_type_typdefaultbin, &isnull);
if (!isnull)
defaultValueBin = DatumGetCString(DirectFunctionCall1(textout, datum));
/*
* Pull out the typelem name of the parent OID.
*
* This is what enables us to make a domain of an array
*/
basetypelem = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
/*
* Run through constraints manually to avoid the additional
* processing conducted by DefineRelation() and friends.
*
* Besides, we don't want any constraints to be cooked. We'll
* do that when the table is created via MergeDomainAttributes().
*/
foreach(listptr, schema)
{
Constraint *colDef = lfirst(listptr);
bool nullDefined = false;
Node *expr;
ParseState *pstate;
switch (colDef->contype)
{
/*
* The inherited default value may be overridden by the user
* with the DEFAULT <expr> statement.
*
* We have to search the entire constraint tree returned as we
* don't want to cook or fiddle too much.
*/
case CONSTR_DEFAULT:
/* Create a dummy ParseState for transformExpr */
pstate = make_parsestate(NULL);
/*
* Cook the colDef->raw_expr into an expression.
* Note: Name is strictly for error message
*/
expr = cookDefault(pstate, colDef->raw_expr,
typeTup->t_data->t_oid,
stmt->typename->typmod,
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(domainName,
InvalidOid),
false);
defaultValueBin = nodeToString(expr);
break;
/*
* Find the NULL constraint.
*/
case CONSTR_NOTNULL:
if (nullDefined) {
elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
} else {
typNotNull = true;
nullDefined = true;
}
break;
case CONSTR_NULL:
if (nullDefined) {
elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
} else {
typNotNull = false;
nullDefined = true;
}
break;
case CONSTR_UNIQUE:
elog(ERROR, "CREATE DOMAIN / UNIQUE indexes not supported");
break;
case CONSTR_PRIMARY:
elog(ERROR, "CREATE DOMAIN / PRIMARY KEY indexes not supported");
break;
case CONSTR_CHECK:
elog(ERROR, "DefineDomain: CHECK Constraints not supported");
break;
case CONSTR_ATTR_DEFERRABLE:
case CONSTR_ATTR_NOT_DEFERRABLE:
case CONSTR_ATTR_DEFERRED:
case CONSTR_ATTR_IMMEDIATE:
elog(ERROR, "DefineDomain: DEFERRABLE, NON DEFERRABLE, DEFERRED and IMMEDIATE not supported");
break;
default:
elog(ERROR, "DefineDomain: unrecognized constraint node type");
break;
}
}
/*
* Have TypeCreate do all the real work.
*/
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 */
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 */
alignment, /* required alignment */
storage, /* TOAST strategy */
stmt->typename->typmod, /* typeMod value */
typNDims, /* Array dimensions for base type */
typNotNull); /* Type NOT NULL */
/*
* Now we can clean up.
*/
ReleaseSysCache(typeTup);
}
/*
* RemoveDomain
* Removes a domain.
*/
void
RemoveDomain(List *names, int behavior)
{
TypeName *typename;
Relation relation;
Oid typeoid;
HeapTuple tup;
char typtype;
/* CASCADE unsupported */
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);
typeoid = typenameTypeId(typename);
tup = SearchSysCache(TYPEOID,
ObjectIdGetDatum(typeoid),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "RemoveDomain: type '%s' does not exist",
TypeNameToString(typename));
if (!pg_type_ownercheck(typeoid, GetUserId()))
elog(ERROR, "RemoveDomain: type '%s': permission denied",
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",
TypeNameToString(typename));
/* Delete any comments associated with this type */
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);
}
/*
* Find a suitable I/O function for a type.
*/
static Oid
findTypeIOFunction(List *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 = LookupFuncName(procname, 1, argList);
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 = LookupFuncName(procname, nargs, argList);
if (!OidIsValid(procOid))
func_error("TypeCreate", procname, 1, argList, NULL);
}
return procOid;
}

View File

@ -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.61 2002/03/29 19:06:08 tgl Exp $
* $Id: view.c,v 1.62 2002/04/15 05:22:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -15,7 +15,7 @@
#include "access/xact.h"
#include "catalog/heap.h"
#include "catalog/namespace.h"
#include "commands/creatinh.h"
#include "commands/tablecmds.h"
#include "commands/view.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"

View File

@ -27,7 +27,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.157 2002/04/08 22:42:18 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.158 2002/04/15 05:22:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -36,7 +36,7 @@
#include "access/heapam.h"
#include "catalog/heap.h"
#include "catalog/namespace.h"
#include "commands/command.h"
#include "commands/tablecmds.h"
#include "commands/trigger.h"
#include "executor/execdebug.h"
#include "executor/execdefs.h"

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.68 2002/03/21 16:00:38 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.69 2002/04/15 05:22:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -16,7 +16,7 @@
#include "access/printtup.h"
#include "catalog/heap.h"
#include "commands/command.h"
#include "commands/portalcmds.h"
#include "executor/spi_priv.h"
#include "tcop/tcopprot.h"
#include "utils/lsyscache.h"

View File

@ -8,14 +8,14 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.51 2002/03/21 16:01:27 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.52 2002/04/15 05:22:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "commands/command.h"
#include "commands/portalcmds.h"
#include "executor/execdefs.h"
#include "executor/executor.h"
#include "tcop/pquery.h"

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.148 2002/04/12 20:38:27 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.149 2002/04/15 05:22:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -22,16 +22,17 @@
#include "catalog/pg_shadow.h"
#include "commands/async.h"
#include "commands/cluster.h"
#include "commands/command.h"
#include "commands/comment.h"
#include "commands/copy.h"
#include "commands/creatinh.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/explain.h"
#include "commands/lockcmds.h"
#include "commands/portalcmds.h"
#include "commands/proclang.h"
#include "commands/rename.h"
#include "commands/schemacmds.h"
#include "commands/sequence.h"
#include "commands/tablecmds.h"
#include "commands/trigger.h"
#include "commands/user.h"
#include "commands/vacuum.h"

View File

@ -1,81 +0,0 @@
/*-------------------------------------------------------------------------
*
* command.h
* prototypes for command.c.
*
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: command.h,v 1.37 2002/04/01 04:35:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef COMMAND_H
#define COMMAND_H
#include "utils/portal.h"
/*
* PerformPortalFetch
* Performs the POSTQUEL function FETCH. Fetches count (or all if 0)
* tuples in portal with name in the forward direction iff goForward.
*
* Exceptions:
* BadArg if forward invalid.
* "ERROR" if portal not found.
*/
extern void PerformPortalFetch(char *name, bool forward, int count,
CommandDest dest, char *completionTag);
/*
* PerformPortalClose
* Performs the POSTQUEL function CLOSE.
*/
extern void PerformPortalClose(char *name, CommandDest dest);
extern void PortalCleanup(Portal portal);
/*
* ALTER TABLE variants
*/
extern void AlterTableAddColumn(Oid myrelid, bool inherits, ColumnDef *colDef);
extern void AlterTableAlterColumnDefault(Oid myrelid, bool inh,
const char *colName, Node *newDefault);
extern void AlterTableAlterColumnDropNotNull(Oid myrelid,
bool inh, const char *colName);
extern void AlterTableAlterColumnSetNotNull(Oid myrelid,
bool inh, const char *colName);
extern void AlterTableAlterColumnFlags(Oid myrelid,
bool inh, const char *colName,
Node *flagValue, const char *flagType);
extern void AlterTableDropColumn(Oid myrelid, bool inh,
const char *colName, int behavior);
extern void AlterTableAddConstraint(Oid myrelid,
bool inh, List *newConstraints);
extern void AlterTableDropConstraint(Oid myrelid,
bool inh, const char *constrName, int behavior);
extern void AlterTableCreateToastTable(Oid relOid, bool silent);
extern void AlterTableOwner(Oid relationOid, int32 newOwnerSysId);
/*
* LOCK
*/
extern void LockTableCommand(LockStmt *lockstmt);
/*
* SCHEMA
*/
extern void CreateSchemaCommand(CreateSchemaStmt *parsetree);
#endif /* COMMAND_H */

View File

@ -1,23 +0,0 @@
/*-------------------------------------------------------------------------
*
* creatinh.h
* prototypes for creatinh.c.
*
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: creatinh.h,v 1.20 2002/03/29 19:06:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef CREATINH_H
#define CREATINH_H
#include "nodes/parsenodes.h"
extern Oid DefineRelation(CreateStmt *stmt, char relkind);
extern void RemoveRelation(const RangeVar *relation);
extern void TruncateRelation(const RangeVar *relation);
#endif /* CREATINH_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: defrem.h,v 1.34 2002/04/09 20:35:54 tgl Exp $
* $Id: defrem.h,v 1.35 2002/04/15 05:22:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -16,6 +16,8 @@
#include "nodes/parsenodes.h"
#define DEFAULT_TYPDELIM ','
/*
* prototypes in indexcmds.c
*/
@ -33,22 +35,33 @@ extern void ReindexTable(RangeVar *relation, bool force);
extern void ReindexDatabase(const char *databaseName, bool force, bool all);
/*
* prototypes in define.c
* DefineFoo and RemoveFoo are now both in foocmds.c
*/
extern void CreateFunction(ProcedureStmt *stmt);
extern void DefineOperator(List *names, List *parameters);
extern void DefineAggregate(List *names, List *parameters);
extern void DefineType(List *names, List *parameters);
extern void DefineDomain(CreateDomainStmt *stmt);
/*
* prototypes in remove.c
*/
extern void RemoveDomain(List *names, int behavior);
extern void CreateFunction(ProcedureStmt *stmt);
extern void RemoveFunction(List *functionName, List *argTypes);
extern void DefineOperator(List *names, List *parameters);
extern void RemoveOperator(char *operatorName,
TypeName *typeName1, TypeName *typeName2);
extern void RemoveType(List *names);
TypeName *typeName1, TypeName *typeName2);
extern void DefineAggregate(List *names, List *parameters);
extern void RemoveAggregate(List *aggName, TypeName *aggType);
extern void DefineType(List *names, List *parameters);
extern void RemoveType(List *names);
extern void DefineDomain(CreateDomainStmt *stmt);
extern void RemoveDomain(List *names, int behavior);
/* support routines in define.c */
extern void case_translate_language_name(const char *input, char *output);
extern char *defGetString(DefElem *def);
extern double defGetNumeric(DefElem *def);
extern List *defGetQualifiedName(DefElem *def);
extern TypeName *defGetTypeName(DefElem *def);
extern int defGetTypeLength(DefElem *def);
#endif /* DEFREM_H */

View File

@ -0,0 +1,24 @@
/*-------------------------------------------------------------------------
*
* lockcmds.h
* prototypes for lockcmds.c.
*
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: lockcmds.h,v 1.1 2002/04/15 05:22:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef LOCKCMDS_H
#define LOCKCMDS_H
#include "nodes/parsenodes.h"
/*
* LOCK
*/
extern void LockTableCommand(LockStmt *lockstmt);
#endif /* LOCKCMDS_H */

View File

@ -0,0 +1,39 @@
/*-------------------------------------------------------------------------
*
* portalcmds.h
* prototypes for portalcmds.c.
*
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: portalcmds.h,v 1.1 2002/04/15 05:22:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PORTALCMDS_H
#define PORTALCMDS_H
#include "utils/portal.h"
/*
* PerformPortalFetch
* Performs the POSTQUEL function FETCH. Fetches count (or all if 0)
* tuples in portal with name in the forward direction iff goForward.
*
* Exceptions:
* BadArg if forward invalid.
* "ERROR" if portal not found.
*/
extern void PerformPortalFetch(char *name, bool forward, int count,
CommandDest dest, char *completionTag);
/*
* PerformPortalClose
* Performs the POSTQUEL function CLOSE.
*/
extern void PerformPortalClose(char *name, CommandDest dest);
extern void PortalCleanup(Portal portal);
#endif /* PORTALCMDS_H */

View File

@ -1,25 +0,0 @@
/*-------------------------------------------------------------------------
*
* rename.h
*
*
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: rename.h,v 1.16 2002/03/31 07:49:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef RENAME_H
#define RENAME_H
extern void renameatt(Oid relid,
const char *oldattname,
const char *newattname,
bool recurse);
extern void renamerel(Oid relid,
const char *newrelname);
#endif /* RENAME_H */

View File

@ -0,0 +1,22 @@
/*-------------------------------------------------------------------------
*
* schemacmds.h
* prototypes for schemacmds.c.
*
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: schemacmds.h,v 1.1 2002/04/15 05:22:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef SCHEMACMDS_H
#define SCHEMACMDS_H
#include "nodes/parsenodes.h"
extern void CreateSchemaCommand(CreateSchemaStmt *parsetree);
#endif /* SCHEMACMDS_H */

View File

@ -0,0 +1,63 @@
/*-------------------------------------------------------------------------
*
* tablecmds.h
* prototypes for tablecmds.c.
*
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: tablecmds.h,v 1.1 2002/04/15 05:22:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef TABLECMDS_H
#define TABLECMDS_H
#include "nodes/parsenodes.h"
extern void AlterTableAddColumn(Oid myrelid, bool inherits,
ColumnDef *colDef);
extern void AlterTableAlterColumnDefault(Oid myrelid, bool inh,
const char *colName,
Node *newDefault);
extern void AlterTableAlterColumnDropNotNull(Oid myrelid, bool inh,
const char *colName);
extern void AlterTableAlterColumnSetNotNull(Oid myrelid, bool inh,
const char *colName);
extern void AlterTableAlterColumnFlags(Oid myrelid, bool inh,
const char *colName,
Node *flagValue, const char *flagType);
extern void AlterTableDropColumn(Oid myrelid, bool inh,
const char *colName, int behavior);
extern void AlterTableAddConstraint(Oid myrelid, bool inh,
List *newConstraints);
extern void AlterTableDropConstraint(Oid myrelid, bool inh,
const char *constrName, int behavior);
extern void AlterTableCreateToastTable(Oid relOid, bool silent);
extern void AlterTableOwner(Oid relationOid, int32 newOwnerSysId);
extern Oid DefineRelation(CreateStmt *stmt, char relkind);
extern void RemoveRelation(const RangeVar *relation);
extern void TruncateRelation(const RangeVar *relation);
extern void renameatt(Oid relid,
const char *oldattname,
const char *newattname,
bool recurse);
extern void renamerel(Oid relid,
const char *newrelname);
#endif /* TABLECMDS_H */