OOW US Travel Tips for ACE Director – Visa, Hotel, Car Rental, etc.

因为我个人是比较早接受Oracle邀请去美国旧金山参加Oracle Open World的ACE Director,而且又带老婆一块儿去过,也租车自驾过,总体来说经验比较丰富,把这些经验写出来,希望对新的ACED会有帮助。

一. 大致流程
6月到7月之间,所有的ACE Director会收到一封邀请参加当年在旧金山举办的Oracle Open World的邮件,在邮件里面会有一个URL需要点进去接受这个邀请,链接里面会有一些问题需要回答,邮件里面也会明确说明接受这个邀请的Deadline日期,所以如果想去参加那么一定要早些接受邀请。

8月中旬,所有接受了邀请的ACE Director又会再收到一封邮件,这次是要注册OOW了,这封邮件会比较长,有很多需要作的事情,后面详细解释。

9月底或者10月初,一年一度的OOW在旧金山举办,主会场永远是旧金山市中心的Moscone Center,ACED入住的酒店永远是Hilton Union Square,从酒店可以步行到会场,中间会路过旧金山的Apple Store。

二. 签证
很多人担心签证会不过,但是就我的经验,参加OOW的签证申请还没有被拒签过,对于首次作美国签证的ACED来说,最好是要Oracle发一封正式邀请函传真件过来(其实心大一些,用Oracle发过来的邀请邮件打印版也是可以的),如果你想带夫人一起前往,那么可以要求邀请函的抬头写上你跟你夫人两个人的名字。

如果不是首次去,那么其实根本就无需等Oracle发给你邀请,觉得时间差不多,就可以自己申请签证了。

今年美国签证的整体流程都发生了变化,需要在CGI网站上先注册预约,然后再进行后续步骤。对于首次签证的需要面签,对于已有签证并且失效不超过4年的(4年哦,48个月呢)只需要让中信银行代传递材料即可。

简单描述一下流程,由于新版流程以后,我不需要面签,因此对于面签流程不熟悉。以下描述为”代传递“流程。
1. 在线填DS160表格,表格比较冗长,不在这里描述了,初填者大概要花1个小时吧。其中有个姓名的telecode,可以通过标准中文电码网站查询。最后有一个Confirmation页面,这个页面要打印出来,上面的确认编号也要记好,后面有用。

2. CGI网站注册,然后登录进去,开始CGI预约。
1) 点击左边菜单最上面的“安排面谈时间”,开始填。
Screen Shot 2013-08-13 at 12.56.27 AM
2) 选择预约使馆时,如果是第一次,选择离你工作地点最近的使馆,如果不需要面签,那么选择最后一项“免面谈代传递服务”。
Screen Shot 2013-08-13 at 12.58.48 AM
3) 签证类型选择Businese/Tours,也就是B1/B2,又表示参加会议又表示要游玩,我一直是这么选的,当然你也可以只选择B1。
4) 填信息的页面有一个地方需要输入DS160确认编号。
5) 到Step 7的时候出现BUG了,无论你在预约类型那里选的是不是“免面谈代传递服务”,这里都会问“是否在DS-160签证申请表格上选择“中国,广州”作为您此次签证的申请地点?”,这里要点“是”,才可以进入到下面的问题,否则就直接进入预约面谈日期的界面了。
6) 指定护照/文件送达地址选择里面,都是中信银行的位置,选择一个离你最近的即可。
7) 进入录入收据编号的页面了,收据是个什么东西?签证是要签证费的,不到1000人民币,交了费就给你一个收据,上面有个编号就是收据编号,以前是直接去中信银行缴纳,现在可以直接在网上交了,点击“点击这里选择付款选项”。
Screen Shot 2013-08-21 at 3.48.09 PM
然后选择右边的“中国中信银行”。即使是准备网上缴费也要选择中信银行,而不是左边的“借记卡”,不要被“在银行柜台付款”的字样迷惑了。
Screen Shot 2013-08-21 at 3.48.26 PM
然后就可以到中信金融商城中去网上缴费,缴费完毕以后返回Step 8的页面自动就帮你填入收据编号了。注意这个页面最上方的CGI Reference Number在缴款的时候是有用的。网上很多人问CGI Number到底从哪里查?就是在这儿。
Screen Shot 2013-08-21 at 3.48.40 PM

8) 最后就是”DropBox Confirmation“页面,点击”可打印版本“,然后打印出来。

3. 把材料带齐去中信银行,交给柜台即可。材料包括:
1) DS160表格确认页;
2) DropBox Confirmation打印页;
3) 护照;
4) 一张美国签证专用照片(要求6个月内近照,但是我还是用去年的照片也OK)。

4. 大约6-8个工作日之后,签证会办好,寄回你之前在CGI网站选择的地址,并且有邮件通知你去取。
Screen_Shot_2013-08-15_at_6.40.13_PM
邮件大致如上面所示,不要被其中不专业的翻译“退回”所吓到,实际上英文是Returned,记好邮件中提到的UID,到了中信银行,告诉他们UID和你的姓名,很快你就可以拿到盖着热腾腾的亚美利加VISA的护照了。

三. 机票酒店
ACED的机票Oracle会帮买,不用自己买,但是如果要带其它人一起去,切记切记最重要的一点,越早买机票越好。三四月份就定的话,直飞大约能拿到往返6000多的价格,五六月份订大约是往返8000多,现在8月份我查大约是12000,再往后就没谱了。
1. 拒签的可能性很小,不需要一定等着签证出来了,再去买机票。
2. 即使被拒签,大不了就是退票,退票费大约1500人民币,但是如果一直等到签证办完再出机票,那么一定不止贵了1500元,算一算,也知道越早买是越划算的。

因为ACED自己的机票酒店,都是Oracle帮助预订的,因此实际上对于ACED自己来说,需要自己搞定的就是美国VISA而已,其它的只需要按照Oracle的节奏一步一步该注册的注册,该发邮件的发邮件即可。以下简单描述让Oracle帮助预订机票酒店的步骤。

1. Oracle处理全球所有ACED行程的人似乎只有美国总部的大美女Lillian一个人,因此节奏有些慢是正常的,给Lillian发邮件她没时间回复也是正常的,不用着急,只要是ACED,每年一定会被邀请到,也一定会被Approve,所以根本无需担心是不是会被批准啊这样的问题。
2. 在前面的大致流程中也提到,6月到7月之间,会收到一个邀请参加OOW的邮件,按照这封邮件的指引,在某个网站回答一些问题,只是表示你愿意接受邀请,之后很长时间会没有任何反馈,这段时间是Oracle在准备OOW,所以等着就好了。
3. 到了8月中旬,Oracle的OOW准备也差不多有眉目了,这时候所有的ACED又会收到一封邮件,这封邮件的内容就丰富了,要做的事情也很多。

首先这封邮件会描述在整个OOW期间专门为ACED准备的活动日程,“Oracle ACE Activities during Oracle OpenWorld”部分。其中最重要的两个活动是:
ACE Director Product Briefing:这是一个通常会在OOW的前两天举行的一个两天的小型会议,邀请全球的ACED参加,在这个会议上会有Oracle各个产品线的总监级人物,预先透露一些会在OOW中宣布的产品新特性,回答ACED的问题,这实际上是给ACED与Oracle更近的交流距离。这个会议会在Oracle总部举行,因此如果想去膜拜一下Oracle总部大楼的话,应该去参加。要知道OOW是在旧金山举办,离Oracle总部所在的Redwood Shore实际上是两个城市了,有不近的距离。
Annual Oracle ACE Dinner:就是饭局了,通常是在OOW第一天的晚上,会有车把所有参加的ACED拉到一个地方,每年吃饭的地方不太一样,如果想认识全球更多的ACED,或者跟老熟人扯扯淡,这个饭局是要去参加的。我通常都在这个饭局里面邀请来年能够来中国参加Oracle技术嘉年华大会的演讲嘉宾。

接下来这封邮件会提到注册OOW,“BLOGGER REGISTRATION”部分。点击邮件里的链接即可,通常每个ACED都是blogger,因此都会注册blogger类型的OOW入场券,blogger类型的入场券适用范围最广,不但可以参加OOW还可以参加Java One,而且在Larry作Keynote的现场会有专门的一个区域,配备了桌椅让你一边听一边发推。跟着注册页面走就行了,会看到门票价格已经自动变为0美元。注册完毕以后,会立刻收到一封确认邮件,主题类似于“Oracle San Francisco 2013 Registration Confirmation”,这封邮件明确提到“Please note that your registration is not confirmed until you receive that approval e-mail.”,也就是这封邮件只是表示收到了你的OOW注册请求,还没有被正式批准,要等下一封批准邮件。但是不用担心,一定会被批准的。

再接下来,需要作的事情就是申请机票,“TRAVEL RESERVATIONS”部分。Oracle的机票预订是交给专门的公司CWT来完成的,邮件中会提到给某个美国电话打电话,或者发邮件到一个地址,对于中国人来说通常都是选择发邮件了。
邮件内容大致应该包括:Group#(这是最重要的,邮件中会提到这个#,因为你的名字已经预先包含在这个Group#中,CWT收到这个#才知道你是ACED来预订机票的),出发和返回的日期,期望乘坐的航班号,乘机人姓名,护照号。
我一般会选国航的CA985(北京-旧金山)和CA986(旧金山-北京),每天一班北京-旧金山往返的飞机,选择国航的一个好处是,如果有国航知音卡,往返一趟美国的积分大约可以换一张去国内任何一个城市的机票了。
发出邮件以后,通常在48小时之内就会有邮件回复,如果你的行程拉的比较长(比如参加完OOW还想在美国玩一段时间),那么可能会遇到说由于你回程太晚,机票价格贵了,所以要额外再提交审批,请你等待。等着就好。

而对于酒店预订,“HOTEL ACCOMMODATIONS”部分,先不要着急,要等着收到了注册OOW的批准邮件之后,再去更新自己的Profile,那时候就会看到有Add Hotel的链接,点进去,输入邮件中提到的专门给ACED提供的预订码(booking code)。
Screen Shot 2013-08-20 at 3.14.40 AM
然后就会自动将Hilton Union Square酒店显示出来了,点选你的入住和离店日期,之后还需要输入一个信用卡号,虽然可以看到每天晚上有数百美金的房费,但是不用担心,预订是不会charge信用卡钱的,入住完毕结账的时候也不会扣款,房费直接会从Oracle结算。

对于参加ACE Director Product Briefing的ACED,不需要任何预订流程,Oracle会自动安排好入住的酒店,到了以后直接入住即可。今年是在Redwood Shores的Sofitel,酒店的名字在邮件中可以找到。

四. 租车
欧洲的租车网站会很便宜,不确定是什么原因,这些网站都是聚合了Herz, Alamo, Dollar, Fox等租车公司的信息,可以从容比价。我最常用的是两个网站,一个是Carhire 3000,通常这个网站的价格是最便宜的,需要用欧元结账;另外一个网站是Holiday Cars,这个网站上Fox租车公司的SUV出奇的便宜,有时候会比普通小车还便宜。

在美国租车有几点需要考虑:
1. 保险:这两个网站租车都带了所有的基本保险。如果要购买额外的人身保险还是很贵的,建议直接在国内买个国外旅游险就OK了。
2. 额外驾驶员:基本价格通常都只有一个驾驶员,有些会写着包含了Additioanl Driver,如果没写,那么期望多个人开车的时候,要另行购买,否则如果被美国警察拦住,可能会被罚的很惨。我们没遇到过。
3. 一箱油:交车给你的时候,都是一箱满油,有些是换车的时候不论是不是油箱空了,都要再直接付一箱油钱;有些是换车的时候,你自己找个地方加满就好了,因为租车公司卖出来的一箱油通常较贵,因此两种方法会有细微的差别,但是相差无几,所以不用考虑过多。
4. GPS:如果你没有自带GPS,也没有美国的朋友可以借给你,那么就需要租一个,每天大约10美金,也不便宜。

五. 其它Tips
1. 到了酒店以后,是要出示信用卡的,为了有额外的消费时可以直接扣款(Oracle只负责每晚基本的房费)。
2. Hilton Union Square的房间宽带网络是要额外付费的,而且是按每个Device收费的,也就是一台笔记本,一个手机算两个Device。如果不想交钱可以到一楼大厅用免费的Wifi。
3. 美国酒店退房一般不需要退还房卡,直接走人就可以了。如果有任何额外消费,酒店会自动从你入住时出示的信用卡中扣款。
4. 美国是小费国家,入住酒店以后通常每天早上要在枕头上放1美元留给房间服务员,当然,如果你死活不愿意放也不会有什么事儿。

【未完待续】

【Oracle Database 12c New Feature】Advanced Security – Oracle Data Redaction

1. 什么是Oracle Data Redaction
不确认正式的中文翻译是什么,我翻译为数据改写。这是一项在12c中出现的Oracle高级安全新组件,其作用是限制SQL语句的返回结果样式,对于特定的用户可以限制某些字段显示被自动改写过的值。这是一项非常有用的安全功能,而在12c之前如果要实现相同的功能,可能需要创建特定的视图,或者在存储到数据库的时候就用加密算法进行加密。而12c的数据改写功能则在最后数据返回到客户端的前一刻将数据改写,这并不会影响到数据真实的存储。看一个简单的例子就明白了。

原本存储的数据记录如下:

SQL> select * from EMPLOYEES;

EMPLOYEE_ID FIRST_NAME           LAST_NAME                 SOCIAL_SECU     SALARY
----------- -------------------- ------------------------- ----------- ----------
        100 Steven               King                      247-85-9056       7000
        101 Neena                Kochhar                   334-08-6578       5000

在设置完Data Redaction之后,再次执行相同的语句,可以看到有隐私性质的列-社会保障号被遮盖了,只显示最后4位,这就实现了安全的目的。

SQL> select * from kamus.employees;

EMPLOYEE_ID FIRST_NAME           LAST_NAME                 SOCIAL_SECU     SALARY
----------- -------------------- ------------------------- ----------- ----------
        100 Steven               King                      ***-**-9056       7000
        101 Neena                Kochhar                   ***-**-6578       5000

2. 如何设置Oracle Data Redaction
设置用户的合适权限,由于Oracle Redaction对于DBA用户不起效果,因此需要将DBA角色收回。

revoke dba from kamus;
grant connect, resource, unlimited tablespace to kamus;
grant select on sys.redaction_policies to kamus;
grant select on sys.redaction_columns to kamus;
grant execute on dbms_redact to kamus;

创建测试环境,包括测试表和测试数据。

CREATE TABLE "EMPLOYEES" (
"EMPLOYEE_ID" NUMBER(6,0), 
"FIRST_NAME" VARCHAR2(20), 
"LAST_NAME" VARCHAR2(25), 
"SOCIAL_SECURITY" VARCHAR2(11), 
"SALARY" NUMBER(4,0)
)
/

Insert into EMPLOYEES (EMPLOYEE_ID,FIRST_NAME,LAST_NAME,SOCIAL_SECURITY,SALARY) values (100,'Steven','King','247-85-9056',7000);
Insert into EMPLOYEES (EMPLOYEE_ID,FIRST_NAME,LAST_NAME,SOCIAL_SECURITY,SALARY) values (101,'Neena','Kochhar','334-08-6578',5000);
commit;

SQL> select * from EMPLOYEES;

EMPLOYEE_ID FIRST_NAME           LAST_NAME                 SOCIAL_SECU     SALARY
----------- -------------------- ------------------------- ----------- ----------
        100 Steven               King                      247-85-9056       7000
        101 Neena                Kochhar                   334-08-6578       5000

Oracle Redaction针对单张表的某个字段进行设置,分别通过ADD_POLICY存储过程的object_name和column_name来控制;Redaction有多种类型,第一种为FULL,也就是完全改写,对于字符类型的字段将改写为一个空格,对于数字类型的字段改写为0,对于日期类型的字段改写为2001-01-01,类型通过function_type参数来控制。

BEGIN
DBMS_REDACT.ADD_POLICY (
   object_schema          => 'KAMUS',
   object_name            => 'EMPLOYEES',
   policy_name            => 'REDACT_EMP',
   column_name            => 'SOCIAL_SECURITY',
   function_type          => DBMS_REDACT.FULL,
   expression             => '1=1',
   enable                 => TRUE
   );
END;
/

SQL> select * from employees;

EMPLOYEE_ID FIRST_NAME           LAST_NAME                 SOCIAL_SECU     SALARY
----------- -------------------- ------------------------- ----------- ----------
        100 Steven               King                                        7000
        101 Neena                Kochhar                                     5000

Redaction的第二种类型是RANDOM,对于字符类型的字段将改写为随机字符,对于数字类型的字段改写为具有相同长度的随机数字,对于日期类型的字段改写为随机日期(永远不会跟真实日期相同)。

BEGIN
DBMS_REDACT.ALTER_POLICY (
   object_schema          => 'KAMUS',
   object_name            => 'EMPLOYEES',
   policy_name            => 'REDACT_EMP',
   column_name            => 'SOCIAL_SECURITY',
   action                 => DBMS_REDACT.MODIFY_COLUMN,
   function_type          => DBMS_REDACT.RANDOM
);
END;
/

SQL> select * from kamus.employees;

EMPLOYEE_ID FIRST_NAME           LAST_NAME                 SOCIAL_SECU     SALARY
----------- -------------------- ------------------------- ----------- ----------
        100 Steven               King                      wa};w~ZC i&       7000
        101 Neena                Kochhar                   Q9N]##T/YAV       5000

Redaction的第三种类型是PARTIAL,将改写为按照function_parameters参数指定的格式。

BEGIN
DBMS_REDACT.ALTER_POLICY (
   object_schema          => 'KAMUS',
   object_name            => 'EMPLOYEES',
   policy_name            => 'REDACT_EMP',
   column_name            => 'SOCIAL_SECURITY',
   action                 => DBMS_REDACT.MODIFY_COLUMN,
   function_type          => DBMS_REDACT.PARTIAL,
   function_parameters    => 'VVVFVVFVVVV,VVV-VV-VVVV,*,1,5'
);
END;
/

SQL> select * from kamus.employees;

EMPLOYEE_ID FIRST_NAME           LAST_NAME                 SOCIAL_SECU     SALARY
----------- -------------------- ------------------------- ----------- ----------
        100 Steven               King                      ***-**-9056       7000
        101 Neena                Kochhar                   ***-**-6578       5000

3. 如何精细化设置哪些用户才启用数据改写
通过expression参数设置,比如如下所示,所有不是KAMUS的用户都启用在EMPLOYEES.SOCIAL_SECURITY字段上的数据改写,而如果是KAMUS用户进行检索,则还是返回真实的数据。

BEGIN
DBMS_REDACT.ALTER_POLICY (
   object_schema          => 'KAMUS',
   object_name            => 'EMPLOYEES',
   policy_name            => 'REDACT_EMP',
   column_name            => 'SOCIAL_SECURITY',
   action                 => DBMS_REDACT.MODIFY_EXPRESSION,
   expression             => 'SYS_CONTEXT ( ''USERENV'',''SESSION_USER'' ) !=''KAMUS'''
);
END;
/

expression参数非常灵活,通过此参数可以使Data Redaction发挥巨大的作用。expression参数可选值如下图所示。
Screen Shot 2013-07-31 at 6.27.12 PM

4. 如何增加数据改写策略
通过DBMS_REDACT.ALTER_POLICY存储过程可以增加多个字段的数据改写策略,比如下例,增加在SALARY字段上的全数据改写。

BEGIN
DBMS_REDACT.ALTER_POLICY (
   object_schema          => 'KAMUS',
   object_name            => 'EMPLOYEES',
   policy_name            => 'REDACT_EMP',
   column_name            => 'SALARY',
   action                 => DBMS_REDACT.ADD_COLUMN,
   function_type          => DBMS_REDACT.FULL,
   expression             => 'SYS_CONTEXT ( ''USERENV'',''SESSION_USER'' ) !=''KAMUS'''
);
END;
/

SQL> select * from kamus.employees;

EMPLOYEE_ID FIRST_NAME           LAST_NAME                 SOCIAL_SECU     SALARY
----------- -------------------- ------------------------- ----------- ----------
        100 Steven               King                      ***-**-9056          0
        101 Neena                Kochhar                   ***-**-6578          0

5. 数据改写到底是发生在哪一阶段,有哪些限制

--where条件中的字段并不会受数据改写影响,可以看到即使最后都是显示SALARY=0,但是where条件还是正常执行并筛选出正确结果的。
SQL> select * from kamus.employees where SALARY>5000;

EMPLOYEE_ID FIRST_NAME           LAST_NAME                 SOCIAL_SECU     SALARY
----------- -------------------- ------------------------- ----------- ----------
        100 Steven               King                      ***-**-9056          0

SQL> select * from kamus.employees where SALARY<5000;

no rows selected

SQL> select * from kamus.employees where SALARY=5000;

EMPLOYEE_ID FIRST_NAME           LAST_NAME                 SOCIAL_SECU     SALARY
----------- -------------------- ------------------------- ----------- ----------
        101 Neena                Kochhar                   ***-**-6578          0

--在启用了数据改写策略的表上无法进行全表的CTAS操作。
SQL> create table t as select * from kamus.employees;
create table t as select * from kamus.employees
                         *
ERROR at line 1:
ORA-28081: Insufficient privileges - the command references a redacted object.

--如果CTAS操作中的字段上没有启用数据改写策略,CTAS可以正常进行。
SQL> create table t as select EMPLOYEE_ID,FIRST_NAME from kamus.employees;

Table created.

SQL> drop table t;

Table dropped.

--如果包含了启用数据改写策略的列,则会报ORA-28081错误。
SQL> create table t as select EMPLOYEE_ID,FIRST_NAME,SALARY from kamus.employees;
create table t as select EMPLOYEE_ID,FIRST_NAME,SALARY from kamus.employees
                                                *
ERROR at line 1:
ORA-28081: Insufficient privileges - the command references a redacted object.

【Oracle Database 12c New Feature】How to Learn Oracle (12c New Feature) from Error

这篇文章也许并不太牵涉什么技术点,只是描述一下我自己在学习的时候大概是什么状态,什么思路,因为自认自己的学习能力还不错,因此也期望这样的学习方法对其他人会有帮助。看这篇文章的时候,你可以同步地想一想如果是你遇到这样的错误,你会怎么处理,怎么发散,怎么研究?

Oracle Database 12c前几天正式发布了,如果学习一个新版本的数据库?我通常是从New Features Guide文档看起,先通览文档的目录,遇到感兴趣的新功能点,就开始做实验来验证这个新功能。当然,这之前需要先把新版本的数据库安装好,先把新版本的全部文档下载到本地,这样即使你坐在飞机上也可以有文档可查。

这次我的计划是实验一下Identity类型的字段,这个字段可以用来作主键,会自动递增,这种类型的字段在SQL Server中早就存在,但是Oracle直到12c才推出这个功能。

通常我不会用sys用户进行任何实验(除非是验证sysdba的新功能),因此总是会先创建一个我自己的dba用户。
在12c中创建这个用户首先就遇到了错误。

SQL> create user kamus identified by oracle default tablespace users;
create user kamus identified by oracle default tablespace users
            *
ERROR at line 1:
ORA-65096: invalid common user or role name

对于一个不熟悉的错误,第一件事情不是去Google(如果你说Baidu那就更幼稚了),而是用oerr实用程序来看看Oracle自己对这个错误是怎么解释的。为什么我喜欢非Windows环境中的Oracle?oerr的存在也是很大一个原因。

[oracle@dbserver-oel ~]$ oerr ora 65096
65096, 00000, "invalid common user or role name"
// *Cause:  An attempt was made to create a common user or role with a name
//          that wass not valid for common users or roles.  In addition to
//          the usual rules for user and role names, common user and role
//          names must start with C## or c## and consist only of ASCII
//          characters.
// *Action: Specify a valid common user or role name.
//

错误信息的解析非常明确地告知“试图创建一个通用用户,必需要用C##或者c##开头”,这时候心里会有疑问,什么是common user?但是我通常不会先急着去翻文档,而是先把手头的事情做完,也就是先把用户创建上。

SQL> create user c##kamus identified by oracle default tablespace users;

User created.

SQL> grant dba to c##kamus;

Grant succeeded.

SQL> select USERNAME,COMMON,ORACLE_MAINTAINED from dba_users;

USERNAME                       COM O
------------------------------ --- -
AUDSYS                         YES Y
GSMUSER                        YES Y
SPATIAL_WFS_ADMIN_USR          YES Y
SPATIAL_CSW_ADMIN_USR          YES Y
APEX_PUBLIC_USER               YES Y
SYSDG                          YES Y
DIP                            YES Y
SYSBACKUP                      YES Y
MDDATA                         YES Y
GSMCATUSER                     YES Y
C##KAMUS                       YES N
SYSKM                          YES Y
XS$NULL                        YES Y
OJVMSYS                        YES Y
ORACLE_OCM                     YES Y
OLAPSYS                        YES Y
SI_INFORMTN_SCHEMA             YES Y
DVSYS                          YES Y
ORDPLUGINS                     YES Y
XDB                            YES Y
ANONYMOUS                      YES Y
CTXSYS                         YES Y
ORDDATA                        YES Y
GSMADMIN_INTERNAL              YES Y
APPQOSSYS                      YES Y
APEX_040200                    YES Y
WMSYS                          YES Y
DBSNMP                         YES Y
ORDSYS                         YES Y
MDSYS                          YES Y
DVF                            YES Y
FLOWS_FILES                    YES Y
SYS                            YES Y
SYSTEM                         YES Y
OUTLN                          YES Y
LBACSYS                        YES Y

36 rows selected.

创建C##KAMUS用户成功之后,再返回去解决心中的疑问,什么是common user?在联机文档的左上角搜索关键字common user,会得到如下的结果。
Oracle Online Doc Search Result

通常我会先浏览Concept,如果看完觉得心中疑问已经解决,就会返回继续作之前的实验,不会再浏览其他的链接;如果想要查询怎么做,比如说如何创建Common User,才会继续去看Task部分。这样的好处是可以保持专注而不至于被过多文档分心

但是由于Common User这个概念几乎是崭新的,所以我很有兴趣继续探索一下,跟Common User相对的Local User该如何创建。继续去看Task当然是个方法,但是这里我选择的是直接去看SQL Language Reference,因为我们知道一定是在Create User语法里面会有不同的定义,进入Create User语法页面,直接搜索common user,就可以看到如下这段话。

CONTAINER Clause

To create a local user in a pluggable database (PDB), ensure that the current container is that PDB and specify CONTAINER = CURRENT. To create a common user, ensure that the current container is the root and specify CONTAINER = ALL. The name of the common user must begin with C## or c##. If you omit this clause and the current container is a PDB, then CONTAINER = CURRENT is the default. If you omit this clause and the current container is the root, then CONTAINER = ALL is the default.

也就是说我们一定要先登录进一个PDB,才可以创建本地用户,那么如何知道现在的sqlplus是登录进了哪个DB呢?这个疑问其实是一个很简单的联想,既然需要去一个地方,那么一定有方法知道我现在在什么地方,通过简单地查询文档,可以得知以下的方法。现在确实在CDB中。

SQL> show con_name

CON_NAME
------------------------------
CDBROOT

SQL> SELECT SYS_CONTEXT ('USERENV', 'CON_NAME') FROM DUAL;

SYS_CONTEXT('USERENV','CON_NAME')
-----------------------------------------------
CDBROOT

dbca建库的时候,有一个新选项是同时创建PDB,我勾选过(对于dbca中出现的新选项,如果不是条件不允许,我都会选中进行测试),创建了名字为pdbtest的PDB,那么现在我想尝试登录这个PDB,去创建一个Local User。如何登录PDB?Administrator’s Guide中有专门新的一个章节“Part VI Managing a Multitenant Environment”来描述如何管理多租户环境,浏览目录就可以直接找到“Connecting to a PDB with SQL*Plus”这部分,如下所示。

You can use the following techniques to connect to a PDB with the SQL*Plus CONNECT command:

Database connection using easy connect
Database connection using a net service name

那尝试直接使用easy connect来登录PDB。

$ sqlplus sys/oracle@127.0.0.1:15210/pdbtest as sysdba

SQL*Plus: Release 10.2.0.4.0 - Production on Sat Jul 6 21:44:42 2013

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.


Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options

SQL>  SELECT SYS_CONTEXT ('USERENV', 'CON_NAME') FROM DUAL;

SYS_CONTEXT('USERENV','CON_NAME')
------------------------------------------
PDBTEST

Elapsed: 00:00:00.01

SQL>  select NAME,PDB from dba_services;
 select NAME,PDB from dba_services
                      *
ERROR at line 1:
ORA-01219: database or pluggable database not open: queries allowed on fixed tables or views only

PDB没有Open?尝试打开。无法使用startup命令。这是显而易见的。 原因是我使用了旧版本的SQL*Plus(如上所示是10.2.0.4.0)连接到12c数据库的PDB中,某些新特性不被支持。

SQL> startup
ORA-24543: instance startup or shutdown not allowed in pluggable database

使用12c自带的SQL*Plus登录,就可以使用startup命令将PDB打开,使用SQL*Plus管理PDB的详细命令可以参看文档描述

SQL> show user
USER is "SYS"
SQL> startup
Pluggable Database opened.
SQL>
SQL> show con_name

CON_NAME
------------------------------
PDBTEST

或者可以使用如下语句打开PDB。

SQL> ALTER PLUGGABLE DATABASE OPEN;

Operation 227 succeeded.

Elapsed: 00:00:02.44

SQL> SELECT NAME, OPEN_MODE, RESTRICTED, OPEN_TIME FROM V$PDBS;

NAME			       OPEN_MODE  RES OPEN_TIME
------------------------------ ---------- --- ------------------------------------------------
PDBTEST 		       READ WRITE NO  06-JUL-13 09.48.57.260 PM

到此,可以创建Local User了。

SQL> create user kamus identified by oracle;

User created.

Elapsed: 00:00:00.10
SQL> grant dba to kamus;

Grant succeeded.

Elapsed: 00:00:00.03

那么在一个PDB中可以看到多少用户呢?可以看到CDB中的用户吗?这又是一个简单的联想,学习的过程其实是一个发散再收缩的循环。看来不可以,只能看到自己的用户,当然这里有很多Common User。可以看到即使是在PDB中,cdb_视图也是可以使用的。

SQL> select CON_ID,count(*) from cdb_users group by con_id;

    CON_ID   COUNT(*)
---------- ----------
	 3	   38

Elapsed: 00:00:00.03

那么再回到CDB中看一下,会是什么情况?可以看到所有Container中的用户都可以查询到。

SQL> select CON_ID,count(*) from cdb_users group by con_id;

    CON_ID   COUNT(*)
---------- ----------
         1         36
         2         35
         3         38

Elapsed: 00:00:00.08

终于,我可以回到最开始的实验目标上去了,在PDB中创建了T1表,id列为Identity类型。

SQL> CREATE TABLE t1 (id NUMBER GENERATED AS IDENTITY);

Table created.

Elapsed: 00:00:00.22

根据文档描述,Identity类型仍然是通过Sequence来实现的,那么应该是自动创建了一个Sequence,果然如此。在你学习的过程中会多此一步来查询一下Sequence视图吗?


默认创建的Sequence,CACHE_SIZE是20,开始值是1,这都跟单独创建的Sequence默认值一样。


插入一条数据试一下,报错报错还是报错。所以如果是generated always的identity列,如果只有这一列,没法插入数据。

SQL> insert into t1 values('');
insert into t1 values('')
*
ERROR at line 1:
ORA-32795: cannot insert into a generated always identity column


Elapsed: 00:00:00.01

SQL> insert into t1 values(ISEQ_91620.nextval);
insert into t1 values(ISEQ_91620.nextval)
*
ERROR at line 1:
ORA-32795: cannot insert into a generated always identity column


Elapsed: 00:00:00.00

SQL> insert into t1 values(null);
insert into t1 values(null)
*
ERROR at line 1:
ORA-32795: cannot insert into a generated always identity column


Elapsed: 00:00:00.00

换GENERATED BY DEFAULT ON NULL 类型试一下,Wait,如果删除了表,对应的序列会自动删除吗?理论上应该会,当然还是要测试一下。

SQL> drop table t1;

Table dropped.

Elapsed: 00:00:00.19

序列还在?


再建一张表。

SQL> CREATE TABLE t2 (id NUMBER GENERATED BY DEFAULT AS IDENTITY);

Table created.

Elapsed: 00:00:00.01

现在是2个序列了。

SQL> select * from user_sequences;

SEQUENCE_NAME															  MIN_VALUE  MAX_VALUE
-------------------------------------------------------------------------------------------------------------------------------- ---------- ----------
INCREMENT_BY C O CACHE_SIZE LAST_NUMBER PARTITION_COUNT S K
------------ - - ---------- ----------- --------------- - -
ISEQ_91620																  1 1.0000E+28
	   1 N N	 20	      1 		N N

ISEQ_91622																  1 1.0000E+28
	   1 N N	 20	      1 		N N


Elapsed: 00:00:00.00

写完整的Drop语句试一下。

SQL> drop table t2 cascade constraint purge;

Table dropped.

Elapsed: 00:00:00.12

后创建的序列已经被自动删除了,之前创建的还在。


两者的不同应该是purge,如果被删除的表还在回收站中,序列是会保留的,Make sense,因为表还可能从回收站里面再restore回来,需要保证序列仍然有效。那么清空回收站实验一下。

SQL> purge recyclebin;

Recyclebin purged.

Elapsed: 00:00:00.04

果然,序列也相应地被删除了。

SQL> select * from user_sequences;

no rows selected

Elapsed: 00:00:00.00

再回到正题,创建T3表,插入一条数据。

SQL> CREATE TABLE t3 (id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY);

Table created.

Elapsed: 00:00:00.01
SQL> insert into t3 values(null);

1 row created.

Elapsed: 00:00:00.01

序列的LAST_NUMBER已经增加为21。


后台如何操作的?使用10046 trace,再插入几条数据。

SQL> insert into t3 values(null);

1 row created.

SQL> insert into t3 values(null);

1 row created.

SQL> select * from t3;

	ID
----------
	 1
	 2
	 3

到此为止,可以休息一下了,从ORA-65096开始大概花费了1个多小时的时间,我学习到了:
1. 什么是Common User,什么是Local User?
2. 如何查询现在的环境是CDB还是某个PDB?
3. 如何登录PDB?
4. 如何启动PDB?
5. PDB和CDB中视图看到的内容有怎样的不同?
6. 如何创建Identity类型的列?
7. 删除表以后,对应的Sequence如何处理?
8. Oracle后台对于Identity列是如何处理的?

你是不是也是这样学习的呢?

Update@2013-07-15
谢谢留言中Asher的建议,增加如下测试。
使用DBMS_METADATA.GET_DDL获取到的DDL信息,已经是符合12c语法的样式了,显示出了Sequence的具体信息。

SQL> select dbms_metadata.GET_DDL('TABLE','T3') from dual;

DBMS_METADATA.GET_DDL('TABLE','T3')
--------------------------------------------------------------------------------

  CREATE TABLE "KAMUS"."T3"
   (	"ID" NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY MINVALUE 1 MAXVALUE 99
99999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER  NOCYCLE
  NOT NULL ENABLE,
	"COMMENTS" VARCHAR2(100)
   ) SEGMENT CREATION IMMEDIATE
  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 FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "USERS"

系统自动产生的序列无法手工修改属性。

SQL> alter sequence "ISEQ_91624" INCREMENT BY 10;
alter sequence "ISEQ_91624" INCREMENT BY 10
*
ERROR at line 1:
ORA-32793: cannot alter a system-generated sequence

SQL> host oerr ora 32793
32793,0000, "cannot alter a system-generated sequence"
// *Cause:  An attempt was made to alter a system-generated sequence.
// *Action: A system-generated sequence, such as one created for an
//          identity column, cannot be altered.

系统自动产生的序列也不允许删除。

SQL> drop sequence "ISEQ_91624";
drop sequence "ISEQ_91624"
              *
ERROR at line 1:
ORA-32794: cannot drop a system-generated sequence

SQL> host oerr ora 32794
32794,0000, "cannot drop a system-generated sequence"
// *Cause:  An attempt was made to drop a system-generated sequence.
// *Action: A system-generated sequence, such as one created for an
//          identity column, cannot be dropped.

在11gR2中错误信息编号在ORA-32790和ORA-32800之间是空白,而12c使用了这其间的8个错误号作为新特性的报错。

ORA-32791: prebuilt table managed column cannot have a default on null
Cause: An attempt was made to create a materialized view on a prebuilt table that has a managed column with a default on null expression.
Action: Either remove the default on null property, or do not include the column in the materialized view definition.

ORA-32792: prebuilt table managed column cannot be an identity column
Cause: An attempt was made to create a materialized view on a prebuilt table that has a managed column that is an identity column.
Action: Either remove the identity property, or do not include the column in the materialized view definition.

ORA-32793: cannot alter a system-generated sequence
Cause: An attempt was made to alter a system-generated sequence.
Action: A system-generated sequence, such as one created for an identity column, cannot be altered.

ORA-32794: cannot drop a system-generated sequence
Cause: An attempt was made to drop a system-generated sequence.
Action: A system-generated sequence, such as one created for an identity column, cannot be dropped.

ORA-32795: cannot insert into a generated always identity column
Cause: An attempt was made to insert a value into an identity column created with GENERATED ALWAYS keywords.
Action: A generated always identity column cannot be directly inserted. Instead, the associated sequence generator must provide the value.

ORA-32796: cannot update a generated always identity column
Cause: An attempt was made to update an identity column created with GENERATED ALWAYS keywords.
Action: A generated always identity column cannot be directly updated.

ORA-32797: identity column sequence mismatch in ALTER TABLE EXCHANGE PARTITION
Cause: The two tables specified in the EXCHANGE have identity columns with sequences that are neither both increasing nor decreasing.
Action: Ensure that the identity columns have sequences with INCREMENT BY having the same sign.

ORA-32798: cannot use ANSI RIGHT or FULL outer join with a left correlation
Cause: An attempt was made to use a lateral view with a left correlation to the first operand of an ANSI RIGHT or FULL outer join.
Action: Rewrite the query without the left correlation.