summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2009-03-10 22:09:26 +0000
committerTom Lane2009-03-10 22:09:26 +0000
commit244a5f98cea3be7a9b8e31f41014bca4704f56cb (patch)
tree8da250f8e2253de8945667c44c4a7895cd17bbb2
parenta210053dd0d84010041e744acf0811b7c893f7cc (diff)
Make SubPlan nodes carry the result's typmod as well as datatype OID. This is
for consistency with the (relatively) recent addition of typmod to SubLink. An example of why it's a good idea is to be seen in the recent "failed to locate grouping columns" bug, which wouldn't have happened if a SubPlan exposed the same typmod info as the SubLink it was derived from. This could be back-patched, since it doesn't affect any on-disk data format, but for the moment it doesn't seem necessary to do so.
-rw-r--r--src/backend/nodes/copyfuncs.c1
-rw-r--r--src/backend/nodes/equalfuncs.c1
-rw-r--r--src/backend/nodes/nodeFuncs.c38
-rw-r--r--src/backend/nodes/outfuncs.c1
-rw-r--r--src/backend/optimizer/plan/subselect.c27
-rw-r--r--src/include/nodes/primnodes.h1
6 files changed, 49 insertions, 20 deletions
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index a6b1621c4b..0623f540f1 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -1113,6 +1113,7 @@ _copySubPlan(SubPlan *from)
COPY_NODE_FIELD(paramIds);
COPY_SCALAR_FIELD(plan_id);
COPY_SCALAR_FIELD(firstColType);
+ COPY_SCALAR_FIELD(firstColTypmod);
COPY_SCALAR_FIELD(useHashTable);
COPY_SCALAR_FIELD(unknownEqFalse);
COPY_NODE_FIELD(setParam);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 6326f3b9f4..3e0487beef 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -342,6 +342,7 @@ _equalSubPlan(SubPlan *a, SubPlan *b)
COMPARE_NODE_FIELD(paramIds);
COMPARE_SCALAR_FIELD(plan_id);
COMPARE_SCALAR_FIELD(firstColType);
+ COMPARE_SCALAR_FIELD(firstColTypmod);
COMPARE_SCALAR_FIELD(useHashTable);
COMPARE_SCALAR_FIELD(unknownEqFalse);
COMPARE_NODE_FIELD(setParam);
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 69aa471319..85ff0f7087 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -28,7 +28,7 @@ static int leftmostLoc(int loc1, int loc2);
/*
* exprType -
- * returns the Oid of the type of the expression. (Used for typechecking.)
+ * returns the Oid of the type of the expression's result.
*/
Oid
exprType(Node *expr)
@@ -117,11 +117,6 @@ exprType(Node *expr)
break;
case T_SubPlan:
{
- /*
- * Although the parser does not ever deal with already-planned
- * expression trees, we support SubPlan nodes in this routine
- * for the convenience of ruleutils.c.
- */
SubPlan *subplan = (SubPlan *) expr;
if (subplan->subLinkType == EXPR_SUBLINK ||
@@ -148,7 +143,6 @@ exprType(Node *expr)
break;
case T_AlternativeSubPlan:
{
- /* As above, supported for the convenience of ruleutils.c */
AlternativeSubPlan *asplan = (AlternativeSubPlan *) expr;
/* subplans should all return the same thing */
@@ -236,8 +230,8 @@ exprType(Node *expr)
/*
* exprTypmod -
- * returns the type-specific attrmod of the expression, if it can be
- * determined. In most cases, it can't and we return -1.
+ * returns the type-specific modifier of the expression's result type,
+ * if it can be determined. In many cases, it can't and we return -1.
*/
int32
exprTypmod(Node *expr)
@@ -286,6 +280,32 @@ exprTypmod(Node *expr)
}
}
break;
+ case T_SubPlan:
+ {
+ SubPlan *subplan = (SubPlan *) expr;
+
+ if (subplan->subLinkType == EXPR_SUBLINK ||
+ subplan->subLinkType == ARRAY_SUBLINK)
+ {
+ /* get the typmod of the subselect's first target column */
+ /* note we don't need to care if it's an array */
+ return subplan->firstColTypmod;
+ }
+ else
+ {
+ /* for all other subplan types, result is boolean */
+ return -1;
+ }
+ }
+ break;
+ case T_AlternativeSubPlan:
+ {
+ AlternativeSubPlan *asplan = (AlternativeSubPlan *) expr;
+
+ /* subplans should all return the same thing */
+ return exprTypmod((Node *) linitial(asplan->subplans));
+ }
+ break;
case T_FieldSelect:
return ((FieldSelect *) expr)->resulttypmod;
case T_RelabelType:
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index c11d1ec5cc..b24126e096 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -957,6 +957,7 @@ _outSubPlan(StringInfo str, SubPlan *node)
WRITE_NODE_FIELD(paramIds);
WRITE_INT_FIELD(plan_id);
WRITE_OID_FIELD(firstColType);
+ WRITE_INT_FIELD(firstColTypmod);
WRITE_BOOL_FIELD(useHashTable);
WRITE_BOOL_FIELD(unknownEqFalse);
WRITE_NODE_FIELD(setParam);
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 1cdd01d2e0..389b8f24a8 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -229,13 +229,13 @@ SS_assign_worktable_param(PlannerInfo *root)
/*
* Get the datatype of the first column of the plan's output.
*
- * This is stored for ARRAY_SUBLINK and for exprType(), which doesn't have any
- * way to get at the plan associated with a SubPlan node. We really only need
- * the value for EXPR_SUBLINK and ARRAY_SUBLINK subplans, but for consistency
- * we set it always.
+ * This is stored for ARRAY_SUBLINK execution and for exprType()/exprTypmod(),
+ * which have no way to get at the plan associated with a SubPlan node.
+ * We really only need the info for EXPR_SUBLINK and ARRAY_SUBLINK subplans,
+ * but for consistency we save it always.
*/
-static Oid
-get_first_col_type(Plan *plan)
+static void
+get_first_col_type(Plan *plan, Oid *coltype, int32 *coltypmod)
{
/* In cases such as EXISTS, tlist might be empty; arbitrarily use VOID */
if (plan->targetlist)
@@ -244,9 +244,14 @@ get_first_col_type(Plan *plan)
Assert(IsA(tent, TargetEntry));
if (!tent->resjunk)
- return exprType((Node *) tent->expr);
+ {
+ *coltype = exprType((Node *) tent->expr);
+ *coltypmod = exprTypmod((Node *) tent->expr);
+ return;
+ }
}
- return VOIDOID;
+ *coltype = VOIDOID;
+ *coltypmod = -1;
}
/*
@@ -414,7 +419,7 @@ build_subplan(PlannerInfo *root, Plan *plan, List *rtable,
splan->subLinkType = subLinkType;
splan->testexpr = NULL;
splan->paramIds = NIL;
- splan->firstColType = get_first_col_type(plan);
+ get_first_col_type(plan, &splan->firstColType, &splan->firstColTypmod);
splan->useHashTable = false;
splan->unknownEqFalse = unknownEqFalse;
splan->setParam = NIL;
@@ -876,7 +881,7 @@ SS_process_ctes(PlannerInfo *root)
splan->subLinkType = CTE_SUBLINK;
splan->testexpr = NULL;
splan->paramIds = NIL;
- splan->firstColType = get_first_col_type(plan);
+ get_first_col_type(plan, &splan->firstColType, &splan->firstColTypmod);
splan->useHashTable = false;
splan->unknownEqFalse = false;
splan->setParam = NIL;
@@ -2111,7 +2116,7 @@ SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,
*/
node = makeNode(SubPlan);
node->subLinkType = EXPR_SUBLINK;
- node->firstColType = get_first_col_type(plan);
+ get_first_col_type(plan, &node->firstColType, &node->firstColTypmod);
node->plan_id = list_length(root->glob->subplans);
root->init_plans = lappend(root->init_plans, node);
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index b279591d2b..068752808d 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -504,6 +504,7 @@ typedef struct SubPlan
int plan_id; /* Index (from 1) in PlannedStmt.subplans */
/* Extra data useful for determining subplan's output type: */
Oid firstColType; /* Type of first column of subplan result */
+ int32 firstColTypmod; /* Typmod of first column of subplan result */
/* Information about execution strategy: */
bool useHashTable; /* TRUE to store subselect output in a hash
* table (implies we are doing "IN") */