Fonctions de documentation des bases de données PostgreSQL. Troisième partie

Il s'agit de la troisième partie de l'article qui décrit les fonctions définies par l'utilisateur pour travailler avec les répertoires système: pg_class, pg_attribute, pg_constraints, etc.

Cette section de l'article décrit les fonctions qui renvoient les caractéristiques des séquences, les tables héritées et les caractéristiques spéciales des attributs de table .

Voir aussi
Fonctions de documentation des bases de données PostgreSQL. Première partie ;
Fonctions de documentation des bases de données PostgreSQL. Deuxième partie ;
Fonctions de documentation des bases de données PostgreSQL. La fin (quatrième partie) .

La première moitié de l'article fournit des commentaires sur la mise en œuvre des fonctions. Le second est le code source des fonctions. Pour les lecteurs qui ne sont intéressés que par les textes sources, nous suggérons de passer immédiatement à l' annexe .

Structure d'une fonction qui renvoie une liste de caractéristiques des séquences de table



Fig. 2. Fonctions dont dépendent les fonctions admtf_Table_Sequences

Tableau 11. Objectif des fonctions.

Non.Le titreRendez-vous
1admtf_Sequence_FeaturesLa fonction renvoie une liste de caractéristiques de séquence de table.
2admtf_Table_SequencesLa fonction renvoie une liste des séquences de tables de base de données et leurs caractéristiques.

Fonction Admtf_Sequence_Features - liste des caractéristiques de séquence de base de données


La fonction admtf_Sequence_Features renvoie une liste des caractéristiques SEQUENCE de la base de données. Le code source peut être consulté et téléchargé ici .


La fonction admtf_Sequence_Features renvoie une liste des caractéristiques de séquence de base de données ( SEQUENCE )

.

En tant que paramètres, la fonction prend le nom de la séquence ( a_SequenceName ) et le nom du schéma dans lequel la séquence est créée ( a_SchemaName ).


La nécessité de la fonction admtf_Sequence_Features est apparue car les principales caractéristiques de la séquence sont réellement stockées dans une table dont le nom correspond au nom de la séquence et les données en sont extraites à l'aide de l' instruction SELECT . Dans ce cas, le nom de la séquence, le nom du schéma et le commentaire de la séquence sont stockés dans les répertoires pg_class , pg_namespace et pg_description .


SELECT * FROM kr_road_network_vertices_pgr_id_seq; 

Remarque 6


PostgreSQL 10 a séparé les caractéristiques de la séquence et les caractéristiques de ses états. Pour cela, le répertoire pg_sequence avec les caractéristiques de séquence a été introduit, contenant la valeur initiale ( start_value ), increment ( increment_by ) et la valeur maximale ( max_value ) de la séquence. La dernière valeur renvoyée par la séquence ( last_value ) a été laissée dans la «table» avec le nom de la séquence.

La fin de la remarque.


Je pense que la présentation de chaque séquence comme un analogue du tableau est dictée par la nécessité de stocker la dernière valeur utilisée de la séquence ( last_value ), qui est une caractéristique de l'état de la séquence, mais pas la séquence elle-même.


L'entrée de séquence dans le répertoire pg_class diffère de l'entrée de table par la valeur du type de relation (relkind = 'S' ).


Pour extraire les caractéristiques d'une séquence arbitraire, vous devez utiliser du SQL dynamique.


 EXECUTE 'SELECT last_value,start_value,increment_by,max_value FROM '|| LOWER(a_SchemaName)||'.'||LOWER(a_SequenceName) INTO v_SequenceLastValue,v_SequenceStartValue, v_SequenceIncrementBy,v_SequenceMaxValue ; 


Tableau 12. Résultat de l'exécution de la fonction admtf_Sequence_Features ('public', 'kr_road_network_vertices_pgr_id_seq').

Le titreCommentaireCourantCommencerIncrémentLa fin
kr_road_network
_vertices_pgr_id
_seq
Séquence138023119223372036854775807

Fonction admtf_Table_Sequences liste des séquences de table de base de données et leurs caractéristiques


La fonction admtf_Table_Sequences renvoie une liste de séquences ( SEQUENCE ) de la table de base de données générant les valeurs de ses champs et les caractéristiques de ces séquences. Le code source peut être consulté et téléchargé ici , et voici une version d'une fonction qui n'utilise pas de curseur .


En tant que paramètres, la fonction prend le nom de la table source ( a_TableName ) et le nom du schéma dans lequel la table est créée (

a_SchemaName

)

le code source de l'opérateur sur la figure
 SELECT pseq.relname AS SequenceName,snsp.nspname AS SequenceSchemaName, COALESCE(dsc.description,',    ' ||da.attname) AS SequenceDescription, d.depType AS DependcyType,da.attname AS AttributeName FROM pg_depend d INNER JOIN pg_class pseq ON d.objid = pseq.oid INNER JOIN pg_namespace snsp ON pseq.relnamespace=snsp.oid LEFT OUTER JOIN pg_Description dsc ON pseq.oid=dsc.objoid AND dsc.objsubid=0 INNER JOIN pg_class tbl ON d.refobjid = tbl.oid INNER JOIN pg_namespace nsp ON tbl.relnamespace=nsp.oid INNER JOIN pg_attribute da ON da.attrelid= d.refobjid AND da.attnum= d.refobjsubid WHERE LOWER(nsp.nspname)=LOWER(a_SchemaName) AND LOWER(tbl.relname)=LOWER(a_TableOID) AND tbl.relkind = 'r' AND pseq.relkind = 'S' ORDER BY pseq.relname; 


Une description d'une séquence unique est une combinaison d'un enregistrement dans pg_class la décrivant comme une relation physique et une table conditionnelle avec le nom de la séquence contenant des données sur les caractéristiques spécifiques de la séquence


Les informations sur la relation entre la séquence et la table source sont stockées dans le répertoire système pg_depend .



Tableau 13. Attributs du répertoire pg_depend nécessaires pour implémenter la fonction.
Le titreLa description
objidOID de la séquence dans le répertoire pg_class
objsubidCe champ contient zéro
refobjidOID de la table dans les champs dont la séquence est utilisée
refobjsubidNuméro d'attribut de table dont les valeurs sont remplies à l'aide d'une séquence

De plus, la fonction accède aux données de catalogue pg_namespace et pg_description afin d'extraire les diagrammes et les commentaires de la séquence et de la table source.


Pour déterminer l'attribut d'une table dont les valeurs sont remplies à l'aide d'une séquence, la fonction accède au répertoire pg_attribute sous la condition: attrelid = refobjid AND attnum = refobjsubid . (Dans cette condition, les noms des attributs du répertoire pg_depend sont indiqués à droite du signe égal).


Les caractéristiques spéciales des séquences de table sont récupérées dans une boucle en appelant admtf_Sequence_Features . Le cycle est utilisé car plusieurs séquences peuvent être affectées pour remplir les champs du tableau.


Tableau 14. Résultat de l'exécution de la fonction admtf_Table_Sequences ('public', 'kr_road_network_vertices_pgr').

Le titreCommentaireCommencerIncrémentLa finLe terrain
kr_road_network
_vertices_pgr_id
_seq
Séquence générant des valeurs de champ id119223372036854775807id

Version sans curseur


Dans un environnement PostgreSQL dont la version est inférieure à 10, il est très probablement impossible d'implémenter la fonction admtf_Table_Sequences sans utiliser de curseur.
Mais les heureux propriétaires de la version 10 peuvent bien se passer d'un curseur, car ils ont le répertoire pg_sequence à leur disposition. Dans ce cas, toutes les caractéristiques de la séquence peuvent être récupérées avec une seule instruction SELECT .


Dans l'implémentation de la fonction donnée, en utilisant la fonction de fenêtre RANK () OVER (PARTITION BY pseq.relname) , le numéro de séquence de la séquence utilisée pour remplir la table source est calculé.



le code source de l'opérateur sur la figure
 SELECT RANK() OVER (PARTITION BY pseq.relname) AS SequenceNo, pseq.relname AS SequenceName,snsp.nspname AS SequenceSchemaName, COALESCE(dsc.description,',    ' ||da.attname) AS SequenceDescription, seq.seqstart AS SequenceStartValue,seq.seqincrement AS SequenceIncrementBy, seq.seqmax AS SequenceMaxValue, d.depType AS DependcyType,da.attname AS AttributeName FROM pg_depend d INNER JOIN pg_class pseq ON d.objid = pseq.oid INNER JOIN pg_sequence seq ON seq.seqrelid= pseq.oid INNER JOIN pg_namespace snsp ON pseq.relnamespace=snsp.oid LEFT OUTER JOIN pg_Description dsc ON pseq.oid=dsc.objoid AND dsc.objsubid=0 INNER JOIN pg_class tbl ON d.refobjid = tbl.oid INNER JOIN pg_namespace nsp ON tbl.relnamespace=nsp.oid INNER JOIN pg_attribute da ON da.attrelid= d.refobjid AND da.attnum= d.refobjsubid WHERE LOWER(nsp.nspname)=LOWER(a_SchemaName) AND LOWER(tbl.relname)=LOWER(a_TableOID) AND tbl.relkind = 'r' AND pseq.relkind = 'S' ORDER BY pseq.relname; 


Remarque 7

.

Cette version de la fonction ne renvoie pas la dernière valeur générée par la séquence ( last_value ).

La fin de la remarque.


Fonction Admtf_Table_InheritanceChildrens - liste des caractéristiques des tables héritées


La fonction admtf_Table_InheritanceChildrens renvoie une liste des caractéristiques des tables héritées ( INHERITS ) de la table de base de données. Le code source peut être consulté et téléchargé ici .


En tant que paramètres, la fonction prend le nom de la table source ( a_TableName ) et le nom du schéma dans lequel la table est créée ( a_SchemaName ).


La description d'une table héritée unique se trouve dans l'entrée de pg_class . Mais pour rechercher des tables héritées par le nom de la table source, vous devez utiliser le catalogue système pg_depend .


Tableau 15. Attributs du répertoire pg_depend nécessaires pour implémenter la fonction.
Le titreLa description
objidOID de la table héritée dans le répertoire pg_class
refobjidOID de la table source


le code source de l'opérateur sur la figure
 SELECT rtbl.relname,rnspc.nspname,rdsc.description,rtbl.relnatts::INTEGER, rtbl.relchecks::INTEGER, rtbl.relhaspkey,rtbl.relhasindex,rtbl.relhassubclass, rtbl.reltuples::INTEGER FROM pg_class tbl INNER JOIN pg_namespace nspc ON tbl.relnamespace = nspc.oid LEFT OUTER JOIN pg_Description dsc ON tbl.oid=dsc.objoid AND dsc.objsubid=0 INNER JOIN pg_depend dp ON tbl.oid=dp.refobjid INNER JOIN pg_class rtbl ON rtbl.OID=dp.objid INNER JOIN pg_namespace rnspc ON rtbl.relnamespace = rnspc.oid LEFT OUTER JOIN pg_Description rdsc ON rtbl.oid=rdsc.objoid AND rdsc.objsubid=0 WHERE LOWER(nspc.nspname)=LOWER(a_SchemaName) AND LOWER(tbl.relname)=LOWER(a_TableOID) AND tbl.relkind = 'r' AND rtbl.relkind = 'r' ORDER BY rtbl.relname; 


De plus, la fonction accède aux données d'annuaire pg_namespace et pg_description afin d'extraire des schémas et des commentaires pour la table héritée et la table source.


Tableau 16. Résultat de l'exécution de la fonction admtf_Table_InheritanceChildrens ('public', 'np_house').

Le titreCommentaireAttributs? clé primaire? indices? descendantsNombre d'enregistrements
np_house 04201 000000Maisons dans les colonies (district d'Achinsky)15fff5651
np_house 4208 000 000Maisons dans les colonies (district de Bogotolsky)15fff4314

Le nombre d'enregistrements dans la table générée est sélectionné dans l'attribut reltuple du répertoire pg_class. Et bien que cette valeur corresponde souvent exactement au nombre réel d'entrées dans le tableau, il s'agit toujours d'une valeur estimée. Par conséquent, vous souhaiterez peut-être obtenir la valeur exacte en conséquence. Par exemple, comme le montre la figure.


 EXECUTE 'SELECT COUNT(*) FROM '||LOWER(a_SchemaName)||'.'||LOWER(a_TableName) INTO v_TableNumberOfRowCalc; 

Mais, tout d'abord, pour remplir cette déclaration dans le texte, la fonction admtf_Table_InheritanceChildrens devra utiliser un curseur.


Deuxièmement, je voudrais que la fonction affiche à la fois le nombre estimé et le nombre exact d'entrées de table.


Par conséquent, la fonction a un autre paramètre facultatif - le mode d'obtention du nombre d'entrées de table ( a_Mode ), qui prend les valeurs "estimation" ( estimation ) ou "exactement" ( exactement ).



En outre, la fonction admfn_Table_RowCount a été créée , qui renvoie le nombre exact d'entrées de table, et l'attribut reltuple est remplacé dans la liste de retour SELECT avec la construction suivante.



le code source de l'opérateur sur la figure
 CASE WHEN a_Mode = 'exactly' THEN admfn_Table_RowCount(rnspc.nspname,rtbl.relname) ELSE reltuples END 


Par conséquent, la fonction renvoie la valeur estimée de l'indicateur "nombre d'entrées de table" si le paramètre a_Mode ne spécifie pas l' obligation de renvoyer la valeur exacte.


Structure d'une fonction qui renvoie une liste de caractéristiques d'attribut de table



Fig. 3. Fonctions appelant admtf_Attribute_Features

version texte du tableau de la figure
Tableau 17. Objectif des fonctions.

Non.Le titreRendez-vous
1admtf_Attribute_PKFeaturesLa fonction renvoie l'attribut de présence d'attribut dans la clé primaire (PRIMARY KEY), ainsi que certaines de ses caractéristiques dans le cadre de cette clé.
2admtf_Attribute_FKFeaturesLa fonction renvoie l'attribut de présence d'attribut dans la clé étrangère (FOREIGN KEY), ainsi que certaines de ses caractéristiques dans le cadre de cette clé.
3admtf_Attribute_FeaturesLa fonction renvoie une liste de caractéristiques d'attribut de table.


Fonction admtf_Attribute_PKFeatures - - si l'attribut est présent dans la clé primaire



La fonction admtf_Attribute_PKFeatures renvoie un signe de la présence d'un attribut de table dans la clé primaire (PRIMARY KEY) de la table, et s'il est présent, quel est son numéro de série dans cette clé, car la clé primaire peut être composite.
Le code source peut être consulté et téléchargé ici .


En tant que paramètres, la fonction prend l'OID de la table source ( a_TableOID ) et le numéro de série de l'attribut souhaité ( a_AttributeNo ).


La fonction extrait les données requises de l' entrée de répertoire pg_constraint contenant les contraintes (CONSTRAINT) de la table source, y compris la contrainte de clé primaire. L'OID de la table souhaitée est stocké dans le champ conrelid , la description de la clé primaire est stockée dans un enregistrement dans lequel le champ contype contient la valeur '' p ''

.
 SELECT INTO v_PKAttributeList,rs_isAttributePK conkey,ARRAY[a_AttributeNo]<@conkey FROM pg_constraint c WHERE c.contype='p' AND c.conrelid=a_TableOID; 

Le champ conkey , trouvé de cette manière, contient un tableau de numéros d'attribut qui constituent la clé primaire. Par conséquent, afin de vérifier la présence de l'attribut source dans la clé primaire, il suffit de calculer l'expression logique ARRAY [a_AttributeNo] <@ conkey .


Si l'attribut est présent dans la clé primaire, son numéro de séquence est calculé dans la boucle.


Fonction admtf_Attribute_FKFeatures - si l'attribut est présent dans la clé étrangère



La fonction admtf_Attribute_FKFeatures renvoie un signe de la présence d'un attribut de table dans une ou plusieurs clés étrangères (FOREIGN KEY) de la table, et s'il est présent, quels sont ses numéros de séquence dans ces clés, car la clé étrangère peut être composite.

Le code source peut être consulté et téléchargé ici .


En tant que paramètres, la fonction prend l'OID de la table source ( a_TableOID ) et le numéro de série de l'attribut souhaité ( a_AttributeNo ).


La fonction récupère les données requises à partir de l' entrée de répertoire pg_constraint contenant la CONSTRAINT de la table source, y compris, mais sans s'y limiter, les contraintes de clé étrangère. L'OID de la table souhaitée est stocké dans le champ conrelid , la description de la clé primaire est stockée dans un enregistrement dans lequel le champ contype contient la valeur '' f ''

.
 SELECT * FROM pg_constraint c WHERE c.contype='f ' AND c.conrelid=a_TableOID AND ARRAY[a_AttributeNo]<@conkey ORDER BY c.oid; 

Le champ conkey , trouvé de cette manière, contient un tableau de numéros d'attribut qui composent la clé étrangère. Par conséquent, afin de vérifier la présence de l'attribut source dans la clé étrangère, il suffit de calculer l'expression logique ARRAY [a_AttributeNo] <@ conkey .


Si l'attribut est présent dans la clé étrangère, alors dans la boucle un tableau de ses numéros de séquence est formé dans les clés étrangères qui le contiennent. En outre, deux tableaux supplémentaires sont formés à partir des noms des tables et de leurs attributs, qui sont référencés par l'attribut source dans les clés étrangères qui le contiennent.


Les noms de table sont extraits de l' entrée de répertoire pg_class par identifiant (OID) extrait du champ confrelid de l'entrée de clé étrangère.


Pour obtenir le nom de l'attribut de la table externe, utilisez un tableau de numéros de série dans le champ

confkey

(il diffère du tableau ci-dessus par la lettre « f » dans le nom). Le numéro de série de l'attribut de la table externe à laquelle l'attribut externe correspond est extrait de ce tableau. Par ce numéro de série de l'attribut de la table externe et de son OID, situé dans le répertoire pg_attribute, il y a une entrée pour la description de l'attribut et son nom est récupéré.

Fonction Admtf_Attribute_Features - liste des caractéristiques des attributs de table


Les fonctions admtf_Attribute_Features renvoient une liste des caractéristiques d'attribut de table suivantes. Le code source peut être consulté et téléchargé ici .



La version texte du tableau de la figure
Non.Le titreTapezRendez-vous
1AttributeNamenomLe nom de l'attribut source.
2UserTypeNameVARCHAR (256)Type d'attribut source personnalisé
3Nom de typeVARCHAR (256)Type de base de l'attribut source
4isNotNULLBOOLEAN? Validité nulle
5isAttributePKBOOLEAN? participation à PK
6ColumnPKNoSMALLINTAttribuer le numéro de série dans PK
7La descriptionTEXTECommentaire sur l'attribut source
8isAttributeFKBOOLEAN? participation à FK
9FKeyNamenom []Un tableau de noms de table de contraintes dans lequel la clé étrangère est définie
10ColumnFKNoSMALLINT []Tableau de numéros de séquence d'attributs dans les clés étrangères d'une table
11FKTableNamenom []Tableau de tables référencées par des clés étrangères
12FKTableColumnNamenom []Tableau de noms d'attributs dans des tables externes correspondant à l'attribut source


En tant que paramètres, la fonction prend l'OID de la table source ( a_TableOID ) et le numéro de série de l'attribut souhaité ( a_AttributeNo ).
Les valeurs des champs AttributeName et isNotNULL sont extraites de l' entrée de répertoire pg_attribute correspondant aux valeurs des paramètres d'entrée.


 SELECT attr.attname, attr.attnotnull FROM pg_attribute attr WHERE attr.attrelid =a_TableOID AND attr.attnum=a_AttributeNo; SELECT rs_isAttributePK,rs_ColumnPKNo FROM admtf_Attribute_PKFeatures (a_TableOID,a_AttributeNo); SELECT rs_isAttributeFK,rs_FKeyName,rs_ColumnFKNo, rs_FKTableName,rs_FKTableColumnName FROM admtf_Attribute_FKFeatures (a_TableOID,a_AttributeNo); 

Les valeurs des champs isAttributePK et ColumnPKNo sont renvoyées par la fonction admtf_Attribute_PKFeatures .


Les valeurs des champs isAttributeFK , FKeyName , ColumnFKNo , FKTableName , FKTableColumnName sont renvoyées par la fonction admtf_Attribute_FKFeatures .


Un appel à admtf_Attribute_Features ((SELECT OID FROM pg_class WHERE relname = 'street'), 2 :: SMALLINT) produira le résultat suivant.


Tableau 18. Résultat de l'exécution de la fonction admtf_Attribute_Features
AttributeNameUserTypeNameNom de typeisNotNULLisAttributePKColumnPKNo
localityidlocalityidentierentierentierentier


La descriptionisAttributeFKFKeyNameColumnFKNoFKTableNameFKTableColumnName
ID de communautét{fk_street_locality}{2}{localité}{localityid}

ANNEXE 1. Scripts


Création de la fonction admtf_Sequence_Features


Vous trouverez des commentaires sur le code source de la fonction ici.
code de fonction
 BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Sequence_Features (a_SchemaName NAME,a_SequenceName NAME); /****************************************************************************/ /*     ,   */ /****************************************************************************/ CREATE OR REPLACE FUNCTION admtf_Sequence_Features (a_SchemaName NAME default 'public', /*     */ a_SequenceName NAME default NULL /*   */ ) RETURNS TABLE (rs_SequenceName NAME,rs_SequenceDescription TEXT,rs_NumberOfAttribute INTEGER,rs_SequenceLastValue BIGINT, rs_SequenceStartValue BIGINT,rs_SequenceIncrementBy BIGINT,rs_SequenceMaxValue BIGINT) AS $BODY$ DECLARE c_SequenceKind CONSTANT CHAR:='S'; v_SequenceOID OID; /*   */ v_SequenceName NAME; /*   */ v_SequenceDescription TEXT; /*   */ v_SequenceStartValue BIGINT; /*    */ v_SequenceIncrementBy BIGINT; /*   */ v_SequenceMaxValue BIGINT; /*    */ v_SequenceLastValue BIGINT; /*    */ v_SequenceNumberOfRowCalc INTEGER; /*     */ --************************************************************************ BEGIN SELECT INTO rs_SequenceName,rs_SequenceDescription,rs_NumberOfAttribute tbl.relname, COALESCE(dsc.description,'') AS r_SequenceDescription, tbl.relnatts::INTEGER,tbl.relchecks::INTEGER,tbl.relhaspkey, tbl.relhasindex,tbl.relhassubclass,tbl.reltuples::INTEGER FROM pg_class tbl INNER JOIN pg_namespace nspc ON tbl.relnamespace = nspc.oid LEFT OUTER JOIN pg_Description dsc ON tbl.oid=dsc.objoid AND dsc.objsubid=0 WHERE nspc.nspname=LOWER(a_SchemaName) AND tbl.relkind=c_SequenceKind AND tbl.relname =LOWER(a_SequenceName); IF FOUND THEN EXECUTE 'SELECT last_value,start_value,increment_by,max_value FROM '||LOWER(a_SchemaName)||'.'||LOWER(a_SequenceName) INTO v_SequenceLastValue,v_SequenceStartValue, v_SequenceIncrementBy,v_SequenceMaxValue ; RETURN QUERY SELECT rs_SequenceName,rs_SequenceDescription, rs_NumberOfAttribute,v_SequenceLastValue, v_SequenceStartValue,v_SequenceIncrementBy, v_SequenceMaxValue; END IF; RETURN; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Sequence_Features(a_SchemaName NAME,a_SequenceName NAME) IS '    ,  '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Sequence_Features (a_SchemaName VARCHAR(256),a_SequenceName VARCHAR(256)); /****************************************************************************/ /*     ,   */ /****************************************************************************/ CREATE OR REPLACE FUNCTION admtf_Sequence_Features (a_SchemaName VARCHAR(256) default 'public', /*     */ a_SequenceName VARCHAR(256) default NULL /*   */ ) RETURNS TABLE (rs_SequenceName VARCHAR(256),rs_SequenceDescription TEXT, rs_NumberOfAttribute INTEGER,rs_SequenceLastValue BIGINT, rs_SequenceStartValue BIGINT,rs_SequenceIncrementBy BIGINT, rs_SequenceMaxValue BIGINT) AS $BODY$ DECLARE c_SequenceKind CONSTANT CHAR:='S'; --******************************************************** BEGIN RETURN QUERY SELECT sf.rs_SequenceName::VARCHAR(256), sf.rs_SequenceDescription::TEXT, sf.rs_NumberOfAttribute::INTEGER, sf.rs_SequenceLastValue::BIGINT, sf.rs_SequenceStartValue::BIGINT, sf.rs_SequenceIncrementBy::BIGINT, sf.rs_SequenceMaxValue::BIGINT FROM admtf_Sequence_Features(a_SchemaName::NAME,a_SequenceName::NAME) sf; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Sequence_Features(a_SchemaName VARCHAR(256),a_SequenceName VARCHAR(256)) IS '    ,  '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; SELECT * FROM admtf_Sequence_Features('public'::VARCHAR(255),'k_dorogi_dijkstra_seq_seq'::VARCHAR(255)); SELECT * FROM admtf_Sequence_Features('public'::NAME,'kr_road_network_vertices_pgr_id_seq'::NAME); 



Création de la fonction admtf_Table_Sequences


Vous trouverez des commentaires sur le code source de la fonction ici.
code de fonction
 BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Table_Sequences (a_SchemaName NAME, a_TableName NAME); /*********************************************************************/ /*    ,     */ /*********************************************************************/ CREATE OR REPLACE FUNCTION admtf_Table_Sequences (a_SchemaName NAME default 'public', /*     */ a_TableName NAME default NULL /*   */ ) RETURNS TABLE (r_SequenceNumber SMALLINT,r_SequenceName NAME, r_SequenceSchemaName NAME,r_SequenceDescription TEXT, r_SequenceStartValue BIGINT,r_SequenceIncrementBy BIGINT, r_SequenceMaxValue BIGINT,r_DependType NAME, r_RefTableName NAME,r_RefTableSchemaName NAME, r_RefAttributeName NAME) AS $BODY$ DECLARE v_TableOID INTEGER;/* OID */ v_Sequence RECORD;/*   */ v_SequenceOID INTEGER;/* OID */ v_SequenceName NAME; /*   */ v_SequenceSchemaName NAME; /*    */ v_SequenceDescription TEXT; /*   */ v_SequenceStartValue BIGINT; /*    */ v_SequenceIncrementBy BIGINT; /*   */ v_SequenceMaxValue BIGINT; /*    */ v_DependcyType NAME; /*     */ /*    */ v_AttributeName NAME; /*  */ v_SequenceNumber SMALLINT; /*   */ c_Delimiter CONSTANT VARCHAR(2):=','; --********************************************************************* BEGIN v_SequenceNumber:=0; FOR v_Sequence IN SELECT pseq.relname AS SequenceName, snsp.nspname AS SequenceSchemaName, COALESCE(dsc.description,',    '||da.attname) AS SequenceDescription, d.depType AS DependcyType,da.attname AS AttributeName FROM pg_depend d INNER JOIN pg_class pseq ON d.objid = pseq.oid INNER JOIN pg_namespace snsp ON pseq.relnamespace=snsp.oid LEFT OUTER JOIN pg_Description dsc ON pseq.oid=dsc.objoid AND dsc.objsubid=0 INNER JOIN pg_class tbl ON d.refobjid = tbl.oid INNER JOIN pg_namespace nsp ON tbl.relnamespace=nsp.oid INNER JOIN pg_attribute da ON da.attrelid= d.refobjid AND d.refobjsubid=da.attnum WHERE tbl.relkind = 'r' AND pseq.relkind = 'S' AND LOWER(nsp.nspname)=LOWER(a_SchemaName) AND LOWER(tbl.relname)=LOWER(a_TableName) ORDER BY pseq.relname LOOP v_SequenceNumber:=v_SequenceNumber+1; v_SequenceName:=v_Sequence.SequenceName; v_SequenceSchemaName:=v_Sequence.SequenceSchemaName; v_DependcyType:=v_Sequence.DependcyType; v_AttributeName:=v_Sequence.AttributeName; v_SequenceDescription:=v_Sequence.SequenceDescription; SELECT INTO v_SequenceStartValue,v_SequenceIncrementBy, v_SequenceMaxValue rs_SequenceStartValue,rs_SequenceIncrementBy, rs_SequenceMaxValue FROM admtf_Sequence_Features(v_SequenceSchemaName,v_SequenceName); RETURN QUERY SELECT v_SequenceNumber,v_SequenceName, v_SequenceSchemaName,v_SequenceDescription, v_SequenceStartValue,v_SequenceIncrementBy, v_SequenceMaxValue,v_DependcyType, a_TableName,a_SchemaName,v_AttributeName; END LOOP; RETURN; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Table_Sequences(a_SchemaName NAME, a_TableName NAME) IS '  ,    '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Table_Sequences (a_SchemaName VARCHAR(256), a_TableName VARCHAR(256)); /**********************************************************************/ /*    ,     */ /**********************************************************************/ CREATE OR REPLACE FUNCTION admtf_Table_Sequences (a_SchemaName VARCHAR(256) default 'public', /*     */ a_TableName VARCHAR(256) default NULL /*   */ ) RETURNS TABLE (r_SequenceNumber SMALLINT,r_SequenceName VARCHAR(256), r_SequenceSchemaName VARCHAR(256),r_SequenceDescription TEXT, r_SequenceStartValue BIGINT,r_SequenceIncrementBy BIGINT, r_SequenceMaxValue BIGINT,r_DependType VARCHAR(256), r_RefTableName VARCHAR(256),r_RefTableSchemaName VARCHAR(256), r_RefAttributeName VARCHAR(256)) AS $BODY$ DECLARE c_Delimiter CONSTANT VARCHAR(2):=','; --****************************************************** BEGIN RETURN QUERY SELECT ts.r_SequenceNumber::SMALLINT, ts.r_SequenceName::VARCHAR(256), ts.r_SequenceSchemaName::VARCHAR(256) , ts.r_SequenceDescription::TEXT, ts.r_SequenceStartValue::BIGINT, ts.r_SequenceIncrementBy::BIGINT, ts.r_SequenceMaxValue::BIGINT, ts.r_DependType::VARCHAR(256), ts.r_RefTableName::VARCHAR(256), ts.r_RefTableSchemaName::VARCHAR(256), ts.r_RefAttributeName::VARCHAR(256) FROM admtf_Table_Sequences(a_SchemaName::NAME,a_TableName::NAME) ts; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Table_Sequences(a_SchemaName VARCHAR(256), a_TableName VARCHAR(256)) IS '  ,    '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; SELECT * FROM admtf_Table_Sequences('public'::VARCHAR(255),'kr_road_network_vertices_pgr'::VARCHAR(255)); SELECT * FROM admtf_Table_Sequences('public'::NAME,'kr_road_network_vertices_pgr'::NAME); 


admtf_Table_Sequences (PostgreSQL 10)


.
 BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Table_Sequences (a_SchemaName NAME, a_TableName NAME); /*********************************************************************/ /*    ,     */ /**********************************************************************/ CREATE OR REPLACE FUNCTION admtf_Table_Sequences (a_SchemaName NAME default 'public', /*     */ a_TableName NAME default NULL /*   */ ) RETURNS TABLE (r_SequenceNumber SMALLINT,r_SequenceName NAME, r_SequenceSchemaName NAME,r_SequenceDescription TEXT, r_SequenceStartValue BIGINT,r_SequenceIncrementBy BIGINT, r_SequenceMaxValue BIGINT,r_DependType NAME, r_RefTableName NAME,r_RefTableSchemaName NAME, r_RefAttributeName NAME) AS $BODY$ DECLARE v_TableOID INTEGER; /* OID */ v_Sequence RECORD; /*   */ v_SequenceOID INTEGER; /* OID */ v_SequenceName NAME; /*   */ v_SequenceSchemaName NAME; /*    */ v_SequenceDescription TEXT; /*   */ v_SequenceStartValue BIGINT; /*    */ v_SequenceIncrementBy BIGINT; /*   */ v_SequenceMaxValue BIGINT; /*    */ v_DependcyType NAME; /*        */ v_AttributeName NAME; /*  */ v_SequenceNumber SMALLINT; /*   */ c_Delimiter CONSTANT VARCHAR(2):=','; --****************************************************************** BEGIN v_SequenceNumber:=0; FOR v_Sequence IN SELECT pseq.relname AS SequenceName, snsp.nspname AS SequenceSchemaName, COALESCE(dsc.description,',    '||da.attname) AS SequenceDescription, d.depType AS DependcyType,da.attname AS AttributeName FROM pg_depend d INNER JOIN pg_class pseq ON d.objid = pseq.oid INNER JOIN pg_namespace snsp ON pseq.relnamespace=snsp.oid LEFT OUTER JOIN pg_Description dsc ON pseq.oid=dsc.objoid AND dsc.objsubid=0 INNER JOIN pg_class tbl ON d.refobjid = tbl.oid INNER JOIN pg_namespace nsp ON tbl.relnamespace=nsp.oid INNER JOIN pg_attribute da ON da.attrelid= d.refobjid ND d.refobjsubid=da.attnum WHERE tbl.relkind = 'r' AND pseq.relkind = 'S' AND LOWER(nsp.nspname)=LOWER(a_SchemaName) AND LOWER(tbl.relname)=LOWER(a_TableName) ORDER BY pseq.relname LOOP v_SequenceNumber:=v_SequenceNumber+1; v_SequenceName:=v_Sequence.SequenceName; v_SequenceSchemaName:=v_Sequence.SequenceSchemaName; v_DependcyType:=v_Sequence.DependcyType; v_AttributeName:=v_Sequence.AttributeName; v_SequenceDescription:=v_Sequence.SequenceDescription; SELECT INTO v_SequenceStartValue,v_SequenceIncrementBy,v_SequenceMaxValue rs_SequenceStartValue,rs_SequenceIncrementBy,rs_SequenceMaxValue FROM admtf_Sequence_Features(v_SequenceSchemaName,v_SequenceName); RETURN QUERY SELECT v_SequenceNumber,v_SequenceName, v_SequenceSchemaName,v_SequenceDescription, v_SequenceStartValue,v_SequenceIncrementBy, v_SequenceMaxValue,v_DependcyType, a_TableName,a_SchemaName,v_AttributeName; END LOOP; RETURN; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Table_Sequences(a_SchemaName NAME, a_TableName NAME) IS '  ,    '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Table_Sequences (a_SchemaName VARCHAR(256), a_TableName VARCHAR(256)); /**********************************************************************/ /*    ,     */ /**********************************************************************/ CREATE OR REPLACE FUNCTION admtf_Table_Sequences (a_SchemaName VARCHAR(256) default 'public', /*     */ a_TableName VARCHAR(256) default NULL /*   */ ) RETURNS TABLE (r_SequenceNumber SMALLINT,r_SequenceName VARCHAR(256), r_SequenceSchemaName VARCHAR(256),r_SequenceDescription TEXT, r_SequenceStartValue BIGINT,r_SequenceIncrementBy BIGINT, r_SequenceMaxValue BIGINT,r_DependType VARCHAR(256), r_RefTableName VARCHAR(256),r_RefTableSchemaName VARCHAR(256), r_RefAttributeName VARCHAR(256)) AS $BODY$ DECLARE c_Delimiter CONSTANT VARCHAR(2):=','; --******************************************************* BEGIN RETURN QUERY SELECT ts.r_SequenceNumber::SMALLINT, ts.r_SequenceName::VARCHAR(256), ts.r_SequenceSchemaName::VARCHAR(256), ts.r_SequenceDescription::TEXT, ts.r_SequenceStartValue::BIGINT, ts.r_SequenceIncrementBy::BIGINT, ts.r_SequenceMaxValue::BIGINT, ts.r_DependType::VARCHAR(256), ts.r_RefTableName::VARCHAR(256), ts.r_RefTableSchemaName::VARCHAR(256), ts.r_RefAttributeName::VARCHAR(256) FROM admtf_Table_Sequences(a_SchemaName::NAME,a_TableName::NAME) ts; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Table_Sequences(a_SchemaName VARCHAR(256), a_TableName VARCHAR(256)) IS '  ,    '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; SELECT * FROM admtf_Table_Sequences('public'::VARCHAR(255), 'kr_road_network_vertices_pgr'::VARCHAR(255)); SELECT * FROM admtf_Table_Sequences('public'::NAME, 'kr_road_network_vertices_pgr'::NAME); 



admfn_Table_RowCount


.
 BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admfn_Table_RowCount (a_SchemaName NAME,a_TableName NAME); /******************************************************/ /*       */ /******************************************************/ CREATE OR REPLACE FUNCTION admfn_Table_RowCount (a_SchemaName NAME default 'public',/*     */ a_TableName NAME default NULL /*   */ ) RETURNS BIGINT AS $BODY$ DECLARE v_TableNumberOfRowCalc BIGINT; /*  */ v_Found BOOLEAN; --*********************************************************** BEGIN IF a_SchemaName ~ E'^[a-z_0-9]+$' AND a_TableName ~ E'^[a-z_0-9]+$' THEN EXECUTE 'SELECT count(*) FROM ' ||a_SchemaName ||'.'|| a_TableName INTO v_TableNumberOfRowCalc; ELSE SELECT INTO v_Found true FROM pg_class tbl INNER JOIN pg_namespace nspc ON tbl.relnamespace = nspc.oid WHERE tbl.relkind='r' AND tbl.relname=a_TableName AND nspc.nspname=a_SchemaName; IF FOUND THEN EXECUTE 'SELECT count(*) FROM ' || CASE WHEN a_SchemaName ~ E'^[a-z_0-9]+$' THEN a_SchemaName ELSE quote_ident(a_SchemaName) END ||'.'|| CASE WHEN a_TableName ~ E'^[a-z_0-9]+$' THEN a_TableName ELSE quote_ident(a_TableName) END INTO v_TableNumberOfRowCalc; ELSE SELECT INTO v_Found true FROM pg_class tbl INNER JOIN pg_namespace nspc ON tbl.relnamespace = nspc.oid WHERE tbl.relkind='r' AND LOWER(tbl.relname)= LOWER(a_TableName) AND nspc.nspname=LOWER(a_SchemaName); IF FOUND THEN EXECUTE 'SELECT count(*) FROM ' || a_SchemaName ||'.'||a_TableName INTO v_TableNumberOfRowCalc; END IF; END IF; END IF; RETURN v_TableNumberOfRowCalc; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admfn_Table_RowCount(a_SchemaName NAME,a_TableName NAME) IS '    '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION;BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admfn_Table_RowCount (a_SchemaName VARCHAR(256),a_TableName VARCHAR(256)); /********************************************************************/ /*       */ /********************************************************************/ CREATE OR REPLACE FUNCTION admfn_Table_RowCount (a_SchemaName VARCHAR(256) default 'public',/*     */ a_TableName VARCHAR(256) default NULL /*   */ ) RETURNS BIGINT AS $BODY$ DECLARE v_TableNumberOfRowCalc BIGINT; /*  */ --********************************************************* BEGIN RETURN admfn_Table_RowCount(a_SchemaName::NAME,a_TableName::NAME); END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admfn_Table_RowCount(a_SchemaName VARCHAR(256),a_TableName VARCHAR(256)) IS '    '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; SELECt admfn_Table_RowCount('public'::NAME,'Street'::NAME); SELECt admfn_Table_RowCount('public'::VARCHAR(256),'Street'::VARCHAR(256)); 


admtf_Table_InheritanceChildrens


.
 BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Table_InheritanceChildrens (a_SchemaName NAME,a_TableName NAME,a_Mode VARCHAR(10)); /************************************************************/ /*       */ /************************************************************/ CREATE OR REPLACE FUNCTION admtf_Table_InheritanceChildrens (a_SchemaName NAME default 'public', /*     */ a_TableName NAME default NULL, /*   */ a_Mode VARCHAR(10) default 'estimate' /*     */ ) RETURNS TABLE (rs_TableName NAME,rs_TableDescription TEXT, rs_NumberOfAttribute INTEGER,rs_NumberOfChecks INTEGER, rs_hasPKey BOOLEAN,rs_hasIndex BOOLEAN, rs_hasSubClass BOOLEAN,rs_NumberOfRow INTEGER) AS $BODY$ DECLARE c_TableKind CONSTANT CHAR:='r'; c_ExactlyMode CONSTANT VARCHAR(10):='exactly'; c_EstimateMode CONSTANT VARCHAR(10):='estimate'; v_TableOID OID; /*   */ v_SchemaName NAME; /*    */ v_TableName NAME; /*   */ v_TableDescription TEXT; /*   */ v_TableNumberOfRowCalc INTEGER; /*     */ v_InheritanceRECORD RECORD; /*    */ v_InheritanceOID OID; /*    */ BEGIN RETURN QUERY SELECT rtbl.relname,rdsc.description,rtbl.relnatts::INTEGER, rtbl.relchecks::INTEGER,rtbl.relhaspkey,rtbl.relhasindex, rtbl.relhassubclass, CASE WHEN a_Mode=c_ExactlyMode THEN admfn_Table_RowCount(rnspc.nspname,rtbl.relname)::INTEGER ELSE rtbl.reltuples::INTEGER END FROM pg_class tbl INNER JOIN pg_namespace nspc ON tbl.relnamespace = nspc.oid LEFT OUTER JOIN pg_Description dsc ON tbl.oid=dsc.objoid AND dsc.objsubid=0 INNER JOIN pg_depend dp ON tbl.oid=dp.refobjid INNER JOIN pg_class rtbl ON rtbl.OID=dp.objid INNER JOIN pg_namespace rnspc ON rtbl.relnamespace = rnspc.oid LEFT OUTER JOIN pg_Description rdsc ON rtbl.oid=rdsc.objoid AND rdsc.objsubid=0 WHERE nspc.nspname=LOWER(a_SchemaName) AND tbl.relkind=c_TableKind AND rtbl.relkind=c_TableKind AND tbl.relname =LOWER(a_TableName) ORDER BY rtbl.relname; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Table_InheritanceChildrens(a_SchemaName NAME,a_TableName NAME,a_Mode VARCHAR(10)) IS '    '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Table_InheritanceChildrens (a_SchemaName VARCHAR(256),a_TableName VARCHAR(256),a_TableName NAME,a_Mode VARCHAR(10)); /************************************************************************/ /*       */ /************************************************************************/ CREATE OR REPLACE FUNCTION admtf_Table_InheritanceChildrens (a_SchemaName VARCHAR(256) default 'public',/*     */ a_TableName VARCHAR(256) default NULL,/*   */ a_Mode VARCHAR(10) default 'estimate' /*     */ ) RETURNS TABLE (rs_TableName VARCHAR(256),rs_TableDescription TEXT, rs_NumberOfAttribute INTEGER,rs_NumberOfChecks INTEGER, rs_hasPKey BOOLEAN,rs_hasIndex BOOLEAN, rs_hasSubClass BOOLEAN,rs_NumberOfRow INTEGER) AS $BODY$ DECLARE c_TableKind CONSTANT CHAR:='r'; BEGIN RETURN QUERY SELECT tic.rs_TableName::VARCHAR(256),tic.rs_TableDescription::TEXT, tic.rs_NumberOfAttribute::INTEGER,tic.rs_NumberOfChecks::INTEGER, tic.rs_hasPKey::BOOLEAN,tic.rs_hasIndex::BOOLEAN, tic.rs_hasSubClass::BOOLEAN,tic.rs_NumberOfRow::INTEGER FROM admtf_Table_InheritanceChildrens(a_SchemaName::NAME, a_TableName::NAME,a_Mode::VARCHAR(10)) tic; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Table_InheritanceChildrens(a_SchemaName VARCHAR(256),a_TableName VARCHAR(256),a_Mode VARCHAR(10)) IS '    '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; SELECT * FROM admtf_Table_InheritanceChildrens('public'::NAME,'np_house'::NAME); SELECT * FROM admtf_Table_InheritanceChildrens('public'::VARCHAR(256),'np_house'::VARCHAR(256)); 


admtf_Attribute_PKFeatures


.
 BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Attribute_PKFeatures (a_TableOID OID,a_AttributeNo SMALLINT); /***************************************************************************/ /*        . */ /*   ,          */ /*   */ /***************************************************************************/ CREATE OR REPLACE FUNCTION admtf_Attribute_PKFeatures (a_TableOID OID, /*   */ a_AttributeNo SMALLINT /*     */ ) RETURNS TABLE (rs_isAttributePK BOOLEAN,rs_PKeyName name,rs_ColumnPKNo SMALLINT) AS $BODY$ DECLARE C_PKAttributeList_NDims CONSTANT INTEGER:=1; /*     */ v_PKAttributeList SMALLINT[]; /*       */ v_PKAttributeIndx INTEGER; /*      */ v_PKAttributeLBound INTEGER; /*      */ v_PKAttributeUBound INTEGER; /*      */ --********************************************************************** BEGIN rs_isAttributePK:=false; rs_ColumnPKNo:=NULL; SELECT INTO rs_PKeyName,v_PKAttributeList,rs_isAttributePK conname,conkey,ARRAY[a_AttributeNo]<@conkey FROM pg_constraint c WHERE c.contype='p' and c.conrelid=a_TableOID; IF FOUND AND rs_isAttributePK THEN --      v_PKAttributeLBound:=array_lower(v_PKAttributeList,C_PKAttributeList_NDims); v_PKAttributeUBound:=array_upper(v_PKAttributeList,C_PKAttributeList_NDims); v_PKAttributeIndx:=v_PKAttributeLBound; WHILE v_PKAttributeIndx <= v_PKAttributeUBound AND a_AttributeNo<>v_PKAttributeList[v_PKAttributeIndx] LOOP v_PKAttributeIndx:=v_PKAttributeIndx+1; END LOOP; IF v_PKAttributeIndx<=v_PKAttributeUBound THEN rs_ColumnPKNo:=v_PKAttributeIndx; END IF; END IF; RETURN QUERY SELECT rs_isAttributePK,rs_PKeyName,rs_ColumnPKNo; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Attribute_PKFeatures(a_TableOID OID,a_AttributeNo SMALLINT) IS '              '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; SELECT * FROM admtf_Attribute_PKFeatures((SELECT OID FROM pg_class WHERE relname='street'),3::SMALLINT); 


admtf_Attribute_FKFeatures


.
 BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Attribute_FKFeatures (a_TableOID OID,a_AttributeNo SMALLINT); /****************************************************************************/ /*        . */ /*   ,         */ /*   . */ /****************************************************************************/ /****************************************************************************/ CREATE OR REPLACE FUNCTION admtf_Attribute_FKFeatures (a_TableOID OID, /*   */ a_AttributeNo SMALLINT /*     */ ) RETURNS TABLE (rs_isAttributeFK BOOLEAN,rs_FKeyName name[],rs_ColumnFKNo SMALLINT[],rs_FKTableName name[],rs_FKTableColumnName name[]) AS $BODY$ DECLARE C_FKAttributeList_NDims CONSTANT INTEGER:=1; /*     */ v_FKAttributeList SMALLINT[]; /*       */ v_RefAttributeList SMALLINT[]; /*     , */ /*     */ v_FKAttributeIndx INTEGER; /*      */ v_RefAttributeListIndx INTEGER; /*     , */ /*     */ v_FKAttributeLBound INTEGER; /*      */ v_FKAttributeUBound INTEGER; /*      */ v_FKConstraintIndx INTEGER; /*     */ v_FKeyName name; /*   , */ /*     */ v_FKTableName name; /*  ,     */ v_FKTableColumnName name; /*    , */ /*     */ v_RefAttributeNo SMALLINT; /*     , */ /*     */ v_Constraint pg_constraint%ROWTYPE; /*     */ /*  (CONSTRANT) */ --****************************************************************************************************** BEGIN rs_isAttributeFK:=false; rs_ColumnFKNo:=NULL; v_FKConstraintIndx:=0; FOR v_Constraint IN SELECT * FROM pg_constraint c WHERE c.contype='f' and c.conrelid=a_TableOID AND ARRAY[a_AttributeNo]<@conkey ORDER BY c.oid LOOP v_FKConstraintIndx:=v_FKConstraintIndx+1; rs_isAttributeFK:=true; v_FKeyName:=v_Constraint.conname; v_FKAttributeList:=v_Constraint.conkey; v_RefAttributeList:=v_Constraint.confkey; v_FKAttributeLBound:=array_lower(v_FKAttributeList,C_FKAttributeList_NDims); v_FKAttributeUBound:=array_upper(v_FKAttributeList,C_FKAttributeList_NDims); v_FKAttributeIndx:=v_FKAttributeLBound; WHILE v_FKAttributeIndx <= v_FKAttributeUBound AND a_AttributeNo<>v_FKAttributeList[v_FKAttributeIndx] LOOP v_FKAttributeIndx:=v_FKAttributeIndx+1; END LOOP; rs_FKeyName[v_FKConstraintIndx]:=v_FKeyName; rs_ColumnFKNo[v_FKConstraintIndx]:=v_FKAttributeIndx; SELECT INTO v_FKTableName ftbl.relname FROM pg_class ftbl WHERE ftbl.oid=v_Constraint.confrelid; rs_FKTableName[v_FKConstraintIndx]:=v_FKTableName; v_RefAttributeNo:=v_RefAttributeList[v_FKAttributeIndx]; v_FKTableColumnName:=NULL; SELECT INTO v_FKTableColumnName attname FROM pg_attribute a WHERE a.attrelid=v_Constraint.confrelid AND a.attnum=v_RefAttributeNo; rs_FKTableColumnName[v_FKConstraintIndx]:=v_FKTableColumnName; END LOOP; RETURN QUERY SELECT rs_isAttributeFK,rs_FKeyName,rs_ColumnFKNo, rs_FKTableName,rs_FKTableColumnName; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Attribute_FKFeatures(a_TableOID OID,a_AttributeNo SMALLINT) IS '              '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; SELECT * FROM admtf_Attribute_FKFeatures((SELECT OID FROM pg_class WHERE relname='street'),4::SMALLINT); 



admtf_Attribute_Features


.
 BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Attribute_Features (a_TableOID OID,a_AttributeNo SMALLINT); /****************************************************************************/ /*      */ /****************************************************************************/ CREATE OR REPLACE FUNCTION admtf_Attribute_Features (a_TableOID OID, /*   */ a_AttributeNo SMALLINT/*     */ ) RETURNS TABLE (rsa_AttributeName name,rsa_UserTypeName VARCHAR(256),rsa_TypeName VARCHAR(256),rsa_isNotNULL BOOLEAN,rsa_isAttributePK BOOLEAN, rsa_ColumnPKNo SMALLINT,rsa_Description Text,rsa_isAttributeFK BOOLEAN,rsa_FKeyName name[],rsa_ColumnFKNo SMALLINT[],rsa_FKTableName name[],rsa_FKTableColumnName name[]) AS $BODY$ DECLARE v_Return_Error Integer := 0; /*  */ --********************************************************************* BEGIN SELECT INTO rsa_AttributeName,rsa_UserTypeName,rsa_TypeName, rsa_isNotNULL,rsa_Description attr.attname, CASE WHEN COALESCE(typ.typbasetype,0)>0 THEN typ.typname::VARCHAR(100) ELSE ''END AS r_UserTypeName, FORMAT_TYPE(COALESCE(NULLIF(typ.typbasetype,0),typ.oid), COALESCE(NULLIF(typ.typtypmod,-1),attr.atttypmod))::VARCHAR(256) AS r_TypeName, attr.attnotnull AS r_isNotNULL, dsc.description AS r_Description FROM pg_attribute attr LEFT OUTER JOIN pg_type typ ON attr.atttypid=typ.oid LEFT OUTER JOIN pg_type btyp ON typ.typbasetype=btyp.oid LEFT OUTER JOIN pg_description dsc ON dsc.objoid=attr.attrelid AND dsc.objsubid=attr.attnum WHERE attr.attrelid =a_TableOID AND attr.attnum=a_AttributeNo; SELECT INTO rsa_isAttributePK,rsa_ColumnPKNo rs_isAttributePK,rs_ColumnPKNo FROM admtf_Attribute_PKFeatures(a_TableOID,a_AttributeNo); SELECT INTO rsa_isAttributeFK,rsa_FKeyName,rsa_ColumnFKNo,rsa_FKTableName, rsa_FKTableColumnName rs_isAttributeFK,rs_FKeyName, rs_ColumnFKNo,rs_FKTableName,rs_FKTableColumnName FROM admtf_Attribute_FKFeatures(a_TableOID,a_AttributeNo); RETURN QUERY SELECT rsa_AttributeName,rsa_UserTypeName,rsa_TypeName,rsa_isNotNULL, rsa_isAttributePK,rsa_ColumnPKNo,rsa_Description,rsa_isAttributeFK, rsa_FKeyName,rsa_ColumnFKNo,rsa_FKTableName,rsa_FKTableColumnName; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Attribute_Features(a_TableOID OID,a_AttributeNo SMALLINT) IS '   '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; SELECT * FROM admtf_Attribute_Features ((SELECT OID FROM pg_class WHERE relname='street'),2::SMALLINT); 


Voir aussi


PostgreSQL. ;
PostgreSQL. .
PostgreSQL. ( ) .

Source: https://habr.com/ru/post/fr418597/


All Articles