在做exp的时候,我们可以做owner级的导出,导出该用户下的所有对象。owner级的导出,会导出所有的表,不太容易排除单独的一些表;而如果做table级的导出,就必须列出所有的table,且当数据库有增加新table的时候,也得把新增的table加到exp的列表中。
今天收到一个客户的要求,做owner级别的导出,但是需要排除几张大表。该需要做成定时的脚本每天执行。
其实,如果在10g中用数据泵,这个exclude很方便处理,但是在9i中,用什么方法才能把某些表单独排除呢?原来我们可以用FGAC来实现。
一、在这里,我们假设我们需要对用户mytest做owner级导出。
SQL>createusermytestidentifiedbymytestdefaulttablespaceusers;
?
用户已创建。
?
SQL>grantconnect,resourcetomytest;
?
授权成功。
?
SQL>
SQL>connmytest/mytest
已连接。
SQL>
SQL>
SQL>createtablet1asselect*fromdual;
?
表已创建。
?
SQL>
SQL>
SQL>createtablet2asselect*fromall_objects;
?
表已创建。
?
SQL>selecttable_namefromuser_tables;
?
TABLE_NAME
------------------------------
T1
T2
?
SQL>
二、新建一个用户用于做exp的导出,新建该用户的目的是:该用户只是用来做exp导出,而不修改原来的dba用户或者application用户来做exp导出:
SQL>createuserexpuseridentifiedbyexpuserdefaulttablespaceusers;
?
用户已创建。
?
SQL>grantconnect,resource,dbatoexpuser;
?
授权成功。
?
SQL>
三、建立exclude_table 函数:
SQL>connexpuser/expuser
已连接。
SQL>CREATEorREPLACEFUNCTIONexclude_table(obj_schemaVARCHAR2,
?2? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?obj_name?
?VARCHAR2)
?3? ?RETURNVARCHAR2IS
?4? ?d_predicateVARCHAR2(2000);
?5?BEGIN
?6? ?ifsys_context('USERENV','SESSION_USER')='EXPUSER'THEN
?7? ? ?d_predicate:='1=2';
?8? ?else
?9? ? ?d_predicate:='';
?10? ?endif;
?11? ?RETURNd_predicate;
?12?ENDexclude_table;
?13? /
?
函数已创建。
?
SQL>
这个函数用来控制用户对某个表的访问,FGAC大致的功能是利用dbsm_rls部署一些策略(policy),这些策略会调用一些函数,比如上面我定义的那个exclude_table函数,利用函数,来使得普通执行的sql后面加上谓词。
比如,某sql是:
selecttable_namefromdba_tables;
被细粒度权限控制之后,这个sql语句会自动在后面加上where的谓词做过滤,变成类似:
selecttable_namefromdba_tableswhereowner='MYUSER';
因此,当被细粒度权限控制之后,就算执行select table_name from
dba_tables;也只能出现owner=’MYUSER’的表。
回到上面的exclude_table函数,大致的意思就是当操作的用户是EXPUSER的时候,就在操作的语句后面加1=2,我们知道1=2为非真,因此能select出来的结果肯定是0行。因此,这样就类似的实现了我们对某些表做exp的时候,不导出数据的目的。
好,我们继续把这个函数的功能加到mytest用户下的t1表上。我们用dbms_rls.add_policy来实现,我们先看一下这个过程的参数:
PROCEDUREADD_POLICY
参数名称? ? ? ? ? ? ? ? ? ? ? ?类型? ? ? ? ? ? ? ? ? ? 输入/输出默认值?
------------------------------ ----------------------- ------
--------
?OBJECT_SCHEMA? ? ? ? ? ? ? ? ?VARCHAR2? ? ? ? ? ? ? ?IN? ?
?DEFAULT
?OBJECT_NAME? ? ? ? ? ? ? ? ? ?VARCHAR2? ? ? ? ? ? ? ?IN
?POLICY_NAME? ? ? ? ? ? ? ? ? ?VARCHAR2? ? ? ? ? ? ? ?IN
?FUNCTION_SCHEMA? ? ? ? ? ? ? ?VARCHAR2? ? ? ? ? ? ? ?IN? ?
?DEFAULT
?POLICY_FUNCTION? ? ? ? ? ? ? ?VARCHAR2? ? ? ? ? ? ? ?IN
?STATEMENT_TYPES? ? ? ? ? ? ? ?VARCHAR2? ? ? ? ? ? ? ?IN? ?
?DEFAULT
?UPDATE_CHECK? ? ? ? ? ? ? ? ? ?BOOLEAN? ? ? ? ? ? ? ? ?IN? ?
?DEFAULT
?ENABLE? ? ? ? ? ? ? ? ? ? ? ? ?BOOLEAN? ? ? ? ? ? ? ? ?IN? ?
?DEFAULT
?STATIC_POLICY? ? ? ? ? ? ? ? ?BOOLEAN? ? ? ? ? ? ? ? ?IN? ?
?DEFAULT
?POLICY_TYPE? ? ? ? ? ? ? ? ? ?BINARY_INTEGER? ? ? ? ?IN? ?
?DEFAULT
?LONG_PREDICATE? ? ? ? ? ? ? ? ?BOOLEAN? ? ? ? ? ? ? ? ?IN? ?
?DEFAULT
?SEC_RELEVANT_COLS? ? ? ? ? ? ?VARCHAR2? ? ? ? ? ? ? ?IN? ?
?DEFAULT
?SEC_RELEVANT_COLS_OPT? ? ? ? ?BINARY_INTEGER? ? ? ? ?IN? ?
?DEFAULT
?
几个主要字段的解释:
object_schema:用来做细粒度访问控制对象所对应的用户,如果为空则默认是当前用户。
object_name:用来做细粒度访问控制对象(可以是表,或视图或同义词)
policy_name:策略名,可自定义。但是如果对同一表或者视图,策略名必须唯一。但是如果是不同用户下的同一个表或者视图,可以用相同的策略名。
function_schema:自定义函数的用户,该用户应该有权限能调用之前我们建立的那个函数。如果为空,则默认是当前用户。
policy_function:函数名,即之前我们自己定义谓词的函数,如果函数定义在包里面,则这里也需写上包的名字。
statement_types:操作的类型,如select,insert,update或delete,如果为空,则默认是所有类型的操作。
因此对于排除mytest用户下的t1表,我们可以执行:
SQL>execdbms_rls.add_policy(OBJECT_SCHEMA=>'MYTEST',OBJECT_NAME=>'T1',POLICY_NAME=>'POL_T1',FUNCTION_SCHEMA=>'EXPUSER'
,POLICY_FUNCTION=>'EXCLUDE_TABLE');
?
PL/SQL过程已成功完成。
?
SQL>
上述的结果可以用这个sql去检查:
SQL>selectOBJECT_OWNER,OBJECT_NAME,POLICY_GROUP,POLICY_NAME,PF_OWNER,FUNCTIONfromdba_policies
?2?wherePF_OWNER='EXPUSER';
?
OBJECT_OWNOBJECT_NAMPOLICY_GROUP? ? ? ? ? ? ? ? ?
?POLICY_NAMPF_OWNER? ?FUNCTION
---------- ---------- ------------------------------ ----------
---------- ------------------------------
MYTEST? ? ?T1? ? ? ? ?SYS_DEFAULT? ? ? ? ? ? ? ? ? ?POL_T1? ?
?EXPUSER? ?EXCLUDE_TABLE
?
SQL>
四、好,我们现在来测试owner级导出:
1、我们先测试一下select操作:
SQL>connsystem/manager
已连接。
SQL>select*frommytest.t1;
?
D
-
X
?
SQL>
SQL>connexpuser/expuser
已连接。
SQL>select*frommytest.t1;
?
未选定行
?
SQL>
这里的区别已经很明显的看出来了。
2、最后我们来实现我们的需求,按照owner级的导出,却排除t1表:
C:>expexpuser/expuserowner=mytestfile=mytest.dmplog=mytest.log;
?
Export:Release10.2.0.1.0-Productionon星期五1月722:25:342011
?
Copyright(c)1982,2005,Oracle.?Allrightsreserved.
?
?
连接到:OracleDatabase10gEnterpriseEditionRelease10.2.0.1.0-Production
WiththePartitioning,OLAPandDataMiningoptions
已导出ZHS16GBK字符集和AL16UTF16NCHAR字符集
?
即将导出指定的用户...
. 正在导出pre-schema过程对象和操作
. 正在导出用户MYTEST的外部函数库名
. 导出PUBLIC类型同义词
. 正在导出专用类型同义词
. 正在导出用户MYTEST的对象类型定义
即将导出MYTEST的对象...
. 正在导出数据库链接
. 正在导出序号
. 正在导出簇定义
. 即将导出MYTEST的表通过常规路径...
EXP-00079:
表"T1"中的数据是被保护的。常规路径只能导出部分表。
. . 正在导出表? ? ? ? ? ? ? ? ? ? ? ? ? ? ?T1导出了? ? ? ? ? ?0行
EXP-00091: 正在导出有问题的统计信息。
. . 正在导出表? ? ? ? ? ? ? ? ? ? ? ? ? ? ?T2导出了? ? ? ?38250行
. 正在导出同义词
. 正在导出视图
. 正在导出存储过程
. 正在导出运算符
. 正在导出引用完整性约束条件
. 正在导出触发器
. 正在导出索引类型
. 正在导出位图, 功能性索引和可扩展索引
. 正在导出后期表活动
. 正在导出实体化视图
. 正在导出快照日志
. 正在导出作业队列
. 正在导出刷新组和子组
. 正在导出维
. 正在导出post-schema过程对象和操作
. 正在导出统计信息
导出成功终止, 但出现警告。
?
C:>
我们看到t1表导出了0行(但是表结构还是被导出的)。
五、取消FGAC。
取消很容易,执行执行dbms_rls中的drop_policy即可:
SQL>execdbms_rls.drop_policy(OBJECT_SCHEMA=>'MYTEST',OBJECT_NAME=>'T1',POLICY_NAME=>'POL_T1');
?
PL/SQL过程已成功完成。
?
SQL>
