Re: cataloguing NOT NULL constraints
On Wed, May 15, 2024 at 09:50:36AM +0200, Álvaro Herrera wrote: > On 2024-May-14, Bruce Momjian wrote: > > > Turns out these commits generated a single release note item, which I > > have now removed with the attached committed patch. > > Hmm, but the commits about not-null constraints for domains were not > reverted, only the ones for constraints on relations. I think the > release notes don't properly address the ones on domains. I think it's > at least these two commits: > > > -Author: Peter Eisentraut > > -2024-03-20 [e5da0fe3c] Catalog domain not-null constraints > > -Author: Peter Eisentraut > > -2024-04-15 [9895b35cb] Fix ALTER DOMAIN NOT NULL syntax > > It may still be a good idea to make a note about those, at least to > point out that information_schema now lists them. For example, pg11 > release notes had this item Let me explain what I did to adjust the release notes. I took your commit hashes, which were longer than mine, and got the commit subject text from them. I then searched the release notes to see which commit subjects existed in the document. Only the first three did, and the release note item has five commits. The then tested if the last two patches could be reverted, and 'patch' thought they could be, so that confirmed they were not reverted. However, there was no text in the release note item that corresponded to the commits, so I just removed the entire item. What I now think happened is that the last two commits were considered part of the larger NOT NULL change, and not worth mentioning separately, but now that the NOT NULL part is reverted, we might need to mention them. I rarely handle such complex cases so I don't think I was totally correct in my handling. Let's get a reply to Peter Eisentraut's question and we can figure out what to do. -- Bruce Momjian https://momjian.us EDB https://enterprisedb.com Only you can decide what is important to you.
Re: cataloguing NOT NULL constraints
On 15.05.24 09:50, Alvaro Herrera wrote: On 2024-May-14, Bruce Momjian wrote: Turns out these commits generated a single release note item, which I have now removed with the attached committed patch. Hmm, but the commits about not-null constraints for domains were not reverted, only the ones for constraints on relations. I think the release notes don't properly address the ones on domains. I think it's at least these two commits: -Author: Peter Eisentraut -2024-03-20 [e5da0fe3c] Catalog domain not-null constraints -Author: Peter Eisentraut -2024-04-15 [9895b35cb] Fix ALTER DOMAIN NOT NULL syntax I'm confused that these were kept. The first one was specifically to make the catalog representation of domain not-null constraints consistent with table not-null constraints. But the table part was reverted, so now the domain constraints are inconsistent again. The second one refers to the first one, but it might also fix some additional older issue, so it would need more investigation.
Re: cataloguing NOT NULL constraints
On 2024-May-14, Bruce Momjian wrote: > Turns out these commits generated a single release note item, which I > have now removed with the attached committed patch. Hmm, but the commits about not-null constraints for domains were not reverted, only the ones for constraints on relations. I think the release notes don't properly address the ones on domains. I think it's at least these two commits: > -Author: Peter Eisentraut > -2024-03-20 [e5da0fe3c] Catalog domain not-null constraints > -Author: Peter Eisentraut > -2024-04-15 [9895b35cb] Fix ALTER DOMAIN NOT NULL syntax It may still be a good idea to make a note about those, at least to point out that information_schema now lists them. For example, pg11 release notes had this item Add information_schema columns related to table constraints and triggers (Peter Eisentraut) Specifically, triggers.action_order, triggers.action_reference_old_table, and triggers.action_reference_new_table are now populated, where before they were always null. Also, table_constraints.enforced now exists but is not yet usefully populated. -- Álvaro HerreraBreisgau, Deutschland — https://www.EnterpriseDB.com/
Re: cataloguing NOT NULL constraints
On Mon, May 13, 2024 at 09:00:28AM -0400, Robert Haas wrote: > > Specifically, the problem is that I mentioned that we could restrict the > > NOT NULL NO INHERIT addition in pg_dump for primary keys to occur only > > in pg_upgrade; but it turns this is not correct. In normal > > dump/restore, there's an additional table scan to check for nulls when > > the constraints is not there, so the PK creation would become measurably > > slower. (In a table with a million single-int rows, PK creation goes > > from 2000ms to 2300ms due to the second scan to check for nulls). > > I have a feeling that any theory of the form "X only needs to happen > during pg_upgrade" is likely to be wrong. pg_upgrade isn't really > doing anything especially unusual: just creating some objects and > loading data. Those things can also be done at other times, so > whatever is needed during pg_upgrade is also likely to be needed at > other times. Maybe that's not sound reasoning for some reason or > other, but that's my intuition. I assume Alvaro is saying that pg_upgrade has only a single session, which is unique and might make things easier for him. -- Bruce Momjian https://momjian.us EDB https://enterprisedb.com Only you can decide what is important to you.
Re: cataloguing NOT NULL constraints
On Sun, May 12, 2024 at 04:56:09PM +0200, Álvaro Herrera wrote: > On 2024-May-11, Alvaro Herrera wrote: > > > I have found two more problems that [] require some more work to fix, > > so I've decided to cut my losses now and revert the whole. > > Here's the revert patch, which I intend to push early tomorrow. > > Commits reverted are: > 21ac38f498b33f0231842238b83847ec63dfe07b > d45597f72fe53a53f6271d5ba4e7acf8fc9308a1 > 13daa33fa5a6d340f9be280db14e7b07ed11f92e > 0cd711271d42b0888d36f8eda50e1092c2fed4b3 > d72d32f52d26c9588256de90b9bc54fe312cee60 > d9f686a72ee91f6773e5d2bc52994db8d7157a8e > c3709100be73ad5af7ff536476d4d713bca41b1a > 3af7217942722369a6eb7629e0fb1cbbef889a9b > b0f7dd915bca6243f3daf52a81b8d0682a38ee3b > ac22a9545ca906e70a819b54e76de38817c93aaf > d0ec2ddbe088f6da35444fad688a62eae4fbd840 > 9b581c53418666205938311ef86047aa3c6b741f > b0e96f311985bceba79825214f8e43f65afa653a > > with some significant conflict fixes (mostly in the last one). Turns out these commits generated a single release note item, which I have now removed with the attached committed patch. -- Bruce Momjian https://momjian.us EDB https://enterprisedb.com Only you can decide what is important to you. diff --git a/doc/src/sgml/release-17.sgml b/doc/src/sgml/release-17.sgml index 9c7c0a0337f..143ee17716d 100644 --- a/doc/src/sgml/release-17.sgml +++ b/doc/src/sgml/release-17.sgml @@ -1486,29 +1486,6 @@ Add event trigger support for REINDEX (Garrett Thornburg, Jian He) - - - - -Allow NOT NULL columns to be specified as column constraints and domains (Alvaro Herrera, Bernd Helmle, Kyotaro Horiguchi, Peter Eisentraut) - - - -Previously NOT NULL could only be specified as a column attribute. - - -
Re: cataloguing NOT NULL constraints
On 2024-May-13, Robert Haas wrote: > It seems to me that the practical thing to do about this problem is > just decide not to solve it. I mean, it's currently the case that if > you establish a PRIMARY KEY when you create a table, the columns of > that key are marked NOT NULL and remain NOT NULL even if the primary > key is later dropped. So, if that didn't change, we would be no less > compliant with the SQL standard (or your reading of it) than we are > now. [...] > So I don't really think it's a great idea to change this behavior, but > even if it is, is it such a good idea that we want to sink the whole > patch set repeatedly over it, as has already happened twice now? I > feel that if we did what Tom suggested a year ago in > https://www.postgresql.org/message-id/3801207.1681057...@sss.pgh.pa.us > -- "I'm inclined to think that this idea of suppressing the implied > NOT NULL from PRIMARY KEY is a nonstarter and we should just go ahead > and make such a constraint" [...] Hmm, I hadn't interpreted Tom's message the way you suggest, and you may be right that it might be a good way forward. I'll keep this in mind for next time. -- Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/ "No es bueno caminar con un hombre muerto"
Re: cataloguing NOT NULL constraints
On Mon, May 13, 2024 at 12:45 PM Alvaro Herrera wrote: > The point is that a column can be in a primary key and not have an > explicit not-null constraint. This is different from having a column be > NOT NULL and having a primary key on top. In both cases the attnotnull > flag is set; the difference between these two scenarios is what happens > if you drop the primary key. If you do not have an explicit not-null > constraint, then the attnotnull flag is lost as soon as you drop the > primary key. You don't have to do DROP NOT NULL for that to happen > > This means that if you have a column that's in the primary key but does > not have an explicit not-null constraint, then we shouldn't make one up. > (Which we would, if we were to keep an unadorned NOT NULL that we can't > drop at the end of the dump.) It seems to me that the practical thing to do about this problem is just decide not to solve it. I mean, it's currently the case that if you establish a PRIMARY KEY when you create a table, the columns of that key are marked NOT NULL and remain NOT NULL even if the primary key is later dropped. So, if that didn't change, we would be no less compliant with the SQL standard (or your reading of it) than we are now. And if you do really want to make that change, why not split it out into its own patch, so that the patch that does $SUBJECT is changing the minimal number of other things at the same time? That way, reverting something might not involve reverting everything, plus you could have a separate design discussion about what that fix ought to look like, separate from the issues that are truly inherent to cataloging NOT NULL constraints per se. What I meant about changing the order of operations is that, currently, the database knows that the column is NOT NULL before the COPY happens, and I don't think we can change that. I think you agree -- that's why you invented the throwaway constraints. As far as I can see, the problems all have to do with getting the "throwaway" part to happen correctly. It can't be a problem to just mark the relevant columns NOT NULL in the relevant tables -- we already do that. But if you want to discard some of those NOT NULL markings once the PRIMARY KEY is added, you have to know which ones to discard. If we just consider the most straightforward scenario where somebody does a full dump-and-restore, getting that right may be annoying, but it seems like it surely has to be possible. The dump will just have to understand which child tables (or, more generally, descendent tables) got a NOT NULL marking on a column because of the PK and which ones had an explicit marking in the old database and do the right thing in each case. But what if somebody does a selective restore of one table from a partitioning hierarchy? Currently, the columns that would have been part of the primary key end up NOT NULL, but the primary key itself is not restored because it can't be. What will happen in this new system? If you don't apply any NOT NULL constraints to those columns, then a user who restores one partition from an old dump and tries to reattach it to the correct partitioned table has to recheck the NOT NULL constraint, unlike now. If you apply a normal-looking garden-variety NOT NULL constraint to that column, you've invented a constraint that didn't exist in the source database. And if you apply a throwaway NOT NULL constraint but the user never attaches that table anywhere, then the throwaway constraint survives. None of those options sound very good to me. Another scenario: Say that you have a table with a PRIMARY KEY. For some reason, you want to drop the primary key and then add it back. Well, with this definitional change, as soon as you drop it, you forget that the underlying columns don't contain any nulls, so when you add it back, you have to check them again. I don't know who would find that behavior an improvement over what we have today. So I don't really think it's a great idea to change this behavior, but even if it is, is it such a good idea that we want to sink the whole patch set repeatedly over it, as has already happened twice now? I feel that if we did what Tom suggested a year ago in https://www.postgresql.org/message-id/3801207.1681057...@sss.pgh.pa.us -- "I'm inclined to think that this idea of suppressing the implied NOT NULL from PRIMARY KEY is a nonstarter and we should just go ahead and make such a constraint" -- there's a very good chance that a revert would have been avoided here and it would still be just as valid to think of revisiting this particular question in a future release as it is now. -- Robert Haas EDB: http://www.enterprisedb.com
Re: cataloguing NOT NULL constraints
On 2024-May-13, Robert Haas wrote: > On Mon, May 13, 2024 at 9:44 AM Alvaro Herrera > wrote: > > The problematic point is the need to add NOT NULL constraints during > > table creation that don't exist in the table being dumped, for > > performance of primary key creation -- I called this a throwaway > > constraint. We needed to be able to drop those constraints after the PK > > was created. These were marked NO INHERIT to allow them to be dropped, > > which is easier if the children don't have them. This all worked fine. > > This seems really weird to me. Why is it necessary? I mean, in > existing releases, if you declare a column as PRIMARY KEY, the columns > included in the key are forced to be NOT NULL, and you can't change > that for so long as they are included in the PRIMARY KEY. The point is that a column can be in a primary key and not have an explicit not-null constraint. This is different from having a column be NOT NULL and having a primary key on top. In both cases the attnotnull flag is set; the difference between these two scenarios is what happens if you drop the primary key. If you do not have an explicit not-null constraint, then the attnotnull flag is lost as soon as you drop the primary key. You don't have to do DROP NOT NULL for that to happen. This means that if you have a column that's in the primary key but does not have an explicit not-null constraint, then we shouldn't make one up. (Which we would, if we were to keep an unadorned NOT NULL that we can't drop at the end of the dump.) > So I would have thought that after this patch, you'd end up with the > same thing. At least as I interpret the standard, you wouldn't. > One way of doing that would be to make the PRIMARY KEY depend on the > now-catalogued NOT NULL constraints, and the other way would be to > keep it as an ad-hoc prohibition, same as now. That would be against what [I think] the standard says. > But I don't see why I need to end up with what the patch generates, > which seems to be something like CONSTRAINT pgdump_throwaway_notnull_0 > NOT NULL NO INHERIT. That kind of thing suggests that we're changing > around the order of operations in pg_dump, probably by adding the NOT > NULL constraints at a later stage than currently, and I think the > proper solution is most likely to be to avoid doing that in the first > place. The point of the throwaway constraints is that they don't remain after the dump has restored completely. They are there only so that we don't have to scan the data looking for possible nulls when we create the primary key. We have a DROP CONSTRAINT for the throwaway not-nulls as soon as the PK is created. We're not changing any order of operations as such. > That's not to say that we shouldn't try to make improvements, just > that it may be hard to get right. Sure, that's why this patch has now been reverted twice :-) and has been in the works for ... how many years now? -- Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/
Re: cataloguing NOT NULL constraints
On Mon, May 13, 2024 at 9:44 AM Alvaro Herrera wrote: > The problematic point is the need to add NOT NULL constraints during > table creation that don't exist in the table being dumped, for > performance of primary key creation -- I called this a throwaway > constraint. We needed to be able to drop those constraints after the PK > was created. These were marked NO INHERIT to allow them to be dropped, > which is easier if the children don't have them. This all worked fine. This seems really weird to me. Why is it necessary? I mean, in existing releases, if you declare a column as PRIMARY KEY, the columns included in the key are forced to be NOT NULL, and you can't change that for so long as they are included in the PRIMARY KEY. So I would have thought that after this patch, you'd end up with the same thing. One way of doing that would be to make the PRIMARY KEY depend on the now-catalogued NOT NULL constraints, and the other way would be to keep it as an ad-hoc prohibition, same as now. In PostgreSQL 16, I get a dump like this: CREATE TABLE public.foo ( a integer NOT NULL, b text ); COPY public.foo (a, b) FROM stdin; \. ALTER TABLE ONLY public.foo ADD CONSTRAINT foo_pkey PRIMARY KEY (a); If I'm dumping from an existing release, I don't see why any of that needs to change. The NOT NULL decoration should lead to a system-generated constraint name. If I'm dumping from a new release, the NOT NULL decoration needs to be replaced with CONSTRAINT existing_constraint_name NOT NULL. But I don't see why I need to end up with what the patch generates, which seems to be something like CONSTRAINT pgdump_throwaway_notnull_0 NOT NULL NO INHERIT. That kind of thing suggests that we're changing around the order of operations in pg_dump, probably by adding the NOT NULL constraints at a later stage than currently, and I think the proper solution is most likely to be to avoid doing that in the first place. > However, at some point we realized that we needed to add NOT NULL > constraints in child tables for the columns in which the parent had a > primary key. Then things become messy because we had the throwaway > constraints on one hand and the not-nulls that descend from the PK on > the other hand, where one was NO INHERIT and the other wasn't; worse if > the child also has a primary key. This seems like another problem that is created by changing the order of operations in pg_dump. > > The other possibility that occurs to me is that I think the motivation > > for cataloging NOT NULL constraints was that we wanted to be able to > > track dependencies on them, or something like that, which seems like > > it might be able to create issues of the type that you're facing, but > > the details aren't clear to me. > > NOT VALID constraints would be extremely useful, for one thing (because > then you don't need to exclusively-lock the table during a long scan in > order to add a constraint), and it's just one step away from having > these constraints be catalogued. It was also fixing some inconsistent > handling of inheritance cases. I agree that NOT VALID constraints would be very useful. I'm a little scared by the idea of fixing inconsistent handling of inheritance cases, just for fear that there may be more things relying on the inconsistent behavior than we realize. I feel like this is an area where it's easy for changes to be scarier than they at first seem. I still have memories of discovering some of the current behavior back in the mid-2000s when I was learning PostgreSQL (and databases generally). It struck me as fiddly back then, and it still does. I feel like there are probably some behaviors that look like arbitrary decisions but are actually very important for some undocumented reason. That's not to say that we shouldn't try to make improvements, just that it may be hard to get right. -- Robert Haas EDB: http://www.enterprisedb.com
Re: cataloguing NOT NULL constraints
On 2024-May-13, Robert Haas wrote: > On Sat, May 11, 2024 at 5:40 AM Alvaro Herrera > wrote: > > Specifically, the problem is that I mentioned that we could restrict the > > NOT NULL NO INHERIT addition in pg_dump for primary keys to occur only > > in pg_upgrade; but it turns this is not correct. In normal > > dump/restore, there's an additional table scan to check for nulls when > > the constraints is not there, so the PK creation would become measurably > > slower. (In a table with a million single-int rows, PK creation goes > > from 2000ms to 2300ms due to the second scan to check for nulls). > > I have a feeling that any theory of the form "X only needs to happen > during pg_upgrade" is likely to be wrong. pg_upgrade isn't really > doing anything especially unusual: just creating some objects and > loading data. Those things can also be done at other times, so > whatever is needed during pg_upgrade is also likely to be needed at > other times. Maybe that's not sound reasoning for some reason or > other, but that's my intuition. True. It may be that by setting up the upgrade SQL script differently, we don't need to make the distinction at all. I hope to be able to do that. > I'm sorry that I haven't been following this thread closely, but I'm > confused about how we ended up here. What exactly are the user-visible > behavior changes wrought by this patch, and how do they give rise to > these issues? The problematic point is the need to add NOT NULL constraints during table creation that don't exist in the table being dumped, for performance of primary key creation -- I called this a throwaway constraint. We needed to be able to drop those constraints after the PK was created. These were marked NO INHERIT to allow them to be dropped, which is easier if the children don't have them. This all worked fine. However, at some point we realized that we needed to add NOT NULL constraints in child tables for the columns in which the parent had a primary key. Then things become messy because we had the throwaway constraints on one hand and the not-nulls that descend from the PK on the other hand, where one was NO INHERIT and the other wasn't; worse if the child also has a primary key. It turned out that we didn't have any mechanism to transform a NO INHERIT constraint into a regular one that would be inherited. I added one, didn't like the way it worked, tried to restrict it but that caused other problems; this is the mess that led to the revert (pg_dump in normal mode would emit scripts that fail for some legitimate cases). One possible way forward might be to make pg_dump smarter by adding one more query to know the relationship between constraints that must be dropped and those that don't. Another might be to allow multiple not-null constraints on the same column (one inherits, the other doesn't, and you can drop them independently). There may be others. > The other possibility that occurs to me is that I think the motivation > for cataloging NOT NULL constraints was that we wanted to be able to > track dependencies on them, or something like that, which seems like > it might be able to create issues of the type that you're facing, but > the details aren't clear to me. NOT VALID constraints would be extremely useful, for one thing (because then you don't need to exclusively-lock the table during a long scan in order to add a constraint), and it's just one step away from having these constraints be catalogued. It was also fixing some inconsistent handling of inheritance cases. -- Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/
Re: cataloguing NOT NULL constraints
On Sat, May 11, 2024 at 5:40 AM Alvaro Herrera wrote: > I have found two more problems that I think are going to require some > more work to fix, so I've decided to cut my losses now and revert the > whole. I'll come back again in 18 with these problems fixed. Bummer, but makes sense. > Specifically, the problem is that I mentioned that we could restrict the > NOT NULL NO INHERIT addition in pg_dump for primary keys to occur only > in pg_upgrade; but it turns this is not correct. In normal > dump/restore, there's an additional table scan to check for nulls when > the constraints is not there, so the PK creation would become measurably > slower. (In a table with a million single-int rows, PK creation goes > from 2000ms to 2300ms due to the second scan to check for nulls). I have a feeling that any theory of the form "X only needs to happen during pg_upgrade" is likely to be wrong. pg_upgrade isn't really doing anything especially unusual: just creating some objects and loading data. Those things can also be done at other times, so whatever is needed during pg_upgrade is also likely to be needed at other times. Maybe that's not sound reasoning for some reason or other, but that's my intuition. > The addition of NOT NULL NO INHERIT constraints for this purpose > collides with addition of constraints for other reasons, and it forces > us to do unpleasant things such as altering an existing constraint to go > from NO INHERIT to INHERIT. If this happens only during pg_upgrade, > that would be okay IMV; but if we're forced to allow in normal operation > (and in some cases we are), it could cause inconsistencies, so I don't > want to do that. I see a way to fix this (adding another query in > pg_dump that detects which columns descend from ones used in PKs in > ancestor tables), but that's definitely too much additional mechanism to > be adding this late in the cycle. I'm sorry that I haven't been following this thread closely, but I'm confused about how we ended up here. What exactly are the user-visible behavior changes wrought by this patch, and how do they give rise to these issues? One change I know about is that a constraint that is explicitly catalogued (vs. just existing implicitly) has a name. But it isn't obvious to me that such a difference, by itself, is enough to cause all of these problems: if a NOT NULL constraint is created without a name, then I suppose we just have to generate one. Maybe the fact that the constraints have names somehow causes ugliness later, but I can't quite understand why it would. The other possibility that occurs to me is that I think the motivation for cataloging NOT NULL constraints was that we wanted to be able to track dependencies on them, or something like that, which seems like it might be able to create issues of the type that you're facing, but the details aren't clear to me. Changing any behavior in this area seems like it could be quite tricky, because of things like the interaction between PRIMARY KEY and NOT NULL, which is rather idiosyncratic but upon which a lot of existing SQL (including SQL not controlled by us) likely depends. If there's not a clear plan for how we keep all the stuff that works today working, I fear we'll end up in an endless game of whack-a-mole. If you've already written the design ideas down someplace, I'd appreciate a pointer in the right direction. Or maybe there's some other issue entirely. In any case, sorry about the revert, and sorry that I haven't paid more attention to this. -- Robert Haas EDB: http://www.enterprisedb.com
Re: cataloguing NOT NULL constraints
On 2024-May-09, Robert Haas wrote: > Yeah, I have to admit that the ongoing bug fixing here has started to > make me a bit nervous, but I also can't totally follow everything > that's under discussion, so I don't want to rush to judgement. I have found two more problems that I think are going to require some more work to fix, so I've decided to cut my losses now and revert the whole. I'll come back again in 18 with these problems fixed. Specifically, the problem is that I mentioned that we could restrict the NOT NULL NO INHERIT addition in pg_dump for primary keys to occur only in pg_upgrade; but it turns this is not correct. In normal dump/restore, there's an additional table scan to check for nulls when the constraints is not there, so the PK creation would become measurably slower. (In a table with a million single-int rows, PK creation goes from 2000ms to 2300ms due to the second scan to check for nulls). The addition of NOT NULL NO INHERIT constraints for this purpose collides with addition of constraints for other reasons, and it forces us to do unpleasant things such as altering an existing constraint to go from NO INHERIT to INHERIT. If this happens only during pg_upgrade, that would be okay IMV; but if we're forced to allow in normal operation (and in some cases we are), it could cause inconsistencies, so I don't want to do that. I see a way to fix this (adding another query in pg_dump that detects which columns descend from ones used in PKs in ancestor tables), but that's definitely too much additional mechanism to be adding this late in the cycle. -- Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/
Re: cataloguing NOT NULL constraints
On Wed, May 8, 2024 at 4:42 PM Alvaro Herrera wrote: > I spent a long time trying to think how to fix this, and I had despaired > wanting to write that I would need to revert the whole NOT NULL business > for pg17 -- but that was until I realized that we don't actually need > this NOT NULL NO INHERIT business except during pg_upgrade, and that > simplifies things enough to give me confidence that the whole feature > can be kept. Yeah, I have to admit that the ongoing bug fixing here has started to make me a bit nervous, but I also can't totally follow everything that's under discussion, so I don't want to rush to judgement. I feel like we might need some documentation or a README or something that explains the takeaway from the recent commits dealing with no-inherit constraints. None of those commits updated the documentation, which may be fine, but neither the resulting behavior nor the reasoning behind it is obvious. It's not enough for it to be correct -- it has to be understandable enough to the hive mind that we can maintain it going forward. -- Robert Haas EDB: http://www.enterprisedb.com
Re: cataloguing NOT NULL constraints
On 2024-May-07, Kyotaro Horiguchi wrote: > Hello, > > At Wed, 1 May 2024 19:49:35 +0200, Alvaro Herrera > wrote in > > Here are two patches that I intend to push soon (hopefully tomorrow). > > This commit added and edited two error messages, resulting in using > slightly different wordings "in" and "on" for relation constraints. > > + errmsg("cannot change NO INHERIT status of NOT NULL constraint \"%s\" on > relation \"%s\"", > === > + errmsg("cannot change NO INHERIT status of NOT NULL constraint \"%s\" in > relation \"%s\"", Thank you, I hadn't noticed the inconsistency -- I fix this in the attached series. While trying to convince myself that I could mark the remaining open item for this work closed, I discovered that pg_dump fails to produce working output for some combinations. Notably, if I create Andrew Bille's example in 16: create table test_0 (id serial primary key); create table test_1 (id integer primary key) inherits (test_0); then current master's pg_dump produces output that the current server fails to restore, failing the PK creation in test_0: ALTER TABLE ONLY public.test_0 ADD CONSTRAINT test_0_pkey PRIMARY KEY (id); ERROR: cannot change NO INHERIT status of NOT NULL constraint "pgdump_throwaway_notnull_0" in relation "test_1" because we have already created the NOT NULL NO INHERIT constraint in test_1 when we created it, and because of d45597f72fe5, we refuse to change it into a regular inheritable constraint, which the PK in its parent table needs. I spent a long time trying to think how to fix this, and I had despaired wanting to write that I would need to revert the whole NOT NULL business for pg17 -- but that was until I realized that we don't actually need this NOT NULL NO INHERIT business except during pg_upgrade, and that simplifies things enough to give me confidence that the whole feature can be kept. Because, remember: the idea of those NO INHERIT "throwaway" constraints is that we can skip reading the data when we create the PRIMARY KEY during binary upgrade. We don't actually need the NO INHERIT constraints for anything during regular pg_dump. So what we can do, is restrict the usage of NOT NULL NO INHERIT so that they occur only during pg_upgrade. I think this will make Justin P. happier, because we no longer have these unsightly NOT NULL NO INHERIT nonstandard syntax in dumps. The attached patch series does that. Actually, it does a little more, but it's not really much: 0001: fix the typos pointed out by Kyotaro. 0002: A mechanical code movement that takes some ugly ballast out of getTableAttrs into its own routine. I realized that this new code was far too ugly and messy to be in the middle of filling the tbinfo struct of attributes. If you use "git show --color-moved --color-moved-ws=ignore-all-space" with this commit you can see that nothing happens apart from the code move. 0003: pgindent, fixes the comments just moved to account for different indentation depth. 0004: moves again the moved PQfnumber() calls back to getTableAttrs(), for efficiency (we don't want to search the result for those resnums for every single attribute of all tables being dumped). 0005: This is the actual code change I describe above. We restrict use_throwaway_nulls so that it's only set during binary upgrade mode. This changes pg_dump output; in the normal case, we no longer have NOT NULL NO INHERIT. I added one test stanza to verify that pg_upgrade retains these clauses, where they are critical. 0006: Tighten up what d45597f72fe5 did, in that outside of binary upgrade mode, we no longer accept changes to NOT NULL NO INHERIT constraints so that they become INHERIT. Previously we accepted that during recursion, but this isn't really very principled. (I had accepted this because pg_dump required it for some other cases). This changes some test output, and I also simplify some test cases that were testing stuff that's no longer interesting. (To push, I'll squash 0002+0003+0004 as a single one, and perhaps 0005 with them; I produced them like this only to make them easy to see what's changing.) I also have a pending patch for 16 that adds tables like the problematic ones so that they remain for future pg_upgrade testing. With the changes in this series, the whole thing finally works AFAICT. I did notice one more small bit of weirdness, which is that at the end of the process you may end up with constraints that retain the throwaway name. This doesn't seem at all critical, considering that you can't drop them anyway and such names do not survive a further dump (because they are marked as inherited constraint without a "local" definition, so they're not dumped separately). I would still like to fix it, but it seems to require unduly contortions so I may end up not doing anything about it. -- Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/ >From 5cdec1b6ce61f75d886109d7daafd57b8064a4a6 Mon Sep 17 00:00:00 2001 From:
Re: cataloguing NOT NULL constraints
Hello, At Wed, 1 May 2024 19:49:35 +0200, Alvaro Herrera wrote in > Here are two patches that I intend to push soon (hopefully tomorrow). This commit added and edited two error messages, resulting in using slightly different wordings "in" and "on" for relation constraints. + errmsg("cannot change NO INHERIT status of NOT NULL constraint \"%s\" on relation \"%s\"", === + errmsg("cannot change NO INHERIT status of NOT NULL constraint \"%s\" in relation \"%s\"", I think we usually use on in this case. regards. -- Kyotaro Horiguchi NTT Open Source Software Center
Re: cataloguing NOT NULL constraints
02.05.2024 19:21, Alvaro Herrera wrote: Now, you could claim that the standard doesn't mention INCLUDING/EXCLUDING CONSTRAINTS, therefore since we have come up with its definition then we should make it affect not-null constraints. However, there's also this note: NOTE 520 — s, except for NOT NULL, are not included in CDi; s are effectively transformed to s and are thereby also excluded. which is explicitly saying that not-null constraints are treated differently; in essence, with INCLUDING CONSTRAINTS we choose to affect the constraints that the standard says to ignore. Thank you for very detailed and convincing explanation! Now I see what the last sentence here (from [1]) means: INCLUDING CONSTRAINTS CHECK constraints will be copied. No distinction is made between column constraints and table constraints. _Not-null constraints are always copied to the new table._ (I hadn't paid enough attention to it, because this exact paragraph is also presented in previous versions...) [1] https://www.postgresql.org/docs/devel/sql-createtable.html Best regards, Alexander
Re: cataloguing NOT NULL constraints
Hello Alexander On 2024-May-02, Alexander Lakhin wrote: > Could you also clarify, please, how CREATE TABLE ... LIKE is expected to > work with NOT NULL constraints? It should behave identically to 16. If in 16 you end up with a not-nullable column, then in 17 you should get a not-null constraint. > I wonder whether EXCLUDING CONSTRAINTS (ALL) should cover not-null > constraints too. What I'm seeing now, is that: > CREATE TABLE t1 (i int, CONSTRAINT nn NOT NULL i); > CREATE TABLE t2 (LIKE t1 EXCLUDING ALL); > \d+ t2 > -- ends with: > Not-null constraints: > "nn" NOT NULL "i" In 16, this results in Table "public.t2" Column │ Type │ Collation │ Nullable │ Default │ Storage │ Compression │ Stats target │ Description ┼─┼───┼──┼─┼─┼─┼──┼─ i │ integer │ │ not null │ │ plain │ │ │ Access method: heap so the fact that we have a not-null constraint in pg17 is correct. > Or a similar case with PRIMARY KEY: > CREATE TABLE t1 (i int PRIMARY KEY); > CREATE TABLE t2 (LIKE t1 EXCLUDING CONSTRAINTS EXCLUDING INDEXES); > \d+ t2 > -- leaves: > Not-null constraints: > "t2_i_not_null" NOT NULL "i" Here you also end up with a not-nullable column in 16, so I made it do that. Now you could argue that EXCLUDING CONSTRAINTS is explicit in saying that we don't want the constraints; but in that case why did 16 mark the columns as not-null? The answer seems to be that the standard requires this. Look at 11.3 syntax rule 9) b) iii) 4): 4) If the nullability characteristic included in LCDi is known not nullable, then let LNCi be NOT NULL; otherwise, let LNCi be the zero-length character string. where LCDi is "1) Let LCDi be the column descriptor of the i-th column of LT." and then 5) Let CDi be the LCNi LDTi LNCi Now, you could claim that the standard doesn't mention INCLUDING/EXCLUDING CONSTRAINTS, therefore since we have come up with its definition then we should make it affect not-null constraints. However, there's also this note: NOTE 520 — s, except for NOT NULL, are not included in CDi; s are effectively transformed to s and are thereby also excluded. which is explicitly saying that not-null constraints are treated differently; in essence, with INCLUDING CONSTRAINTS we choose to affect the constraints that the standard says to ignore. Thanks for looking! -- Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/ "Learn about compilers. Then everything looks like either a compiler or a database, and now you have two problems but one of them is fun." https://twitter.com/thingskatedid/status/1456027786158776329
Re: cataloguing NOT NULL constraints
Hello Alvaro, 01.05.2024 20:49, Alvaro Herrera wrote: Here are two patches that I intend to push soon (hopefully tomorrow). Thank you for fixing those issues! Could you also clarify, please, how CREATE TABLE ... LIKE is expected to work with NOT NULL constraints? I wonder whether EXCLUDING CONSTRAINTS (ALL) should cover not-null constraints too. What I'm seeing now, is that: CREATE TABLE t1 (i int, CONSTRAINT nn NOT NULL i); CREATE TABLE t2 (LIKE t1 EXCLUDING ALL); \d+ t2 -- ends with: Not-null constraints: "nn" NOT NULL "i" Or a similar case with PRIMARY KEY: CREATE TABLE t1 (i int PRIMARY KEY); CREATE TABLE t2 (LIKE t1 EXCLUDING CONSTRAINTS EXCLUDING INDEXES); \d+ t2 -- leaves: Not-null constraints: "t2_i_not_null" NOT NULL "i" Best regards, Alexander
Re: cataloguing NOT NULL constraints
On 2024-Apr-25, Alvaro Herrera wrote: > > Also, I've found a weird behaviour with a non-inherited NOT NULL > > constraint for a partitioned table: > > CREATE TABLE pt(a int NOT NULL NO INHERIT) PARTITION BY LIST (a); > Ugh. Maybe a way to handle this is to disallow NO INHERIT in > constraints on partitioned tables altogether. I mean, they are a > completely useless gimmick, aren't they? Here are two patches that I intend to push soon (hopefully tomorrow). -- Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/ "No me acuerdo, pero no es cierto. No es cierto, y si fuera cierto, no me acuerdo." (Augusto Pinochet a una corte de justicia) >From 97318ac81cfe82cf52629f141b26a5a497b0913c Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Wed, 1 May 2024 17:32:50 +0200 Subject: [PATCH 1/2] Disallow direct change of NO INHERIT of not-null constraints We support changing NO INHERIT constraint to INHERIT for constraints in child relations when adding a constraint to some ancestor relation, and also during pg_upgrade's schema restore; but other than those special cases, command ALTER TABLE ADD CONSTRAINT should not be allowed to change an existing constraint from NO INHERIT to INHERIT, as that would require to process child relations so that they also acquire an appropriate constraint, which we may not be in a position to do. (It'd also be surprising behavior.) It is conceivable that we want to allow ALTER TABLE SET NOT NULL to make such a change; but in that case some more code is needed to implement it correctly, so for now I've made that throw the same error message. Also, during the prep phase of ALTER TABLE ADD CONSTRAINT, acquire locks on all descendant tables; otherwise we might operate on child tables on which no locks are held, particularly in the mode where a primary key causes not-null constraints to be created on children. Reported-by: Alexander Lakhin Discussion: https://postgr.es/m/7d923a66-55f0-3395-cd40-81c142b54...@gmail.com --- doc/src/sgml/ref/alter_table.sgml | 2 +- src/backend/catalog/heap.c| 20 +++- src/backend/catalog/pg_constraint.c | 15 +++ src/backend/commands/tablecmds.c | 17 +++-- src/include/catalog/pg_constraint.h | 2 +- src/test/regress/expected/inherit.out | 24 +++- src/test/regress/sql/inherit.sql | 15 +++ 7 files changed, 81 insertions(+), 14 deletions(-) diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgml index ebd8c62038..0bf11f6cb6 100644 --- a/doc/src/sgml/ref/alter_table.sgml +++ b/doc/src/sgml/ref/alter_table.sgml @@ -105,7 +105,7 @@ WITH ( MODULUS numeric_literal, REM and column_constraint is: [ CONSTRAINT constraint_name ] -{ NOT NULL | +{ NOT NULL [ NO INHERIT ] | NULL | CHECK ( expression ) [ NO INHERIT ] | DEFAULT default_expr | diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index f0278b9c01..136cc42a92 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -2549,13 +2549,23 @@ AddRelationNewConstraints(Relation rel, /* * If the column already has an inheritable not-null constraint, - * we need only adjust its inheritance status and we're done. If - * the constraint is there but marked NO INHERIT, then it is - * updated in the same way, but we also recurse to the children - * (if any) to add the constraint there as well. + * we need only adjust its coninhcount and we're done. In certain + * cases (see below), if the constraint is there but marked NO + * INHERIT, then we mark it as no longer such and coninhcount + * updated, plus we must also recurse to the children (if any) to + * add the constraint there. + * + * We only allow the inheritability status to change during binary + * upgrade (where it's used to add the not-null constraints for + * children of tables with primary keys), or when we're recursing + * processing a table down an inheritance hierarchy; directly + * allowing a constraint to change from NO INHERIT to INHERIT + * during ALTER TABLE ADD CONSTRAINT would be far too surprising + * behavior. */ existing = AdjustNotNullInheritance1(RelationGetRelid(rel), colnum, - cdef->inhcount, cdef->is_no_inherit); + cdef->inhcount, cdef->is_no_inherit, + IsBinaryUpgrade || allow_merge); if (existing == 1) continue; /* all done! */ else if (existing == -1) diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c index aaf3537d3f..6b8496e085 100644 --- a/src/backend/catalog/pg_constraint.c +++ b/src/backend/catalog/pg_constraint.c @@ -721,7 +721,7 @@ extractNotNullColumn(HeapTuple constrTup) */ int AdjustNotNullInheritance1(Oid relid, AttrNumber attnum, int count, - bool is_no_inherit) + bool is_no_inherit, bool allow_noinherit_change) { HeapTuple
Re: cataloguing NOT NULL constraints
On 2024-Apr-25, Alexander Lakhin wrote: > While studying the NO INHERIT option, I've noticed that the documentation > probably misses it's specification for NOT NULL: > https://www.postgresql.org/docs/devel/sql-createtable.html > > where column_constraint is: > ... > [ CONSTRAINT constraint_name ] > { NOT NULL | > NULL | > CHECK ( expression ) [ NO INHERIT ] | Hmm, okay, will fix. > Also, I've found a weird behaviour with a non-inherited NOT NULL > constraint for a partitioned table: > CREATE TABLE pt(a int NOT NULL NO INHERIT) PARTITION BY LIST (a); > CREATE TABLE dp(a int NOT NULL); > ALTER TABLE pt ATTACH PARTITION dp DEFAULT; > ALTER TABLE pt DETACH PARTITION dp; > fails with: > ERROR: relation 16389 has non-inherited constraint "dp_a_not_null" Ugh. Maybe a way to handle this is to disallow NO INHERIT in constraints on partitioned tables altogether. I mean, they are a completely useless gimmick, aren't they? -- Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/
Re: cataloguing NOT NULL constraints
24.04.2024 20:36, Alvaro Herrera wrote: So I added a restriction that we only accept such a change when recursively adding a constraint, or during binary upgrade. This should limit the damage: you're no longer able to change an existing constraint from NO INHERIT to YES INHERIT merely by doing another ALTER TABLE ADD CONSTRAINT. One thing that has me a little nervous about this whole business is whether we're set up to error out where some child table down the hierarchy has nulls, and we add a not-null constraint to it but fail to do a verification scan. I tried a couple of cases and AFAICS it works correctly, but maybe there are other cases I haven't thought about where it doesn't. Thank you for the fix! While studying the NO INHERIT option, I've noticed that the documentation probably misses it's specification for NOT NULL: https://www.postgresql.org/docs/devel/sql-createtable.html where column_constraint is: ... [ CONSTRAINT constraint_name ] { NOT NULL | NULL | CHECK ( expression ) [ NO INHERIT ] | Also, I've found a weird behaviour with a non-inherited NOT NULL constraint for a partitioned table: CREATE TABLE pt(a int NOT NULL NO INHERIT) PARTITION BY LIST (a); CREATE TABLE dp(a int NOT NULL); ALTER TABLE pt ATTACH PARTITION dp DEFAULT; ALTER TABLE pt DETACH PARTITION dp; fails with: ERROR: relation 16389 has non-inherited constraint "dp_a_not_null" Though with an analogous check constraint, I get: CREATE TABLE pt(a int, CONSTRAINT nna CHECK (a IS NOT NULL) NO INHERIT) PARTITION BY LIST (a); ERROR: cannot add NO INHERIT constraint to partitioned table "pt" Best regards, Alexander
Re: cataloguing NOT NULL constraints
On 2024-Apr-22, Alvaro Herrera wrote: > > On d9f686a72~1 this script results in: > > ERROR: cannot change NO INHERIT status of inherited NOT NULL constraint > > "t_a_not_null" on relation "t" > > Right. Now I'm beginning to wonder if allowing ADD CONSTRAINT to mutate > a pre-existing NO INHERIT constraint into a inheritable constraint > (while accepting a constraint name in the command that we don't heed) is > really what we want. Maybe we should throw some error when the affected > constraint is the topmost one, and only accept the inheritance status > change when we're recursing. So I added a restriction that we only accept such a change when recursively adding a constraint, or during binary upgrade. This should limit the damage: you're no longer able to change an existing constraint from NO INHERIT to YES INHERIT merely by doing another ALTER TABLE ADD CONSTRAINT. One thing that has me a little nervous about this whole business is whether we're set up to error out where some child table down the hierarchy has nulls, and we add a not-null constraint to it but fail to do a verification scan. I tried a couple of cases and AFAICS it works correctly, but maybe there are other cases I haven't thought about where it doesn't. -- Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/ "You're _really_ hosed if the person doing the hiring doesn't understand relational systems: you end up with a whole raft of programmers, none of whom has had a Date with the clue stick." (Andrew Sullivan) https://postgr.es/m/20050809113420.gd2...@phlogiston.dyndns.org >From 238bc09bed57dcd0e4887615f3c57a580eb26d9e Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Mon, 22 Apr 2024 11:32:04 +0200 Subject: [PATCH v2 1/2] Acquire locks on children before recursing ALTER TABLE ADD CONSTRAINT was missing this, as evidenced by assertion failures. While at it, create a small routine to encapsulate the weird find_all_inheritors() call. Reported-by: Alexander Lakhin Discussion: https://postgr.es/m/5b4cd32f-1d5b-c080-c688-31736bbcd...@gmail.com --- src/backend/commands/tablecmds.c | 40 +--- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 3556240c8e..9058a0de7a 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -427,6 +427,7 @@ static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowe static void ATSimpleRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context); +static void ATLockAllDescendants(Oid relid, LOCKMODE lockmode); static void ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode); static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode, @@ -1621,9 +1622,7 @@ RemoveRelations(DropStmt *drop) * will lock those objects in the other order. */ if (state.actual_relkind == RELKIND_PARTITIONED_INDEX) - (void) find_all_inheritors(state.heapOid, - state.heap_lockmode, - NULL); + ATLockAllDescendants(state.heapOid, state.heap_lockmode); /* OK, we're ready to delete this one */ obj.classId = RelationRelationId; @@ -4979,10 +4978,12 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, break; case AT_AddConstraint: /* ADD CONSTRAINT */ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE); - /* Recursion occurs during execution phase */ - /* No command-specific prep needed except saving recurse flag */ if (recurse) + { +/* if recursing, set flag and lock all descendants */ cmd->recurse = true; +ATLockAllDescendants(RelationGetRelid(rel), lockmode); + } pass = AT_PASS_ADD_CONSTR; break; case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */ @@ -6721,6 +6722,21 @@ ATSimpleRecursion(List **wqueue, Relation rel, } } +/* + * ATLockAllDescendants + * + * Acquire lock on all descendant relations of the given relation. + */ +static void +ATLockAllDescendants(Oid relid, LOCKMODE lockmode) +{ + /* + * This is only used in DDL code, so it doesn't matter that we leak the + * list storage; it'll be gone soon enough. + */ + (void) find_all_inheritors(relid, lockmode, NULL); +} + /* * Obtain list of partitions of the given table, locking them all at the given * lockmode and ensuring that they all pass CheckTableNotInUse. @@ -9370,10 +9386,9 @@ ATPrepAddPrimaryKey(List **wqueue, Relation rel, AlterTableCmd *cmd, /* * Acquire locks all the way down the hierarchy. The recursion to lower - * levels occurs at execution time as necessary, so we don't need to do it - * here, and we don't need the returned list either. + * levels occurs at execution time as necessary. */ - (void) find_all_inheritors(RelationGetRelid(rel), lockmode, NULL); +
Re: cataloguing NOT NULL constraints
Hi Alexander, On 2024-Apr-18, Alexander Lakhin wrote: > 18.04.2024 16:39, Alvaro Herrera wrote: > > I have pushed a fix which should hopefully fix this problem > > (d9f686a72e). Please give this a look. Thanks for reporting the issue. > > Please look at an assertion failure, introduced with d9f686a72: > CREATE TABLE t(a int, NOT NULL a NO INHERIT); > CREATE TABLE t2() INHERITS (t); > > ALTER TABLE t ADD CONSTRAINT nna NOT NULL a; > TRAP: failed Assert("lockmode != NoLock || IsBootstrapProcessingMode() || > CheckRelationLockedByMe(r, AccessShareLock, true)"), File: "relation.c", > Line: 67, PID: 2980258 Ah, of course -- we're missing acquiring locks during the prep phase for the recursive case of ADD CONSTRAINT. So we just need to add find_all_inheritors() to do so in the AT_AddConstraint case in ATPrepCmd(). However these naked find_all_inheritors() call look a bit ugly to me, so I couldn't resist the temptation of adding a static function ATLockAllDescendants to clean it up a bit. I'll also add your script to the tests and push shortly. > On d9f686a72~1 this script results in: > ERROR: cannot change NO INHERIT status of inherited NOT NULL constraint > "t_a_not_null" on relation "t" Right. Now I'm beginning to wonder if allowing ADD CONSTRAINT to mutate a pre-existing NO INHERIT constraint into a inheritable constraint (while accepting a constraint name in the command that we don't heed) is really what we want. Maybe we should throw some error when the affected constraint is the topmost one, and only accept the inheritance status change when we're recursing. Also I just noticed that in 9b581c534186 (which introduced this error message) I used ERRCODE_DATATYPE_MISMATCH ... Is that really appropriate here? -- Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/ "Once again, thank you and all of the developers for your hard work on PostgreSQL. This is by far the most pleasant management experience of any database I've worked on." (Dan Harris) http://archives.postgresql.org/pgsql-performance/2006-04/msg00247.php >From 35b485b72d0675d631cde9f95e65d9c0db9254b8 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Mon, 22 Apr 2024 11:32:04 +0200 Subject: [PATCH] Acquire locks on children before recursing ALTER TABLE ADD CONSTRAINT was missing this, as evidenced by assertion failures. Reported-by: Alexander Lakhin Discussion: https://postgr.es/m/5b4cd32f-1d5b-c080-c688-31736bbcd...@gmail.com --- src/backend/commands/tablecmds.c | 33 ++-- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 3556240c8e..8941181912 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -427,6 +427,7 @@ static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowe static void ATSimpleRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context); +static void ATLockAllDescendants(Oid relid, LOCKMODE lockmode); static void ATCheckPartitionsNotInUse(Relation rel, LOCKMODE lockmode); static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode, @@ -1621,9 +1622,7 @@ RemoveRelations(DropStmt *drop) * will lock those objects in the other order. */ if (state.actual_relkind == RELKIND_PARTITIONED_INDEX) - (void) find_all_inheritors(state.heapOid, - state.heap_lockmode, - NULL); + ATLockAllDescendants(state.heapOid, state.heap_lockmode); /* OK, we're ready to delete this one */ obj.classId = RelationRelationId; @@ -4979,10 +4978,15 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, break; case AT_AddConstraint: /* ADD CONSTRAINT */ ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE); - /* Recursion occurs during execution phase */ - /* No command-specific prep needed except saving recurse flag */ if (recurse) + { +/* + * Make note for execution phase about need for recursion; + * also acquire lock on all descendants. + */ +ATLockAllDescendants(RelationGetRelid(rel), lockmode); cmd->recurse = true; + } pass = AT_PASS_ADD_CONSTR; break; case AT_AddIndexConstraint: /* ADD CONSTRAINT USING INDEX */ @@ -6721,6 +6725,17 @@ ATSimpleRecursion(List **wqueue, Relation rel, } } +/* + * ATLockAllDescendants + * + * Acquire lock on all descendants of the given relation. + */ +static void +ATLockAllDescendants(Oid relid, LOCKMODE lockmode) +{ + (void) find_all_inheritors(relid, lockmode, NULL); +} + /* * Obtain list of partitions of the given table, locking them all at the given * lockmode and ensuring that they all pass CheckTableNotInUse. @@ -9370,10 +9385,9 @@ ATPrepAddPrimaryKey(List **wqueue, Relation rel, AlterTableCmd *cmd, /* *
Re: cataloguing NOT NULL constraints
Hello Alvaro, 18.04.2024 16:39, Alvaro Herrera wrote: I have pushed a fix which should hopefully fix this problem (d9f686a72e). Please give this a look. Thanks for reporting the issue. Please look at an assertion failure, introduced with d9f686a72: CREATE TABLE t(a int, NOT NULL a NO INHERIT); CREATE TABLE t2() INHERITS (t); ALTER TABLE t ADD CONSTRAINT nna NOT NULL a; TRAP: failed Assert("lockmode != NoLock || IsBootstrapProcessingMode() || CheckRelationLockedByMe(r, AccessShareLock, true)"), File: "relation.c", Line: 67, PID: 2980258 On d9f686a72~1 this script results in: ERROR: cannot change NO INHERIT status of inherited NOT NULL constraint "t_a_not_null" on relation "t" Best regards, Alexander
Re: cataloguing NOT NULL constraints
On 2024-Jan-25, Andrew Bille wrote: > Starting from b0e96f31, pg_upgrade fails with inherited NOT NULL constraint: > For example upgrade from 9c13b6814a (or REL_12_STABLE .. REL_16_STABLE) to > b0e96f31 (or master) with following two tables (excerpt from > src/test/regress/sql/rules.sql) > > create table test_0 (id serial primary key); > create table test_1 (id integer primary key) inherits (test_0); I have pushed a fix which should hopefully fix this problem (d9f686a72e). Please give this a look. Thanks for reporting the issue. -- Álvaro HerreraBreisgau, Deutschland — https://www.EnterpriseDB.com/ "I apologize for the confusion in my previous responses. There appears to be an error." (ChatGPT)
Re: cataloguing NOT NULL constraints
(I think I had already argued this point, but I don't see it in the archives, so here it is again). On 2024-Feb-07, jian he wrote: > if you place CommandCounterIncrement inside the `if (recurse)` branch, > then the regression test will be ok. Yeah, but don't you think this is too magical? I mean, randomly added CCIs in the execution path for other reasons would break this. Worse -- how can we _ensure_ that no CCIs occur at all? I mean, it's possible that an especially crafted multi-subcommand ALTER TABLE could contain just the right CCI to break things in the opposite way. The difference in behavior would be difficult to justify. (For good or ill, ALTER TABLE ATTACH PARTITION cannot run in a multi-subcommand ALTER TABLE, so this concern might be misplaced. Still, more certainty seems better than less.) I've pushed both these patches now, adding what seemed a reasonable set of test cases. If there still are cases behaving in unexpected ways, please let me know. -- Álvaro HerreraBreisgau, Deutschland — https://www.EnterpriseDB.com/ "La espina, desde que nace, ya pincha" (Proverbio africano)
Re: cataloguing NOT NULL constraints
On Mon, Feb 5, 2024 at 5:51 PM Alvaro Herrera wrote: > > On 2024-Feb-05, Alvaro Herrera wrote: > > > Hmm, let me have a look, I can probably get this one fixed today before > > embarking on a larger fix elsewhere in the same feature. > > You know what -- this missing CCI has a much more visible impact, which > is that the attnotnull marker that a primary key imposes on a partition > is propagated early. So this regression test no longer fails: > > create table cnn2_parted(a int primary key) partition by list (a); > create table cnn2_part1(a int); > alter table cnn2_parted attach partition cnn2_part1 for values in (1); > > Here, in the existing code the ALTER TABLE ATTACH fails with the error > message that > ERROR: primary key column "a" is not marked NOT NULL > but with the patch, this no longer occurs. > > I'm not sure that this behavior change is desirable ... I have vague > memories of people complaining that this sort of error was not very > welcome ... but on the other hand it seems now pretty clear that if it > *is* desirable, then its implementation is no good, because a single > added CCI breaks it. > > I'm leaning towards accepting the behavior change, but I'd like to > investigate a little bit more first, but what do others think? > if you place CommandCounterIncrement inside the `if (recurse)` branch, then the regression test will be ok. diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 9f516967..25e225c2 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -7719,6 +7719,9 @@ set_attnotnull(List **wqueue, Relation rel, AttrNumber attnum, bool recurse, false)); retval |= set_attnotnull(wqueue, childrel, childattno, recurse, lockmode); + + CommandCounterIncrement();
Re: cataloguing NOT NULL constraints
On 2024-Feb-05, Alvaro Herrera wrote: > While playing with it I noticed this other behavior change from 16, > > create table pa (a int primary key) partition by list (a); > create table pe (a int unique); > alter table pa attach partition pe for values in (1, null); > > In 16, we get the error: > ERROR: column "a" in child table must be marked NOT NULL > which is correct (because the PK requires not-null). In master we just > let that through, but that seems to be a separate bug. Hmm, so my initial reaction was to make the constraint-matching code ignore the constraint in the partition-to-be if it's not the same type (this is what patch 0002 here does) ... but what ends up happening is that we create a separate, identical constraint+index for the primary key. I don't like that behavior too much myself, as it seems too magical and surprising, since it could cause the ALTER TABLE ATTACH operation of a large partition become costly and slower, since it needs to create an index instead of merely scanning the whole data. I'll look again at the idea of raising an error if the not-null constraint is not already present. That seems safer (and also, it's what we've been doing all along). -- Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/ >From 6a9feb7800675983198fbb3928c3f34360ac5a49 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Mon, 5 Feb 2024 10:18:43 +0100 Subject: [PATCH v2 1/2] Fix failure to merge NOT NULL constraints in inheritance set_attnotnull() was not careful to CommandCounterIncrement() in cases of multiple recursion. Omission in b0e96f311985. Reported-by: Alexander Lakhin Discussion: https://postgr.es/m/045dec3f-9b3d-aa44-0c99-85f699230...@gmail.com --- src/backend/commands/tablecmds.c | 4 src/test/regress/expected/constraints.out | 1 - src/test/regress/expected/inherit.out | 8 src/test/regress/sql/inherit.sql | 8 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 9f51696740..02724d5f04 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -7703,6 +7703,10 @@ set_attnotnull(List **wqueue, Relation rel, AttrNumber attnum, bool recurse, List *children; ListCell *lc; + /* Make above catalog changes visible */ + if (retval) + CommandCounterIncrement(); + children = find_inheritance_children(RelationGetRelid(rel), lockmode); foreach(lc, children) { diff --git a/src/test/regress/expected/constraints.out b/src/test/regress/expected/constraints.out index 5b068477bf..bef3d6577c 100644 --- a/src/test/regress/expected/constraints.out +++ b/src/test/regress/expected/constraints.out @@ -1010,7 +1010,6 @@ ERROR: constraint "cnn_parent_pkey" of relation "cnn_parent" does not exist create table cnn2_parted(a int primary key) partition by list (a); create table cnn2_part1(a int); alter table cnn2_parted attach partition cnn2_part1 for values in (1); -ERROR: primary key column "a" is not marked NOT NULL drop table cnn2_parted, cnn2_part1; create table cnn2_parted(a int not null) partition by list (a); create table cnn2_part1(a int primary key); diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index 130a924228..fe33bc4c2f 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -2496,6 +2496,14 @@ drop table inh_p1, inh_p2, inh_p3, inh_p4 cascade; NOTICE: drop cascades to 2 other objects DETAIL: drop cascades to table inh_multiparent drop cascades to table inh_multiparent2 +-- recursively add column with constraint while merging existing column +create table inh_p1 (); +create table inh_p2 (f1 int) inherits (inh_p1); +create table inh_p3 () inherits (inh_p1, inh_p2); +alter table inh_p1 add column f1 int not null; +NOTICE: merging definition of column "f1" for child "inh_p2" +NOTICE: merging definition of column "f1" for child "inh_p3" +drop table inh_p1, inh_p2, inh_p3; -- -- Mixed ownership inheritance tree -- diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql index 0ef9a61bc1..41cdde1d90 100644 --- a/src/test/regress/sql/inherit.sql +++ b/src/test/regress/sql/inherit.sql @@ -961,6 +961,14 @@ select conrelid::regclass, contype, conname, drop table inh_p1, inh_p2, inh_p3, inh_p4 cascade; +-- recursively add column with constraint while merging existing column +create table inh_p1 (); +create table inh_p2 (f1 int) inherits (inh_p1); +create table inh_p3 () inherits (inh_p1, inh_p2); +alter table inh_p1 add column f1 int not null; + +drop table inh_p1, inh_p2, inh_p3; + -- -- Mixed ownership inheritance tree -- -- 2.39.2 >From e871a4a991762ec5312239aa1a1e0ff918d6ce90 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Mon, 5 Feb 2024 19:05:34 +0100 Subject: [PATCH v2 2/2] ATTACH PARTITION: Don't let a UNIQUE constraint match a PRIMARY
Re: cataloguing NOT NULL constraints
On 2024-Feb-05, Alvaro Herrera wrote: > So this regression test no longer fails: > > create table cnn2_parted(a int primary key) partition by list (a); > create table cnn2_part1(a int); > alter table cnn2_parted attach partition cnn2_part1 for values in (1); > Here, in the existing code the ALTER TABLE ATTACH fails with the error > message that > ERROR: primary key column "a" is not marked NOT NULL > but with the patch, this no longer occurs. I think this change is OK. In the partition, the primary key is created in the partition anyway (as expected) which marks the column as attnotnull[*], and the table is scanned for presence of NULLs if there's no not-null constraint, and not scanned if there's one. (The actual scan is inevitable anyway because we must check the partition constraint). This seems the behavior we want. [*] This attnotnull constraint is lost if you DETACH the partition and drop the primary key, which is also the behavior we want. While playing with it I noticed this other behavior change from 16, create table pa (a int primary key) partition by list (a); create table pe (a int unique); alter table pa attach partition pe for values in (1, null); In 16, we get the error: ERROR: column "a" in child table must be marked NOT NULL which is correct (because the PK requires not-null). In master we just let that through, but that seems to be a separate bug. -- Álvaro HerreraBreisgau, Deutschland — https://www.EnterpriseDB.com/ "Saca el libro que tu religión considere como el indicado para encontrar la oración que traiga paz a tu alma. Luego rebootea el computador y ve si funciona" (Carlos Duclós)
Re: cataloguing NOT NULL constraints
On 2024-Feb-05, Alvaro Herrera wrote: > Subject: [PATCH v1] Fix failure to merge NOT NULL constraints in inheritance > > set_attnotnull() was not careful to CommandCounterIncrement() in cases > of multiple recursion. Omission in b0e96f311985. Eh, this needs to read "multiple inheritance" rather than "multiple recursion". (I'd also need to describe the change for the partitioning cases in the commit message.) -- Álvaro HerreraBreisgau, Deutschland — https://www.EnterpriseDB.com/ "Someone said that it is at least an order of magnitude more work to do production software than a prototype. I think he is wrong by at least an order of magnitude." (Brian Kernighan)
Re: cataloguing NOT NULL constraints
On 2024-Feb-05, Alvaro Herrera wrote: > Hmm, let me have a look, I can probably get this one fixed today before > embarking on a larger fix elsewhere in the same feature. You know what -- this missing CCI has a much more visible impact, which is that the attnotnull marker that a primary key imposes on a partition is propagated early. So this regression test no longer fails: create table cnn2_parted(a int primary key) partition by list (a); create table cnn2_part1(a int); alter table cnn2_parted attach partition cnn2_part1 for values in (1); Here, in the existing code the ALTER TABLE ATTACH fails with the error message that ERROR: primary key column "a" is not marked NOT NULL but with the patch, this no longer occurs. I'm not sure that this behavior change is desirable ... I have vague memories of people complaining that this sort of error was not very welcome ... but on the other hand it seems now pretty clear that if it *is* desirable, then its implementation is no good, because a single added CCI breaks it. I'm leaning towards accepting the behavior change, but I'd like to investigate a little bit more first, but what do others think? -- Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/ >From 486f6bfa8faa6162257c5f12b52180b5a3d89704 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Mon, 5 Feb 2024 10:18:43 +0100 Subject: [PATCH v1] Fix failure to merge NOT NULL constraints in inheritance set_attnotnull() was not careful to CommandCounterIncrement() in cases of multiple recursion. Omission in b0e96f311985. Reported-by: Alexander Lakhin Discussion: https://postgr.es/m/045dec3f-9b3d-aa44-0c99-85f699230...@gmail.com --- src/backend/commands/tablecmds.c | 4 src/test/regress/expected/constraints.out | 1 - src/test/regress/expected/inherit.out | 8 src/test/regress/sql/inherit.sql | 8 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 9f51696740..02724d5f04 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -7703,6 +7703,10 @@ set_attnotnull(List **wqueue, Relation rel, AttrNumber attnum, bool recurse, List *children; ListCell *lc; + /* Make above catalog changes visible */ + if (retval) + CommandCounterIncrement(); + children = find_inheritance_children(RelationGetRelid(rel), lockmode); foreach(lc, children) { diff --git a/src/test/regress/expected/constraints.out b/src/test/regress/expected/constraints.out index 5b068477bf..bef3d6577c 100644 --- a/src/test/regress/expected/constraints.out +++ b/src/test/regress/expected/constraints.out @@ -1010,7 +1010,6 @@ ERROR: constraint "cnn_parent_pkey" of relation "cnn_parent" does not exist create table cnn2_parted(a int primary key) partition by list (a); create table cnn2_part1(a int); alter table cnn2_parted attach partition cnn2_part1 for values in (1); -ERROR: primary key column "a" is not marked NOT NULL drop table cnn2_parted, cnn2_part1; create table cnn2_parted(a int not null) partition by list (a); create table cnn2_part1(a int primary key); diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index 130a924228..fe33bc4c2f 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -2496,6 +2496,14 @@ drop table inh_p1, inh_p2, inh_p3, inh_p4 cascade; NOTICE: drop cascades to 2 other objects DETAIL: drop cascades to table inh_multiparent drop cascades to table inh_multiparent2 +-- recursively add column with constraint while merging existing column +create table inh_p1 (); +create table inh_p2 (f1 int) inherits (inh_p1); +create table inh_p3 () inherits (inh_p1, inh_p2); +alter table inh_p1 add column f1 int not null; +NOTICE: merging definition of column "f1" for child "inh_p2" +NOTICE: merging definition of column "f1" for child "inh_p3" +drop table inh_p1, inh_p2, inh_p3; -- -- Mixed ownership inheritance tree -- diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql index 0ef9a61bc1..41cdde1d90 100644 --- a/src/test/regress/sql/inherit.sql +++ b/src/test/regress/sql/inherit.sql @@ -961,6 +961,14 @@ select conrelid::regclass, contype, conname, drop table inh_p1, inh_p2, inh_p3, inh_p4 cascade; +-- recursively add column with constraint while merging existing column +create table inh_p1 (); +create table inh_p2 (f1 int) inherits (inh_p1); +create table inh_p3 () inherits (inh_p1, inh_p2); +alter table inh_p1 add column f1 int not null; + +drop table inh_p1, inh_p2, inh_p3; + -- -- Mixed ownership inheritance tree -- -- 2.39.2
Re: cataloguing NOT NULL constraints
On 2024-Feb-05, Michael Paquier wrote: > On Fri, Feb 02, 2024 at 07:00:01PM +0300, Alexander Lakhin wrote: > > results in: > > NOTICE: merging definition of column "i" for child "b" > > NOTICE: merging definition of column "i" for child "c" > > ERROR: tuple already updated by self > > > > (This is similar to bug #18297, but ATExecAddColumn() isn't guilty in this > > case.) > > Still I suspect that the fix should be similar, so I'll go put a coin > on a missing CCI(). Hmm, let me have a look, I can probably get this one fixed today before embarking on a larger fix elsewhere in the same feature. -- Álvaro HerreraBreisgau, Deutschland — https://www.EnterpriseDB.com/ "After a quick R of TFM, all I can say is HOLY CR** THAT IS COOL! PostgreSQL was amazing when I first started using it at 7.2, and I'm continually astounded by learning new features and techniques made available by the continuing work of the development team." Berend Tober, http://archives.postgresql.org/pgsql-hackers/2007-08/msg01009.php
Re: cataloguing NOT NULL constraints
On Fri, Feb 02, 2024 at 07:00:01PM +0300, Alexander Lakhin wrote: > results in: > NOTICE: merging definition of column "i" for child "b" > NOTICE: merging definition of column "i" for child "c" > ERROR: tuple already updated by self > > (This is similar to bug #18297, but ATExecAddColumn() isn't guilty in this > case.) Still I suspect that the fix should be similar, soI'll go put a coin on a missing CCI(). -- Michael signature.asc Description: PGP signature
Re: cataloguing NOT NULL constraints
Hello Alvaro, Please look at an anomaly introduced with b0e96f311. The following script: CREATE TABLE a (); CREATE TABLE b (i int) INHERITS (a); CREATE TABLE c () INHERITS (a, b); ALTER TABLE a ADD COLUMN i int NOT NULL; results in: NOTICE: merging definition of column "i" for child "b" NOTICE: merging definition of column "i" for child "c" ERROR: tuple already updated by self (This is similar to bug #18297, but ATExecAddColumn() isn't guilty in this case.) Best regards, Alexander
Re: cataloguing NOT NULL constraints
Hi Alvaro, 25.08.2023 14:38, Alvaro Herrera wrote: > I have now pushed this again. Hopefully it'll stick this time. Starting from b0e96f31, pg_upgrade fails with inherited NOT NULL constraint: For example upgrade from 9c13b6814a (or REL_12_STABLE .. REL_16_STABLE) to b0e96f31 (or master) with following two tables (excerpt from src/test/regress/sql/rules.sql) create table test_0 (id serial primary key); create table test_1 (id integer primary key) inherits (test_0); I get the failure: Setting frozenxid and minmxid counters in new cluster ok Restoring global objects in the new cluster ok Restoring database schemas in the new cluster test *failure* Consult the last few lines of "new/pg_upgrade_output.d/20240125T151231.112/log/pg_upgrade_dump_16384.log" for the probable cause of the failure. Failure, exiting In log: pg_restore: connecting to database for restore pg_restore: creating DATABASE "test" pg_restore: connecting to new database "test" pg_restore: creating DATABASE PROPERTIES "test" pg_restore: connecting to new database "test" pg_restore: creating pg_largeobject "pg_largeobject" pg_restore: creating COMMENT "SCHEMA "public"" pg_restore: creating TABLE "public.test_0" pg_restore: creating SEQUENCE "public.test_0_id_seq" pg_restore: creating SEQUENCE OWNED BY "public.test_0_id_seq" pg_restore: creating TABLE "public.test_1" pg_restore: creating DEFAULT "public.test_0 id" pg_restore: executing SEQUENCE SET test_0_id_seq pg_restore: creating CONSTRAINT "public.test_0 test_0_pkey" pg_restore: creating CONSTRAINT "public.test_1 test_1_pkey" pg_restore: while PROCESSING TOC: pg_restore: from TOC entry 3200; 2606 16397 CONSTRAINT test_1 test_1_pkey andrew pg_restore: error: could not execute query: ERROR: cannot drop inherited constraint "pgdump_throwaway_notnull_0" of relation "test_1" Command was: -- For binary upgrade, must preserve pg_class oids and relfilenodes SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('16396'::pg_catalog.oid); SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('16396'::pg_catalog.oid); ALTER TABLE ONLY "public"."test_1" ADD CONSTRAINT "test_1_pkey" PRIMARY KEY ("id"); ALTER TABLE ONLY "public"."test_1" DROP CONSTRAINT pgdump_throwaway_notnull_0; Thanks! On Thu, Jan 25, 2024 at 3:06 PM Alvaro Herrera wrote: > I have now pushed this again. Hopefully it'll stick this time. > > We may want to make some further tweaks to the behavior in some cases -- > for example, don't disallow ALTER TABLE DROP NOT NULL when the > constraint is both inherited and has a local definition; the other > option is to mark the constraint as no longer having a local definition. > I left it the other way because that's what CHECK does; maybe we would > like to change both at once. > > I ran it through CI, and the pg_upgrade test with a dump from 14's > regression test database and everything worked well, but it's been a > while since I tested the sepgsql part of it, so that might the first > thing to explode. > > -- > Álvaro Herrera 48°01'N 7°57'E — > https://www.EnterpriseDB.com/ > > > > >
Re: cataloguing NOT NULL constraints
On 2023-Oct-12, Alexander Lakhin wrote: Hello, > I've discovered that that commit added several recursive functions, and > some of them are not protected from stack overflow. True. I reproduced the first two, but didn't attempt to reproduce the third one -- patching all these to check for stack depth is cheap protection. I also patched ATAddCheckNNConstraint: > (ATAddCheckNNConstraint() is protected because it calls > AddRelationNewConstraints(), which in turn calls StoreRelCheck() -> > CreateConstraintEntry() -> recordDependencyOnSingleRelExpr() -> > find_expr_references_walker() -> expression_tree_walker() -> > expression_tree_walker() -> check_stack_depth().) because it seems uselessly risky to rely on depth checks that exist on completely unrelated pieces of code, when the function visibly recurses on itself. Especially so since the test cases that demonstrate crashes are so expensive to run, which means we're not going to detect it if at some point that other stack depth check stops being called for whatever reason. BTW probably the tests could be made much cheaper by running the server with a lower "ulimit -s" setting. I didn't try. I noticed one more crash while trying to "drop table" one of the hierarchies your scripts create. But it's a preexisting issue which needs a backpatched fix, and I think Egor already reported it in the other thread. Thank you -- Álvaro HerreraBreisgau, Deutschland — https://www.EnterpriseDB.com/ "Industry suffers from the managerial dogma that for the sake of stability and continuity, the company should be independent of the competence of individual employees." (E. Dijkstra)
Re: cataloguing NOT NULL constraints
Hi Alvaro, 25.08.2023 14:38, Alvaro Herrera wrote: I have now pushed this again. Hopefully it'll stick this time. I've discovered that that commit added several recursive functions, and some of them are not protected from stack overflow. Namely, with "max_locks_per_transaction = 600" and default ulimit -s (8192), I observe server crashes with the following scripts: # ATExecSetNotNull() (n=4; printf "create table t0 (a int, b int);"; for ((i=1;i<=$n;i++)); do printf "create table t$i() inherits(t$(( $i - 1 ))); "; done; printf "alter table t0 alter b set not null;" ) | psql >psql.log # dropconstraint_internal() (n=2; printf "create table t0 (a int, b int not null);"; for ((i=1;i<=$n;i++)); do printf "create table t$i() inherits(t$(( $i - 1 ))); "; done; printf "alter table t0 alter b drop not null;" ) | psql >psql.log # set_attnotnull() (n=11; printf "create table tp (a int, b int, primary key(a, b)) partition by range (a); create table tp0 (a int primary key, b int) partition by range (a);"; for ((i=1;i<=$n;i++)); do printf "create table tp$i partition of tp$(( $i - 1 )) for values from ($i) to (100) partition by range (a);"; done; printf "alter table tp attach partition tp0 for values from (0) to (100);") | psql >psql.log # this takes half an hour on my machine May be you would find appropriate to add check_stack_depth() to these functions. (ATAddCheckNNConstraint() is protected because it calls AddRelationNewConstraints(), which in turn calls StoreRelCheck() -> CreateConstraintEntry() -> recordDependencyOnSingleRelExpr() -> find_expr_references_walker() -> expression_tree_walker() -> expression_tree_walker() -> check_stack_depth().) (There were patches prepared for similar cases [1], but they don't cover new functions, of course, and I'm not sure how to handle all such instances.) [1] https://commitfest.postgresql.org/45/4239/ Best regards, Alexander
Re: cataloguing NOT NULL constraints
On 2023-Sep-05, Peter Eisentraut wrote: > The following information schema views are affected by the not-null > constraint catalog entries: > > 1. CHECK_CONSTRAINTS > 2. CONSTRAINT_COLUMN_USAGE > 3. DOMAIN_CONSTRAINTS > 4. TABLE_CONSTRAINTS > > Note that 1 and 3 also contain domain constraints. So as long as the domain > not-null constraints are not similarly catalogued, we can't delete the > separate not-null union branch. (3 never had one, so arguably a bit buggy.) > > I think we can fix up 4 by just deleting the not-null union branch. > > For 2, the simple fix is also easy, but there are some other options, as you > discuss above. > > How do you want to proceed? I posted as a patch in a separate thread[1]. Let me fix up the definitions for views 1 and 3 for domains per your comments, and I'll post in that thread again. [1] https://postgr.es/m/202309041710.psytrxlsiqex@alvherre.pgsql -- Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/ "Ninguna manada de bestias tiene una voz tan horrible como la humana" (Orual)
Re: cataloguing NOT NULL constraints
On 31.08.23 12:02, Alvaro Herrera wrote: In constraint_column_usage, you're adding a relkind to the catalog scan that goes through pg_depend for CHECK constraints. Here we can rely on a simple conkey[1] check and a separate UNION ALL arm[q5]; this is also faster when there are many tables. The third view definition looks ok. It's certainly very nice to be able to delete XXX comments there. The following information schema views are affected by the not-null constraint catalog entries: 1. CHECK_CONSTRAINTS 2. CONSTRAINT_COLUMN_USAGE 3. DOMAIN_CONSTRAINTS 4. TABLE_CONSTRAINTS Note that 1 and 3 also contain domain constraints. So as long as the domain not-null constraints are not similarly catalogued, we can't delete the separate not-null union branch. (3 never had one, so arguably a bit buggy.) I think we can fix up 4 by just deleting the not-null union branch. For 2, the simple fix is also easy, but there are some other options, as you discuss above. How do you want to proceed?
Re: cataloguing NOT NULL constraints
Looking at your 0001 patch, which adds tests for some of the information_schema views, I think it's a bad idea to put them in whatever other regression .sql files; they would be subject to concurrent changes depending on what other tests are being executed in the same parallel test. I suggest to put them all in a separate .sql file, and schedule that to run in the last concurrent group, together with the tablespace test. This way, it would capture all the objects left over by other test files. -- Álvaro HerreraBreisgau, Deutschland — https://www.EnterpriseDB.com/
Re: cataloguing NOT NULL constraints
On 2023-Aug-31, Alvaro Herrera wrote: > Hmm, that's some weird code I left there all right. Can you please try > this patch? (Not final; I'll review it more completely later, > particularly to add this test case.) The change in MergeAttributesIntoExisting turned out to be close but not quite there, so I pushed another version of the fix. In case you're wondering, the change in MergeConstraintsIntoExisting is a related but different case, for which I added the other test case you see there. I also noticed, while looking at this, that there's another problem when a child has a NO INHERIT not-null constraint and the parent has a primary key in the same column. It should refuse, or take over by marking it no longer NO INHERIT. But it just accepts silently and all appears to be good. The problems appear when you add a child to that child. I'll look into this later; it's not exactly the same code. At least it's not a crasher. -- Álvaro HerreraBreisgau, Deutschland — https://www.EnterpriseDB.com/
Re: cataloguing NOT NULL constraints
31.08.2023 13:26, Alvaro Herrera wrote: Hmm, that's some weird code I left there all right. Can you please try this patch? (Not final; I'll review it more completely later, particularly to add this test case.) Yes, your patch fixes the issue. I get the same error now: ERROR: column "a" in child table must be marked NOT NULL Thank you! Best regards, Alexander
Re: cataloguing NOT NULL constraints
Hello Alexander, Thanks for testing. On 2023-Aug-31, Alexander Lakhin wrote: > 25.08.2023 14:38, Alvaro Herrera wrote: > > I have now pushed this again. Hopefully it'll stick this time. > > I've found that after that commit the following query: > CREATE TABLE t(a int PRIMARY KEY) PARTITION BY RANGE (a); > CREATE TABLE tp1(a int); > ALTER TABLE t ATTACH PARTITION tp1 FOR VALUES FROM (0) to (1); > > triggers a server crash: Hmm, that's some weird code I left there all right. Can you please try this patch? (Not final; I'll review it more completely later, particularly to add this test case.) -- Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/ It does it in a really, really complicated way why does it need to be complicated? Because it's MakeMaker. >From ab241913dec84265ca64d3cb76d1509bb7ce1808 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Thu, 31 Aug 2023 12:24:18 +0200 Subject: [PATCH] Fix not-null constraint test Per report from Alexander Lakhin --- src/backend/commands/tablecmds.c | 13 - 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index d097da3c78..5941d0a4be 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -15750,7 +15750,8 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel) contup = findNotNullConstraintAttnum(RelationGetRelid(parent_rel), attribute->attnum); -if (!((Form_pg_constraint) GETSTRUCT(contup))->connoinherit) + +if (!HeapTupleIsValid(contup)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("column \"%s\" in child table must be marked NOT NULL", @@ -15975,10 +15976,20 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel) systable_endscan(child_scan); if (!found) + { + if (parent_con->contype == CONSTRAINT_NOTNULL) +ereport(ERROR, + errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("column \"%s\" in child table must be marked NOT NULL", + get_attname(parent_relid, + extractNotNullColumn(parent_tuple), + false))); + ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("child table is missing constraint \"%s\"", NameStr(parent_con->conname; + } } systable_endscan(parent_scan); -- 2.39.2
Re: cataloguing NOT NULL constraints
On 2023-Mar-29, Peter Eisentraut wrote: > On 27.03.23 15:55, Peter Eisentraut wrote: > > The information schema should be updated. I think the following views: > > > > - CHECK_CONSTRAINTS > > - CONSTRAINT_COLUMN_USAGE > > - DOMAIN_CONSTRAINTS > > - TABLE_CONSTRAINTS > > > > It looks like these have no test coverage; maybe that could be addressed > > at the same time. > > Here are patches for this. I haven't included the expected files for the > tests; this should be checked again that output is correct or the changes > introduced by this patch set are as expected. > > The reason we didn't have tests for this before was probably in part because > the information schema made up names for not-null constraints involving > OIDs, so the test wouldn't have been stable. > > Feel free to integrate this, or we can add it on afterwards. I'm eyeing patch 0002 here. I noticed that in view check_constraints it defines the not-null constraint definition as substrings over the pg_get_constraintdef() function[q1], so I wondered whether it might be better to join to pg_attribute instead. I see two options: 1. add a scalar subselect in the select list for each constraint [q2] 2. add a LEFT JOIN to pg_attribute to the main FROM list [q3] ON con.conrelid=att.attrelid AND con.conkey[1] = con.attrelid With just the regression test tables in place, these forms are all pretty much the same in execution time. I then created 20k tables with 6 columns each and NOT NULL constraint on each column[4]. That's not a huge amount but it's credible for a medium-size database with a bunch of partitions (it's amazing what passes for a medium-size database these days). I was surprised to find out that q3 (~130ms) is three times faster than q2 (~390ms), which is in turn more than twice faster than your proposed q1 (~870ms). So unless you have another reason to prefer it, I think we should use q3 here. In constraint_column_usage, you're adding a relkind to the catalog scan that goes through pg_depend for CHECK constraints. Here we can rely on a simple conkey[1] check and a separate UNION ALL arm[q5]; this is also faster when there are many tables. The third view definition looks ok. It's certainly very nice to be able to delete XXX comments there. [q1] SELECT current_database()::information_schema.sql_identifier AS constraint_catalog, rs.nspname::information_schema.sql_identifier AS constraint_schema, con.conname::information_schema.sql_identifier AS constraint_name, CASE con.contype WHEN 'c'::"char" THEN "left"(SUBSTRING(pg_get_constraintdef(con.oid) FROM 8), '-1'::integer) WHEN 'n'::"char" THEN SUBSTRING(pg_get_constraintdef(con.oid) FROM 10) || ' IS NOT NULL'::text ELSE NULL::text END::information_schema.character_data AS check_clause FROM pg_constraint con LEFT JOIN pg_namespace rs ON rs.oid = con.connamespace LEFT JOIN pg_class c ON c.oid = con.conrelid LEFT JOIN pg_type t ON t.oid = con.contypid WHERE pg_has_role(COALESCE(c.relowner, t.typowner), 'USAGE'::text) AND (con.contype = ANY (ARRAY['c'::"char", 'n'::"char"])); [q2] SELECT current_database()::information_schema.sql_identifier AS constraint_catalog, rs.nspname::information_schema.sql_identifier AS constraint_schema, con.conname::information_schema.sql_identifier AS constraint_name, CASE con.contype WHEN 'c'::"char" THEN "left"(SUBSTRING(pg_get_constraintdef(con.oid) FROM 8), '-1'::integer) WHEN 'n'::"char" THEN FORMAT('CHECK (%s IS NOT NULL)', (SELECT attname FROM pg_attribute WHERE attrelid = conrelid AND attnum = conkey[1])) ELSE NULL::text END::information_schema.character_data AS check_clause FROM pg_constraint con LEFT JOIN pg_namespace rs ON rs.oid = con.connamespace LEFT JOIN pg_class c ON c.oid = con.conrelid LEFT JOIN pg_type t ON t.oid = con.contypid WHERE pg_has_role(COALESCE(c.relowner, t.typowner), 'USAGE'::text) AND (con.contype = ANY (ARRAY['c'::"char", 'n'::"char"])); [q3] SELECT current_database()::information_schema.sql_identifier AS constraint_catalog, rs.nspname::information_schema.sql_identifier AS constraint_schema, con.conname::information_schema.sql_identifier AS constraint_name, CASE con.contype WHEN 'c'::"char" THEN "left"(SUBSTRING(pg_get_constraintdef(con.oid) FROM 8), '-1'::integer) WHEN 'n'::"char" THEN FORMAT('CHECK (%s IS NOT NULL)', at.attname) ELSE NULL::text END::information_schema.character_data AS check_clause FROM pg_constraint con LEFT JOIN pg_namespace rs ON rs.oid = con.connamespace LEFT JOIN pg_class c ON c.oid = con.conrelid
Re: cataloguing NOT NULL constraints
Hi Alvaro, 25.08.2023 14:38, Alvaro Herrera wrote: I have now pushed this again. Hopefully it'll stick this time. I've found that after that commit the following query: CREATE TABLE t(a int PRIMARY KEY) PARTITION BY RANGE (a); CREATE TABLE tp1(a int); ALTER TABLE t ATTACH PARTITION tp1 FOR VALUES FROM (0) to (1); triggers a server crash: Core was generated by `postgres: law regression [local] ALTER TABLE '. Program terminated with signal SIGSEGV, Segmentation fault. warning: Section `.reg-xstate/2194811' in core file too small. #0 0x556007711d77 in MergeAttributesIntoExisting (child_rel=0x7fc30ba309d8, parent_rel=0x7fc30ba33f18) at tablecmds.c:15771 15771 if (!((Form_pg_constraint) GETSTRUCT(contup))->connoinherit) (gdb) bt #0 0x556007711d77 in MergeAttributesIntoExisting (child_rel=0x7fc30ba309d8, parent_rel=0x7fc30ba33f18) at tablecmds.c:15771 #1 0x5560077118d4 in CreateInheritance (child_rel=0x7fc30ba309d8, parent_rel=0x7fc30ba33f18) at tablecmds.c:15631 ... (gdb) print contup $1 = (HeapTuple) 0x0 On b0e96f311~1 I get: ERROR: column "a" in child table must be marked NOT NULL Best regards, Alexander
Re: cataloguing NOT NULL constraints
On 2023-Aug-28, Peter Eisentraut wrote: > It looks like we forgot about domain constraints? For example, > > create domain testdomain as int not null; > > should create a row in pg_constraint? Well, at some point I purposefully left them out; they were sufficiently different from the ones in tables that doing both things at the same time was not saving any effort. I guess we could try to bake them in now. -- Álvaro HerreraBreisgau, Deutschland — https://www.EnterpriseDB.com/ "Doing what he did amounts to sticking his fingers under the hood of the implementation; if he gets his fingers burnt, it's his problem." (Tom Lane)
Re: cataloguing NOT NULL constraints
On 25.08.23 13:38, Alvaro Herrera wrote: I have now pushed this again. Hopefully it'll stick this time. We may want to make some further tweaks to the behavior in some cases -- for example, don't disallow ALTER TABLE DROP NOT NULL when the constraint is both inherited and has a local definition; the other option is to mark the constraint as no longer having a local definition. I left it the other way because that's what CHECK does; maybe we would like to change both at once. I ran it through CI, and the pg_upgrade test with a dump from 14's regression test database and everything worked well, but it's been a while since I tested the sepgsql part of it, so that might the first thing to explode. It looks like we forgot about domain constraints? For example, create domain testdomain as int not null; should create a row in pg_constraint?
Re: cataloguing NOT NULL constraints
On 2023-Aug-25, Alvaro Herrera wrote: > I have now pushed this again. Hopefully it'll stick this time. Hmm, failed under the Czech locale[1]; apparently "inh_grandchld" sorts earlier than "inh_child1" there. I think I'll rename inh_grandchld to inh_child3 or something like that. [1] https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=hippopotamus=2023-08-25%2011%3A33%3A07 -- Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/
Re: cataloguing NOT NULL constraints
I have now pushed this again. Hopefully it'll stick this time. We may want to make some further tweaks to the behavior in some cases -- for example, don't disallow ALTER TABLE DROP NOT NULL when the constraint is both inherited and has a local definition; the other option is to mark the constraint as no longer having a local definition. I left it the other way because that's what CHECK does; maybe we would like to change both at once. I ran it through CI, and the pg_upgrade test with a dump from 14's regression test database and everything worked well, but it's been a while since I tested the sepgsql part of it, so that might the first thing to explode. -- Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/
Re: cataloguing NOT NULL constraints
I have two small patches that you can integrate into your patch set: The first just changes the punctuation of "Not-null constraints" in the psql output to match what the documentation mostly uses. The second has some changes to ddl.sgml to reflect that not-null constraints are now named and can be operated on like other constraints. You might want to read that again to make sure it matches your latest intentions, but I think it catches all the places that are required to change.From 324f0050eee51c47e4c558867e6cc832652b39bb Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Wed, 16 Aug 2023 10:26:09 +0200 Subject: [PATCH 1/2] fixup! Have psql print the NOT NULL constraints on \d+ --- contrib/test_decoding/expected/ddl.out| 8 +- src/bin/psql/describe.c | 2 +- src/test/regress/expected/create_table.out| 6 +- .../regress/expected/create_table_like.out| 10 +-- src/test/regress/expected/foreign_data.out| 84 +-- src/test/regress/expected/generated.out | 2 +- src/test/regress/expected/identity.out| 2 +- src/test/regress/expected/publication.out | 6 +- .../regress/expected/replica_identity.out | 6 +- src/test/regress/expected/rowsecurity.out | 2 +- 10 files changed, 64 insertions(+), 64 deletions(-) diff --git a/contrib/test_decoding/expected/ddl.out b/contrib/test_decoding/expected/ddl.out index 95a0722c33..bcd1f74b2b 100644 --- a/contrib/test_decoding/expected/ddl.out +++ b/contrib/test_decoding/expected/ddl.out @@ -492,7 +492,7 @@ WITH (user_catalog_table = true) options | text[] | | | | extended | | Indexes: "replication_metadata_pkey" PRIMARY KEY, btree (id) -Not null constraints: +Not-null constraints: "replication_metadata_id_not_null" NOT NULL "id" "replication_metadata_relation_not_null" NOT NULL "relation" Options: user_catalog_table=true @@ -509,7 +509,7 @@ ALTER TABLE replication_metadata RESET (user_catalog_table); options | text[] | | | | extended | | Indexes: "replication_metadata_pkey" PRIMARY KEY, btree (id) -Not null constraints: +Not-null constraints: "replication_metadata_id_not_null" NOT NULL "id" "replication_metadata_relation_not_null" NOT NULL "relation" @@ -525,7 +525,7 @@ ALTER TABLE replication_metadata SET (user_catalog_table = true); options | text[] | | | | extended | | Indexes: "replication_metadata_pkey" PRIMARY KEY, btree (id) -Not null constraints: +Not-null constraints: "replication_metadata_id_not_null" NOT NULL "id" "replication_metadata_relation_not_null" NOT NULL "relation" Options: user_catalog_table=true @@ -547,7 +547,7 @@ ALTER TABLE replication_metadata SET (user_catalog_table = false); rewritemeornot | integer | | | | plain| | Indexes: "replication_metadata_pkey" PRIMARY KEY, btree (id) -Not null constraints: +Not-null constraints: "replication_metadata_id_not_null" NOT NULL "id" "replication_metadata_relation_not_null" NOT NULL "relation" Options: user_catalog_table=false diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index d1dc8fa066..4d36e0cfd8 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -3072,7 +3072,7 @@ describeOneTableDetails(const char *schemaname, tuples = PQntuples(result); if (tuples > 0) - printTableAddFooter(, _("Not null constraints:")); + printTableAddFooter(, _("Not-null constraints:")); /* Might be an empty set - that's ok */ for (i = 0; i < tuples; i++) diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out index 3f6516c3f8..477e8839e9 100644 --- a/src/test/regress/expected/create_table.out +++ b/src/test/regress/expected/create_table.out @@ -854,7 +854,7 @@ drop table test_part_coll_posix; b | integer | | not null | 1 | plain| | Partition of: parted FOR VALUES IN ('b') Partition constraint: ((a IS NOT NULL) AND (a = 'b'::text)) -Not null constraints: +Not-null constraints: "part_b_b_not_null" NOT NULL "b" -- Both partition bound and partition key in describe output @@ -867,7 +867,7 @@ Not null constraints: Partition of: parted FOR VALUES IN ('c') Partition constraint: ((a IS NOT NULL) AND (a = 'c'::text)) Partition key: RANGE (b) -Not null constraints: +Not-null constraints: "part_c_b_not_null" NOT NULL "b" Partitions: part_c_1_10 FOR VALUES FROM (1) TO (10) @@ -880,7 +880,7 @@ Partitions: part_c_1_10 FOR
Re: cataloguing NOT NULL constraints
On 15.08.23 11:57, Dean Rasheed wrote: Something else I noticed when reading the SQL standard is that a user-defined CHECK (col IS NOT NULL) constraint should be recognised by the system as also making the column not null (setting its "nullability characteristic" to "known not nullable"). I think that's more than just an artefact of how they say NOT NULL constraints should be implemented, because the effect of such a CHECK constraint should be exposed in the "columns" view of the information schema -- the value of "is_nullable" should be "NO" if the column is "known not nullable". Nullability determination is different from not-null constraints. The nullability characteristic of a column can be derived from multiple sources, including not-null constraints, check constraints, primary key constraints, domain constraints, as well as more complex rules in case of views, joins, etc. But this is all distinct and separate from the issue of not-null constraints that we are discussing here.
Re: cataloguing NOT NULL constraints
On 2023-Aug-15, Dean Rasheed wrote: > I think perhaps for ALTER TABLE INHERIT, it should check that the > child has a NOT NULL constraint, and error out if not. That's the > current behaviour, and also matches other constraints types (e.g., > CHECK constraints). Yeah, I reached the same conclusion yesterday while trying it out, so that's what I implemented. I'll post later today. > More generally though, I'm worried that this is starting to get very > complicated. I wonder if there might be a different, simpler approach. > One vague idea is to have a new attribute on the column that counts > the number of constraints (local and inherited PK and NOT NULL > constraints) that make the column not null. Hmm. I grant that this is different, but I don't see that it is simpler. > Something else I noticed when reading the SQL standard is that a > user-defined CHECK (col IS NOT NULL) constraint should be recognised > by the system as also making the column not null (setting its > "nullability characteristic" to "known not nullable"). I agree with this view actually, but I've refrained from implementing it(*) because our SQL-standards people have advised against it. Insider knowledge? I don't know. I think this is a comparatively smaller consideration though, and we can adjust for it afterwards. (*) Rather: at some point I removed the implementation of that from the patch. > I'm also wondering whether creating a pg_constraint entry for *every* > not-nullable column is actually going too far. If we were to > distinguish between "defined as NOT NULL" and being not null as a > result of one or more constraints, in the way that the standard seems > to suggest, perhaps the former (likely to be much more common) could > simply be a new attribute stored on the column. I think we actually > only need to create pg_constraint entries if a constraint name or any > additional constraint properties such as NOT VALID are specified. That > would lead to far fewer new constraints, less catalog bloat, and less > noise in the \d output. There is a problem if we do this, though, which is that we cannot use the constraints for the things that we want them for -- for example, remove_useless_groupby_columns() would like to use unique constraints, not just primary keys; but it depends on the NOT NULL rows being there for invalidation reasons (namely: if the NOT NULL constraint is dropped, we need to be able to replan. Without catalog rows, we don't have a mechanism to let that happen). If we don't add all those redundant catalog rows, then this is all for naught. -- Álvaro HerreraBreisgau, Deutschland — https://www.EnterpriseDB.com/ Bob [Floyd] used to say that he was planning to get a Ph.D. by the "green stamp method," namely by saving envelopes addressed to him as 'Dr. Floyd'. After collecting 500 such letters, he mused, a university somewhere in Arizona would probably grant him a degree. (Don Knuth)
Re: cataloguing NOT NULL constraints
On Fri, 11 Aug 2023 at 14:54, Alvaro Herrera wrote: > > Right, in the end I got around to that point of view. I abandoned the > idea of adding these dependency links, and I'm back at relying on the > coninhcount/conislocal markers. But there were a couple of bugs in the > accounting for that, so I've fixed some of those, but it's not yet > complete: > > - ALTER TABLE parent ADD PRIMARY KEY > needs to create NOT NULL constraints in children. I added this, but > I'm not yet sure it works correctly (for example, if a child already > has a NOT NULL constraint, we need to bump its inhcount, but we > don't.) > - ALTER TABLE parent ADD PRIMARY KEY USING index > Not sure if this is just as above or needs separate handling > - ALTER TABLE DROP PRIMARY KEY > needs to decrement inhcount or drop the constraint if there are no > other sources for that constraint to exist. I've adjusted the drop > constraint code to do this. > - ALTER TABLE INHERIT > needs to create a constraint on the new child, if parent has PK. Not > implemented > - ALTER TABLE NO INHERIT > needs to delink any constraints (decrement inhcount, possibly drop > the constraint). > I think perhaps for ALTER TABLE INHERIT, it should check that the child has a NOT NULL constraint, and error out if not. That's the current behaviour, and also matches other constraints types (e.g., CHECK constraints). More generally though, I'm worried that this is starting to get very complicated. I wonder if there might be a different, simpler approach. One vague idea is to have a new attribute on the column that counts the number of constraints (local and inherited PK and NOT NULL constraints) that make the column not null. Something else I noticed when reading the SQL standard is that a user-defined CHECK (col IS NOT NULL) constraint should be recognised by the system as also making the column not null (setting its "nullability characteristic" to "known not nullable"). I think that's more than just an artefact of how they say NOT NULL constraints should be implemented, because the effect of such a CHECK constraint should be exposed in the "columns" view of the information schema -- the value of "is_nullable" should be "NO" if the column is "known not nullable". In this sense, the standard does allow multiple not null constraints on a column, independently of whether the column is "defined as NOT NULL". My understanding of the standard is that ALTER COLUMN ... SET/DROP NOT NULL change whether or not the column is "defined as NOT NULL", and manage a single system-generated constraint, but there may be any number of other user-defined constraints that also make the column "known not nullable", and they need to be tracked in some way. I'm also wondering whether creating a pg_constraint entry for *every* not-nullable column is actually going too far. If we were to distinguish between "defined as NOT NULL" and being not null as a result of one or more constraints, in the way that the standard seems to suggest, perhaps the former (likely to be much more common) could simply be a new attribute stored on the column. I think we actually only need to create pg_constraint entries if a constraint name or any additional constraint properties such as NOT VALID are specified. That would lead to far fewer new constraints, less catalog bloat, and less noise in the \d output. Regards, Dean
Re: cataloguing NOT NULL constraints
On 2023-Aug-09, Peter Eisentraut wrote: > I wonder whether the root of these problems is that we mix together primary > key constraints and not-null constraints. I understand that right now, with > the proposed patch, when a table inherits from a parent table with a primary > key constraint, we generate not-null constraints on the child, in order to > enforce the not-nullness. What if we did something like this instead: In > the child table, we don't generate a not-null constraint, but instead a > primary key constraint entry. But we mark the primary key constraint > somehow to say, this is just for the purpose of inheritance, don't enforce > uniqueness, but enforce not-nullness. Would that work? Hmm. One table can have many parents, and many of them can have primary keys. If we tried to model it the way you suggest, the child table would need to have several primary keys. I don't think this would work. But I think I just need to stare at the dependency graph a little while longer. Maybe I just need to add some extra edges to make it work correctly. -- Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/
Re: cataloguing NOT NULL constraints
On 05.08.23 21:50, Dean Rasheed wrote: Anyway, I was at the same time fixing the other problem you reported with inheritance (namely, adding a PK ends up with the child column being marked NOT NULL but no corresponding constraint). At some point I wondered if the easy way out wouldn't be to give up on the idea that creating a PK causes the child columns to be marked not-nullable. However, IIRC I decided against that because it breaks restoring of old dumps, so it wouldn't be acceptable. To make matters worse: pg_dump creates the PK as ALTER TABLE ONLY parent ADD PRIMARY KEY ( ... ) note the ONLY there. It seems I'm forced to cause the PK to affect children even though ONLY is given. This is undesirable but I don't see a way out of that. It is all a bit of a rat's nest. I wonder if that could be made to work in the same way as inherited CHECK constraints -- dump the child's inherited NOT NULL constraints, and then manually update conislocal in pg_constraint. I wonder whether the root of these problems is that we mix together primary key constraints and not-null constraints. I understand that right now, with the proposed patch, when a table inherits from a parent table with a primary key constraint, we generate not-null constraints on the child, in order to enforce the not-nullness. What if we did something like this instead: In the child table, we don't generate a not-null constraint, but instead a primary key constraint entry. But we mark the primary key constraint somehow to say, this is just for the purpose of inheritance, don't enforce uniqueness, but enforce not-nullness. Would that work?
Re: cataloguing NOT NULL constraints
On Sat, 5 Aug 2023 at 18:37, Alvaro Herrera wrote: > > Yeah, something like that. However, if the child had a NOT NULL > constraint of its own, then it should not be deleted when the > PK-on-parent is, but merely marked as no longer inherited. (This is > also what happens with a straight NOT NULL constraint.) I think what > this means is that at some point during the deletion of the PK we must > remove the dependency link rather than letting it be followed. I'm not > yet sure how to do this. > I'm not sure that adding that new dependency was the right thing to do. I think perhaps this could just be made to work using conislocal and coninhcount to track whether the child constraint needs to be deleted, or just updated. > Anyway, I was at the same time fixing the other problem you reported > with inheritance (namely, adding a PK ends up with the child column > being marked NOT NULL but no corresponding constraint). > > At some point I wondered if the easy way out wouldn't be to give up on > the idea that creating a PK causes the child columns to be marked > not-nullable. However, IIRC I decided against that because it breaks > restoring of old dumps, so it wouldn't be acceptable. > > To make matters worse: pg_dump creates the PK as > > ALTER TABLE ONLY parent ADD PRIMARY KEY ( ... ) > > note the ONLY there. It seems I'm forced to cause the PK to affect > children even though ONLY is given. This is undesirable but I don't see > a way out of that. > > It is all a bit of a rat's nest. > I wonder if that could be made to work in the same way as inherited CHECK constraints -- dump the child's inherited NOT NULL constraints, and then manually update conislocal in pg_constraint. Regards, Dean
Re: cataloguing NOT NULL constraints
On 2023-Aug-05, Dean Rasheed wrote: > Hmm, thinking about this some more, I think this might be the wrong > approach to fixing the original problem. I think it was probably OK > that the NOT NULL constraint on the child was marked as inherited, but > I think what should have happened is that dropping the PRIMARY KEY > constraint on the parent should have caused the NOT NULL constraint on > the child to have been deleted (in the same way as it would have been, > if it had been a NOT NULL constraint on the parent). Yeah, something like that. However, if the child had a NOT NULL constraint of its own, then it should not be deleted when the PK-on-parent is, but merely marked as no longer inherited. (This is also what happens with a straight NOT NULL constraint.) I think what this means is that at some point during the deletion of the PK we must remove the dependency link rather than letting it be followed. I'm not yet sure how to do this. Anyway, I was at the same time fixing the other problem you reported with inheritance (namely, adding a PK ends up with the child column being marked NOT NULL but no corresponding constraint). At some point I wondered if the easy way out wouldn't be to give up on the idea that creating a PK causes the child columns to be marked not-nullable. However, IIRC I decided against that because it breaks restoring of old dumps, so it wouldn't be acceptable. To make matters worse: pg_dump creates the PK as ALTER TABLE ONLY parent ADD PRIMARY KEY ( ... ) note the ONLY there. It seems I'm forced to cause the PK to affect children even though ONLY is given. This is undesirable but I don't see a way out of that. It is all a bit of a rat's nest. -- Álvaro HerreraBreisgau, Deutschland — https://www.EnterpriseDB.com/ "Nunca se desea ardientemente lo que solo se desea por razón" (F. Alexandre)
Re: cataloguing NOT NULL constraints
On Fri, 4 Aug 2023 at 19:10, Alvaro Herrera wrote: > > On 2023-Jul-28, Alvaro Herrera wrote: > > > To avoid that, one option would be to make this NN constraint > > undroppable ... but I don't see how. One option might be to add a > > pg_depend row that links the NOT NULL constraint to its PK constraint. > > But this will be a strange case that occurs nowhere else, since other > > NOT NULL constraint don't have such pg_depend rows. Also, I won't know > > how pg_dump likes this until I implement it. > > I've been completing the implementation for this. It seems to work > reasonably okay; pg_dump requires somewhat strange contortions, but they > are similar to what we do in flagInhTables already, so I don't feel too > bad about that. > > What *is* odd and bothersome is that it also causes a problem dropping > the child table. > Hmm, thinking about this some more, I think this might be the wrong approach to fixing the original problem. I think it was probably OK that the NOT NULL constraint on the child was marked as inherited, but I think what should have happened is that dropping the PRIMARY KEY constraint on the parent should have caused the NOT NULL constraint on the child to have been deleted (in the same way as it would have been, if it had been a NOT NULL constraint on the parent). Regards, Dean
Re: cataloguing NOT NULL constraints
On 2023-Jul-28, Alvaro Herrera wrote: > To avoid that, one option would be to make this NN constraint > undroppable ... but I don't see how. One option might be to add a > pg_depend row that links the NOT NULL constraint to its PK constraint. > But this will be a strange case that occurs nowhere else, since other > NOT NULL constraint don't have such pg_depend rows. Also, I won't know > how pg_dump likes this until I implement it. I've been completing the implementation for this. It seems to work reasonably okay; pg_dump requires somewhat strange contortions, but they are similar to what we do in flagInhTables already, so I don't feel too bad about that. What *is* odd and bothersome is that it also causes a problem dropping the child table. For example, CREATE TABLE parent (a int primary key); CREATE TABLE child () INHERITS (parent); \d+ child Tabla «public.child» Columna │ Tipo │ Ordenamiento │ Nulable │ Por omisión │ Almacenamiento │ Compresión │ Estadísticas │ Descripción ─┼─┼──┼──┼─┼┼┼──┼─ a │ integer │ │ not null │ │ plain │ │ │ Not null constraints: "child_a_not_null" NOT NULL "a" Hereda: parent Método de acceso: heap This is the behavior that I think we wanted to prevent drop of the child constraint, and it seems okay to me: =# alter table child drop constraint child_a_not_null; ERROR: cannot drop constraint child_a_not_null on table child because constraint parent_pkey on table parent requires it SUGERENCIA: You can drop constraint parent_pkey on table parent instead. But the problem is this: =# drop table child; ERROR: cannot drop table child because other objects depend on it DETALLE: constraint parent_pkey on table parent depends on table child SUGERENCIA: Use DROP ... CASCADE to drop the dependent objects too. To be clear, what my patch is doing is add one new dependency: dep │ ref │ deptype ┼┼─ type foo │ table foo │ i table foo │ schema public │ n constraint foo_pkey on table foo │ column a of table foo │ a type bar │ table bar │ i table bar │ schema public │ n table bar │ table foo │ n constraint bar_a_not_null on table bar │ column a of table bar │ a constraint child_a_not_null on table child │ column a of table child │ a constraint child_a_not_null on table child │ constraint parent_pkey on table parent │ i the last row here is what is new. I'm not sure what's the right fix. Maybe I need to invert the direction of that dependency. Even with that fixed, I'd still need to write more code so that ALTER TABLE INHERIT adds the link (I already patched the DROP INHERIT part). Not sure what else might I be missing. Separately, I also noticed that some code that's currently dropconstraint_internal needs to be moved to DropConstraintById, because if the PK is dropped for some other reason than ALTER TABLE DROP CONSTRAINT, some ancillary actions are not taken. Sigh. -- Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/ Are you not unsure you want to delete Firefox? [Not unsure] [Not not unsure][Cancel] http://smylers.hates-software.com/2008/01/03/566e45b2.html
Re: cataloguing NOT NULL constraints
On 24.07.23 12:32, Alvaro Herrera wrote: However, 11.16 ( as part of 11.12 ), says that DROP NOT NULL causes the indication of the column as NOT NULL to be removed. This, to me, says that if you do have multiple such constraints, you'd better remove them all with that command. All in all, I lean towards allowing just one as best as we can. Another clue is in 11.15 , which says 1) Let C be the column identified by the CN in the containing . If the column descriptor of C does not contain an indication that C is defined as NOT NULL, then: [do things] Otherwise it does nothing. So there can only be one such constraint per table.
Re: cataloguing NOT NULL constraints
> > Given the following sequence: > > > > drop table if exists p,c; > > create table p(a int primary key); > > create table c() inherits (p); > > alter table p drop constraint p_pkey; > > However, c.a remains non-nullable, with a NOT NULL constraint that > > claims to be inherited: > > > > \d+ c > > Table "public.c" > > Column | Type | Collation | Nullable | Default | Storage | > > Compression | Stats target | Description > > +-+---+--+-+-+-+--+- > > a | integer | | not null | | plain | > > | | > > Not null constraints: > > "c_a_not_null" NOT NULL "a" (inherited) > > Inherits: p > > Access method: heap > > > > That's a problem, because now the NOT NULL constraint on c cannot be > > dropped (attempting to drop it on c errors out because it thinks it's > > inherited, but it can't be dropped via p, because p.a is already > > nullable). So I implemented a fix for this (namely: fix the inhcount to be 0 initially), and it works well, but it does cause a definitional problem: any time we create a child table that inherits from another table that has a primary key, all the columns in the child table will get normal, visible, droppable NOT NULL constraints. Thus, pg_dump for example will output that constraint exactly as if the user had specified it in the child's CREATE TABLE command. By itself this doesn't bother me, though I admit it seems a little odd. When you restore such a setup from pg_dump, things work perfectly -- I mean, you don't get a second constraint. But if you do drop the constraint, then it will be reinstated by the next pg_dump as if you hadn't dropped it, by way of it springing to life from the PK. To avoid that, one option would be to make this NN constraint undroppable ... but I don't see how. One option might be to add a pg_depend row that links the NOT NULL constraint to its PK constraint. But this will be a strange case that occurs nowhere else, since other NOT NULL constraint don't have such pg_depend rows. Also, I won't know how pg_dump likes this until I implement it. -- Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/
Re: cataloguing NOT NULL constraints
On 2023-Jul-26, Alvaro Herrera wrote: > On 2023-Jul-26, Dean Rasheed wrote: > > > The new \d+ output certainly makes testing and reviewing easier, > > though I do understand people's concerns that this may make the output > > significantly longer in many real-world cases. > > Yeah, at this point I'm inclined to get the \d+ version committed > immediately after the main patch, and we can tweak the psql UI after the > fact -- for instance so that they are only shown in \d++, or some other > idea we may come across. (For example, maybe we could add \dtc [PATTERN] or some such, that lists all the constraints of all kinds in tables matching PATTERN.) -- Álvaro HerreraBreisgau, Deutschland — https://www.EnterpriseDB.com/ "If you want to have good ideas, you must have many ideas. Most of them will be wrong, and what you have to learn is which ones to throw away." (Linus Pauling)
Re: cataloguing NOT NULL constraints
Thanks for spending so much time with this patch -- really appreciated. On 2023-Jul-26, Dean Rasheed wrote: > On Tue, 25 Jul 2023 at 13:36, Alvaro Herrera wrote: > > > > Okay then, I've made these show up in the footer of \d+. This is in > > patch 0003 here. Please let me know what do you think of the regression > > changes. > > The new \d+ output certainly makes testing and reviewing easier, > though I do understand people's concerns that this may make the output > significantly longer in many real-world cases. I don't think it would > be a good idea to filter the list in any way though, because I think > that will only lead to confusion. I think it should be all-or-nothing, > though I'm not necessarily opposed to using something like \d++ to > enable it, if that turns out to be the least-bad option. Yeah, at this point I'm inclined to get the \d+ version committed immediately after the main patch, and we can tweak the psql UI after the fact -- for instance so that they are only shown in \d++, or some other idea we may come across. > Going back to this example: > > drop table if exists p1, p2, foo; > create table p1(a int not null check (a > 0)); > create table p2(a int not null check (a > 0)); > create table foo () inherits (p1,p2); > I remain of the opinion that that should create 2 NOT NULL constraints > on foo, for consistency with CHECK constraints, and the misleading > name that results if p1_a_not_null is dropped from p1. That way, the > names of inherited NOT NULL constraints could be kept in sync, as they > are for other constraint types, making it easier to keep track of > where they come from, and it wouldn't be necessary to treat them > differently (e.g., matching by column number, when dropping NOT NULL > constraints). I think having two constraints is more problematic, UI-wise. Previous versions of this patchset did it that way, and it's not great: for example ALTER TABLE ALTER COLUMN DROP NOT NULL fails and tells you to choose which exact constraint you want to drop and use DROP CONSTRAINT instead. And when searching for the not-null constraints for a column, the code had to consider the case of there being multiple ones, which led to strange contortions. Allowing a single one is simpler and covers all important cases well. Anyway, you still can't drop the doubly-inherited constraint directly, because it'll complain that it is an inherited constraint. So you have to deinherit first and only then can you drop the constraint. Now, one possible improvement here would be to ignore the parent constraint's name, and have 'foo' recompute its own constraint name from scratch, inheriting the name only if one of the parents had a manually-specified constraint name (and we would choose the first one, if there's more than one). I think complicating things more than that is unnecessary -- particularly considering that legacy inheritance is, well, legacy, and I doubt people are relying too much on it. > Given the following sequence: > > drop table if exists p,c; > create table p(a int primary key); > create table c() inherits (p); > alter table p drop constraint p_pkey; > > p.a ends up being nullable, where previously it would have been left > non-nullable. That change makes sense, and is presumably one of the > benefits of tying the nullability of columns to pg_constraint entries. Right. > However, c.a remains non-nullable, with a NOT NULL constraint that > claims to be inherited: > > \d+ c > Table "public.c" > Column | Type | Collation | Nullable | Default | Storage | > Compression | Stats target | Description > +-+---+--+-+-+-+--+- > a | integer | | not null | | plain | > | | > Not null constraints: > "c_a_not_null" NOT NULL "a" (inherited) > Inherits: p > Access method: heap > > That's a problem, because now the NOT NULL constraint on c cannot be > dropped (attempting to drop it on c errors out because it thinks it's > inherited, but it can't be dropped via p, because p.a is already > nullable). Oh, I think the bug here is just that this constraint should not claim to be inherited, but standalone. So you can drop it afterwards; but if you drop it and end up with NULL values in your PK-labelled column in the parent table, that's on you. > I wonder if NOT NULL constraints created as a result of inherited PKs > should have names based on the PK name (e.g., > __not_null), to make it more obvious where they > came from. That would be more consistent with the way NOT NULL > constraint names are inherited. Hmm, interesting idea. I'll play with it. (It may quickly lead to constraint names that are too long, though.) > Given the following sequence: > > drop table if exists p,c; > create table p(a int); > create table c() inherits (p); > alter table p add primary key (a); > > c.a ends up
Re: cataloguing NOT NULL constraints
On Tue, 25 Jul 2023 at 13:36, Alvaro Herrera wrote: > > Okay then, I've made these show up in the footer of \d+. This is in > patch 0003 here. Please let me know what do you think of the regression > changes. > The new \d+ output certainly makes testing and reviewing easier, though I do understand people's concerns that this may make the output significantly longer in many real-world cases. I don't think it would be a good idea to filter the list in any way though, because I think that will only lead to confusion. I think it should be all-or-nothing, though I'm not necessarily opposed to using something like \d++ to enable it, if that turns out to be the least-bad option. Going back to this example: drop table if exists p1, p2, foo; create table p1(a int not null check (a > 0)); create table p2(a int not null check (a > 0)); create table foo () inherits (p1,p2); \d+ foo Table "public.foo" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description +-+---+--+-+-+-+--+- a | integer | | not null | | plain | | | Check constraints: "p1_a_check" CHECK (a > 0) "p2_a_check" CHECK (a > 0) Not null constraints: "p1_a_not_null" NOT NULL "a" (inherited) Inherits: p1, p2 Access method: heap I remain of the opinion that that should create 2 NOT NULL constraints on foo, for consistency with CHECK constraints, and the misleading name that results if p1_a_not_null is dropped from p1. That way, the names of inherited NOT NULL constraints could be kept in sync, as they are for other constraint types, making it easier to keep track of where they come from, and it wouldn't be necessary to treat them differently (e.g., matching by column number, when dropping NOT NULL constraints). Doing a little more testing, I found some other issues. Given the following sequence: drop table if exists p,c; create table p(a int primary key); create table c() inherits (p); alter table p drop constraint p_pkey; p.a ends up being nullable, where previously it would have been left non-nullable. That change makes sense, and is presumably one of the benefits of tying the nullability of columns to pg_constraint entries. However, c.a remains non-nullable, with a NOT NULL constraint that claims to be inherited: \d+ c Table "public.c" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description +-+---+--+-+-+-+--+- a | integer | | not null | | plain | | | Not null constraints: "c_a_not_null" NOT NULL "a" (inherited) Inherits: p Access method: heap That's a problem, because now the NOT NULL constraint on c cannot be dropped (attempting to drop it on c errors out because it thinks it's inherited, but it can't be dropped via p, because p.a is already nullable). I wonder if NOT NULL constraints created as a result of inherited PKs should have names based on the PK name (e.g., __not_null), to make it more obvious where they came from. That would be more consistent with the way NOT NULL constraint names are inherited. Given the following sequence: drop table if exists p,c; create table p(a int); create table c() inherits (p); alter table p add primary key (a); c.a ends up non-nullable, but there is no pg_constraint entry enforcing the constraint: \d+ c Table "public.c" Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description +-+---+--+-+-+-+--+- a | integer | | not null | | plain | | | Inherits: p Access method: heap Given a database containing these 2 tables: create table p(a int primary key); create table c() inherits (p); doing a pg_dump and restore fails to restore the NOT NULL constraint on c, because all constraints created by the dump are local to p. That's it for now. I'll try to do more testing later. Regards, Dean
Re: cataloguing NOT NULL constraints
On Tue, Jul 25, 2023 at 3:07 PM Isaac Morland wrote: > OK, I suppose ALTER CONSTRAINT to change the deferrable status and validity > (that is why we're doing this, right?) needs the constraint name. But the > constraint name is formulaic by default, and my proposal is to suppress it > only when it matches the formula, so you could just construct the constraint > name using the documented formula if it's not explicitly listed. > > I really don’t see it as a good use of space to add n lines to the \d+ > display just to confirm that the "not null" designations in the "Nullable" > column are implemented by named constraints with the expected names. Yeah, I mean, I get that. That was my initial concern, too. But I also think if there's some complicated rule that determines what gets displayed and what doesn't, nobody's going to remember it, and then when you don't see something, you're never going to be sure exactly what's going on. Displaying everything is going to be clunky especially if, like me, you tend to be careful to mark columns NOT NULL when they are, but when something goes wrong, the last thing you want to do is run a \d command and have it show you incomplete information. I can't count the number of times that somebody's shown me the output of a query against pg_locks or pg_stat_activity that had been filtered to remove irrelevant information and it turned out that the hidden information was not so irrelevant as the person who wrote the query thought. It happens all the time. I don't want to create the same kind of situation here. -- Robert Haas EDB: http://www.enterprisedb.com
Re: cataloguing NOT NULL constraints
On Tue, 25 Jul 2023 at 14:59, Robert Haas wrote: > On Tue, Jul 25, 2023 at 1:33 PM Isaac Morland > wrote: > > My suggestion is for \d+ to show NOT NULL constraints only if there is > something weird going on (wrong name, duplicate constraints, …). If there > is nothing weird about the constraint then explicitly listing it provides > absolutely no information that is not given by "not null" in the "Nullable" > column. Easier said than done I suppose. I'm just worried about my \d+ > displays becoming less useful. > > I mean, the problem is that if you want to ALTER TABLE .. DROP > CONSTRAINT, you need to know what the valid arguments to that command > are, and the names of these constraints will be just as valid as the > names of any other constraints. > Can't I just ALTER TABLE … DROP NOT NULL still? OK, I suppose ALTER CONSTRAINT to change the deferrable status and validity (that is why we're doing this, right?) needs the constraint name. But the constraint name is formulaic by default, and my proposal is to suppress it only when it matches the formula, so you could just construct the constraint name using the documented formula if it's not explicitly listed. I really don’t see it as a good use of space to add n lines to the \d+ display just to confirm that the "not null" designations in the "Nullable" column are implemented by named constraints with the expected names.
Re: cataloguing NOT NULL constraints
On Tue, Jul 25, 2023 at 1:33 PM Isaac Morland wrote: > My suggestion is for \d+ to show NOT NULL constraints only if there is > something weird going on (wrong name, duplicate constraints, …). If there is > nothing weird about the constraint then explicitly listing it provides > absolutely no information that is not given by "not null" in the "Nullable" > column. Easier said than done I suppose. I'm just worried about my \d+ > displays becoming less useful. I mean, the problem is that if you want to ALTER TABLE .. DROP CONSTRAINT, you need to know what the valid arguments to that command are, and the names of these constraints will be just as valid as the names of any other constraints. -- Robert Haas EDB: http://www.enterprisedb.com
Re: cataloguing NOT NULL constraints
On Tue, 25 Jul 2023 at 12:24, Alvaro Herrera wrote: > On 2023-Jul-25, Isaac Morland wrote: > > > I agree. I definitely do *not* want a bunch of NOT NULL constraint names > > cluttering up displays. Can we legislate that all NOT NULL implementing > > constraints are named by mashing together the table name, column name, > and > > something to identify it as a NOT NULL constraint? > > All constraints are named like that already, and NOT NULL constraints > just inherited the same idea. The names are __not_null > for NOT NULL constraints. pg_dump goes great lengths to avoid printing > constraint names when they have this pattern. > OK, this is helpful. Can \d do the same thing? I use a lot of NOT NULL constraints and I very seriously do not want \d (including \d+) to have an extra line for almost every column. It's just noise, and while my screen is large, it's still not infinite. I do not want these constraint names cluttering the output either. > That's why I propose moving them to a new \d++ command, where they will > only bother you if you absolutely need them. But so far I have only one > vote supporting that idea. My suggestion is for \d+ to show NOT NULL constraints only if there is something weird going on (wrong name, duplicate constraints, …). If there is nothing weird about the constraint then explicitly listing it provides absolutely no information that is not given by "not null" in the "Nullable" column. Easier said than done I suppose. I'm just worried about my \d+ displays becoming less useful.
Re: cataloguing NOT NULL constraints
On 2023-Jul-25, Isaac Morland wrote: > I agree. I definitely do *not* want a bunch of NOT NULL constraint names > cluttering up displays. Can we legislate that all NOT NULL implementing > constraints are named by mashing together the table name, column name, and > something to identify it as a NOT NULL constraint? All constraints are named like that already, and NOT NULL constraints just inherited the same idea. The names are __not_null for NOT NULL constraints. pg_dump goes great lengths to avoid printing constraint names when they have this pattern. I do not want these constraint names cluttering the output either. That's why I propose moving them to a new \d++ command, where they will only bother you if you absolutely need them. But so far I have only one vote supporting that idea. -- Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/
Re: cataloguing NOT NULL constraints
On Tue, 25 Jul 2023 at 11:39, Robert Haas wrote: > > I'm not really thrilled with the idea of every not-null constraint > having a name, to be honest. Of all the kinds of constraints that we > have in the system, NOT NULL constraints are probably the ones where > naming them is least likely to be interesting, because they don't > really have any interesting properties. A CHECK constraint has an > expression; a foreign key constraint has columns that it applies to on > each side plus the identity of the table and opclass information, but > a NOT NULL constraint seems like it can never have any property other > than which column. So it sort of seems like a waste to name it. But if > we want it catalogued then we don't really have an option, so I > suppose we just have to accept a bit of clutter as the price of doing > business. > I agree. I definitely do *not* want a bunch of NOT NULL constraint names cluttering up displays. Can we legislate that all NOT NULL implementing constraints are named by mashing together the table name, column name, and something to identify it as a NOT NULL constraint? Maybe even something like pg_not_null_[relname]_[attname] (with some escaping), using the pg_ prefix to make the name reserved similar to schemas and tables? And then don't show such constraints in \d, not even \d+ - just indicate it in the Nullable column of the column listing as done now. Show a NOT NULL constraint if there is something odd about it - for example, if it gets renamed, or not renamed when the table is renamed. Sorry for the noise if this has already been decided otherwise.
Re: cataloguing NOT NULL constraints
On Tue, Jul 25, 2023 at 8:36 AM Alvaro Herrera wrote: > Okay then, I've made these show up in the footer of \d+. This is in > patch 0003 here. Please let me know what do you think of the regression > changes. Seems OK. I'm not really thrilled with the idea of every not-null constraint having a name, to be honest. Of all the kinds of constraints that we have in the system, NOT NULL constraints are probably the ones where naming them is least likely to be interesting, because they don't really have any interesting properties. A CHECK constraint has an expression; a foreign key constraint has columns that it applies to on each side plus the identity of the table and opclass information, but a NOT NULL constraint seems like it can never have any property other than which column. So it sort of seems like a waste to name it. But if we want it catalogued then we don't really have an option, so I suppose we just have to accept a bit of clutter as the price of doing business. -- Robert Haas EDB: http://www.enterprisedb.com
Re: cataloguing NOT NULL constraints
On Mon, Jul 24, 2023 at 6:33 AM Alvaro Herrera wrote: > That's the first thing I proposed actually. I got one vote down from > Robert Haas[1], but while the idea seems to have had support from Justin > Pryzby (in \dt++) [2] and definitely did from Peter Eisentraut [3], I do > not like it too much myself, mainly because the partition list has a > very similar treatment and I find that one an annoyance. I think I might want to retract my earlier -1 vote. I mean, I agree with former me that having the \d+ output get a whole lot longer is not super-appealing. But I also agree with Dean that having this information available somewhere is probably important, and I also agree with your point that inventing \d++ for this isn't necessarily a good idea. I fear that will just result in having to type an extra plus sign any time you want to see all of the table details, to make sure that psql knows that you really mean it. So, maybe showing it in the \d+ output as Dean proposes is the least of evils. -- Robert Haas EDB: http://www.enterprisedb.com
Re: cataloguing NOT NULL constraints
On Mon, 24 Jul 2023 at 17:42, Alvaro Herrera wrote: > > On 2023-Jul-24, Dean Rasheed wrote: > > > Something else I noticed: the error message from ALTER TABLE ... ADD > > CONSTRAINT in the case of a duplicate constraint name is not very > > friendly: > > > > ERROR: duplicate key value violates unique constraint > > "pg_constraint_conrelid_contypid_conname_index" > > DETAIL: Key (conrelid, contypid, conname)=(16540, 0, nn) already exists. > > To reproduce this error, try to create 2 constraints with the same name on different columns: create table foo(a int, b int); alter table foo add constraint nn not null a; alter table foo add constraint nn not null b; I found another, separate issue: create table p1(a int not null); create table p2(a int); create table foo () inherits (p1,p2); alter table p2 add not null a; ERROR: column "a" of table "foo" is already NOT NULL whereas doing "alter table p2 alter column a set not null" works OK, merging the constraints as expected. Regards, Dean
Re: cataloguing NOT NULL constraints
On 7/24/23 18:42, Alvaro Herrera wrote: 55490 17devel 3166154=# create table foo (a int constraint nn not null); CREATE TABLE 55490 17devel 3166154=# alter table foo add constraint nn not null a; ERROR: column "a" of table "foo" is already NOT NULL Surely this should be a WARNING or INFO? I see no reason to ERROR here. -- Vik Fearing
Re: cataloguing NOT NULL constraints
Hello, While discussing the matter of multiple constraints with Vik Fearing, I noticed that we were throwing an unnecessary error if you used CREATE TABLE foo (a int NOT NULL NOT NULL); That would die with "redundant NOT NULL declarations", but current master doesn't do that; and we don't do it for UNIQUE UNIQUE either. So I modified the patch to make it ignore the dupe and create a single constraint. This (and rebasing to current master) are the only changes in v15. I have not changed the psql presentation, but I'll do as soon as we have rough consensus on what to do. To reiterate, the options are: 1. Don't show the constraint names. This is what the current patch does 2. Show the constraint name in \d+ in the "nullable" column. I did this early on, to much booing. 3. Show the constraint name in \d++ (a new command) tabular output 4. Show the constraint name in the footer of \d+ I also did this at some point; there are some +1s and some -1s. 5. Show the constraint name in the footer of \d++ Many thanks, Dean, for the discussion so far. -- Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/ Bob [Floyd] used to say that he was planning to get a Ph.D. by the "green stamp method," namely by saving envelopes addressed to him as 'Dr. Floyd'. After collecting 500 such letters, he mused, a university somewhere in Arizona would probably grant him a degree. (Don Knuth)
Re: cataloguing NOT NULL constraints
On 2023-Jul-24, Dean Rasheed wrote: > Something else I noticed: the error message from ALTER TABLE ... ADD > CONSTRAINT in the case of a duplicate constraint name is not very > friendly: > > ERROR: duplicate key value violates unique constraint > "pg_constraint_conrelid_contypid_conname_index" > DETAIL: Key (conrelid, contypid, conname)=(16540, 0, nn) already exists. > > To match the error message for other constraint types, this should be: > > ERROR: constraint "nn" for relation "foo" already exists Hmm, how did you get this one? I can't reproduce it: 55490 17devel 3166154=# create table foo (a int constraint nn not null); CREATE TABLE 55490 17devel 3166154=# alter table foo add constraint nn not null a; ERROR: column "a" of table "foo" is already NOT NULL 55490 17devel 3166154=# drop table foo; DROP TABLE 55490 17devel 3166154=# create table foo (a int); CREATE TABLE Duración: 1,472 ms 55490 17devel 3166154=# alter table foo add constraint nn not null a, add constraint nn not null a; ERROR: column "a" of table "foo" is already NOT NULL -- Álvaro HerreraBreisgau, Deutschland — https://www.EnterpriseDB.com/ "El número de instalaciones de UNIX se ha elevado a 10, y se espera que este número aumente" (UPM, 1972)
Re: cataloguing NOT NULL constraints
On 2023-Jul-24, Dean Rasheed wrote: > Hmm, I'm not so sure. I think perhaps multiple NOT NULL constraints on > the same column should just be allowed, otherwise things might get > confusing. For example: > create table p1 (a int not null check (a > 0)); create table p2 (a int not null check (a > 0)); create table foo () inherits (p1, p2); Have a look at the conislocal / coninhcount values. These should reflect the fact that the constraint has multiple sources; and the constraint does disappear if you drop it from both sources. > If I then drop the p1 constraints: > > alter table p1 drop constraint p1_a_check; > alter table p1 drop constraint p1_a_not_null; > > I end up with column "a" still being not null, and the "p1_a_not_null" > constraint still being there on foo, which seems even more > counter-intuitive, because I just dropped that constraint, and it > really should now be the "p2_a_not_null" constraint that makes "a" not > null: I can see that it might make sense to not inherit the constraint name in some cases. Perhaps: 1. never inherit a name. Each table has its own constraint name always 2. only inherit if there's a single parent 3. always inherit the name from the first parent (current implementation) > So I'd say that ALTER TABLE ... ADD NOT NULL should always add a > constraint, even if there already is one. For example ALTER TABLE ... > ADD UNIQUE does nothing to prevent multiple unique constraints on the > same column(s). It seems pretty dumb, but maybe there is a reason to > allow it, and it doesn't feel like we should be second-guessing what > the user wants. That was my initial implementation but I changed it to allowing a single constraint because of the way the standard describes SET NOT NULL; specifically, 11.15 says that "If the column descriptor of C does not contain an indication that C is defined as NOT NULL, then:" a constraint is added; otherwise (i.e., such an indication does exist), nothing happens. -- Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/ "La virtud es el justo medio entre dos defectos" (Aristóteles)
Re: cataloguing NOT NULL constraints
On 2023-Jul-24, Dean Rasheed wrote: > Hmm, I don't particularly like that approach, because I think it will > be difficult to cram any additional details into the table, and also I > don't know whether having multiple not null constraints for a > particular column can be entirely ruled out. > > I may well be in the minority here, but I think the best way is to > list them in a separate footer section, in the same way as CHECK > constraints, allowing other constraint properties to be included. So > it might look something like: That's the first thing I proposed actually. I got one vote down from Robert Haas[1], but while the idea seems to have had support from Justin Pryzby (in \dt++) [2] and definitely did from Peter Eisentraut [3], I do not like it too much myself, mainly because the partition list has a very similar treatment and I find that one an annoyance. > and also I don't know whether having multiple not null constraints for > a particular column can be entirely ruled out. I had another look at the standard. In 11.26 () it says that "If [the constraint being removed] causes some column COL to be known not nullable and no other constraint causes COL to be known not nullable, then the nullability characteristic of the column descriptor of COL is changed to possibly nullable". Which supports the idea that there might be multiple such constraints. (However, we could also read this as meaning that the PK could be one such constraint while NOT NULL is another one.) However, 11.16 ( as part of 11.12 ), says that DROP NOT NULL causes the indication of the column as NOT NULL to be removed. This, to me, says that if you do have multiple such constraints, you'd better remove them all with that command. All in all, I lean towards allowing just one as best as we can. [1] https://postgr.es/m/ca+tgmobnoxt83y1qesbnvarhfm-flwwkduyiv84e+psaydw...@mail.gmail.com [2] https://postgr.es/m/20230301223214.GC4268%40telsasoft.com [3] https://postgr.es/m/1c4f3755-2d10-cae9-647f-91a9f006410e%40enterprisedb.com -- Álvaro HerreraBreisgau, Deutschland — https://www.EnterpriseDB.com/ “Cuando no hay humildad las personas se degradan” (A. Christie)
Re: cataloguing NOT NULL constraints
Something else I noticed: the error message from ALTER TABLE ... ADD CONSTRAINT in the case of a duplicate constraint name is not very friendly: ERROR: duplicate key value violates unique constraint "pg_constraint_conrelid_contypid_conname_index" DETAIL: Key (conrelid, contypid, conname)=(16540, 0, nn) already exists. To match the error message for other constraint types, this should be: ERROR: constraint "nn" for relation "foo" already exists Regards, Dean
Re: cataloguing NOT NULL constraints
On Thu, 20 Jul 2023 at 16:31, Alvaro Herrera wrote: > > On 2023-Jul-13, Dean Rasheed wrote: > > > Something else I noticed is that the result from "ALTER TABLE ... > > ALTER COLUMN ... DROP NOT NULL" is no longer easily predictable -- if > > there are multiple NOT NULL constraints on the column, it just drops > > one (chosen at random?) and leaves the others. I think that it should > > either drop all the constraints, or throw an error. Either way, I > > would expect that if DROP NOT NULL succeeds, the result is that the > > column is nullable. > > Hmm, there shouldn't be multiple NOT NULL constraints for the same > column; if there's one, a further SET NOT NULL should do nothing. At > some point the code was creating two constraints, but I realized that > trying to support multiple constraints caused other problems, and it > seems to serve no purpose, so I removed it. Maybe there are ways to end > up with multiple constraints, but at this stage I would say that those > are bugs to be fixed, rather than something we want to keep. > Hmm, I'm not so sure. I think perhaps multiple NOT NULL constraints on the same column should just be allowed, otherwise things might get confusing. For example: create table p1 (a int not null check (a > 0)); create table p2 (a int not null check (a > 0)); create table foo () inherits (p1, p2); causes foo to have 2 CHECK constraints, but only 1 NOT NULL constraint: \d foo Table "public.foo" Column | Type | Collation | Nullable | Default +-+---+--+- a | integer | | not null | Check constraints: "p1_a_check" CHECK (a > 0) "p2_a_check" CHECK (a > 0) Inherits: p1, p2 select conname from pg_constraint where conrelid = 'foo'::regclass; conname --- p1_a_not_null p2_a_check p1_a_check (3 rows) which I find a little counter-intuitive / inconsistent. If I then drop the p1 constraints: alter table p1 drop constraint p1_a_check; alter table p1 drop constraint p1_a_not_null; I end up with column "a" still being not null, and the "p1_a_not_null" constraint still being there on foo, which seems even more counter-intuitive, because I just dropped that constraint, and it really should now be the "p2_a_not_null" constraint that makes "a" not null: \d foo Table "public.foo" Column | Type | Collation | Nullable | Default +-+---+--+- a | integer | | not null | Check constraints: "p2_a_check" CHECK (a > 0) Inherits: p1, p2 select conname from pg_constraint where conrelid = 'foo'::regclass; conname --- p1_a_not_null p2_a_check (2 rows) I haven't thought through various other cases in any detail, but I can't help feeling that it would be simpler and more logical / consistent to just allow multiple NOT NULL constraints on a column, rather than trying to enforce a rule that only one is allowed. That way, I think it would be easier for the user to keep track of why a column is not null. So I'd say that ALTER TABLE ... ADD NOT NULL should always add a constraint, even if there already is one. For example ALTER TABLE ... ADD UNIQUE does nothing to prevent multiple unique constraints on the same column(s). It seems pretty dumb, but maybe there is a reason to allow it, and it doesn't feel like we should be second-guessing what the user wants. Regards, Dean
Re: cataloguing NOT NULL constraints
On Thu, 20 Jul 2023 at 16:31, Alvaro Herrera wrote: > > On 2023-Jul-13, Dean Rasheed wrote: > > > I see that it's already been discussed, but I don't like the fact that > > there is no way to get hold of the new constraint names in psql. I > > think for the purposes of dropping named constraints, and also > > possible future stuff like NOT VALID / DEFERRABLE constraints, having > > some way to get their names will be important. > > Yeah, so there are two proposals: > > 1. Have \d+ replace the "not null" literal in the \d+ display with the > constraint name; if the column is not nullable because of the primary > key, it says "(primary key)" instead. There's a patch for this in the > thread somewhere. > > 2. Same, but use \d++ for this purpose > > Using ++ would be a novelty in psql, so I'm hesitant to make that an > integral part of the current proposal. However, to me (2) seems to most > comfortable way forward, because while you're right that people do need > the constraint name from time to time, this is very seldom the case, so > polluting \d+ might inconvenience people for not much gain. And people > didn't like having the constraint name in \d+. > > Do you have an opinion on these ideas? > Hmm, I don't particularly like that approach, because I think it will be difficult to cram any additional details into the table, and also I don't know whether having multiple not null constraints for a particular column can be entirely ruled out. I may well be in the minority here, but I think the best way is to list them in a separate footer section, in the same way as CHECK constraints, allowing other constraint properties to be included. So it might look something like: \d foo Table "public.foo" Column | Type | Collation | Nullable | Default +-+---+--+- a | integer | | not null | b | integer | | not null | c | integer | | not null | d | integer | | not null | Indexes: "foo_pkey" PRIMARY KEY, btree (a, b) Check constraints: "foo_a_check" CHECK (a > 0) "foo_b_check" CHECK (b > 0) NO INHERIT NOT VALID Not null constraints: "foo_c_not_null" NOT NULL c "foo_d_not_null" NOT NULL d NO INHERIT As for CHECK constraints, the contents of each constraint line would match the "table_constraint" SQL syntax needed to reconstruct the constraint. Doing it this way allows for things like NOT VALID and DEFERRABLE to be added in the future. I think that's probably too verbose for a plain "\d", but I think it would be OK with "\d+". Regards, Dean
Re: cataloguing NOT NULL constraints
On Wed, 12 Jul 2023 at 18:11, Alvaro Herrera wrote: > > v13, because a conflict was just committed to alter_table.sql. > > Here I also call out the relcache.c change by making it a separate > commit. I'm likely to commit it that way, too. To recap: the change is > to have a partitioned table's index list include the primary key, even > when said primary key is marked invalid. This turns out to be necessary > for the currently proposed pg_dump strategy to work; if this is not in > place, attaching the per-partition PK indexes to the parent index fails > because it sees that the columns are not marked NOT NULL. > Hmm, looking at that change, it looks a little ugly. I think someone reading that code in the future will have no idea why it's including some invalid indexes, and not others. > There are no other changes from v12. One thing I should probably get > to, is fixing the constraint name comparison code in pg_dump. Right now > it's a bit dumb and will get in silly trouble with overlength > table/column names (nothing that would actually break, just that it will > emit constraint names when there's no need to.) > Yeah, that seems a bit ugly. Presumably, also, if something like a column rename happens, the constraint name will no longer match. I see that it's already been discussed, but I don't like the fact that there is no way to get hold of the new constraint names in psql. I think for the purposes of dropping named constraints, and also possible future stuff like NOT VALID / DEFERRABLE constraints, having some way to get their names will be important. Something else I noticed is that the result from "ALTER TABLE ... ALTER COLUMN ... DROP NOT NULL" is no longer easily predictable -- if there are multiple NOT NULL constraints on the column, it just drops one (chosen at random?) and leaves the others. I think that it should either drop all the constraints, or throw an error. Either way, I would expect that if DROP NOT NULL succeeds, the result is that the column is nullable. Regards, Dean
Re: cataloguing NOT NULL constraints
On 30.06.23 13:44, Alvaro Herrera wrote: OK, so here's a new attempt to get this working correctly. Attached is a small fixup patch for the documentation. Furthermore, there are a few outdated comments that are probably left over from previous versions of this patch set. * src/backend/catalog/pg_constraint.c Outdated comment: + /* only tuples for CHECK constraints should be given */ + Assert(((Form_pg_constraint) GETSTRUCT(constrTup))->contype == CONSTRAINT_NOTNULL); * src/backend/parser/gram.y Should processCASbits() set >skip_validation, like in the CHECK case? _outConstraint() looks at the field, so it seems relevant. * src/backend/parser/parse_utilcmd.c The updated comment says List *ckconstraints; /* CHECK and NOT NULL constraints */ but it seems to me that NOT NULL constraints are not actually added there but in nnconstraints instead. It would be nice if the field nnconstraints was listed after ckconstraints consistently throughout the file. It's a bit random right now. This comment is outdated: + /* +* For NOT NULL declarations, we need to mark the column as +* not nullable, and set things up to have a CHECK constraint +* created. Also, duplicate NOT NULL declarations are not +* allowed. +*/ About this: case CONSTR_CHECK: cxt->ckconstraints = lappend(cxt->ckconstraints, constraint); + + /* +* XXX If the user says CHECK (IS NOT NULL), should we turn +* that into a regular NOT NULL constraint? +*/ break; I think this was decided against. + /* +* Copy NOT NULL constraints, too (these do not require any option to have +* been given). +*/ Shouldn't that be governed by the INCLUDING CONSTRAINTS option? Btw., there is some asymmetry here between check constraints and not-null constraints: Check constraints are in the tuple descriptor, but not-null constraints are not. Should that be unified? Or at least explained? * src/include/nodes/parsenodes.h This comment appears to be outdated: + * intermixed in tableElts, and constraints and notnullcols are NIL. After + * parse analysis, tableElts contains just ColumnDefs, notnullcols has been + * filled with not-nullable column names from various sources, and constraints + * contains just Constraint nodes (in fact, only CONSTR_CHECK nodes, in the + * present implementation). There is no "notnullcolls". * src/test/regress/parallel_schedule This change appears to be correct, but unrelated to this patch, so I suggest committing this separately. * src/test/regress/sql/create_table.sql -SELECT conislocal, coninhcount FROM pg_constraint WHERE conrelid = 'part_b'::regclass; +SELECT conislocal, coninhcount FROM pg_constraint WHERE conrelid = 'part_b'::regclass ORDER BY coninhcount DESC, conname; Maybe add conname to the select list here as well, for consistency with nearby queries. From c481b58c3e48ff0ab4738e5cf2440d2ad6fc3e47 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Mon, 3 Jul 2023 15:44:59 +0200 Subject: [PATCH] fixup! Add pg_constraint rows for NOT NULL constraints --- doc/src/sgml/catalogs.sgml| 2 +- doc/src/sgml/ref/alter_table.sgml | 9 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 9137b1bc58..36460126f4 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -2552,7 +2552,7 @@ pg_constraint Columns c = check constraint, f = foreign key constraint, - n = not null constraint, + n = not-null constraint, p = primary key constraint, u = unique constraint, t = constraint trigger, diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgml index 0b65731b1f..2c4138e4e9 100644 --- a/doc/src/sgml/ref/alter_table.sgml +++ b/doc/src/sgml/ref/alter_table.sgml @@ -113,13 +113,12 @@ [ CONSTRAINT constraint_name ] { CHECK ( expression ) [ NO INHERIT ] | + NOT NULL column_name [ NO INHERIT ] | UNIQUE [ NULLS [ NOT ] DISTINCT ] ( column_name [, ... ] ) index_parameters | PRIMARY KEY ( column_name [, ... ] ) index_parameters | EXCLUDE [ USING index_method ] ( exclude_element WITH operator [, ... ] ) index_parameters [ WHERE ( predicate ) ] | FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ ( refcolumn [, ... ] ) ] -[ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE referential_action ] [ ON UPDATE referential_action ] | - NOT NULL column_name [ NO INHERIT ] -} +[ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE referential_action ] [ ON UPDATE referential_action ] } [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] and table_constraint_using_index is: @@ -1765,7 +1764,7 @@ Examples Compatibility
Re: cataloguing NOT NULL constraints
On 2023-Jun-30, Andres Freund wrote: > On 2023-06-30 13:44:03 +0200, Alvaro Herrera wrote: > > > The main novelty in this version of the patch, is that we now emit > > "throwaway" NOT NULL constraints when a column is part of the primary > > key. Then, after the PK is created, we run a DROP for that constraint. > > That lets us create the PK without having to scan the table during > > pg_upgrade. > > Have you considered extending the DDL statement for this purpose? We have > ALTER TABLE ... ADD CONSTRAINT ... PRIMARY KEY USING INDEX ...; > we could just do something similar for the NOT NULL constraint? Which would > then delete the separate constraint NOT NULL constraint. Hmm, I hadn't. I think if we have to explicitly list the constraint that we want dropped, then it's pretty much the same than as if we used a comma-separated list of subcommands, like ALTER TABLE ... ADD CONSTRAINT .. PRIMARY KEY (a,b), DROP CONSTRAINT pgdump_throwaway_notnull_0, DROP CONSTRAINT pgdump_throwaway_notnull_1; However, I think it would be ideal if we *don't* have to specify the list of constraints: we would do this on any ALTER TABLE .. ADD CONSTRAINT PRIMARY KEY, without having any additional clause. But how to distinguish which NOT NULL markings to drop? Maybe we would have to specify a flag at NOT NULL constraint creation time. So pg_dump would emit something like CREATE TABLE foo (a int CONSTRAINT NOT NULL THROWAWAY); ... (much later) ... ALTER TABLE foo ADD CONSTRAINT .. PRIMARY KEY; and by the time this second command is run, those throwaway constraints are removed. The problems now are 1) how to make this CREATE statement more SQL-conformant (answer: make pg_dump emit a separate ALTER TABLE command for the constraint addition; it already knows how to do this, so it'd be very little code); but also 2) where to store the flag server-side flag that says this constraint has this property. I think it'd have to be a new pg_constraint column, and I don't like to add one for such a minor issue. On 2023-Jun-30, Alvaro Herrera wrote: > Scanning this thread, I think I left one reported issue unfixed related > to tables created LIKE others. I'll give it a look later. Other than > that I think all bases are covered, but I intend to leave the patch open > until near the end of the CF, in case someone wants to play with it. So it was [1] that I meant, where this example was provided: # create table t1 (c int primary key null unique); # create table t2 (like t1); # alter table t2 alter c drop not null; ERROR: no NOT NULL constraint found to drop The problem here is that because we didn't give INCLUDING INDEXES in the LIKE clause, we end up with a column marked NOT NULL for which we have no pg_constraint row. Okay, I thought, we can just make sure *not* to mark that case as not null; that works fine and looks reasonable. However, it breaks the following use case, which is already in use in the regression tests and possibly by users: CREATE TABLE pk (a int PRIMARY KEY) PARTITION BY RANGE (a); CREATE TABLE pk4 (LIKE pk); ALTER TABLE pk ATTACH PARTITION pk4 FOR VALUES FROM (3000) TO (4000); +ERROR: column "a" in child table must be marked NOT NULL The problem here is that we were assuming, by the time the third command is run, that the column had been marked NOT NULL by the second command. So my solution above is simply not acceptable. What we must do, in order to handle this backward-compatibly, is to ensure that a column part of a PK automatically gets a NOT NULL constraint for all the PK columns, for the case where INCLUDING INDEXES is not given. This is the same we do for regular INHERITS children and PKs. I'll go write this code now; should be simple enough. [1] https://postgr.es/m/CAMbWs48astPDb3K+L89wb8Yju0jM_Czm8svmU=uzd+wm61c...@mail.gmail.com -- Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/ It does it in a really, really complicated way why does it need to be complicated? Because it's MakeMaker.
Re: cataloguing NOT NULL constraints
Hi, On 2023-06-30 13:44:03 +0200, Alvaro Herrera wrote: > OK, so here's a new attempt to get this working correctly. Thanks for continuing to work on this! > The main novelty in this version of the patch, is that we now emit > "throwaway" NOT NULL constraints when a column is part of the primary > key. Then, after the PK is created, we run a DROP for that constraint. > That lets us create the PK without having to scan the table during > pg_upgrade. Have you considered extending the DDL statement for this purpose? We have ALTER TABLE ... ADD CONSTRAINT ... PRIMARY KEY USING INDEX ...; we could just do something similar for the NOT NULL constraint? Which would then delete the separate constraint NOT NULL constraint. Greetings, Andres Freund
Re: cataloguing NOT NULL constraints
Alvaro Herrera writes: >> I'm inclined to think that this idea of suppressing the implied >> NOT NULL from PRIMARY KEY is a nonstarter and we should just >> go ahead and make such a constraint. Another idea could be for >> pg_dump to emit the NOT NULL, load data, do the ALTER ADD PRIMARY >> KEY, and then ALTER DROP NOT NULL. > I like that second idea, yeah. It might be tough to make it work, but > I'll try. Yeah, I've been thinking more about it, and this might also yield a workable solution for the TestUpgrade breakage. The idea would be, roughly, for pg_dump to emit NOT NULL column decoration in all the same places it does now, and then to drop it again immediately after doing ADD PRIMARY KEY if it judges that there was no other reason to have it. This gets rid of the inconsistency for --binary-upgrade which I think is what is causing the breakage. I also ran into something else I didn't much care for: regression=# create table foo(f1 int primary key, f2 int); CREATE TABLE regression=# create table foochild() inherits(foo); CREATE TABLE regression=# alter table only foo alter column f2 set not null; ERROR: cannot add constraint only to table with inheritance children HINT: Do not specify the ONLY keyword. Previous versions accepted this case, and I don't really see why we can't do so with this new implementation -- isn't this exactly what pg_constraint.connoinherit was invented to represent? Moreover, existing pg_dump files can contain precisely this construct, so blowing it off isn't going to be zero-cost. regards, tom lane
Re: cataloguing NOT NULL constraints
On 2023-Apr-09, Tom Lane wrote: > In the new dispensation, pg_dump omits the NOT NULL clauses. > Great, you say, that makes the output more like what the user wrote. > I'm not so sure. This means that the ALTER TABLE will be compelled > to perform a full-table scan to verify that there are no nulls in the > already-loaded data before it can add the missing NOT NULL constraint. Yeah, I agree that this unintended consequence isn't very palatable. I think the other pg_upgrade problem is easily fixed (haven't tried yet), but having to rethink the pg_dump representation would likely take longer than we'd like. > I'm inclined to think that this idea of suppressing the implied > NOT NULL from PRIMARY KEY is a nonstarter and we should just > go ahead and make such a constraint. Another idea could be for > pg_dump to emit the NOT NULL, load data, do the ALTER ADD PRIMARY > KEY, and then ALTER DROP NOT NULL. I like that second idea, yeah. It might be tough to make it work, but I'll try. > In any case, I wonder whether that's the sort of redesign we should > be doing post-feature-freeze. It might be best to revert and try > again in v17. Yeah, sounds like reverting for now and retrying in v17 with the discussed changes might be better. -- Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/ "La espina, desde que nace, ya pincha" (Proverbio africano)
Re: cataloguing NOT NULL constraints
Andres Freund writes: > I think > https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=drongo=2023-04-07%2021%3A16%3A04 > might point out a problem with the pg_dump or pg_upgrade backward compat > paths: Yeah, this patch has broken every single upgrade-from-back-branch test. I think there's a second problem, though: even without considering back branches, this has changed pg_dump output in a way that I fear is unacceptable. Consider for instance this table definition (from rules.sql): create table rule_and_refint_t1 ( id1a integer, id1b integer, primary key (id1a, id1b) ); This used to be dumped as CREATE TABLE public.rule_and_refint_t1 ( id1a integer NOT NULL, id1b integer NOT NULL ); ... ... load data ... ... ALTER TABLE ONLY public.rule_and_refint_t1 ADD CONSTRAINT rule_and_refint_t1_pkey PRIMARY KEY (id1a, id1b); In the new dispensation, pg_dump omits the NOT NULL clauses. Great, you say, that makes the output more like what the user wrote. I'm not so sure. This means that the ALTER TABLE will be compelled to perform a full-table scan to verify that there are no nulls in the already-loaded data before it can add the missing NOT NULL constraint. The old dump output was carefully designed to avoid the need for that scan. Admittedly, we have to do a scan anyway to build the index, so this is strictly less than a 2X penalty on the ALTER, but is that acceptable? It might be all right in the context of regular dump/restore, where we're surely doing a lot of per-row work anyway to load the data and make the index. In the context of pg_upgrade, though, it seems absolutely disastrous: there will now be a per-row cost where there was none before, and that is surely a deal-breaker. BTW, I note from testing that the NOT NULL clauses *are* still emitted in at least some cases when doing --binary-upgrade from an old version. (This may be directly related to the buildfarm failures, not sure.) That's no solution though, because now what you get in pg_constraint will differ depending on which way you upgraded, which seems unacceptable too. I'm inclined to think that this idea of suppressing the implied NOT NULL from PRIMARY KEY is a nonstarter and we should just go ahead and make such a constraint. Another idea could be for pg_dump to emit the NOT NULL, load data, do the ALTER ADD PRIMARY KEY, and then ALTER DROP NOT NULL. In any case, I wonder whether that's the sort of redesign we should be doing post-feature-freeze. It might be best to revert and try again in v17. regards, tom lane
Re: cataloguing NOT NULL constraints
Hi, On 2023-04-07 17:19:42 -0700, Andres Freund wrote: > I think > https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=drongo=2023-04-07%2021%3A16%3A04 > might point out a problem with the pg_dump or pg_upgrade backward compat > paths: > > --- C:\\prog\\bf/root/upgrade.drongo/HEAD/origin-REL9_5_STABLE.sql.fixed > 2023-04-07 23:51:27.641328600 + > +++ > C:\\prog\\bf/root/upgrade.drongo/HEAD/converted-REL9_5_STABLE-to-HEAD.sql.fixed >2023-04-07 23:51:27.672571900 + > @@ -416,9 +416,9 @@ > -- Name: entry; Type: TABLE; Schema: public; Owner: buildfarm > -- > CREATE TABLE public.entry ( > -accession text, > -eid integer, > -txid smallint > +accession text NOT NULL, > +eid integer NOT NULL, > +txid smallint NOT NULL > ); > ALTER TABLE public.entry OWNER TO buildfarm; > -- > > Looks like we're making up NOT NULL constraints when migrating from 9.5, for > some reason? My compiler complains: ../../../../home/andres/src/postgresql/src/backend/catalog/heap.c: In function ‘AddRelationNotNullConstraints’: ../../../../home/andres/src/postgresql/src/backend/catalog/heap.c:2829:37: warning: ‘conname’ may be used uninitialized [-Wmaybe-uninitialized] 2829 | if (strcmp(lfirst(lc2), conname) == 0) | ^~~~ ../../../../home/andres/src/postgresql/src/backend/catalog/heap.c:2802:29: note: ‘conname’ was declared here 2802 | char *conname; | ^~~ I think the compiler may be right - I think the first use of conname might have been intended as constr->conname? Greetings, Andres Freund
Re: cataloguing NOT NULL constraints
Hi, On 2023-04-07 18:26:28 -0400, Tom Lane wrote: > Andres Freund writes: > > On 2023-04-07 17:46:33 -0400, Tom Lane wrote: > >> After quickly eyeing the diffs, I'm just going to take the new output > >> as good. I'm not surprised that there are additional output messages > >> given the additional catalog entries this made. I *am* a bit surprised > >> that some messages seem to have disappeared --- are there places where > >> this resulted in fewer catalog accesses than before? Nonetheless, > >> there's no good reason to assume this test is exposing any bugs. > > > I wonder if the issue is that the new paths miss a hook invocation. > > Perhaps. I'm content to silence the buildfarm for today; we can > investigate more closely later. Makes sense. I think https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=drongo=2023-04-07%2021%3A16%3A04 might point out a problem with the pg_dump or pg_upgrade backward compat paths: --- C:\\prog\\bf/root/upgrade.drongo/HEAD/origin-REL9_5_STABLE.sql.fixed 2023-04-07 23:51:27.641328600 + +++ C:\\prog\\bf/root/upgrade.drongo/HEAD/converted-REL9_5_STABLE-to-HEAD.sql.fixed 2023-04-07 23:51:27.672571900 + @@ -416,9 +416,9 @@ -- Name: entry; Type: TABLE; Schema: public; Owner: buildfarm -- CREATE TABLE public.entry ( -accession text, -eid integer, -txid smallint +accession text NOT NULL, +eid integer NOT NULL, +txid smallint NOT NULL ); ALTER TABLE public.entry OWNER TO buildfarm; -- Looks like we're making up NOT NULL constraints when migrating from 9.5, for some reason? Greetings, Andres Freund
Re: cataloguing NOT NULL constraints
... BTW, shouldn't https://commitfest.postgresql.org/42/3869/ now get closed as committed? regards, tom lane
Re: cataloguing NOT NULL constraints
Andres Freund writes: > On 2023-04-07 17:46:33 -0400, Tom Lane wrote: >> After quickly eyeing the diffs, I'm just going to take the new output >> as good. I'm not surprised that there are additional output messages >> given the additional catalog entries this made. I *am* a bit surprised >> that some messages seem to have disappeared --- are there places where >> this resulted in fewer catalog accesses than before? Nonetheless, >> there's no good reason to assume this test is exposing any bugs. > I wonder if the issue is that the new paths miss a hook invocation. Perhaps. I'm content to silence the buildfarm for today; we can investigate more closely later. regards, tom lane
Re: cataloguing NOT NULL constraints
Hi, On 2023-04-07 17:46:33 -0400, Tom Lane wrote: > Andres Freund writes: > > On 2023-04-07 23:11:55 +0200, Alvaro Herrera wrote: > >> Ah, cool, no worries. I would have stopped indeed, but I had to stay > >> around in case of any test failures. > > > Looks like there's work for you if you want ;) > > https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=rhinoceros=2023-04-07%2018%3A52%3A13 > > > But IMO fixing sepgsql can easily wait till tomorrow. > > I can deal with that one -- it's a bit annoying to work with sepgsql > if you're not on a Red Hat platform. Indeed. I tried to get them running a while back, to enable the tests with meson, without lot of success. Then I realized that they're also not wired up in make... ;) > After quickly eyeing the diffs, I'm just going to take the new output > as good. I'm not surprised that there are additional output messages > given the additional catalog entries this made. I *am* a bit surprised > that some messages seem to have disappeared --- are there places where > this resulted in fewer catalog accesses than before? Nonetheless, > there's no good reason to assume this test is exposing any bugs. I wonder if the issue is that the new paths miss a hook invocation. @@ -160,11 +160,7 @@ ALTER TABLE regtest_table ALTER b SET DEFAULT 'XYZ';-- not supported yet ALTER TABLE regtest_table ALTER b DROP DEFAULT; -- not supported yet ALTER TABLE regtest_table ALTER b SET NOT NULL; -LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table.b" permissive=0 -LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.b" permissive=0 ALTER TABLE regtest_table ALTER b DROP NOT NULL; -LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table.b" permissive=0 -LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.b" permissive=0 ALTER TABLE regtest_table ALTER b SET STATISTICS -1; LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema_2.regtest_table.b" permissive=0 LOG: SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:sepgsql_regtest_superuser_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="regtest_schema.regtest_table_2.b" permissive=0 The 'not supported yet' cases don't emit messages. Previously SET NOT NULL wasn't among that set, but seemingly it now is. Greetings, Andres Freund
Re: cataloguing NOT NULL constraints
Andres Freund writes: > On 2023-04-07 23:11:55 +0200, Alvaro Herrera wrote: >> Ah, cool, no worries. I would have stopped indeed, but I had to stay >> around in case of any test failures. > Looks like there's work for you if you want ;) > https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=rhinoceros=2023-04-07%2018%3A52%3A13 > But IMO fixing sepgsql can easily wait till tomorrow. I can deal with that one -- it's a bit annoying to work with sepgsql if you're not on a Red Hat platform. After quickly eyeing the diffs, I'm just going to take the new output as good. I'm not surprised that there are additional output messages given the additional catalog entries this made. I *am* a bit surprised that some messages seem to have disappeared --- are there places where this resulted in fewer catalog accesses than before? Nonetheless, there's no good reason to assume this test is exposing any bugs. regards, tom lane
Re: cataloguing NOT NULL constraints
Hi, On 2023-04-07 23:11:55 +0200, Alvaro Herrera wrote: > On 2023-Apr-07, Andres Freund wrote: > > > I just pushed a fix - sorry, I thought you might have stopped working for > > the > > day and CI finished with the modification a few seconds before your email > > arrived... > > Ah, cool, no worries. I would have stopped indeed, but I had to stay > around in case of any test failures. Looks like there's work for you if you want ;) https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=rhinoceros=2023-04-07%2018%3A52%3A13 But IMO fixing sepgsql can easily wait till tomorrow. Greetings, Andres Freund
Re: cataloguing NOT NULL constraints
On 2023-Apr-07, Andres Freund wrote: > I just pushed a fix - sorry, I thought you might have stopped working for the > day and CI finished with the modification a few seconds before your email > arrived... Ah, cool, no worries. I would have stopped indeed, but I had to stay around in case of any test failures. -- Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/ "No me acuerdo, pero no es cierto. No es cierto, y si fuera cierto, no me acuerdo." (Augusto Pinochet a una corte de justicia)
Re: cataloguing NOT NULL constraints
Hi, On 2023-04-07 23:00:01 +0200, Alvaro Herrera wrote: > On 2023-Apr-07, Andres Freund wrote: > > > src/test/regress/sql/triggers.sql > > 2127:create table child partition of parent for values in ('AAA'); > > 2266:create table child () inherits (parent); > > 2759:create table child () inherits (parent); > > > > The inherit.sql part is new. > > Yeah. > > > I'll see how hard it is to fix. > > Running the tests for it now -- it's a short fix. I just pushed a fix - sorry, I thought you might have stopped working for the day and CI finished with the modification a few seconds before your email arrived... Greetings, Andres Freund
Re: cataloguing NOT NULL constraints
On 2023-Apr-07, Andres Freund wrote: > src/test/regress/sql/triggers.sql > 2127:create table child partition of parent for values in ('AAA'); > 2266:create table child () inherits (parent); > 2759:create table child () inherits (parent); > > The inherit.sql part is new. Yeah. > I'll see how hard it is to fix. Running the tests for it now -- it's a short fix. -- Álvaro HerreraBreisgau, Deutschland — https://www.EnterpriseDB.com/ "Learn about compilers. Then everything looks like either a compiler or a database, and now you have two problems but one of them is fun." https://twitter.com/thingskatedid/status/1456027786158776329
Re: cataloguing NOT NULL constraints
Hi, On 2023-04-07 13:38:43 -0700, Andres Freund wrote: > I suspect there's a naming conflict between tests in different groups. Yep: test: create_aggregate create_function_sql create_cast constraints triggers select inherit typed_table vacuum drop_if_exists updatable_views roleattributes create_am hash_func errors infinite_recurse src/test/regress/sql/inherit.sql 851:create table child(f1 int not null, f2 text not null) inherits(inh_parent_1, inh_parent_2); src/test/regress/sql/triggers.sql 2127:create table child partition of parent for values in ('AAA'); 2266:create table child () inherits (parent); 2759:create table child () inherits (parent); The inherit.sql part is new. I'll see how hard it is to fix. Greetings, Andres Freund
Re: cataloguing NOT NULL constraints
Hi, I think there's some test instability: Fail: https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=parula=2023-04-07%2018%3A43%3A02 Subsequent success, without relevant changes: https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=parula=2023-04-07%2020%3A22%3A01 Followed by a failure: https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=parula=2023-04-07%2020%3A31%3A02 Similar failures on other animals: https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=komodoensis=2023-04-07%2020%3A27%3A43 https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=siskin=2023-04-07%2020%3A09%3A25 There's also as second type of failure: https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=dragonet=2023-04-07%2020%3A23%3A35 .. I suspect there's a naming conflict between tests in different groups. Greetings, Andres Freund