(*long*) Re: Package procedure call from forms

From: Steven P. Muench <smuench_at_oracle.com>
Date: 10 Nov 1994 07:15:17 GMT
Message-ID: <SMUENCH.94Nov9231517_at_doh.oracle.com>


The README.30 (sometimes named 'release.doc' on Unix ports) file shipped with Forms 3.0 documents the various restrictions (most of which have quite simple equivalences to achieve your result). Here's the relevant section for your reference. In particular, see the section on the restriction regarding directly referencing SCHEMA.PACKAGE.SUBPROGRAM which can be easily solved by creating a synonym for SCHEMA.PACKAGE or a synonym for PACKAGE.SUBPROGRAM, such that the reference in PL/SQL ends up looking like SYMBOL.SYMBOL instead of SYMBOL.SYMBOL.SYMBOL.

Hope this helps.

Steve Muench         Email: smuench_at_oracle.com
Forms Development      CIS: 73404,676

Sr. Product Manager
Oracle Corporation

CALLING STORED PROCEDURES

(*) OVERVIEW


       A database procedure is a PL/SQL block designed to be executed by
       the server-side PL/SQL engine. It may accept inputs, and may return
       outputs, neither of which is mandatory. It runs under the security
       domain (or schema) of the *creator* of the procedure, and not the
       current user. The current user needs EXECUTE privilege on the
       procedure to use it.  One important difference is that server-side
       PL/SQL procedures do not understand references to SQL*Forms bind
       variables (like :BLOCK.FIELDNAME, :GLOBAL.VARNAME, or
       :SYSTEM.CURSOR_FIELD). Any data which procedures need for processing
       must be passed into the "black box" via parameters of appropriate
       datatype, package variables, or by selecting from tables.

       For this reason it is advisable to structure your SQL*Forms
       procedures now in such a way that they accept inputs and return
       results in parameters. This will make the eventual migration of the
       procedure into the database as painless as adding the word CREATE in
       front of the PROCEDURE declaration, and running the script resulting
       script in SQLPLUS.

       

(*) SYNTAX
~~~~~~ Call a stored procedure/function from within SQL*Forms exactly as you would invoke a form-level procedure/function: DECLARE ---------------/ Example SQLFORMS Trigger /--------- ld DATE; ln NUMBER; lv VARCHAR2(30); BEGIN /* || Calling Form-Level Procedure/Function */ forms_procedure_name( ld, ln, lv ); ld := forms_function_name( ln, lv ); /* || Calling Database Procedure/Function */ database_procedure_name( ld, ln, lv ); ld := database_function_name( ln, lv ); END;
(*) SUPPORTED DATATYPES FOR
PARAMETERS & FUNCTION RETURN VALUES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Stored Procedures, Functions, and Packages are created using version 2.0 of PL/SQL within the Oracle7 database. Since SQL*Forms 3.0 is built on PL/SQL version 1.0, for backward compatibility reasons only the following PL/SQL 2.0 datatypes are supported for Parameters and as Function Return values. VARCHAR2 -- Maximum of VARCHAR2(2000) NUMBER DATE BOOLEAN Recall that your stored procedures and functions can *internally* be written using all new PL/SQL version 2.0 datatypes and functionality. The above restriction on datatypes only applies to the interface that your stored routines have with their version 1.0 PL/SQL counterparts, namely parameters and function return values. An attempt to reference a stored procedure or stored function which uses unsupported parameter or return-value datatypes will result in the failure to "recognize" the stored subprogram, and an error will be generated: PL/SQL error 313 at line xxx, column yyy 'PROCNAME' not declared in this scope or PL/SQL error 201 at line xxx, column yyy identifier 'FUNCTNAME' must be declared.
(*) SUPPORTED CONSTRUCTS
~~~~~~~~~~~~~~~~~~~~ When invoking a stored procedure or function, only the following subset of possible usages is supported: ProcName(arg1,...,argN) FuncName(arg1,...,argN) PackName.ProcName(arg1,...,argN) PackName.FuncName(arg1,...,argN) To access a subprogram (i.e. Procedure or Function) in another user's schema or one at a remote database you must create a synonym to "hide" the username and/or Db_Link name from the PLSQL compiler such that the result takes the form: ProcSynonym(arg1,...,argN) FuncSynonym(arg1,...,argN) PackSynonym.ProcName(arg1,...,argN) PackSynonym.FuncName(arg1,...,argN) You can create synonyms to nickname: Subprogram_at_DbLink Package_at_DbLink Package.Subprogram_at_DbLink Schema.Subprogram_at_DbLink Schema.Package Schema.Package_at_DbLink Schema.Package.Subprogram_at_DbLink Where 'Subprogram' is either Procedure or Function. For example to call the package function 'LIBOWNER.LIB_HR.GET_SSN' you would create a synonym for the LIB_HR package which includes the Schema name as follows: CREATE SYNONYM lib_hr_syn FOR libowner.lib_hr; Then invoke the function from within your form like: ss_num := lib_hr_syn.get_ssn(:Emp.Empno); If the package function were at a remote site accessible via a database link named 'BASEL', for example, then you could create a synonym for the package, including the database link name: CREATE SYNONYM basel_lib_hr_syn FOR libowner.lib_hr_at_basel; and invoke the function within your PL/SQL code as: ss_num := basel_lib_hr_syn.get_ssn(:Emp.Empno); Alternately you can create a synonym for the function itself, "hiding" both the Schema and DbLink information: CREATE SYNONYM basel_lib_hr_get_ssn_syn FOR libowner.lib_hr.get_ssn_at_basel; and invoke the function from forms as: ss_num := basel_lib_hr_get_ssn_syn(:Emp.Empno); Of course, any of the synonyms above could have been created as PUBLIC SYNONYMS if appropriate.
(*) NAME RESOLUTION
~~~~~~~~~~~~~~~ When encountering the name of an identifier which could be a procedure or function, the PLSQL compiler uses a precedence mechanism to resolve possible ambiguities. If an identifier like 'PROCNAME' is encountered which has the structure of a procedure or function, the compiler will use the first match found in the following search order: (1) Is it defined within the current PLSQL block? (2) Is it a standard PLSQL command? (3) Is it a SQL*Forms packaged procedure/function? (4) Is it a user-defined, Form-Level procedure/function? (5) Is it defined in package DBMS_STANDARD on the server-side? (6) Does the current user have access to any such procedure/function on the server side? If the answer is NO to all of the above, then the compiler signals an error: PL/SQL error 313 at line xxx, column yyy 'PROCNAME' not declared in this scope or PL/SQL error 201 at line xxx, column yyy identifier 'FUNCTNAME' must be declared.
(*) IMPLEMENTATION
~~~~~~~~~~~~~~ When you generate a form containing references to stored procedures, functions, or packages, SQL*Forms must perform the following: (1) Insure that the stored subprogram to which you make reference exist on the server during compilation. (2) Include an intermediate "access routine" for each stored subprogram you reference. There will be one access routine for each procedure, function or package that is referenced. If you reference functions or procedures within a package, they will use the access routine associated to the entire package. The access routines handles the integration between PL/SQL version 1 and version 2, and are included in the .FRM file of your generated form. These access routines are not visible by the designer.
(*) CONSIDERATIONS
~~~~~~~~~~~~~~ Processing within the form is on hold until the stored procedure or function completes execution, so the network and database load come into play when considering response time. Recall that the first time some user executes a stored procedure or function, it's executable code gets cached in the Oracle7 SGA. Subsequent executions by you or any other user are thus faster. The first time any subprogram within a package is referenced, the entire package is loaded and shareable. Use a database procedure instead of a Forms procedure when: (1) It provides standard functionality that other tools will want to share -- like validation and calculations, (2) performs a significant amount of DML operations -- in order to have them performed in a bundle by the server, (3) If new PL/SQL V2 functionality like TABLES, RECORDS, or TYPES is required -- since the PL/SQL on the SQL*Forms side will remain V1 in Version 3.0 of SQL*Forms.
(*) RESTRICTIONS
~~~~~~~~~~~~ SQL*Forms disables commits in stored procedures and functions that are called while SQL*Forms (Runform) is active. A stored procedure or function may not issue a COMMIT or ROLLBACK when called by forms. An attempt to do so will raise the error: ORA-0034: Commit and Rollback from PL/SQL disabled for this session However, if your C program calls SQL*Forms by way of the IAPCAL() interface, your stored procedures can issue commits once control is returned to the C program from the iapcal routine. Since SQL*Forms creates the "access routine" for each stored subprogram to which your trigger/form-level-procedure PL/SQL code makes reference, it is NOT possible to write a form containing calls to stored procedures or functions that will generate against both Oracle version 6.0 and version 7.0. Once a form includes a reference to at least one stored subprogram, then it must be generated against a Version 7.0 database, otherwise compilation errors will result when the names of stored subprograms cannot be resolved by the PL/SQL compiler. Character (CHAR or VARCHAR2) values passed-IN to a stored procedure or function, passed-OUT from a stored procedure, or returned from a stored function may not exceed 2000 characters. Actual character parameters exceeding 2000 characters will be truncated to 2000 before passing to the stored procedure/function. Any OUT character parameters or character return values exceeding 2000 characters will be truncated to a length of 2000. The truncation which may occur on IN, OUT or return character values is performed without raising the PL/SQL VALUE_ERROR exception, and without raising a SQL*Forms truncation error. ============================================================================
ORGANIZING COLLECTIONS OF PROCEDURES/FUNCTIONS INTO PACKAGES

(*) OVERVIEW


       Procedures and functions can be organized into Packages, to form a
       "suitcase" of PL/SQL objects. Packages can contain variables which
       are persistent for a user's entire session  (akin to a server-side
       GLOBAL variable and just as useful), as well as Cursors which may
       remain open across calls to functions and procedures in the
       package. 

       See the PL/SQL version 2.0 User's Guide and Reference for more
       information on packages.


(*) EXAMPLE
~~~~~~~ CREATE OR REPLACE PACKAGE LIB_HR AS -- Retrieve Social Security Number for an Employee FUNCTION get_ssn( theEmpNo NUMBER ) RETURN NUMBER; -- Hire a new Employee and return his/her Employee Number FUNCTION hire_employee( theName VARCHAR2, theDept NUMBER, theSal NUMBER, theDate DATE, theSSN NUMBER ) RETURN NUMBER; -- Terminate an existing Employee PROCEDURE fire_employee( theEmpno NUMBER, theReason VARCHAR2 ); -- Set Signing Bonus Variable PROCEDURE set_bonus( newValue NUMBER ); END LIB_HR; CREATE OR REPLACE PACKAGE BODY LIB_HR AS -- Package Variables -- signingBonus NUMBER := 1000; -- Package Cursor -- CURSOR next_empid IS SELECT empid_sequence.NEXTVAL FROM dual; -- Retrieve Social Security Number for an Employee FUNCTION get_ssn( theEmpNo NUMBER ) RETURN NUMBER IS tmpSSN NUMBER; BEGIN SELECT ssn INTO tmpSSN FROM emp WHERE empno = theEmpNo; RETURN( tmpSSN ); EXCEPTION WHEN NO_DATA_FOUND THEN RETURN( -1 ); END; -- Hire a new Employee and return Employee Number FUNCTION hire_employee( theName VARCHAR2, theDept NUMBER, theSal NUMBER, theDate DATE, theSSN NUMBER ) RETURN NUMBER IS tmpEmpNo NUMBER; BEGIN IF (NOT next_empid%ISOPEN) THEN OPEN next_empid; END IF; FETCH next_empid INTO tmpEmpNo; -- We don't have to CLOSE the cursor because it will -- remain open between calls INSERT INTO EMP( empno, ename, deptno, sal, hiredate, ssn, bonus ) VALUES( tmpEmpNo, theName, theDept, theSal, theDate, theSSN, signingBonus ); RETURN( tmpEmpNo ); EXCEPTION WHEN OTHERS THEN RETURN( -1 ); END; -- Terminate an existing Employee PROCEDURE fire_employee( theEmpno NUMBER, theReason VARCHAR2 ) IS BEGIN DELETE FROM emp WHERE empno = theEmpno; INSERT INTO terminations( empno, reason ) VALUES( theEmpno, theReason ); END; -- Set Signing Bonus Variable PROCEDURE set_bonus( newValue NUMBER ) IS BEGIN signingBonus := newValue; END; END LIB_HR;
(*) CONSIDERATIONS
~~~~~~~~~~~~~~ The first time a package is referenced (by any user on the instance) the entire package is loaded into the Oracle7 SGA to make subsequent invocation of any procedures or functions it contains very fast.
(*) RESTRICTIONS
~~~~~~~~~~~~ As SQL*Forms only provides direct support for invoking stored procedures and functions, and not for directly referencing package variables or package cursors, you must design a function or procedure to manipulate package variables and package cursors within the code on the server side. If their datatypes are among the four supported above, values of package variables and fetched cursor data can be returned to the (SQL*Forms) caller via parameters or a function return value. SQL*Forms requires that both Package Specification and Body be valid in order to compile a Forms PL/SQL block which makes reference to the package. ============================================================================
PACKAGES AVAILABLE TO PUBLIC
       The following packages are create then the Oracle7 kernel is
       installed:

           Dbms_Standard
           Dbms_Transaction
           Dbms_Session
           Dbms_Ddl
           Dbms_Utility

       All packages listed above run as the invoking user rather than the
       package owner.

       Only package dbms_standard is a 'standard extension'.  This means
       that its procedure names are inserted into the scope just outside of
       a package or top-level procedure, but before the kernel's package
       'STANDARD'.

       Public synonyms are created during execution, and EXECUTE privilege
       is granted to public, for the above packages.

       From SQL*Forms, you can invoke procedures included in any of these
       packages by using the syntax <package>.<procedure>, for example:

                DBMS_SESSION.SET_ROLE('role');

       For information on the procedures included in these packages refer
       to the Oracle7 documentation.

--

Steve Muench         Email: smuench_at_oracle.com
Forms Development      CIS: 73404,676
Sr. Product Manager
Oracle Corporation
Received on Thu Nov 10 1994 - 08:15:17 CET

Original text of this message