X-Original-To: pgsql-sql-postgresql.org@localhost.postgresql.org Received: from localhost (unknown [64.117.224.130]) by svr1.postgresql.org (Postfix) with ESMTP id 6827ED1B4EB for ; Sun, 14 Sep 2003 17:31:17 +0000 (GMT) Received: from svr1.postgresql.org ([64.117.224.193]) by localhost (neptune.hub.org [64.117.224.130]) (amavisd-new, port 10024) with ESMTP id 76539-02 for ; Sun, 14 Sep 2003 14:31:07 -0300 (ADT) Received: from sss.pgh.pa.us (unknown [192.204.191.242]) by svr1.postgresql.org (Postfix) with ESMTP id 36058D1B509 for ; Sun, 14 Sep 2003 14:31:06 -0300 (ADT) Received: from sss2.sss.pgh.pa.us (tgl@localhost [127.0.0.1]) by sss.pgh.pa.us (8.12.9/8.12.9) with ESMTP id h8EHUxUe018570; Sun, 14 Sep 2003 13:31:00 -0400 (EDT) To: Peter Childs Cc: ow , pgsql-sql@postgresql.org, Lance Thomas Subject: Re: A generic trigger? In-reply-to: <200309140926.50281.Blue.Dragon@blueyonder.co.uk> References: <20030914011347.60690.qmail@web21401.mail.yahoo.com> <200309140926.50281.Blue.Dragon@blueyonder.co.uk> Comments: In-reply-to Peter Childs message dated "Sun, 14 Sep 2003 09:26:50 +0100" Date: Sun, 14 Sep 2003 13:30:59 -0400 Message-ID: <18569.1063560659@sss.pgh.pa.us> From: Tom Lane X-Virus-Scanned: by amavisd-new at postgresql.org X-Archive-Number: 200309/123 X-Sequence-Number: 15101 Peter Childs writes: > Yes it is possible and I've done it. The reason I'm not using it is because I > wrote it in Pl/Python and if you attach the same trigger to more than one > table in the same transaction pg/python (actually the entire server crashes > but thats not the point) crashes. Well it did when I last tested it in early > versions. I've been expecting someone to submit a fix for this, but nobody did :-(. So I went ahead and repaired it in CVS tip. The patch is attached if you want to try patching your local copy (it looks like it will apply to 7.3 branch with some fuzz, but I have not actually tested it there). regards, tom lane *** src/pl/plpython/plpython.c.orig Mon Aug 4 14:40:50 2003 --- src/pl/plpython/plpython.c Sun Sep 14 13:07:02 2003 *************** *** 224,236 **** static PyObject *PLy_procedure_call(PLyProcedure *, char *, PyObject *); ! /* returns a cached PLyProcedure, or creates, stores and returns ! * a new PLyProcedure. ! */ ! static PLyProcedure *PLy_procedure_get(FunctionCallInfo fcinfo, bool); static PLyProcedure *PLy_procedure_create(FunctionCallInfo fcinfo, ! bool is_trigger, HeapTuple procTup, char *key); static void PLy_procedure_compile(PLyProcedure *, const char *); --- 224,234 ---- static PyObject *PLy_procedure_call(PLyProcedure *, char *, PyObject *); ! static PLyProcedure *PLy_procedure_get(FunctionCallInfo fcinfo, ! Oid tgreloid); static PLyProcedure *PLy_procedure_create(FunctionCallInfo fcinfo, ! Oid tgreloid, HeapTuple procTup, char *key); static void PLy_procedure_compile(PLyProcedure *, const char *); *************** *** 326,332 **** { DECLARE_EXC(); Datum retval; - volatile bool is_trigger; PLyProcedure *volatile proc = NULL; enter(); --- 324,329 ---- *************** *** 337,343 **** elog(ERROR, "could not connect to SPI manager"); CALL_LEVEL_INC(); - is_trigger = CALLED_AS_TRIGGER(fcinfo); SAVE_EXC(); if (TRAP_EXC()) --- 334,339 ---- *************** *** 364,379 **** * PLy_restart_in_progress); */ ! proc = PLy_procedure_get(fcinfo, is_trigger); ! ! if (is_trigger) { ! HeapTuple trv = PLy_trigger_handler(fcinfo, proc); retval = PointerGetDatum(trv); } else retval = PLy_function_handler(fcinfo, proc); CALL_LEVEL_DEC(); RESTORE_EXC(); --- 360,380 ---- * PLy_restart_in_progress); */ ! if (CALLED_AS_TRIGGER(fcinfo)) { ! TriggerData *tdata = (TriggerData *) fcinfo->context; ! HeapTuple trv; + proc = PLy_procedure_get(fcinfo, + RelationGetRelid(tdata->tg_relation)); + trv = PLy_trigger_handler(fcinfo, proc); retval = PointerGetDatum(trv); } else + { + proc = PLy_procedure_get(fcinfo, InvalidOid); retval = PLy_function_handler(fcinfo, proc); + } CALL_LEVEL_DEC(); RESTORE_EXC(); *************** *** 962,971 **** } ! /* PLyProcedure functions */ static PLyProcedure * ! PLy_procedure_get(FunctionCallInfo fcinfo, bool is_trigger) { Oid fn_oid; HeapTuple procTup; --- 963,979 ---- } ! /* ! * PLyProcedure functions ! */ ! ! /* PLy_procedure_get: returns a cached PLyProcedure, or creates, stores and ! * returns a new PLyProcedure. fcinfo is the call info, tgreloid is the ! * relation OID when calling a trigger, or InvalidOid (zero) for ordinary ! * function calls. */ static PLyProcedure * ! PLy_procedure_get(FunctionCallInfo fcinfo, Oid tgreloid) { Oid fn_oid; HeapTuple procTup; *************** *** 983,991 **** if (!HeapTupleIsValid(procTup)) elog(ERROR, "cache lookup failed for function %u", fn_oid); ! rv = snprintf(key, sizeof(key), "%u%s", ! fn_oid, ! is_trigger ? "_trigger" : ""); if ((rv >= sizeof(key)) || (rv < 0)) elog(ERROR, "key too long"); --- 991,997 ---- if (!HeapTupleIsValid(procTup)) elog(ERROR, "cache lookup failed for function %u", fn_oid); ! rv = snprintf(key, sizeof(key), "%u_%u", fn_oid, tgreloid); if ((rv >= sizeof(key)) || (rv < 0)) elog(ERROR, "key too long"); *************** *** 1012,1018 **** } if (proc == NULL) ! proc = PLy_procedure_create(fcinfo, is_trigger, procTup, key); ReleaseSysCache(procTup); --- 1018,1024 ---- } if (proc == NULL) ! proc = PLy_procedure_create(fcinfo, tgreloid, procTup, key); ReleaseSysCache(procTup); *************** *** 1020,1026 **** } static PLyProcedure * ! PLy_procedure_create(FunctionCallInfo fcinfo, bool is_trigger, HeapTuple procTup, char *key) { char procName[NAMEDATALEN + 256]; --- 1026,1032 ---- } static PLyProcedure * ! PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid, HeapTuple procTup, char *key) { char procName[NAMEDATALEN + 256]; *************** *** 1037,1047 **** procStruct = (Form_pg_proc) GETSTRUCT(procTup); ! rv = snprintf(procName, sizeof(procName), ! "__plpython_procedure_%s_%u%s", ! NameStr(procStruct->proname), ! fcinfo->flinfo->fn_oid, ! is_trigger ? "_trigger" : ""); if ((rv >= sizeof(procName)) || (rv < 0)) elog(ERROR, "procedure name would overrun buffer"); --- 1043,1059 ---- procStruct = (Form_pg_proc) GETSTRUCT(procTup); ! if (OidIsValid(tgreloid)) ! rv = snprintf(procName, sizeof(procName), ! "__plpython_procedure_%s_%u_trigger_%u", ! NameStr(procStruct->proname), ! fcinfo->flinfo->fn_oid, ! tgreloid); ! else ! rv = snprintf(procName, sizeof(procName), ! "__plpython_procedure_%s_%u", ! NameStr(procStruct->proname), ! fcinfo->flinfo->fn_oid); if ((rv >= sizeof(procName)) || (rv < 0)) elog(ERROR, "procedure name would overrun buffer"); *************** *** 1073,1079 **** * get information required for output conversion of the return value, * but only if this isn't a trigger. */ ! if (!is_trigger) { HeapTuple rvTypeTup; Form_pg_type rvTypeStruct; --- 1085,1091 ---- * get information required for output conversion of the return value, * but only if this isn't a trigger. */ ! if (!CALLED_AS_TRIGGER(fcinfo)) { HeapTuple rvTypeTup; Form_pg_type rvTypeStruct;