Re: [HACKERS] Incorrect comment for build_child_join_rel

2017-11-12 Thread Etsuro Fujita

(2017/11/11 0:58), Robert Haas wrote:

On Fri, Nov 10, 2017 at 4:34 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp>  wrote:

Here is a small patch for $Subject.


Good catch.  Committed.


Thanks!

Best regards,
Etsuro Fujita


--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Another oddity in handling of WCO constraints in postgres_fdw

2017-11-10 Thread Etsuro Fujita

(2017/11/01 11:16), Robert Haas wrote:

On Wed, Oct 4, 2017 at 5:58 PM, Ashutosh Bapat
<ashutosh.ba...@enterprisedb.com>  wrote:

The view with WCO is local but the modification which violates WCO is
being made on remote server by a trigger on remote table. Trying to
control that doesn't seem to be a good idea, just like we can't
control what rows get inserted on the foreign server when they violate
local constraints.


I think that's a fair point.


For local constraints on foreign tables, it's the user's responsibility 
to ensure that those constraints matches the remote side, so we don't 
need to ensure those constraints locally.  But I'm not sure if the same 
thing applies to WCOs on views defined on foreign tables, because in 
some case it's not possible to impose constraints on the remote side 
that match those WCOs, as I explained before.


Best regards,
Etsuro Fujita


--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] Incorrect comment for build_child_join_rel

2017-11-10 Thread Etsuro Fujita
Hi,

Here is a small patch for $Subject.

Best regards,
Etsuro Fujita
*** a/src/backend/optimizer/util/relnode.c
--- b/src/backend/optimizer/util/relnode.c
***
*** 676,683  build_join_rel(PlannerInfo *root,
   * 'sjinfo': child-join context info
   * 'restrictlist': list of RestrictInfo nodes that apply to this particular
   *pair of joinable relations
!  * 'join_appinfos': list of AppendRelInfo nodes for base child relations
!  *involved in this join
   */
  RelOptInfo *
  build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
--- 676,682 
   * 'sjinfo': child-join context info
   * 'restrictlist': list of RestrictInfo nodes that apply to this particular
   *pair of joinable relations
!  * 'jointype' is the join type (inner, left, full, etc)
   */
  RelOptInfo *
  build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] Reorder header files in alphabetical order

2017-11-09 Thread Etsuro Fujita
Hi,

Attached is a patch to reorder header files in joinrels.c and pathnode.c
in alphabetical order, removing unnecessary ones.

Best regards,
Etsuro Fujita
*** a/src/backend/optimizer/path/joinrels.c
--- b/src/backend/optimizer/path/joinrels.c
***
*** 16,30 
  
  #include "miscadmin.h"
  #include "catalog/partition.h"
- #include "nodes/relation.h"
  #include "optimizer/clauses.h"
  #include "optimizer/joininfo.h"
  #include "optimizer/pathnode.h"
  #include "optimizer/paths.h"
  #include "optimizer/prep.h"
- #include "optimizer/cost.h"
- #include "utils/memutils.h"
  #include "utils/lsyscache.h"
  
  
  static void make_rels_by_clause_joins(PlannerInfo *root,
--- 16,28 
  
  #include "miscadmin.h"
  #include "catalog/partition.h"
  #include "optimizer/clauses.h"
  #include "optimizer/joininfo.h"
  #include "optimizer/pathnode.h"
  #include "optimizer/paths.h"
  #include "optimizer/prep.h"
  #include "utils/lsyscache.h"
+ #include "utils/memutils.h"
  
  
  static void make_rels_by_clause_joins(PlannerInfo *root,
*** a/src/backend/optimizer/util/pathnode.c
--- b/src/backend/optimizer/util/pathnode.c
***
*** 17,24 
  #include 
  
  #include "miscadmin.h"
! #include "nodes/nodeFuncs.h"
  #include "nodes/extensible.h"
  #include "optimizer/clauses.h"
  #include "optimizer/cost.h"
  #include "optimizer/pathnode.h"
--- 17,25 
  #include 
  
  #include "miscadmin.h"
! #include "foreign/fdwapi.h"
  #include "nodes/extensible.h"
+ #include "nodes/nodeFuncs.h"
  #include "optimizer/clauses.h"
  #include "optimizer/cost.h"
  #include "optimizer/pathnode.h"
***
*** 29,35 
  #include "optimizer/tlist.h"
  #include "optimizer/var.h"
  #include "parser/parsetree.h"
- #include "foreign/fdwapi.h"
  #include "utils/lsyscache.h"
  #include "utils/memutils.h"
  #include "utils/selfuncs.h"
--- 30,35 

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Comment typo

2017-10-31 Thread Etsuro Fujita

On 2017/10/30 22:39, Magnus Hagander wrote:
On Mon, Oct 30, 2017 at 3:49 AM, Etsuro Fujita 
<fujita.ets...@lab.ntt.co.jp <mailto:fujita.ets...@lab.ntt.co.jp>> wrote:


Here is a patch to fix a typo in a comment in partition.c:
s/specificiation/specification/.


Applied, thanks.


Thank you!

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] Comment typo

2017-10-29 Thread Etsuro Fujita
Here is a patch to fix a typo in a comment in partition.c: 
s/specificiation/specification/.


Best regards,
Etsuro Fujita
diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 07fdf66..e234167 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -703,7 +703,7 @@ partition_bounds_equal(int partnatts, int16 *parttyplen, 
bool *parttypbyval,
 
 /*
  * Return a copy of given PartitionBoundInfo structure. The data types of 
bounds
- * are described by given partition key specificiation.
+ * are described by given partition key specification.
  */
 extern PartitionBoundInfo
 partition_bounds_copy(PartitionBoundInfo src,

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Typos in src/backend/optimizer/README

2017-10-29 Thread Etsuro Fujita

On 2017/10/28 18:15, Robert Haas wrote:

On Fri, Oct 27, 2017 at 9:34 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

This sentence in the section of Partition-wise joins in
src/backend/optimizer/README should be fixed: "This technique of breaking
down a join between partition tables into join between their partitions is
called partition-wise join."

(1) s/a join between partition tables/a join between partitioned tables/
(2) s/join between their partitions/joins between their partitions/

It might be okay to leave #2 as-is, but I'd like to propose to change that
way to make the meaning clear.


I think you are right.  I have committed the patch.


Thank you.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Add support for tuple routing to foreign partitions

2017-10-27 Thread Etsuro Fujita

On 2017/10/26 16:40, Etsuro Fujita wrote:
Other changes I made 
to the executor are: (1) currently, we set the RT index for the root 
partitioned table to ri_RangeTableIndex of partitions' ResultRelInfos, 
but the proposed EXPLAIN requires that the partition's 
ri_RangeTableIndex is set to the RT index for that partition's RTE, to 
show that partition info in the output.  So, I made that change.


One thing I forgot to mention is: that would be also required to call 
BeginForeignModify, ExecForeignInsert, and EndForeignModify with the 
partition's ResultRelInfo.


I updated docs in doc/src/sgml/ddl.sgml the same way as [1].  (I used 
only the ddl.sgml change proposed by [1], not all the changes.)  I did 
some cleanup as well.  Please find attached an updated version of the patch.


Best regards,
Etsuro Fujita

[1] 
https://www.postgresql.org/message-id/b19a8e2b-e000-f592-3e0b-3e90ba0fa816%40lab.ntt.co.jp
*** a/contrib/file_fdw/input/file_fdw.source
--- b/contrib/file_fdw/input/file_fdw.source
***
*** 176,182  COPY pt FROM '@abs_srcdir@/data/list2.csv' with (format 'csv', 
delimiter ',');
--- 176,188 
  SELECT tableoid::regclass, * FROM pt;
  SELECT tableoid::regclass, * FROM p1;
  SELECT tableoid::regclass, * FROM p2;
+ \t on
+ EXPLAIN (VERBOSE, COSTS FALSE) INSERT INTO pt VALUES (1, 'xyzzy');
+ \t off
  INSERT INTO pt VALUES (1, 'xyzzy'); -- ERROR
+ \t on
+ EXPLAIN (VERBOSE, COSTS FALSE) INSERT INTO pt VALUES (2, 'xyzzy');
+ \t off
  INSERT INTO pt VALUES (2, 'xyzzy');
  SELECT tableoid::regclass, * FROM pt;
  SELECT tableoid::regclass, * FROM p1;
*** a/contrib/file_fdw/output/file_fdw.source
--- b/contrib/file_fdw/output/file_fdw.source
***
*** 315,321  SELECT tableoid::regclass, * FROM p2;
  (0 rows)
  
  COPY pt FROM '@abs_srcdir@/data/list2.bad' with (format 'csv', delimiter 
','); -- ERROR
! ERROR:  cannot route inserted tuples to a foreign table
  CONTEXT:  COPY pt, line 2: "1,qux"
  COPY pt FROM '@abs_srcdir@/data/list2.csv' with (format 'csv', delimiter ',');
  SELECT tableoid::regclass, * FROM pt;
--- 315,321 
  (0 rows)
  
  COPY pt FROM '@abs_srcdir@/data/list2.bad' with (format 'csv', delimiter 
','); -- ERROR
! ERROR:  cannot route copied tuples to a foreign table
  CONTEXT:  COPY pt, line 2: "1,qux"
  COPY pt FROM '@abs_srcdir@/data/list2.csv' with (format 'csv', delimiter ',');
  SELECT tableoid::regclass, * FROM pt;
***
*** 341,348  SELECT tableoid::regclass, * FROM p2;
   p2   | 2 | qux
  (2 rows)
  
  INSERT INTO pt VALUES (1, 'xyzzy'); -- ERROR
! ERROR:  cannot route inserted tuples to a foreign table
  INSERT INTO pt VALUES (2, 'xyzzy');
  SELECT tableoid::regclass, * FROM pt;
   tableoid | a |   b   
--- 341,366 
   p2   | 2 | qux
  (2 rows)
  
+ \t on
+ EXPLAIN (VERBOSE, COSTS FALSE) INSERT INTO pt VALUES (1, 'xyzzy');
+  Insert on public.pt
+Foreign Insert on public.p1
+Insert on public.p2
+->  Result
+  Output: 1, 'xyzzy'::text
+ 
+ \t off
  INSERT INTO pt VALUES (1, 'xyzzy'); -- ERROR
! ERROR:  cannot route inserted tuples to foreign table "p1"
! \t on
! EXPLAIN (VERBOSE, COSTS FALSE) INSERT INTO pt VALUES (2, 'xyzzy');
!  Insert on public.pt
!Foreign Insert on public.p1
!Insert on public.p2
!->  Result
!  Output: 2, 'xyzzy'::text
! 
! \t off
  INSERT INTO pt VALUES (2, 'xyzzy');
  SELECT tableoid::regclass, * FROM pt;
   tableoid | a |   b   
*** a/contrib/postgres_fdw/expected/postgres_fdw.out
--- b/contrib/postgres_fdw/expected/postgres_fdw.out
***
*** 7029,7034  NOTICE:  drop cascades to foreign table bar2
--- 7029,7236 
  drop table loct1;
  drop table loct2;
  -- ===
+ -- test tuple routing for foreign-table partitions
+ -- ===
+ create table pt (a int, b int) partition by list (a);
+ create table locp partition of pt for values in (1);
+ create table locfoo (a int check (a in (2)), b int);
+ create foreign table remp partition of pt for values in (2) server loopback 
options (table_name 'locfoo');
+ explain (verbose, costs off)
+ insert into pt values (1, 1), (2, 1);
+QUERY PLAN
+ -
+  Insert on public.pt
+Insert on public.locp
+Foreign Insert on public.remp
+  Remote SQL: INSERT INTO public.locfoo(a, b) VALUES ($1, $2)
+->  Values Scan on "*VALUES*"
+  Output: "*VALUES*".column1, "*VALUES*".column2
+ (6 rows)
+ 
+ insert into pt values (1, 1), (2, 1);
+ select tableoid::regclass, * FROM pt;
+  tableoid | a | b 
+ --+---+---
+  locp | 1 | 1
+  remp | 2 | 1
+ (2 rows)
+ 
+ select tableoid::regclass, * FROM locp;
+  tableoid | a | b 
+ --+---+---
+  locp | 1 | 1
+ (1 

[HACKERS] Typos in src/backend/optimizer/README

2017-10-27 Thread Etsuro Fujita

Hi,

This sentence in the section of Partition-wise joins in 
src/backend/optimizer/README should be fixed: "This technique of 
breaking down a join between partition tables into join between their 
partitions is called partition-wise join."


(1) s/a join between partition tables/a join between partitioned tables/
(2) s/join between their partitions/joins between their partitions/

It might be okay to leave #2 as-is, but I'd like to propose to change 
that way to make the meaning clear.


Attached is a patch for that.

Best regards,
Etsuro Fujita
diff --git a/src/backend/optimizer/README b/src/backend/optimizer/README
index 031e503..1e4084d 100644
--- a/src/backend/optimizer/README
+++ b/src/backend/optimizer/README
@@ -1088,8 +1088,8 @@ broken into joins between the matching partitions. The 
resultant join is
 partitioned in the same way as the joining relations, thus allowing an N-way
 join between similarly partitioned tables having equi-join condition between
 their partition keys to be broken down into N-way joins between their matching
-partitions. This technique of breaking down a join between partition tables
-into join between their partitions is called partition-wise join. We will use
+partitions. This technique of breaking down a join between partitioned tables
+into joins between their partitions is called partition-wise join. We will use
 term "partitioned relation" for either a partitioned table or a join between
 compatibly partitioned tables.
 

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Add support for tuple routing to foreign partitions

2017-10-26 Thread Etsuro Fujita

Hi Maksim,

On 2017/10/02 21:37, Maksim Milyutin wrote:

On 11.09.2017 16:01, Etsuro Fujita wrote:
* Query planning: the patch creates copies of Query/Plan with a 
foreign partition as target from the original Query/Plan for each 
foreign partition and invokes PlanForeignModify with those copies, to 
allow the FDW to do query planning for remote INSERT with the existing 
API.  To make such Queries the similar way inheritance_planner does, I 
modified transformInsertStmt so that the inh flag for the partitioned 
table's RTE is set to true, which allows (1) expand_inherited_rtentry 
to build an RTE and AppendRelInfo for each partition in the 
partitioned table and (2) make_modifytable to build such Queries using 
adjust_appendrel_attrs and those AppendRelInfos.


* explain.c: I modified show_modifytable_info so that we can show 
remote queries for foreign partitions in EXPLAIN for INSERT into a 
partitioned table the same way as for inherited UPDATE/DELETE cases. 
Here is an example:


postgres=# explain verbose insert into pt values (1), (2);
    QUERY PLAN
---
 Insert on public.pt  (cost=0.00..0.03 rows=2 width=4)
   Foreign Insert on public.fp1
 Remote SQL: INSERT INTO public.t1(a) VALUES ($1)
   Foreign Insert on public.fp2
 Remote SQL: INSERT INTO public.t2(a) VALUES ($1)
   ->  Values Scan on "*VALUES*"  (cost=0.00..0.03 rows=2 width=4)
 Output: "*VALUES*".column1
(7 rows)

I think I should add more explanation about the patch, but I don't 
have time today, so I'll write additional explanation in the next 
email. Sorry about that.


Could you update your patch, it isn't applied on the actual state of 
master. Namely conflict in src/backend/executor/execMain.c


Attached is an updated version.

* As mentioned in "Query planning", the patch builds an RTE for each 
partition so that the FDW can make reference to that RTE in eg, 
PlanForeignModify.  set_plan_references also uses such RTEs to record 
plan dependencies for plancache.c to invalidate cached plans.  See an 
example for that added to the regression tests in postgres_fdw.


* As mentioned in "explain.c", the EXPLAIN shows all partitions beneath 
the ModifyTable node.  One merit of that is we can show remote queries 
for foreign partitions in the output as shown above.  Another one I can 
think of is when reporting execution stats for triggers.  Here is an 
example for that:


postgres=# explain analyze insert into list_parted values (1, 'hi 
there'), (2, 'hi there');

  QUERY PLAN
--
 Insert on list_parted  (cost=0.00..0.03 rows=2 width=36) (actual 
time=0.375..0.375 rows=0 loops=1)

   Insert on part1
   Insert on part2
   ->  Values Scan on "*VALUES*"  (cost=0.00..0.03 rows=2 width=36) 
(actual time=0.004..0.007 rows=2 loops=1)

 Planning time: 0.089 ms
 Trigger part1brtrig on part1: time=0.059 calls=1
 Trigger part2brtrig on part2: time=0.021 calls=1
 Execution time: 0.422 ms
(8 rows)

This would allow the user to understand easily that "part1" and "part2" 
in the trigger lines are the partitions of list_parted.  So, I think 
it's useful to show partition info in the ModifyTable node even in the 
case where a partitioned table only contains plain tables.


* The patch modifies make_modifytable and ExecInitModifyTable so that 
the former can allow the FDW to construct private plan data for each 
foreign partition and accumulate it all into a list, and that the latter 
can perform BeginForeignModify for each partition using that plan data 
stored in the list passed from make_modifytable.  Other changes I made 
to the executor are: (1) currently, we set the RT index for the root 
partitioned table to ri_RangeTableIndex of partitions' ResultRelInfos, 
but the proposed EXPLAIN requires that the partition's 
ri_RangeTableIndex is set to the RT index for that partition's RTE, to 
show that partition info in the output.  So, I made that change. 
Because of that, ExecPartitionCheck, ExecConstraints, and 
ExecWithCheckOptions are adjusted accordingly.  (2) I added a new member 
to ResultRelInfo (ie, ri_PartitionIsValid), and modified 
CheckValidResultRel so that it checks a given partition without throwing 
an error and save the result in that flag so that ExecInsert determines 
using that flag whether a partition chosen by ExecFindPartition is valid 
for tuple-routing as proposed before.


* copy.c: I still don't think it's a good idea to implement COPY 
tuple-routing for foreign partitions using PlanForeignModify.  (I plan 
to propose new FDW APIs for bulkload as discussed before, to implement 
this feature.)  So, I kept that as-is.  Two things I changed there are: 
(1) currently, ExecSetupPartitionTupleRouti

Re: [HACKERS] Another oddity in handling of WCO constraints in postgres_fdw

2017-10-06 Thread Etsuro Fujita

On 2017/10/05 20:06, Kyotaro HORIGUCHI wrote:

Since WCO ensures finally inserted values, we can't do other than
acturally requesting for the values.


I think so too.


So just merging WCO columns
to RETURNING in deparsed query is ok. But can't we concatenate
returningList and withCheckOptionList at more higher level?
Specifically, just passing calculated used_attr to
deparse(Insert|Update)Sql instead of returningList and
withCheckOptionList separately.  Deparsed queries anyway forget
the origin of requested columns.


We could do that, but I think that would need a bit more code to 
postgresPlanForeignModify including changes to the deparseDeleteSql API 
in addition to the deparse(Insert|Update)Sql APIs.  I prefer making high 
level functions simple, so I'd vote for just passing withCheckOptionList 
separately to deparse(Insert|Update)Sql, as proposed in the patch.


Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Comment typo

2017-10-06 Thread Etsuro Fujita

On 2017/10/05 21:48, Robert Haas wrote:

On Thu, Oct 5, 2017 at 6:11 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

Here is a small patch to fix a typo in a comment in partition.c:
s/mantain/maintain/.


Committed.


Thanks!

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] Comment typo

2017-10-05 Thread Etsuro Fujita
Here is a small patch to fix a typo in a comment in partition.c: 
s/mantain/maintain/.


Best regards,
Etsuro Fujita
diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 1ab6dba..9777d40 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -1236,7 +1236,7 @@ RelationGetPartitionDispatchInfo(Relation rel,
  * get_partition_dispatch_recurse
  * Recursively expand partition tree rooted at rel
  *
- * As the partition tree is expanded in a depth-first manner, we mantain two
+ * As the partition tree is expanded in a depth-first manner, we maintain two
  * global lists: of PartitionDispatch objects corresponding to partitioned
  * tables in *pds and of the leaf partition OIDs in *leaf_part_oids.
  *

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Another oddity in handling of WCO constraints in postgres_fdw

2017-10-05 Thread Etsuro Fujita

On 2017/10/04 21:28, Ashutosh Bapat wrote:

On Wed, Oct 4, 2017 at 5:32 PM, Robert Haas <robertmh...@gmail.com> wrote:

On Wed, Oct 4, 2017 at 6:40 AM, Ashutosh Bapat
<ashutosh.ba...@enterprisedb.com> wrote:

We can
check whether a row being sent from the local server to the foreign
server obeys WCO, but what foreign server does to that row is beyond
local server's scope.


But I think right now we're not checking the row being sent from the
local server, either.


We don't check the row *before* sending it to the remote server, but 
check the row returned by ExecForeignInsert/ExecForeignUpdate, which is 
allowed to have been changed by the remote server.  In postgres_fdw, we 
currently return the data actually inserted/updated if RETURNING/AFTER 
TRIGGER present, but not if WCO only presents.  So, for the postgres_fdw 
foreign table, WCO is enforced on the data that was actually 
inserted/updated if RETURNING/AFTER TRIGGER present and on the original 
data core supplied if WCO only presents, which is inconsistent behavior.



Didn't 7086be6e3627c1ad797e32ebbdd232905b5f577f fix that?


No.  The commit addressed another issue.


The WCO that is being ignored isn't a
constraint on the foreign table; it's a constraint on a view which
happens to reference the foreign table.  It seems quite odd for the
"assume constraints are valid" property of the foreign table to
propagate back up into the view that references it.


Agreed.


The view with WCO is local but the modification which violates WCO is
being made on remote server by a trigger on remote table. Trying to
control that doesn't seem to be a good idea, just like we can't
control what rows get inserted on the foreign server when they violate
local constraints. I am using local constraints as an example of
precedence where we ignore what's happening on remote side and enforce
whatever we could enforce locally. Local server should make sure that
any rows sent from local server to the remote server do not violate
any local WCO.


Seems odd (and too restrictive) to me too.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Another oddity in handling of WCO constraints in postgres_fdw

2017-10-04 Thread Etsuro Fujita

On 2017/10/03 18:16, Ashutosh Bapat wrote:

Enforcing WCO constraints imposed by the local server on the row/DML
being passed to the foreign server is fine, but trying to impose them
on the row being inserted/updated at the foreign server looks odd. May
be we should just leave this case as it is. I am comparing this case
with the way we handle constraints on a foreign table.


Hmm, I think that would be okay in the case where WCO constraints match 
constraints on the foreign table, but I'm not sure that would be okay 
even in the case where WCO constraints don't match?  Consider:


create table bt (a int check (a % 2 = 0));
create foreign table ft (a int check (a % 2 = 0)) server loopback 
options (table_name 'bt');

create view rw_view_2 as select * from ft where a % 2 = 0 with check option;

In that case the WCO constraint matches the constraint on the foreign 
table, so there would be no need to ensure the WCO constraint locally 
(to make the explanation simple, we assume here that we don't have 
triggers on the remote end).  BUT: for another auto-updatable view 
defined using the same foreign table like this:


create view rw_view_4 as select * from ft where a % 4 = 0 with check option;

how is the WCO constraint (ie, a % 4 = 0) ensured remotely, which is 
different from the constraint on the foreign table (ie, a % 2 = 0)? 
Maybe I'm missing something, though.


Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] Another oddity in handling of WCO constraints in postgres_fdw

2017-09-28 Thread Etsuro Fujita

Hi,

Commit 7086be6e3627c1ad797e32ebbdd232905b5f577f addressed mishandling of 
WCO in direct foreign table modification by disabling it when we have 
WCO, but I noticed another oddity in postgres_fdw:


postgres=# create table base_tbl (a int, b int);
postgres=# create function row_before_insupd_trigfunc() returns trigger 
as $$begin new.a := new.a + 10; return new; end$$ language plpgsql;
postgres=# create trigger row_before_insupd_trigger before insert or 
update on base_tbl for each row execute procedure 
row_before_insupd_trigfunc();
postgres=# create server loopback foreign data wrapper postgres_fdw 
options (dbname 'postgres');

postgres=# create user mapping for CURRENT_USER server loopback;
postgres=# create foreign table foreign_tbl (a int, b int) server 
loopback options (table_name 'base_tbl');
postgres=# create view rw_view as select * from foreign_tbl where a < b 
with check option;


So, this should fail, but

postgres=# insert into rw_view values (0, 5);
INSERT 0 1

The reason for that is: this is processed using postgres_fdw's 
non-direct foreign table modification (ie. ForeignModify), but unlike 
the RETURNING or local after trigger case, the ForeignModify doesn't 
take care that remote triggers might change the data in that case, so 
the WCO is evaluated using the data supplied, not the data actually 
inserted, which I think is wrong.  (I should have noticed that as well 
while working on the fix, though.)  So, I'd propose to fix that by 
modifying postgresPlanForeignModify so that it handles WCO the same way 
as for the RETURNING case.  Attached is a patch for that.  I'll add the 
patch to the next commitfest.


Best regards,
Etsuro Fujita
*** a/contrib/postgres_fdw/deparse.c
--- b/contrib/postgres_fdw/deparse.c
***
*** 138,143  static void deparseSubqueryTargetList(deparse_expr_cxt 
*context);
--- 138,144 
  static void deparseReturningList(StringInfo buf, PlannerInfo *root,
 Index rtindex, Relation rel,
 bool trig_after_row,
+List *withCheckOptionList,
 List *returningList,
 List **retrieved_attrs);
  static void deparseColumnRef(StringInfo buf, int varno, int varattno,
***
*** 1548,1554  void
  deparseInsertSql(StringInfo buf, PlannerInfo *root,
 Index rtindex, Relation rel,
 List *targetAttrs, bool doNothing,
!List *returningList, List **retrieved_attrs)
  {
AttrNumber  pindex;
boolfirst;
--- 1549,1556 
  deparseInsertSql(StringInfo buf, PlannerInfo *root,
 Index rtindex, Relation rel,
 List *targetAttrs, bool doNothing,
!List *withCheckOptionList, List *returningList,
!List **retrieved_attrs)
  {
AttrNumber  pindex;
boolfirst;
***
*** 1597,1603  deparseInsertSql(StringInfo buf, PlannerInfo *root,
  
deparseReturningList(buf, root, rtindex, rel,
 rel->trigdesc && 
rel->trigdesc->trig_insert_after_row,
!returningList, 
retrieved_attrs);
  }
  
  /*
--- 1599,1605 
  
deparseReturningList(buf, root, rtindex, rel,
 rel->trigdesc && 
rel->trigdesc->trig_insert_after_row,
!withCheckOptionList, 
returningList, retrieved_attrs);
  }
  
  /*
***
*** 1610,1616  deparseInsertSql(StringInfo buf, PlannerInfo *root,
  void
  deparseUpdateSql(StringInfo buf, PlannerInfo *root,
 Index rtindex, Relation rel,
!List *targetAttrs, List *returningList,
 List **retrieved_attrs)
  {
AttrNumber  pindex;
--- 1612,1619 
  void
  deparseUpdateSql(StringInfo buf, PlannerInfo *root,
 Index rtindex, Relation rel,
!List *targetAttrs,
!List *withCheckOptionList, List *returningList,
 List **retrieved_attrs)
  {
AttrNumber  pindex;
***
*** 1639,1645  deparseUpdateSql(StringInfo buf, PlannerInfo *root,
  
deparseReturningList(buf, root, rtindex, rel,
 rel->trigdesc && 
rel->trigdesc->trig_update_after_row,
!returningList, 
retrieved_attrs);
  }
  
  /*
--- 1642,1648 
  
deparseReturningList(buf, root, rtindex, rel,

Re: [HACKERS] postgres_fdw: evaluate placeholdervars on remote server

2017-09-26 Thread Etsuro Fujita

On 2017/09/16 0:19, Robert Haas wrote:

On Fri, Sep 15, 2017 at 10:15 AM, Daniel Gustafsson <dan...@yesql.se> wrote:

Have you had a chance to look at this such that we can expect a rebased version
of this patch during the commitfest?


Frankly, I think things where there was a ping multiple weeks before
the CommitFest started and no rebase before it started should be
regarded as untimely submissions, and summarily marked Returned with
Feedback.  The CommitFest is supposed to be a time to get things that
are ready before it starts committed before it ends.  Some amount of
back-and-forth during the CF is of course to be expected, but we don't
even really have enough bandwidth to deal with the patches that are
being timely updated, never mind the ones that aren't.


Agreed.  I marked this as RWF.  Thank you.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Add support for tuple routing to foreign partitions

2017-09-11 Thread Etsuro Fujita

On 2017/08/17 17:27, Etsuro Fujita wrote:

On 2017/07/11 6:56, Robert Haas wrote:

I have to admit that I'm a little bit fuzzy about why foreign insert
routing requires all of these changes.  I think this patch would
benefit from being accompanied by several paragraphs of explanation
outlining the rationale for each part of the patch.


Will do.


Here is an updated version of the patch.

* Query planning: the patch creates copies of Query/Plan with a foreign 
partition as target from the original Query/Plan for each foreign 
partition and invokes PlanForeignModify with those copies, to allow the 
FDW to do query planning for remote INSERT with the existing API.  To 
make such Queries the similar way inheritance_planner does, I modified 
transformInsertStmt so that the inh flag for the partitioned table's RTE 
is set to true, which allows (1) expand_inherited_rtentry to build an 
RTE and AppendRelInfo for each partition in the partitioned table and 
(2) make_modifytable to build such Queries using adjust_appendrel_attrs 
and those AppendRelInfos.


* explain.c: I modified show_modifytable_info so that we can show remote 
queries for foreign partitions in EXPLAIN for INSERT into a partitioned 
table the same way as for inherited UPDATE/DELETE cases.  Here is an 
example:


postgres=# explain verbose insert into pt values (1), (2);
QUERY PLAN
---
 Insert on public.pt  (cost=0.00..0.03 rows=2 width=4)
   Foreign Insert on public.fp1
 Remote SQL: INSERT INTO public.t1(a) VALUES ($1)
   Foreign Insert on public.fp2
 Remote SQL: INSERT INTO public.t2(a) VALUES ($1)
   ->  Values Scan on "*VALUES*"  (cost=0.00..0.03 rows=2 width=4)
 Output: "*VALUES*".column1
(7 rows)

I think I should add more explanation about the patch, but I don't have 
time today, so I'll write additional explanation in the next email. 
Sorry about that.


Best regards,
Etsuro Fujita
*** a/contrib/file_fdw/output/file_fdw.source
--- b/contrib/file_fdw/output/file_fdw.source
***
*** 315,321  SELECT tableoid::regclass, * FROM p2;
  (0 rows)
  
  COPY pt FROM '@abs_srcdir@/data/list2.bad' with (format 'csv', delimiter 
','); -- ERROR
! ERROR:  cannot route inserted tuples to a foreign table
  CONTEXT:  COPY pt, line 2: "1,qux"
  COPY pt FROM '@abs_srcdir@/data/list2.csv' with (format 'csv', delimiter ',');
  SELECT tableoid::regclass, * FROM pt;
--- 315,321 
  (0 rows)
  
  COPY pt FROM '@abs_srcdir@/data/list2.bad' with (format 'csv', delimiter 
','); -- ERROR
! ERROR:  cannot route copied tuples to a foreign table
  CONTEXT:  COPY pt, line 2: "1,qux"
  COPY pt FROM '@abs_srcdir@/data/list2.csv' with (format 'csv', delimiter ',');
  SELECT tableoid::regclass, * FROM pt;
***
*** 342,348  SELECT tableoid::regclass, * FROM p2;
  (2 rows)
  
  INSERT INTO pt VALUES (1, 'xyzzy'); -- ERROR
! ERROR:  cannot route inserted tuples to a foreign table
  INSERT INTO pt VALUES (2, 'xyzzy');
  SELECT tableoid::regclass, * FROM pt;
   tableoid | a |   b   
--- 342,348 
  (2 rows)
  
  INSERT INTO pt VALUES (1, 'xyzzy'); -- ERROR
! ERROR:  cannot route inserted tuples to foreign table "p1"
  INSERT INTO pt VALUES (2, 'xyzzy');
  SELECT tableoid::regclass, * FROM pt;
   tableoid | a |   b   
*** a/contrib/postgres_fdw/expected/postgres_fdw.out
--- b/contrib/postgres_fdw/expected/postgres_fdw.out
***
*** 7029,7034  NOTICE:  drop cascades to foreign table bar2
--- 7029,7172 
  drop table loct1;
  drop table loct2;
  -- ===
+ -- test tuple routing to foreign-table partitions
+ -- ===
+ create table pt (a int, b int) partition by list (a);
+ create table locp partition of pt for values in (1);
+ create table locfoo (a int check (a in (2)), b int);
+ create foreign table remp partition of pt for values in (2) server loopback 
options (table_name 'locfoo');
+ explain (verbose, costs off)
+ insert into pt values (1, 1), (2, 1);
+QUERY PLAN
+ -
+  Insert on public.pt
+Insert on public.locp
+Foreign Insert on public.remp
+  Remote SQL: INSERT INTO public.locfoo(a, b) VALUES ($1, $2)
+->  Values Scan on "*VALUES*"
+  Output: "*VALUES*".column1, "*VALUES*".column2
+ (6 rows)
+ 
+ insert into pt values (1, 1), (2, 1);
+ select tableoid::regclass, * FROM pt;
+  tableoid | a | b 
+ --+---+---
+  locp | 1 | 1
+  remp | 2 | 1
+ (2 rows)
+ 
+ select tableoid::regclass, * FROM locp;
+  tableoid | a | b 
+ --+---+---
+  locp | 1 | 1
+ (1 row)
+ 
+ select tableoid::regclass, * FROM remp;
+  tableoid | a | b 
+ --+---+---
+  r

Re: [HACKERS] Tuple-routing for certain partitioned tables not working as expected

2017-09-07 Thread Etsuro Fujita

On 2017/09/08 0:21, Robert Haas wrote:

On Thu, Sep 7, 2017 at 5:13 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

On 2017/08/30 17:20, Etsuro Fujita wrote:

Here is a patch to skip the CheckValidResultRel checks for a target table
if it's a foreign partition to perform tuple-routing for, as proposed by
Robert.


In the patch, to skip the checks, I passed to CheckValidResultRel a new flag
indicating whether the target relation is a partition to do tuple-routing
for, but while updating another patch for tuple-routing for foreign
partitions in PG11, I noticed that it would be better to pass ResultRelInfo
than that flag.  The reason is: (1) we can see whether the relation is such
a partition by looking at the ResultRelInfo's ri_PartitionRoot, instead of
that flag, and (2) this is for tuple-routing for foreign partitions, but we
could extend that function with that argument to do the checks without
throwing an error and save the result in a new member of ResultRelInfo (eg,
ri_PartitionIsValid) so that we can use that info to determine in ExecInsert
whether a foreign partition chosen by ExecFindPartition is valid for
tuple-routing.  So, I updated the patch that way.  Attached is an updated
version of the patch.


OK, committed to master and v10.  I am less convinced than you that
this was a must-fix issue, but it's not a very invasive change the way
you did it here.


Thank you!

I'll update the tuple-routing-for-foreign-partitions patch that way.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Tuple-routing for certain partitioned tables not working as expected

2017-09-07 Thread Etsuro Fujita

On 2017/08/30 17:20, Etsuro Fujita wrote:
Here is a patch to skip the CheckValidResultRel checks for a 
target table if it's a foreign partition to perform tuple-routing for, 
as proposed by Robert.


In the patch, to skip the checks, I passed to CheckValidResultRel a new 
flag indicating whether the target relation is a partition to do 
tuple-routing for, but while updating another patch for tuple-routing 
for foreign partitions in PG11, I noticed that it would be better to 
pass ResultRelInfo than that flag.  The reason is: (1) we can see 
whether the relation is such a partition by looking at the 
ResultRelInfo's ri_PartitionRoot, instead of that flag, and (2) this is 
for tuple-routing for foreign partitions, but we could extend that 
function with that argument to do the checks without throwing an error 
and save the result in a new member of ResultRelInfo (eg, 
ri_PartitionIsValid) so that we can use that info to determine in 
ExecInsert whether a foreign partition chosen by ExecFindPartition is 
valid for tuple-routing.  So, I updated the patch that way.  Attached is 
an updated version of the patch.


(I discussed about lazy initialization of partition ResultRelInfos 
before, but I changed my mind because I noticed that the change to 
EXPLAIN for INSERT into a partitioned table, which I'd like to propose 
in the tuple-routing-for-foereign-partitions patch, needs partition 
ResultRelInfos.)


Best regards,
Etsuro Fujita
*** /dev/null
--- b/contrib/file_fdw/data/list1.csv
***
*** 0 
--- 1,2 
+ 1,foo
+ 1,bar
*** /dev/null
--- b/contrib/file_fdw/data/list2.bad
***
*** 0 
--- 1,2 
+ 2,baz
+ 1,qux
*** /dev/null
--- b/contrib/file_fdw/data/list2.csv
***
*** 0 
--- 1,2 
+ 2,baz
+ 2,qux
*** a/contrib/file_fdw/input/file_fdw.source
--- b/contrib/file_fdw/input/file_fdw.source
***
*** 162,167  SELECT tableoid::regclass, * FROM agg FOR UPDATE;
--- 162,188 
  ALTER FOREIGN TABLE agg_csv NO INHERIT agg;
  DROP TABLE agg;
  
+ -- declarative partitioning tests
+ SET ROLE regress_file_fdw_superuser;
+ CREATE TABLE pt (a int, b text) partition by list (a);
+ CREATE FOREIGN TABLE p1 partition of pt for values in (1) SERVER file_server
+ OPTIONS (format 'csv', filename '@abs_srcdir@/data/list1.csv', delimiter ',');
+ CREATE TABLE p2 partition of pt for values in (2);
+ SELECT tableoid::regclass, * FROM pt;
+ SELECT tableoid::regclass, * FROM p1;
+ SELECT tableoid::regclass, * FROM p2;
+ COPY pt FROM '@abs_srcdir@/data/list2.bad' with (format 'csv', delimiter 
','); -- ERROR
+ COPY pt FROM '@abs_srcdir@/data/list2.csv' with (format 'csv', delimiter ',');
+ SELECT tableoid::regclass, * FROM pt;
+ SELECT tableoid::regclass, * FROM p1;
+ SELECT tableoid::regclass, * FROM p2;
+ INSERT INTO pt VALUES (1, 'xyzzy'); -- ERROR
+ INSERT INTO pt VALUES (2, 'xyzzy');
+ SELECT tableoid::regclass, * FROM pt;
+ SELECT tableoid::regclass, * FROM p1;
+ SELECT tableoid::regclass, * FROM p2;
+ DROP TABLE pt;
+ 
  -- privilege tests
  SET ROLE regress_file_fdw_superuser;
  SELECT * FROM agg_text ORDER BY a;
*** a/contrib/file_fdw/output/file_fdw.source
--- b/contrib/file_fdw/output/file_fdw.source
***
*** 289,294  SELECT tableoid::regclass, * FROM agg FOR UPDATE;
--- 289,375 
  
  ALTER FOREIGN TABLE agg_csv NO INHERIT agg;
  DROP TABLE agg;
+ -- declarative partitioning tests
+ SET ROLE regress_file_fdw_superuser;
+ CREATE TABLE pt (a int, b text) partition by list (a);
+ CREATE FOREIGN TABLE p1 partition of pt for values in (1) SERVER file_server
+ OPTIONS (format 'csv', filename '@abs_srcdir@/data/list1.csv', delimiter ',');
+ CREATE TABLE p2 partition of pt for values in (2);
+ SELECT tableoid::regclass, * FROM pt;
+  tableoid | a |  b  
+ --+---+-
+  p1   | 1 | foo
+  p1   | 1 | bar
+ (2 rows)
+ 
+ SELECT tableoid::regclass, * FROM p1;
+  tableoid | a |  b  
+ --+---+-
+  p1   | 1 | foo
+  p1   | 1 | bar
+ (2 rows)
+ 
+ SELECT tableoid::regclass, * FROM p2;
+  tableoid | a | b 
+ --+---+---
+ (0 rows)
+ 
+ COPY pt FROM '@abs_srcdir@/data/list2.bad' with (format 'csv', delimiter 
','); -- ERROR
+ ERROR:  cannot route inserted tuples to a foreign table
+ CONTEXT:  COPY pt, line 2: "1,qux"
+ COPY pt FROM '@abs_srcdir@/data/list2.csv' with (format 'csv', delimiter ',');
+ SELECT tableoid::regclass, * FROM pt;
+  tableoid | a |  b  
+ --+---+-
+  p1   | 1 | foo
+  p1   | 1 | bar
+  p2   | 2 | baz
+  p2   | 2 | qux
+ (4 rows)
+ 
+ SELECT tableoid::regclass, * FROM p1;
+  tableoid | a |  b  
+ --+---+-
+  p1   | 1 | foo
+  p1   | 1 | bar
+ (2 rows)
+ 
+ SELECT tableoid::regclass, * FROM p2;
+  tableoid | a |  b  
+ --+---+-
+  p2   | 2 | baz
+  p2   | 2 | qux
+ (2 rows)
+ 
+ INSERT INTO pt VALUES (1, 'xyzzy'); -- ERROR
+ ERROR:  cannot route inserted tuples to a foreign table
+ INSERT INTO pt VALUES (2, 'xyzzy')

Re: [HACKERS] Tuple-routing for certain partitioned tables not working as expected

2017-09-05 Thread Etsuro Fujita

On 2017/08/30 17:20, Etsuro Fujita wrote:

On 2017/08/30 9:13, Amit Langote wrote:

On 2017/08/29 20:18, Etsuro Fujita wrote:

On 2017/08/25 22:26, Robert Haas wrote:

On Wed, Aug 23, 2017 at 4:55 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:
Agreed, but I'd vote for fixing this in v10 as proposed; I agree 
that just
ripping the CheckValidResultRel checks out entirely is not a good 
idea,

but
that seems OK to me at least as a fix just for v10.


I'm still not on-board with having this be the one case where we don't
do CheckValidResultRel.  If we want to still call it but pass down
some additional information that can selectively skip certain checks,
I could probably live with that.


Another idea would be to not do CheckValidResultRel for partitions in
ExecSetupPartitionTupleRouting; instead, do that the first time the
partition is chosen by ExecFindPartition, and if successfully checked,
initialize the partition's ResultRelInfo and other stuff.  (We could 
skip

this after the first time by checking whether we already have a valid
ResultRelInfo for the chosen partition.)  That could allow us to not 
only

call CheckValidResultRel the way it is, but avoid initializing useless
partitions for which tuples aren't routed at all.


I too have thought about the idea of lazy initialization of the partition
ResultRelInfos.  I think it would be a good idea, but definitely 
something

for PG 11.


Agreed.  Here is a patch to skip the CheckValidResultRel checks for a 
target table if it's a foreign partition to perform tuple-routing for, 
as proposed by Robert.


I'll add this to the open items list for v10.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] postgres_fdw bug in 9.6

2017-09-05 Thread Etsuro Fujita

On 2017/09/05 13:43, Ryan Murphy wrote:

The following review has been posted through the commitfest application:
make installcheck-world:  tested, passed
Implements feature:   not tested
Spec compliant:   not tested
Documentation:not tested

This feature is obviously a pretty deep cut, and I don't understand the JOIN 
system enough to comment on whether the code is correct.  I did not see any 
issues when glancing through the patch.


Thank you for the review!


I ran "make check", "make installcheck" and "make installcheck-world" and had ALMOST no 
problems:  I marked it Tested and Passed because the only issue I had was a recurring issue I've had with "make 
installcheck-world" which I think is unrelated:

*** path/to/postgres/src/interfaces/ecpg/test/expected/connect-test5.stderr 
2017-02-14 09:22:25.0 -0600
--- path/to/postgres/src/interfaces/ecpg/test/results/connect-test5.stderr  
2017-09-04 23:31:50.0 -0500
***
*** 36,42 
   [NO_PID]: sqlca: code: 0, state: 0
   [NO_PID]: ECPGconnect: opening database  on  port 
  for user regress_ecpg_user2
   [NO_PID]: sqlca: code: 0, state: 0
! [NO_PID]: ECPGconnect: could not open database: FATAL:  database 
"regress_ecpg_user2" does not exist
...


I tested that with HEAD, but couldn't reproduce this problem.  Didn't 
you test that with HEAD?



But this still Needs Review by someone who knows the JOIN system better.


I think Tom is reviewing this patch [1].

Best regards,
Etsuro Fujita

[1] https://www.postgresql.org/message-id/22168.1504041271%40sss.pgh.pa.us



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] Copyright in partition.h and partition.c

2017-09-05 Thread Etsuro Fujita

Here is the copyright in partition.h:

 * Copyright (c) 2007-2017, PostgreSQL Global Development Group

I think it's reasonable that that matches the copyright in partition.c, 
but partition.c has:


 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California

Is that intentional?

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Partition-wise join for join between (declaratively) partitioned tables

2017-09-05 Thread Etsuro Fujita

On 2017/09/05 13:20, Amit Langote wrote:

On 2017/09/04 21:32, Ashutosh Bapat wrote:



+1. Will Fujita-san's patch also handle getting rid of partitioned_rels list?


As Fujita-san mentioned, his patch won't.  Actually, I suppose he didn't
say that partitioned_rels itself is useless, just that its particular
usage in ExecInitModifyTable is.


That's right.  (I thought there would probably be no need to create that 
list if we created AppendRelInfos even for partitioned partitions.)



We still need that list for planner to
tell the executor that there are some RT entries the latter would need to
lock before executing a given plan.  Without that dedicated list, the
executor cannot know at all that certain tables in the partition tree
(viz. the partitioned ones) need to be locked.  I mentioned the reason -
(Merge)Append.subplans, ModifyTable.resultRelations does not contain
respective entries corresponding to the partitioned tables, and
traditionally, the executor looks at those lists to figure out the tables
to lock.


I think so too.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Partition-wise join for join between (declaratively) partitioned tables

2017-09-04 Thread Etsuro Fujita

On 2017/09/04 21:32, Ashutosh Bapat wrote:

On Mon, Sep 4, 2017 at 10:04 AM, Amit Langote

By the way, if you want to get rid of PartitionedChildRelInfo, you can do
that as long as you find some other way of putting together the
partitioned_rels list to add into the ModifyTable (Append/MergeAppend)
node created for the root partitioned table.  Currently,
PartitionedChildRelInfo (and the root->pcinfo_list) is the way for
expand_inherited_rtentry() to pass that information to the planner's
path-generating code.  We may be able to generate that list when actually
creating the path using set_append_rel_pathlist() or
inheritance_planner(), without having created a PartitionedChildRelInfo
node beforehand.


AFAIU, the list contained RTIs of the relations, which didnt' have
corresponding AppendRelInfos to lock those relations. Now that we
create AppendRelInfos even for partitioned partitions, I don't think
we need the list to take care of the locks.
I don't think so either.  (Since I haven't followed discussions on this 
thread in detail yet, I don't understand the idea/need of creating 
AppendRelInfos for partitioned partitions, though.)



Though I haven't read the patch yet, I think the above code is useless.
And I proposed a patch to clean it up before [1].  I'll add that patch to
the next commitfest.


+1.

+1. Will Fujita-san's patch also handle getting rid of partitioned_rels list?


No.  The patch just removes the partitioned_rels list from 
nodeModifyTable.c.


Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Useless code in ExecInitModifyTable

2017-09-04 Thread Etsuro Fujita

On 2017/06/21 17:57, Amit Langote wrote:

On 2017/06/21 16:59, Etsuro Fujita wrote:

Commit d3cc37f1d801a6b5cad9bf179274a8d767f1ee50 added this to
ExecInitModifyTable:

+   /* The root table RT index is at the head of the partitioned_rels list */
+   if (node->partitioned_rels)
+   {
+   Index   root_rti;
+   Oid root_oid;
+
+   root_rti = linitial_int(node->partitioned_rels);
+   root_oid = getrelid(root_rti, estate->es_range_table);
+   rel = heap_open(root_oid, NoLock);  /* locked by InitPlan */
+   }

but I noticed that that function doesn't use the relation descriptor at
all.  Since partitioned_rels is given in case of an UPDATE/DELETE on a
partitioned table, the relation is opened in that case, but the relation
descriptor isn't referenced at all in initializing WITH CHECK OPTION
constraints and/or RETURNING projections.  (The mtstate->resultRelinfo
array is referenced in those initialization, instead.)  So, I'd like to
propose to remove this from that function.  Attached is a patch for that.


Thanks for cleaning that up.  I cannot see any problem in applying the patch.


I noticed that the patch needs to be rebased.  Updated patch attached.

Thanks for the review!

Best regards,
Etsuro Fujita
*** a/src/backend/executor/nodeModifyTable.c
--- b/src/backend/executor/nodeModifyTable.c
***
*** 45,51 
  #include "foreign/fdwapi.h"
  #include "miscadmin.h"
  #include "nodes/nodeFuncs.h"
- #include "parser/parsetree.h"
  #include "storage/bufmgr.h"
  #include "storage/lmgr.h"
  #include "utils/builtins.h"
--- 45,50 
***
*** 1894,1913  ExecInitModifyTable(ModifyTable *node, EState *estate, int 
eflags)
  
estate->es_result_relation_info = saved_resultRelInfo;
  
-   /* The root table RT index is at the head of the partitioned_rels list 
*/
-   if (node->partitioned_rels)
-   {
-   Index   root_rti;
-   Oid root_oid;
- 
-   root_rti = linitial_int(node->partitioned_rels);
-   root_oid = getrelid(root_rti, estate->es_range_table);
-   rel = heap_open(root_oid, NoLock);  /* locked by InitPlan */
-   }
-   else
-   rel = mtstate->resultRelInfo->ri_RelationDesc;
- 
/* Build state for INSERT tuple routing */
if (operation == CMD_INSERT &&
rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
--- 1893,1900 
  
estate->es_result_relation_info = saved_resultRelInfo;
  
/* Build state for INSERT tuple routing */
+   rel = mtstate->resultRelInfo->ri_RelationDesc;
if (operation == CMD_INSERT &&
rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
***
*** 2091,2100  ExecInitModifyTable(ModifyTable *node, EState *estate, int 
eflags)
mtstate->ps.ps_ExprContext = NULL;
}
  
-   /* Close the root partitioned rel if we opened it above. */
-   if (rel != mtstate->resultRelInfo->ri_RelationDesc)
-   heap_close(rel, NoLock);
- 
/*
 * If needed, Initialize target list, projection and qual for ON 
CONFLICT
 * DO UPDATE.
--- 2078,2083 

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Partition-wise join for join between (declaratively) partitioned tables

2017-09-03 Thread Etsuro Fujita

On 2017/09/02 4:10, Ashutosh Bapat wrote:

This rebase mainly changes patch 0001, which translates partition
hierarchy into inheritance hierarchy creating AppendRelInfos and
RelOptInfos for partitioned partitions. Because of that, it's not
necessary to record the partitioned partitions in a
PartitionedChildRelInfos::child_rels. The only RTI that goes in there
is the RTI of child RTE which is same as the parent RTE except inh
flag. I tried removing that with a series of changes but it seems that
following code in ExecInitModifyTable() requires it.
1897 /* The root table RT index is at the head of the
partitioned_rels list */
1898 if (node->partitioned_rels)
1899 {
1900 Index   root_rti;
1901 Oid root_oid;
1902
1903 root_rti = linitial_int(node->partitioned_rels);
1904 root_oid = getrelid(root_rti, estate->es_range_table);
1905 rel = heap_open(root_oid, NoLock);  /* locked by InitPlan */
1906 }
1907 else
1908 rel = mtstate->resultRelInfo->ri_RelationDesc;

I don't know whether we could change this code not to use
PartitionedChildRelInfos::child_rels.
Though I haven't read the patch yet, I think the above code is useless. 
And I proposed a patch to clean it up before [1].  I'll add that patch 
to the next commitfest.


Best regards,
Etsuro Fujita

[1] 
https://www.postgresql.org/message-id/93cf9816-2f7d-0f67-8ed2-4a4e497a6ab8%40lab.ntt.co.jp




--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Minor code improvement to postgresGetForeignPlan

2017-09-01 Thread Etsuro Fujita
On 2017/04/07 13:12, Tatsuro Yamada wrote:> The declaration of  
postgresGetForeignPlan uses baserel, but

the actual definition uses foreignrel. It would be better to sync.


Agreed.


Please find attached a patch.


The patch looks good to me, so I'll mark this as Ready for Committer.

(I'm not sure we should do the same thing to the function declaration in  
other places such as fdwapi.h and the documentation for consistency, but  
if so, I'd vote for leaving that for another patch.)


Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Update comment in ExecPartitionCheck

2017-09-01 Thread Etsuro Fujita

On 2017/08/26 2:28, Robert Haas wrote:

On Tue, Jul 4, 2017 at 4:55 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

This comment in an error handling in ExecPartitionCheck():

 if (!ExecCheck(resultRelInfo->ri_PartitionCheckExpr, econtext))
 {
 char   *val_desc;
 Relationorig_rel = rel;

 /* See the comment above. */
 if (resultRelInfo->ri_PartitionRoot)

should be updated because we don't have any comment on that above in the
code.  Since we have a comment on that in ExecConstraints() defined just
below that function, I think the comment should be something like this: "See
the comment in ExecConstraints().".  Attached is a patch for that.


Hrm.  I'm not sure I understand which comment in ExecConstraints()
this is supposed to refer to.  Maybe we need to think a bit harder
about how to make this clear.


The comment in ExecConstraints is this:

/*
 * If the tuple has been routed, it's been converted to the
 * partition's rowtype, which might differ from the root
 * table's.  We must convert it back to the root table's
 * rowtype so that val_desc shown error message matches the
 * input tuple.
 */
if (resultRelInfo->ri_PartitionRoot)

How about replacing the comment "See the comment above." in 
ExecPartitionCheck with something like this: "If the tuple has been 
routed, convert it from the partition's rowtype to the root table's. See 
the comment in ExecConstraints().".  I think that would make it easy to 
specify that comment in ExecConstrains.  I'd like to propose to update 
the same comments in other places as well, just for consistency.


PFA an updated version of the patch.

Best regards,
Etsuro Fujita
*** a/src/backend/executor/execMain.c
--- b/src/backend/executor/execMain.c
***
*** 1884,1890  ExecPartitionCheck(ResultRelInfo *resultRelInfo, 
TupleTableSlot *slot,
char   *val_desc;
Relationorig_rel = rel;
  
!   /* See the comment above. */
if (resultRelInfo->ri_PartitionRoot)
{
HeapTuple   tuple = ExecFetchSlotTuple(slot);
--- 1884,1893 
char   *val_desc;
Relationorig_rel = rel;
  
!   /*
!* If the tuple has been routed, convert it from the partition's
!* rowtype to the root table's.  See the comment in 
ExecConstraints().
!*/
if (resultRelInfo->ri_PartitionRoot)
{
HeapTuple   tuple = ExecFetchSlotTuple(slot);
***
*** 2011,2017  ExecConstraints(ResultRelInfo *resultRelInfo,
char   *val_desc;
Relationorig_rel = rel;
  
!   /* See the comment above. */
if (resultRelInfo->ri_PartitionRoot)
{
HeapTuple   tuple = 
ExecFetchSlotTuple(slot);
--- 2014,2023 
char   *val_desc;
Relationorig_rel = rel;
  
!   /*
!* If the tuple has been routed, convert it from the 
partition's
!* rowtype to the root table's.  See the comment above.
!*/
if (resultRelInfo->ri_PartitionRoot)
{
HeapTuple   tuple = 
ExecFetchSlotTuple(slot);
***
*** 2121,2127  ExecWithCheckOptions(WCOKind kind, ResultRelInfo 
*resultRelInfo,
 * USING policy.
 */
case WCO_VIEW_CHECK:
!   /* See the comment in 
ExecConstraints(). */
if (resultRelInfo->ri_PartitionRoot)
{
HeapTuple   tuple = 
ExecFetchSlotTuple(slot);
--- 2127,2137 
 * USING policy.
 */
case WCO_VIEW_CHECK:
!   /*
!* If the tuple has been routed, 
convert it from the
!* partition's rowtype to the root 
table's.  See the
!* comment in ExecConstraints().
!*/
if (resultRelInfo->ri_PartitionRoot)
{
HeapTuple  

Re: [HACKERS] Add support for tuple routing to foreign partitions

2017-09-01 Thread Etsuro Fujita

On 2017/08/26 1:43, Robert Haas wrote:

On Sun, Aug 20, 2017 at 11:25 PM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

I agree, but I wonder if we ought to make it work first using the
existing APIs and then add these new APIs as an optimization.


I'm not sure that's a good idea because that once we support INSERT
tuple-routing for foreign partitions, we would have a workaround: INSERT
INTO partitioned_table SELECT * from data_table where data_table is a
foreign table defined for an input file using file_fdw.


That's true, but I don't see how it refutes the point I was trying to raise.


My concern is: the existing APIs can really work well for any FDW to do 
COPY tuple-routing?  I know the original version of the patch showed the 
existing APIs would work well for postgres_fdw but nothing beyond.  For 
example: the original version made a dummy Query/Plan only containing a 
leaf partition as its result relation, and passed it to 
PlanForeignModify, IIRC.  That would work well for postgres_fdw because 
it doesn't look at the Query/Plan except the result relation, but might 
not for other FDWs that look at more stuff of the given Query/Plan and 
do something based on that information.  Some FDW might check to see 
whether the Plan is to do INSERT .. VALUES with a single VALUES sublist 
or INSERT .. VALUES with multiple VALUES sublists, for optimizing remote 
INSERT, for example.


Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Tuple-routing for certain partitioned tables not working as expected

2017-08-30 Thread Etsuro Fujita

On 2017/08/30 9:13, Amit Langote wrote:

On 2017/08/29 20:18, Etsuro Fujita wrote:

On 2017/08/25 22:26, Robert Haas wrote:

On Wed, Aug 23, 2017 at 4:55 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

Agreed, but I'd vote for fixing this in v10 as proposed; I agree that just
ripping the CheckValidResultRel checks out entirely is not a good idea,
but
that seems OK to me at least as a fix just for v10.


I'm still not on-board with having this be the one case where we don't
do CheckValidResultRel.  If we want to still call it but pass down
some additional information that can selectively skip certain checks,
I could probably live with that.


Another idea would be to not do CheckValidResultRel for partitions in
ExecSetupPartitionTupleRouting; instead, do that the first time the
partition is chosen by ExecFindPartition, and if successfully checked,
initialize the partition's ResultRelInfo and other stuff.  (We could skip
this after the first time by checking whether we already have a valid
ResultRelInfo for the chosen partition.)  That could allow us to not only
call CheckValidResultRel the way it is, but avoid initializing useless
partitions for which tuples aren't routed at all.


I too have thought about the idea of lazy initialization of the partition
ResultRelInfos.  I think it would be a good idea, but definitely something
for PG 11.


Agreed.  Here is a patch to skip the CheckValidResultRel checks for a 
target table if it's a foreign partition to perform tuple-routing for, 
as proposed by Robert.


Best regards,
Etsuro Fujita
*** /dev/null
--- b/contrib/file_fdw/data/list1.csv
***
*** 0 
--- 1,2 
+ 1,foo
+ 1,bar
*** /dev/null
--- b/contrib/file_fdw/data/list2.bad
***
*** 0 
--- 1,2 
+ 2,baz
+ 1,qux
*** /dev/null
--- b/contrib/file_fdw/data/list2.csv
***
*** 0 
--- 1,2 
+ 2,baz
+ 2,qux
*** a/contrib/file_fdw/input/file_fdw.source
--- b/contrib/file_fdw/input/file_fdw.source
***
*** 162,167  SELECT tableoid::regclass, * FROM agg FOR UPDATE;
--- 162,188 
  ALTER FOREIGN TABLE agg_csv NO INHERIT agg;
  DROP TABLE agg;
  
+ -- declarative partitioning tests
+ SET ROLE regress_file_fdw_superuser;
+ CREATE TABLE pt (a int, b text) partition by list (a);
+ CREATE FOREIGN TABLE p1 partition of pt for values in (1) SERVER file_server
+ OPTIONS (format 'csv', filename '@abs_srcdir@/data/list1.csv', delimiter ',');
+ CREATE TABLE p2 partition of pt for values in (2);
+ SELECT tableoid::regclass, * FROM pt;
+ SELECT tableoid::regclass, * FROM p1;
+ SELECT tableoid::regclass, * FROM p2;
+ COPY pt FROM '@abs_srcdir@/data/list2.bad' with (format 'csv', delimiter 
','); -- ERROR
+ COPY pt FROM '@abs_srcdir@/data/list2.csv' with (format 'csv', delimiter ',');
+ SELECT tableoid::regclass, * FROM pt;
+ SELECT tableoid::regclass, * FROM p1;
+ SELECT tableoid::regclass, * FROM p2;
+ INSERT INTO pt VALUES (1, 'xyzzy'); -- ERROR
+ INSERT INTO pt VALUES (2, 'xyzzy');
+ SELECT tableoid::regclass, * FROM pt;
+ SELECT tableoid::regclass, * FROM p1;
+ SELECT tableoid::regclass, * FROM p2;
+ DROP TABLE pt;
+ 
  -- privilege tests
  SET ROLE regress_file_fdw_superuser;
  SELECT * FROM agg_text ORDER BY a;
*** a/contrib/file_fdw/output/file_fdw.source
--- b/contrib/file_fdw/output/file_fdw.source
***
*** 289,294  SELECT tableoid::regclass, * FROM agg FOR UPDATE;
--- 289,375 
  
  ALTER FOREIGN TABLE agg_csv NO INHERIT agg;
  DROP TABLE agg;
+ -- declarative partitioning tests
+ SET ROLE regress_file_fdw_superuser;
+ CREATE TABLE pt (a int, b text) partition by list (a);
+ CREATE FOREIGN TABLE p1 partition of pt for values in (1) SERVER file_server
+ OPTIONS (format 'csv', filename '@abs_srcdir@/data/list1.csv', delimiter ',');
+ CREATE TABLE p2 partition of pt for values in (2);
+ SELECT tableoid::regclass, * FROM pt;
+  tableoid | a |  b  
+ --+---+-
+  p1   | 1 | foo
+  p1   | 1 | bar
+ (2 rows)
+ 
+ SELECT tableoid::regclass, * FROM p1;
+  tableoid | a |  b  
+ --+---+-
+  p1   | 1 | foo
+  p1   | 1 | bar
+ (2 rows)
+ 
+ SELECT tableoid::regclass, * FROM p2;
+  tableoid | a | b 
+ --+---+---
+ (0 rows)
+ 
+ COPY pt FROM '@abs_srcdir@/data/list2.bad' with (format 'csv', delimiter 
','); -- ERROR
+ ERROR:  cannot route inserted tuples to a foreign table
+ CONTEXT:  COPY pt, line 2: "1,qux"
+ COPY pt FROM '@abs_srcdir@/data/list2.csv' with (format 'csv', delimiter ',');
+ SELECT tableoid::regclass, * FROM pt;
+  tableoid | a |  b  
+ --+---+-
+  p1   | 1 | foo
+  p1   | 1 | bar
+  p2   | 2 | baz
+  p2   | 2 | qux
+ (4 rows)
+ 
+ SELECT tableoid::regclass, * FROM p1;
+  tableoid | a |  b  
+ --+---+-
+  p1   | 1 | foo
+  p1   | 1 | bar
+ (2 rows)
+ 
+ SELECT tableoid::regclass, * FROM p2;
+  tableoid | a |  b  
+ --+---+-
+  p2   | 2 | baz
+  p2   | 2 | qux
+ (2 rows)
+ 
+ INSERT INTO pt V

Re: [HACKERS] Tuple-routing for certain partitioned tables not working as expected

2017-08-29 Thread Etsuro Fujita

On 2017/08/25 22:26, Robert Haas wrote:

On Wed, Aug 23, 2017 at 4:55 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

Agreed, but I'd vote for fixing this in v10 as proposed; I agree that just
ripping the CheckValidResultRel checks out entirely is not a good idea, but
that seems OK to me at least as a fix just for v10.


I'm still not on-board with having this be the one case where we don't
do CheckValidResultRel.  If we want to still call it but pass down
some additional information that can selectively skip certain checks,
I could probably live with that.


Another idea would be to not do CheckValidResultRel for partitions in 
ExecSetupPartitionTupleRouting; instead, do that the first time the 
partition is chosen by ExecFindPartition, and if successfully checked, 
initialize the partition's ResultRelInfo and other stuff.  (We could 
skip this after the first time by checking whether we already have a 
valid ResultRelInfo for the chosen partition.)  That could allow us to 
not only call CheckValidResultRel the way it is, but avoid initializing 
useless partitions for which tuples aren't routed at all.



At some point we've got to stop developing v10 and just let it be what it is.


I agree on that point, but ISTM that this is more like a bug.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] postgres_fdw bug in 9.6

2017-08-29 Thread Etsuro Fujita

On 2017/08/21 20:37, Etsuro Fujita wrote:

Attached is an updated version of the patch.


I corrected some comments.  New version attached.

Best regards,
Etsuro Fujita
*** a/contrib/postgres_fdw/expected/postgres_fdw.out
--- b/contrib/postgres_fdw/expected/postgres_fdw.out
***
*** 1701,1722  SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = 
t2.c1) ORDER BY t1.c3, t
 Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
 Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
 Remote SQL: SELECT r1."C 1", r1.c3, CASE WHEN (r1.*)::text IS 
NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) 
END, r2."C 1", CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, 
r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN 
"S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1" ORDER BY r1.c3 ASC NULLS LAST, 
r1."C 1" ASC NULLS LAST FOR UPDATE OF r1
!->  Merge Join
   Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!  Merge Cond: (t1.c1 = t2.c1)
!  ->  Sort
 Output: t1.c1, t1.c3, t1.*
!Sort Key: t1.c1
!->  Foreign Scan on public.ft1 t1
!  Output: t1.c1, t1.c3, t1.*
!  Remote SQL: SELECT "C 1", c2, c3, c4, c5, 
c6, c7, c8 FROM "S 1"."T 1" FOR UPDATE
!  ->  Sort
 Output: t2.c1, t2.*
!Sort Key: t2.c1
!->  Foreign Scan on public.ft2 t2
!  Output: t2.c1, t2.*
!  Remote SQL: SELECT "C 1", c2, c3, c4, c5, 
c6, c7, c8 FROM "S 1"."T 1"
! (23 rows)
  
  SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY 
t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR UPDATE OF t1;
   c1  | c1  
--- 1701,1716 
 Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
 Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
 Remote SQL: SELECT r1."C 1", r1.c3, CASE WHEN (r1.*)::text IS 
NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) 
END, r2."C 1", CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, 
r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN 
"S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1" ORDER BY r1.c3 ASC NULLS LAST, 
r1."C 1" ASC NULLS LAST FOR UPDATE OF r1
!->  Nested Loop
   Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!  Join Filter: (t1.c1 = t2.c1)
!  ->  Foreign Scan on public.ft1 t1
 Output: t1.c1, t1.c3, t1.*
!Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, 
c8 FROM "S 1"."T 1" FOR UPDATE
!  ->  Foreign Scan on public.ft2 t2
 Output: t2.c1, t2.*
!Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, 
c8 FROM "S 1"."T 1"
! (17 rows)
  
  SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY 
t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR UPDATE OF t1;
   c1  | c1  
***
*** 1745,1766  SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = 
t2.c1) ORDER BY t1.c3, t
 Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
 Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
 Remote SQL: SELECT r1."C 1", r1.c3, CASE WHEN (r1.*)::text IS 
NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) 
END, r2."C 1", CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, 
r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN 
"S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1" ORDER BY r1.c3 ASC NULLS LAST, 
r1."C 1" ASC NULLS LAST FOR UPDATE OF r1 FOR UPDATE OF r2
!->  Merge Join
   Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!  Merge Cond: (t1.c1 = t2.c1)
!  ->  Sort
 Output: t1.c1, t1.c3, t1.*
!Sort Key: t1.c1
!->  Foreign Scan on public.ft1 t1
!  Output: t1.c1, t1.c3, t1.*
!  Remote SQL: SELECT "C 1", c2, c3, c4, c5, 
c6, c7, c8 FROM "S 1&quo

Re: [HACKERS] Tuple-routing for certain partitioned tables not working as expected

2017-08-23 Thread Etsuro Fujita

On 2017/08/22 9:55, Amit Langote wrote:

On 2017/08/22 1:08, Robert Haas wrote:

On Mon, Aug 21, 2017 at 7:45 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

If there are no objections, I'll add this to the open item list for v10.


This seems fairly ad-hoc to me.  I mean, now you have
CheckValidResultRel not being called in just this one case -- but that
bypasses all the checks that function might do, not just this one.  It
so happens that's OK at the moment because CheckCmdReplicaIdentity()
doesn't do anything in the insert case.

I'm somewhat inclined to just view this as a limitation of v10 and fix
it in v11.


That limitation seems too restrictive to me.


If you want to fix it in v10, I think we need a different
approach -- just ripping the CheckValidResultRel checks out entirely
doesn't seem like a good idea to me.


Before 389af951552f, the relkind check that is now performed by
CheckValidResultRel(), used to be done in InitResultRelInfo().  ISTM, it
was separated out so that certain ResultRelInfos could be initialized
without the explicit relkind check, either because it's taken care of
elsewhere or the table in question is *known* to be a valid result
relation.  Maybe, mostly just the former of the two reasons when that
commit went in.

IMO, the latter case applies when initializing ResultRelInfos for
partitions during tuple-routing, because the table types we allow to
become partitions are fairly restricted.


Agreed.


Also, it seems okay to show the error messages that CheckValidResultRel()
shows when the concerned table is *directly* addressed in a query, but the
same error does not seem so user-friendly when emitted for one of the
partitions while tuple-routing is being set up.  IMHO, there should be
"tuple routing" somewhere in the error message shown in that case, even if
it's for the total lack of support for inserts by a FDW.


Agreed, but I'd vote for fixing this in v10 as proposed; I agree that 
just ripping the CheckValidResultRel checks out entirely is not a good 
idea, but that seems OK to me at least as a fix just for v10.


Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Tuple-routing for certain partitioned tables not working as expected

2017-08-21 Thread Etsuro Fujita

On 2017/08/07 15:45, Etsuro Fujita wrote:

On 2017/08/07 15:33, Amit Langote wrote:

On 2017/08/07 15:22, Etsuro Fujita wrote:

On 2017/08/07 13:11, Amit Langote wrote:> The patch looks good too.
Although, looking at the following hunk:


+ Assert(partrel->rd_rel->relkind == RELKIND_RELATION ||
+    partrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE);
+
    /*
 * Verify result relation is a valid target for the current
operation.
 */
! if (partrel->rd_rel->relkind == RELKIND_RELATION)
! CheckValidResultRel(partrel, CMD_INSERT);

makes me now wonder if we need the CheckValidResultRel check at 
all.  The

only check currently in place for RELKIND_RELATION is
CheckCmdReplicaIdentity(), which is a noop (returns true) for inserts
anyway.


Good point!  I left the verification for a plain table because that is
harmless but as you mentioned, that is nothing but an overhead.  So, 
here

is a new version which removes the verification at all from
ExecSetupPartitionTupleRouting.


The updated patch looks good to me, thanks.


Thanks for the review!


If there are no objections, I'll add this to the open item list for v10.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] postgres_fdw bug in 9.6

2017-08-21 Thread Etsuro Fujita

On 2017/04/08 4:24, Robert Haas wrote:

Looking at the code itself, I find the changes to joinpath.c rather alarming.


I missed this mail.  Sorry about that, Robert.


+/* Save hashclauses for possible use by the FDW */
+if (extra->consider_foreignjoin && hashclauses)
+extra->hashclauses = hashclauses;

A minor consideration is that this is fairly far away from where
hashclauses actually gets populated, so if someone later added an
early "return" statement to this function -- after creating some paths
-- it could subtly break join pushdown.  But I also think there's no
real need for this.  The loop that extracts hash clauses is simple
enough that we could just refactor it into a separate function, or if
necessary duplicate the logic.


I refactored that into a new function so that we can call that function 
at the top of add_paths_to_joinrel and store the result in 
JoinPathExtraData.



+/* Save first mergejoin data for possible use by the FDW */
+if (extra->consider_foreignjoin && outerkeys == all_pathkeys)
+{
+extra->mergeclauses = cur_mergeclauses;
+extra->outersortkeys = outerkeys;
+extra->innersortkeys = innerkeys;
+}

Similarly here.  select_outer_pathkeys_for_merge(),
find_mergeclauses_for_pathkeys(), and make_inner_pathkeys_for_merge()
are all extern, so there's nothing to keep CreateLocalJoinPath() from
just doing that work itself instead of getting help from joinpath,
which I guess seems better to me.  I think it's just better if we
don't burden joinpath.c with keeping little bits of data around that
CreateLocalJoinPath() can easily get for itself.


Done that way.


There appears to be no regression test covering the case where we get
a Merge Full Join with a non-empty list of mergeclauses.  Hash Full
Join is tested, as is Merge Full Join without merge clauses, but
there's no test for Merge Full Join with mergeclauses, and since that
is a separate code path it seems like it should be tested.


Done.


-/*
- * If either inner or outer path is a ForeignPath corresponding to a
- * pushed down join, replace it with the fdw_outerpath, so that we
- * maintain path for EPQ checks built entirely of local join
- * strategies.
- */
-if (IsA(joinpath->outerjoinpath, ForeignPath))
-{
-ForeignPath *foreign_path;
-
-foreign_path = (ForeignPath *) joinpath->outerjoinpath;
-if (IS_JOIN_REL(foreign_path->path.parent))
-joinpath->outerjoinpath = foreign_path->fdw_outerpath;
-}
-
-if (IsA(joinpath->innerjoinpath, ForeignPath))
-{
-ForeignPath *foreign_path;
-
-foreign_path = (ForeignPath *) joinpath->innerjoinpath;
-if (IS_JOIN_REL(foreign_path->path.parent))
-joinpath->innerjoinpath = foreign_path->fdw_outerpath;
-}

This logic is removed and not replaced with anything, but I don't see
what keeps this code...

+Path   *outer_path = outerrel->cheapest_total_path;
+Path   *inner_path = innerrel->cheapest_total_path;

...from picking a ForeignPath?


CreateLocalJoinPath creates an alternative local join path for a foreign 
join from the cheapest total paths for the outer/inner relations.  The 
reason for the above is to pass these paths to that function.  On second 
thought, however, I think it would be convenient for the caller to just 
pass outerrel/innerrel to that function.  So, I modified that function's 
API as such.  Another change is: the previous version of that function 
allowed the caller to create a parameterized local-join path 
corresponding to a parameterized foreign join, but that is a feature, 
not a bug fix, so I dropped that.  (I'll propose that as part of the 
patch in [1].)



There's probably more to think about here, but those are my question
on an initial read-through.


Thanks for the review!

Attached is an updated version of the patch.

Best regards,
Etsuro Fujita

[1] https://commitfest.postgresql.org/14/1042/
*** a/contrib/postgres_fdw/expected/postgres_fdw.out
--- b/contrib/postgres_fdw/expected/postgres_fdw.out
***
*** 1701,1722  SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = 
t2.c1) ORDER BY t1.c3, t
 Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
 Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
 Remote SQL: SELECT r1."C 1", r1.c3, CASE WHEN (r1.*)::text IS 
NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) 
END, r2."C 1", CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, 
r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN 
"S 1"."T 1" r2 ON (((r1."C 1" = r2."

[HACKERS] Re: Stats for triggers on partitioned tables not shown in EXPLAIN ANALYZE

2017-08-20 Thread Etsuro Fujita

On 2017/08/21 9:18, Amit Langote wrote:

On 2017/08/19 2:09, Robert Haas wrote:

On Fri, Aug 18, 2017 at 1:15 AM, Noah Misch <n...@leadboat.com> wrote:

The above-described topic is currently a PostgreSQL 10 open item.  Robert,
since you committed the patch believed to have created it, you own this open
item.  If some other commit is more relevant or if this does not belong as a
v10 open item, please let us know.  Otherwise, please observe the policy on
open item ownership[1] and send a status update within three calendar days of
this message.  Include a date for your subsequent status update.  Testers may
discover new open items at any time, and I want to plan to get them all fixed
well in advance of shipping v10.  Consequently, I will appreciate your efforts
toward speedy resolution.  Thanks.

[1] 
https://www.postgresql.org/message-id/20170404140717.GA2675809%40tornado.leadboat.com


Committed and back-patched the proposed patch.


Thanks.


Thank you!

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Add support for tuple routing to foreign partitions

2017-08-20 Thread Etsuro Fujita

On 2017/08/19 2:12, Robert Haas wrote:

On Thu, Aug 17, 2017 at 4:27 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

I think that would be much more efficient than INSERTing tuples into the
remote server one by one.  What do you think about that?


I agree, but I wonder if we ought to make it work first using the
existing APIs and then add these new APIs as an optimization.


I'm not sure that's a good idea because that once we support INSERT 
tuple-routing for foreign partitions, we would have a workaround: INSERT 
INTO partitioned_table SELECT * from data_table where data_table is a 
foreign table defined for an input file using file_fdw.



postgres_fdw isn't the only FDW in the world, and it's better if
getting a working implementation doesn't require too many interfaces.


Agreed.  My vote would be to leave the COPY part as-is until we have 
these new APIs.


Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Add support for tuple routing to foreign partitions

2017-08-20 Thread Etsuro Fujita

On 2017/08/18 22:41, David Fetter wrote:

On Fri, Aug 18, 2017 at 05:10:29PM +0900, Etsuro Fujita wrote:

On 2017/08/17 23:48, David Fetter wrote:

On Thu, Aug 17, 2017 at 05:27:05PM +0900, Etsuro Fujita wrote:

On 2017/07/11 6:56, Robert Haas wrote:

On Thu, Jun 29, 2017 at 6:20 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

So, I dropped the COPY part.


Ouch.  I think we should try to figure out how the COPY part will be
handled before we commit to a design.


I spent some time on this.  To handle that, I'd like to propose doing
something similar to \copy (frontend copy): submit a COPY query "COPY ...

>FROM STDIN" to the remote server and route data from a file to the remote

server.  For that, I'd like to add new FDW APIs called during CopyFrom that
allow us to copy to foreign tables:

* BeginForeignCopyIn: this would be called after creating a ResultRelInfo
for the target table (or each leaf partition of the target partitioned
table) if it's a foreign table, and perform any initialization needed before
the remote copy can start.  In the postgres_fdw case, I think this function
would be a good place to send "COPY ... FROM STDIN" to the remote server.

* ExecForeignCopyInOneRow: this would be called instead of heap_insert if
the target is a foreign table, and route the tuple read from the file by
NextCopyFrom to the remote server.  In the postgres_fdw case, I think this
function would convert the tuple to text format for portability, and then
send the data to the remote server using PQputCopyData.

* EndForeignCopyIn: this would be called at the bottom of CopyFrom, and
release resources such as connections to the remote server.  In the
postgres_fdw case, this function would do PQputCopyEnd to terminate data
transfer.


These primitives look good.  I know it seems unlikely at first
blush, but do we know of bulk load APIs for non-PostgreSQL data
stores that this would be unable to serve?


Maybe I'm missing something, but I think these would allow the FDW
to do the remote copy the way it would like; in
ExecForeignCopyInOneRow, for example, the FDW could buffer tuples in
a buffer memory and transmit the buffered data to the remote server
if the data size exceeds a threshold.  The naming is not so good?
Suggestions are welcome.


The naming seems reasonable.

I was trying to figure out whether this fits well enough with the bulk
load APIs for databases other than PostgreSQL.  I'm guessing it's
"well enough" based on checking MySQL, Oracle, and MS SQL Server.


Good to know.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Add support for tuple routing to foreign partitions

2017-08-18 Thread Etsuro Fujita

On 2017/08/17 23:48, David Fetter wrote:

On Thu, Aug 17, 2017 at 05:27:05PM +0900, Etsuro Fujita wrote:

On 2017/07/11 6:56, Robert Haas wrote:

On Thu, Jun 29, 2017 at 6:20 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

So, I dropped the COPY part.


Ouch.  I think we should try to figure out how the COPY part will be
handled before we commit to a design.


I spent some time on this.  To handle that, I'd like to propose doing
something similar to \copy (frontend copy): submit a COPY query "COPY ...
FROM STDIN" to the remote server and route data from a file to the remote
server.  For that, I'd like to add new FDW APIs called during CopyFrom that
allow us to copy to foreign tables:

* BeginForeignCopyIn: this would be called after creating a ResultRelInfo
for the target table (or each leaf partition of the target partitioned
table) if it's a foreign table, and perform any initialization needed before
the remote copy can start.  In the postgres_fdw case, I think this function
would be a good place to send "COPY ... FROM STDIN" to the remote server.

* ExecForeignCopyInOneRow: this would be called instead of heap_insert if
the target is a foreign table, and route the tuple read from the file by
NextCopyFrom to the remote server.  In the postgres_fdw case, I think this
function would convert the tuple to text format for portability, and then
send the data to the remote server using PQputCopyData.

* EndForeignCopyIn: this would be called at the bottom of CopyFrom, and
release resources such as connections to the remote server.  In the
postgres_fdw case, this function would do PQputCopyEnd to terminate data
transfer.


These primitives look good.  I know it seems unlikely at first blush,
but do we know of bulk load APIs for non-PostgreSQL data stores that
this would be unable to serve?


Maybe I'm missing something, but I think these would allow the FDW to do 
the remote copy the way it would like; in ExecForeignCopyInOneRow, for 
example, the FDW could buffer tuples in a buffer memory and transmit the 
buffered data to the remote server if the data size exceeds a threshold. 
 The naming is not so good?  Suggestions are welcome.


Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] postgres_fdw bug in 9.6

2017-08-17 Thread Etsuro Fujita

On 2017/08/18 8:16, Michael Paquier wrote:

On Fri, Aug 18, 2017 at 3:59 AM, Tom Lane <t...@sss.pgh.pa.us> wrote:

Robert Haas <robertmh...@gmail.com> writes:

On Thu, Aug 17, 2017 at 8:00 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

I rebased the patch to HEAD.  PFA a new version of the patch.



Tom, you were instrumental in identifying what was going wrong here
initially.  Any chance you'd be willing to have a look at the patch?


I will, but probably not for a week or so.  Going eclipse-chasing.


Good luck:
https://xkcd.com/1876/
And enjoy:
https://xkcd.com/1877/


Enjoy!

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Garbled comment in postgresGetForeignJoinPaths

2017-08-17 Thread Etsuro Fujita

On 2017/08/17 1:31, Tom Lane wrote:

postgres_fdw.c around line 4500:

 /*
  * If there is a possibility that EvalPlanQual will be executed, we need
  * to be able to reconstruct the row using scans of the base relations.
  * GetExistingLocalJoinPath will find a suitable path for this purpose in
  * the path list of the joinrel, if one exists.  We must be careful to
  * call it before adding any ForeignPath, since the ForeignPath might
  * dominate the only suitable local path available.  We also do it before
-->  * reconstruct the row for EvalPlanQual(). Find an alternative local path
  * calling foreign_join_ok(), since that function updates fpinfo and marks
  * it as pushable if the join is found to be pushable.
  */

Should the marked line simply be deleted?  If not, what correction is
appropriate?


In relation to this, I updated the patch for addressing the 
GetExistingLocalJoinPath issue [1].


Best regards,
Etsuro Fujita

[1] 
https://www.postgresql.org/message-id/6008ca34-906f-e61d-478b-8f85fde2c090%40lab.ntt.co.jp




--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] postgres_fdw bug in 9.6

2017-08-17 Thread Etsuro Fujita

On 2017/04/04 18:01, Etsuro Fujita wrote:
I rebased the patch also.  Please find attached an updated version of 
the patch.


I rebased the patch to HEAD.  PFA a new version of the patch.

Best regards,
Etsuro Fujita
*** a/contrib/postgres_fdw/expected/postgres_fdw.out
--- b/contrib/postgres_fdw/expected/postgres_fdw.out
***
*** 1701,1722  SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = 
t2.c1) ORDER BY t1.c3, t
 Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
 Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
 Remote SQL: SELECT r1."C 1", r1.c3, CASE WHEN (r1.*)::text IS 
NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) 
END, r2."C 1", CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, 
r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN 
"S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1" ORDER BY r1.c3 ASC NULLS LAST, 
r1."C 1" ASC NULLS LAST FOR UPDATE OF r1
!->  Merge Join
   Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!  Merge Cond: (t1.c1 = t2.c1)
!  ->  Sort
 Output: t1.c1, t1.c3, t1.*
!Sort Key: t1.c1
!->  Foreign Scan on public.ft1 t1
!  Output: t1.c1, t1.c3, t1.*
!  Remote SQL: SELECT "C 1", c2, c3, c4, c5, 
c6, c7, c8 FROM "S 1"."T 1" FOR UPDATE
!  ->  Sort
 Output: t2.c1, t2.*
!Sort Key: t2.c1
!->  Foreign Scan on public.ft2 t2
!  Output: t2.c1, t2.*
!  Remote SQL: SELECT "C 1", c2, c3, c4, c5, 
c6, c7, c8 FROM "S 1"."T 1"
! (23 rows)
  
  SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY 
t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR UPDATE OF t1;
   c1  | c1  
--- 1701,1716 
 Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
 Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
 Remote SQL: SELECT r1."C 1", r1.c3, CASE WHEN (r1.*)::text IS 
NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) 
END, r2."C 1", CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, 
r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN 
"S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1" ORDER BY r1.c3 ASC NULLS LAST, 
r1."C 1" ASC NULLS LAST FOR UPDATE OF r1
!->  Nested Loop
   Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!  Join Filter: (t1.c1 = t2.c1)
!  ->  Foreign Scan on public.ft1 t1
 Output: t1.c1, t1.c3, t1.*
!Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, 
c8 FROM "S 1"."T 1" FOR UPDATE
!  ->  Foreign Scan on public.ft2 t2
 Output: t2.c1, t2.*
!Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, 
c8 FROM "S 1"."T 1"
! (17 rows)
  
  SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY 
t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR UPDATE OF t1;
   c1  | c1  
***
*** 1745,1766  SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = 
t2.c1) ORDER BY t1.c3, t
 Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
 Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
 Remote SQL: SELECT r1."C 1", r1.c3, CASE WHEN (r1.*)::text IS 
NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) 
END, r2."C 1", CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, 
r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN 
"S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1" ORDER BY r1.c3 ASC NULLS LAST, 
r1."C 1" ASC NULLS LAST FOR UPDATE OF r1 FOR UPDATE OF r2
!->  Merge Join
   Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!  Merge Cond: (t1.c1 = t2.c1)
!  ->  Sort
 Output: t1.c1, t1.c3, t1.*
!Sort Key: t1.c1
!->  Foreign Scan on public.ft1 t1
!  Output: t1.c1, t1.c3, t1.*
!  Remote SQL: SELECT "C 1", c2

Re: [HACKERS] Add support for tuple routing to foreign partitions

2017-08-17 Thread Etsuro Fujita

On 2017/08/17 20:37, Ashutosh Bapat wrote:

On Thu, Aug 17, 2017 at 1:57 PM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

I spent some time on this.  To handle that, I'd like to propose doing
something similar to \copy (frontend copy): submit a COPY query "COPY ...
FROM STDIN" to the remote server and route data from a file to the remote
server.  For that, I'd like to add new FDW APIs called during CopyFrom that
allow us to copy to foreign tables:


The description seems to support only COPY to a foreign table from a
file, but probably we need the support other way round as well. This
looks like a feature (support copy to and from a foreign table) to be
handled by itself.


Agreed.  I'll consider how to handle copy-from-a-foreign-table as well.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Add support for tuple routing to foreign partitions

2017-08-17 Thread Etsuro Fujita

On 2017/07/11 6:56, Robert Haas wrote:

On Thu, Jun 29, 2017 at 6:20 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

So, I dropped the COPY part.


Ouch.  I think we should try to figure out how the COPY part will be
handled before we commit to a design.


I spent some time on this.  To handle that, I'd like to propose doing 
something similar to \copy (frontend copy): submit a COPY query "COPY 
... FROM STDIN" to the remote server and route data from a file to the 
remote server.  For that, I'd like to add new FDW APIs called during 
CopyFrom that allow us to copy to foreign tables:


* BeginForeignCopyIn: this would be called after creating a 
ResultRelInfo for the target table (or each leaf partition of the target 
partitioned table) if it's a foreign table, and perform any 
initialization needed before the remote copy can start.  In the 
postgres_fdw case, I think this function would be a good place to send 
"COPY ... FROM STDIN" to the remote server.


* ExecForeignCopyInOneRow: this would be called instead of heap_insert 
if the target is a foreign table, and route the tuple read from the file 
by NextCopyFrom to the remote server.  In the postgres_fdw case, I think 
this function would convert the tuple to text format for portability, 
and then send the data to the remote server using PQputCopyData.


* EndForeignCopyIn: this would be called at the bottom of CopyFrom, and 
release resources such as connections to the remote server.  In the 
postgres_fdw case, this function would do PQputCopyEnd to terminate data 
transfer.


I think that would be much more efficient than INSERTing tuples into the 
remote server one by one.  What do you think about that?



I have to admit that I'm a little bit fuzzy about why foreign insert
routing requires all of these changes.  I think this patch would
benefit from being accompanied by several paragraphs of explanation
outlining the rationale for each part of the patch.


Will do.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] Stats for triggers on partitioned tables not shown in EXPLAIN ANALYZE

2017-08-15 Thread Etsuro Fujita

Hi hackers,

I noticed that runtime stats for BEFORE ROW INSERT triggers on leaf 
partitions of partitioned tables aren't reported in EXPLAIN ANALYZE. 
Here is an example:


postgres=# create table trigger_test (a int, b text) partition by list (a);
CREATE TABLE
postgres=# create table trigger_test1 partition of trigger_test for 
values in (1);

CREATE TABLE
postgres=# create trigger before_ins_row_trig BEFORE INSERT ON 
trigger_test1 FOR EACH ROW EXECUTE PROCEDURE trigger_data();

CREATE TRIGGER
postgres=# create trigger after_ins_row_trig AFTER INSERT ON 
trigger_test1 FOR EACH ROW EXECUTE PROCEDURE trigger_data();

CREATE TRIGGER
postgres=# explain analyze insert into trigger_test values (1, 'foo');
NOTICE:  before_ins_row_trig() BEFORE ROW INSERT ON trigger_test1
NOTICE:  NEW: (1,foo)
NOTICE:  after_ins_row_trig() AFTER ROW INSERT ON trigger_test1
NOTICE:  NEW: (1,foo)
 QUERY PLAN
-
 Insert on trigger_test  (cost=0.00..0.01 rows=1 width=36) (actual 
time=0.193..0.193 rows=0 loops=1)
   ->  Result  (cost=0.00..0.01 rows=1 width=36) (actual 
time=0.002..0.003 rows=1 loops=1)

 Planning time: 0.027 ms
 Trigger after_ins_row_trig on trigger_test1: time=0.075 calls=1
 Execution time: 0.310 ms
(5 rows)

where trig_data() is borrowed from the regression test in postgres_fdw. 
The stats for the AFTER ROW INSERT trigger after_ins_row_trig are well 
shown in the output, but the stats for the BEFORE ROW INSERT trigger 
before_ins_row_trig aren't at all.  I think we should show the latter as 
well.


Another thing I noticed is: runtime stats for BEFORE STATEMENT 
UPDATE/DELETE triggers on partitioned table roots aren't reported in 
EXPLAIN ANALYZE, either, as shown in a below example:


postgres=# create trigger before_upd_stmt_trig BEFORE UPDATE ON 
trigger_test FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func();

CREATE TRIGGER
postgres=# create trigger after_upd_stmt_trig AFTER UPDATE ON 
trigger_test FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func();

CREATE TRIGGER
postgres=# explain analyze update trigger_test set b = 'bar' where a = 1;
NOTICE:  trigger_func() called: action = UPDATE, when = BEFORE, 
level = STATEMENT
NOTICE:  trigger_func() called: action = UPDATE, when = AFTER, 
level = STATEMENT

  QUERY PLAN

--
-
 Update on trigger_test  (cost=0.00..25.88 rows=6 width=42) (actual 
time=0.296..0.296 rows=0 loops=1)

   Update on trigger_test1
   ->  Seq Scan on trigger_test1  (cost=0.00..25.88 rows=6 width=42) 
(actual time=0.010..0.011 rows=1 loops=1)

 Filter: (a = 1)
 Planning time: 0.152 ms
 Trigger after_upd_stmt_trig on trigger_test: time=0.141 calls=1
 Execution time: 0.476 ms
(7 rows)

where trigger_func() is borrowed from the regression test, too.  The 
stats for the BEFORE STATEMENT UPDATE trigger before_upd_stmt_trig 
aren't shown at all in the output.  I think this should also be fixed. 
So here is a patch for fixing both issues.  Changes I made are:


* To fix the former, I added a new List member es_leaf_result_relations 
to EState, modified ExecSetupPartitionTupleRouting so that it creates 
ResultRelInfos with the EState's es_instrument and then saves them in 
that list, and modified ExplainPrintTriggers to show stats for BEFORE 
ROW INSERT triggers on leaf partitions (if any) by looking at that list. 
 I also modified copy.c so that ExecSetupPartitionTupleRouting and 
related things are performed in CopyFrom after its EState creation.


* To fix the latter, I modified ExplainPrintTriggers to show stats for 
BEFORE STATEMENT UPDATE/DELETE triggers on partitioned table roots (if 
any) by looking at the es_root_result_relations array.


* While fixing these, I noticed that AFTER ROW INSERT triggers on leaf 
partitions and BEFORE STATEMENT UPDATE/DELETE triggers on partitioned 
table roots re-open relations and re-create ResultRelInfos (trigger-only 
ResultRelInfos!) in ExecGetTriggerResultRel when executing triggers (and 
that in the above examples, the stats for AFTER ROW INSERT trigger/AFTER 
STATEMENT UPDATE trigger are shown the result for 
es_trig_target_relations in ExplainPrintTriggers).  But that wouldn't be 
efficient (and EXPLAIN ANALYZE might produce odd outputs), so I modified 
ExecGetTriggerResultRel so that it searches es_leaf_result_relations and 
es_root_result_relations in addition to es_result_relations.


Best regards,
Etsuro Fujita
*** a/src/backend/commands/copy.c
--- b/src/backend/commands/copy.c
***
*** 1415,1473  BeginCopy(ParseState *pstate,
(errcode(ERRCODE_UNDEFINED_COLUMN),
 errmsg("table \"%s\"

Re: [HACKERS] Comment typo in plannodes.h

2017-08-13 Thread Etsuro Fujita

On 2017/08/11 2:18, Robert Haas wrote:

On Thu, Aug 10, 2017 at 8:25 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

Here is a small patch for fixing a comment typo in plannodes.h: s/all the
partitioned table/all the partitioned tables/.


Committed.


Thank you.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] Comment typo in plannodes.h

2017-08-10 Thread Etsuro Fujita

Hi,

Here is a small patch for fixing a comment typo in plannodes.h: s/all 
the partitioned table/all the partitioned tables/.


Best regards,
Etsuro Fujita
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index f1a1b24..7c51e7f 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -67,7 +67,7 @@ typedef struct PlannedStmt
 
/*
 * rtable indexes of non-leaf target relations for UPDATE/DELETE on all
-* the partitioned table mentioned in the query.
+* the partitioned tables mentioned in the query.
 */
List   *nonleafResultRelations;
 

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Tuple-routing for certain partitioned tables not working as expected

2017-08-07 Thread Etsuro Fujita

On 2017/08/07 15:33, Amit Langote wrote:

On 2017/08/07 15:22, Etsuro Fujita wrote:

On 2017/08/07 13:11, Amit Langote wrote:> The patch looks good too.
Although, looking at the following hunk:


+ Assert(partrel->rd_rel->relkind == RELKIND_RELATION ||
+partrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE);
+
/*
 * Verify result relation is a valid target for the current
operation.
 */
! if (partrel->rd_rel->relkind == RELKIND_RELATION)
! CheckValidResultRel(partrel, CMD_INSERT);

makes me now wonder if we need the CheckValidResultRel check at all.  The
only check currently in place for RELKIND_RELATION is
CheckCmdReplicaIdentity(), which is a noop (returns true) for inserts
anyway.


Good point!  I left the verification for a plain table because that is
harmless but as you mentioned, that is nothing but an overhead.  So, here
is a new version which removes the verification at all from
ExecSetupPartitionTupleRouting.


The updated patch looks good to me, thanks.


Thanks for the review!

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Tuple-routing for certain partitioned tables not working as expected

2017-08-07 Thread Etsuro Fujita
On 2017/08/07 13:11, Amit Langote wrote:> The patch looks good too. 
Although, looking at the following hunk:


+   Assert(partrel->rd_rel->relkind == RELKIND_RELATION ||
+  partrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE);
+
/*
 * Verify result relation is a valid target for the current 
operation.
 */
!   if (partrel->rd_rel->relkind == RELKIND_RELATION)
!   CheckValidResultRel(partrel, CMD_INSERT);

makes me now wonder if we need the CheckValidResultRel check at all.  The
only check currently in place for RELKIND_RELATION is
CheckCmdReplicaIdentity(), which is a noop (returns true) for inserts anyway.


Good point!  I left the verification for a plain table because that is 
harmless but as you mentioned, that is nothing but an overhead.  So, 
here is a new version which removes the verification at all from 
ExecSetupPartitionTupleRouting.


Best regards,
Etsuro Fujita
*** /dev/null
--- b/contrib/file_fdw/data/list1.csv
***
*** 0 
--- 1,2 
+ 1,foo
+ 1,bar
*** /dev/null
--- b/contrib/file_fdw/data/list2.bad
***
*** 0 
--- 1,2 
+ 2,baz
+ 1,qux
*** /dev/null
--- b/contrib/file_fdw/data/list2.csv
***
*** 0 
--- 1,2 
+ 2,baz
+ 2,qux
*** a/contrib/file_fdw/input/file_fdw.source
--- b/contrib/file_fdw/input/file_fdw.source
***
*** 162,167  SELECT tableoid::regclass, * FROM agg FOR UPDATE;
--- 162,188 
  ALTER FOREIGN TABLE agg_csv NO INHERIT agg;
  DROP TABLE agg;
  
+ -- declarative partitioning tests
+ SET ROLE regress_file_fdw_superuser;
+ CREATE TABLE pt (a int, b text) partition by list (a);
+ CREATE FOREIGN TABLE p1 partition of pt for values in (1) SERVER file_server
+ OPTIONS (format 'csv', filename '@abs_srcdir@/data/list1.csv', delimiter ',');
+ CREATE TABLE p2 partition of pt for values in (2);
+ SELECT tableoid::regclass, * FROM pt;
+ SELECT tableoid::regclass, * FROM p1;
+ SELECT tableoid::regclass, * FROM p2;
+ COPY pt FROM '@abs_srcdir@/data/list2.bad' with (format 'csv', delimiter 
','); -- ERROR
+ COPY pt FROM '@abs_srcdir@/data/list2.csv' with (format 'csv', delimiter ',');
+ SELECT tableoid::regclass, * FROM pt;
+ SELECT tableoid::regclass, * FROM p1;
+ SELECT tableoid::regclass, * FROM p2;
+ INSERT INTO pt VALUES (1, 'xyzzy'); -- ERROR
+ INSERT INTO pt VALUES (2, 'xyzzy');
+ SELECT tableoid::regclass, * FROM pt;
+ SELECT tableoid::regclass, * FROM p1;
+ SELECT tableoid::regclass, * FROM p2;
+ DROP TABLE pt;
+ 
  -- privilege tests
  SET ROLE regress_file_fdw_superuser;
  SELECT * FROM agg_text ORDER BY a;
*** a/contrib/file_fdw/output/file_fdw.source
--- b/contrib/file_fdw/output/file_fdw.source
***
*** 289,294  SELECT tableoid::regclass, * FROM agg FOR UPDATE;
--- 289,375 
  
  ALTER FOREIGN TABLE agg_csv NO INHERIT agg;
  DROP TABLE agg;
+ -- declarative partitioning tests
+ SET ROLE regress_file_fdw_superuser;
+ CREATE TABLE pt (a int, b text) partition by list (a);
+ CREATE FOREIGN TABLE p1 partition of pt for values in (1) SERVER file_server
+ OPTIONS (format 'csv', filename '@abs_srcdir@/data/list1.csv', delimiter ',');
+ CREATE TABLE p2 partition of pt for values in (2);
+ SELECT tableoid::regclass, * FROM pt;
+  tableoid | a |  b  
+ --+---+-
+  p1   | 1 | foo
+  p1   | 1 | bar
+ (2 rows)
+ 
+ SELECT tableoid::regclass, * FROM p1;
+  tableoid | a |  b  
+ --+---+-
+  p1   | 1 | foo
+  p1   | 1 | bar
+ (2 rows)
+ 
+ SELECT tableoid::regclass, * FROM p2;
+  tableoid | a | b 
+ --+---+---
+ (0 rows)
+ 
+ COPY pt FROM '@abs_srcdir@/data/list2.bad' with (format 'csv', delimiter 
','); -- ERROR
+ ERROR:  cannot route inserted tuples to a foreign table
+ CONTEXT:  COPY pt, line 2: "1,qux"
+ COPY pt FROM '@abs_srcdir@/data/list2.csv' with (format 'csv', delimiter ',');
+ SELECT tableoid::regclass, * FROM pt;
+  tableoid | a |  b  
+ --+---+-
+  p1   | 1 | foo
+  p1   | 1 | bar
+  p2   | 2 | baz
+  p2   | 2 | qux
+ (4 rows)
+ 
+ SELECT tableoid::regclass, * FROM p1;
+  tableoid | a |  b  
+ --+---+-
+  p1   | 1 | foo
+  p1   | 1 | bar
+ (2 rows)
+ 
+ SELECT tableoid::regclass, * FROM p2;
+  tableoid | a |  b  
+ --+---+-
+  p2   | 2 | baz
+  p2   | 2 | qux
+ (2 rows)
+ 
+ INSERT INTO pt VALUES (1, 'xyzzy'); -- ERROR
+ ERROR:  cannot route inserted tuples to a foreign table
+ INSERT INTO pt VALUES (2, 'xyzzy');
+ SELECT tableoid::regclass, * FROM pt;
+  tableoid | a |   b   
+ --+---+---
+  p1   | 1 | foo
+  p1   | 1 | bar
+  p2   | 2 | baz
+  p2   | 2 | qux
+  p2   | 2 | xyzzy
+ (5 rows)
+ 
+ SELECT tableoid::regclass, * FROM p1;
+  tableoid | a |  b  
+ --+---+-
+  p1   | 1 | foo
+  p1   | 1 | bar
+ (2 rows)
+ 
+ SELECT tableoid::regclass, * FROM p2;
+  tableoid | a |   b   

[HACKERS] Tuple-routing for certain partitioned tables not working as expected

2017-08-06 Thread Etsuro Fujita

Hi,

I noticed that tuple-routing for partitioned tables that contain 
non-writable foreign partitions doesn't work as expected.  Here is an 
example:


postgres=# create extension file_fdw;
postgres=# create server file_server foreign data wrapper file_fdw;
postgres=# create user mapping for CURRENT_USER server file_server;
postgres=# create table p (a int) partition by list (a);
postgres=# create foreign table t1 partition of p for values in (1) 
server file_server options (format 'csv', filename '/path/to/file', 
delimiter ',');

postgres=# create table t2 partition of p for values in (2);
postgres=# insert into p values (1);
ERROR:  cannot insert into foreign table "t1"

Looks good, but:

postgres=# insert into p values (2);
ERROR:  cannot insert into foreign table "t1"

The insert should work but doesn't.  (It also seems odd to me that the 
error message points to t1, not t2.)  The reason for that is 
CheckValidResultRel in ExecSetupPartitionTupleRouting aborts any insert 
into a partitioned table in the case where the partitioned table 
contains at least one foreign partition into which the FDW can't insert. 
 I don't think that that is intentional behavior, so I'd like to 
propose to fix that by skipping CheckValidResultRel for foreign 
partitions because we can abort an insert into a foreign partition after 
ExecFindPartition in ExecInsert, by checking to see if 
resultRelInfo->ri_FdwRoutine is not NULL.  Attached is a proposed patch 
for that.  Since COPY FROM has the same issue, I added regression tests 
for COPY FROM as well as INSERT to file_fdw.


Best regards,
Etsuro Fujita
*** /dev/null
--- b/contrib/file_fdw/data/list1.csv
***
*** 0 
--- 1,2 
+ 1,foo
+ 1,bar
*** /dev/null
--- b/contrib/file_fdw/data/list2.bad
***
*** 0 
--- 1,2 
+ 2,baz
+ 1,qux
*** /dev/null
--- b/contrib/file_fdw/data/list2.csv
***
*** 0 
--- 1,2 
+ 2,baz
+ 2,qux
*** a/contrib/file_fdw/input/file_fdw.source
--- b/contrib/file_fdw/input/file_fdw.source
***
*** 162,167  SELECT tableoid::regclass, * FROM agg FOR UPDATE;
--- 162,188 
  ALTER FOREIGN TABLE agg_csv NO INHERIT agg;
  DROP TABLE agg;
  
+ -- declarative partitioning tests
+ SET ROLE regress_file_fdw_superuser;
+ CREATE TABLE pt (a int, b text) partition by list (a);
+ CREATE FOREIGN TABLE p1 partition of pt for values in (1) SERVER file_server
+ OPTIONS (format 'csv', filename '@abs_srcdir@/data/list1.csv', delimiter ',');
+ CREATE TABLE p2 partition of pt for values in (2);
+ SELECT tableoid::regclass, * FROM pt;
+ SELECT tableoid::regclass, * FROM p1;
+ SELECT tableoid::regclass, * FROM p2;
+ COPY pt FROM '@abs_srcdir@/data/list2.bad' with (format 'csv', delimiter 
','); -- ERROR
+ COPY pt FROM '@abs_srcdir@/data/list2.csv' with (format 'csv', delimiter ',');
+ SELECT tableoid::regclass, * FROM pt;
+ SELECT tableoid::regclass, * FROM p1;
+ SELECT tableoid::regclass, * FROM p2;
+ INSERT INTO pt VALUES (1, 'xyzzy'); -- ERROR
+ INSERT INTO pt VALUES (2, 'xyzzy');
+ SELECT tableoid::regclass, * FROM pt;
+ SELECT tableoid::regclass, * FROM p1;
+ SELECT tableoid::regclass, * FROM p2;
+ DROP TABLE pt;
+ 
  -- privilege tests
  SET ROLE regress_file_fdw_superuser;
  SELECT * FROM agg_text ORDER BY a;
*** a/contrib/file_fdw/output/file_fdw.source
--- b/contrib/file_fdw/output/file_fdw.source
***
*** 289,294  SELECT tableoid::regclass, * FROM agg FOR UPDATE;
--- 289,375 
  
  ALTER FOREIGN TABLE agg_csv NO INHERIT agg;
  DROP TABLE agg;
+ -- declarative partitioning tests
+ SET ROLE regress_file_fdw_superuser;
+ CREATE TABLE pt (a int, b text) partition by list (a);
+ CREATE FOREIGN TABLE p1 partition of pt for values in (1) SERVER file_server
+ OPTIONS (format 'csv', filename '@abs_srcdir@/data/list1.csv', delimiter ',');
+ CREATE TABLE p2 partition of pt for values in (2);
+ SELECT tableoid::regclass, * FROM pt;
+  tableoid | a |  b  
+ --+---+-
+  p1   | 1 | foo
+  p1   | 1 | bar
+ (2 rows)
+ 
+ SELECT tableoid::regclass, * FROM p1;
+  tableoid | a |  b  
+ --+---+-
+  p1   | 1 | foo
+  p1   | 1 | bar
+ (2 rows)
+ 
+ SELECT tableoid::regclass, * FROM p2;
+  tableoid | a | b 
+ --+---+---
+ (0 rows)
+ 
+ COPY pt FROM '@abs_srcdir@/data/list2.bad' with (format 'csv', delimiter 
','); -- ERROR
+ ERROR:  cannot route inserted tuples to a foreign table
+ CONTEXT:  COPY pt, line 2: "1,qux"
+ COPY pt FROM '@abs_srcdir@/data/list2.csv' with (format 'csv', delimiter ',');
+ SELECT tableoid::regclass, * FROM pt;
+  tableoid | a |  b  
+ --+---+-
+  p1   | 1 | foo
+  p1   | 1 | bar
+  p2   | 2 | baz
+  p2   | 2 | qux
+ (4 rows)
+ 
+ SELECT tableoid::regclass, * FROM p1;
+  tableoid | a |  b  
+ --+---+-
+  p1   | 1 | foo
+  p1   | 1 | bar
+ (2 rows)
+ 
+ SELECT tableoid::regclass, * FROM p2;
+  tableoid | a |  b  
+ --+---+-
+  p2   | 2

Re: [HACKERS] Update comments in nodeModifyTable.c

2017-08-03 Thread Etsuro Fujita

On 2017/08/04 1:52, Robert Haas wrote:

On Thu, Aug 3, 2017 at 5:55 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

I updated the patch that way.  Attached is a new version of the patch.


Committed.


Thanks again.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] map_partition_varattnos() and whole-row vars

2017-08-03 Thread Etsuro Fujita

On 2017/08/04 10:00, Amit Langote wrote:

On 2017/08/04 1:06, Robert Haas wrote:

On Thu, Aug 3, 2017 at 4:40 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

On 2017/08/03 17:12, Amit Langote wrote:

Attached updated patches.


Thanks for the patch!  That looks good to me.


Committed with some comment changes.


Thanks a lot.


Thanks!

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Update comments in nodeModifyTable.c

2017-08-03 Thread Etsuro Fujita

On 2017/08/02 4:07, Robert Haas wrote:

On Tue, Aug 1, 2017 at 12:31 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

Maybe I'm missing something, but I'm not sure that's a good idea because the
change says like we might have 'wholerow' only for the FDW case, but that
isn't correct because we would have 'wholerow' for a view as well. ISTM that
views should be one of the typical cases, so I'd like to propose to modify
the sentence starting with 'Typically' to something like this: "Typically,
this will be a 'ctid' or 'wholerow' attribute, but in the case of a foreign
data wrapper it might be a set of junk attributes sufficient to identify the
remote row."  What do you think about that?


Works for me.


I updated the patch that way.  Attached is a new version of the patch.

Best regards,
Etsuro Fujita
diff --git a/src/backend/executor/nodeModifyTable.c 
b/src/backend/executor/nodeModifyTable.c
index 0dde0ed..0199c9d 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1696,7 +1696,7 @@ ExecModifyTable(PlanState *pstate)
 * the old relation tuple.
 *
 * Foreign table updates have a wholerow 
attribute when the
-* relation has an AFTER ROW trigger.  Note 
that the wholerow
+* relation has a row-level trigger.  Note that 
the wholerow
 * attribute does not carry system columns.  
Foreign table
 * triggers miss seeing those, except that we 
know enough here
 * to set t_tableOid.  Quite separately from 
this, the FDW may
@@ -2182,8 +2182,11 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, 
int eflags)
/*
 * Initialize the junk filter(s) if needed.  INSERT queries need a 
filter
 * if there are any junk attrs in the tlist.  UPDATE and DELETE always
-* need a filter, since there's always a junk 'ctid' or 'wholerow'
-* attribute present --- no need to look first.
+* need a filter, since there's always at least one junk attribute 
present
+* --- no need to look first.  Typically, this will be a 'ctid' or
+* 'wholerow' attribute, but in the case of a foreign data wrapper it
+* might be a set of junk attributes sufficient to identify the remote
+* row.
 *
 * If there are multiple result relations, each one needs its own junk
 * filter.  Note multiple rels are only possible for UPDATE/DELETE, so 
we
@@ -2251,7 +2254,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, 
int eflags)
else if (relkind == 
RELKIND_FOREIGN_TABLE)
{
/*
-* When there is an AFTER 
trigger, there should be a
+* When there is a row-level 
trigger, there should be a
 * wholerow attribute.
 */
j->jf_junkAttNo = 
ExecFindJunkAttribute(j, "wholerow");

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] map_partition_varattnos() and whole-row vars

2017-08-03 Thread Etsuro Fujita

On 2017/08/03 17:12, Amit Langote wrote:

Attached updated patches.


Thanks for the patch!  That looks good to me.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] map_partition_varattnos() and whole-row vars

2017-08-03 Thread Etsuro Fujita

On 2017/08/02 15:21, Amit Langote wrote:

Thanks Fuita-san and Amit for reviewing.

On 2017/08/02 1:33, Amit Khandekar wrote:

On 1 August 2017 at 15:11, Etsuro Fujita <fujita.ets...@lab.ntt.co.jp> wrote:

On 2017/07/31 18:56, Amit Langote wrote:

Yes, that's what's needed here.  So we need to teach
map_variable_attnos_mutator() to convert whole-row vars just like it's
done in adjust_appendrel_attrs_mutator().



Seems reasonable.  (Though I think it might be better to do this kind of
conversion in the planner, not the executor, because that would increase the
efficiency of cached plans.)


That's a good point, although it sounds like a bigger project that, IMHO,
should be undertaken separately, because that would involve designing for
considerations of expanding inheritance even in the INSERT case.


Agreed.  I think that would be definitely a material for PG11.


I think the work of shifting to planner should be taken as a different
task when we shift the preparation of DispatchInfo to the planner.


Yeah, I think it'd be a good idea to do those projects together.  That is,
doing what Fujita-san suggested and expanding partitioned tables in
partition bound order in the planner.


OK


---

Few more comments :

@@ -1240,7 +1247,7 @@ map_variable_attnos_mutator(Node *node,
  var->varlevelsup == context->sublevels_up)
  {
  /* Found a matching variable, make the substitution */

- Var*newvar = (Var *) palloc(sizeof(Var));
+ Var*newvar = copyObject(var);
   int attno = var->varattno;

  *newvar = *var;

Here, "*newvar = *var" should be removed.


Done.


I'm not sure this change is a good idea, because the copy by "*newvar = 
*var" would be more efficient than the copyObject().  (We have this 
optimization in other places as well.  See eg, copyVar() in setrefs.c.)


Here are some other comments:

+   /* If the callers expects us to convert the 
same, do so. */
+   if (OidIsValid(context->to_rowtype))
+   {
+   ConvertRowtypeExpr *r;
+
+   /* Var itself is converted to the 
requested rowtype. */
+   newvar->vartype = context->to_rowtype;
+
+   /*
+* And a conversion step on top to 
convert back to the
+* original type.
+*/
+   r = makeNode(ConvertRowtypeExpr);
+   r->arg = (Expr *) newvar;
+   r->resulttype = var->vartype;
+   r->convertformat = COERCE_IMPLICIT_CAST;
+   r->location = -1;
+
+   return (Node *) r;
+   }

Why not do this conversion if to_rowtype is valid and it's different 
from the rowtype of the original whole-row Var like the previous patch? 
Also, I think it's better to add an assertion that the rowtype of the 
original whole-row Var is a named one.  So, what I have in mind is:


  if (OidIsValid(context->to_rowtype))
  {
Assert(var->vartype != RECORDOID)
if (var->vartype != context->to_rowtype)
{
  ConvertRowtypeExpr *r;

  /* Var itself is converted to the requested rowtype. */
  ...
  /* And a conversion step on top to convert back to the ... */
  ...
  return (Node *) r;
}
  }

Here is the modification to the map_variable_attnos()'s API:

 map_variable_attnos(Node *node,
int target_varno, int sublevels_up,
const AttrNumber *attno_map, 
int map_length,

-   bool *found_whole_row)
+   bool *found_whole_row, Oid 
to_rowtype)


This is nitpicking, but I think it would be better to put the new 
argument to_rowtype right before the output argument found_whole_row.


+ * RelationGetRelType
+ * Returns the rel's pg_type OID.
+ */
+#define RelationGetRelType(relation) \
+   ((relation)->rd_rel->reltype)

This macro is used in only one place.  Do we really need that?  (This 
macro would be useful for other places such as expand_inherited_rtentry, 
but I think it's better to introduce this in a separate patch, maybe for 
PG11.)


+-- check that wholerow vars in the RETUNING list work with partitioned 
tables


Typo: s/RETUNING/RETURNING/

Sorry for the delay.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] map_partition_varattnos() and whole-row vars

2017-08-02 Thread Etsuro Fujita

On 2017/08/03 12:06, Robert Haas wrote:

On Wed, Aug 2, 2017 at 2:25 AM, Amit Langote
<langote_amit...@lab.ntt.co.jp> wrote:

On 2017/08/02 15:21, Amit Langote wrote:

Thanks Fuita-san and Amit for reviewing.


Sorry, I meant Fujita-san.


Time is growing short here.  Is there more review or coding that needs
to be done here?


I'll take another look at the patch from now.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Another comment typo in execMain.c

2017-08-02 Thread Etsuro Fujita

On 2017/08/01 6:09, Peter Eisentraut wrote:

On 7/6/17 03:23, Etsuro Fujita wrote:

Here is a comment in ExecFindPartition() in execMain.c:

  /*
   * First check the root table's partition constraint, if any.  No
point in
   * routing the tuple it if it doesn't belong in the root table itself.
   */

I think that in the second sentence "it" just before "if" is a typo.
Attached is a small patch for fixing that.


fixed


Thanks!

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] map_partition_varattnos() and whole-row vars

2017-08-01 Thread Etsuro Fujita
*/
+   newvar->vartype = context->to_rowtype;
+   return (Node *) r;
+   }

I think we could set r->resulttype to the vartype (ie, "r->resulttype = 
newvar->vartype" instead of "r->resulttype = context->from_rowtype").


Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Update comments in nodeModifyTable.c

2017-07-31 Thread Etsuro Fujita

On 2017/08/01 1:03, Robert Haas wrote:

On Fri, Jul 28, 2017 at 8:12 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

On 2017/07/26 22:39, Robert Haas wrote:

So the first part of the change weakens the assertion that a 'ctid' or
'wholerow' attribute will always be present by saying that an FDW may
instead have other attributes sufficient to identify the row.


That's right.


But
then the additional sentence says that there will be a 'wholerow'
attribute after all.  So this whole change seems to me to be going
around in a circle.


What I mean by the additional one is: if the result table that is a foreign
table has a row-level UPDATE/DELETE trigger, a 'wholerow' will also be
present.  So, if the result table didn't have the trigger, there wouldn't be
'whole-row', so in that case it could be possible that there would be only
attributes other than 'ctid' and 'wholerow'.


I think maybe something like this would be clearer, then:

  /*
   * Initialize the junk filter(s) if needed.  INSERT queries need a filter
   * if there are any junk attrs in the tlist.  UPDATE and DELETE always
- * need a filter, since there's always a junk 'ctid' or 'wholerow'
- * attribute present --- no need to look first.
+ * need a filter, since there's always at least one junk attribute present
+ * --- no need to look first.  Typically, this will be a 'ctid'
+ * attribute, but in the case of a foreign data wrapper it might be a
+ * 'wholerow' attribute or some other set of junk attributes sufficient to
+ * identify the remote row.
   *
   * If there are multiple result relations, each one needs its own junk
   * filter.  Note multiple rels are only possible for UPDATE/DELETE, so we


Maybe I'm missing something, but I'm not sure that's a good idea because 
the change says like we might have 'wholerow' only for the FDW case, but 
that isn't correct because we would have 'wholerow' for a view as well. 
ISTM that views should be one of the typical cases, so I'd like to 
propose to modify the sentence starting with 'Typically' to something 
like this: "Typically, this will be a 'ctid' or 'wholerow' attribute, 
but in the case of a foreign data wrapper it might be a set of junk 
attributes sufficient to identify the remote row."  What do you think 
about that?


Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [BUGS] BUG #14759: insert into foreign data partitions fail

2017-07-31 Thread Etsuro Fujita

On 2017/08/01 10:18, Amit Langote wrote:

Good points; fixed in the updated patch.


I should have mentioned this in an earlier mail, but one thing I noticed 
is this:


-the remote server.
+the remote server.  That becomes especially important if the table is
+being used in a partition hierarchy, where it is recommended to add
+a constraint matching the partition constraint expression on
+the remote table.

I think this would apply to CHECK constraints on foreign tables when 
implementing partitioning with inheritance.  Why do we only mention this 
for partition constraints?


Other than that, the patch looks good to me.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Update comments in nodeModifyTable.c

2017-07-28 Thread Etsuro Fujita

On 2017/07/26 22:39, Robert Haas wrote:

On Wed, Jun 14, 2017 at 10:40 PM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

Attached is an updated version of the patch.


Well, now I'm confused:

   * Initialize the junk filter(s) if needed.  INSERT queries need a filter
   * if there are any junk attrs in the tlist.  UPDATE and DELETE always
   * need a filter, since there's always a junk 'ctid' or 'wholerow'
- * attribute present --- no need to look first.
+ * attribute present if not foreign table, and if foreign table, there
+ * are always junk attributes present the FDW needs to identify the exact
+ * row to update or delete --- no need to look first.  For foreign tables,
+ * there's also a wholerow attribute when the relation has a row-level
+ * trigger on UPDATE/DELETE but not on INSERT.

So the first part of the change weakens the assertion that a 'ctid' or
'wholerow' attribute will always be present by saying that an FDW may
instead have other attributes sufficient to identify the row.


That's right.


But
then the additional sentence says that there will be a 'wholerow'
attribute after all.  So this whole change seems to me to be going
around in a circle.


What I mean by the additional one is: if the result table that is a 
foreign table has a row-level UPDATE/DELETE trigger, a 'wholerow' will 
also be present.  So, if the result table didn't have the trigger, there 
wouldn't be 'whole-row', so in that case it could be possible that there 
would be only attributes other than 'ctid' and 'wholerow'.


Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [BUGS] BUG #14759: insert into foreign data partitions fail

2017-07-28 Thread Etsuro Fujita

On 2017/07/26 15:29, Amit Langote wrote:

On 2017/07/25 9:43, David G. Johnston wrote:

On Mon, Jul 24, 2017 at 5:19 PM, Amit Langote <langote_amit...@lab.ntt.co.jp

wrote:
On 2017/07/25 6:28, mtun...@gmail.com wrote:

The following bug has been logged on the website:

Bug reference:  14759
Logged by:  Murat Tuncer
Email address:  mtun...@gmail.com
PostgreSQL version: 10beta2
Operating system:   Mac 10.12.6
Description:

I got

ERROR:  cannot route inserted tuples to a foreign table


Inserting tuples into a partitioned table that will route to one of its
foreign table partitions is unsupported in PG 10.  The limitation is
mentioned on the following page:
https://www.postgresql.org/docs/devel/static/ddl-partitioning.html



It would be nice to also note this limitation here:

https://www.postgresql.org/docs/devel/static/sql-createforeigntable.html


Yeah, I thought the same when writing my previous email.


Also, the ddl-partitioning.html page has a section "5.10.2.3.
Limitations".  Moving (or duplicating maybe) the existing comment on that
page in that section would make finding out about this limitation a bit
easier.


Yeah, perhaps.


I'd probably move (and rework) the "limitation wording" to the limitation
sections and do something like the following in the main section.

"Foreign Tables can be added to a partitioning structure but inserts to the
partitioned table will fail if they are routed to a foreign table
partition.  Direct writes to the foreign table, and partition reads, work
normally."


Done that in the attached.


I'm curious what the other limitations are...


I think COPY has the same limitation as INSERT.


When I first wrote that documentation line (I am assuming you're asking
about "although these have some limitations that normal tables do not"), I
was thinking about the fact that the core system does not enforce
(locally) any constraints defined on foreign tables.  Since we allow
inserting data into partitions directly, it is imperative that we enforce
the "partition constraint" along with the traditional constraints such as
NOT NULL and CHECK constraints, which we can do for local table partitions
but not for foreign table ones.

Anyway, attached patch documents all these limitations about foreign table
partitions more prominently.


Typo: s/the they is/they are/

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] UPDATE of partition key

2017-07-26 Thread Etsuro Fujita

On 2017/07/26 6:07, Robert Haas wrote:

On Thu, Jul 13, 2017 at 1:09 PM, Amit Khandekar <amitdkhan...@gmail.com> wrote:

Attached is a WIP patch (make_resultrels_ordered.patch) that generates
the result rels in canonical order. This patch is kept separate from
the update-partition-key patch, and can be applied on master branch.


Thank you for working on this, Amit!


Hmm, I like the approach you've taken here in general,


+1 for the approach.


Is there any real benefit in this "walker" interface?  It looks to me
like it might be simpler to just change things around so that it
returns a list of OIDs, like find_all_inheritors, but generated
differently.  Then if you want bound-ordering rather than
OID-ordering, you just do this:

list_free(inhOids);
inhOids = get_partition_oids_in_bound_order(rel);

That'd remove the need for some if/then logic as you've currently got
in get_next_child().


Yeah, that would make the code much simple, so +1 for Robert's idea.


I think we should always expand in bound order rather than only when
it's a result relation. I think for partition-wise join, we're going
to want to do it this way for all relations in the query, or at least
for all relations in the query that might possibly be able to
participate in a partition-wise join.  If there are multiple cases
that are going to need this ordering, it's hard for me to accept the
idea that it's worth the complexity of trying to keep track of when we
expanded things in one order vs. another.  There are other
applications of having things in bound order too, like MergeAppend ->
Append strength-reduction (which might not be legal anyway if there
are list partitions with multiple, non-contiguous list bounds or if
any NULL partition doesn't end up in the right place in the order, but
there will be lots of cases where it can work).


+1 for that as well.  Another benefit from that would be EXPLAIN; we 
could display partitions for a partitioned table in the same order for 
Append and ModifyTable (ie, SELECT/UPDATE/DELETE), which I think would 
make the EXPLAIN result much readable.


Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Mishandling of WCO constraints in direct foreign table modification

2017-07-25 Thread Etsuro Fujita

On 2017/07/25 5:35, Robert Haas wrote:

On Fri, Jul 21, 2017 at 6:21 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

I mean constraints derived from WITH CHECK OPTIONs specified for parent
views.  We use the words "WITH CHECK OPTION constraints" in comments in
nodeModifyTable.c, so the expression "CHECK OPTION constrains" doesn't sound
not that bad to me.  (I used "CHECK OPTION", not "WITH CHECK OPTION",
because we use "CHECK OPTION" a lot more in the documentation than "WITH
CHECK OPTION".)


Yeah, it seems OK to me, too; if the consensus is otherwise, we also
have the option to change it later.

Agreed.


Committed and back-patched as you
had it, but I removed a spurious comma.


Thanks for that, Robert!  Thanks for reviewing, Horiguchi-san!

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Oddity in error handling of constraint violation in ExecConstraints for partitioned tables

2017-07-24 Thread Etsuro Fujita

On 2017/07/24 16:16, Amit Khandekar wrote:

On 24 July 2017 at 12:11, Amit Langote <langote_amit...@lab.ntt.co.jp> wrote:

Attached is the updated version of your patch.


Good catch, Amit K. and Amit L.!


Now that this is done, any particular reason it is not done in
ExecPartitionCheck() ? I see that there is a do_convert_tuple() in
that function, again without changing the slot descriptor.


Yeah, I think we would need that in ExecPartitionCheck() as well.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Bug in ExecModifyTable function and trigger issues for foreign tables

2017-07-23 Thread Etsuro Fujita

On 2017/07/21 19:16, Etsuro Fujita wrote:

On 2017/07/20 11:21, Etsuro Fujita wrote:

On 2017/07/19 23:36, Tom Lane wrote:

Please put the responsibility of doing const-expression simplification
in these cases somewhere closer to where the problem is being created.


It would be reasonable that it's the FDW's responsibility to do that 
const-simplification if necessary?
There seems to be no objections, so I removed the const-expression 
simplification from the patch and I added the note to the docs for 
AddForeignUpdateTargets.


Attached is an updated version of the patch.


I cleaned up the patch a bit.  PFA a new version of the patch.

Best regards,
Etsuro Fujita
*** a/contrib/postgres_fdw/expected/postgres_fdw.out
--- b/contrib/postgres_fdw/expected/postgres_fdw.out
***
*** 6962,6967  update bar set f2 = f2 + 100 returning *;
--- 6962,7026 
7 | 277
  (6 rows)
  
+ -- Test that UPDATE/DELETE with inherited target works with row-level triggers
+ CREATE TRIGGER trig_row_before
+ BEFORE UPDATE OR DELETE ON bar2
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ CREATE TRIGGER trig_row_after
+ AFTER UPDATE OR DELETE ON bar2
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ explain (verbose, costs off)
+ update bar set f2 = f2 + 100;
+   QUERY PLAN  

+ 
--
+  Update on public.bar
+Update on public.bar
+Foreign Update on public.bar2
+  Remote SQL: UPDATE public.loct2 SET f2 = $2 WHERE ctid = $1 RETURNING 
f1, f2, f3
+->  Seq Scan on public.bar
+  Output: bar.f1, (bar.f2 + 100), bar.ctid
+->  Foreign Scan on public.bar2
+  Output: bar2.f1, (bar2.f2 + 100), bar2.f3, bar2.ctid, bar2.*
+  Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE
+ (9 rows)
+ 
+ update bar set f2 = f2 + 100;
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
+ NOTICE:  OLD: (3,333,33),NEW: (3,433,33)
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
+ NOTICE:  OLD: (4,344,44),NEW: (4,444,44)
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
+ NOTICE:  OLD: (7,277,77),NEW: (7,377,77)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
+ NOTICE:  OLD: (3,333,33),NEW: (3,433,33)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
+ NOTICE:  OLD: (4,344,44),NEW: (4,444,44)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
+ NOTICE:  OLD: (7,277,77),NEW: (7,377,77)
+ explain (verbose, costs off)
+ delete from bar where f2 < 400;
+  QUERY PLAN   
   
+ 
-
+  Delete on public.bar
+Delete on public.bar
+Foreign Delete on public.bar2
+  Remote SQL: DELETE FROM public.loct2 WHERE ctid = $1 RETURNING f1, f2, f3
+->  Seq Scan on public.bar
+  Output: bar.ctid
+  Filter: (bar.f2 < 400)
+->  Foreign Scan on public.bar2
+  Output: bar2.ctid, bar2.*
+  Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 WHERE ((f2 < 
400)) FOR UPDATE
+ (10 rows)
+ 
+ delete from bar where f2 < 400;
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW DELETE ON bar2
+ NOTICE:  OLD: (7,377,77)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW DELETE ON bar2
+ NOTICE:  OLD: (7,377,77)
+ -- cleanup
+ DROP TRIGGER trig_row_before ON bar2;
+ DROP TRIGGER trig_row_after ON bar2;
  drop table foo cascade;
  NOTICE:  drop cascades to foreign table foo2
  drop table bar cascade;
*** a/contrib/postgres_fdw/sql/postgres_fdw.sql
--- b/contrib/postgres_fdw/sql/postgres_fdw.sql
***
*** 1632,1637  explain (verbose, costs off)
--- 1632,1657 
  update bar set f2 = f2 + 100 returning *;
  update bar set f2 = f2 + 100 returning *;
  
+ -- Test that UPDATE/DELETE with inherited target works with row-level triggers
+ CREATE TRIGGER trig_row_before
+ BEFORE UPDATE OR DELETE ON bar2
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ 
+ CREATE TRIGGER trig_row_after
+ AFTER UPDATE OR DELETE ON bar2
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ 
+ explain (verbose, costs off)
+ update bar set f2 = f2 + 100;
+ update bar set f2 = f2 + 100;
+ 
+ explain (verbose, costs off)
+ delete from bar where f2 < 400;
+ delete from bar where f2 < 400;
+ 
+ -- cleanup
+ DROP TRIGGER trig_row_before ON bar2;
+ DROP TRIGGER trig_row_after ON bar2;
  drop table foo cascade;
  drop table bar cascade;
  drop table loct1;
*** a/doc/src/sgml/fdwhandler.sgml
--- b/doc/src/sgml/fdwhandler.sgml
***
*** 428,438  AddForeignUpdateTargets (Query *parsetree,
   Avoid using names matching ctidN,
   wholerow, or
   wholerowN, as the core system can
!  genera

Re: [HACKERS] Mishandling of WCO constraints in direct foreign table modification

2017-07-21 Thread Etsuro Fujita

On 2017/07/21 17:18, Kyotaro HORIGUCHI wrote:

At Fri, 21 Jul 2017 12:00:03 +0900, Etsuro Fujita <fujita.ets...@lab.ntt.co.jp> wrote 
in <15aa9936-9bd8-c9e3-7ca1-394861073...@lab.ntt.co.jp>

Attached is the second version which updated docs in postgres-fdw.sgml
as well.


!no local joins for the query, no row-level local BEFORE or
!AFTER triggers on the target table, and no
!CHECK OPTION constraints from parent views.
!In UPDATE,

Might be a silly question, is CHECK OPTION a "constraint"?


I mean constraints derived from WITH CHECK OPTIONs specified for parent 
views.  We use the words "WITH CHECK OPTION constraints" in comments in 
nodeModifyTable.c, so the expression "CHECK OPTION constrains" doesn't 
sound not that bad to me.  (I used "CHECK OPTION", not "WITH CHECK 
OPTION", because we use "CHECK OPTION" a lot more in the documentation 
than "WITH CHECK OPTION".)


Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Bug in ExecModifyTable function and trigger issues for foreign tables

2017-07-21 Thread Etsuro Fujita

On 2017/07/20 11:21, Etsuro Fujita wrote:

On 2017/07/19 23:36, Tom Lane wrote:

Please put the responsibility of doing const-expression simplification
in these cases somewhere closer to where the problem is being created.


It would be reasonable that it's the FDW's responsibility to do that 
const-simplification if necessary?
There seems to be no objections, so I removed the const-expression 
simplification from the patch and I added the note to the docs for 
AddForeignUpdateTargets.


Attached is an updated version of the patch.

Best regards,
Etsuro Fujita
*** a/contrib/postgres_fdw/expected/postgres_fdw.out
--- b/contrib/postgres_fdw/expected/postgres_fdw.out
***
*** 6924,6929  update bar set f2 = f2 + 100 returning *;
--- 6924,6988 
7 | 277
  (6 rows)
  
+ -- Test that UPDATE/DELETE with inherited target works with row-level triggers
+ CREATE TRIGGER trig_row_before
+ BEFORE UPDATE OR DELETE ON bar2
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ CREATE TRIGGER trig_row_after
+ AFTER UPDATE OR DELETE ON bar2
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ explain (verbose, costs off)
+ update bar set f2 = f2 + 100;
+   QUERY PLAN  

+ 
--
+  Update on public.bar
+Update on public.bar
+Foreign Update on public.bar2
+  Remote SQL: UPDATE public.loct2 SET f2 = $2 WHERE ctid = $1 RETURNING 
f1, f2, f3
+->  Seq Scan on public.bar
+  Output: bar.f1, (bar.f2 + 100), bar.ctid
+->  Foreign Scan on public.bar2
+  Output: bar2.f1, (bar2.f2 + 100), bar2.f3, bar2.ctid, bar2.*
+  Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE
+ (9 rows)
+ 
+ update bar set f2 = f2 + 100;
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
+ NOTICE:  OLD: (3,333,33),NEW: (3,433,33)
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
+ NOTICE:  OLD: (4,344,44),NEW: (4,444,44)
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
+ NOTICE:  OLD: (7,277,77),NEW: (7,377,77)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
+ NOTICE:  OLD: (3,333,33),NEW: (3,433,33)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
+ NOTICE:  OLD: (4,344,44),NEW: (4,444,44)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
+ NOTICE:  OLD: (7,277,77),NEW: (7,377,77)
+ explain (verbose, costs off)
+ delete from bar where f2 < 400;
+  QUERY PLAN   
   
+ 
-
+  Delete on public.bar
+Delete on public.bar
+Foreign Delete on public.bar2
+  Remote SQL: DELETE FROM public.loct2 WHERE ctid = $1 RETURNING f1, f2, f3
+->  Seq Scan on public.bar
+  Output: bar.ctid
+  Filter: (bar.f2 < 400)
+->  Foreign Scan on public.bar2
+  Output: bar2.ctid, bar2.*
+  Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 WHERE ((f2 < 
400)) FOR UPDATE
+ (10 rows)
+ 
+ delete from bar where f2 < 400;
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW DELETE ON bar2
+ NOTICE:  OLD: (7,377,77)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW DELETE ON bar2
+ NOTICE:  OLD: (7,377,77)
+ -- cleanup
+ DROP TRIGGER trig_row_before ON bar2;
+ DROP TRIGGER trig_row_after ON bar2;
  drop table foo cascade;
  NOTICE:  drop cascades to foreign table foo2
  drop table bar cascade;
*** a/contrib/postgres_fdw/sql/postgres_fdw.sql
--- b/contrib/postgres_fdw/sql/postgres_fdw.sql
***
*** 1609,1614  explain (verbose, costs off)
--- 1609,1634 
  update bar set f2 = f2 + 100 returning *;
  update bar set f2 = f2 + 100 returning *;
  
+ -- Test that UPDATE/DELETE with inherited target works with row-level triggers
+ CREATE TRIGGER trig_row_before
+ BEFORE UPDATE OR DELETE ON bar2
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ 
+ CREATE TRIGGER trig_row_after
+ AFTER UPDATE OR DELETE ON bar2
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ 
+ explain (verbose, costs off)
+ update bar set f2 = f2 + 100;
+ update bar set f2 = f2 + 100;
+ 
+ explain (verbose, costs off)
+ delete from bar where f2 < 400;
+ delete from bar where f2 < 400;
+ 
+ -- cleanup
+ DROP TRIGGER trig_row_before ON bar2;
+ DROP TRIGGER trig_row_after ON bar2;
  drop table foo cascade;
  drop table bar cascade;
  drop table loct1;
*** a/doc/src/sgml/fdwhandler.sgml
--- b/doc/src/sgml/fdwhandler.sgml
***
*** 428,438  AddForeignUpdateTargets (Query *parsetree,
   Avoid using names matching ctidN,
   wholerow, or
   wholerowN, as the core system can
!  generate junk columns of these names.
  
  
  
!  This function is called in the rewriter, not the planner, so th

Re: [HACKERS] Mishandling of WCO constraints in direct foreign table modification

2017-07-20 Thread Etsuro Fujita

On 2017/07/21 3:24, Robert Haas wrote:

I think that's reasonable.  This should be committed and back-patched
to 9.6, right?


Yeah, because direct modify was introduced in 9.6.

Attached is the second version which updated docs in postgres-fdw.sgml 
as well.


Best regards,
Etsuro Fujita
*** a/contrib/postgres_fdw/expected/postgres_fdw.out
--- b/contrib/postgres_fdw/expected/postgres_fdw.out
***
*** 5856,5861  INSERT INTO ft1(c1, c2) VALUES(, 2);
--- 5856,5921 
  UPDATE ft1 SET c2 = c2 + 1 WHERE c1 = 1;
  ALTER FOREIGN TABLE ft1 DROP CONSTRAINT ft1_c2negative;
  -- ===
+ -- test WITH CHECK OPTION constraints
+ -- ===
+ CREATE TABLE base_tbl (a int, b int);
+ CREATE FOREIGN TABLE foreign_tbl (a int, b int)
+   SERVER loopback OPTIONS(table_name 'base_tbl');
+ CREATE VIEW rw_view AS SELECT * FROM foreign_tbl
+   WHERE a < b WITH CHECK OPTION;
+ \d+ rw_view
+View "public.rw_view"
+  Column |  Type   | Collation | Nullable | Default | Storage | Description 
+ +-+---+--+-+-+-
+  a  | integer |   |  | | plain   | 
+  b  | integer |   |  | | plain   | 
+ View definition:
+  SELECT foreign_tbl.a,
+ foreign_tbl.b
+FROM foreign_tbl
+   WHERE foreign_tbl.a < foreign_tbl.b;
+ Options: check_option=cascaded
+ 
+ INSERT INTO rw_view VALUES (0, 10); -- ok
+ INSERT INTO rw_view VALUES (10, 0); -- should fail
+ ERROR:  new row violates check option for view "rw_view"
+ DETAIL:  Failing row contains (10, 0).
+ EXPLAIN (VERBOSE, COSTS OFF)
+ UPDATE rw_view SET b = 20 WHERE a = 0; -- not pushed down
+ QUERY PLAN

+ 
--
+  Update on public.foreign_tbl
+Remote SQL: UPDATE public.base_tbl SET b = $2 WHERE ctid = $1
+->  Foreign Scan on public.foreign_tbl
+  Output: foreign_tbl.a, 20, foreign_tbl.ctid
+  Remote SQL: SELECT a, ctid FROM public.base_tbl WHERE ((a < b)) AND 
((a = 0)) FOR UPDATE
+ (5 rows)
+ 
+ UPDATE rw_view SET b = 20 WHERE a = 0; -- ok
+ EXPLAIN (VERBOSE, COSTS OFF)
+ UPDATE rw_view SET b = -20 WHERE a = 0; -- not pushed down
+ QUERY PLAN

+ 
--
+  Update on public.foreign_tbl
+Remote SQL: UPDATE public.base_tbl SET b = $2 WHERE ctid = $1
+->  Foreign Scan on public.foreign_tbl
+  Output: foreign_tbl.a, '-20'::integer, foreign_tbl.ctid
+  Remote SQL: SELECT a, ctid FROM public.base_tbl WHERE ((a < b)) AND 
((a = 0)) FOR UPDATE
+ (5 rows)
+ 
+ UPDATE rw_view SET b = -20 WHERE a = 0; -- should fail
+ ERROR:  new row violates check option for view "rw_view"
+ DETAIL:  Failing row contains (0, -20).
+ SELECT * FROM foreign_tbl;
+  a | b  
+ ---+
+  0 | 20
+ (1 row)
+ 
+ DROP FOREIGN TABLE foreign_tbl CASCADE;
+ NOTICE:  drop cascades to view rw_view
+ DROP TABLE base_tbl;
+ -- ===
  -- test serial columns (ie, sequence-based defaults)
  -- ===
  create table loc1 (f1 serial, f2 text);
*** a/contrib/postgres_fdw/sql/postgres_fdw.sql
--- b/contrib/postgres_fdw/sql/postgres_fdw.sql
***
*** 1158,1163  UPDATE ft1 SET c2 = c2 + 1 WHERE c1 = 1;
--- 1158,1187 
  ALTER FOREIGN TABLE ft1 DROP CONSTRAINT ft1_c2negative;
  
  -- ===
+ -- test WITH CHECK OPTION constraints
+ -- ===
+ 
+ CREATE TABLE base_tbl (a int, b int);
+ CREATE FOREIGN TABLE foreign_tbl (a int, b int)
+   SERVER loopback OPTIONS(table_name 'base_tbl');
+ CREATE VIEW rw_view AS SELECT * FROM foreign_tbl
+   WHERE a < b WITH CHECK OPTION;
+ \d+ rw_view
+ 
+ INSERT INTO rw_view VALUES (0, 10); -- ok
+ INSERT INTO rw_view VALUES (10, 0); -- should fail
+ EXPLAIN (VERBOSE, COSTS OFF)
+ UPDATE rw_view SET b = 20 WHERE a = 0; -- not pushed down
+ UPDATE rw_view SET b = 20 WHERE a = 0; -- ok
+ EXPLAIN (VERBOSE, COSTS OFF)
+ UPDATE rw_view SET b = -20 WHERE a = 0; -- not pushed down
+ UPDATE rw_view SET b = -20 WHERE a = 0; -- should fail
+ SELECT * FROM foreign_tbl;
+ 
+ DROP FOREIGN TABLE foreign_tbl CASCADE;
+ DROP TABLE base_tbl;
+ 
+ -- ===
  -- test serial columns (ie, sequence-based defaults)
  -- 

[HACKERS] Mishandling of WCO constraints in direct foreign table modification

2017-07-20 Thread Etsuro Fujita

Here is an example for $subject using postgres_fdw:

postgres=# create foreign table foreign_tbl (a int, b int) server 
loopback options (table_name 'base_tbl');

CREATE FOREIGN TABLE
postgres=# create view rw_view as select * from foreign_tbl where a < b 
with check option;

CREATE VIEW
postgres=# insert into rw_view values (0, 10);
INSERT 0 1
postgres=# explain verbose update rw_view set a = 20 where b = 10;
  QUERY PLAN
--
 Update on public.foreign_tbl  (cost=100.00..146.21 rows=4 width=14)
   ->  Foreign Update on public.foreign_tbl  (cost=100.00..146.21 
rows=4 width=14)
 Remote SQL: UPDATE public.base_tbl SET a = 20 WHERE ((a < b)) 
AND ((b = 10))

(3 rows)

postgres=# update rw_view set a = 20 where b = 10;
UPDATE 1

This is wrong!  This should fail.  The reason for that is; direct modify 
is overlooking checking WITH CHECK OPTION constraints from parent views. 
 I think we could do direct modify, even if there are any WITH CHECK 
OPTIONs, in some way or other, but I think that is a feature.  So, I'd 
like to propose to fix this by just giving up direct modify if there are 
any WITH CHECK OPTIONs.  Attached is a patch for that.  I'll add it to 
the next commitfest.


Best regards,
Etsuro Fujita
*** a/contrib/postgres_fdw/expected/postgres_fdw.out
--- b/contrib/postgres_fdw/expected/postgres_fdw.out
***
*** 5856,5861  INSERT INTO ft1(c1, c2) VALUES(, 2);
--- 5856,5921 
  UPDATE ft1 SET c2 = c2 + 1 WHERE c1 = 1;
  ALTER FOREIGN TABLE ft1 DROP CONSTRAINT ft1_c2negative;
  -- ===
+ -- test WITH CHECK OPTION constraints
+ -- ===
+ CREATE TABLE base_tbl (a int, b int);
+ CREATE FOREIGN TABLE foreign_tbl (a int, b int)
+   SERVER loopback OPTIONS(table_name 'base_tbl');
+ CREATE VIEW rw_view AS SELECT * FROM foreign_tbl
+   WHERE a < b WITH CHECK OPTION;
+ \d+ rw_view
+View "public.rw_view"
+  Column |  Type   | Collation | Nullable | Default | Storage | Description 
+ +-+---+--+-+-+-
+  a  | integer |   |  | | plain   | 
+  b  | integer |   |  | | plain   | 
+ View definition:
+  SELECT foreign_tbl.a,
+ foreign_tbl.b
+FROM foreign_tbl
+   WHERE foreign_tbl.a < foreign_tbl.b;
+ Options: check_option=cascaded
+ 
+ INSERT INTO rw_view VALUES (0, 10); -- ok
+ INSERT INTO rw_view VALUES (10, 0); -- should fail
+ ERROR:  new row violates check option for view "rw_view"
+ DETAIL:  Failing row contains (10, 0).
+ EXPLAIN (VERBOSE, COSTS OFF)
+ UPDATE rw_view SET b = 20 WHERE a = 0; -- not pushed down
+ QUERY PLAN

+ 
--
+  Update on public.foreign_tbl
+Remote SQL: UPDATE public.base_tbl SET b = $2 WHERE ctid = $1
+->  Foreign Scan on public.foreign_tbl
+  Output: foreign_tbl.a, 20, foreign_tbl.ctid
+  Remote SQL: SELECT a, ctid FROM public.base_tbl WHERE ((a < b)) AND 
((a = 0)) FOR UPDATE
+ (5 rows)
+ 
+ UPDATE rw_view SET b = 20 WHERE a = 0; -- ok
+ EXPLAIN (VERBOSE, COSTS OFF)
+ UPDATE rw_view SET b = -20 WHERE a = 0; -- not pushed down
+ QUERY PLAN

+ 
--
+  Update on public.foreign_tbl
+Remote SQL: UPDATE public.base_tbl SET b = $2 WHERE ctid = $1
+->  Foreign Scan on public.foreign_tbl
+  Output: foreign_tbl.a, '-20'::integer, foreign_tbl.ctid
+  Remote SQL: SELECT a, ctid FROM public.base_tbl WHERE ((a < b)) AND 
((a = 0)) FOR UPDATE
+ (5 rows)
+ 
+ UPDATE rw_view SET b = -20 WHERE a = 0; -- should fail
+ ERROR:  new row violates check option for view "rw_view"
+ DETAIL:  Failing row contains (0, -20).
+ SELECT * FROM foreign_tbl;
+  a | b  
+ ---+
+  0 | 20
+ (1 row)
+ 
+ DROP FOREIGN TABLE foreign_tbl CASCADE;
+ NOTICE:  drop cascades to view rw_view
+ DROP TABLE base_tbl;
+ -- ===
  -- test serial columns (ie, sequence-based defaults)
  -- ===
  create table loc1 (f1 serial, f2 text);
*** a/contrib/postgres_fdw/sql/postgres_fdw.sql
--- b/contrib/postgres_fdw/sql/postgres_fdw.sql
***
*** 1158,1163  UPDATE ft1 SET c2 = c2 + 1 WHERE c1 = 1;
--- 1158,1187 
  ALTER FOREIGN TABLE ft1 DROP CONSTRAINT ft1_c2negative;
  
  -- ==

Re: [HACKERS] Bug in ExecModifyTable function and trigger issues for foreign tables

2017-07-19 Thread Etsuro Fujita

On 2017/07/19 23:36, Tom Lane wrote:

Etsuro Fujita <fujita.ets...@lab.ntt.co.jp> writes:

* Modified rewrite_targetlist(), which is a new function added to
preptlist.c, so that we do const-simplification to junk TLEs that
AddForeignUpdateTargets() added, as that API allows the FDW to add junk
TLEs containing non-Var expressions to the query's targetlist.


This does not seem like a good idea to me.  eval_const_expressions is not
a cheap thing, and for most use-cases those cycles will be wasted, and it
has never been the responsibility of preprocess_targetlist to do this sort
of thing.


Hm, I added that const-simplification to that function so that the 
existing FDWs that append junk TLEs that need const-simplification, 
which I don't know really exist, would work well for this fix, without 
any changes, but I agree on that point.



Please put the responsibility of doing const-expression simplification
in these cases somewhere closer to where the problem is being created.


It would be reasonable that it's the FDW's responsibility to do that 
const-simplification if necessary?


Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Bug in ExecModifyTable function and trigger issues for foreign tables

2017-07-19 Thread Etsuro Fujita

On 2017/07/13 21:10, Etsuro Fujita wrote:

Attached is an updated version of the patch.

Here is an updated version of the patch.  Changes are:

* Modified rewrite_targetlist(), which is a new function added to 
preptlist.c, so that we do const-simplification to junk TLEs that 
AddForeignUpdateTargets() added, as that API allows the FDW to add junk 
TLEs containing non-Var expressions to the query's targetlist.

* Updated docs in fdwhandler.sgml.

Best regards,
Etsuro Fujita
*** a/contrib/postgres_fdw/expected/postgres_fdw.out
--- b/contrib/postgres_fdw/expected/postgres_fdw.out
***
*** 6924,6929  update bar set f2 = f2 + 100 returning *;
--- 6924,6988 
7 | 277
  (6 rows)
  
+ -- Test that UPDATE/DELETE with inherited target works with row-level triggers
+ CREATE TRIGGER trig_row_before
+ BEFORE UPDATE OR DELETE ON bar2
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ CREATE TRIGGER trig_row_after
+ AFTER UPDATE OR DELETE ON bar2
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ explain (verbose, costs off)
+ update bar set f2 = f2 + 100;
+   QUERY PLAN  

+ 
--
+  Update on public.bar
+Update on public.bar
+Foreign Update on public.bar2
+  Remote SQL: UPDATE public.loct2 SET f2 = $2 WHERE ctid = $1 RETURNING 
f1, f2, f3
+->  Seq Scan on public.bar
+  Output: bar.f1, (bar.f2 + 100), bar.ctid
+->  Foreign Scan on public.bar2
+  Output: bar2.f1, (bar2.f2 + 100), bar2.f3, bar2.ctid, bar2.*
+  Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE
+ (9 rows)
+ 
+ update bar set f2 = f2 + 100;
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
+ NOTICE:  OLD: (3,333,33),NEW: (3,433,33)
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
+ NOTICE:  OLD: (4,344,44),NEW: (4,444,44)
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
+ NOTICE:  OLD: (7,277,77),NEW: (7,377,77)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
+ NOTICE:  OLD: (3,333,33),NEW: (3,433,33)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
+ NOTICE:  OLD: (4,344,44),NEW: (4,444,44)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
+ NOTICE:  OLD: (7,277,77),NEW: (7,377,77)
+ explain (verbose, costs off)
+ delete from bar where f2 < 400;
+  QUERY PLAN   
   
+ 
-
+  Delete on public.bar
+Delete on public.bar
+Foreign Delete on public.bar2
+  Remote SQL: DELETE FROM public.loct2 WHERE ctid = $1 RETURNING f1, f2, f3
+->  Seq Scan on public.bar
+  Output: bar.ctid
+  Filter: (bar.f2 < 400)
+->  Foreign Scan on public.bar2
+  Output: bar2.ctid, bar2.*
+  Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 WHERE ((f2 < 
400)) FOR UPDATE
+ (10 rows)
+ 
+ delete from bar where f2 < 400;
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW DELETE ON bar2
+ NOTICE:  OLD: (7,377,77)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW DELETE ON bar2
+ NOTICE:  OLD: (7,377,77)
+ -- cleanup
+ DROP TRIGGER trig_row_before ON bar2;
+ DROP TRIGGER trig_row_after ON bar2;
  drop table foo cascade;
  NOTICE:  drop cascades to foreign table foo2
  drop table bar cascade;
*** a/contrib/postgres_fdw/sql/postgres_fdw.sql
--- b/contrib/postgres_fdw/sql/postgres_fdw.sql
***
*** 1609,1614  explain (verbose, costs off)
--- 1609,1634 
  update bar set f2 = f2 + 100 returning *;
  update bar set f2 = f2 + 100 returning *;
  
+ -- Test that UPDATE/DELETE with inherited target works with row-level triggers
+ CREATE TRIGGER trig_row_before
+ BEFORE UPDATE OR DELETE ON bar2
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ 
+ CREATE TRIGGER trig_row_after
+ AFTER UPDATE OR DELETE ON bar2
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ 
+ explain (verbose, costs off)
+ update bar set f2 = f2 + 100;
+ update bar set f2 = f2 + 100;
+ 
+ explain (verbose, costs off)
+ delete from bar where f2 < 400;
+ delete from bar where f2 < 400;
+ 
+ -- cleanup
+ DROP TRIGGER trig_row_before ON bar2;
+ DROP TRIGGER trig_row_after ON bar2;
  drop table foo cascade;
  drop table bar cascade;
  drop table loct1;
*** a/doc/src/sgml/fdwhandler.sgml
--- b/doc/src/sgml/fdwhandler.sgml
***
*** 432,438  AddForeignUpdateTargets (Query *parsetree,
  
  
  
!  This function is called in the rewriter, not the planner, so the
   information available is a bit different from that available to the
   planning routines.
   parsetree is the parse tree for the UPDATE or
--- 432,438 
  
  
  
!  Although this fun

[HACKERS] Re: Oddity in error handling of constraint violation in ExecConstraints for partitioned tables

2017-07-18 Thread Etsuro Fujita

On 2017/07/18 11:03, Robert Haas wrote:

On Mon, Jul 10, 2017 at 5:44 PM, Robert Haas <robertmh...@gmail.com> wrote:

The posted patches look OK to me.  Barring developments, I will commit
them on 2017-07-17, or send another update by then.


Committed them.


Thank you!

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Bug in ExecModifyTable function and trigger issues for foreign tables

2017-07-13 Thread Etsuro Fujita

On 2017/06/30 18:44, Etsuro Fujita wrote:

On 2017/06/16 21:29, Etsuro Fujita wrote:
I'll have second thought about this, so I'll mark this as waiting on 
author.


I spent quite a bit of time on this and came up with a solution for 
addressing the concern mentioned by Ashutosh [1].  The basic idea is, as 
I said before, to move rewriteTargetListUD from the rewriter to the 
planner (whether the update or delete is inherited or not), except for 
the view case.  In case of inherited UPDATE/DELETE, the planner adds a 
necessary junk column needed for the update or delete for each child 
relation, without the assumption I made before about junk tlist entries, 
so I think this would be more robust for future changes as mentioned in 
[1].  It wouldn't work well that the planner does the same thing for the 
view case (ie, add a whole-row reference to the given target relation), 
unlike other cases, because what we need to do for that case is to add a 
whole-row reference to the view as the source for an INSTEAD OF trigger, 
not the target.  So, ISTM that it's reasonable to handle that case in 
the rewriter as-is, not in the planner, but one thing I'd like to 
propose to simplify the code in rewriteHandler.c is to move the code for 
the view case in rewriteTargetListUD to ApplyRetrieveRule.  By that 
change, we won't add a whole-row reference to the view in RewriteQuery, 
so we don't need this annoying thing in rewriteTargetView any more:


/*
 * For UPDATE/DELETE, rewriteTargetListUD will have added a 
wholerow junk
 * TLE for the view to the end of the targetlist, which we no 
longer need.

 * Remove it to avoid unnecessary work when we process the targetlist.
 * Note that when we recurse through rewriteQuery a new junk TLE 
will be

 * added to allow the executor to find the proper row in the new target
 * relation.  (So, if we failed to do this, we might have multiple junk
 * TLEs with the same name, which would be disastrous.)
 */
if (parsetree->commandType != CMD_INSERT)
{
TargetEntry *tle = (TargetEntry *) llast(parsetree->targetList);

Assert(tle->resjunk);
Assert(IsA(tle->expr, Var) &&
   ((Var *) tle->expr)->varno == parsetree->resultRelation &&
   ((Var *) tle->expr)->varattno == 0);
parsetree->targetList = list_delete_ptr(parsetree->targetList, 
tle);

}

Attached is an updated version of the patch.  Comments are welcome!

Best regards,
Etsuro Fujita

[1] 
https://www.postgresql.org/message-id/CAFjFpRfTpamoUz6fNyk6gPh%3DecfBJjbUHJNKbDxscpyPJ3FfjQ%40mail.gmail.com
*** a/contrib/postgres_fdw/expected/postgres_fdw.out
--- b/contrib/postgres_fdw/expected/postgres_fdw.out
***
*** 6924,6929  update bar set f2 = f2 + 100 returning *;
--- 6924,6988 
7 | 277
  (6 rows)
  
+ -- Test that UPDATE/DELETE with inherited target works with row-level triggers
+ CREATE TRIGGER trig_row_before
+ BEFORE UPDATE OR DELETE ON bar2
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ CREATE TRIGGER trig_row_after
+ AFTER UPDATE OR DELETE ON bar2
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ explain (verbose, costs off)
+ update bar set f2 = f2 + 100;
+   QUERY PLAN  

+ 
--
+  Update on public.bar
+Update on public.bar
+Foreign Update on public.bar2
+  Remote SQL: UPDATE public.loct2 SET f2 = $2 WHERE ctid = $1 RETURNING 
f1, f2, f3
+->  Seq Scan on public.bar
+  Output: bar.f1, (bar.f2 + 100), bar.ctid
+->  Foreign Scan on public.bar2
+  Output: bar2.f1, (bar2.f2 + 100), bar2.f3, bar2.ctid, bar2.*
+  Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE
+ (9 rows)
+ 
+ update bar set f2 = f2 + 100;
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
+ NOTICE:  OLD: (3,333,33),NEW: (3,433,33)
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
+ NOTICE:  OLD: (4,344,44),NEW: (4,444,44)
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
+ NOTICE:  OLD: (7,277,77),NEW: (7,377,77)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
+ NOTICE:  OLD: (3,333,33),NEW: (3,433,33)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
+ NOTICE:  OLD: (4,344,44),NEW: (4,444,44)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
+ NOTICE:  OLD: (7,277,77),NEW: (7,377,77)
+ explain (verbose, costs off)
+ delete from bar where f2 < 400;
+  QUERY PLAN   
   
+ 
-
+  Delete on public.bar
+Delete on public.bar
+Foreign Delete on public.bar2
+  Remote SQL: DELETE FROM public.lo

Re: [HACKERS] Oddity in error handling of constraint violation in ExecConstraints for partitioned tables

2017-07-09 Thread Etsuro Fujita

On 2017/07/07 18:47, Amit Langote wrote:

On 2017/07/06 16:06, Etsuro Fujita wrote:

I think this should be fixed.  Attached is a patch for that.


Looking up the ResultRelInfo using the proposed method in
ExecFindResultRelInfo() can be unreliable sometimes, that is, the method
of using the root table OID to pin down the RangeTableEntry to get the the
modified columns set.


You are right.  Thank you for pointing that out.


How about setting ri_RangeTableIndex of the partition ResultRelInfo
correctly in the first place?  If you look at the way InitResultRelInfo()
is called in ExecSetupPartitionTupleRouting(), a dummy RT index of 1 is
passed.  We could instead pass the correct one.  I think
ModifyTable.nominalRelation is that (at least in the INSERT case.

The attached patch implements that.  It modifies
ExecSetupPartitionTupleRouting to accept one more argument resultRTindex
and passes along the same to InitResultRelInfo().  Later when
ExecConstraints() wants to build the modifiedCols set, it looks up the
correct RTE using the partition ResultRelInfo, which has the appropriate
ri_RangeTableIndex set and uses the same.


Looks good to me.


The patch keeps tests that you added in your patch.  Added this to the
open items list.


Another thing I noticed is the error handling in ExecWithCheckOptions; 
it doesn't take any care for partition tables, so the column description 
in the error message for WCO_VIEW_CHECK is built using the partition 
table's rowtype, not the root table's.  But I think it'd be better to 
build that using the root table's rowtype, like ExecConstraints, because 
that would make the column description easier to understand since the 
parent view(s) (from which WithCheckOptions evaluated there are created) 
would have been defined on the root table.  This seems independent from 
the above issue, so I created a separate patch, which I'm attaching. 
What do you think about that?


Best regards,
Etsuro Fujita
*** a/src/backend/executor/execMain.c
--- b/src/backend/executor/execMain.c
***
*** 2097,2102  ExecWithCheckOptions(WCOKind kind, ResultRelInfo 
*resultRelInfo,
--- 2097,2121 
 * USING policy.
 */
case WCO_VIEW_CHECK:
+   /* See the comment in 
ExecConstraints(). */
+   if (resultRelInfo->ri_PartitionRoot)
+   {
+   HeapTuple   tuple = 
ExecFetchSlotTuple(slot);
+   TupleDesc   old_tupdesc = 
RelationGetDescr(rel);
+   TupleConversionMap *map;
+ 
+   rel = 
resultRelInfo->ri_PartitionRoot;
+   tupdesc = RelationGetDescr(rel);
+   /* a reverse map */
+   map = 
convert_tuples_by_name(old_tupdesc, tupdesc,
+   
 gettext_noop("could not convert row type"));
+   if (map != NULL)
+   {
+   tuple = 
do_convert_tuple(tuple, map);
+   ExecStoreTuple(tuple, 
slot, InvalidBuffer, false);
+   }
+   }
+ 
insertedCols = 
GetInsertedColumns(resultRelInfo, estate);
updatedCols = 
GetUpdatedColumns(resultRelInfo, estate);
modifiedCols = bms_union(insertedCols, 
updatedCols);
*** a/src/test/regress/expected/updatable_views.out
--- b/src/test/regress/expected/updatable_views.out
***
*** 2424,2429  select tableoid::regclass, * from pt;
  create view ptv_wco as select * from pt where a = 0 with check option;
  insert into ptv_wco values (1, 2);
  ERROR:  new row violates check option for view "ptv_wco"
! DETAIL:  Failing row contains (2, 1).
  drop view ptv, ptv_wco;
  drop table pt, pt1, pt11;
--- 2424,2429 
  create view ptv_wco as select * from pt where a = 0 with check option;
  insert into ptv_wco values (1, 2);
  ERROR:  new row violates check option for view "ptv_wco"
! DETAIL:  Failing row contains (1, 2).
  drop view ptv, ptv_wco;
  drop table pt, pt1, pt11;

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Add support for tuple routing to foreign partitions

2017-07-06 Thread Etsuro Fujita

On 2017/07/05 9:13, Amit Langote wrote:

On 2017/06/29 20:20, Etsuro Fujita wrote:



In relation to this, I also allowed expand_inherited_rtentry() to
build an RTE and AppendRelInfo for each partition of a partitioned table
that is an INSERT target, as mentioned by Amit in [1], by modifying
transformInsertStmt() so that we set the inh flag for the target table's
RTE to true when the target table is a partitioned table.


About this part, Robert sounded a little unsure back then [1]; his words:

"Doing more inheritance expansion early is probably not a good idea
because it likely sucks for performance, and that's especially unfortunate
if it's only needed for foreign tables."

But...


The partition
RTEs are not only referenced by FDWs, but used in selecting relation
aliases for EXPLAIN (see below) as well as extracting plan dependencies in
setref.c so that we force rebuilding of the plan on any change to
partitions.  (We do replanning on FDW table-option changes to foreign
partitions, currently.  See regression tests in the attached patch.)


...this part means we cannot really avoid locking at least the foreign
partitions during the planning stage, which we currently don't, as we
don't look at partitions at all before ExecSetupPartitionTupleRouting() is
called by ExecInitModifyTable().


Another case where we need inheritance expansion during the planning 
stage would probably be INSERT .. ON CONFLICT into a partitioned table, 
I guess.  We don't support that yet, but if implementing that, I guess 
we would probably need to look at each partition and do something like 
infer_arbiter_indexes() for each partition during the planner stage. 
Not sure.



Since we are locking *all* the partitions anyway, it may be better to
shift the cost of locking to the planner by doing the inheritance
expansion even in the insert case (for partitioned tables) and avoid
calling the lock manager again in the executor when setting up
tuple-routing data structures (that is, in ExecSetupPartitionTupleRouting).


We need the execution-time lock, anyway.  See the comments from Robert 
in [3].



An idea that Robert recently mentioned on the nearby "UPDATE partition
key" thread [2] seems relevant in this regard.  By that idea,
expand_inherited_rtentry(), instead of reading in the partition OIDs in
the old catalog order, will instead call
RelationBuildPartitionDispatchInfo(), which locks the partitions and
returns their OIDs in the canonical order.  If we store the foreign
partition RT indexes in that order in ModifyTable.partition_rels
introduced by this patch, then the following code added by the patch could
be made more efficient (as also explained in aforementioned Robert's email):

+foreach(l, node->partition_rels)
+{
+Index   rti = lfirst_int(l);
+Oid relid = getrelid(rti, estate->es_range_table);
+boolfound;
+int j;
+
+/* First, find the ResultRelInfo for the partition */
+found = false;
+for (j = 0; j < mtstate->mt_num_partitions; j++)
+{
+resultRelInfo = partitions + j;
+
+if (RelationGetRelid(resultRelInfo->ri_RelationDesc) ==
relid)
+{
+Assert(mtstate->mt_partition_indexes[i] == 0);
+mtstate->mt_partition_indexes[i] = j;
+found = true;
+break;
+}
+}
+if (!found)
+elog(ERROR, "failed to find ResultRelInfo for rangetable
index %u", rti);


Agreed.  I really want to improve this based on that idea.

Thank you for the comments!

Best regards,
Etsuro Fujita

[3] 
https://www.postgresql.org/message-id/ca+tgmoyiwvicdri3zk+quxj1r7umu9t_kdnq+17pcwgzrbz...@mail.gmail.com




--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] Another comment typo in execMain.c

2017-07-06 Thread Etsuro Fujita

Here is a comment in ExecFindPartition() in execMain.c:

/*
 * First check the root table's partition constraint, if any.  No 
point in

 * routing the tuple it if it doesn't belong in the root table itself.
 */

I think that in the second sentence "it" just before "if" is a typo. 
Attached is a small patch for fixing that.


Best regards,
Etsuro Fujita
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 0f08283..06b467b 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -3310,7 +3310,7 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, 
PartitionDispatch *pd,
 
/*
 * First check the root table's partition constraint, if any.  No point 
in
-* routing the tuple it if it doesn't belong in the root table itself.
+* routing the tuple if it doesn't belong in the root table itself.
 */
if (resultRelInfo->ri_PartitionCheck)
ExecPartitionCheck(resultRelInfo, slot, estate);

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] Oddity in error handling of constraint violation in ExecConstraints for partitioned tables

2017-07-06 Thread Etsuro Fujita

Here is an example:

postgres=# create table col_desc (a int, b int) partition by list (a);
postgres=# create table col_desc_1 partition of col_desc for values in (1);
postgres=# alter table col_desc_1 add check (b > 0);
postgres=# create role col_desc_user;
postgres=# grant insert on col_desc to col_desc_user;
postgres=# revoke select on col_desc from col_desc_user;
postgres=# set role col_desc_user;
postgres=> insert into col_desc values (1, -1) returning 1;
ERROR:  new row for relation "col_desc_1" violates check constraint 
"col_desc_1_b_check"

DETAIL:  Failing row contains (a, b) = (1, -1).

Looks good, but

postgres=> reset role;
postgres=# create table result (f1 text default 'foo', f2 text default 
'bar', f3 int);

postgres=# grant insert on result to col_desc_user;
postgres=# set role col_desc_user;
postgres=> with t as (insert into col_desc values (1, -1) returning 1) 
insert into result (f3) select * from t;
ERROR:  new row for relation "col_desc_1" violates check constraint 
"col_desc_1_b_check"


Looks odd to me because the error message doesn't show any DETAIL info; 
since the CTE query, which produces the message, is the same as the 
above query, the message should also be the same as the one for the 
above query.  I think the reason for that is: ExecConstraints looks at 
an incorrect resultRelInfo to build the message for a violating tuple 
that has been routed *in the case where the partitioned table isn't the 
primary ModifyTable node*, which leads to deriving an incorrect 
modifiedCols and then invoking ExecBuildSlotValueDescription with the 
wrong bitmap.  I think this should be fixed.  Attached is a patch for that.


Best regards,
Etsuro Fujita
*** a/src/backend/executor/execMain.c
--- b/src/backend/executor/execMain.c
***
*** 92,97  static bool ExecCheckRTEPermsModified(Oid relOid, Oid userid,
--- 92,99 
  Bitmapset *modifiedCols,
  AclMode requiredPerms);
  static void ExecCheckXactReadOnly(PlannedStmt *plannedstmt);
+ static ResultRelInfo *ExecFindResultRelInfo(EState *estate, Oid relid,
+   
bool missing_ok);
  static char *ExecBuildSlotValueDescription(Oid reloid,
  TupleTableSlot *slot,
  TupleDesc tupdesc,
***
*** 1360,1365  InitResultRelInfo(ResultRelInfo *resultRelInfo,
--- 1362,1392 
  }
  
  /*
+  * ExecFindResultRelInfo -- find the ResultRelInfo struct for given relation 
OID
+  *
+  * If no such struct, either return NULL or throw error depending on 
missing_ok
+  */
+ static ResultRelInfo *
+ ExecFindResultRelInfo(EState *estate, Oid relid, bool missing_ok)
+ {
+   ResultRelInfo *rInfo;
+   int nr;
+ 
+   rInfo = estate->es_result_relations;
+   nr = estate->es_num_result_relations;
+   while (nr > 0)
+   {
+   if (RelationGetRelid(rInfo->ri_RelationDesc) == relid)
+   return rInfo;
+   rInfo++;
+   nr--;
+   }
+   if (!missing_ok)
+   elog(ERROR, "failed to find ResultRelInfo for relation %u", 
relid);
+   return NULL;
+ }
+ 
+ /*
   *ExecGetTriggerResultRel
   *
   * Get a ResultRelInfo for a trigger target relation.  Most of the time,
***
*** 1379,1399  ResultRelInfo *
  ExecGetTriggerResultRel(EState *estate, Oid relid)
  {
ResultRelInfo *rInfo;
-   int nr;
ListCell   *l;
Relationrel;
MemoryContext oldcontext;
  
/* First, search through the query result relations */
!   rInfo = estate->es_result_relations;
!   nr = estate->es_num_result_relations;
!   while (nr > 0)
!   {
!   if (RelationGetRelid(rInfo->ri_RelationDesc) == relid)
!   return rInfo;
!   rInfo++;
!   nr--;
!   }
/* Nope, but maybe we already made an extra ResultRelInfo for it */
foreach(l, estate->es_trig_target_relations)
{
--- 1406,1419 
  ExecGetTriggerResultRel(EState *estate, Oid relid)
  {
ResultRelInfo *rInfo;
ListCell   *l;
Relationrel;
MemoryContext oldcontext;
  
/* First, search through the query result relations */
!   rInfo = ExecFindResultRelInfo(estate, relid, true);
!   if (rInfo)
!   return rInfo;
/* Nope, but maybe we already made an extra ResultRelInfo for it */
foreach(l, estate->es_trig_target_relations)
{
***
*** 1828,1833  ExecPartitionCheck(ResultRelInfo *resultRelInfo, 
TupleTableSlot *slot,
--- 1848,1854 
  

Re: [HACKERS] Update comment in ExecPartitionCheck

2017-07-06 Thread Etsuro Fujita

On 2017/07/04 18:15, Amit Langote wrote:

On 2017/07/04 17:55, Etsuro Fujita wrote:

This comment in an error handling in ExecPartitionCheck():

 if (!ExecCheck(resultRelInfo->ri_PartitionCheckExpr, econtext))
 {
 char   *val_desc;
 Relationorig_rel = rel;

 /* See the comment above. */
 if (resultRelInfo->ri_PartitionRoot)

should be updated because we don't have any comment on that above in the
code.  Since we have a comment on that in ExecConstraints() defined just
below that function, I think the comment should be something like this:
"See the comment in ExecConstraints().".  Attached is a patch for that.


Thanks for fixing that.  I forgot to do the same in the patch that got
committed as 15ce775faa428 [1], which moved that code block from
ExecConstraints() to ExecPartitionCheck().


Thanks for the explanation!

In relation to this, I found odd behavior in the error handling.  Since 
that is another topic, I'll start a new thread.


Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] Update comment in ExecPartitionCheck

2017-07-04 Thread Etsuro Fujita

This comment in an error handling in ExecPartitionCheck():

if (!ExecCheck(resultRelInfo->ri_PartitionCheckExpr, econtext))
{
char   *val_desc;
Relationorig_rel = rel;

/* See the comment above. */
if (resultRelInfo->ri_PartitionRoot)

should be updated because we don't have any comment on that above in the 
code.  Since we have a comment on that in ExecConstraints() defined just 
below that function, I think the comment should be something like this: 
"See the comment in ExecConstraints().".  Attached is a patch for that.


Best regards,
Etsuro Fujita
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 0f08283..dcf685a 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -1864,7 +1864,7 @@ ExecPartitionCheck(ResultRelInfo *resultRelInfo, 
TupleTableSlot *slot,
char   *val_desc;
Relationorig_rel = rel;
 
-   /* See the comment above. */
+   /* See the comment in ExecConstraints(). */
if (resultRelInfo->ri_PartitionRoot)
{
HeapTuple   tuple = ExecFetchSlotTuple(slot);

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] UPDATE of partition key

2017-07-04 Thread Etsuro Fujita

On 2017/07/03 18:54, Amit Langote wrote:

On 2017/07/02 20:10, Robert Haas wrote:



But that seems like it wouldn't be too hard to fix: let's have
expand_inherited_rtentry() expand the partitioned table in the same
order that will be used by ExecSetupPartitionTupleRouting().


That's really what I wanted when updating the patch for tuple-routing to 
foreign partitions.  (I don't understand the issue discussed here, though.)



That
seems pretty easy to do - just have expand_inherited_rtentry() notice
that it's got a partitioned table and call
RelationGetPartitionDispatchInfo() instead of find_all_inheritors() to
produce the list of OIDs.

Seems like a good idea.


Interesting idea.

If we are going to do this, I think we may need to modify
RelationGetPartitionDispatchInfo() a bit or invent an alternative that
does not do as much work.  Currently, it assumes that it's only ever
called by ExecSetupPartitionTupleRouting() and hence also generates
PartitionDispatchInfo objects for partitioned child tables.  We don't need
that if called from within the planner.

Actually, it seems that RelationGetPartitionDispatchInfo() is too coupled
with its usage within the executor, because there is this comment:

 /*
  * We keep the partitioned ones open until we're done using the
  * information being collected here (for example, see
  * ExecEndModifyTable).
  */


Yeah, we need some refactoring work.  Is anyone working on that?

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Bug in ExecModifyTable function and trigger issues for foreign tables

2017-06-30 Thread Etsuro Fujita

On 2017/06/16 21:29, Etsuro Fujita wrote:

On 2017/06/16 19:26, Ashutosh Bapat wrote:



That issue has not been addressed. The reason stated was that it would
make code complicated. But I have not had chance to look at how
complicated would be and assess myself whether that's worth the
trouble.
I have to admit that what I proposed upthread is a quick-and-dirty 
kluge.  One thing I thought to address your concern was to move 
rewriteTargetListUD entirely from the rewriter to the planner when doing 
inherited UPDATE/DELETE, but I'm not sure that's a good idea, because at 
least I think that would need a lot more changes to the rewriter.


I'll have second thought about this, so I'll mark this as waiting on author.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Declarative partitioning - another take

2017-06-29 Thread Etsuro Fujita

Hi Maksim,

On 2017/04/07 19:52, Maksim Milyutin wrote:

On 07.04.2017 13:05, Etsuro Fujita wrote:



On 2016/12/09 19:46, Maksim Milyutin wrote:

I would like to work on two tasks:
 - insert (and eventually update) tuple routing for foreign partition.
 - the ability to create an index on the parent and have all of the
children inherit it;



There seems to be no work on the first one, so I'd like to work on that.



Yes, you can start to work on this, I'll join later as a reviewer.


Great!  I added the patch to the next commitfest:

https://commitfest.postgresql.org/14/1184/

Sorry for the delay.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] Add support for tuple routing to foreign partitions

2017-06-29 Thread Etsuro Fujita

Hi,

Here is a patch for $subject.  This is based on Amit's original patch 
(patch '0007-Tuple-routing-for-partitioned-tables-15.patch' in [1]). 
Main changes are:


* I like Amit's idea that for each partition that is a foreign table, 
the FDW performs query planning in the same way as in non-partition 
cases, but the changes to make_modifytable() in the original patch that 
creates a working-copy of Query to pass to PlanForeignModify() seem 
unacceptable.  So, I modified the changes so that we create 
more-valid-looking copies of Query and ModifyTable with the foreign 
partition as target, as I said before.  In relation to this, I also 
allowed expand_inherited_rtentry() to build an RTE and AppendRelInfo for 
each partition of a partitioned table that is an INSERT target, as 
mentioned by Amit in [1], by modifying transformInsertStmt() so that we 
set the inh flag for the target table's RTE to true when the target 
table is a partitioned table.  The partition RTEs are not only 
referenced by FDWs, but used in selecting relation aliases for EXPLAIN 
(see below) as well as extracting plan dependencies in setref.c so that 
we force rebuilding of the plan on any change to partitions.  (We do 
replanning on FDW table-option changes to foreign partitions, currently. 
 See regression tests in the attached patch.)


* The original patch added tuple routing to foreign partitions in COPY 
FROM, but I'm not sure the changes to BeginCopy() in the patch are the 
right way to go.  For example, the patch passes a dummy empty Query to 
PlanForeignModify() to make FDWs perform query planning, but I think 
FDWs would be surprised by the Query.  Currently, we don't support COPY 
to foreign tables, so ISTM that it's better to revisit this issue when 
adding support for COPY to foreign tables.  So, I dropped the COPY part.


* I modified explain.c so that EXPLAIN for an INSERT into a partitioned 
table displays partitions just below the ModifyTable node, and shows 
remote queries for foreign partitions in the same way as EXPLAIN for 
UPDATE/DELETE cases.  Here is an example:


postgres=# explain verbose insert into pt values (1), (2);
QUERY PLAN
---
 Insert on public.pt  (cost=0.00..0.03 rows=2 width=4)
   Foreign Insert on public.fp1
 Remote SQL: INSERT INTO public.t1(a) VALUES ($1)
   Foreign Insert on public.fp2
 Remote SQL: INSERT INTO public.t2(a) VALUES ($1)
   ->  Values Scan on "*VALUES*"  (cost=0.00..0.03 rows=2 width=4)
 Output: "*VALUES*".column1
(7 rows)

Comments are welcome!  Anyway, I'll add this to the next commitfest.

Best regards,
Etsuro Fujita

[1] 
https://www.postgresql.org/message-id/aa874eaf-cd3b-0f75-c647-6c0ea823781e%40lab.ntt.co.jp
*** a/contrib/postgres_fdw/expected/postgres_fdw.out
--- b/contrib/postgres_fdw/expected/postgres_fdw.out
***
*** 6931,6936  NOTICE:  drop cascades to foreign table bar2
--- 6931,7074 
  drop table loct1;
  drop table loct2;
  -- ===
+ -- test tuple routing to foreign-table partitions
+ -- ===
+ create table pt (a int, b int) partition by list (a);
+ create table locp partition of pt for values in (1);
+ create table locfoo (a int check (a in (2)), b int);
+ create foreign table remp partition of pt for values in (2) server loopback 
options (table_name 'locfoo');
+ explain (verbose, costs off)
+ insert into pt values (1, 1), (2, 1);
+QUERY PLAN
+ -
+  Insert on public.pt
+Insert on public.locp
+Foreign Insert on public.remp
+  Remote SQL: INSERT INTO public.locfoo(a, b) VALUES ($1, $2)
+->  Values Scan on "*VALUES*"
+  Output: "*VALUES*".column1, "*VALUES*".column2
+ (6 rows)
+ 
+ insert into pt values (1, 1), (2, 1);
+ select tableoid::regclass, * FROM pt;
+  tableoid | a | b 
+ --+---+---
+  locp | 1 | 1
+  remp | 2 | 1
+ (2 rows)
+ 
+ select tableoid::regclass, * FROM locp;
+  tableoid | a | b 
+ --+---+---
+  locp | 1 | 1
+ (1 row)
+ 
+ select tableoid::regclass, * FROM remp;
+  tableoid | a | b 
+ --+---+---
+  remp | 2 | 1
+ (1 row)
+ 
+ explain (verbose, costs off)
+ insert into pt values (1, 2), (2, 2) returning *;
+QUERY PLAN 
  
+ 

+  Insert on public.pt
+Output: pt.a, pt.b
+Insert on public.locp
+Foreign Insert on public.remp
+  Remote SQL: INSERT INTO public.locfoo(a, b) VALUES ($1, $2) RETURNING a, 
b
+->  Values Scan on "*VALUES*"
+  Output: "*VALUES*".column1, &q

Re: [HACKERS] Missing comment for create_modifytable_path

2017-06-22 Thread Etsuro Fujita

On 2017/06/23 2:53, Robert Haas wrote:

On Thu, Jun 15, 2017 at 4:40 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

While working on adding support for tuple routing for foreign partitions, I
noticed that in create_modifytable_path, we forgot to add a comment on its
new argument 'partitioned_rels'.  Attached a patch for including that in the
comments for that function.


Committed with a slight adjustment.


Thank you for committing this patch (and another one)!

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Useless code in ExecInitModifyTable

2017-06-21 Thread Etsuro Fujita

On 2017/06/21 23:52, Robert Haas wrote:


You're right that there is a comment missing from the function header,
but it's not too hard to figure out what it should be.  Just consult
the definition of ModifyTable itself:

 /* RT indexes of non-leaf tables in a partition tree */
 List   *partitioned_rels;


I agree on that point, but I think it's better to add the missing 
comment for the create_modifytable_path argument, as proposed in [1].


Best regards,
Etsuro Fujita

[1] 
https://www.postgresql.org/message-id/e87c4a6d-23d7-5e7c-e8db-44ed418eb5d1%40lab.ntt.co.jp




--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] Comment typo in execMain.c

2017-06-21 Thread Etsuro Fujita
Here is a patch to fix a typo in a comment in ExecWithCheckOptions(): 
s/as as/as/.


Best regards,
Etsuro Fujita
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 7f460bd..9dbe175 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -2093,8 +2093,8 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo 
*resultRelInfo,
 * the permissions on the relation 
(that is, if the user
 * could view it directly anyway).  For 
RLS violations, we
 * don't include the data since we 
don't know if the user
-* should be able to view the tuple as 
as that depends on
-* the USING policy.
+* should be able to view the tuple as 
that depends on the
+* USING policy.
 */
case WCO_VIEW_CHECK:
insertedCols = 
GetInsertedColumns(resultRelInfo, estate);

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] Useless code in ExecInitModifyTable

2017-06-21 Thread Etsuro Fujita
Commit d3cc37f1d801a6b5cad9bf179274a8d767f1ee50 added this to 
ExecInitModifyTable:


+   /* The root table RT index is at the head of the partitioned_rels 
list */

+   if (node->partitioned_rels)
+   {
+   Index   root_rti;
+   Oid root_oid;
+
+   root_rti = linitial_int(node->partitioned_rels);
+   root_oid = getrelid(root_rti, estate->es_range_table);
+   rel = heap_open(root_oid, NoLock);  /* locked by InitPlan */
+   }

but I noticed that that function doesn't use the relation descriptor at 
all.  Since partitioned_rels is given in case of an UPDATE/DELETE on a 
partitioned table, the relation is opened in that case, but the relation 
descriptor isn't referenced at all in initializing WITH CHECK OPTION 
constraints and/or RETURNING projections.  (The mtstate->resultRelinfo 
array is referenced in those initialization, instead.)  So, I'd like to 
propose to remove this from that function.  Attached is a patch for that.


Best regards,
Etsuro Fujita
*** a/src/backend/executor/nodeModifyTable.c
--- b/src/backend/executor/nodeModifyTable.c
***
*** 45,51 
  #include "foreign/fdwapi.h"
  #include "miscadmin.h"
  #include "nodes/nodeFuncs.h"
- #include "parser/parsetree.h"
  #include "storage/bufmgr.h"
  #include "storage/lmgr.h"
  #include "utils/builtins.h"
--- 45,50 
***
*** 1767,1786  ExecInitModifyTable(ModifyTable *node, EState *estate, int 
eflags)
  
estate->es_result_relation_info = saved_resultRelInfo;
  
-   /* The root table RT index is at the head of the partitioned_rels list 
*/
-   if (node->partitioned_rels)
-   {
-   Index   root_rti;
-   Oid root_oid;
- 
-   root_rti = linitial_int(node->partitioned_rels);
-   root_oid = getrelid(root_rti, estate->es_range_table);
-   rel = heap_open(root_oid, NoLock);  /* locked by 
InitPlan */
-   }
-   else
-   rel = mtstate->resultRelInfo->ri_RelationDesc;
- 
/* Build state for INSERT tuple routing */
if (operation == CMD_INSERT &&
rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
--- 1766,1773 
  
estate->es_result_relation_info = saved_resultRelInfo;
  
/* Build state for INSERT tuple routing */
+   rel = mtstate->resultRelInfo->ri_RelationDesc;
if (operation == CMD_INSERT &&
rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
***
*** 1959,1968  ExecInitModifyTable(ModifyTable *node, EState *estate, int 
eflags)
mtstate->ps.ps_ExprContext = NULL;
}
  
-   /* Close the root partitioned rel if we opened it above. */
-   if (rel != mtstate->resultRelInfo->ri_RelationDesc)
-   heap_close(rel, NoLock);
- 
/*
 * If needed, Initialize target list, projection and qual for ON 
CONFLICT
 * DO UPDATE.
--- 1946,1951 

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Missing comment for ResultRelInfo in execnodes.h

2017-06-20 Thread Etsuro Fujita

On 2017/06/21 3:30, Peter Eisentraut wrote:

On 6/20/17 05:50, Etsuro Fujita wrote:

Here is a small patch to add a comment on its new member PartitionRoot.


The existing comment style is kind of unusual.  How about the attached
to clean it up a bit?


+1 for that change.

Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] Missing comment for ResultRelInfo in execnodes.h

2017-06-20 Thread Etsuro Fujita

Here is a small patch to add a comment on its new member PartitionRoot.

Best regards,
Etsuro Fujita
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index d33392f..7175a42 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -365,6 +365,7 @@ typedef struct JunkFilter
  * onConflictSetWhere  list of ON CONFLICT DO UPDATE 
exprs (qual)
  * PartitionCheck  partition check expression
  * PartitionCheckExpr  partition check expression state
+ * PartitionRoot   relation descriptor for root 
partitioned table
  * 
  */
 typedef struct ResultRelInfo

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Bug in ExecModifyTable function and trigger issues for foreign tables

2017-06-16 Thread Etsuro Fujita

On 2017/06/16 19:26, Ashutosh Bapat wrote:

On Fri, Jun 16, 2017 at 3:35 PM, Etsuro Fujita

Ashutosh mentioned his concern about what I proposed above before [2], but
I'm not sure we should address that.  And there have been no opinions from
him (or anyone else) since then.  So, I'd like to leave that for committer
(ie, +1 for Ready for Committer).


That issue has not been addressed. The reason stated was that it would
make code complicated. But I have not had chance to look at how
complicated would be and assess myself whether that's worth the
trouble.
I have to admit that what I proposed upthread is a quick-and-dirty 
kluge.  One thing I thought to address your concern was to move 
rewriteTargetListUD entirely from the rewriter to the planner when doing 
inherited UPDATE/DELETE, but I'm not sure that's a good idea, because at 
least I think that would need a lot more changes to the rewriter.


Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Bug in ExecModifyTable function and trigger issues for foreign tables

2017-06-16 Thread Etsuro Fujita

On 2017/06/16 19:26, Ashutosh Bapat wrote:

Also, I don't see any discussion about my concern [3] about a parent
with child from multiple foreign servers with different FDWs. So, I am
not sure whether the patch really fixes the problem in its entirety.


The patch would allow child tables to have different foreign servers 
with different FDWs since it applies rewriteTargetListUD to each child 
table when generating a modified query with that child table with the 
target in inheritance_planner.  I didn't any regression tests for that, 
though.


Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Bug in ExecModifyTable function and trigger issues for foreign tables

2017-06-16 Thread Etsuro Fujita

On 2017/06/16 0:05, Ildus Kurbangaliev wrote:

I wrote:

One approach I came up with to fix this issue is to rewrite the
targetList entries of an inherited UPDATE/DELETE properly using
rewriteTargetListUD, when generating a plan for each child table
in inheritance_planner.  Attached is a WIP patch for that.  Maybe
I am missing something, though.


While updating the patch, I noticed the patch rewrites the UPDATE
targetList incorrectly in some cases; rewrite_inherited_tlist I
added to adjust_appendrel_attrs (1) removes all junk items from the
targetList and (2) adds junk items for the child table using
rewriteTargetListUD, but it's wrong to drop all junk items in cases
where there are junk items for some other reasons than
rewriteTargetListUD.  Consider junk items containing MULTIEXPR
SubLink.  One way I came up with to fix this is to change (1) to
only remove junk items with resname; since junk items added by
rewriteTargetListUD should have resname (note: we would need
resname to call ExecFindJunkAttributeInTlist at execution time!)
while other junk items wouldn't have resname (see
transformUpdateTargetList), we could correctly replace junk items
added by rewriteTargetListUD for the parent with ones for the
child, by that change.  I might be missing something, though.
Comments welcome.


I updated the patch that way.  Please find attached an updated
version.

Other changes:
* Moved the initialization for "tupleid" I added in ExecModifyTable
as discussed before, which I think is essentially the same as
proposed by Ildus in [1], since I think that would be more consistent
with "oldtuple".
* Added regression tests.

Anyway I'll add this to the next commitfest.



Checked the latest patch. Looks good.
Shouldn't this patch be backported to 9.6 and 10beta? The bug
affects them too.


Thank you for the review!

The bug is in foreign table inheritance, which was supported in 9.5, so 
I think this patch should be backported to 9.5.


Ashutosh mentioned his concern about what I proposed above before [2], 
but I'm not sure we should address that.  And there have been no 
opinions from him (or anyone else) since then.  So, I'd like to leave 
that for committer (ie, +1 for Ready for Committer).


Attached is a slightly-updated version; I renamed some variables used in 
rewrite_inherited_tlist() to match other existing code in prepunion.c 
and revised some comments a bit.  I didn't make any functional changes, 
so I'll keep this Ready for Committer.


Best regards,
Etsuro Fujita

[2] 
https://www.postgresql.org/message-id/CAFjFpRfTpamoUz6fNyk6gPh%3DecfBJjbUHJNKbDxscpyPJ3FfjQ%40mail.gmail.com
*** a/contrib/postgres_fdw/expected/postgres_fdw.out
--- b/contrib/postgres_fdw/expected/postgres_fdw.out
***
*** 6924,6929  update bar set f2 = f2 + 100 returning *;
--- 6924,7038 
7 | 277
  (6 rows)
  
+ -- Test that UPDATE/DELETE with inherited target works with row-level triggers
+ CREATE TRIGGER trig_row_before
+ BEFORE UPDATE OR DELETE ON bar2
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ CREATE TRIGGER trig_row_after
+ AFTER UPDATE OR DELETE ON bar2
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ explain (verbose, costs off)
+ update bar set f2 = f2 + 100;
+   QUERY PLAN  

+ 
--
+  Update on public.bar
+Update on public.bar
+Foreign Update on public.bar2
+  Remote SQL: UPDATE public.loct2 SET f2 = $2 WHERE ctid = $1 RETURNING 
f1, f2, f3
+->  Seq Scan on public.bar
+  Output: bar.f1, (bar.f2 + 100), bar.ctid
+->  Foreign Scan on public.bar2
+  Output: bar2.f1, (bar2.f2 + 100), bar2.f3, bar2.ctid, bar2.*
+  Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE
+ (9 rows)
+ 
+ update bar set f2 = f2 + 100;
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
+ NOTICE:  OLD: (3,333,33),NEW: (3,433,33)
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
+ NOTICE:  OLD: (4,344,44),NEW: (4,444,44)
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
+ NOTICE:  OLD: (7,277,77),NEW: (7,377,77)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
+ NOTICE:  OLD: (3,333,33),NEW: (3,433,33)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
+ NOTICE:  OLD: (4,344,44),NEW: (4,444,44)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
+ NOTICE:  OLD: (7,277,77),NEW: (7,377,77)
+ explain (verbose, costs off)
+ update bar set (f2,f1) = (select f1, f2 from bar2 where f3 = 77) where f1 = 7;
+   QUERY PLAN  
 
+ 
---
+  Update on public.bar
+Update on public.bar
+Foreign Update on public.bar2
+  Remote SQ

[HACKERS] Missing comment for create_modifytable_path

2017-06-15 Thread Etsuro Fujita
While working on adding support for tuple routing for foreign 
partitions, I noticed that in create_modifytable_path, we forgot to add 
a comment on its new argument 'partitioned_rels'.  Attached a patch for 
including that in the comments for that function.


Best regards,
Etsuro Fujita
diff --git a/src/backend/optimizer/util/pathnode.c 
b/src/backend/optimizer/util/pathnode.c
index ec4a093..46bc1df 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -3159,6 +3159,8 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
  * 'operation' is the operation type
  * 'canSetTag' is true if we set the command tag/es_processed
  * 'nominalRelation' is the parent RT index for use of EXPLAIN
+ * 'partitioned_rels' is an integer list of RT indexes of non-leaf tables in
+ * the partition tree if UPDATE/DELETE to a partitioned table, 
else NIL
  * 'resultRelations' is an integer list of actual RT indexes of target rel(s)
  * 'subpaths' is a list of Path(s) producing source data (one per rel)
  * 'subroots' is a list of PlannerInfo structs (one per rel)

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Update comments in nodeModifyTable.c

2017-06-14 Thread Etsuro Fujita

On 2017/06/07 0:30, Robert Haas wrote:

On Mon, Jun 5, 2017 at 4:45 AM, Etsuro Fujita
<fujita.ets...@lab.ntt.co.jp> wrote:

While working on [1], I noticed that the comment in ExecModifyTable:

  * Foreign table updates have a wholerow attribute when the
  * relation has an AFTER ROW trigger.

is not 100% correct because a foreign table has a wholerow attrubute when
the relation has an AFTER ROW or BEFORE ROW trigger (see
rewriteTargetListUD).  So I'd propose s/an AFTER ROW trigger/a row-level
trigger/.  Attached is a patch for that.


That seems better, but looking at rewriteTargetListUD, it seems that
the actual rule is that this happens when there is a row-level on
either UPDATE or DELETE.  If there is only a row-level trigger on
INSERT, then it is not done.  Perhaps we should try to include that
detail in the comment as well.


Agreed, but I think it's better to add that detail to this comment in 
ExecInitModifyTable:


 * Initialize the junk filter(s) if needed.  INSERT queries need a 
filter

 * if there are any junk attrs in the tlist.  UPDATE and DELETE always
 * need a filter, since there's always a junk 'ctid' or 'wholerow'
 * attribute present --- no need to look first.

I'd also like to propose to update the third sentence in this comment, 
since there isn't necessarily a ctid or wholerow in the UPDATE/DELETE 
tlist when the result relation is a foreign table.


Attached is an updated version of the patch.

Best regards,
Etsuro Fujita
diff --git a/src/backend/executor/nodeModifyTable.c 
b/src/backend/executor/nodeModifyTable.c
index cf555fe..07bc870 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1554,7 +1554,7 @@ ExecModifyTable(ModifyTableState *node)
 * the old relation tuple.
 *
 * Foreign table updates have a wholerow 
attribute when the
-* relation has an AFTER ROW trigger.  Note 
that the wholerow
+* relation has a row-level trigger.  Note that 
the wholerow
 * attribute does not carry system columns.  
Foreign table
 * triggers miss seeing those, except that we 
know enough here
 * to set t_tableOid.  Quite separately from 
this, the FDW may
@@ -2025,7 +2025,11 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, 
int eflags)
 * Initialize the junk filter(s) if needed.  INSERT queries need a 
filter
 * if there are any junk attrs in the tlist.  UPDATE and DELETE always
 * need a filter, since there's always a junk 'ctid' or 'wholerow'
-* attribute present --- no need to look first.
+* attribute present if not foreign table, and if foreign table, there
+* are always junk attributes present the FDW needs to identify the 
exact
+* row to update or delete --- no need to look first.  For foreign 
tables,
+* there's also a wholerow attribute when the relation has a row-level
+* trigger on UPDATE/DELETE but not on INSERT.
 *
 * If there are multiple result relations, each one needs its own junk
 * filter.  Note multiple rels are only possible for UPDATE/DELETE, so 
we
@@ -2093,7 +2097,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, 
int eflags)
else if (relkind == 
RELKIND_FOREIGN_TABLE)
{
/*
-* When there is an AFTER 
trigger, there should be a
+* When there is a row-level 
trigger, there should be a
 * wholerow attribute.
 */
j->jf_junkAttNo = 
ExecFindJunkAttribute(j, "wholerow");

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Bug in ExecModifyTable function and trigger issues for foreign tables

2017-06-05 Thread Etsuro Fujita

On 2017/06/05 17:39, Ashutosh Bapat wrote:

On Fri, Jun 2, 2017 at 2:40 PM, Etsuro Fujita



While updating the patch, I noticed the patch rewrites the UPDATE targetList
incorrectly in some cases; rewrite_inherited_tlist I added to
adjust_appendrel_attrs (1) removes all junk items from the targetList and
(2) adds junk items for the child table using rewriteTargetListUD, but it's
wrong to drop all junk items in cases where there are junk items for some
other reasons than rewriteTargetListUD.  Consider junk items containing
MULTIEXPR SubLink.  One way I came up with to fix this is to change (1) to
only remove junk items with resname; since junk items added by
rewriteTargetListUD should have resname (note: we would need resname to call
ExecFindJunkAttributeInTlist at execution time!) while other junk items
wouldn't have resname (see transformUpdateTargetList), we could correctly
replace junk items added by rewriteTargetListUD for the parent with ones for
the child, by that change.  I might be missing something, though.  Comments
welcome.


I haven't looked at the patch, but that doesn't look right. In future
some code path other than rewriteTargetListUD() may add junk items
with resname and this fix will remove those junk items as well.


Yeah, I thought that too.  I think we could replace junk tlist entries 
added by rewriteTargetListUD() more safely, by adding a lot more code, 
but I'm not sure it's worth complicating the code at the current stage.


Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] Update comments in nodeModifyTable.c

2017-06-05 Thread Etsuro Fujita

While working on [1], I noticed that the comment in ExecModifyTable:

 * Foreign table updates have a wholerow attribute when the
 * relation has an AFTER ROW trigger.

is not 100% correct because a foreign table has a wholerow attrubute 
when the relation has an AFTER ROW or BEFORE ROW trigger (see 
rewriteTargetListUD).  So I'd propose s/an AFTER ROW trigger/a row-level 
trigger/.  Attached is a patch for that.


Best regards,
Etsuro Fujita

[1] 
https://www.postgresql.org/message-id/a31f779e-9cb8-1ea5-71a6-bca6adbfa6a4%40lab.ntt.co.jp
diff --git a/src/backend/executor/nodeModifyTable.c 
b/src/backend/executor/nodeModifyTable.c
index cf555fe..5dde93c 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1554,7 +1554,7 @@ ExecModifyTable(ModifyTableState *node)
 * the old relation tuple.
 *
 * Foreign table updates have a wholerow 
attribute when the
-* relation has an AFTER ROW trigger.  Note 
that the wholerow
+* relation has a row-level trigger.  Note that 
the wholerow
 * attribute does not carry system columns.  
Foreign table
 * triggers miss seeing those, except that we 
know enough here
 * to set t_tableOid.  Quite separately from 
this, the FDW may
@@ -2093,7 +2093,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, 
int eflags)
else if (relkind == 
RELKIND_FOREIGN_TABLE)
{
/*
-* When there is an AFTER 
trigger, there should be a
+* When there is a row-level 
trigger, there should be a
 * wholerow attribute.
 */
j->jf_junkAttNo = 
ExecFindJunkAttribute(j, "wholerow");

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Bug in ExecModifyTable function and trigger issues for foreign tables

2017-06-05 Thread Etsuro Fujita

On 2017/06/02 18:10, Etsuro Fujita wrote:

On 2017/05/16 21:36, Etsuro Fujita wrote:
One approach I came up with to fix this issue is to rewrite the 
targetList entries of an inherited UPDATE/DELETE properly using 
rewriteTargetListUD, when generating a plan for each child table in 
inheritance_planner.  Attached is a WIP patch for that.  Maybe I am 
missing something, though.


While updating the patch, I noticed the patch rewrites the UPDATE 
targetList incorrectly in some cases; rewrite_inherited_tlist I added to 
adjust_appendrel_attrs (1) removes all junk items from the targetList 
and (2) adds junk items for the child table using rewriteTargetListUD, 
but it's wrong to drop all junk items in cases where there are junk 
items for some other reasons than rewriteTargetListUD.  Consider junk 
items containing MULTIEXPR SubLink.  One way I came up with to fix this 
is to change (1) to only remove junk items with resname; since junk 
items added by rewriteTargetListUD should have resname (note: we would 
need resname to call ExecFindJunkAttributeInTlist at execution time!) 
while other junk items wouldn't have resname (see 
transformUpdateTargetList), we could correctly replace junk items added 
by rewriteTargetListUD for the parent with ones for the child, by that 
change.  I might be missing something, though.  Comments welcome.


I updated the patch that way.  Please find attached an updated version.

Other changes:
* Moved the initialization for "tupleid" I added in ExecModifyTable as 
discussed before, which I think is essentially the same as proposed by 
Ildus in [1], since I think that would be more consistent with "oldtuple".

* Added regression tests.

Anyway I'll add this to the next commitfest.

Best regards,
Etsuro Fujita

[1] 
https://www.postgresql.org/message-id/20170514150525.0346ba72%40postgrespro.ru
*** a/contrib/postgres_fdw/expected/postgres_fdw.out
--- b/contrib/postgres_fdw/expected/postgres_fdw.out
***
*** 6924,6929  update bar set f2 = f2 + 100 returning *;
--- 6924,7038 
7 | 277
  (6 rows)
  
+ -- Test that UPDATE/DELETE with inherited target works with row-level triggers
+ CREATE TRIGGER trig_row_before
+ BEFORE UPDATE OR DELETE ON bar2
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ CREATE TRIGGER trig_row_after
+ AFTER UPDATE OR DELETE ON bar2
+ FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+ explain (verbose, costs off)
+ update bar set f2 = f2 + 100;
+   QUERY PLAN  

+ 
--
+  Update on public.bar
+Update on public.bar
+Foreign Update on public.bar2
+  Remote SQL: UPDATE public.loct2 SET f2 = $2 WHERE ctid = $1 RETURNING 
f1, f2, f3
+->  Seq Scan on public.bar
+  Output: bar.f1, (bar.f2 + 100), bar.ctid
+->  Foreign Scan on public.bar2
+  Output: bar2.f1, (bar2.f2 + 100), bar2.f3, bar2.ctid, bar2.*
+  Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE
+ (9 rows)
+ 
+ update bar set f2 = f2 + 100;
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
+ NOTICE:  OLD: (3,333,33),NEW: (3,433,33)
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
+ NOTICE:  OLD: (4,344,44),NEW: (4,444,44)
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
+ NOTICE:  OLD: (7,277,77),NEW: (7,377,77)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
+ NOTICE:  OLD: (3,333,33),NEW: (3,433,33)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
+ NOTICE:  OLD: (4,344,44),NEW: (4,444,44)
+ NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
+ NOTICE:  OLD: (7,277,77),NEW: (7,377,77)
+ explain (verbose, costs off)
+ update bar set (f2,f1) = (select f1, f2 from bar2 where f3 = 77) where f1 = 7;
+   QUERY PLAN  
 
+ 
---
+  Update on public.bar
+Update on public.bar
+Foreign Update on public.bar2
+  Remote SQL: UPDATE public.loct2 SET f1 = $2, f2 = $3 WHERE ctid = $1 
RETURNING f1, f2, f3
+InitPlan 1 (returns $0,$1)
+  ->  Foreign Scan on public.bar2 bar2_1
+Output: bar2_1.f1, bar2_1.f2
+Remote SQL: SELECT f1, f2 FROM public.loct2 WHERE ((f3 = 77))
+->  Seq Scan on public.bar
+  Output: $1, $0, NULL::record, bar.ctid
+  Filter: (bar.f1 = 7)
+->  Foreign Scan on public.bar2
+  Output: $1, $0, bar2.f3, NULL::record, bar2.ctid, bar2.*
+  Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 WHERE ((f1 = 
7)) FOR UPDATE
+ (14 rows)
+ 
+ update bar set (f2,f1) = (select f1, f2 from bar2 where f3 = 77) where f1 = 7;
+ NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
+ NOTICE:  OLD: 

Re: [HACKERS] Bug in ExecModifyTable function and trigger issues for foreign tables

2017-06-02 Thread Etsuro Fujita

On 2017/05/16 21:36, Etsuro Fujita wrote:
One approach I came up with to fix this issue is to rewrite the 
targetList entries of an inherited UPDATE/DELETE properly using 
rewriteTargetListUD, when generating a plan for each child table in 
inheritance_planner.  Attached is a WIP patch for that.  Maybe I am 
missing something, though.


While updating the patch, I noticed the patch rewrites the UPDATE 
targetList incorrectly in some cases; rewrite_inherited_tlist I added to 
adjust_appendrel_attrs (1) removes all junk items from the targetList 
and (2) adds junk items for the child table using rewriteTargetListUD, 
but it's wrong to drop all junk items in cases where there are junk 
items for some other reasons than rewriteTargetListUD.  Consider junk 
items containing MULTIEXPR SubLink.  One way I came up with to fix this 
is to change (1) to only remove junk items with resname; since junk 
items added by rewriteTargetListUD should have resname (note: we would 
need resname to call ExecFindJunkAttributeInTlist at execution time!) 
while other junk items wouldn't have resname (see 
transformUpdateTargetList), we could correctly replace junk items added 
by rewriteTargetListUD for the parent with ones for the child, by that 
change.  I might be missing something, though.  Comments welcome.


Best regards,
Etsuro Fujita



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


  1   2   3   4   5   6   7   8   9   10   >