Forum OpenACS Development: Response to Package Porting

Collapse
Posted by Vinod Kurup on
Well, since the grownups are away (grownups in wisdom, that is, not necessarily age), I'll give ya my 2 cents.

A package in Oracle is a way to encapsulate procedures & functions in a single unit.

So the following Oracle package (showing only the package header) defines 2 functions and 1 procedure.

create package acs as function add_user ( user_id in users.user_id%TYPE default null, ... member_state in membership_rels.member_state%TYPE default 'approved' ) return users.user_id%TYPE; procedure remove_user ( user_id in users.user_id%TYPE ); function magic_object_id ( name in acs_magic_objects.name%TYPE ) return acs_objects.object_id%TYPE; end acs;
These would be called as:

    acs.add_user( ... );
    acs.remove_user( ... );
    acs.magic_object_id( ... );
Since postgres doesn't have a way to encapsulate functions together, we need to agree on a convention, which I think is described in the Guidelines document.

So in postgres, we would create 3 functions:


    create function acs__add_user( ... ) ...
    create function acs__remove_user( ... ) ...
    create function acs__magic_object_id( ... ) ...
Those are 2 underscores between the "package name" and the "function name". The function would then be ported just as any oracle function/procedure would be. One of the problems is going to be figuring out how to deal with all the default parameters.

This provides understandable function names (i.e. acs_user__new() creates a new user and party__new() creates a new party) and it potentially allows a way to create an API-browser by showing a list of "packages" and then the "functions" within those packages.

A few other differences between PL/SQL and plpgsql:

  • You can't use %TYPE types in the parameters or the return var. You can use them for variables that you create in the function
  • You can't reference parameter variables by prefacing them with the package/function name. For example, in many ACS functions, the use of v_varname variables have been removed. Instead, they're using the 'varname' directly (without the v_), but distinguishing it from columns of the same name by calling the full package_name.function_name.varname. This doesn't work in pg, so we need to reinstate v_varnames.
  • You can't call functions by specifying the parameter label in the call. So you can't do acs_permission.grant_permission( object_id => v_user_id ...). Instead, you need to send parameters in the order that they're defined.
So, here's how I would redefine one acs package function:
create package body acs as ... < other functions & procedures > function magic_object_id ( name in acs_magic_objects.name%TYPE ) return acs_objects.object_id%TYPE is object_id acs_objects.object_id%TYPE; begin select object_id into magic_object_id.object_id from acs_magic_objects where name = magic_object_id.name; return object_id; end magic_object_id;
in postgres:
drop function acs__magic_object_id( varchar ); create function acs__magic_object_id ( varchar ) returns integer as ' declare v_name alias for $1; v_object_id acs_objects.object_id%TYPE; begin select into v_object_id object_id from acs_magic_objects where name = v_name; return v_object_id; end; ' language 'plpgsql';
All package calls in the tcl & sql code would then have to be changed to use these conventions.

I hope that this is what you were looking for and that the experts will liberally correct where necessary.

BTW, Happy Birthday tomorrow Don - you know that forgetting your birthday is a sure sign of age 😊