From 9fa12ddda62549a0e0225220745c3bf89434dab3 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 10 Dec 2006 22:13:27 +0000 Subject: [PATCH] Add a paramtypmod field to Param nodes. This is dead weight for Params representing externally-supplied values, since the APIs that carry such values only specify type not typmod. However, for PARAM_SUBLINK Params it is handy to carry the typmod of the sublink's output column. This is a much cleaner solution for the recently reported 'could not find pathkey item to sort' and 'failed to find unique expression in subplan tlist' bugs than my original 8.2-compatible patch. Besides, someday we might want to support typmods for external parameters ... --- src/backend/nodes/copyfuncs.c | 3 +- src/backend/nodes/equalfuncs.c | 3 +- src/backend/nodes/outfuncs.c | 3 +- src/backend/nodes/readfuncs.c | 3 +- src/backend/optimizer/plan/subselect.c | 48 +++++++------------------- src/backend/parser/parse_agg.c | 5 ++- src/backend/parser/parse_coerce.c | 10 +++++- src/backend/parser/parse_expr.c | 6 +++- src/include/catalog/catversion.h | 4 +-- src/include/nodes/primnodes.h | 12 +++++-- 10 files changed, 50 insertions(+), 47 deletions(-) diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index c1858e6746..5047dc8ad7 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.353 2006/11/05 22:42:08 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.354 2006/12/10 22:13:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -745,6 +745,7 @@ _copyParam(Param *from) COPY_SCALAR_FIELD(paramkind); COPY_SCALAR_FIELD(paramid); COPY_SCALAR_FIELD(paramtype); + COPY_SCALAR_FIELD(paramtypmod); return newnode; } diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index a42afb77a3..e341b74f3e 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -18,7 +18,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.287 2006/11/05 22:42:08 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.288 2006/12/10 22:13:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -147,6 +147,7 @@ _equalParam(Param *a, Param *b) COMPARE_SCALAR_FIELD(paramkind); COMPARE_SCALAR_FIELD(paramid); COMPARE_SCALAR_FIELD(paramtype); + COMPARE_SCALAR_FIELD(paramtypmod); return true; } diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index cbffa3a3a4..daeb3fe872 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.285 2006/09/19 22:49:52 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.286 2006/12/10 22:13:26 tgl Exp $ * * NOTES * Every node type that can appear in stored rules' parsetrees *must* @@ -634,6 +634,7 @@ _outParam(StringInfo str, Param *node) WRITE_ENUM_FIELD(paramkind, ParamKind); WRITE_INT_FIELD(paramid); WRITE_OID_FIELD(paramtype); + WRITE_INT_FIELD(paramtypmod); } static void diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index ab66fc6ac8..df0a217027 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.195 2006/08/12 02:52:04 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.196 2006/12/10 22:13:26 tgl Exp $ * * NOTES * Path and Plan nodes do not have any readfuncs support, because we @@ -337,6 +337,7 @@ _readParam(void) READ_ENUM_FIELD(paramkind, ParamKind); READ_INT_FIELD(paramid); READ_OID_FIELD(paramtype); + READ_INT_FIELD(paramtypmod); READ_DONE(); } diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 72b986002d..7793d071cd 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.113 2006/12/06 19:40:01 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.114 2006/12/10 22:13:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -75,7 +75,6 @@ typedef struct convert_testexpr_context { int rtindex; /* RT index for Vars, or 0 for Params */ List *righthandIds; /* accumulated list of Vars or Param IDs */ - List *sub_tlist; /* subselect targetlist (if given) */ } convert_testexpr_context; typedef struct finalize_primnode_context @@ -87,8 +86,7 @@ typedef struct finalize_primnode_context static Node *convert_testexpr(Node *testexpr, int rtindex, - List **righthandIds, - List *sub_tlist); + List **righthandIds); static Node *convert_testexpr_mutator(Node *node, convert_testexpr_context *context); static bool subplan_is_hashable(SubLink *slink, SubPlan *node); @@ -166,6 +164,7 @@ replace_outer_var(Var *var) retval->paramkind = PARAM_EXEC; retval->paramid = i; retval->paramtype = var->vartype; + retval->paramtypmod = var->vartypmod; return retval; } @@ -204,6 +203,7 @@ replace_outer_agg(Aggref *agg) retval->paramkind = PARAM_EXEC; retval->paramid = i; retval->paramtype = agg->aggtype; + retval->paramtypmod = -1; return retval; } @@ -212,8 +212,6 @@ replace_outer_agg(Aggref *agg) * Generate a new Param node that will not conflict with any other. * * This is used to allocate PARAM_EXEC slots for subplan outputs. - * - * paramtypmod is currently unused but might be wanted someday. */ static Param * generate_new_param(Oid paramtype, int32 paramtypmod) @@ -225,6 +223,7 @@ generate_new_param(Oid paramtype, int32 paramtypmod) retval->paramkind = PARAM_EXEC; retval->paramid = list_length(PlannerParamList); retval->paramtype = paramtype; + retval->paramtypmod = paramtypmod; pitem = (PlannerParamItem *) palloc(sizeof(PlannerParamItem)); pitem->item = (Node *) retval; @@ -371,7 +370,7 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual) if (!OidIsValid(arraytype)) elog(ERROR, "could not find array type for datatype %s", format_type_be(exprType((Node *) te->expr))); - prm = generate_new_param(arraytype, -1); + prm = generate_new_param(arraytype, exprTypmod((Node *) te->expr)); node->setParam = list_make1_int(prm->paramid); PlannerInitPlan = lappend(PlannerInitPlan, node); result = (Node *) prm; @@ -381,8 +380,7 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual) /* Adjust the Params */ result = convert_testexpr(testexpr, 0, - &node->paramIds, - NIL); + &node->paramIds); node->setParam = list_copy(node->paramIds); PlannerInitPlan = lappend(PlannerInitPlan, node); @@ -399,8 +397,7 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual) /* Adjust the Params */ node->testexpr = convert_testexpr(testexpr, 0, - &node->paramIds, - NIL); + &node->paramIds); /* * We can't convert subplans of ALL_SUBLINK or ANY_SUBLINK types to @@ -474,10 +471,6 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual) * of the Var nodes are returned in *righthandIds (this is a bit of a type * cheat, but we can get away with it). * - * The subquery targetlist need be supplied only if rtindex is not 0. - * We consult it to extract the correct typmods for the created Vars. - * (XXX this is a kluge that could go away if Params carried typmod.) - * * The given testexpr has already been recursively processed by * process_sublinks_mutator. Hence it can no longer contain any * PARAM_SUBLINK Params for lower SubLink nodes; we can safely assume that @@ -486,15 +479,13 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual) static Node * convert_testexpr(Node *testexpr, int rtindex, - List **righthandIds, - List *sub_tlist) + List **righthandIds) { Node *result; convert_testexpr_context context; context.rtindex = rtindex; context.righthandIds = NIL; - context.sub_tlist = sub_tlist; result = convert_testexpr_mutator(testexpr, &context); *righthandIds = context.righthandIds; return result; @@ -526,23 +517,10 @@ convert_testexpr_mutator(Node *node, /* Make the Var node representing the subplan's result */ Var *newvar; - /* - * XXX kluge: since Params don't carry typmod, we have to - * look into the subquery targetlist to find out the right - * typmod to assign to the Var. - */ - TargetEntry *ste = get_tle_by_resno(context->sub_tlist, - param->paramid); - - if (ste == NULL || ste->resjunk) - elog(ERROR, "subquery output %d not found", - param->paramid); - Assert(param->paramtype == exprType((Node *) ste->expr)); - newvar = makeVar(context->rtindex, param->paramid, param->paramtype, - exprTypmod((Node *) ste->expr), + param->paramtypmod, 0); /* @@ -558,7 +536,8 @@ convert_testexpr_mutator(Node *node, /* Make the Param node representing the subplan's result */ Param *newparam; - newparam = generate_new_param(param->paramtype, -1); + newparam = generate_new_param(param->paramtype, + param->paramtypmod); /* Record its ID */ context->righthandIds = lappend_int(context->righthandIds, newparam->paramid); @@ -775,8 +754,7 @@ convert_IN_to_join(PlannerInfo *root, SubLink *sublink) */ return convert_testexpr(sublink->testexpr, rtindex, - &ininfo->sub_targetlist, - subselect->targetList); + &ininfo->sub_targetlist); } /* diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c index 3bda907c99..438d7398c3 100644 --- a/src/backend/parser/parse_agg.c +++ b/src/backend/parser/parse_agg.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.73 2006/07/27 19:52:05 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.74 2006/12/10 22:13:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -394,6 +394,7 @@ build_aggregate_fnexprs(Oid *agg_input_types, argp->paramkind = PARAM_EXEC; argp->paramid = -1; argp->paramtype = agg_state_type; + argp->paramtypmod = -1; args = list_make1(argp); @@ -403,6 +404,7 @@ build_aggregate_fnexprs(Oid *agg_input_types, argp->paramkind = PARAM_EXEC; argp->paramid = -1; argp->paramtype = agg_input_types[i]; + argp->paramtypmod = -1; args = lappend(args, argp); } @@ -425,6 +427,7 @@ build_aggregate_fnexprs(Oid *agg_input_types, argp->paramkind = PARAM_EXEC; argp->paramid = -1; argp->paramtype = agg_state_type; + argp->paramtypmod = -1; args = list_make1(argp); *finalfnexpr = (Expr *) makeFuncExpr(finalfn_oid, diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index a8972342af..2a468c6827 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.146 2006/11/28 12:54:41 petere Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.147 2006/12/10 22:13:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -264,6 +264,14 @@ coerce_type(ParseState *pstate, Node *node, } param->paramtype = targetTypeId; + /* + * Note: it is tempting here to set the Param's paramtypmod to + * targetTypeMod, but that is probably unwise because we have no + * infrastructure that enforces that the value delivered for a + * Param will match any particular typmod. Leaving it -1 ensures + * that a run-time length check/coercion will occur if needed. + */ + param->paramtypmod = -1; return (Node *) param; } diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 7c72ae9e22..b1b6ea8145 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.198 2006/10/04 00:29:55 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.199 2006/12/10 22:13:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -572,6 +572,7 @@ transformParamRef(ParseState *pstate, ParamRef *pref) param->paramkind = PARAM_EXTERN; param->paramid = paramno; param->paramtype = toppstate->p_paramtypes[paramno - 1]; + param->paramtypmod = -1; return (Node *) param; } @@ -1180,6 +1181,7 @@ transformSubLink(ParseState *pstate, SubLink *sublink) param->paramkind = PARAM_SUBLINK; param->paramid = tent->resno; param->paramtype = exprType((Node *) tent->expr); + param->paramtypmod = exprTypmod((Node *) tent->expr); right_list = lappend(right_list, param); } @@ -1721,6 +1723,8 @@ exprTypmod(Node *expr) } } break; + case T_Param: + return ((Param *) expr)->paramtypmod; case T_FuncExpr: { int32 coercedTypmod; diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 246eef42f4..e6bcdfb054 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.361 2006/12/06 18:06:47 neilc Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.362 2006/12/10 22:13:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200612061 +#define CATALOG_VERSION_NO 200612101 #endif diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 841d85336e..6c5e761275 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -10,7 +10,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.117 2006/10/04 00:30:09 momjian Exp $ + * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.118 2006/12/10 22:13:27 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -113,7 +113,7 @@ typedef struct Var * table (could also be INNER or OUTER) */ AttrNumber varattno; /* attribute number of this var, or zero for * all */ - Oid vartype; /* pg_type tuple OID for the type of this var */ + Oid vartype; /* pg_type OID for the type of this var */ int32 vartypmod; /* pg_attribute typmod value */ Index varlevelsup; @@ -159,6 +159,11 @@ typedef struct Const * node's sub-select. The column number is contained in the * `paramid' field. (This type of Param is converted to * PARAM_EXEC during planning.) + * + * Note: currently, paramtypmod is valid for PARAM_SUBLINK Params, and for + * PARAM_EXEC Params generated from them; it is always -1 for PARAM_EXTERN + * params, since the APIs that supply values for such parameters don't carry + * any typmod info. * ---------------- */ typedef enum ParamKind @@ -173,7 +178,8 @@ typedef struct Param Expr xpr; ParamKind paramkind; /* kind of parameter. See above */ int paramid; /* numeric ID for parameter */ - Oid paramtype; /* PG_TYPE OID of parameter's datatype */ + Oid paramtype; /* pg_type OID of parameter's datatype */ + int32 paramtypmod; /* typmod value, if known */ } Param; /* -- 2.40.0