Thread: BUG #18392: Can't restore database (using pg_restore) after latest Feb 8 update
BUG #18392: Can't restore database (using pg_restore) after latest Feb 8 update
From
PG Bug reporting form
Date:
The following bug has been logged on the website: Bug reference: 18392 Logged by: Carl Smith Email address: carl@msupply.foundation PostgreSQL version: 14.11 Operating system: MacOS Description: We regularly save snapshots of our app state using pg_dump and restore them with pg_restore. However, after the latest update (12.18 etc), we can no longer use pg_restore to restore the database -- it just throws a bunch of errors, mainly to do with tables not existing (that should exist). The command we've been dumping with is: `pg_dump -U postgres tmf_app_manager --format=custom -f output_folder/database.dump` And restoring with: `pg_restore -U postgres --clean --if-exists --dbname tmf_app_manager output_folder/database.dump` This seems to have become a problem with ALL of the recent (Feb 8) minor updates -- I can restore fine with 12.17, 14.10, 15.5 etc, but get the identical failures with 12.18, 14.11, 15.6 etc. So currently there is no "current" version we can use, which is frustrating as most repos only offer the latest minor version (easily anyway), so it's become very difficult/impossible to set up on a new system. I presume there is something about our database state that is "illegal" in some way with respect to the new updates, but we have no way to know what exactly the problem is. Reading through the release notes doesn't offer any insight. I'm happy to share a copy of one of our database dumps in order to demonstrate the problem.
Re: BUG #18392: Can't restore database (using pg_restore) after latest Feb 8 update
From
Laurenz Albe
Date:
On Thu, 2024-03-14 at 03:06 +0000, PG Bug reporting form wrote: > PostgreSQL version: 14.11 > Operating system: MacOS > > We regularly save snapshots of our app state using pg_dump and restore them > with pg_restore. However, after the latest update (12.18 etc), we can no > longer use pg_restore to restore the database -- it just throws a bunch of > errors, mainly to do with tables not existing (that should exist). Please don't keep us guessing and show us the errors. The first couple of error messages will be enough, the remainder is often a consequence of those. Yours, Laurenz Albe
Re: BUG #18392: Can't restore database (using pg_restore) after latest Feb 8 update
From
Carl Smith
Date:
Sure, here is the full console output.
If you’d like a copy of the database, I’m happy to send it via a non-public channel. (I can share a Dropbox link if you give me a private address to send it to)
Thanks,
Carl
Command failed: pg_restore -U postgres --clean --if-exists --dbname tmf_app_manager /Users/carl/GitHub/conforma/conforma-server/database/_snapshots/TEST_14_11_2024-03-14_15-27-40/database.dump
pg_restore: error: could not execute query: ERROR: relation "public.template" does not exist
LINE 5: public.template
^
QUERY:
SELECT
template.code
FROM
public.template
JOIN public.template_section ON template_id = template.id
WHERE
template_section.id = $1;
CONTEXT: SQL function "get_template_code" during inlining
Command was: CREATE TABLE public.template_element (
id integer NOT NULL,
section_id integer NOT NULL,
code character varying NOT NULL,
index integer,
title character varying,
category public.template_element_category,
element_type_plugin_code character varying,
visibility_condition jsonb DEFAULT 'true'::jsonb,
is_required jsonb DEFAULT 'true'::jsonb,
is_editable jsonb DEFAULT 'true'::jsonb,
validation jsonb DEFAULT 'true'::jsonb,
initial_value jsonb,
validation_message character varying,
help_text character varying,
parameters jsonb,
reviewability public.reviewability DEFAULT 'ONLY_IF_APPLICANT_ANSWER'::public.reviewability NOT NULL,
template_code character varying GENERATED ALWAYS AS (public.get_template_code(section_id)) STORED,
template_version character varying GENERATED ALWAYS AS (public.get_template_version(section_id)) STORED
);
pg_restore: error: could not execute query: ERROR: relation "public.template_element" does not exist
Command was: ALTER TABLE public.template_element OWNER TO postgres;
pg_restore: error: could not execute query: ERROR: type public.template_element does not exist
Command was: CREATE FUNCTION public.template_element_parameters_string(template_element public.template_element) RETURNS text
LANGUAGE sql STABLE
AS $_$
SELECT
parameters::text
FROM
public.template_element
WHERE
id = $1.id
$_$;
pg_restore: error: could not execute query: ERROR: type "public.template_element" does not exist
Command was: ALTER FUNCTION public.template_element_parameters_string(template_element public.template_element) OWNER TO postgres;
pg_restore: error: could not execute query: ERROR: relation "public.template_element" does not exist
Command was: ALTER SEQUENCE public.template_element_id_seq OWNED BY public.template_element.id;
pg_restore: error: could not execute query: ERROR: relation "public.template_element" does not exist
Command was: ALTER TABLE ONLY public.template_element ALTER COLUMN id SET DEFAULT nextval('public.template_element_id_seq'::regclass);
pg_restore: error: could not execute query: ERROR: relation "public.template_element" does not exist
Command was: COPY public.template_element (id, section_id, code, index, title, category, element_type_plugin_code, visibility_condition, is_required, is_editable, validation, initial_value, validation_message, help_text, parameters, reviewability) FROM stdin;
pg_restore: error: could not execute query: ERROR: relation "public.template_element" does not exist
Command was: ALTER TABLE ONLY public.template_element
ADD CONSTRAINT template_element_pkey PRIMARY KEY (id);
pg_restore: error: could not execute query: ERROR: relation "public.template_element" does not exist
Command was: ALTER TABLE ONLY public.template_element
ADD CONSTRAINT template_element_template_code_code_template_version_key UNIQUE (template_code, code, template_version);
pg_restore: error: could not execute query: ERROR: relation "public.template_element" does not exist
Command was: CREATE INDEX i_template_element_category ON public.template_element USING btree (category);
pg_restore: error: could not execute query: ERROR: relation "public.template_element" does not exist
Command was: CREATE INDEX i_template_element_code ON public.template_element USING btree (code);
pg_restore: error: could not execute query: ERROR: relation "public.template_element" does not exist
Command was: CREATE INDEX i_template_element_reviewability ON public.template_element USING btree (reviewability);
pg_restore: error: could not execute query: ERROR: relation "public.template_element" does not exist
Command was: CREATE INDEX i_template_element_section_id_fkey ON public.template_element USING btree (section_id);
pg_restore: error: could not execute query: ERROR: relation "public.template_element" does not exist
Command was: CREATE INDEX i_template_element_template_code ON public.template_element USING btree (template_code);
pg_restore: error: could not execute query: ERROR: relation "public.template_element" does not exist
Command was: ALTER TABLE ONLY public.application_response
ADD CONSTRAINT application_response_template_element_id_fkey FOREIGN KEY (template_element_id) REFERENCES public.template_element(id) ON DELETE CASCADE;
pg_restore: error: could not execute query: ERROR: relation "public.template_element" does not exist
Command was: ALTER TABLE ONLY public.review_response
ADD CONSTRAINT review_response_template_element_id_fkey FOREIGN KEY (template_element_id) REFERENCES public.template_element(id) ON DELETE CASCADE;
pg_restore: error: could not execute query: ERROR: relation "public.template_element" does not exist
Command was: ALTER TABLE ONLY public.template_element
ADD CONSTRAINT template_element_section_id_fkey FOREIGN KEY (section_id) REFERENCES public.template_section(id) ON DELETE CASCADE;
pg_restore: error: could not execute query: ERROR: relation "public.template_element" does not exist
Command was: GRANT ALL ON TABLE public.template_element TO graphile_user;
pg_restore: warning: errors ignored on restore: 18
On 14 Mar 2024, at 6:58 PM, Laurenz Albe <laurenz.albe@cybertec.at> wrote:On Thu, 2024-03-14 at 03:06 +0000, PG Bug reporting form wrote:PostgreSQL version: 14.11
Operating system: MacOS
We regularly save snapshots of our app state using pg_dump and restore them
with pg_restore. However, after the latest update (12.18 etc), we can no
longer use pg_restore to restore the database -- it just throws a bunch of
errors, mainly to do with tables not existing (that should exist).
Please don't keep us guessing and show us the errors. The first couple of
error messages will be enough, the remainder is often a consequence of those.
Yours,
Laurenz Albe
On 14 Mar 2024, at 6:58 PM, Laurenz Albe <laurenz.albe@cybertec.at> wrote:On Thu, 2024-03-14 at 03:06 +0000, PG Bug reporting form wrote:PostgreSQL version: 14.11
Operating system: MacOS
We regularly save snapshots of our app state using pg_dump and restore them
with pg_restore. However, after the latest update (12.18 etc), we can no
longer use pg_restore to restore the database -- it just throws a bunch of
errors, mainly to do with tables not existing (that should exist).
Please don't keep us guessing and show us the errors. The first couple of
error messages will be enough, the remainder is often a consequence of those.
Yours,
Laurenz Albe
Re: BUG #18392: Can't restore database (using pg_restore) after latest Feb 8 update
From
Laurenz Albe
Date:
On Thu, 2024-03-14 at 19:03 +1300, Carl Smith wrote: > Command failed: pg_restore -U postgres --clean --if-exists --dbname tmf_app_manager /Users/carl/GitHub/conforma/conforma-server/database/_snapshots/TEST_14_11_2024-03-14_15-27-40/database.dump > pg_restore: error: could not execute query: ERROR: relation "public.template" does not exist > LINE 5: public.template > ^ > QUERY: > SELECT > template.code > FROM > public.template > JOIN public.template_section ON template_id = template.id > WHERE > template_section.id = $1; > > > CONTEXT: SQL function "get_template_code" during inlining > Command was: CREATE TABLE public.template_element ( > id integer NOT NULL, > section_id integer NOT NULL, > code character varying NOT NULL, > index integer, > title character varying, > category public.template_element_category, > element_type_plugin_code character varying, > visibility_condition jsonb DEFAULT 'true'::jsonb, > is_required jsonb DEFAULT 'true'::jsonb, > is_editable jsonb DEFAULT 'true'::jsonb, > validation jsonb DEFAULT 'true'::jsonb, > initial_value jsonb, > validation_message character varying, > help_text character varying, > parameters jsonb, > reviewability public.reviewability DEFAULT 'ONLY_IF_APPLICANT_ANSWER'::public.reviewability NOT NULL, > template_code character varying GENERATED ALWAYS AS (public.get_template_code(section_id)) STORED, > template_version character varying GENERATED ALWAYS AS (public.get_template_version(section_id)) STORED > ); That's not a PostgreSQL bug, that's a bug in your code. You must have declared the function public.get_template_code(integer) as IMMUTABLE, but it SELECTs from public.template, so it clearly is *not* immutable. It depends on the state of the database, in your case on the existence of a certain table (and on its contents). So you lied when you declared the function IMMUTABLE, and the consequences are your fault. You should instead use a trigger to populate template_code. That is the correct solution, and then you wouldn't get that error. If that worked previously, it's purely by coincidence: if public.template happens to exist, the restore doesn't fail. Yours, Laurenz Albe
Re: BUG #18392: Can't restore database (using pg_restore) after latest Feb 8 update
From
Tom Lane
Date:
Laurenz Albe <laurenz.albe@cybertec.at> writes: > That's not a PostgreSQL bug, that's a bug in your code. > You must have declared the function public.get_template_code(integer) as IMMUTABLE, but > it SELECTs from public.template, so it clearly is *not* immutable. It depends on the state > of the database, in your case on the existence of a certain table (and on its contents). Yeah. The concrete problem so far as pg_dump is concerned is that it can't see the dependencies that the body of get_template_code has, so it doesn't realize that it would have to postpone creation of this table till after public.template is created. There are various ways that you could hack around that by preventing the function from being considered for inlining, but as Laurenz suggests, that's just band-aiding over a fundamentally unsafe design. Pretending that this function is immutable will bite you eventually. BTW, I believe that what broke it for you as of the current releases is commits 743ddafc7 et al, which caused GENERATED expressions to be run through expression preprocessing at CREATE TABLE time: Two actual bugs of this ilk are fixed here. We failed to preprocess column GENERATED expressions before checking mutability, so that the code could fail to detect the use of a volatile function default-argument expression, or it could reject a polymorphic function that is actually immutable on the datatype of interest. Likewise, column DEFAULT expressions weren't preprocessed before determining if it's safe to apply the attmissingval mechanism. A false negative would just result in an unnecessary table rewrite, but a false positive could allow the attmissingval mechanism to be used in a case where it should not be, resulting in unexpected initial values in a new column. One of the things that happens in that preprocessing is inlining of inline-able SQL functions. This particular function is not inline-able I think, but we'd hit the parser error on the way to discovering that. (Hmm, I wonder if we could make inline_function do some tests on the raw parse tree so it could bail out earlier; I think we could verify that it's a SELECT with no FROM before invoking parse analysis. The extra complication could be justified as saving cycles for obviously non-inlinable SQL functions.) regards, tom lane
Re: BUG #18392: Can't restore database (using pg_restore) after latest Feb 8 update
From
Carl Smith
Date:
Thanks Tom and Laurenz, This is very helpful information and I’m sure will allow me to fix our database problem. Kind regards, Carl > On 15 Mar 2024, at 10:49 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote: > > Laurenz Albe <laurenz.albe@cybertec.at> writes: >> That's not a PostgreSQL bug, that's a bug in your code. > >> You must have declared the function public.get_template_code(integer) as IMMUTABLE, but >> it SELECTs from public.template, so it clearly is *not* immutable. It depends on the state >> of the database, in your case on the existence of a certain table (and on its contents). > > Yeah. The concrete problem so far as pg_dump is concerned is that > it can't see the dependencies that the body of get_template_code has, > so it doesn't realize that it would have to postpone creation of this > table till after public.template is created. There are various ways > that you could hack around that by preventing the function from being > considered for inlining, but as Laurenz suggests, that's just > band-aiding over a fundamentally unsafe design. Pretending that this > function is immutable will bite you eventually. > > BTW, I believe that what broke it for you as of the current releases > is commits 743ddafc7 et al, which caused GENERATED expressions to be > run through expression preprocessing at CREATE TABLE time: > > Two actual bugs of this ilk are fixed here. We failed to preprocess > column GENERATED expressions before checking mutability, so that the > code could fail to detect the use of a volatile function > default-argument expression, or it could reject a polymorphic function > that is actually immutable on the datatype of interest. Likewise, > column DEFAULT expressions weren't preprocessed before determining if > it's safe to apply the attmissingval mechanism. A false negative > would just result in an unnecessary table rewrite, but a false > positive could allow the attmissingval mechanism to be used in a case > where it should not be, resulting in unexpected initial values in a > new column. > > One of the things that happens in that preprocessing is inlining > of inline-able SQL functions. This particular function is not > inline-able I think, but we'd hit the parser error on the way to > discovering that. (Hmm, I wonder if we could make inline_function > do some tests on the raw parse tree so it could bail out earlier; > I think we could verify that it's a SELECT with no FROM before > invoking parse analysis. The extra complication could be justified > as saving cycles for obviously non-inlinable SQL functions.) > > regards, tom lane