Thread: psql display of foreign keys
When \d a table referenced by a foreign key on a partitioned table, you currently get this: Table "public.referenced" Column | Type | Collation | Nullable | Default --------+---------+-----------+----------+--------- a | integer | | not null | Indexes: "referenced_pkey" PRIMARY KEY, btree (a) Referenced by: TABLE "hashp96_39" CONSTRAINT "hashp_a_fkey" FOREIGN KEY (a) REFERENCES referenced(a) TABLE "hashp96_38" CONSTRAINT "hashp_a_fkey" FOREIGN KEY (a) REFERENCES referenced(a) TABLE "hashp96_37" CONSTRAINT "hashp_a_fkey" FOREIGN KEY (a) REFERENCES referenced(a) TABLE "hashp96_36" CONSTRAINT "hashp_a_fkey" FOREIGN KEY (a) REFERENCES referenced(a) (thousands more) This is not very useful. I propose that we change it so that it only displays the one on the partitioned table on which the constraint was defined: Table "public.referenced" Column │ Type │ Collation │ Nullable │ Default ────────┼─────────┼───────────┼──────────┼───────── a │ integer │ │ not null │ Indexes: "referenced_pkey" PRIMARY KEY, btree (a) Referenced by: TABLE "hashp" CONSTRAINT "hashp_a_fkey" FOREIGN KEY (a) REFERENCES referenced(a) TABLE "hashp" CONSTRAINT "hashp_b_fkey" FOREIGN KEY (b) REFERENCES referenced(a) TABLE "parted" CONSTRAINT "parted_a_fkey" FOREIGN KEY (a) REFERENCES referenced(a) Which results in the actually useful info. Also, when describing one of the partitions, I propose we add a "TABLE foo" prefix to the constraint line, so that it indicates on which ancestor table the constraint was defined. So instead of this: \d parted1 Table "public.parted1" Column | Type | Collation | Nullable | Default --------+---------+-----------+----------+--------- a | integer | | not null | Partition of: parted FOR VALUES FROM (0) TO (1) Foreign-key constraints: "parted_a_fkey" FOREIGN KEY (a) REFERENCES referenced(a) we get this: \d parted1 Table "public.parted1" Column │ Type │ Collation │ Nullable │ Default ────────┼─────────┼───────────┼──────────┼───────── a │ integer │ │ not null │ Partition of: parted FOR VALUES FROM (0) TO (1) Foreign-key constraints: TABLE "parted" CONSTRAINT "parted_a_fkey" FOREIGN KEY (a) REFERENCES referenced(a) In some cases (such as in the regression tests that change in this commit) the constraint name is different in the parent than the partition, and it is more useful to display the parent's constraint name rather than the partition's. My first instinct is to change this in psql for Postgres 11, unless there's much opposition to that. Patch attached. PS -- it surprises me that we've got this far without an index on pg_constraint.confrelid. -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Attachment
Alvaro Herrera <alvherre@2ndquadrant.com> writes: > This is not very useful. I propose that we change it so that it only > displays the one on the partitioned table on which the constraint was > defined: OK goal, but ... > Patch attached. ... this patch breaks the expectation set at the top of describe.c: * Support for the various \d ("describe") commands. Note that the current * expectation is that all functions in this file will succeed when working * with servers of versions 7.4 and up. It's okay to omit irrelevant * information for an old server, but not to fail outright. Do you really need WITH RECURSIVE for this? If so, I'd suggest applying it only when relkind == RELKIND_PARTITIONED_TABLE, so that the case doesn't happen in servers too old to have WITH. That's probably a win performance-wise anyway, as I have no doubt that the performance of this query is awful compared to what it replaces, so we don't really want to use it if we don't have to. regards, tom lane
On Tue, Dec 04, 2018 at 10:00:00AM -0500, Tom Lane wrote: > Alvaro Herrera <alvherre@2ndquadrant.com> writes: > > This is not very useful. I propose that we change it so that it only > > displays the one on the partitioned table on which the constraint was > > defined: > > OK goal, but ... > > > Patch attached. > > ... this patch breaks the expectation set at the top of describe.c: > > * Support for the various \d ("describe") commands. Note that the current > * expectation is that all functions in this file will succeed when working > * with servers of versions 7.4 and up. It's okay to omit irrelevant > * information for an old server, but not to fail outright. > > Do you really need WITH RECURSIVE for this? If so, I'd suggest > applying it only when relkind == RELKIND_PARTITIONED_TABLE, so > that the case doesn't happen in servers too old to have WITH. Makes sense. > That's probably a win performance-wise anyway, as I have no doubt > that the performance of this query is awful compared to what it > replaces, so we don't really want to use it if we don't have to. Do you have cases where we should be measuring performance dips? Also, is there something about about indexes involved in this query or WITH RECURSIVE itself that's pessimizing performance, generally? Best, David. -- David Fetter <david(at)fetter(dot)org> http://fetter.org/ Phone: +1 415 235 3778 Remember to vote! Consider donating to Postgres: http://www.postgresql.org/about/donate
On 2018-Dec-04, David Fetter wrote: > On Tue, Dec 04, 2018 at 10:00:00AM -0500, Tom Lane wrote: > > That's probably a win performance-wise anyway, as I have no doubt > > that the performance of this query is awful compared to what it > > replaces, so we don't really want to use it if we don't have to. Sure thing. Fixed the easy one. On to the other one ... > Do you have cases where we should be measuring performance dips? > Also, is there something about about indexes involved in this query > or WITH RECURSIVE itself that's pessimizing performance, generally? Note that there are two queries being changed in this patch, one for each side of any foreign key. They start with either a lookup on conrelid or confrelid; only one of those columns has an index (so priming the CTE is a little slow for the confrelid one, if your pg_constraint is bloated). But after that the CTE iterates on the OID column, which is indexed, so it should be quick enough. This is the conrelid plan: Sort (cost=1605.38..1605.39 rows=1 width=101) Sort Key: ((constraints.conrelid = '311099'::oid)) DESC, constraints.conname CTE constraints -> Recursive Union (cost=0.29..1600.82 rows=202 width=76) -> Index Scan using pg_constraint_conrelid_contypid_conname_index on pg_constraint (cost=0.29..11.77 rows=2width=76) Index Cond: (conrelid = '311099'::oid) Filter: (contype = 'f'::"char") -> Nested Loop (cost=0.29..158.50 rows=20 width=76) -> WorkTable Scan on constraints constraints_1 (cost=0.00..0.40 rows=20 width=4) -> Index Scan using pg_constraint_oid_index on pg_constraint pc (cost=0.29..7.90 rows=1 width=76) Index Cond: (oid = constraints_1.parent) -> CTE Scan on constraints (cost=0.00..4.55 rows=1 width=101) Filter: (parent = '0'::oid) This is the confrelid plan: Sort (cost=1793.40..1793.40 rows=1 width=100) Sort Key: constraints.conname CTE constraints -> Recursive Union (cost=0.00..1791.11 rows=101 width=80) -> Seq Scan on pg_constraint (cost=0.00..956.59 rows=1 width=80) Filter: ((contype = 'f'::"char") AND (confrelid = '311099'::oid)) -> Nested Loop (cost=0.29..83.25 rows=10 width=80) -> WorkTable Scan on constraints constraints_1 (cost=0.00..0.20 rows=10 width=4) -> Index Scan using pg_constraint_oid_index on pg_constraint pc (cost=0.29..8.30 rows=1 width=80) Index Cond: (oid = constraints_1.parent) -> CTE Scan on constraints (cost=0.00..2.27 rows=1 width=100) Filter: (parent = '0'::oid) Of course, the original queries did the same thing (lookup via unindexed confrelid) and nobody has complained about that yet. Then again, the difference between a query taking 0.1 ms (the original query on conrelid, without recursive CTE) and one that takes 6ms (recursive one on confrelid) is not noticeable to humans anyway; it's not like this is a hot path. In any case, if anyone can think of another method to obtain the topmost constraint of a hierarchy involving the current table (not involving a recursive CTE, or maybe with a better one), I'm all ears. -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
On 2018-Dec-04, Tom Lane wrote: > ... this patch breaks the expectation set at the top of describe.c: > > * Support for the various \d ("describe") commands. Note that the current > * expectation is that all functions in this file will succeed when working > * with servers of versions 7.4 and up. It's okay to omit irrelevant > * information for an old server, but not to fail outright. Fixed in the attached. > Do you really need WITH RECURSIVE for this? I don't see any other way, but I'm open to ideas. > If so, I'd suggest applying it only when relkind == > RELKIND_PARTITIONED_TABLE, so that the case doesn't happen in servers > too old to have WITH. That's probably a win performance-wise anyway, > as I have no doubt that the performance of this query is awful > compared to what it replaces, so we don't really want to use it if we > don't have to. The query to display foreign keys on the current table can continue to use the old, fast version when the table is not a partition (I had to add the relispartition column to another query for this to work). But I cannot use the old version for the query that searches for FKs referencing the current table, because the table for which partitionedness matters is the other one. (The WITH version is only used for servers that can have foreign keys on partitioned tables, viz. 11). I spent a few minutes trying to think of a way of determining which query to use at SQL-execution time -- two CTEs, one of which would be short-circuited ... but I couldn't figure out how. I also tried to use the new pg_partition_tree() function, but it's useless for this purpose because it roots at its argument table, and there doesn't seem to be a convenient way to obtain the topmost ancestor. v2 attached. Many thanks for reviewing. -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
On 2018-Dec-04, Alvaro Herrera wrote: > v2 attached. Oops. -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Attachment
On Tue, Dec 04, 2018 at 03:41:59PM -0300, Alvaro Herrera wrote: > I spent a few minutes trying to think of a way of determining which > query to use at SQL-execution time -- two CTEs, one of which would be > short-circuited ... but I couldn't figure out how. I also tried to use > the new pg_partition_tree() function, but it's useless for this purpose > because it roots at its argument table, and there doesn't seem to be a > convenient way to obtain the topmost ancestor. This has been mentioned on the thread where pg_partition_tree has been discussed: https://www.postgresql.org/message-id/6baeb45a-6222-6b88-342d-37fc7d3cf89a%40lab.ntt.co.jp It got shaved from the final patch for simplicity as we had enough issues to deal with first. Adding a pg_partition_root or a new column in pg_partition_tree makes sense. My guts are telling me that a separate function is more instinctive to use. -- Michael
Attachment
On 2018-Dec-05, Michael Paquier wrote: > This has been mentioned on the thread where pg_partition_tree has been > discussed: > https://www.postgresql.org/message-id/6baeb45a-6222-6b88-342d-37fc7d3cf89a%40lab.ntt.co.jp > > It got shaved from the final patch for simplicity as we had enough > issues to deal with first. Adding a pg_partition_root or a new column > in pg_partition_tree makes sense. My guts are telling me that a > separate function is more instinctive to use. I agree with your guts ... you can combine them (the functions, not the guts) to obtain the full view of the partition hierarchy just by applying pg_partition_root() to the argument of pg_partition_tree. I think with pg_partition_root we can rewrite the FK queries to avoid WITH RECURSIVE with pg12 servers, but of course with a pg11 server we'll have to keep using WITH RECURSIVE. -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
I added this patch to commitfest in order to get more opinions, particularly on whether to backpatch this. I might commit sooner than that if others care to comment. -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
On 2018-Dec-04, Alvaro Herrera wrote: > On 2018-Dec-04, Alvaro Herrera wrote: > > > v2 attached. > > Oops. One more oops: The version I posted was for pg11, and does not apply to master. This version applies to master. -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Attachment
On Wed, Dec 5, 2018 at 11:30 AM Alvaro Herrera <alvherre@2ndquadrant.com> wrote: > I added this patch to commitfest in order to get more opinions, > particularly on whether to backpatch this. I might commit sooner than > that if others care to comment. I don't think this is a bug fix, and therefore I oppose back-patching it. -- Robert Haas EnterpriseDB: http://www.enterprisedb.com The Enterprise PostgreSQL Company
On 2018-Dec-06, Robert Haas wrote: > On Wed, Dec 5, 2018 at 11:30 AM Alvaro Herrera <alvherre@2ndquadrant.com> wrote: > > I added this patch to commitfest in order to get more opinions, > > particularly on whether to backpatch this. I might commit sooner than > > that if others care to comment. > > I don't think this is a bug fix, and therefore I oppose back-patching it. OK. That means I can just get pg_partition_root() done first, and try to write the queries using that instead of WITH RECURSIVE. -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
On Thu, Dec 06, 2018 at 01:26:30PM -0300, Alvaro Herrera wrote: > That means I can just get pg_partition_root() done first, and try to > write the queries using that instead of WITH RECURSIVE. FWIW, I was just writing a patch about this one, so I was going to spawn a new thread today :) Let's definitely avoid WITH RECURSIVE if we can. -- Michael
Attachment
On 06/12/2018 23:56, Michael Paquier wrote: > On Thu, Dec 06, 2018 at 01:26:30PM -0300, Alvaro Herrera wrote: >> That means I can just get pg_partition_root() done first, and try to >> write the queries using that instead of WITH RECURSIVE. > > FWIW, I was just writing a patch about this one, so I was going to spawn > a new thread today :) > > Let's definitely avoid WITH RECURSIVE if we can. I'm setting this to "Waiting on Author", awaiting a new version based on pg_partition_root() once that one is done. -- Peter Eisentraut http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
On Wed, Jan 02, 2019 at 09:38:40PM +0100, Peter Eisentraut wrote: > I'm setting this to "Waiting on Author", awaiting a new version based on > pg_partition_root() once that one is done. pg_partition_root() has not made it to the finish line yet, still it would have been nice to see a rebase, and the patch has been waiting for input for 4 weeks now. So I am marking it as returned with feedback. -- Michael
Attachment
On 2019-Feb-04, Michael Paquier wrote: > pg_partition_root() has not made it to the finish line yet, still it > would have been nice to see a rebase, and the patch has been waiting > for input for 4 weeks now. So I am marking it as returned with > feedback. Thanks for committing pg_partition_root ... but it turns out to be useless for this purpose. It turns out that we need to obtain the list of *ancestors* of the table being displayed, which pg_partition_tree does not easily give you. So I ended up adding yet another auxiliary function, pg_partition_ancestors, which in its current formulation returns just a lits of OIDs of ancestor tables. This seems generally useful, and can be used in conjunction with pg_partition_tree(): alvherre=# select t.* from pg_partition_tree(pg_partition_root('pk11')) t join pg_partition_ancestors('pk11', true) a on (t.relid = a.relid); relid | parentrelid | isleaf | level -------+-------------+--------+------- pk | | f | 0 pk1 | pk | f | 1 pk11 | pk1 | t | 2 (3 filas) (A small tweak is to change the return type from OID to regclass. Docbook additions missing also.) Anyway, given this function, it's possible to fix the psql display to be as I showed previously. Patches attached. -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Attachment
On Tue, Feb 26, 2019 at 07:27:57PM -0300, Alvaro Herrera wrote: > Thanks for committing pg_partition_root ... but it turns out to be > useless for this purpose. Well, what's done is done. The thing is useful by itself in my opinion. > It turns out that we need to obtain the list > of *ancestors* of the table being displayed, which pg_partition_tree > does not easily give you. So I ended up adding yet another auxiliary > function, pg_partition_ancestors, which in its current formulation > returns just a lits of OIDs of ancestor tables. This seems generally > useful, and can be used in conjunction with pg_partition_tree(): > > alvherre=# select t.* from pg_partition_tree(pg_partition_root('pk11')) t > join pg_partition_ancestors('pk11', true) a on (t.relid = a.relid); > relid | parentrelid | isleaf | level > -------+-------------+--------+------- > pk | | f | 0 > pk1 | pk | f | 1 > pk11 | pk1 | t | 2 > (3 filas) > > (A small tweak is to change the return type from OID to regclass. > Docbook additions missing also.) In the second patch, pg_partition_ancestors always sets include_self to true. What's the use case you have in mind to set it to false? In the other existing functions we always include the argument itself, so we may want to keep things consistent. I think that you should make the function return a record of regclass elements instead of OIDs to be consistent. This could save casts for the callers. Adding the self-member at the beginning of the record set is more consistent with the order of the results returned by get_partition_ancestors(). It would be nice to add some tests in partition_info.sql for tables and indexes (both work). > Anyway, given this function, it's possible to fix the psql display to be > as I showed previously. Patches attached. + " FROM pg_constraint, pg_partition_ancestors('%s', 't')\n" + " WHERE confrelid = relid AND contype = 'f' AND conparentid = 0\n" A JOIN would have been cleaner in my opinion, but feel free with the style you think is more adapted. For the meaning of using pg_partition_ancestors, I see... Not only do you want to show the foreign keys defined in the top-most parent, but also these defined in intermediate layers. That makes sense. Using only pg_partition_root would have been enough to show FKs in the top-most parent, but the intermediate ones would be missed (using only pg_partition_root() would miss the FKs fk_partitioned_fk_5_a_fkey1 and fk_partitioned_fk_5_a_fkey when doing "\d fk_partitioned_fk_5_1" based on the test set). -- Michael
Attachment
On 2019-Feb-27, Michael Paquier wrote: > On Tue, Feb 26, 2019 at 07:27:57PM -0300, Alvaro Herrera wrote: > > Thanks for committing pg_partition_root ... but it turns out to be > > useless for this purpose. > > Well, what's done is done. The thing is useful by itself in my > opinion. Eh, of course -- note that the psql query I added does use pg_partition_root, it's just that it is not useful *all by itself*. > In the second patch, pg_partition_ancestors always sets include_self > to true. What's the use case you have in mind to set it to false? In > the other existing functions we always include the argument itself, so > we may want to keep things consistent. Hmm, true. > I think that you should make the function return a record of regclass > elements instead of OIDs to be consistent. This could save casts for > the callers. Yeah, done. > Adding the self-member at the beginning of the record set is more > consistent with the order of the results returned by > get_partition_ancestors(). You're right, done. > It would be nice to add some tests in partition_info.sql for tables > and indexes (both work). Well. I tried this scenario create table t1 (a int); create table t11 () inherits (t1); create table t2 (b int); create table t111() inherits (t1, t2); and the result I get from my new function is not good: alvherre=# select * from pg_partition_ancestors('t111'); relid ------- t111 t1 (2 filas) it should have listed t2 too, but it doesn't. Since these functions aren't supposed to work on legacy inheritance anyway, I think the right action is to return the empty set. In the current version I just do what pg_partition_tree does, but I think we should adjust that behavior. I'll start a new thread about that. > For the meaning of using pg_partition_ancestors, I see... Not only do > you want to show the foreign keys defined in the top-most parent, but > also these defined in intermediate layers. That makes sense. Using > only pg_partition_root would have been enough to show FKs in the > top-most parent, but the intermediate ones would be missed (using only > pg_partition_root() would miss the FKs fk_partitioned_fk_5_a_fkey1 and > fk_partitioned_fk_5_a_fkey when doing "\d fk_partitioned_fk_5_1" based > on the test set). Exactly -- that's the whole point. We need to list all FKs that are applicable to the partition, indicating which relation is the one where the FK generates, and without polluting the output with countless "internal" pg_constraint rows. The output psql presents for the PK-side relation when it's partitioned, with my patch to support that, is quite ugly when there are many partitions. -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Attachment
On Wed, Feb 27, 2019 at 03:37:23PM -0300, Alvaro Herrera wrote: > It should have listed t2 too, but it doesn't. Since these functions > aren't supposed to work on legacy inheritance anyway, I think the right > action is to return the empty set. In the current version I just do > what pg_partition_tree does, but I think we should adjust that behavior. > I'll start a new thread about that. Yes, that's not good. The internal wrapper for ancestors should be reworked. The results of pg_partition_tree are what I would expect them to be though? Taking your example, t111 gets listed if listing the trees from t1 or t2. This seems natural to me. I am wondering the amount of work that it would take to actually have the function return both relations in this case.. > +pg_partition_ancestors(PG_FUNCTION_ARGS) > +{ > + Oid relid = PG_GETARG_OID(0); > + FuncCallContext *funcctx; > + ListCell **next; > + > + if (!check_rel_can_be_partition(relid)) > + PG_RETURN_NULL(); Not returning an empty set here? ;) I would have added tests with pg_partition_ancestors(NULL) and pg_partition_ancestors(0) for consistency with the rest. Except that and the ancestor tracking for inheritance, the shape of the patch looks good to me. -- Michael
Attachment
On 2019-Feb-28, Michael Paquier wrote: > On Wed, Feb 27, 2019 at 03:37:23PM -0300, Alvaro Herrera wrote: > > +pg_partition_ancestors(PG_FUNCTION_ARGS) > > +{ > > + Oid relid = PG_GETARG_OID(0); > > + FuncCallContext *funcctx; > > + ListCell **next; > > + > > + if (!check_rel_can_be_partition(relid)) > > + PG_RETURN_NULL(); > > Not returning an empty set here? ;) Yeah, I adapted to what was there then, but in the original coding I had the SRF_RETURN_DONE that you committed for pg_partition_tree. > I would have added tests with pg_partition_ancestors(NULL) and > pg_partition_ancestors(0) for consistency with the rest. Done. > Except that and the ancestor tracking for inheritance, the shape of > the patch looks good to me. Thanks for reviewing! I have pushed with your proposed changes. Here's the patch I'm really interested about :-) -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Attachment
On 2019/03/05 4:41, Alvaro Herrera wrote: > Here's the patch I'm really interested about :-) Thanks for the updated patch. I applied it and rebased the foreign-keys-referencing-partitioned-tables patch on top. Here's something I think you may have missed: -- partitioned primary key table create table p (a int primary key) partition by list (a); create table p1 partition of p for values in (1) partition by list (a); create table p11 partition of p1 for values in (1); -- regular primary key table create table pk (a int primary key); -- another partitioned table to define FK on create table q (a int) partition by list (a); create table q1 partition of q for values in (1) partition by list (a); create table q11 partition of q1 for values in (1); -- FK on q referencing p alter table q add foreign key (a) references p; -- seems OK \d p Partitioned table "public.p" Column │ Type │ Collation │ Nullable │ Default ────────┼─────────┼───────────┼──────────┼───────── a │ integer │ │ not null │ Partition key: LIST (a) Indexes: "p_pkey" PRIMARY KEY, btree (a) Referenced by: TABLE "q" CONSTRAINT "q_a_fkey" FOREIGN KEY (a) REFERENCES p(a) Number of partitions: 1 (Use \d+ to list them.) \d p1 Partitioned table "public.p1" Column │ Type │ Collation │ Nullable │ Default ────────┼─────────┼───────────┼──────────┼───────── a │ integer │ │ not null │ Partition of: p FOR VALUES IN (1) Partition key: LIST (a) Indexes: "p1_pkey" PRIMARY KEY, btree (a) Referenced by: TABLE "q" CONSTRAINT "q_a_fkey" FOREIGN KEY (a) REFERENCES p(a) Number of partitions: 1 (Use \d+ to list them.) \d p11 Table "public.p11" Column │ Type │ Collation │ Nullable │ Default ────────┼─────────┼───────────┼──────────┼───────── a │ integer │ │ not null │ Partition of: p1 FOR VALUES IN (1) Indexes: "p11_pkey" PRIMARY KEY, btree (a) Referenced by: TABLE "q" CONSTRAINT "q_a_fkey" FOREIGN KEY (a) REFERENCES p(a) -- change the FK to reference regular table alter table q drop constraint q_a_fkey ; alter table q add foreign key (a) references pk; -- not OK? \d pk Table "public.pk" Column │ Type │ Collation │ Nullable │ Default ────────┼─────────┼───────────┼──────────┼───────── a │ integer │ │ not null │ Indexes: "pk_pkey" PRIMARY KEY, btree (a) Referenced by: TABLE "q" CONSTRAINT "q_a_fkey" FOREIGN KEY (a) REFERENCES pk(a) TABLE "q1" CONSTRAINT "q_a_fkey" FOREIGN KEY (a) REFERENCES pk(a) TABLE "q11" CONSTRAINT "q_a_fkey" FOREIGN KEY (a) REFERENCES pk(a) Shouldn't the above only list the constraint on q as follows? Referenced by: TABLE "q" CONSTRAINT "q_a_fkey" FOREIGN KEY (a) REFERENCES pk(a) Maybe: @@ -2488,7 +2488,8 @@ describeOneTableDetails(const char *schemaname, "SELECT conname, conrelid::pg_catalog.regclass,\n" " pg_catalog.pg_get_constraintdef(c.oid, true) as condef\n" "FROM pg_catalog.pg_constraint c\n" - "WHERE c.confrelid = '%s' AND c.contype = 'f' ORDER BY 1;", + "WHERE c.confrelid = '%s' AND c.contype = 'f' AND conparentid = 0\n" + "ORDER BY conname;", Thanks, Amit
On 2019-Mar-05, Amit Langote wrote: > On 2019/03/05 4:41, Alvaro Herrera wrote: > > Here's the patch I'm really interested about :-) > > Thanks for the updated patch. I applied it and rebased the > foreign-keys-referencing-partitioned-tables patch on top. Here's > something I think you may have missed: I missed that indeed! Thanks for noticing. Here's an updated and rebased version of this patch. -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Attachment
On 2019-Mar-22, Alvaro Herrera wrote: > On 2019-Mar-05, Amit Langote wrote: > > > On 2019/03/05 4:41, Alvaro Herrera wrote: > > > Here's the patch I'm really interested about :-) > > > > Thanks for the updated patch. I applied it and rebased the > > foreign-keys-referencing-partitioned-tables patch on top. Here's > > something I think you may have missed: > > I missed that indeed! Thanks for noticing. Here's an updated and > rebased version of this patch. I forgot to "git add" the new changes to the expected file. Here's v8 with that fixed. -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Attachment
On 2019-03-23 03:30, Alvaro Herrera wrote: >>> Thanks for the updated patch. I applied it and rebased the >>> foreign-keys-referencing-partitioned-tables patch on top. Here's >>> something I think you may have missed: >> >> I missed that indeed! Thanks for noticing. Here's an updated and >> rebased version of this patch. > > I forgot to "git add" the new changes to the expected file. Here's v8 > with that fixed. Looks OK in general. relispartition was added in PG10, so the conditional in describeOneTableDetails() seems wrong. In the older branches of that same function, I'd prefer writing false AS relispartition for clarity. Some of the other queries could also use some column aliases, like conrelid = '%s'::pg_catalog.regclass AS isroot (?) or pg_catalog.pg_get_constraintdef(oid, true) AS condef (as in the other branch). A test case for the incoming foreign key display would be nice, as that was the original argument for the patch. -- Peter Eisentraut http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
v9 attached; this one's final AFAICT. On 2019-Mar-25, Peter Eisentraut wrote: > relispartition was added in PG10, so the conditional in > describeOneTableDetails() seems wrong. Hmm, yeah, we weren't using it anyway (since we can only use the new display with pg_partition_ancestors which is new in pg12), but I guess you have a point that this could confuse somebody in the future. > In the older branches of that same function, I'd prefer writing > > false AS relispartition > > for clarity. Yeah, some previous commits in that area have added "false" flags here and there without adding aliases. We should fix those sometime. And also the new "amname" output column is conditional on the version number and changes column numbering for any column that appears afterwards ... that one definitely deserves a "NULL as amname" in the older branches. I changed some code to use PQfnumber() the way pg_dump does it; that code's support for back-branch compatibility is much more battle-tested than psql's and I trust that to be more maintainable. In fact, my motivation for doing it that way is that I found psql's way to be confusing. > Some of the other queries could also use some column aliases, like > > conrelid = '%s'::pg_catalog.regclass AS isroot (?) > > or > > pg_catalog.pg_get_constraintdef(oid, true) AS condef > > (as in the other branch). Agreed, added. > A test case for the incoming foreign key display would be nice, as that > was the original argument for the patch. Agreed, added. -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Attachment
On 2019-Mar-25, Alvaro Herrera wrote: > v9 attached; this one's final AFAICT. Actually, I propose this fixup. It doesn't change the current output, but of course it affects how this works with my patch in https://postgr.es/m/20190321215420.GA22766@alvherre.pgsql The v9 patch does not show anything for the partitions of the referenced partitioned table; with this one it shows like this -- verify psql behaves sanely \d droppk Partitioned table "regress_fk.droppk" Column | Type | Collation | Nullable | Default --------+---------+-----------+----------+--------- a | integer | | not null | Partition key: RANGE (a) Indexes: "droppk_pkey" PRIMARY KEY, btree (a) Referenced by: TABLE "dropfk" CONSTRAINT "dropfk_a_fkey" FOREIGN KEY (a) REFERENCES droppk(a) Number of partitions: 3 (Use \d+ to list them.) \d droppk21 Table "regress_fk.droppk21" Column | Type | Collation | Nullable | Default --------+---------+-----------+----------+--------- a | integer | | not null | Partition of: droppk2 FOR VALUES FROM (1000) TO (1400) Indexes: "droppk21_pkey" PRIMARY KEY, btree (a) Referenced by: TABLE "dropfk" CONSTRAINT "dropfk_a_fkey" FOREIGN KEY (a) REFERENCES droppk(a) -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Attachment
Hi, On 2019/03/26 7:38, Alvaro Herrera wrote: > v9 attached; this one's final AFAICT. Agreed. Thanks, Amit
Patch tester didn't like that one bit. Here's v10 with the fixup applied. -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Attachment
On 2019-03-26 03:42, Alvaro Herrera wrote: > Patch tester didn't like that one bit. Here's v10 with the fixup > applied. Looks good to me. -- Peter Eisentraut http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services