Inheritance of functions shows unexpected behaviour

From: pgsql-bugs(at)postgresql(dot)org
To: pgsql-bugs(at)postgresql(dot)org
Subject: Inheritance of functions shows unexpected behaviour
Date: 2001-04-30 05:37:53
Message-ID: 200104300537.f3U5brK62902@hub.org
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

Ganesh Prasad (ganesh(dot)prasad(at)reply2(dot)com) reports a bug with a severity of 2
The lower the number the more severe it is.

Short Description
Inheritance of functions shows unexpected behaviour

Long Description
This is an example to demonstrate a possible bug in the inheritance behaviour of the PostgreSQL object model.
You can run the test yourself to see if the behaviour is as expected.

The installation should be PostgreSQL 7.1 with PL/pgSQL installed.

If a class (table) has a method (function) defined, then we should be able to invoke it on all instances of that class (even those of any inherited class), because they are all instances of the parent class as well.

Take a class "employee" with key "id" and attributes "name" and "salary". Define a function "getTax()" that calculates tax as 20% of salary.

Invocation of "getTax()" on instances of the "employee" class should yield correct results.

Now define a subclass of "employee" called "manager" with one extra attribute "dept", and insert a record into it.

The "getTax()" method *should* continue to work for all instances of "employee", because managers are employees too. The extra attribute "dept" should be ignored, because the query is on the "employee" class, not the "manager" class. Regular selects seem to ignore the extra attribute.

However, invocation of "getTax()" fails on the "employee" class for records corresponding to "manager".

STEPS:

1. Run the script "setup.sql". This creates the two tables, populates them with a record each, and creates the function "getTax()".

2. Run the script "test1.sql". This invokes the "getTax()" method on the "employee" table for the record corresponding to the parent class itself (employee). The following output should occur:

gettax
--------
20000
(1 row)

3. Run the script "test2.sql". This invokes the "getTax()" method on the "employee" table for the record corresponding to the child class (manager). The following (unexpected) output occurs:

ERROR: query didn't return correct # of attributes for $1

Apparently, the extra attribute "dept" defined for manager is somehow affecting the result. But why? When the query is on the parent class, all instances should behave like instances of the parent class.

Is this a bug?

COROLLARY:

If we now define a "getTax()" function on the "manager" class that calculates tax differently (say 25% of salary), then polymorphism says that any invocation of "getTax()", even on the parent class (employee), should yield different results for different employees (having the same salary) depending on whether the particular employee is a manager or not. The appropriate method should be transparently used.

Is this considered desirable behaviour? What would the function definition be like? If the function is defined for "manager", then how can it override the corresponding function defined for "employee"?

Resolution of this "bug" is vey important as it has implications for implementing object persistence directly in PostgreSQL without the need for Object-Relational mapping (say) in a Container-Managed Entity Bean (EJB).

Sample Code
setup.sql:

drop table t_manager;
drop table t_employee;

/*
Employees have an id (key), a name and a salary.
*/
create table t_employee
(
id int4 primary key,
name varchar(50) not null,
salary float8
);

/*
Managers are employees who manage a department.
*/
create table t_manager
(
dept char(2)
)
inherits (t_employee);

/*
An ordinary employee.
*/
insert into t_employee
values
(
1,
'Joe Bloggs',
100000.0
);

/*
A manager.
*/
insert into t_manager
values
(
2,
'John Doe',
150000.0,
'HR'
);

/*
A "method" defined for the "employee" class,
which should be inherited by the "manager" class.
*/
drop function getTax( t_employee );
create function getTax( t_employee ) returns float8 as '
declare
emp alias for $1;
begin
return emp.salary * 0.2 ;
end;
' language 'plpgsql';

test1.sql:

/*
The "method" is correctly invoked for an ordinary employee.
*/
select getTax( t_employee ) from t_employee where id = 1;

test2.sql:

/*
The "method" fails for managers, who should have inherited it
from employees.
*/
select getTax( t_employee ) from t_employee where id = 2;

No file was uploaded with this report

Responses

Browse pgsql-bugs by date

  From Date Subject
Next Message Tom Lane 2001-04-30 05:52:57 Re: Re: can external C-function get multiple rows?
Previous Message Bruce Momjian 2001-04-30 02:29:57 Re: DECIMAL NULL value