分享
 
 
 

Oracle中提取和存储数据库对象的DDL

王朝oracle·作者佚名  2008-05-31
窄屏简体版  字體: |||超大  

从对象(例如数据库表、索引、约束、触发器等)中提取DDL命令的普通方法涉及到的操作包括从这些对象中提取元数据(metadata),并把这些数据存储在内存中。尽管目前有很多脚本可以实现这样的功能,但是它们通常都是不完整的或者过时的。

幸运的是,Oracle 9.2提供了一个实现这样的功能的API:DBMS_METADATA程序包。

在很多情况下,数据库中数据的维护操作要求我们提取多种对象(例如数据库表、索引、约束、触发器等)的DDL(Data Definition Language,数据定义语言)。

最近我承担了一个任务,我需要编写一组数据库程序包来执行高性能的大量的数据删除(DELETE)操作。这样的操作要求我拥有提取和存储数据库对象DDL的相关技术。

提取和存储数据库对象的DDL的方法如下:

· 建立与源表结构相同的数据表,但是它不带主键、备用键和外部键约束。

· 例如,使用MyTable_X,其中MyTable是要被删除的目标数据表。

· 把需要保存的数据插入新建立的数据表(MyTable_X)中。

· 使用NOLOGGING PARALLEL选项在新数据表上建立索引。

· 在新数据表上建立约束。

· MyTable和MyTable_X数据表进行交换。把主表改名为MyTable_T,把MyTable_X改名为MyTable。

· 验证结果并删除MyTable_T表。

很明显,为了编写实现上面目标的代码,你必须提取数据库对象的元数据(定义和被选中的属性),并把它存储在内存中,这样在执行上面的操作的时候才能够使用它。

在网上存在大量的脚本,它们可以从多种Oracle数据字典(user_tables、user_indexes、user_ind_columns、user_constraints、user_cons_columns等)中提取数据库对象的元数据,接着为特定的对象构造DDL命令。这些脚本的一个问题是,它们通常是SQL*Plus脚本,它会生成客户端文本文件,而这个文件不能被服务器端代码访问。它们的主要问题有:

· 不完整:不能提取所有的选项,并组合进DDL语句中。

· 过时了:这些脚本通常不支持Oracle最新的数据库特性--分区(partitioning)、基于函数的索引、自动段空间治理(ASSM)等。这些脚本可能崩溃或生成错误的DDL语句。

问题总结:尽管有大量的从Oracle数据字典中提取数据库对象元数据的脚本,但是它们中的大多数要么不完整,要么过期了。

解决方案:使用DBMS_METADATA程序包,学习如何用最佳的、没有错误的和易于维护的方式执行上面的事务。

使用Oracle的本地API:DBMS_METADATA程序包

Oracle数据库采用补充PL/SQL程序包的形式提供了丰富的预先包装好的API。Oracle 9.2版本中引入的DBMS_METADATA程序包可能正好适合你的需求。它包含了用于检索数据库对象定义的API。

我们将使用的API主要是DBMS_METADATA.GET_DDL函数。这个函数返回的对象定义SQL字符串是CLOB。它拥有下面一些输入参数:

· object_type VARCHAR2

· name VARCHAR2

· schema VARCHAR2 DEFAULT NULL

· version VARCHAR2 DEFAULT ’COMPATIBLE’

· model VARCHAR2 DEFAULT ’ORACLE’,

· transform VARCHAR2 DEFAULT ’DDL’

下面建立了一个用于测试的EmpTest数据表,它带有索引和约束:

create table EmpTest

(

empNo integer not null,

lastName varchar2(30) not null,

firstName varchar2(20) not null,

job varchar2(9) ’

hireDate date ’

isActive number(1)

constraint EmpTest_CK1

check (isActive in (0,1)) ,

salary number(9,2) ,

commision number(9,2) ,

deptNo number(2) ,

constraint EmpTest_PK

primary key (empNo),

constraint EmpTest_AK1

unique (lastName, firstName)

);

create index EmpTest_HireDate_Salary

on EmpTest

(

salary,

hireDate

);

运行上面的脚本之后,就建立了一个带有三个索引(两个唯一的和一个不唯一的索引)的EmpTest表:

select index_name, index_type, uniqueness

from user_indexes

where table_name = ’EMPTEST’;

索引名称

索引类型

唯一性

EMPTEST_AK1

NORMAL

UNIQUE

EMPTEST_HIREDATE_SALARY

NORMAL

NONUNIQUE

EMPTEST_PK

NORMAL

UNIQUE

EmpTest表还包括六个约束:

· 一个主键-EmpTest_PK

· 一个备用键-EmpTest_AK

· 一个检查约束-EmpTest_CK1

· 系统生成的(SYS_*)三个非空的约束,名称如下:

约束名称

约束类型

索引名称

SYS_C002144065

C

SYS_C002144066

C

SYS_C002144067

C

EMPTEST_CK1

C

EMPTEST_PK

P

EMPTEST_PK

EMPTEST_AK1

U

EMPTEST_AK1

现在我们执行匿名的PL/SQL代码块来调用DBMS_METADATA.GET_DDL函数,检索数据表的定义。

DBMS_OUTPUT程序包只能输出最长为255个字符的字符串,由于在处理数据表的DDL字符串的时候太轻易超过这个限制,所以这是一个问题。为了解决这个问题,我们使用了本地过程Show()(列表1所示)。

列表1:调用DBMS_METADATA.GET_DDL()函数的PL/SQL代码块

declare

vClob clob;

vLongString varchar2(32767);

vOffSet pls_integer := 0;

vLength pls_integer := 0;

vTable varchar2(30) := ’EmpTest’;

procedure Show (pVariable varchar2, pLineSize pls_integer := 80)

is

begin

dbms_output.enable(1000000);

if (length(pVariable) > pLineSize)

then

dbms_output.put_line(substr(pVariable, 1, pLineSize));

Show(substr(pVariable, pLineSize + 1), pLineSize);

else

dbms_output.put_line(pVariable);

end if;

end Show;

begin

-- 获取 DDL

vClob := dbms_metadata.get_ddl(’TABLE’, upper(vTable));

-- 获取 CLOB 长度

vLength := dbms_lob.GetLength(vClob);

dbms_output.put_line(’DDL length: ’ to_char(vLength));

vOffSet := 1;

dbms_lob.read(vClob, vLength, vOffSet, vLongString);

-- 关闭 CLOB

if (dbms_lob.isOpen(vClob) > 0)

then

dbms_lob.close(vClob);

end if;

Show(vLongString, 80);

end;

列表1生成下面的输出信息:

DDL length: 461

CREATE TABLE "BORIS"."EMPTEST"

( "EMPNO" NUMBER(*,0) NOT NULL ENABLE,

"LASTNAME" VARCHAR2(30) NOT NULL ENABLE,

"FIRSTNAME" VARCHAR2(20) NOT NULL ENABLE,

"JOB" VARCHAR2(9),

"HIREDATE" DATE,

"ISACTIVE" NUMBER(1,0),

"SALARY" NUMBER(9,2),

"COMMISION" NUMBER(9,2),

"DEPTNO" NUMBER(2,0),

CONSTRAINT "EMPTEST_CK1" CHECK (isActive in (0,1)) ENABLE,

CONSTRAINT "EMPTEST_PK" PRIMARY KEY ("EMPNO")

USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255

STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645

PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)

TABLESPACE "TOOLS" ENABLE, CONSTRAINT "EMPTEST_AK1" UNIQUE ("LASTNAME", "FIRSTNAME")

USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255

STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645

PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)

TABLESPACE "TOOLS" ENABLE) PCTFREE 10 PCTUSED 40 INITRANS 1

MAXTRANS 255 NOCOMPRESS LOGGING

STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645

PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)

TABLESPACE "TOOLS"

它运行的情况太好了,返回的数据表的DDL字符串带有主键EmpTest_PK、备用键EmpTest_AK1和检查约束EmpTest_CK1。它建立了两个唯一的索引来支持主键和备用键约束。这不是你需要的结果:你需要一个表,但是为了加快数据载入速度,它不要包含约束和索引。只有在数据载入工作完成以后,你才建立索引和约束。

保证对象的定义独立的另外一个原因在于灵活性:你可能需要改变对象建立的次序。

现在可以设计一个数据结构来存储对象的元数据了。

元数据存储器:MetaDataPkg程序包规范

首先,你必须建立记录类型来存储独立的对象(例如数据表、索引等)的所有必要信息:

suBType tString is varchar2(30);

subtype tDBString is varchar2(255);

subtype tDBLongString is varchar2(4000);

subtype tLongString is varchar2(32767);

type tArrayLongString is table of tLongString

index by pls_integer;

type tMetaObject is record

(

aName tString,

aType tString,

aLogging tString,

aParallel tString,

aStatus tString,

aValidated tString,

aRely tString,

aDDLString tLongString

);

tMetaObject属性保存了下面一些信息:

· aName:对象的名称,例如EMPTEST_PK1。

· aType:对象的类型,例如’YES’ (分区的)/’NO’ (分区的) (用于表)、 ’UNIQUE’/’NONUNIQUE’ (用于索引)、 约束类型 ’P’/’U’/’C’/’R’ (用于约束)。

· aLogging:对象的日志选项,例如’LOGGING’/ ’NOLOGGING’ (用于表和索引)。

· aParallel: 对象的平行程度(用于表和索引)。

· AStatus:对象的状态,例如’VALID’/’UNUSABLE’ 用于索引、 ’Y’ (备份了)/’N’ (未备份)用于表。

· AValidated:对象的验证选项,例如’VALIDATED’/’NOT VALIDATED’(用于约束)。

· ARely:对象的依靠选项,例如’RELY’/’NORELY’ (用于约束)。

· ADDLString:对象的定义SQL字符串。

现在你必须定义一个相关的数组类型,它能够列举出某种类型的对象,从保存tMetaObject类型的多个对象,例如,所有的EmpTest索引:

type tArrayMetaObject is table of tMetaObject

index by pls_integer;

下一步需要建立一个记录类型,它包含了数据表表自身(aTable)的tMetaObject属性和三个tArrayMetaObject属性:一个用于索引(aIndexes),一个用于约束(aConstraints),一个用于触发器(aTriggers):

type tFullMetaObject is record

(

aTable tMetaObject,

aIndexes tArrayMetaObject,

aConstraints tArrayMetaObject,

aTriggers tArrayMetaObject

);

tFullMetaObject对象类型保存了单个表的全部对象的元数据。最后,位于顶层的类型是tFullMetaObject数组。TarrayFullMetaObjectByString类型是tFullMetaObject的一个表,索引类型是varchar2(30)。

列表2:MetaDataPkg程序包规范

用如下的方式建立或更新MetaDataPkg:

cEnabled constant char(7) := ’ENABLED’;

cDisabled constant char(8) := ’DISABLED’;

cUsable constant char(6) := ’USABLE’;

cUnusable constant char(8) := ’UNUSABLE’;

cValid constant char(5) := ’VALID’;

cInvalid constant char(7) := ’INVALID’;

cTable constant char(5) := ’TABLE’;

cView constant char(4) := ’VIEW’;

cIndex constant char(5) := ’INDEX’;

cConstraint constant char(10) := ’CONSTRAINT’;

cTrigger constant char(7) := ’TRIGGER’;

cLobType constant char(3) := ’LOB’;

cClobType constant char(4) := ’CLOB’;

cBlobType constant char(4) := ’BLOB’;

cPackage constant char(7) := ’PACKAGE’;

cPackageBody constant char(12) := ’PACKAGE BODY’;

cProcedure constant char(9) := ’PROCEDURE’;

cFunction constant char(8) := ’FUNCTION’;

cSequence constant char(8) := ’SEQUENCE’;

cSynonym constant char(7) := ’SYNONYM’;

cType constant char(4) := ’TYPE’;

cColumn constant char(6) := ’COLUMN’;

cJavaSource constant char(11) := ’JAVA SOURCE’;

cJavaClass constant char(10) := ’JAVA CLASS’;

cYes constant char(3) := ’YES’;

cNo constant char(2) := ’NO’;

cPKConsType constant char(1) := ’P’;

cUNConsType constant char(1) := ’U’;

cFKConsType constant char(1) := ’R’;

cCKConsType constant char(1) := ’C’;

cDropStorage constant char(12) := ’DROP STORAGE’;

cReuseStorage constant char(13) := ’REUSE STORAGE’;

cCascade constant char(19) := ’CASCADE CONSTRAINTS’;

cNoCascade constant char(10) := ’NO CASCADE’;

cEnable constant char(6) := ’ENABLE’;

cNovalidate constant char(10) := ’NOVALIDATE’;

cRely constant char(4) := ’RELY’;

cNoRely constant char(6) := ’NORELY’;

cValidated constant char(9) := ’VALIDATED’;

cNotValidated constant char(13) := ’NOT VALIDATED’;

cLogging constant char(7) := ’LOGGING’;

cNoLogging constant char(9) := ’NOLOGGING’;

cParallel constant char(8) := ’PARALLEL’;

cNoParallel constant char(10) := ’NOPARALLEL’;

cNull constant char(4) := ’NULL’;

cNotNull constant char(8) := ’NOT NULL’;

cDefault constant char(7) := ’DEFAULT’;

cSYSPrefix constant char(4) := ’SYS_’;

cDoubleQuote constant char(1) := ’"’;

subtype tString is varchar2(30);

subtype tDBString is varchar2(255);

subtype tDBLongString is varchar2(4000);

subtype tLongString is varchar2(32767);

type tArrayLongString is table of tLongString

index by pls_integer;

type tMetaObject is record

(

aName tString,

aType tString,

aLogging tString,

aParallel tString,

aStatus tString,

aValidated tString,

aRely tString,

aDDLString tLongString

);

type tArrayMetaObject is table of tMetaObject

index by pls_integer;

type tFullMetaObject is record

(

aTable tMetaObject,

aIndexes tArrayMetaObject,

aConstraints tArrayMetaObject,

aTriggers tArrayMetaObject

);

type tArrayFullMetaObjectByString is table of tFullMetaObject

index by varchar2(30);

procedure Load

(

pTable in tString,

pForce in boolean := false

);

procedure Reset

(

pTable in tString

);

procedure Reset;

function GetMeta

(

pTable in tString,

pForce in boolean := false

)

return tFullMetaObject;

function GetMeta

return tArrayFullMetaObjectByString;

procedure SetMeta

(

pTable in tString,

pFullMetaObject in tFullMetaObject

);

procedure SetMeta

(

pArrayFullMetaObjectByString in tArrayFullMetaObjectByString

);

procedure Show

(

pTable in tString

);

procedure Show;

end MetaDataPkg;

上面的类型对象是作为元数据存储器的,用于存放多个表的完整的元数据信息集合。所有上面的类型都包含在程序包规范中(列表2所示)。我还介绍了下面一些API:

· MetaDataPkg.Load()过程:把特定表的元数据信息载入存储器中。

· MetaDataPkg.GetMeta()函数:它从存储器中检索tFullMetaObject类型的对象。

· MetaDataPkg.SetMeta()过程(重载的):把对象的元数据存储到存储器中。

· MetaDataPkg.Reset过程(重载的):对存储器复位。

· MetaDataPkg.Show过程(重载的):显示存储器的内容。

实现所有这些事务的代码

列表3显示了MetaDataPkg程序包主体代码的一些解释。私有过程SetEnvironment()包含了所有的环境设置代码。在程序包的初始化部分会调用这个过程,因此在每个对话中它都只执行一次,符合你的需求(你希望在开头设置一次)。程序包提供了用于设置环境参数的API:DBMS_METADATA.SET_TRANSFORM_PARAM()过程。

列表3:MetaDataPkg程序包主体

vMetaData tArrayFullMetaObjectByString;

procedure SetEnvironment

is

begin

dbms_metadata.set_transform_param(

dbms_metadata.session_transform, ’PRETTY’, false);

dbms_metadata.SET_TRANSFORM_PARAM(

dbms_metadata.session_transform, ’SEGMENT_ATTRIBUTES’, true);

dbms_metadata.set_transform_param(

dbms_metadata.session_transform, ’STORAGE’, true);

dbms_metadata.set_transform_param(

dbms_metadata.session_transform, ’TABLESPACE’, true);

dbms_metadata.set_transform_param(

dbms_metadata.session_transform, ’CONSTRAINTS’, false);

dbms_metadata.set_transform_param(

dbms_metadata.session_transform, ’REF_CONSTRAINTS’, false);

dbms_metadata.set_transform_param(

dbms_metadata.session_transform, ’CONSTRAINTS_AS_ALTER’, false);

end SetEnvironment;

procedure Print

(

pString varchar2,

pLineSize positive := 80

)

is

vLineSize pls_integer := least(nvl(pLineSize, 80), 255);

begin

dbms_output.enable(1000000);

if (length(pString) > vLineSize)

then

dbms_output.put_line(substr(pString, 1, vLineSize));

Print(substr(pString, pLineSize + 1), vLineSize);

else

dbms_output.put_line(pString);

end if;

end Print;

procedure Show

(

pMetaObject in tMetaObject

)

is

begin

dbms_output.put_line(’***’);

dbms_output.put_line(’Name: ’ pMetaObject.aName);

dbms_output.put_line(’Type: ’ pMetaObject.aType);

dbms_output.put_line(’Logging: ’ pMetaObject.aLogging);

dbms_output.put_line(’Parallel: ’

to_char(pMetaObject.aParallel));

dbms_output.put_line(’Status: ’ pMetaObject.aStatus);

dbms_output.put_line(’Validated: ’

pMetaObject.aValidated);

dbms_output.put_line(’Rely: ’ pMetaObject.aRely);

print(’DDL String: ’ pMetaObject.aDDLString, 255);

dbms_output.put_line(’***’);

end Show;

function GetDDL

(

pName in tString,

pType in tString

)

return tLongString

is

vClob clob;

vLongStrings tArrayLongString;

vFullLength pls_integer := 0;

vOffSet pls_integer := 0;

vLength pls_integer := 0;

begin

vClob := dbms_metadata.get_ddl(pType, upper(pName));

vFullLength := dbms_lob.GetLength(vClob);

for nIndex in 1..ceil(vFullLength / 32767)

loop

vOffSet := vLength + 1;

vLength := least(vFullLength - (nIndex - 1) * 32767, 32767);

dbms_lob.read(vClob, vLength, vOffSet, vLongStrings(nIndex));

vLongStrings(nIndex) := replace(vLongStrings(nIndex),

cDoubleQuote user cDoubleQuote ’.’,

’’);

vLongStrings(nIndex) :=ltrim(rtrim(replace(vLongStrings(nIndex), chr(10), ’’)));

end loop;

if (dbms_lob.isOpen(vClob) > 0)

then

dbms_lob.close(vClob);

end if;

return vLongStrings(1);

end GetDDL;

function ObjectExists

(

pObjectName in tString,

pObjectType in tString,

pTableName in tString := null

)

return boolean

is

vCount pls_integer := 0;

vObjectName tString := ltrim(rtrim(pObjectName));

vObjectType tString := upper(ltrim(rtrim(pObjectType)));

vTableName tString := upper(ltrim(rtrim(pTableName)));

begin

case

when vObjectType = cColumn

then

select count(*)

into vCount

from Dual

where exists (select ’1’

from user_tab_columns

where column_name = upper(vObjectName)

and table_name = vTableName);

when vObjectType = cConstraint

then

select count(*)

into vCount

from Dual

where exists (select ’1’

from user_constraints

where constraint_name = upper(vObjectName)

and table_name = vTableName);

when vObjectType in (cJavaSource, cJavaClass)

then

select count(*)

into vCount

from Dual

where exists (select ’1’

from user_objects

where object_name = vObjectName and object_type = vObjectType);

else

select count(*)

into vCount

from Dual

where exists (select ’1’

from user_objects

where object_name = upper(pObjectName)

and object_type = vObjectType);

end case;

return (vCount > 0);

end ObjectExists;

procedure Load

(

pTable in tString,

pForce in boolean := false

)

is

vFullMetaObject tFullMetaObject;

vTable tString := upper(ltrim(rtrim(pTable)));

vCount pls_integer := 0;

begin

if (not vMetaData.exists(vTable) or nvl(pForce, false))

then

if not ObjectExists(pTable, cTable)

then

raise_application_error(-20500,

’Unable to load metadata for ’ nvl(pTable, ’NULL’)

’. ’ ’Table does not exist.’

);

end if;

for rec in (select table_name,

logging,

ltrim(rtrim(degree)) as degree,

partitioned,

backed_up

from user_tables

where table_name = vTable)

loop

vFullMetaObject.aTable.aName := rec.table_name;

vFullMetaObject.aTable.aType := rec.partitioned;

vFullMetaObject.aTable.aLogging := rec.logging;

vFullMetaObject.aTable.aParallel := ltrim(rtrim(rec.degree));

vFullMetaObject.aTable.aStatus := rec.backed_up;

vFullMetaObject.aTable.aDDLString := GetDDL(rec.table_name, cTable);

end loop;

for rec in (select index_name,

uniqueness,

logging,

ltrim(rtrim(degree)) as degree,

status

from user_indexes

where table_name = vTable

and index_type != cLobType)

loop

vCount := vCount + 1;

vFullMetaObject.aIndexes(vCount).aName := rec.index_name;

vFullMetaObject.aIndexes(vCount).aType := rec.uniqueness;

vFullMetaObject.aIndexes(vCount).aLogging := rec.logging;

vFullMetaObject.aIndexes(vCount).aParallel :=

ltrim(rtrim(rec.degree));

vFullMetaObject.aIndexes(vCount).aStatus := rec.status;

vFullMetaObject.aIndexes(vCount).aDDLString :=

GetDDL(rec.index_name, cIndex);

end loop;

vCount := 0;

for rec in (select constraint_name,constraint_type,status,search_condition,validated,rely from user_constraints where table_name = vTable

order by decode(constraint_type,

cPKConsType, 10,

cUNConsType, 20,

cFKConsType, 30,

cCKConsType, 40,

100),

constraint_name)

loop

vCount := vCount + 1;

vFullMetaObject.aConstraints(vCount).aName := rec.constraint_name;

vFullMetaObject.aConstraints(vCount).aType := rec.constraint_type;

vFullMetaObject.aConstraints(vCount).aLogging := null;

vFullMetaObject.aConstraints(vCount).aParallel := null;

vFullMetaObject.aConstraints(vCount).aStatus := rec.status;

vFullMetaObject.aConstraints(vCount).aValidated := rec.validated;

vFullMetaObject.aConstraints(vCount).aRely := rec.rely;

if substr(rec.constraint_name, 1, length(cSYSPrefix)) = cSYSPrefix and

upper(rec.search_condition) like ’%IS ’ cNotNull ’%’

then

vFullMetaObject.aConstraints(vCount).aDDLString :=

’ALTER TABLE ’ cDoubleQuote vFullMetaObject.aTable.aName cDoubleQuote ’ ’

’MODIFY ’ replace(rec.search_condition, ’IS ’ cNotNull, cNotNull)

(case when vFullMetaObject.aConstraints(vCount).aValidated = cNotValidated

then ’ ’ cNovalidate

else ’’end);

else

vFullMetaObject.aConstraints(vCount).aDDLString := GetDDL(rec.constraint_name, cConstraint);

end if;

end loop;

SetMeta(pTable, vFullMetaObject);

end if;

end Load;

procedure Reset

(

pTable in tString

)

is

begin

vMetaData.delete(pTable);

end Reset;

procedure Reset

is

begin

vMetaData.delete;

end Reset;

function GetMeta

(

pTable in tString,

pForce in boolean := false

)

return tFullMetaObject

is

begin

if (not vMetaData.exists(pTable) or nvl(pForce, false))

then

Load(pTable, pForce);

if not vMetaData.exists(pTable)

then

raise_application_error(-20501, ’Unable to find metadata for ’ pTable ’ in repository.’);

end if;

end if;

return vMetaData(pTable);

end GetMeta;

function GetMeta

return tArrayFullMetaObjectByString

is

begin

return vMetaData;

end GetMeta;

procedure SetMeta

(

pTable in tString,

pFullMetaObject in tFullMetaObject

)

is

begin

vMetaData(pTable) := pFullMetaObject;

end SetMeta;

procedure SetMeta

(

pArrayFullMetaObjectByString in tArrayFullMetaObjectByString

)

is

begin

vMetaData := pArrayFullMetaObjectByString;

end SetMeta;

procedure Show

(

pTable in tString

)

is

vFullMetaObject tFullMetaObject;

begin

if (vMetaData.exists(pTable))

then

dbms_output.enable(1000000);

vFullMetaObject := vMetaData(pTable);

dbms_output.put_line(’Start Full Object: ’ pTable);

dbms_output.put_line(’Start Table: ’ pTable);

Show(vFullMetaObject.aTable);

dbms_output.put_line(’Finish Table: ’ pTable);

dbms_output.put_line(’Start Indexes: ’ pTable);

if (vFullMetaObject.aIndexes.count > 0)

then

for nIndex in vFullMetaObject.aIndexes.first..vFullMetaObject.aIndexes.last

loop

Show(vFullMetaObject.aIndexes(nIndex));

end loop;

end if;

dbms_output.put_line(’Finish Indexes: ’ pTable);

dbms_output.put_line(’Start Constraints: ’ pTable);

if (vFullMetaObject.aConstraints.count > 0)

then

for nIndex in vFullMetaObject.aConstraints.first..vFullMetaObject.aConstraints.last

loop

Show(vFullMetaObject.aConstraints(nIndex));

end loop;

end if;

dbms_output.put_line(’Finish Constraints: ’ pTable);

dbms_output.put_line(’Start Triggers: ’ pTable);

if (vFullMetaObject.aTriggers.count > 0)

then

for nIndex in vFullMetaObject.aTriggers.first..vFullMetaObject.aTriggers.last

loop

Show(vFullMetaObject.aTriggers(nIndex));

end loop;

end if;

dbms_output.put_line(’Finish Triggers: ’ pTable);

dbms_output.put_line(’Finish Full Object: ’ pTable);

end if;

end Show;

procedure Show

is

vTable tString;

begin

if vMetaData.count > 0

then

dbms_output.put_line(’Total Meta Objects: ’ to_char(vMetaData.count));

vTable := vMetaData.first;

while (vTable is not null)

loop

Show(vTable);

vTable := vMetaData.next(vTable);

end loop;

end if;

end Show;

begin

SetEnvironment;

end MetaDataPkg;

下面的代码防止输出信息采用缩排或换行格式化:

dbms_metadata.set_transform_param(dbms_metadata.session_transform, ’PRETTY’, false);

下面的三行输出片段属性(物理属性、存储属性、表空间、日志等)、数据表的存储、表空间子句和索引对象定义:

dbms_metadata.set_transform_param(dbms_metadata.session_transform, ’SEGMENT_ATTRIBUTES’, true);

dbms_metadata.set_transform_param(dbms_metadata.session_transform, ’STORAGE’, true);

dbms_metadata.set_transform_param(dbms_metadata.session_transform, ’TABLESPACE’, true);

明确地指定所有的物理、存储和日志属性是非常重要的--否则,它们会被设为默认值,而这个值可能与原始设置的值不同。

SetEnvironment()过程最后的三行防止所有的非参考和参考约束被包含到表的DDL中。它还禁止独立的ALTER TABLE语句(假如必要,还可以禁止CREATE INDEX语句)来生成数据表约束:

dbms_metadata.set_transform_param(dbms_metadata.session_transform, ’CONSTRAINTS’, false);

dbms_metadata.set_transform_param(dbms_metadata.session_transform, ’REF_CONSTRAINTS’, false);

dbms_metadata.set_transform_param(dbms_metadata.session_transform, ’CONSTRAINTS_AS_ALTER’, false);

为了达到最大的灵活性,最好分别提取数据表、索引和约束的对象定义并保证它们彼此都相互独立。通过这种办法,你可以控制这些对象的建立次序。

MetaDataPkg程序包的主要工作部分是MetaDataPkg.GetDDL()函数。MetaDataPkg.GetDDL()包含了列表1代码的扩展版本。添加到里面的是提取超过32767个字符的DDL字符串的能力。它可以帮助处理分区的数据表定义--随着分区数量的增长,它可能变得很长。这也是GetDDL()代码把DDL字符串分析并载入每个长达32767字符的字符串数组的原因。目前的代码版本只返回第一个数组元素,因此你需要修改这段代码,把该数组转换为tMetaObject记录类型的属性。这样就答应它处理长于32767字符的字符串,当然这种情况非常少见。

使用MetaDataPkg.GetMeta() API可以得到每个特定数据表的完整的元数据对象。这个API接受两个参数:pTable,它是表的名称;pForce,布尔型标记。当pForce被设置为TRUE的时候,它强迫元数据从Oracle数据字典中检索,接着把元数据载入存储器中--不管是否预备好了。但是默认的值是FALSE,因此第一个调用把元数据载入存储器中并返回tFullMetaObject类型的对象,后面的GetMeta()调用简单地从存储器中检索元数据。

使用MetaDataPkg程序包

为了演示如何使用MetaDataPkg程序包,我建立了一小段匿名代码块。它把EmpTest表中的元数据载入元数据存储器中,并输出它的内容。

下面就是匿名的PL/SQL代码块:

declare

vTable MetaDataPkg.tString := ’EmpTest’;

vRunStartTime number;

begin

vRunStartTime := dbms_utility.get_time;

MetaDataPkg.Load(vTable, true);

MetaDataPkg.Show();

dbms_output.put_line(’Time Elapsed: ’

to_char((dbms_utility.get_time - vRunStartTime) / 100) ’ sec.’);

end;

列表4显示了前面的代码的输出信息。

你可以看到,这段代码把EmpTest数据表和其索引、约束的全部元数据信息载入到存储器中,并在一秒钟之内把它检索出来了。你现在拥有了一个用于开发自动的解决方案的API了,它可以进行任何数据维护操作,包括更名、转换和删除数据库对象。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有