PL/SQL - Oracle 9i

Contributed by Chris Rathman

Shape Class (shape-type.sql)

SET SERVEROUTPUT ON;

-- kind of a silly quirk in that can't recompile super class unless you drop subclasses first
DROP TYPE circle;
DROP TYPE rectangle;

CREATE OR REPLACE TYPE shape AS OBJECT(
   x NUMBER,
   y NUMBER,
   MEMBER FUNCTION getX RETURN NUMBER,
   MEMBER FUNCTION getY RETURN NUMBER,
   MEMBER PROCEDURE setX(newx NUMBER),
   MEMBER PROCEDURE setY(newy NUMBER),
   MEMBER PROCEDURE moveTo(newx NUMBER, newy NUMBER),
   MEMBER PROCEDURE rMoveTo(deltax NUMBER, deltay NUMBER),
   MEMBER PROCEDURE draw
) NOT FINAL NOT INSTANTIABLE;
/
SHOW ERRORS;

EXIT;

Shape Implementation (shape-body.sql)

SET SERVEROUTPUT ON;

CREATE OR REPLACE TYPE BODY shape AS
   -- accessors for x and y coordinates
   MEMBER FUNCTION getX RETURN NUMBER AS
   BEGIN
      RETURN x;
   END;
   MEMBER FUNCTION getY RETURN NUMBER AS
   BEGIN
      RETURN y;
   END;
   MEMBER PROCEDURE setX(newx NUMBER) AS
   BEGIN
      x := newx;
   END;
   MEMBER PROCEDURE setY(newy NUMBER) AS
   BEGIN
      y := newy;
   END;

   -- move the shape position
   MEMBER PROCEDURE moveTo(newx NUMBER, newy NUMBER) AS
   BEGIN
      setX(newx);
      setY(newy);
   END;
   MEMBER PROCEDURE rMoveTo(deltax NUMBER, deltay NUMBER) AS
   BEGIN
      moveTo(deltax + getX(), deltay + getY());
   END;

   -- abstract draw method
   MEMBER PROCEDURE draw AS
   BEGIN
      NULL;
   END;
END;
/
SHOW ERRORS;

EXIT;

Rectangle Class (rectangle-type.sql)

SET SERVEROUTPUT ON;

CREATE OR REPLACE TYPE rectangle UNDER shape(
   width NUMBER,
   height NUMBER,
   CONSTRUCTOR FUNCTION rectangle(x NUMBER, y NUMBER, width NUMBER, height NUMBER)
      RETURN SELF AS RESULT,
   MEMBER FUNCTION getWidth RETURN NUMBER,
   MEMBER FUNCTION getHeight RETURN NUMBER,
   MEMBER PROCEDURE setWidth(newwidth NUMBER),
   MEMBER PROCEDURE setHeight(newheight NUMBER),
   OVERRIDING MEMBER PROCEDURE draw
);
/
SHOW ERRORS;

EXIT;

Rectangle Implementation (rectangle-body.sql)

SET SERVEROUTPUT ON;

CREATE OR REPLACE TYPE BODY rectangle AS
   -- constructor
   CONSTRUCTOR FUNCTION rectangle(x NUMBER, y NUMBER, width NUMBER, height NUMBER)
      RETURN SELF AS RESULT AS
   BEGIN
      SELF.moveTo(x, y);
      setWidth(width);
      setHeight(height);
      RETURN;
   END;

   -- accessors for width and height
   MEMBER FUNCTION getWidth RETURN NUMBER AS
   BEGIN
      RETURN width;
   END;
   MEMBER FUNCTION getHeight RETURN NUMBER AS
   BEGIN
      RETURN height;
   END;
   MEMBER PROCEDURE setWidth(newwidth NUMBER) AS
   BEGIN
      width := newwidth;
   END;
   MEMBER PROCEDURE setHeight(newheight NUMBER) AS
   BEGIN
      height := newheight;
   END;

   -- draw the rectangle
   OVERRIDING MEMBER PROCEDURE draw AS
   BEGIN
      DBMS_OUTPUT.PUT_LINE('Drawing a Rectangle at:(' || SELF.getX() || ',' || SELF.getY() ||
         '), Width ' || getWidth() || ', Height ' || getHeight());
   END;
END;
/
SHOW ERRORS;

EXIT;

Circle Interface (circle-type.sql)

SET SERVEROUTPUT ON;

CREATE OR REPLACE TYPE circle UNDER shape(
   radius NUMBER,
   CONSTRUCTOR FUNCTION circle(x NUMBER, y NUMBER, radius NUMBER)
      RETURN SELF AS RESULT,
   MEMBER FUNCTION getRadius RETURN NUMBER,
   MEMBER PROCEDURE setRadius(newradius NUMBER),
   OVERRIDING MEMBER PROCEDURE draw
);
/
SHOW ERRORS;

EXIT;

Circle Implementation (circle-body.sql)

SET SERVEROUTPUT ON;

CREATE OR REPLACE TYPE BODY circle AS
   -- constructor
   CONSTRUCTOR FUNCTION circle(x NUMBER, y NUMBER, radius NUMBER)
      RETURN SELF AS RESULT AS
   BEGIN
      SELF.moveTo(x, y);
      setRadius(radius);
      RETURN;
   END;

   -- accessors for the radius
   MEMBER FUNCTION getRadius RETURN NUMBER AS
   BEGIN
      RETURN Radius;
   END;
   MEMBER PROCEDURE setRadius(newradius NUMBER) AS
   BEGIN
      radius := newradius;
   END;

   -- draw the circle
   OVERRIDING MEMBER PROCEDURE draw AS
   BEGIN
      DBMS_OUTPUT.PUT_LINE('Drawing a Circle at:(' || SELF.getX() || ',' || SELF.getY() ||
         '), Radius ' || getRadius());
   END;
END;
/
SHOW ERRORS;

EXIT;

Try shapes procedure (polymorph.sql)

SET SERVEROUTPUT ON;

DECLARE
   TYPE ShapeCollection IS TABLE OF shape;
   scribble ShapeCollection;
   rect rectangle;
   i PLS_INTEGER;
BEGIN
   -- create some shape instance
   scribble := ShapeCollection(rectangle(10, 20, 5, 6), circle(15, 25, 8));

   -- iterate through the list and handle shapes polymorphically
   FOR i IN scribble.FIRST..scribble.LAST LOOP
      scribble(i).draw();
      scribble(i).rMoveTo(100, 100);
      scribble(i).draw();
   END LOOP;

   -- call a rectangle specific function
   rect := rectangle(0, 0, 15, 15);
   rect.setWidth(30);
   rect.draw();
END;
/
SHOW ERRORS;

EXIT;

Output

SQL*Plus: Release 9.2.0.1.0 - Production on Wed Aug 13 10:59:06 2003

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.


Connected to:
Personal Oracle9i Release 9.2.0.1.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.1.0 - Production

Drawing a Rectangle at:(10,20), Width 5, Height 6
Drawing a Rectangle at:(110,120), Width 5, Height 6
Drawing a Circle at:(15,25), Radius 8
Drawing a Circle at:(115,125), Radius 8
Drawing a Rectangle at:(0,0), Width 30, Height 15

PL/SQL procedure successfully completed.

No errors.
Disconnected from Personal Oracle9i Release 9.2.0.1.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.1.0 - Production

Chris Rathman / Chris.Rathman@tx.rr.com