|
|
|
@ -1386,57 +1386,15 @@ PLy_procedure_get(Oid fn_oid, bool is_trigger) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Create a new PLyProcedure structure |
|
|
|
|
* Set up output conversion functions for a procedure |
|
|
|
|
*/ |
|
|
|
|
static PLyProcedure * |
|
|
|
|
PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) |
|
|
|
|
static void |
|
|
|
|
PLy_procedure_output_conversion(PLyProcedure *proc, Form_pg_proc procStruct) |
|
|
|
|
{ |
|
|
|
|
char procName[NAMEDATALEN + 256]; |
|
|
|
|
Form_pg_proc procStruct; |
|
|
|
|
PLyProcedure *volatile proc; |
|
|
|
|
char *volatile procSource = NULL; |
|
|
|
|
Datum prosrcdatum; |
|
|
|
|
bool isnull; |
|
|
|
|
int i, |
|
|
|
|
rv; |
|
|
|
|
|
|
|
|
|
procStruct = (Form_pg_proc) GETSTRUCT(procTup); |
|
|
|
|
rv = snprintf(procName, sizeof(procName), |
|
|
|
|
"__plpython_procedure_%s_%u", |
|
|
|
|
NameStr(procStruct->proname), |
|
|
|
|
fn_oid); |
|
|
|
|
if (rv >= sizeof(procName) || rv < 0) |
|
|
|
|
elog(ERROR, "procedure name would overrun buffer"); |
|
|
|
|
|
|
|
|
|
proc = PLy_malloc(sizeof(PLyProcedure)); |
|
|
|
|
proc->proname = PLy_strdup(NameStr(procStruct->proname)); |
|
|
|
|
proc->pyname = PLy_strdup(procName); |
|
|
|
|
proc->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data); |
|
|
|
|
proc->fn_tid = procTup->t_self; |
|
|
|
|
/* Remember if function is STABLE/IMMUTABLE */ |
|
|
|
|
proc->fn_readonly = |
|
|
|
|
(procStruct->provolatile != PROVOLATILE_VOLATILE); |
|
|
|
|
PLy_typeinfo_init(&proc->result); |
|
|
|
|
for (i = 0; i < FUNC_MAX_ARGS; i++) |
|
|
|
|
PLy_typeinfo_init(&proc->args[i]); |
|
|
|
|
proc->nargs = 0; |
|
|
|
|
proc->code = proc->statics = NULL; |
|
|
|
|
proc->globals = NULL; |
|
|
|
|
proc->is_setof = procStruct->proretset; |
|
|
|
|
proc->setof = NULL; |
|
|
|
|
proc->argnames = NULL; |
|
|
|
|
|
|
|
|
|
PG_TRY(); |
|
|
|
|
{ |
|
|
|
|
/*
|
|
|
|
|
* 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; |
|
|
|
|
|
|
|
|
|
/* Get the return type */ |
|
|
|
|
rvTypeTup = SearchSysCache1(TYPEOID, |
|
|
|
|
ObjectIdGetDatum(procStruct->prorettype)); |
|
|
|
|
if (!HeapTupleIsValid(rvTypeTup)) |
|
|
|
@ -1469,20 +1427,21 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) |
|
|
|
|
proc->result.is_rowtype = 2; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
/* Do the real work */ |
|
|
|
|
PLy_output_datum_func(&proc->result, rvTypeTup); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ReleaseSysCache(rvTypeTup); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now get information required for input conversion of the |
|
|
|
|
* procedure's arguments. Note that we ignore output arguments here |
|
|
|
|
* --- since we don't support returning record, and that was already |
|
|
|
|
* checked above, there's no need to worry about multiple output |
|
|
|
|
* arguments. |
|
|
|
|
/*
|
|
|
|
|
* Set up output conversion functions for a procedure |
|
|
|
|
*/ |
|
|
|
|
if (procStruct->pronargs) |
|
|
|
|
{ |
|
|
|
|
static void |
|
|
|
|
PLy_procedure_input_conversion(PLyProcedure *proc, HeapTuple procTup, |
|
|
|
|
Form_pg_proc procStruct) |
|
|
|
|
{ |
|
|
|
|
Oid *types; |
|
|
|
|
char **names, |
|
|
|
|
*modes; |
|
|
|
@ -1490,10 +1449,10 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) |
|
|
|
|
pos, |
|
|
|
|
total; |
|
|
|
|
|
|
|
|
|
/* extract argument type info from the pg_proc tuple */ |
|
|
|
|
/* Extract argument type info from the pg_proc tuple */ |
|
|
|
|
total = get_func_arg_info(procTup, &types, &names, &modes); |
|
|
|
|
|
|
|
|
|
/* count number of in+inout args into proc->nargs */ |
|
|
|
|
/* Count number of in+inout args into proc->nargs */ |
|
|
|
|
if (modes == NULL) |
|
|
|
|
proc->nargs = total; |
|
|
|
|
else |
|
|
|
@ -1526,7 +1485,7 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) |
|
|
|
|
elog(ERROR, "cache lookup failed for type %u", types[i]); |
|
|
|
|
argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup); |
|
|
|
|
|
|
|
|
|
/* check argument type is OK, set up I/O function info */ |
|
|
|
|
/* Check argument type is OK, set up I/O function info */ |
|
|
|
|
switch (argTypeStruct->typtype) |
|
|
|
|
{ |
|
|
|
|
case TYPTYPE_PSEUDO: |
|
|
|
@ -1537,7 +1496,7 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) |
|
|
|
|
format_type_be(types[i])))); |
|
|
|
|
break; |
|
|
|
|
case TYPTYPE_COMPOSITE: |
|
|
|
|
/* we'll set IO funcs at first call */ |
|
|
|
|
/* We'll set IO funcs at first call */ |
|
|
|
|
proc->args[pos].is_rowtype = 2; |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
@ -1547,14 +1506,74 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* get argument name */ |
|
|
|
|
/* Get argument name */ |
|
|
|
|
proc->argnames[pos] = names ? PLy_strdup(names[i]) : NULL; |
|
|
|
|
|
|
|
|
|
ReleaseSysCache(argTypeTup); |
|
|
|
|
|
|
|
|
|
pos++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Create a new PLyProcedure structure |
|
|
|
|
*/ |
|
|
|
|
static PLyProcedure * |
|
|
|
|
PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) |
|
|
|
|
{ |
|
|
|
|
char procName[NAMEDATALEN + 256]; |
|
|
|
|
Form_pg_proc procStruct; |
|
|
|
|
PLyProcedure *volatile proc; |
|
|
|
|
char *volatile procSource = NULL; |
|
|
|
|
Datum prosrcdatum; |
|
|
|
|
bool isnull; |
|
|
|
|
int i, |
|
|
|
|
rv; |
|
|
|
|
|
|
|
|
|
procStruct = (Form_pg_proc) GETSTRUCT(procTup); |
|
|
|
|
rv = snprintf(procName, sizeof(procName), |
|
|
|
|
"__plpython_procedure_%s_%u", |
|
|
|
|
NameStr(procStruct->proname), |
|
|
|
|
fn_oid); |
|
|
|
|
if (rv >= sizeof(procName) || rv < 0) |
|
|
|
|
elog(ERROR, "procedure name would overrun buffer"); |
|
|
|
|
|
|
|
|
|
proc = PLy_malloc(sizeof(PLyProcedure)); |
|
|
|
|
proc->proname = PLy_strdup(NameStr(procStruct->proname)); |
|
|
|
|
proc->pyname = PLy_strdup(procName); |
|
|
|
|
proc->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data); |
|
|
|
|
proc->fn_tid = procTup->t_self; |
|
|
|
|
/* Remember if function is STABLE/IMMUTABLE */ |
|
|
|
|
proc->fn_readonly = |
|
|
|
|
(procStruct->provolatile != PROVOLATILE_VOLATILE); |
|
|
|
|
PLy_typeinfo_init(&proc->result); |
|
|
|
|
for (i = 0; i < FUNC_MAX_ARGS; i++) |
|
|
|
|
PLy_typeinfo_init(&proc->args[i]); |
|
|
|
|
proc->nargs = 0; |
|
|
|
|
proc->code = proc->statics = NULL; |
|
|
|
|
proc->globals = NULL; |
|
|
|
|
proc->is_setof = procStruct->proretset; |
|
|
|
|
proc->setof = NULL; |
|
|
|
|
proc->argnames = NULL; |
|
|
|
|
|
|
|
|
|
PG_TRY(); |
|
|
|
|
{ |
|
|
|
|
/*
|
|
|
|
|
* get information required for output conversion of the return value, |
|
|
|
|
* but only if this isn't a trigger. |
|
|
|
|
*/ |
|
|
|
|
if (!is_trigger) |
|
|
|
|
PLy_procedure_output_conversion(proc, procStruct); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now get information required for input conversion of the |
|
|
|
|
* procedure's arguments. Note that we ignore output arguments here |
|
|
|
|
* --- since we don't support returning record, and that was already |
|
|
|
|
* checked above, there's no need to worry about multiple output |
|
|
|
|
* arguments. |
|
|
|
|
*/ |
|
|
|
|
if (procStruct->pronargs) |
|
|
|
|
PLy_procedure_input_conversion(proc, procTup, procStruct); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* get the text of the function. |
|
|
|
|