我无法理解Oracle DBMS的这种行为。我已经制作了两个PL / SQL类型创建示例。第一个是:
create or replace type TEST_TYPE as object (
ID CHAR(36),
NAME VARCHAR2(117 CHAR),
IS_DEFAULT CHAR(1),
APPLICATION_ORDER NUMBER(38,0),
CONSTRUCTOR FUNCTION TEST_TYPE(
ID VARCHAR2,
NAME VARCHAR2,
APPLICATION_ORDER NUMBER default 0,
IS_DEFAULT VARCHAR2 default 'N'
) RETURN SELF AS RESULT
);
CREATE OR REPLACE TYPE BODY TEST_TYPE IS
CONSTRUCTOR FUNCTION TEST_TYPE(
ID VARCHAR2,
NAME VARCHAR2,
APPLICATION_ORDER NUMBER default 0,
IS_DEFAULT VARCHAR2 default 'N'
) RETURN SELF AS RESULT IS
BEGIN
SELF.ID := ID;
SELF.NAME := NAME;
SELF.IS_DEFAULT := IS_DEFAULT;
SELF.APPLICATION_ORDER := APPLICATION_ORDER;
RETURN;
END;
END;
declare
app TEST_TYPE;
begin
app := TEST_TYPE(
'00000000-0000-0000-0000-000000000000'
,'APP_NAME'
,13
,'N'
);
end;
运作良好。但是如果你改变了构造函数参数的顺序:
create or replace type TEST_TYPE as object (
ID CHAR(36),
NAME VARCHAR2(117 CHAR),
IS_DEFAULT CHAR(1),
APPLICATION_ORDER NUMBER(38,0),
CONSTRUCTOR FUNCTION TEST_TYPE(
ID VARCHAR2,
NAME VARCHAR2,
IS_DEFAULT VARCHAR2 default 'N',
APPLICATION_ORDER NUMBER default 0
) RETURN SELF AS RESULT
);
CREATE OR REPLACE TYPE BODY TEST_TYPE IS
CONSTRUCTOR FUNCTION TEST_TYPE(
ID VARCHAR2,
NAME VARCHAR2,
IS_DEFAULT VARCHAR2 default 'N',
APPLICATION_ORDER NUMBER default 0
) RETURN SELF AS RESULT IS
BEGIN
SELF.ID := ID;
SELF.NAME := NAME;
SELF.IS_DEFAULT := IS_DEFAULT;
SELF.APPLICATION_ORDER := APPLICATION_ORDER;
RETURN;
END;
END;
declare
app TEST_TYPE;
begin
app := TEST_TYPE(
'00000000-0000-0000-0000-000000000000'
,'APP_NAME'
,'N'
,13
);
end;
此代码将导致PLS-00307错误。这真的很奇怪,因为在我需要更多VARCHAR2和默认值的实例中我必须在最后放置APPLICATION_ORDER变量以避免跟随PLS错误,但是在这个小例子代码中我必须做相反的事情。任何人都可以解释这种行为并告诉我如何避免将来出现错误吗?
答案 0 :(得分:1)
问题在于您创建自己的构造函数时,几乎(但不完全)与the default constructor具有相同的签名:
数据库隐式为您创建的每个用户定义类型定义构造函数方法。构造函数是系统提供的过程,在SQL语句或PL / SQL代码中用于构造类型值的实例。构造函数方法的名称是用户定义类型的名称。您还可以使用 constructor_spec 语法创建用户定义的构造函数。
这也称为the attribute-value constructor。
您的代码无需定义自己的构造函数即可运行:
create or replace type TEST_TYPE as object (
ID CHAR(36),
NAME VARCHAR2(117 CHAR),
IS_DEFAULT CHAR(1),
APPLICATION_ORDER NUMBER(38,0)
);
/
Type TEST_TYPE compiled
declare
app TEST_TYPE;
begin
app := TEST_TYPE(
'00000000-0000-0000-0000-000000000000'
,'APP_NAME'
,'N'
,13
);
end;
/
PL/SQL procedure successfully completed.
...但如果使用较少的参数调用,则不会获取default
值。
在第一个代码块中,您使用不同的签名定义自己的构造函数,因为参数(和数据类型)的顺序与默认值不同。使用该构造函数创建实例时,只有一个匹配,因为number
值出现在列表或参数中。
在第二个代码块中,您定义了自己的构造函数,几乎与默认签名相同。当您尝试创建类型的实例时,Oracle能够隐式转换您传递给任一构造函数的参数类型的参数,因此它无法分辨两个构造函数中的哪一个你真打算打电话;并因此抛出PLS-00307错误,因为错误消息"太多的TEST_TYPE'匹配这个电话"是对的。
你可以覆盖(或隐藏)默认构造函数but the signature has to match exactly:
[...]但是,如果用户定义的构造函数的签名与属性值构造函数的签名完全匹配,则用户定义的构造函数会隐藏并因此取代其类型的属性值构造函数。对于要匹配的签名,用户定义的构造函数的参数的名称和类型(在隐式
SELF
参数之后)必须与该类型的属性的名称和类型相同。用户定义的构造函数的参数模式(隐式SELF
参数之后)必须为IN
。
即。您必须使用char
代替varchar2
来匹配属性类型:
create or replace type TEST_TYPE as object (
ID CHAR(36),
NAME VARCHAR2(117 CHAR),
IS_DEFAULT CHAR(1),
APPLICATION_ORDER NUMBER(38,0),
CONSTRUCTOR FUNCTION TEST_TYPE(
ID CHAR,
NAME VARCHAR2,
IS_DEFAULT CHAR default 'N',
APPLICATION_ORDER NUMBER default 0
) RETURN SELF AS RESULT
);
/
Type TEST_TYPE compiled
CREATE OR REPLACE TYPE BODY TEST_TYPE IS
CONSTRUCTOR FUNCTION TEST_TYPE(
ID CHAR,
NAME VARCHAR2,
IS_DEFAULT CHAR default 'N',
APPLICATION_ORDER NUMBER default 0
) RETURN SELF AS RESULT IS
BEGIN
SELF.ID := ID;
SELF.NAME := NAME;
SELF.IS_DEFAULT := IS_DEFAULT;
SELF.APPLICATION_ORDER := APPLICATION_ORDER;
RETURN;
END;
END;
/
Type Body TEST_TYPE compiled
declare
app TEST_TYPE;
begin
app := TEST_TYPE(
'00000000-0000-0000-0000-000000000000'
,'APP_NAME'
,'N'
,13
);
end;
/
PL/SQL procedure successfully completed.
现在,默认构造函数被用户定义的构造函数隐藏,因此没有混淆。