mirror of
https://github.com/postgres/postgres.git
synced 2025-06-13 07:41:39 +03:00
Invalidate PL/Python functions with composite type argument when the
type changes. The invalidation will cause the type information to be refetched, and everything will work. Jan Urbański, reviewed by Alex Hunsaker
This commit is contained in:
@ -101,6 +101,7 @@ typedef int Py_ssize_t;
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "tcop/tcopprot.h"
|
||||
#include "access/transam.h"
|
||||
#include "access/xact.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/hsearch.h"
|
||||
@ -195,6 +196,10 @@ typedef struct PLyTypeInfo
|
||||
* datatype; 1 = rowtype; 2 = rowtype, but I/O functions not set up yet
|
||||
*/
|
||||
int is_rowtype;
|
||||
/* used to check if the type has been modified */
|
||||
Oid typ_relid;
|
||||
TransactionId typrel_xmin;
|
||||
ItemPointerData typrel_tid;
|
||||
} PLyTypeInfo;
|
||||
|
||||
|
||||
@ -1335,11 +1340,50 @@ PLy_function_delete_args(PLyProcedure *proc)
|
||||
static bool
|
||||
PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup)
|
||||
{
|
||||
int i;
|
||||
bool valid;
|
||||
|
||||
Assert(proc != NULL);
|
||||
|
||||
/* If the pg_proc tuple has changed, it's not valid */
|
||||
return (proc->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&
|
||||
ItemPointerEquals(&proc->fn_tid, &procTup->t_self));
|
||||
if (!(proc->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&
|
||||
ItemPointerEquals(&proc->fn_tid, &procTup->t_self)))
|
||||
return false;
|
||||
|
||||
valid = true;
|
||||
/* If there are composite input arguments, they might have changed */
|
||||
for (i = 0; i < proc->nargs; i++)
|
||||
{
|
||||
Oid relid;
|
||||
HeapTuple relTup;
|
||||
|
||||
/* Short-circuit on first changed argument */
|
||||
if (!valid)
|
||||
break;
|
||||
|
||||
/* Only check input arguments that are composite */
|
||||
if (proc->args[i].is_rowtype != 1)
|
||||
continue;
|
||||
|
||||
Assert(OidIsValid(proc->args[i].typ_relid));
|
||||
Assert(TransactionIdIsValid(proc->args[i].typrel_xmin));
|
||||
Assert(ItemPointerIsValid(&proc->args[i].typrel_tid));
|
||||
|
||||
/* Get the pg_class tuple for the argument type */
|
||||
relid = proc->args[i].typ_relid;
|
||||
relTup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
|
||||
if (!HeapTupleIsValid(relTup))
|
||||
elog(ERROR, "cache lookup failed for relation %u", relid);
|
||||
|
||||
/* If it has changed, the function is not valid */
|
||||
if (!(proc->args[i].typrel_xmin == HeapTupleHeaderGetXmin(relTup->t_data) &&
|
||||
ItemPointerEquals(&proc->args[i].typrel_tid, &relTup->t_self)))
|
||||
valid = false;
|
||||
|
||||
ReleaseSysCache(relTup);
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
||||
@ -1747,6 +1791,33 @@ PLy_input_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
|
||||
arg->in.r.atts = PLy_malloc0(desc->natts * sizeof(PLyDatumToOb));
|
||||
}
|
||||
|
||||
/* Can this be an unnamed tuple? If not, then an Assert would be enough */
|
||||
if (desc->tdtypmod != -1)
|
||||
elog(ERROR, "received unnamed record type as input");
|
||||
|
||||
Assert(OidIsValid(desc->tdtypeid));
|
||||
|
||||
/*
|
||||
* RECORDOID means we got called to create input functions for a tuple
|
||||
* fetched by plpy.execute or for an anonymous record type
|
||||
*/
|
||||
if (desc->tdtypeid != RECORDOID && !TransactionIdIsValid(arg->typrel_xmin))
|
||||
{
|
||||
HeapTuple relTup;
|
||||
|
||||
/* Get the pg_class tuple corresponding to the type of the input */
|
||||
arg->typ_relid = typeidTypeRelid(desc->tdtypeid);
|
||||
relTup = SearchSysCache1(RELOID, ObjectIdGetDatum(arg->typ_relid));
|
||||
if (!HeapTupleIsValid(relTup))
|
||||
elog(ERROR, "cache lookup failed for relation %u", arg->typ_relid);
|
||||
|
||||
/* Extract the XMIN value to later use it in PLy_procedure_valid */
|
||||
arg->typrel_xmin = HeapTupleHeaderGetXmin(relTup->t_data);
|
||||
arg->typrel_tid = relTup->t_self;
|
||||
|
||||
ReleaseSysCache(relTup);
|
||||
}
|
||||
|
||||
for (i = 0; i < desc->natts; i++)
|
||||
{
|
||||
HeapTuple typeTup;
|
||||
@ -1951,6 +2022,9 @@ PLy_typeinfo_init(PLyTypeInfo *arg)
|
||||
arg->in.r.natts = arg->out.r.natts = 0;
|
||||
arg->in.r.atts = NULL;
|
||||
arg->out.r.atts = NULL;
|
||||
arg->typ_relid = InvalidOid;
|
||||
arg->typrel_xmin = InvalidTransactionId;
|
||||
ItemPointerSetInvalid(&arg->typrel_tid);
|
||||
}
|
||||
|
||||
static void
|
||||
|
Reference in New Issue
Block a user