constructor в Oracle9

SQL во всех проявлениях - от ANSI-92 до TSQL.

Модераторы: Yurich, Absurd

Ответить
cahek2000
Сообщения: 5
Зарегистрирован: 29 дек 2004, 06:48

Недавно перешел на 9ый оракл, решил опробовать более продвинутую технологию - объектно-ориентированную СУБД. Но сразу же столкнулся с проблемой: у объектов в оракле есть конструктор по умолчанию, а мне бы желательно его перегрузить и обработать по-своему. Причем при описании типа все проходит нормально, без ошибок. А вот когда уже пытаюсь создать экземпляр объекта, то возникает ошибка PLS-00307.
Чтобы было более понятно, привожу небольшой пример:

Описание типа:
create or replace type Obj as object
(
n number,
constructor function Obj(n1 number) return Self as result
) not final;

create or replace type body Obj as
constructor function Obj(n1 number) return Self as result is
begin
n := n1 * 2;
end;
end;


PL/SQL блок:
declare
o Obj := Obj(1); -- Здесь ошибка
begin
dbms_output.put_line('n = ' || o.n); -- Должно быть 2
end;

Вопрос:
Как же все таки можно перегрузить конструктор по умолчанию????
Аватара пользователя
Naeel Maqsudov
Сообщения: 2570
Зарегистрирован: 20 фев 2004, 19:17
Откуда: Moscow, Russia
Контактная информация:

У меня тоже на получилось.
Интереснее выглядит эксперимент, когда количество аргументов в конструкторе не равно числу полей (свойств) объекта:

Код: Выделить всё

create or replace type Obj as object(
n number,
constructor function Obj return self as result
)
/
create or replace type body Obj as
  constructor function Obj return Self as result is
  begin
    self.n:=2;
  end;
end;
/

Получается

Код: Выделить всё

SQL> declare
  2    o Obj;
  3  begin
  4    o:=Obj;
  5    dbms_output.put_line('n = ' || o.n);
  6  end;
  7  /
declare
*
ERROR at line 1:
ORA-06503: PL/SQL: Function returned without value
ORA-06512: at "HR.OBJ", line 4
ORA-06512: at line 4
Но если сделать Obj(X) то все работает, как будто стандартный конструктор не переопределился!

Код: Выделить всё

SQL> ed
Wrote file AFIEDT.BUF

  1  declare
  2    o Obj;
  3  begin
  4    o:=Obj(1);
  5    dbms_output.put_line('n = ' || o.n);
  6* end;
SQL> /

PL/SQL procedure successfully completed.

SQL> set serveroutput on;
SQL> /
n = 1

PL/SQL procedure successfully completed.
Аватара пользователя
Naeel Maqsudov
Сообщения: 2570
Зарегистрирован: 20 фев 2004, 19:17
Откуда: Moscow, Russia
Контактная информация:

Т.е., если правильнопонимамю прорисходящее, при
o:=Obj;
Моя функция вызывается, но она как бы не является конструкторорм и ничего не возвращает, а
o:=Obj(1);
работает, так как стандартный конструктор так и не отменился.
Аватара пользователя
Naeel Maqsudov
Сообщения: 2570
Зарегистрирован: 20 фев 2004, 19:17
Откуда: Moscow, Russia
Контактная информация:

ЭВРИКА!
Я копал в нужную сторону - в сторону количества аргументов!
Я пошерстил доки и применил пример оттуда. Все отлично работает.

Код: Выделить всё

SQL> CREATE OR REPLACE TYPE rectangle AS OBJECT
  2  (
  3  -- The type has 3 attributes.
  4    length NUMBER,
  5    width NUMBER,
  6    area NUMBER,
  7  -- Define a constructor that has only 2 parameters.
  8    CONSTRUCTOR FUNCTION rectangle(length NUMBER, width NUMBER)
  9      RETURN SELF AS RESULT
 10  );
 11  /

Type created.

SQL> CREATE OR REPLACE TYPE BODY rectangle AS
  2    CONSTRUCTOR FUNCTION rectangle(length NUMBER, width NUMBER)
  3      RETURN SELF AS RESULT
  4    AS
  5    BEGIN
  6      SELF.length := length;
  7      SELF.width := width;
  8  -- We compute the area rather than accepting it as a parameter.
  9      SELF.area := length * width;
 10      RETURN;
 11    END;
 12  END;
 13  /

Type body created.

SQL> DECLARE
  2    r1 rectangle;
  3    r2 rectangle;
  4  BEGIN
  5  -- We can still call the default constructor, with all 3 parameters.
  6    r1 := NEW rectangle(10,20,200);
  7  -- But it is more robust to call our constructor, which computes
  8  -- the AREA attribute. This guarantees that the initial value is OK.
  9    r2 := NEW rectangle(10,20);
 10  END;
 11  /

PL/SQL procedure successfully completed.
Получается, что стандартный конструктор не переопределяется. Имеется только возможность создавать альтернативные конструкторы...
cahek2000
Сообщения: 5
Зарегистрирован: 29 дек 2004, 06:48

Это очень криво, если нельзя переопределить стандартный конструктор!
Теряется смысл ООП!! Зачем я буду мучиться создавать альтернативные конструкторы с правильной обработкой всех данных, если какой-нить крендель возмет создаст объект при помощи стандартного конструктора!!
Должнобыть какой-нить волшебное ключевое слово, или какой-нить нестандартный обход через энное место. Но я уверен, что стандартный конструктор можно перебить! Нужно только коллективно подумать или поискать!
Аватара пользователя
Naeel Maqsudov
Сообщения: 2570
Зарегистрирован: 20 фев 2004, 19:17
Откуда: Moscow, Russia
Контактная информация:

При переопределении стандартного в 9.2.0.3 стабильно натыкаемся на PLS-00307.
Коллеги! Если у кого-то есть, скажем, 9.2.0.6 - попробуйте сделать тоже, что cahek2000 может это просто баг такой.
Кроме того, никак не удается создать конструктор с нулевым количеством аргументов.

В документации ничего не нашел кроме упомянутого выше.
cahek2000
Сообщения: 5
Зарегистрирован: 29 дек 2004, 06:48

Как бы это странно не звучало, но ответ на этот вопрос я нашел в доке по 9ому ораклу! ))
Когда я нашел пример:

Код: Выделить всё

CREATE OR REPLACE TYPE shape AS OBJECT
(
    name VARCHAR2(30),
    area NUMBER,
    CONSTRUCTOR FUNCTION shape(name VARCHAR2) RETURN SELF AS RESULT,
    CONSTRUCTOR FUNCTION shape(name VARCHAR2, area NUMBER) RETURN
      SELF AS RESULT
) NOT FINAL;

CREATE OR REPLACE TYPE BODY shape IS
    CONSTRUCTOR FUNCTION shape(name VARCHAR2) RETURN SELF AS RESULT IS
    BEGIN
        SELF.name := name;
        SELF.area := 0;
        return;
    END;
    CONSTRUCTOR FUNCTION shape(name VARCHAR2, area NUMBER) RETURN shape
    SELF AS RESULT IS
    BEGIN
        SELF.name := name;
        SELF.area := area;
        return;
    END;
END;
я честно говоря засовмевался, что он будет работать, но после проверки был удивлен, что все работает на ура! Попробовал поизменять код второго конструктора ( SELF.area := area * 3; ), и все опять работает без ошибок и как надо!...
Вобщем повозившись с ним побольше я выяснил, что если хотя бы одно из имен параметров пользовательского конструктора не совпадает с именем соответствующего поля объекта (или их порядок), то получаем ошибку PLS-00307!
Так что дерзайте!!!
Ответить