Ganesh Prasad (ganesh.prasad@reply2.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
(eventhose 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
taxas 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.
Theextra attribute "dept" should be ignored, because the query is on the "employee" class, not the "manager" class.
Regularselects 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
tothe 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
tothe 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
onthe 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
polymorphismsays that any invocation of "getTax()", even on the parent class (employee), should yield different results
fordifferent employees (having the same salary) depending on whether the particular employee is a manager or not. The
appropriatemethod 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
PostgreSQLwithout 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