1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-12 05:01:15 +03:00

Implement CREATE/DROP OPERATOR CLASS. Work still remains: need more

documentation (xindex.sgml should be rewritten), need to teach pg_dump
about it, need to update contrib modules that currently build pg_opclass
entries by hand.  Original patch by Bill Studenmund, grammar adjustments
and general update for 7.3 by Tom Lane.
This commit is contained in:
Tom Lane
2002-07-29 22:14:11 +00:00
parent b9459c6adb
commit ea4686e3e1
26 changed files with 1697 additions and 373 deletions

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.71 2002/07/20 05:16:56 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.72 2002/07/29 22:14:10 tgl Exp $
*
* NOTES
* See acl.h.
@@ -26,6 +26,7 @@
#include "catalog/pg_group.h"
#include "catalog/pg_language.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_shadow.h"
@@ -1369,3 +1370,30 @@ pg_namespace_ownercheck(Oid nsp_oid, Oid userid)
return userid == owner_id;
}
/*
* Ownership check for an operator class (specified by OID).
*/
bool
pg_opclass_ownercheck(Oid opc_oid, Oid userid)
{
HeapTuple tuple;
AclId owner_id;
/* Superusers bypass all permission checking. */
if (superuser_arg(userid))
return true;
tuple = SearchSysCache(CLAOID,
ObjectIdGetDatum(opc_oid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "pg_opclass_ownercheck: operator class %u not found",
opc_oid);
owner_id = ((Form_pg_opclass) GETSTRUCT(tuple))->opcowner;
ReleaseSysCache(tuple);
return userid == owner_id;
}

View File

@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.6 2002/07/25 10:07:10 ishii Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.7 2002/07/29 22:14:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,15 +21,16 @@
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_attrdef.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_language.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "commands/comment.h"
#include "commands/defrem.h"
#include "commands/proclang.h"
@@ -40,6 +41,7 @@
#include "optimizer/clauses.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteRemove.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
@@ -48,15 +50,16 @@
/* This enum covers all system catalogs whose OIDs can appear in classid. */
typedef enum ObjectClasses
{
OCLASS_CAST, /* pg_cast */
OCLASS_CLASS, /* pg_class */
OCLASS_PROC, /* pg_proc */
OCLASS_TYPE, /* pg_type */
OCLASS_CAST, /* pg_cast */
OCLASS_CONSTRAINT, /* pg_constraint */
OCLASS_CONVERSION, /* pg_conversion */
OCLASS_DEFAULT, /* pg_attrdef */
OCLASS_LANGUAGE, /* pg_language */
OCLASS_OPERATOR, /* pg_operator */
OCLASS_OPCLASS, /* pg_opclass */
OCLASS_REWRITE, /* pg_rewrite */
OCLASS_TRIGGER, /* pg_trigger */
OCLASS_SCHEMA, /* pg_namespace */
@@ -579,6 +582,10 @@ doDeletion(const ObjectAddress *object)
RemoveTypeById(object->objectId);
break;
case OCLASS_CAST:
DropCastById(object->objectId);
break;
case OCLASS_CONSTRAINT:
RemoveConstraintById(object->objectId);
break;
@@ -599,6 +606,10 @@ doDeletion(const ObjectAddress *object)
RemoveOperatorById(object->objectId);
break;
case OCLASS_OPCLASS:
RemoveOpClassById(object->objectId);
break;
case OCLASS_REWRITE:
RemoveRewriteRuleById(object->objectId);
break;
@@ -611,10 +622,6 @@ doDeletion(const ObjectAddress *object)
RemoveSchemaById(object->objectId);
break;
case OCLASS_CAST:
DropCastById(object->objectId);
break;
default:
elog(ERROR, "doDeletion: Unsupported object class %u",
object->classId);
@@ -990,15 +997,16 @@ term_object_addresses(ObjectAddresses *addrs)
static void
init_object_classes(void)
{
object_classes[OCLASS_CAST] = get_system_catalog_relid(CastRelationName);
object_classes[OCLASS_CLASS] = RelOid_pg_class;
object_classes[OCLASS_PROC] = RelOid_pg_proc;
object_classes[OCLASS_TYPE] = RelOid_pg_type;
object_classes[OCLASS_CAST] = get_system_catalog_relid(CastRelationName);
object_classes[OCLASS_CONSTRAINT] = get_system_catalog_relid(ConstraintRelationName);
object_classes[OCLASS_CONVERSION] = get_system_catalog_relid(ConversionRelationName);
object_classes[OCLASS_DEFAULT] = get_system_catalog_relid(AttrDefaultRelationName);
object_classes[OCLASS_LANGUAGE] = get_system_catalog_relid(LanguageRelationName);
object_classes[OCLASS_OPERATOR] = get_system_catalog_relid(OperatorRelationName);
object_classes[OCLASS_OPCLASS] = get_system_catalog_relid(OperatorClassRelationName);
object_classes[OCLASS_REWRITE] = get_system_catalog_relid(RewriteRelationName);
object_classes[OCLASS_TRIGGER] = get_system_catalog_relid(TriggerRelationName);
object_classes[OCLASS_SCHEMA] = get_system_catalog_relid(NamespaceRelationName);
@@ -1066,6 +1074,11 @@ getObjectClass(const ObjectAddress *object)
Assert(object->objectSubId == 0);
return OCLASS_OPERATOR;
}
if (object->classId == object_classes[OCLASS_OPCLASS])
{
Assert(object->objectSubId == 0);
return OCLASS_OPCLASS;
}
if (object->classId == object_classes[OCLASS_REWRITE])
{
Assert(object->objectSubId == 0);
@@ -1101,10 +1114,6 @@ getObjectDescription(const ObjectAddress *object)
switch (getObjectClass(object))
{
case OCLASS_CAST:
appendStringInfo(&buffer, "cast");
break;
case OCLASS_CLASS:
getRelationDescription(&buffer, object->objectId);
if (object->objectSubId != 0)
@@ -1114,24 +1123,46 @@ getObjectDescription(const ObjectAddress *object)
break;
case OCLASS_PROC:
/* XXX could improve on this */
appendStringInfo(&buffer, "function %s",
get_func_name(object->objectId));
format_procedure(object->objectId));
break;
case OCLASS_TYPE:
{
HeapTuple typeTup;
typeTup = SearchSysCache(TYPEOID,
ObjectIdGetDatum(object->objectId),
0, 0, 0);
if (!HeapTupleIsValid(typeTup))
elog(ERROR, "getObjectDescription: Type %u does not exist",
object->objectId);
appendStringInfo(&buffer, "type %s",
NameStr(((Form_pg_type) GETSTRUCT(typeTup))->typname));
ReleaseSysCache(typeTup);
format_type_be(object->objectId));
break;
case OCLASS_CAST:
{
Relation castDesc;
ScanKeyData skey[1];
SysScanDesc rcscan;
HeapTuple tup;
Form_pg_cast castForm;
castDesc = heap_openr(CastRelationName, AccessShareLock);
ScanKeyEntryInitialize(&skey[0], 0x0,
ObjectIdAttributeNumber, F_OIDEQ,
ObjectIdGetDatum(object->objectId));
rcscan = systable_beginscan(castDesc, CastOidIndex, true,
SnapshotNow, 1, skey);
tup = systable_getnext(rcscan);
if (!HeapTupleIsValid(tup))
elog(ERROR, "getObjectDescription: Cast %u does not exist",
object->objectId);
castForm = (Form_pg_cast) GETSTRUCT(tup);
appendStringInfo(&buffer, "cast from %s to %s",
format_type_be(castForm->castsource),
format_type_be(castForm->casttarget));
systable_endscan(rcscan);
heap_close(castDesc, AccessShareLock);
break;
}
@@ -1248,11 +1279,52 @@ getObjectDescription(const ObjectAddress *object)
}
case OCLASS_OPERATOR:
/* XXX could improve on this */
appendStringInfo(&buffer, "operator %s",
get_opname(object->objectId));
format_operator(object->objectId));
break;
case OCLASS_OPCLASS:
{
HeapTuple opcTup;
Form_pg_opclass opcForm;
HeapTuple amTup;
Form_pg_am amForm;
char *nspname;
opcTup = SearchSysCache(CLAOID,
ObjectIdGetDatum(object->objectId),
0, 0, 0);
if (!HeapTupleIsValid(opcTup))
elog(ERROR, "cache lookup of opclass %u failed",
object->objectId);
opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
/* Qualify the name if not visible in search path */
if (OpclassIsVisible(object->objectId))
nspname = NULL;
else
nspname = get_namespace_name(opcForm->opcnamespace);
appendStringInfo(&buffer, "operator class %s",
quote_qualified_identifier(nspname,
NameStr(opcForm->opcname)));
amTup = SearchSysCache(AMOID,
ObjectIdGetDatum(opcForm->opcamid),
0, 0, 0);
if (!HeapTupleIsValid(amTup))
elog(ERROR, "syscache lookup for AM %u failed",
opcForm->opcamid);
amForm = (Form_pg_am) GETSTRUCT(amTup);
appendStringInfo(&buffer, " for %s",
NameStr(amForm->amname));
ReleaseSysCache(amTup);
ReleaseSysCache(opcTup);
break;
}
case OCLASS_REWRITE:
{
Relation ruleDesc;
@@ -1323,17 +1395,13 @@ getObjectDescription(const ObjectAddress *object)
case OCLASS_SCHEMA:
{
HeapTuple schemaTup;
char *nspname;
schemaTup = SearchSysCache(NAMESPACEOID,
ObjectIdGetDatum(object->objectId),
0, 0, 0);
if (!HeapTupleIsValid(schemaTup))
nspname = get_namespace_name(object->objectId);
if (!nspname)
elog(ERROR, "getObjectDescription: Schema %u does not exist",
object->objectId);
appendStringInfo(&buffer, "schema %s",
NameStr(((Form_pg_namespace) GETSTRUCT(schemaTup))->nspname));
ReleaseSysCache(schemaTup);
appendStringInfo(&buffer, "schema %s", nspname);
break;
}
@@ -1356,49 +1424,58 @@ getRelationDescription(StringInfo buffer, Oid relid)
{
HeapTuple relTup;
Form_pg_class relForm;
char *nspname;
char *relname;
relTup = SearchSysCache(RELOID,
ObjectIdGetDatum(relid),
0, 0, 0);
if (!HeapTupleIsValid(relTup))
elog(ERROR, "getObjectDescription: Relation %u does not exist",
relid);
elog(ERROR, "cache lookup of relation %u failed", relid);
relForm = (Form_pg_class) GETSTRUCT(relTup);
/* Qualify the name if not visible in search path */
if (RelationIsVisible(relid))
nspname = NULL;
else
nspname = get_namespace_name(relForm->relnamespace);
relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
switch (relForm->relkind)
{
case RELKIND_RELATION:
appendStringInfo(buffer, "table %s",
NameStr(relForm->relname));
relname);
break;
case RELKIND_INDEX:
appendStringInfo(buffer, "index %s",
NameStr(relForm->relname));
relname);
break;
case RELKIND_SPECIAL:
appendStringInfo(buffer, "special system relation %s",
NameStr(relForm->relname));
relname);
break;
case RELKIND_SEQUENCE:
appendStringInfo(buffer, "sequence %s",
NameStr(relForm->relname));
relname);
break;
case RELKIND_UNCATALOGED:
appendStringInfo(buffer, "uncataloged table %s",
NameStr(relForm->relname));
relname);
break;
case RELKIND_TOASTVALUE:
appendStringInfo(buffer, "toast table %s",
NameStr(relForm->relname));
relname);
break;
case RELKIND_VIEW:
appendStringInfo(buffer, "view %s",
NameStr(relForm->relname));
relname);
break;
default:
/* shouldn't get here */
appendStringInfo(buffer, "relation %s",
NameStr(relForm->relname));
relname);
break;
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.186 2002/07/20 05:16:56 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.187 2002/07/29 22:14:10 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -712,7 +712,7 @@ index_create(Oid heapRelationId,
false, /* isDeferred */
heapRelationId,
indexInfo->ii_KeyAttrNumbers,
indexInfo->ii_NumIndexAttrs,
indexInfo->ii_NumKeyAttrs,
InvalidOid, /* no domain */
InvalidOid, /* no foreign key */
NULL,
@@ -732,7 +732,7 @@ index_create(Oid heapRelationId,
}
else
{
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
{
referenced.classId = RelOid_pg_class;
referenced.objectId = heapRelationId;
@@ -742,6 +742,16 @@ index_create(Oid heapRelationId,
}
}
/* Store dependency on operator classes */
referenced.classId = get_system_catalog_relid(OperatorClassRelationName);
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
{
referenced.objectId = classObjectId[i];
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
/* Store the dependency on the function (if appropriate) */
if (OidIsValid(indexInfo->ii_FuncOid))
{

View File

@@ -4,7 +4,7 @@
# Makefile for backend/commands
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.29 2002/07/11 07:39:27 ishii Exp $
# $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.30 2002/07/29 22:14:10 tgl Exp $
#
#-------------------------------------------------------------------------
@@ -15,7 +15,8 @@ include $(top_builddir)/src/Makefile.global
OBJS = aggregatecmds.o analyze.o async.o cluster.o comment.o \
conversioncmds.o copy.o \
dbcommands.o define.o explain.o functioncmds.o \
indexcmds.o lockcmds.o operatorcmds.o portalcmds.o proclang.o \
indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
portalcmds.o proclang.o \
schemacmds.o sequence.o tablecmds.o trigger.o typecmds.o user.o \
vacuum.o vacuumlazy.o variable.o view.o

View File

@@ -0,0 +1,639 @@
/*-------------------------------------------------------------------------
*
* opclasscmds.c
*
* Routines for opclass manipulation commands
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/opclasscmds.c,v 1.1 2002/07/29 22:14:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_am.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_opclass.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
static void storeOperators(Oid opclassoid, int numOperators,
Oid *operators, bool *recheck);
static void storeProcedures(Oid opclassoid, int numProcs, Oid *procedures);
/*
* DefineOpClass
* Define a new index operator class.
*/
void
DefineOpClass(CreateOpClassStmt *stmt)
{
char *opcname; /* name of opclass we're creating */
Oid amoid, /* our AM's oid */
typeoid, /* indexable datatype oid */
storageoid, /* storage datatype oid, if any */
namespaceoid, /* namespace to create opclass in */
opclassoid; /* oid of opclass we create */
int numOperators, /* amstrategies value */
numProcs; /* amsupport value */
Oid *operators, /* oids of operators, by strategy num */
*procedures; /* oids of support procs */
bool *recheck; /* do operators need recheck */
List *iteml;
Relation rel;
HeapTuple tup;
Datum values[Natts_pg_opclass];
char nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
int i;
ObjectAddress myself,
referenced;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
&opcname);
/* Check we have creation rights in target namespace */
aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, get_namespace_name(namespaceoid));
/* Get necessary info about access method */
tup = SearchSysCache(AMNAME,
CStringGetDatum(stmt->amname),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "DefineOpClass: access method \"%s\" not found",
stmt->amname);
amoid = HeapTupleGetOid(tup);
numOperators = ((Form_pg_am) GETSTRUCT(tup))->amstrategies;
numProcs = ((Form_pg_am) GETSTRUCT(tup))->amsupport;
/* XXX Should we make any privilege check against the AM? */
ReleaseSysCache(tup);
/* Look up the datatype */
typeoid = typenameTypeId(stmt->datatype);
/* Check we have ownership of the datatype */
if (!pg_type_ownercheck(typeoid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, format_type_be(typeoid));
/* Storage datatype is optional */
storageoid = InvalidOid;
/*
* Create work arrays to hold info about operators and procedures.
* We do this mainly so that we can detect duplicate strategy
* numbers and support-proc numbers.
*/
operators = (Oid *) palloc(sizeof(Oid) * numOperators);
MemSet(operators, 0, sizeof(Oid) * numOperators);
procedures = (Oid *) palloc(sizeof(Oid) * numProcs);
MemSet(procedures, 0, sizeof(Oid) * numProcs);
recheck = (bool *) palloc(sizeof(bool) * numOperators);
MemSet(recheck, 0, sizeof(bool) * numOperators);
/*
* Scan the "items" list to obtain additional info.
*/
foreach(iteml, stmt->items)
{
CreateOpClassItem *item = lfirst(iteml);
Oid operOid;
Oid funcOid;
AclResult aclresult;
Assert(IsA(item, CreateOpClassItem));
switch (item->itemtype)
{
case OPCLASS_ITEM_OPERATOR:
if (item->number <= 0 || item->number > numOperators)
elog(ERROR, "DefineOpClass: invalid operator number %d,"
" must be between 1 and %d",
item->number, numOperators);
if (operators[item->number - 1] != InvalidOid)
elog(ERROR, "DefineOpClass: operator number %d appears more than once",
item->number);
if (item->args != NIL)
{
TypeName *typeName1 = (TypeName *) lfirst(item->args);
TypeName *typeName2 = (TypeName *) lsecond(item->args);
operOid = LookupOperNameTypeNames(item->name,
typeName1, typeName2,
"DefineOpClass");
/* No need to check for error */
}
else
{
/* Default to binary op on input datatype */
operOid = LookupOperName(item->name, typeoid, typeoid);
if (!OidIsValid(operOid))
elog(ERROR, "DefineOpClass: Operator '%s' for types '%s' and '%s' does not exist",
NameListToString(item->name),
format_type_be(typeoid),
format_type_be(typeoid));
}
/* Caller must have execute permission on operators */
funcOid = get_opcode(operOid);
aclresult = pg_proc_aclcheck(funcOid, GetUserId(),
ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, get_func_name(funcOid));
operators[item->number - 1] = operOid;
recheck[item->number - 1] = item->recheck;
break;
case OPCLASS_ITEM_FUNCTION:
if (item->number <= 0 || item->number > numProcs)
elog(ERROR, "DefineOpClass: invalid procedure number %d,"
" must be between 1 and %d",
item->number, numProcs);
if (procedures[item->number - 1] != InvalidOid)
elog(ERROR, "DefineOpClass: procedure number %d appears more than once",
item->number);
funcOid = LookupFuncNameTypeNames(item->name, item->args,
true, "DefineOpClass");
/* Caller must have execute permission on functions */
aclresult = pg_proc_aclcheck(funcOid, GetUserId(),
ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, get_func_name(funcOid));
procedures[item->number - 1] = funcOid;
break;
case OPCLASS_ITEM_STORAGETYPE:
if (OidIsValid(storageoid))
elog(ERROR, "DefineOpClass: storage type specified more than once");
storageoid = typenameTypeId(item->storedtype);
break;
default:
elog(ERROR, "DefineOpClass: bogus item type %d",
item->itemtype);
break;
}
}
/*
* If storagetype is specified, make sure it's legal.
*/
if (OidIsValid(storageoid))
{
/* Just drop the spec if same as column datatype */
if (storageoid == typeoid)
storageoid = InvalidOid;
else
{
/*
* Currently, only GiST allows storagetype different from
* datatype. This hardcoded test should be eliminated in
* favor of adding another boolean column to pg_am ...
*/
if (amoid != GIST_AM_OID)
elog(ERROR, "Storage type may not be different from datatype for access method %s",
stmt->amname);
}
}
rel = heap_openr(OperatorClassRelationName, RowExclusiveLock);
/*
* Make sure there is no existing opclass of this name (this is
* just to give a more friendly error message than "duplicate key").
*/
if (SearchSysCacheExists(CLAAMNAMENSP,
ObjectIdGetDatum(amoid),
CStringGetDatum(opcname),
ObjectIdGetDatum(namespaceoid),
0))
elog(ERROR, "Operator class \"%s\" already exists for access method \"%s\"",
opcname, stmt->amname);
/*
* If we are creating a default opclass, check there isn't one already.
* (XXX should we restrict this test to visible opclasses?)
*/
if (stmt->isDefault)
{
ScanKeyData skey[1];
SysScanDesc scan;
ScanKeyEntryInitialize(&skey[0], 0x0,
Anum_pg_opclass_opcamid, F_OIDEQ,
ObjectIdGetDatum(amoid));
scan = systable_beginscan(rel, OpclassAmNameNspIndex, true,
SnapshotNow, 1, skey);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
if (opclass->opcintype == typeoid && opclass->opcdefault)
elog(ERROR, "Can't add class \"%s\" as default for type %s"
"\n\tclass \"%s\" already is the default",
opcname,
TypeNameToString(stmt->datatype),
NameStr(opclass->opcname));
}
systable_endscan(scan);
}
/*
* Okay, let's create the pg_opclass entry.
*/
for (i = 0; i < Natts_pg_opclass; ++i)
{
nulls[i] = ' ';
values[i] = (Datum) NULL; /* redundant, but safe */
}
i = 0;
values[i++] = ObjectIdGetDatum(amoid); /* opcamid */
namestrcpy(&opcName, opcname);
values[i++] = NameGetDatum(&opcName); /* opcname */
values[i++] = ObjectIdGetDatum(namespaceoid); /* opcnamespace */
values[i++] = Int32GetDatum(GetUserId()); /* opcowner */
values[i++] = ObjectIdGetDatum(typeoid); /* opcintype */
values[i++] = BoolGetDatum(stmt->isDefault); /* opcdefault */
values[i++] = ObjectIdGetDatum(storageoid); /* opckeytype */
tup = heap_formtuple(rel->rd_att, values, nulls);
opclassoid = simple_heap_insert(rel, tup);
if (RelationGetForm(rel)->relhasindex)
{
Relation idescs[Num_pg_opclass_indices];
CatalogOpenIndices(Num_pg_opclass_indices, Name_pg_opclass_indices,
idescs);
CatalogIndexInsert(idescs, Num_pg_opclass_indices, rel, tup);
CatalogCloseIndices(Num_pg_opclass_indices, idescs);
}
heap_freetuple(tup);
/*
* Now add tuples to pg_amop and pg_amproc tying in the
* operators and functions.
*/
storeOperators(opclassoid, numOperators, operators, recheck);
storeProcedures(opclassoid, numProcs, procedures);
/*
* Create dependencies. Note: we do not create a dependency link to
* the AM, because we don't currently support DROP ACCESS METHOD.
*/
myself.classId = RelationGetRelid(rel);
myself.objectId = opclassoid;
myself.objectSubId = 0;
/* dependency on namespace */
referenced.classId = get_system_catalog_relid(NamespaceRelationName);
referenced.objectId = namespaceoid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* dependency on indexed datatype */
referenced.classId = RelOid_pg_type;
referenced.objectId = typeoid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* dependency on storage datatype */
if (OidIsValid(storageoid))
{
referenced.classId = RelOid_pg_type;
referenced.objectId = storageoid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
/* dependencies on operators */
referenced.classId = get_system_catalog_relid(OperatorRelationName);
for (i = 0; i < numOperators; i++)
{
if (operators[i] == InvalidOid)
continue;
referenced.objectId = operators[i];
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
/* dependencies on procedures */
for (i = 0; i < numProcs; i++)
{
if (procedures[i] == InvalidOid)
continue;
referenced.classId = RelOid_pg_proc;
referenced.objectId = procedures[i];
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
heap_close(rel, RowExclusiveLock);
}
/*
* Dump the operators to pg_amop
*/
static void
storeOperators(Oid opclassoid, int numOperators,
Oid *operators, bool *recheck)
{
Relation rel;
Datum values[Natts_pg_amop];
char nulls[Natts_pg_amop];
HeapTuple tup;
int i, j;
rel = heap_openr(AccessMethodOperatorRelationName, RowExclusiveLock);
for (j = 0; j < numOperators; j++)
{
if (operators[j] == InvalidOid)
continue;
for (i = 0; i < Natts_pg_amop; ++i)
{
nulls[i] = ' ';
values[i] = (Datum) NULL;
}
i = 0;
values[i++] = ObjectIdGetDatum(opclassoid); /* amopclaid */
values[i++] = Int16GetDatum(j + 1); /* amopstrategy */
values[i++] = BoolGetDatum(recheck[j]); /* amopreqcheck */
values[i++] = ObjectIdGetDatum(operators[j]); /* amopopr */
tup = heap_formtuple(rel->rd_att, values, nulls);
simple_heap_insert(rel, tup);
if (RelationGetForm(rel)->relhasindex)
{
Relation idescs[Num_pg_amop_indices];
CatalogOpenIndices(Num_pg_amop_indices, Name_pg_amop_indices,
idescs);
CatalogIndexInsert(idescs, Num_pg_amop_indices, rel, tup);
CatalogCloseIndices(Num_pg_amop_indices, idescs);
}
heap_freetuple(tup);
}
heap_close(rel, RowExclusiveLock);
}
/*
* Dump the procedures (support routines) to pg_amproc
*/
static void
storeProcedures(Oid opclassoid, int numProcs, Oid *procedures)
{
Relation rel;
Datum values[Natts_pg_amproc];
char nulls[Natts_pg_amproc];
HeapTuple tup;
int i, j;
rel = heap_openr(AccessMethodProcedureRelationName, RowExclusiveLock);
for (j = 0; j < numProcs; j++)
{
if (procedures[j] == InvalidOid)
continue;
for (i = 0; i < Natts_pg_amproc; ++i)
{
nulls[i] = ' ';
values[i] = (Datum) NULL;
}
i = 0;
values[i++] = ObjectIdGetDatum(opclassoid); /* amopclaid */
values[i++] = Int16GetDatum(j + 1); /* amprocnum */
values[i++] = ObjectIdGetDatum(procedures[j]); /* amproc */
tup = heap_formtuple(rel->rd_att, values, nulls);
simple_heap_insert(rel, tup);
if (RelationGetForm(rel)->relhasindex)
{
Relation idescs[Num_pg_amproc_indices];
CatalogOpenIndices(Num_pg_amproc_indices, Name_pg_amproc_indices,
idescs);
CatalogIndexInsert(idescs, Num_pg_amproc_indices, rel, tup);
CatalogCloseIndices(Num_pg_amproc_indices, idescs);
}
heap_freetuple(tup);
}
heap_close(rel, RowExclusiveLock);
}
/*
* RemoveOpClass
* Deletes an opclass.
*/
void
RemoveOpClass(RemoveOpClassStmt *stmt)
{
Oid amID, opcID;
char *catalogname;
char *schemaname = NULL;
char *opcname = NULL;
HeapTuple tuple;
ObjectAddress object;
/*
* Get the access method's OID.
*/
amID = GetSysCacheOid(AMNAME,
CStringGetDatum(stmt->amname),
0, 0, 0);
if (!OidIsValid(amID))
elog(ERROR, "RemoveOpClass: access method \"%s\" not found",
stmt->amname);
/*
* Look up the opclass.
*/
/* deconstruct the name list */
switch (length(stmt->opclassname))
{
case 1:
opcname = strVal(lfirst(stmt->opclassname));
break;
case 2:
schemaname = strVal(lfirst(stmt->opclassname));
opcname = strVal(lsecond(stmt->opclassname));
break;
case 3:
catalogname = strVal(lfirst(stmt->opclassname));
schemaname = strVal(lsecond(stmt->opclassname));
opcname = strVal(lfirst(lnext(lnext(stmt->opclassname))));
/*
* We check the catalog name and then ignore it.
*/
if (strcmp(catalogname, DatabaseName) != 0)
elog(ERROR, "Cross-database references are not implemented");
break;
default:
elog(ERROR, "Improper opclass name (too many dotted names): %s",
NameListToString(stmt->opclassname));
break;
}
if (schemaname)
{
/* Look in specific schema only */
Oid namespaceId;
namespaceId = GetSysCacheOid(NAMESPACENAME,
CStringGetDatum(schemaname),
0, 0, 0);
if (!OidIsValid(namespaceId))
elog(ERROR, "Namespace \"%s\" does not exist",
schemaname);
tuple = SearchSysCache(CLAAMNAMENSP,
ObjectIdGetDatum(amID),
PointerGetDatum(opcname),
ObjectIdGetDatum(namespaceId),
0);
}
else
{
/* Unqualified opclass name, so search the search path */
opcID = OpclassnameGetOpcid(amID, opcname);
if (!OidIsValid(opcID))
elog(ERROR, "RemoveOpClass: operator class \"%s\" not supported by access method \"%s\"",
opcname, stmt->amname);
tuple = SearchSysCache(CLAOID,
ObjectIdGetDatum(opcID),
0, 0, 0);
}
if (!HeapTupleIsValid(tuple))
elog(ERROR, "RemoveOpClass: operator class \"%s\" not supported by access method \"%s\"",
NameListToString(stmt->opclassname), stmt->amname);
opcID = HeapTupleGetOid(tuple);
/* Permission check: must own opclass or its namespace */
if (!pg_opclass_ownercheck(opcID, GetUserId()) &&
!pg_namespace_ownercheck(((Form_pg_opclass) GETSTRUCT(tuple))->opcnamespace,
GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER,
NameListToString(stmt->opclassname));
ReleaseSysCache(tuple);
/*
* Do the deletion
*/
object.classId = get_system_catalog_relid(OperatorClassRelationName);
object.objectId = opcID;
object.objectSubId = 0;
performDeletion(&object, stmt->behavior);
}
/*
* Guts of opclass deletion.
*/
void
RemoveOpClassById(Oid opclassOid)
{
Relation rel;
HeapTuple tup;
ScanKeyData skey[1];
SysScanDesc scan;
/*
* First remove the pg_opclass entry itself.
*/
rel = heap_openr(OperatorClassRelationName, RowExclusiveLock);
tup = SearchSysCache(CLAOID,
ObjectIdGetDatum(opclassOid),
0, 0, 0);
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "RemoveOpClassById: couldn't find pg_class entry %u",
opclassOid);
simple_heap_delete(rel, &tup->t_self);
ReleaseSysCache(tup);
heap_close(rel, RowExclusiveLock);
/*
* Remove associated entries in pg_amop.
*/
ScanKeyEntryInitialize(&skey[0], 0,
Anum_pg_amop_amopclaid, F_OIDEQ,
ObjectIdGetDatum(opclassOid));
rel = heap_openr(AccessMethodOperatorRelationName, RowExclusiveLock);
scan = systable_beginscan(rel, AccessMethodStrategyIndex, true,
SnapshotNow, 1, skey);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
simple_heap_delete(rel, &tup->t_self);
}
systable_endscan(scan);
heap_close(rel, RowExclusiveLock);
/*
* Remove associated entries in pg_amproc.
*/
ScanKeyEntryInitialize(&skey[0], 0,
Anum_pg_amproc_amopclaid, F_OIDEQ,
ObjectIdGetDatum(opclassOid));
rel = heap_openr(AccessMethodProcedureRelationName, RowExclusiveLock);
scan = systable_beginscan(rel, AccessMethodProcedureIndex, true,
SnapshotNow, 1, skey);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
simple_heap_delete(rel, &tup->t_self);
}
systable_endscan(scan);
heap_close(rel, RowExclusiveLock);
}

View File

@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.197 2002/07/24 19:11:10 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.198 2002/07/29 22:14:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2147,6 +2147,19 @@ _copyRemoveOperStmt(RemoveOperStmt *from)
return newnode;
}
static RemoveOpClassStmt *
_copyRemoveOpClassStmt(RemoveOpClassStmt *from)
{
RemoveOpClassStmt *newnode = makeNode(RemoveOpClassStmt);
Node_Copy(from, newnode, opclassname);
if (from->amname)
newnode->amname = pstrdup(from->amname);
newnode->behavior = from->behavior;
return newnode;
}
static RenameStmt *
_copyRenameStmt(RenameStmt *from)
{
@@ -2252,6 +2265,36 @@ _copyCreateDomainStmt(CreateDomainStmt *from)
return newnode;
}
static CreateOpClassStmt *
_copyCreateOpClassStmt(CreateOpClassStmt *from)
{
CreateOpClassStmt *newnode = makeNode(CreateOpClassStmt);
Node_Copy(from, newnode, opclassname);
if (from->amname)
newnode->amname = pstrdup(from->amname);
Node_Copy(from, newnode, datatype);
Node_Copy(from, newnode, items);
newnode->isDefault = from->isDefault;
return newnode;
}
static CreateOpClassItem *
_copyCreateOpClassItem(CreateOpClassItem *from)
{
CreateOpClassItem *newnode = makeNode(CreateOpClassItem);
newnode->itemtype = from->itemtype;
Node_Copy(from, newnode, name);
Node_Copy(from, newnode, args);
newnode->number = from->number;
newnode->recheck = from->recheck;
Node_Copy(from, newnode, storedtype);
return newnode;
}
static CreatedbStmt *
_copyCreatedbStmt(CreatedbStmt *from)
{
@@ -2872,6 +2915,9 @@ copyObject(void *from)
case T_RemoveOperStmt:
retval = _copyRemoveOperStmt(from);
break;
case T_RemoveOpClassStmt:
retval = _copyRemoveOpClassStmt(from);
break;
case T_RenameStmt:
retval = _copyRenameStmt(from);
break;
@@ -2899,6 +2945,12 @@ copyObject(void *from)
case T_CreateDomainStmt:
retval = _copyCreateDomainStmt(from);
break;
case T_CreateOpClassStmt:
retval = _copyCreateOpClassStmt(from);
break;
case T_CreateOpClassItem:
retval = _copyCreateOpClassItem(from);
break;
case T_CreatedbStmt:
retval = _copyCreatedbStmt(from);
break;

View File

@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.144 2002/07/24 19:11:10 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.145 2002/07/29 22:14:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -976,6 +976,18 @@ _equalRemoveOperStmt(RemoveOperStmt *a, RemoveOperStmt *b)
return true;
}
static bool
_equalRemoveOpClassStmt(RemoveOpClassStmt *a, RemoveOpClassStmt *b)
{
if (!equal(a->opclassname, b->opclassname))
return false;
if (!equalstr(a->amname, b->amname))
return false;
if (a->behavior != b->behavior)
return false;
return true;
}
static bool
_equalRenameStmt(RenameStmt *a, RenameStmt *b)
@@ -1082,6 +1094,42 @@ _equalCreateDomainStmt(CreateDomainStmt *a, CreateDomainStmt *b)
return true;
}
static bool
_equalCreateOpClassStmt(CreateOpClassStmt *a, CreateOpClassStmt *b)
{
if (!equal(a->opclassname, b->opclassname))
return false;
if (!equalstr(a->amname, b->amname))
return false;
if (!equal(a->datatype, b->datatype))
return false;
if (!equal(a->items, b->items))
return false;
if (a->isDefault != b->isDefault)
return false;
return true;
}
static bool
_equalCreateOpClassItem(CreateOpClassItem *a, CreateOpClassItem *b)
{
if (a->itemtype != b->itemtype)
return false;
if (!equal(a->name, b->name))
return false;
if (!equal(a->args, b->args))
return false;
if (a->number != b->number)
return false;
if (a->recheck != b->recheck)
return false;
if (!equal(a->storedtype, b->storedtype))
return false;
return true;
}
static bool
_equalCreatedbStmt(CreatedbStmt *a, CreatedbStmt *b)
{
@@ -2036,6 +2084,9 @@ equal(void *a, void *b)
case T_RemoveOperStmt:
retval = _equalRemoveOperStmt(a, b);
break;
case T_RemoveOpClassStmt:
retval = _equalRemoveOpClassStmt(a, b);
break;
case T_RenameStmt:
retval = _equalRenameStmt(a, b);
break;
@@ -2063,6 +2114,12 @@ equal(void *a, void *b)
case T_CreateDomainStmt:
retval = _equalCreateDomainStmt(a, b);
break;
case T_CreateOpClassStmt:
retval = _equalCreateOpClassStmt(a, b);
break;
case T_CreateOpClassItem:
retval = _equalCreateOpClassItem(a, b);
break;
case T_CreatedbStmt:
retval = _equalCreatedbStmt(a, b);
break;

View File

@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.349 2002/07/24 19:11:10 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.350 2002/07/29 22:14:10 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -136,11 +136,11 @@ static void doNegateFloat(Value *v);
AlterTableStmt, AlterUserStmt, AlterUserSetStmt,
AnalyzeStmt, ClosePortalStmt, ClusterStmt, CommentStmt,
ConstraintsSetStmt, CopyStmt, CreateAsStmt, CreateCastStmt,
CreateDomainStmt, CreateGroupStmt, CreatePLangStmt,
CreateDomainStmt, CreateGroupStmt, CreateOpClassStmt, CreatePLangStmt,
CreateSchemaStmt, CreateSeqStmt, CreateStmt,
CreateAssertStmt, CreateTrigStmt, CreateUserStmt,
CreatedbStmt, CursorStmt, DefineStmt, DeleteStmt,
DropGroupStmt, DropPLangStmt, DropStmt,
DropGroupStmt, DropOpClassStmt, DropPLangStmt, DropStmt,
DropAssertStmt, DropTrigStmt, DropRuleStmt, DropCastStmt,
DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt,
@@ -156,7 +156,7 @@ static void doNegateFloat(Value *v);
%type <node> select_no_parens, select_with_parens, select_clause,
simple_select
%type <node> alter_column_default
%type <node> alter_column_default, opclass_item
%type <ival> add_drop
%type <dbehavior> opt_drop_behavior
@@ -218,7 +218,7 @@ static void doNegateFloat(Value *v);
target_list, update_target_list, insert_column_list,
insert_target_list, def_list, opt_indirection,
group_clause, TriggerFuncArgs, select_limit,
opt_select_limit
opt_select_limit, opclass_item_list
%type <range> into_clause, OptTempTableName
@@ -240,7 +240,7 @@ static void doNegateFloat(Value *v);
%type <boolean> opt_instead, opt_cursor
%type <boolean> index_opt_unique, opt_verbose, opt_full
%type <boolean> opt_freeze, opt_default
%type <boolean> opt_freeze, opt_default, opt_recheck
%type <defelt> opt_binary, opt_oids, copy_delimiter
%type <boolean> copy_from
@@ -326,7 +326,7 @@ static void doNegateFloat(Value *v);
BOOLEAN, BY,
CACHE, CALLED, CASCADE, CASE, CAST, CHAIN, CHAR_P,
CHARACTER, CHARACTERISTICS, CHECK, CHECKPOINT, CLOSE,
CHARACTER, CHARACTERISTICS, CHECK, CHECKPOINT, CLASS, CLOSE,
CLUSTER, COALESCE, COLLATE, COLUMN, COMMENT, COMMIT,
COMMITTED, CONSTRAINT, CONSTRAINTS, CONVERSION_P, COPY, CREATE, CREATEDB,
CREATEUSER, CROSS, CURRENT_DATE, CURRENT_TIME,
@@ -371,7 +371,7 @@ static void doNegateFloat(Value *v);
PRECISION, PRIMARY, PRIOR, PRIVILEGES, PROCEDURE,
PROCEDURAL,
READ, REAL, REFERENCES, REINDEX, RELATIVE, RENAME, REPLACE,
READ, REAL, RECHECK, REFERENCES, REINDEX, RELATIVE, RENAME, REPLACE,
RESET, RESTRICT, RETURNS, REVOKE, RIGHT, ROLLBACK, ROW,
RULE,
@@ -481,6 +481,7 @@ stmt :
| CreateSchemaStmt
| CreateGroupStmt
| CreateSeqStmt
| CreateOpClassStmt
| CreatePLangStmt
| CreateAssertStmt
| CreateTrigStmt
@@ -492,6 +493,7 @@ stmt :
| CommentStmt
| DropCastStmt
| DropGroupStmt
| DropOpClassStmt
| DropPLangStmt
| DropAssertStmt
| DropTrigStmt
@@ -2265,6 +2267,93 @@ def_arg: func_return { $$ = (Node *)$1; }
;
/*****************************************************************************
*
* QUERIES :
* CREATE OPERATOR CLASS ...
* DROP OPERATOR CLASS ...
*
*****************************************************************************/
CreateOpClassStmt:
CREATE OPERATOR CLASS any_name opt_default FOR TYPE_P Typename
USING access_method AS opclass_item_list
{
CreateOpClassStmt *n = makeNode(CreateOpClassStmt);
n->opclassname = $4;
n->isDefault = $5;
n->datatype = $8;
n->amname = $10;
n->items = $12;
$$ = (Node *) n;
}
;
opclass_item_list:
opclass_item { $$ = makeList1($1); }
| opclass_item_list ',' opclass_item { $$ = lappend($1, $3); }
;
opclass_item:
OPERATOR Iconst any_operator opt_recheck
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
n->itemtype = OPCLASS_ITEM_OPERATOR;
n->name = $3;
n->args = NIL;
n->number = $2;
n->recheck = $4;
$$ = (Node *) n;
}
| OPERATOR Iconst any_operator '(' oper_argtypes ')' opt_recheck
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
n->itemtype = OPCLASS_ITEM_OPERATOR;
n->name = $3;
n->args = $5;
n->number = $2;
n->recheck = $7;
$$ = (Node *) n;
}
| FUNCTION Iconst func_name func_args
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
n->itemtype = OPCLASS_ITEM_FUNCTION;
n->name = $3;
n->args = $4;
n->number = $2;
$$ = (Node *) n;
}
| STORAGE Typename
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
n->itemtype = OPCLASS_ITEM_STORAGETYPE;
n->storedtype = $2;
$$ = (Node *) n;
}
;
opt_default: DEFAULT { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
opt_recheck: RECHECK { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
DropOpClassStmt:
DROP OPERATOR CLASS any_name USING access_method opt_drop_behavior
{
RemoveOpClassStmt *n = makeNode(RemoveOpClassStmt);
n->opclassname = $4;
n->amname = $6;
n->behavior = $7;
$$ = (Node *) n;
}
;
/*****************************************************************************
*
* QUERY:
@@ -3655,10 +3744,6 @@ CreateConversionStmt:
}
;
opt_default: DEFAULT { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
/*****************************************************************************
*
* QUERY:
@@ -6624,6 +6709,7 @@ unreserved_keyword:
| CHAIN
| CHARACTERISTICS
| CHECKPOINT
| CLASS
| CLOSE
| CLUSTER
| COMMENT
@@ -6715,6 +6801,7 @@ unreserved_keyword:
| PROCEDURAL
| PROCEDURE
| READ
| RECHECK
| REINDEX
| RELATIVE
| RENAME

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.122 2002/07/18 23:11:28 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.123 2002/07/29 22:14:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -68,6 +68,7 @@ static const ScanKeyword ScanKeywords[] = {
{"characteristics", CHARACTERISTICS},
{"check", CHECK},
{"checkpoint", CHECKPOINT},
{"class", CLASS},
{"close", CLOSE},
{"cluster", CLUSTER},
{"coalesce", COALESCE},
@@ -232,6 +233,7 @@ static const ScanKeyword ScanKeywords[] = {
{"procedure", PROCEDURE},
{"read", READ},
{"real", REAL},
{"recheck", RECHECK},
{"references", REFERENCES},
{"reindex", REINDEX},
{"relative", RELATIVE},

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.272 2002/07/18 23:11:28 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.273 2002/07/29 22:14:11 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -1693,7 +1693,7 @@ PostgresMain(int argc, char *argv[], const char *username)
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
puts("$Revision: 1.272 $ $Date: 2002/07/18 23:11:28 $\n");
puts("$Revision: 1.273 $ $Date: 2002/07/29 22:14:11 $\n");
}
/*
@@ -2452,6 +2452,14 @@ CreateCommandTag(Node *parsetree)
tag = "DROP CAST";
break;
case T_CreateOpClassStmt:
tag = "CREATE OPERATOR CLASS";
break;
case T_RemoveOpClassStmt:
tag = "DROP OPERATOR CLASS";
break;
default:
elog(LOG, "CreateCommandTag: unknown parse node type %d",
nodeTag(parsetree));

View File

@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.165 2002/07/25 10:07:11 ishii Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.166 2002/07/29 22:14:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -836,6 +836,14 @@ ProcessUtility(Node *parsetree,
DropCast((DropCastStmt *) parsetree);
break;
case T_CreateOpClassStmt:
DefineOpClass((CreateOpClassStmt *) parsetree);
break;
case T_RemoveOpClassStmt:
RemoveOpClass((RemoveOpClassStmt *) parsetree);
break;
default:
elog(ERROR, "ProcessUtility: command #%d unsupported",
nodeTag(parsetree));

View File

@@ -13,7 +13,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.71 2002/07/20 05:16:58 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.72 2002/07/29 22:14:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -280,23 +280,19 @@ regprocedurein(PG_FUNCTION_ARGS)
}
/*
* regprocedureout - converts proc OID to "pro_name(args)"
* format_procedure - converts proc OID to "pro_name(args)"
*
* This exports the useful functionality of regprocedureout for use
* in other backend modules. The result is a palloc'd string.
*/
Datum
regprocedureout(PG_FUNCTION_ARGS)
char *
format_procedure(Oid procedure_oid)
{
RegProcedure proid = PG_GETARG_OID(0);
char *result;
HeapTuple proctup;
if (proid == InvalidOid)
{
result = pstrdup("-");
PG_RETURN_CSTRING(result);
}
proctup = SearchSysCache(PROCOID,
ObjectIdGetDatum(proid),
ObjectIdGetDatum(procedure_oid),
0, 0, 0);
if (HeapTupleIsValid(proctup))
@@ -316,7 +312,7 @@ regprocedureout(PG_FUNCTION_ARGS)
* Would this proc be found (given the right args) by regprocedurein?
* If not, we need to qualify it.
*/
if (FunctionIsVisible(proid))
if (FunctionIsVisible(procedure_oid))
nspname = NULL;
else
nspname = get_namespace_name(procform->pronamespace);
@@ -344,9 +340,26 @@ regprocedureout(PG_FUNCTION_ARGS)
{
/* If OID doesn't match any pg_proc entry, return it numerically */
result = (char *) palloc(NAMEDATALEN);
snprintf(result, NAMEDATALEN, "%u", proid);
snprintf(result, NAMEDATALEN, "%u", procedure_oid);
}
return result;
}
/*
* regprocedureout - converts proc OID to "pro_name(args)"
*/
Datum
regprocedureout(PG_FUNCTION_ARGS)
{
RegProcedure proid = PG_GETARG_OID(0);
char *result;
if (proid == InvalidOid)
result = pstrdup("-");
else
result = format_procedure(proid);
PG_RETURN_CSTRING(result);
}
@@ -602,23 +615,19 @@ regoperatorin(PG_FUNCTION_ARGS)
}
/*
* regoperatorout - converts operator OID to "opr_name(args)"
* format_operator - converts operator OID to "opr_name(args)"
*
* This exports the useful functionality of regoperatorout for use
* in other backend modules. The result is a palloc'd string.
*/
Datum
regoperatorout(PG_FUNCTION_ARGS)
char *
format_operator(Oid operator_oid)
{
Oid oprid = PG_GETARG_OID(0);
char *result;
HeapTuple opertup;
if (oprid == InvalidOid)
{
result = pstrdup("0");
PG_RETURN_CSTRING(result);
}
opertup = SearchSysCache(OPEROID,
ObjectIdGetDatum(oprid),
ObjectIdGetDatum(operator_oid),
0, 0, 0);
if (HeapTupleIsValid(opertup))
@@ -636,7 +645,7 @@ regoperatorout(PG_FUNCTION_ARGS)
* Would this oper be found (given the right args) by regoperatorin?
* If not, we need to qualify it.
*/
if (!OperatorIsVisible(oprid))
if (!OperatorIsVisible(operator_oid))
{
nspname = get_namespace_name(operform->oprnamespace);
appendStringInfo(&buf, "%s.",
@@ -665,9 +674,26 @@ regoperatorout(PG_FUNCTION_ARGS)
{
/* If OID doesn't match any pg_operator entry, return it numerically */
result = (char *) palloc(NAMEDATALEN);
snprintf(result, NAMEDATALEN, "%u", oprid);
snprintf(result, NAMEDATALEN, "%u", operator_oid);
}
return result;
}
/*
* regoperatorout - converts operator OID to "opr_name(args)"
*/
Datum
regoperatorout(PG_FUNCTION_ARGS)
{
Oid oprid = PG_GETARG_OID(0);
char *result;
if (oprid == InvalidOid)
result = pstrdup("0");
else
result = format_operator(oprid);
PG_RETURN_CSTRING(result);
}