Copiando metadados sobre um link de banco de dados no Oracle 10g
Pergunta
Agradecemos antecipadamente por seus especialistas em ajuda.
Quero poder copiar objetos de banco de dados do banco de dados A no banco de dados B com um procedimento criado no banco de dados B.
Criei um link de banco de dados entre os dois e ajustei a função get_ddl do dbms_metadata para se parecer com o seguinte:
create or replace function GetDDL
(
p_name in MetaDataPkg.t_string
p_type in MetaDataPkg.t_string
)
return MetaDataPkg.t_longstring
is
-- clob
v_clob clob;
-- array of long strings
c_SYSPrefix constant char(4) := 'SYS_';
c_doublequote constant char(1) := '"';
v_longstrings metadatapkg.t_arraylongstring;
v_schema metadatapkg.t_string;
v_fullength pls_integer := 0;
v_offset pls_integer := 0;
v_length pls_integer := 0;
begin
SELECT DISTINCT OWNER
INTO v_schema
FROM all_objects@ENTORA
where object_name = upper(p_name);
-- get DDL
v_clob := dbms_metadata.get_ddl(p_type, upper(p_name), upper(v_schema));
-- get CLOB length
v_fullength := dbms_lob.GetLength(v_clob);
for nIndex in 1..ceil(v_fullength / 32767)
loop
v_offset := v_length + 1;
v_length := least(v_fullength - (nIndex - 1) * 32767, 32767);
dbms_lob.read(v_clob, v_length, v_offset, v_longstrings(nIndex));
-- Remove table’s owner from DDL string:
v_longstrings(nIndex) := replace(
v_longstrings(nIndex),
c_doublequote || user || c_doublequote || '.',
''
);
-- Remove the following from DDL string:
-- 1) "new line" characters (chr(10))
-- 2) leading and trailing spaces
v_longstrings(nIndex) :=
ltrim(rtrim(replace(v_longstrings(nIndex), chr(10), '')));
end loop;
-- close CLOB
if (dbms_lob.isOpen(v_clob) > 0)
then
dbms_lob.close(v_clob);
end if;
return v_longstrings(1);
end GetDDL;
para remover o prefixo do esquema que geralmente vem com metadados. Recebo um valor nulo sempre que executo essa função no link do banco de dados com as consultas a seguir.
selecione getddl ('tabela', 'tabela1') de user_tables@entora onde tabela_name = 'tabela1';
Selecione getddl ('tabela', 'tabela1') em dual@entora;
t_string é varchar2 (30) t_longString é varchar2 (32767) e o tipo t_arraylongstring é a tabela de t_longstring
Eu realmente apreciaria se alguém pudesse ajudar. Muito Obrigado.
Solução
CREATE OR REPLACE function DEMO_FN
(object_type varchar2, table_name varchar2) return varchar2
is
v_longstrings varchar2(32223);
c_doublequote constant char(1) := '"';
begin
v_longstrings := dbms_metadata.get_ddl(object_type,table_name);
-- Remove double quotes from DDL string:
v_longstrings := replace(v_longstrings, c_doublequote || user || c_doublequote || '.','');
-- Remove the following from DDL string:
-- 1) "new line" characters (chr(10))
-- 2) leading and trailing spaces
v_longstrings := ltrim(rtrim(replace(v_longstrings, chr(10), '')));
return v_longstrings;
end;
/
Observe que o esquema assinado deve ter o select_catalog_role para executar esta função.
Um exemplo é
selecione Demo_FN@db_link ('tabela', 'tabela_name') do dual;
Outras dicas
Isso funciona bem
declare
v_ddl clob;
V_DDL_PART varchar2(4000);
begin
for I in 0 .. 50 loop
select DBMS_LOB.SUBSTR@db_link(DBMS_METADATA.GET_DDL@db_link('TABLE','MYTABLE'),(4000 * I + 1)) into V_DDL_PART from dual@db_link;
V_DDL := V_DDL || V_DDL_PART;
end loop;
end;
Este trabalho é bom, pequeno bug corrigido:
declare
v_ddl clob;
V_DDL_PART varchar2(4000);
begin
for I in 0 .. 10 loop
select DBMS_LOB.SUBSTR@LINK(
DBMS_METADATA.GET_DDL@LINK('TABLE','NAME','SCHEMA'),
4000,(4000 * I + 1)) into V_DDL_PART from dual@LINK;
V_DDL := V_DDL || V_DDL_PART;
end loop;
dbms_output.put_line(v_ddl);
end;
Espero acertar a sintaxe, mas acho que deveria ser v_clob := dbms_metadata@ENTORA.get_ddl(...)
ao invés de v_clob := dbms_metadata.get_ddl(...)