mirror of
https://github.com/postgres/postgres.git
synced 2025-08-11 04:22:52 +03:00
Back-patch fix for proper labeling of whole-row Datums generated from
subquery results.
This commit is contained in:
@@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.95 2004/12/31 21:59:07 pgsql Exp $
|
* $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.95.4.1 2005/10/19 22:51:26 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The old interface functions have been converted to macros
|
* The old interface functions have been converted to macros
|
||||||
@@ -466,33 +466,6 @@ heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
|
|||||||
case TableOidAttributeNumber:
|
case TableOidAttributeNumber:
|
||||||
result = ObjectIdGetDatum(tup->t_tableOid);
|
result = ObjectIdGetDatum(tup->t_tableOid);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
|
||||||
* If the attribute number is 0, then we are supposed to
|
|
||||||
* return the entire tuple as a row-type Datum. (Using zero
|
|
||||||
* for this purpose is unclean since it risks confusion with
|
|
||||||
* "invalid attr" result codes, but it's not worth changing
|
|
||||||
* now.)
|
|
||||||
*
|
|
||||||
* We have to make a copy of the tuple so we can safely insert
|
|
||||||
* the Datum overhead fields, which are not set in on-disk
|
|
||||||
* tuples.
|
|
||||||
*/
|
|
||||||
case InvalidAttrNumber:
|
|
||||||
{
|
|
||||||
HeapTupleHeader dtup;
|
|
||||||
|
|
||||||
dtup = (HeapTupleHeader) palloc(tup->t_len);
|
|
||||||
memcpy((char *) dtup, (char *) tup->t_data, tup->t_len);
|
|
||||||
|
|
||||||
HeapTupleHeaderSetDatumLength(dtup, tup->t_len);
|
|
||||||
HeapTupleHeaderSetTypeId(dtup, tupleDesc->tdtypeid);
|
|
||||||
HeapTupleHeaderSetTypMod(dtup, tupleDesc->tdtypmod);
|
|
||||||
|
|
||||||
result = PointerGetDatum(dtup);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "invalid attnum: %d", attnum);
|
elog(ERROR, "invalid attnum: %d", attnum);
|
||||||
result = 0; /* keep compiler quiet */
|
result = 0; /* keep compiler quiet */
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.171 2004/12/31 21:59:45 pgsql Exp $
|
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.171.4.1 2005/10/19 22:51:26 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -63,6 +63,8 @@ static Datum ExecEvalAggref(AggrefExprState *aggref,
|
|||||||
bool *isNull, ExprDoneCond *isDone);
|
bool *isNull, ExprDoneCond *isDone);
|
||||||
static Datum ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
|
static Datum ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
|
||||||
bool *isNull, ExprDoneCond *isDone);
|
bool *isNull, ExprDoneCond *isDone);
|
||||||
|
static Datum ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext,
|
||||||
|
bool *isNull, ExprDoneCond *isDone);
|
||||||
static Datum ExecEvalConst(ExprState *exprstate, ExprContext *econtext,
|
static Datum ExecEvalConst(ExprState *exprstate, ExprContext *econtext,
|
||||||
bool *isNull, ExprDoneCond *isDone);
|
bool *isNull, ExprDoneCond *isDone);
|
||||||
static Datum ExecEvalParam(ExprState *exprstate, ExprContext *econtext,
|
static Datum ExecEvalParam(ExprState *exprstate, ExprContext *econtext,
|
||||||
@@ -527,6 +529,77 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------
|
||||||
|
* ExecEvalWholeRowVar
|
||||||
|
*
|
||||||
|
* Returns a Datum for a whole-row variable.
|
||||||
|
*
|
||||||
|
* This could be folded into ExecEvalVar, but we make it a separate
|
||||||
|
* routine so as not to slow down ExecEvalVar with tests for this
|
||||||
|
* uncommon case.
|
||||||
|
* ----------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
static Datum
|
||||||
|
ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext,
|
||||||
|
bool *isNull, ExprDoneCond *isDone)
|
||||||
|
{
|
||||||
|
Var *variable = (Var *) exprstate->expr;
|
||||||
|
TupleTableSlot *slot;
|
||||||
|
HeapTuple tuple;
|
||||||
|
TupleDesc tupleDesc;
|
||||||
|
HeapTupleHeader dtuple;
|
||||||
|
|
||||||
|
if (isDone)
|
||||||
|
*isDone = ExprSingleResult;
|
||||||
|
*isNull = false;
|
||||||
|
|
||||||
|
Assert(variable->varattno == InvalidAttrNumber);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Whole-row Vars can only appear at the level of a relation scan,
|
||||||
|
* never in a join.
|
||||||
|
*/
|
||||||
|
Assert(variable->varno != INNER);
|
||||||
|
Assert(variable->varno != OUTER);
|
||||||
|
slot = econtext->ecxt_scantuple;
|
||||||
|
|
||||||
|
tuple = slot->val;
|
||||||
|
tupleDesc = slot->ttc_tupleDescriptor;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We have to make a copy of the tuple so we can safely insert the
|
||||||
|
* Datum overhead fields, which are not set in on-disk tuples.
|
||||||
|
*/
|
||||||
|
dtuple = (HeapTupleHeader) palloc(tuple->t_len);
|
||||||
|
memcpy((char *) dtuple, (char *) tuple->t_data, tuple->t_len);
|
||||||
|
|
||||||
|
HeapTupleHeaderSetDatumLength(dtuple, tuple->t_len);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the Var identifies a named composite type, label the tuple
|
||||||
|
* with that type; otherwise use what is in the tupleDesc.
|
||||||
|
*
|
||||||
|
* It's likely that the slot's tupleDesc is a record type; if so,
|
||||||
|
* make sure it's been "blessed", so that the Datum can be interpreted
|
||||||
|
* later.
|
||||||
|
*/
|
||||||
|
if (variable->vartype != RECORDOID)
|
||||||
|
{
|
||||||
|
HeapTupleHeaderSetTypeId(dtuple, variable->vartype);
|
||||||
|
HeapTupleHeaderSetTypMod(dtuple, variable->vartypmod);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (tupleDesc->tdtypeid == RECORDOID &&
|
||||||
|
tupleDesc->tdtypmod < 0)
|
||||||
|
assign_record_type_typmod(tupleDesc);
|
||||||
|
HeapTupleHeaderSetTypeId(dtuple, tupleDesc->tdtypeid);
|
||||||
|
HeapTupleHeaderSetTypMod(dtuple, tupleDesc->tdtypmod);
|
||||||
|
}
|
||||||
|
|
||||||
|
return PointerGetDatum(dtuple);
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* ExecEvalConst
|
* ExecEvalConst
|
||||||
*
|
*
|
||||||
@@ -2830,8 +2903,15 @@ ExecInitExpr(Expr *node, PlanState *parent)
|
|||||||
switch (nodeTag(node))
|
switch (nodeTag(node))
|
||||||
{
|
{
|
||||||
case T_Var:
|
case T_Var:
|
||||||
|
{
|
||||||
|
Var *var = (Var *) node;
|
||||||
|
|
||||||
state = (ExprState *) makeNode(ExprState);
|
state = (ExprState *) makeNode(ExprState);
|
||||||
|
if (var->varattno != InvalidAttrNumber)
|
||||||
state->evalfunc = ExecEvalVar;
|
state->evalfunc = ExecEvalVar;
|
||||||
|
else
|
||||||
|
state->evalfunc = ExecEvalWholeRowVar;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case T_Const:
|
case T_Const:
|
||||||
state = (ExprState *) makeNode(ExprState);
|
state = (ExprState *) makeNode(ExprState);
|
||||||
@@ -3170,7 +3250,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
|
|||||||
{
|
{
|
||||||
/* generic record, use runtime type assignment */
|
/* generic record, use runtime type assignment */
|
||||||
rstate->tupdesc = ExecTypeFromExprList(rowexpr->args);
|
rstate->tupdesc = ExecTypeFromExprList(rowexpr->args);
|
||||||
rstate->tupdesc = BlessTupleDesc(rstate->tupdesc);
|
BlessTupleDesc(rstate->tupdesc);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user