.\" XXX standard disclaimer belongs here....
.\" $Header: RCS/definePfunction,v 1.14 91/12/02 01:42:50 kemnitz Exp $
.SP "DEFINE FUNCTION <POSTQUEL>" 6/14/90
.SS COMMANDS
.XA 2 "Define FUNCTION <POSTQUEL>"
.uh NAME
.lp
define function <POSTQUEL> \*- define a new POSTQUEL function 
.uh SYNOPSIS
.lp
.b "define function"
function_name
.b "("
language = "postquel",
.b ,
returntype = <typename>
.b ")"
.b arg 
.b as
.br
postquel-query |
.b {
list-of-postquel-queries 
.b }
.lp
.uh DESCRIPTION
.lp
The user can define a POSTQUEL function which consists
of a single postquel query or a brace-enclosed list
of postquel queries.
Via this command, the implementor of a
.b "POSTQUEL function"
can register it to POSTGRES.
Subsequently, this user is treated as the owner of the function.
.lp
When defining a POSTQUEL function,
the input data types,
.i type-1 ,
.i type-2 ,
\&...,
.i type-n 
must be specified,
along with the
queries that constitute the function.
The return type of a \*(PQ function is one of the composite types
indicated in the 
.b introduction 
(commands) section of the manual.  If not specified, then 
.i set 
is the 
default return type.
.lp
POSTQUEL functions are automatically cachable as long
as no POSTQUEL command in the function in turn contains an uncachable
function.
Lastly, functions coded in POSTQUEL are automatically trusted,
since a POSTQUEL function cannot escape from the POSTGRES 
run-time system.
.lp
POSTQUEL functions are currently available in the same
two variations allowed for C functions.  If
a POSTQUEL function is defined whose arguments are
all 
.b base
types, then this is a
.b normal
function.  
Normal functions can be used in the query language POSTQUEL
to perform computations.
The parameters to a normal function are
specified in the body of the function using
the markers, $1, ..., $n, as noted
in the example function, TP1, defined as follows:
.(l
define postquel function TP1(int4, float8) is
	replace BANK (balance = balance - $2)
	where BANK.accountno = $1
.)l
A user could execute this function to debit account 17 by $100.00
as follows:
.(l
retrieve (x = TP1( 17,100.0))
.)l
.lp
On the other hand, the first argument to
a POSTQUEL function can also be a class name, in which case
an 
.b inheritable 
function is defined.
Inheritable functions can be referenced
using either the column notation or the function
notation in POSTQUEL as explained in the example below. 
Moreover, the 
"cascaded dot"
notation available to reference composite columns is 
available for inheritable functions.
Lastly, an inheritable function takes a value for each instance in the class,
.i classname,
which is the first argument to the function.  Hence, in the
body of the function, any references to classname.attribute  
are automatically references to the corresponding data
element in the current instance of classname.  Other parameters
are denoted positionally as in normal functions.
.lp
To illustrate inheritable functions we use the
GROUPS class as follows:
.(l
create GROUPS(name = char16, age = int4)
.)l
An example inheritable function would be: 
.(l
define postquel function composition (GROUPS), 
retrieve (EMP.all)
where EMP.age > GROUPS.age
.)l
Composition has a value for each instance of GROUPS which is the query:
.(l
retrieve (EMP.all)
where EMP.age > current.age
.)l
Hence, the following 
command would define a new group 
"elders" 
whose members were over 50.
.(l
append to groups (name = "elders", age = 50)
.)l
Both of the following commands obtain the names of all
employees who are "elders". 
.(l
retrieve (GROUPS.composition.name)
where GROUPS.name = "elders"

retrieve (composition(GROUPS).name)
where GROUPS.name = "elders"
.)l
.lp
Alternately, the user can manually achieve the same
definition of the composition function 
by the following two commands:
.(l
addattr (composition = EMP) to GROUPS

define rule example
on retrieve to GROUPS.composition 
then do instead retrieve (EMP.all) where EMP.age > current.age
.)l
.uh BUGS 
.lp
POSTQUEL functions currently 
can neither accept arguments nor return results of a base type. 
.lp
Inheritable functions are currently restricted to a 
single argument of type classname.
.lp
Inheritable POSTQUEL functions are not currently propagated thru the
inheritance hierarchy.
.lp
Inheritable functions cannot currently use functional notation
and must instead use the column notation.  For example, if a function
foo takes the class EMP as an argument
.(l
retrieve ( EMP.foo.all ) 
.)l
works, but
.(l
retrieve ( foo(EMP).all ) 
.)l
does not.
.lp
POSTQUEL functions cannot currently take a list of queries as the
function body.
.lp
In Version 3.0, POSTQUEL functions are not cachable, no matter what
their composition may be.  
.lp
In Version 3.0, POSTQUEL functions 
exhibit relational-cross-product rather than outer-join semantics.
This means, for instance, that given this schema :
.(l
create emp ( name = char16, salary = int4, dept = char16 )

define postquel function hobbies ( emp ) returns hobbies is
retrieve ( hobbies.all ) where hobbies.empname = emp.name

append emp ( name = "goh", salary = 1000, dept = "toy" )
append emp ( name = "hong", salary = 1000, dept = "not-toy" )
append emp ( name = "cimarron", salary = 1500, dept = "toy" )
append emp ( name = "ron", salary = 29000, dept = "sys-admin" )

create hobbies ( activity = char16, empname = char16 )

append hobbies ( activity = "kayaking", empname = "goh" )
append hobbies ( activity = "basketball", empname = "hong" )
append hobbies ( activity = "basketball", empname = "ron" )
.)l
.sp
the query
.(l
retrieve ( emp.hobbies.activity , emp.name ) 
.)l
returns
.(l
	activity    	name
	--------------------------------------
	kayaking	goh
	basketball	hong
	basketball	ron
	--------------------------------------
.)l
rather than
.(l
	activity   	name
	--------------------------------------
	kayaking	goh
	basketball	hong
	basketball	ron
	NULL    	cimarron
	--------------------------------------
.)l
