Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA384:256) (Exim 4.89) (envelope-from ) id 1ela3J-0000zW-7E for pgsql-hackers@arkaria.postgresql.org; Tue, 13 Feb 2018 12:51:17 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ela3H-0001K1-Bs for pgsql-hackers@arkaria.postgresql.org; Tue, 13 Feb 2018 12:51:15 +0000 Received: from makus.postgresql.org ([2001:4800:1501:1::229]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1ela3G-0001Jq-V2 for pgsql-hackers@lists.postgresql.org; Tue, 13 Feb 2018 12:51:15 +0000 Received: from mail-pg0-x236.google.com ([2607:f8b0:400e:c05::236]) by makus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1ela38-0002Qd-UW for pgsql-hackers@postgresql.org; Tue, 13 Feb 2018 12:51:13 +0000 Received: by mail-pg0-x236.google.com with SMTP id j9so9235110pgp.11 for ; Tue, 13 Feb 2018 04:51:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=enterprisedb-com.20150623.gappssmtp.com; s=20150623; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=2XPXv79U4oCk9UdjSPTMYgCLrheHhQHEynabDIq7f6M=; b=1U/Ct3fOIxUxwlRsH1YnoqzOk4gGvA671NzzFOvS8tjBmmsSPKJBbVN7tWXfRTCQAw 0l8e1X82OJ111k6moM8wmlw/+lrMbd3VQSnxY3xz8JEwCNBsK6FrDZP8mZ5gPYBAA+ki 8oDZ/aiadb4ZfLT04dzxtdDkII4tOHA+bVw/p9mmQlfpl3S9Tdn4VkEmtmORMv4QMEdg nc/haBWev6tu8VBdyq1frjx3rD71ED6WQI7Ggr+6eNgjFm4vCEHqQmQsL4eFGgfOebaa 3O1YVpsBNQ8GG6bNZImpXtjaHC2HnbwrO3QoNuhwtjFuVRsBHx5B/IPZPxg4u+q2YDxC XKHQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=2XPXv79U4oCk9UdjSPTMYgCLrheHhQHEynabDIq7f6M=; b=V35yT3VpjT7G96SIHSOyRiMRRbp9fyWxoVWjhA18jaexHJEYO+iU/M1fxoQSIy50p4 pnr76BIlRVKoRjcnUgIdxumYrac4Gjh/bXs7XJ1hy9oIe6+6g47v2jN70WTc7+SUyN95 fsCNpZWaXzFoU13dzHN7M1pAFjcUwxR9GZe4wzWQTn0CYUksbcBDy5lLyUafEo5m010C rMcuKRKZ/dAeLKrkO4v+Fu0tEjLDfR/fJNbeLFFLiQtlfv80B1wljistnly0Wc0s+vYc caY3NVxqn8Z6RoT+1OmhvmLG+nNe/miWwpa/364gy4RcWjNHqHdjI2QPGz4ZtYvjNLT2 QbXQ== X-Gm-Message-State: APf1xPCmeMlY+pTwuPsfjSyjrNe7pl1Mr+hv2oaJlQPWyIGygkUdEX7d seKJyCohIMUaXds0ry6UiLZ2M55JEQo4eIQ55e/1Ag== X-Google-Smtp-Source: AH8x2275DOFn7CCio8Va+ksO3pM/daPTJ5MXoYCugmAoqSq774jj0sT1FZw3s/zFjw/XP50vdvy0m4F1OfAlAzWKPlw= X-Received: by 10.98.214.153 with SMTP id a25mr1142301pfl.173.1518526265147; Tue, 13 Feb 2018 04:51:05 -0800 (PST) MIME-Version: 1.0 Received: by 10.236.137.139 with HTTP; Tue, 13 Feb 2018 04:51:04 -0800 (PST) In-Reply-To: References: From: Ashutosh Bapat Date: Tue, 13 Feb 2018 18:21:04 +0530 Message-ID: Subject: Re: Expression errors with "FOR UPDATE" and postgres_fdw with partition wise join enabled. To: Rajkumar Raghuwanshi Cc: pgsql-hackers Content-Type: text/plain; charset="UTF-8" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk On Mon, Feb 12, 2018 at 6:00 PM, Rajkumar Raghuwanshi wrote: > Hi, > > I am getting "ERROR: unexpected expression in subquery output" and "ERROR: > variable not found in subplan target lists" errors, for "FOR UPDATE" with > postgres_fdw. (when set enable_partition_wise_join to true); > > Attached patch have queries which are throwing mentioned error on running > make check in contrib/postgres_fdw folder. > Thanks a lot for the patch. I can apply it and reproduce the error. Here's my analysis of the bug. The node for which this error comes is a ConvertRowtypeExpr node with Var::varattno = 0 under it. Whole row reference of the parent is converted to ConvertRowtypeExpr with whole row of child as an argument. When partition-wise join is used, targetlist of child-joins contain such ConvertRowtypeExpr when the parent-join's targetlist has whole-row references of joining partitioned tables. When we deparse the targetlist of join pushed down by postgres FDW, build_tlist_to_deparse() pulls only Var nodes nodes from the join's targetlist. So it pulls Var reprensenting a whole-row reference of a child from a ConvertRowtypeExpr, when building targetlist to be deparsed for a child-join with whole-row references. This targetlist is then saved as fdw_scan_tlist in ForeignScanPlan. This causes two problems shown by the two queries below > > EXPLAIN (VERBOSE, COSTS OFF) > SELECT t1.c1, ss.a, ss.b FROM (SELECT c1 FROM pt1 WHERE c1 = 50) t1 INNER > JOIN (SELECT t2.c1, t3.c1 FROM (SELECT c1 FROM pt1 WHERE c1 between 50 and > 60) t2 FULL JOIN (SELECT c1 FROM pt2 WHERE c1 between 50 and 60) t3 ON > (t2.c1 = t3.c1) WHERE t2.c1 IS NULL OR t2.c1 IS NOT NULL) ss(a, b) ON (TRUE) > ORDER BY t1.c1, ss.a, ss.b FOR UPDATE OF t1; > ERROR: unexpected expression in subquery output get_relation_column_alias_ids() uses foreignrel's targetlist (foreignrel->reltarget->exprs) as it is to locate given node to be deparsed. If the joining relation corresponding to ConvertRowtypeExpr is deparsed as a subquery, this function is called with whole-row reference node (Var node with varattno = 0). But the relation's targetlist doesn't contain its whole-row reference directly but has it embedded in ConvertRowtypeExpr. So, the function doesn't find the given node and throws error. > > EXPLAIN (VERBOSE, COSTS OFF) > SELECT t1.c1, ss.a, ss.b FROM (SELECT c1 FROM pt1) t1 INNER JOIN (SELECT > t2.c1, t3.c1 FROM (SELECT c1 FROM pt1) t2 FULL JOIN (SELECT c1 FROM pt1) t3 > ON (t2.c1 = t3.c1)) ss(a, b) ON (TRUE) ORDER BY t1.c1, ss.a, ss.b FOR UPDATE > OF t1; > ERROR: variable not found in subplan target lists When there is possibility of EvalPlanQual being called, we construct local join plan matching the pushed down foreign join. In postgresGetForeignPlan() after we have built the local join plan, the topmost plan node's targetlist is changed to fdw_scan_tlist to match the output of the ForeignScan node. As explained above, this targetlist contains a bare reference to whole-row reference of a child relation if the child-join's targetlist contains a ConvertRowtypeExpr. When changing the topmost plan node's targetlist, we do not modify the targetlists of its left and right tree nodes. The left/right plan involving corresponding child relation will have ConvertRowtypeExpr expression in its targetlist, but not whole-row reference directly. When the topmost local join plan node's targetlist is processed by set_plan_ref(), it throws error "variable not found in subplan target lists" since it doesn't find bare whole-row reference of the child relation in subplan's targetlists. The problem can be solved in two ways: 1. Push down ConvertRowtypeExpr and include it in the pushed down targetlist. This would solve both the problems described above. Both set_plan_ref() and get_relation_column_alias_ids() will find ConvertRowtypeExpr, they are looking for and won't throw an error. This requires two parts a. In build_tlist_to_deparse(), instead of pulling Var node from ConvertRowtypeExpr, we pull whole ConvertRowtypeExpr and include it in the targetlist being deparsed which is also used as to set fdw_scan_tlist. In order to pull any ConvertRowtypeExpr's in the local quals, which may be hidden in the expression tree, we will add two more options to flags viz. PVC_INCLUDE_CONVERTROWTYPEEXPR and PVC_RECURSE_CONVERTROWTYPEEXPR. Unlike the other PVC_* options, which do not default to a value, we may want to default to PVC_RECURSE_CONVERTROWTYPEEXPR if nothing is specified. That will avoid, possibly updating every pull_var_clause call with PVC_RECURSE_CONVERTROWTYPEEXPR. b. deparse ConvertRowtypeExpr For this we need to get the conversion map between the parent and child. We then deparse ConvertRowtypeExpr as a ROW() with the attributes of child rearranged per the conversion map. A multi-level partitioned table will have nested ConvertRowtypeExpr. To deparse such expressions, we need to find the conversion map between the topmost parent and the child, by ignoring any intermediate parents. 2. Modify the local join plan entirely to contain whole row reference of child relations instead of ConvertRowtypeExpr and deparse a ConvertRowtypeExpr as a whole-row reference in a subquery. Again we need two part solution: a. For this we need to write a walker which walks the plan tree distributing the Vars in the topmost targetlist to the left and right subtrees. Thus we replace ConvertRowtypeExpr with corresponding whole-row references in the whole plan tree. b. When get_relation_column_alias_ids() encounters a ConvertRowtypeExpr, it pulls out the embedded whole row reference and returns the corresponding column id. deparseExpr() calls deparseVar() by pulling out the embedded whole-row reference Var when it encouters ConvertRowtypeExpr. Comments, thoughts any other solutions? -- Best Wishes, Ashutosh Bapat EnterpriseDB Corporation The Postgres Database Company