在很多情况下,数据库中数据的维护操作要求我们提取多种对象(例如数据库表、索引、约束、触发器等)的DDL(DataDefinitionLanguage,数据定义语言)。
最近我承担了一个任务,我需要编写一组数据库程序包来执行高性能的大量的数据删除(DELETE)操作。这样的操作要求我拥有提取和存储数据库对象DDL的相关技术。
提取和存储数据库对象的DDL的方法如下:
·建立与源表结构相同的数据表,但是它不带主键、备用键和外部键约束。
财,软联盟,fs119.net
·例如,使用MyTable_X,其中MyTable是要被删除的目标数据表。
·把需要保存的数据插入新建立的数据表(MyTable_X)中。
·使用NOLOGGINGPARALLEL选项在新数据表上建立索引。
·在新数据表上建立约束。
·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。Oracle9.2版本中引入的DBMS_METADATA程序包可能正好适合你的需求。它包含了用于检索数据库对象定义的API。
我们将使用的API主要是DBMS_METADATA.GET_DDL函数。这个函数返回的对象定义SQL字符串是CLOB。它拥有下面一些输入参数:
·object_typeVARCHAR2
·nameVARCHAR2
·schemaVARCHAR2DEFAULTNULL
·versionVARCHAR2DEFAULT’COMPATIBLE’
·modelVARCHAR2DEFAULT’ORACLE’,
·transformVARCHAR2DEFAULT’DDL’
下面建立了一个用于测试的EmpTest数据表,它带有索引和约束:
(
empNointegernotnull,
lastNamevarchar2(30)notnull,
firstNamevarchar2(20)notnull,
jobvarchar2(9)’
hireDatedate’
isActivenumber(1)
constraintEmpTest_CK1
check(isActivein(0,1)),
salarynumber(9,2),
commisionnumber(9,2),
deptNonumber(2),
constraintEmpTest_PK
primarykey(empNo),
constraintEmpTest_AK1
unique(lastName,firstName)
);
createindexEmpTest_HireDate_Salary
onEmpTest
(
salary,
hireDate
);
运行上面的脚本之后,就建立了一个带有三个索引(两个唯一的和一个不唯一的索引)的EmpTest表:
财,软联盟,fs119.net
fromuser_indexes
wheretable_name=’EMPTEST’;
EmpTest表还包括六个约束:
·一个主键-EmpTest_PK
·一个备用键-EmpTest_AK
·一个检查约束-EmpTest_CK1
·系统生成的(SYS_*)三个非空的约束,名称如下:
现在我们执行匿名的PL/SQL代码块来调用DBMS_METADATA.GET_DDL函数,检索数据表的定义。
DBMS_OUTPUT程序包只能输出最长为255个字符的字符串,由于在处理数据表的DDL字符串的时候太容易超过这个限制,所以这是一个问题。为了解决这个问题,我们使用了本地过程Show()(列表1所示)。
列表1:调用DBMS_METADATA.GET_DDL()函数的PL/SQL代码块
vClobclob;
vLongStringvarchar2(32767);
vOffSetpls_integer:=0;
vLengthpls_integer:=0;
vTablevarchar2(30):=’EmpTest’;
procedureShow(pVariablevarchar2,pLineSizepls_integer:=80)
is
begin
dbms_output.enable(1000000);
if(length(pVariable)>pLineSize)
then
dbms_output.put_line(substr(pVariable,1,pLineSize));
Show(substr(pVariable,pLineSize1),pLineSize);
else
dbms_output.put_line(pVariable);
endif;
财管家,园,fs119.net
endShow;
begin
--获取DDL
vClob:=dbms_metadata.get_ddl(’TABLE’,upper(vTable));
--获取CLOB长度
vLength:=dbms_lob.GetLength(vClob);
dbms_output.put_line(’DDLlength:’||to_char(vLength));
vOffSet:=1;
dbms_lob.read(vClob,vLength,vOffSet,vLongString);
--关闭CLOB
if(dbms_lob.isOpen(vClob)>0)
then
dbms_lob.close(vClob);
endif;
Show(vLongString,80);
end;
列表1生成下面的输出信息:
CREATETABLE"BORIS"."EMPTEST"
("EMPNO"NUMBER(*,0)NOTNULLENABLE,
"LASTNAME"VARCHAR2(30)NOTNULLENABLE,
"FIRSTNAME"VARCHAR2(20)NOTNULLENABLE,
"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(isActivein(0,1))ENABLE,
CONSTRAINT"EMPTEST_PK"PRIMARYKEY("EMPNO")
USINGINDEXPCTFREE10INITRANS2MAXTRANS255
STORAGE(INITIAL65536NEXT1048576MINEXTENTS1MAXEXTENTS2147483645
PCTINCREASE0FREELISTS1FREELISTGROUPS1BUFFER_POOLDEFAULT)
TABLESPACE"TOOLS"ENABLE,CONSTRAINT"EMPTEST_AK1"UNIQUE("LASTNAME","FIRSTNAME")
USINGINDEXPCTFREE10INITRANS2MAXTRANS255
STORAGE(INITIAL65536NEXT1048576MINEXTENTS1MAXEXTENTS2147483645
PCTINCREASE0FREELISTS1FREELISTGROUPS1BUFFER_POOLDEFAULT)
TABLESPACE"TOOLS"ENABLE)PCTFREE10PCTUSED40INITRANS1
MAXTRANS255NOCOMPRESSLOGGING
STORAGE(INITIAL65536NEXT1048576MINEXTENTS1MAXEXTENTS2147483645
PCTINCREASE0FREELISTS1FREELISTGROUPS1BUFFER_POOLDEFAULT)
TABLESPACE"TOOLS"
它运行的情况太好了,返回的数据表的DDL字符串带有主键EmpTest_PK、备用键EmpTest_AK1和检查约束EmpTest_CK1。它建立了两个唯一的索引来支持主键和备用键约束。这不是你需要的结果:你需要一个表,但是为了加快数据载入速度,它不要包含约束和索引。只有在数据载入工作完成以后,你才建立索引和约束。
保证对象的定义独立的另外一个原因在于灵活性:你可能需要改变对象建立的次序。
现在可以设计一个数据结构来存储对象的元数据了。
财软联盟 fs119.net
财软联,盟,fs119.net
财管.家园.fs119.net
元数据存储器:MetaDataPkg程序包规范
首先,你必须建立记录类型来存储独立的对象(例如数据表、索引等)的所有必要信息:
subtypetStringisvarchar2(30);
subtypetDBStringisvarchar2(255);
subtypetDBLongStringisvarchar2(4000);
subtypetLongStringisvarchar2(32767);
typetArrayLongStringistableoftLongString
indexbypls_integer;
typetMetaObjectisrecord
(
aNametString,
aTypetString,
aLoggingtString,
aParalleltString,
aStatustString,
aValidatedtString,
aRelytString,
aDDLStringtLongString
);
tMetaObject属性保存了下面一些信息:
·aName:对象的名称,例如EMPTEST_PK1。
·aType:对象的类型,例如’YES’(分区的)/’NO’(分区的)(用于表)、’UNIQUE’/’NONUNIQUE’(用于索引)、约束类型’P’/’U’/’C’/’R’(用于约束)。
·aLogging:对象的日志选项,例如’LOGGING’/’NOLOGGING’(用于表和索引)。
·aParallel:对象的平行程度(用于表和索引)。
·AStatus:对象的状态,例如’VALID’/’UNUSABLE’用于索引、’Y’(备份了)/’N’(未备份)用于表。
·AValidated:对象的验证选项,例如’VALIDATED’/’NOTVALIDATED’(用于约束)。
·ARely:对象的依赖选项,例如’RELY’/’NORELY’(用于约束)。
·ADDLString:对象的定义SQL字符串。
现在你必须定义一个相关的数组类型,它能够列举出某种类型的对象,从保存tMetaObject类型的多个对象,例如,所有的EmpTest索引:
typetArrayMetaObjectistableoftMetaObject
indexbypls_integer;
下一步需要建立一个记录类型,它包含了数据表表自身(aTable)的tMetaObject属性和三个tArrayMetaObject属性:一个用于索引(aIndexes),一个用于约束(aConstraints),一个用于触发器(aTriggers): 财管家 园 fs119.net
typetFullMetaObjectisrecord
(
aTabletMetaObject,
aIndexestArrayMetaObject,
aConstraintstArrayMetaObject,
aTriggerstArrayMetaObject
);
tFullMetaObject对象类型保存了单个表的全部对象的元数据。最后,位于顶层的类型是tFullMetaObject数组。TarrayFullMetaObjectByString类型是tFullMetaObject的一个表,索引类型是varchar2(30)。
列表2:MetaDataPkg程序包规范
用如下的方式建立或更新MetaDataPkg:
cEnabledconstantchar(7):=’ENABLED’;
cDisabledconstantchar(8):=’DISABLED’;
cUsableconstantchar(6):=’USABLE’;
cUnusableconstantchar(8):=’UNUSABLE’;
cValidconstantchar(5):=’VALID’;
cInvalidconstantchar(7):=’INVALID’;
cTableconstantchar(5):=’TABLE’; 财软联盟.fs119.net
cViewconstantchar(4):=’VIEW’;
cIndexconstantchar(5):=’INDEX’;
cConstraintconstantchar(10):=’CONSTRAINT’;
cTriggerconstantchar(7):=’TRIGGER’;
cLobTypeconstantchar(3):=’LOB’;
cClobTypeconstantchar(4):=’CLOB’;
cBlobTypeconstantchar(4):=’BLOB’;
cPackageconstantchar(7):=’PACKAGE’;
cPackageBodyconstantchar(12):=’PACKAGEBODY’;
cProcedureconstantchar(9):=’PROCEDURE’;
cFunctionconstantchar(8):=’FUNCTION’;
cSequenceconstantchar(8):=’SEQUENCE’;
cSynonymconstantchar(7):=’SYNONYM’;
cTypeconstantchar(4):=’TYPE’;
cColumnconstantchar(6):=’COLUMN’;
cJavaSourceconstantchar(11):=’JAVASOURCE’;
cJavaClassconstantchar(10):=’JAVACLASS’;
cYesconstantchar(3):=’YES’;
cNoconstantchar(2):=’NO’;
cPKConsTypeconstantchar(1):=’P’;
cUNConsTypeconstantchar(1):=’U’;
cFKConsTypeconstantchar(1):=’R’;
cCKConsTypeconstantchar(1):=’C’;
cDropStorageconstantchar(12):=’DROPSTORAGE’; 财管家园.fs119.net
cReuseStorageconstantchar(13):=’REUSESTORAGE’;
cCascadeconstantchar(19):=’CASCADECONSTRAINTS’;
cNoCascadeconstantchar(10):=’NOCASCADE’;
cEnableconstantchar(6):=’ENABLE’;
cNovalidateconstantchar(10):=’NOVALIDATE’;
cRelyconstantchar(4):=’RELY’;
cNoRelyconstantchar(6):=’NORELY’;
cValidatedconstantchar(9):=’VALIDATED’;
cNotValidatedconstantchar(13):=’NOTVALIDATED’;
cLoggingconstantchar(7):=’LOGGING’;
cNoLoggingconstantchar(9):=’NOLOGGING’;
cParallelconstantchar(8):=’PARALLEL’;
cNoParallelconstantchar(10):=’NOPARALLEL’;
cNullconstantchar(4):=’NULL’;
cNotNullconstantchar(8):=’NOTNULL’;
cDefaultconstantchar(7):=’DEFAULT’;
cSYSPrefixconstantchar(4):=’SYS_’;
cDoubleQuoteconstantchar(1):=’"’;
subtypetStringisvarchar2(30);
subtypetDBStringisvarchar2(255);
subtypetDBLongStringisvarchar2(4000);
subtypetLongStringisvarchar2(32767);
typetArrayLongStringistableoftLongString
indexbypls_integer; 财软联 盟 fs119.net
typetMetaObjectisrecord
(
aNametString,
aTypetString,
aLoggingtString,
aParalleltString,
aStatustString,
aValidatedtString,
aRelytString,
aDDLStringtLongString
);
typetArrayMetaObjectistableoftMetaObject
indexbypls_integer;
typetFullMetaObjectisrecord
(
aTabletMetaObject,
aIndexestArrayMetaObject,
aConstraintstArrayMetaObject,
aTriggerstArrayMetaObject
);
typetArrayFullMetaObjectByStringistableoftFullMetaObject
indexbyvarchar2(30);
procedureLoad
(
pTableintString,
pForceinboolean:=false
);
procedureReset
(
pTableintString
);
procedureReset;
functionGetMeta
(
pTableintString,
pForceinboolean:=false
)
returntFullMetaObject;
functionGetMeta
returntArrayFullMetaObjectByString;
procedureSetMeta
(
pTableintString,
pFullMetaObjectintFullMetaObject
);
procedureSetMeta
(
pArrayFullMetaObjectByStringintArrayFullMetaObjectByString 财管家.园.fs119.net
);
procedureShow
(
pTableintString
);
procedureShow;
endMetaDataPkg;
上面的类型对象是作为元数据存储器的,用于存放多个表的完整的元数据信息集合。所有上面的类型都包含在程序包规范中(列表2所示)。我还介绍了下面一些API:
·MetaDataPkg.Load()过程:把特定表的元数据信息载入存储器中。
·MetaDataPkg.GetMeta()函数:它从存储器中检索tFullMetaObject类型的对象。
·MetaDataPkg.SetMeta()过程(重载的):把对象的元数据存储到存储器中。
·MetaDataPkg.Reset过程(重载的):对存储器复位。
·MetaDataPkg.Show过程(重载的):显示存储器的内容。
财,软联盟,fs119.net
财,管家园,fs119.net
财管 家园 fs119.net
实现所有这些事务的代码 财软联盟.fs119.net 财 软联盟 fs119.net
列表3显示了MetaDataPkg程序包主体代码的一些解释。私有过程SetEnvironment()包含了所有的环境设置代码。在程序包的初始化部分会调用这个过程,因此在每个对话中它都只执行一次,符合你的需求(你希望在开头设置一次)。程序包提供了用于设置环境参数的API:DBMS_METADATA.SET_TRANSFORM_PARAM()过程。
列表3:MetaDataPkg程序包主体
vMetaDatatArrayFullMetaObjectByString;
procedureSetEnvironment
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( 财管家园.fs119.net
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);
endSetEnvironment;
procedurePrint
(
pStringvarchar2,
pLineSizepositive:=80
)
is
vLineSizepls_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,pLineSize1),vLineSize);
else
dbms_output.put_line(pString);
endif;
endPrint;
procedureShow
(
pMetaObjectintMetaObject
)
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(’DDLString:’||pMetaObject.aDDLString,255);
dbms_output.put_line(’***’);
endShow;
functionGetDDL
(
pNameintString,
pTypeintString
)
returntLongString
is
vClobclob;
vLongStringstArrayLongString;
vFullLengthpls_integer:=0;
vOffSetpls_integer:=0;
vLengthpls_integer:=0;
begin
vClob:=dbms_metadata.get_ddl(pType,upper(pName));
vFullLength:=dbms_lob.GetLength(vClob);
fornIndexin1..ceil(vFullLength/32767)
loop
vOffSet:=vLength1;
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),’’)));
endloop;
if(dbms_lob.isOpen(vClob)>0)
then
dbms_lob.close(vClob);
endif;
returnvLongStrings(1);
endGetDDL;
functionObjectExists
(
pObjectNameintString,
pObjectTypeintString,
pTableNameintString:=null
)
returnboolean
is
vCountpls_integer:=0;
vObjectNametString:=ltrim(rtrim(pObjectName));
vObjectTypetString:=upper(ltrim(rtrim(pObjectType)));
vTableNametString:=upper(ltrim(rtrim(pTableName)));
begin
case
whenvObjectType=cColumn
then
selectcount(*)
intovCount
fromDual
whereexists(select’1’
fromuser_tab_columns
wherecolumn_name=upper(vObjectName)
andtable_name=vTableName);
whenvObjectType=cConstraint
then
selectcount(*)
intovCount
fromDual
whereexists(select’1’
fromuser_constraints
whereconstraint_name=upper(vObjectName)
andtable_name=vTableName);
whenvObjectTypein(cJavaSource,cJavaClass)
then
selectcount(*)
intovCount
fromDual
whereexists(select’1’
fromuser_objects
whereobject_name=vObjectNameandobject_type=vObjectType);
else
selectcount(*)
intovCount
fromDual
whereexists(select’1’
fromuser_objects
whereobject_name=upper(pObjectName)
andobject_type=vObjectType);
endcase;
return(vCount>0);
endObjectExists;
procedureLoad
(
pTableintString,
pForceinboolean:=false
)
is
vFullMetaObjecttFullMetaObject;
vTabletString:=upper(ltrim(rtrim(pTable)));
vCountpls_integer:=0;
begin
if(notvMetaData.exists(vTable)ornvl(pForce,false))
then 财软联盟,fs119.net
ifnotObjectExists(pTable,cTable)
then
raise_application_error(-20500,
’Unabletoloadmetadatafor’||nvl(pTable,’NULL’)||
’.’||’Tabledoesnotexist.’
);
endif;
forrecin(selecttable_name,
logging,
ltrim(rtrim(degree))asdegree,
partitioned,
backed_up
fromuser_tables
wheretable_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);
endloop;
forrecin(selectindex_name,
uniqueness,
logging,
ltrim(rtrim(degree))asdegree,
status
fromuser_indexes
wheretable_name=vTable
andindex_type!=cLobType)
loop
vCount:=vCount1;
vFullMetaObject.aIndexes(vCount).aName:=rec.index_name; 财管.家园.fs119.net
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);
endloop;
vCount:=0;
forrecin(selectconstraint_name,constraint_type,status,search_condition,validated,relyfrom user_constraintswheretable_name=vTable
orderbydecode(constraint_type,
cPKConsType,10,
cUNConsType,20,
cFKConsType,30,
cCKConsType,40,
100),
constraint_name)
loop
vCount:=vCount1;
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; 财管家 园 fs119.net
vFullMetaObject.aConstraints(vCount).aValidated:=rec.validated;
vFullMetaObject.aConstraints(vCount).aRely:=rec.rely;
ifsubstr(rec.constraint_name,1,length(cSYSPrefix))=cSYSPrefixand
upper(rec.search_condition)like’%IS’||cNotNull||’%’
then
vFullMetaObject.aConstraints(vCount).aDDLString:=
’ALTERTABLE’||cDoubleQuote||vFullMetaObject.aTable.aName||cDoubleQuote||’’||
’MODIFY’||replace(rec.search_condition,’IS’||cNotNull,cNotNull)||
(casewhenvFullMetaObject.aConstraints(vCount).aValidated=cNotValidated
then’’||cNovalidate
else’’end);
else
vFullMetaObject.aConstraints(vCount).aDDLString:=GetDDL(rec.constraint_name,cConstraint);
endif;
endloop;
SetMeta(pTable,vFullMetaObject);
endif;
endLoad;
procedureReset
(
pTableintString
)
is
begin
vMetaData.delete(pTable);
endReset;
procedureReset
is
begin
vMetaData.delete;
endReset;
functionGetMeta
(
pTableintString,
pForceinboolean:=false
)
returntFullMetaObject
is
begin
if(notvMetaData.exists(pTable)ornvl(pForce,false))
then
Load(pTable,pForce);
ifnotvMetaData.exists(pTable)
then
raise_application_error(-20501,’Unabletofindmetadatafor’||pTable||’inrepository.’);
endif;
endif;
returnvMetaData(pTable);
endGetMeta;
functionGetMeta
returntArrayFullMetaObjectByString
is
begin
returnvMetaData;
endGetMeta;
procedureSetMeta
(
pTableintString,
pFullMetaObjectintFullMetaObject
)
is
begin
vMetaData(pTable):=pFullMetaObject;
endSetMeta;
procedureSetMeta
(
pArrayFullMetaObjectByStringintArrayFullMetaObjectByString
)
is
begin
vMetaData:=pArrayFullMetaObjectByString;
endSetMeta;
procedureShow
(
pTableintString 财软联,盟,fs119.net
)
is
vFullMetaObjecttFullMetaObject;
begin
if(vMetaData.exists(pTable))
then
dbms_output.enable(1000000);
vFullMetaObject:=vMetaData(pTable);
dbms_output.put_line(’StartFullObject:’||pTable);
dbms_output.put_line(’StartTable:’||pTable);
Show(vFullMetaObject.aTable);
dbms_output.put_line(’FinishTable:’||pTable);
dbms_output.put_line(’StartIndexes:’||pTable);
if(vFullMetaObject.aIndexes.count>0)
then
fornIndexinvFullMetaObject.aIndexes.first..vFullMetaObject.aIndexes.last
loop
Show(vFullMetaObject.aIndexes(nIndex));
endloop;
endif;
dbms_output.put_line(’FinishIndexes:’||pTable);
dbms_output.put_line(’StartConstraints:’||pTable);
if(vFullMetaObject.aConstraints.count>0)
then
fornIndexinvFullMetaObject.aConstraints.first..vFullMetaObject.aConstraints.last
loop
Show(vFullMetaObject.aConstraints(nIndex));
endloop;
endif;
dbms_output.put_line(’FinishConstraints:’||pTable);
dbms_output.put_line(’StartTriggers:’||pTable); 财.管家园.fs119.net
if(vFullMetaObject.aTriggers.count>0)
then
fornIndexinvFullMetaObject.aTriggers.first..vFullMetaObject.aTriggers.last
loop
Show(vFullMetaObject.aTriggers(nIndex));
endloop;
endif;
dbms_output.put_line(’FinishTriggers:’||pTable);
dbms_output.put_line(’FinishFullObject:’||pTable);
endif;
endShow;
procedureShow
is
vTabletString;
begin
ifvMetaData.count>0
then
dbms_output.put_line(’TotalMetaObjects:’||to_char(vMetaData.count));
vTable:=vMetaData.first;
while(vTableisnotnull)
loop
Show(vTable);
vTable:=vMetaData.next(vTable);
endloop;
endif;
endShow;
begin
SetEnvironment;
endMetaDataPkg;
下面的代码防止输出信息采用缩排或换行格式化:
财管家园 fs119.net 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中。它还禁止独立的ALTERTABLE语句(如果必要,还可以禁止CREATEINDEX语句)来生成数据表约束:
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
vTableMetaDataPkg.tString:=’EmpTest’;
vRunStartTimenumber;
begin
vRunStartTime:=dbms_utility.get_time; 财软.联盟.fs119.net
MetaDataPkg.Load(vTable,true);
MetaDataPkg.Show();
dbms_output.put_line(’TimeElapsed:’||
to_char((dbms_utility.get_time-vRunStartTime)/100)||’sec.’);
end;
列表4显示了前面的代码的输出信息。
你可以看到,这段代码把EmpTest数据表和其索引、约束的全部元数据信息载入到存储器中,并在一秒钟之内把它检索出来了。你现在拥有了一个用于开发自动的解决方案的API了,它可以进行任何数据维护操作,包括更名、转换和删除数据库对象。 财管,家园,fs119.net
Google.cn搜索相关文章:
谷歌中搜索全球网 Oracle中提取和存储数据库对象的DDL
百度中搜索 Oracle中提取和存储数据库对象的DDL
谷歌中搜索www.fs119.net Oracle中提取和存储数据库对象的DDL
下一篇:PL/SQL实现Oracle数据库任务调度
