Funções para documentar bancos de dados PostgreSQL. Parte três

Esta é a terceira parte do artigo que descreve funções definidas pelo usuário para trabalhar com diretórios do sistema: pg_class, pg_attribute, pg_constraints etc.

Esta seção do artigo discute funções que retornam as características de sequências, tabelas herdadas e as características especiais de atributos de tabela .

Veja também
Funções para documentar bancos de dados PostgreSQL. Parte um ;
Funções para documentar bancos de dados PostgreSQL. Parte dois ;
Funções para documentar bancos de dados PostgreSQL. O fim (parte quatro) .

A primeira metade do artigo fornece comentários sobre a implementação de funções. O segundo é o código fonte das funções. Para os leitores que estão interessados ​​apenas nos textos originais, sugerimos seguir imediatamente para o Apêndice .

Estrutura de uma função que retorna uma lista de características de seqüências de tabela



Fig. 2. Funções das quais as funções admtf_Table_Sequences dependem

Tabela 11. Objetivo das funções.

Não.TítuloNomeação
1admtf_Sequence_FeaturesA função retorna uma lista de características da sequência da tabela.
2admtf_Table_SequencesA função retorna uma lista de sequências de tabelas do banco de dados e suas características.

Função Admtf_Sequence_Features - lista de características de sequência do banco de dados


A função admtf_Sequence_Features retorna uma lista de características SEQUENCE do banco de dados. O código-fonte pode ser visualizado e baixado aqui .


A função admtf_Sequence_Features retorna uma lista de características de sequência do banco de dados ( SEQUENCE )

.

Como parâmetros, a função assume o nome da sequência ( a_SequenceName ) e o nome do esquema no qual a sequência é criada ( a_SchemaName ).


A necessidade da função admtf_Sequence_Features surgiu porque as principais características da sequência são realmente armazenadas em uma tabela cujo nome corresponde ao nome da sequência e os dados são extraídos usando a instrução SELECT . Nesse caso, o nome da sequência, o nome do esquema e o comentário à sequência são armazenados nos diretórios pg_class , pg_namespace e pg_description .


SELECT * FROM kr_road_network_vertices_pgr_id_seq; 

Observação 6


O PostgreSQL 10 separou as características da sequência e as características de seus estados. Para isso, foi introduzido o diretório pg_sequence com características de sequência, contendo o valor inicial ( start_value ), incremento ( increment_by ) e o valor máximo ( max_value ) da sequência. O último valor retornado pela sequência ( last_value ) foi deixado na "tabela" com o nome da sequência.

O fim da observação.


A apresentação de cada sequência como um análogo da tabela, creio, é ditada pela necessidade de armazenar o último valor usado da sequência ( last_value ), que é uma característica do estado da sequência, mas não a própria sequência.


A entrada de sequência no diretório pg_class difere da entrada da tabela pelo valor do tipo de relação (relkind = 'S' ).


Para extrair as características de uma sequência arbitrária, você deve usar o SQL dinâmico.


 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 ; 


Tabela 12. O resultado da execução da função admtf_Sequence_Features ('public', 'kr_road_network_vertices_pgr_id_seq').

TítuloComentárioAtualIniciarIncrementarO fim
kr_road_network
_vertices_pgr_id
_seq
Sequência138023119223372036854775807

Função admtf_Table_Sequences lista de sequências de tabelas do banco de dados e suas características


A função admtf_Table_Sequences retorna uma lista de sequências ( SEQUENCE ) da tabela do banco de dados, gerando os valores de seus campos e as características dessas sequências. O código-fonte pode ser visualizado e baixado aqui , e aqui está uma versão de uma função que não usa um cursor .


Como parâmetros, a função assume o nome da tabela de origem ( a_TableName ) e o nome do esquema no qual a tabela é criada (

a_SchemaName

)

o código fonte do operador na figura
 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; 


Uma descrição de uma única sequência é uma combinação de um registro em pg_class descrevendo-o como uma relação física e uma tabela condicional com o nome da sequência contendo dados sobre as características específicas da sequência


As informações sobre o relacionamento entre a sequência e a tabela de origem são armazenadas no diretório do sistema pg_depend .



Tabela 13. Atributos do diretório pg_depend necessários para implementar a função.
TítuloDescrição do produto
objidOID da sequência no diretório pg_class
objsubidEste campo contém zero
refobjidOID da tabela nos campos em que a sequência é usada
refobjsubidNúmero do atributo da tabela cujos valores são preenchidos usando uma sequência

Além disso, a função acessa os dados do catálogo pg_namespace e pg_description para extrair os diagramas e comentários da sequência e da tabela de origem.


Para determinar o atributo de uma tabela cujos valores são preenchidos usando uma sequência, a função acessa o diretório pg_attribute na condição: attrelid = refobjid AND attnum = refobjsubid . (Nessa condição, os nomes dos atributos do diretório pg_depend são indicados à direita do sinal de igual).


As características especiais das seqüências de tabela são recuperadas em um loop chamando admtf_Sequence_Features . O ciclo é usado porque mais de uma sequência pode ser atribuída para preencher os campos da tabela.


Tabela 14. O resultado da execução da função admtf_Table_Sequences ('public', 'kr_road_network_vertices_pgr').

TítuloComentárioIniciarIncrementarO fimO campo
kr_road_network
_vertices_pgr_id
_seq
Sequência que gera valores de campo de ID119223372036854775807id

Versão sem cursor


Em um ambiente PostgreSQL cuja versão é menor que 10, é provavelmente impossível implementar a função admtf_Table_Sequences sem usar um cursor.
Mas os sortudos proprietários da versão 10 podem passar sem um cursor, porque eles têm o diretório pg_sequence à sua disposição. Nesse caso, todas as características da sequência podem ser recuperadas com uma única instrução SELECT .


Na implementação de função especificada, usando a função de janela RANK () OVER (PARTITION BY pseq.relname) , é calculado o número de sequência da sequência usada para preencher a tabela de origem.



o código fonte do operador na figura
 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; 


Observação 7

.

Esta versão da função não retorna o último valor gerado pela sequência ( last_value ).

O fim da observação.


Função Admtf_Table_InheritanceChildrens - lista de características de tabelas herdadas


A função admtf_Table_InheritanceChildrens retorna uma lista de características das tabelas herdadas ( INHERITS ) da tabela do banco de dados. O código-fonte pode ser visualizado e baixado aqui .


Como parâmetros, a função assume o nome da tabela de origem ( a_TableName ) e o nome do esquema no qual a tabela é criada ( a_SchemaName ).


A descrição de uma única tabela herdada está na entrada em pg_class . Mas, para procurar tabelas herdadas pelo nome da tabela de origem, é necessário usar o catálogo do sistema pg_depend .


Tabela 15. Atributos do diretório pg_depend necessários para implementar a função.
TítuloDescrição do produto
objidOID da tabela herdada no diretório pg_class
refobjidOID da tabela de origem


o código fonte do operador na figura
 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; 


Além disso, a função acessa os dados do diretório pg_namespace e pg_description para extrair esquemas e comentários para as tabelas herdada e de origem.


Tabela 16. O resultado da execução da função admtf_Table_InheritanceChildrens ('public', 'np_house').

TítuloComentárioAtributos? chave primária? índices? descendentesNúmero de registros
np_house 04201 000000Casas em assentamentos (distrito de Achinsky)15fff5651
np_house 4208 000 000Casas em assentamentos (distrito de Bogotolsky)15fff4314

O número de registros na tabela gerada é selecionado no atributo reltuple do diretório pg_class. E embora esse valor geralmente corresponda exatamente ao número real de entradas na tabela, ainda é um valor estimado. Portanto, convém obter o valor exato como resultado. Por exemplo, como mostrado na figura.


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

Mas, primeiro, para cumprir esta declaração no texto, a função admtf_Table_InheritanceChildrens precisará usar um cursor.


Em segundo lugar, eu gostaria que a função exibisse o número estimado e o número exato de entradas da tabela.


Portanto, a função possui outro parâmetro opcional - o modo de obter o número de entradas da tabela ( a_Mode ), que utiliza os valores "estimativa" ( estimativa ) ou "exatamente" ( exatamente ).



Além disso, a função admfn_Table_RowCount foi criada , que retorna o número exato de entradas da tabela e o atributo reltuple é substituído na lista de retorno SELECT com a seguinte construção.



o código fonte do operador na figura
 CASE WHEN a_Mode = 'exactly' THEN admfn_Table_RowCount(rnspc.nspname,rtbl.relname) ELSE reltuples END 


Como resultado, a função retornará o valor estimado do indicador "número de entradas da tabela" se o parâmetro a_Mode não especificar o requisito para retornar o valor exato.


Estrutura de uma função que retorna uma lista de características de atributos da tabela



Fig. 3. Funções que admtf_Attribute_Features Chamadas

versão em texto da tabela na figura
Tabela 17. Objetivo das funções.

Não.TítuloNomeação
1admtf_Attribute_PKFeaturesA função retorna o atributo de presença do atributo na chave primária (PRIMARY KEY), bem como algumas de suas características como parte dessa chave.
2admtf_Attribute_FKFeaturesA função retorna o atributo de presença do atributo na chave estrangeira (FOREIGN KEY), bem como algumas de suas características como parte dessa chave.
3admtf_Attribute_FeaturesA função retorna uma lista de características de atributos da tabela.


Função admtf_Attribute_PKFeatures - - se o atributo está presente na chave primária



A função admtf_Attribute_PKFeatures retorna um sinal da presença de um atributo de tabela na chave primária (PRIMARY KEY) da tabela e, se estiver presente, qual é o número de série nessa chave, pois chave primária pode ser composta.
O código-fonte pode ser visualizado e baixado aqui .


Como parâmetros, a função pega o OID da tabela de origem ( a_TableOID ) e o número de série do atributo desejado ( a_AttributeNo ).


A função extrai os dados necessários da entrada do diretório pg_constraint que contém as restrições (CONSTRAINT) da tabela de origem, incluindo a restrição de chave primária. O OID da tabela desejada é armazenado no campo conrelid , a descrição da chave primária é armazenada em um registro no qual o campo contype contém o valor '' 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; 

O campo conkey , encontrado dessa maneira, contém uma matriz de números de atributos que compõem a chave primária. Portanto, para verificar a presença do atributo de origem na chave primária, basta calcular a expressão lógica ARRAY [a_AttributeNo] <@ conkey .


Se o atributo estiver presente na chave primária, seu número de sequência será calculado no loop.


Função admtf_Attribute_FKFeatures - se o atributo está presente na chave estrangeira



A função admtf_Attribute_FKFeatures retorna um sinal da presença de um atributo da tabela em uma ou mais chaves estrangeiras (FOREIGN KEY) da tabela e, se estiver presente, quais são os números de sequência nessas chaves, porque chave estrangeira pode ser composta.

O código-fonte pode ser visualizado e baixado aqui .


Como parâmetros, a função pega o OID da tabela de origem ( a_TableOID ) e o número de série do atributo desejado ( a_AttributeNo ).


A função recupera os dados necessários da entrada do diretório pg_constraint que contém o CONSTRAINT da tabela de origem, incluindo, entre outros, restrições de chave estrangeira. O OID da tabela desejada é armazenado no campo conrelid , a descrição da chave primária é armazenada em um registro no qual o campo contype contém o valor '' f '

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

O campo conkey , encontrado dessa maneira, contém uma matriz de números de atributos que compõem a chave estrangeira. Portanto, para verificar a presença do atributo de origem na chave estrangeira, basta calcular a expressão lógica ARRAY [a_AttributeNo] <@ conkey .


Se o atributo estiver presente na chave estrangeira, no loop uma matriz de seus números de sequência é formada nas chaves estrangeiras que o contêm. Além disso, mais duas matrizes são formadas a partir dos nomes das tabelas e seus atributos, que são referenciados pelo atributo source nas chaves estrangeiras que a contêm.


Os nomes de tabela são recuperados da entrada do diretório pg_class pelo identificador (OID) recuperado do campo confrelid da entrada da chave estrangeira.


Para obter o nome do atributo da tabela externa, use uma matriz de números de série do campo

confkey

(difere da matriz acima pela letra " f " no nome). O número de série do atributo da tabela externa à qual o atributo externo corresponde é extraído dessa matriz. Por esse número de série do atributo da tabela externa e seu OID, localizado no diretório pg_attribute, há uma entrada para a descrição do atributo e seu nome é recuperado.

Função Admtf_Attribute_Features - lista de características de atributos da tabela


As funções admtf_Attribute_Features retornam uma lista das seguintes características de atributo da tabela. O código-fonte pode ser visualizado e baixado aqui .



A versão em texto da tabela na figura
Não.TítuloTipoNomeação
1AttributeNamenomeO nome do atributo de origem.
2UserTypeNameVARCHAR (256)Tipo de atributo de origem personalizado
3TypenameVARCHAR (256)Tipo base do atributo de origem
4isNotNULLBOOLEAN? Validade nula
5isAttributePKBOOLEAN? participação em PK
6ColumnPKNoSMALLINTNúmero de série do atributo em PK
7Descrição do produtoTEXTOComentar no atributo de origem
8isAttributeFKBOOLEAN? participação no FK
9FKeyNamenome []Uma matriz de nomes de tabela de restrição na qual a chave estrangeira é definida
10ColumnFKNoSMALLINT []Matriz de números de sequência de atributos em chaves estrangeiras de uma tabela
11FKTableNamenome []Matriz de tabelas referenciadas por chaves estrangeiras
12FKTableColumnNamenome []Matriz de nomes de atributos em tabelas externas correspondentes ao atributo de origem


Como parâmetros, a função pega o OID da tabela de origem ( a_TableOID ) e o número de série do atributo desejado ( a_AttributeNo ).
Os valores dos campos AttributeName e isNotNULL são recuperados da entrada do diretório pg_attribute correspondente aos valores dos parâmetros de entrada.


 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); 

Os valores dos campos isAttributePK e ColumnPKNo são retornados pela função admtf_Attribute_PKFeatures .


Os valores dos campos isAttributeFK , FKeyName , ColumnFKNo , FKTableName , FKTableColumnName são retornados pela função admtf_Attribute_FKFeatures .


Uma chamada para admtf_Attribute_Features ((SELECT OID FROM pg_class WHERE relname = 'street'), 2 :: SMALLINT) produzirá o seguinte resultado.


Tabela 18. Resultado da execução da função admtf_Attribute_Features
AttributeNameUserTypeNameTypenameisNotNULLisAttributePKColumnPKNo
localityidlocalityidinteirointeirointeirointeiro


Descrição do produtoisAttributeFKFKeyNameColumnFKNoFKTableNameFKTableColumnName
ID da comunidadet{fk_street_locality}{2}{localidade}{localityid}

APÊNDICE 1. Scripts


Criando a função admtf_Sequence_Features


Comentários sobre o código fonte da função podem ser encontrados aqui.
código de função
 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); 



Criando a função admtf_Table_Sequences


Comentários sobre o código fonte da função podem ser encontrados aqui.
código de função
 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); 


Veja também


PostgreSQL. ;
PostgreSQL. .
PostgreSQL. ( ) .

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


All Articles