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?
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.
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é.
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
.
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.
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