Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions src/backend/catalog/dependency.c
Original file line number Diff line number Diff line change
Expand Up @@ -1582,10 +1582,19 @@ doDeletion(const ObjectAddress *object, int flags)
elog(ERROR, "global objects cannot be deleted by doDeletion");
break;

default:
{
struct CustomObjectClass *coc;

coc = find_custom_object_class_by_classid(object->classId, false);
if (coc->do_delete)
coc->do_delete(coc, object, flags);
/*
* There's intentionally no default: case here; we want the
* compiler to warn if a new OCLASS hasn't been handled above.
*/
break;
}
}
}

Expand Down Expand Up @@ -2960,6 +2969,15 @@ getObjectClass(const ObjectAddress *object)

case TaskRelationId:
return OCLASS_TASK;

default:
{
struct CustomObjectClass *coc;
coc = find_custom_object_class_by_classid(object->classId, true);
if (coc)
return coc->oclass;
break;
}
}

/* shouldn't get here */
Expand Down Expand Up @@ -3097,3 +3115,67 @@ DeleteInitPrivs(const ObjectAddress *object)

table_close(relation, RowExclusiveLock);
}

/* Custom object class */
#define FIRST_COSTOM_OBJECT_CLASS 512
static List *custom_object_class_list = NIL;

/*
* don't support unregister object class in a session.
* Return: the oclass allocated by the kernel
*/
int
register_custom_object_class(struct CustomObjectClass *coc)
{
MemoryContext saved_ctx;
/* check class_id and required callbacks */
Assert(OidIsValid(coc->class_id));
Assert(coc->do_delete);

if (find_custom_object_class_by_classid(coc->class_id, true))
elog(ERROR, "class_id %u exists already", coc->class_id);

coc->oclass = FIRST_COSTOM_OBJECT_CLASS + list_length(custom_object_class_list);
saved_ctx = MemoryContextSwitchTo(TopMemoryContext);
custom_object_class_list = lappend(custom_object_class_list, coc);
MemoryContextSwitchTo(saved_ctx);
return coc->oclass;
}

struct CustomObjectClass *
find_custom_object_class(int oclass)
{
int index = oclass - FIRST_COSTOM_OBJECT_CLASS;

if (oclass < FIRST_COSTOM_OBJECT_CLASS)
elog(ERROR, "unexpected oclass, found builtin one %u", oclass);
if (index >= list_length(custom_object_class_list))
elog(ERROR, "unexpected oclass beyond custom object class %u", oclass);

return (struct CustomObjectClass *) list_nth(custom_object_class_list, index);
}

struct CustomObjectClass *
find_custom_object_class_by_classid(Oid class_id, bool missing_ok)
{
ListCell *lc;

#ifdef USE_ASSERT_CHECKING
int n = lengthof(object_classes);
Assert(n < FIRST_COSTOM_OBJECT_CLASS);

for (int i = 0; i < n; i++) {
if (object_classes[i] == class_id)
elog(ERROR, "find builtin object class by class id %u", class_id);
}
#endif

foreach(lc, custom_object_class_list) {
struct CustomObjectClass *coc = (struct CustomObjectClass *)lfirst(lc);
if (coc->class_id == class_id)
return coc;
}
if (!missing_ok)
ereport(ERROR, (errmsg("found no custom object class for class_id=%u", class_id)));
return NULL;
}
27 changes: 27 additions & 0 deletions src/backend/catalog/objectaddress.c
Original file line number Diff line number Diff line change
Expand Up @@ -4079,6 +4079,15 @@ getObjectDescription(const ObjectAddress *object, bool missing_ok)
appendStringInfo(&buffer, _("history password for role %s"), username);
break;
}

default:
{
struct CustomObjectClass *coc;

coc = find_custom_object_class_by_classid(object->classId, missing_ok);
if (coc && coc->object_desc)
coc->object_desc(coc, object, missing_ok, &buffer);
}
}

/* an empty buffer is equivalent to no object found */
Expand Down Expand Up @@ -4650,10 +4659,19 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
appendStringInfoString(&buffer, "password_history");
break;

default:
{
struct CustomObjectClass *coc;

coc = find_custom_object_class_by_classid(object->classId, false);
if (coc->object_type_desc)
coc->object_type_desc(coc, object, missing_ok, &buffer);
/*
* There's intentionally no default: case here; we want the
* compiler to warn if a new OCLASS hasn't been handled above.
*/
break;
}
}

/* the result can never be empty */
Expand Down Expand Up @@ -5988,10 +6006,19 @@ getObjectIdentityParts(const ObjectAddress *object,
break;
}

default:
{
struct CustomObjectClass *coc;

coc = find_custom_object_class_by_classid(object->classId, false);
if (coc->object_identity_parts)
coc->object_identity_parts(coc, object, objname, objargs, missing_ok, &buffer);
/*
* There's intentionally no default: case here; we want the
* compiler to warn if a new OCLASS hasn't been handled above.
*/
break;
}
}

if (!missing_ok)
Expand Down
9 changes: 9 additions & 0 deletions src/backend/commands/alter.c
Original file line number Diff line number Diff line change
Expand Up @@ -736,10 +736,19 @@ AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid,
/* ignore object types that don't have schema-qualified names */
break;

default:
{
struct CustomObjectClass *coc;

coc = find_custom_object_class_by_classid(classId, false);
if (coc->alter_namespace)
coc->alter_namespace(coc, &dep, nspOid, objsMoved);
/*
* There's intentionally no default: case here; we want the
* compiler to warn if a new OCLASS hasn't been handled above.
*/
break;
}
}

return oldNspOid;
Expand Down
10 changes: 10 additions & 0 deletions src/backend/commands/event_trigger.c
Original file line number Diff line number Diff line change
Expand Up @@ -1069,10 +1069,20 @@ EventTriggerSupportsObjectClass(ObjectClass objclass)
case OCLASS_TASK:
return false;

default:
{
struct CustomObjectClass *coc;

coc = find_custom_object_class(objclass);
Assert(coc);
if (coc->support_event_trigger)
return coc->support_event_trigger(coc);
/*
* There's intentionally no default: case here; we want the
* compiler to warn if a new OCLASS hasn't been handled above.
*/
break;
}
}

return true;
Expand Down
8 changes: 8 additions & 0 deletions src/backend/commands/tablecmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -14028,10 +14028,18 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
getObjectDescription(&foundObject, false));
break;

default:
{
struct CustomObjectClass *coc;
coc = find_custom_object_class_by_classid(foundObject.classId, false);
if (coc->alter_column_type)
coc->alter_column_type(coc);
/*
* There's intentionally no default: case here; we want the
* compiler to warn if a new OCLASS hasn't been handled above.
*/
break;
}
}
}

Expand Down
35 changes: 35 additions & 0 deletions src/include/catalog/dependency.h
Original file line number Diff line number Diff line change
Expand Up @@ -290,4 +290,39 @@ extern void recordProfileDependency(Oid roleId, Oid profileId);

extern void changeProfileDependency(Oid roleId, Oid profileId);

/* Custom object class */
struct StringInfoData;
struct CustomObjectClass {
Oid class_id;
int oclass;

void (*do_delete)(struct CustomObjectClass *self,
const ObjectAddress *object, int flags);
void (*object_desc)(struct CustomObjectClass *self,
const ObjectAddress *object,
bool missing_ok,
struct StringInfoData *buffer);
void (*object_type_desc)(struct CustomObjectClass *self,
const ObjectAddress *object,
bool missing_ok,
struct StringInfoData *buffer);
void (*object_identity_parts)(struct CustomObjectClass *self,
const ObjectAddress *object,
List **objname,
List **objargs,
bool missing_ok,
struct StringInfoData *buffer);

Oid (*alter_namespace)(struct CustomObjectClass *self,
const ObjectAddress *object,
Oid nspOid,
ObjectAddresses *objsMoved);
bool (*support_event_trigger)(struct CustomObjectClass *self);
// FIXME: unclear which arguments should pass
void (*alter_column_type)(struct CustomObjectClass *self);

};
extern int register_custom_object_class(struct CustomObjectClass *coc);
extern struct CustomObjectClass *find_custom_object_class(int oclass);
extern struct CustomObjectClass *find_custom_object_class_by_classid(Oid class_id, bool missing_ok);
#endif /* DEPENDENCY_H */