diff options
Diffstat (limited to 'src/backend/executor/execQual.c')
-rw-r--r-- | src/backend/executor/execQual.c | 139 |
1 files changed, 137 insertions, 2 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 086df146420..9aec0965610 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.169 2004/09/22 17:41:50 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.170 2004/12/11 23:26:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -87,6 +87,9 @@ static Datum ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); static Datum ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); +static Datum ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate, + ExprContext *econtext, + bool *isNull, ExprDoneCond *isDone); static Datum ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); static Datum ExecEvalCaseTestExpr(ExprState *exprstate, @@ -428,7 +431,8 @@ ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext, * * Returns a Datum whose value is the value of a range * variable with respect to given expression context. - * ---------------------------------------------------------------- */ + * ---------------------------------------------------------------- + */ static Datum ExecEvalVar(ExprState *exprstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone) @@ -1844,6 +1848,75 @@ ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext, return BoolGetDatum(!AnyNull); } +/* ---------------------------------------------------------------- + * ExecEvalConvertRowtype + * + * Evaluate a rowtype coercion operation. This may require + * rearranging field positions. + * ---------------------------------------------------------------- + */ +static Datum +ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate, + ExprContext *econtext, + bool *isNull, ExprDoneCond *isDone) +{ + HeapTuple result; + Datum tupDatum; + HeapTupleHeader tuple; + HeapTupleData tmptup; + AttrNumber *attrMap = cstate->attrMap; + Datum *invalues = cstate->invalues; + char *innulls = cstate->innulls; + Datum *outvalues = cstate->outvalues; + char *outnulls = cstate->outnulls; + int i; + int outnatts = cstate->outdesc->natts; + + tupDatum = ExecEvalExpr(cstate->arg, econtext, isNull, isDone); + + /* this test covers the isDone exception too: */ + if (*isNull) + return tupDatum; + + tuple = DatumGetHeapTupleHeader(tupDatum); + + Assert(HeapTupleHeaderGetTypeId(tuple) == cstate->indesc->tdtypeid); + Assert(HeapTupleHeaderGetTypMod(tuple) == cstate->indesc->tdtypmod); + + /* + * heap_deformtuple needs a HeapTuple not a bare HeapTupleHeader. + */ + 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_deformtuple(&tmptup, cstate->indesc, invalues + 1, innulls + 1); + invalues[0] = (Datum) 0; + innulls[0] = 'n'; + + /* + * Transpose into proper fields of the new tuple. + */ + for (i = 0; i < outnatts; i++) + { + int j = attrMap[i]; + + outvalues[i] = invalues[j]; + outnulls[i] = innulls[j]; + } + + /* + * Now form the new tuple. + */ + result = heap_formtuple(cstate->outdesc, outvalues, outnulls); + + return HeapTupleGetDatum(result); +} /* ---------------------------------------------------------------- * ExecEvalCase @@ -2969,6 +3042,68 @@ ExecInitExpr(Expr *node, PlanState *parent) state = (ExprState *) gstate; } break; + case T_ConvertRowtypeExpr: + { + ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node; + ConvertRowtypeExprState *cstate = makeNode(ConvertRowtypeExprState); + int i; + int n; + + cstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalConvertRowtype; + cstate->arg = ExecInitExpr(convert->arg, parent); + /* save copies of needed tuple descriptors */ + cstate->indesc = lookup_rowtype_tupdesc(exprType((Node *) convert->arg), -1); + cstate->indesc = CreateTupleDescCopy(cstate->indesc); + cstate->outdesc = lookup_rowtype_tupdesc(convert->resulttype, -1); + cstate->outdesc = CreateTupleDescCopy(cstate->outdesc); + /* 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->innulls = (char *) palloc(n * sizeof(char)); + n = cstate->outdesc->natts; + cstate->outvalues = (Datum *) palloc(n * sizeof(Datum)); + cstate->outnulls = (char *) palloc(n * sizeof(char)); + state = (ExprState *) cstate; + } + break; case T_CaseExpr: { CaseExpr *caseexpr = (CaseExpr *) node; |