15-22. | Suppose you define the following package:
/* Filename on web page onecur.sql */
CREATE OR REPLACE PACKAGE onecur
IS
CURSOR onerow (
id_in IN employee.employee_id%TYPE)
IS
SELECT * FROM employee
WHERE employee_id = id_in;
END onecur;
/ You then create the following procedure, procA: CREATE OR REPLACE PROCEDURE procA
IS
BEGIN
OPEN onecur.allrows (1005);
END procA;
/ Next, you create the procedure procB: CREATE OR REPLACE PROCEDURE procB
IS
BEGIN
OPEN onecur.allrows (2356);
procA;
END procB;
/ What happens when you execute procB? |
15-23. | Rewrite the package in 15-22 so that it provides procedures to open and close the cursor, ensuring that a user never receives a “cursor already open” error when opening the cursor and never receives an “invalid cursor” error when closing the cursor. |
15-24. | Every time you reference the USER function to retrieve the currently connected username, you do a SELECT FROM dual. On a 300-MHz laptop, 10,000 consecutive calls to USER take approximately 2.5 seconds to complete. While this is not a long time, it’s not exactly fast either. How could you modify the loop so that the USER function is called only once? |
15-25. | The following package won’t compile because it’s too big: proc1 contains 20 KB of source code, and proc2 contains 22 KB. How can you redefine this code so that the call interface remains the same, but you can still call toobig.proc1 and toobig.proc2 to get your work done?
/* Filename on web page: splitpkg.pkg */
CREATE OR REPLACE PACKAGE toobig
IS
PROCEDURE proc1;
PROCEDURE proc2;
END;
/
CREATE OR REPLACE PACKAGE BODY toobig
IS
PROCEDURE proc1
IS
BEGIN
/* lots of code */
NULL;
END;
PROCEDURE proc2
IS
BEGIN
/* lots more code */
NULL;
END;
END;
/ |
15-26. | Does the following package specification contain a valid implementation of overloading? Specifically, does the package specification compile? If so, can you actually run either of the programs successfully?
/* Filename on web page: sales.pkg */
CREATE OR REPLACE PACKAGE salespkg
IS
PROCEDURE calc_total (zone_in IN VARCHAR2);
PROCEDURE calc_total (reg_in IN VARCHAR2);
END salespkg;
/ |
15-27. | Suppose you want more flexibility than DBMS_OUTPUT can provide for your tracing and debugging needs. For example, in some circumstances, you want to see the output from your program while it is still running; most of the time, though, you’re quite content with output to the screen. You also want to see the execution call stack when your trace program is called to see where you are in the process. Create a package that offers a replacement for the built-in procedure, DBMS_OUTPUT.PUT_LINE, with the options mentioned. Build a body to fit the following specification for such a package:
/* Filename on web page: watch.pkg */
CREATE OR REPLACE PACKAGE watch
IS
/* Direct output to the screen; the default. */
PROCEDURE toscreen;
/* Direct output to a pipe so it can be viewed even
while the program is still running. */
PROCEDURE topipe;
/* Watch a specific action; the replacement for the
DBMS_OUTPUT.PUT_LINE procedure. */
PROCEDURE action (prog IN VARCHAR2, val IN VARCHAR2);
/* Show the contents of the database pipe. */
PROCEDURE show;
END; |
15-28. | When you want to execute a SQL statement constructed at runtime (dynamic SQL), you must call the DBMS_SQL.EXECUTE function. If your SQL statement is an INSERT, UPDATE, or DELETE, this function returns the number of rows modified by the statement. Otherwise, the return value is ignored. This means that if you execute a query or a DDL statement or a PL/SQL block—anything except a DML statement—you must declare a variable to hold a return value and then not use it, as shown: DECLARE
cur INTEGER := DBMS_SQL.OPEN_CURSOR;
feedback INTEGER;
BEGIN
DBMS_SQL.PARSE (cur, 'TRUNCATE TABLE employee', DBMS_SQL.NATIVE);
feedback := DBMS_SQL.EXECUTE (cur);
DBMS_SQL.CLOSE (cur);
END; Do what Oracle should have done: create a package that offers an implementation of the EXECUTE program that allows developers to avoid the need to declare a “feedback” variable unless they are executing DML. |
15-29. | Suppose that you have set up a database table to store standard user configuration information. These configuration values are changed only when users are off the system; they do not change during an active session. Here is the definition of the table:
/* Filename on web page: usrcnfg.ins */
CREATE TABLE user_config (
username VARCHAR2(30),
cubicle# VARCHAR2(20),
max_coffee_breaks INTEGER
); Furthermore, suppose you use this package to retrieve this information:
/* Filename on web page: usrcnfg1.pkg */
CREATE OR REPLACE PACKAGE userconfig
IS
FUNCTION cubicle# RETURN VARCHAR2;
FUNCTION max_coffee_breaks RETURN INTEGER;
END userconfig;
/
CREATE OR REPLACE PACKAGE BODY userconfig
IS
FUNCTION cubicle# RETURN VARCHAR2
IS
retval user_config.cubicle#%TYPE;
BEGIN
SELECT user_config.cubicle#
INTO retval
FROM user_config
WHERE username = USER;
RETURN retval;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
RETURN 'SECURITY DESK';
END;
FUNCTION max_coffee_breaks RETURN INTEGER
IS
retval user_config.max_coffee_breaks%TYPE;
BEGIN
SELECT user_config.max_coffee_breaks
INTO retval
FROM user_config
WHERE username = USER;
RETURN retval;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
RETURN 0;
END;
END userconfig;
/ What are the problems with the design of this package? How would you change the package to improve its performance? As you design your changes, remember that only the package body should change, so that existing calls to the usrcnfg package aren’t affected. |
15-30. | As a general rule, when you define data structures in a package, but not within any procedure or function of the package, this data persists for your entire session. What feature in Oracle8i Release 8.1 allows you to have your package data treated like “local” data (i.e., to discard memory and reinstantiate data structures with each block execution)? |