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:
@ -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).
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -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 --
|
||||
*
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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},
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user