Skip to content

Commit d9cb487

Browse files
committed
Better solution to the problem of labeling whole-row Datums that are
generated from subquery outputs: use the type info stored in the Var itself. To avoid making ExecEvalVar and slot_getattr more complex and slower, I split out the whole-row case into a separate ExecEval routine.
1 parent 07908c9 commit d9cb487

File tree

2 files changed

+87
-40
lines changed

2 files changed

+87
-40
lines changed

src/backend/access/common/heaptuple.c

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
*
1717
*
1818
* IDENTIFICATION
19-
* $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.101 2005/10/19 18:18:32 tgl Exp $
19+
* $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.102 2005/10/19 22:30:30 tgl Exp $
2020
*
2121
*-------------------------------------------------------------------------
2222
*/
@@ -27,7 +27,6 @@
2727
#include "access/tuptoaster.h"
2828
#include "catalog/pg_type.h"
2929
#include "executor/tuptable.h"
30-
#include "utils/typcache.h"
3130

3231

3332
/* ----------------------------------------------------------------
@@ -595,38 +594,6 @@ heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
595594
case TableOidAttributeNumber:
596595
result = ObjectIdGetDatum(tup->t_tableOid);
597596
break;
598-
599-
/*
600-
* If the attribute number is 0, then we are supposed to return
601-
* the entire tuple as a row-type Datum. (Using zero for this
602-
* purpose is unclean since it risks confusion with "invalid attr"
603-
* result codes, but it's not worth changing now.)
604-
*
605-
* We have to make a copy of the tuple so we can safely insert the
606-
* Datum overhead fields, which are not set in on-disk tuples.
607-
*
608-
* It's possible that the passed tupleDesc is a record type that
609-
* hasn't been "blessed" yet, so cover that case.
610-
*/
611-
case InvalidAttrNumber:
612-
{
613-
HeapTupleHeader dtup;
614-
615-
if (tupleDesc->tdtypeid == RECORDOID &&
616-
tupleDesc->tdtypmod < 0)
617-
assign_record_type_typmod(tupleDesc);
618-
619-
dtup = (HeapTupleHeader) palloc(tup->t_len);
620-
memcpy((char *) dtup, (char *) tup->t_data, tup->t_len);
621-
622-
HeapTupleHeaderSetDatumLength(dtup, tup->t_len);
623-
HeapTupleHeaderSetTypeId(dtup, tupleDesc->tdtypeid);
624-
HeapTupleHeaderSetTypMod(dtup, tupleDesc->tdtypmod);
625-
626-
result = PointerGetDatum(dtup);
627-
}
628-
break;
629-
630597
default:
631598
elog(ERROR, "invalid attnum: %d", attnum);
632599
result = 0; /* keep compiler quiet */

src/backend/executor/execQual.c

Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.182 2005/10/19 18:18:33 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.183 2005/10/19 22:30:30 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -64,6 +64,8 @@ static Datum ExecEvalAggref(AggrefExprState *aggref,
6464
bool *isNull, ExprDoneCond *isDone);
6565
static Datum ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
6666
bool *isNull, ExprDoneCond *isDone);
67+
static Datum ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext,
68+
bool *isNull, ExprDoneCond *isDone);
6769
static Datum ExecEvalConst(ExprState *exprstate, ExprContext *econtext,
6870
bool *isNull, ExprDoneCond *isDone);
6971
static Datum ExecEvalParam(ExprState *exprstate, ExprContext *econtext,
@@ -448,9 +450,9 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
448450
/*
449451
* Get the slot and attribute number we want
450452
*
451-
* The asserts check that references to system attributes only appear at the
452-
* level of a relation scan; at higher levels, system attributes must be
453-
* treated as ordinary variables (since we no longer have access to the
453+
* The asserts check that references to system attributes only appear at
454+
* the level of a relation scan; at higher levels, system attributes must
455+
* be treated as ordinary variables (since we no longer have access to the
454456
* original tuple).
455457
*/
456458
attnum = variable->varattno;
@@ -505,6 +507,77 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
505507
return slot_getattr(slot, attnum, isNull);
506508
}
507509

510+
/* ----------------------------------------------------------------
511+
* ExecEvalWholeRowVar
512+
*
513+
* Returns a Datum for a whole-row variable.
514+
*
515+
* This could be folded into ExecEvalVar, but we make it a separate
516+
* routine so as not to slow down ExecEvalVar with tests for this
517+
* uncommon case.
518+
* ----------------------------------------------------------------
519+
*/
520+
static Datum
521+
ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext,
522+
bool *isNull, ExprDoneCond *isDone)
523+
{
524+
Var *variable = (Var *) exprstate->expr;
525+
TupleTableSlot *slot;
526+
HeapTuple tuple;
527+
TupleDesc tupleDesc;
528+
HeapTupleHeader dtuple;
529+
530+
if (isDone)
531+
*isDone = ExprSingleResult;
532+
*isNull = false;
533+
534+
Assert(variable->varattno == InvalidAttrNumber);
535+
536+
/*
537+
* Whole-row Vars can only appear at the level of a relation scan,
538+
* never in a join.
539+
*/
540+
Assert(variable->varno != INNER);
541+
Assert(variable->varno != OUTER);
542+
slot = econtext->ecxt_scantuple;
543+
544+
tuple = slot->tts_tuple;
545+
tupleDesc = slot->tts_tupleDescriptor;
546+
547+
/*
548+
* We have to make a copy of the tuple so we can safely insert the
549+
* Datum overhead fields, which are not set in on-disk tuples.
550+
*/
551+
dtuple = (HeapTupleHeader) palloc(tuple->t_len);
552+
memcpy((char *) dtuple, (char *) tuple->t_data, tuple->t_len);
553+
554+
HeapTupleHeaderSetDatumLength(dtuple, tuple->t_len);
555+
556+
/*
557+
* If the Var identifies a named composite type, label the tuple
558+
* with that type; otherwise use what is in the tupleDesc.
559+
*
560+
* It's likely that the slot's tupleDesc is a record type; if so,
561+
* make sure it's been "blessed", so that the Datum can be interpreted
562+
* later.
563+
*/
564+
if (variable->vartype != RECORDOID)
565+
{
566+
HeapTupleHeaderSetTypeId(dtuple, variable->vartype);
567+
HeapTupleHeaderSetTypMod(dtuple, variable->vartypmod);
568+
}
569+
else
570+
{
571+
if (tupleDesc->tdtypeid == RECORDOID &&
572+
tupleDesc->tdtypmod < 0)
573+
assign_record_type_typmod(tupleDesc);
574+
HeapTupleHeaderSetTypeId(dtuple, tupleDesc->tdtypeid);
575+
HeapTupleHeaderSetTypMod(dtuple, tupleDesc->tdtypmod);
576+
}
577+
578+
return PointerGetDatum(dtuple);
579+
}
580+
508581
/* ----------------------------------------------------------------
509582
* ExecEvalConst
510583
*
@@ -2841,8 +2914,15 @@ ExecInitExpr(Expr *node, PlanState *parent)
28412914
switch (nodeTag(node))
28422915
{
28432916
case T_Var:
2844-
state = (ExprState *) makeNode(ExprState);
2845-
state->evalfunc = ExecEvalVar;
2917+
{
2918+
Var *var = (Var *) node;
2919+
2920+
state = (ExprState *) makeNode(ExprState);
2921+
if (var->varattno != InvalidAttrNumber)
2922+
state->evalfunc = ExecEvalVar;
2923+
else
2924+
state->evalfunc = ExecEvalWholeRowVar;
2925+
}
28462926
break;
28472927
case T_Const:
28482928
state = (ExprState *) makeNode(ExprState);

0 commit comments

Comments
 (0)