1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-27 12:41:57 +03:00

Add CREATE/ALTER/DROP OPERATOR FAMILY commands, also COMMENT ON OPERATOR

FAMILY; and add FAMILY option to CREATE OPERATOR CLASS to allow adding a
class to a pre-existing family.  Per previous discussion.  Man, what a
tedious lot of cutting and pasting ...
This commit is contained in:
Tom Lane
2007-01-23 05:07:18 +00:00
parent 8502b68513
commit a33cf1041f
22 changed files with 1981 additions and 90 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.134 2007/01/05 22:19:24 momjian Exp $
* $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.135 2007/01/23 05:07:17 tgl Exp $
*
* NOTES
* See acl.h.
@ -30,6 +30,7 @@
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_type.h"
@ -1413,6 +1414,8 @@ static const char *const no_priv_msg[MAX_ACL_KIND] =
gettext_noop("permission denied for schema %s"),
/* ACL_KIND_OPCLASS */
gettext_noop("permission denied for operator class %s"),
/* ACL_KIND_OPFAMILY */
gettext_noop("permission denied for operator family %s"),
/* ACL_KIND_CONVERSION */
gettext_noop("permission denied for conversion %s"),
/* ACL_KIND_TABLESPACE */
@ -1439,6 +1442,8 @@ static const char *const not_owner_msg[MAX_ACL_KIND] =
gettext_noop("must be owner of schema %s"),
/* ACL_KIND_OPCLASS */
gettext_noop("must be owner of operator class %s"),
/* ACL_KIND_OPFAMILY */
gettext_noop("must be owner of operator family %s"),
/* ACL_KIND_CONVERSION */
gettext_noop("must be owner of conversion %s"),
/* ACL_KIND_TABLESPACE */
@ -2239,6 +2244,35 @@ pg_opclass_ownercheck(Oid opc_oid, Oid roleid)
return has_privs_of_role(roleid, ownerId);
}
/*
* Ownership check for an operator family (specified by OID).
*/
bool
pg_opfamily_ownercheck(Oid opf_oid, Oid roleid)
{
HeapTuple tuple;
Oid ownerId;
/* Superusers bypass all permission checking. */
if (superuser_arg(roleid))
return true;
tuple = SearchSysCache(OPFAMILYOID,
ObjectIdGetDatum(opf_oid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator family with OID %u does not exist",
opf_oid)));
ownerId = ((Form_pg_opfamily) GETSTRUCT(tuple))->opfowner;
ReleaseSysCache(tuple);
return has_privs_of_role(roleid, ownerId);
}
/*
* Ownership check for a database (specified by OID).
*/

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.21 2007/01/05 22:19:25 momjian Exp $
* $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.22 2007/01/23 05:07:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -66,6 +66,10 @@ ExecRenameStmt(RenameStmt *stmt)
RenameOpClass(stmt->object, stmt->subname, stmt->newname);
break;
case OBJECT_OPFAMILY:
RenameOpFamily(stmt->object, stmt->subname, stmt->newname);
break;
case OBJECT_ROLE:
RenameRole(stmt->subname, stmt->newname);
break;
@ -211,6 +215,10 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
AlterOpClassOwner(stmt->object, stmt->addname, newowner);
break;
case OBJECT_OPFAMILY:
AlterOpFamilyOwner(stmt->object, stmt->addname, newowner);
break;
case OBJECT_SCHEMA:
AlterSchemaOwner((char *) linitial(stmt->object), newowner);
break;

View File

@ -7,7 +7,7 @@
* Copyright (c) 1996-2007, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.94 2007/01/05 22:19:25 momjian Exp $
* $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.95 2007/01/23 05:07:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -28,6 +28,7 @@
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_shdescription.h"
@ -72,6 +73,7 @@ static void CommentConstraint(List *qualname, char *comment);
static void CommentConversion(List *qualname, char *comment);
static void CommentLanguage(List *qualname, char *comment);
static void CommentOpClass(List *qualname, List *arguments, char *comment);
static void CommentOpFamily(List *qualname, List *arguments, char *comment);
static void CommentLargeObject(List *qualname, char *comment);
static void CommentCast(List *qualname, List *arguments, char *comment);
static void CommentTablespace(List *qualname, char *comment);
@ -134,6 +136,9 @@ CommentObject(CommentStmt *stmt)
case OBJECT_OPCLASS:
CommentOpClass(stmt->objname, stmt->objargs, stmt->comment);
break;
case OBJECT_OPFAMILY:
CommentOpFamily(stmt->objname, stmt->objargs, stmt->comment);
break;
case OBJECT_LARGEOBJECT:
CommentLargeObject(stmt->objname, stmt->comment);
break;
@ -1263,6 +1268,92 @@ CommentOpClass(List *qualname, List *arguments, char *comment)
CreateComments(opcID, OperatorClassRelationId, 0, comment);
}
/*
* CommentOpFamily --
*
* This routine is used to allow a user to provide comments on an
* operator family. The operator family for commenting is determined by both
* its name and its argument list which defines the index method
* the operator family is used for. The argument list is expected to contain
* a single name (represented as a string Value node).
*/
static void
CommentOpFamily(List *qualname, List *arguments, char *comment)
{
char *amname;
char *schemaname;
char *opfname;
Oid amID;
Oid opfID;
HeapTuple tuple;
Assert(list_length(arguments) == 1);
amname = strVal(linitial(arguments));
/*
* Get the access method's OID.
*/
amID = GetSysCacheOid(AMNAME,
CStringGetDatum(amname),
0, 0, 0);
if (!OidIsValid(amID))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist",
amname)));
/*
* Look up the opfamily.
*/
/* deconstruct the name list */
DeconstructQualifiedName(qualname, &schemaname, &opfname);
if (schemaname)
{
/* Look in specific schema only */
Oid namespaceId;
namespaceId = LookupExplicitNamespace(schemaname);
tuple = SearchSysCache(OPFAMILYAMNAMENSP,
ObjectIdGetDatum(amID),
PointerGetDatum(opfname),
ObjectIdGetDatum(namespaceId),
0);
}
else
{
/* Unqualified opfamily name, so search the search path */
opfID = OpfamilynameGetOpfid(amID, opfname);
if (!OidIsValid(opfID))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator family \"%s\" does not exist for access method \"%s\"",
opfname, amname)));
tuple = SearchSysCache(OPFAMILYOID,
ObjectIdGetDatum(opfID),
0, 0, 0);
}
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator family \"%s\" does not exist for access method \"%s\"",
NameListToString(qualname), amname)));
opfID = HeapTupleGetOid(tuple);
/* Permission check: must own opfamily */
if (!pg_opfamily_ownercheck(opfID, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
NameListToString(qualname));
ReleaseSysCache(tuple);
/* Call CreateComments() to create/drop the comments */
CreateComments(opfID, OperatorFamilyRelationId, 0, comment);
}
/*
* CommentLargeObject --
*

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.52 2007/01/05 22:19:26 momjian Exp $
* $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.53 2007/01/23 05:07:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -55,15 +55,30 @@ typedef struct
} OpFamilyMember;
static void AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
int maxOpNumber, int maxProcNumber,
List *items);
static void AlterOpFamilyDrop(List *opfamilyname, Oid amoid, Oid opfamilyoid,
int maxOpNumber, int maxProcNumber,
List *items);
static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype);
static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
static void addFamilyMember(List **list, OpFamilyMember *member, bool isProc);
static void storeOperators(Oid amoid, Oid opfamilyoid, Oid opclassoid,
List *operators);
static void storeProcedures(Oid amoid, Oid opfamilyoid, Oid opclassoid,
List *procedures);
static void storeOperators(List *opfamilyname, Oid amoid,
Oid opfamilyoid, Oid opclassoid,
List *operators, bool isAdd);
static void storeProcedures(List *opfamilyname, Oid amoid,
Oid opfamilyoid, Oid opclassoid,
List *procedures, bool isAdd);
static void dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
List *operators);
static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
List *procedures);
static void AlterOpClassOwner_internal(Relation rel, HeapTuple tuple,
Oid newOwnerId);
static void AlterOpFamilyOwner_internal(Relation rel, HeapTuple tuple,
Oid newOwnerId);
/*
@ -452,6 +467,12 @@ DefineOpClass(CreateOpClassStmt *stmt)
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->object = funcOid;
member->number = item->number;
/* allow overriding of the function's actual arg types */
if (item->class_args)
processTypesSpec(item->class_args,
&member->lefttype, &member->righttype);
assignProcTypes(member, amoid, typeoid);
addFamilyMember(&procedures, member, true);
break;
@ -570,8 +591,10 @@ DefineOpClass(CreateOpClassStmt *stmt)
* Now add tuples to pg_amop and pg_amproc tying in the operators and
* functions. Dependencies on them are inserted, too.
*/
storeOperators(amoid, opfamilyoid, opclassoid, operators);
storeProcedures(amoid, opfamilyoid, opclassoid, procedures);
storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
opclassoid, operators, false);
storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
opclassoid, procedures, false);
/*
* Create dependencies for the opclass proper. Note: we do not create a
@ -615,6 +638,420 @@ DefineOpClass(CreateOpClassStmt *stmt)
heap_close(rel, RowExclusiveLock);
}
/*
* DefineOpFamily
* Define a new index operator family.
*/
void
DefineOpFamily(CreateOpFamilyStmt *stmt)
{
char *opfname; /* name of opfamily we're creating */
Oid amoid, /* our AM's oid */
namespaceoid, /* namespace to create opfamily in */
opfamilyoid; /* oid of opfamily we create */
Relation rel;
HeapTuple tup;
Datum values[Natts_pg_opfamily];
char nulls[Natts_pg_opfamily];
AclResult aclresult;
NameData opfName;
ObjectAddress myself,
referenced;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
&opfname);
/* Check we have creation rights in target namespace */
aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceoid));
/* Get necessary info about access method */
tup = SearchSysCache(AMNAME,
CStringGetDatum(stmt->amname),
0, 0, 0);
if (!HeapTupleIsValid(tup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist",
stmt->amname)));
amoid = HeapTupleGetOid(tup);
/* XXX Should we make any privilege check against the AM? */
ReleaseSysCache(tup);
/*
* Currently, we require superuser privileges to create an opfamily.
* See comments in DefineOpClass.
*
* XXX re-enable NOT_USED code sections below if you remove this test.
*/
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to create an operator family")));
rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
/*
* Make sure there is no existing opfamily of this name (this is just to
* give a more friendly error message than "duplicate key").
*/
if (SearchSysCacheExists(OPFAMILYAMNAMENSP,
ObjectIdGetDatum(amoid),
CStringGetDatum(opfname),
ObjectIdGetDatum(namespaceoid),
0))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("operator family \"%s\" for access method \"%s\" already exists",
opfname, stmt->amname)));
/*
* Okay, let's create the pg_opfamily entry.
*/
memset(values, 0, sizeof(values));
memset(nulls, ' ', sizeof(nulls));
values[Anum_pg_opfamily_opfmethod - 1] = ObjectIdGetDatum(amoid);
namestrcpy(&opfName, opfname);
values[Anum_pg_opfamily_opfname - 1] = NameGetDatum(&opfName);
values[Anum_pg_opfamily_opfnamespace - 1] = ObjectIdGetDatum(namespaceoid);
values[Anum_pg_opfamily_opfowner - 1] = ObjectIdGetDatum(GetUserId());
tup = heap_formtuple(rel->rd_att, values, nulls);
opfamilyoid = simple_heap_insert(rel, tup);
CatalogUpdateIndexes(rel, tup);
heap_freetuple(tup);
/*
* Create dependencies for the opfamily proper. Note: we do not create a
* dependency link to the AM, because we don't currently support DROP
* ACCESS METHOD.
*/
myself.classId = OperatorFamilyRelationId;
myself.objectId = opfamilyoid;
myself.objectSubId = 0;
/* dependency on namespace */
referenced.classId = NamespaceRelationId;
referenced.objectId = namespaceoid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* dependency on owner */
recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId());
heap_close(rel, RowExclusiveLock);
}
/*
* AlterOpFamily
* Add or remove operators/procedures within an existing operator family.
*
* Note: this implements only ALTER OPERATOR FAMILY ... ADD/DROP. Some
* other commands called ALTER OPERATOR FAMILY exist, but go through
* different code paths.
*/
void
AlterOpFamily(AlterOpFamilyStmt *stmt)
{
Oid amoid, /* our AM's oid */
opfamilyoid; /* oid of opfamily */
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
Form_pg_am pg_am;
/* Get necessary info about access method */
tup = SearchSysCache(AMNAME,
CStringGetDatum(stmt->amname),
0, 0, 0);
if (!HeapTupleIsValid(tup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist",
stmt->amname)));
amoid = HeapTupleGetOid(tup);
pg_am = (Form_pg_am) GETSTRUCT(tup);
maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
maxProcNumber = pg_am->amsupport;
/* XXX Should we make any privilege check against the AM? */
ReleaseSysCache(tup);
/* Look up the opfamily */
tup = OpFamilyCacheLookup(amoid, stmt->opfamilyname);
if (!HeapTupleIsValid(tup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator family \"%s\" does not exist for access method \"%s\"",
NameListToString(stmt->opfamilyname), stmt->amname)));
opfamilyoid = HeapTupleGetOid(tup);
ReleaseSysCache(tup);
/*
* Currently, we require superuser privileges to alter an opfamily.
*
* XXX re-enable NOT_USED code sections below if you remove this test.
*/
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to alter an operator family")));
/*
* ADD and DROP cases need separate code from here on down.
*/
if (stmt->isDrop)
AlterOpFamilyDrop(stmt->opfamilyname, amoid, opfamilyoid,
maxOpNumber, maxProcNumber,
stmt->items);
else
AlterOpFamilyAdd(stmt->opfamilyname, amoid, opfamilyoid,
maxOpNumber, maxProcNumber,
stmt->items);
}
/*
* ADD part of ALTER OP FAMILY
*/
static void
AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
int maxOpNumber, int maxProcNumber,
List *items)
{
List *operators; /* OpFamilyMember list for operators */
List *procedures; /* OpFamilyMember list for support procs */
ListCell *l;
operators = NIL;
procedures = NIL;
/*
* Scan the "items" list to obtain additional info.
*/
foreach(l, items)
{
CreateOpClassItem *item = lfirst(l);
Oid operOid;
Oid funcOid;
OpFamilyMember *member;
Assert(IsA(item, CreateOpClassItem));
switch (item->itemtype)
{
case OPCLASS_ITEM_OPERATOR:
if (item->number <= 0 || item->number > maxOpNumber)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("invalid operator number %d,"
" must be between 1 and %d",
item->number, maxOpNumber)));
if (item->args != NIL)
{
TypeName *typeName1 = (TypeName *) linitial(item->args);
TypeName *typeName2 = (TypeName *) lsecond(item->args);
operOid = LookupOperNameTypeNames(NULL, item->name,
typeName1, typeName2,
false, -1);
}
else
{
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("operator argument types must be specified in ALTER OPERATOR FAMILY")));
operOid = InvalidOid; /* keep compiler quiet */
}
#ifdef NOT_USED
/* XXX this is unnecessary given the superuser check above */
/* Caller must own operator and its underlying function */
if (!pg_oper_ownercheck(operOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
get_opname(operOid));
funcOid = get_opcode(operOid);
if (!pg_proc_ownercheck(funcOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
get_func_name(funcOid));
#endif
/* Save the info */
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->object = operOid;
member->number = item->number;
member->recheck = item->recheck;
assignOperTypes(member, amoid, InvalidOid);
addFamilyMember(&operators, member, false);
break;
case OPCLASS_ITEM_FUNCTION:
if (item->number <= 0 || item->number > maxProcNumber)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("invalid procedure number %d,"
" must be between 1 and %d",
item->number, maxProcNumber)));
funcOid = LookupFuncNameTypeNames(item->name, item->args,
false);
#ifdef NOT_USED
/* XXX this is unnecessary given the superuser check above */
/* Caller must own function */
if (!pg_proc_ownercheck(funcOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
get_func_name(funcOid));
#endif
/* Save the info */
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->object = funcOid;
member->number = item->number;
/* allow overriding of the function's actual arg types */
if (item->class_args)
processTypesSpec(item->class_args,
&member->lefttype, &member->righttype);
assignProcTypes(member, amoid, InvalidOid);
addFamilyMember(&procedures, member, true);
break;
case OPCLASS_ITEM_STORAGETYPE:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("STORAGE may not be specified in ALTER OPERATOR FAMILY")));
break;
default:
elog(ERROR, "unrecognized item type: %d", item->itemtype);
break;
}
}
/*
* Add tuples to pg_amop and pg_amproc tying in the operators and
* functions. Dependencies on them are inserted, too.
*/
storeOperators(opfamilyname, amoid, opfamilyoid,
InvalidOid, operators, true);
storeProcedures(opfamilyname, amoid, opfamilyoid,
InvalidOid, procedures, true);
}
/*
* DROP part of ALTER OP FAMILY
*/
static void
AlterOpFamilyDrop(List *opfamilyname, Oid amoid, Oid opfamilyoid,
int maxOpNumber, int maxProcNumber,
List *items)
{
List *operators; /* OpFamilyMember list for operators */
List *procedures; /* OpFamilyMember list for support procs */
ListCell *l;
operators = NIL;
procedures = NIL;
/*
* Scan the "items" list to obtain additional info.
*/
foreach(l, items)
{
CreateOpClassItem *item = lfirst(l);
Oid lefttype,
righttype;
OpFamilyMember *member;
Assert(IsA(item, CreateOpClassItem));
switch (item->itemtype)
{
case OPCLASS_ITEM_OPERATOR:
if (item->number <= 0 || item->number > maxOpNumber)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("invalid operator number %d,"
" must be between 1 and %d",
item->number, maxOpNumber)));
processTypesSpec(item->args, &lefttype, &righttype);
/* Save the info */
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->number = item->number;
member->lefttype = lefttype;
member->righttype = righttype;
addFamilyMember(&operators, member, false);
break;
case OPCLASS_ITEM_FUNCTION:
if (item->number <= 0 || item->number > maxProcNumber)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("invalid procedure number %d,"
" must be between 1 and %d",
item->number, maxProcNumber)));
processTypesSpec(item->args, &lefttype, &righttype);
/* Save the info */
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->number = item->number;
member->lefttype = lefttype;
member->righttype = righttype;
addFamilyMember(&procedures, member, true);
break;
case OPCLASS_ITEM_STORAGETYPE:
/* grammar prevents this from appearing */
default:
elog(ERROR, "unrecognized item type: %d", item->itemtype);
break;
}
}
/*
* Remove tuples from pg_amop and pg_amproc.
*/
dropOperators(opfamilyname, amoid, opfamilyoid, operators);
dropProcedures(opfamilyname, amoid, opfamilyoid, procedures);
}
/*
* Deal with explicit arg types used in ALTER ADD/DROP
*/
static void
processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
{
TypeName *typeName;
Assert(args != NIL);
typeName = (TypeName *) linitial(args);
*lefttype = typenameTypeId(NULL, typeName);
if (list_length(args) > 1)
{
typeName = (TypeName *) lsecond(args);
*righttype = typenameTypeId(NULL, typeName);
}
else
*righttype = *lefttype;
if (list_length(args) > 2)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("one or two argument types must be specified")));
}
/*
* Determine the lefttype/righttype to assign to an operator,
* and do any validity checking we can manage.
@ -781,7 +1218,9 @@ addFamilyMember(List **list, OpFamilyMember *member, bool isProc)
* else make an AUTO dependency on the opfamily.
*/
static void
storeOperators(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators)
storeOperators(List *opfamilyname, Oid amoid,
Oid opfamilyoid, Oid opclassoid,
List *operators, bool isAdd)
{
Relation rel;
Datum values[Natts_pg_amop];
@ -798,6 +1237,24 @@ storeOperators(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators)
{
OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
/*
* If adding to an existing family, check for conflict with an
* existing pg_amop entry (just to give a nicer error message)
*/
if (isAdd &&
SearchSysCacheExists(AMOPSTRATEGY,
ObjectIdGetDatum(opfamilyoid),
ObjectIdGetDatum(op->lefttype),
ObjectIdGetDatum(op->righttype),
Int16GetDatum(op->number)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("operator %d(%s,%s) already exists in operator family \"%s\"",
op->number,
format_type_be(op->lefttype),
format_type_be(op->righttype),
NameListToString(opfamilyname))));
/* Create the pg_amop entry */
memset(values, 0, sizeof(values));
memset(nulls, ' ', sizeof(nulls));
@ -862,7 +1319,9 @@ storeOperators(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators)
* else make an AUTO dependency on the opfamily.
*/
static void
storeProcedures(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *procedures)
storeProcedures(List *opfamilyname, Oid amoid,
Oid opfamilyoid, Oid opclassoid,
List *procedures, bool isAdd)
{
Relation rel;
Datum values[Natts_pg_amproc];
@ -879,6 +1338,24 @@ storeProcedures(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *procedures)
{
OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
/*
* If adding to an existing family, check for conflict with an
* existing pg_amproc entry (just to give a nicer error message)
*/
if (isAdd &&
SearchSysCacheExists(AMPROCNUM,
ObjectIdGetDatum(opfamilyoid),
ObjectIdGetDatum(proc->lefttype),
ObjectIdGetDatum(proc->righttype),
Int16GetDatum(proc->number)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("function %d(%s,%s) already exists in operator family \"%s\"",
proc->number,
format_type_be(proc->lefttype),
format_type_be(proc->righttype),
NameListToString(opfamilyname))));
/* Create the pg_amproc entry */
memset(values, 0, sizeof(values));
memset(nulls, ' ', sizeof(nulls));
@ -934,6 +1411,87 @@ storeProcedures(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *procedures)
}
/*
* Remove operator entries from an opfamily.
*
* Note: this is only allowed for "loose" members of an opfamily, hence
* behavior is always RESTRICT.
*/
static void
dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
List *operators)
{
ListCell *l;
foreach(l, operators)
{
OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
Oid amopid;
ObjectAddress object;
amopid = GetSysCacheOid(AMOPSTRATEGY,
ObjectIdGetDatum(opfamilyoid),
ObjectIdGetDatum(op->lefttype),
ObjectIdGetDatum(op->righttype),
Int16GetDatum(op->number));
if (!OidIsValid(amopid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
op->number,
format_type_be(op->lefttype),
format_type_be(op->righttype),
NameListToString(opfamilyname))));
object.classId = AccessMethodOperatorRelationId;
object.objectId = amopid;
object.objectSubId = 0;
performDeletion(&object, DROP_RESTRICT);
}
}
/*
* Remove procedure entries from an opfamily.
*
* Note: this is only allowed for "loose" members of an opfamily, hence
* behavior is always RESTRICT.
*/
static void
dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
List *procedures)
{
ListCell *l;
foreach(l, procedures)
{
OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
Oid amprocid;
ObjectAddress object;
amprocid = GetSysCacheOid(AMPROCNUM,
ObjectIdGetDatum(opfamilyoid),
ObjectIdGetDatum(op->lefttype),
ObjectIdGetDatum(op->righttype),
Int16GetDatum(op->number));
if (!OidIsValid(amprocid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
op->number,
format_type_be(op->lefttype),
format_type_be(op->righttype),
NameListToString(opfamilyname))));
object.classId = AccessMethodProcedureRelationId;
object.objectId = amprocid;
object.objectSubId = 0;
performDeletion(&object, DROP_RESTRICT);
}
}
/*
* RemoveOpClass
* Deletes an opclass.
@ -997,6 +1555,70 @@ RemoveOpClass(RemoveOpClassStmt *stmt)
performDeletion(&object, stmt->behavior);
}
/*
* RemoveOpFamily
* Deletes an opfamily.
*/
void
RemoveOpFamily(RemoveOpFamilyStmt *stmt)
{
Oid amID,
opfID;
HeapTuple tuple;
ObjectAddress object;
/*
* Get the access method's OID.
*/
amID = GetSysCacheOid(AMNAME,
CStringGetDatum(stmt->amname),
0, 0, 0);
if (!OidIsValid(amID))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist",
stmt->amname)));
/*
* Look up the opfamily.
*/
tuple = OpFamilyCacheLookup(amID, stmt->opfamilyname);
if (!HeapTupleIsValid(tuple))
{
if (!stmt->missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator family \"%s\" does not exist for access method \"%s\"",
NameListToString(stmt->opfamilyname), stmt->amname)));
else
ereport(NOTICE,
(errmsg("operator family \"%s\" does not exist for access method \"%s\"",
NameListToString(stmt->opfamilyname), stmt->amname)));
return;
}
opfID = HeapTupleGetOid(tuple);
/* Permission check: must own opfamily or its namespace */
if (!pg_opfamily_ownercheck(opfID, GetUserId()) &&
!pg_namespace_ownercheck(((Form_pg_opfamily) GETSTRUCT(tuple))->opfnamespace,
GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
NameListToString(stmt->opfamilyname));
ReleaseSysCache(tuple);
/*
* Do the deletion
*/
object.classId = OperatorFamilyRelationId;
object.objectId = opfID;
object.objectSubId = 0;
performDeletion(&object, stmt->behavior);
}
/*
* Deletion subroutines for use by dependency.c.
*/
@ -1202,29 +1824,104 @@ RenameOpClass(List *name, const char *access_method, const char *newname)
}
/*
* Change opclass owner by oid
* Rename opfamily
*/
#ifdef NOT_USED
void
AlterOpClassOwner_oid(Oid opcOid, Oid newOwnerId)
RenameOpFamily(List *name, const char *access_method, const char *newname)
{
Relation rel;
Oid opfOid;
Oid amOid;
Oid namespaceOid;
char *schemaname;
char *opfname;
HeapTuple tup;
Relation rel;
AclResult aclresult;
rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
amOid = GetSysCacheOid(AMNAME,
CStringGetDatum(access_method),
0, 0, 0);
if (!OidIsValid(amOid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist",
access_method)));
tup = SearchSysCacheCopy(CLAOID,
ObjectIdGetDatum(opcOid),
0, 0, 0);
if (!HeapTupleIsValid(tup)) /* shouldn't happen */
elog(ERROR, "cache lookup failed for opclass %u", opcOid);
rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
AlterOpClassOwner_internal(rel, tup, newOwnerId);
/*
* Look up the opfamily
*/
DeconstructQualifiedName(name, &schemaname, &opfname);
if (schemaname)
{
namespaceOid = LookupExplicitNamespace(schemaname);
tup = SearchSysCacheCopy(OPFAMILYAMNAMENSP,
ObjectIdGetDatum(amOid),
PointerGetDatum(opfname),
ObjectIdGetDatum(namespaceOid),
0);
if (!HeapTupleIsValid(tup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator family \"%s\" does not exist for access method \"%s\"",
opfname, access_method)));
opfOid = HeapTupleGetOid(tup);
}
else
{
opfOid = OpfamilynameGetOpfid(amOid, opfname);
if (!OidIsValid(opfOid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator family \"%s\" does not exist for access method \"%s\"",
opfname, access_method)));
tup = SearchSysCacheCopy(OPFAMILYOID,
ObjectIdGetDatum(opfOid),
0, 0, 0);
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for opfamily %u", opfOid);
namespaceOid = ((Form_pg_opfamily) GETSTRUCT(tup))->opfnamespace;
}
/* make sure the new name doesn't exist */
if (SearchSysCacheExists(OPFAMILYAMNAMENSP,
ObjectIdGetDatum(amOid),
CStringGetDatum(newname),
ObjectIdGetDatum(namespaceOid),
0))
{
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
newname, access_method,
get_namespace_name(namespaceOid))));
}
/* must be owner */
if (!pg_opfamily_ownercheck(opfOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
NameListToString(name));
/* must have CREATE privilege on namespace */
aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceOid));
/* rename */
namestrcpy(&(((Form_pg_opfamily) GETSTRUCT(tup))->opfname), newname);
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
heap_freetuple(tup);
heap_close(rel, NoLock);
heap_freetuple(tup);
}
#endif
/*
* Change opclass owner by name
@ -1352,3 +2049,130 @@ AlterOpClassOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
newOwnerId);
}
}
/*
* Change opfamily owner by name
*/
void
AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwnerId)
{
Oid amOid;
Relation rel;
HeapTuple tup;
char *opfname;
char *schemaname;
amOid = GetSysCacheOid(AMNAME,
CStringGetDatum(access_method),
0, 0, 0);
if (!OidIsValid(amOid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist",
access_method)));
rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
/*
* Look up the opfamily
*/
DeconstructQualifiedName(name, &schemaname, &opfname);
if (schemaname)
{
Oid namespaceOid;
namespaceOid = LookupExplicitNamespace(schemaname);
tup = SearchSysCacheCopy(OPFAMILYAMNAMENSP,
ObjectIdGetDatum(amOid),
PointerGetDatum(opfname),
ObjectIdGetDatum(namespaceOid),
0);
if (!HeapTupleIsValid(tup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator family \"%s\" does not exist for access method \"%s\"",
opfname, access_method)));
}
else
{
Oid opfOid;
opfOid = OpfamilynameGetOpfid(amOid, opfname);
if (!OidIsValid(opfOid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator family \"%s\" does not exist for access method \"%s\"",
opfname, access_method)));
tup = SearchSysCacheCopy(OPFAMILYOID,
ObjectIdGetDatum(opfOid),
0, 0, 0);
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for opfamily %u", opfOid);
}
AlterOpFamilyOwner_internal(rel, tup, newOwnerId);
heap_freetuple(tup);
heap_close(rel, NoLock);
}
/*
* The first parameter is pg_opfamily, opened and suitably locked. The second
* parameter is a copy of the tuple from pg_opfamily we want to modify.
*/
static void
AlterOpFamilyOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
{
Oid namespaceOid;
AclResult aclresult;
Form_pg_opfamily opfForm;
Assert(tup->t_tableOid == OperatorFamilyRelationId);
Assert(RelationGetRelid(rel) == OperatorFamilyRelationId);
opfForm = (Form_pg_opfamily) GETSTRUCT(tup);
namespaceOid = opfForm->opfnamespace;
/*
* If the new owner is the same as the existing owner, consider the
* command to have succeeded. This is for dump restoration purposes.
*/
if (opfForm->opfowner != newOwnerId)
{
/* Superusers can always do it */
if (!superuser())
{
/* Otherwise, must be owner of the existing object */
if (!pg_opfamily_ownercheck(HeapTupleGetOid(tup), GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
NameStr(opfForm->opfname));
/* Must be able to become new owner */
check_is_member_of_role(GetUserId(), newOwnerId);
/* New owner must have CREATE privilege on namespace */
aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceOid));
}
/*
* Modify the owner --- okay to scribble on tup because it's a copy
*/
opfForm->opfowner = newOwnerId;
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
/* Update owner dependency reference */
changeDependencyOnOwner(OperatorFamilyRelationId, HeapTupleGetOid(tup),
newOwnerId);
}
}

View File

@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.363 2007/01/22 20:00:39 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.364 2007/01/23 05:07:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -2158,6 +2158,19 @@ _copyRemoveOpClassStmt(RemoveOpClassStmt *from)
return newnode;
}
static RemoveOpFamilyStmt *
_copyRemoveOpFamilyStmt(RemoveOpFamilyStmt *from)
{
RemoveOpFamilyStmt *newnode = makeNode(RemoveOpFamilyStmt);
COPY_NODE_FIELD(opfamilyname);
COPY_STRING_FIELD(amname);
COPY_SCALAR_FIELD(behavior);
COPY_SCALAR_FIELD(missing_ok);
return newnode;
}
static RenameStmt *
_copyRenameStmt(RenameStmt *from)
{
@ -2332,11 +2345,36 @@ _copyCreateOpClassItem(CreateOpClassItem *from)
COPY_NODE_FIELD(args);
COPY_SCALAR_FIELD(number);
COPY_SCALAR_FIELD(recheck);
COPY_NODE_FIELD(class_args);
COPY_NODE_FIELD(storedtype);
return newnode;
}
static CreateOpFamilyStmt *
_copyCreateOpFamilyStmt(CreateOpFamilyStmt *from)
{
CreateOpFamilyStmt *newnode = makeNode(CreateOpFamilyStmt);
COPY_NODE_FIELD(opfamilyname);
COPY_STRING_FIELD(amname);
return newnode;
}
static AlterOpFamilyStmt *
_copyAlterOpFamilyStmt(AlterOpFamilyStmt *from)
{
AlterOpFamilyStmt *newnode = makeNode(AlterOpFamilyStmt);
COPY_NODE_FIELD(opfamilyname);
COPY_STRING_FIELD(amname);
COPY_SCALAR_FIELD(isDrop);
COPY_NODE_FIELD(items);
return newnode;
}
static CreatedbStmt *
_copyCreatedbStmt(CreatedbStmt *from)
{
@ -3163,6 +3201,9 @@ copyObject(void *from)
case T_RemoveOpClassStmt:
retval = _copyRemoveOpClassStmt(from);
break;
case T_RemoveOpFamilyStmt:
retval = _copyRemoveOpFamilyStmt(from);
break;
case T_RenameStmt:
retval = _copyRenameStmt(from);
break;
@ -3205,6 +3246,12 @@ copyObject(void *from)
case T_CreateOpClassItem:
retval = _copyCreateOpClassItem(from);
break;
case T_CreateOpFamilyStmt:
retval = _copyCreateOpFamilyStmt(from);
break;
case T_AlterOpFamilyStmt:
retval = _copyAlterOpFamilyStmt(from);
break;
case T_CreatedbStmt:
retval = _copyCreatedbStmt(from);
break;

View File

@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.296 2007/01/20 20:45:38 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.297 2007/01/23 05:07:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1053,6 +1053,17 @@ _equalRemoveOpClassStmt(RemoveOpClassStmt *a, RemoveOpClassStmt *b)
return true;
}
static bool
_equalRemoveOpFamilyStmt(RemoveOpFamilyStmt *a, RemoveOpFamilyStmt *b)
{
COMPARE_NODE_FIELD(opfamilyname);
COMPARE_STRING_FIELD(amname);
COMPARE_SCALAR_FIELD(behavior);
COMPARE_SCALAR_FIELD(missing_ok);
return true;
}
static bool
_equalRenameStmt(RenameStmt *a, RenameStmt *b)
{
@ -1199,11 +1210,32 @@ _equalCreateOpClassItem(CreateOpClassItem *a, CreateOpClassItem *b)
COMPARE_NODE_FIELD(args);
COMPARE_SCALAR_FIELD(number);
COMPARE_SCALAR_FIELD(recheck);
COMPARE_NODE_FIELD(class_args);
COMPARE_NODE_FIELD(storedtype);
return true;
}
static bool
_equalCreateOpFamilyStmt(CreateOpFamilyStmt *a, CreateOpFamilyStmt *b)
{
COMPARE_NODE_FIELD(opfamilyname);
COMPARE_STRING_FIELD(amname);
return true;
}
static bool
_equalAlterOpFamilyStmt(AlterOpFamilyStmt *a, AlterOpFamilyStmt *b)
{
COMPARE_NODE_FIELD(opfamilyname);
COMPARE_STRING_FIELD(amname);
COMPARE_SCALAR_FIELD(isDrop);
COMPARE_NODE_FIELD(items);
return true;
}
static bool
_equalCreatedbStmt(CreatedbStmt *a, CreatedbStmt *b)
{
@ -2148,6 +2180,9 @@ equal(void *a, void *b)
case T_RemoveOpClassStmt:
retval = _equalRemoveOpClassStmt(a, b);
break;
case T_RemoveOpFamilyStmt:
retval = _equalRemoveOpFamilyStmt(a, b);
break;
case T_RenameStmt:
retval = _equalRenameStmt(a, b);
break;
@ -2190,6 +2225,12 @@ equal(void *a, void *b)
case T_CreateOpClassItem:
retval = _equalCreateOpClassItem(a, b);
break;
case T_CreateOpFamilyStmt:
retval = _equalCreateOpFamilyStmt(a, b);
break;
case T_AlterOpFamilyStmt:
retval = _equalAlterOpFamilyStmt(a, b);
break;
case T_CreatedbStmt:
retval = _equalCreatedbStmt(a, b);
break;

View File

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.575 2007/01/22 01:35:21 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.576 2007/01/23 05:07:17 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@ -152,11 +152,12 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
AlterUserStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt
AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
CreateDomainStmt CreateGroupStmt CreateOpClassStmt CreatePLangStmt
CreateDomainStmt CreateGroupStmt CreateOpClassStmt
CreateOpFamilyStmt AlterOpFamilyStmt CreatePLangStmt
CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
CreateAssertStmt CreateTrigStmt CreateUserStmt CreateRoleStmt
CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt
DropGroupStmt DropOpClassStmt DropPLangStmt DropStmt
DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt
DropUserStmt DropdbStmt DropTableSpaceStmt ExplainStmt FetchStmt
GrantStmt GrantRoleStmt IndexStmt InsertStmt ListenStmt LoadStmt
@ -174,7 +175,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
%type <node> select_no_parens select_with_parens select_clause
simple_select values_clause
%type <node> alter_column_default opclass_item alter_using
%type <node> alter_column_default opclass_item opclass_drop alter_using
%type <ival> add_drop opt_asc_desc opt_nulls_order
%type <node> alter_table_cmd alter_rel_cmd
@ -229,7 +230,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
OptTableElementList TableElementList OptInherit definition
OptWith opt_distinct opt_definition func_args func_args_list
func_as createfunc_opt_list alterfunc_opt_list
aggr_args aggr_args_list old_aggr_definition old_aggr_list
aggr_args old_aggr_definition old_aggr_list
oper_argtypes RuleActionList RuleActionMulti
opt_column_list columnList opt_name_list
sort_clause opt_sort_clause sortby_list index_params
@ -240,10 +241,10 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
set_clause_list set_clause multiple_set_clause
ctext_expr_list ctext_row def_list indirection opt_indirection
group_clause TriggerFuncArgs select_limit
opt_select_limit opclass_item_list
transaction_mode_list_or_empty
opt_select_limit opclass_item_list opclass_drop_list
opt_opfamily transaction_mode_list_or_empty
TableFuncElementList opt_type_modifiers
prep_type_clause prep_type_list
prep_type_clause
execute_param_clause using_clause returning_clause
%type <range> into_clause OptTempTableName
@ -381,7 +382,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ESCAPE EXCEPT EXCLUDING
EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
FALSE_P FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD
FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD
FREEZE FROM FULL FUNCTION
GLOBAL GRANT GRANTED GREATEST GROUP_P
@ -548,6 +549,8 @@ stmt :
| CreateFunctionStmt
| CreateGroupStmt
| CreateOpClassStmt
| CreateOpFamilyStmt
| AlterOpFamilyStmt
| CreatePLangStmt
| CreateSchemaStmt
| CreateSeqStmt
@ -565,6 +568,7 @@ stmt :
| DropCastStmt
| DropGroupStmt
| DropOpClassStmt
| DropOpFamilyStmt
| DropOwnedStmt
| DropPLangStmt
| DropRuleStmt
@ -929,7 +933,7 @@ AlterGroupStmt:
}
;
add_drop: ADD_P { $$ = +1; }
add_drop: ADD_P { $$ = +1; }
| DROP { $$ = -1; }
;
@ -2879,15 +2883,10 @@ def_arg: func_type { $$ = (Node *)$1; }
| Sconst { $$ = (Node *)makeString($1); }
;
aggr_args: '(' aggr_args_list ')' { $$ = $2; }
aggr_args: '(' type_list ')' { $$ = $2; }
| '(' '*' ')' { $$ = NIL; }
;
aggr_args_list:
Typename { $$ = list_make1($1); }
| aggr_args_list ',' Typename { $$ = lappend($1, $3); }
;
old_aggr_definition: '(' old_aggr_list ')' { $$ = $2; }
;
@ -2906,20 +2905,24 @@ old_aggr_elem: IDENT '=' def_arg
*
* QUERIES :
* CREATE OPERATOR CLASS ...
* CREATE OPERATOR FAMILY ...
* ALTER OPERATOR FAMILY ...
* DROP OPERATOR CLASS ...
* DROP OPERATOR FAMILY ...
*
*****************************************************************************/
CreateOpClassStmt:
CREATE OPERATOR CLASS any_name opt_default FOR TYPE_P Typename
USING access_method AS opclass_item_list
USING access_method opt_opfamily AS opclass_item_list
{
CreateOpClassStmt *n = makeNode(CreateOpClassStmt);
n->opclassname = $4;
n->isDefault = $5;
n->datatype = $8;
n->amname = $10;
n->items = $12;
n->opfamilyname = $11;
n->items = $13;
$$ = (Node *) n;
}
;
@ -2959,6 +2962,16 @@ opclass_item:
n->number = $2;
$$ = (Node *) n;
}
| FUNCTION Iconst '(' type_list ')' func_name func_args
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
n->itemtype = OPCLASS_ITEM_FUNCTION;
n->name = $6;
n->args = extractArgTypes($7);
n->number = $2;
n->class_args = $4;
$$ = (Node *) n;
}
| STORAGE Typename
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
@ -2968,12 +2981,72 @@ opclass_item:
}
;
opt_default: DEFAULT { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
opt_default: DEFAULT { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
opt_recheck: RECHECK { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
opt_opfamily: FAMILY any_name { $$ = $2; }
| /*EMPTY*/ { $$ = NIL; }
;
opt_recheck: RECHECK { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
CreateOpFamilyStmt:
CREATE OPERATOR FAMILY any_name USING access_method
{
CreateOpFamilyStmt *n = makeNode(CreateOpFamilyStmt);
n->opfamilyname = $4;
n->amname = $6;
$$ = (Node *) n;
}
;
AlterOpFamilyStmt:
ALTER OPERATOR FAMILY any_name USING access_method ADD_P opclass_item_list
{
AlterOpFamilyStmt *n = makeNode(AlterOpFamilyStmt);
n->opfamilyname = $4;
n->amname = $6;
n->isDrop = false;
n->items = $8;
$$ = (Node *) n;
}
| ALTER OPERATOR FAMILY any_name USING access_method DROP opclass_drop_list
{
AlterOpFamilyStmt *n = makeNode(AlterOpFamilyStmt);
n->opfamilyname = $4;
n->amname = $6;
n->isDrop = true;
n->items = $8;
$$ = (Node *) n;
}
;
opclass_drop_list:
opclass_drop { $$ = list_make1($1); }
| opclass_drop_list ',' opclass_drop { $$ = lappend($1, $3); }
;
opclass_drop:
OPERATOR Iconst '(' type_list ')'
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
n->itemtype = OPCLASS_ITEM_OPERATOR;
n->number = $2;
n->args = $4;
$$ = (Node *) n;
}
| FUNCTION Iconst '(' type_list ')'
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
n->itemtype = OPCLASS_ITEM_FUNCTION;
n->number = $2;
n->args = $4;
$$ = (Node *) n;
}
;
@ -2998,6 +3071,28 @@ DropOpClassStmt:
}
;
DropOpFamilyStmt:
DROP OPERATOR FAMILY any_name USING access_method opt_drop_behavior
{
RemoveOpFamilyStmt *n = makeNode(RemoveOpFamilyStmt);
n->opfamilyname = $4;
n->amname = $6;
n->behavior = $7;
n->missing_ok = false;
$$ = (Node *) n;
}
| DROP OPERATOR FAMILY IF_P EXISTS any_name USING access_method opt_drop_behavior
{
RemoveOpFamilyStmt *n = makeNode(RemoveOpFamilyStmt);
n->opfamilyname = $6;
n->amname = $8;
n->behavior = $9;
n->missing_ok = true;
$$ = (Node *) n;
}
;
/*****************************************************************************
*
* QUERY:
@ -3201,6 +3296,15 @@ CommentStmt:
n->comment = $9;
$$ = (Node *) n;
}
| COMMENT ON OPERATOR FAMILY any_name USING access_method IS comment_text
{
CommentStmt *n = makeNode(CommentStmt);
n->objtype = OBJECT_OPFAMILY;
n->objname = $5;
n->objargs = list_make1(makeString($7));
n->comment = $9;
$$ = (Node *) n;
}
| COMMENT ON LARGE_P OBJECT_P NumericOnly IS comment_text
{
CommentStmt *n = makeNode(CommentStmt);
@ -4115,9 +4219,9 @@ oper_argtypes:
}
| Typename ',' Typename
{ $$ = list_make2($1, $3); }
| NONE ',' Typename /* left unary */
| NONE ',' Typename /* left unary */
{ $$ = list_make2(NULL, $3); }
| Typename ',' NONE /* right unary */
| Typename ',' NONE /* right unary */
{ $$ = list_make2($1, NULL); }
;
@ -4174,8 +4278,8 @@ DropCastStmt: DROP CAST opt_if_exists '(' Typename AS Typename ')' opt_drop_beha
}
;
opt_if_exists: IF_P EXISTS { $$ = true; }
| /*EMPTY*/ { $$ = false; }
opt_if_exists: IF_P EXISTS { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
@ -4294,6 +4398,15 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
n->newname = $9;
$$ = (Node *)n;
}
| ALTER OPERATOR FAMILY any_name USING access_method RENAME TO name
{
RenameStmt *n = makeNode(RenameStmt);
n->renameType = OBJECT_OPFAMILY;
n->object = $4;
n->subname = $6;
n->newname = $9;
$$ = (Node *)n;
}
| ALTER SCHEMA name RENAME TO name
{
RenameStmt *n = makeNode(RenameStmt);
@ -4493,6 +4606,15 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $9;
$$ = (Node *)n;
}
| ALTER OPERATOR FAMILY any_name USING access_method OWNER TO RoleId
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPFAMILY;
n->object = $4;
n->addname = $6;
n->newowner = $9;
$$ = (Node *)n;
}
| ALTER SCHEMA name OWNER TO RoleId
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
@ -5302,15 +5424,10 @@ PrepareStmt: PREPARE name prep_type_clause AS PreparableStmt
}
;
prep_type_clause: '(' prep_type_list ')' { $$ = $2; }
prep_type_clause: '(' type_list ')' { $$ = $2; }
| /* EMPTY */ { $$ = NIL; }
;
prep_type_list: Typename { $$ = list_make1($1); }
| prep_type_list ',' Typename
{ $$ = lappend($1, $3); }
;
PreparableStmt:
SelectStmt
| InsertStmt
@ -7968,14 +8085,8 @@ extract_list:
| /*EMPTY*/ { $$ = NIL; }
;
type_list: type_list ',' Typename
{
$$ = lappend($1, $3);
}
| Typename
{
$$ = list_make1($1);
}
type_list: Typename { $$ = list_make1($1); }
| type_list ',' Typename { $$ = lappend($1, $3); }
;
array_expr_list: array_expr
@ -8604,6 +8715,7 @@ unreserved_keyword:
| EXECUTE
| EXPLAIN
| EXTERNAL
| FAMILY
| FETCH
| FIRST_P
| FORCE

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.182 2007/01/22 01:35:21 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.183 2007/01/23 05:07:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -145,6 +145,7 @@ static const ScanKeyword ScanKeywords[] = {
{"external", EXTERNAL},
{"extract", EXTRACT},
{"false", FALSE_P},
{"family", FAMILY},
{"fetch", FETCH},
{"first", FIRST_P},
{"float", FLOAT_P},

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.270 2007/01/05 22:19:39 momjian Exp $
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.271 2007/01/23 05:07:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -322,6 +322,8 @@ check_xact_readonly(Node *parsetree)
case T_IndexStmt:
case T_CreatePLangStmt:
case T_CreateOpClassStmt:
case T_CreateOpFamilyStmt:
case T_AlterOpFamilyStmt:
case T_RuleStmt:
case T_CreateSchemaStmt:
case T_CreateSeqStmt:
@ -338,6 +340,7 @@ check_xact_readonly(Node *parsetree)
case T_DropRoleStmt:
case T_DropPLangStmt:
case T_RemoveOpClassStmt:
case T_RemoveOpFamilyStmt:
case T_DropPropertyStmt:
case T_GrantStmt:
case T_GrantRoleStmt:
@ -1099,10 +1102,22 @@ ProcessUtility(Node *parsetree,
DefineOpClass((CreateOpClassStmt *) parsetree);
break;
case T_CreateOpFamilyStmt:
DefineOpFamily((CreateOpFamilyStmt *) parsetree);
break;
case T_AlterOpFamilyStmt:
AlterOpFamily((AlterOpFamilyStmt *) parsetree);
break;
case T_RemoveOpClassStmt:
RemoveOpClass((RemoveOpClassStmt *) parsetree);
break;
case T_RemoveOpFamilyStmt:
RemoveOpFamily((RemoveOpFamilyStmt *) parsetree);
break;
default:
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(parsetree));
@ -1445,6 +1460,9 @@ CreateCommandTag(Node *parsetree)
case OBJECT_OPCLASS:
tag = "ALTER OPERATOR CLASS";
break;
case OBJECT_OPFAMILY:
tag = "ALTER OPERATOR FAMILY";
break;
case OBJECT_ROLE:
tag = "ALTER ROLE";
break;
@ -1518,6 +1536,9 @@ CreateCommandTag(Node *parsetree)
case OBJECT_OPCLASS:
tag = "ALTER OPERATOR CLASS";
break;
case OBJECT_OPFAMILY:
tag = "ALTER OPERATOR FAMILY";
break;
case OBJECT_SCHEMA:
tag = "ALTER SCHEMA";
break;
@ -1777,10 +1798,22 @@ CreateCommandTag(Node *parsetree)
tag = "CREATE OPERATOR CLASS";
break;
case T_CreateOpFamilyStmt:
tag = "CREATE OPERATOR FAMILY";
break;
case T_AlterOpFamilyStmt:
tag = "ALTER OPERATOR FAMILY";
break;
case T_RemoveOpClassStmt:
tag = "DROP OPERATOR CLASS";
break;
case T_RemoveOpFamilyStmt:
tag = "DROP OPERATOR FAMILY";
break;
case T_PrepareStmt:
tag = "PREPARE";
break;
@ -2147,10 +2180,22 @@ GetCommandLogLevel(Node *parsetree)
lev = LOGSTMT_DDL;
break;
case T_CreateOpFamilyStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterOpFamilyStmt:
lev = LOGSTMT_DDL;
break;
case T_RemoveOpClassStmt:
lev = LOGSTMT_DDL;
break;
case T_RemoveOpFamilyStmt:
lev = LOGSTMT_DDL;
break;
case T_PrepareStmt:
{
PrepareStmt *stmt = (PrepareStmt *) parsetree;

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.79 2007/01/05 22:19:53 momjian Exp $
* $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.80 2007/01/23 05:07:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -79,13 +79,18 @@ extern void AlterAggregateOwner(List *name, List *args, Oid newOwnerId);
/* commands/opclasscmds.c */
extern void DefineOpClass(CreateOpClassStmt *stmt);
extern void DefineOpFamily(CreateOpFamilyStmt *stmt);
extern void AlterOpFamily(AlterOpFamilyStmt *stmt);
extern void RemoveOpClass(RemoveOpClassStmt *stmt);
extern void RemoveOpFamily(RemoveOpFamilyStmt *stmt);
extern void RemoveOpClassById(Oid opclassOid);
extern void RemoveOpFamilyById(Oid opfamilyOid);
extern void RemoveAmOpEntryById(Oid entryOid);
extern void RemoveAmProcEntryById(Oid entryOid);
extern void RenameOpClass(List *name, const char *access_method, const char *newname);
extern void RenameOpFamily(List *name, const char *access_method, const char *newname);
extern void AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId);
extern void AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwnerId);
/* support routines in commands/define.c */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.192 2007/01/20 20:45:40 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.193 2007/01/23 05:07:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -286,7 +286,10 @@ typedef enum NodeTag
T_CreateCastStmt,
T_DropCastStmt,
T_CreateOpClassStmt,
T_CreateOpFamilyStmt,
T_AlterOpFamilyStmt,
T_RemoveOpClassStmt,
T_RemoveOpFamilyStmt,
T_PrepareStmt,
T_ExecuteStmt,
T_DeallocateStmt,

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.338 2007/01/09 02:14:15 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.339 2007/01/23 05:07:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -852,6 +852,7 @@ typedef enum ObjectType
OBJECT_LARGEOBJECT,
OBJECT_OPCLASS,
OBJECT_OPERATOR,
OBJECT_OPFAMILY,
OBJECT_ROLE,
OBJECT_RULE,
OBJECT_SCHEMA,
@ -1194,7 +1195,7 @@ typedef struct DropTableSpaceStmt
{
NodeTag type;
char *tablespacename;
bool missing_ok; /* skip error if a missing? */
bool missing_ok; /* skip error if missing? */
} DropTableSpaceStmt;
/* ----------------------
@ -1362,10 +1363,35 @@ typedef struct CreateOpClassItem
List *args; /* argument types */
int number; /* strategy num or support proc num */
bool recheck; /* only used for operators */
List *class_args; /* only used for functions */
/* fields used for a storagetype item: */
TypeName *storedtype; /* datatype stored in index */
} CreateOpClassItem;
/* ----------------------
* Create Operator Family Statement
* ----------------------
*/
typedef struct CreateOpFamilyStmt
{
NodeTag type;
List *opfamilyname; /* qualified name (list of Value strings) */
char *amname; /* name of index AM opfamily is for */
} CreateOpFamilyStmt;
/* ----------------------
* Alter Operator Family Statement
* ----------------------
*/
typedef struct AlterOpFamilyStmt
{
NodeTag type;
List *opfamilyname; /* qualified name (list of Value strings) */
char *amname; /* name of index AM opfamily is for */
bool isDrop; /* ADD or DROP the items? */
List *items; /* List of CreateOpClassItem nodes */
} AlterOpFamilyStmt;
/* ----------------------
* Drop Table|Sequence|View|Index|Type|Domain|Conversion|Schema Statement
* ----------------------
@ -1395,7 +1421,7 @@ typedef struct DropPropertyStmt
char *property; /* name of rule, trigger, etc */
ObjectType removeType; /* OBJECT_RULE or OBJECT_TRIGGER */
DropBehavior behavior; /* RESTRICT or CASCADE behavior */
bool missing_ok; /* skip error if a missing? */
bool missing_ok; /* skip error if missing? */
} DropPropertyStmt;
/* ----------------------
@ -1546,7 +1572,7 @@ typedef struct RemoveFuncStmt
List *name; /* qualified name of object to drop */
List *args; /* types of the arguments */
DropBehavior behavior; /* RESTRICT or CASCADE behavior */
bool missing_ok; /* skip error if a missing? */
bool missing_ok; /* skip error if missing? */
} RemoveFuncStmt;
/* ----------------------
@ -1559,9 +1585,22 @@ typedef struct RemoveOpClassStmt
List *opclassname; /* qualified name (list of Value strings) */
char *amname; /* name of index AM opclass is for */
DropBehavior behavior; /* RESTRICT or CASCADE behavior */
bool missing_ok; /* skip error if a missing? */
bool missing_ok; /* skip error if missing? */
} RemoveOpClassStmt;
/* ----------------------
* Drop Operator Family Statement
* ----------------------
*/
typedef struct RemoveOpFamilyStmt
{
NodeTag type;
List *opfamilyname; /* qualified name (list of Value strings) */
char *amname; /* name of index AM opfamily is for */
DropBehavior behavior; /* RESTRICT or CASCADE behavior */
bool missing_ok; /* skip error if missing? */
} RemoveOpFamilyStmt;
/* ----------------------
* Alter Object Rename Statement
* ----------------------
@ -1917,7 +1956,7 @@ typedef struct DropCastStmt
TypeName *sourcetype;
TypeName *targettype;
DropBehavior behavior;
bool missing_ok; /* skip error if a missing? */
bool missing_ok; /* skip error if missing? */
} DropCastStmt;

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.99 2007/01/05 22:19:58 momjian Exp $
* $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.100 2007/01/23 05:07:18 tgl Exp $
*
* NOTES
* An ACL array is simply an array of AclItems, representing the union
@ -178,6 +178,7 @@ typedef enum AclObjectKind
ACL_KIND_LANGUAGE, /* pg_language */
ACL_KIND_NAMESPACE, /* pg_namespace */
ACL_KIND_OPCLASS, /* pg_opclass */
ACL_KIND_OPFAMILY, /* pg_opfamily */
ACL_KIND_CONVERSION, /* pg_conversion */
ACL_KIND_TABLESPACE, /* pg_tablespace */
MAX_ACL_KIND /* MUST BE LAST */
@ -276,6 +277,7 @@ extern bool pg_proc_ownercheck(Oid proc_oid, Oid roleid);
extern bool pg_namespace_ownercheck(Oid nsp_oid, Oid roleid);
extern bool pg_tablespace_ownercheck(Oid spc_oid, Oid roleid);
extern bool pg_opclass_ownercheck(Oid opc_oid, Oid roleid);
extern bool pg_opfamily_ownercheck(Oid opf_oid, Oid roleid);
extern bool pg_database_ownercheck(Oid db_oid, Oid roleid);
extern bool pg_conversion_ownercheck(Oid conv_oid, Oid roleid);