<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
  <channel xmlns:blog="http://www.dotnetnuke.com/blog/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
    <title>Steven Feuerstein's Blog</title>
    <description>&lt;table cellspacing="1" cellpadding="1"&gt;
        &lt;tr&gt;
            &lt;td valign="top"&gt;&lt;img height="183" alt="" width="139" src="/Portals/0/Blog/blog-steven-feuerstein.png" /&gt;&lt;/td&gt;
            &lt;td valign="top"&gt;Steven Feuerstein is considered one of the world's leading experts on the Oracle PL/SQL language, having written ten books on PL/SQL (all published by O'Reilly Media, including Oracle PL/SQL Programming. Steven has been developing software since 1980, spent five years with Oracle (1987-1992) and has served as PL/SQL Evangelist for Quest Software since January 2001. He is also an Oracle ACE Director. He writes regularly for Oracle Magazine, which named him the PL/SQL Developer of the Year in both 2002 and 2006.
            &lt;p&gt;&amp;#160;Steven's blog provides advice and code that you can put to immediate use in your world of programming.&amp;#160;&lt;/p&gt;
            &lt;p&gt;&lt;font color="#003366" size="3"&gt;&lt;strong&gt;Recent postings on his  PL/SQL Obsession:&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
&lt;/table&gt;</description>
    <link>http://www.toadworld.com/BLOGS/tabid/67/BlogId/13/Default.aspx</link>
    <language>en-US</language>
    <webMaster>Steven Feuerstein</webMaster>
    <pubDate>Thu, 02 Sep 2010 17:30:16 GMT</pubDate>
    <lastBuildDate>Thu, 02 Sep 2010 17:30:16 GMT</lastBuildDate>
    <docs>http://backend.userland.com/rss</docs>
    <generator>Blog RSS Generator Version 4.0.0.0</generator>
    <item>
      <title>Should you use an associative array or a nested table?</title>
      <link>http://toadworld.com/BLOGS/tabid/67/EntryId/584/Should-you-use-an-associative-array-or-a-nested-table.aspx</link>
      <description>&lt;div&gt;I recently received this question from Syed:&lt;/div&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;div&gt;"How does Oracle store the data for associative arrays and nested tables internally? Which type of collection is better for processing a huge volume of data without putting back into the database?"&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div&gt;First, regarding the question of "internal" storage: I have no idea how Oracle manages these structures. I expect that the PL/SQL development team uses some kind of linked list implementation. I also suppose that I could ask Bryn Llewellyn (the PL/SQL Product Manager) about this, but I am certain his answers will be:&lt;/div&gt;
&lt;ol&gt;
    &lt;li&gt;Why should you care?&lt;/li&gt;
    &lt;li&gt;We don't give out information like this.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;And I agree with him: why should we care? We just need to know that we can use the data structures with confidence (no or minimal bugs, good performance). Why get caught up with "internal" details that can change from version to version anyway?&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Now, on to the question of which is better.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;If my memory serves me, back in the early days of the introduction of nested tables and varrays (Oracle8), the performance and memory management of associative arrays (the "original" collection type, introduced in Oracle7) was better than that for nested tables.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;These days (Oracle10g Release 2 and higher), I believe that you will see comparable levels of performance and memory usage, regardless of the type of collection you use.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I don't have lots of time to build scripts that exercise lots of test cases, but I did put together a script to compare the amount of memory and time required to load over 1.2M rows into both an associative array and nested table.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The code is shown below, and relies on several packages you will find in my &lt;a href="http://www.toadworld.comhttp://www.toadworld.com/Portals/0/stevenf/demo.zip"&gt;demo.zip&lt;/a&gt; file. The results of one row is as follows:&lt;/div&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre&gt;SQL&gt; @c:\work\demo-seminar\aa_vs_nt&lt;br /&gt;Connected.&lt;br /&gt;Associative memory&lt;br /&gt;1225043&lt;br /&gt;- Elapsed CPU : 3.02 seconds.&lt;br /&gt;Change in UGA memory: 65512 (Current = 373096)&lt;br /&gt;Change in PGA memory: 485490688 (Current = 486150372)&lt;br /&gt; &lt;br /&gt;PL/SQL procedure successfully completed.&lt;br /&gt; &lt;br /&gt;Connected.&lt;br /&gt;Nested table&lt;br /&gt;1225043&lt;br /&gt;- Elapsed CPU : 2.82 seconds.&lt;br /&gt;Change in UGA memory: 65512 (Current = 373096)&lt;br /&gt;Change in PGA memory: 485490688 (Current = 486150372)&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;div&gt;The bottom line? You will not see any discernable difference between the two.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So when you are trying to decide which of the collection types you should use, base the decision on functionality, not performance.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;With associative arrays, you get:&lt;/div&gt;
&lt;ul&gt;
    &lt;li&gt;Ability to index by strings&lt;/li&gt;
    &lt;li&gt;Use of negative index values and a larger range of index values than with a nested table&lt;/li&gt;
    &lt;li&gt;Sparse collections (nested tables can be sparse, but they are more naturally used with densely-filled lists of information).&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;With nested tables, you get:&lt;/div&gt;
&lt;ul&gt;
    &lt;li&gt;Use of MULTISET operators to perform set-level operations, just like in SQL&lt;/li&gt;
    &lt;li&gt;Ability to query from nested tables using the TABLE operator&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;p&gt; &lt;hr /&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;font size="3"&gt;The script (in &lt;a href="http://www.toadworld.comhttp://www.toadworld.com/Portals/0/stevenf/demo.zip"&gt;demo.zip&lt;/a&gt; - aa_vs_nt.sql)&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;pre&gt;connecthr/hr&lt;br /&gt; &lt;br /&gt;setserveroutputon&lt;br /&gt; &lt;br /&gt;DECLARE&lt;br /&gt;   TYPEemployees_aatISTABLEOFemployees%ROWTYPE&lt;br /&gt;                            INDEXBYPLS_INTEGER;&lt;br /&gt; &lt;br /&gt;   l_aat   employees_aat;&lt;br /&gt; &lt;br /&gt;   TYPEemployees_ntISTABLEOFemployees%ROWTYPE;&lt;br /&gt; &lt;br /&gt;   l_nt    employees_nt;&lt;br /&gt; &lt;br /&gt;   PROCEDUREstart_test(tVARCHAR2)&lt;br /&gt;   IS&lt;br /&gt;   BEGIN&lt;br /&gt;      DBMS_OUTPUT.put_line(t);&lt;br /&gt;      DBMS_SESSION.free_unused_user_memory;&lt;br /&gt;      plsql_memory.start_analysis;&lt;br /&gt;      sf_timer.start_timer;&lt;br /&gt;   END;&lt;br /&gt;BEGIN&lt;br /&gt;   start_test('Associative memory');&lt;br /&gt; &lt;br /&gt;   SELECTe1.*&lt;br /&gt;     BULKCOLLECTINTOl_aat&lt;br /&gt;     FROMemployees,employees,employeese1;&lt;br /&gt; &lt;br /&gt;   DBMS_OUTPUT.put_line(l_aat.COUNT);&lt;br /&gt;   sf_timer.show_elapsed_time;&lt;br /&gt;   plsql_memory.show_memory_usage;&lt;br /&gt;   l_aat.delete;&lt;br /&gt;END;&lt;br /&gt;/&lt;br /&gt; &lt;br /&gt;connecthr/hr&lt;br /&gt; &lt;br /&gt;setserveroutputon&lt;br /&gt; &lt;br /&gt;DECLARE&lt;br /&gt;   TYPEemployees_aatISTABLEOFemployees%ROWTYPE&lt;br /&gt;                            INDEXBYPLS_INTEGER;&lt;br /&gt; &lt;br /&gt;   l_aat   employees_aat;&lt;br /&gt; &lt;br /&gt;   TYPEemployees_ntISTABLEOFemployees%ROWTYPE;&lt;br /&gt; &lt;br /&gt;   l_nt    employees_nt;&lt;br /&gt; &lt;br /&gt;   PROCEDUREstart_test(tVARCHAR2)&lt;br /&gt;   IS&lt;br /&gt;   BEGIN&lt;br /&gt;      DBMS_OUTPUT.put_line(t);&lt;br /&gt;      DBMS_SESSION.free_unused_user_memory;&lt;br /&gt;      plsql_memory.start_analysis;&lt;br /&gt;      sf_timer.start_timer;&lt;br /&gt;   END;&lt;br /&gt;BEGIN&lt;br /&gt;   start_test('Nested table');&lt;br /&gt; &lt;br /&gt;   SELECTe1.*&lt;br /&gt;     BULKCOLLECTINTOl_nt&lt;br /&gt;     FROMemployees,employees,employeese1;&lt;br /&gt; &lt;br /&gt;   DBMS_OUTPUT.put_line(l_nt.COUNT);&lt;br /&gt;   sf_timer.show_elapsed_time;&lt;br /&gt;   plsql_memory.show_memory_usage;&lt;br /&gt;END;&lt;br /&gt;/&lt;/pre&gt;&lt;br /&gt;&lt;a href=http://toadworld.com/BLOGS/tabid/67/EntryId/584/Should-you-use-an-associative-array-or-a-nested-table.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: oracle,plsql,nested table&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://toadworld.com/BLOGS/tabid/67/EntryId/584/Should-you-use-an-associative-array-or-a-nested-table.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://toadworld.com/BLOGS/tabid/67/EntryId/584/Should-you-use-an-associative-array-or-a-nested-table.aspx</guid>
      <pubDate>Tue, 17 Aug 2010 14:33:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=584</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/149/Default.aspx">nested table</blog:tag>
    </item>
    <item>
      <title>PL/SQL Developers win over US$2000 in prizes at PL/SQL Challenge playoff</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/572/PL-SQL-Developers-win-over-US-2000-in-prizes-at-PL-SQL-Challenge-playoff.aspx</link>
      <description>&lt;p&gt;On 15 July 2010, 32 developers participated in the first-ever PL/SQL Challenge championship playoff. This playoff (consisting of ten questions to be answered in 15 minutes) was the culmination of a three-month competition in which PL/SQL developers from around the world tested their knowledge of PL/SQL against one another through daily quizzes.&lt;/p&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/572/PL-SQL-Developers-win-over-US-2000-in-prizes-at-PL-SQL-Challenge-playoff.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/572/PL-SQL-Developers-win-over-US-2000-in-prizes-at-PL-SQL-Challenge-playoff.aspx</guid>
      <pubDate>Tue, 20 Jul 2010 13:51:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=572</trackback:ping>
    </item>
    <item>
      <title>RAISE vs RAISE_APPLICATION_ERROR?</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/568/RAISE-vs-RAISE_APPLICATION_ERROR.aspx</link>
      <description>&lt;p&gt;Steven explains the difference between RAISE_APPLICATION_ERROR and RAISE and why you would use one vs. the other.&lt;/p&gt;&lt;div class="tags"&gt;Tags: plsql,oracle&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/568/RAISE-vs-RAISE_APPLICATION_ERROR.aspx#Comments</comments>
      <slash:comments>2</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/568/RAISE-vs-RAISE_APPLICATION_ERROR.aspx</guid>
      <pubDate>Wed, 14 Jul 2010 20:02:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=568</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
    </item>
    <item>
      <title>New Utilities in demo.zip</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/556/New-Utilities-in-demo-zip.aspx</link>
      <description>&lt;div&gt;I recently needed to move the contents of clobs and collections to and from files, and also write simple reporting routines. So I ended up creating the following and uploading them to my &lt;u&gt;&lt;a href="http://www.toadworld.com/Portals/0/stevenf/demo.zip"&gt;demo.zip&lt;/a&gt;&lt;/u&gt; download:&lt;/div&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;export_clob.sql&lt;/strong&gt; - move the contents of a clob to the specified file or to system output, if no file is specified. &lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;file_to_clob.sql&lt;/strong&gt; - load the contents of a file into a clob&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;collection_to_file.sql&lt;/strong&gt; - writes the contents of a collection declared on the DBMS_SQL.varchar2a type to the specified file.&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;display_clob_by_cr.sql&lt;/strong&gt; - writes the contents of a clob to system output, using a line feed (CHR(10)) as the delimiter. &lt;em&gt;[Note: original publication of blog entry said "carriage return"; I changed it to "line feed"]&lt;/em&gt;&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;display_header.sql&lt;/strong&gt; - displays the specified string as a "header", which means that it looks like this:&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre&gt;===========================================================&lt;br /&gt;Written by Steven Feuerstein&lt;br /&gt;===========================================================&lt;/pre&gt;
&lt;div&gt;You can specify the length of the header, the border character, and more.&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div&gt;I hope you find these utilities useful. As always, it is your responsibility to ensure that these programs meet your requirements and have no bugs.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;If you &lt;em&gt;do&lt;/em&gt; find a bug or a way to improve any of these programs, please don't hesitate to let me know.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/556/New-Utilities-in-demo-zip.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,oracle&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/556/New-Utilities-in-demo-zip.aspx#Comments</comments>
      <slash:comments>2</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/556/New-Utilities-in-demo-zip.aspx</guid>
      <pubDate>Mon, 28 Jun 2010 13:18:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=556</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
    </item>
    <item>
      <title>Handy new warning in Oracle 11.2</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/550/Handy-new-warning-in-Oracle-11-2.aspx</link>
      <description>&lt;div style="margin: 2pt 0in 3pt"&gt;Way back when Oracle10g was released, Oracle added compile-time warnings to the PL/SQL compiler.&lt;/div&gt;
&lt;div style="margin: 2pt 0in 3pt"&gt;
&lt;p&gt;When you enabled warnings in your session (or for a specific program), then at the time of compilation, Oracle will check to see if it can identify ways in which you might be able to improve the quality or performance of your code.&lt;/p&gt;
&lt;p&gt;You can read more about the compile time warnings feature &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10472/errors.htm#LNPLS00711"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div style="margin: 2pt 0in 3pt"&gt;You can see a list of all compile time warnings available &lt;a href="http://download.oracle.com/docs/cd/E11882_01/server.112/e10880/plwus.htm#sthref18222"&gt;here&lt;/a&gt;.&lt;/div&gt;
&lt;div style="margin: 2pt 0in 3pt"&gt;
&lt;p&gt;When this feature was first made available, I was both excited and disappointed.&lt;/p&gt;
&lt;/div&gt;
&lt;div style="margin: 2pt 0in 3pt"&gt;Excited, because I could now easily determine if, for example, my program unit had any "dead code" - code that would never execute, no matter what (that's warning PLW-06002).&lt;/div&gt;
&lt;div style="margin: 2pt 0in 3pt"&gt;
&lt;p&gt;Disappointed, because Oracle did not implement warnings for some of the most common and irritating coding mistakes, such as:&lt;/p&gt;
&lt;/div&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;SQL&gt; &lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;CREATE &lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;OR &lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;REPLACE &lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;PROCEDURE &lt;/span&gt;&lt;span style="background: white; color: black; font-size: 10pt"&gt;my_prod&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;&lt;span style="background: white; color: black"&gt;  &lt;/span&gt;&lt;span style="background: white; color: maroon; font-size: 10pt"&gt;2&lt;/span&gt;&lt;span style="background: white; color: black"&gt;        &lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;AUTHID &lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;CURRENT_USER&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;&lt;span style="background: white; color: black"&gt;  &lt;/span&gt;&lt;span style="background: white; color: maroon; font-size: 10pt"&gt;3&lt;/span&gt;&lt;span style="background: white; color: black"&gt;   &lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;IS&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;&lt;span style="background: white; color: black"&gt;  &lt;/span&gt;&lt;span style="background: white; color: maroon; font-size: 10pt"&gt;4&lt;/span&gt;&lt;span style="background: white; color: black"&gt;        &lt;/span&gt;&lt;span style="background: white; color: black; font-size: 10pt"&gt;l_string &lt;/span&gt;&lt;span style="background: white; color: red; font-size: 10pt"&gt;VARCHAR2&lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;(&lt;/span&gt;&lt;span style="background: white; color: maroon; font-size: 10pt"&gt;1&lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;) &lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;:= &lt;/span&gt;&lt;span style="background: white; color: red; font-size: 10pt"&gt;'abc'&lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;&lt;span style="background: white; color: black"&gt;  &lt;/span&gt;&lt;span style="background: white; color: maroon; font-size: 10pt"&gt;5&lt;/span&gt;&lt;span style="background: white; color: black"&gt;   &lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;BEGIN&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;&lt;span style="background: white; color: black"&gt;  &lt;/span&gt;&lt;span style="background: white; color: maroon; font-size: 10pt"&gt;6&lt;/span&gt;&lt;span style="background: white; color: black"&gt;     &lt;/span&gt;&lt;span style="background: white; color: black; font-size: 10pt"&gt;l_string &lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;:= &lt;/span&gt;&lt;span style="background: white; color: red; font-size: 10pt"&gt;'abc'&lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;&lt;span style="background: white; color: black"&gt;  &lt;/span&gt;&lt;span style="background: white; color: maroon; font-size: 10pt"&gt;7&lt;/span&gt;&lt;span style="background: white; color: black"&gt;   &lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;END;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;&lt;span style="background: white; color: black"&gt;  &lt;/span&gt;&lt;span style="background: white; color: maroon; font-size: 10pt"&gt;8  &lt;/span&gt;&lt;span style="background: white; color: black"&gt; &lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;/&lt;/span&gt;&lt;/pre&gt;
&lt;div style="margin: 2pt 0in 3pt"&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;span style="background: white"&gt;In this program, I try to assign a value that is too big for the variable, which will cause Oracle to raise a runtime VALUE_ERROR exception. But I want to hear about this problem at compile-time, not run-time.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div style="margin: 2pt 0in 3pt"&gt;&lt;span style="background: white"&gt;Well, in 11.2, code like that found in lines 4 and 6 are now flagged as problematic, as you can see when I show the errors after I attempt to compile this procedure:&lt;/span&gt;&lt;/div&gt;
&lt;div style="margin: 2pt 0in 3pt"&gt; &lt;/div&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;SQL&gt; &lt;/span&gt;&lt;span style="background: white; color: black; font-size: 10pt"&gt;sho &lt;/span&gt;&lt;span style="background: white; color: black; font-size: 10pt"&gt;err&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;Errors &lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;for &lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;PROCEDURE &lt;/span&gt;&lt;span style="background: white; color: black; font-size: 10pt"&gt;MY_PROC&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt; &lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;&lt;span style="background: white; color: black; font-size: 10pt"&gt;LINE&lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;/&lt;/span&gt;&lt;span style="background: white; color: black; font-size: 10pt"&gt;COL &lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;ERROR&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;&lt;span style="background: white; color: green; font-size: 10pt"&gt;-------- -----------------------------------------------------------------&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;&lt;span style="background: white; color: maroon; font-size: 10pt"&gt;4&lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;/&lt;/span&gt;&lt;span style="background: white; color: maroon; font-size: 10pt"&gt;4&lt;/span&gt;&lt;span style="background: white; color: black"&gt;      &lt;/span&gt;&lt;span style="background: white; color: black; font-size: 10pt"&gt;PLW&lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;-&lt;/span&gt;&lt;span style="background: white; color: maroon; font-size: 10pt"&gt;06017&lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;: &lt;/span&gt;&lt;span style="background: white; color: black; font-size: 10pt"&gt;an &lt;/span&gt;&lt;span style="background: white; color: black; font-size: 10pt"&gt;operation &lt;/span&gt;&lt;span style="background: white; color: black; font-size: 10pt"&gt;will &lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;raise &lt;/span&gt;&lt;span style="background: white; color: black; font-size: 10pt"&gt;an &lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;exception&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;&lt;span style="background: white; color: maroon; font-size: 10pt"&gt;6&lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;/&lt;/span&gt;&lt;span style="background: white; color: maroon; font-size: 10pt"&gt;4&lt;/span&gt;&lt;span style="background: white; color: black"&gt;      &lt;/span&gt;&lt;span style="background: white; color: black; font-size: 10pt"&gt;PLW&lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;-&lt;/span&gt;&lt;span style="background: white; color: maroon; font-size: 10pt"&gt;06017&lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;: &lt;/span&gt;&lt;span style="background: white; color: black; font-size: 10pt"&gt;an &lt;/span&gt;&lt;span style="background: white; color: black; font-size: 10pt"&gt;operation &lt;/span&gt;&lt;span style="background: white; color: black; font-size: 10pt"&gt;will &lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;raise &lt;/span&gt;&lt;span style="background: white; color: black; font-size: 10pt"&gt;an &lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;exception&lt;/span&gt;&lt;/pre&gt;
&lt;div style="margin: 2pt 0in 3pt"&gt;
&lt;p&gt;So that is very, very nice….but it would have been so much nicer if the warning message could have been a bit more specific. Here's the explanation for this warning:&lt;/p&gt;
&lt;/div&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;div style="margin: 2pt 0in 3pt"&gt;&lt;span style="color: blue; font-size: 10pt"&gt;"&lt;/span&gt;The compiler has determined that some operation near this location is certain to raise an exception during execution. This may be a programming error; consider rewriting the code. If the intention is to raise an exception, use an explicit RAISE statement."&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div style="margin: 2pt 0in 3pt"&gt;
&lt;p&gt;Well, that covers a lot of territory.&lt;/p&gt;
&lt;p&gt;Another problem with this warning is that it only works for VARCHAR2; you will not see this warning if you write a line of code like:&lt;/p&gt;
&lt;/div&gt;
&lt;pre style="margin: 2pt 0in 3pt"&gt;&lt;span style="background: white; color: black; font-size: 10pt"&gt;l_string &lt;/span&gt;&lt;span style="background: white; color: red; font-size: 10pt"&gt;CHAR&lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;(&lt;/span&gt;&lt;span style="background: white; color: maroon; font-size: 10pt"&gt;1&lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;) &lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;:= &lt;/span&gt;&lt;span style="background: white; color: red; font-size: 10pt"&gt;'abc'&lt;/span&gt;&lt;span style="background: white; color: blue; font-size: 10pt"&gt;;&lt;/span&gt;&lt;/pre&gt;
&lt;div style="margin: 2pt 0in 3pt"&gt;
&lt;p&gt;Still, it is a nice enhancement and I am very glad that Oracle did this for us. Thanks, PL/SQL development team!&lt;/p&gt;
&lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/550/Handy-new-warning-in-Oracle-11-2.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,oracle,11g&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/550/Handy-new-warning-in-Oracle-11-2.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/550/Handy-new-warning-in-Oracle-11-2.aspx</guid>
      <pubDate>Fri, 11 Jun 2010 20:18:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=550</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/11/Default.aspx">11g</blog:tag>
    </item>
    <item>
      <title>Why can't I execute DDL natively in PL/SQL</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/549/Why-cant-I-execute-DDL-natively-in-PL-SQL.aspx</link>
      <description>&lt;div&gt;I recently received an email from Syed asking this very question as follows:&lt;/div&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;div&gt;"Could you please let me know why DDL statements are not allowed [natively] in PLSQL? I read somewhere that the reason is that DDL statements will cause objects to be invalidated and then require recompilation. As all objects are already in a compiled [VALID] state, compiling again will be an overhead. But when we execute DDL statements [with EXECUTE IMMEDIATE] objects will still be invalidated and require additional recompilation - the same drawback. So why not allow it in as static SQL?"&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div&gt;There are generally two classes of questions that I prefer to not answer:&lt;/div&gt;
&lt;ol&gt;
    &lt;li&gt;Why did Oracle do X that way?&lt;/li&gt;
    &lt;li&gt;Why doesn't Oracle let us do X?&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;I don't like speaking for Oracle, nor do I like speculating about why Oracle decides to do or not do something (or do it in a particular way).&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So I suggested to Syed that he contact the Oracle PL/SQL Product Manager, Bryn Llewellyn. Hey, it's Bryn's job to represent Oracle to the PL/SQL developer community (among other responsibilities, though none more important. &lt;font face="Wingdings"&gt;&lt;img alt="" src="/Providers/HtmlEditorProviders/Fck/FCKeditor/editor/images/smiley/msn/regular_smile.gif" /&gt;&lt;/font&gt; ).&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Syed did just that, and Bryn gave me approval to publish his reply. Here it is:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;From the Keyboard of Bryn Llewellyn:&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The answer is obvious, and not what you think.&lt;br /&gt;
&lt;br /&gt;
First off, it helps to remember that at run time, all SQL issued by a PL/SQL program is "dynamic" in that the sense that the text of the SQL statement is handed over, at run time, from the PL/SQL subsystem to the SQL subsystem for execution and the SQL subsystem processes it in the same way. This is the case even for PL/SQL's embedded SQL (I don't like to call it "static" because of the point I just made). For embedded SQL, whatever parsing of the SQL statement that the PL/SQL subsystem did at PL/SQL compile time (in order to work out how to do the &lt;em&gt;binds&lt;/em&gt; and &lt;em&gt;defines&lt;/em&gt;, to establish dependencies, and so on -- see below) is re-done at run time.&lt;br /&gt;
&lt;br /&gt;
PL/SQL's embedded SQL has these big advantages:&lt;br /&gt;
&lt;br /&gt;
(1) The text is checked at compile time for correct syntax and (unhelpfully for invoker's rights programs) for correct semantics. Following on from this, dependencies are set up to the referenced objects (but for IR units they might not be helpful).&lt;br /&gt;
&lt;br /&gt;
(2) When the statement includes local PL/SQL variables (which &lt;em&gt;select, insert, update, delete,&lt;/em&gt; and &lt;em&gt;merge&lt;/em&gt; statements, a.k.a. DML statements, typically do), these are converted to placeholders in the SQL that will be used at run time and appropriate binding code is included in your executable PL/SQL program. Appropriate code is also generated to handle values returned by &lt;em&gt;select &lt;/em&gt;statements, and by change-statements that use &lt;em&gt;returning&lt;/em&gt;. Embedded SQL makes all this highly usable.&lt;br /&gt;
&lt;br /&gt;
(3) The statement execution code that's generated implements a special soft-parse avoidance scheme. You can think of the benefit as rather like that by setting &lt;em&gt;Session_Cached_Cursors&lt;/em&gt; to a non-zero value for an ordinary OCI program -- only quite a lot better.&lt;br /&gt;
&lt;br /&gt;
Non-DML statements cannot benefit from these advantages. Notice that ready-to-go statements that are not &lt;em&gt;select, insert, update, delete,&lt;/em&gt; or &lt;em&gt;merge &lt;/em&gt;are never cached in the shared pool. Further, especially because the names of the target objects are typically not known until run time, and because only DML statements allow binding, these non-DML statements are almost always composed programmatically -- ideally with the help of the &lt;em&gt;DBMS_Assert&lt;/em&gt; functions. In other words, you never see an &lt;em&gt;into&lt;/em&gt; or &lt;em&gt;using&lt;/em&gt; clause when execute immediate is used for anything except DML.&lt;br /&gt;
&lt;br /&gt;
This means that there would be no real benefit if a scheme were invented to allow non-DML statements to be written in PL/SQL using a new kind of embedded SQL.&lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/549/Why-cant-I-execute-DDL-natively-in-PL-SQL.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,oracle,ddl&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/549/Why-cant-I-execute-DDL-natively-in-PL-SQL.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/549/Why-cant-I-execute-DDL-natively-in-PL-SQL.aspx</guid>
      <pubDate>Tue, 01 Jun 2010 19:29:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=549</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/173/Default.aspx">ddl</blog:tag>
    </item>
    <item>
      <title>How big can my program get?</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/537/How-big-can-my-program-get.aspx</link>
      <description>&lt;p&gt;I recently received this question from a PL/SQL developer:&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;p&gt;&lt;em&gt;"What is the maximum size of a PL/SQL procedure?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;
&lt;p&gt;The answer is interesting: there is not a maximum size, per se. Instead, the limitation has to do with the maximum number of &lt;em&gt;DIANA nodes&lt;/em&gt; your program generates in the compilation process.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;DIANA code is in the form of a tree structure, and nodes in the tree correspond to &lt;em&gt;tokens&lt;/em&gt; in your programs, which include identifiers, keywords and operators.&lt;/p&gt;
&lt;p&gt;So here's the actual limitation regarding "size" (quoting now from the &lt;a href="http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28370/limits.htm"&gt;Oracle documentation&lt;/a&gt;): "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."&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;In other words, you &lt;em&gt;really&lt;/em&gt; should not have to worry about "running out of space" when building your PL/SQL program units.&lt;/p&gt;
&lt;p&gt;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 &lt;em&gt;too big&lt;/em&gt;, you should break it up into smaller units, with different names and distinct purposes.&lt;/p&gt;
&lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/537/How-big-can-my-program-get.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,oracle&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/537/How-big-can-my-program-get.aspx#Comments</comments>
      <slash:comments>1</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/537/How-big-can-my-program-get.aspx</guid>
      <pubDate>Mon, 10 May 2010 13:09:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=537</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
    </item>
    <item>
      <title>Little things can get you</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/536/Little-things-can-get-you.aspx</link>
      <description>&lt;div&gt;
&lt;p&gt;I received yesterday this email from a PL/SQL developer:&lt;/p&gt;
&lt;/div&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;p&gt;I am stumped. My PL/SQL code does not seem to be handling dates properly. Here is a block of code I extracted from my actual program to demonstrate the problem:&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre&gt;DECLARE&lt;br /&gt;   global_end_date   DATE := '04-May-2010';&lt;br /&gt;   global_beg_date   DATE := '01-May-2010';&lt;br /&gt;BEGIN&lt;br /&gt;   IF TRUNC (SYSDATE) &gt; TO_DATE (global_end_date, 'DD-MON-YYYY')&lt;br /&gt;   THEN&lt;br /&gt;      DBMS_OUTPUT.put_line (TRUNC (SYSDATE));&lt;br /&gt;      DBMS_OUTPUT.put_line (TO_DATE (global_end_date, 'DD-MON-YYYY'));&lt;br /&gt;      DBMS_OUTPUT.put_line ('&gt; global_end_date');&lt;br /&gt;   ELSIF TRUNC (SYSDATE) &lt; TO_DATE (global_beg_date, 'DD-MON-YYYY')&lt;br /&gt;   THEN&lt;br /&gt;      DBMS_OUTPUT.put_line ('sysdate &lt; beg_date');&lt;br /&gt;   ELSE&lt;br /&gt;      DBMS_OUTPUT.put_line ('Neither');&lt;br /&gt;   END IF;&lt;br /&gt;END;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;My problem is that when I run this code (on 4 May 2010), it shows me "&gt; global_end_date".&lt;/p&gt;
&lt;p&gt;How can that be, when it is "obvious" that:&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre&gt;TRUNC (SYSDATE) &gt; TO_DATE (global_end_date, 'DD-MON-YYYY')&lt;/pre&gt;
&lt;/blockquote&gt;&lt;/blockquote&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Being the nice guy that I am, I grabbed the code from the email, pasted it into Toad and ran it myself. She was &lt;em&gt;right!&lt;/em&gt;  What the heck is going on here?&lt;/p&gt;
&lt;p&gt;Perhaps some of you have seen the issue already; it actually took me a few minutes of playing with the code.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;If you have not yet seen it, DO NOT READ ANY FURTHER IN THIS BLOG.&lt;/p&gt;
&lt;p&gt;Instead, take a few moments to carefully read the code and make sure that it makes sense to you.&lt;/p&gt;
&lt;/div&gt;
&lt;div align="center"&gt;&lt;img alt="" width="300" height="300" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog050510-1.gif" /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Did you read the code? Do you now see the problem?&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;The developer is calling TO_DATE on a &lt;em&gt;date&lt;/em&gt;. So what is actually happening is that the date value in global_end_date is being converted implicitly to a string, and then converted explicitly back to a date with TO_DATE.&lt;/p&gt;
&lt;p&gt;In fact, there is no reason to call TO_DATE (or TO_CHAR). Just perform a direct comparison:&lt;/p&gt;
&lt;/div&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre&gt;TRUNC (SYSDATE) &gt; global_end_date&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you hadn't yet caught the problem, you are probably now slapping yourself on the forehead and exclaiming "Duh! How could I miss something so obvious?"&lt;/p&gt;
&lt;div&gt;
&lt;p&gt;How can we miss, over and over again, such obvious problems in our code?&lt;/p&gt;
&lt;p&gt;Human psychology, is the answer.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;There are, I believe, several factors that make it hard to see issues in our programs, including:&lt;/div&gt;
&lt;ul type="disc"&gt;
    &lt;li&gt;We are inclined to believe that what we have written is correct or likely to be correct. So when we look at our code, we are not critical enough of what we are seeing.&lt;/li&gt;
    &lt;li&gt;We think we &lt;em&gt;know&lt;/em&gt; what we are reading (after all, we wrote it), so we &lt;em&gt;skim&lt;/em&gt; rather than read closely. This is true not just for reading code, but reading text as well.&lt;/li&gt;
    &lt;li&gt;We are too far "inside" our programs and our bugs to take a clear, unbiased look at our code.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;How can we avoid overlooking problems in our code?&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Ask someone else to look at the code. And ask for help sooner rather than later. I know, I know, you &lt;em&gt;hate&lt;/em&gt; to ask for help. But it's OK to admit that you are having trouble; the person you ask for help will feel very good about being &lt;em&gt;able&lt;/em&gt; to help you. And they will have fresh eyes, making it easier to identify the source of a problem.&lt;/li&gt;
    &lt;li&gt;Develop a habit of reading, truly &lt;em&gt;reading&lt;/em&gt;, your code. All too often, we type a bunch of statements, get it to compile and then "try it." "Let's just see what happens," is a common programmer refrain. &lt;em&gt;Trying&lt;/em&gt; something is very different from either actually &lt;em&gt;testing it&lt;/em&gt; or using &lt;em&gt;symbolic logic&lt;/em&gt; to step through your code (with your eyes, not the runtime PL/SQL engine) and verify the algorithm.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My sense is that relatively few developers spend the requisite time to simply sit and read their code. They instead rely on tracing, debugging, &lt;em&gt;trying&lt;/em&gt;.  A de-emphasis on reading/verifying logic results in a poorly-trained eye and the likelihood that you will "skip over" bugs and other kinds of weaknesses in your programs.&lt;/p&gt;
&lt;div&gt;So next time you are truly puzzled by what your program is doing, the next time you say to yourself "That's impossible!", recognize that it is not only possible, but happening, and go back to the code and read it line by line with care and objectivity.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/536/Little-things-can-get-you.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/536/Little-things-can-get-you.aspx#Comments</comments>
      <slash:comments>3</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/536/Little-things-can-get-you.aspx</guid>
      <pubDate>Wed, 05 May 2010 13:17:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=536</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
    </item>
    <item>
      <title>New standards document available</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/533/New-standards-document-available.aspx</link>
      <description>&lt;div&gt;The &lt;a href="http://www.toadworld.com/LinkClick.aspx?link=580&amp;tabid=67"&gt;PL/SQL Standards page&lt;/a&gt; of &lt;a href="http://www.toadworld.com/LinkClick.aspx?link=153&amp;tabid=67"&gt;PL/SQL Obsession&lt;/a&gt; now offers a third choice for pre-defined standards for PL/SQL development.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;This document has been fine-tuned by Bill Coulam (&lt;a href="http://www.dbartisans.com/"&gt;www.dbartisans.com&lt;/a&gt;) as part of his effort to construct a development framework for PL/SQL applications. You don't have to use his framework, however, to benefit from his standards. Many thanks to Bill for sharing his experience and efforts with us!&lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/533/New-standards-document-available.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,standards,oracle&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/533/New-standards-document-available.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/533/New-standards-document-available.aspx</guid>
      <pubDate>Mon, 26 Apr 2010 19:49:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=533</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/172/Default.aspx">standards</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
    </item>
    <item>
      <title>Collaborate 10 - A report from the casinos</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/531/Collaborate-10-A-report-from-the-casinos.aspx</link>
      <description>&lt;div&gt;
&lt;p&gt;I've just returned from Collaborate 10, the international Oracle conference organized through a collaboration (hence the name!) between IOUG, Quest (the user group) and OAUG.&lt;/p&gt;
&lt;p&gt;It was held at the Mandalay Bay Convention Center in Las Vegas. Now, I must admit, I really don't like Las Vegas (the pretend parts) very much at all. The &lt;em&gt;real&lt;/em&gt; parts, like the &lt;a href="http://www.redrockcanyonlv.org/"&gt;Red Rock Canyon National Conservation Area&lt;/a&gt;, are beautiful and I very much enjoy. Forests of slot machines surrounded by posters hawking various forms of excess? They just don't do much for me.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Fortunately, I was there to "work" (as if you can really call what I and most programmers do &lt;em&gt;work&lt;/em&gt;). So I could bury my curmudgeonly inclinations under a burning obsession with the PL/SQL language.&lt;/p&gt;
&lt;p&gt;I did a couple of presentations, including my first ever PL/SQL quiz. As you may know, I recently started the &lt;a href="http://www.plsqlchallenge.com/"&gt;&lt;font color="#800080"&gt;PL/SQL Challenge&lt;/font&gt;&lt;/a&gt;, a daily PL/SQL quiz that culminates in a quarterly championship, with a grand prize of $1000 USD (with other prizes along the way). Needless to say, if you haven't already started playing the Challenge, get over there fast, register, and start taking the quiz!&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Reading documentation and books are fine, but I think that taking a quiz, getting the competitive juices flowing, is a great way to focus our brains and learn more effectively. So I have decided to start offering PL/SQL quizzes as technical sessions at conferences.&lt;/p&gt;
&lt;p&gt;On Monday afternoon, over 150 developers filled the Palm C room to take the quiz. In addition, my session was streamed out over the Internet, so hopefully hundreds more also played. I presented ten multiple choice questions (which I will &lt;em&gt;not&lt;/em&gt; repeat here! You may, after all, attend such a quiz in the future.) We then went through the answers.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;I was very impressed with how many people knew about AUTHID CURRENT_USER (invoker rights). And I found that the number of people aware of and using collections (with all their related benefits, like FORALL and BULK COLLECT) seems to be growing. Excllent!&lt;/p&gt;
&lt;p&gt;Many people came up afterwards to tell me they enjoyed taking the quiz. I heard later from another attendee that her co-worker, who had attended one of my trainings last year, was very excited. He says he got the quiz 100% right. That &lt;em&gt;is&lt;/em&gt; impressive.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;I also learned about ways to improve the quiz:&lt;/div&gt;
&lt;ul type="disc"&gt;
    &lt;li&gt;It would be nice to provide answer forms, so you can easily mark your choices and compare them to my answers later.&lt;/li&gt;
    &lt;li&gt;You need to have hard-copies of any questions with more than a few lines of code. It is very hard to stare at a screen and absorb the details of a block of code.&lt;/li&gt;
    &lt;li&gt;I need to have example scripts pre-written to verify all answers, clearly and quickly. Can't afford to waste time fumbling around typing up blocks of code on the fly!&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;p&gt;I will be able to apply all these lessons almost immediately. On 29 June 2010, at ODTUG's &lt;a href="http://odtugkaleidoscope.com/"&gt;Kaleidoscope conference&lt;/a&gt;, ODTUG and the &lt;a href="http://www.plsqlchallenge.com/"&gt;&lt;font color="#800080"&gt;PL/SQL Challenge&lt;/font&gt;&lt;/a&gt; will co-sponsor a special evening event, "PL/SQL Developer, Quiz Thyself," that will feature another PL/SQL quiz, this time with a first place cash prize of $500, and many other fantastic prizes. This will be a &lt;em&gt;monitored&lt;/em&gt; quiz - we will grade your answers, rather than rely on the honor system (hey, there's money involved!). It will, therefore, be a great opportunity to demonstrate your deep knowledge of PL/SQL.&lt;/p&gt;
&lt;p&gt;But to win, you must attend &lt;a href="http://odtugkaleidoscope.com/"&gt;Kaleidoscope&lt;/a&gt; &lt;em&gt;and&lt;/em&gt; come to the quiz event. I hope to see you there, and best of luck in both the &lt;a href="http://www.plsqlchallenge.com/"&gt;&lt;font color="#800080"&gt;PL/SQL Challenge&lt;/font&gt;&lt;/a&gt; and the &lt;a href="http://odtugkaleidoscope.com/"&gt;Kaleidoscope&lt;/a&gt; quiz.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;My second presentation on error management also went well. Another full room, lots of good questions, not enough time to get through all the material.&lt;/p&gt;
&lt;p&gt;Here are the main points from that presentation:&lt;/p&gt;
&lt;/div&gt;
&lt;ul type="disc"&gt;
    &lt;li&gt;When an exception is raised in the declaration section, it always propagates unhandled to the outer block.&lt;/li&gt;
    &lt;li&gt;Call DBMS_UTILITY.FORMAT_CALL_STACK whenever you log or trace. It answers the question "How did I get here?"&lt;/li&gt;
    &lt;li&gt;Call DBMS_UTILITY.FORMAT_ERROR_STACK instead of SQLERRM, to avoid possible truncation of error message text.&lt;/li&gt;
    &lt;li&gt;Call DBMS_UTILITY.FORMAT_ERROR_BACKTRACE whenever you log an error. It answers the question "On what line of code was my error raised?" (RDBMS version 10.2 and higher)&lt;/li&gt;
    &lt;li&gt;All developers should use a shared utility to raise, handle, log and communicate errors. If you don't already have one in place, check out the &lt;a href="http://toadworld.com/LinkClick.aspx?link=685&amp;tabid=153"&gt;Quest Error Manager&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;p&gt;In between my presentations, I took advantage of the Luxor Hotel's very nice fitness center. I also spent a most enjoyable evening at a party sponsored by Oracle Magazine. They reserved the whole Red Square restaurant to celebrate a thorough re-design of the magazine. They even had new photos taken of all their columnists. Oh, and Oracle has penned an agreement with Marvel Comics to use the Iron Man character (and upcoming sequel movie) to promote Oracle technology. So...look for references to Oracle in Iron Man 2.&lt;/p&gt;
&lt;p&gt;From what I could tell, the Collaborate conference bounced back very nicely from a big drop in attendance experienced in 2009 (when everyone was worried that the fall of capitalism would throw us into a deep depression). There seemed to be a whole lot of people hurrying from session to casino to restaurant to session to pool to....doing whatever it is people do in Vegas that "stays in Vegas."&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/531/Collaborate-10-A-report-from-the-casinos.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/531/Collaborate-10-A-report-from-the-casinos.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/531/Collaborate-10-A-report-from-the-casinos.aspx</guid>
      <pubDate>Thu, 22 Apr 2010 14:44:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=531</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
    </item>
    <item>
      <title>Making sure invoker rights is defined properly</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/527/Making-sure-invoker-rights-is-defined-properly.aspx</link>
      <description>&lt;p&gt;"Invoker rights, what's that?" you may be asking.&lt;/p&gt;
&lt;p&gt;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!&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;When you create a PL/SQL program unit, you can include an optional AUTHID clause. There are two forms of this clause:&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;AUTHID DEFINER&lt;br /&gt;
AUTHID CURRENT_USER&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;AUTHID DEFINER is the default. So these two procedures specify "definer rights"&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre style="margin-right: 0px" dir="ltr"&gt;PROCEDURE show_emp_count AUTHID DEFINER&lt;br /&gt;PROCEDURE show_emp_count&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;And this version specifies "invoker rights":&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre style="margin-right: 0px" dir="ltr"&gt;PROCEDURE show_emp_count AUTHID CURRENT_USER&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;So that's the syntax. What does it do for you?&lt;/p&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;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).&lt;/p&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;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.&lt;/p&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;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).&lt;/p&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;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.&lt;/p&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;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.&lt;/p&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;Consider &lt;a href="http://www.quest.com/code-tester-for-oracle"&gt;Quest Code Tester for Oracle&lt;/a&gt;. 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.&lt;/p&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;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.&lt;/p&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;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.&lt;/p&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;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.&lt;br /&gt;
In essence, with invoker rights, Oracle "reflects" back into the invoking schema to resolve references as you see below:&lt;/p&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog041310-1.gif" /&gt;&lt;br /&gt;
 &lt;br /&gt;
Now let's walk through a simple demonstration. I will first create a table in SCOTT with two rows:&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre style="margin-right: 0px" dir="ltr"&gt;&lt;font color="#0000ff"&gt;CONNECT&lt;/font&gt; scott&lt;font color="#0000ff"&gt;/&lt;/font&gt;tiger&lt;/pre&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;CREATE TABLE&lt;/font&gt; authid_demo &lt;font color="#0000ff"&gt;(&lt;/font&gt;n &lt;font color="#ff0000"&gt;NUMBER&lt;/font&gt;&lt;font color="#0000ff"&gt;)&lt;/font&gt;&lt;br /&gt;&lt;font color="#0000ff"&gt;/&lt;/font&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;BEGIN&lt;br /&gt;   INSERT INTO&lt;/strong&gt;&lt;/font&gt; authid_demo&lt;br /&gt;   &lt;strong&gt;&lt;font color="#0000ff"&gt;VALUES (&lt;/font&gt;&lt;font color="#800000"&gt;1&lt;/font&gt;&lt;font color="#0000ff"&gt;);&lt;/font&gt;&lt;/strong&gt;&lt;/pre&gt;
&lt;pre&gt;   &lt;font color="#0000ff"&gt;&lt;strong&gt;INSERT INTO&lt;/strong&gt;&lt;/font&gt; authid_demo&lt;br /&gt;   &lt;strong&gt;&lt;font color="#0000ff"&gt;VALUES (&lt;/font&gt;&lt;font color="#800000"&gt;2&lt;/font&gt;&lt;font color="#0000ff"&gt;);&lt;/font&gt;&lt;/strong&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;strong&gt;  &lt;/strong&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt; COMMIT;&lt;br /&gt;END;&lt;br /&gt;/&lt;/strong&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;I will create the "same" table in HR, but with no rows:&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;CONNECT&lt;/font&gt; hr&lt;font color="#0000ff"&gt;/&lt;/font&gt;hr&lt;/pre&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;CREATE TABLE&lt;/strong&gt;&lt;/font&gt; authid_demo &lt;font color="#0000ff"&gt;(&lt;/font&gt;n &lt;font color="#ff0000"&gt;NUMBER&lt;/font&gt;&lt;font color="#0000ff"&gt;)&lt;br /&gt;&lt;strong&gt;/&lt;/strong&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;CREATE OR REPLACE PROCEDURE&lt;/strong&gt;&lt;/font&gt; proc1 &lt;font color="#0000ff"&gt;&lt;strong&gt;AUTHID CURRENT_USER&lt;/strong&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;IS&lt;/strong&gt;&lt;/font&gt;&lt;br /&gt;   num   &lt;font color="#0000ff"&gt;&lt;strong&gt;PLS_INTEGER;&lt;/strong&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;BEGIN&lt;br /&gt;   SELECT COUNT (&lt;/strong&gt;&lt;/font&gt;*&lt;font color="#0000ff"&gt;&lt;strong&gt;) INTO&lt;/strong&gt;&lt;/font&gt; num &lt;font color="#0000ff"&gt;&lt;strong&gt;FROM&lt;/strong&gt;&lt;/font&gt; authid_demo;&lt;br /&gt;   &lt;em&gt;DBMS_OUTPUT.put_line&lt;/em&gt; &lt;font color="#0000ff"&gt;&lt;strong&gt;(&lt;/strong&gt;&lt;/font&gt;&lt;font color="#ff0000"&gt;'proc 1 invoker authid_demo count = '&lt;/font&gt; || num&lt;font color="#0000ff"&gt;&lt;strong&gt;);&lt;br /&gt;END;&lt;br /&gt;/&lt;/strong&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;CREATE OR REPLACE PROCEDURE&lt;/strong&gt;&lt;/font&gt; proc2 &lt;font color="#0000ff"&gt;&lt;strong&gt;AUTHID DEFINER&lt;/strong&gt;&lt;/font&gt;&lt;br /&gt;&lt;strong&gt;&lt;font color="#0000ff"&gt;IS&lt;br /&gt;&lt;/font&gt;&lt;/strong&gt;   &lt;font color="#0000ff"&gt;&lt;font color="#000000" size="+0"&gt;num&lt;/font&gt;   &lt;strong&gt;PLS_INTEGER;&lt;br /&gt;BEGIN&lt;br /&gt;   SELECT COUNT (&lt;/strong&gt;&lt;/font&gt;*&lt;font color="#0000ff"&gt;&lt;strong&gt;) INTO&lt;/strong&gt;&lt;/font&gt; num &lt;font color="#0000ff"&gt;&lt;strong&gt;FROM&lt;/strong&gt;&lt;/font&gt; authid_demo;&lt;br /&gt;   &lt;em&gt;DBMS_OUTPUT.put_line&lt;/em&gt; &lt;font color="#0000ff"&gt;&lt;strong&gt;(&lt;/strong&gt;&lt;/font&gt;&lt;font color="#ff0000"&gt;'proc 2 definer authid_demo count = '&lt;/font&gt; || num&lt;font color="#0000ff"&gt;&lt;strong&gt;);&lt;/strong&gt;&lt;/font&gt;&lt;br /&gt;   proc1;&lt;br /&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;END;&lt;br /&gt;/&lt;/strong&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;CREATE OR REPLACE PROCEDURE&lt;/strong&gt;&lt;/font&gt; proc3 &lt;font color="#0000ff"&gt;&lt;strong&gt;AUTHID CURRENT_USER&lt;/strong&gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;IS&lt;br /&gt;&lt;/strong&gt;&lt;/font&gt;   num   &lt;font color="#0000ff"&gt;&lt;strong&gt;PLS_INTEGER;&lt;br /&gt;BEGIN&lt;br /&gt;   SELECT COUNT (&lt;/strong&gt;&lt;/font&gt;*&lt;font color="#0000ff"&gt;&lt;strong&gt;) INTO&lt;/strong&gt;&lt;/font&gt; num &lt;font color="#0000ff"&gt;&lt;strong&gt;FROM&lt;/strong&gt;&lt;/font&gt; authid_demo;&lt;br /&gt;   &lt;em&gt;DBMS_OUTPUT.put_line&lt;/em&gt; &lt;font color="#0000ff"&gt;&lt;strong&gt;(&lt;/strong&gt;&lt;/font&gt;&lt;font color="#ff0000"&gt;'proc 3 invoker authid_demo count = '&lt;/font&gt; || num&lt;font color="#0000ff"&gt;&lt;strong&gt;);&lt;br /&gt;&lt;/strong&gt;&lt;/font&gt;   proc1;&lt;br /&gt;   proc2;&lt;br /&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;END;&lt;br /&gt;/&lt;/strong&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;Note that we have these two sequence of calls:&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre&gt;PROC3 -&gt; PROC1&lt;br /&gt;PROC3 -&gt; PROC2 -&gt; PROC1&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;and that PROC3 and PROC1 are invoker rights, while PROC2 is definer rights.&lt;/p&gt;
&lt;p&gt;I then allow HR to run all this code and access the underlying table in SCOTT:&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;GRANT&lt;/strong&gt; EXECUTE &lt;strong&gt;ON&lt;/strong&gt;&lt;/font&gt; proc1 &lt;font color="#0000ff"&gt;&lt;strong&gt;TO&lt;/strong&gt;&lt;/font&gt; hr&lt;br /&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;/&lt;/strong&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;GRANT&lt;/strong&gt; EXECUTE &lt;strong&gt;ON&lt;/strong&gt;&lt;/font&gt; proc2 &lt;font color="#0000ff"&gt;&lt;strong&gt;TO&lt;/strong&gt;&lt;/font&gt; hr&lt;br /&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;/&lt;/strong&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;GRANT&lt;/strong&gt; EXECUTE &lt;strong&gt;ON&lt;/strong&gt;&lt;/font&gt; proc3 &lt;font color="#0000ff"&gt;&lt;strong&gt;TO&lt;/strong&gt;&lt;/font&gt; hr&lt;br /&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;/&lt;/strong&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;GRANT&lt;/strong&gt; SELECT &lt;strong&gt;ON&lt;/strong&gt;&lt;/font&gt; scott.authid_demo &lt;font color="#0000ff"&gt;&lt;strong&gt;TO&lt;/strong&gt;&lt;/font&gt; hr&lt;br /&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;/&lt;/strong&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;Finally, I run PROC3 - from HR:&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;BEGIN&lt;/strong&gt;&lt;/font&gt;&lt;br /&gt;   scott.proc3&lt;font color="#0000ff"&gt;&lt;strong&gt;;&lt;br /&gt;END;&lt;br /&gt;/&lt;/strong&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here's the output I see:&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre&gt;Line 1: proc 3 invoker authid_demo count = 0&lt;br /&gt;Line 2: proc 1 invoker authid_demo count = 0&lt;br /&gt;Line 3: proc 2 definer authid_demo count = 2&lt;br /&gt;Line 4: proc 1 invoker authid_demo count = 2&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;So: same code executes, but returns different answer. Very troubling, wouldn't you say?&lt;/p&gt;
&lt;p&gt;Here's the problem: if at any point along the execution call stack (in this case, PROC3 -&gt; PROC2 -&gt; 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.&lt;/p&gt;
&lt;p&gt;When PROC3 called PROC1, that was invoker rights calling invoker rights, and so the current user was HR and the procedure showed 0 rows.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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?&lt;/p&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt; &lt;/p&gt;
&lt;pre&gt;----- PL/SQL Call Stack -----&lt;br /&gt;  object      line  object&lt;br /&gt;  handle    number  name&lt;br /&gt;3B6C8C64         1  anonymous block&lt;br /&gt;3FA473E8      1012  package body QCTO183.QU_RUNTIME&lt;br /&gt;3FA473E8      1042  package body QCTO183.QU_RUNTIME&lt;br /&gt;3FA32EF8      3120  package body QCTO183.QU_ALL_OBJECTS&lt;br /&gt;3FA32EF8      3138  package body QCTO183.QU_ALL_OBJECTS&lt;br /&gt;3FA12F2C      2613  package body QCTO183.QU_GENERATE&lt;br /&gt;3FA12F2C      3269  package body QCTO183.QU_GENERATE&lt;br /&gt;3FA12F2C      3341  package body QCTO183.QU_GENERATE&lt;br /&gt;3FA12F2C      3601  package body QCTO183.QU_GENERATE&lt;br /&gt;3FA12F2C      6192  package body QCTO183.QU_GENERATE&lt;br /&gt;3FA12F2C      8835  package body QCTO183.QU_GENERATE&lt;br /&gt;3FA12F2C      9138  package body QCTO183.QU_GENERATE&lt;br /&gt;3FA12F2C      9196  package body QCTO183.QU_GENERATE&lt;br /&gt;3FA12F2C      9487  package body QCTO183.QU_GENERATE&lt;br /&gt;4DA12F23      9737  package body QCTO183.QU_HARNESS&lt;br /&gt;3BC12F2C      9800  package body QCTO183.QU_TEST&lt;br /&gt;3BC12F2C     10130  package body QCTO183.QU_TEST&lt;br /&gt;3B6F83F8         4  anonymous block&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;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.&lt;/p&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;Perhaps there is another way. Consider the ALL_PROCEDURES data dictionary view:&lt;/p&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog041310-2.gif" /&gt;&lt;br /&gt;
 &lt;br /&gt;
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.&lt;/p&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;Yes, you &lt;em&gt;could&lt;/em&gt; do that. But likely you want, because you have a &lt;em&gt;real job&lt;/em&gt; and a &lt;em&gt;real life&lt;/em&gt; and very little time to write such programs.&lt;/p&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;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. &lt;font face="Wingdings"&gt;J&lt;/font&gt; ) 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.&lt;/p&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;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 &lt;a href="http://www.toadworld.com/Portals/0/stevenf/demo.zip"&gt;demo.zip&lt;/a&gt;, that will perform precisely this analysis on your behalf.&lt;/p&gt;
&lt;p style="margin-right: 0px" dir="ltr"&gt;Here's the header of the package:&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre style="margin-right: 0px" dir="ltr"&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;CREATE OR REPLACE PACKAGE&lt;/strong&gt;&lt;/font&gt; authid_analysis&lt;br /&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;IS&lt;br /&gt;   FUNCTION&lt;/strong&gt;&lt;/font&gt; authid_setting &lt;font color="#0000ff"&gt;(&lt;/font&gt;program_owner_in &lt;font color="#0000ff"&gt;&lt;strong&gt;IN&lt;/strong&gt;&lt;/font&gt; &lt;font color="#ff0000"&gt;VARCHAR2&lt;/font&gt;&lt;br /&gt;                          &lt;font color="#0000ff"&gt;,&lt;/font&gt; program_name_in  &lt;font color="#0000ff"&gt;&lt;strong&gt;IN&lt;/strong&gt;&lt;/font&gt; &lt;font color="#ff0000"&gt;VARCHAR2&lt;/font&gt;&lt;br /&gt;                           &lt;font color="#0000ff"&gt;)&lt;br /&gt;&lt;/font&gt;      &lt;font color="#0000ff"&gt;&lt;strong&gt;RETURN&lt;/strong&gt;&lt;/font&gt; &lt;font color="#ff0000"&gt;VARCHAR2&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;/font&gt;&lt;/pre&gt;
&lt;pre&gt;   &lt;font color="#0000ff"&gt;&lt;strong&gt;FUNCTION&lt;/strong&gt;&lt;/font&gt; is_current_user &lt;font color="#0000ff"&gt;(&lt;/font&gt;program_owner_in &lt;font color="#0000ff"&gt;&lt;strong&gt;IN&lt;/strong&gt;&lt;/font&gt; &lt;font color="#ff0000"&gt;VARCHAR2&lt;/font&gt;&lt;br /&gt;                           &lt;font color="#0000ff"&gt;,&lt;/font&gt; program_name_in  &lt;font color="#0000ff"&gt;&lt;strong&gt;IN&lt;/strong&gt;&lt;/font&gt; &lt;font color="#ff0000"&gt;VARCHAR2&lt;/font&gt;&lt;br /&gt;                            &lt;font color="#0000ff"&gt;)&lt;/font&gt;&lt;br /&gt;      &lt;font color="#0000ff"&gt;&lt;strong&gt;RETURN&lt;/strong&gt;&lt;/font&gt; &lt;font color="#0000ff"&gt;&lt;strong&gt;BOOLEAN&lt;/strong&gt;&lt;/font&gt;;&lt;/pre&gt;
&lt;pre&gt;   &lt;font color="#0000ff"&gt;&lt;strong&gt;FUNCTION&lt;/strong&gt;&lt;/font&gt; is_definer &lt;font color="#0000ff"&gt;(&lt;/font&gt;program_owner_in &lt;font color="#0000ff"&gt;&lt;strong&gt;IN&lt;/strong&gt;&lt;/font&gt; &lt;font color="#ff0000"&gt;VARCHAR2&lt;/font&gt;&lt;br /&gt;                      &lt;font color="#0000ff"&gt;,&lt;/font&gt; program_name_in  &lt;font color="#0000ff"&gt;&lt;strong&gt;IN&lt;/strong&gt;&lt;/font&gt; &lt;font color="#ff0000"&gt;VARCHAR2&lt;/font&gt;&lt;br /&gt;                       &lt;font color="#0000ff"&gt;)&lt;/font&gt;&lt;br /&gt;      &lt;font color="#0000ff"&gt;&lt;strong&gt;RETURN BOOLEAN;&lt;/strong&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;pre&gt;   &lt;font color="#0000ff"&gt;&lt;strong&gt;PROCEDURE&lt;/strong&gt;&lt;/font&gt; analyze_callstack &lt;font color="#0000ff"&gt;&lt;strong&gt;(&lt;/strong&gt;&lt;/font&gt;callstack_in &lt;font color="#0000ff"&gt;&lt;strong&gt;IN&lt;/strong&gt;&lt;/font&gt; &lt;font color="#ff0000"&gt;VARCHAR2&lt;/font&gt; &lt;font color="#0000ff"&gt;&lt;strong&gt;DEFAULT NULL);&lt;br /&gt;END&lt;/strong&gt;&lt;/font&gt; authid_analysis&lt;font color="#0000ff"&gt;&lt;strong&gt;;&lt;/strong&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;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).&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 &lt;a href="http://www.toadworld.com/LinkClick.aspx?link=685&amp;tabid=67"&gt;Quest Error Manager&lt;/a&gt; as soon as I have a moment.&lt;/p&gt;
&lt;p&gt;The authid_analysis.tst scritp will allow you run a quick test of this utility. Here's what I see:&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;CREATE OR REPLACE PROCEDURE&lt;/strong&gt;&lt;/font&gt; proc1&lt;br /&gt;   &lt;font color="#0000ff"&gt;&lt;strong&gt;AUTHID CURRENT_USER&lt;br /&gt;IS&lt;br /&gt;BEGIN&lt;/strong&gt;&lt;/font&gt;&lt;br /&gt;   authid_analysis.analyze_callstack;&lt;br /&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;END;&lt;br /&gt;/&lt;/strong&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;CREATE OR REPLACE PROCEDURE&lt;/strong&gt;&lt;/font&gt; proc2&lt;br /&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;IS&lt;br /&gt;BEGIN&lt;/strong&gt;&lt;/font&gt;&lt;br /&gt;   proc1;&lt;br /&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;END;&lt;br /&gt;/&lt;/strong&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;CREATE OR REPLACE PROCEDURE&lt;/strong&gt;&lt;/font&gt; proc3&lt;br /&gt;   &lt;font color="#0000ff"&gt;&lt;strong&gt;AUTHID CURRENT_USER&lt;br /&gt;IS&lt;br /&gt;BEGIN&lt;br /&gt;&lt;/strong&gt;&lt;/font&gt;   proc2;&lt;br /&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;END;&lt;br /&gt;/&lt;/strong&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;&lt;strong&gt;BEGIN&lt;br /&gt;&lt;/strong&gt;&lt;/font&gt;   proc3;&lt;br /&gt;&lt;strong&gt;&lt;font color="#0000ff"&gt;END;&lt;br /&gt;/&lt;br /&gt;&lt;/font&gt;&gt; DEFINER      package body HR.AUTHID_ANALYSIS called by...&lt;br /&gt;&gt; CURRENT_USER procedure HR.PROC1 called by...&lt;br /&gt;&gt; DEFINER      procedure HR.PROC2 called by...&lt;br /&gt;&gt; CURRENT_USER procedure HR.PROC3 called by...&lt;br /&gt;&gt;              anonymous block&lt;/strong&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;I hope you find this utility useful.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/527/Making-sure-invoker-rights-is-defined-properly.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,oracle,invoker rights&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/527/Making-sure-invoker-rights-is-defined-properly.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/527/Making-sure-invoker-rights-is-defined-properly.aspx</guid>
      <pubDate>Tue, 13 Apr 2010 12:54:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=527</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/171/Default.aspx">invoker rights</blog:tag>
    </item>
    <item>
      <title>Books That Taught Me Lots</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/521/Books-That-Taught-Me-Lots.aspx</link>
      <description>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>
      <author>Steven Feuerstein</author>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/521/Books-That-Taught-Me-Lots.aspx#Comments</comments>
      <slash:comments>1</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/521/Books-That-Taught-Me-Lots.aspx</guid>
      <pubDate>Mon, 29 Mar 2010 13:01:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=521</trackback:ping>
    </item>
    <item>
      <title>Beta Testing Starts for the PL/SQL Challenge</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/516/Beta-Testing-Starts-for-the-PL-SQL-Challenge.aspx</link>
      <description>&lt;p&gt;The PL/SQL Challenge is a daily quiz that culminates every three months in a championship tournament to determine the most knowledgeable PL/SQL developers in the world. You could win cash, O'Reilly Media books and other goodies - but only if you play!&lt;/p&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/516/Beta-Testing-Starts-for-the-PL-SQL-Challenge.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/516/Beta-Testing-Starts-for-the-PL-SQL-Challenge.aspx</guid>
      <pubDate>Thu, 18 Mar 2010 15:14:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=516</trackback:ping>
    </item>
    <item>
      <title>Say goodbye to hard-coding!</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/510/Say-goodbye-to-hard-coding.aspx</link>
      <description>&lt;p&gt;We all know that hard-coding is a bad thing in software. But most developers think of hard-coding simply as typing a literal value into your program whenever you need it.&lt;/p&gt;&lt;div class="tags"&gt;Tags: plsql,package,oracle&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/510/Say-goodbye-to-hard-coding.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/510/Say-goodbye-to-hard-coding.aspx</guid>
      <pubDate>Mon, 01 Mar 2010 16:26:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=510</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/164/Default.aspx">package</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
    </item>
    <item>
      <title>Code Tester Version 1.9 Now Available!</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/506/Code-Tester-Version-1-9-Now-Available.aspx</link>
      <description>&lt;div&gt;You can now &lt;a href="http://unittest.inside.quest.com/downloads.jspa"&gt;download&lt;/a&gt; version 1.9 of Code Tester. This release features the following enhancements:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Object type support&lt;/strong&gt;   You can now test directly the methods of object types, test the contents of object type instances for equality and inequality, and specify the values of attributes through a grid.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Default value support&lt;/strong&gt;   You now request that the default of a parameter be used when testing your program. The generated test code will not pass a value for this argument.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Improved code coverage support&lt;/strong&gt;   You can now specify your code coverage target as a percentage, both as a preference (global target) and for specific program units. Actual code coverage % and target % values are now shown in Test Editor and code coverage reports. These reports have also been expanded.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Specifying order of execution of test suites&lt;/strong&gt;   You can now specify the order of execution of tests in a suite through the Dashboard (right-click on suite name, choose "Specify order of tests in suite").&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Random test execution&lt;/strong&gt;   You can request through the Test Editor that unit tests and test cases within a unit test be executed in random order.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;We have also cleaned up various parts of the user interface, most notably the Preferences Window, which has finally caught up with the rest of the tool (greatly expanded preferences, such as for export/import, as well as removal of old, unused preferences). All preferences are also now stored in their own preferences ini file, so that you can copy it to the workstations of other Code Tester users and easily apply a standard set of preferences to a development team.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;If you have not yet checked out Code Tester, I urge you to do so. There is no better way to build and run regression tests that can finally break out of the vicious cycle of....&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;"I don't have enough time to do it right because I am too busy fixing bugs from the last release."&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;a href="http://unittest.inside.quest.com/downloads.jspa"&gt;Download Quest Code Tester for Oracle v1.9&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/506/Code-Tester-Version-1-9-Now-Available.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: code tester&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/10/Default.aspx&gt;Code Tester for Oracle&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/10/Default.aspx">Code Tester for Oracle</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/506/Code-Tester-Version-1-9-Now-Available.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/506/Code-Tester-Version-1-9-Now-Available.aspx</guid>
      <pubDate>Thu, 18 Feb 2010 14:15:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=506</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/1/Default.aspx">code tester</blog:tag>
    </item>
    <item>
      <title>Retrieving values from a record dynamically</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/501/Retrieving-values-from-a-record-dynamically.aspx</link>
      <description>&lt;p&gt;Steven discusses generic retrieval/change challenges when it comes to PL/SQL records.&lt;/p&gt;&lt;div class="tags"&gt;Tags: plsql&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/501/Retrieving-values-from-a-record-dynamically.aspx#Comments</comments>
      <slash:comments>1</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/501/Retrieving-values-from-a-record-dynamically.aspx</guid>
      <pubDate>Tue, 09 Feb 2010 19:19:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=501</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
    </item>
    <item>
      <title>Binding sparse arrays in a FORALL statement</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/477/Binding-sparse-arrays-in-a-FORALL-statement.aspx</link>
      <description>&lt;p&gt;FORALL was introduced into PL/SQL in Version 8i. It is a &lt;em&gt;fantastic &lt;/em&gt;feature; you should use it in place of all loops that contain DML statements performing row-by-row processing. You will generally see performance improvements of at least an order of magnitude. &lt;/p&gt;
&lt;div style="margin: 0in 0in 0pt"&gt;If you are not familiar with FORALL, make it a priority to &lt;em&gt;get&lt;/em&gt; familiar. You can start with my brand new 5&lt;sup&gt;th&lt;/sup&gt; edition of &lt;a href="http://oreilly.com/catalog/9780596009779/"&gt;Oracle PL/SQL Programming&lt;/a&gt;, complemented by the &lt;a href="http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14261/tuning.htm#sthref2181"&gt;Oracle documentation&lt;/a&gt;. Follow up with a perusal of my &lt;a href="http://toadworld.com/Education/StevenFeuersteinsPLSQLExperience/TrainingandPresentations/PLSQLNewFeatures/tabid/161/Default.aspx#21st%20Century"&gt;21&lt;sup&gt;st&lt;/sup&gt; Century PL/SQL&lt;/a&gt; course materials.&lt;/div&gt;
&lt;div style="margin: 0in 0in 0pt"&gt; &lt;/div&gt;
&lt;div style="margin: 0in 0in 0pt"&gt;I assume a working knowledge of FORALL for the remainder of this post.&lt;/div&gt;
&lt;div style="margin: 0in 0in 0pt"&gt; &lt;/div&gt;
&lt;p style="margin: 0in 0in 0pt"&gt;The typical (and, in Oracle8i and Oracle9i, the &lt;em&gt;only&lt;/em&gt;) way to construct a FORALL statement is to use a header that is very similar to a numeric FOR loop. Here is an example:&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;div style="margin: 0in 0in 0pt"&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;DECLARE&lt;br /&gt;   TYPE&lt;/font&gt; namelist_t &lt;font color="#0000ff"&gt;IS TABLE OF&lt;/font&gt; employees.first_name%&lt;font color="#0000ff"&gt;TYPE&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;/font&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;   l_enames   namelist_t := namelist_t &lt;font color="#0000ff"&gt;(&lt;/font&gt;&lt;font color="#ff0000"&gt;'ABC'&lt;/font&gt;&lt;font color="#0000ff"&gt;,&lt;/font&gt; &lt;font color="#ff0000"&gt;'DEF'&lt;/font&gt;&lt;font color="#0000ff"&gt;,&lt;/font&gt; &lt;font color="#ff0000"&gt;'SMITHIE'&lt;/font&gt;&lt;font color="#0000ff"&gt;);&lt;/font&gt;&lt;br /&gt;&lt;font color="#0000ff"&gt;BEGIN&lt;br /&gt;   FORALL&lt;/font&gt; indx &lt;font color="#0000ff"&gt;IN&lt;/font&gt; 1 .. l_enames&lt;font color="#0000ff"&gt;.COUNT&lt;/font&gt;&lt;br /&gt;      &lt;font color="#0000ff"&gt;UPDATE&lt;/font&gt; employees&lt;br /&gt;         &lt;font color="#0000ff"&gt;SET&lt;/font&gt; first_name = l_enames &lt;font color="#0000ff"&gt;(&lt;/font&gt;indx&lt;font color="#0000ff"&gt;);&lt;/font&gt;&lt;br /&gt;&lt;font color="#0000ff"&gt;END;&lt;/font&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;div style="margin: 0in 0in 0pt"&gt;More generally, the FORALL header looks like this:&lt;/div&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;div style="margin: 0in 0in 0pt"&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;FORALL&lt;/font&gt; &lt;em&gt;integer_index&lt;/em&gt; &lt;font color="#0000ff"&gt;IN&lt;/font&gt; &lt;font color="#800000"&gt;&lt;em&gt;low_value&lt;/em&gt; .. &lt;em&gt;high_value&lt;/em&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style="margin: 0in 0in 0pt"&gt;where integer_index is an implicitly declared integer iterator, low_value is the low end of the integer range and high_value is the high end. Each integer between low and high must reference a defined index value in any of the collections that are bound into the FORALL's DML statement (in the above case, there is just one: l_enames).&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div style="margin: 0in 0in 0pt"&gt;In other words, the binding array must be &lt;em&gt;densely filled&lt;/em&gt; between the low and high values.&lt;/div&gt;
&lt;div style="margin: 0in 0in 0pt"&gt;
&lt;p&gt;If the collection is sparse and the FORALL statement tries to read an element at an undefined element, it will raise an exception as shown below:&lt;/p&gt;
&lt;p&gt;&lt;img alt="" width="534" height="309" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog112309-1.gif" /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div style="margin: 0in 0in 0pt"&gt;Notice that it does not raise NO_DATA_FOUND. I point this out because it seems like Oracle goes out of its way to raise this exception whenever the error bears even the &lt;em&gt;remotest&lt;/em&gt; resemblance to "I tried to get something and it wasn't there" (SELECT INTO, read an element in a collection at an undefined index value, read past the end of a file).&lt;/div&gt;
&lt;div style="margin: 0in 0in 0pt"&gt; &lt;/div&gt;
&lt;div style="margin: 0in 0in 0pt"&gt;Notice also that even if I include the SAVE EXCEPTIONS clause in my FORALL statement, &lt;em&gt;this &lt;/em&gt;exception is &lt;em&gt;not&lt;/em&gt; "saved" to the SQL%BULK_EXCEPTIONS pseudo-collection. That's because this is a "meta-error" for the FORALL statement. The exception is not raised by the SQL engine as it performs the DML statement. It is, instead, raised by the PL/SQL engine &lt;em&gt;before&lt;/em&gt; the SQL statements are passed along to the SQL engine.&lt;/div&gt;
&lt;div style="margin: 0in 0in 0pt"&gt; &lt;/div&gt;
&lt;div style="margin: 0in 0in 0pt"&gt;So what's a programmer to do if your binding array is not densely-filled?&lt;/div&gt;
&lt;div style="margin: 0in 0in 0pt"&gt; &lt;/div&gt;
&lt;div style="margin: 0in 0in 0pt"&gt;In Oracle10g Release 2, Oracle added support for two new ways to construct the FORALL header:  INDICES OF and VALUES OF. With either of these, your FORALL header no longer looks like a numeric FOR loop. Instead you specify that you want the FORALL statement to reference only those elements in the binding array whose index value is defined in the INDICES OF array.&lt;/div&gt;
&lt;div style="margin: 0in 0in 0pt"&gt; &lt;/div&gt;
&lt;p style="margin: 0in 0in 0pt"&gt;The simplest form uses the same collection as the binding and INDICES OF arrays, as in:&lt;/p&gt;
&lt;div style="margin: 0in 0in 0pt"&gt;
&lt;pre&gt;   &lt;font color="#0000ff"&gt;FORALL&lt;/font&gt; indx &lt;font color="#0000ff"&gt;IN&lt;/font&gt; INDICES &lt;font color="#0000ff"&gt;OF&lt;/font&gt; l_enames&lt;br /&gt;      &lt;font color="#0000ff"&gt;UPDATE&lt;/font&gt; &lt;font color="#808080"&gt;employees&lt;/font&gt; &lt;font color="#0000ff"&gt;SET&lt;/font&gt; first_name &lt;font color="#0000ff"&gt;=&lt;/font&gt; l_enames &lt;font color="#0000ff"&gt;(&lt;/font&gt;indx&lt;font color="#0000ff"&gt;);&lt;/font&gt; &lt;/pre&gt;
&lt;/div&gt;
&lt;div style="margin: 0in 0in 0pt"&gt;Now, an update statement will be sent to the PL/SQL engine only for this index values that are defined in the collection.&lt;/div&gt;
&lt;div style="margin: 0in 0in 0pt"&gt; &lt;/div&gt;
&lt;p style="margin: 0in 0in 0pt"&gt;But the collection referenced in the INDICES OF clause need not be the same as the binding array. Here is an example of using INDICES OF with a distinct collection:&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;div style="margin: 0in 0in 0pt"&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;DECLARE&lt;br /&gt;   TYPE&lt;/font&gt; employee_aat &lt;font color="#0000ff"&gt;IS TABLE OF&lt;/font&gt; employees.employee_id%&lt;font color="#0000ff"&gt;TYPE&lt;/font&gt;&lt;br /&gt;      &lt;font color="#0000ff"&gt;INDEX BY PLS_INTEGER;&lt;/font&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;   l_employees          employee_aat;&lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt; &lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;   &lt;font color="#0000ff"&gt;TYPE&lt;/font&gt; boolean_aat &lt;font color="#0000ff"&gt;IS TABLE OF BOOLEAN&lt;br /&gt;      INDEX BY PLS_INTEGER;&lt;/font&gt;&lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt; &lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;   l_employee_indices   boolean_aat;&lt;br /&gt;&lt;font color="#0000ff"&gt;BEGIN&lt;/font&gt;&lt;br /&gt;   l_employees &lt;font color="#0000ff"&gt;(&lt;/font&gt;&lt;font color="#800000"&gt;1&lt;/font&gt;&lt;font color="#0000ff"&gt;)&lt;/font&gt; := &lt;font color="#800000"&gt;137&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;/font&gt;&lt;br /&gt;   l_employees &lt;font color="#0000ff"&gt;(&lt;/font&gt;&lt;font color="#800000"&gt;100&lt;/font&gt;&lt;font color="#0000ff"&gt;)&lt;/font&gt; := &lt;font color="#800000"&gt;126&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;&lt;/font&gt;   l_employees &lt;font color="#0000ff"&gt;(&lt;/font&gt;&lt;font color="#800000"&gt;500&lt;/font&gt;&lt;font color="#0000ff"&gt;)&lt;/font&gt; := &lt;font color="#800000"&gt;147&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;&lt;/font&gt;   &lt;br /&gt;   l_employee_indices &lt;font color="#0000ff"&gt;(&lt;/font&gt;&lt;font color="#800000"&gt;1&lt;/font&gt;&lt;font color="#0000ff"&gt;)&lt;/font&gt; &lt;font color="#0000ff"&gt;:= FALSE;&lt;/font&gt;&lt;br /&gt;   l_employee_indices &lt;font color="#0000ff"&gt;(&lt;/font&gt;&lt;font color="#800000"&gt;500&lt;/font&gt;&lt;font color="#0000ff"&gt;)&lt;/font&gt; &lt;font color="#0000ff"&gt;:= TRUE;&lt;/font&gt;&lt;br /&gt;   l_employee_indices &lt;font color="#0000ff"&gt;(&lt;/font&gt;&lt;font color="#800000"&gt;799&lt;/font&gt;&lt;font color="#0000ff"&gt;)&lt;/font&gt; &lt;font color="#0000ff"&gt;:= NULL;&lt;/font&gt;&lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt; &lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;   &lt;font color="#0000ff"&gt;FORALL&lt;/font&gt; l_index &lt;font color="#0000ff"&gt;IN&lt;/font&gt; INDICES &lt;font color="#0000ff"&gt;OF&lt;/font&gt; l_employee_indices &lt;br /&gt;                  &lt;font color="#0000ff"&gt;BETWEEN&lt;/font&gt; &lt;font color="#800000"&gt;1&lt;/font&gt; &lt;font color="#0000ff"&gt;AND&lt;/font&gt; &lt;font color="#800000"&gt;500&lt;/font&gt;&lt;br /&gt;      &lt;font color="#0000ff"&gt;UPDATE&lt;/font&gt; employees&lt;br /&gt;         &lt;font color="#0000ff"&gt;SET&lt;/font&gt; salary &lt;font color="#0000ff"&gt;=&lt;/font&gt; &lt;font color="#800000"&gt;10000&lt;/font&gt;&lt;br /&gt;       &lt;font color="#0000ff"&gt;WHERE&lt;/font&gt; employee_id &lt;font color="#0000ff"&gt;=&lt;/font&gt; l_employees &lt;font color="#0000ff"&gt;(&lt;/font&gt;l_index&lt;font color="#0000ff"&gt;);&lt;/font&gt;&lt;br /&gt;&lt;font color="#0000ff"&gt;END;&lt;/font&gt; &lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p style="margin: 0in 0in 0pt"&gt;Updates will be run only for employee IDs 137 and 147.&lt;/p&gt;
&lt;div style="margin: 0in 0in 0pt"&gt; &lt;/div&gt;
&lt;div style="margin: 0in 0in 0pt"&gt;The VALUES_OF clause offers an additional layer of "indirection." With VALUES_OF, the FORALL statement executes a DML statement for each index value in the binding array that is an element in (not an index value in) the VALUES OF collection.&lt;/div&gt;
&lt;div style="margin: 0in 0in 0pt"&gt; &lt;/div&gt;
&lt;p style="margin: 0in 0in 0pt"&gt;Here is an example:&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;div style="margin: 0in 0in 0pt"&gt;
&lt;pre&gt;&lt;font color="#0000ff"&gt;DECLARE&lt;br /&gt;   TYPE&lt;/font&gt; employee_aat &lt;font color="#0000ff"&gt;IS TABLE OF&lt;/font&gt; employees.employee_id%&lt;font color="#0000ff"&gt;TYPE&lt;br /&gt;      INDEX BY PLS_INTEGER;&lt;/font&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;   l_employees          employee_aat;&lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt; &lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;   &lt;font color="#0000ff"&gt;TYPE&lt;/font&gt; indices_aat &lt;font color="#0000ff"&gt;IS TABLE OF PLS_INTEGER&lt;br /&gt;      INDEX BY PLS_INTEGER;&lt;/font&gt;&lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt; &lt;/pre&gt;
&lt;pre style="margin: 0in 0in 0pt"&gt;   l_employee_indices   indices_aat;&lt;br /&gt;&lt;font color="#0000ff"&gt;BEGIN&lt;/font&gt;&lt;br /&gt;   l_employees &lt;font color="#0000ff"&gt;(&lt;/font&gt;&lt;font color="#800000"&gt;-77&lt;/font&gt;&lt;font color="#0000ff"&gt;) :=&lt;/font&gt; &lt;font color="#800000"&gt;134&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;&lt;/font&gt;   l_employees &lt;font color="#0000ff"&gt;(&lt;/font&gt;&lt;font color="#800000"&gt;13067&lt;/font&gt;&lt;font color="#0000ff"&gt;) :=&lt;/font&gt; &lt;font color="#800000"&gt;123&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;&lt;/font&gt;   l_employees &lt;font color="#0000ff"&gt;(&lt;/font&gt;&lt;font color="#800000"&gt;99999999&lt;/font&gt;&lt;font color="#0000ff"&gt;) :=&lt;/font&gt; &lt;font color="#800000"&gt;147&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;/font&gt;&lt;br /&gt;   l_employees &lt;font color="#0000ff"&gt;(&lt;/font&gt;&lt;font color="#800000"&gt;1070&lt;/font&gt;&lt;font color="#0000ff"&gt;) :=&lt;/font&gt; &lt;font color="#800000"&gt;429&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;&lt;/font&gt;   &lt;br /&gt;   l_employee_indices &lt;font color="#0000ff"&gt;(&lt;/font&gt;&lt;font color="#800000"&gt;100&lt;/font&gt;&lt;font color="#0000ff"&gt;) :=&lt;/font&gt; &lt;font color="#800000"&gt;-77&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;&lt;/font&gt;   l_employee_indices &lt;font color="#0000ff"&gt;(&lt;/font&gt;&lt;font color="#800000"&gt;200&lt;/font&gt;&lt;font color="#0000ff"&gt;) :=&lt;/font&gt; &lt;font color="#800000"&gt;13067&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;/font&gt;&lt;br /&gt;   l_employee_indices &lt;font color="#0000ff"&gt;(&lt;/font&gt;&lt;font color="#800000"&gt;300&lt;/font&gt;&lt;font color="#0000ff"&gt;) :=&lt;/font&gt; &lt;font color="#800000"&gt;1070&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;/font&gt;&lt;br /&gt;   &lt;br /&gt;   &lt;font color="#0000ff"&gt;FORALL&lt;/font&gt; l_index &lt;font color="#0000ff"&gt;IN VALUES&lt;/font&gt; OF l_employee_indices&lt;br /&gt;      &lt;font color="#0000ff"&gt;UPDATE&lt;/font&gt; employees&lt;br /&gt;         &lt;font color="#0000ff"&gt;SET&lt;/font&gt; salary &lt;font color="#0000ff"&gt;=&lt;/font&gt; &lt;font color="#800000"&gt;10000&lt;/font&gt;&lt;br /&gt;       &lt;font color="#0000ff"&gt;WHERE&lt;/font&gt; employee_id &lt;font color="#0000ff"&gt;=&lt;/font&gt; l_employees &lt;font color="#0000ff"&gt;(&lt;/font&gt;l_index&lt;font color="#0000ff"&gt;);&lt;/font&gt;&lt;br /&gt;   &lt;em&gt;DBMS_OUTPUT.put_line&lt;/em&gt; &lt;font color="#0000ff"&gt;(SQL&lt;/font&gt;%&lt;font color="#0000ff"&gt;ROWCOUNT);&lt;/font&gt;&lt;br /&gt;&lt;font color="#0000ff"&gt;END;&lt;/font&gt; &lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p style="margin: 0in 0in 0pt"&gt;In this block of code, an UPDATE is executed for employee IDs134, 123 and 429.&lt;/p&gt;
&lt;div style="margin: 0in 0in 0pt"&gt; &lt;/div&gt;
&lt;div style="margin: 0in 0in 0pt"&gt;So if you are using FORALL but running into situations where your binding array may not be sequentially filled, give INDICES OF or VALUES_OF a try. It might simplify your life and code dramatically.&lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/477/Binding-sparse-arrays-in-a-FORALL-statement.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,oracle,forall&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/477/Binding-sparse-arrays-in-a-FORALL-statement.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/477/Binding-sparse-arrays-in-a-FORALL-statement.aspx</guid>
      <pubDate>Mon, 23 Nov 2009 15:44:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=477</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/130/Default.aspx">forall</blog:tag>
    </item>
    <item>
      <title>The Subtleties of Programming </title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/474/The-Subtleties-of-Programming.aspx</link>
      <description>&lt;div&gt;I recently published the following puzzle in the ToadWorld newsletter:&lt;/div&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;strong&gt;&lt;font size="2" face="arial"&gt;Which of the following queries return the names of programs (without duplication) defined in the currently connected schema whose source contains a call to DBMS_OUTPUT.PUT_LINE (assume that this program name does not appear inside comments)?&lt;/font&gt; &lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;strong&gt;A.&lt;/strong&gt;   &lt;font face="Courier New"&gt;SELECT name FROM USER_DEPENDENCIES&lt;br /&gt;
    WHERE referenced_name = 'DBMS_OUTPUT.PUT_LINE'&lt;br /&gt;
&lt;/font&gt;&lt;br /&gt;
&lt;strong&gt;B.   &lt;/strong&gt;&lt;font face="Courier New"&gt;SELECT name from ALL_SOURCE&lt;br /&gt;
    WHERE owner = USER&lt;br /&gt;
      AND name = 'DBMS_OUTPUT.PUT_LINE'&lt;br /&gt;
&lt;/font&gt;&lt;br /&gt;
&lt;strong&gt;C.&lt;/strong&gt;   &lt;font face="Courier New"&gt;SELECT DISTINCT name from ALL_SOURCE&lt;br /&gt;
 &lt;/font&gt;&lt;span&gt;&lt;font face="Courier New"&gt;   WHERE INSTR (text, 'DBMS_OUTPUT.PUT_LINE') &gt; 0 &lt;br /&gt;
&lt;/font&gt;&lt;br /&gt;
&lt;strong&gt;D.&lt;/strong&gt;   &lt;font face="Courier New"&gt;SELECT DISTINCT name from USER_SOURCE&lt;br /&gt;
    WHERE INSTR (UPPER (text), 'DBMS_OUTPUT.PUT_LINE') &gt; 0&lt;/font&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div&gt;I believed that (D) was correct. Certainly, A, B and C do not do the trick (click &lt;u&gt;&lt;a href="http://www.toadworld.com/LinkClick.aspx?link=396&amp;tabid=67"&gt;here&lt;/a&gt;&lt;/u&gt; to see my explanation). But I recently received the following email from Wim de Lange of the Netherlands:&lt;/div&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;div&gt;"None of the answers below is correct. (D) &lt;em&gt;could&lt;/em&gt; be the solution, but DBMS_OUTPUT.PUT_LINE could be spelled as DBMS_OUTPUT . PUT_LINE (spaces around the dot) and that code will still compile and run. So the spaces are destroying the solution here."&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div&gt;Wim is absolutely correct. You could put spaces between the package name, dot and subprogram name, and the PL/SQL compiler will have no trouble with that code.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Thanks, Wim, for your very close reading of my puzzle, and for reminding me that programming can be a very subtle and nuanced craft. Oh, and also that it is so difficult to come up with all the test cases for a program.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;And just to show you that I am not the least bit upset about someone finding an error in my code and writing, Wim is hereby declared &lt;em&gt;another&lt;/em&gt; winner of that contest and will receive a Toad World t-shirt in addition to the randomly selected four winners.&lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/474/The-Subtleties-of-Programming.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,oracle&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/474/The-Subtleties-of-Programming.aspx#Comments</comments>
      <slash:comments>3</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/474/The-Subtleties-of-Programming.aspx</guid>
      <pubDate>Mon, 16 Nov 2009 15:54:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=474</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
    </item>
    <item>
      <title>The Most Important Language to Learn</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/468/The-Most-Important-Language-to-Learn.aspx</link>
      <description>&lt;p&gt;I was recently in Germany, and did an interview with Erik Franz of database|pro. One of the questions he asked me was: "Which programming language would you recommend a college student learn to give them the strongest chance at a good job upon graduation?" I would have loved to be able to answer: "Learn PL/SQL!&lt;/p&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/468/The-Most-Important-Language-to-Learn.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/468/The-Most-Important-Language-to-Learn.aspx</guid>
      <pubDate>Mon, 02 Nov 2009 13:54:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=468</trackback:ping>
    </item>
    <item>
      <title>An Amazing Visit to Mexico City</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/463/An-Amazing-Visit-to-Mexico-City.aspx</link>
      <description>&lt;div&gt;As I write this, I am flying back to Chicago now, 9 PM Oct 21, from Mexico City, after a very nice two day visit.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Quest Mexico asked me to come down to help celebrate the release of &lt;a href="http://www.toadworld.com/LandingPages/ToadforOracleVersion10/tabid/622/Default.aspx"&gt;&lt;font color="#800080"&gt;Toad Version 10&lt;/font&gt;&lt;/a&gt;. I said "OK."&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;And, wow, they did a really fantastic job of making me feel appreciated. Besides putting me up in a fabulous, old but very excellent hotel, &lt;a href="http://www.caminoreal.com/mexico_i/main.php"&gt;El Camino Real Polenco&lt;/a&gt;, and making sure I enjoyed outstanding meals of (surprise) Mexican cuisine, they pulled together an enormous gathering of over 250 Oracle technologists for an evening presentation at the beautiful &lt;a href="http://www.haciendadelosmorales.com/index.php"&gt;http://www.haciendadelosmorales.com/index.php&lt;/a&gt; by Claudia Fernandez, Quest product manager supreme, to talk about Toad 10, and me to talk about, well, pretty much whatever I felt like talking about, which turned out to be the function result cache feature of Oracle11g.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Quest Mexico also ordered 100 of my Oracle PL/SQL Best Practices books to give away to the first 100 people who arrived on the 20th. That turned out to be a fine motivator. Developers started arriving at 2 PM or so for a 5 PM start time. Unfortunately, due to problems with Customs in Mexico, we didn't have those orange books. Fortunately, we had a nice big pile of a book that Claudia co-authored, &lt;a href="http://www.rampant-books.com/book_0701_database_benchmarking.htm"&gt;Database Benchmarking&lt;/a&gt;. So attendees received those. And then they lined up for autographs. As I signed books, I got to meet a lot of very enthusiastic PL/SQL developers - several of which said that they benefited greatly from my writing. How satisfying!&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;On the wall behind our signing table was a banner with a reproduction of my head that must have been five feet high. I kid you not - in fact, you can see it &lt;a href="http://www.flickr.com/photos/stevenfeuerstein/4035323125/in/set-72157622517976999/"&gt;&lt;font color="#800080"&gt;here&lt;/font&gt;&lt;/a&gt;. Fortunately, I am a humble fellow, so I only posed in front of the banner for a few photos.&lt;/div&gt;
&lt;div&gt;Many attendees also asked to have their photo taken with me. And Ricardo of Quest was kind enough to use my camera to also capture those moments. You can view all those photos &lt;a href="http://www.flickr.com/photos/stevenfeuerstein/sets/72157622517976999/"&gt;here&lt;/a&gt;.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I must tell you that years ago, when people first asked for autographs, asked to have their picture taken with me, I was a little bit embarrassed by the whole situation. C'mon, I just wrote a few (well, 10) books about this one language, PL/SQL. Why are they getting so excited? They are being weird, ridiculous. But I eventually came to realize that it really doesn't matter what I think. What matters is that for whatever reason (I have some idea of why this happened, but it is still a bit of a mystery to me) my books, my writings, my trainings have had a substantial impact on the lives of these developers. My ideas and my ways of expressing them have improved their lives.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Now, that realization is/was a continually humbling experience. Now, I am honored that anyone would care to have me sign their book or share a photo with them. And I have decided to start celebrating this honor and, at least this is my intention, honor my readers by &lt;a href="http://www.flickr.com/photos/stevenfeuerstein/sets/72157622517976999/"&gt;posting on Flickr&lt;/a&gt; the photos we took together (and others from the event in La Hacienda Morales in Mexico City).&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;If anyone sees their photo on this page and does not want it to be available publicly, please &lt;/strong&gt;&lt;a href="http://www.toadworld.commailto:steven.feuerstein@quest.com"&gt;&lt;strong&gt;let me know immediately&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; and I will remove it. My apologies in advance for any liberties taken.&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Many thanks to Diana, Belen, Daniel, Pablo, Ricardo and others at Quest Mexico for organizing a fantastic set of events (beyond just the public program), media interviews and overall stay. I look forward to a triumphant return, or perhaps a visit to Monterey.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Once again, I find myself marveling at my good fortune and the fine life I have. I only wish I was able to spend time with all my PL/SQL friends around the world and not be away from wife, Veva, and my boys. That is a substantial price to pay. Sigh....&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Finally, I very much enjoyed having an opportunity to resurrect my rusty (not) command of the Spanish language. I am not sure whether it is a blessing or a curse, but they tell me that I am able to pronounce words in Spanish very well (roll those r's, put the accent on the correct syllable, etc.). This leads native speakers to believe that I can speak and understand much more than I actually can. So I start out strong, but immediately stumble over a serious lack of vocabulary, and very poor comprehension (I can talk better than I can understand - big surprise, I spend so much of my life talking at others).&lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/463/An-Amazing-Visit-to-Mexico-City.aspx&gt;More ...&lt;/a&gt;</description>
      <author>Steven Feuerstein</author>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/463/An-Amazing-Visit-to-Mexico-City.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/463/An-Amazing-Visit-to-Mexico-City.aspx</guid>
      <pubDate>Fri, 23 Oct 2009 12:38:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=463</trackback:ping>
    </item>
    <item>
      <title>Resolving an LTRIM mystery</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/461/Resolving-an-LTRIM-mystery.aspx</link>
      <description>&lt;p&gt;Steven discusses how LTRIM works and an alternative solution for a user's problem.&lt;/p&gt;&lt;div class="tags"&gt;Tags: plsql,oracle,ltrim&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/461/Resolving-an-LTRIM-mystery.aspx#Comments</comments>
      <slash:comments>3</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/461/Resolving-an-LTRIM-mystery.aspx</guid>
      <pubDate>Thu, 15 Oct 2009 13:42:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=461</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/150/Default.aspx">ltrim</blog:tag>
    </item>
    <item>
      <title>Compare Nested Tables of Non-Scalar Datatypes</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/458/Compare-Nested-Tables-of-Non-Scalar-Datatypes.aspx</link>
      <description>&lt;p&gt;A little known, but very handy feature of PL/SQL is the ability to apply set operators, like union, intersect and minus, to nested tables.&lt;/p&gt;&lt;div class="tags"&gt;Tags: plsql,set operator,nested table,oracle&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/458/Compare-Nested-Tables-of-Non-Scalar-Datatypes.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/458/Compare-Nested-Tables-of-Non-Scalar-Datatypes.aspx</guid>
      <pubDate>Mon, 12 Oct 2009 14:28:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=458</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/148/Default.aspx">set operator</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/149/Default.aspx">nested table</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
    </item>
    <item>
      <title>PL/SQL on DB2 9.7 ?!</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/444/PL-SQL-on-DB2-9-7.aspx</link>
      <description>&lt;div&gt;Check out this &lt;a href="http://www.youtube.com/watch?v=EnpDMvobUmE"&gt;video&lt;/a&gt;. IBM claims to now provide native support for PL/SQL programs, including support for many built-in packages, collections, etc. Wow! Lots more details &lt;a href="http://www.ibm.com/developerworks/data/library/techarticle/dm-0907oracleappsondb2/index.html"&gt;here&lt;/a&gt;, but you will find below some&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;&lt;img alt="" width="580" height="512" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog091609-1.gif" /&gt;&lt;/p&gt;
&lt;p&gt;I think this is wonderful news for the PL/SQL community. Not only can I rebrand all of my books for DB2 (as in "DB2 PL/SQL Programming" - wow!), but PL/SQL developers should have growing opportunities for jobs.&lt;/p&gt;
&lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/444/PL-SQL-on-DB2-9-7.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,db2,oracle&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/444/PL-SQL-on-DB2-9-7.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/444/PL-SQL-on-DB2-9-7.aspx</guid>
      <pubDate>Wed, 16 Sep 2009 13:36:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=444</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/143/Default.aspx">db2</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
    </item>
    <item>
      <title>Online Training for the New Economy</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/438/Online-Training-for-the-New-Economy.aspx</link>
      <description>&lt;div&gt;When the going gets tough and budgets get tight, money for training is often cut first. You still, however, need to learn how to best leverage the PL/SQL language and write high quality code. To help you, Quest is offering a three-part, webcast training series that I will be teaching. Each session consists of two hours of in-depth coverage of a specific functionality area or best practice.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The cost is far less than would be for an onsite or public training - and I don't have to travel (and neither do you)!&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;More information about session logistics and registration are available through these links below. For much more detail on each session, please check out the descriptions at the end of this posting:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;&lt;font size="3"&gt;Webcast Details&lt;/font&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;ul type="disc"&gt;
    &lt;li&gt;&lt;strong&gt;Session 1: &lt;/strong&gt;&lt;a href="http://qlist1.quest.com/t/2840626/59069726/17309/0/"&gt;&lt;font color="#003366"&gt;"Turbo-charge PL/SQL Execution with Bulk Processing"&lt;/font&gt;&lt;/a&gt; &lt;br /&gt;
    Thursday, October 22, 2009 at 2 p.m. ET&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Session 2: &lt;/strong&gt;&lt;a href="http://qlist1.quest.com/t/2840626/59069726/17309/0/"&gt;&lt;font color="#003366"&gt;"Writing Maintainable PL/SQL Code"&lt;/font&gt;&lt;/a&gt; &lt;br /&gt;
    Thursday, November 12, 2009, at 2 p.m. ET&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Session 3: &lt;/strong&gt;&lt;a href="http://qlist1.quest.com/t/2840626/59069726/17309/0/"&gt;&lt;font color="#003366"&gt;"Error Management Features of Oracle PL/SQL"&lt;/font&gt;&lt;/a&gt; &lt;br /&gt;
    Thursday December 10, 2009, at 2:00 p.m. ET&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;I hope that you can take advantage of this opportunity. Click on the link below to:&lt;/div&gt;
&lt;div&gt; 
&lt;div align="center"&gt;&lt;a href="http://qlist1.quest.com/t/2840626/59069726/17309/0/"&gt;&lt;font color="#003366" size="4"&gt;Get Details and Register&lt;/font&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div&gt;&lt;strong&gt;&lt;font color="#365f91" size="3"&gt;Optimizing PL/SQL Execution with Bulk Processing&lt;/font&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;This session focuses on how to turbo-charge the performance of multi-row SQL statements executed from within a PL/SQL using FORALL and BULK COLLECT. These features have been around since Oracle8i, but many developers still don't use them or only scratch the surface of what is possible.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The Bulk Processing webinar will talk about why these features were needed and how they work.  Steven will start with simple examples and syntax and drill down into all nuances, including the LIMIT clause for BULK COLLECT and the SAVE EXCEPTIONS, INDICES OF and VALUES OF clauses for FORALL.&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;After attending this webinar, you will be able to both create new programs built around these features and also redesign existing programs safely to improve performance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;font color="#365f91" size="3"&gt;&lt;br /&gt;
Writing Maintainable PL/SQL Code&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;Software managers (and, therefore, their developers) are very focused on delivering applications "on time" (that is, to meet the current production deadline). Sure, that's important. But as (or maybe even &lt;em&gt;more&lt;/em&gt;) important is to build applications so that they can be maintained and enhanced without consuming all the resources of the development team (thereby interfering with &lt;em&gt;new &lt;/em&gt;development).&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;This webinar offers a wide-ranging set of techniques to make your code easy to understand and maintain over time. These techniques include: the use of subtypes and local modules; how to activate and check compliance with standards; and encapsulation (information hiding).&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;After attending this webinar, you will be able to write code that minimizes the amount of development resources needed to maintain that code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;font color="#365f91" size="3"&gt;Error Management Features of Oracle PL/SQL&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Consistent, robust error management is a critical feature of any s&lt;/strong&gt;uccessful application. Developers need to know all that is possible in PL/SQL regarding the raising, handling and logging of errors, and that standardize the way in which those tasks are performed.&lt;/div&gt;
&lt;div&gt;This webinar takes you beyond the basics of exception handling in PL/SQL to explore the wide range of specialized error management features in Oracle, plus recommendations for best practices for consistent, robust application construction.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;We will cover FORALL's SAVE EXCEPTIONS, DML error logging with the DBMS_ERRLOG package, the AFTERSERVERERROR trigger, the DBMS_UTILITY.FORMAT_ERROR_BACKTRACE function, and more. In addition, we will talk about hiding error management functionality behind a PL/SQL packaged API and then deploying it as a set of services for application developers.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;After attending this webinar, you will be able to fully leverage PL/SQL error management features and follow best practices for consistent error management across your entire development team.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/438/Online-Training-for-the-New-Economy.aspx&gt;More ...&lt;/a&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/438/Online-Training-for-the-New-Economy.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/438/Online-Training-for-the-New-Economy.aspx</guid>
      <pubDate>Tue, 08 Sep 2009 18:23:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=438</trackback:ping>
    </item>
    <item>
      <title>Oracle Database 11g Release 2 Has Arrived!</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/437/Oracle-Database-11g-Release-2-Has-Arrived.aspx</link>
      <description>&lt;div&gt;What a big relief....I was in the beta program, checking out the new features of PL/SQL in this latest release of the Oracle database. That's quite a privilege, but also a burden; Oracle is very severe about not wanting us to talk about upcoming features &lt;em&gt;before&lt;/em&gt; they officially release the product to their adoring public.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;That's tough on me, because I have a hard time keeping my mouth shut about anything, especially wondrous new features in PL/SQL. So what I usually do is say something like this:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;"It is &lt;em&gt;possible&lt;/em&gt;, just &lt;em&gt;possible&lt;/em&gt; that in the next release of Oracle you will be able to...."&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;And I leave it up to my audience to draw their own conclusions.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;No longer. I can now disclose to you the new features for PL/SQL in Oracle Database 11g Release 2. Drum roll, please!&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So what's new? Hmmm. Not much, in PL/SQL specifically.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Probably the most important thing to me won't mean much to most of you, because it is an improvement over an 11.1 feature – and who's upgraded to 11g already? Not many.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Still, I will tell you about it: when working with the Function Result Cache, you no longer need to include the RELIES_ON clause. Oracle will automatically determine what tables the cache is reliant on. When and if any changes are committed to that table, all dependent caches will be invalidated.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;It's a nice improvement and it also means that for most of you, RELIES_ON will be completely ignored. Lucky you! This sort of "instant deprecation" reminds me of the RESTRICT_REFERENCES pragma that was required back in Oracle7 or 8 to be able to execute user-defined functions inside SQL statements. Now &lt;em&gt;that&lt;/em&gt; was an enormous pain in the neck and in Oracle8i, it was no longer required.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Besides the enhancement to the Function Result Cache, we have the following changes in and additions to PL/SQL (I encourage you to download the &lt;a href="http://www.oracle.com/technology/documentation/database11gR1.html"&gt;11.2 documentation library&lt;/a&gt;, even if you have no plans to upgrade to 11.2 anytime soon. Then you can review the PL/SQL Users Guide yourself!):&lt;/div&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10472/whatsnew.htm#CJADFHHG"&gt;DBMS_PARALLEL_EXECUTE Package&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10472/whatsnew.htm#CJAFBCBH"&gt;FORCE Option in CREATE TYPE Statement&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10472/whatsnew.htm#CJACJEHC"&gt;Crossedition Triggers&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10472/whatsnew.htm#CJAJBFGD"&gt;ALTER TYPE Statement Restrictions for Editioned ADTs&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10472/whatsnew.htm#CJACEHIG"&gt;RESET option for ALTER TYPE Statement&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10472/whatsnew.htm#CJAGBBEC"&gt;Automatic Detection of Data Sources of Result-Cached Function&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10472/whatsnew.htm#CJACABII"&gt;Result Caches in Oracle RAC Environment Are No Longer Private&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;Surely, you are thinking, 11.2 consists of more than this. Certainly it does. The major new feature in 11.2 is "edition-based redefinition," which (according to the &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10471/adfns_editions.htm"&gt;doc&lt;/a&gt;) " enables you to upgrade the database component of an application while it is in use, thereby minimizing or eliminating down time."&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;This is REALLY BIG NEWS. You can now "hot patch" your application code, which means that Oracle is &lt;em&gt;finally&lt;/em&gt; and truly a 24x7 database platform. This feature will have a big impact on application architects and some impact on PL/SQL developers, but there is actually very little change in the PL/SQL language itself.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;And now for the biggest news of all: now that Oracle has officially released 11.2, O'Reilly can publish the &lt;a href="http://oreilly.com/catalog/9780596514464/?CMP=AFC-ak_book&amp;ATT=Oracle+PL%2FSQL+Programming%2c+Fifth+Edition%2c"&gt;5&lt;sup&gt;th&lt;/sup&gt; edition of Oracle PL/SQL Programming&lt;/a&gt;. This edition has lots of good stuff in it, but most important are:&lt;/div&gt;
&lt;ul&gt;
    &lt;li&gt;Optimize PL/SQL performance with the aid of a brand-new chapter in the fifth edition;&lt;/li&gt;
    &lt;li&gt;Understand and use new Oracle Database 11g features, including the edition-based redefinition capability, the function result cache, the new CONTINUE statement, fine-grained dependency tracking, sequences in PL/SQL expressions, supertype invocation from subtypes, and enhancements to native compilation, triggers, and dynamic SQL;&lt;/li&gt;
    &lt;li&gt;Use new Oracle Database 11g tools and techniques such as PL/Scope, the PL/SQL hierarchical profiler, and the SecureFiles technology for large objects.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;[ By the way, I am considering making it possible to order a signed copy of OPP5 through my own website. If you are interested, please drop me a &lt;a href="http://www.toadworld.commailto:steven@stevenfeuerstein.com"&gt;note&lt;/a&gt;. ]&lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/437/Oracle-Database-11g-Release-2-Has-Arrived.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,oracle,11g&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/437/Oracle-Database-11g-Release-2-Has-Arrived.aspx#Comments</comments>
      <slash:comments>2</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/437/Oracle-Database-11g-Release-2-Has-Arrived.aspx</guid>
      <pubDate>Fri, 04 Sep 2009 22:25:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=437</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/11/Default.aspx">11g</blog:tag>
    </item>
    <item>
      <title>Making Change Happen</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/433/Making-Change-Happen.aspx</link>
      <description>&lt;div&gt;[ It is very likely that if you are reading this you are a developer, but this is really geared towards software managers. So feel free to copy and paste into a Word doc and pass it along to your manager or team lead! ]&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I very often give trainings and presentations on the topic of PL/SQL best practices. I offer lots of ideas for writing code that is easier to read and maintain, runs more efficiently, can be tested with less difficulty, and utilize more fully the best features of PL/SQL.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;And all too often, the response I get to these ideas are: "They all sound great, but I know that when I go back to work, I'll just fall back into the same way I've been doing things. And even if I change, the rest of the group will still be stuck in the old ruts."&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Well, that's depressing, isn't it?&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;When I was in Singapore last week, I gave one of those "Here's the right way to do everything" talks to a group of developers at a major financial services firm. Then I met with the Deputy Director of IT and he presented me that same challenge:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;"How can I get my people to change the way they do things?"&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So I decided to try to come up with an answer. Here's what I suggested to him:&lt;/div&gt;
&lt;blockquote dir="ltr" style="margin-right: 0px"&gt;
&lt;div&gt;&lt;strong&gt;Champions&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Research Time&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Team-building Reviews&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Incentives&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Selective Enforcement&lt;/strong&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div&gt;Perhaps I should go into a bit more detail....&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;First of all, it is important to recognize that the biggest challenge to bringing about change is not making sure that developers &lt;em&gt;know&lt;/em&gt; about the new features and the right way to do things. The technology is actually the easy part. The hard part is to change &lt;em&gt;behavior&lt;/em&gt;. We are all creatures of habit, and we like our comfort zones. They're so comfortable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;font color="#365f91" size="3"&gt;Champions&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;For any new product (we were talking about Quest Code Tester, but it applies to anything) or major new feature, you should assign a person on your team to be the "champion" of that technology. They should become expert in the technology, be enthusiastic about what it can do for the team, and they should be ready, willing and able to mentor others.&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Without a strong proponent of a new direction, you won't be able to build the momentum to ensure a solid, consistent, team-wide implementation. With a champion in place, everyone on the team knows who to go to when they get stuck. And since the role is well-defined and "public knowledge," there is no reluctance to approach the champion for help.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;font color="#365f91" size="3"&gt;Research Time&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;I continue to be shocked at how many developers still do not seem to know about and use many important features added to PL/SQL in Oracle8i. Yes, &lt;em&gt;Oracle8i&lt;/em&gt;. Things like: invoker rights, autonomous transactions, FORALL and BULK COLLECT. And then of course, there are the many new features of 9i and 10g, such as string-indexed collections, MULTISET operators, DBMS_UTILITY.FORMAT_ERROR_BACKTRACE, and more.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;It's easy to understand why so many developers remain ignorant about such things and consequently under-utilize the language: they don't have the time (or feel like they have the freedom) to &lt;em&gt;explore&lt;/em&gt; PL/SQL.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Managers usually ask just one or two questions of their developers: "When you will be done?" and "Why is your code so buggy?" Neither of those questions are conducive to expanding one's knowledge of a programming language.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I strongly urge managers and team leads to ask each developer to come up with a research plan: spend 4 hours every two weeks (5% of your time - more is better, but I don't want to sound crazy) exploring technologies that could be helpful to the project.&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Insist that the developer &lt;em&gt;not&lt;/em&gt; work directly on application code, but also that they put together a proposal for precisely what they want to study and why. They will feel great about the opportunity, and both the team and application will benefit in short order.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;font color="#365f91" size="3"&gt;Team-building Reviews&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;Everyone knows that code review is a good idea. I would even go so far as to say that no critical code should go into production until at least one other human being (besides the one who wrote it) looks it over and makes sure it isn't totally crazy (that is, unreadable spaghetti code). Often the form of such a review is "one on one" - the team lead looks over the good and gives private feedback to the developer.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;That's not what I'm talking about here (though it's a fine thing to do!). Rather (or in addition), I propose that once a month, the entire team gets together to critique, as group, a piece of code. The aim of the review is not so much to find flaws in code, but to share knowledge about the application and elevate the whole team's awareness of how best to use PL/SQL.&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Whoever is the senior developer on the team should take the lead; you can't expect junior programmers to be willing to subject themselves to potential humiliation (at least not until they see there is nothing to be afraid of). The best developer should set an example: everyone's code can be improved; it's OK to make mistakes; we can all learn from one another.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;font color="#365f91" size="3"&gt;Incentives&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;What's the best way to motivate a developer: carrot (incentive) or stick (punishment)? We all know the answer, and not just for developers: we aren't motivated to change for the better with a threat of punishment (though we may still change because we have no choice). I think the world would be a far better place if without coercion.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;And certainly when it comes to getting developers to create higher quality software, well, it's really important to make that they &lt;em&gt;want&lt;/em&gt; to do. So....let's use incentives!&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Managers should identify ways to measure objectively progress in important areas, and then give out rewards (both recognition/status and goodies, like gift certificates to restaurants, Amazon.com, etc.) to those who are high achievers in those areas.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Here are some ideas for possible metrics:&lt;/div&gt;
&lt;ul&gt;
    &lt;li&gt;Reusable code: we don't want to reinvent the wheel, but sometimes it's hard to find and reuse code. Perhaps prizes will help. You can run searches through the code base to find all external (not in the same package) program calls, for one example. And I suggest you give a reward for (a) the person writes the most reusable code - usually a senior developer, and (b) the person who &lt;em&gt;uses&lt;/em&gt; the most reusable code. That way even a junior developer has a chance to win and is very much incented to learn from the use the work of others.&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;Naming standards: we usually have some set of naming standards, but how do you check to see if people are following them? Consider installing Oracle Database 11g on a workstation, load up your application code, and use PL/Scope to analyzer variable declarations. For an example of a query that demonstrates this powerful feature, check out the AMIS blog, and search for "PL/Scope".&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;Unit tests (especially &lt;em&gt;automated&lt;/em&gt; tests): I would give out a really substantial reward for a developer who does the most automated testing of their code, building and putting in place regression tests. This will have the biggest impact on the quality and success of your applications, so get people motivated to do it! It will greatly help to provide a tool to make it easy(ier) to automate the process. Check out Quest Code Tester for Oracle, utPLSQL, dbFit, PLUTO or PL/Unit.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;strong&gt;&lt;font color="#365f91" size="3"&gt;Selective Enforcement&lt;/font&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;No doubt about it: carrots are the way to go. But that doesn't mean that you (a manager or team lead) shouldn't be ready to bring out the stick now and then.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Well, that's probably a bad way to put it. I am not making an argument for punishing developers if they don't do things a certain way. I do believe, however, that a manager should in at least some cases, &lt;em&gt;insist&lt;/em&gt; and&lt;em&gt; enforce&lt;/em&gt; certain critical changes in behavior. Some things are just too important to leave up to developer preference and hopes for good behavior.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The following areas come to mind:&lt;/div&gt;
&lt;ul&gt;
    &lt;li&gt;Testing (yes, that again): let's face it. Our applications have too many bugs in them. That's not only a big drag for our users, but it makes our live miserable, too. Rather than focus on building new applications or adding interesting functionality, we spend way too much of our time putting out fires. We are stuck in a vicious cycle: no time to write better code, because we have too many bugs to fix. The only way out is better and more automated testing. Managers should find tools to help make this a reality (see list in previous section) and they should &lt;em&gt;insist&lt;/em&gt; that developers write repeatable, automated tests.&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;Version control: it seems obvious, but I still run into development shops that do not have VC systems in place. Sometimes I even encounter developers who do not maintain their source code in files, but simply edit and compile right out of the database. Totally insane! That's a sure recipe for losing work and creating terrible frustration on your team.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;I could list other ideas, but I don't want to end this note with too much of heavy hand. And managers should definitely not go overboard with putting lots of new requirements in place at once. Phase them in, and make sure that you provide support (tools, champions, training time) to ensure success.&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;&lt;strong&gt;&lt;font color="#365f91" size="3"&gt;No Guarantees But It Won't Hurt to Try!&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;Maybe none of these ideas will make a difference in your team, but surely it's worth trying some new directions to see what if anything will stick.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I have no doubt that developers will be excited to see their manager trying new approaches, especially ones that don't simply mean more work and longer hours.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/433/Making-Change-Happen.aspx&gt;More ...&lt;/a&gt;</description>
      <author>Steven Feuerstein</author>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/433/Making-Change-Happen.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/433/Making-Change-Happen.aspx</guid>
      <pubDate>Sun, 23 Aug 2009 00:18:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=433</trackback:ping>
    </item>
    <item>
      <title>Watch Out for Data Caching!</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/422/Watch-Out-for-Data-Caching.aspx</link>
      <description>&lt;p&gt;I just fixed a bug in Quest Code Tester for Oracle, and I thought I would share my experience with you.&lt;/p&gt;
&lt;p&gt;The bug was reported by our most excellent QA tester, Danny Pham. He is not only good at going through the defined test cases to verify correct behavior. He also takes devilish delight in trying all sorts of "crazy" stuff to see what happens.&lt;/p&gt;
&lt;p&gt;So Danny encountered this error after he set up a test case with three outcomes, all built on cursor variable expression tests (something that is very unlikely for a customer to have done):&lt;/p&gt;
&lt;p&gt;    &lt;font face="Courier New"&gt;PL/SQL: numeric or value error: NULL index table key value&lt;br /&gt;
  ORA-06512: at "QCTO.QU_TEMPLATE_XP", line 1523&lt;br /&gt;
  ORA-06512: at "QCTO.QU_TEMPLATE_XP", line 1570&lt;br /&gt;
  ORA-06512: at "QCTO.QU_GENERATE", line 6062&lt;br /&gt;
  ORA-06512: at "QCTO.QU_GENERATE", line 6138&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;I did some tracing, digging around, etc. and I concluded that this is very quirky behavior, likely specific to this unlikely scenario, and I was just about to write him an email suggesting that this one will not be easy to fix, is not a high priority bug to fix (we are in final QA testing - only able to fix "P0" bugs - the product is considered broken if a P0 is not addressed), and we should leave it for next version.&lt;/p&gt;
&lt;p&gt;But then I thought: "Aw, heck, let's try to reproduce the problem with a simpler, more likely scenario." And, lo and behold, and much to my stunned disappointment, it was very  easy to replicate the error with a much more likely scenario.&lt;/p&gt;
&lt;p&gt;That left me with no choice: MUST FIX BUG. And it was very odd behavior, too. The error occurred when I first defined the test and any time I tried to run it in that session. But when I exported and imported the test definition, the bug went away, and I could run the test just fine.&lt;/p&gt;
&lt;p&gt;After a little bit more analysis, I also found that if I closed Code Tester and reopened it, the bug would disappear. How could this be? What was different?&lt;/p&gt;
&lt;p&gt;Well, any time a bug's behavior changes with a new connection, you should think about what was cached in the session, either by Oracle or by the application. That led me to remember that I had implemented some caching of key data in the Code Tester backend to improve performance when generating and running tests.&lt;/p&gt;
&lt;p&gt;I cache the data when validating the test definition, and then reuse that same cached data when generating the test code and finally when running the test (at least in those situations where I need to generate some "just in time" code elements).&lt;/p&gt;
&lt;p&gt;Caching is fine and wonderful - especially Oracle 11g's new function result cache, which is a thing of great beauty - but you have to make sure that the underlying data hasn't changed!&lt;/p&gt;
&lt;p&gt;So maybe that was the problem...something had changed. But why would it change? So I opened up one of my program files and did some searching for DML operations. And I found a point in the validation phase when I go back and make a change to the underlying data (actually, I knew about this step and had studied it, but hadn't connected it to the caching issue).&lt;/p&gt;
&lt;p&gt;Now, you could argue (and I did so to myself) that validation is not the place for data changing. You could also argue that there is no time to refactor this convoluted piece of code. You could, finally, argue that you should put it on your to do list to get back to this piece of code and clean it up.&lt;/p&gt;
&lt;p&gt;I put the following on my to do list: "Get back to this piece of code and clean it up."&lt;/p&gt;
&lt;p&gt;In the meantime, however, I put in a call to invalidate the cache and force new retrieval of data, immediately after the change I made to the qu_attributes table.&lt;/p&gt;
&lt;p&gt;And then the bug disappeared. Ah...so nice.&lt;/p&gt;
&lt;p&gt;Lessons learned (or of which I was reminded):&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Don't be hasty in drawing conclusions about the causes of bugs, especially if your conclusion seems anything like a rationalization for not doing something you know you should do.&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;Be very, very, very careful when caching data. It's a powerful performance optimization technique, but it can lead to dirty data and bugs that are hard to identify and fix.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/422/Watch-Out-for-Data-Caching.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: code tester,plsql&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/10/Default.aspx&gt;Code Tester for Oracle&lt;/a&gt;&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/10/Default.aspx">Code Tester for Oracle</category>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/422/Watch-Out-for-Data-Caching.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/422/Watch-Out-for-Data-Caching.aspx</guid>
      <pubDate>Mon, 03 Aug 2009 18:31:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=422</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/1/Default.aspx">code tester</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
    </item>
    <item>
      <title>Must Know Features of PL/SQL</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/413/Must-Know-Features-of-PL-SQL.aspx</link>
      <description>&lt;div&gt;I spend way too much of my life on airplanes zipping around to different places, doing presentations and trainings on PL/SQL. In the process, I meet many PL/SQL developers – and I continue to be surprised and disappointed at how many developers do not know about or at least do not seem to take advantage of very powerful and useful features of PL/SQL. So I have to decided to list below all those elements of PL/SQL that I consider to be "must know." In other words, if you are not familiar with the following features, and not utilizing them, then your PL/SQL programs likely leave lots to be desired from the standpoints of efficiency and maintainability.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;In the table below, you will find on the left the PL/SQL keywords that identify the feature and on the right a brief description and link to the Oracle documentation on this feature. Of course, you can also download my trainings at &lt;u&gt;&lt;a href="http://www.toadworld.com/LinkClick.aspx?link=153&amp;tabid=67"&gt;PL/SQL Obsession&lt;/a&gt;&lt;/u&gt; and learn about these features – oh, and don't forget to &lt;u&gt;&lt;a href="http://www.oreillynet.com/pub/au/344"&gt;buy my books&lt;/a&gt;&lt;/u&gt;. &lt;font face="Wingdings"&gt;J&lt;/font&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;table border="1" cellspacing="0" cellpadding="10"&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="187"&gt;
            &lt;div&gt;&lt;strong&gt;Collections&lt;/strong&gt;&lt;/div&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="403"&gt;
            &lt;div&gt;Associative arrays, nested tables, varrays: if these terms mean little to you, then you are missing out on some of the most important functionality in PL/SQL. The collection is PL/SQL's version of an array, and they can help you in so many different ways.&lt;/div&gt;
            &lt;div&gt; &lt;/div&gt;
            &lt;div&gt;&gt;&lt;a href="http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14261/collections.htm#LNPLS005"&gt;More info&lt;/a&gt;&lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="187"&gt;
            &lt;div&gt;&lt;strong&gt;FORALL&lt;/strong&gt;&lt;/div&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="403"&gt;
            &lt;div&gt;Bulk processing of DML statements. This is the most important new feature in PL/SQL since Oracle8i was released. Anytime you execute an insert, update, delete or merge inside a loop of some sort (multi-row DML), you should convert this looping operation to a FORALL statement. You will see an amazing improvement in performance...and you need to use collections to leverage FORALL.&lt;/div&gt;
            &lt;div&gt; &lt;/div&gt;
            &lt;div&gt;Don't forget to also check out these nuances of FORALL: SAVE EXCEPTIONS, INDICES OF, VALUES OF.&lt;/div&gt;
            &lt;div&gt; &lt;/div&gt;
            &lt;div&gt;&gt;&lt;a href="http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14261/tuning.htm#sthref2181"&gt;More Info&lt;/a&gt;&lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="187"&gt;
            &lt;div&gt;&lt;strong&gt;BULK COLLECT&lt;/strong&gt;&lt;/div&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="403"&gt;
            &lt;div&gt;Bulk retrieval of data. Second only to FORALL in importance, use BULK COLLECT with both implicit and explicit cursors to drastically speed up the performance of data retrieval. Don't forget to use the LIMIT clause to manage the amount of PGA memory consumed by your program. As with FORALL, you need to use collections to leverage BULK COLLECT.&lt;/div&gt;
            &lt;div&gt; &lt;/div&gt;
            &lt;div&gt;&gt;&lt;a href="http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14261/sqloperations.htm#sthref1351"&gt;More Info&lt;/a&gt;&lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="187"&gt;
            &lt;div&gt;&lt;strong&gt;DBMS_UTILITY.FORMAT_ERROR_BACKTRACE&lt;/strong&gt;&lt;/div&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="403"&gt;
            &lt;div&gt;Answers the question "On what line number was the most recent exception raised?" Available in Oracle Database 10g Release 2 and above, this function should be called whenever you trap and log an error.&lt;/div&gt;
            &lt;div&gt; &lt;/div&gt;
            &lt;div&gt;&gt;&lt;a href="http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_util.htm#sthref7777"&gt;More Info&lt;/a&gt;&lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="187"&gt;
            &lt;div&gt;&lt;strong&gt;DBMS_UTILITY.FORMAT_CALL_STACK&lt;/strong&gt;&lt;/div&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="403"&gt;
            &lt;div&gt;Answers the question "How did I get here?" In other words, it shows you the execution call stack (A called B called C). Very useful information when logging errors or tracing application execution.&lt;/div&gt;
            &lt;div&gt; &lt;/div&gt;
            &lt;div&gt;&gt;&lt;a href="http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_util.htm#sthref7773"&gt;More Info&lt;/a&gt;&lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="187"&gt;
            &lt;div&gt;&lt;strong&gt;DBMS_UTILITY.FORMAT_ERROR_STACK&lt;/strong&gt;&lt;/div&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="403"&gt;
            &lt;div&gt;Returns the current Oracle error message (sometimes as a single string, and sometimes as a &lt;em&gt;stack&lt;/em&gt; of messages, if the exception has been re-raised one or more times). Oracle recommends you use this instead of SQLERRM, which may truncate your error message.&lt;/div&gt;
            &lt;div&gt; &lt;/div&gt;
            &lt;div&gt;&gt;&lt;a href="http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_util.htm#sthref7777"&gt;More Info&lt;/a&gt;&lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="187"&gt;
            &lt;div&gt;&lt;strong&gt;PRAGMA AUTONOMOUS_TRANSACTION;&lt;/strong&gt;&lt;/div&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="403"&gt;
            &lt;div&gt;This pragma defines your procedure or function as an &lt;em&gt;autonomous transaction&lt;/em&gt;, which means that any DML operations performed within this subprogram are saved or rolled back without affecting any other uncommitted changes in your session. Very handy when logging errors or tracing, also useful in a variety of other circumstances.&lt;/div&gt;
            &lt;div&gt; &lt;/div&gt;
            &lt;div&gt;&gt;&lt;a href="http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14261/sqloperations.htm#sthref1521"&gt;More Info&lt;/a&gt;&lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="187"&gt;
            &lt;div&gt;&lt;strong&gt;AUTHID CURRENT_USER&lt;/strong&gt;&lt;/div&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="403"&gt;
            &lt;div&gt;When you include this clause in the header of a program unit, then when the program is run, the privileges of the &lt;em&gt;current user &lt;/em&gt;or invoker of the program are used to resolve references to table and view names. This is called&lt;em&gt; invoker rights&lt;/em&gt; and is in contrast to &lt;em&gt;definer rights&lt;/em&gt;, the default (or AUTHID DEFINER), in which the privileges of the owner of the program determine at compile time how references to database objects are resolved.&lt;/div&gt;
            &lt;div&gt; &lt;/div&gt;
            &lt;div&gt;Invoker rights comes in very handy when you need the same code to work against different tables, depending on who is calling the program.&lt;/div&gt;
            &lt;div&gt; &lt;/div&gt;
            &lt;div&gt;&gt;&lt;a href="http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14261/subprograms.htm#LNPLS00809"&gt;More Info&lt;/a&gt;&lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="187"&gt;
            &lt;div&gt;&lt;strong&gt;SUBTYPE&lt;/strong&gt;&lt;/div&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="403"&gt;
            &lt;div&gt;The SUBTYPE keyword allows you to define your own, application-specific datatypes. It is a trivial feature to learn and use, but a very powerful one from the standpoint of writing maintainable code.&lt;/div&gt;
            &lt;div&gt; &lt;/div&gt;
            &lt;div&gt;Use packaged-based subtypes to hide the actual datatype definition, such as VARCHAR2(500). That way, if you ever need to change the datatype (for example, to make the maximum size of the string larger), you can change it one place and all the variables that are declared using the subtype will use this new definition after recompilation.&lt;/div&gt;
            &lt;div&gt; &lt;/div&gt;
            &lt;div&gt;&gt;&lt;a href="http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14261/datatypes.htm#sthref831"&gt;More Info&lt;/a&gt;&lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="187"&gt;
            &lt;div&gt;&lt;strong&gt;RESULT_CACHE&lt;/strong&gt;&lt;/div&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="403"&gt;
            &lt;div&gt;New to Oracle Database 11g, you can specify that a function is a &lt;em&gt;result cache&lt;/em&gt;. This means that Oracle will cache the inputs and return values of the function in a new SGA cache, and share this data across all sessions in the instance. It can provide a significant boost in query performance for any tables that are queried more frequently than they are updated.&lt;/div&gt;
            &lt;div&gt; &lt;/div&gt;
            &lt;div&gt;Sure, you are not using 11g yet, but you will. And you can get ready to take advantage of the result cache by hiding your queries inside functions &lt;em&gt;now&lt;/em&gt;.&lt;/div&gt;
            &lt;div&gt; &lt;/div&gt;
            &lt;div&gt;&gt;&lt;a href="http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28370/subprograms.htm#LNPLS00817"&gt;More Info&lt;/a&gt;&lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="187"&gt;
            &lt;div&gt;&lt;strong&gt;DBMS_ERRLOG&lt;/strong&gt;&lt;/div&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="403"&gt;
            &lt;div&gt;Introduced in Oracle Database 10g Release 2, this package and the associated LOG ERRORS clause, allows you to suppress the raising of exceptions in for DML statements, instead writing error information to a log table. This feature is very handy when performing large numbers of DML operations (ie, batch loads) from within PL/SQL and you need to continue past any exceptions raised. You can also use this within a FORALL statement.&lt;/div&gt;
            &lt;div&gt; &lt;/div&gt;
            &lt;div&gt;&gt;&lt;a href="http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28419/d_errlog.htm#CHDDFGGI"&gt;More Info&lt;/a&gt;&lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt; &lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/413/Must-Know-Features-of-PL-SQL.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,oracle,collection,forall,bulk collect,pragma&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/413/Must-Know-Features-of-PL-SQL.aspx#Comments</comments>
      <slash:comments>2</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/413/Must-Know-Features-of-PL-SQL.aspx</guid>
      <pubDate>Wed, 22 Jul 2009 14:50:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=413</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/85/Default.aspx">collection</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/130/Default.aspx">forall</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/54/Default.aspx">bulk collect</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/131/Default.aspx">pragma</blog:tag>
    </item>
    <item>
      <title>Avoiding repetitive coding for repetitive column structures</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/410/Avoiding-repetitive-coding-for-repetitive-column-structures.aspx</link>
      <description>&lt;p&gt;Steven proposes a solution to a customer's question about using a 2 dimensional array in PL/SQL.&lt;/p&gt;&lt;div class="tags"&gt;Tags: plsql,array,oracle&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/410/Avoiding-repetitive-coding-for-repetitive-column-structures.aspx#Comments</comments>
      <slash:comments>3</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/410/Avoiding-repetitive-coding-for-repetitive-column-structures.aspx</guid>
      <pubDate>Wed, 15 Jul 2009 13:10:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=410</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/126/Default.aspx">array</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
    </item>
    <item>
      <title>Oracle PL/SQL Programming 5th Edition - "Early Warning"</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/390/Oracle-PL-SQL-Programming-5th-Edition-Early-Warning.aspx</link>
      <description>&lt;div&gt;I was on the phone with a &lt;a href="http://www.quest.com/code-tester-for-oracle"&gt;Quest Code Tester&lt;/a&gt; user the other day and he asked me if I was working on the next edition of my original "magnum opus", Oracle PL/SQL Programming, which would include Oracle11g features.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I cannot describe to you how good it felt to say: "No, I'm not working on it. I'm &lt;em&gt;finished&lt;/em&gt; working on it."&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;In fact, just last week, my editor (Debby Russell) sent all the chapters to the production department, so that they could begin the long process of converting Word docs into an actual, publishable book.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;This fifth edition will cover all features of Oracle11g, through Release 2 - which means it will not be published until the fall, probably at the same time as Oracle Open World (week of October 12), or whenever Oracle formally announces availability of Release 2.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;We have also added a single, very extensive chapter on optimizing performance of PL/SQL code.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;You can see more information about the book and even pre-order the book at:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;a href="http://oreilly.com/catalog/9780596514464/%23top"&gt;http://oreilly.com/catalog/9780596514464/#top&lt;/a&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;But you may want to hold off a little bit on that pre-order. I am considering offering the ability to order the book directly from me, and have it signed whatever personalized message you request. So....you will hopefully see an update about that soon!&lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/390/Oracle-PL-SQL-Programming-5th-Edition-Early-Warning.aspx&gt;More ...&lt;/a&gt;</description>
      <author>Steven Feuerstein</author>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/390/Oracle-PL-SQL-Programming-5th-Edition-Early-Warning.aspx#Comments</comments>
      <slash:comments>1</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/390/Oracle-PL-SQL-Programming-5th-Edition-Early-Warning.aspx</guid>
      <pubDate>Wed, 10 Jun 2009 18:19:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=390</trackback:ping>
    </item>
    <item>
      <title>Naming Conventions and Coding Standards, the Feuerstein Way</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/381/Naming-Conventions-and-Coding-Standards-the-Feuerstein-Way.aspx</link>
      <description>&lt;div&gt;I am often asked about the naming conventions and coding standards that I use. My answer is usually a combination of muttering and vague statements and hand-waving.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;That's because I have a confession: I don't have a single naming conventions and coding standards document that I use. Why not? Because I am a software developer! That is, I feel (well, I &lt;em&gt;am&lt;/em&gt;) very busy, overwhelmed by deadlines. I don't feel like I have the time to stop and write down the few rules that I might actually follow more of less consistently. And it seems that a part of me is somewhat resistant to being accountable to a standard. Sound familiar?&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Sigh...unfortunately (no, make that &lt;em&gt;very&lt;/em&gt; fortunately), lots of other PL/SQL developers look to me for advice about how to "do things right." Ah, the pressure, the pressure!&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Ah, the hypocrisy. That's what it really comes down to: I am a big hypocrite. I routinely violate just about every best practice I push on others. I sound high and mighty, but when I write code, I feel the same pull to do the quick and dirty.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So I've decided to take a few moments out of my various plane rides (I am now - when I started this document, anyway - flying from Manchester, UK, to Sweden to do a presentation to the Stockholm OUG, then a couple of days of customer visits in Stockholm and Milan, then two days of training for Oracle in Helsinki) to jot down what have become my &lt;em&gt;de facto&lt;/em&gt; coding standards.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;You see, I &lt;em&gt;do&lt;/em&gt; have standards, and I even follow them, more or less. I just don't like to bother writing them down.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So that's what (finally) you'll find &lt;u&gt;&lt;a href="http://www.toadworld.com/LinkClick.aspx?link=580&amp;tabid=67"&gt;here&lt;/a&gt;&lt;/u&gt;. It's a combination of the naming conventions I follow, certain naming conventions with which I disagree, and a variety of other suggestions. I hope you find it useful. I'm not going to make much of an effort to justify my approach or explain away the inconsistencies. I'll just show you what I do and you can decide for yourself if you'd like to use my path as a model for your own journey.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I also hereby declare this to be a &lt;em&gt;work in progress&lt;/em&gt;. So...&lt;/div&gt;
&lt;ul&gt;
    &lt;li&gt;If you have disagreements with my approach, &lt;u&gt;&lt;a href="http://www.toadworld.comhttp://www.toadworld.commailto:steven.feuerstein@quest.com?subject=PL%2FSQL%20Standards"&gt;let me know&lt;/a&gt;&lt;/u&gt;. Perhaps I will agree with &lt;em&gt;you&lt;/em&gt;, and change my document (you will get the credit).&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;If you have a suggestion for something to add to the document, &lt;u&gt;&lt;a href="http://www.toadworld.comhttp://www.toadworld.commailto:steven.feuerstein@quest.com?subject=PL%2FSQL%20Standards"&gt;send it to me&lt;/a&gt;&lt;/u&gt;. If I like it, I will put it into the document (and give you credit).&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;If you would like to offer your own set of naming conventions and coding standards to the world of PL/SQL developers, I will add it to the webpage.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt; The URL for my standards document is:  &lt;a href="http://www.ToadWorld.com/SF/standards"&gt;&lt;strong&gt;www.ToadWorld.com/SF/standards&lt;/strong&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/381/Naming-Conventions-and-Coding-Standards-the-Feuerstein-Way.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,naming standards&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/381/Naming-Conventions-and-Coding-Standards-the-Feuerstein-Way.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/381/Naming-Conventions-and-Coding-Standards-the-Feuerstein-Way.aspx</guid>
      <pubDate>Thu, 28 May 2009 17:32:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=381</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/116/Default.aspx">naming standards</blog:tag>
    </item>
    <item>
      <title>A Classic Error in My Monthly Puzzle!</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/365/A-Classic-Error-in-My-Monthly-Puzzle.aspx</link>
      <description>&lt;div&gt;
&lt;p&gt;Every month, a Toad World newsletter goes out to thousands of Toad users and it includes a monthly puzzle that I write. Last month's puzzle went like this:&lt;/p&gt;
&lt;blockquote&gt;Which of the following blocks &lt;strong&gt;does not&lt;/strong&gt; contain an infinite loop?
&lt;p&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;strong&gt;&lt;font face="Arial"&gt;A.&lt;/font&gt;&lt;/strong&gt;&lt;br /&gt;
DECLARE&lt;br /&gt;
   l_line VARCHAR2(32767);&lt;br /&gt;
   l_file UTL_FILE.file_type :=&lt;br /&gt;
      UTL_FILE.fopen ('C:\temp', 'my_file.txt', 'R');&lt;br /&gt;
BEGIN&lt;br /&gt;
   LOOP&lt;br /&gt;
      UTL_FILE.get_line (l_file, l_line);&lt;br /&gt;
   END LOOP;&lt;br /&gt;
END;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;&lt;font face="Arial"&gt;B.&lt;/font&gt;&lt;/strong&gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
   LOOP&lt;br /&gt;
      DBMS_OUTPUT.PUT_LINE ('abc');&lt;br /&gt;
   END LOOP;&lt;br /&gt;
END;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;&lt;font face="Arial"&gt;C.&lt;/font&gt;&lt;/strong&gt;&lt;br /&gt;
DECLARE&lt;br /&gt;
   l_keep_going BOOLEAN;&lt;br /&gt;
BEGIN&lt;br /&gt;
   WHILE (l_keep_going)&lt;br /&gt;
   LOOP&lt;br /&gt;
      DBMS_OUTPUT.PUT_LINE ('abc');&lt;br /&gt;
      l_keep_going := SYSDATE IS NOT NULL;&lt;br /&gt;
   END LOOP;&lt;br /&gt;
END;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;&lt;font face="Arial"&gt;D.&lt;/font&gt;&lt;/strong&gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
   &lt;&lt;start_of_block&gt;&lt;/start_of_block&gt;&gt;&lt;br /&gt;
   DBMS_OUTPUT.PUT_LINE ('abc');&lt;br /&gt;
   GOTO start_of_block;&lt;br /&gt;
END;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I told my friends at Toad World that the answer was (A), because  UTL_FILE.GET_LINE raises the NO_DATA_FOUND exception when you read past the end of the file. Since files cannot be of infinite size, you will eventually read to the end of the file and then the loop will terminate.&lt;/p&gt;
&lt;p&gt;And I wiped my hands of that puzzle. Unfortunately, it came back to haunt me in the form of a message from the Toad World editor-in-chief:&lt;/p&gt;
&lt;blockquote&gt;"Steven, normally I don't worry when I get just a few responses to the puzzler with answers different from what you’ve told us is the correct one, but this month I’m wondering if we missed something because we’ve had close to 50% of the respondents picking the wrong answer (C), and explaining their choice as follows: The value of l_keep_going is not initialized to TRUE and is therefore unknown. It will not enter the loop and therefore the loop is not infinite."&lt;/blockquote&gt;
&lt;p&gt;Oh my, oh my. They are so right. And I was so sloppy. And I was so over-confident, that I did not ask anyone with PL/SQL experience to proof my Q&amp;A.&lt;/p&gt;
&lt;p&gt;Let's take a closer look at choice C:&lt;/p&gt;
&lt;blockquote&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;DECLARE&lt;br /&gt;
   l_keep_going BOOLEAN;&lt;br /&gt;
BEGIN&lt;br /&gt;
   WHILE (l_keep_going)&lt;br /&gt;
   LOOP&lt;br /&gt;
      DBMS_OUTPUT.PUT_LINE ('abc');&lt;br /&gt;
      l_keep_going := SYSDATE IS NOT NULL;&lt;br /&gt;
   END LOOP;&lt;br /&gt;
END;&lt;/font&gt;&lt;/font&gt;&lt;/blockquote&gt;
&lt;p&gt;I declare a variable that I will use to determine termination of the loop, but I neglected to provide a non-null default value. As a result, the WHILE condition fails immediately, the loop body never executes even once – and certainly not an infinite number of times!&lt;/p&gt;
&lt;p&gt;This kind of bug often manifests in this form as well:&lt;/p&gt;
&lt;blockquote&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;DECLARE&lt;br /&gt;
   l_counter PLS_INTEGER;&lt;br /&gt;
BEGIN&lt;br /&gt;
   LOOP&lt;br /&gt;
      do_something;&lt;br /&gt;
      l_counter := l_counter + 1;&lt;br /&gt;
      EXIT WHEN l_counter = 100;&lt;br /&gt;
   END LOOP;&lt;br /&gt;
END;&lt;/font&gt;&lt;/font&gt;&lt;/blockquote&gt;
&lt;p&gt;Again, I have failed to initialize my counter (likely it would be set to 1) and in this case the result is an infinite loop.&lt;/p&gt;
&lt;p&gt;Hey, that must have been what I meant to use as choice C! Yeah, right.&lt;/p&gt;
&lt;p&gt;So the lessons to be learned are:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Anyone can and everyone does make mistakes. Including the self-named PL/SQL Evangelist. &lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;Code review is a critical component of high quality development. All critical code (and what isn't?) should be looked at by another human being before it goes "live."&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/365/A-Classic-Error-in-My-Monthly-Puzzle.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,while loop&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/365/A-Classic-Error-in-My-Monthly-Puzzle.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/365/A-Classic-Error-in-My-Monthly-Puzzle.aspx</guid>
      <pubDate>Mon, 27 Apr 2009 15:47:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=365</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/84/Default.aspx">while loop</blog:tag>
    </item>
    <item>
      <title>An interview with Steven Feuerstein</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/364/An-interview-with-Steven-Feuerstein.aspx</link>
      <description>&lt;div&gt;In case you simply can't get enough of Steven Feuerstein (no, I don't generally talk about my self in the third person or in the royal "we"), I invite you to check out this &lt;a href="http://www.databasedesign-resource.com/interview-with-steven-feuerstein.html"&gt;interview&lt;/a&gt;. I had an awful lot of fun answering the questions, and you might be entertained reading them.&lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/364/An-interview-with-Steven-Feuerstein.aspx&gt;More ...&lt;/a&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/364/An-interview-with-Steven-Feuerstein.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/364/An-interview-with-Steven-Feuerstein.aspx</guid>
      <pubDate>Thu, 23 Apr 2009 01:06:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=364</trackback:ping>
    </item>
    <item>
      <title>A handy string parsing utility - extended</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/362/A-handy-string-parsing-utility-extended.aspx</link>
      <description>&lt;div&gt;It's truly one of the oddities of the PL/SQL language that it does not offer a delimited string parsing program. The closest we can get is DBMS_UTILITY.COMMA_TO_TABLE, and that is sadly deficient (it only parses comma-delimited strings and each item between the commas must be a valid PL/SQL identifier).&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So I built one myself (the parse package) and put it in the &lt;u&gt;&lt;a href="http://www.toadworld.com/Portals/0/stevenf/demo.zip"&gt;demo.zip file&lt;/a&gt;&lt;/u&gt; that accompanies my training materials. You will find it in the parse.pkg file. For the past few years it has consisted of a single function that accepts a delimited list and returns a collection of the items in the list.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;On a flight from London Heathrow to Istanbul in April 2009, though, I decided to make this package a bit more useful. I added two overloadings of the string_to_list function so that you can now easily parse (1) a string that contains multiple lists and (2) a string that contains multiple lists, each of which has a name.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So I have updated the demo.zip download to include this new version, and I thought I would bring it to your attention. The demo.zip contains about 2000 files and there is no index. So it's just a tad bit difficult to find the useful programs within it.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I have also created a &lt;u&gt;&lt;a href="http://www.toadworld.com/LinkClick.aspx?link=430&amp;tabid=67"&gt;Quest Code Tester for Oracle&lt;/a&gt;&lt;/u&gt; test definition to verify the behavior of these functions. If you would like to check that out, install Quest Code Tester 1.8.3 or higher (available as a beta &lt;u&gt;&lt;a href="http://unittest.inside.quest.com/beta.jspa"&gt;here&lt;/a&gt;&lt;/u&gt; until mid-May 2009), and then import the Q#PARSE.qut file (also in demo.zip).&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Here are examples of using the three different overloadings of parse.string_to_list:&lt;/div&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre&gt;DECLARE&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;l_list&lt;span&gt;   &lt;/span&gt;parse.items_tt;&lt;br /&gt;BEGIN&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;l_list:=parse.string_to_list('a,b,c,d',',');&lt;br /&gt;END;&lt;br /&gt;/&lt;/pre&gt;
&lt;pre&gt;DECLARE&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;l_list&lt;span&gt;   &lt;/span&gt;parse.nested_items_tt;&lt;br /&gt;BEGIN&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;l_list:=parse.string_to_list('a,b,c,d|1,2,3,4','|',',');&lt;br /&gt;END;&lt;br /&gt;/&lt;/pre&gt;
&lt;pre&gt;DECLARE&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;l_list&lt;span&gt;   &lt;/span&gt;parse.named_nested_items_tt;&lt;br /&gt;BEGIN&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;l_list:=parse.string_to_list('a,b,c,d|1,2,3,4','|',',');&lt;br /&gt;END;&lt;br /&gt;/&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;div&gt;The third overloading, which returns a collection of type parse.named_nested_items_tt, also offers a demonstration of the elegance and usefulness of multi-level and string-indexed collections.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I hope you find the parse package useful.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;And I hope that someday we can happily deprecate it, for the very good reason that PL/SQL finally offers one of its own.&lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/362/A-handy-string-parsing-utility-extended.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,string parser&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/10/Default.aspx&gt;Code Tester for Oracle&lt;/a&gt;&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/10/Default.aspx">Code Tester for Oracle</category>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/362/A-handy-string-parsing-utility-extended.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/362/A-handy-string-parsing-utility-extended.aspx</guid>
      <pubDate>Mon, 13 Apr 2009 16:57:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=362</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/110/Default.aspx">string parser</blog:tag>
    </item>
    <item>
      <title>Run an OS command from within PL/SQL</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/356/Run-an-OS-command-from-within-PL-SQL.aspx</link>
      <description>&lt;div&gt;
&lt;p&gt;Developers are hard people to satisfy. Oracle gives us this incredibly robust, powerful and easy to use database programming language – and all we can do is complain about what it &lt;em&gt;doesn't &lt;/em&gt;do for us.&lt;/p&gt;
&lt;p&gt;Well, that's reality for you: PL/SQL is powerful and robust and easy to use, but also very narrowly focused. So if you want it to do something outside of its area of expertise, sometimes you have to jump through a few more hoops than you'd like.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;A good example of this is figuring out how to run an OS command from a PL/SQL block. There is not, unfortunately, a native "execute host command" statement within PL/SQL . Instead, Oracle offers (at least) three ways to do this:&lt;/div&gt;
&lt;ul type="disc"&gt;
    &lt;li&gt;Use the DBMS_SCHEDULER package&lt;/li&gt;
    &lt;li&gt;Run a Java method to execute your command.&lt;/li&gt;
    &lt;li&gt;Run a C program to execute your command.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;DBMS_SCHEDULER offers the simplest and most intuitive solution, especially from the standpoint of DBA and system administration tasks. I talk about this solution on the OTN Best Practice page:&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;p&gt;&lt;a href="http://apex.oracle.com/pls/otn/f?p=2853:4:1544539351000407::NO::P4_QA_ID:16282"&gt;http://apex.oracle.com/pls/otn/f?p=2853:4:1544539351000407::NO::P4_QA_ID:16282&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I will, in this Toad World blog, offer brief guidance on the other two options. It is very unlikely that you will be able to rely solely on the content below to implement either approach. Instead, I suggest you use this as a starting point and then from there visit the detailed &lt;a href="http://tahiti.oracle.com"&gt;&lt;strong&gt;Oracle documentation&lt;/strong&gt;&lt;/a&gt; and/or the full chapter coverage of both these techniques in my &lt;a href="http://www.oreillynet.com/cs/catalog/view/au/344"&gt;&lt;strong&gt;Oracle PL/SQL Programming&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;font size="3"&gt;Executing an OS command with Java&lt;/font&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With the Java approach, you will take these steps:&lt;/p&gt;
&lt;/div&gt;
&lt;ol&gt;
    &lt;li&gt;Find the Java class that implements host command execution.&lt;/li&gt;
    &lt;li&gt;Build a class that invokes that host command method. Let's call it HostCommand.&lt;/li&gt;
    &lt;li&gt;Build a PL/SQL program that calls a method in HostCommand to run your command.&lt;/li&gt;
    &lt;li&gt;Acquire the privileges needed to execute host commands via Java in the database.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let's go through each of these steps.&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;&lt;strong&gt;Find the Java class that implements host command execution.&lt;/strong&gt;&lt;br /&gt;
    &lt;br /&gt;
    Objects of the java&lt;strong&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;lang&lt;strong&gt;.&lt;/strong&gt;Runtime&lt;/span&gt; class include an &lt;em&gt;exec&lt;/em&gt; method that will execute a host command.&lt;br /&gt;
     &lt;/strong&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Build a class that invokes that host command method. Let's call it HostCommand.&lt;/strong&gt;&lt;br /&gt;
    &lt;br /&gt;
    Here's code to create a new Java class in the database to invoke this command for the Windows XP operating system:&lt;br /&gt;
    &lt;br /&gt;
    &lt;font face="Courier New"&gt;&lt;font color="#0000ff"&gt;CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED&lt;/font&gt; &lt;font color="#ff0000"&gt;"UTLcmd"&lt;/font&gt;&lt;br /&gt;
    &lt;font color="#0000ff"&gt;AS&lt;/font&gt; import java.lang.Runtime;&lt;br /&gt;
    &lt;/font&gt;&lt;font face="Courier New"&gt;&lt;br /&gt;
    public class execHostCommand&lt;br /&gt;
    { &lt;br /&gt;
      public static void execute (String command) &lt;br /&gt;
        throws java.io.IOException&lt;br /&gt;
      {&lt;br /&gt;
       String osName = System.getProperty("&lt;font color="#0000ff"&gt;os.name&lt;/font&gt;");&lt;br /&gt;
       if(osName.equals("&lt;font color="#0000ff"&gt;Windows XP&lt;/font&gt;"))&lt;br /&gt;
           command = "&lt;font color="#0000ff"&gt;cmd /c&lt;/font&gt; " + command;&lt;br /&gt;
       Runtime rt = java.lang.Runtime.getRuntime();&lt;br /&gt;
       rt.exec(command);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    /&lt;br /&gt;
    &lt;/font&gt;&lt;br /&gt;
    You can easily modify the execute method to support other operating systems based on the value of osName.&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Build a PL/SQL program that calls a method in HostCommand to run your command.&lt;br /&gt;
    &lt;/strong&gt;&lt;font size="2" face="Courier New"&gt;&lt;br /&gt;
    CREATE OR REPLACE PACKAGE host_command IS&lt;br /&gt;
    &lt;/font&gt;&lt;font size="2" face="Courier New"&gt;  PROCEDURE execute (cmd IN VARCHAR2) AS LANGUAGE JAVA NAME&lt;br /&gt;
    &lt;/font&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span&gt;           &lt;/span&gt;'execHostCommand.execute(java.lang.String)';&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Courier New"&gt;END;&lt;br /&gt;
    &lt;/font&gt;&lt;font size="2" face="Courier New"&gt;/&lt;br /&gt;
    &lt;/font&gt; &lt;br /&gt;
    Notice that I "map" the VARCHAR2 datatype to the java.lang.String class in my call to the new Java method.&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Acquire the privileges needed to execute host commands via Java in the database.&lt;br /&gt;
    &lt;/strong&gt; &lt;br /&gt;
    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):&lt;br /&gt;
     &lt;br /&gt;
    &lt;img alt="" width="456" height="183" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog032709-1.gif" /&gt;&lt;br /&gt;
     &lt;br /&gt;
    One way to obtain these privileges to have the JAVASYSPRIV role granted to your schema. This role contains all the privileges you need (and more).&lt;br /&gt;
     &lt;br /&gt;
    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:&lt;br /&gt;
    &lt;font size="2"&gt;&lt;br /&gt;
    &lt;font face="Courier New"&gt;BEGIN&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span&gt;   &lt;/span&gt;DBMS_JAVA.grant_permission ('HR'&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span&gt;                             &lt;/span&gt;, 'SYS:java.io.FilePermission'&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span&gt;                             &lt;/span&gt;, '&lt;&lt;all files=""&gt;&lt;/all&gt;&gt;'&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span&gt;                             &lt;/span&gt;, 'execute'&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span&gt;                              &lt;/span&gt;);&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span&gt;   &lt;/span&gt;DBMS_JAVA.grant_permission ('HR'&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span&gt;                             &lt;/span&gt;, 'SYS:java.lang.RuntimePermission'&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span&gt;                             &lt;/span&gt;, 'writeFileDescriptor'&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span&gt;                             &lt;/span&gt;, ''&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span&gt;                              &lt;/span&gt;);&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span&gt;   &lt;/span&gt;DBMS_JAVA.grant_permission ('HR'&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span&gt;                             &lt;/span&gt;, 'SYS:java.lang.RuntimePermission'&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span&gt;                             &lt;/span&gt;, 'readFileDescriptor'&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span&gt;                             &lt;/span&gt;, ''&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span&gt;                              &lt;/span&gt;);&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Courier New"&gt;END;&lt;br /&gt;
    &lt;/font&gt;&lt;font size="2" face="Courier New"&gt;/&lt;/font&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;font size="3"&gt;Executing an OS command with C&lt;/font&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To use C, you must define an &lt;em&gt;external procedure&lt;/em&gt; 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, check out Oracle documentation at:&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;div&gt;&lt;a href="http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14251/adfns_extern_proc.htm#ADFNS010"&gt;http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14251/adfns_extern_proc.htm#ADFNS010&lt;/a&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;p&gt;and also read Chapter 27 of Oracle PL/SQL Programming, 4&lt;sup&gt;th&lt;/sup&gt; edition, in which my co-author Bill Pribyl thoroughly explains external procedures.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;As with Java, you will need help your database administrator to supply the privileges needed to execute your host command in C.&lt;/p&gt;
&lt;p&gt;Here are the steps to follow with C:&lt;/p&gt;
&lt;/div&gt;
&lt;ol&gt;
    &lt;li&gt;Find (or build) the C program that implements host command execution.&lt;/li&gt;
    &lt;li&gt;Save the C source to a file and generate a shared library for it.&lt;/li&gt;
    &lt;li&gt;Save the library file where Oracle can find it.&lt;/li&gt;
    &lt;li&gt;Define a library inside Oracle that is associated with the shared library on disk.&lt;/li&gt;
    &lt;li&gt;Create a PL/SQL wrapper for the C function.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let's go through each of these steps.&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;&lt;strong&gt;Find (or build) the C program that implements host command execution.&lt;/strong&gt;&lt;br /&gt;
     &lt;br /&gt;
    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 &lt;span&gt;&lt;font color="#ff0000"&gt;system&lt;/font&gt;&lt;/span&gt; function for execution:&lt;br /&gt;
    &lt;font size="2"&gt; &lt;br /&gt;
    &lt;font face="Courier New"&gt;int extprocsh(char *cmd)&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Courier New"&gt;{&lt;br /&gt;
    &lt;/font&gt;&lt;font size="2" face="Courier New"&gt;   return system(cmd);&lt;br /&gt;
    &lt;/font&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;}&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt; &lt;br /&gt;
    The function returns the result code as provided by &lt;span&gt;&lt;font color="#ff0000"&gt;system&lt;/font&gt;&lt;/span&gt;, a function normally found in the C runtime library (&lt;span&gt;&lt;em&gt;&lt;font color="#ff0000"&gt;libc&lt;/font&gt;&lt;/em&gt;&lt;/span&gt;) on Unix, or in &lt;span&gt;&lt;em&gt;&lt;font color="#ff0000"&gt;msvcrt.dll&lt;/font&gt;&lt;/em&gt;&lt;/span&gt; on Microsoft platforms.&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Save the C source to a file and generate a shared library for it.&lt;br /&gt;
    &lt;/strong&gt; &lt;br /&gt;
    I save the source code in a file named &lt;span&gt;&lt;em&gt;&lt;font color="#ff0000"&gt;extprocsh.c&lt;/font&gt;&lt;/em&gt;&lt;/span&gt;. 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:&lt;br /&gt;
    &lt;font size="2"&gt; &lt;br /&gt;
    &lt;font face="Courier New"&gt;gcc -m64 extprocsh.c -fPIC -G -o extprocsh.so&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt; &lt;br /&gt;
    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:&lt;br /&gt;
    &lt;font size="2"&gt; &lt;br /&gt;
    &lt;font face="Courier New"&gt;c:\MinGW\bin\gcc extprocsh.c -shared -o extprocsh.dll&lt;br /&gt;
     &lt;/font&gt;&lt;/font&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Save the library file where Oracle can find it.&lt;br /&gt;
    &lt;/strong&gt; &lt;br /&gt;
    These commands generate a shared library file, &lt;span&gt;&lt;em&gt;&lt;font color="#ff0000"&gt;extprocsh.so&lt;/font&gt;&lt;/em&gt;&lt;/span&gt; or &lt;span&gt;&lt;em&gt;&lt;font color="#ff0000"&gt;extprocsh.dll&lt;/font&gt;&lt;/em&gt;&lt;/span&gt;. Now I need to put the library file somewhere that Oracle can find it. The default locations for Windows and Unix respectively are:&lt;br /&gt;
    &lt;span&gt;&lt;font size="2"&gt;&lt;font color="#ff6600"&gt;&lt;em&gt; &lt;br /&gt;
    &lt;font color="#ff0000" face="Courier New"&gt;$ORACLE_HOME/bin&lt;br /&gt;
    &lt;/font&gt;&lt;/em&gt;&lt;/font&gt;&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;em&gt;&lt;font size="2"&gt;&lt;font color="#ff0000" face="Courier New"&gt;$ORACLE_HOME/lib&lt;br /&gt;
    &lt;/font&gt;&lt;/font&gt;&lt;/em&gt;&lt;/span&gt; &lt;br /&gt;
    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...".&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Define a library inside Oracle that is associated with the shared library on disk.&lt;br /&gt;
    &lt;/strong&gt; &lt;br /&gt;
    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:&lt;br /&gt;
    &lt;font size="2" face="Courier New"&gt; &lt;br /&gt;
    CREATE OR REPLACE LIBRARY extprocshell_lib &lt;br /&gt;
    &lt;/font&gt;&lt;font size="2" face="Courier New"&gt;   AS '/u01/app/oracle/local/lib/extprocsh.so';   &lt;font color="#009933"&gt;&lt;strong&gt;-- Unix&lt;br /&gt;
    &lt;/strong&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2" face="Courier New"&gt;     &lt;br /&gt;
    &lt;/font&gt;&lt;font size="2" face="Courier New"&gt;CREATE OR REPLACE LIBRARY extprocshell_lib&lt;br /&gt;
    &lt;/font&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;   AS 'c:\oracle\local\lib\extprocsh.dll';      &lt;font color="#009933"&gt;&lt;strong&gt;-- Microsoft&lt;br /&gt;
    &lt;/strong&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt; &lt;br /&gt;
    &lt;strong&gt;Note:&lt;/strong&gt; performing this step requires Oracle’s CREATE LIBRARY privilege.&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Create a PL/SQL wrapper for the C function.&lt;br /&gt;
    &lt;/strong&gt; &lt;br /&gt;
    Now I can create a PL/SQL call specification which uses the newly created library:&lt;br /&gt;
    &lt;font size="2" face="Courier New"&gt; &lt;br /&gt;
    CREATE OR REPLACE FUNCTION exec_host_command (cmd IN VARCHAR2)&lt;br /&gt;
    &lt;/font&gt;&lt;font size="2" face="Courier New"&gt;   RETURN PLS_INTEGER&lt;br /&gt;
    &lt;/font&gt;&lt;font size="2" face="Courier New"&gt;AS&lt;br /&gt;
    &lt;/font&gt;&lt;font size="2" face="Courier New"&gt;   LANGUAGE C&lt;br /&gt;
    &lt;/font&gt;&lt;font size="2" face="Courier New"&gt;   LIBRARY extprocshell_lib&lt;br /&gt;
    &lt;/font&gt;&lt;font size="2" face="Courier New"&gt;   NAME "extprocsh"&lt;br /&gt;
    &lt;/font&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;   PARAMETERS (cmd STRING, RETURN INT);&lt;/font&gt;&lt;/font&gt;
    &lt;p&gt;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. &lt;/p&gt;
    &lt;p&gt;Note that these operating system commands will execute with the same privileges as the Oracle Net listener that spawns the &lt;span&gt;&lt;em&gt;&lt;font color="#ff0000"&gt;extproc&lt;/font&gt;&lt;/em&gt;&lt;/span&gt; process. &lt;br /&gt;
     &lt;/p&gt;
    &lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt; &lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/356/Run-an-OS-command-from-within-PL-SQL.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,os command&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/356/Run-an-OS-command-from-within-PL-SQL.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/356/Run-an-OS-command-from-within-PL-SQL.aspx</guid>
      <pubDate>Fri, 27 Mar 2009 13:14:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=356</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/53/Default.aspx">os command</blog:tag>
    </item>
    <item>
      <title>Automatic refactoring in PL/SQL tools – Part 3</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/346/Automatic-refactoring-in-PL-SQL-tools-Part-3.aspx</link>
      <description>&lt;div&gt;In &lt;a href="http://www.toadworld.com/Default.aspx?tabid=67&amp;EntryID=321"&gt;part 1&lt;/a&gt; of this series, I reviewed the automated refactoring features in SQL Developer. In &lt;a href="http://www.toadworld.com/Default.aspx?tabid=67&amp;EntryID=328"&gt;part 2&lt;/a&gt;, I checked out PL/SQL Developer's refactoring features. Now, it's time for Toad.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Differently from both PL/SQL Developer and SQL Developer, Toad does not have a separate Refactoring right click menu. Instead, the main (and most important) refactoring is explicitly visible from the right click menu in the editor: Extract Procedure.&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;&lt;img alt="" width="713" height="660" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog030909-1.gif" /&gt;&lt;/p&gt;
&lt;p&gt;Let's dive right in and explore this feature. When I select Extract procedure...., I see the following window:&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog030909-2.gif" /&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;When I choose the default (and check the "With replace option" – which I would argue should be checked by default), Toad then opens another tab in my editor and fills it with this:&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog030909-3.gif" /&gt;&lt;/p&gt;
&lt;p&gt;It did not automatically compile the procedure for me, which I actually like. I'd rather be responsible for the act of compiling - and perhaps over-writing an existing procedure of the same name, which in fact would have occurred here, as you can see from my list of existing procedures:&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog030909-4.gif" /&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The extraction was smart; I ended up with a procedure that has two formal parameters, ensuring that it is completely independent of the original context (the use_cursor procedure). That original procedure is also changed appropriately:&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog030909-5.gif" /&gt;&lt;/p&gt;
&lt;p&gt;If I choose the "local procedure" option, then Toad correctly creates a local subprogram for me:&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog030909-6.gif" /&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;  a very handy and competent refactoring. It performs correctly under all tested circumstances (PL/SQL Developer had a number of bugs, which I have been told is fixed in a later release than I used). My suggestions for improvement? Let me specify that I want the stored program to be not schema-level, but inside a package. And if I could choose an existing package to put it &lt;em&gt;into&lt;/em&gt;, well, that would be fantastic! I could cut down on the number of independent stored program units (I try to avoid schema-level functions and procedures whenever possible), and increase the likelihood of code re-use.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;That is the only truly automatic refactoring feature in Toad, at least from my perspective. But for the sake of performing a true apples-to-apples comparison, you may recall that SQL Developer offers these options on its refactoring menu:&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog030909-7.gif" /&gt;&lt;/p&gt;
&lt;p&gt;I don't really consider case conversion to be refactoring, but in case you do, you can certainly do that in Toad, either under the Edit menu in Toad or  on Editor toolbar (or you can simply use the keyboard shortcuts):&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog030909-8.gif" /&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Toad doesn't offer any kind of rename feature, as does SQL Developer and PL/SQL Developer, but both of those implementations were a bit hobbled in how they worked. I doubt they are used much on a day to day basis.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;font size="3"&gt;Overall Conclusion&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;All three tools examined (Toad, SQL Developer and PL/SQL Developer) offer competent Extract Procedure functionality, though at least in the versions I used, Toad had the fewest drawbacks in its implementation. Beyond that, Toad has fewer explicit refactoring features than PL/SQL Developer. My feeling, however, is that outside of Extract Procedure, the refactorings are minor and of limited importance.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I hope that with the introduction of PL/Scope and ALL_IDENTIFIERS in Oracle11g, we will see a major step forward by all IDE vendors as regards refactoring and code analysis.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/346/Automatic-refactoring-in-PL-SQL-tools-Part-3.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,refactoring&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/1/Default.aspx&gt;Toad for Oracle&lt;/a&gt;&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/1/Default.aspx">Toad for Oracle</category>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/346/Automatic-refactoring-in-PL-SQL-tools-Part-3.aspx#Comments</comments>
      <slash:comments>1</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/346/Automatic-refactoring-in-PL-SQL-tools-Part-3.aspx</guid>
      <pubDate>Mon, 09 Mar 2009 15:18:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=346</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/79/Default.aspx">refactoring</blog:tag>
    </item>
    <item>
      <title>Automatic refactoring in PL/SQL tools – Part 2</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/328/Automatic-refactoring-in-PL-SQL-tools-Part-2.aspx</link>
      <description>&lt;div&gt;In &lt;a href="http://www.toadworld.com/Default.aspx?tabid=67&amp;EntryID=321"&gt;part 1 of this series&lt;/a&gt;, I reviewed the automated refactoring features in SQL Developer. Now I will check out PL/SQL Developer (version 7.1.5)'s refactoring features.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;To access these features, I highlight some code in a procedure edit window and then choose Refactoring from the right click menu. I see these options:&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;img alt="" width="432" height="134" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-1.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I explore each of these below.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;&lt;font size="3"&gt;Rename item&lt;/font&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;If I highlight the name of identifier in its declaration section, the Rename item option is enabled:&lt;/div&gt;
&lt;div&gt; &lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-2.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I specified "abc" as the new name for this variable and PL/SQL Developer correctly substituted all instances of that identifier:&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-3.gif" /&gt; &lt;/div&gt;
&lt;div&gt; &lt;br /&gt;
What if I have another variable with the same name in a different scope? PL/SQL Developer does a nice job of recognizing that it should not change it:&lt;/div&gt;
&lt;div&gt; &lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-4.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Sadly, it's not yet working at genius level. If I include in the subprogram a reference to the outer l_cursor variable, it does not change that name:&lt;br /&gt;
&lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-5.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;  Works quite well, though it would be nice if I could highlight an identifier name anywhere in the program and have it do a rename (not only in the declaration statement for that variable). Could be a bit smarter, but for most "normal" scenarios, it should be fine.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;&lt;font size="3"&gt;Extract procedure&lt;/font&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;This is one of the most important refactorings: take logic out of your executable section and "hide" it inside a local procedure – or in a schema-level procedure. So I highlighted a line of code and choose this option. I was then asked to provide the new procedure name:&lt;br /&gt;
&lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-6.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;After providing that name and pressing OK, I see the following:&lt;br /&gt;
&lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-7.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Well...that didn't go very well. Notice that it grabbed a part of the next line (DBMS_SQL.PARSE), even though I didn't highlight it. Ugh. OK, I will do it again, with just the code from that single open_cursor line. The result looks much better; notice that the tool correctly extracted all local variables and arguments referenced in the code and now passes them in as arguments:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-8.gif" /&gt;&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;There is one big problem, however: the code will not compile, because the subprogram was inserted &lt;em&gt;before&lt;/em&gt; the l_cursor declaration and that is invalid:&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-9.gif" /&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Here's a nice touch, though: if your highlighted code references local variable that are used &lt;em&gt;only&lt;/em&gt; in that highlighted code, PL/SQL Developer will move the declaration for that variable out of the main program and into the local module. In other words, from this:&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-10.gif" /&gt; &lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;to:&lt;br /&gt;
&lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-11.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;  Disappointing overall. It's got the right idea and has been pretty-well thought through, but has at least two fairly serious flaws. Also, SQL Developer offers the option to define locally or store as a separate subprogram, which PL/SQL Dev does not.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;&lt;font size="3"&gt;Extract local constant&lt;/font&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;Here's what the help doc says about this one:&lt;br /&gt;
&lt;br /&gt;
"If a certain expression should be converted to a local constant, you can select it and provide the constant name. A local constant will be created within the current subprogram, of a type that is determined from the expression. All occurrences of the expression in the current subprogram will be replaced by the constant name."&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;All righty – let's try it out. I will create a constant for the call to the open_cursor function:&lt;br /&gt;
&lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-12.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;And the result:&lt;br /&gt;
&lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-13.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;PL/SQL Dev did a good job of &lt;em&gt;not&lt;/em&gt; including the ; from the highlighted text in the value assigned to the constant. It correctly replaced the call to the function with the named constant. It did &lt;em&gt;not&lt;/em&gt;, however, come up with the right datatype for the constant. Instead, it seems to have simply added up the number of characters in the selected text. That's just weird!&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Next I will highlight the local variable and change it to a constant:&lt;/div&gt;
&lt;div&gt; &lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-14.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The result is not great:&lt;br /&gt;
&lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-15.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;It seems to me that it should have left the original declaration of l_cursor alone. The result is code that will not compile.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;  marginally useful refactoring.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;&lt;font size="3"&gt;Extract global constant&lt;/font&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;PL/SQL Dev help tells us the following about this feature:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;"If a certain expression should be converted to a global constant, you can select it and provide the constant name. A global constant will be created within the current package, of a type that is determined from the expression. All occurrences of the expression in the current package will be replaced by the constant name."&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So what does this do? Well, if I use it inside my procedure, it acts the same as with a local constant extraction. I would have thought it should prompt me for the package name and either move the variable to that package or create a new package with that name.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Next I tried in a package:&lt;br /&gt;
&lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-16.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;and it did the right thing, sort of:&lt;br /&gt;
&lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-17.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;It still does not work properly with datatypes, though. It just defines them as VARCHAR2 all the time.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;  same as for local constant....minimally useful.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;&lt;font size="3"&gt;Swap assignment&lt;/font&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;A very minor "refactoring". Use it to change an assignment of this form:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;a := b;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;to&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;b := a;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;It's fairly smart. You don't have to highlight the entire assignment statement, just a part of it, and PL/SQL Dev will move everything on the right to the left.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;  not really a refactoring, but it could be a useful accelerator on occasion.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;&lt;font size="3"&gt;Replace assignment with initialization&lt;/font&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;The help doc says:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;"If a local variable assignment is purely for initialization, you can move it to the declaration of the variable. You can right-click on a statement or select multiple statements."&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So I started with this code:&lt;/div&gt;
&lt;div&gt; &lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-18.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;When I clicked on the variable name, the identifiers lit up:&lt;br /&gt;
&lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-19.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I then chose my refactoring option&lt;/div&gt;
&lt;div&gt; &lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-20.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;and ended up with this:&lt;br /&gt;
&lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog010509-21.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;That's nice...though I have one concern and one desire:&lt;/div&gt;
&lt;ul type="disc"&gt;
    &lt;li&gt;Concern: the change is valid, but it could cause problems. When an exception raised in the declaration section, it cannot be handled within that block's exception section. The exception &lt;em&gt;always &lt;/em&gt;propagates unhandled to the outer block. So making this change could affect program behavior. &lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;Desire: This would be even nicer if it was combined with the option to move the assignment to an initialization &lt;em&gt;procedure&lt;/em&gt; not simply to the declaration statement.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;  mildly useful, but sometimes &lt;em&gt;not desireable&lt;/em&gt; due to the way exception propagation works in PL/SQL.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;&lt;font size="3"&gt;Overall Conclusion&lt;/font&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;Refactoring in PL/SQL Developer is minimal, but useful. It's done in a fairly smart way. Now if they would only give me a key stroke to pop up the refactoring menu, rather than having to make my way down through two levels of right click menu options.&lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/328/Automatic-refactoring-in-PL-SQL-tools-Part-2.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,refactoring&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/328/Automatic-refactoring-in-PL-SQL-tools-Part-2.aspx#Comments</comments>
      <slash:comments>1</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/328/Automatic-refactoring-in-PL-SQL-tools-Part-2.aspx</guid>
      <pubDate>Tue, 06 Jan 2009 16:30:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=328</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/79/Default.aspx">refactoring</blog:tag>
    </item>
    <item>
      <title>Automatic refactoring in PL/SQL tools – Part 1  </title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/321/Automatic-refactoring-in-PL-SQL-tools-Part-1.aspx</link>
      <description>&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div&gt;I have long been attracted to the idea and process of refactoring (explained below). It is now very exciting to see that automated refactoring features are working their way into tools for PL/SQL development. I will analyze these features over the next few entries in my ToadWorld blog, starting with SQL Developer and then moving on to PL/SQL Developer, and finishing up with SQL Navigator and Toad.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Oracle recently released Version 1.5.1 of SQL Developer, its free development tool for PL/SQL developers. I have been watching SQL Developer since Oracle first brought it into the world, seeing as (a) I am obsessed with PL/SQL; and (b) Oracle has had a checkered history when it comes to producing decent development tools for us PL/SQL developers; and (c) I work for Quest Software and of course we are keen to see how SQL Developer stacks up with Toad and SQL Navigator.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;My overall assessment of SQL Developer has been: it's a fine, clean, light development environment – with lots of room for growth and catching up. That is, for a free product that is relatively new, it is a nice effort. Not too surprising, since it leverages the JDeveloper framework, into which Oracle has invested lots and lots of resources.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Would I use it instead of Toad or SQL Navigator or a number of the other tools that have been out there for awhile? Not unless my budget consisted of $0 for PL/SQL development tools. As with any piece of software, it will take time for SQL Developer to mature and fill out its feature set.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The SQL Developer team is certainly not standing still, however, and with Version 1.5, they have added several new features. One feature that caught my eye in particular was support for automated refactoring.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;" Refactoring? What's that?" some of you may be wondering. You can see lots of information at &lt;a href="http://www.refactoring.com/"&gt;&lt;font color="#000000"&gt;http://www.refactoring.com/&lt;/font&gt;&lt;/a&gt;, but briefly (and from that site):&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;" Refactoring is a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior. Its heart is a series of small behavior preserving transformations. Each transformation (called a 'refactoring') does little, but a sequence of transformations can produce a significant restructuring. Since each refactoring is small, it's less likely to go wrong. The system is also kept fully working after each small refactoring, reducing the chances that a system can get seriously broken during the restructuring."&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The bottom line is that it is a highly structured methodology for going through clearly defined steps (each ideally verified by a pre-defined regression test) to make your code more maintainable.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;em&gt;Automated&lt;/em&gt; refactoring is a process that applies well-established and accepted refactorings automatically to your code. IDEs for object oriented languages have offered automated refactorings, albeit very simple ones, for a while. Now, SQL Developer offers this capability.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Exciting! So I decided to take a look. After installing SQL Developer 1.5, I opened up a program definition in an editor window, highlighted some code and checked out the right click menu. There it is!&lt;/div&gt;
&lt;p align="center"&gt;&lt;img alt="" width="498" height="103" src="http://www.toadworld.com/Portals/0/blogimages/Steven%20Feuerstein/SF-Blog120908-1.gif" /&gt; &lt;/p&gt;
&lt;div&gt;Interesting....but what are they? I dipped into Help just to see what I could find about these and found....very little. Just a window on Extract Procedure. So let's start with that first. SQL Developer tells me:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;"This dialog box is displayed if you are editing a procedure, select one or more PL/SQL statements, right-click, and select Refactoring, then Extract Procedure. The selected statements are encapsulated into the procedure to be created.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;"Defined Locally: For a standalone procedure, defines the newly refactored code in the definition section of the original procedure.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;"Stored: For a standalone procedure, defines the newly refactored code in a new standalone procedure.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;"Name: Name of the procedure to encapsulate the selected statements. For a packaged procedure, the newly extracted procedure text is placed immediately after the current procedure."&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Now, I &lt;em&gt;really&lt;/em&gt; like this. I do. I believe that encapsulation or information hiding is one of the most important factors in writing maintainable code. And I believe in particular that we should make extensive use of locally-declared modules to do this.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So I highlight the line of code I want to encapsulate (the open cursor statement). I then, for starters, ask to create it as a schema-level procedure: &lt;/div&gt;
&lt;p align="center"&gt;&lt;img alt="" src="http://www.toadworld.com/Portals/0/blogimages/Steven%20Feuerstein/SF-Blog120908-2.gif" /&gt; &lt;/p&gt;
&lt;div&gt;Type in the name, press OK, and I see this:&lt;/div&gt;
&lt;p align="center"&gt;&lt;img alt="" src="http://www.toadworld.com/Portals/0/blogimages/Steven%20Feuerstein/SF-Blog120908-3.gif" /&gt; &lt;/p&gt;
&lt;div&gt;So far...OK, but just OK. Notice that it does not recognize that my line of code references a parameter from the main program. It would seem to me that the refactoring process should automatically create an argument for this procedure. This code isn't even valid. But I press Yes, and the box goes away, fine, but then I see that the original code is still present in my procedure:&lt;/div&gt;
&lt;p align="center"&gt;&lt;img alt="" src="http://www.toadworld.com/Portals/0/blogimages/Steven%20Feuerstein/SF-Blog120908-4.gif" /&gt; &lt;/p&gt;
&lt;div&gt;That's no good – I wanted to replace it with the new stored procedure. I check the browser and find that this procedure has not been created in my schema:&lt;/div&gt;
&lt;p align="center"&gt;&lt;img alt="" src="http://www.toadworld.com/Portals/0/blogimages/Steven%20Feuerstein/SF-Blog120908-5.gif" /&gt; &lt;/p&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Now maybe that's because there was an error in the code (un-declared referenced to security_level_in), but I didn't get any notification. OK, I will try it again with code that &lt;em&gt;will&lt;/em&gt; compile, but still I see nothing. Well, I have no idea what is going on here, but really what I want to do is create a local module, so let's try that.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I highlight the code, choose my refactoring option, choose Local:&lt;/div&gt;
&lt;p align="center"&gt;&lt;img alt="" src="http://www.toadworld.com/Portals/0/blogimages/Steven%20Feuerstein/SF-Blog120908-6.gif" /&gt; &lt;/p&gt;
&lt;div&gt;I type in the name of my new local module and press OK. I then see this:&lt;/div&gt;
&lt;p align="center"&gt;&lt;img alt="" src="http://www.toadworld.com/Portals/0/blogimages/Steven%20Feuerstein/SF-Blog120908-7.gif" /&gt;&lt;/p&gt;
&lt;div&gt;Ugh. That's no good. It's supposed to be a &lt;em&gt;local&lt;/em&gt; module. SQL Developer has placed this code &lt;em&gt;above and outside&lt;/em&gt; of the use_cursor procedure. I then have to move it inside to make it work.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Bottom line, SQL Developer developers: nice idea, but your implementation leaves much to be desired. I don't see how I can use this to help me develop more modular, maintainable code any more easily than if I cut and paste myself.&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Let's check out the other refactoring options. "Rename Local Variable..."&lt;/p&gt;
&lt;/div&gt;
&lt;p align="center"&gt;&lt;img alt="" src="http://www.toadworld.com/Portals/0/blogimages/Steven%20Feuerstein/SF-Blog120908-8.gif" /&gt;&lt;/p&gt;
&lt;div&gt;Hey, I like the sound of that! All too often we come up initially (in the heat of development) with bad variable names like "d" or "l_integer." Yuch! So the ability to be able to provide a new name and have the product sweep through my code and replace all instances...well, that would be pretty darned cool. Let's give it a try; in the program below I reference l_cursor four times:&lt;/div&gt;
&lt;p align="center"&gt;&lt;img alt="" src="http://www.toadworld.com/Portals/0/blogimages/Steven%20Feuerstein/SF-Blog120908-9.gif" /&gt;&lt;/p&gt;
&lt;div&gt;There's no help for this feature, so I figure I will highlight the variable name and then specify a new one that indicates that this is a dynamic cursor:&lt;/div&gt;
&lt;p align="center"&gt;&lt;img alt="" src="http://www.toadworld.com/Portals/0/blogimages/Steven%20Feuerstein/SF-Blog120908-10.gif" /&gt;&lt;/p&gt;
&lt;div&gt;Press OK, and it worked very nicely:&lt;/div&gt;
&lt;p align="center"&gt;&lt;img alt="" src="http://www.toadworld.com/Portals/0/blogimages/Steven%20Feuerstein/SF-Blog120908-11.gif" /&gt;&lt;/p&gt;
&lt;div&gt;Excellent! Now I will add a reference to a package variable with the same name:&lt;/div&gt;
&lt;p align="center"&gt;&lt;img alt="" src="http://www.toadworld.com/Portals/0/blogimages/Steven%20Feuerstein/SF-Blog120908-12.gif" /&gt;&lt;/p&gt;
&lt;div&gt;and try to do another renaming. This last addition should &lt;em&gt;not &lt;/em&gt; be changed, as it is &lt;em&gt;not &lt;/em&gt;the local variable. OK, I highlight the variable inside the code and try to change it, but I get this message:&lt;/div&gt;
&lt;p align="center"&gt;&lt;img alt="" src="http://www.toadworld.com/Portals/0/blogimages/Steven%20Feuerstein/SF-Blog120908-13.gif" /&gt;&lt;/p&gt;
&lt;div&gt;Hmmm. I guess I need to highlight the declaration itself, though that shouldn't be necessary. OK, I do that, ask to rename variables to abc and sadly I see this:&lt;/div&gt;
&lt;p align="center"&gt;&lt;img alt="" src="http://www.toadworld.com/Portals/0/blogimages/Steven%20Feuerstein/SF-Blog120908-14.gif" /&gt;&lt;/p&gt;
&lt;div&gt;So the rename feature is nice enough, but if it is not &lt;em&gt;scope-aware&lt;/em&gt; (that is, if it cannot distinguish between locals, globals and even program names – yes, in another test, it even replaced the name of a &lt;em&gt;packaged&lt;/em&gt; &lt;em&gt;program&lt;/em&gt; that happened to have the same name as the local variable), then it really isn't doing anything better than a search and replace.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;It also lets me change the variable name to something that is &lt;em&gt;not&lt;/em&gt; a valid identifier, such as 123. If this feature is really directed at changing variable names, it should be aware of the rules and at a minimum put invalid names inside double quotes.&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Finally, I tried to change a local variable's name from abc to something with about 100 characters in it and got this message:&lt;/p&gt;
&lt;/div&gt;
&lt;p align="center"&gt;&lt;img alt="" src="http://www.toadworld.com/Portals/0/blogimages/Steven%20Feuerstein/SF-Blog120908-15.gif" /&gt;&lt;/p&gt;
&lt;div&gt;Not sure what this means, but it certainly isn't helpful.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So I have to rate this feature a marketing-inflated misnomer. Sorry, SQL Developer developers!&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;And the third refactoring:&lt;/p&gt;
&lt;/div&gt;
&lt;p align="center"&gt;&lt;img alt="" src="http://www.toadworld.com/Portals/0/blogimages/Steven%20Feuerstein/SF-Blog120908-16.gif" /&gt;&lt;/p&gt;
&lt;p align="left"&gt;This lets you toggle between different case formats. It seems to work well enough. Honestly, however, I believe that it is not appropriate to include something like this under the Refactoring banner. It is a simple key driven formatting feature.&lt;/p&gt;
&lt;div&gt;In conclusion, I am very pleased that the SQL Developer has introduced automated refactoring to the PL/SQL community. This is a concept and capability which is badly needed. The implementation in Version 1.5, however, leaves much to be desired.&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Next/soon, I will take a look at PL/SQL Developer's refactoring capabilities.&lt;/p&gt;
&lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/321/Automatic-refactoring-in-PL-SQL-tools-Part-1.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,refactoring&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/321/Automatic-refactoring-in-PL-SQL-tools-Part-1.aspx#Comments</comments>
      <slash:comments>1</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/321/Automatic-refactoring-in-PL-SQL-tools-Part-1.aspx</guid>
      <pubDate>Tue, 09 Dec 2008 19:23:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=321</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/79/Default.aspx">refactoring</blog:tag>
    </item>
    <item>
      <title>Congratulations to the newest Oracle Magazine PL/SQL Developer of the Year!</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/305/Congratulations-to-the-newest-Oracle-Magazine-PL-SQL-Developer-of-the-Year.aspx</link>
      <description>&lt;div&gt;As I travel certain parts of the globe doing presentations on PL/SQL, I meet many extremely talented PL/SQL programmers – people who meet the most complex challenges you can imagine with a deft combination of intense creativity, hard work, and of course Oracle PL/SQL.&lt;/div&gt;
&lt;p&gt;Oracle Magazine names only one as the PL/SQL Developer of the Year at each Oracle Open World, and this year the award was given to Alex De Vergori of Betfair.  Oracle Magazine &lt;a href="http://www.oracle.com/technology/oramag/oracle/08-nov/o68awards.html#devergori"&gt;writes&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;p&gt;&lt;strong&gt;Developer works with 250,000 lines of PL/SQL code that deliver success.&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;Successful PL/SQL developers require more than just good technical knowledge, according to Alex De Vergori, Oracle Magazine’s PL/SQL Developer of the Year. &lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;“They also need fine attention to detail, a passion about what they’re doing, and a high degree of pride in the software that they’re producing,” says De Vergori, a database architect who channels those skills at Betfair, an online gaming company that pioneered the concept of betting exchanges in 2000. &lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;To manage customers’ bets, De Vergori and the Betfair team have created a core betting engine and business logic that encompass more than 250,000 lines of PL/SQL code. The Betfair solution runs on Oracle Database using distributed databases around the world and an Oracle data warehouse running Oracle Real Application Clusters. Betfair also uses Oracle Coherence for its in-memory distributed data caching requirements, Java for its middle tier, and Ajax for its front-end applications. &lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;“We take in excess of five million transactions a day, and they all go straight through to the database, where those bets match with other transactions in real time,” says De Vergori. “At peak, we can easily see something like 1,000 bet transactions per second. With Oracle, our growth has been exponential, so that has enabled us to succeed in our market.”&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div&gt;Click &lt;a href="http://www.oracle.com/technology/oramag/oracle/08-may/o38developer.html"&gt;here&lt;/a&gt; if you would like to read more details about how Betfair is using PL/SQL.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;Alex, welcome to the "select circle" of PL/SQL Developer of the Year awardees. Now, finally, you understand why you were spending all those long days, nights and weekends writing PL/SQL code!&lt;br /&gt;
 &lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/305/Congratulations-to-the-newest-Oracle-Magazine-PL-SQL-Developer-of-the-Year.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/305/Congratulations-to-the-newest-Oracle-Magazine-PL-SQL-Developer-of-the-Year.aspx#Comments</comments>
      <slash:comments>1</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/305/Congratulations-to-the-newest-Oracle-Magazine-PL-SQL-Developer-of-the-Year.aspx</guid>
      <pubDate>Mon, 03 Nov 2008 15:03:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=305</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
    </item>
    <item>
      <title>Play games to become a better developer!</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/301/Play-games-to-become-a-better-developer.aspx</link>
      <description>&lt;div&gt;&lt;strong&gt;Part 2: The Game of Mastermind&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Software development is one heck of a serious job. It turns out, however, that there are several games you can play to improve the quality of code you write. This is the second of two blog entries that introduce you to two of my favorite brain development and training games: &lt;a href="http://www.toadworld.com/Community/Blogs/tabid/67/EntryID/289/Default.aspx"&gt;Set&lt;/a&gt; and Mastermind.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Play either (preferably both) of these games, and you will write better software.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;[ Note that I do &lt;em&gt;not &lt;/em&gt;include Solitaire in this list. Playing this game will definitely not help you become a better developer, but it will pass the time. ]&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I even encourage you to play these games &lt;em&gt;on company time&lt;/em&gt;, with management approval. It will be a good investment by your employer. Sound crazy? I have been told by a number of my students that their manager did, in fact, agree to do this, and everyone is happy with the results. I will come back to this point at the end of this blog.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So the game featured in this blog is Mastermind. Mastermind has been around for decades, usually played on a small plastic box filled with holes into which pegs of different colors are placed. You can find lots of electronic versions of Mastermind on the Internet. Here's the one I used in my blog:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;a href="http://www.irt.org/games/js/mind/index.htm?b=8&amp;t=8&amp;c=4"&gt;http://www.irt.org/games/js/mind/index.htm?b=8&amp;t=8&amp;c=4&lt;/a&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So how does it work? You have to guess the colors of the pegs in each of the positions, with the smallest possible number of guesses. Each time you make a guess, Mastermind (the electronic version) tells you how close you are by providing clues (when playing with another human being, &lt;em&gt;they &lt;/em&gt;provide the clues – and hopefully they don't make any mistakes).&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;There are two kinds of clues:&lt;/div&gt;
&lt;ul type="disc"&gt;
    &lt;li&gt;You got the color and the position right. Usually this clue is indicated with a black peg.&lt;/li&gt;
    &lt;li&gt;You got the color right, but the position is wrong. Usually this clue is indicated with a white peg.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;When you get four black pegs, you have won that round.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The game is more or less difficult depending on:&lt;/div&gt;
&lt;ul type="disc"&gt;
    &lt;li&gt;the number of positions&lt;/li&gt;
    &lt;li&gt;the number of choices of colors (including or excluding blanks)&lt;/li&gt;
    &lt;li&gt;whether or not you can repeat colors in the solution&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;You could, of course, simply &lt;em&gt;guess &lt;/em&gt;each time, in which case you will be very lucky (and only lucky) to actually ever win. But the point of the game (at least, the way that I understood the point of the game) is to use &lt;em&gt;logic&lt;/em&gt; to narrow down the choices that are valid based on the clues provided.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Let's walk through a game of Mastermind. In this version, we will not allow blanks nor repeated colors. Here's the starting point:&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;img alt="" width="452" height="531" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102808-1.gif" /&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;First try: it's luck and random selection. In other words, one guess is as good as any other (this first turn is the only time at which this statement is valid)....so I will simply choose the first four colors in the order shown in the game.&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102808-2.gif" /&gt; &lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;Then I press OK and Mastermind shows me how close I got. One white clue. &lt;/div&gt;
&lt;div&gt; &lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102808-3.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Not very close! So only one of these colors is in the solution. This is a good start, precisely because there is so little information. Once I figure out which of these colors is in the solution, I know that the other three are &lt;em&gt;not&lt;/em&gt;.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;What shall I do next? Pick the color that I will assume is in the solution, and move it to another location so that, theoretically, it could then result in a black clue.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I will make the smallest possible effort here, and move black over one. I will then use the next three colors on the second row:&lt;/div&gt;
&lt;div&gt; &lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102808-4.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Time to verify my second guess against my first clue. I have only color repeated from the first guess, and it is in a different position. OK, this could be right. Wish me luck....press OK..and:&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102808-5.gif" /&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Not bad at all! Now Mastermind is telling me that two of these four colors are in the solution &lt;em&gt;and&lt;/em&gt; they are in the right place. One other color is also in the solution, but is in the wrong place.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Time to make another guess. Let's assume that red and black are the black clues and white is in the wrong place. We already know that green, brown and purples are not in the solution (if my assumption about black is correct), so what can I use for the fourth color? There is just one left: yellow.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Where should I put the yellow and white? I have already assumed that red and black are in the right positions. So that means that white would have to be in the fourth position (I don't have three black clues), and yellow in the third.&lt;/div&gt;
&lt;div&gt; &lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102808-6.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;This is getting suspenseful! Press OK and....&lt;/div&gt;
&lt;div&gt; &lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102808-7.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Hmmm. I seem to have taken a step backwards. Instead of two black clues, I have just one. OK, it is time now to stop and take stock.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;What can I now conclude about the solution, given these three sets of clues? Quite a lot, namely:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;table border="1" cellspacing="2" cellpadding="2"&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="193"&gt;
            &lt;div&gt;&lt;strong&gt;A fact&lt;/strong&gt;&lt;/div&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="397"&gt;
            &lt;div&gt;&lt;strong&gt;How do I know?&lt;/strong&gt;&lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="193"&gt;
            &lt;div&gt;The white is in the third position or the blue is in the fourth. &lt;/div&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="397"&gt;
            &lt;div&gt;I repeated red and black and lost a black clue. Therefore, one of the two on the right half must have been the source of the black clue.&lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="193"&gt;
            &lt;div&gt;Both black and red cannot be in the solution.&lt;/div&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="397"&gt;
            &lt;div&gt;If black is in the solution, then green, brown and purple are not. If red is also in the solution, then only one of white and blue can be in it. If white is in it, then the fourth clue tells me that yellow cannot be in it. I have now exhausted all the colors and we do not have a &lt;em&gt;fourth&lt;/em&gt; color. That's not possible. So it's either red or black, but not both.&lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="193"&gt;
            &lt;div&gt;White, blue and yellow must be in the solution.&lt;/div&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="397"&gt;
            &lt;div&gt;The second guess has three clues, so three of the four must be in the solution, but only one of red and black can be, so the other two must be. The third guess also has three clues and again, this means that the two that are &lt;em&gt;not&lt;/em&gt; red and black must be in the solution, so yellow must be in it.&lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Now I have enough information to make the smallest numbers of assumptions and produce a solution. If this works, we win. If it doesn't, I will get lots of additional data from which to work (that is, it will show me that an assumption was invalid, forcing me to re-evaluate and take a new path).&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Let's keep going with black in the second position; I haven't yet encountered any reason to think it is not there. That accounts for the one black clue from the second turn. Let's now go with white in the third position. Blue must then be in the first position, and yellow in the fourth.&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102808-8.gif" /&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I then go back and make sure this last guess is consistent with all previous guesses and clues:&lt;/div&gt;
&lt;ul&gt;
    &lt;li&gt;Guess/clue 1: Only black is repeated from the first turn and it is in a different position, so guess 4 could be correct based on this clue.&lt;/li&gt;
    &lt;li&gt;Guess/clue 2: The black and white colors are in the same position and the blue is in a different position, so guess 4 could be correct based on this clue.&lt;/li&gt;
    &lt;li&gt;Guess/clue 3: The black is in the same position, but yellow and white are now in two different positions, and I added in a different color. Guess 4 could be correct based on this clue.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;OK, I have verified that this guess &lt;em&gt;could&lt;/em&gt; be correct. So how did I do? Press OK and....&lt;/div&gt;
&lt;div&gt; &lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102808-9.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I did it!&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Now, that's very satisfying, but I must also stay humble. I was lucky enough to make the correct assumption about black in the very first turn. I could easily have decided to assume that green was the correct color, and then spent several turns making guesses before I discovered I was wrong.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Regardless, at each step of the way, I used deductive logic to extract all possible information from the clues, and use them to construct another guess that is consistent will previous clues.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;&lt;font size="3"&gt;So what does this have to do with software?&lt;br /&gt;
 &lt;/font&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;Isn't it enough fun all by itself?&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Sure, but I did claim that playing this game would help you become a better developer. So I really &lt;em&gt;should&lt;/em&gt; explain. Here goes....&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I claim that playing Mastermind a lot and getting really good at it will help you debug your code more quickly and accurately.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Conversely, if you have trouble "mining" conclusions from clues in Mastermind, I believe that you would find it very difficult, perhaps even torturous to debug your (or anyone else's) code.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Why do I say this? Well, let's walk through how we build our code.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I am handed requirements. I write a first pass at the code to implement those requirements. I get my code to compile (wow!). Then (theoretically), it is time to test my code.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So I run my test, and I get "clues" – my test (hopefully a regression test that exercises my code for a variety of input scenarios) tells me the circumstances of failure (When I pass in "ABC", I get 1 – the right answer. When I pass in "123", I get NULL – the wrong answer).&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I might also trace execution of my code, giving me &lt;em&gt;lots&lt;/em&gt; of additional clues.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I then take all this information (forget about up to four conveniently colored clues – I will usually get many more pieces of feedback then that!), use it to guide my debugging session, and identify changes to the code that I believe will result in a correct program.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;That's my next "guess." I then rerun my tests, get my next set of clues, and on I go.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Now, doesn't that sound just like the process of finding a solution to Mastermind, only way more complicated?&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So if you have trouble playing Mastermind, I've got to conclude that you will more easily get lost in the tangle of code and clues you get when testing. And if you can play Mastermind very well (which means, by the way, that you can also rapidly get to a solution even when duplicate colors and blanks are allowed, greatly increasing the number of possible solutions and requiring more sophisticated strategies for solving the puzzle), I am certain you will find it that much easier to juggle larger amounts of test feedback and apply all of that productively to your code.&lt;br /&gt;
 &lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/301/Play-games-to-become-a-better-developer.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/301/Play-games-to-become-a-better-developer.aspx#Comments</comments>
      <slash:comments>2</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/301/Play-games-to-become-a-better-developer.aspx</guid>
      <pubDate>Tue, 28 Oct 2008 16:23:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=301</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
    </item>
    <item>
      <title>Play games to become a better developer!</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/289/Play-games-to-become-a-better-developer.aspx</link>
      <description>&lt;div&gt;&lt;strong&gt;Part 1:  The Game of Set&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Software development is one heck of a serious job. It turns out, however, that there are several games you can play to improve the quality of code you write. This is the first of two blog entries that introduce you to two of my favorite brain development and training games: Set and Mastermind.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Play either (preferably both) of these games, and you will write better software.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;[ Note that I do &lt;em&gt;not &lt;/em&gt;include Solitaire in this list. Playing this game will definitely not help you become a better developer, but it will pass the time. ]&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I even encourage you to play these games &lt;em&gt;on company time&lt;/em&gt;, with management approval. It will be a good investment by your employer. Sound crazy? I have been told by a number of my students that their manager did, in fact, agree to do this, and everyone is happy with the results. I will come back to this point at the end of this blog.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So the game featured in this blog is Set. Set is a "family game of visual perception," according to the creator (lots more details at &lt;a href="http://www.setgame.com"&gt;www.setgame.com&lt;/a&gt;). I think it is better described as a subtle and sophisticated pattern analysis/matching game.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Set is a physical card game, though you can play the daily puzzle &lt;a href="http://setgame.com/set/index.html"&gt;here&lt;/a&gt;. They used to sell a software version of the game, which I will be using in this blog, but it is no longer available.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So how does it work? You lay out twelve cards from the deck on the table of your choice. Here we go:&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;img alt="" width="400" height="300" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102008-1.gif" /&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So, the object of the game is to find sets of three cards. Whoever finds the most sets wins the game.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;You are now wondering: how do I know which three cards go together in a set? Here are the rules:&lt;/div&gt;
&lt;ul type="disc"&gt;
    &lt;li&gt;Each card has four characteristics: shape, coloring, number, and filling.&lt;/li&gt;
    &lt;li&gt;Each characteristic has three possible values. Oval, squiggle and diamond for shape; green, red or purple for color; one, two or three objects for number; lined, solid and empty for filling.&lt;/li&gt;
    &lt;li&gt;Three cards make up a set if each characteristic, independent of the others, is all the same or all different.   &lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;An example of a set: all reds, all ones, oval-squiggle-diamond and lined-empty-solid.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Three cards that do not make up a set: red-red-red, two-one-three, solid-solid-solid, and oval-diamond-oval. Two ovals and one diamond are neither all different or all the same.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;In other words, two out of three is a no-go in Set.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Note that you can never have all four characteristics the same (they would then be the same card, and the Set deck contains no repeats). You can, however, have a set in which all characteristics are different. I find this to be the challenging and satisfying set to find.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;OK, let's use deductive logic to find ourselves a set. Notice the two cards in the middle of the top row?&lt;/div&gt;
&lt;p&gt;&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102008-2.gif" /&gt;&lt;/p&gt;
&lt;div&gt;They could be in a set (any two could, in fact!). Let's see if we can figure out what the third card would &lt;em&gt;have &lt;/em&gt;to be. Then if we are lucky enough to have that card on the table, I will have my first set.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The first two cards:&lt;/div&gt;
&lt;ul&gt;
    &lt;li&gt;Each have two items. So the third card has to have two items, too.&lt;/li&gt;
    &lt;li&gt;Are green and red. So the third card would have to have a different color: purple.&lt;/li&gt;
    &lt;li&gt;Are solid and lined. So the third card would have to have a different filling: empty.&lt;/li&gt;
    &lt;li&gt;Are oval and squiggle. So the third card would have to have a different shape: empty.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;So the third card would have to be: two-purple-diamond-empty.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Can you see it?&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102008-3.gif" /&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;There it is on the bottom row, third column!&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Now, if we were sitting around a table together, I would shout: "Set!" and if did so before anyone else, I would scoop up my set. If someone else said "Set" first, they could then take that or a different set, if they had found one (I don't think there is one).&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So those three cards go into my pile and we put down another three cards:&lt;/div&gt;
&lt;div&gt; &lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102008-4.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;And the game proceeds this way until all sets have been found.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Can you identify the (at least) three sets in the above twelve cards?&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;There are two different sets using &lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102008-5.gif" /&gt; and two different sets using &lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102008-6.gif" /&gt;. Can you find them? See answer at end of this entry.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So that is Set. When you first start to play this game, you will likely follow the path to a solution I showed above; namely, use deductive logic to find the third card given the first two.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;You probably, however, will not play this way very long, at least not if you are playing (competing) with others.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;In Set, stepping your way through a logical proof ("If the first two are red, the third must be red.") is too slow. You will lose again and again. Not to wrry! After you have been playing for a while, your brain will of its own accord (whatever &lt;em&gt;that&lt;/em&gt; means) abandon explicit deductive logic. Instead, your eyes will roam over the entire set of twelve cards and the three cards that make up a set will "appear." Your brain will have by this time trained itself to assimilate the various kinds of input and resolve the problem very rapidly.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;&lt;font size="3"&gt;&lt;font size="2"&gt;How does Set help software developers?&lt;br /&gt;
&lt;/font&gt; &lt;/font&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;So what's the connection to software? There is a movement in the world of software called "Design Patterns." Here's the basic idea: there's nothing new under the sun; any code you write today is likely very similar to what you or someone else wrote yesterday. Most of our code, in other words, follow common patterns, because we are mostly solving the same kinds of problems, albeit described differently in different domains, over and over again.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So if you can abstract out the pattern, and then provide a similarly generic &lt;em&gt;solution&lt;/em&gt; to the pattern, the next time you encounter a problem that fits the pattern, you can immediately apply the general solution, and work simply on fitting it precisely to the specifics of your current challenge.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;In other words, lots of software development is all about pattern analysis and recognition, followed by taking logic-based action in response to that pattern.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The better you are at identifying patterns, the better you will be at writing elegant software that avoids the repetitions of logic that invites bugs and mitigates against maintainability.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;And that is why I encourage playing this game while you are on company time. In fact, I suggest that team leads or managers organize a weekly Friday pizza lunch during which you play Set as a group. Great team builder and brain builder!&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;&lt;font size="2"&gt;Is Set only good for work?&lt;br /&gt;
 &lt;/font&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;Ha! No way. In fact, if you have children under the age of twelve or thirteen – anyway, at an age when they are still willing to play a game with you, order Set now (you can find locations in the U.S. that sell Set right &lt;a href="http://setgame.com/stores/stores.htm"&gt;here&lt;/a&gt;) and start playing it with your kids.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I bet a child as young as four could get started (perhaps with only two colors, or some other way of simplifying the rules). The sooner the better – Set will help make your child smarter!&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The other nice thing about playing Set with your kids is that it is very likely that once they get the hang of it, they will regularly and decisively defeat you. Their minds are so nimble, probably devoting their full concentration to the game, while yours is jumbled full of bills to pay, what to cook for dinner, and so on, that you will spare only a part of your total (and totally awesome) brain power.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;And that's OK. Kids generally don't get to control too much of their environment. To know that you are trying hard as you can and &lt;em&gt;still&lt;/em&gt; lose to them, well, that is very empowering. Great for kids when they're young, perhaps a point of regret when they become teenagers.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;In conclusion, I urge you to get your copy of Set today. Play it at home with your family and friends. Play it at work with your co-workers. Make your brain strong and help make the world a far better place than it is today.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;&lt;font size="3"&gt;The Answers&lt;br /&gt;
 &lt;/font&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;&lt;em&gt;&lt;font size="2"&gt;Two with &lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102008-5.gif" /&gt;&lt;/font&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Green-purple-red&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;One-one-one&lt;/div&gt;
&lt;div&gt;Squiggle- squiggle- squiggle&lt;/div&gt;
&lt;div&gt;Lined-lined-lined&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt; &lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102008-7.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;One-two-three&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;Purple-purple-purple&lt;/div&gt;
&lt;div&gt;Lined-lined-lined&lt;/div&gt;
&lt;div&gt;Squiggle- squiggle- squiggle&lt;/div&gt;
&lt;div&gt; &lt;br /&gt;
&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102008-8.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;&lt;em&gt;&lt;font size="2"&gt;Two with &lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102008-6.gif" /&gt;&lt;/font&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Same as before, namely:&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Green-purple-red&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;One-one-one&lt;/div&gt;
&lt;div&gt;Squiggle- squiggle- squiggle&lt;/div&gt;
&lt;div&gt;Lined-lined-lined&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102008-9.gif" /&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;And&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Green-purple-red&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;One-one-one&lt;/div&gt;
&lt;div&gt;Squiggle- oval-diamond&lt;/div&gt;
&lt;div&gt;Lined-solid-empty&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;img alt="" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog102008-10.gif" /&gt; &lt;/div&gt;
&lt;div&gt;  &lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/289/Play-games-to-become-a-better-developer.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/289/Play-games-to-become-a-better-developer.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/289/Play-games-to-become-a-better-developer.aspx</guid>
      <pubDate>Mon, 20 Oct 2008 14:01:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=289</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
    </item>
    <item>
      <title>Doing SQL in PL/SQL: key resource from Bryn Llewellyn</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/286/Doing-SQL-in-PL-SQL-key-resource-from-Bryn-Llewellyn.aspx</link>
      <description>&lt;div&gt;One of the highlights of Oracle Open World 2008 for me was the presentation by Bryn Llewellyn (PL/SQL Product Manager) on “Doing SQL in PL/SQL.”&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Bryn surely has the most thorough and clear understanding of the PL/SQL language of anyone I have met (definitely including me).&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;His talk was detailed and precise (and maybe just a little bit overwhelming. He needed twice the time allotted) on this most important topic.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The bad news about this talk is that most PL/SQL developers will never be able to hear Bryn present it.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The good news is that everything he talks about (and more) may be found in a newly published whitepaper of the same name.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Simply visit the &lt;a href="http://www.oracle.com/technology/tech/pl_sql/index.html"&gt;Oracle Technology Network PL/SQL Homepage&lt;/a&gt; and click on the hyperlink for that paper. Notice also that Bryn has published an important whitepaper on SQL injection. &lt;br /&gt;
 &lt;br /&gt;
&lt;img alt="" width="700" height="402" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog100808-1.gif" /&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Your understanding of PL/SQL will increase dramatically, as will your ability to write high quality PL/SQL programs, by reading both of these papers.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Thanks, Bryn!&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/286/Doing-SQL-in-PL-SQL-key-resource-from-Bryn-Llewellyn.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,oracle,sql&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/286/Doing-SQL-in-PL-SQL-key-resource-from-Bryn-Llewellyn.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/286/Doing-SQL-in-PL-SQL-key-resource-from-Bryn-Llewellyn.aspx</guid>
      <pubDate>Wed, 08 Oct 2008 17:09:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=286</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/86/Default.aspx">sql</blog:tag>
    </item>
    <item>
      <title>For loops or While loops to scan collections?</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/280/For-loops-or-While-loops-to-scan-collections.aspx</link>
      <description>&lt;div&gt;I have generally recommended in the past that whenever you are writing code to iterate through the elements of a collection, you should use a while loop, combined with the FIRST-NEXT or LAST-PRIOR collection methods.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;The key advantage of this approach is that the code will not raise a NO_DATA_FOUND exception if your collection is sparse (there is an index value between FIRST and LAST that is not defined). And if your collection is empty, the loop will not execute at all, whereas with a for loop, an empty collection could cause a VALUE_ERROR exception if you are not careful.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;Here is an example of the kind of code that requires the use of the while loop:&lt;/div&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre&gt;DECLARE&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;TYPE employee_tt&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;IS&lt;br /&gt;&lt;span&gt;      &lt;/span&gt;TABLE OF employees%ROWTYPE&lt;br /&gt;&lt;span&gt;         &lt;/span&gt;INDEX BY pls_integer; &lt;/pre&gt;
&lt;pre&gt;&lt;span&gt;   &lt;/span&gt;employee_cache&lt;span&gt;   &lt;/span&gt;employee_tt;&lt;br /&gt;BEGIN&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;/* Fill the collection using the employee ID&lt;br /&gt;&lt;span&gt;      as the index value - most like these values are&lt;br /&gt;&lt;/span&gt;&lt;span&gt;      NOT sequentially defined; primary keys can&lt;br /&gt;&lt;/span&gt;&lt;span&gt;      certainly have "gaps". */&lt;br /&gt;&lt;/span&gt;&lt;span&gt;   &lt;/span&gt;FOR rec IN (SELECT&lt;span&gt;   *&lt;br /&gt;&lt;/span&gt;&lt;span&gt;                 &lt;/span&gt;FROM&lt;span&gt;   &lt;/span&gt;employees)&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;LOOP&lt;br /&gt;&lt;span&gt;      &lt;/span&gt;employee_cache (rec.employee_id) := rec;&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;END LOOP; &lt;/pre&gt;
&lt;pre&gt;&lt;span&gt;   &lt;/span&gt;FOR indx IN 1 .. employee_cache.COUNT&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;LOOP&lt;br /&gt;&lt;span&gt;      &lt;/span&gt;DBMS_OUTPUT.put_line (employee_cache (indx).last_name);&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;END LOOP;&lt;br /&gt;END;&lt;br /&gt;/&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;div&gt;When I execute this block, I get the following error:&lt;br /&gt;
 &lt;br /&gt;
&lt;img alt="" width="448" height="173" src="/Portals/0/blogimages/Steven Feuerstein/SF-Blog092208-1.gif" /&gt;&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;Instead, I should use a while loop:&lt;/div&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre&gt;DECLARE&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;TYPE employee_tt&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;IS&lt;br /&gt;&lt;span&gt;      &lt;/span&gt;TABLE OF employees%ROWTYPE&lt;br /&gt;&lt;span&gt;         &lt;/span&gt;INDEX BY pls_integer;&lt;/pre&gt;
&lt;pre&gt;&lt;span&gt;   &lt;/span&gt;employee_cache&lt;span&gt;   &lt;/span&gt;employee_tt;&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;l_index&lt;span&gt;           &lt;/span&gt;pls_integer;&lt;br /&gt;BEGIN&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;/* Fill the collection using the employee ID&lt;br /&gt;&lt;span&gt;      as the index value - most like these values are&lt;br /&gt;&lt;/span&gt;&lt;span&gt;      NOT sequentially defined; primary keys can&lt;br /&gt;&lt;/span&gt;&lt;span&gt;      certainly have "gaps". */&lt;br /&gt;&lt;/span&gt;&lt;span&gt;   &lt;/span&gt;FOR rec IN (SELECT&lt;span&gt;   *&lt;br /&gt;&lt;/span&gt;&lt;span&gt;                 &lt;/span&gt;FROM&lt;span&gt;   &lt;/span&gt;employees)&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;LOOP&lt;br /&gt;&lt;span&gt;      &lt;/span&gt;employee_cache (rec.employee_id) := rec;&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;END LOOP;&lt;/pre&gt;
&lt;pre&gt;&lt;span&gt;   &lt;/span&gt;l_index := employee_cache.FIRST;&lt;/pre&gt;
&lt;pre&gt;&lt;span&gt;   &lt;/span&gt;WHILE (l_index IS NOT NULL)&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;LOOP&lt;br /&gt;&lt;span&gt;      &lt;/span&gt;DBMS_OUTPUT.put_line (employee_cache (l_index).last_name);&lt;br /&gt;&lt;span&gt;      &lt;/span&gt;l_index := employee_cache.NEXT (l_index);&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;END LOOP;&lt;br /&gt;END;&lt;br /&gt;/&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;div&gt;and then I will not see any errors.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;So, no doubt about it, this is good advice – but should you &lt;em&gt;always&lt;/em&gt; use the while loop?&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;I suggest that in situations when you know, when you are absolutely sure, that your collection is densely-filled, you should use the FOR loop, for two reasons:&lt;/div&gt;
&lt;ul type="disc"&gt;
    &lt;li&gt;It is a simpler solution, requiring less code (reducing the chance of a bug creeping into your code and making it easier to maintain).&lt;/li&gt;
    &lt;li&gt;It is more self-documenting. By using the for loop construct, you are stating that an assumption of this code is that the collection is densely-filled.&lt;/li&gt;
    &lt;li&gt;It is more efficient than the while loop.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;So when you can be certain that your collection is densely-filled? When....&lt;/div&gt;
&lt;ul type="disc"&gt;
    &lt;li&gt;The collection is populated by a BULK COLLECT query. In this situation, the first index used is always 1, and the collection is filled sequentially (2, 3, 4...) from that index.&lt;/li&gt;
    &lt;li&gt;The collection is a nested table assigned its contents from a MULTISET operator (UNION, INTERSECT and EXCEPT). These set level operators always fill sequentially a nested table from index value 1.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;And what kind of difference in performance can you expect to see? Not a very big difference, but the FOR loop is &lt;em&gt;definitely &lt;/em&gt;faster. I put together the script below (relying on the sf_timer package, included in the &lt;a href="http://www.toadworld.com/Portals/0/stevenf/demo.zip"&gt;demo.zip&lt;/a&gt;.&lt;/div&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre&gt;DECLARE&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;l_index&lt;span&gt;     &lt;/span&gt;pls_integer;&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;l_source&lt;span&gt;   &lt;/span&gt;DBMS_SQL.varchar2a;&lt;br /&gt;BEGIN&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;sf_timer.start_timer; &lt;/pre&gt;
&lt;pre&gt;&lt;span&gt;       &lt;/span&gt;SELECT&lt;span&gt;    &lt;/span&gt;text&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;BULK COLLECT INTO&lt;span&gt;   &lt;/span&gt;l_source&lt;br /&gt;&lt;span&gt;         &lt;/span&gt;FROM&lt;span&gt;    &lt;/span&gt;all_source; &lt;/pre&gt;
&lt;pre&gt;&lt;span&gt;   &lt;/span&gt;sf_timer.show_elapsed_time (&lt;br /&gt;&lt;span&gt;      &lt;/span&gt;'Retrieved ' || TO_CHAR(l_source.COUNT) || ' elements'&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;);&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;--&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;sf_timer.start_timer; &lt;/pre&gt;
&lt;pre&gt;&lt;span&gt;   &lt;/span&gt;FOR indx IN 1 .. l_source.COUNT&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;LOOP&lt;br /&gt;&lt;span&gt;      &lt;/span&gt;NULL;&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;END LOOP; &lt;/pre&gt;
&lt;pre&gt;&lt;span&gt;   &lt;/span&gt;sf_timer.show_elapsed_time ('FOR loop through collection');&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;--&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;sf_timer.start_timer;&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;l_index := l_source.FIRST; &lt;/pre&gt;
&lt;pre&gt;&lt;span&gt;   &lt;/span&gt;WHILE (l_index IS NOT NULL)&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;LOOP&lt;br /&gt;&lt;span&gt;      &lt;/span&gt;NULL;&lt;br /&gt;&lt;span&gt;      &lt;/span&gt;l_index := l_source.NEXT (l_index);&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;END LOOP; &lt;/pre&gt;
&lt;pre&gt;&lt;span&gt;   &lt;/span&gt;sf_timer.show_elapsed_time ('Full collection scan with NEXT');&lt;br /&gt;END;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;div&gt;I saw the following results:&lt;/div&gt;
&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
&lt;pre&gt;Retrieved 3079394 elements - Elapsed CPU : 11.14 seconds.&lt;br /&gt;FOR loop through collection - Elapsed CPU : .05 seconds.&lt;br /&gt;Full collection scan with NEXT - Elapsed CPU : .48 seconds. &lt;/pre&gt;
&lt;/blockquote&gt;
&lt;div&gt;In other words, the while loop is an &lt;em&gt;order of magnitude slower &lt;/em&gt; than the for loop. That sounds like a big deal, but it's only a difference of .4 seconds with a scan of over 3,000,000 elements. With smaller collections, you'll probably never notice the difference.&lt;br /&gt;
 &lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/280/For-loops-or-While-loops-to-scan-collections.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,for loop,while loop,collection,bulk collect,oracle&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/280/For-loops-or-While-loops-to-scan-collections.aspx#Comments</comments>
      <slash:comments>1</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/280/For-loops-or-While-loops-to-scan-collections.aspx</guid>
      <pubDate>Mon, 22 Sep 2008 16:21:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=280</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/83/Default.aspx">for loop</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/84/Default.aspx">while loop</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/85/Default.aspx">collection</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/54/Default.aspx">bulk collect</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
    </item>
    <item>
      <title>Analyzing code coverage with the PL/SQL profiler</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/267/Analyzing-code-coverage-with-the-PL-SQL-profiler.aspx</link>
      <description>&lt;p&gt;I have, for the past several years, focused heavily on designing and building an automated code testing tool for PL/SQL: &lt;a href="http://www.toadworld.com/LinkClick.aspx?link=431&amp;tabid=67"&gt;Quest Code Tester for Oracle&lt;/a&gt;. One feature that is often requested as a part of code testing is analysis of code coverage, answering questions like:&lt;/p&gt;
&lt;ul type="disc"&gt;
    &lt;li&gt;When I run my program do I use 50% of the code? 75% of the code?  &lt;/li&gt;
    &lt;li&gt;Are there chunks of logic that are never run&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;The only way to get this kind of information is to turn on the PL/SQL profiler (and/or the new hierarchical profiler delivered with Oracle11g). The profiler keeps track of each line run by the program during the profile session. You then query the contents of the plsql_profiler_data|units|runs tables and draw your own conclusions.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;And therein lies the rub.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;Code Tester users don't want to see lengthy reports showing which lines where executed. Instead, they want us to provide them a single number that tells them all they need to know: "75% of my program was executed." Period.&lt;/div&gt;
&lt;div&gt;And I would like to provide that feature, I really would. But I am feeling a little bit stumped and thought I would share with you what I have done so far, and my areas of befuddlement, in hopes that you, my dear reader, may be able to help provide additional clarity.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;So what's the problem? Well....to figure out the % of code coverage, I need to....&lt;/div&gt;
&lt;ul&gt;
    &lt;li&gt;decide &lt;em&gt;which&lt;/em&gt; lines of code I should include in the &lt;em&gt;total&lt;/em&gt; number of possible lines that could be executed. For example: do I include comments? What about the IS, BEGIN, END keywords?&lt;/li&gt;
    &lt;li&gt;understand what lines of the code the profiler actually pays attention to, and records as having been run. I have never found the profiler data to be entirely straightforward.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And so I have decided to do some research and exploration. I created a package that contains lines of code with all sorts of line breaks to see if I could isolate how Oracle treats such code in the context of profiling.&lt;/p&gt;
&lt;p&gt;You will find below the code for this package, followed by a utility I wrote to show profiling data in a way that I thought would be useful, and then the output from a profiling session.&lt;/p&gt;
&lt;p&gt;Which leads to my questions for you:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Do you have any ideas on how I should go about computing this single, golden number regarding code coverage?&lt;/li&gt;
    &lt;li&gt;What lines do you think should be included or not?&lt;/li&gt;
    &lt;li&gt;Should I take a different approach in analyzing code and profiler behavior?&lt;/li&gt;
    &lt;li&gt;What do you think of the output I got from my "test" package?&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;Looking forward to your comments,&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;Steven&lt;br /&gt;
 &lt;hr /&gt;
&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;&lt;font size="3"&gt;Package to exercise profiler&lt;/font&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;pre&gt;CREATE OR REPLACE PACKAGE what_is_profiled&lt;br /&gt;IS&lt;br /&gt;   TYPE aa1 IS TABLE OF VARCHAR2 (100)&lt;br /&gt;      INDEX BY PLS_INTEGER;&lt;/pre&gt;
&lt;pre&gt;   TYPE aa2 IS TABLE OF VARCHAR2 (100)&lt;br /&gt;      INDEX BY PLS_INTEGER;&lt;/pre&gt;
&lt;pre&gt;   PROCEDURE proc1 (arg IN NUMBER, arg2 OUT VARCHAR2);&lt;/pre&gt;
&lt;pre&gt;   FUNCTION func1&lt;br /&gt;      RETURN VARCHAR2;&lt;br /&gt;      &lt;br /&gt;      procedure driver ;&lt;br /&gt;END what_is_profiled;&lt;br /&gt;/&lt;/pre&gt;
&lt;pre&gt;CREATE OR REPLACE PACKAGE BODY what_is_profiled&lt;br /&gt;IS&lt;br /&gt;   TYPE p_aa1 IS TABLE OF VARCHAR2 (100)&lt;br /&gt;      INDEX BY PLS_INTEGER;&lt;/pre&gt;
&lt;pre&gt;   TYPE p_aa2 IS TABLE OF VARCHAR2 (100)&lt;br /&gt;      INDEX BY PLS_INTEGER;&lt;/pre&gt;
&lt;pre&gt;   PROCEDURE loops (arg IN NUMBER, arg2 OUT VARCHAR2)&lt;br /&gt;   IS&lt;br /&gt;      val&lt;br /&gt;      INTEGER;&lt;br /&gt;      condition1 boolean := true;&lt;br /&gt;      condition2 boolean &lt;br /&gt;      := &lt;br /&gt;      true;&lt;br /&gt;      &lt;br /&gt;   BEGIN&lt;br /&gt;      FOR indx IN 1 .. 100&lt;br /&gt;      LOOP&lt;br /&gt;         NULL;&lt;br /&gt;      END LOOP;&lt;br /&gt;            &lt;br /&gt;      FOR &lt;br /&gt;      indx &lt;br /&gt;      IN &lt;br /&gt;      1 &lt;br /&gt;      .. &lt;br /&gt;      100&lt;br /&gt;      LOOP&lt;br /&gt;         val := 1;&lt;br /&gt;      END &lt;br /&gt;      LOOP; &lt;br /&gt;      &lt;br /&gt;      FOR indx IN 1 .. 100 LOOP NULL; END LOOP;     &lt;/pre&gt;
&lt;pre&gt;      FOR rec IN (SELECT *&lt;br /&gt;                    FROM all_source&lt;br /&gt;                   WHERE ROWNUM &lt; 101)&lt;br /&gt;      LOOP&lt;br /&gt;         val := 1;&lt;br /&gt;      END LOOP;&lt;/pre&gt;
&lt;pre&gt;      FOR &lt;br /&gt;      rec &lt;br /&gt;      IN &lt;br /&gt;      (&lt;br /&gt;      SELECT *&lt;br /&gt;                    FROM all_source&lt;br /&gt;                   WHERE ROWNUM &lt; 101&lt;br /&gt;      )&lt;br /&gt;      LOOP&lt;br /&gt;         val := 1;&lt;br /&gt;      END &lt;br /&gt;      LOOP;&lt;br /&gt;      &lt;br /&gt;      WHILE (condition1 AND condition2)&lt;br /&gt;      LOOP&lt;br /&gt;         condition1 := FALSE;&lt;br /&gt;      END LOOP;&lt;/pre&gt;
&lt;pre&gt;      WHILE &lt;br /&gt;      (&lt;br /&gt;      condition1 &lt;br /&gt;      AND &lt;br /&gt;      condition2&lt;br /&gt;      )&lt;br /&gt;      LOOP&lt;br /&gt;         condition1 &lt;br /&gt;         := &lt;br /&gt;         FALSE&lt;br /&gt;         ;&lt;br /&gt;      END LOOP;&lt;br /&gt;      &lt;br /&gt;      DECLARE&lt;br /&gt;         indx   INTEGER := 1;&lt;br /&gt;      BEGIN&lt;br /&gt;         LOOP&lt;br /&gt;            EXIT WHEN indx &gt; 100;&lt;br /&gt;            indx := indx + 1;&lt;br /&gt;         END LOOP;&lt;br /&gt;      END;&lt;br /&gt;      &lt;br /&gt;      DECLARE&lt;br /&gt;         indx   INTEGER := 1;&lt;br /&gt;      BEGIN&lt;br /&gt;         LOOP&lt;br /&gt;            EXIT &lt;br /&gt;            WHEN &lt;br /&gt;            indx &lt;br /&gt;            &gt; &lt;br /&gt;            100;&lt;br /&gt;            indx := indx + &lt;br /&gt;            1&lt;br /&gt;            ;&lt;br /&gt;         END LOOP;&lt;br /&gt;      END;      &lt;br /&gt;   END;&lt;/pre&gt;
&lt;pre&gt;   PROCEDURE conditionals &lt;br /&gt;   IS&lt;br /&gt;   a &lt;br /&gt;   boolean;&lt;br /&gt;   b boolean;&lt;br /&gt;   c boolean&lt;br /&gt;   ;&lt;br /&gt;   BEGIN&lt;br /&gt;      IF (a AND b OR c)&lt;br /&gt;      THEN&lt;br /&gt;         NULL;&lt;br /&gt;         elsif&lt;br /&gt;         a&lt;br /&gt;         then&lt;br /&gt;         null;&lt;br /&gt;         else&lt;br /&gt;         dbms_output.put_line ('a');&lt;br /&gt;      END IF;&lt;br /&gt;      &lt;br /&gt;      a := case&lt;br /&gt;      true&lt;br /&gt;      when true&lt;br /&gt;      then&lt;br /&gt;      false&lt;br /&gt;      when &lt;br /&gt;      false then&lt;br /&gt;      true&lt;br /&gt;      else&lt;br /&gt;      false&lt;br /&gt;      end&lt;br /&gt;      ;&lt;br /&gt;      a := case true&lt;br /&gt;      when true&lt;br /&gt;      then&lt;br /&gt;      false&lt;br /&gt;      when &lt;br /&gt;      false then&lt;br /&gt;      true&lt;br /&gt;      else&lt;br /&gt;      false&lt;br /&gt;      end&lt;br /&gt;      ;  &lt;br /&gt;      &lt;br /&gt;      case when &lt;br /&gt;      sysdate &gt; sysdate + 1&lt;br /&gt;      then&lt;br /&gt;      a := false;&lt;br /&gt;      when 1 &gt; 2 then&lt;br /&gt;      b := false;&lt;br /&gt;      when 1&lt;br /&gt;      &gt; 2   &lt;br /&gt;      then&lt;br /&gt;      c := false;&lt;br /&gt;      else null; end case; &lt;br /&gt;   END;&lt;/pre&gt;
&lt;pre&gt;   FUNCTION p_func1&lt;br /&gt;      RETURN VARCHAR2&lt;br /&gt;   IS&lt;br /&gt;   BEGIN&lt;br /&gt;      RETURN NULL;&lt;br /&gt;   END;&lt;/pre&gt;
&lt;pre&gt;   PROCEDURE proc1 (arg IN NUMBER, arg2 OUT VARCHAR2)&lt;br /&gt;   IS&lt;br /&gt;   BEGIN&lt;br /&gt;      NULL;&lt;br /&gt;   END;&lt;/pre&gt;
&lt;pre&gt;   FUNCTION func1&lt;br /&gt;      RETURN VARCHAR2&lt;br /&gt;   IS&lt;br /&gt;   BEGIN&lt;br /&gt;      RETURN p_func1;&lt;br /&gt;   END;&lt;br /&gt;   &lt;br /&gt;   procedure driver is&lt;br /&gt;   l varchar2(100);&lt;br /&gt;   begin&lt;br /&gt;   loops(1, l);&lt;br /&gt;   conditionals;&lt;br /&gt;   proc1&lt;br /&gt;   (&lt;br /&gt;   1&lt;br /&gt;   ,&lt;br /&gt;   l);&lt;br /&gt;   GOTO checkloop;&lt;br /&gt;   &lt;&lt;checkloop&gt;&lt;/checkloop&gt;&gt;&lt;br /&gt;   dbms_output.put_line ('a');&lt;br /&gt;   end;&lt;br /&gt;END what_is_profiled;&lt;br /&gt;/&lt;/pre&gt;
&lt;pre&gt;&lt;hr /&gt;&lt;/pre&gt;
&lt;div&gt;&lt;strong&gt;&lt;font size="4"&gt;&lt;font size="3"&gt;Utility to show profiler data&lt;/font&gt;&lt;/font&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;pre&gt;CREATE OR REPLACE PROCEDURE show_lines_profiled&lt;br /&gt;/*&lt;br /&gt;Assumptions: the ONLY data inside the profiler tables are for a single&lt;br /&gt;run of what_is_profiled.driver&lt;br /&gt;*/&lt;br /&gt;IS&lt;br /&gt;   l_type varchar2( 10000 );&lt;br /&gt;BEGIN&lt;br /&gt;   DBMS_OUTPUT.put_line( 'Profiling Report' );&lt;br /&gt;   DBMS_OUTPUT.put_line( '  NOT PROFILED = No profile data for this line' );&lt;br /&gt;   DBMS_OUTPUT.put_line( '  ZERO RUNS    = Profiled, but TOTAL_OCCURS = 0' );&lt;br /&gt;   DBMS_OUTPUT.put_line( '  LINE RUN     = This line was executed at least once' );&lt;/pre&gt;
&lt;pre&gt;   DBMS_OUTPUT.put_line( 'Profile Info   Line Source');&lt;br /&gt;   DBMS_OUTPUT.put_line( &lt;br /&gt;'============== ==== ==============================================================');&lt;/pre&gt;
&lt;pre&gt;   FOR rec&lt;br /&gt;   IN (  SELECT line, text&lt;br /&gt;           FROM all_source als&lt;br /&gt;          WHERE     als.owner = USER&lt;br /&gt;                AND als.name = 'WHAT_IS_PROFILED'&lt;br /&gt;                AND als.TYPE = 'PACKAGE BODY'&lt;br /&gt;       ORDER BY line )&lt;br /&gt;   LOOP&lt;br /&gt;      BEGIN&lt;br /&gt;         SELECT CASE&lt;br /&gt;                   WHEN total_occur = 0 THEN 'ZERO RUNS'&lt;br /&gt;                   ELSE 'LINE RUN'&lt;br /&gt;                END&lt;br /&gt;                   profile_type&lt;br /&gt;           INTO l_type&lt;br /&gt;           FROM plsql_profiler_data ppd&lt;br /&gt;          WHERE ppd.line# = rec.line AND ppd.unit_number = 2;&lt;br /&gt;      EXCEPTION&lt;br /&gt;         WHEN NO_DATA_FOUND&lt;br /&gt;         THEN&lt;br /&gt;            l_type      := 'NOT PROFILED';&lt;br /&gt;      END;&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre&gt;      DBMS_OUTPUT.put_line(   RPAD( l_type, 15 )&lt;br /&gt;                           || LPAD( rec.line, 4 )&lt;br /&gt;                           || ' '&lt;br /&gt;                           || rtrim (rec.text, chr(10)));&lt;br /&gt;   END LOOP;&lt;br /&gt;END show_lines_profiled;&lt;/pre&gt;
&lt;pre&gt;&lt;hr /&gt;&lt;/pre&gt;
&lt;div&gt;&lt;strong&gt;&lt;font size="4"&gt;&lt;font size="3"&gt;Results of profiling the package&lt;/font&gt;&lt;/font&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;pre&gt;BEGIN&lt;br /&gt;   DELETE FROM plsql_profiler_data;&lt;/pre&gt;
&lt;pre&gt;   DELETE FROM plsql_profiler_units;&lt;/pre&gt;
&lt;pre&gt;   DELETE FROM plsql_profiler_runs;&lt;/pre&gt;
&lt;pre&gt;   DBMS_OUTPUT.put_line(&lt;br /&gt;                         DBMS_PROFILER.start_profiler( 'What is profiled?' )&lt;br /&gt;   );&lt;br /&gt;   what_is_profiled.driver( );&lt;br /&gt;   DBMS_PROFILER.stop_profiler;&lt;br /&gt;   --&lt;br /&gt;   show_lines_profiled();&lt;br /&gt;END;&lt;br /&gt;/&lt;br /&gt;Profiling Report&lt;br /&gt;  NOT PROFILED = No profile data for this line&lt;br /&gt;  ZERO RUNS    = Profiled, but TOTAL_OCCURS = 0&lt;br /&gt;  LINE RUN     = This line was executed at least once&lt;br /&gt;Profile Info   Line Source&lt;br /&gt;============== ==== ==============================================================&lt;br /&gt;NOT PROFILED      1 PACKAGE BODY what_is_profiled&lt;br /&gt;NOT PROFILED      2 IS&lt;br /&gt;NOT PROFILED      3    TYPE p_aa1 IS TABLE OF VARCHAR2 (100)&lt;br /&gt;NOT PROFILED      4       INDEX BY PLS_INTEGER;&lt;br /&gt;NOT PROFILED      5 &lt;br /&gt;NOT PROFILED      6    TYPE p_aa2 IS TABLE OF VARCHAR2 (100)&lt;br /&gt;NOT PROFILED      7       INDEX BY PLS_INTEGER;&lt;br /&gt;NOT PROFILED      8 &lt;br /&gt;ZERO RUNS         9    PROCEDURE loops (arg IN NUMBER, arg2 OUT VARCHAR2)&lt;br /&gt;NOT PROFILED     10    IS&lt;br /&gt;NOT PROFILED     11       val&lt;br /&gt;NOT PROFILED     12       INTEGER;&lt;br /&gt;LINE RUN         13       condition1 boolean := true;&lt;br /&gt;LINE RUN         14       condition2 boolean &lt;br /&gt;NOT PROFILED     15       := &lt;br /&gt;NOT PROFILED     16       true;&lt;br /&gt;NOT PROFILED     17       &lt;br /&gt;NOT PROFILED     18    BEGIN&lt;br /&gt;LINE RUN         19       FOR indx IN 1 .. 100&lt;br /&gt;NOT PROFILED     20       LOOP&lt;br /&gt;LINE RUN         21          NULL;&lt;br /&gt;NOT PROFILED     22       END LOOP;&lt;br /&gt;NOT PROFILED     23             &lt;br /&gt;LINE RUN         24       FOR &lt;br /&gt;NOT PROFILED     25       indx &lt;br /&gt;NOT PROFILED     26       IN &lt;br /&gt;NOT PROFILED     27       1 &lt;br /&gt;NOT PROFILED     28       .. &lt;br /&gt;NOT PROFILED     29       100&lt;br /&gt;NOT PROFILED     30       LOOP&lt;br /&gt;LINE RUN         31          val := 1;&lt;br /&gt;NOT PROFILED     32       END &lt;br /&gt;NOT PROFILED     33       LOOP; &lt;br /&gt;NOT PROFILED     34       &lt;br /&gt;LINE RUN         35       FOR indx IN 1 .. 100 LOOP NULL; END LOOP;      &lt;br /&gt;NOT PROFILED     36 &lt;br /&gt;LINE RUN         37       FOR rec IN (SELECT *&lt;br /&gt;NOT PROFILED     38                     FROM all_source&lt;br /&gt;NOT PROFILED     39                    WHERE ROWNUM &lt; 101)&lt;br /&gt;NOT PROFILED     40       LOOP&lt;br /&gt;LINE RUN         41          val := 1;&lt;br /&gt;NOT PROFILED     42       END LOOP;&lt;br /&gt;NOT PROFILED     43 &lt;br /&gt;LINE RUN         44       FOR &lt;br /&gt;NOT PROFILED     45       rec &lt;br /&gt;NOT PROFILED     46       IN &lt;br /&gt;NOT PROFILED     47       (&lt;br /&gt;ZERO RUNS        48       SELECT *&lt;br /&gt;NOT PROFILED     49                     FROM all_source&lt;br /&gt;NOT PROFILED     50                    WHERE ROWNUM &lt; 101&lt;br /&gt;NOT PROFILED     51       )&lt;br /&gt;NOT PROFILED     52       LOOP&lt;br /&gt;LINE RUN         53          val := 1;&lt;br /&gt;NOT PROFILED     54       END &lt;br /&gt;NOT PROFILED     55       LOOP;&lt;br /&gt;NOT PROFILED     56       &lt;br /&gt;LINE RUN         57       WHILE (condition1 AND condition2)&lt;br /&gt;NOT PROFILED     58       LOOP&lt;br /&gt;NOT PROFILED     59          condition1 := FALSE;&lt;br /&gt;NOT PROFILED     60       END LOOP;&lt;br /&gt;NOT PROFILED     61 &lt;br /&gt;NOT PROFILED     62       WHILE &lt;br /&gt;NOT PROFILED     63       (&lt;br /&gt;NOT PROFILED     64       condition1 &lt;br /&gt;NOT PROFILED     65       AND &lt;br /&gt;NOT PROFILED     66       condition2&lt;br /&gt;NOT PROFILED     67       )&lt;br /&gt;NOT PROFILED     68       LOOP&lt;br /&gt;NOT PROFILED     69          condition1 &lt;br /&gt;NOT PROFILED     70          := &lt;br /&gt;NOT PROFILED     71          FALSE&lt;br /&gt;NOT PROFILED     72          ;&lt;br /&gt;NOT PROFILED     73       END LOOP;&lt;br /&gt;NOT PROFILED     74       &lt;br /&gt;NOT PROFILED     75       DECLARE&lt;br /&gt;LINE RUN         76          indx   INTEGER := 1;&lt;br /&gt;NOT PROFILED     77       BEGIN&lt;br /&gt;LINE RUN         78          LOOP&lt;br /&gt;LINE RUN         79             EXIT WHEN indx &gt; 100;&lt;br /&gt;LINE RUN         80             indx := indx + 1;&lt;br /&gt;NOT PROFILED     81          END LOOP;&lt;br /&gt;NOT PROFILED     82       END;&lt;br /&gt;NOT PROFILED     83       &lt;br /&gt;NOT PROFILED     84       DECLARE&lt;br /&gt;LINE RUN         85          indx   INTEGER := 1;&lt;br /&gt;NOT PROFILED     86       BEGIN&lt;br /&gt;LINE RUN         87          LOOP&lt;br /&gt;LINE RUN         88             EXIT &lt;br /&gt;NOT PROFILED     89             WHEN &lt;br /&gt;NOT PROFILED     90             indx &lt;br /&gt;NOT PROFILED     91             &gt; &lt;br /&gt;NOT PROFILED     92             100;&lt;br /&gt;LINE RUN         93             indx := indx + &lt;br /&gt;NOT PROFILED     94             1&lt;br /&gt;NOT PROFILED     95             ;&lt;br /&gt;NOT PROFILED     96          END LOOP;&lt;br /&gt;NOT PROFILED     97       END;      &lt;br /&gt;LINE RUN         98    END;&lt;br /&gt;NOT PROFILED     99 &lt;br /&gt;ZERO RUNS       100    PROCEDURE conditionals &lt;br /&gt;NOT PROFILED    101    IS&lt;br /&gt;NOT PROFILED    102    a &lt;br /&gt;NOT PROFILED    103    boolean;&lt;br /&gt;NOT PROFILED    104    b boolean;&lt;br /&gt;NOT PROFILED    105    c boolean&lt;br /&gt;NOT PROFILED    106    ;&lt;br /&gt;NOT PROFILED    107    BEGIN&lt;br /&gt;LINE RUN        108       IF (a AND b OR c)&lt;br /&gt;NOT PROFILED    109       THEN&lt;br /&gt;NOT PROFILED    110          NULL;&lt;br /&gt;NOT PROFILED    111          elsif&lt;br /&gt;LINE RUN        112          a&lt;br /&gt;NOT PROFILED    113          then&lt;br /&gt;NOT PROFILED    114          null;&lt;br /&gt;NOT PROFILED    115          else&lt;br /&gt;LINE RUN        116          dbms_output.put_line ('a');&lt;br /&gt;NOT PROFILED    117       END IF;&lt;br /&gt;NOT PROFILED    118       &lt;br /&gt;LINE RUN        119       a := case&lt;br /&gt;NOT PROFILED    120       true&lt;br /&gt;NOT PROFILED    121       when true&lt;br /&gt;NOT PROFILED    122       then&lt;br /&gt;NOT PROFILED    123       false&lt;br /&gt;NOT PROFILED    124       when &lt;br /&gt;NOT PROFILED    125       false then&lt;br /&gt;NOT PROFILED    126       true&lt;br /&gt;NOT PROFILED    127       else&lt;br /&gt;NOT PROFILED    128       false&lt;br /&gt;NOT PROFILED    129       end&lt;br /&gt;NOT PROFILED    130       ;&lt;br /&gt;LINE RUN        131       a := case true&lt;br /&gt;NOT PROFILED    132       when true&lt;br /&gt;NOT PROFILED    133       then&lt;br /&gt;NOT PROFILED    134       false&lt;br /&gt;NOT PROFILED    135       when &lt;br /&gt;NOT PROFILED    136       false then&lt;br /&gt;NOT PROFILED    137       true&lt;br /&gt;NOT PROFILED    138       else&lt;br /&gt;NOT PROFILED    139       false&lt;br /&gt;NOT PROFILED    140       end&lt;br /&gt;NOT PROFILED    141       ;  &lt;br /&gt;NOT PROFILED    142       &lt;br /&gt;LINE RUN        143       case when &lt;br /&gt;NOT PROFILED    144       sysdate &gt; sysdate + 1&lt;br /&gt;NOT PROFILED    145       then&lt;br /&gt;LINE RUN        146       a := false;&lt;br /&gt;NOT PROFILED    147       when 1 &gt; 2 then&lt;br /&gt;NOT PROFILED    148       b := false;&lt;br /&gt;NOT PROFILED    149       when 1&lt;br /&gt;NOT PROFILED    150       &gt; 2   &lt;br /&gt;NOT PROFILED    151       then&lt;br /&gt;NOT PROFILED    152       c := false;&lt;br /&gt;NOT PROFILED    153       else null; end case; &lt;br /&gt;NOT PROFILED    154    END;&lt;br /&gt;NOT PROFILED    155 &lt;br /&gt;ZERO RUNS       156    FUNCTION p_func1&lt;br /&gt;NOT PROFILED    157       RETURN VARCHAR2&lt;br /&gt;NOT PROFILED    158    IS&lt;br /&gt;NOT PROFILED    159    BEGIN&lt;br /&gt;ZERO RUNS       160       RETURN NULL;&lt;br /&gt;ZERO RUNS       161    END;&lt;br /&gt;NOT PROFILED    162 &lt;br /&gt;ZERO RUNS       163    PROCEDURE proc1 (arg IN NUMBER, arg2 OUT VARCHAR2)&lt;br /&gt;NOT PROFILED    164    IS&lt;br /&gt;NOT PROFILED    165    BEGIN&lt;br /&gt;LINE RUN        166       NULL;&lt;br /&gt;NOT PROFILED    167    END;&lt;br /&gt;NOT PROFILED    168 &lt;br /&gt;ZERO RUNS       169    FUNCTION func1&lt;br /&gt;NOT PROFILED    170       RETURN VARCHAR2&lt;br /&gt;NOT PROFILED    171    IS&lt;br /&gt;NOT PROFILED    172    BEGIN&lt;br /&gt;ZERO RUNS       173       RETURN p_func1;&lt;br /&gt;ZERO RUNS       174    END;&lt;br /&gt;NOT PROFILED    175    &lt;br /&gt;ZERO RUNS       176    procedure driver is&lt;br /&gt;NOT PROFILED    177    l varchar2(100);&lt;br /&gt;NOT PROFILED    178    begin&lt;br /&gt;LINE RUN        179    loops(1, l);&lt;br /&gt;LINE RUN        180    conditionals;&lt;br /&gt;LINE RUN        181    proc1&lt;br /&gt;NOT PROFILED    182    (&lt;br /&gt;NOT PROFILED    183    1&lt;br /&gt;NOT PROFILED    184    ,&lt;br /&gt;NOT PROFILED    185    l);&lt;br /&gt;LINE RUN        186    GOTO checkloop;&lt;br /&gt;NOT PROFILED    187    &lt;&lt;checkloop&gt;&lt;/checkloop&gt;&gt;&lt;br /&gt;LINE RUN        188    dbms_output.put_line ('a');&lt;br /&gt;LINE RUN        189    end;&lt;br /&gt;NOT PROFILED    190 END what_is_profiled;&lt;/pre&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/267/Analyzing-code-coverage-with-the-PL-SQL-profiler.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: code tester,code coverage,plsql&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/10/Default.aspx&gt;Code Tester for Oracle&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/10/Default.aspx">Code Tester for Oracle</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/267/Analyzing-code-coverage-with-the-PL-SQL-profiler.aspx#Comments</comments>
      <slash:comments>3</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/267/Analyzing-code-coverage-with-the-PL-SQL-profiler.aspx</guid>
      <pubDate>Wed, 27 Aug 2008 22:55:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=267</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/1/Default.aspx">code tester</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/74/Default.aspx">code coverage</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
    </item>
    <item>
      <title>Oracle Open World Presentations</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/252/Oracle-Open-World-Presentations.aspx</link>
      <description>&lt;p&gt;Hey folks, &lt;br /&gt;
 &lt;br /&gt;
For anyone attending Oracle Open World this year, here is my schedule of presentations: &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Session ID: S300184&lt;br /&gt;
Session Title: &lt;strong&gt;Weird PL/SQL&lt;br /&gt;
&lt;/strong&gt;Track: Oracle Develop: Database&lt;br /&gt;
Room: Golden Gate C3&lt;br /&gt;
Date: 2008-09-21&lt;br /&gt;
Start Time: 15:45&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
Session ID: S300183&lt;br /&gt;
Session Title: &lt;strong&gt;Break Your Addiction to SQL!&lt;br /&gt;
&lt;/strong&gt;Track: Oracle Develop: Database&lt;br /&gt;
Room: Salon 02&lt;br /&gt;
Date: 2008-09-22&lt;br /&gt;
Start Time: 13:00
&lt;p&gt; &lt;/p&gt;
Session ID: S300185&lt;br /&gt;
Session Title: &lt;strong&gt;Why You Should Care About Oracle 11g PL/SQL Now&lt;/strong&gt;&lt;br /&gt;
Track: Oracle Develop: Database&lt;br /&gt;
Room: Salon 02&lt;br /&gt;
Date: 2008-09-23&lt;br /&gt;
Start Time: 11:30&lt;/blockquote&gt;
&lt;p&gt; &lt;/p&gt;
Hope to see you there!
&lt;p&gt; &lt;/p&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/252/Oracle-Open-World-Presentations.aspx&gt;More ...&lt;/a&gt;</description>
      <author>Steven Feuerstein</author>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/252/Oracle-Open-World-Presentations.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/252/Oracle-Open-World-Presentations.aspx</guid>
      <pubDate>Tue, 22 Jul 2008 15:41:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=252</trackback:ping>
    </item>
    <item>
      <title>Always Bulk Collect</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/239/Always-Bulk-Collect.aspx</link>
      <description>&lt;div&gt;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 &lt;em&gt;everything&lt;/em&gt;. Far from it.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;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.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;Several years ago, he informed me (and provided a script to verify the statement: 10g_optimize_cfl.sql in the &lt;a href="http://www.toadworld.com/LinkClick.aspx?fileticket=WdgBQ7kABao%3d&amp;tabid=67"&gt;demo.zip&lt;/a&gt;) that in Oracle10g, the compiler now optimizes every cursor FOR loop to execute at a level of performance similar to BULK COLLECT. &lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;This is a wonderful and non-trivial optimization. Rather than have to go through a manual rewrite of all cursor FOR loops, you can leave them in place and reap the benefits of the BULK COLLECT (sort of).&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;Well, that's not quite true – and it's even less true than I thought.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;First of all, if your cursor FOR loop contains any DML statements, you will still want to explicitly convert to BULK COLLECT. The reason is that while the optimizer will improve the performance of the query step, it will &lt;em&gt;not&lt;/em&gt; optimize the DML statements to execute like FORALLs (the bulk processing analogue for updates, inserts and deletes).&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;So if you have code that looks like (cfl_to_bulk_0.sql in &lt;em&gt;&lt;u&gt;&lt;a href="http://www.toadworld.comhttp://www.toadworld.com/LinkClick.aspx?fileticket=WdgBQ7kABao%3d&amp;tabid=67"&gt;demo.zip&lt;/a&gt;&lt;/u&gt;&lt;/em&gt;):&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;&lt;font size="2" face="courier new"&gt;PROCEDURE upd_for_dept (&lt;br /&gt;
   dept_in     IN   employees.department_id%TYPE&lt;br /&gt;
 , newsal_in   IN   employees.salary%TYPE&lt;br /&gt;
)&lt;br /&gt;
IS&lt;br /&gt;
   CURSOR emp_cur&lt;br /&gt;
   IS&lt;br /&gt;
      SELECT employee_id, salary, hire_date&lt;br /&gt;
        FROM employees&lt;br /&gt;
       WHERE department_id = dept_in;&lt;br /&gt;
BEGIN&lt;br /&gt;
   FOR rec IN emp_cur&lt;br /&gt;
   LOOP&lt;br /&gt;
      BEGIN&lt;br /&gt;
         INSERT INTO employee_history&lt;br /&gt;
                     (employee_id, salary, hire_date&lt;br /&gt;
                     )&lt;br /&gt;
              VALUES (rec.employee_id, rec.salary, rec.hire_date&lt;br /&gt;
                     );&lt;br /&gt;
 &lt;br /&gt;
         adjust_compensation (rec.employee_id, rec.salary);&lt;br /&gt;
 &lt;br /&gt;
         UPDATE employees&lt;br /&gt;
            SET salary = newsal_in&lt;br /&gt;
          WHERE employee_id = rec.employee_id;&lt;br /&gt;
      EXCEPTION&lt;br /&gt;
         WHEN OTHERS&lt;br /&gt;
         THEN&lt;br /&gt;
            log_error;&lt;br /&gt;
      END;&lt;br /&gt;
   END LOOP;&lt;br /&gt;
END upd_for_dept;&lt;br /&gt;
&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;/div&gt;
&lt;div&gt;You will need to change the cursor FOR loop to BULK COLLECT so that you can fill up collections with data from the query, which can then be used in the FORALL statement. You will, sadly (due to increased complexity and program length) end up with something like this (cfl_to_bulk_5.sql in &lt;em&gt;&lt;u&gt;&lt;a href="http://www.toadworld.comhttp://www.toadworld.com/LinkClick.aspx?fileticket=WdgBQ7kABao%3d&amp;tabid=67"&gt;demo.zip&lt;/a&gt;&lt;/u&gt;&lt;/em&gt;):&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;&lt;font size="2"&gt;&lt;font size="2" face="courier new"&gt;PROCEDURE upd_for_dept (&lt;br /&gt;
   dept_in     IN   employees.department_id%TYPE&lt;br /&gt;
 , newsal_in   IN   employees.salary%TYPE&lt;br /&gt;
)&lt;br /&gt;
IS&lt;br /&gt;
   bulk_errors    EXCEPTION;&lt;br /&gt;
   PRAGMA EXCEPTION_INIT (bulk_errors, -24381);&lt;br /&gt;
 &lt;br /&gt;
   TYPE employee_tt IS TABLE OF employees.employee_id%TYPE&lt;br /&gt;
      INDEX BY BINARY_INTEGER;&lt;br /&gt;
 &lt;br /&gt;
   employee_ids   employee_tt;&lt;br /&gt;
 &lt;br /&gt;
   TYPE salary_tt IS TABLE OF employees.salary%TYPE&lt;br /&gt;
     INDEX BY BINARY_INTEGER;&lt;br /&gt;
 &lt;br /&gt;
   salaries       salary_tt;&lt;br /&gt;
 &lt;br /&gt;
   TYPE hire_date_tt IS TABLE OF employees.hire_date%TYPE&lt;br /&gt;
      INDEX BY BINARY_INTEGER;&lt;br /&gt;
 &lt;br /&gt;
   hire_dates     hire_date_tt;&lt;br /&gt;
 &lt;br /&gt;
   CURSOR employees_cur&lt;br /&gt;
   IS&lt;br /&gt;
      SELECT     employee_id, salary, hire_date&lt;br /&gt;
            FROM employees&lt;br /&gt;
           WHERE department_id = dept_in&lt;br /&gt;
      FOR UPDATE;&lt;br /&gt;
 &lt;br /&gt;
   PROCEDURE fetch_data_quickly (&lt;br /&gt;
      limit_in           IN       PLS_INTEGER&lt;br /&gt;
    , employee_ids_out   OUT      employee_tt&lt;br /&gt;
    , salaries_out       OUT      salary_tt&lt;br /&gt;
    , hire_dates_out     OUT      hire_date_tt&lt;br /&gt;
   )&lt;br /&gt;
   IS&lt;br /&gt;
   BEGIN&lt;br /&gt;
      FETCH employees_cur&lt;br /&gt;
      BULK COLLECT INTO employee_ids_out, salaries_out, hire_dates_out LIMIT limit_in;&lt;br /&gt;
   END fetch_data_quickly;&lt;br /&gt;
 &lt;br /&gt;
   PROCEDURE adj_comp_for_arrays (&lt;br /&gt;
      employee_ids_io   IN OUT   employee_tt&lt;br /&gt;
    , salaries_io       IN OUT   salary_tt&lt;br /&gt;
   )&lt;br /&gt;
   IS&lt;br /&gt;
   BEGIN&lt;br /&gt;
      FOR indx IN 1 .. employee_ids_io.COUNT&lt;br /&gt;
      LOOP&lt;br /&gt;
         adjust_compensation (employee_ids_io (indx), salaries_io (indx));&lt;br /&gt;
      END LOOP;&lt;br /&gt;
   END adj_comp_for_arrays;&lt;br /&gt;
 &lt;br /&gt;
   PROCEDURE insert_history&lt;br /&gt;
   IS&lt;br /&gt;
   BEGIN&lt;br /&gt;
      FORALL indx IN employee_ids.FIRST .. employee_ids.LAST SAVE EXCEPTIONS&lt;br /&gt;
         INSERT INTO employee_history&lt;br /&gt;
                     (employee_id, salary, hire_date&lt;br /&gt;
                     )&lt;br /&gt;
              VALUES (employee_ids (indx), salaries (indx), hire_dates (indx)&lt;br /&gt;
                     );&lt;br /&gt;
   EXCEPTION&lt;br /&gt;
      WHEN bulk_errors&lt;br /&gt;
      THEN&lt;br /&gt;
         FOR indx IN 1 .. SQL%BULK_EXCEPTIONS.COUNT&lt;br /&gt;
         LOOP&lt;br /&gt;
            -- Log the error&lt;br /&gt;
            log_error&lt;br /&gt;
                     (   'Unable to insert history row for employee '&lt;br /&gt;
                      || employee_ids&lt;br /&gt;
                                     (SQL%BULK_EXCEPTIONS (indx).ERROR_INDEX)&lt;br /&gt;
                    , SQL%BULK_EXCEPTIONS (indx).ERROR_CODE&lt;br /&gt;
                     );&lt;br /&gt;
            /*&lt;br /&gt;
            Communicate this failure to the update phase:&lt;br /&gt;
            Delete this row so that the update will not take place.&lt;br /&gt;
            */&lt;br /&gt;
            employee_ids.DELETE (SQL%BULK_EXCEPTIONS (indx).ERROR_INDEX);&lt;br /&gt;
         END LOOP;&lt;br /&gt;
   END insert_history;&lt;br /&gt;
 &lt;br /&gt;
   PROCEDURE update_employee&lt;br /&gt;
   IS&lt;br /&gt;
   BEGIN&lt;br /&gt;
      /*&lt;br /&gt;
        Use Oracle10g INDICES OF to avoid errors &lt;br /&gt;
        from a sparsely-populated employee_ids collection.&lt;br /&gt;
      */&lt;br /&gt;
      FORALL indx IN INDICES OF employee_ids SAVE EXCEPTIONS&lt;br /&gt;
         UPDATE employees&lt;br /&gt;
            SET salary = newsal_in&lt;br /&gt;
              , hire_date = hire_dates (indx)&lt;br /&gt;
          WHERE employee_id = employee_ids (indx);&lt;br /&gt;
   EXCEPTION&lt;br /&gt;
      WHEN bulk_errors&lt;br /&gt;
      THEN&lt;br /&gt;
         FOR indx IN 1 .. SQL%BULK_EXCEPTIONS.COUNT&lt;br /&gt;
         LOOP&lt;br /&gt;
            log_error&lt;br /&gt;
                     (   'Unable to update salary for employee '&lt;br /&gt;
                      || employee_ids&lt;br /&gt;
                                     (SQL%BULK_EXCEPTIONS (indx).ERROR_INDEX)&lt;br /&gt;
                    , SQL%BULK_EXCEPTIONS (indx).ERROR_CODE&lt;br /&gt;
                     );&lt;br /&gt;
         END LOOP;&lt;br /&gt;
   END update_employee;&lt;br /&gt;
BEGIN&lt;br /&gt;
   OPEN employees_cur;&lt;br /&gt;
 &lt;br /&gt;
   LOOP&lt;br /&gt;
      fetch_data_quickly (100, employee_ids, salaries, hire_dates);&lt;br /&gt;
      EXIT WHEN employee_ids.COUNT = 0;&lt;br /&gt;
      insert_history;&lt;br /&gt;
      adj_comp_for_arrays (employee_ids, salaries);&lt;br /&gt;
      update_employee;&lt;br /&gt;
   END LOOP;&lt;br /&gt;
END upd_for_dept;&lt;br /&gt;
&lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;/div&gt;
&lt;div&gt;Sorry, I know that I should probably explain this code but to be brutally honest my dad had heart bypass surgery and I am currently at the hospital and so you get the abbreviated version ....&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;Anyway, that is one scenario where you definitely need to convert from the cursor FOR loop. &lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;But Bryn, to my surprise, recommends that you &lt;em&gt;always&lt;/em&gt; convert explicitly to BULK COLLECT. Why is that? For performance reasons. Apparently, the cursor FOR loop optimization makes the code run faster, but not as quickly as BULK COLLECT.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;In my tests (which you can reproduce in cfl_vs_bulkcollect.sql), I found that BULK COLLECT ran 33% faster than the cursor FOR loop:&lt;/div&gt;
&lt;p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Cursor For Loop Elapsed: 8.12 seconds.&lt;/li&gt;
    &lt;li&gt;Bulk Collect Elapsed: 5.46 seconds. &lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;So if you really want the best performance, take the time and make the effort to switch over to BULK COLLECT.&lt;br /&gt;
 &lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/239/Always-Bulk-Collect.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,oracle,bulk collect,cursor for loop&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/239/Always-Bulk-Collect.aspx#Comments</comments>
      <slash:comments>4</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/239/Always-Bulk-Collect.aspx</guid>
      <pubDate>Mon, 23 Jun 2008 14:34:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=239</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/54/Default.aspx">bulk collect</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/55/Default.aspx">cursor for loop</blog:tag>
    </item>
    <item>
      <title>How to Run an OS Command from PL/SQL</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/228/How-to-Run-an-OS-Command-from-PL-SQL.aspx</link>
      <description>&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;As I understand it, there are basically three ways to do this:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Invoke a Java method from within a PL/SQL wrapper&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;Call a C program as an external procedure from within PL/SQL.&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;Use the new DBMS_SCHEDULER package.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;&lt;font size="3"&gt;&lt;strong&gt;Executing Host Command with Java&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;With the Java approach, you will take these steps:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Find the Java class that implements host command execution.&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;Build a class that invokes that host command method. Let's call it HostCommand.&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;Build a PL/SQL program that calls a method in HostCommand to run your command.&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;Acquire the privileges needed to execute host commands via Java in the database.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let's go through each of these steps.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Find the Java class that implements host command execution.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Objects of the java.lang.Runtime class include an exec method that will execute a host command.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Build a class that invokes that host command method.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let's call it HostCommand.&lt;/p&gt;
&lt;p&gt;Here's code to create a new Java class in the database to invoke this command for the Windows XP operating system:&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "UTLcmd"&lt;br /&gt;AS import java.lang.Runtime;&lt;br /&gt;public class execHostCommand&lt;br /&gt;{ &lt;br /&gt;  public static void execute (String command) &lt;br /&gt;    throws java.io.IOException&lt;br /&gt;  {&lt;br /&gt;   String osName = System.getProperty("os.name");&lt;br /&gt;   if(osName.equals("Windows XP"))&lt;br /&gt;       command = "cmd /c " + command;&lt;br /&gt;   Runtime rt = java.lang.Runtime.getRuntime();&lt;br /&gt;   rt.exec(command);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;/&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can easily modify the execute method to support other operating systems based on the value of osName.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Build a PL/SQL program that calls a method in HostCommand to run your command.&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;CREATE OR REPLACE PACKAGE host_command IS&lt;br /&gt;  PROCEDURE execute (cmd IN VARCHAR2) AS LANGUAGE JAVA NAME&lt;br /&gt;           'execHostCommand.execute(java.lang.String)';&lt;br /&gt;END;&lt;br /&gt;/&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;Notice that I "map" the VARCHAR2 datatype to the java.lang.String class in my call to the new Java method.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Acquire the privileges needed to execute host commands via Java in the database.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;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):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;img alt="" width="449" height="178" src="/Portals/0/blogimages/sf_blog060408.gif" /&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;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).&lt;/p&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;BEGIN&lt;br /&gt;   DBMS_JAVA.grant_permission ('HR'&lt;br /&gt;                             , 'SYS:java.io.FilePermission'&lt;br /&gt;                             , '&lt;&lt;all files=""&gt;&lt;/all&gt;&gt;'&lt;br /&gt;                             , 'execute'&lt;br /&gt;                              );&lt;br /&gt;   DBMS_JAVA.grant_permission ('HR'&lt;br /&gt;                             , 'SYS:java.lang.RuntimePermission'&lt;br /&gt;                             , 'writeFileDescriptor'&lt;br /&gt;                             , ''&lt;br /&gt;                              );&lt;br /&gt;   DBMS_JAVA.grant_permission ('HR'&lt;br /&gt;                             , 'SYS:java.lang.RuntimePermission'&lt;br /&gt;                             , 'readFileDescriptor'&lt;br /&gt;                             , ''&lt;br /&gt;                              );&lt;br /&gt;END;&lt;br /&gt;/&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;font size="3"&gt;&lt;strong&gt;Executing Host Command with C&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;As with Java, you will need help from your database administrator to supply the privileges needed to execute your host command in C.&lt;/p&gt;
&lt;p&gt;Here are the steps to follow with C:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Find (or build) the C program that implements host command execution.&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;Save the C source to a file and generate a shared library for it.&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;Save the library file where Oracle can find it.&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;Define a library inside Oracle that is associated with the shared library on disk.&lt;br /&gt;
     &lt;/li&gt;
    &lt;li&gt;Create a PL/SQL wrapper for the C function.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let's go through each of these steps.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Find (or build) the C program that implements host command execution.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;int extprocsh(char *cmd)&lt;br /&gt;{&lt;br /&gt;   return system(cmd);&lt;br /&gt;}&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Save the C source to a file and generate a shared library for it.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;gcc -m64 extprocsh.c -fPIC -G -o extprocsh.so&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;c:\MinGW\bin\gcc extprocsh.c -shared -o extprocsh.dll&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;3. Save the library file where Oracle can find it.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;$ORACLE_HOME/bin&lt;br /&gt;$ORACLE_HOME/lib&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;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...".&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Define a library inside Oracle that is associated with the shared library on disk.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;CREATE OR REPLACE LIBRARY extprocshell_lib &lt;br /&gt;   AS '/u01/app/oracle/local/lib/extprocsh.so';   -- Unix&lt;br /&gt;     &lt;br /&gt;CREATE OR REPLACE LIBRARY extprocshell_lib&lt;br /&gt;   AS 'c:\oracle\local\lib\extprocsh.dll';      -- Microsoft&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; performing this step requires Oracle's CREATE LIBRARY privilege.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Create a PL/SQL wrapper for the C function.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now I can create a PL/SQL call specification which uses the newly created library:&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;CREATE OR REPLACE FUNCTION exec_host_command (cmd IN VARCHAR2)&lt;br /&gt;   RETURN PLS_INTEGER&lt;br /&gt;AS&lt;br /&gt;   LANGUAGE C&lt;br /&gt;   LIBRARY extprocshell_lib&lt;br /&gt;   NAME "extprocsh"&lt;br /&gt;   PARAMETERS (cmd STRING, RETURN INT);&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Note that these operating system commands will execute with the same privileges as the Oracle Net listener that spawns the extproc process.&lt;/p&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/228/How-to-Run-an-OS-Command-from-PL-SQL.aspx&gt;More ...&lt;/a&gt;&lt;div class="tags"&gt;Tags: plsql,oracle,os command&lt;/div&gt;&lt;div class="category"&gt;Category: &lt;a href=http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx&gt;PL/SQL Obsession&lt;/a&gt;&lt;/div&gt;</description>
      <author>Steven Feuerstein</author>
      <category domain="http://www.toadworld.com/BLOGS/tabid/67/CatID/15/Default.aspx">PL/SQL Obsession</category>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/228/How-to-Run-an-OS-Command-from-PL-SQL.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/228/How-to-Run-an-OS-Command-from-PL-SQL.aspx</guid>
      <pubDate>Wed, 04 Jun 2008 14:11:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=228</trackback:ping>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/5/Default.aspx">plsql</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/2/Default.aspx">oracle</blog:tag>
      <blog:tag blog:url="http://www.toadworld.com/BLOGS/tabid/67/TagID/53/Default.aspx">os command</blog:tag>
    </item>
    <item>
      <title>Testing and refreshing data from production</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/204/Testing-and-refreshing-data-from-production.aspx</link>
      <description>&lt;div&gt;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.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;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.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;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.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;Here's the way this belief was expressed by a customer recently:&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;"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."&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;"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."&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;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.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;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.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;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.&lt;/div&gt;
&lt;div&gt;In fact, I think that when it comes to &lt;em&gt;functional testing of your programs &lt;/em&gt;(does it meet user requirements?), you should &lt;em&gt;not&lt;/em&gt; be refreshing your test tables from production. To understand why I would say this, let's talk about....&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;&lt;em&gt;&lt;font size="3"&gt;How we make sure our programs work&lt;br /&gt;
 &lt;/font&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;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.&lt;/div&gt;
&lt;div&gt; &lt;br /&gt;
&lt;a href="http://unittest.inside.quest.com/index.jspa"&gt;Quest Code Tester&lt;/a&gt; is designed specifically to help you implement tests on functional requirements; in essence, to verify that your program is correct.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;To do this, I will almost always want to compare the actual results of running my program with the expected results or control data. &lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;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.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;In general, there is no room for ambiguity here. Either the program works as expected or it does not. &lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;Now, if I want to build regression tests and &lt;em&gt;automate&lt;/em&gt; 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. &lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;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.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;Every time you refresh data from production, you change the values in your table and thus you cannot reliably execute your regression test.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;&lt;em&gt;&lt;font size="3"&gt;But don't we need real production data to really test?&lt;br /&gt;
 &lt;/font&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;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.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;Clearly, our code does need to work properly with production data.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;This does not mean, however, that you need to constantly change the data for your functional tests as production data changes. It &lt;em&gt;does&lt;/em&gt; mean that the data used in functional tests should &lt;em&gt;represent&lt;/em&gt; the variety of data found in production. &lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;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 &lt;em&gt;the same&lt;/em&gt; as that found in production.&lt;/div&gt;
&lt;div&gt;And, again, if you keep changing the test data, you must also change your test definition.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;&lt;em&gt;&lt;font size="3"&gt;OK, but don’t we need to test against production volume?&lt;br /&gt;
 &lt;/font&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;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. &lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;You certainly do need to make sure your code executes with production volumes of data. But that sort of &lt;em&gt;stress testing&lt;/em&gt; should be done independently of your functionality testing. With functionality testing, you want your tests to run as quickly as possible, for these reasons:&lt;/div&gt;
&lt;ul type="disc"&gt;
    &lt;li&gt;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.&lt;br /&gt;
      &lt;/li&gt;
    &lt;li&gt;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. &lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;strong&gt;&lt;em&gt;&lt;font size="3"&gt;Conclusion: Segregate your functional test environment&lt;br /&gt;
 &lt;/font&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;The most important thing to verify about your program is that it is &lt;em&gt;correct&lt;/em&gt;: it meets user requirements. &lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;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. &lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;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 &lt;em&gt;not&lt;/em&gt; 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.]&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;In addition, you want regression tests to run as efficiently as possible. These tests focus on program functionality, not performance. So you want the &lt;em&gt;minimum &lt;/em&gt;volume of data in test tables that allow you to cover your requirements. Use different tests to verify adequate performance.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;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.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/204/Testing-and-refreshing-data-from-production.aspx&gt;More ...&lt;/a&gt;</description>
      <author>Steven Feuerstein</author>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/204/Testing-and-refreshing-data-from-production.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/204/Testing-and-refreshing-data-from-production.aspx</guid>
      <pubDate>Thu, 17 Apr 2008 16:21:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=204</trackback:ping>
    </item>
    <item>
      <title>Auto-formatting of templates for Toad</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/200/Auto-formatting-of-templates-for-Toad.aspx</link>
      <description>&lt;div&gt;A few months ago, I posted on this blog an explanation of how to use Toad's Code Templates to standardize development and improve productivity. I included an XML document that contains over 20 templates that I thought you might find useful. I also asked my readers to produce XML transformations so that the XML document could be "output" in the format that Toad recognizes (and SQL Navigator as well).&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I am happy to say that Sean Gilbert has done this for Toad 8 and is working on a transformation for Toad 9.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;For more information, check out &lt;a href="https://getonthetrail.blogsite.org/Blog/post/2008/04/Transform-Custom-TOAD-XML-Template-with-XSLT.aspx"&gt;https://getonthetrail.blogsite.org/Blog/post/2008/04/Transform-Custom-TOAD-XML-Template-with-XSLT.aspx&lt;/a&gt;. &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Thanks, Sean!&lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/200/Auto-formatting-of-templates-for-Toad.aspx&gt;More ...&lt;/a&gt;</description>
      <author>Steven Feuerstein</author>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/200/Auto-formatting-of-templates-for-Toad.aspx#Comments</comments>
      <slash:comments>2</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/200/Auto-formatting-of-templates-for-Toad.aspx</guid>
      <pubDate>Thu, 10 Apr 2008 16:14:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=200</trackback:ping>
    </item>
    <item>
      <title>Weird PL/SQL</title>
      <link>http://www.toadworld.com/BLOGS/tabid/67/EntryId/187/Weird-PL-SQL.aspx</link>
      <description>&lt;div&gt; &lt;br /&gt;
Collaborate08, annual conference of the International Oracle User Group, and several other national and international user groups, will be held in Denver this year, from April 13th to the 16&lt;sup&gt;th&lt;/sup&gt;. I am going to present three papers, including (for the first time) &lt;em&gt;Weird PL/SQL&lt;/em&gt;. I thought you might enjoy reading about some of the weirdnesses of PL/SQL in my ToadWorld blog, so here's an excerpt from the beginning of my whitepaper:&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;&lt;font size="3"&gt;&lt;font size="-0"&gt;Introduction&lt;/font&gt;&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;You probably think that PL/SQL is rather ordinary programming language. Well, it truly is a very powerful and straightforward language, but there are some features "less traveled" which can seem nothing less than &lt;em&gt;weird&lt;/em&gt;. This presentation explores some of  stranger nooks and crannies of the PL/SQL language, perhaps in the process making them a little bit less weird to the everyday programmer.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;All the code I reference in this paper is available at my PL/SQL Obsession site: www.ToadWorld.com/SF. Just click on the "Trainings" link and then click on the "demo.zip" link.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;Disclosure: I will poke fun at Oracle, the PL/SQL language, and implicitly the folks who are responsible for building and enhancing PL/SQL. Please know that it is all done in a spirit of deep appreciation for what PL/SQL (and its developers) has done for me and so many others around the world. But, hey, there's always room for improvement and you've got to keep a sense of humor about all this stuff!&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;&lt;font size="3"&gt;Error Codes: Negative or Positive? Make up your mind, Oracle!&lt;/font&gt;&lt;br /&gt;
  &lt;br /&gt;
&lt;/strong&gt;I really would have thought that Oracle would have sorted this out by now. Here's the issue:&lt;/p&gt;
&lt;div&gt;When you see this string:&lt;/div&gt;
&lt;pre&gt;ORA-01855&lt;/pre&gt;
&lt;div&gt;do you interpret the "-" character as a &lt;em&gt;hyphen&lt;/em&gt; or a &lt;em&gt;negative sign&lt;/em&gt;? &lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;I always considered it to be a negative sign, and that just about every single error code in the world of Oracle is negative. The only exceptions are 1 (user-defined exception) and 100 ("No data found" – which is another little weirdness in PL/SQL. The "No data found" exception has &lt;em&gt;two &lt;/em&gt;error codes: 100 and -1403).&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;Yet sometimes Oracle treats the error codes as positive numbers, most notably when using the SAVE EXCEPTIONS clause of FORALL. When you include SAVE EXCEPTIONS, Oracle "saves up" any exceptions it encounters as it executes all the DML statements specified by the bind array. Then if at least one error occurred, it raises the ORA-24381 exception (Argh! Sometimes I worry about all the little bits of information that are stuck in my head!). It also populates the SQL%BULK_EXCEPTIONS pseudo-collection with all the exceptions that were raised. &lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;Here's an example of a program that uses this feature:&lt;/div&gt;
&lt;pre&gt;/* bulkexc.sql */&lt;br /&gt;DECLARE&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;bulk_errors&lt;span&gt;          &lt;/span&gt;EXCEPTION;&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;PRAGMA EXCEPTION_INIT (&lt;span&gt;bulk_errors,&lt;/span&gt; -&lt;span&gt;24381);&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span&gt;   &lt;/span&gt;TYPE namelist_t IS TABLE OF VARCHAR2 (&lt;span&gt;1000);&lt;/span&gt; &lt;/pre&gt;
&lt;pre&gt;&lt;span&gt;   &lt;/span&gt;enames_with_errors&lt;span&gt;   &lt;/span&gt;namelist_t&lt;br /&gt;&lt;span&gt;      &lt;/span&gt;:= namelist_t (&lt;span&gt;'ABC'&lt;br /&gt;&lt;/span&gt;&lt;span&gt;                   &lt;/span&gt;, 'DEF'&lt;br /&gt;&lt;span&gt;                   &lt;/span&gt;, NULL&lt;br /&gt;&lt;span&gt;                   &lt;/span&gt;, 'LITTLE'&lt;br /&gt;&lt;span&gt;                   &lt;/span&gt;, RPAD (&lt;span&gt;'BIGBIGGERBIGGEST',&lt;/span&gt; 250, 'ABC')&lt;br /&gt;&lt;span&gt;                   &lt;/span&gt;, 'SMITHIE'&lt;br /&gt;&lt;span&gt;                    &lt;/span&gt;);&lt;br /&gt;BEGIN&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;FORALL indx IN enames_with_errors.FIRST .. enames_with_errors.LAST SAVE EXCEPTIONS&lt;br /&gt;&lt;span&gt;      &lt;/span&gt;UPDATE employees&lt;br /&gt;&lt;span&gt;         &lt;/span&gt;SET last_name = enames_with_errors (&lt;span&gt;indx);&lt;br /&gt;&lt;/span&gt;&lt;span&gt;   &lt;/span&gt;ROLLBACK;&lt;br /&gt;EXCEPTION&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;WHEN bulk_errors&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;THEN&lt;br /&gt;&lt;span&gt;      &lt;/span&gt;FOR indx IN 1 .. SQL%BULK_EXCEPTIONS.COUNT&lt;br /&gt;&lt;span&gt;      &lt;/span&gt;LOOP&lt;br /&gt;&lt;span&gt;         &lt;/span&gt;DBMS_OUTPUT.put_line (&lt;span&gt;   &lt;/span&gt;'Error '&lt;br /&gt;&lt;span&gt;                               || &lt;/span&gt;indx&lt;br /&gt;&lt;span&gt;                               || &lt;/span&gt;' occurred on index '&lt;br /&gt;&lt;span&gt;                               || &lt;/span&gt;SQL%BULK_EXCEPTIONS (&lt;span&gt;indx).ERROR_INDEX&lt;br /&gt;&lt;/span&gt;&lt;span&gt;                               || &lt;/span&gt;' with error code '&lt;br /&gt;&lt;span&gt;                               || &lt;/span&gt;SQL%BULK_EXCEPTIONS (&lt;span&gt;indx).ERROR_CODE&lt;br /&gt;&lt;/span&gt;&lt;span&gt;                              &lt;/span&gt;);&lt;br /&gt;&lt;span&gt;      &lt;/span&gt;END LOOP; &lt;/pre&gt;
&lt;pre&gt;&lt;span&gt;      &lt;/span&gt;ROLLBACK;&lt;br /&gt;END;&lt;br /&gt;/&lt;/pre&gt;
&lt;div&gt;And this is what I see when I run the program:&lt;/div&gt;
&lt;pre&gt;Error 1 occurred on index 3 with error code 1407&lt;br /&gt;Error 2 occurred on index 5 with error code 12899&lt;/pre&gt;
&lt;div&gt;Hmmm. Oracle returns the error code as a positive number! So if I want to use SQLERRM to look up the error message for that code, I have to multiply it by -1:&lt;/div&gt;
&lt;pre&gt;FOR indx IN 1 .. SQL%BULK_EXCEPTIONS&lt;span&gt;.COUNT&lt;br /&gt;&lt;/span&gt;LOOP&lt;br /&gt;&lt;span&gt;   &lt;/span&gt;DBMS_OUTPUT.put_line&lt;br /&gt;&lt;span&gt;                      &lt;/span&gt;(&lt;span&gt;   &lt;/span&gt;'Error '&lt;br /&gt;&lt;span&gt;                       || &lt;/span&gt;indx&lt;br /&gt;&lt;span&gt;                       || &lt;/span&gt;' occurred on index '&lt;br /&gt;&lt;span&gt;                       || &lt;/span&gt;SQL%BULK_EXCEPTIONS (indx&lt;span&gt;).ERROR_INDEX&lt;br /&gt;&lt;/span&gt;&lt;span&gt;                       || &lt;/span&gt;' with error '&lt;br /&gt;&lt;span&gt;                       || &lt;/span&gt;SQLERRM&lt;br /&gt;&lt;span&gt;                                &lt;/span&gt;( -1&lt;br /&gt;&lt;span&gt;                                 * &lt;/span&gt;SQL%BULK_EXCEPTIONS (indx&lt;span&gt;).ERROR_CODE&lt;br /&gt;&lt;/span&gt;&lt;span&gt;                                &lt;/span&gt;)&lt;br /&gt;&lt;span&gt;                      &lt;/span&gt;);&lt;br /&gt;END LOOP;&lt;/pre&gt;
&lt;div&gt;And then I see this output:&lt;/div&gt;
&lt;pre&gt;Error 1 occurred on index 3 with error ORA-01407: cannot update () to NULL&lt;br /&gt;Error 2 occurred on index 5 with error ORA-12899: value too large for column &lt;/pre&gt;
&lt;p&gt;It would be nice if Larry would decide once and for all if error codes are positive or negative, and then &lt;em&gt;lay down the law.&lt;/em&gt; &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;font size="3"&gt;SQLERRM and DBMS_OUTPUT.PUT_LINE&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;Speaking of SQLERRM....let's talk about everybody's favorite program: DBMS_OUTPUT.PUT_LINE. For many, many years – all the way up to the release of Oracle Database 10g Release 2, if you tried to display a string of more than 255 characters with DBMS_OUTPUT.PUT_LINE, that built-in would raise an exception. This caused no end of teeth-gnashing and anguished moans from developers over the year. Fortunately, that restriction was lifted in Oracle Database 10g Release 2 – you can now display up to 32K characters. &lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;But there is still a problem with SQLERRM. We all know about SQLERRM. You call it to return the error message for the current error (obtained by calling SQLCODE). Did you know, however, that Oracle recommends that you &lt;em&gt;not use this function&lt;/em&gt;,. and instead call DBMS_UTILITY.FORMAT_ERROR_STACK? &lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;Why would that be? The problem is that SQLERRM may truncate your error message. In earlier versions of Oracle, truncated occurred at 255 characters. Now, it is 512. DBMS_UTILITY.FORMAT_ERROR_STACK, on the other hand, returns strings of up to 2000 bytes. &lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;I can just picture some developer years and years ago, confronted with a nasty problem:&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;He has found that SQLERRM can return error messages that get quite long, depending on application-specific information, like the names of identifiers. And when you try to display that string with DBMS_OUTPUT.PUT_LINE, an exception is raised.&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;What's a developer to do?&lt;/div&gt;
&lt;blockquote style="margin-right: 0px;" dir="ltr"&gt;
&lt;div&gt;&lt;span&gt;1.&lt;span&gt;       &lt;/span&gt;&lt;/span&gt;Fix DBMS_OUTPUT.PUT_LINE so it displays longer strings.&lt;/div&gt;
&lt;blockquote style="margin-right: 0px;" dir="ltr"&gt;
&lt;div&gt;or&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div&gt;&lt;span&gt;2.&lt;span&gt;       &lt;/span&gt;&lt;/span&gt;Truncate your error message.&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div&gt;Well, obviously, the solution is to truncate the error message!&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;Isn't that weird?&lt;br /&gt;
 &lt;/div&gt;
&lt;div&gt;I am &lt;em&gt;so &lt;/em&gt;glad the PL/SQL team finally got around to fixing DBMS_OUTPUT.PUT_LINE! And according to the PL/SQL development manager at the time, all they had to was change one number!&lt;br /&gt;
 &lt;br /&gt;
So...there's a little bit of weirdness in PL/SQL...more to come at Collaborate08 and this blog.&lt;/div&gt;
&lt;div&gt;  &lt;/div&gt;&lt;br /&gt;&lt;a href=http://www.toadworld.com/BLOGS/tabid/67/EntryId/187/Weird-PL-SQL.aspx&gt;More ...&lt;/a&gt;</description>
      <author>Steven Feuerstein</author>
      <comments>http://www.toadworld.com/BLOGS/tabid/67/EntryId/187/Weird-PL-SQL.aspx#Comments</comments>
      <slash:comments>0</slash:comments>
      <guid isPermaLink="true">http://www.toadworld.com/BLOGS/tabid/67/EntryId/187/Weird-PL-SQL.aspx</guid>
      <pubDate>Mon, 17 Mar 2008 19:57:00 GMT</pubDate>
      <trackback:ping>http://www.toadworld.comDesktopModules/BlogTrackback.aspx?id=187</trackback:ping>
    </item>
  </channel>
</rss>