Thread: CREATE TABLE IF NOT EXISTS fails with privilege exception when tableexists
CREATE TABLE IF NOT EXISTS fails with privilege exception when tableexists
From
duvall@comfychair.org
Date:
I posted this here: https://dba.stackexchange.com/questions/260184/create-table-if-not-exists-fails-with-privilege-exception-when-table-exists and after a bit of time on chat with Peter Vandivier, decided I should ask here for confirmation. The question as posed: ====================================================================== I discovered that CREATE TABLE IF NOT EXISTS will fail with insufficient_privilege if the role executing the statement does, in fact, not have the necessary privileges, but does so regardless of whether the table exists or not. I would expect that if the table exists, the statement succeeds without making any modifications. Is that reasonable, or am I missing something? The docs (for 9, 10, 11, and 12) all say simply IF NOT EXISTS Do not throw an error if a relation with the same name already exists. A notice is issued in this case. Note that there is no guarantee that the existing relation is anything like the one that would have been created. I don't know whether a notice about the privilege check taking precedence over the existence check is appropriate here, but I feel like either it should be documented (maybe it is, somewhere else?), or that the behavior should change (could this be a backwards compatibility issue?). I've worked around it by DO $$ BEGIN CREATE TABLE IF NOT EXISTS tbl(); EXCEPTION WHEN insufficient_privilege THEN IF NOT EXISTS ( SELECT FROM pg_catalog.pg_tables WHERE schemaname = current_schema() AND tablename = 'tbl' ) THEN RAISE; END IF; WHEN others THEN RAISE; END; $$; but in the end, that query is not in code I own, so my ability to change it is limited, and if I can't get that change accepted, I believe I either have to get Postgres changed (which is admittedly likely a larger lift) or accept that I have to give the user more privilege than I want it to have. ====================================================================== Peter had some confusion about the "I can't change the code, but I changed the code" bit in the last paragraph. It's code in a third-party module I'd rather not fork (though I probably will, in order to fix the problem, if the author doesn't respond). But it led to his comment CREATE IF NOT EXISTS... must be a pseudo-transactional command (at first glance) 1. schema lock identifier 2. schema check identifier 3. schema modify 4. schema unlock identifier if you don't have the permission to do #2, that doesn't mean you get to skip #1 hence the error which, after a bit of thought, I realized that the insufficient_privilege might very well be coming from #1, not #3, which is where I thought it was coming from. So my question is a) is that the case, and b) if so, would an update to the docs be warranted? Or is this actually documented somewhere? Thanks! Danek
duvall@comfychair.org writes: > I discovered that CREATE TABLE IF NOT EXISTS will fail with > insufficient_privilege if the role executing the statement does, in fact, not > have the necessary privileges, but does so regardless of whether the table > exists or not. I would expect that if the table exists, the statement succeeds > without making any modifications. I'm a little skeptical about that expectation. IF NOT EXISTS is not a "get out of jail free" card; it is certainly not going to let you ignore, say, syntax errors elsewhere in the command. So I reject the notion that no other errors may be thrown before detecting table existence. We surely need to look up the schema mentioned or implied by the command before we can determine whether the table exists, and the current code checks CREATE permissions on it at that point. I don't see a strong argument that we should delay that check. Moreover, if we don't check CREATE there then I think we'd morally have to check USAGE, because otherwise you could use CREATE TABLE to find out whether a table exists in a schema you have no privileges at all for, which doesn't seem right. So one way or another there is going to be a permissions check in front of the IF-NOT-EXISTS early exit. (Admittedly, you can find out table existence anyway by looking in the system catalogs; but that's not a good argument for CREATE TABLE ignoring permissions considerations.) regards, tom lane
Re: CREATE TABLE IF NOT EXISTS fails with privilege exception whentable exists
From
duvall@comfychair.org
Date:
On Thu, Feb 20, 2020 at 07:18:55PM -0500, Tom Lane wrote: > duvall@comfychair.org writes: > > I discovered that CREATE TABLE IF NOT EXISTS will fail with > > insufficient_privilege if the role executing the statement does, in fact, not > > have the necessary privileges, but does so regardless of whether the table > > exists or not. I would expect that if the table exists, the statement succeeds > > without making any modifications. > > I'm a little skeptical about that expectation. IF NOT EXISTS is not a > "get out of jail free" card; it is certainly not going to let you ignore, > say, syntax errors elsewhere in the command. So I reject the notion that > no other errors may be thrown before detecting table existence. I agree; my statement made a stronger claim than I'd actually intended. My expectation was, specifically, that a permission error (involving the creation of the table, not its visibility; if I didn't have perms to see whether the table existed or not, I'd certainly expect to see that error) would not be thrown before detecting table existence. > We surely need to look up the schema mentioned or implied by the command > before we can determine whether the table exists, and the current code checks > CREATE permissions on it at that point. I don't see a strong argument that we > should delay that check. I consider the principle of least surprise to be a pretty strong argument, but it's also pretty subjective: I may be the only person to whom this behavior is surprising. But I've also only gotten other opinions from people who know this world very well, and have more context in which the behavior might make more sense. I also don't know of any other argument in favor of changing it, though I also don't know of any strong argument in favor of keeping it the way it is (I don't know whether backwards compatibility would be an issue here, for instance). > Moreover, if we don't check CREATE there then I think we'd morally have to > check USAGE, because otherwise you could use CREATE TABLE to find out whether > a table exists in a schema you have no privileges at all for, which doesn't > seem right. So one way or another there is going to be a permissions check in > front of the IF-NOT-EXISTS early exit. That's fair; I wouldn't want a side-channel existence check to succeed where something more direct would fail; that seems like it violates least surprise, too. But splitting the check in two would make everyone happy, no? (Except whoever had to code it, I suppose. :) Unless the hypothesis is correct that taking the lock is what causes the permissions error (in which case, it sounds like it simply can't be changed to match my expctations), but from what I'm getting from your response, that's not the case. > (Admittedly, you can find out table existence anyway by looking in the > system catalogs; but that's not a good argument for CREATE TABLE > ignoring permissions considerations.) Agreed. Thanks, Danek