mirror of
https://github.com/postgres/postgres.git
synced 2025-04-25 21:42:33 +03:00
Instead of supposing (wrongly, in the general case) that the rowtype
of an inheritance child table is binary-compatible with the rowtype of its parent, invent an expression node type that does the conversion correctly. Fixes the new bug exhibited by Kris Shannon as well as a lot of old bugs that would only show up when using multiple inheritance or after altering the parent table.
This commit is contained in:
parent
fd536dd257
commit
12b1b5d837
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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);
|
bool *isNull, ExprDoneCond *isDone);
|
||||||
static Datum ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext,
|
static Datum ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext,
|
||||||
bool *isNull, ExprDoneCond *isDone);
|
bool *isNull, ExprDoneCond *isDone);
|
||||||
|
static Datum ExecEvalConvertRowtype(ConvertRowtypeExprState *cstate,
|
||||||
|
ExprContext *econtext,
|
||||||
|
bool *isNull, ExprDoneCond *isDone);
|
||||||
static Datum ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
|
static Datum ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
|
||||||
bool *isNull, ExprDoneCond *isDone);
|
bool *isNull, ExprDoneCond *isDone);
|
||||||
static Datum ExecEvalCaseTestExpr(ExprState *exprstate,
|
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
|
* Returns a Datum whose value is the value of a range
|
||||||
* variable with respect to given expression context.
|
* variable with respect to given expression context.
|
||||||
* ---------------------------------------------------------------- */
|
* ----------------------------------------------------------------
|
||||||
|
*/
|
||||||
static Datum
|
static Datum
|
||||||
ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
|
ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
|
||||||
bool *isNull, ExprDoneCond *isDone)
|
bool *isNull, ExprDoneCond *isDone)
|
||||||
@ -1844,6 +1848,75 @@ ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext,
|
|||||||
return BoolGetDatum(!AnyNull);
|
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
|
* ExecEvalCase
|
||||||
@ -2969,6 +3042,68 @@ ExecInitExpr(Expr *node, PlanState *parent)
|
|||||||
state = (ExprState *) gstate;
|
state = (ExprState *) gstate;
|
||||||
}
|
}
|
||||||
break;
|
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:
|
case T_CaseExpr:
|
||||||
{
|
{
|
||||||
CaseExpr *caseexpr = (CaseExpr *) node;
|
CaseExpr *caseexpr = (CaseExpr *) node;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.293 2004/11/05 19:15:59 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.294 2004/12/11 23:26:33 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -876,6 +876,21 @@ _copyRelabelType(RelabelType *from)
|
|||||||
return newnode;
|
return newnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _copyConvertRowtypeExpr
|
||||||
|
*/
|
||||||
|
static ConvertRowtypeExpr *
|
||||||
|
_copyConvertRowtypeExpr(ConvertRowtypeExpr *from)
|
||||||
|
{
|
||||||
|
ConvertRowtypeExpr *newnode = makeNode(ConvertRowtypeExpr);
|
||||||
|
|
||||||
|
COPY_NODE_FIELD(arg);
|
||||||
|
COPY_SCALAR_FIELD(resulttype);
|
||||||
|
COPY_SCALAR_FIELD(convertformat);
|
||||||
|
|
||||||
|
return newnode;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* _copyCaseExpr
|
* _copyCaseExpr
|
||||||
*/
|
*/
|
||||||
@ -2696,6 +2711,9 @@ copyObject(void *from)
|
|||||||
case T_RelabelType:
|
case T_RelabelType:
|
||||||
retval = _copyRelabelType(from);
|
retval = _copyRelabelType(from);
|
||||||
break;
|
break;
|
||||||
|
case T_ConvertRowtypeExpr:
|
||||||
|
retval = _copyConvertRowtypeExpr(from);
|
||||||
|
break;
|
||||||
case T_CaseExpr:
|
case T_CaseExpr:
|
||||||
retval = _copyCaseExpr(from);
|
retval = _copyCaseExpr(from);
|
||||||
break;
|
break;
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.232 2004/11/05 19:15:59 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.233 2004/12/11 23:26:33 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -380,6 +380,24 @@ _equalRelabelType(RelabelType *a, RelabelType *b)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
_equalConvertRowtypeExpr(ConvertRowtypeExpr *a, ConvertRowtypeExpr *b)
|
||||||
|
{
|
||||||
|
COMPARE_NODE_FIELD(arg);
|
||||||
|
COMPARE_SCALAR_FIELD(resulttype);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Special-case COERCE_DONTCARE, so that planner can build coercion
|
||||||
|
* nodes that are equal() to both explicit and implicit coercions.
|
||||||
|
*/
|
||||||
|
if (a->convertformat != b->convertformat &&
|
||||||
|
a->convertformat != COERCE_DONTCARE &&
|
||||||
|
b->convertformat != COERCE_DONTCARE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
_equalCaseExpr(CaseExpr *a, CaseExpr *b)
|
_equalCaseExpr(CaseExpr *a, CaseExpr *b)
|
||||||
{
|
{
|
||||||
@ -1844,6 +1862,9 @@ equal(void *a, void *b)
|
|||||||
case T_RelabelType:
|
case T_RelabelType:
|
||||||
retval = _equalRelabelType(a, b);
|
retval = _equalRelabelType(a, b);
|
||||||
break;
|
break;
|
||||||
|
case T_ConvertRowtypeExpr:
|
||||||
|
retval = _equalConvertRowtypeExpr(a, b);
|
||||||
|
break;
|
||||||
case T_CaseExpr:
|
case T_CaseExpr:
|
||||||
retval = _equalCaseExpr(a, b);
|
retval = _equalCaseExpr(a, b);
|
||||||
break;
|
break;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.243 2004/08/29 05:06:43 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.244 2004/12/11 23:26:33 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Every node type that can appear in stored rules' parsetrees *must*
|
* Every node type that can appear in stored rules' parsetrees *must*
|
||||||
@ -767,6 +767,16 @@ _outRelabelType(StringInfo str, RelabelType *node)
|
|||||||
WRITE_ENUM_FIELD(relabelformat, CoercionForm);
|
WRITE_ENUM_FIELD(relabelformat, CoercionForm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_outConvertRowtypeExpr(StringInfo str, ConvertRowtypeExpr *node)
|
||||||
|
{
|
||||||
|
WRITE_NODE_TYPE("CONVERTROWTYPEEXPR");
|
||||||
|
|
||||||
|
WRITE_NODE_FIELD(arg);
|
||||||
|
WRITE_OID_FIELD(resulttype);
|
||||||
|
WRITE_ENUM_FIELD(convertformat, CoercionForm);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_outCaseExpr(StringInfo str, CaseExpr *node)
|
_outCaseExpr(StringInfo str, CaseExpr *node)
|
||||||
{
|
{
|
||||||
@ -1728,6 +1738,9 @@ _outNode(StringInfo str, void *obj)
|
|||||||
case T_RelabelType:
|
case T_RelabelType:
|
||||||
_outRelabelType(str, obj);
|
_outRelabelType(str, obj);
|
||||||
break;
|
break;
|
||||||
|
case T_ConvertRowtypeExpr:
|
||||||
|
_outConvertRowtypeExpr(str, obj);
|
||||||
|
break;
|
||||||
case T_CaseExpr:
|
case T_CaseExpr:
|
||||||
_outCaseExpr(str, obj);
|
_outCaseExpr(str, obj);
|
||||||
break;
|
break;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.173 2004/08/29 04:12:33 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.174 2004/12/11 23:26:34 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Path and Plan nodes do not have any readfuncs support, because we
|
* Path and Plan nodes do not have any readfuncs support, because we
|
||||||
@ -575,6 +575,21 @@ _readRelabelType(void)
|
|||||||
READ_DONE();
|
READ_DONE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _readConvertRowtypeExpr
|
||||||
|
*/
|
||||||
|
static ConvertRowtypeExpr *
|
||||||
|
_readConvertRowtypeExpr(void)
|
||||||
|
{
|
||||||
|
READ_LOCALS(ConvertRowtypeExpr);
|
||||||
|
|
||||||
|
READ_NODE_FIELD(arg);
|
||||||
|
READ_OID_FIELD(resulttype);
|
||||||
|
READ_ENUM_FIELD(convertformat, CoercionForm);
|
||||||
|
|
||||||
|
READ_DONE();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* _readCaseExpr
|
* _readCaseExpr
|
||||||
*/
|
*/
|
||||||
@ -971,6 +986,8 @@ parseNodeString(void)
|
|||||||
return_value = _readFieldStore();
|
return_value = _readFieldStore();
|
||||||
else if (MATCH("RELABELTYPE", 11))
|
else if (MATCH("RELABELTYPE", 11))
|
||||||
return_value = _readRelabelType();
|
return_value = _readRelabelType();
|
||||||
|
else if (MATCH("CONVERTROWTYPEEXPR", 18))
|
||||||
|
return_value = _readConvertRowtypeExpr();
|
||||||
else if (MATCH("CASE", 4))
|
else if (MATCH("CASE", 4))
|
||||||
return_value = _readCaseExpr();
|
return_value = _readCaseExpr();
|
||||||
else if (MATCH("WHEN", 4))
|
else if (MATCH("WHEN", 4))
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.23 2004/08/29 05:06:44 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.24 2004/12/11 23:26:37 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -839,6 +839,13 @@ find_nonnullable_rels(Node *node, bool top_level)
|
|||||||
|
|
||||||
result = find_nonnullable_rels((Node *) expr->arg, top_level);
|
result = find_nonnullable_rels((Node *) expr->arg, top_level);
|
||||||
}
|
}
|
||||||
|
else if (IsA(node, ConvertRowtypeExpr))
|
||||||
|
{
|
||||||
|
/* not clear this is useful, but it can't hurt */
|
||||||
|
ConvertRowtypeExpr *expr = (ConvertRowtypeExpr *) node;
|
||||||
|
|
||||||
|
result = find_nonnullable_rels((Node *) expr->arg, top_level);
|
||||||
|
}
|
||||||
else if (IsA(node, NullTest))
|
else if (IsA(node, NullTest))
|
||||||
{
|
{
|
||||||
NullTest *expr = (NullTest *) node;
|
NullTest *expr = (NullTest *) node;
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.117 2004/10/02 22:39:47 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.118 2004/12/11 23:26:37 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -40,6 +40,8 @@ typedef struct
|
|||||||
{
|
{
|
||||||
Index old_rt_index;
|
Index old_rt_index;
|
||||||
Index new_rt_index;
|
Index new_rt_index;
|
||||||
|
Oid old_rel_type;
|
||||||
|
Oid new_rel_type;
|
||||||
TupleDesc old_tupdesc;
|
TupleDesc old_tupdesc;
|
||||||
TupleDesc new_tupdesc;
|
TupleDesc new_tupdesc;
|
||||||
char *old_rel_name;
|
char *old_rel_name;
|
||||||
@ -826,6 +828,8 @@ adjust_inherited_attrs(Node *node,
|
|||||||
|
|
||||||
context.old_rt_index = old_rt_index;
|
context.old_rt_index = old_rt_index;
|
||||||
context.new_rt_index = new_rt_index;
|
context.new_rt_index = new_rt_index;
|
||||||
|
context.old_rel_type = oldrelation->rd_rel->reltype;
|
||||||
|
context.new_rel_type = newrelation->rd_rel->reltype;
|
||||||
context.old_tupdesc = RelationGetDescr(oldrelation);
|
context.old_tupdesc = RelationGetDescr(oldrelation);
|
||||||
context.new_tupdesc = RelationGetDescr(newrelation);
|
context.new_tupdesc = RelationGetDescr(newrelation);
|
||||||
context.old_rel_name = RelationGetRelationName(oldrelation);
|
context.old_rel_name = RelationGetRelationName(oldrelation);
|
||||||
@ -910,50 +914,6 @@ translate_inherited_attnum(AttrNumber old_attno,
|
|||||||
return 0; /* keep compiler quiet */
|
return 0; /* keep compiler quiet */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Translate a whole-row Var to be correct for a child table.
|
|
||||||
*
|
|
||||||
* In general the child will not have a suitable field layout to be used
|
|
||||||
* directly, so we translate the simple whole-row Var into a ROW() construct.
|
|
||||||
*/
|
|
||||||
static Node *
|
|
||||||
generate_whole_row(Var *var,
|
|
||||||
adjust_inherited_attrs_context *context)
|
|
||||||
{
|
|
||||||
RowExpr *rowexpr;
|
|
||||||
List *fields = NIL;
|
|
||||||
int oldnatts = context->old_tupdesc->natts;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < oldnatts; i++)
|
|
||||||
{
|
|
||||||
Form_pg_attribute att = context->old_tupdesc->attrs[i];
|
|
||||||
Var *newvar;
|
|
||||||
|
|
||||||
if (att->attisdropped)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* can't use atttypid here, but it doesn't really matter what
|
|
||||||
* type the Const claims to be.
|
|
||||||
*/
|
|
||||||
newvar = (Var *) makeNullConst(INT4OID);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
newvar = makeVar(context->new_rt_index,
|
|
||||||
translate_inherited_attnum(i + 1, context),
|
|
||||||
att->atttypid,
|
|
||||||
att->atttypmod,
|
|
||||||
0);
|
|
||||||
fields = lappend(fields, newvar);
|
|
||||||
}
|
|
||||||
rowexpr = makeNode(RowExpr);
|
|
||||||
rowexpr->args = fields;
|
|
||||||
rowexpr->row_typeid = var->vartype; /* report parent's rowtype */
|
|
||||||
rowexpr->row_format = COERCE_IMPLICIT_CAST;
|
|
||||||
|
|
||||||
return (Node *) rowexpr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Node *
|
static Node *
|
||||||
adjust_inherited_attrs_mutator(Node *node,
|
adjust_inherited_attrs_mutator(Node *node,
|
||||||
adjust_inherited_attrs_context *context)
|
adjust_inherited_attrs_context *context)
|
||||||
@ -977,8 +937,22 @@ adjust_inherited_attrs_mutator(Node *node,
|
|||||||
}
|
}
|
||||||
else if (var->varattno == 0)
|
else if (var->varattno == 0)
|
||||||
{
|
{
|
||||||
/* expand whole-row reference into a ROW() construct */
|
/*
|
||||||
return generate_whole_row(var, context);
|
* Whole-row Var: we need to insert a coercion step to convert
|
||||||
|
* the tuple layout to the parent's rowtype.
|
||||||
|
*/
|
||||||
|
if (context->old_rel_type != context->new_rel_type)
|
||||||
|
{
|
||||||
|
ConvertRowtypeExpr *r = makeNode(ConvertRowtypeExpr);
|
||||||
|
|
||||||
|
r->arg = (Expr *) var;
|
||||||
|
r->resulttype = context->old_rel_type;
|
||||||
|
r->convertformat = COERCE_IMPLICIT_CAST;
|
||||||
|
/* Make sure the Var node has the right type ID, too */
|
||||||
|
Assert(var->vartype == context->old_rel_type);
|
||||||
|
var->vartype = context->new_rel_type;
|
||||||
|
return (Node *) r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* system attributes don't need any translation */
|
/* system attributes don't need any translation */
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.184 2004/11/09 21:42:53 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.185 2004/12/11 23:26:39 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -1047,6 +1047,13 @@ strip_implicit_coercions(Node *node)
|
|||||||
if (r->relabelformat == COERCE_IMPLICIT_CAST)
|
if (r->relabelformat == COERCE_IMPLICIT_CAST)
|
||||||
return strip_implicit_coercions((Node *) r->arg);
|
return strip_implicit_coercions((Node *) r->arg);
|
||||||
}
|
}
|
||||||
|
else if (IsA(node, ConvertRowtypeExpr))
|
||||||
|
{
|
||||||
|
ConvertRowtypeExpr *c = (ConvertRowtypeExpr *) node;
|
||||||
|
|
||||||
|
if (c->convertformat == COERCE_IMPLICIT_CAST)
|
||||||
|
return strip_implicit_coercions((Node *) c->arg);
|
||||||
|
}
|
||||||
else if (IsA(node, CoerceToDomain))
|
else if (IsA(node, CoerceToDomain))
|
||||||
{
|
{
|
||||||
CoerceToDomain *c = (CoerceToDomain *) node;
|
CoerceToDomain *c = (CoerceToDomain *) node;
|
||||||
@ -1082,11 +1089,13 @@ set_coercionform_dontcare_walker(Node *node, void *context)
|
|||||||
return false;
|
return false;
|
||||||
if (IsA(node, FuncExpr))
|
if (IsA(node, FuncExpr))
|
||||||
((FuncExpr *) node)->funcformat = COERCE_DONTCARE;
|
((FuncExpr *) node)->funcformat = COERCE_DONTCARE;
|
||||||
if (IsA(node, RelabelType))
|
else if (IsA(node, RelabelType))
|
||||||
((RelabelType *) node)->relabelformat = COERCE_DONTCARE;
|
((RelabelType *) node)->relabelformat = COERCE_DONTCARE;
|
||||||
if (IsA(node, RowExpr))
|
else if (IsA(node, ConvertRowtypeExpr))
|
||||||
|
((ConvertRowtypeExpr *) node)->convertformat = COERCE_DONTCARE;
|
||||||
|
else if (IsA(node, RowExpr))
|
||||||
((RowExpr *) node)->row_format = COERCE_DONTCARE;
|
((RowExpr *) node)->row_format = COERCE_DONTCARE;
|
||||||
if (IsA(node, CoerceToDomain))
|
else if (IsA(node, CoerceToDomain))
|
||||||
((CoerceToDomain *) node)->coercionformat = COERCE_DONTCARE;
|
((CoerceToDomain *) node)->coercionformat = COERCE_DONTCARE;
|
||||||
return expression_tree_walker(node, set_coercionform_dontcare_walker,
|
return expression_tree_walker(node, set_coercionform_dontcare_walker,
|
||||||
context);
|
context);
|
||||||
@ -2647,6 +2656,8 @@ expression_tree_walker(Node *node,
|
|||||||
break;
|
break;
|
||||||
case T_RelabelType:
|
case T_RelabelType:
|
||||||
return walker(((RelabelType *) node)->arg, context);
|
return walker(((RelabelType *) node)->arg, context);
|
||||||
|
case T_ConvertRowtypeExpr:
|
||||||
|
return walker(((ConvertRowtypeExpr *) node)->arg, context);
|
||||||
case T_CaseExpr:
|
case T_CaseExpr:
|
||||||
{
|
{
|
||||||
CaseExpr *caseexpr = (CaseExpr *) node;
|
CaseExpr *caseexpr = (CaseExpr *) node;
|
||||||
@ -3057,6 +3068,16 @@ expression_tree_mutator(Node *node,
|
|||||||
return (Node *) newnode;
|
return (Node *) newnode;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case T_ConvertRowtypeExpr:
|
||||||
|
{
|
||||||
|
ConvertRowtypeExpr *convexpr = (ConvertRowtypeExpr *) node;
|
||||||
|
ConvertRowtypeExpr *newnode;
|
||||||
|
|
||||||
|
FLATCOPY(newnode, convexpr, ConvertRowtypeExpr);
|
||||||
|
MUTATE(newnode->arg, convexpr->arg, Expr *);
|
||||||
|
return (Node *) newnode;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case T_CaseExpr:
|
case T_CaseExpr:
|
||||||
{
|
{
|
||||||
CaseExpr *caseexpr = (CaseExpr *) node;
|
CaseExpr *caseexpr = (CaseExpr *) node;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.124 2004/11/06 17:46:33 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.125 2004/12/11 23:26:42 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -321,13 +321,16 @@ coerce_type(ParseState *pstate, Node *node,
|
|||||||
if (typeInheritsFrom(inputTypeId, targetTypeId))
|
if (typeInheritsFrom(inputTypeId, targetTypeId))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Input class type is a subclass of target, so nothing to do ---
|
* Input class type is a subclass of target, so generate an
|
||||||
* except relabel the type. This is binary compatibility for
|
* appropriate runtime conversion (removing unneeded columns
|
||||||
* complex types.
|
* and possibly rearranging the ones that are wanted).
|
||||||
*/
|
*/
|
||||||
return (Node *) makeRelabelType((Expr *) node,
|
ConvertRowtypeExpr *r = makeNode(ConvertRowtypeExpr);
|
||||||
targetTypeId, -1,
|
|
||||||
cformat);
|
r->arg = (Expr *) node;
|
||||||
|
r->resulttype = targetTypeId;
|
||||||
|
r->convertformat = cformat;
|
||||||
|
return (Node *) r;
|
||||||
}
|
}
|
||||||
/* If we get here, caller blew it */
|
/* If we get here, caller blew it */
|
||||||
elog(ERROR, "failed to find conversion function from %s to %s",
|
elog(ERROR, "failed to find conversion function from %s to %s",
|
||||||
@ -567,6 +570,8 @@ hide_coercion_node(Node *node)
|
|||||||
((FuncExpr *) node)->funcformat = COERCE_IMPLICIT_CAST;
|
((FuncExpr *) node)->funcformat = COERCE_IMPLICIT_CAST;
|
||||||
else if (IsA(node, RelabelType))
|
else if (IsA(node, RelabelType))
|
||||||
((RelabelType *) node)->relabelformat = COERCE_IMPLICIT_CAST;
|
((RelabelType *) node)->relabelformat = COERCE_IMPLICIT_CAST;
|
||||||
|
else if (IsA(node, ConvertRowtypeExpr))
|
||||||
|
((ConvertRowtypeExpr *) node)->convertformat = COERCE_IMPLICIT_CAST;
|
||||||
else if (IsA(node, RowExpr))
|
else if (IsA(node, RowExpr))
|
||||||
((RowExpr *) node)->row_format = COERCE_IMPLICIT_CAST;
|
((RowExpr *) node)->row_format = COERCE_IMPLICIT_CAST;
|
||||||
else if (IsA(node, CoerceToDomain))
|
else if (IsA(node, CoerceToDomain))
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.176 2004/08/29 05:06:44 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.177 2004/12/11 23:26:42 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -940,6 +940,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
|||||||
case T_FieldSelect:
|
case T_FieldSelect:
|
||||||
case T_FieldStore:
|
case T_FieldStore:
|
||||||
case T_RelabelType:
|
case T_RelabelType:
|
||||||
|
case T_ConvertRowtypeExpr:
|
||||||
case T_CaseTestExpr:
|
case T_CaseTestExpr:
|
||||||
case T_CoerceToDomain:
|
case T_CoerceToDomain:
|
||||||
case T_CoerceToDomainValue:
|
case T_CoerceToDomainValue:
|
||||||
@ -1406,6 +1407,9 @@ exprType(Node *expr)
|
|||||||
case T_RelabelType:
|
case T_RelabelType:
|
||||||
type = ((RelabelType *) expr)->resulttype;
|
type = ((RelabelType *) expr)->resulttype;
|
||||||
break;
|
break;
|
||||||
|
case T_ConvertRowtypeExpr:
|
||||||
|
type = ((ConvertRowtypeExpr *) expr)->resulttype;
|
||||||
|
break;
|
||||||
case T_CaseExpr:
|
case T_CaseExpr:
|
||||||
type = ((CaseExpr *) expr)->casetype;
|
type = ((CaseExpr *) expr)->casetype;
|
||||||
break;
|
break;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* back to source text
|
* back to source text
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.185 2004/11/05 19:16:11 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.186 2004/12/11 23:26:45 tgl Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -2622,6 +2622,9 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
|
|||||||
case T_RelabelType:
|
case T_RelabelType:
|
||||||
return isSimpleNode((Node *) ((RelabelType *) node)->arg,
|
return isSimpleNode((Node *) ((RelabelType *) node)->arg,
|
||||||
node, prettyFlags);
|
node, prettyFlags);
|
||||||
|
case T_ConvertRowtypeExpr:
|
||||||
|
return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg,
|
||||||
|
node, prettyFlags);
|
||||||
|
|
||||||
case T_OpExpr:
|
case T_OpExpr:
|
||||||
{
|
{
|
||||||
@ -3133,6 +3136,30 @@ get_rule_expr(Node *node, deparse_context *context,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_ConvertRowtypeExpr:
|
||||||
|
{
|
||||||
|
ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;
|
||||||
|
Node *arg = (Node *) convert->arg;
|
||||||
|
|
||||||
|
if (convert->convertformat == COERCE_IMPLICIT_CAST &&
|
||||||
|
!showimplicit)
|
||||||
|
{
|
||||||
|
/* don't show the implicit cast */
|
||||||
|
get_rule_expr_paren(arg, context, false, node);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!PRETTY_PAREN(context))
|
||||||
|
appendStringInfoChar(buf, '(');
|
||||||
|
get_rule_expr_paren(arg, context, false, node);
|
||||||
|
if (!PRETTY_PAREN(context))
|
||||||
|
appendStringInfoChar(buf, ')');
|
||||||
|
appendStringInfo(buf, "::%s",
|
||||||
|
format_type_with_typemod(convert->resulttype, -1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case T_CaseExpr:
|
case T_CaseExpr:
|
||||||
{
|
{
|
||||||
CaseExpr *caseexpr = (CaseExpr *) node;
|
CaseExpr *caseexpr = (CaseExpr *) node;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.120 2004/10/07 18:38:51 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.121 2004/12/11 23:26:49 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -578,6 +578,23 @@ typedef struct FieldStoreState
|
|||||||
TupleDesc argdesc; /* tupdesc for most recent input */
|
TupleDesc argdesc; /* tupdesc for most recent input */
|
||||||
} FieldStoreState;
|
} FieldStoreState;
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* ConvertRowtypeExprState node
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
typedef struct ConvertRowtypeExprState
|
||||||
|
{
|
||||||
|
ExprState xprstate;
|
||||||
|
ExprState *arg; /* input tuple value */
|
||||||
|
TupleDesc indesc; /* tupdesc for source rowtype */
|
||||||
|
TupleDesc outdesc; /* tupdesc for result rowtype */
|
||||||
|
AttrNumber *attrMap; /* indexes of input fields, or 0 for null */
|
||||||
|
Datum *invalues; /* workspace for deconstructing source */
|
||||||
|
char *innulls;
|
||||||
|
Datum *outvalues; /* workspace for constructing result */
|
||||||
|
char *outnulls;
|
||||||
|
} ConvertRowtypeExprState;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* CaseExprState node
|
* CaseExprState node
|
||||||
* ----------------
|
* ----------------
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.161 2004/09/14 03:21:25 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.162 2004/12/11 23:26:49 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -112,6 +112,7 @@ typedef enum NodeTag
|
|||||||
T_FieldSelect,
|
T_FieldSelect,
|
||||||
T_FieldStore,
|
T_FieldStore,
|
||||||
T_RelabelType,
|
T_RelabelType,
|
||||||
|
T_ConvertRowtypeExpr,
|
||||||
T_CaseExpr,
|
T_CaseExpr,
|
||||||
T_CaseWhen,
|
T_CaseWhen,
|
||||||
T_CaseTestExpr,
|
T_CaseTestExpr,
|
||||||
@ -145,6 +146,7 @@ typedef enum NodeTag
|
|||||||
T_SubPlanState,
|
T_SubPlanState,
|
||||||
T_FieldSelectState,
|
T_FieldSelectState,
|
||||||
T_FieldStoreState,
|
T_FieldStoreState,
|
||||||
|
T_ConvertRowtypeExprState,
|
||||||
T_CaseExprState,
|
T_CaseExprState,
|
||||||
T_CaseWhenState,
|
T_CaseWhenState,
|
||||||
T_ArrayExprState,
|
T_ArrayExprState,
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.104 2004/08/29 05:06:57 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.105 2004/12/11 23:26:49 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -591,6 +591,27 @@ typedef struct RelabelType
|
|||||||
CoercionForm relabelformat; /* how to display this node */
|
CoercionForm relabelformat; /* how to display this node */
|
||||||
} RelabelType;
|
} RelabelType;
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* ConvertRowtypeExpr
|
||||||
|
*
|
||||||
|
* ConvertRowtypeExpr represents a type coercion from one composite type
|
||||||
|
* to another, where the source type is guaranteed to contain all the columns
|
||||||
|
* needed for the destination type plus possibly others; the columns need not
|
||||||
|
* be in the same positions, but are matched up by name. This is primarily
|
||||||
|
* used to convert a whole-row value of an inheritance child table into a
|
||||||
|
* valid whole-row value of its parent table's rowtype.
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct ConvertRowtypeExpr
|
||||||
|
{
|
||||||
|
Expr xpr;
|
||||||
|
Expr *arg; /* input expression */
|
||||||
|
Oid resulttype; /* output type (always a composite type) */
|
||||||
|
/* result typmod is not stored, but must be -1; see RowExpr comments */
|
||||||
|
CoercionForm convertformat; /* how to display this node */
|
||||||
|
} ConvertRowtypeExpr;
|
||||||
|
|
||||||
/*----------
|
/*----------
|
||||||
* CaseExpr - a CASE expression
|
* CaseExpr - a CASE expression
|
||||||
*
|
*
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.123 2004/11/30 03:50:29 neilc Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.124 2004/12/11 23:26:51 tgl Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -4024,6 +4024,9 @@ exec_simple_check_node(Node *node)
|
|||||||
case T_RelabelType:
|
case T_RelabelType:
|
||||||
return exec_simple_check_node((Node *) ((RelabelType *) node)->arg);
|
return exec_simple_check_node((Node *) ((RelabelType *) node)->arg);
|
||||||
|
|
||||||
|
case T_ConvertRowtypeExpr:
|
||||||
|
return exec_simple_check_node((Node *) ((ConvertRowtypeExpr *) node)->arg);
|
||||||
|
|
||||||
case T_CaseExpr:
|
case T_CaseExpr:
|
||||||
{
|
{
|
||||||
CaseExpr *expr = (CaseExpr *) node;
|
CaseExpr *expr = (CaseExpr *) node;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user