Apress.Expert.Oracle.Database.Architecture.9i.and.10g.Programming.Techniques.and.Solutions.Sep.2005

rekharaghuram
from rekharaghuram More from this publisher
05.11.2015 Views

CHAPTER 12 ■ DATATYPES 517 Note that on line 2, we specify AUTHID CURRENT_USER. This makes the package run as the invoker, with all roles and grants in place. This is important for two reasons. First, we’d like the database security to not be subverted—this package will only return substrings of columns we (the invoker) are allowed to see. Second, we’d like to install this package once in the database and have its functionality available for all to use; using invoker rights allows us to do that. If we used the default security model of PL/SQL—definer rights—the package would run with the privileges of the owner of the package, meaning it would only be able to see data the owner of the package could see, which may not include the set of data the invoker is allowed to see. The concept behind the function SUBSTR_OF is to take a query that selects at most one row and one column: the LONG value we are interested in. SUBSTR_OF will parse that query if needed, bind any inputs to it, and fetch the results programmatically, returning the necessary piece of the LONG value. The package body, the implementation, begins with two global variables. The G_CURSOR variable holds a persistent cursor open for the duration of our session. This is to avoid having to repeatedly open and close the cursor and to avoid parsing SQL more than we need to. The second global variable, G_QUERY, is used to remember the text of the last SQL query we’ve parsed in this package. As long as the query remains constant, we’ll just parse it once. So, even if we query 5,000 rows in a query, as long as the SQL query we pass to this function doesn’t change, we’ll have only one parse call: ops$tkyte@ORA10G> create or replace package body long_help 2 as 3 4 g_cursor number := dbms_sql.open_cursor; 5 g_query varchar2(32765); 6 Next in this package is a private procedure, BIND_VARIABLE, that we’ll use to bind inputs passed to us by the caller. We implemented this as a separate private procedure only to make life easier; we want to bind only when the input name is NOT NULL. Rather than perform that check four times in the code for each input parameter, we do it once in this procedure: 7 procedure bind_variable( p_name in varchar2, p_value in varchar2 ) 8 is 9 begin 10 if ( p_name is not null ) 11 then 12 dbms_sql.bind_variable( g_cursor, p_name, p_value ); 13 end if; 14 end; 15 Next is the actual implementation of SUBSTR_OF in the package body. This routine begins with a function declaration from the package specification and the declaration for some local variables. L_BUFFER will be used to return the value, and L_BUFFER_LEN will be used to hold the length returned by an Oracle-supplied function:

518 CHAPTER 12 ■ DATATYPES 16 17 function substr_of 18 ( p_query in varchar2, 19 p_from in number, 20 p_for in number, 21 p_name1 in varchar2 default NULL, 22 p_bind1 in varchar2 default NULL, 23 p_name2 in varchar2 default NULL, 24 p_bind2 in varchar2 default NULL, 25 p_name3 in varchar2 default NULL, 26 p_bind3 in varchar2 default NULL, 27 p_name4 in varchar2 default NULL, 28 p_bind4 in varchar2 default NULL ) 29 return varchar2 30 as 31 l_buffer varchar2(4000); 32 l_buffer_len number; 33 begin Now, the first thing our code does is a sanity check on the P_FROM and P_FOR inputs. P_FROM must be a number greater than or equal to 1, and P_FOR must be between 1 and 4,000—just like the built-in function SUBSTR: 34 if ( nvl(p_from,0)

518<br />

CHAPTER 12 ■ DATATYPES<br />

16<br />

17 function substr_of<br />

18 ( p_query in varchar2,<br />

19 p_from in number,<br />

20 p_for in number,<br />

21 p_name1 in varchar2 default NULL,<br />

22 p_bind1 in varchar2 default NULL,<br />

23 p_name2 in varchar2 default NULL,<br />

24 p_bind2 in varchar2 default NULL,<br />

25 p_name3 in varchar2 default NULL,<br />

26 p_bind3 in varchar2 default NULL,<br />

27 p_name4 in varchar2 default NULL,<br />

28 p_bind4 in varchar2 default NULL )<br />

29 return varchar2<br />

30 as<br />

31 l_buffer varchar2(4000);<br />

32 l_buffer_len number;<br />

33 begin<br />

Now, the first thing our code does is a sanity check on the P_FROM <strong>and</strong> P_FOR inputs. P_FROM<br />

must be a number greater than or equal to 1, <strong>and</strong> P_FOR must be between 1 <strong>and</strong> 4,000—just<br />

like the built-in function SUBSTR:<br />

34 if ( nvl(p_from,0)

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!