diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2001-10-19 02:43:46 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2001-10-19 02:43:46 +0000 |
commit | abbc95e5c66e954a7b06cad2d9ac16457c63e7c9 (patch) | |
tree | 72a6afa816b28f38f489dcc636beb365b1b4f941 /src/pl | |
parent | efd72ce37650c59e83bb023a842369d95d4a35e9 (diff) | |
download | postgresql-abbc95e5c66e954a7b06cad2d9ac16457c63e7c9.tar.gz |
Fix pltcl to update cached function def after
CREATE OR REPLACE FUNCTION.
Diffstat (limited to 'src/pl')
-rw-r--r-- | src/pl/tcl/pltcl.c | 700 |
1 files changed, 311 insertions, 389 deletions
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c index af3af23cd0..b929fea623 100644 --- a/src/pl/tcl/pltcl.c +++ b/src/pl/tcl/pltcl.c @@ -31,7 +31,7 @@ * ENHANCEMENTS, OR MODIFICATIONS. * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.44 2001/10/13 04:23:50 momjian Exp $ + * $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.45 2001/10/19 02:43:46 tgl Exp $ * **********************************************************************/ @@ -99,6 +99,8 @@ utf_e2u(unsigned char *src) { typedef struct pltcl_proc_desc { char *proname; + TransactionId fn_xmin; + CommandId fn_cmin; bool lanpltrusted; FmgrInfo result_in_func; Oid result_in_elem; @@ -155,6 +157,8 @@ static Datum pltcl_func_handler(PG_FUNCTION_ARGS); static HeapTuple pltcl_trigger_handler(PG_FUNCTION_ARGS); +static pltcl_proc_desc *compile_pltcl_function(Oid fn_oid, bool is_trigger); + static int pltcl_elog(ClientData cdata, Tcl_Interp *interp, int argc, char *argv[]); static int pltcl_quote(ClientData cdata, Tcl_Interp *interp, @@ -201,11 +205,6 @@ perm_fmgr_info(Oid functionId, FmgrInfo *finfo) static void pltcl_init_all(void) { - Tcl_HashEntry *hashent; - Tcl_HashSearch hashsearch; - pltcl_proc_desc *prodesc; - pltcl_query_desc *querydesc; - /************************************************************ * Do initialization only once ************************************************************/ @@ -450,243 +449,22 @@ pltclu_call_handler(PG_FUNCTION_ARGS) static Datum pltcl_func_handler(PG_FUNCTION_ARGS) { - Tcl_Interp *interp; - int i; - char internal_proname[512]; - Tcl_HashEntry *hashent; - int hashnew; - pltcl_proc_desc *volatile prodesc; + pltcl_proc_desc *prodesc; + Tcl_Interp *volatile interp; Tcl_DString tcl_cmd; Tcl_DString list_tmp; + int i; int tcl_rc; Datum retval; sigjmp_buf save_restart; - /************************************************************ - * Build our internal proc name from the functions Oid - ************************************************************/ - sprintf(internal_proname, "__PLTcl_proc_%u", fcinfo->flinfo->fn_oid); - - /************************************************************ - * Lookup the internal proc name in the hashtable - ************************************************************/ - hashent = Tcl_FindHashEntry(pltcl_proc_hash, internal_proname); - if (hashent == NULL) - { - /************************************************************ - * If we haven't found it in the hashtable, we analyze - * the functions arguments and returntype and store - * the in-/out-functions in the prodesc block and create - * a new hashtable entry for it. - * - * Then we load the procedure into the safe interpreter. - ************************************************************/ - HeapTuple procTup; - HeapTuple langTup; - HeapTuple typeTup; - Form_pg_proc procStruct; - Form_pg_language langStruct; - Form_pg_type typeStruct; - Tcl_DString proc_internal_def; - Tcl_DString proc_internal_body; - char proc_internal_args[4096]; - char *proc_source; - char buf[512]; - - /************************************************************ - * Allocate a new procedure description block - ************************************************************/ - prodesc = (pltcl_proc_desc *) malloc(sizeof(pltcl_proc_desc)); - prodesc->proname = malloc(strlen(internal_proname) + 1); - strcpy(prodesc->proname, internal_proname); - - /************************************************************ - * Lookup the pg_proc tuple by Oid - ************************************************************/ - procTup = SearchSysCache(PROCOID, - ObjectIdGetDatum(fcinfo->flinfo->fn_oid), - 0, 0, 0); - if (!HeapTupleIsValid(procTup)) - { - free(prodesc->proname); - free(prodesc); - elog(ERROR, "pltcl: cache lookup for proc %u failed", - fcinfo->flinfo->fn_oid); - } - procStruct = (Form_pg_proc) GETSTRUCT(procTup); - - /************************************************************ - * Lookup the pg_language tuple by Oid - ************************************************************/ - langTup = SearchSysCache(LANGOID, - ObjectIdGetDatum(procStruct->prolang), - 0, 0, 0); - if (!HeapTupleIsValid(langTup)) - { - free(prodesc->proname); - free(prodesc); - elog(ERROR, "pltcl: cache lookup for language %u failed", - procStruct->prolang); - } - langStruct = (Form_pg_language) GETSTRUCT(langTup); - - prodesc->lanpltrusted = langStruct->lanpltrusted; - if (prodesc->lanpltrusted) - interp = pltcl_safe_interp; - else - interp = pltcl_norm_interp; - ReleaseSysCache(langTup); - - /************************************************************ - * Get the required information for input conversion of the - * return value. - ************************************************************/ - typeTup = SearchSysCache(TYPEOID, - ObjectIdGetDatum(procStruct->prorettype), - 0, 0, 0); - if (!HeapTupleIsValid(typeTup)) - { - free(prodesc->proname); - free(prodesc); - if (!OidIsValid(procStruct->prorettype)) - elog(ERROR, "pltcl functions cannot return type \"opaque\"" - "\n\texcept when used as triggers"); - else - elog(ERROR, "pltcl: cache lookup for return type %u failed", - procStruct->prorettype); - } - typeStruct = (Form_pg_type) GETSTRUCT(typeTup); - - if (typeStruct->typrelid != InvalidOid) - { - free(prodesc->proname); - free(prodesc); - elog(ERROR, "pltcl: return types of tuples not supported yet"); - } - - perm_fmgr_info(typeStruct->typinput, &(prodesc->result_in_func)); - prodesc->result_in_elem = typeStruct->typelem; - - ReleaseSysCache(typeTup); - - /************************************************************ - * Get the required information for output conversion - * of all procedure arguments - ************************************************************/ - prodesc->nargs = procStruct->pronargs; - proc_internal_args[0] = '\0'; - for (i = 0; i < prodesc->nargs; i++) - { - typeTup = SearchSysCache(TYPEOID, - ObjectIdGetDatum(procStruct->proargtypes[i]), - 0, 0, 0); - if (!HeapTupleIsValid(typeTup)) - { - free(prodesc->proname); - free(prodesc); - if (!OidIsValid(procStruct->proargtypes[i])) - elog(ERROR, "pltcl functions cannot take type \"opaque\""); - else - elog(ERROR, "pltcl: cache lookup for argument type %u failed", - procStruct->proargtypes[i]); - } - typeStruct = (Form_pg_type) GETSTRUCT(typeTup); - - if (typeStruct->typrelid != InvalidOid) - { - prodesc->arg_is_rel[i] = 1; - if (i > 0) - strcat(proc_internal_args, " "); - sprintf(buf, "__PLTcl_Tup_%d", i + 1); - strcat(proc_internal_args, buf); - ReleaseSysCache(typeTup); - continue; - } - else - prodesc->arg_is_rel[i] = 0; - - perm_fmgr_info(typeStruct->typoutput, &(prodesc->arg_out_func[i])); - prodesc->arg_out_elem[i] = (Oid) (typeStruct->typelem); - prodesc->arg_out_len[i] = typeStruct->typlen; - - if (i > 0) - strcat(proc_internal_args, " "); - sprintf(buf, "%d", i + 1); - strcat(proc_internal_args, buf); - - ReleaseSysCache(typeTup); - } - - /************************************************************ - * Create the tcl command to define the internal - * procedure - ************************************************************/ - Tcl_DStringInit(&proc_internal_def); - Tcl_DStringInit(&proc_internal_body); - Tcl_DStringAppendElement(&proc_internal_def, "proc"); - Tcl_DStringAppendElement(&proc_internal_def, internal_proname); - Tcl_DStringAppendElement(&proc_internal_def, proc_internal_args); - - /************************************************************ - * prefix procedure body with - * upvar #0 <internal_procname> GD - * and with appropriate upvars for tuple arguments - ************************************************************/ - Tcl_DStringAppend(&proc_internal_body, "upvar #0 ", -1); - Tcl_DStringAppend(&proc_internal_body, internal_proname, -1); - Tcl_DStringAppend(&proc_internal_body, " GD\n", -1); - for (i = 0; i < fcinfo->nargs; i++) - { - if (!prodesc->arg_is_rel[i]) - continue; - sprintf(buf, "array set %d $__PLTcl_Tup_%d\n", i + 1, i + 1); - Tcl_DStringAppend(&proc_internal_body, buf, -1); - } - proc_source = DatumGetCString(DirectFunctionCall1(textout, - PointerGetDatum(&procStruct->prosrc))); - UTF_BEGIN; - Tcl_DStringAppend(&proc_internal_body, UTF_E2U(proc_source), -1); - UTF_END; - pfree(proc_source); - Tcl_DStringAppendElement(&proc_internal_def, - Tcl_DStringValue(&proc_internal_body)); - Tcl_DStringFree(&proc_internal_body); + /* Find or compile the function */ + prodesc = compile_pltcl_function(fcinfo->flinfo->fn_oid, false); - /************************************************************ - * Create the procedure in the interpreter - ************************************************************/ - tcl_rc = Tcl_GlobalEval(interp, - Tcl_DStringValue(&proc_internal_def)); - Tcl_DStringFree(&proc_internal_def); - if (tcl_rc != TCL_OK) - { - free(prodesc->proname); - free(prodesc); - elog(ERROR, "pltcl: cannot create internal procedure %s - %s", - internal_proname, interp->result); - } - - /************************************************************ - * Add the proc description block to the hashtable - ************************************************************/ - hashent = Tcl_CreateHashEntry(pltcl_proc_hash, - prodesc->proname, &hashnew); - Tcl_SetHashValue(hashent, (ClientData) prodesc); - - ReleaseSysCache(procTup); - } + if (prodesc->lanpltrusted) + interp = pltcl_safe_interp; else - { - /************************************************************ - * Found the proc description block in the hashtable - ************************************************************/ - prodesc = (pltcl_proc_desc *) Tcl_GetHashValue(hashent); - - if (prodesc->lanpltrusted) - interp = pltcl_safe_interp; - else - interp = pltcl_norm_interp; - } + interp = pltcl_norm_interp; /************************************************************ * Create the tcl command to call the internal @@ -694,7 +472,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS) ************************************************************/ Tcl_DStringInit(&tcl_cmd); Tcl_DStringInit(&list_tmp); - Tcl_DStringAppendElement(&tcl_cmd, internal_proname); + Tcl_DStringAppendElement(&tcl_cmd, prodesc->proname); /************************************************************ * Catch elog(ERROR) during build of the Tcl command @@ -841,13 +619,10 @@ pltcl_func_handler(PG_FUNCTION_ARGS) static HeapTuple pltcl_trigger_handler(PG_FUNCTION_ARGS) { - Tcl_Interp *interp; + pltcl_proc_desc *prodesc; + Tcl_Interp *volatile interp; TriggerData *trigdata = (TriggerData *) fcinfo->context; - char internal_proname[512]; char *stroid; - Tcl_HashEntry *hashent; - int hashnew; - pltcl_proc_desc *prodesc; TupleDesc tupdesc; volatile HeapTuple rettup; Tcl_DString tcl_cmd; @@ -865,154 +640,13 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS) sigjmp_buf save_restart; - /************************************************************ - * Build our internal proc name from the functions Oid - ************************************************************/ - sprintf(internal_proname, "__PLTcl_proc_%u", fcinfo->flinfo->fn_oid); - - /************************************************************ - * Lookup the internal proc name in the hashtable - ************************************************************/ - hashent = Tcl_FindHashEntry(pltcl_proc_hash, internal_proname); - if (hashent == NULL) - { - /************************************************************ - * If we haven't found it in the hashtable, - * we load the procedure into the safe interpreter. - ************************************************************/ - Tcl_DString proc_internal_def; - Tcl_DString proc_internal_body; - HeapTuple procTup; - HeapTuple langTup; - Form_pg_proc procStruct; - Form_pg_language langStruct; - char *proc_source; - - /************************************************************ - * Allocate a new procedure description block - ************************************************************/ - prodesc = (pltcl_proc_desc *) malloc(sizeof(pltcl_proc_desc)); - memset(prodesc, 0, sizeof(pltcl_proc_desc)); - prodesc->proname = malloc(strlen(internal_proname) + 1); - strcpy(prodesc->proname, internal_proname); - - /************************************************************ - * Lookup the pg_proc tuple by Oid - ************************************************************/ - procTup = SearchSysCache(PROCOID, - ObjectIdGetDatum(fcinfo->flinfo->fn_oid), - 0, 0, 0); - if (!HeapTupleIsValid(procTup)) - { - free(prodesc->proname); - free(prodesc); - elog(ERROR, "pltcl: cache lookup for proc %u failed", - fcinfo->flinfo->fn_oid); - } - procStruct = (Form_pg_proc) GETSTRUCT(procTup); - - /************************************************************ - * Lookup the pg_language tuple by Oid - ************************************************************/ - langTup = SearchSysCache(LANGOID, - ObjectIdGetDatum(procStruct->prolang), - 0, 0, 0); - if (!HeapTupleIsValid(langTup)) - { - free(prodesc->proname); - free(prodesc); - elog(ERROR, "pltcl: cache lookup for language %u failed", - procStruct->prolang); - } - langStruct = (Form_pg_language) GETSTRUCT(langTup); - - prodesc->lanpltrusted = langStruct->lanpltrusted; - if (prodesc->lanpltrusted) - interp = pltcl_safe_interp; - else - interp = pltcl_norm_interp; - ReleaseSysCache(langTup); + /* Find or compile the function */ + prodesc = compile_pltcl_function(fcinfo->flinfo->fn_oid, true); - /************************************************************ - * Create the tcl command to define the internal - * procedure - ************************************************************/ - Tcl_DStringInit(&proc_internal_def); - Tcl_DStringInit(&proc_internal_body); - Tcl_DStringAppendElement(&proc_internal_def, "proc"); - Tcl_DStringAppendElement(&proc_internal_def, internal_proname); - Tcl_DStringAppendElement(&proc_internal_def, - "TG_name TG_relid TG_relatts TG_when TG_level TG_op __PLTcl_Tup_NEW __PLTcl_Tup_OLD args"); - - /************************************************************ - * prefix procedure body with - * upvar #0 <internal_procname> GD - * and with appropriate setting of NEW, OLD, - * and the arguments as numerical variables. - ************************************************************/ - Tcl_DStringAppend(&proc_internal_body, "upvar #0 ", -1); - Tcl_DStringAppend(&proc_internal_body, internal_proname, -1); - Tcl_DStringAppend(&proc_internal_body, " GD\n", -1); - - Tcl_DStringAppend(&proc_internal_body, - "array set NEW $__PLTcl_Tup_NEW\n", -1); - Tcl_DStringAppend(&proc_internal_body, - "array set OLD $__PLTcl_Tup_OLD\n", -1); - - Tcl_DStringAppend(&proc_internal_body, - "set i 0\n" - "set v 0\n" - "foreach v $args {\n" - " incr i\n" - " set $i $v\n" - "}\n" - "unset i v\n\n", -1); - - proc_source = DatumGetCString(DirectFunctionCall1(textout, - PointerGetDatum(&procStruct->prosrc))); - UTF_BEGIN; - Tcl_DStringAppend(&proc_internal_body, UTF_E2U(proc_source), -1); - UTF_END; - pfree(proc_source); - Tcl_DStringAppendElement(&proc_internal_def, - Tcl_DStringValue(&proc_internal_body)); - Tcl_DStringFree(&proc_internal_body); - - /************************************************************ - * Create the procedure in the interpreter - ************************************************************/ - tcl_rc = Tcl_GlobalEval(interp, - Tcl_DStringValue(&proc_internal_def)); - Tcl_DStringFree(&proc_internal_def); - if (tcl_rc != TCL_OK) - { - free(prodesc->proname); - free(prodesc); - elog(ERROR, "pltcl: cannot create internal procedure %s - %s", - internal_proname, interp->result); - } - - /************************************************************ - * Add the proc description block to the hashtable - ************************************************************/ - hashent = Tcl_CreateHashEntry(pltcl_proc_hash, - prodesc->proname, &hashnew); - Tcl_SetHashValue(hashent, (ClientData) prodesc); - - ReleaseSysCache(procTup); - } + if (prodesc->lanpltrusted) + interp = pltcl_safe_interp; else - { - /************************************************************ - * Found the proc description block in the hashtable - ************************************************************/ - prodesc = (pltcl_proc_desc *) Tcl_GetHashValue(hashent); - - if (prodesc->lanpltrusted) - interp = pltcl_safe_interp; - else - interp = pltcl_norm_interp; - } + interp = pltcl_norm_interp; tupdesc = trigdata->tg_relation->rd_att; @@ -1041,7 +675,7 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS) } /* The procedure name */ - Tcl_DStringAppendElement(&tcl_cmd, internal_proname); + Tcl_DStringAppendElement(&tcl_cmd, prodesc->proname); /* The trigger name for argument TG_name */ Tcl_DStringAppendElement(&tcl_cmd, trigdata->tg_trigger->tgname); @@ -1304,6 +938,295 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS) /********************************************************************** + * compile_pltcl_function - compile (or hopefully just look up) function + **********************************************************************/ +static pltcl_proc_desc * +compile_pltcl_function(Oid fn_oid, bool is_trigger) +{ + HeapTuple procTup; + Form_pg_proc procStruct; + char internal_proname[64]; + Tcl_HashEntry *hashent; + pltcl_proc_desc *prodesc = NULL; + Tcl_Interp *interp; + int i; + int hashnew; + int tcl_rc; + + /* We'll need the pg_proc tuple in any case... */ + procTup = SearchSysCache(PROCOID, + ObjectIdGetDatum(fn_oid), + 0, 0, 0); + if (!HeapTupleIsValid(procTup)) + elog(ERROR, "pltcl: cache lookup for proc %u failed", fn_oid); + procStruct = (Form_pg_proc) GETSTRUCT(procTup); + + /************************************************************ + * Build our internal proc name from the functions Oid + ************************************************************/ + if (!is_trigger) + sprintf(internal_proname, "__PLTcl_proc_%u", fn_oid); + else + sprintf(internal_proname, "__PLTcl_proc_%u_trigger", fn_oid); + + /************************************************************ + * Lookup the internal proc name in the hashtable + ************************************************************/ + hashent = Tcl_FindHashEntry(pltcl_proc_hash, internal_proname); + + /************************************************************ + * If it's present, must check whether it's still up to date. + * This is needed because CREATE OR REPLACE FUNCTION can modify the + * function's pg_proc entry without changing its OID. + ************************************************************/ + if (hashent != NULL) + { + bool uptodate; + + prodesc = (pltcl_proc_desc *) Tcl_GetHashValue(hashent); + + uptodate = (prodesc->fn_xmin == procTup->t_data->t_xmin && + prodesc->fn_cmin == procTup->t_data->t_cmin); + + if (!uptodate) + { + Tcl_DeleteHashEntry(hashent); + hashent = NULL; + } + } + + /************************************************************ + * If we haven't found it in the hashtable, we analyze + * the functions arguments and returntype and store + * the in-/out-functions in the prodesc block and create + * a new hashtable entry for it. + * + * Then we load the procedure into the safe interpreter. + ************************************************************/ + if (hashent == NULL) + { + HeapTuple langTup; + HeapTuple typeTup; + Form_pg_language langStruct; + Form_pg_type typeStruct; + Tcl_DString proc_internal_def; + Tcl_DString proc_internal_body; + char proc_internal_args[4096]; + char *proc_source; + char buf[512]; + + /************************************************************ + * Allocate a new procedure description block + ************************************************************/ + prodesc = (pltcl_proc_desc *) malloc(sizeof(pltcl_proc_desc)); + if (prodesc == NULL) + elog(ERROR, "pltcl: out of memory"); + MemSet(prodesc, 0, sizeof(pltcl_proc_desc)); + prodesc->proname = strdup(internal_proname); + prodesc->fn_xmin = procTup->t_data->t_xmin; + prodesc->fn_cmin = procTup->t_data->t_cmin; + + /************************************************************ + * Lookup the pg_language tuple by Oid + ************************************************************/ + langTup = SearchSysCache(LANGOID, + ObjectIdGetDatum(procStruct->prolang), + 0, 0, 0); + if (!HeapTupleIsValid(langTup)) + { + free(prodesc->proname); + free(prodesc); + elog(ERROR, "pltcl: cache lookup for language %u failed", + procStruct->prolang); + } + langStruct = (Form_pg_language) GETSTRUCT(langTup); + prodesc->lanpltrusted = langStruct->lanpltrusted; + ReleaseSysCache(langTup); + + if (prodesc->lanpltrusted) + interp = pltcl_safe_interp; + else + interp = pltcl_norm_interp; + + /************************************************************ + * Get the required information for input conversion of the + * return value. + ************************************************************/ + if (!is_trigger) + { + typeTup = SearchSysCache(TYPEOID, + ObjectIdGetDatum(procStruct->prorettype), + 0, 0, 0); + if (!HeapTupleIsValid(typeTup)) + { + free(prodesc->proname); + free(prodesc); + if (!OidIsValid(procStruct->prorettype)) + elog(ERROR, "pltcl functions cannot return type \"opaque\"" + "\n\texcept when used as triggers"); + else + elog(ERROR, "pltcl: cache lookup for return type %u failed", + procStruct->prorettype); + } + typeStruct = (Form_pg_type) GETSTRUCT(typeTup); + + if (typeStruct->typrelid != InvalidOid) + { + free(prodesc->proname); + free(prodesc); + elog(ERROR, "pltcl: return types of tuples not supported yet"); + } + + perm_fmgr_info(typeStruct->typinput, &(prodesc->result_in_func)); + prodesc->result_in_elem = typeStruct->typelem; + + ReleaseSysCache(typeTup); + } + + /************************************************************ + * Get the required information for output conversion + * of all procedure arguments + ************************************************************/ + if (!is_trigger) + { + prodesc->nargs = procStruct->pronargs; + proc_internal_args[0] = '\0'; + for (i = 0; i < prodesc->nargs; i++) + { + typeTup = SearchSysCache(TYPEOID, + ObjectIdGetDatum(procStruct->proargtypes[i]), + 0, 0, 0); + if (!HeapTupleIsValid(typeTup)) + { + free(prodesc->proname); + free(prodesc); + if (!OidIsValid(procStruct->proargtypes[i])) + elog(ERROR, "pltcl functions cannot take type \"opaque\""); + else + elog(ERROR, "pltcl: cache lookup for argument type %u failed", + procStruct->proargtypes[i]); + } + typeStruct = (Form_pg_type) GETSTRUCT(typeTup); + + if (typeStruct->typrelid != InvalidOid) + { + prodesc->arg_is_rel[i] = 1; + if (i > 0) + strcat(proc_internal_args, " "); + sprintf(buf, "__PLTcl_Tup_%d", i + 1); + strcat(proc_internal_args, buf); + ReleaseSysCache(typeTup); + continue; + } + else + prodesc->arg_is_rel[i] = 0; + + perm_fmgr_info(typeStruct->typoutput, &(prodesc->arg_out_func[i])); + prodesc->arg_out_elem[i] = (Oid) (typeStruct->typelem); + prodesc->arg_out_len[i] = typeStruct->typlen; + + if (i > 0) + strcat(proc_internal_args, " "); + sprintf(buf, "%d", i + 1); + strcat(proc_internal_args, buf); + + ReleaseSysCache(typeTup); + } + } + else + { + /* trigger procedure has fixed args */ + strcpy(proc_internal_args, + "TG_name TG_relid TG_relatts TG_when TG_level TG_op __PLTcl_Tup_NEW __PLTcl_Tup_OLD args"); + } + + /************************************************************ + * Create the tcl command to define the internal + * procedure + ************************************************************/ + Tcl_DStringInit(&proc_internal_def); + Tcl_DStringInit(&proc_internal_body); + Tcl_DStringAppendElement(&proc_internal_def, "proc"); + Tcl_DStringAppendElement(&proc_internal_def, internal_proname); + Tcl_DStringAppendElement(&proc_internal_def, proc_internal_args); + + /************************************************************ + * prefix procedure body with + * upvar #0 <internal_procname> GD + * and with appropriate setting of arguments + ************************************************************/ + Tcl_DStringAppend(&proc_internal_body, "upvar #0 ", -1); + Tcl_DStringAppend(&proc_internal_body, internal_proname, -1); + Tcl_DStringAppend(&proc_internal_body, " GD\n", -1); + if (!is_trigger) + { + for (i = 0; i < prodesc->nargs; i++) + { + if (!prodesc->arg_is_rel[i]) + continue; + sprintf(buf, "array set %d $__PLTcl_Tup_%d\n", i + 1, i + 1); + Tcl_DStringAppend(&proc_internal_body, buf, -1); + } + } + else + { + Tcl_DStringAppend(&proc_internal_body, + "array set NEW $__PLTcl_Tup_NEW\n", -1); + Tcl_DStringAppend(&proc_internal_body, + "array set OLD $__PLTcl_Tup_OLD\n", -1); + + Tcl_DStringAppend(&proc_internal_body, + "set i 0\n" + "set v 0\n" + "foreach v $args {\n" + " incr i\n" + " set $i $v\n" + "}\n" + "unset i v\n\n", -1); + } + + /************************************************************ + * Add user's function definition to proc body + ************************************************************/ + proc_source = DatumGetCString(DirectFunctionCall1(textout, + PointerGetDatum(&procStruct->prosrc))); + UTF_BEGIN; + Tcl_DStringAppend(&proc_internal_body, UTF_E2U(proc_source), -1); + UTF_END; + pfree(proc_source); + Tcl_DStringAppendElement(&proc_internal_def, + Tcl_DStringValue(&proc_internal_body)); + Tcl_DStringFree(&proc_internal_body); + + /************************************************************ + * Create the procedure in the interpreter + ************************************************************/ + tcl_rc = Tcl_GlobalEval(interp, + Tcl_DStringValue(&proc_internal_def)); + Tcl_DStringFree(&proc_internal_def); + if (tcl_rc != TCL_OK) + { + free(prodesc->proname); + free(prodesc); + elog(ERROR, "pltcl: cannot create internal procedure %s - %s", + internal_proname, interp->result); + } + + /************************************************************ + * Add the proc description block to the hashtable + ************************************************************/ + hashent = Tcl_CreateHashEntry(pltcl_proc_hash, + prodesc->proname, &hashnew); + Tcl_SetHashValue(hashent, (ClientData) prodesc); + } + + ReleaseSysCache(procTup); + + return prodesc; +} + + +/********************************************************************** * pltcl_elog() - elog() support for PLTcl **********************************************************************/ static int @@ -1486,7 +1409,6 @@ static int pltcl_returnnull(ClientData cdata, Tcl_Interp *interp, int argc, char *argv[]) { - int argno; FunctionCallInfo fcinfo = pltcl_current_fcinfo; /************************************************************ |