pg_restore: [archiveur (db)] n'a pas pu exécuter la requête: ERREUR: le schéma "public" existe déjà

17

J'utilise pg_dump / pg_restore pour sauvegarder et restaurer une base de données PostgreSQL, mais je reçois des messages d'erreur (et un état de sortie non nul) de pg_restore. J'ai essayé un cas de base super simple (décrit ci-dessous) mais j'ai quand même eu ces erreurs:

pg_restore: [archiveur (db)] Erreur lors du traitement de la table des matières:
pg_restore: [archiveur (db)] Erreur de l'entrée 5 de la table des matières; 2615 2200 SCHEMA postgres publics
pg_restore: [archiveur (db)] n'a pas pu exécuter la requête: ERREUR: le schéma "public" existe déjà
    La commande était: CREATE SCHEMA public;

Étapes à reproduire:

  1. Installez une nouvelle distribution Ubuntu 14.04 vanille (j'utilise Vagrant avec cette boîte Vagrant ).
  2. Installez PostgreSQL 9.3, configurez pour autoriser les connexions locales en tant qu'utilisateur PostgreSQL "postgres" à partir de n'importe quel utilisateur Linux.
  3. Créez une base de données de test. Je fais juste:

    vagrant @ vagrant-ubuntu-trusty-64: ~ $ psql --username = postgres postgres
    psql (9.3.5)
    Tapez "help" pour obtenir de l'aide.
    
    postgres = # create database mydb;
    CRÉER UNE BASE DE DONNÉES
    postgres = # \ q
    vagrant @ vagrant-ubuntu-trusty-64: ~ $ psql --username = postgres mydb
    psql (9.3.5)
    Tapez "help" pour obtenir de l'aide.
    
    mydb = # créer des données de table (entrée bigint);
    CRÉER UNE TABLE
    mydb = # insérer dans les valeurs de données (1);
    INSÉRER 0 1
    mydb = # insérer dans les valeurs de données (2);
    INSÉRER 0 1
    mydb = # insérer dans les valeurs de données (3);
    INSÉRER 0 1
    mydb = # \ q
    
  4. Créez une sauvegarde de la base de données comme ceci:

    PGPASSWORD = "postgres" pg_dump --dbname = mydb --username = postgres --format = custom> pg_backup.dump
  5. Supprimez quelques lignes du tableau de données dans mydb afin que nous puissions savoir si nous avons restauré les données avec succès.

  6. Restaurez la base de données avec:

    PGPASSWORD = "postgres" pg_restore --clean --create --dbname = postgres --username = postgres pg_backup.dump

Les données sont restaurées, mais la commande pg_restore à l'étape 6 se termine avec l'état 1et affiche la sortie suivante:

pg_restore: [archiveur (db)] Erreur lors du traitement de la table des matières:
pg_restore: [archiveur (db)] Erreur de l'entrée 5 de la table des matières; 2615 2200 SCHEMA postgres publics
pg_restore: [archiveur (db)] n'a pas pu exécuter la requête: ERREUR: le schéma "public" existe déjà
    La commande était: CREATE SCHEMA public;



AVERTISSEMENT: erreurs ignorées lors de la restauration: 1

Je ne peux pas simplement ignorer cela car j'exécute cette commande par programme et j'ai besoin d'utiliser l'état de sortie pour déterminer si la restauration a échoué ou non. Au départ, je me demandais si ce problème était dû au fait que je mettais ma base de données en public (le schéma par défaut). J'ai pensé que public serait créé à la suite de l' --createoption de pg_restore avant que les données ne soient restaurées (ce qui pourrait également essayer de créer ce schéma car c'est là que se trouve ma table), mais quand j'ai essayé les étapes ci-dessus avec ma table dans un schéma différent, les résultats étaient les mêmes et les messages d'erreur étaient identiques.

Est-ce que je fais quelque chose de mal? Pourquoi est-ce que je vois cette erreur?

KSletmoe
la source

Réponses:

16

L'erreur est inoffensive mais pour s'en débarrasser, je pense que vous devez diviser cette restauration en deux commandes, comme dans:

dropdb -U postgres mydb && \
 pg_restore --create --dbname=postgres --username=postgres pg_backup.dump

L' --cleanoption dans pg_restore ne ressemble pas beaucoup mais soulève en fait des problèmes non triviaux.

Pour les versions jusqu'à 9.1

La combinaison des options --createet --cleandans pg_restore était une erreur dans les anciennes versions de PG (jusqu'à 9.1). Il y a en effet une certaine contradiction entre (citant la page de manuel 9.1):

--Clean Clean (drop) objets de base de données avant de les recréer

et

--créer Créez la base de données avant de la restaurer.

Car à quoi bon nettoyer une nouvelle base de données?

À partir de la version 9.2

La combinaison est maintenant acceptée et le doc le dit (en citant la page de manuel 9.3):

--clean Nettoyer (supprimer) les objets de base de données avant de les recréer. (Cela pourrait générer des messages d'erreur inoffensifs, si aucun objet n'était présent dans la base de données de destination.)

--créer Créez la base de données avant de la restaurer. Si --clean est également spécifié, supprimez et recréez la base de données cible avant de vous y connecter.

Maintenant, avoir les deux ensemble conduit à ce type de séquence lors de votre restauration:

DROP DATABASE mydb;
...
CREATE DATABASE mydb WITH TEMPLATE = template0... [other options]
...
CREATE SCHEMA public;
...
CREATE TABLE...

Il n'y a pas DROPpour chaque objet individuel, seulement un DROP DATABASEau début. Sinon, --createce serait le contraire.

Quoi qu'il en soit, cette séquence soulève l'erreur de publicschéma déjà existant car la création à mydbpartir de l' template0a déjà importé (ce qui est normal, c'est le point d'une base de données modèle).

Je ne sais pas pourquoi cette affaire n'est pas traitée automatiquement par pg_restore. Peut-être que cela entraînerait des effets secondaires indésirables lorsqu'un administrateur déciderait de personnaliser template0et / ou de changer l'objectif public, même si nous ne sommes pas censés le faire.

Daniel Vérité
la source
J'utilise 9.6, et spécifier --createsans cleanne résout pas le problème.
Cerin
7

Dans mon cas, la raison était que j'utilisais à pg_restorepartir de la version 11.2 de postgresql-contrib pour restaurer un vidage effectué par pg_dump9.6 vers un cluster PostgreSQL 9.6.

Après avoir rétrogradé mon pg_restoredos à 9.6, cette schema "public" already existserreur a disparu et le processus de restauration a fonctionné comme auparavant.

Lu Liu
la source
Mais avez-vous restauré le vidage à l'aide de pg_restore 9.6 dans une base de données postgres 11.2?
Mariano Ruiz
@MarianoRuiz Je pense que ma réponse originale est claire: "J'utilisais pg_restore à partir de la version 11.2 de postgresql-contrib pour restaurer un vidage effectué par pg_dump 9.6 sur un cluster PostgreSQL 9.6." Donc à votre question: non, je ne l'ai pas fait. Mon pg_restore était de 11,2 tandis que le cluster de pg était de 9,6
Lu Liu