web-dev-qa-db-fra.com

Comment dupliquer des schémas dans PostgreSQL

J'ai une base de données avec le schéma public et schema_A. Je dois créer un nouveau schéma schema_b avec la même structure que schema_a. J'ai trouvé la fonction ci-dessous, le problème est qu'elle ne copie pas les contraintes de clé étrangère.

CREATE OR REPLACE FUNCTION clone_schema(source_schema text, dest_schema text)
  RETURNS void AS
$BODY$
DECLARE
  object text;
  buffer text;
  default_ text;
  column_ text;
BEGIN
  EXECUTE 'CREATE SCHEMA ' || dest_schema ;

  -- TODO: Find a way to make this sequence's owner is the correct table.
  FOR object IN
    SELECT sequence_name::text FROM information_schema.SEQUENCES WHERE sequence_schema = source_schema
  LOOP
    EXECUTE 'CREATE SEQUENCE ' || dest_schema || '.' || object;
  END LOOP;

  FOR object IN
    SELECT table_name::text FROM information_schema.TABLES WHERE table_schema = source_schema
  LOOP
    buffer := dest_schema || '.' || object;
    EXECUTE 'CREATE TABLE ' || buffer || ' (LIKE ' || source_schema || '.' || object || ' INCLUDING CONSTRAINTS INCLUDING INDEXES INCLUDING DEFAULTS)';

    FOR column_, default_ IN
      SELECT column_name::text, REPLACE(column_default::text, source_schema, dest_schema) FROM information_schema.COLUMNS WHERE table_schema = dest_schema AND table_name = object AND column_default LIKE 'nextval(%' || source_schema || '%::regclass)'
    LOOP
      EXECUTE 'ALTER TABLE ' || buffer || ' ALTER COLUMN ' || column_ || ' SET DEFAULT ' || default_;
    END LOOP;
  END LOOP;

END;
$BODY$  LANGUAGE plpgsql

Comment puis-je cloner/copier schema_A avec les contraintes de clé étrangère?

20
Cristhian Boujon

Vous pouvez probablement le faire à partir de la ligne de commande sans utiliser de fichiers:

pg_dump -U user --schema='fromschema' database | sed 's/fromschmea/toschema/g' | psql -U user -d database

Remarque que cela recherche et remplace toutes les occurrences de la chaîne qui est le nom de votre schéma, donc cela peut affecter vos données.

21
user1517922

J'utiliserais (pg_dump pour vider le schéma sans données:

-s
--schema-only

Vider uniquement les définitions d'objet (schéma), pas les données.

Cette option est l'inverse de --data-only. Il est similaire, mais pour des raisons historiques non identiques à, en spécifiant --section=pre-data --section=post-data.

(Ne confondez pas cela avec le --schema option, qui utilise le mot "schéma" dans un sens différent.)

Pour exclure des données de table uniquement pour un sous-ensemble de tables de la base de données, voir --exclude-table-data.

pg_dump $DB -p $PORT -n $SCHEMA -s -f filename.pgsql

Renommez ensuite le schéma dans le vidage (recherche et remplacement) et restaurez-le avec psql.

psql $DB -f filename.pgsql

Les contraintes de clé étrangère référençant les tables dans les schémas autre sont copiées pour pointer vers le même schéma.
Les références aux tables dans le schéma pareil pointent vers les tables respectives dans le schéma copié.

13
Erwin Brandstetter

Un peu tard pour la fête, mais quelques m² ici pourraient vous aider tout au long de votre chemin:

Récupère l'oid du schéma:

namespace_id = SELECT oid 
                  FROM pg_namespace 
                 WHERE nspname = '<schema name>';

récupère l'oid de la table:

table_id = SELECT relfilenode 
                FROM pg_class 
               WHERE relnamespace = '<namespace_id>' AND relname = '<table_name>'

obtenir des contraintes de clé étrangère:

SELECT con.conname, pg_catalog.pg_get_constraintdef(con.oid) AS condef 
  FROM pg_catalog.pg_constraint AS con 
  JOIN pg_class AS cl ON cl.relnamespace = con.connamespace AND cl.relfilenode = con.conrelid 
 WHERE con.conrelid = '<table_relid>'::pg_catalog.oid AND con.contype = 'f';

Une bonne ressource pour les tables système PostgreSQL peut être trouvée ici . De plus, vous pouvez en savoir plus sur les requêtes internes pg_dump permet de recueillir des informations de vidage en affichant c'est code source .

Probablement le moyen le plus simple de voir comment pg_dump rassemble toutes vos données serait d'utiliser strace dessus, comme ceci:

$ strace -f -e sendto -s8192 -o pg_dump.trace pg_dump -s -n <schema>
$ grep -oP '(SET|SELECT)\s.+(?=\\0)' pg_dump.trace

Vous devrez toujours trier le bourbier des instructions, mais cela devrait vous aider à reconstituer un outil de clonage par programme et éviter d'avoir à passer à un shell pour appeler pg_dump.

4
rabbitt

Je vais partager une solution à mon problème qui était la même avec un petit ajout. Je devais cloner un schéma, créer un nouvel utilisateur de base de données et attribuer la propriété de tous les objets du nouveau schéma à cet utilisateur.

Pour l'exemple suivant, supposons que le schéma de référence s'appelle ref_schema et le schéma cible new_schema. Le schéma de référence et tous les objets qu'il contient appartiennent à un utilisateur appelé ref_user.

1. videz le schéma de référence avec pg_dump:

pg_dump -n ref_schema -f dump.sql database_name

2. Créer un nouvel utilisateur de base de données avec le nom new_user :

CREATE USER new_user

. Renommez le schéma ref_schema en new_schema :

ALTER SCHEMA ref_schema RENAME TO new_schema

4. changer le propriétaire de tous les objets dans le schéma renommé au nouvel utilisateur

REASSIGN OWNED BY ref_user TO new_user

5. restaurez le schéma de référence d'origine à partir du vidage

psql -f dump.sql database_name

J'espère que quelqu'un trouve cela utile.

4
Adam

Je suis juste tombé sur le même. Parfois, je manque remap_schema :)
Le problème - ni l'un ni l'autre ci-dessus ne concerne le format standard Fc - qui est crucial pour les grands schémas.
J'ai donc trouvé quelque chose qui l'utilise:
Pseudo-code ci-dessous - devrait fonctionner.
Nécessite le changement de nom de la source pour la durée de pg_dump qui, bien sûr, pourrait ne pas être une option :(
Source:

pg_dump --pre-data in sql format
psql rename sosurce to target
pg_dump -Fc --data-only
psql rename back
pg_dump --post-data in sql format

Cible:

sed source_schema->target_schema pre-data sql |psql
pg_restore Fc dump
sed source_schema->target_schema post-data sql |psql

sed ci-dessus inclura généralement toutes les autres manipulations (disons des noms d'utilisateurs différents entre la source et la cible) Mais ce sera beaucoup plus rapide car les données ne feront pas partie du fichier

0
Ilya Dorfman