diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c new file mode 100644 index 470db57..06dbe28 *** a/src/backend/commands/functioncmds.c --- b/src/backend/commands/functioncmds.c *************** *** 41,46 **** --- 41,47 ---- #include "catalog/objectaccess.h" #include "catalog/pg_aggregate.h" #include "catalog/pg_cast.h" + #include "catalog/pg_depend.h" #include "catalog/pg_language.h" #include "catalog/pg_namespace.h" #include "catalog/pg_proc.h" *************** interpret_AS_clause(Oid languageOid, con *** 805,810 **** --- 806,875 ---- } + /* + * Checks if there is an index that depends on the function. + */ + static bool + has_dependent_index(Oid funcoid) + { + bool result = false; + Relation depRel, relRel; + ScanKeyData key[2]; + SysScanDesc depScan; + HeapTuple depTup, relTup; + + /* + * We scan pg_depend to find dependent indexes. + */ + depRel = heap_open(DependRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_refclassid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(ProcedureRelationId)); + ScanKeyInit(&key[1], + Anum_pg_depend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(funcoid)); + + depScan = systable_beginscan(depRel, DependReferenceIndexId, true, + NULL, 2, key); + + while (HeapTupleIsValid(depTup = systable_getnext(depScan))) + { + Form_pg_depend pg_depend = (Form_pg_depend)GETSTRUCT(depTup); + + if (pg_depend->classid == RelationRelationId && + pg_depend->deptype == DEPENDENCY_NORMAL) + { + Form_pg_class pg_class; + + /* check if the dependent relation is an index */ + relRel = heap_open(RelationRelationId, AccessShareLock); + + relTup = SearchSysCache1(RELOID, ObjectIdGetDatum(pg_depend->objid)); + if (!HeapTupleIsValid(relTup)) + elog(ERROR, "cache lookup failed for relation %u", pg_depend->objid); + + pg_class = (Form_pg_class)GETSTRUCT(relTup); + + if (pg_class->relkind == RELKIND_INDEX) + result = true; + + ReleaseSysCache(relTup); + + relation_close(relRel, AccessShareLock); + } + } + + systable_endscan(depScan); + + relation_close(depRel, AccessShareLock); + + return result; + } + + /* * CreateFunction *************** CreateFunction(CreateFunctionStmt *stmt, *** 929,934 **** --- 994,1027 ---- &variadicArgType, &requiredResultType); + /* + * Replacing an existing function is not allowed if there is an index + * that depends on the function. Changing such a function would corrupt + * the index. + */ + if (stmt->replace) + { + HeapTuple tup; + Oid funcoid = InvalidOid; + + /* find the function if it exists */ + tup = SearchSysCache3(PROCNAMEARGSNSP, + PointerGetDatum(funcname), + PointerGetDatum(parameterTypes), + ObjectIdGetDatum(namespaceId)); + + if (HeapTupleIsValid(tup)) + funcoid = HeapTupleGetOid(tup); + + ReleaseSysCache(tup); + + if (funcoid != InvalidOid && has_dependent_index(funcoid)) + ereport(ERROR, + (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), + errmsg("cannot replace a function that is used to define an index"), + errhint("Drop all indexes that depend on the function before modifying it."))); + } + if (stmt->returnType) { /* explicit RETURNS clause */ *************** AlterFunction(AlterFunctionStmt *stmt) *** 1126,1131 **** --- 1219,1234 ---- elog(ERROR, "option \"%s\" not recognized", defel->defname); } + /* + * Forbid changing the strictness of functions used in index definitions. + * That could lead to behaviour changes, thus corrupting the indexes. + */ + if (has_dependent_index(funcOid) && strict_item) + ereport(ERROR, + (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), + errmsg("cannot change strictness of a function that is used to define an index"), + errhint("Drop all indexes that depend on the function before modifying it."))); + if (volatility_item) procForm->provolatile = interpret_func_volatility(volatility_item); if (strict_item)