RI triggers would fail for datatypes using old-style equal function,
authorTom Lane <[email protected]>
Thu, 31 May 2001 17:33:03 +0000 (17:33 +0000)
committerTom Lane <[email protected]>
Thu, 31 May 2001 17:33:03 +0000 (17:33 +0000)
because cached fmgr info contained reference to a shorter-lived data
structure.  Also guard against possibility that fmgr_info could fail,
leaving an incomplete entry present in the hash table.

src/backend/utils/adt/ri_triggers.c

index b8e8558ddac3af5567138b3edecf0af798d03d1f..e5e63142d207ab0ec1d2e8c759d196c1c401ace0 100644 (file)
@@ -3243,7 +3243,9 @@ ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue)
        if (!found)
        {
                HeapTuple       opr_tup;
-               Form_pg_operator opr_struct;
+               Oid                     opr_proc;
+               MemoryContext   oldcontext;
+               FmgrInfo        finfo;
 
                opr_tup = SearchSysCache(OPERNAME,
                                                                 PointerGetDatum("="),
@@ -3251,9 +3253,22 @@ ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue)
                                                                 ObjectIdGetDatum(typeid),
                                                                 CharGetDatum('b'));
                if (!HeapTupleIsValid(opr_tup))
-                       elog(ERROR, "ri_AttributesEqual(): cannot find '=' operator "
-                                "for type %u", typeid);
-               opr_struct = (Form_pg_operator) GETSTRUCT(opr_tup);
+                       elog(ERROR,
+                                "ri_AttributesEqual(): cannot find '=' operator for type %u",
+                                typeid);
+               opr_proc = ((Form_pg_operator) GETSTRUCT(opr_tup))->oprcode;
+               ReleaseSysCache(opr_tup);
+
+               /*
+                * Since fmgr_info could fail, call it *before* creating the
+                * hashtable entry --- otherwise we could elog leaving an incomplete
+                * entry in the hashtable.  Also, because this will be a permanent
+                * table entry, we must make sure any subsidiary structures of the
+                * fmgr record are kept in TopMemoryContext.
+                */
+               oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+               fmgr_info(opr_proc, &finfo);
+               MemoryContextSwitchTo(oldcontext);
 
                entry = (RI_OpreqHashEntry *) hash_search(ri_opreq_cache,
                                                                                                  (char *) &typeid,
@@ -3263,8 +3278,7 @@ ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue)
                        elog(FATAL, "can't insert into RI operator cache");
 
                entry->typeid = typeid;
-               fmgr_info(opr_struct->oprcode, &(entry->oprfmgrinfo));
-               ReleaseSysCache(opr_tup);
+               memcpy(&(entry->oprfmgrinfo), &finfo, sizeof(FmgrInfo));
        }
 
        /*