diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2009-08-06 20:44:32 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2009-08-06 20:44:32 +0000 |
commit | dcb2bda9b7042dbf43f876c94ebf35d951de10e9 (patch) | |
tree | 0d9ab8f54b720f105c6f3e05530ba69b623d55c2 /src/backend/executor | |
parent | 40001705353845ea157ea081355bd0eeedd2673a (diff) | |
download | postgresql-dcb2bda9b7042dbf43f876c94ebf35d951de10e9.tar.gz postgresql-dcb2bda9b7042dbf43f876c94ebf35d951de10e9.zip |
Improve plpgsql's ability to cope with rowtypes containing dropped columns,
by supporting conversions in places that used to demand exact rowtype match.
Since this issue is certain to come up elsewhere (in fact, already has,
in ExecEvalConvertRowtype), factor out the support code into new core
functions for tuple conversion. I chose to put these in a new source
file since heaptuple.c is already overly long.
Heavily revised version of a patch by Pavel Stehule.
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execQual.c | 109 |
1 files changed, 22 insertions, 87 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index b1bd9e4e7e1..4f94bab1c6d 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.250 2009/06/11 17:25:38 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.251 2009/08/06 20:44:31 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -37,6 +37,7 @@ #include "postgres.h" #include "access/nbtree.h" +#include "access/tupconvert.h" #include "catalog/pg_type.h" #include "commands/typecmds.h" #include "executor/execdebug.h" @@ -2548,13 +2549,6 @@ ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate, Datum tupDatum; HeapTupleHeader tuple; HeapTupleData tmptup; - AttrNumber *attrMap; - Datum *invalues; - bool *inisnull; - Datum *outvalues; - bool *outisnull; - int i; - int outnatts; tupDatum = ExecEvalExpr(cstate->arg, econtext, isNull, isDone); @@ -2566,110 +2560,51 @@ ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate, /* Lookup tupdescs if first time through or after rescan */ if (cstate->indesc == NULL) + { get_cached_rowtype(exprType((Node *) convert->arg), -1, &cstate->indesc, econtext); + cstate->initialized = false; + } if (cstate->outdesc == NULL) + { get_cached_rowtype(convert->resulttype, -1, &cstate->outdesc, econtext); + cstate->initialized = false; + } Assert(HeapTupleHeaderGetTypeId(tuple) == cstate->indesc->tdtypeid); Assert(HeapTupleHeaderGetTypMod(tuple) == cstate->indesc->tdtypmod); - /* if first time through, initialize */ - if (cstate->attrMap == NULL) + /* if first time through, initialize conversion map */ + if (!cstate->initialized) { MemoryContext old_cxt; - int n; - /* allocate state in long-lived memory context */ + /* allocate map in long-lived memory context */ old_cxt = MemoryContextSwitchTo(econtext->ecxt_per_query_memory); /* prepare map from old to new attribute numbers */ - n = cstate->outdesc->natts; - cstate->attrMap = (AttrNumber *) palloc0(n * sizeof(AttrNumber)); - for (i = 0; i < n; i++) - { - Form_pg_attribute att = cstate->outdesc->attrs[i]; - char *attname; - Oid atttypid; - int32 atttypmod; - int j; - - if (att->attisdropped) - continue; /* attrMap[i] is already 0 */ - attname = NameStr(att->attname); - atttypid = att->atttypid; - atttypmod = att->atttypmod; - for (j = 0; j < cstate->indesc->natts; j++) - { - att = cstate->indesc->attrs[j]; - if (att->attisdropped) - continue; - if (strcmp(attname, NameStr(att->attname)) == 0) - { - /* Found it, check type */ - if (atttypid != att->atttypid || atttypmod != att->atttypmod) - elog(ERROR, "attribute \"%s\" of type %s does not match corresponding attribute of type %s", - attname, - format_type_be(cstate->indesc->tdtypeid), - format_type_be(cstate->outdesc->tdtypeid)); - cstate->attrMap[i] = (AttrNumber) (j + 1); - break; - } - } - if (cstate->attrMap[i] == 0) - elog(ERROR, "attribute \"%s\" of type %s does not exist", - attname, - format_type_be(cstate->indesc->tdtypeid)); - } - /* preallocate workspace for Datum arrays */ - n = cstate->indesc->natts + 1; /* +1 for NULL */ - cstate->invalues = (Datum *) palloc(n * sizeof(Datum)); - cstate->inisnull = (bool *) palloc(n * sizeof(bool)); - n = cstate->outdesc->natts; - cstate->outvalues = (Datum *) palloc(n * sizeof(Datum)); - cstate->outisnull = (bool *) palloc(n * sizeof(bool)); + cstate->map = convert_tuples_by_name(cstate->indesc, + cstate->outdesc, + gettext_noop("could not convert row type")); + cstate->initialized = true; MemoryContextSwitchTo(old_cxt); } - attrMap = cstate->attrMap; - invalues = cstate->invalues; - inisnull = cstate->inisnull; - outvalues = cstate->outvalues; - outisnull = cstate->outisnull; - outnatts = cstate->outdesc->natts; - /* - * heap_deform_tuple needs a HeapTuple not a bare HeapTupleHeader. + * No-op if no conversion needed (not clear this can happen here). */ - tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple); - tmptup.t_data = tuple; - - /* - * Extract all the values of the old tuple, offsetting the arrays so that - * invalues[0] is NULL and invalues[1] is the first source attribute; this - * exactly matches the numbering convention in attrMap. - */ - heap_deform_tuple(&tmptup, cstate->indesc, invalues + 1, inisnull + 1); - invalues[0] = (Datum) 0; - inisnull[0] = true; + if (cstate->map == NULL) + return tupDatum; /* - * Transpose into proper fields of the new tuple. + * do_convert_tuple needs a HeapTuple not a bare HeapTupleHeader. */ - for (i = 0; i < outnatts; i++) - { - int j = attrMap[i]; - - outvalues[i] = invalues[j]; - outisnull[i] = inisnull[j]; - } + tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple); + tmptup.t_data = tuple; - /* - * Now form the new tuple. - */ - result = heap_form_tuple(cstate->outdesc, outvalues, outisnull); + result = do_convert_tuple(&tmptup, cstate->map); return HeapTupleGetDatum(result); } |