<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>Sinoptix</title>
	<atom:link href="http://www.sinoptix.ro/feed" rel="self" type="application/rss+xml" />
	<link>http://www.sinoptix.ro</link>
	<description>Oracle Developers</description>
	<pubDate>Fri, 28 May 2010 09:24:09 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.2</generator>
	<language>en</language>
			<item>
		<title>Resource Manager and 11g</title>
		<link>http://feedproxy.google.com/~r/DougsOracleBlog/~3/gnpZtvLORz8/index.php</link>
		<comments>http://feedproxy.google.com/~r/DougsOracleBlog/~3/gnpZtvLORz8/index.php#comments</comments>
		<pubDate>Mon, 17 May 2010 22:30:00 +0000</pubDate>
		<dc:creator>Doug Burns</dc:creator>
		
		<category><![CDATA[Doug's Oracle Blog]]></category>

		<guid isPermaLink="false">http://oracledoug.com/serendipity/index.php?/archives/1604-guid.html</guid>
		<description><![CDATA[I will get back to the stats stuff at some point, but I'm quite busy at the moment working on something that I can't talk too much about, but which is throwing up enough generic issues to talk about. This is one that I meant to blog about ages ago when I first noticed it but when it caused us some problems last week, it was a useful reminder.<br /><br /><strong>In summary you need to be careful when you upgrade to 11g because Resource Manager is enabled by default!</strong><br /><br />I don't want to blog about the ins and outs of Resource Manager and whether it's a good thing or not, but I do think this is a pretty extreme change to implement without a lot of surrounding publicity. It's a bit like the auto stats gather job that appeared in 10g that caused so many problems for Oracle users. It <em>seems</em> like it might be a good idea, but would you really want to introduce it on to a stable system that you're upgrading to 11g?<br /><br />But rather than just talk about the change, I wanted to highlight how I first realised it was going on ...<br /><br /><br /><!-- s9ymdb:292 --><!-- s9ymdb:292 --><a class="serendipity_image_link" href="http://oracledoug.com/serendipity/uploads/RM_11g.jpg"><!-- s9ymdb:292 --><img height="62" width="110" class="serendipity_image_center" src="http://oracledoug.com/serendipity/uploads/RM_11g.serendipityThumb.jpg" alt=""  /></a><br /><br />Yes, a pretty picture (albeit not too legible at that resolution, even when you click the thumbnail to see the bigger version). This is the sort of change that could have completely passed me by (and I am utterly convinced it has others) but, because I have a habit of looking at the Top Activity page for any system I'm working on, this activity leaps out at me as the new pale green wait class - Scheduler - which sits just above CPU + Wait for CPU (the addition of + Wait for CPU is one of the tiny details I really like in 11g). I should say that the specific event these sessions are waiting on is &#34;resmgr:cpu quantum&#34;.<br /><br />As soon as I upgraded my first laptop db to 11g (quite a while ago now) I noticed the additional activity and though, mmmm, that's interesting and when I checked the resource_manager_plan parameter, it was set to DEFAULT_PLAN, to my surprise.<br /><br />Low and behold, whilst working on an 11gR2 system last week that we couldn't get enough parallelism out of, I checked and the DEFAULT_PLAN was enabled. Once it was disabled, like so ....<br /><br /> 
<pre>alter system set resource_manager_plan=''; 
</pre><br />Everything started running as expected.<br /><br />So I went home to do a little background research and the first obvious place to look was <a href="http://download.oracle.com/docs/cd/E11882_01/server.112/e10820/initparams211.htm#CHDIGGIG">the documentation</a>. But that's pretty misleading because it says there is no default value for resource_manager_plan. I checked v$PARAMETER and, sure enough, the default is not DEFAULT_PLAN. So I started to doubt myself. Maybe it was just because I'd created Mickey Mouse databases on my laptop, using the GUI. However, that wouldn't apply to the database I'm working on and, after some discussion with the DBA who completed the upgrade, it became clear that the Upgrade Assistant (dbua) sets this parameter.<br /><br />But that's not all. In total, 11gR2 creates 10 plans as far as I can tell and DEFAULT_PLAN is not the only one used, but maintenance plans are also used during maintenance windows. Here is my laptop database right now, while it's in a maintenance window.<br /><br /> 
<pre>SQL&#62; show parameter resource_manager_plan

NAME&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; TYPE&#160;&#160;&#160;&#160;&#160;&#160;&#160; VALUE
------------------------------------ ----------- ------------------------------
resource_manager_plan&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; string&#160;&#160;&#160;&#160;&#160; SCHEDULER[0x3003]:DEFAULT_MAIN
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; TENANCE_PLAN
</pre><br />I can imagine this leading to a lot of confusion, so thanks again to Jari Kuhanen for pointing out <a href="https://support.oracle.com/CSP/main/article?cmd=show&#38;type=NOT&#38;id=786346.1">this Metalink Note</a> to me that covers it.<br /><br />Definitely something to look out for but, in fairness to Oracle, if I had re-read <a href="http://download.oracle.com/docs/cd/E11882_01/server.112/e10595/tasks.htm">the relevant documentation</a> it is all clear in there. I wonder how many people do that before every upgrade though?<br /><img src="http://feeds.feedburner.com/~r/DougsOracleBlog/~4/gnpZtvLORz8" height="1" width="1"/>]]></description>
			<content:encoded><![CDATA[I don't want to blog about the ins and outs of Resource Manager and whether it's a good thing or not, but I do think this is a pretty extreme change to implement without a lot of surrounding publicity. It's a bit like the auto stats gather job that appeared in 10g that caused so many problems for Oracle users. It <em>seems</em> like it might be a good idea, but would you really want to introduce it on to a stable system that you're upgrading to 11g?

<img src="http://feeds.feedburner.com/~r/DougsOracleBlog/~4/gnpZtvLORz8" alt="" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://feedproxy.google.com/~r/DougsOracleBlog/~3/gnpZtvLORz8/index.php/feed</wfw:commentRss>
		</item>
		<item>
		<title>How big can my program get?</title>
		<link>http://www.toadworld.com/BLOGS/tabid/67/EntryID/537/Default.aspx</link>
		<comments>http://www.toadworld.com/BLOGS/tabid/67/EntryID/537/Default.aspx#comments</comments>
		<pubDate>Mon, 10 May 2010 13:09:00 +0000</pubDate>
		<dc:creator>Steven Feuerstein</dc:creator>
		
		<category><![CDATA[Steven Feuerstein's Blog]]></category>

		<guid isPermaLink="false">http://www.toadworld.com/Default.aspx?tabid=67&EntryID=537</guid>
		<description><![CDATA[<p>I recently received this question from a PL/SQL developer:</p>
<blockquote style="margin-right: 0px" dir="ltr">
<p><em>"What is the maximum size of a PL/SQL procedure?"</em></p>
</blockquote>
<div>
<p>The answer is interesting: there is not a maximum size, per se. Instead, the limitation has to do with the maximum number of <em>DIANA nodes</em> your program generates in the compilation process.</p>
<p>DIANA is an intermediate language produced and used by the compiler. DIANA standards for “Descriptive Intermediate Attributed Notation for Ada" - and reminds us that PL/SQL is based on Ada, a programming language originally developed for the U.S. Department of Defense.</p>
</div>
<div>
<p>DIANA code is in the form of a tree structure, and nodes in the tree correspond to <em>tokens</em> in your programs, which include identifiers, keywords and operators.</p>
<p>So here's the actual limitation regarding "size" (quoting now from the <a href="http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28370/limits.htm">Oracle documentation</a>): "a package spec, object type spec, standalone subprogram, or anonymous block is limited to 67108864 (2**26) DIANA nodes....[which] allows for ~6,000,000 lines of code."</p>
</div>
<div>
<p>In other words, you <em>really</em> should not have to worry about "running out of space" when building your PL/SQL program units.</p>
<p>You will run up against maintainability issues way before you run into PL/SQL limitations. If your program unit is getting big enough that you are even wondering if it is <em>too big</em>, you should break it up into smaller units, with different names and distinct purposes.</p>
</div>]]></description>
			<content:encoded><![CDATA[I recently received this question from a PL/SQL developer:
<blockquote dir="ltr"><em>"What is the maximum size of a PL/SQL procedure?"</em></blockquote>
<div>

The answer is interesting: there is not a maximum size, per se. Instead, the limitation has to do with the maximum number of <em>DIANA nodes</em> your program generates in the compilation process.

DIANA is an intermediate language produced and used by the compiler. DIANA standards for “Descriptive Intermediate Attributed Notation for Ada" - and reminds us that PL/SQL is based on Ada, a programming language originally developed for the U.S. Department of Defense.</div>
<div></div>]]></content:encoded>
			<wfw:commentRss>http://www.toadworld.com/BLOGS/tabid/67/EntryID/537/Default.aspx/feed</wfw:commentRss>
		</item>
		<item>
		<title>Making sure invoker rights is defined properly</title>
		<link>http://www.toadworld.com/BLOGS/tabid/67/EntryID/527/Default.aspx</link>
		<comments>http://www.toadworld.com/BLOGS/tabid/67/EntryID/527/Default.aspx#comments</comments>
		<pubDate>Tue, 13 Apr 2010 12:54:00 +0000</pubDate>
		<dc:creator>Steven Feuerstein</dc:creator>
		
		<category><![CDATA[Steven Feuerstein's Blog]]></category>

		<guid isPermaLink="false">http://www.toadworld.com/Default.aspx?tabid=67&EntryID=527</guid>
		<description><![CDATA[<p>"Invoker rights, what's that?" you may be asking.</p>
<p>That wouldn't surprise me, greatly, though one might consider it a bit odd because the invoker rights feature of PL/SQL was added in Oracle8i - many years ago!</p>
<p>So I will first offer a brief overview of invoker rights, why you'd use it, how you use it. Then I will introduce one of the major challenges with invoker rights. Finally, I offer a utility that can help you overcome that challenge.</p>
<p>When you create a PL/SQL program unit, you can include an optional AUTHID clause. There are two forms of this clause:</p>
<blockquote style="margin-right: 0px" dir="ltr">
<p style="margin-right: 0px" dir="ltr">AUTHID DEFINER<br />
AUTHID CURRENT_USER</p>
</blockquote>
<p style="margin-right: 0px" dir="ltr">AUTHID DEFINER is the default. So these two procedures specify "definer rights"</p>
<blockquote style="margin-right: 0px" dir="ltr">
<pre style="margin-right: 0px" dir="ltr">PROCEDURE show_emp_count AUTHID DEFINER<br />PROCEDURE show_emp_count</pre>
</blockquote>
<p style="margin-right: 0px" dir="ltr">And this version specifies "invoker rights":</p>
<blockquote style="margin-right: 0px" dir="ltr">
<pre style="margin-right: 0px" dir="ltr">PROCEDURE show_emp_count AUTHID CURRENT_USER</pre>
</blockquote>
<p style="margin-right: 0px" dir="ltr">So that's the syntax. What does it do for you?</p>
<p style="margin-right: 0px" dir="ltr">In many application environments, the code is owned by one schema (let's call it CODE_SCHEMA), and then privileges are granted to execute that code to other schemas (USER_SCHEMA).</p>
<p style="margin-right: 0px" dir="ltr">When a program unit is created in CODE_SCHEMA with definer rights, then when a user connected to USER_SCHEMA runs that program, it runs under the privileges of CODE_SCHEMA.</p>
<p style="margin-right: 0px" dir="ltr">When a program unit is created in CODE_SCHEMA with invoker rights, then when a user connected to USER_SCHEMA runs that program, it runs under the privileges of USER_SCHEMA. And all such privileges must be directly granted (no role-based privileges).</p>
<p style="margin-right: 0px" dir="ltr">In other words, at the time an invoker rights program is executed, Oracle resolves all references to SQL-related database objects (tables and views, for the most part) according to the current user's privileges, and not the privileges of the owner of the program. And role-based privileges are used by Oracle with invoker rights programs.</p>
<p style="margin-right: 0px" dir="ltr">I will step through a simple demonstration below. You are, however, probably wondering what invoker rights is good for. Invoker rights comes in very handy whenever you have a program that needs to work differently (with different tables) depending on who is running the code.</p>
<p style="margin-right: 0px" dir="ltr">Consider <a href="http://www.quest.com/code-tester-for-oracle">Quest Code Tester for Oracle</a>. This automated testing tool for PL/SQL is built around a test repository: 30+ tables and associated code. Usually, this repository is installed in a central schema, and then access to the repository is allowed through synonyms.</p>
<p style="margin-right: 0px" dir="ltr">As a use of Quest Code Tester, I connect to my own development schema, and then call Code Tester programs to define and run my tests.</p>
<p style="margin-right: 0px" dir="ltr">If Quest Code Tester relied on definer rights, then the test repository schema would need to have the authority to execute code in all the development schemas, and probably have directly granted privileges on underlying tables as well. That is a very risky test repository and most DBAs will not create such a powerful schema.</p>
<p style="margin-right: 0px" dir="ltr">Instead, many of the packages in Quest Code Tester are defined as invoker rights. So when the developer asks Code Tester to run a test of the program in her schema, no special privileges are needed in the test repository schema. And Code Tester is not able to do anything to application data that the developer's code does not specifically allow.<br />
In essence, with invoker rights, Oracle "reflects" back into the invoking schema to resolve references as you see below:</p>
<p style="margin-right: 0px" dir="ltr"><img alt="" src="http://www.toadworld.comhttp://www.toadworld.com/Portals/0/blogimages/Steven Feuerstein/SF-Blog041310-1.gif" /><br />
 <br />
Now let's walk through a simple demonstration. I will first create a table in SCOTT with two rows:</p>
<blockquote style="margin-right: 0px" dir="ltr">
<pre style="margin-right: 0px" dir="ltr"><font color="#0000ff">CONNECT</font> scott<font color="#0000ff">/</font>tiger</pre>
<pre><font color="#0000ff">CREATE TABLE</font> authid_demo <font color="#0000ff">(</font>n <font color="#ff0000">NUMBER</font><font color="#0000ff">)</font><br /><font color="#0000ff">/</font></pre>
<pre><font color="#0000ff"><strong>BEGIN<br />   INSERT INTO</strong></font> authid_demo<br />   <strong><font color="#0000ff">VALUES (</font><font color="#800000">1</font><font color="#0000ff">);</font></strong></pre>
<pre>   <font color="#0000ff"><strong>INSERT INTO</strong></font> authid_demo<br />   <strong><font color="#0000ff">VALUES (</font><font color="#800000">2</font><font color="#0000ff">);</font></strong></pre>
<pre><strong>  </strong><font color="#0000ff"><strong> COMMIT;<br />END;<br />/</strong></font></pre>
</blockquote>
<p>I will create the "same" table in HR, but with no rows:</p>
<blockquote style="margin-right: 0px" dir="ltr">
<pre><font color="#0000ff">CONNECT</font> hr<font color="#0000ff">/</font>hr</pre>
<pre><font color="#0000ff"><strong>CREATE TABLE</strong></font> authid_demo <font color="#0000ff">(</font>n <font color="#ff0000">NUMBER</font><font color="#0000ff">)<br /><strong>/</strong></font></pre>
</blockquote>
<p>Then in SCOTT, I create three procedures, each of which do mostly the same thing: show the number of rows in the authid_demo table.</p>
<blockquote style="margin-right: 0px" dir="ltr">
<pre><font color="#0000ff"><strong>CREATE OR REPLACE PROCEDURE</strong></font> proc1 <font color="#0000ff"><strong>AUTHID CURRENT_USER</strong></font><br /><font color="#0000ff"><strong>IS</strong></font><br />   num   <font color="#0000ff"><strong>PLS_INTEGER;</strong></font><br /><font color="#0000ff"><strong>BEGIN<br />   SELECT COUNT (</strong></font>*<font color="#0000ff"><strong>) INTO</strong></font> num <font color="#0000ff"><strong>FROM</strong></font> authid_demo;<br />   <em>DBMS_OUTPUT.put_line</em> <font color="#0000ff"><strong>(</strong></font><font color="#ff0000">'proc 1 invoker authid_demo count = '</font> &#124;&#124; num<font color="#0000ff"><strong>);<br />END;<br />/</strong></font></pre>
<pre><font color="#0000ff"><strong>CREATE OR REPLACE PROCEDURE</strong></font> proc2 <font color="#0000ff"><strong>AUTHID DEFINER</strong></font><br /><strong><font color="#0000ff">IS<br /></font></strong>   <font color="#0000ff"><font color="#000000" size="+0">num</font>   <strong>PLS_INTEGER;<br />BEGIN<br />   SELECT COUNT (</strong></font>*<font color="#0000ff"><strong>) INTO</strong></font> num <font color="#0000ff"><strong>FROM</strong></font> authid_demo;<br />   <em>DBMS_OUTPUT.put_line</em> <font color="#0000ff"><strong>(</strong></font><font color="#ff0000">'proc 2 definer authid_demo count = '</font> &#124;&#124; num<font color="#0000ff"><strong>);</strong></font><br />   proc1;<br /><font color="#0000ff"><strong>END;<br />/</strong></font></pre>
<pre><font color="#0000ff"><strong>CREATE OR REPLACE PROCEDURE</strong></font> proc3 <font color="#0000ff"><strong>AUTHID CURRENT_USER</strong></font><br /><font color="#0000ff"><strong>IS<br /></strong></font>   num   <font color="#0000ff"><strong>PLS_INTEGER;<br />BEGIN<br />   SELECT COUNT (</strong></font>*<font color="#0000ff"><strong>) INTO</strong></font> num <font color="#0000ff"><strong>FROM</strong></font> authid_demo;<br />   <em>DBMS_OUTPUT.put_line</em> <font color="#0000ff"><strong>(</strong></font><font color="#ff0000">'proc 3 invoker authid_demo count = '</font> &#124;&#124; num<font color="#0000ff"><strong>);<br /></strong></font>   proc1;<br />   proc2;<br /><font color="#0000ff"><strong>END;<br />/</strong></font></pre>
</blockquote>
<p>Note that we have these two sequence of calls:</p>
<blockquote style="margin-right: 0px" dir="ltr">
<pre>PROC3 -> PROC1<br />PROC3 -> PROC2 -> PROC1</pre>
</blockquote>
<p>and that PROC3 and PROC1 are invoker rights, while PROC2 is definer rights.</p>
<p>I then allow HR to run all this code and access the underlying table in SCOTT:</p>
<blockquote style="margin-right: 0px" dir="ltr">
<pre><font color="#0000ff"><strong>GRANT</strong> EXECUTE <strong>ON</strong></font> proc1 <font color="#0000ff"><strong>TO</strong></font> hr<br /><font color="#0000ff"><strong>/</strong></font></pre>
<pre><font color="#0000ff"><strong>GRANT</strong> EXECUTE <strong>ON</strong></font> proc2 <font color="#0000ff"><strong>TO</strong></font> hr<br /><font color="#0000ff"><strong>/</strong></font></pre>
<pre><font color="#0000ff"><strong>GRANT</strong> EXECUTE <strong>ON</strong></font> proc3 <font color="#0000ff"><strong>TO</strong></font> hr<br /><font color="#0000ff"><strong>/</strong></font></pre>
<pre><font color="#0000ff"><strong>GRANT</strong> SELECT <strong>ON</strong></font> scott.authid_demo <font color="#0000ff"><strong>TO</strong></font> hr<br /><font color="#0000ff"><strong>/</strong></font></pre>
</blockquote>
<p>Finally, I run PROC3 - from HR:</p>
<blockquote style="margin-right: 0px" dir="ltr">
<pre><font color="#0000ff"><strong>BEGIN</strong></font><br />   scott.proc3<font color="#0000ff"><strong>;<br />END;<br />/</strong></font></pre>
</blockquote>
<p>Here's the output I see:</p>
<blockquote style="margin-right: 0px" dir="ltr">
<pre>Line 1: proc 3 invoker authid_demo count = 0<br />Line 2: proc 1 invoker authid_demo count = 0<br />Line 3: proc 2 definer authid_demo count = 2<br />Line 4: proc 1 invoker authid_demo count = 2</pre>
</blockquote>
<p>Lines 1 and 2 demonstrate invoker rights at work: even though HR called SCOTT's PROC3 and PROC1 programs, the count of rows in authid_demo is retuned as 0, not 2.</p>
<p>Line 3 demonstrates definer rights: it shows the number of rows in SCOTT's authid_demo table, even though the program was called by HR.</p>
<p>But line 4 - now that is puzzling, isn't it? Notice that I got an answer of 2, not 0, for the count in the authid_demo table. Yet I called the same program (PROC1) that two lines earlier showed 2.</p>
<p>So: same code executes, but returns different answer. Very troubling, wouldn't you say?</p>
<p>Here's the problem: if at any point along the execution call stack (in this case, PROC3 -> PROC2 -> PROC1), a definer rights program is executed, then from that point on down the stack the "current user" is resolved by Oracle to be the owner of that definer rights program and not the currently connected user.</p>
<p>When PROC3 called PROC1, that was invoker rights calling invoker rights, and so the current user was HR and the procedure showed 0 rows.</p>
<p>When PROC3 called PROC2, Oracle reset "current user" to SCOTT. Then when PROC2 called PROC1, Oracle resolved the reference to the authid_demo table using SCOTT, and theprocedure therefore showed 2 rows.</p>
<p>This change in expected behavior can cause many problems in your application, ranging from raising "table or view does not exist" and "insufficient privileges" errors to returning or changing the wrong rows of data.</p>
<p>Assuming this is not the behavior you want, you need to make sure that all the program units executed in your call stack are all definer rights or all invoker rights, or at least that once you call a definer rights program, you only call other definer rights programs from that point on.</p>
<p>Fine advice (at least I think so), but how do you apply it? Call stacks in real applications can be very deep, easily a dozen or more entries. Plus, how can you even get hold of the call stack to analyze it?</p>
<p>First, you can call the DBMS_UTILITY.FORMAT_CALL_STACK at any point in your code, and Oracle will return a string that contains the call stack. Here's an example of the formatted call stack Oracle returns, taken from the Quest Code Tester log:</p>
<blockquote style="margin-right: 0px" dir="ltr">
<p style="margin-right: 0px" dir="ltr"> </p>
<pre>----- PL/SQL Call Stack -----<br />  object      line  object<br />  handle    number  name<br />3B6C8C64         1  anonymous block<br />3FA473E8      1012  package body QCTO183.QU_RUNTIME<br />3FA473E8      1042  package body QCTO183.QU_RUNTIME<br />3FA32EF8      3120  package body QCTO183.QU_ALL_OBJECTS<br />3FA32EF8      3138  package body QCTO183.QU_ALL_OBJECTS<br />3FA12F2C      2613  package body QCTO183.QU_GENERATE<br />3FA12F2C      3269  package body QCTO183.QU_GENERATE<br />3FA12F2C      3341  package body QCTO183.QU_GENERATE<br />3FA12F2C      3601  package body QCTO183.QU_GENERATE<br />3FA12F2C      6192  package body QCTO183.QU_GENERATE<br />3FA12F2C      8835  package body QCTO183.QU_GENERATE<br />3FA12F2C      9138  package body QCTO183.QU_GENERATE<br />3FA12F2C      9196  package body QCTO183.QU_GENERATE<br />3FA12F2C      9487  package body QCTO183.QU_GENERATE<br />4DA12F23      9737  package body QCTO183.QU_HARNESS<br />3BC12F2C      9800  package body QCTO183.QU_TEST<br />3BC12F2C     10130  package body QCTO183.QU_TEST<br />3B6F83F8         4  anonymous block</pre>
<p> </p>
</blockquote>
<p style="margin-right: 0px" dir="ltr">So to follow my own advice, I would now have to open each of these package specifications and check the AUTHID setting. That's rather tedious.</p>
<p style="margin-right: 0px" dir="ltr">Perhaps there is another way. Consider the ALL_PROCEDURES data dictionary view:</p>
<p style="margin-right: 0px" dir="ltr"><img alt="" src="http://www.toadworld.comhttp://www.toadworld.com/Portals/0/blogimages/Steven Feuerstein/SF-Blog041310-2.gif" /><br />
 <br />
Notice the AUTHID column. You can look up the AUTHID setting for your program unit from this view. So it seems as though you could write a program to parse the call stack and then look up the AUTHID setting for each program unit in the stack, and make sure there are no problems with  a switch from invoker rights to definer rights, and back, in that stack.</p>
<p style="margin-right: 0px" dir="ltr">Yes, you <em>could</em> do that. But likely you want, because you have a <em>real job</em> and a <em>real life</em> and very little time to write such programs.</p>
<p style="margin-right: 0px" dir="ltr">Fortunately, I don't have a "real job" (well, believe you me, they keep me very busy here at Quest, but they also more or less let me do what I want. <font face="Wingdings">J</font> ) and I sure don't have a real life. My office is at home, so the boundaries between work (PL/SQL) and non-work crumbled years ago.</p>
<p style="margin-right: 0px" dir="ltr">Well, enough about me and my life. The bottom line is that I have created a package, called authid_analysis, available in authid_analysis.pkg file of my <a href="http://www.toadworld.com/Portals/0/stevenf/demo.zip">demo.zip</a>, that will perform precisely this analysis on your behalf.</p>
<p style="margin-right: 0px" dir="ltr">Here's the header of the package:</p>
<blockquote style="margin-right: 0px" dir="ltr">
<pre style="margin-right: 0px" dir="ltr"><font color="#0000ff"><strong>CREATE OR REPLACE PACKAGE</strong></font> authid_analysis<br /><font color="#0000ff"><strong>IS<br />   FUNCTION</strong></font> authid_setting <font color="#0000ff">(</font>program_owner_in <font color="#0000ff"><strong>IN</strong></font> <font color="#ff0000">VARCHAR2</font><br />                          <font color="#0000ff">,</font> program_name_in  <font color="#0000ff"><strong>IN</strong></font> <font color="#ff0000">VARCHAR2</font><br />                           <font color="#0000ff">)<br /></font>      <font color="#0000ff"><strong>RETURN</strong></font> <font color="#ff0000">VARCHAR2</font><font color="#0000ff">;</font></pre>
<pre>   <font color="#0000ff"><strong>FUNCTION</strong></font> is_current_user <font color="#0000ff">(</font>program_owner_in <font color="#0000ff"><strong>IN</strong></font> <font color="#ff0000">VARCHAR2</font><br />                           <font color="#0000ff">,</font> program_name_in  <font color="#0000ff"><strong>IN</strong></font> <font color="#ff0000">VARCHAR2</font><br />                            <font color="#0000ff">)</font><br />      <font color="#0000ff"><strong>RETURN</strong></font> <font color="#0000ff"><strong>BOOLEAN</strong></font>;</pre>
<pre>   <font color="#0000ff"><strong>FUNCTION</strong></font> is_definer <font color="#0000ff">(</font>program_owner_in <font color="#0000ff"><strong>IN</strong></font> <font color="#ff0000">VARCHAR2</font><br />                      <font color="#0000ff">,</font> program_name_in  <font color="#0000ff"><strong>IN</strong></font> <font color="#ff0000">VARCHAR2</font><br />                       <font color="#0000ff">)</font><br />      <font color="#0000ff"><strong>RETURN BOOLEAN;</strong></font></pre>
<pre>   <font color="#0000ff"><strong>PROCEDURE</strong></font> analyze_callstack <font color="#0000ff"><strong>(</strong></font>callstack_in <font color="#0000ff"><strong>IN</strong></font> <font color="#ff0000">VARCHAR2</font> <font color="#0000ff"><strong>DEFAULT NULL);<br />END</strong></font> authid_analysis<font color="#0000ff"><strong>;</strong></font></pre>
</blockquote>
<p>You can retrieve the AUTHID setting of a program from ALL_PROCEDURES and find out if a program is invoker rights (is_current_user) or definer rights (is_definer).</p>
<p>Finally, call the analyze_callstack procedure to identify possible problems, as described above. If you do not pass the call stack, analyze_callstack will call the FORMAT_CALL_STACK function for you.</p>
<p>You can easily integrate this package into your error logging and tracing routine, making it easy to identify possible program areas in your code. I plan to add this to <a href="http://www.toadworld.com/LinkClick.aspx?link=685&#038;tabid=67">Quest Error Manager</a> as soon as I have a moment.</p>
<p>The authid_analysis.tst scritp will allow you run a quick test of this utility. Here's what I see:</p>
<blockquote style="margin-right: 0px" dir="ltr">
<pre><font color="#0000ff"><strong>CREATE OR REPLACE PROCEDURE</strong></font> proc1<br />   <font color="#0000ff"><strong>AUTHID CURRENT_USER<br />IS<br />BEGIN</strong></font><br />   authid_analysis.analyze_callstack;<br /><font color="#0000ff"><strong>END;<br />/</strong></font></pre>
<pre><font color="#0000ff"><strong>CREATE OR REPLACE PROCEDURE</strong></font> proc2<br /><font color="#0000ff"><strong>IS<br />BEGIN</strong></font><br />   proc1;<br /><font color="#0000ff"><strong>END;<br />/</strong></font></pre>
<pre><font color="#0000ff"><strong>CREATE OR REPLACE PROCEDURE</strong></font> proc3<br />   <font color="#0000ff"><strong>AUTHID CURRENT_USER<br />IS<br />BEGIN<br /></strong></font>   proc2;<br /><font color="#0000ff"><strong>END;<br />/</strong></font></pre>
<pre><font color="#0000ff"><strong>BEGIN<br /></strong></font>   proc3;<br /><strong><font color="#0000ff">END;<br />/<br /></font>> DEFINER      package body HR.AUTHID_ANALYSIS called by...<br />> CURRENT_USER procedure HR.PROC1 called by...<br />> DEFINER      procedure HR.PROC2 called by...<br />> CURRENT_USER procedure HR.PROC3 called by...<br />>              anonymous block</strong></pre>
</blockquote>
<p>As you can see, I have a switch from invoker rights to definer rights in the call to PROC2 and that will likely cause problems.</p>
<p>I hope you find this utility useful.</p>
<p> </p>]]></description>
			<content:encoded><![CDATA["Invoker rights, what's that?" you may be asking.

That wouldn't surprise me, greatly, though one might consider it a bit odd because the invoker rights feature of PL/SQL was added in Oracle8i - many years ago!

So I will first offer a brief overview of invoker rights, why you'd use it, how you use it. Then I will introduce one of the major challenges with invoker rights. Finally, I offer a utility that can help you overcome that challenge.]]></content:encoded>
			<wfw:commentRss>http://www.toadworld.com/BLOGS/tabid/67/EntryID/527/Default.aspx/feed</wfw:commentRss>
		</item>
		<item>
		<title>Books That Taught Me Lots</title>
		<link>http://www.toadworld.com/BLOGS/tabid/67/EntryID/521/Default.aspx</link>
		<comments>http://www.toadworld.com/BLOGS/tabid/67/EntryID/521/Default.aspx#comments</comments>
		<pubDate>Mon, 29 Mar 2010 13:01:00 +0000</pubDate>
		<dc:creator>Steven Feuerstein</dc:creator>
		
		<category><![CDATA[Steven Feuerstein's Blog]]></category>

		<guid isPermaLink="false">http://www.toadworld.com/Default.aspx?tabid=67&EntryID=521</guid>
		<description><![CDATA[I have certainly learned a lot over the years from other authors, and I thought I would share with you my fairly eclectic collection of favorite books (those that have informed my programming, in any case). ]]></description>
			<content:encoded><![CDATA[I have certainly learned a lot over the years from other authors, and I thought I would share with you my fairly eclectic collection of favorite books (those that have informed my programming, in any case).]]></content:encoded>
			<wfw:commentRss>http://www.toadworld.com/BLOGS/tabid/67/EntryID/521/Default.aspx/feed</wfw:commentRss>
		</item>
		<item>
		<title>DECODE/CASE vs. Mapping Tables</title>
		<link>http://thinkoracle.blogspot.com/2010/03/decodecase-vs-mapping-tables.html</link>
		<comments>http://thinkoracle.blogspot.com/2010/03/decodecase-vs-mapping-tables.html#comments</comments>
		<pubDate>Thu, 25 Mar 2010 10:00:00 +0000</pubDate>
		<dc:creator>Robert Vollman</dc:creator>
		
		<category><![CDATA[Robert Vollman's OracleBlog]]></category>

		<guid isPermaLink="false">tag:blogger.com,1999:blog-12950820.post-3540526415671193008</guid>
		<description><![CDATA[If you've got several queries that are all using DECODE and/or CASE to map one value to another, consider creating a mapping table and joining that into your queries instead. It will make them easier to maintain, and depending on your indexes it might even speed up some queries.]]></description>
			<content:encoded><![CDATA[If you've got several queries that are all using DECODE and/or CASE to map one value to another, consider creating a mapping table and joining that into your queries instead. It will make them easier to maintain, and depending on your indexes it might even speed up some queries.]]></content:encoded>
			<wfw:commentRss>http://thinkoracle.blogspot.com/2010/03/decodecase-vs-mapping-tables.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>Improving your SQL Queries</title>
		<link>http://thinkoracle.blogspot.com/2010/02/improving-your-sql-queries.html</link>
		<comments>http://thinkoracle.blogspot.com/2010/02/improving-your-sql-queries.html#comments</comments>
		<pubDate>Tue, 23 Feb 2010 14:27:00 +0000</pubDate>
		<dc:creator>Robert Vollman</dc:creator>
		
		<category><![CDATA[Robert Vollman's OracleBlog]]></category>

		<guid isPermaLink="false">tag:blogger.com,1999:blog-12950820.post-7655092510718296478</guid>
		<description><![CDATA[Recently I've been of service to some of my colleagues who have been writing SQL Queries. Based on their feedback, I have helped them write faster-performing queries, in a shorter period of time, with fewer mistakes, and in such a way that maintenance was simpler. If you have found any use in what I'm about [...]]]></description>
			<content:encoded><![CDATA[Recently I've been of service to some of my colleagues who have been writing SQL Queries. Based on their feedback, I have helped them write faster-performing queries, in a shorter period of time, with fewer mistakes, and in such a way that maintenance was simpler. If you have found any use in what I'm about to present, you can thank them for encouraging me to dust off my blog and make another contribution to the community.]]></content:encoded>
			<wfw:commentRss>http://thinkoracle.blogspot.com/2010/02/improving-your-sql-queries.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>Always Bulk Collect</title>
		<link>http://www.toadworld.com/Community/QuestExpertsBlogs/tabid/67/EntryID/239/Default.aspx</link>
		<comments>http://www.toadworld.com/Community/QuestExpertsBlogs/tabid/67/EntryID/239/Default.aspx#comments</comments>
		<pubDate>Mon, 23 Jun 2008 14:34:00 +0000</pubDate>
		<dc:creator>Steven Feuerstein</dc:creator>
		
		<category><![CDATA[Steven Feuerstein's Blog]]></category>

		<guid isPermaLink="false">http://www.toadworld.com/Default.aspx?tabid=67&EntryID=239</guid>
		<description><![CDATA[You learn something new every day, right? Well, I certainly do (more or less). Even about PL/SQL, about which I am sure many people think I already know <em>everything</em>. Far from it.

In fact, I learned just last week from the PL/SQL Product Manager, Bryn Llewellyn, that his recommendation regarding cursor FOR loops and bulk collect is different from mine – and for a very good reason.]]></description>
			<content:encoded><![CDATA[<div>You learn something new every day, right? Well, I certainly do (more or less). Even about PL/SQL, about which I am sure many people think I already know <em>everything</em>. Far from it.</div>
<div>In fact, I learned just last week from the PL/SQL Product Manager, Bryn Llewellyn, that his recommendation regarding cursor FOR loops and bulk collect is different from mine – and for a very good reason.</div>]]></content:encoded>
			<wfw:commentRss>http://www.toadworld.com/Community/QuestExpertsBlogs/tabid/67/EntryID/239/Default.aspx/feed</wfw:commentRss>
		</item>
		<item>
		<title>More Blogs</title>
		<link>http://oracledoug.com/serendipity/index.php?/archives/1419-More-Blogs.html</link>
		<comments>http://oracledoug.com/serendipity/index.php?/archives/1419-More-Blogs.html#comments</comments>
		<pubDate>Tue, 10 Jun 2008 19:55:46 +0000</pubDate>
		<dc:creator>Doug Burns</dc:creator>
		
		<category><![CDATA[Doug's Oracle Blog]]></category>

		<guid isPermaLink="false">http://oracledoug.com/serendipity/index.php?/archives/1419-guid.html</guid>
		<description><![CDATA[    It's good to see some more people joining in, particularly those I already know and admire.<br /><br />First up is <a href="http://markjbobak.wordpress.com/">Mark Bobak</a>, who I've met at several conferences and, as you can tell from his first few posts, is likely to have some interesting technical tales to tell.<br /><br />Via Mark's blog-roll, I noticed <a href="http://adhdocddba.blogspot.com/">Robyn Sands</a> has been blogging for a while, too. As well as having shared DBA interests (being oddly organised; OFA and anything else that brings some engineering discipline to our field), we have the same taste in presentation images.<br /><br />Next is <a href="http://karenmorton.blogspot.com/">Karen Morton</a> of <a href="http://method-r.com/">Method R Corp</a>., Cary Millsap's new company, who has an interesting blog post about <a href="http://karenmorton.blogspot.com/2008/06/future-of-presenting.html">presentation style</a>. Maybe I'll comment more on that later, but it's been a very long (if interesting) day at work and Ibrahimovic just scored the first goal after I missed laying the bet on him that I'd planned <img src="http://oracledoug.com/serendipity/templates/default/img/emoticons/sad.png" alt=":-(" style="display: inline; vertical-align: bottom;" class="emoticon" /><br /><br />Oh, and to revisit <a href="http://www.liberidu.com/blog/">an old favourite</a> - do you think that the Dutch are quite pleased about last night's 3-0 victory against Italy? (I don't know whether he's changed the oranje, but it seems much calmer than how it looked in the office today!) They have every right to be too, but don't tell me that prone Italian defender was playing Van Nistelrooy onside! (Ooops, slipped into a personal blog moment there)<br />
 
    ]]></description>
			<content:encoded><![CDATA[It's good to see some more people joining in, particularly those I already know and admire.

First up is <a href="http://markjbobak.wordpress.com/">Mark Bobak</a>, who I've met at several conferences and, as you can tell from his first few posts, is likely to have some interesting technical tales to tell.]]></content:encoded>
			<wfw:commentRss>http://oracledoug.com/serendipity/index.php?/archives/1419-More-Blogs.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>How to Run an OS Command from PL/SQL</title>
		<link>http://www.toadworld.com/Community/QuestExpertsBlogs/tabid/67/EntryID/228/Default.aspx</link>
		<comments>http://www.toadworld.com/Community/QuestExpertsBlogs/tabid/67/EntryID/228/Default.aspx#comments</comments>
		<pubDate>Wed, 04 Jun 2008 14:11:00 +0000</pubDate>
		<dc:creator>Steven Feuerstein</dc:creator>
		
		<category><![CDATA[Steven Feuerstein's Blog]]></category>

		<guid isPermaLink="false">http://www.toadworld.com/Default.aspx?tabid=67&EntryID=228</guid>
		<description><![CDATA[<p>Oracle doesn't make it terribly easy to run operating system commands from within a PL/SQL block. I suppose that's understandable, given that PL/SQL is an embedded database-oriented language. Still, developers do ask me on a regular basis about how they can do this.</p>
<p>As I understand it, there are basically three ways to do this:</p>
<ol>
    <li>Invoke a Java method from within a PL/SQL wrapper<br />
     </li>
    <li>Call a C program as an external procedure from within PL/SQL.<br />
     </li>
    <li>Use the new DBMS_SCHEDULER package.</li>
</ol>
<p>I will soon publish a DBMS_SCHEDULER solution (written by Bryn Llewellyn, PL/SQL Product Manager) on my OTN Best Practices column. In the meantime, you will find below a quick review of the steps needed to do this in Java and C.</p>
<p><font size="3"><strong>Executing Host Command with Java</strong></font></p>
<p>With the Java approach, you will take these steps:</p>
<ol>
    <li>Find the Java class that implements host command execution.<br />
     </li>
    <li>Build a class that invokes that host command method. Let's call it HostCommand.<br />
     </li>
    <li>Build a PL/SQL program that calls a method in HostCommand to run your command.<br />
     </li>
    <li>Acquire the privileges needed to execute host commands via Java in the database.</li>
</ol>
<p>Let's go through each of these steps.</p>
<p><strong>1. Find the Java class that implements host command execution.</strong></p>
<p>Objects of the java.lang.Runtime class include an exec method that will execute a host command.</p>
<p><strong>2. Build a class that invokes that host command method.</strong></p>
<p>Let's call it HostCommand.</p>
<p>Here's code to create a new Java class in the database to invoke this command for the Windows XP operating system:</p>
<blockquote>
<pre>CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "UTLcmd"<br />AS import java.lang.Runtime;<br />public class execHostCommand<br />{ <br />  public static void execute (String command) <br />    throws java.io.IOException<br />  {<br />   String osName = System.getProperty("os.name");<br />   if(osName.equals("Windows XP"))<br />       command = "cmd /c " + command;<br />   Runtime rt = java.lang.Runtime.getRuntime();<br />   rt.exec(command);<br />  }<br />}<br />/</pre>
</blockquote>
<p>You can easily modify the execute method to support other operating systems based on the value of osName.</p>
<p><strong>3. Build a PL/SQL program that calls a method in HostCommand to run your command.</strong></p>
<blockquote>
<pre>CREATE OR REPLACE PACKAGE host_command IS<br />  PROCEDURE execute (cmd IN VARCHAR2) AS LANGUAGE JAVA NAME<br />           'execHostCommand.execute(java.lang.String)';<br />END;<br />/</pre>
</blockquote>
<p>Notice that I "map" the VARCHAR2 datatype to the java.lang.String class in my call to the new Java method.</p>
<p><strong>4. Acquire the privileges needed to execute host commands via Java in the database.</strong></p>
<p>You need special privileges to execute host commands from within the database through Java. Otherwise when you try to execute your command you will see an error like this (the error message will vary depending on what you are trying to do):</p>
<blockquote>
<p><img width="449" height="178" src="http://www.toadworld.com/Portals/0/blogimages/sf_blog060408.gif" alt="" /><br />
</p>
</blockquote>
<p>One way to obtain these privileges is to have the JAVASYSPRIV role granted to your schema. This role contains all the privileges you need (and more).</p>
<p>For a more nuanced approach to granting the required privileges, you can also use the Java security API available in the Oracle database. For example, if I want to delete a file using a host command (perhaps it is not accessible through UTL_FILE), I will need to grant the following privileges to the schema in which the command is executed, such as HR:</p>
<blockquote>
<pre>BEGIN<br />   DBMS_JAVA.grant_permission ('HR'<br />                             , 'SYS:java.io.FilePermission'<br />                             , '<<ALL FILES>>'<br />                             , 'execute'<br />                              );<br />   DBMS_JAVA.grant_permission ('HR'<br />                             , 'SYS:java.lang.RuntimePermission'<br />                             , 'writeFileDescriptor'<br />                             , ''<br />                              );<br />   DBMS_JAVA.grant_permission ('HR'<br />                             , 'SYS:java.lang.RuntimePermission'<br />                             , 'readFileDescriptor'<br />                             , ''<br />                              );<br />END;<br />/</pre>
</blockquote>
<p><font size="3"><strong>Executing Host Command with C</strong></font></p>
<p>To use C, you must define an external procedure and then invoke it within your PL/SQL block. It is not possible within this article to cover completely all the steps and issues involved in setting up such an external procedure. I will, instead, cover the highlights. For the full details, read Chapter 27 of Oracle PL/SQL Programming, 4th edition, in which my co-author Bill Pribyl thoroughly explains external procedures.</p>
<p>As with Java, you will need help from your database administrator to supply the privileges needed to execute your host command in C. </p>
<p>Here are the steps to follow with C:</p>
<ol>
    <li>Find (or build) the C program that implements host command execution.<br />
     </li>
    <li>Save the C source to a file and generate a shared library for it.<br />
     </li>
    <li>Save the library file where Oracle can find it.<br />
     </li>
    <li>Define a library inside Oracle that is associated with the shared library on disk.<br />
     </li>
    <li>Create a PL/SQL wrapper for the C function.</li>
</ol>
<p>Let's go through each of these steps.</p>
<p><strong>1. Find (or build) the C program that implements host command execution.</strong></p>
<p>The C system function executes an operating system command. So I build a simple C function, extprocsh(), that accepts a string and passes it to the system function for execution:</p>
<blockquote>
<pre>int extprocsh(char *cmd)<br />{<br />   return system(cmd);<br />}</pre>
</blockquote>
<p>The function returns the result code as provided by system, a function normally found in the C runtime library (libc) on Unix, or in msvcrt.dll on Microsoft platforms.</p>
<p><strong>2. Save the C source to a file and generate a shared library for it.</strong></p>
<p>I save the source code in a file named extprocsh.c. I then use the GNU C compiler to generate a shared library. On a 64-bit Solaris machine running GCC 3.4.2 and Oracle Database 10g Release 2, the following compiler command worked to create a shared library:</p>
<blockquote>
<pre>gcc -m64 extprocsh.c -fPIC -G -o extprocsh.so</pre>
</blockquote>
<p>Similarly, on Microsoft Windows XP Pro running GCC 3.2.3 from Minimal GNU for Windows (MinGW), also with Oracle Database 10g Release 2, this works:</p>
<blockquote>
<pre>c:\MinGW\bin\gcc extprocsh.c -shared -o extprocsh.dll</pre>
</blockquote>
<p><strong>3. Save the library file where Oracle can find it.</strong></p>
<p>These commands generate a shared library file, extprocsh.so or extprocsh.dll. Now I need to put the library file somewhere that Oracle can find it. The default locations for Windows and Unix respectively are:</p>
<blockquote>
<pre>$ORACLE_HOME/bin<br />$ORACLE_HOME/lib</pre>
</blockquote>
<p>If you want to use a non-default location, you will need to edit the listener configuration file and supply path value(s) for the ENVS="EXTPROC_DLLS...".</p>
<p><strong>4. Define a library inside Oracle that is associated with the shared library on disk.</strong></p>
<p>After copying the file and/or making adjustments to the listener, you will then define a "library" inside Oracle to point to the DLL. For example:</p>
<blockquote>
<pre>CREATE OR REPLACE LIBRARY extprocshell_lib <br />   AS '/u01/app/oracle/local/lib/extprocsh.so';   -- Unix<br />     <br />CREATE OR REPLACE LIBRARY extprocshell_lib<br />   AS 'c:\oracle\local\lib\extprocsh.dll';      -- Microsoft</pre>
</blockquote>
<p><strong>Note:</strong> performing this step requires Oracle's CREATE LIBRARY privilege.</p>
<p><strong>5. Create a PL/SQL wrapper for the C function.</strong></p>
<p>Now I can create a PL/SQL call specification which uses the newly created library:</p>
<blockquote>
<pre>CREATE OR REPLACE FUNCTION exec_host_command (cmd IN VARCHAR2)<br />   RETURN PLS_INTEGER<br />AS<br />   LANGUAGE C<br />   LIBRARY extprocshell_lib<br />   NAME "extprocsh"<br />   PARAMETERS (cmd STRING, RETURN INT);</pre>
</blockquote>
<p>Then, assuming that your DBA has set up the system environment to support external procedures, the exec_host_command function can now be called anywhere you can invoke a PL/SQL function.  </p>
<p>Note that these operating system commands will execute with the same privileges as the Oracle Net listener that spawns the extproc process.</p>]]></description>
			<content:encoded><![CDATA[Oracle doesn't make it terribly easy to run operating system commands from within a PL/SQL block. I suppose that's understandable, given that PL/SQL is an embedded database-oriented language. Still, developers do ask me on a regular basis about how they can do this.]]></content:encoded>
			<wfw:commentRss>http://www.toadworld.com/Community/QuestExpertsBlogs/tabid/67/EntryID/228/Default.aspx/feed</wfw:commentRss>
		</item>
		<item>
		<title>Testing and refreshing data from production</title>
		<link>http://www.toadworld.com/Community/QuestExpertsBlogs/tabid/67/EntryID/204/Default.aspx</link>
		<comments>http://www.toadworld.com/Community/QuestExpertsBlogs/tabid/67/EntryID/204/Default.aspx#comments</comments>
		<pubDate>Thu, 17 Apr 2008 16:21:00 +0000</pubDate>
		<dc:creator>Steven Feuerstein</dc:creator>
		
		<category><![CDATA[Steven Feuerstein's Blog]]></category>

		<guid isPermaLink="false">http://www.toadworld.com/Default.aspx?tabid=67&EntryID=204</guid>
		<description><![CDATA[<div>As many of my readers likely know by now, I have been working for the past several years on the Quest Code Tester development effort.<br />
 </div>
<div>Code Tester is the most powerful PL/SQL test automation tool available. You describe the expected behavior of your programs and Code Tester generates your test code, which can then be run from the UI or via a script. With Code Tester, you can build comprehensive regression tests and even implement the Test Driven Development methodology.<br />
 </div>
<div>In the process of talking about Code Tester with many developers, I have come across a belief regarding code testing and the refreshing of data from production tables that I think actually reflects a misunderstanding about both how to use Code Tester specifically and, more generally, how to test our code.<br />
 </div>
<div>Here's the way this belief was expressed by a customer recently:<br />
 </div>
<div>"We have a development environment - let's call it TEST. Inside this environment is the supporting schema / repository for Code Tester, as well as the test definitions and generated test code."<br />
 </div>
<div>"Once a week, we refresh the TEST environment from the production environment, PROD. PROD doesn't contain a Code Tester repository, so after I refresh, I lose my test repository and code."<br />
 </div>
<div>Clearly, this developer can do an export of the Code Tester schema and then import it after refresh, but he was concerned about having to add any overhead for the DBA to this refresh process.<br />
 </div>
<div>Actually, I think the problem goes much deeper than that: if you refresh your test tables with production data on a regular basis, you will find it very difficult indeed to create stable regression tests that can be run against your code.<br />
 </div>
<div>Why do I say that? Because when you refresh data from production, you change the "inputs" to your programs (contents of the tables) and therefore you will almost certainly have to change the expected results for your tests.</div>
<div>In fact, I think that when it comes to <em>functional testing of your programs </em>(does it meet user requirements?), you should <em>not</em> be refreshing your test tables from production. To understand why I would say this, let's talk about....<br />
 </div>
<div><strong><em><font size="3">How we make sure our programs work<br />
 </font></em></strong></div>
<div>There are as many kinds of tests as there are definitions of what it means for a program to "work." We need to make sure, for example, that our programs meet functional requirements (they are correct) and also that they run quickly enough to avoid user frustration. The programs need to scale up for many users and lots of data, etc.</div>
<div> <br />
<a href="http://unittest.inside.quest.com/index.jspa">Quest Code Tester</a> is designed specifically to help you implement tests on functional requirements; in essence, to verify that your program is correct.<br />
 </div>
<div>To do this, I will almost always want to compare the actual results of running my program with the expected results or control data. <br />
 </div>
<div>For example, if table XYZ contains a certain set of rows, then after running the program, table ABC should be changed in a specific way. Or the program is a function such that when I pass "ABC" for an IN argument, the function returns 100, and so on.<br />
 </div>
<div>In general, there is no room for ambiguity here. Either the program works as expected or it does not. <br />
 </div>
<div>Now, if I want to build regression tests and <em>automate</em> the process of testing my program, I need to able to tell Code Tester that for a given set of inputs, I expect the associated outcomes. And – this is the key thing to realize – those inputs can't keep changing on me. Every time the inputs change, I would need to change the expected outcomes. <br />
 </div>
<div>Constantly updating one's test code might make sense if you are perform manual tests from hand-coded scripts. But if you want to build comprehensive, serious regression tests, then you need a stable, consistent environment from which to run those tests.<br />
 </div>
<div>Every time you refresh data from production, you change the values in your table and thus you cannot reliably execute your regression test.<br />
 </div>
<div><strong><em><font size="3">But don't we need real production data to really test?<br />
 </font></em></strong></div>
<div>Is this a big problem? Does this mean that we can't or shouldn't build static, repeatable regression tests for our code? After all (so the thinking goes), we need to test our code against production data to make sure that code handles "real world" situations.<br />
 </div>
<div>Clearly, our code does need to work properly with production data.<br />
 </div>
<div>This does not mean, however, that you need to constantly change the data for your functional tests as production data changes. It <em>does</em> mean that the data used in functional tests should <em>represent</em> the variety of data found in production. <br />
 </div>
<div>In other words, the data in your test tables must be sufficiently varied to allow you to exercise the program to verify all requirements. It doesn't really matter so much that the data is precisely <em>the same</em> as that found in production.</div>
<div>And, again, if you keep changing the test data, you must also change your test definition.<br />
 </div>
<div><strong><em><font size="3">OK, but don’t we need to test against production volume?<br />
 </font></em></strong></div>
<div>There's another problem with basing functionality testing around production data: the data volumes are generally too large, increasing the time it takes to complete the tests. <br />
 </div>
<div>You certainly do need to make sure your code executes with production volumes of data. But that sort of <em>stress testing</em> should be done independently of your functionality testing. With functionality testing, you want your tests to run as quickly as possible, for these reasons:</div>
<ul type="disc">
    <li>You will have lots of (dozens, perhaps hundreds) of separate test cases to run; if each test takes five minutes due to data volume, the test cycle will take an enormous amount of time.<br />
      </li>
    <li>Ideally, you run your tests after each change you make to your program. That way, you can immediately determine if you have introduced any bugs. But if running those tests takes an hour, you will test less frequently and you will get less "return" on your investment of creating your tests. </li>
</ul>
<div><strong><em><font size="3">Conclusion: Segregate your functional test environment<br />
 </font></em></strong></div>
<div>The most important thing to verify about your program is that it is <em>correct</em>: it meets user requirements. <br />
 </div>
<div>The best way to do this is to build a regression test that you can run after any change to the program, to ensure that it has no bugs. <br />
 </div>
<div>A regression test should not have to be changed as long as the program itself has not changed. It should work from a consistent set of "inputs" (values for IN arguments, contents of any tables queried by programs, etc.) that do <em>not</em> change. [Of course, you may need to make some changes along the way as program requirements change, as you add more test cases, etc. That is different, however, from daily or weekly refreshes.]<br />
 </div>
<div>In addition, you want regression tests to run as efficiently as possible. These tests focus on program functionality, not performance. So you want the <em>minimum </em>volume of data in test tables that allow you to cover your requirements. Use different tests to verify adequate performance.<br />
 </div>
<div>Consequently, when it comes to functionality testing, you should avoid refreshing your test tables from production. Instead, invest the time upfront to come up with setup scripts to populate tables with data that fully exercises your code. Include those setup scripts in your Code Tester test definitions and then you have an independent, consistent test environment.</div>
<div> </div>
<div> </div>
<div> </div>
<div> </div>]]></description>
			<content:encoded><![CDATA[<div>As many of my readers likely know by now, I have been working for the past several years on the Quest Code Tester development effort.
</div>
<div>Code Tester is the most powerful PL/SQL test automation tool available. You describe the expected behavior of your programs and Code Tester generates your test code, which can then be run from the UI or via a script. With Code Tester, you can build comprehensive regression tests and even implement the Test Driven Development methodology.</div>
<div></div>
<div></div>]]></content:encoded>
			<wfw:commentRss>http://www.toadworld.com/Community/QuestExpertsBlogs/tabid/67/EntryID/204/Default.aspx/feed</wfw:commentRss>
		</item>
	</channel>
</rss>
