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

<channel>
	<title>Oracle SQLOracle SQL</title>
	<atom:link href="http://orasql.org/feed/" rel="self" type="application/rss+xml" />
	<link>http://orasql.org</link>
	<description>XTended Oracle SQL</description>
	<lastBuildDate>Tue, 21 May 2013 23:29:06 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>SQL*Plus tips #6: Colorizing output</title>
		<link>http://orasql.org/2013/05/22/sqlplus-tips-6-colorizing-output/</link>
		<comments>http://orasql.org/2013/05/22/sqlplus-tips-6-colorizing-output/#comments</comments>
		<pubDate>Tue, 21 May 2013 23:29:06 +0000</pubDate>
		<dc:creator>Sayan Malakshinov</dc:creator>
				<category><![CDATA[oracle]]></category>
		<category><![CDATA[SQL*Plus]]></category>

		<guid isPermaLink="false">http://orasql.org/?p=292</guid>
		<description><![CDATA[If you have seen a colored scripts like a fish from &#8220;Session Snapper v.4&#8243; by Tanel Poder or OraLatencyMap by Luca Canali, you may be also want to colorize your scripts. I&#8217;ve created the script for this purposes with predefined substitution variables. Just download colors.sql and use it like that: You&#8217;l get something like this: [...]]]></description>
				<content:encoded><![CDATA[<img src="http://orasql.org/wp-content/plugins/simple-feed-stats/tracker.php?sfs_tracking=true&amp;feed_type=feed&amp;v=1902497" width="1" height="1" alt=""> <p>If you have seen a colored scripts like a fish from <a href="http://blog.tanelpoder.com/2013/02/10/session-snapper-v4-the-worlds-most-advanced-oracle-troubleshooting-script/" title="Session Snapper v.4" target="_blank">&#8220;Session Snapper v.4&#8243;</a> by <a href="http://blog.tanelpoder.com/" title="Tanel Poder" target="_blank">Tanel Poder</a> or <a href="http://externaltable.blogspot.ru/2013/05/latency-heat-map-in-sqlplus-with.html" target="_blank">OraLatencyMap</a> by <a href="http://www.blogger.com/profile/06252662329568134677" target="_blank">Luca Canali</a>, you may be also want to colorize your scripts.<br />
I&#8217;ve created the script for this purposes with predefined substitution variables.<br />
Just download <a href="http://orasql.org/scripts/colors.sql" title="colors.sql" target="_blank">colors.sql</a> and use it like that:</p>
<pre class="brush: sql; title: ; notranslate">
@colors.sql;
prompt ::: &amp;_C_RED ***  TEST PASSED  *** &amp;_C_RESET :::
prompt ::: &amp;_C_RED *** &amp;_C_BLINK TEST PASSED &amp;_C_BLINK_OFF *** &amp;_C_RESET :::
</pre>
<p>You&#8217;l get something like this:<br />
<a href="http://orasql.org/wp-content/uploads/2013/05/sqltips6.png"><img src="http://orasql.org/wp-content/uploads/2013/05/sqltips6.png" alt="sqltips6" width="50%" class="alignnone size-full wp-image-293" /></a><br />

<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: List of variables</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv1dff8001"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv1dff8001",true,"Show","Hide","fast",false); return false;' id='spoilerDiv1dff8001_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv1dff8001' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>
</p>
<table border=1 style="font-size:0.8em;line-height:80%;">
<tr>
<th>Description</th>
<th>Variable</th>
</tr>
<tr>
<td>
_C_RESET         </td>
<td>Reset formatting &#8211; Turn off all attributes</td>
</tr>
<tr>
<td>
_C_BOLD          <br/><br />
_C_BOLD_OFF      </td>
<td><b>Set bright mode on/off</b> </td>
</tr>
<tr>
<td>
_C_UNDERLINE     <br/><br />
_C_UNDERLINE_OFF </td>
<td><u>Set underline mode on/off</u> </td>
</tr>
<tr>
<td>
_C_BLINK         <br/><br />
_C_BLINK_OFF     </td>
<td>Set blink mode on/off </td>
</tr>
<tr>
<td>
_C_REVERSE       <br/><br />
_C_REVERSE_OFF   </td>
<td>Exchange foreground and background colors </td>
</tr>
<tr>
<td>
_C_HIDE          <br/><br />
_C_HIDE_OFF      </td>
<td>Hide text (foreground color would be the same as background)</td>
</tr>
<tr>
<td>
_C_BLACK        <br/><br />
_C_RED          <br/><br />
_C_GREEN        <br/><br />
_C_YELLOW       <br/><br />
_C_BLUE         <br/><br />
_C_MAGENTA      <br/><br />
_C_CYAN         <br/><br />
_C_WHITE        <br/><br />
_C_DEFAULT      </td>
<td>Font colors </td>
</tr>
<tr>
<td>
_CB_BLACK       <br/><br />
_CB_RED         <br/><br />
_CB_GREEN       <br/><br />
_CB_YELLOW      <br/><br />
_CB_BLUE        <br/><br />
_CB_MAGENTA     <br/><br />
_CB_CYAN        <br/><br />
_CB_WHITE       <br/><br />
_CB_DEFAULT     </td>
<td>Background colors </td>
</tr>
</table>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
<br />
In addition, i want to show simple example of printing histograms.<br />
We can simple print histogram with query:<br />

<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: Сolorless histogram</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv41468002"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv41468002",true,"Show","Hide","fast",false); return false;' id='spoilerDiv41468002_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv41468002' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
-- loading colors variables:
@inc/colors;
-- set max length of bar:
def _max_length=80;
-- columns formatting:
col bar format a&amp;_max_length;
-- clear screen:
prompt &amp;_CLS
with t as (-- it's just a test values for example:
            select level id
                 , round(dbms_random.value(1,100)) val 
            from dual 
            connect by level&lt;=10
          )
select t.* 
      -- bar length is just &quot; (value / max_value) * max_length&quot; in symbols:
      ,floor( val * &amp;_max_length / max(val)over() 
            ) as bar_length
      -- generating of bar:
      ,lpad( chr(176)
            ,ceil(val * &amp;_max_length / max(val)over())
            ,chr(192)
           ) as bar
from t;
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
<br />
<a href="http://orasql.org/wp-content/uploads/2013/05/sqltips6-1.png"><img src="http://orasql.org/wp-content/uploads/2013/05/sqltips6-1.png" alt="sqltips6-1" width="50%" class="alignnone size-full wp-image-301" /></a><br />
And now we can colorize it:<br />

<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: Colorized script</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv6178003"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv6178003",true,"Show","Hide","fast",false); return false;' id='spoilerDiv6178003_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv6178003' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
-- loading colors variables:
@inc/colors;
-- set max length of bar:
def _max_length=100;
-- column formatting
col bar format a&amp;_max_length;
-- clear screen:
prompt &amp;_CLS

-- test query which prints histogram(or may be simply bars?):
with t as (-- it's just a test values for example:
            select level id
                 , round(dbms_random.value(1,100)) val 
            from dual 
            connect by level&lt;=10
          )
select 
       id
      ,val
      , case 
           when pct &gt;= 0.9 then '&amp;_C_RED' 
           when pct &lt;= 0.4 then '&amp;_C_GREEN'
           else '&amp;_C_YELLOW'
        end 
        -- string generation:
      ||lpad( chr(192)
             ,ceil(pct * &amp;_max_length)-9 -- color - 5 chars and reset - 4
             ,chr(192)
            )
      ||'&amp;_C_RESET'
       as bar
from (
     select 
        t.*
       ,val / max(val)over() as pct -- as a percentage of max value:
     from t
     ) t2
/
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
<br />
<a href="http://orasql.org/wp-content/uploads/2013/05/sqltips6-2.png"><img src="http://orasql.org/wp-content/uploads/2013/05/sqltips6-2.png" alt="sqltips6-2" width="40%" class="alignnone size-full wp-image-302" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://orasql.org/2013/05/22/sqlplus-tips-6-colorizing-output/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL*Plus tips #5: sql_text/sql_fulltext formatting(sql beatifier)</title>
		<link>http://orasql.org/2013/04/29/sql_text-formatting-sql-beatifier/</link>
		<comments>http://orasql.org/2013/04/29/sql_text-formatting-sql-beatifier/#comments</comments>
		<pubDate>Mon, 29 Apr 2013 19:53:18 +0000</pubDate>
		<dc:creator>Sayan Malakshinov</dc:creator>
				<category><![CDATA[oracle]]></category>
		<category><![CDATA[SQL*Plus]]></category>

		<guid isPermaLink="false">http://orasql.org/?p=282</guid>
		<description><![CDATA[Sometimes I get tired of watching unformatted query text from v$sqlarea, dba_hist_sqltext in SQL*Plus, so I decided to include automatic query formatting in my scripts. I thought that there are many libraries for such purposes on languages which i know, and it&#8217;s true, but it turned out that many of them are not appropriate for [...]]]></description>
				<content:encoded><![CDATA[<p>Sometimes I get tired of watching unformatted query text from v$sqlarea, dba_hist_sqltext in SQL*Plus, so I decided to include automatic query formatting in my scripts.<br />
I thought that there are many libraries for such purposes on languages which i know, and it&#8217;s true, but it turned out that many of them are not appropriate for Oracle.<br />
So I took the most appropriate &#8211; perl module <a href="http://search.cpan.org/~jkramer/SQL-Beautify-0.04/" title=""SQL::Beautify" by Jonas Kramer" target="_blank">SQL::Beautify</a> and corrected it. Now i can share my first solution.</p>
<p>How it looks:<br />
<a href="http://orasql.org/wp-content/uploads/2013/04/sql_textf.png"><img src="http://orasql.org/wp-content/uploads/2013/04/sql_textf.png" alt="sql_textf" width="80%" class="alignnone size-full wp-image-283" /></a></p>
<p>What you need to do it:<br />
1. If you on Windows and you have not install Oracle RDBMS or cygwin, you need to install perl. It can be done for example with <a href="http://www.activestate.com/activeperl">ActivePerl</a> or <a href="http://strawberryperl.com/">StrawberryPerl</a>, but i recommend <a href="http://www.cygwin.com/">cygwin</a><br />
2. You need to save <a href="http://orasql.org/scripts/sql_format_standalone.pl" title="inc/sql_format_standalone.pl" target="_blank">sql_format_standalone.pl</a> within <strong><em>$SQL_PATH</em>/inc</strong> directory.<br />

<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: inc/sql_format_standalone.pl</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv7c48004"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv7c48004",true,"Show","Hide","fast",false); return false;' id='spoilerDiv7c48004_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv7c48004' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
package OraTokenizer;

use warnings;
use strict;

use 5.006002;

use Exporter;

our @ISA = qw(Exporter);

our @EXPORT_OK= qw(tokenize_sql);

our $VERSION= '0.24';

my $re= qr{
    (
        (?:--)[\ \t\S]*      # single line comments
        |
        (?:&lt;&gt;|&lt;=&gt;|&gt;=|&lt;=|==|=|!=|!|&lt;&lt;|&gt;&gt;|&lt;|&gt;|\|\||\||&amp;&amp;|&amp;|-|\+|\*(?!/)|/(?!\*)|\%|~|\^|\?)
                                # operators and tests
        |
        \(\+\)
                                 # oracle join
        |
        [\[\]\(\),;.]            # punctuation (parenthesis, comma)
        |
        \'\'(?!\')              # empty single quoted string
        |
        \&quot;\&quot;(?!\&quot;&quot;)             # empty double quoted string
        |
        &quot;(?&gt;(?:(?&gt;[^&quot;\\]+)|&quot;&quot;|\\.)*)+&quot;
                                # anything inside double quotes, ungreedy
        |
        `(?&gt;(?:(?&gt;[^`\\]+)|``|\\.)*)+`
                                # anything inside backticks quotes, ungreedy
        |
        '(?&gt;(?:(?&gt;[^'\\]+)|''|\\.)*)+'
                                # anything inside single quotes, ungreedy.
        |
        /\*[\ \t\r\n\S]*?\*/      # C style comments
        |
        (?:[\w:@]+(?:[.\$](?:\w+|\*)?)*)
                                # words, standard named placeholders, db.table.*, db.*
        |
        \n                      # newline
        |
        [\t\ ]+                 # any kind of white spaces
    )
}smx;

sub tokenize_sql {
    my ( $query, $remove_white_tokens )= @_;

    my @query= $query =~ m{$re}smxg;

    if ($remove_white_tokens) {
        @query= grep( !/^[\s\n\r]*$/, @query );
    }

    return wantarray ? @query : \@query;
}

sub tokenize {
    my $class= shift;
    return tokenize_sql(@_);
}

1;

=pod

=head1 NAME

OraTokenizer - A simple SQL tokenizer.

=head1 VERSION

0.20

=head1 SYNOPSIS

 use OraTokenizer qw(tokenize_sql);

 my $query= q{SELECT 1 + 1};
 my @tokens= OraTokenizer-&gt;tokenize($query);

 # @tokens now contains ('SELECT', ' ', '1', ' ', '+', ' ', '1')

 @tokens= tokenize_sql($query); # procedural interface

=head1 DESCRIPTION

OraTokenizer is a simple tokenizer for SQL queries. It does not claim to be
a parser or query verifier. It just creates sane tokens from a valid SQL
query.

It supports SQL with comments like:

 -- This query is used to insert a message into
 -- logs table
 INSERT INTO log (application, message) VALUES (?, ?)

Also supports C&lt;''&gt;, C&lt;&quot;&quot;&gt; and C&lt;\'&gt; escaping methods, so tokenizing queries
like the one below should not be a problem:

 INSERT INTO log (application, message)
 VALUES ('myapp', 'Hey, this is a ''single quoted string''!')

=head1 API

=over 4

=item tokenize_sql

 use OraTokenizer qw(tokenize_sql);

 my @tokens= tokenize_sql($query);
 my $tokens= tokenize_sql($query);

 $tokens= tokenize_sql( $query, $remove_white_tokens );

C&lt;tokenize_sql&gt; can be imported to current namespace on request. It receives a
SQL query, and returns an array of tokens if called in list context, or an
arrayref if called in scalar context.

=item tokenize

 my @tokens= OraTokenizer-&gt;tokenize($query);
 my $tokens= OraTokenizer-&gt;tokenize($query);

 $tokens= OraTokenizer-&gt;tokenize( $query, $remove_white_tokens );

This is the only available class method. It receives a SQL query, and returns an
array of tokens if called in list context, or an arrayref if called in scalar
context.

If C&lt;$remove_white_tokens&gt; is true, white spaces only tokens will be removed from
result.

=back

=head1 ACKNOWLEDGEMENTS

=over 4

=item

Evan Harris, for implementing Shell comment style and SQL operators.

=item

Charlie Hills, for spotting a lot of important issues I haven't thought.

=item

Jonas Kramer, for fixing MySQL quoted strings and treating dot as punctuation character correctly.

=item

Emanuele Zeppieri, for asking to fix OraTokenizer to support dollars as well.

=item

Nigel Metheringham, for extending the dollar signal support.

=item

Devin Withers, for making it not choke on CR+LF in comments.

=item

Luc Lanthier, for simplifying the regex and make it not choke on backslashes.

=back

=head1 AUTHOR

Copyright (c) 2007, 2008, 2009, 2010, 2011 Igor Sutton Lopes &quot;&lt;IZUT@cpan.org&gt;&quot;. All rights
reserved.

This module is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.

=cut

###################################

package OraBeautify;

use strict;
use warnings;

our $VERSION = 0.04;

use Carp;


# Keywords from SQL-92, SQL-99 and SQL-2003.
use constant KEYWORDS =&gt; qw(
	ABSOLUTE ACTION ADD AFTER ALL ALLOCATE ALTER AND ANY ARE ARRAY AS ASC
	ASENSITIVE ASSERTION ASYMMETRIC AT ATOMIC AUTHORIZATION AVG BEFORE BEGIN
	BETWEEN BIGINT BINARY BIT BIT_LENGTH BLOB BOOLEAN BOTH BREADTH BY CALL
	CALLED CASCADE CASCADED CASE CAST CATALOG CHAR CHARACTER CHARACTER_LENGTH
	CHAR_LENGTH CHECK CLOB CLOSE COALESCE COLLATE COLLATION COLUMN COMMIT
	CONDITION CONNECT CONNECTION CONSTRAINT CONSTRAINTS CONSTRUCTOR CONTAINS
	CONTINUE CONVERT CORRESPONDING COUNT CREATE CROSS CUBE CURRENT CURRENT_DATE
	CURRENT_DEFAULT_TRANSFORM_GROUP CURRENT_PATH CURRENT_ROLE CURRENT_TIME
	CURRENT_TIMESTAMP CURRENT_TRANSFORM_GROUP_FOR_TYPE CURRENT_USER CURSOR
	CYCLE DATA DATE DAY DEALLOCATE DEC DECIMAL DECLARE DEFAULT DEFERRABLE
	DEFERRED DELETE DEPTH DEREF DESC DESCRIBE DESCRIPTOR DETERMINISTIC
	DIAGNOSTICS DISCONNECT DISTINCT DO DOMAIN DOUBLE DROP DYNAMIC EACH ELEMENT
	ELSE ELSEIF END EPOCH EQUALS ESCAPE EXCEPT EXCEPTION EXEC EXECUTE EXISTS
	EXIT EXTERNAL EXTRACT FALSE FETCH FILTER FIRST FLOAT FOR FOREIGN FOUND FREE
	FROM FULL FUNCTION GENERAL GET GLOBAL GO GOTO GRANT GROUP GROUPING HANDLER
	HAVING HOLD HOUR IDENTITY IF IMMEDIATE IN INDICATOR INITIALLY INNER INOUT
	INPUT INSENSITIVE INSERT INT INTEGER INTERSECT INTERVAL INTO IS ISOLATION
	ITERATE JOIN KEY LANGUAGE LARGE LAST LATERAL LEADING LEAVE LEFT LEVEL LIKE
	LIMIT LOCAL LOCALTIME LOCALTIMESTAMP LOCATOR LOOP LOWER MAP MATCH MAX
	MEMBER MERGE METHOD MIN MINUTE MODIFIES MODULE MONTH MULTISET NAMES
	NATIONAL NATURAL NCHAR NCLOB NEW NEXT NO NONE NOT NULL NULLIF NUMERIC
	OBJECT OCTET_LENGTH OF OLD ON ONLY OPEN OPTION OR ORDER ORDINALITY OUT
	OUTER OUTPUT OVER OVERLAPS PAD PARAMETER PARTIAL PARTITION PATH POSITION
	PRECISION PREPARE PRESERVE PRIMARY PRIOR PRIVILEGES PROCEDURE PUBLIC RANGE
	READ READS REAL RECURSIVE REF REFERENCES REFERENCING RELATIVE RELEASE
	REPEAT RESIGNAL RESTRICT RESULT RETURN RETURNS REVOKE RIGHT ROLE ROLLBACK
	ROLLUP ROUTINE ROW ROWS PIVOT UNPIVOT XMLTABLE XMLSEQUENCE XMLQUERY
	SAVEPOINT SCHEMA SCOPE SCROLL SEARCH SECOND SECTION SEQUENCE
	SELECT SENSITIVE SESSION SESSION_USER SET SETS SIGNAL SIMILAR SIZE SMALLINT
	SOME SPACE SPECIFIC SPECIFICTYPE SQL SQLCODE SQLERROR SQLEXCEPTION SQLSTATE
	SQLWARNING START STATE STATIC SUBMULTISET SUBSTRING SUM SYMMETRIC SYSTEM
	SYSTEM_USER TABLE TABLESAMPLE TEMPORARY TEXT THEN TIME TIMESTAMP
	TIMEZONE_HOUR TIMEZONE_MINUTE TINYINT TO TRAILING TRANSACTION TRANSLATE
	TRANSLATION TREAT TRIGGER TRIM TRUE UNDER UNDO UNION UNIQUE UNKNOWN UNNEST
	UNTIL UPDATE UPPER USAGE USER USING VALUE VALUES VARCHAR VARYING VIEW WHEN
	WHENEVER WHERE WHILE WINDOW WITH WITHIN WITHOUT WORK WRITE YEAR ZONE
);


sub new {
	my ($class, %options) = @_;

	my $self = bless { %options }, $class;

	# Set some defaults.
	$self-&gt;{query}    = ''   unless defined($self-&gt;{query});
	$self-&gt;{spaces}   = 4    unless defined($self-&gt;{spaces});
	$self-&gt;{space}    = ' '  unless defined($self-&gt;{space});
	$self-&gt;{break}    = &quot;\n&quot; unless defined($self-&gt;{break});
	$self-&gt;{wrap}     = {}   unless defined($self-&gt;{wrap});
	$self-&gt;{keywords} = []   unless defined($self-&gt;{keywords});
	$self-&gt;{rules}    = {}   unless defined($self-&gt;{rules});
	$self-&gt;{uc_keywords} = 0 unless defined $self-&gt;{uc_keywords};

	push @{$self-&gt;{keywords}}, KEYWORDS;

	# Initialize internal stuff.
	$self-&gt;{_level} = 0;

	return $self;
}


# Add more SQL.
sub add {
	my ($self, $addendum) = @_;

	$addendum =~ s/^\s*/ /;

	$self-&gt;{query} .= $addendum;
}


# Set SQL to beautify.
sub query {
	my ($self, $query) = @_;

	$self-&gt;{query} = $query if(defined($query));

	return $self-&gt;{query};
}


# Beautify SQL.
sub beautify {
	my ($self) = @_;

	$self-&gt;{_output} = '';
	$self-&gt;{_level_stack} = [];
	$self-&gt;{_new_line} = 1;

	my $last;

	$self-&gt;{_tokens} = [ OraTokenizer-&gt;tokenize($self-&gt;query, 1) ];

	while(defined(my $token = $self-&gt;_token)) {
		my $rule = $self-&gt;_get_rule($token);

		# Allow custom rules to override defaults.
		if($rule) {
			$self-&gt;_process_rule($rule, $token);
		}

		elsif($token eq '(') {
			$self-&gt;_add_token($token);
			$self-&gt;_new_line;
			push @{$self-&gt;{_level_stack}}, $self-&gt;{_level};
			$self-&gt;_over unless $last and uc($last) eq 'WHERE';
		}

		elsif($token eq ')') {
			$self-&gt;_new_line;
			$self-&gt;{_level} = pop(@{$self-&gt;{_level_stack}}) || 0;
			$self-&gt;_add_token($token);
			$self-&gt;_new_line;
		}

		elsif($token eq ',') {
			$self-&gt;_add_token($token);
			$self-&gt;_new_line;
		}

		elsif($token eq ';') {
			$self-&gt;_add_token($token);
			$self-&gt;_new_line;

			# End of statement; remove all indentation.
			@{$self-&gt;{_level_stack}} = ();
			$self-&gt;{_level} = 0;
		}

		elsif($token =~ /^(?:SELECT|FROM|WHERE|HAVING)$/i) {
			$self-&gt;_back unless $last and $last eq '(';
			$self-&gt;_new_line;
			$self-&gt;_add_token($token);
			$self-&gt;_new_line if($self-&gt;_next_token and $self-&gt;_next_token ne '(');
			$self-&gt;_over;
		}

		elsif($token =~ /^(?:GROUP|ORDER|LIMIT)$/i) {
			$self-&gt;_back;
			$self-&gt;_new_line;
			$self-&gt;_add_token($token);
		}

		elsif($token =~ /^(?:BY)$/i) {
			$self-&gt;_add_token($token);
			$self-&gt;_new_line;
			$self-&gt;_over;
		}

		elsif($token =~ /^(?:UNION|INTERSECT|EXCEPT)$/i) {
			$self-&gt;_new_line;
			$self-&gt;_add_token($token);
			$self-&gt;_new_line;
		}

		elsif($token =~ /^(?:LEFT|RIGHT|INNER|OUTER|CROSS)$/i) {
			$self-&gt;_back;
			$self-&gt;_new_line;
			$self-&gt;_add_token($token);
			$self-&gt;_over;
		}

		elsif($token =~ /^(?:JOIN)$/i) {
			if($last and $last !~ /^(?:LEFT|RIGHT|INNER|OUTER|CROSS)$/) {
				$self-&gt;_new_line;
			}

			$self-&gt;_add_token($token);
		}

		elsif($token =~ /^(?:AND|OR)$/i) {
			$self-&gt;_new_line;
			$self-&gt;_add_token($token);
			$self-&gt;_new_line;
		}

		else {
			$self-&gt;_add_token($token, $last);
		}

		$last = $token;
	}

	$self-&gt;_new_line;

	$self-&gt;{_output};
}


# Add a token to the beautified string.
sub _add_token {
	my ($self, $token, $last_token) = @_;

	if($self-&gt;{wrap}) {
		my $wrap;

		if($self-&gt;_is_keyword($token)) {
			$wrap = $self-&gt;{wrap}-&gt;{keywords};
		}
		elsif($self-&gt;_is_constant($token)) {
			$wrap = $self-&gt;{wrap}-&gt;{constants};
		}

		if($wrap) {
			$token = $wrap-&gt;[0] . $token . $wrap-&gt;[1];
		}
	}

	my $last_is_dot =
		defined($last_token) &amp;&amp; $last_token eq '.';

	if(!$self-&gt;_is_punctuation($token) and !$last_is_dot) {
		$self-&gt;{_output} .= $self-&gt;_indent;
	}

	# uppercase keywords
	$token = uc $token
		if $self-&gt;_is_keyword($token) and $self-&gt;{uc_keywords};

	$self-&gt;{_output} .= $token;

	# This can't be the beginning of a new line anymore.
	$self-&gt;{_new_line} = 0;
}


# Increase the indentation level.
sub _over {
	my ($self) = @_;

	++$self-&gt;{_level};
}


# Decrease the indentation level.
sub _back {
	my ($self) = @_;

	--$self-&gt;{_level} if($self-&gt;{_level} &gt; 0);
}


# Return a string of spaces according to the current indentation level and the
# spaces setting for indenting.
sub _indent {
	my ($self) = @_;

	if($self-&gt;{_new_line}) {
		return $self-&gt;{space} x ($self-&gt;{spaces} * $self-&gt;{_level});
	}
	else {
		return $self-&gt;{space};
	}
}


# Add a line break, but make sure there are no empty lines.
sub _new_line {
	my ($self) = @_;

	$self-&gt;{_output} .= $self-&gt;{break} unless($self-&gt;{_new_line});
	$self-&gt;{_new_line} = 1;
}


# Have a look at the token that's coming up next.
sub _next_token {
	my ($self) = @_;

	return @{$self-&gt;{_tokens}} ? $self-&gt;{_tokens}-&gt;[0] : undef;
}


# Get the next token, removing it from the list of remaining tokens.
sub _token {
	my ($self) = @_;

	return shift @{$self-&gt;{_tokens}};
}


# Check if a token is a known SQL keyword.
sub _is_keyword {
	my ($self, $token) = @_;

	return ~~ grep { $_ eq uc($token) } @{$self-&gt;{keywords}};
}


# Add new keywords to highlight.
sub add_keywords {
	my $self = shift;

	for my $keyword (@_) {
		push @{$self-&gt;{keywords}}, ref($keyword) ? @{$keyword} : $keyword;
	}
}


# Add new rules.
sub add_rule {
	my ($self, $format, $token) = @_;

	my $rules = $self-&gt;{rules}    ||= {};
	my $group = $rules-&gt;{$format} ||= [];

	push @{$group}, ref($token) ? @{$token} : $token;
}


# Find custom rule for a token.
sub _get_rule {
	my ($self, $token) = @_;

	values %{$self-&gt;{rules}}; # Reset iterator.

	while(my ($rule, $list) = each %{$self-&gt;{rules}}) {
		return $rule if(grep { uc($token) eq uc($_) } @$list);
	}

	return undef;
}


sub _process_rule {
	my ($self, $rule, $token) = @_;

	my $format = {
		break =&gt; sub { $self-&gt;_new_line                                     },
		over  =&gt; sub { $self-&gt;_over                                         },
		back  =&gt; sub { $self-&gt;_back                                         },
		token =&gt; sub { $self-&gt;_add_token($token)                            },
		push  =&gt; sub { push @{$self-&gt;{_level_stack}}, $self-&gt;{_level}       },
		pop   =&gt; sub { $self-&gt;{_level} = pop(@{$self-&gt;{_level_stack}}) || 0 },
		reset =&gt; sub { $self-&gt;{_level} = 0; @{$self-&gt;{_level_stack}} = ();  },
	};

	for(split /-/, lc $rule) {
		&amp;{$format-&gt;{$_}} if($format-&gt;{$_});
	}
}


# Check if a token is a constant.
sub _is_constant {
	my ($self, $token) = @_;

	return ($token =~ /^\d+$/ or $token =~ /^(['&quot;`]).*\1$/);
}


# Check if a token is punctuation.
sub _is_punctuation {
	my ($self, $token) = @_;

	return ($token =~ /^[,;.]$/);
}

1;

=pod

=head1 NAME

OraBeautify - Beautify SQL statements by adding line breaks indentation

=head1 SYNOPSIS

	my $sql = OraBeautify-&gt;new;

	$sql-&gt;query($sql_query);

	my $nice_sql = $sql-&gt;beautify;

=head1 DESCRIPTION

Beautifies SQL statements by adding line breaks indentation.

=head1 METHODS

=over 4

=item B&lt;new&gt;(query =&gt; '', spaces =&gt; 4, space =&gt; ' ', break =&gt; &quot;\n&quot;, wrap =&gt; {})

Constructor. Takes a few options.

=over 4

=item B&lt;query&gt; =&gt; ''

Initialize the instance with a SQL string. Defaults to an empty string.

=item B&lt;spaces&gt; =&gt; 4

Number of spaces that make one indentation level. Defaults to 4.

=item B&lt;space&gt; =&gt; ' '

A string that is used as space. Default is an ASCII space character.

=item B&lt;break&gt; =&gt; &quot;\n&quot;

String that is used for linebreaks. Default is &quot;\n&quot;.

=item B&lt;wrap&gt; =&gt; {}

Use this if you want to surround certain tokens with markup stuff. Known token
types are &quot;keywords&quot; and &quot;constants&quot; for now. The value of each token type
should be an array with two elements, one that is placed before the token and
one that is placed behind it. For example, use make keywords red using terminal
color escape sequences.

	{ keywords =&gt; [ &quot;\x1B[0;31m&quot;, &quot;\x1B[0m&quot; ] }

=item B&lt;uc_keywords&gt; =&gt; 1|0

When true (1) all SQL keywords will be uppercased in output.  Default is false (0).

=back

=item B&lt;add&gt;($more_sql)

Appends another chunk of SQL.

=item B&lt;query&gt;($query)

Sets the query to the new query string. Overwrites anything that was added with
prior calls to B&lt;query&gt; or B&lt;add&gt;.

=item B&lt;beautify&gt;

Beautifies the internally saved SQL string and returns the result.

=item B&lt;add_keywords&gt;($keyword, $another_keyword, \@more_keywords)

Add any amount of keywords of arrays of keywords to highlight.

=item B&lt;add_rule&gt;($rule, $token)

Add a custom formatting rule. The first argument is the rule, a string
containing one or more commands (explained below), separated by dashes. The
second argument may be either a token (string) or a list of strings. Tokens are
grouped by rules internally, so you may call this method multiple times with
the same rule string and different tokens, and the rule will apply to all of
the tokens.

The following formatting commands are known at the moment:

=over 4

=item B&lt;token&gt; - insert the token this rule applies to

=item B&lt;over&gt; - increase indentation level

=item B&lt;back&gt; - decrease indentation level

=item B&lt;break&gt; - insert line break

=item B&lt;push&gt; - push current indentation level to an internal stack

=item B&lt;pop&gt; - restore last indentation level from the stack

=item B&lt;reset&gt; - reset internal indentation level stack

=back

B&lt;push&gt;, B&lt;pop&gt; and B&lt;reset&gt; should be rarely needed.


B&lt;NOTE&gt;:
Custom rules override default rules. Some default rules do things that
can't be done using custom rules, such as changing the format of a token
depending on the last or next token.


B&lt;NOTE&gt;:
I'm trying to provide sane default rules. If you find that a custom
rule of yours would make more sense as a default rule, please create a ticket.


=back

=head1 BUGS

Needs more tests.

Please report bugs in the CPAN bug tracker.

This module is not complete (known SQL keywords, special formatting of
keywords), so if you want see something added, just send me a patch.

=head1 COPYRIGHT

Copyright (C) 2009 by Jonas Kramer.  Published under the terms of the Artistic
License 2.0.

=cut

########################################
package main;
use strict;

open (SQL, &quot;&lt;&quot;, $ARGV[0]) || die ('File not found!');
my $query = join(&quot;\n&quot;,&lt;SQL&gt;);


my $beautifier = OraBeautify-&gt;new;
$beautifier -&gt; add_keywords(qw{
    pivot unpivot 
    model dimension measures rules 
    xmltable xmlsequence columns});


$beautifier-&gt;query(
            $query, 
            spaces =&gt; 4, 
            space =&gt; ' ', 
            break =&gt; &quot;\n&quot;, 
            wrap =&gt; {'$','$'}
            );

my $nice_sql = $beautifier-&gt;beautify;

print $nice_sql .&quot;\n&quot;;
__END__

</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
<br />
3. Create empty directory &#8220;tmp&#8221; within $SQL_PATH<br />
4. Now you can use it for example like i did it in <a href="http://orasql.org/scripts/sql_textf.sql" title="sql_textf.sql" target="_blank">sql_textf.sql</a>:<br />

<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: sql_textf.sql</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv78498005"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv78498005",true,"Show","Hide","fast",false); return false;' id='spoilerDiv78498005_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv78498005' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
set timing off head off
col qtext format a150
prompt ################################  Original query text:  ################################################;
spool tmp/to_format.sql
select
    coalesce(
        (select sql_fulltext from v$sqlarea a where a.sql_id='&amp;1')
    ,   (select sql_text from dba_hist_sqltext a where a.sql_id='&amp;1' and dbid=(select dbid from v$database))
    ) qtext
from dual
;
spool off

prompt ################################  Formatted query text #################################################;
host perl inc/sql_format_standalone.pl tmp/to_format.sql
prompt ################################  Formatted query text End #############################################;
set termout on head on
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
</p>
<p>I also use it in other scripts, like sqlid.sql:<br />

<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv61138006"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv61138006",true,"Show","Hide","fast",false); return false;' id='spoilerDiv61138006_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv61138006' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
@inc/input_vars_init;

REM ############### COMMON FORMATTING #######################
col SQL_ID                              for a13
col sql_child_number    head CH#        for 999
col SQL_PROFILE         head PROFILE    for a19
-----------------------------------------
--    params check:
set termout off timing off
def _sqlid=&amp;1
col _child new_val _child noprint
select 
   case 
      when translate('&amp;2','x0123456789','x') is null  
         then nvl('&amp;2','%') 
      else '%'
   end &quot;_CHILD&quot;
from dual;
-----------------------------------------
set termout on

prompt ####################################################################################################;
prompt #               Show SQL text, child cursors and execution stats for SQLID &amp;1 child &amp;2
prompt ####################################################################################################;

REM ################### SHOW SQL TEXT ############################
@sql_textf &amp;_sqlid

REM ################### SHOW  V$SQL ##############################
col proc_name           for a30
col P_schema            for a20

select 
    s.sql_id
   ,s.CHILD_NUMBER                                                      sql_child_number
   ,s.address                                                           parent_handle
   ,s.child_address                                                     object_handle
   ,s.PLAN_HASH_VALUE                                                   plan_hv
   ,s.hash_value                                                        hv
   ,s.SQL_PROFILE                                                       sql_profile
   ,decode(s.EXECUTIONS,0,0, s.ELAPSED_TIME/1e6/s.EXECUTIONS)           elaexe
   ,s.EXECUTIONS                                                        cnt
   ,s.FETCHES                                                           fetches
   ,s.END_OF_FETCH_COUNT                                                end_of_fetch_count
   ,s.FIRST_LOAD_TIME                                                   first_load_time
   ,s.PARSE_CALLS                                                       parse_calls
   ,decode(s.executions,0,0, s.DISK_READS    /s.executions)             disk_reads
   ,decode(s.executions,0,0, s.BUFFER_GETS   /s.executions)             buffer_gets
   ,decode(s.executions,0,0, s.DIRECT_WRITES /s.executions)             direct_writes
   ,decode(s.executions,0,0, s.APPLICATION_WAIT_TIME/1e6/s.executions)  app_wait
   ,decode(s.executions,0,0, s.CONCURRENCY_WAIT_TIME/1e6/s.executions)  concurrency
   ,decode(s.executions,0,0, s.USER_IO_WAIT_TIME    /1e6/s.executions)  io_wait
   ,decode(s.executions,0,0, s.PLSQL_EXEC_TIME      /1e6/s.executions)  plsql_t
   ,decode(s.executions,0,0, s.java_exec_time       /1e6/s.executions)  java_exec_t
   ,s.ROWS_PROCESSED                                                    row_processed
   ,s.OPTIMIZER_MODE                                                    opt_mode
   ,s.OPTIMIZER_COST                                                    cost
   ,s.OPTIMIZER_ENV_HASH_VALUE                                          env_hash
   ,s.PARSING_SCHEMA_NAME                                               P_schema
   ,decode(s.executions,0,0, s.CPU_TIME/1e6/s.executions)               CPU_TIME
   ,s.PROGRAM_ID
   ,(select object_name from dba_objects o where o.object_id=s.PROGRAM_ID) proc_name
   ,s.PROGRAM_LINE#                                                        proc_line
from v$sql s 
where 
    sql_id = ('&amp;_sqlid')
and child_number like '&amp;_child'
order by
    sql_id,
    hash_value,
    child_number
/
REM ##################### END V$SQL ##############################

REM ################### PLSQL OBJECT ##############################
col owner           for a10
col object_name     for a30
col text            for a120

select 
   a.SQL_ID,a.SQL_PROFILE
  ,p.owner,p.object_name
  ,s.line
  ,rtrim(s.text,chr(10)) text
from
    v$sqlarea a
    left join dba_procedures p
              on a.PROGRAM_ID=p.OBJECT_ID
    left join dba_source s
              on p.owner=s.owner
              and p.OBJECT_NAME=s.name
              and s.line between a.PROGRAM_LINE#-5 and a.PROGRAM_LINE#+5
where a.SQL_ID='&amp;_sqlid'
/
REM ################### EXECUTIONS IN SQL_MONITOR ######################
@if &quot;'&amp;_O_RELEASE'&gt;'11.2'&quot; then

   col error_message       for a40
   @rtsm/execs &quot;&amp;_sqlid&quot; &quot;&amp;_child&quot;

/* end if */
REM ###########################   clearing ############################
col SQL_PROFILE     clear
col owner           clear
col object_name     clear
col text            clear
col error_message   clear
@inc/input_vars_undef;
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
</p>
]]></content:encoded>
			<wfw:commentRss>http://orasql.org/2013/04/29/sql_text-formatting-sql-beatifier/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL*Plus tips #4: Branching execution</title>
		<link>http://orasql.org/2013/04/17/sqlplus-tips-4-branching-execution/</link>
		<comments>http://orasql.org/2013/04/17/sqlplus-tips-4-branching-execution/#comments</comments>
		<pubDate>Tue, 16 Apr 2013 21:38:40 +0000</pubDate>
		<dc:creator>Sayan Malakshinov</dc:creator>
				<category><![CDATA[oracle]]></category>
		<category><![CDATA[SQL*Plus]]></category>

		<guid isPermaLink="false">http://orasql.org/?p=274</guid>
		<description><![CDATA[Today I&#8217;ll show trick how we can use branching in SQL*Plus. Although I previously showed the conditional execution of scripts and it really can be used for branching, but today I&#8217;ll show how to do it without splitting the script into several smaller scripts. In contrast to the conditional script execution, I&#8217;ll use a different [...]]]></description>
				<content:encoded><![CDATA[<p>Today I&#8217;ll show trick how we can use branching in SQL*Plus.<br />
Although I previously showed the conditional execution of scripts and it really can be used for branching, but today I&#8217;ll show how to do it without splitting the script into several smaller scripts. In contrast to the conditional script execution, I&#8217;ll use a different method. </p>
<p>It is very simple, as usual &#8211; if you want to execute only one part of script, you can just comment out all unnecessary. So depending on the conditions, we can execute a script which will start a comment. </p>
<p>Suppose we need to create a script, which, depending on the input parameter will be required to execute a specific query.<br />
See how this can be done:<br />
1. <strong>&#8220;test.sql&#8221;</strong>:</p>
<pre class="brush: sql; title: ; notranslate">
def param = &amp;1

@if &amp;param=1
   select 1 from dual;
/* end_if */

@if &amp;param=2
   select 2 from dual;
/* end_if */

@if &amp;param=3
   select 3 from dual;
/* end_if */
</pre>
<p>2. <strong>&#8220;if.sql&#8221;</strong>:</p>
<pre class="brush: sql; title: ; notranslate">
col do_next new_val do_next noprint;
select 
      case 
         when &amp;1 then 'inc/null'
         else 'inc/comment_on'
      end as do_next
from dual;
@&amp;do_next
</pre>
<p>3. <strong>&#8220;inc/comment_on.sql&#8221;</strong> contains only 2 chars:</p>
<blockquote><p>/*</p></blockquote>
<p>4. <strong>&#8220;inc/null.sql&#8221;</strong> is the same as in the previous examples &#8211; just empty file.</p>
<p>Ok, lets test it:</p>
<pre class="brush: sql; title: ; notranslate">
SQL&gt; @test 1

         1
----------
         1


SQL&gt; @test 2


         2
----------
         2


SQL&gt; @test 3


         3
----------
         3
</pre>
<p>As you see, we got what we wanted. Please note that we have to close the multiline comments in the right places only(<strong><em>/* end_if */</em></strong>). So we cannot use in these parts another &#8220;*/&#8221;. But you can use it in another child scripts.</p>
<p>Same way we can make an analogue of switch/case:<br />
<em><strong>&#8220;test2.sql&#8221;:</strong></em>
<pre class="brush: sql; title: ; notranslate">
@switch &amp;1

   @when 1 then
      select 1 from dual;
   /* end when */

   @when 2 then
      select 2 from dual;
   /* end when */

   @when 3 then
      select 3 from dual;
   /* end when */

/* end switch */
</pre>
<p>
<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: switch.sql</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv614a8007"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv614a8007",true,"Show","Hide","fast",false); return false;' id='spoilerDiv614a8007_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv614a8007' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
def switch_param=&amp;1
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
<br />

<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: when.sql</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv1828008"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv1828008",true,"Show","Hide","fast",false); return false;' id='spoilerDiv1828008_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv1828008' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
col do_next new_val do_next noprint;
select 
      case 
         when &amp;1 = &amp;switch_param then 'inc/null'
         else 'inc/comment_on'
      end as do_next
from dual;
@&amp;do_next
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
<br />
Example:
<pre class="brush: sql; title: ; notranslate">
SQL&gt; @test2 2

         2
----------
         2

SQL&gt; @test2 3

         3
----------
         3
</pre>
]]></content:encoded>
			<wfw:commentRss>http://orasql.org/2013/04/17/sqlplus-tips-4-branching-execution/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL*Plus tips #3: Iterators and recursions</title>
		<link>http://orasql.org/2013/04/09/sqlplus-tips-3-iterators-and-recursions/</link>
		<comments>http://orasql.org/2013/04/09/sqlplus-tips-3-iterators-and-recursions/#comments</comments>
		<pubDate>Tue, 09 Apr 2013 20:35:29 +0000</pubDate>
		<dc:creator>Sayan Malakshinov</dc:creator>
				<category><![CDATA[oracle]]></category>
		<category><![CDATA[SQL*Plus]]></category>

		<guid isPermaLink="false">http://orasql.org/?p=265</guid>
		<description><![CDATA[We all used to iterators, recursions and branching in programming, but sql*plus does not have such commands. Today I will show how to do iterators/recusions. Suppose we want to call a script 3 times. So it would be convenient if we can do it like: It is very easy: We can recursively call the script [...]]]></description>
				<content:encoded><![CDATA[<p>We all used to iterators, recursions and branching in programming, but sql*plus does not have such commands. Today I will show how to do iterators/recusions.</p>
<p>Suppose we want to call a script 3 times. So it would be convenient if we can do it like: </p>
<pre class="brush: sql; title: ; notranslate">
@iterate 3 @some_script
</pre>
<p>It is very easy: We can recursively call the script by reducing variable until it is greater than zero. and if a variable is zero, then call an empty &#8220;NULL&#8221; script.<br />
iterate.sql:</p>
<pre class="brush: sql; title: ; notranslate">
-- initializing input parameters as i showed in previous tips:
@inc/input_params_init.sql;
-- for example max number of input parameters = 14:
def _INIT_PARAMS = '&quot;&amp;3&quot; &quot;&amp;4&quot; &quot;&amp;5&quot; &quot;&amp;6&quot; &quot;&amp;7&quot; &quot;&amp;8&quot; &quot;&amp;9&quot; &quot;&amp;10&quot; &quot;&amp;11&quot; &quot;&amp;12&quot; &quot;&amp;13&quot; &quot;&amp;14&quot; &quot;&amp;15&quot; &quot;&amp;16&quot;'
def _ITER = &quot;&amp;1&quot;

prompt ------   iteration &amp;_ITER start: &quot;@&amp;2  -----------;
set termout off


col _SCRIPT    new_val _SCRIPT   noprint;
col _CONTINUE  new_val _CONTINUE noprint;
col _PARAMS    new_val _PARAMS   noprint;
select 
   replace('&quot;&amp;3&quot; &quot;&amp;4&quot; &quot;&amp;5&quot; &quot;&amp;6&quot; &quot;&amp;7&quot; &quot;&amp;8&quot; &quot;&amp;9&quot; &quot;&amp;10&quot; &quot;&amp;11&quot; &quot;&amp;12&quot; &quot;&amp;13&quot; &quot;&amp;14&quot; &quot;&amp;15&quot; &quot;&amp;16&quot;'
          ,'${ITER}'
          ,'&amp;_ITER'
          )          as &quot;_PARAMS&quot;
  ,case 
      when &amp;1 &gt; 0 then 'iterate '||(&amp;1 - 1)
      else 'inc/null'
   end               as &quot;_CONTINUE&quot;
  ,case 
      when &amp;1 &gt; 0 then '&amp;2' 
      else 'inc/null'
   end               as &quot;_SCRIPT&quot;
from dual;
set termout on

@&amp;_script            &amp;_PARAMS
@&amp;_CONTINUE &amp;_SCRIPT &amp;_INIT_PARAMS
</pre>
<p>As you see i also added option to pass iteration_number as input parameter, so we can call it like: <em><strong>@iterate 3 script.sql ${ITER}</strong></em><br />
And <strong><em>null.sql</em></strong> in &#8220;<em>inc</em>&#8221; directory is just empty file.</p>
<p>Lets test it:</p>
<pre class="brush: sql; title: ; notranslate">
SQL&gt; $cat test.sql
select &amp;1 a,'&amp;2' b,'&amp;3' c from dual;

SQL&gt; @iterate 3 test.sql 1 2 3
------   iteration 3 start: &quot;@test.sql  -----------

         A B C
---------- - -
         1 2 3

------   iteration 2 start: &quot;@test.sql  -----------

         A B C
---------- - -
         1 2 3

------   iteration 1 start: &quot;@test.sql  -----------

         A B C
---------- - -
         1 2 3

------   iteration 0 start: &quot;@test.sql  -----------

SQL&gt; @iterate 2 test.sql 1 2 ${ITER}
------   iteration 2 start: &quot;@test.sql  -----------

         A B C
---------- - -
         1 2 2

------   iteration 1 start: &quot;@test.sql  -----------

         A B C
---------- - -
         1 2 1

------   iteration 0 start: &quot;@test.sql  -----------
</pre>
<p>Note that last string <em>&#8220;iteration 0 start&#8221;</em> just means that it is last empty call. I made this only for showing how we can do postprocessing after all iterations.<br />
Ok, it works good, but with a little modification we can also add option to call such script with list of values too:<br />

<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: final iterate.sql</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv18ce8009"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv18ce8009",true,"Show","Hide","fast",false); return false;' id='spoilerDiv18ce8009_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv18ce8009' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
@inc/input_params_init.sql;

set termout off
def _INIT_PARAMS = '&quot;&amp;3&quot; &quot;&amp;4&quot; &quot;&amp;5&quot; &quot;&amp;6&quot; &quot;&amp;7&quot; &quot;&amp;8&quot; &quot;&amp;9&quot; &quot;&amp;10&quot; &quot;&amp;11&quot; &quot;&amp;12&quot; &quot;&amp;13&quot; &quot;&amp;14&quot; &quot;&amp;15&quot; &quot;&amp;16&quot;'
col _ITER_CURR new_val _ITER_CURR noprint
col _ITER_NEXT new_val _ITER_NEXT noprint
select
   case 
      -- simple N iterations:
      when translate('&amp;1','x0123456789','x') is null 
         then '&amp;1'
      -- list iteration:
      when substr('&amp;1',1,1)='(' 
         then decode( instr('&amp;1',',')
                     ,0,substr('&amp;1',2,length('&amp;1')-2)
                     ,substr('&amp;1',2,instr('&amp;1',',')-2)
                    )
   end &quot;_ITER_CURR&quot;,
   case 
      when translate('&amp;1','x0123456789','x') is null 
         then 
            case 
               when '&amp;1'&gt;1 then 'iterate '||('&amp;1' - 1)
               else 'inc/null'
            end
      when substr('&amp;1',1,1)='(' 
         then 
            case 
               when instr('&amp;1',',')=0 or '&amp;1'='()' then 'inc/null'
               else 'iterate '
                  ||'('
                  ||decode( instr('&amp;1',',')
                           ,0,')'
                           ,substr('&amp;1',instr('&amp;1',',')+1)
                          )
            end
   end &quot;_ITER_NEXT&quot;
from dual;

set termout on
prompt ******   iteration &amp;_ITER_CURR start: &quot;@&amp;2  ***********;
set termout off

col _SCRIPT    new_val _SCRIPT   noprint;
col _PARAMS    new_val _PARAMS   noprint;
select 
   replace('&quot;&amp;3&quot; &quot;&amp;4&quot; &quot;&amp;5&quot; &quot;&amp;6&quot; &quot;&amp;7&quot; &quot;&amp;8&quot; &quot;&amp;9&quot; &quot;&amp;10&quot; &quot;&amp;11&quot; &quot;&amp;12&quot; &quot;&amp;13&quot; &quot;&amp;14&quot; &quot;&amp;15&quot; &quot;&amp;16&quot;'
          ,'${ITER}'
          ,'&amp;_ITER_CURR'
          )          as &quot;_PARAMS&quot;
  ,case 
      when nvl('&amp;_ITER_CURR',0) in ('0','()') then 'inc/null'
      else '&amp;2'
   end               as &quot;_SCRIPT&quot;
from dual;
set termout on

@&amp;_script             &amp;_PARAMS
@&amp;_ITER_NEXT &amp;_SCRIPT &amp;_INIT_PARAMS
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
<br />
See how it works:</p>
<pre class="brush: sql; title: ; notranslate">
-- iterate by list of values  (7,3,10):
SQL&gt; @iterate (7,3,10) test.sql 1 2 ${ITER}
******   iteration 7 start: &quot;@test.sql  ***********

         A B C
---------- - -
         1 2 7

******   iteration 3 start: &quot;@test.sql  ***********

         A B C
---------- - -
         1 2 3

******   iteration 10 start: &quot;@test.sql  ***********

         A B C
---------- - --
         1 2 10

-- now with simple 2 iterations:
SQL&gt; @iterate 2 test.sql 1 2 ${ITER}
******   iteration 2 start: &quot;@test.sql  ***********

         A B C
---------- - -
         1 2 2

******   iteration 1 start: &quot;@test.sql  ***********

         A B C
---------- - -
         1 2 1

</pre>
<p>So if you call script with &#8220;iterate N &#8230;&#8221; it will iterate N times, and if you specify &#8220;iterate (X,Y,&#8230;,Z)&#8221; it will iterate by this list.</p>
<p>PS. About a branching i will wrote later&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://orasql.org/2013/04/09/sqlplus-tips-3-iterators-and-recursions/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>SQL*Plus tips. #2</title>
		<link>http://orasql.org/2013/04/02/sqlplus-tips-2/</link>
		<comments>http://orasql.org/2013/04/02/sqlplus-tips-2/#comments</comments>
		<pubDate>Mon, 01 Apr 2013 23:33:33 +0000</pubDate>
		<dc:creator>Sayan Malakshinov</dc:creator>
				<category><![CDATA[oracle]]></category>
		<category><![CDATA[SQL*Plus]]></category>

		<guid isPermaLink="false">http://orasql.org/?p=252</guid>
		<description><![CDATA[I think you know the famous print_table procedure by Tom Kyte. It is really great, but a little hard(it requires create procedure or place it in anonymous block) and in last oracle versions we can do same with one simple query with xmltable/xmlsequence: It is very easy, but for conveniency we need to add &#8220;rownum&#8221;: [...]]]></description>
				<content:encoded><![CDATA[<p>I think you know the famous <a href="http://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:1035431863958" title="AskTom's print_table" target="_blank">print_table</a> procedure by Tom Kyte. It is really great, but a little hard(it requires create procedure or place it in anonymous block) and in last oracle versions we can do same with one simple query with xmltable/xmlsequence:</p>
<pre class="brush: sql; title: ; notranslate">
SQL&gt; select *
  2  from
  3     xmltable( '/ROWSET/ROW/*'
  4               passing xmltype(cursor(select * from hr.employees where rownum&lt;3))
  5               columns
  6                  col varchar2(100) path 'name()'
  7                 ,val varchar2(100) path '.'
  8        );

COL                            VAL
------------------------------ ------------------------------------------------------
EMPLOYEE_ID                    198
FIRST_NAME                     Donald
LAST_NAME                      OConnell
EMAIL                          DOCONNEL
PHONE_NUMBER                   650.507.9833
HIRE_DATE                      21-JUN-07
JOB_ID                         SH_CLERK
SALARY                         2600
MANAGER_ID                     124
DEPARTMENT_ID                  50
EMPLOYEE_ID                    199
FIRST_NAME                     Douglas
LAST_NAME                      Grant
EMAIL                          DGRANT
PHONE_NUMBER                   650.507.9844
HIRE_DATE                      13-JAN-08
JOB_ID                         SH_CLERK
SALARY                         2600
MANAGER_ID                     124
DEPARTMENT_ID                  50

20 rows selected.
</pre>
<p>It is very easy, but for conveniency we need to add &#8220;rownum&#8221;:</p>
<pre class="brush: sql; title: ; notranslate">
SQL&gt; select *
  2  from
  3     xmltable( 'for $a at $i in /ROWSET/ROW
  4                   ,$r in $a/*
  5                     return element ROW{
  6                                       element ROW_NUM{$i}
  7                                      ,element COL_NAME{$r/name()}
  8                                      ,element COL_VALUE{$r/text()}
  9                                      }'
 10               passing xmltype(cursor(select * from hr.employees where rownum&lt;3))
 11               columns
 12                  row_num   int
 13                 ,col_name  varchar2(30)
 14                 ,col_value varchar2(100)
 15        );

   ROW_NUM COL_NAME                       COL_VALUE
---------- ------------------------------ ------------------------------------------
         1 EMPLOYEE_ID                    198
         1 FIRST_NAME                     Donald
         1 LAST_NAME                      OConnell
         1 EMAIL                          DOCONNEL
         1 PHONE_NUMBER                   650.507.9833
         1 HIRE_DATE                      21-JUN-07
         1 JOB_ID                         SH_CLERK
         1 SALARY                         2600
         1 MANAGER_ID                     124
         1 DEPARTMENT_ID                  50
         2 EMPLOYEE_ID                    199
         2 FIRST_NAME                     Douglas
         2 LAST_NAME                      Grant
         2 EMAIL                          DGRANT
         2 PHONE_NUMBER                   650.507.9844
         2 HIRE_DATE                      13-JAN-08
         2 JOB_ID                         SH_CLERK
         2 SALARY                         2600
         2 MANAGER_ID                     124
         2 DEPARTMENT_ID                  50

20 rows selected.</pre>
<p>Now we can create simple script for it with formatting:<br />

<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: print_table.sql</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv234b800a"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv234b800a",true,"Show","Hide","fast",false); return false;' id='spoilerDiv234b800a_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv234b800a' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
-- show output  
set termout on
-- but without echo
set echo off
-- without newpage on start:
set embedded on
-- scrolling control
set pause on
-- two lines between rows:
set newpage 2
-- text for prompt after each page:
set pause &quot;Press Enter to view next row...&quot;
-- new page on new &quot;row_num&quot;
break on row_num skip page

-- main query:
select *
from 
   xmltable( 'for $a at $i in /ROWSET/ROW
                 ,$r in $a/*
                   return element ROW{
                                     element ROW_NUM{$i}
                                    ,element COL_NAME{$r/name()}
                                    ,element COL_VALUE{$r/text()}
                                    }'
             passing xmltype(cursor( &amp;1 ))
             columns
                row_num   int
               ,col_name  varchar2(30) 
               ,col_value varchar2(100) 
      );
-- disabling pause and breaks:
set pause off
clear breaks
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
<br />
Usage example:<a href="http://orasql.org/wp-content/uploads/2013/04/print_table.png"><img src="http://orasql.org/wp-content/uploads/2013/04/print_table.png" alt="print_table example" width="585" height="268" class="alignnone size-full wp-image-253" /></a><br />
As you see script works fine, but it is require to pass query as parameter, though sometimes it is not so convenient. For example if we want started query and later decided to show it with print_table. In that case we can create scripts with tricks <a href="http://orasql.org/2013/03/29/sqlplus-tips-1/" target="_blank">from previous part</a>:<br />

<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: print_last.sql</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv62ea800b"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv62ea800b",true,"Show","Hide","fast",false); return false;' id='spoilerDiv62ea800b_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv62ea800b' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
store set settings.sql replace
-- saving previous query:
save tmp.sql replace

-- OS-dependent removing trailing slash from file, choose one:
-- 1. for *nix through head:
!head -1 tmp.sql &gt;tmp2.sql

-- 2. for for *nix through grep:
--!grep -v tmp.sql &gt;tmp2.sql

-- 3. for windows without grep and head:
-- $cmd /C findstr /v /C:&quot;/&quot; tmp.sql &gt; tmp2.sql

-- 4. for windows with &quot;head&quot;(eg from cygwin)
--$cmd /C head -1 tmp.sql &gt; tmp2.sql

-- 5. for windows with &quot;grep&quot;:
--$cmd /C grep -v &quot;/&quot; tmp.sql &gt; tmp2.sql



-- same setting as in print_table:
set termout on echo off embedded on pause on newpage 2
set pause &quot;Press Enter to view next row...&quot;
break on row_num skip page

-- main query:
select *
from
   xmltable( 'for $a at $i in /ROWSET/ROW
                 ,$r in $a/*
                   return element ROW{
                                     element ROW_NUM{$i}
                                    ,element COL_NAME{$r/name()}
                                    ,element COL_VALUE{$r/text()}
                                    }'
             passing dbms_xmlgen.getxmltype(
             q'[
               @tmp2.sql
             ]'
             )
             columns
                row_num   int
               ,col_name  varchar2(30)
               ,col_value varchar2(100)
      );
-- disabling pause and breaks:
set pause off
clear breaks
@settings.sql
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
<br />
Example:
<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv73af800c"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv73af800c",true,"Show","Hide","fast",false); return false;' id='spoilerDiv73af800c_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv73af800c' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
SQL&gt; select * from hr.employees where rownum&lt;3;

EMPLOYEE_ID FIRST_NAME           LAST_NAME                 EMAIL                     PHONE_NUMBER      HIRE_DATE JOB_ID    SALARY COMMISSION_PCT MANAGER_ID DEPARTMENT_ID
----------- -------------------- ------------------------- ------------------------- -------------------- --------- ---------- ---------- -------------- ---------- -------------
        198 Donald               OConnell                  DOCONNEL                  650.507.9833         21-JUN-07 SH_CLERK         2600                       124            50
        199 Douglas              Grant                     DGRANT                    650.507.9844         13-JAN-08 SH_CLERK         2600                       124            50

Elapsed: 00:00:00.01
SQL&gt; @print_last
Wrote file settings.sql
Wrote file tmp.sql

   ROW_NUM COL_NAME                       COL_VALUE
---------- ------------------------------ ----------------------------------------------------------------------------------------------------
         1 EMPLOYEE_ID                    198
           FIRST_NAME                     Donald
           LAST_NAME                      OConnell
           EMAIL                          DOCONNEL
           PHONE_NUMBER                   650.507.9833
           HIRE_DATE                      21-JUN-07
           JOB_ID                         SH_CLERK
           SALARY                         2600
           MANAGER_ID                     124
           DEPARTMENT_ID                  50
Press Enter to view next row...
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
<br />
<em><strong>PS. if you will use <i>xmltype(cursor(&#8230;))</i> on versions less that 11.2.0.3 you can get errors with xml rewriting. In this case you need to disable it:</strong></em></p>
<pre class="brush: plain; title: ; notranslate">alter session set events '19027 trace name context forever, level 0x1';</pre>
<hr />
<a name="update" /><strong>Update:</strong><br />
<a href="http://ru.linkedin.com/pub/vladimir-przyjalkowski/0/2b4/907/" title="Vladimir Przyjalkowski" target="_blank">Vladimir Przyjalkowski</a> rightly pointed out that such approach will be suboptimal in case of big amount of data:</p>
<figure>
<blockquote cite="http://dev.w3.org/html5/spec/the-figure-element.html#the-figure-element"><p>
    A nice toy, but i&#8217;m sure it will not tolerate big data.
  </p></blockquote>
</figure>
<p>It is absolutely true, because at first, <strong><em>&#8220;xmltype(cursor(&#8230;))&#8221;</em></strong> aggregated data as xmltype, and only then <em>xmltable</em> returns data.<br />
But I use print_table for small amount of data only, and in case of when i want to see sample of data, i usually add limitation by rownum, which also convenient because it automatically changes optimizer mode with enabled parameter <em>&#8220;_optimizer_rownum_pred_based_fkr&#8221;</em> (it is default):</p>
<pre class="brush: sql; highlight: [6]; title: ; notranslate">
SQL&gt; @param_ rownum

NAME                               VALUE   DEFLT  TYPE     DESCRIPTION
---------------------------------- ------- ------ -------- ------------------------------------------------------
_optimizer_rownum_bind_default     10      TRUE   number   Default value to use for rownum bind
_optimizer_rownum_pred_based_fkr   TRUE    TRUE   boolean  enable the use of first K rows due to rownum predicate
_px_rownum_pd                      TRUE    TRUE   boolean  turn off/on parallel rownum pushdown optimization
</pre>
<p>However, we can easily change the our query to make it optimally with a lot of data too:</p>
<pre class="brush: sql; highlight: [6]; title: ; notranslate">
select row_num
      ,t2.*
from 
   (select rownum row_num
         , column_value x
    from table(xmlsequence(cursor( &amp;1 )))
   ) t1
  ,xmltable( '/ROW/*'
             passing t1.x
             columns
                col_num for ordinality
               ,col_name  varchar2(30) path 'name()'
               ,col_value varchar2(100) path '.'
      )(+) t2;
</pre>
<p>Lets test it with pipelined function which will pipe rows infinitely and log count of fetched rows:</p>
<pre class="brush: sql; title: ; notranslate">
-- drop table xt_log purge;
-- drop function f_infinite;

create table xt_log(n int);

create function f_infinite 
   return sys.ku$_objnumset pipelined 
as
   i int:=0;
   pragma autonomous_transaction;
begin
   loop 
      i:=i+1;
      insert into xt_log values(i);
      commit;
      pipe row(i);
   end loop;

exception 
   when NO_DATA_NEEDED then
      commit;
end;
/
</pre>
<p>
<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: New version of print_table: print_table2.sql</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv48cc800d"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv48cc800d",true,"Show","Hide","fast",false); return false;' id='spoilerDiv48cc800d_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv48cc800d' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
-- set arraysize for minimal value, so sqlplus did not fetch extra rows:
set arraysize 2
-- show output  
set termout on
-- but without echo
set echo off
-- without newpage on start:
set embedded on
-- scrolling control
set pause on
-- two lines between rows:
set newpage 2
-- text for prompt after each page:
set pause &quot;Press Enter to view next row...&quot;
-- new page on new &quot;row_num&quot;
break on row_num skip page

-- main query:
select row_num
      ,t2.*
from 
   (select rownum row_num
         , column_value x
    from table(xmlsequence(cursor( &amp;1 )))
   ) t1
  ,xmltable( '/ROW/*'
             passing t1.x
             columns
                col_num for ordinality
               ,col_name  varchar2(30) path 'name()'
               ,col_value varchar2(100) path '.'
      )(+) t2;
-- disabling pause and breaks:
set pause off
clear breaks
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
<br />
And look final test:</p>
<pre class="brush: sql; title: ; notranslate">
SQL&gt; select * from xt_log;

no rows selected

SQL&gt; @print_table2 &quot;select * from table(f_infinite)&quot;
Press Enter to view next row...


   ROW_NUM    COL_NUM COL_NAME                       COL_VALUE
---------- ---------- ------------------------------ -----------
         1          1 COLUMN_VALUE                   1
Press Enter to view next row...


   ROW_NUM    COL_NUM COL_NAME                       COL_VALUE
---------- ---------- ------------------------------ -----------
         2          1 COLUMN_VALUE                   2
Press Enter to view next row...


   ROW_NUM    COL_NUM COL_NAME                       COL_VALUE
---------- ---------- ------------------------------ -----------
         3          1 COLUMN_VALUE                   3
Press Enter to view next row...


   ROW_NUM    COL_NUM COL_NAME                       COL_VALUE
---------- ---------- ------------------------------ -----------
         4          1 COLUMN_VALUE                   4
Press Enter to view next row...

   ROW_NUM    COL_NUM COL_NAME                       COL_VALUE
         5          1 COLUMN_VALUE                   5
Press Enter to view next row...


6 rows selected.
-------------------------------
SQL&gt; select * from xt_log;

         N
----------
         1
         2
         3
         4
         5
         6
         7

7 rows selected.
</pre>
<p>So we got what we wanted!</p>
<p>PS. Full scripts:<br />
1. Simple: <a href="http://orasql.org/scripts/print_table.sql" title="simple print_table" target="_blank">print_table.sql</a><br />
2. For big queries: <a href="http://orasql.org/scripts/print_table2.sql" title="print_table for big_tables" target="_blank">print_table2.sql</a> </p>
]]></content:encoded>
			<wfw:commentRss>http://orasql.org/2013/04/02/sqlplus-tips-2/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>SQL*Plus tips. #1</title>
		<link>http://orasql.org/2013/03/29/sqlplus-tips-1/</link>
		<comments>http://orasql.org/2013/03/29/sqlplus-tips-1/#comments</comments>
		<pubDate>Thu, 28 Mar 2013 23:58:01 +0000</pubDate>
		<dc:creator>Sayan Malakshinov</dc:creator>
				<category><![CDATA[oracle]]></category>
		<category><![CDATA[SQL*Plus]]></category>

		<guid isPermaLink="false">http://orasql.org/?p=242</guid>
		<description><![CDATA[If you are using SQL*Plus, you are likely to use the input parameters. And if you omit one of them, SQL*Plus will show prompt for it, like this: It is allright, if all variables are needed, but what if we don&#8217;t want to press enter for all omitted variables or specify they(especially if script can [...]]]></description>
				<content:encoded><![CDATA[<p>If you are using SQL*Plus, you are likely to use the input parameters. And if you omit one of them, SQL*Plus will show prompt for it, like this:</p>
<pre class="brush: sql; highlight: [8]; title: ; notranslate">
SQL&gt; get test.sql
  1  select 'Input variable 1 = &amp;1' from dual
  2  union all
  3  select 'Input variable 2 = &amp;2' from dual
  4  union all
  5* select 'Input variable 3 = &amp;3' from dual
SQL&gt; @test var1 var2
Enter value for 3:

'INPUTVARIABLE1=VAR1'
-----------------------
Input variable 1 = var1
Input variable 2 = var2
Input variable 3 =

Elapsed: 00:00:00.01
</pre>
<p>It is allright, if all variables are needed, but what if we don&#8217;t want to press enter for all omitted variables or specify they(especially if script can be start in silent, non interactive mode) and want to use <em>default</em> values for omitted variables or these variables can be unnecessary?<br />
Strictly speaking, there are many different techniques for solving it, see some of them:<br />

<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: Comma-separated params</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv4f0c800e"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv4f0c800e",true,"Show","Hide","fast",false); return false;' id='spoilerDiv4f0c800e_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv4f0c800e' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
SQL&gt; get test1
  1  col var1 new_value var1 noprint
  2  col var2 new_value var2 noprint
  3  col var3 new_value var3 noprint
  4  set termout off
  5  with any_splitting_technique as (
  6       select *
  7       from xmltable('ora:tokenize(.,&quot;,&quot;)[position()&gt;1]'
  8                      passing ','||'&amp;1'
  9                      columns
 10                        i for ordinality
 11                       ,&quot;.&quot; varchar2(30)
 12                    )
 13  )
 14  select
 15    nvl(&quot;1&quot;,'default1') var1
 16   ,nvl(&quot;2&quot;,'default2') var2
 17   ,nvl(&quot;3&quot;,'default3') var3
 18  from any_splitting_technique
 19  pivot (max(&quot;.&quot;) for i in (1,2,3))
 20  /
 21  set termout on
 22* prompt var1 = &amp;var1, var2 = &amp;var2, var3 = &amp;var3;
SQL&gt; @test1 1,2,3
var1 = 1, var2 = 2, var3 = 3
SQL&gt; @test1 1,2
var1 = 1, var2 = 2, var3 = default3
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
<br />

<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: With SPOOL and DEFINE</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv49ac800f"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv49ac800f",true,"Show","Hide","fast",false); return false;' id='spoilerDiv49ac800f_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv49ac800f' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
SQL&gt; get test2
  1  set termout off
  2  spool tmp.sql
  3  def 1
  4  def 2
  5  def 3
  6  spool off
  7  col var1 new_value var1
  8  col var2 new_value var2
  9  col var3 new_value var3
 10  with tmp as (
 11  select '
 12  @tmp.sql
 13  ' params from dual
 14  )
 15  select
 16    nvl(regexp_substr(params,'DEFINE 1\s+ = &quot;([^&quot;]*)',1,1,'i',1),'default1') var1
 17  , nvl(regexp_substr(params,'DEFINE 2\s+ = &quot;([^&quot;]*)',1,1,'i',1),'default2') var2
 18  , nvl(regexp_substr(params,'DEFINE 3\s+ = &quot;([^&quot;]*)',1,1,'i',1),'default3') var3
 19  from tmp
 20  ;
 21  col var1 clear;
 22  col var2 clear;
 23  col var3 clear;
 24  set termout on
 25  prompt var1 = &amp;var1, var2 = &amp;var2, var3 = &amp;var3;
 26  undef 1
 27  undef 2
 28* undef 3
 29  .
SQL&gt; @test2 1 2 3
var1 = 1, var2 = 2, var3 = 3
SQL&gt; @test2 1 2
var1 = 1, var2 = 2, var3 = default3
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
<br />
Last example also shows a very useful <em><strong>way to read file into a variable</strong></em>.<br />
But i think, the best option for initializing parameters is the <a href="http://vbegun.blogspot.nl/2008/04/on-sqlplus-defines.html" title="Vladimir's Diary. On SQL*Plus defines" target="_blank">solution by Vladimir Begun</a>:</p>
<pre class="brush: sql; title: ; notranslate">
SQL&gt; get test3
  1  set termout off
  2  COLUMN 1 NEW_VALUE 1    noprint
  3  COLUMN 2 NEW_VALUE 2    noprint
  4  COLUMN 3 NEW_VALUE 3    noprint
  5  SELECT '' &quot;1&quot;, '' &quot;2&quot;, '' &quot;3&quot; FROM dual WHERE 1=0;
  6  SELECT nvl('&amp;1','default1') &quot;1&quot;
  7       , nvl('&amp;2','default2') &quot;2&quot;
  8       , nvl('&amp;3','default3') &quot;3&quot;
  9    FROM dual;
 10  col var1 clear;
 11  col var2 clear;
 12  col var3 clear;
 13  set termout on
 14  prompt var1 = &amp;1, var2 = &amp;2, var3 = &amp;3;
 15  undef 1
 16  undef 2
 17* undef 3
 18  .
SQL&gt; @test3 1 2 3
var1 = 1, var2 = 2, var3 = 3
SQL&gt; @test3 1 2
var1 = 1, var2 = 2, var3 = default3
</pre>
<p>So i can create 2 include files &#8211; for execution at the start and at the end of all scripts. I created directory &#8220;inc&#8221; for include files and files:<br />

<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: inc/s_begin.sql</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv51b18010"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv51b18010",true,"Show","Hide","fast",false); return false;' id='spoilerDiv51b18010_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv51b18010' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
store set splus_restore.sql replace
set termout off
COLUMN  1  NEW_VALUE  1    noprint
COLUMN  2  NEW_VALUE  2    noprint
COLUMN  4  NEW_VALUE  4    noprint
COLUMN  3  NEW_VALUE  3    noprint
COLUMN  5  NEW_VALUE  5    noprint
COLUMN  6  NEW_VALUE  6    noprint
COLUMN  7  NEW_VALUE  7    noprint
COLUMN  8  NEW_VALUE  8    noprint
COLUMN  9  NEW_VALUE  9    noprint
COLUMN 10  NEW_VALUE 10    noprint
COLUMN 11  NEW_VALUE 11    noprint
COLUMN 12  NEW_VALUE 12    noprint
COLUMN 13  NEW_VALUE 13    noprint
COLUMN 14  NEW_VALUE 14    noprint
COLUMN 15  NEW_VALUE 15    noprint
COLUMN 16  NEW_VALUE 16    noprint


SELECT ''  &quot;1&quot;, '' &quot;5&quot;, ''  &quot;9&quot;, '' &quot;13&quot;
      ,''  &quot;2&quot;, '' &quot;6&quot;, '' &quot;10&quot;, '' &quot;14&quot;
      ,''  &quot;3&quot;, '' &quot;7&quot;, '' &quot;11&quot;, '' &quot;15&quot;
      ,''  &quot;4&quot;, '' &quot;8&quot;, '' &quot;12&quot;, '' &quot;16&quot;
  FROM dual
 WHERE 1=0;
set termout on;
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
<br />
and 
<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: inc/s_end.sql</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv7ad18011"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv7ad18011",true,"Show","Hide","fast",false); return false;' id='spoilerDiv7ad18011_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv7ad18011' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
undef 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
@splus_restore;
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
And for example get_index.sql:
<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: get_index.sql</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv2e3c8012"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv2e3c8012",true,"Show","Hide","fast",false); return false;' id='spoilerDiv2e3c8012_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv2e3c8012' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
@inc/s_begin;
col table_owner format a12
col column_name format a30
col index_owner format a12
col index_name  format a30

col &quot;#&quot; format 99
break on table_owner on table_name on index_owner on index_name on partition_name on mbytes on bytes on blocks
select 
         ic.table_owner
        ,ic.table_name
        ,ic.index_owner
        ,ic.index_name
        ,s.partition_name
        ,round(s.bytes/1024/1024) mbytes
        ,s.blocks
        ,ic.column_position &quot;#&quot;
        ,decode(ic.column_position,1,'','  ,')||ic.column_name column_name
from dba_ind_columns ic 
    ,dba_segments s
where
     upper(ic.table_name) like upper('&amp;1')
 and upper(ic.table_owner) like nvl(upper('&amp;2'),'%')
 and s.owner        = ic.index_owner
 and s.segment_name = ic.index_name
order by
         1,2,3,4,8
/
clear break;
col &quot;#&quot; clear;
@inc/s_end;
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
</p>
<p>
<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: Sample output</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv52f08013"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv52f08013",true,"Show","Hide","fast",false); return false;' id='spoilerDiv52f08013_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv52f08013' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
SQL&gt; @get_indexes wrh$%tab%stat xtender
Wrote file splus_restore.sql

no rows selected

Elapsed: 00:00:05.79
SQL&gt; @get_indexes wrh$%undostat
Wrote file splus_restore.sql

TABLE_OWNER  TABLE_NAME     INDEX_OWNER  INDEX_NAME        PARTITION_NAME  MBYTES  BLOCKS   # COLUMN_NAME
------------ -------------- ------------ ----------------- -------------- ------- ------- --- --------------------
SYS          WRH$_UNDOSTAT  SYS          WRH$_UNDOSTAT_PK                       0      16   1 BEGIN_TIME
                                                                                            2   ,END_TIME
                                                                                            3   ,DBID
                                                                                            4   ,INSTANCE_NUMBER
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
As you see i can omit owner parameter and in this case it will search in all schemas.</p>
]]></content:encoded>
			<wfw:commentRss>http://orasql.org/2013/03/29/sqlplus-tips-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Example of controlling “direct path reads” decision through SQL profile hints (index_stats/table_stats)</title>
		<link>http://orasql.org/2013/03/18/example-of-controlling-direct-path-reads-decision-through-sql-profile-hints/</link>
		<comments>http://orasql.org/2013/03/18/example-of-controlling-direct-path-reads-decision-through-sql-profile-hints/#comments</comments>
		<pubDate>Sun, 17 Mar 2013 23:33:06 +0000</pubDate>
		<dc:creator>Sayan Malakshinov</dc:creator>
				<category><![CDATA[adaptive serial direct path reads]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[undocumented]]></category>
		<category><![CDATA[direct path reads]]></category>

		<guid isPermaLink="false">http://orasql.org/?p=218</guid>
		<description><![CDATA[Previously i showed not obvious example with hint &#8220;INDEX_STATS(&#8220;OWNER&#8221;.&#8221;TABLE_NAME&#8221;, &#8220;INDEX_NAME&#8221;, scale, blocks=X, rows=Y)&#8220;. Strictly speaking i don&#8217;t know how exactly cbo calculates number of index leaf blocks in that case: in those examples they was 1981 for &#8220;blocks=1, rows=50&#8243; and 49525 for &#8220;blocks=5, rows=10&#8243;. But i know that with &#8220;INDEX_STATS(&#8220;OWNER&#8221;.&#8221;TABLE_NAME&#8221;, &#8220;INDEX_NAME&#8221;, scale, blocks=X)&#8221; i can [...]]]></description>
				<content:encoded><![CDATA[<p>Previously i showed not obvious example with hint <em>&#8220;<b>INDEX_STATS(&#8220;OWNER&#8221;.&#8221;TABLE_NAME&#8221;, &#8220;INDEX_NAME&#8221;, scale, blocks=X, rows=Y)</b>&#8220;</em>. Strictly speaking i don&#8217;t know how exactly cbo calculates number of index leaf blocks in that case: in those examples they was 1981 for &#8220;blocks=1, rows=50&#8243; and 49525 for &#8220;blocks=5, rows=10&#8243;.<br />
But i know that with <em><b>&#8220;INDEX_STATS(&#8220;OWNER&#8221;.&#8221;TABLE_NAME&#8221;, &#8220;INDEX_NAME&#8221;, scale, blocks=X)&#8221;</b></em> i can set exact blocks number.<br />
Also those test-cases didn&#8217;t show when occurs decision changing. So todays my test will show it.</p>
<p>BTW, it is very interesting that a turning point was <em>_very_large_object_threshold</em>, but not 5 * <em>_small_table_threshold</em>. AFAIK, direct path reads decision depends on many factors (such as number of object blocks in buffer cache), and would be great to know all of them.<br />
You can download script as file: <a href="http://orasql.org/wp-content/uploads/2013/03/controlling_direct_reads_with_profiles.sql_.txt">controlling_direct_reads_with_profiles.sql</a><br />

<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: Test code</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv308014"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv308014",true,"Show","Hide","fast",false); return false;' id='spoilerDiv308014_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv308014' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
/** SQLPLUS Example of controlling adaptive serial direct path reads through SQL profiles.
*/
set serverout on termout on timing off feed off;
clear scr;
def _IF_XT_RUNSTATS_EXISTS=&quot;--&quot;
col if_xt_runstats_exists new_value _IF_XT_RUNSTATS_EXISTS noprint;
select decode(count(*),1,'  ','--') if_xt_runstats_exists 
from all_objects where object_name='XT_RUNSTATS' and rownum=1;
/**
 * Main test.
 * You can use it also in other clients, 
 * but in that case you have to manually 
 * set substitution variable _IF_XT_RUNSTATS_EXISTS:
 *  if you have not this package - to &quot;--&quot; 
 *  otherwise                    - to space(&quot; &quot;)
 * Latest version of XT_RUNSTATS you can get from:
 *  https://github.com/xtender/xt_runstats
 */

declare

   C_SQL_TEXT      constant varchar2(300):='SELECT SUM(A) FROM XT_IFFS T';
   C_PROFILE_NAME  constant varchar2(30) :='PRF_ADPR_TEST';
   v_small_table_threshold        int;
   v_db_block_buffers             int;
   v_very_large_object_threshold  int;
   v__db_cache_size               int;
      
   procedure exec(p varchar2) is
     e_table_is_not_created_yet exception;
     e_index_is_not_created_yet exception;
     pragma exception_init(e_table_is_not_created_yet, -942);
     pragma exception_init(e_index_is_not_created_yet, -1418);
   begin
     execute immediate p;
   exception 
      when e_table_is_not_created_yet 
        or e_index_is_not_created_yet
        then null;
   end;

   /** Creating table and setting stats */   
   procedure create_table is
   begin
     exec('drop table xt_iffs purge');
     exec('create table xt_iffs as 
           with gen as(
                       select level a,mod(level,10) b,lpad(1,50,1) c
                       from dual 
                       connect by level&lt;=1e3
           )
           select gen.* 
           from gen,gen gen2'
         );
     --dbms_stats.set_table_stats('','XT_IFFS',numrows =&gt; 1e6,numblks =&gt; 5e5,avgrlen =&gt; 800);
     dbms_stats.gather_table_stats('','XT_IFFS');
   end;
   
   /** Recreating index and setting stats */
   procedure create_index is
   begin
     exec('drop index ix_iffs');
     exec('create index ix_iffs on xt_iffs(a,b)');
     dbms_stats.set_index_stats('','IX_IFFS',numrows =&gt; 1e6,numlblks =&gt; 1e4);
   end;
   
   /** Setting index numblks for query through SQL profile */
   procedure set_numblks(p_numblks int) is
     e_profile_not_created_yet  exception;
     pragma exception_init( e_profile_not_created_yet, -13833);
   begin
     begin
        dbms_sqltune.drop_sql_profile(C_PROFILE_NAME);
     exception when e_profile_not_created_yet then null;
     end;
     dbms_sqltune.import_sql_profile(
        sql_text    =&gt; C_SQL_TEXT,
        profile     =&gt; sys.sqlprof_attr(
                                 'INDEX_FFS(@&quot;SEL$1&quot; &quot;T&quot;@&quot;SEL$1&quot; (&quot;XT_IFFS&quot;.&quot;A&quot;))'
                                ,'INDEX_STATS(&quot;'||user||'&quot;.&quot;XT_IFFS&quot;, &quot;IX_IFFS&quot;, scale, blocks='||p_numblks||')'
                       ),
        category     =&gt; 'DEFAULT',
        name        =&gt; C_PROFILE_NAME,
        force_match =&gt; false,
        replace     =&gt; true
     );
   end; 
     
   procedure test( p_description varchar2
                 , p_numblks int default null) is

     type t_seg_stat is 
        table of number 
        index by v$segstat_name.name%type;
     -- segments statistics by index:
     cursor c_stats is
        select sn.name,nvl(st.value,0) value
        from v$segstat_name sn
            ,v$segment_statistics st 
        where 
              sn.statistic#     = st.statistic#(+)
          and st.owner(+)       = user 
          and st.object_name(+) ='IX_IFFS';
     -- var for previous stats:
     v_pre     t_seg_stat;
     v_delta   number;
     n         number;
   begin
     dbms_output.put_line('-');
     dbms_output.put_line('-');
     dbms_output.put_line(lpad('-',150,'-'));
     dbms_output.put_line(lpad('-',150,'-'));
     dbms_output.put_line(  '###                ' 
                         || p_description||': '
                         ||nvl(to_char(p_numblks),'default')||' blocks');
     dbms_output.put_line('-');

     create_index;
     -- if p_numblks is null then default stats used
     if p_numblks is not null then
       set_numblks(p_numblks);
     end if;
     execute immediate C_SQL_TEXT into n;
     exec('alter system flush buffer_cache');
     -- saving segment statistics
     for r in c_stats loop
        v_pre(r.name) := r.value;
     end loop;

     &amp;_IF_XT_RUNSTATS_EXISTS  xt_runstats.init(p_latches =&gt; false);
     -- executing query
     execute immediate C_SQL_TEXT into n;
   &amp;_IF_XT_RUNSTATS_EXISTS  xt_runstats.snap;
   &amp;_IF_XT_RUNSTATS_EXISTS  xt_runstats.print(
   &amp;_IF_XT_RUNSTATS_EXISTS     p_stats_mask =&gt; '(reads (cache|direct)\.)|index fast full scans \((full|direct)'
   &amp;_IF_XT_RUNSTATS_EXISTS    ,p_sta_diff_pct =&gt; 0);

     -- printing segments stats delta:
     for r in c_stats loop
        v_delta:= r.value - v_pre(r.name);
        if v_delta!=0 then
          dbms_output.put_line( rpad(r.name,40,'.')||v_delta );
        end if;
     end loop;
   end;

   procedure load_and_print_params is
   begin
      select
         max(decode(a.ksppinm, '_small_table_threshold'       ,b.ksppstvl)) 
        ,max(decode(a.ksppinm, '_db_block_buffers'            ,b.ksppstvl))
        ,max(decode(a.ksppinm, '_very_large_object_threshold' ,b.ksppstvl))
        ,max(decode(a.ksppinm, '__db_cache_size'              ,b.ksppstvl))
         into v_small_table_threshold,v_db_block_buffers,v_very_large_object_threshold,v__db_cache_size
      from
        sys.x$ksppi a
       ,sys.x$ksppcv b
      where
           a.indx = b.indx
       and a.ksppinm in('_small_table_threshold','_db_block_buffers','_very_large_object_threshold','__db_cache_size');
      dbms_output.put_line('_small_table_threshold       = '||v_small_table_threshold);
      dbms_output.put_line('_db_block_buffers            = '||v_db_block_buffers);
      dbms_output.put_line('_very_large_object_threshold = '||v_very_large_object_threshold);
      dbms_output.put_line('__db_cache_size              = '||v__db_cache_size);
      
   end;
begin
  create_table;
  load_and_print_params;

  test( '_very_large_object_threshold + 1'
       ,v_db_block_buffers * v_very_large_object_threshold/100 + 1 );
  test( '_very_large_object_threshold'
       ,v_db_block_buffers * v_very_large_object_threshold/100     );
  test( '_very_large_object_threshold - 1'
       ,v_db_block_buffers * v_very_large_object_threshold/100 - 1 );

  test( '_db_block_buffers + 1'
       ,v_db_block_buffers + 1 );
  test( '_db_block_buffers - 1'
       ,v_db_block_buffers - 1 );
  
  test( '_small_table_threshold * 5 + 1'
       ,v_small_table_threshold * 5 + 1 );
  test( '_small_table_threshold * 5 - 1'
       ,v_small_table_threshold * 5 - 1 );

  test( ' 1 block ', 1);
  test( ' Default ', null);

  test( ' Again _very_large_object_threshold + 1'
       ,v_db_block_buffers * v_very_large_object_threshold/100 + 1 );
  test( ' Again _very_large_object_threshold'
       ,v_db_block_buffers * v_very_large_object_threshold/100     );

end;
/
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
<br />

<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: Test results</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv11ac8015"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv11ac8015",true,"Show","Hide","fast",false); return false;' id='spoilerDiv11ac8015_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv11ac8015' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>
</p>
<pre class="brush: sql; highlight: [9,17,19,25,31,41,52,62,73,83,94,104,115,125,136,146,157,167,178,188,199,209,221,231]; title: ; notranslate">
_small_table_threshold       = 166
_db_block_buffers            = 8347
_very_large_object_threshold = 500
__db_cache_size              = 4194304
-
-
------------------------------------------------------------------------------
------------------------------------------------------------------------------
###                _very_large_object_threshold + 1: 41736 blocks
-
################     Results:      ##################
Run #  01 ran in 11 hsecs
##########################################################
Statistics                               | Run # 1
##########################################################
physical reads cache.................... |              1
physical reads direct................... |          2,491
index fast full scans (full)............ |              1
index fast full scans (direct read)..... |              1
##########################################################
-
logical reads...........................2496
physical reads..........................2492
physical read requests..................86
physical reads direct...................2491
segment scans...........................1
-
-
------------------------------------------------------------------------------
------------------------------------------------------------------------------
###                _very_large_object_threshold: 41735 blocks
-
################     Results:      ##################
Run #  01 ran in 6 hsecs
##########################################################
Statistics                               | Run # 1
##########################################################
physical reads cache.................... |          2,494
physical reads direct................... |              0
index fast full scans (full)............ |              1
index fast full scans (direct read)..... |              0
##########################################################
-
logical reads...........................2496
physical reads..........................2494
physical read requests..................95
segment scans...........................1
-
-
------------------------------------------------------------------------------
------------------------------------------------------------------------------
###                _very_large_object_threshold - 1: 41734 blocks
-
################     Results:      ##################
Run #  01 ran in 11 hsecs
##########################################################
Statistics                               | Run # 1
##########################################################
physical reads cache.................... |          3,386
physical reads direct................... |              1
index fast full scans (full)............ |              1
index fast full scans (direct read)..... |              0
##########################################################
-
logical reads...........................2512
physical reads..........................2494
physical read requests..................95
segment scans...........................1
-
-
------------------------------------------------------------------------------
------------------------------------------------------------------------------
###                _db_block_buffers + 1: 8348 blocks
-
################     Results:      ##################
Run #  01 ran in 6 hsecs
##########################################################
Statistics                               | Run # 1
##########################################################
physical reads cache.................... |          2,494
physical reads direct................... |              0
index fast full scans (full)............ |              1
index fast full scans (direct read)..... |              0
##########################################################
-
logical reads...........................2512
physical reads..........................2494
physical read requests..................95
segment scans...........................1
-
-
------------------------------------------------------------------------------
------------------------------------------------------------------------------
###                _db_block_buffers - 1: 8346 blocks
-
################     Results:      ##################
Run #  01 ran in 8 hsecs
##########################################################
Statistics                               | Run # 1
##########################################################
physical reads cache.................... |          2,494
physical reads direct................... |              0
index fast full scans (full)............ |              1
index fast full scans (direct read)..... |              0
##########################################################
-
logical reads...........................2512
physical reads..........................2494
physical read requests..................95
segment scans...........................1
-
-
------------------------------------------------------------------------------
------------------------------------------------------------------------------
###                _small_table_threshold * 5 + 1: 831 blocks
-
################     Results:      ##################
Run #  01 ran in 6 hsecs
##########################################################
Statistics                               | Run # 1
##########################################################
physical reads cache.................... |          2,494
physical reads direct................... |              0
index fast full scans (full)............ |              1
index fast full scans (direct read)..... |              0
##########################################################
-
logical reads...........................2512
physical reads..........................2494
physical read requests..................95
segment scans...........................1
-
-
------------------------------------------------------------------------------
------------------------------------------------------------------------------
###                _small_table_threshold * 5 - 1: 829 blocks
-
################     Results:      ##################
Run #  01 ran in 7 hsecs
##########################################################
Statistics                               | Run # 1
##########################################################
physical reads cache.................... |          2,494
physical reads direct................... |              0
index fast full scans (full)............ |              1
index fast full scans (direct read)..... |              0
##########################################################
-
logical reads...........................2496
physical reads..........................2494
physical read requests..................95
segment scans...........................1
-
-
------------------------------------------------------------------------------
------------------------------------------------------------------------------
###                 1 block : 1 blocks
-
################     Results:      ##################
Run #  01 ran in 6 hsecs
##########################################################
Statistics                               | Run # 1
##########################################################
physical reads cache.................... |          2,494
physical reads direct................... |              0
index fast full scans (full)............ |              1
index fast full scans (direct read)..... |              0
##########################################################
-
logical reads...........................2512
physical reads..........................2494
physical read requests..................95
segment scans...........................1
-
-
------------------------------------------------------------------------------
------------------------------------------------------------------------------
###                 Default : default blocks
-
################     Results:      ##################
Run #  01 ran in 7 hsecs
##########################################################
Statistics                               | Run # 1
##########################################################
physical reads cache.................... |          2,494
physical reads direct................... |              0
index fast full scans (full)............ |              1
index fast full scans (direct read)..... |              0
##########################################################
-
logical reads...........................2496
physical reads..........................2494
physical read requests..................95
segment scans...........................1
-
-
------------------------------------------------------------------------------
------------------------------------------------------------------------------
###                 Again _very_large_object_threshold + 1: 41736 blocks
-
################     Results:      ##################
Run #  01 ran in 6 hsecs
##########################################################
Statistics                               | Run # 1
##########################################################
physical reads cache.................... |              1
physical reads direct................... |          2,491
index fast full scans (full)............ |              1
index fast full scans (direct read)..... |              1
##########################################################
-
logical reads...........................2496
physical reads..........................2492
physical read requests..................86
physical reads direct...................2491
segment scans...........................1
-
-
------------------------------------------------------------------------------
------------------------------------------------------------------------------
###                 Again _very_large_object_threshold: 41735 blocks
-
################     Results:      ##################
Run #  01 ran in 7 hsecs
##########################################################
Statistics                               | Run # 1
##########################################################
physical reads cache.................... |          2,494
physical reads direct................... |              0
index fast full scans (full)............ |              1
index fast full scans (direct read)..... |              0
##########################################################
-
logical reads...........................2496
physical reads..........................2494
physical read requests..................95
segment scans...........................1

PL/SQL procedure successfully completed.
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
</p>
]]></content:encoded>
			<wfw:commentRss>http://orasql.org/2013/03/18/example-of-controlling-direct-path-reads-decision-through-sql-profile-hints/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Unresolved quiz: Avoiding in-list iterator</title>
		<link>http://orasql.org/2013/03/14/unresolved-quiz-avoiding-in-list-iterator/</link>
		<comments>http://orasql.org/2013/03/14/unresolved-quiz-avoiding-in-list-iterator/#comments</comments>
		<pubDate>Wed, 13 Mar 2013 22:34:23 +0000</pubDate>
		<dc:creator>Sayan Malakshinov</dc:creator>
				<category><![CDATA[oracle]]></category>
		<category><![CDATA[query optimizing]]></category>
		<category><![CDATA[query optimization]]></category>

		<guid isPermaLink="false">http://orasql.org/?p=211</guid>
		<description><![CDATA[A couple days ago i had very interesting quiz, which is not resolved yet. Look at this simplified query: As you see, in such queries cbo always generating plans with INLIST ITERATOR, and it is reasonably in cases when there are many rows with different values of field B for most values of A, and [...]]]></description>
				<content:encoded><![CDATA[<p>A couple days ago i had very interesting quiz, which is not resolved yet.<br />
Look at this simplified query:</p>
<pre class="brush: sql; collapse: true; light: false; title: ; toolbar: true; notranslate">
  select *
  from xt1,xt2
  where
       xt1.b=10
   and xt1.a=xt2.a
   and xt2.b in (1,2);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------
Plan hash value: 2715236140

----------------------------------------------------------------------------------------
| Id  | Operation                     | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |        |   100 | 36900 |   501   (0)| 00:00:07 |
|   1 |  NESTED LOOPS                 |        |       |       |            |          |
|   2 |   NESTED LOOPS                |        |   100 | 36900 |   501   (0)| 00:00:07 |
|   3 |    TABLE ACCESS BY INDEX ROWID| XT1    |   100 | 31000 |   101   (0)| 00:00:02 |
|*  4 |     INDEX RANGE SCAN          | IX_XT1 |   100 |       |     1   (0)| 00:00:01 |
|   5 |    INLIST ITERATOR            |        |       |       |            |          |
|*  6 |     INDEX RANGE SCAN          | IX_XT2 |     1 |       |     3   (0)| 00:00:01 |
|   7 |   TABLE ACCESS BY INDEX ROWID | XT2    |     1 |    59 |     4   (0)| 00:00:01 |
----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access(&quot;XT1&quot;.&quot;B&quot;=10)
   6 - access(&quot;XT1&quot;.&quot;A&quot;=&quot;XT2&quot;.&quot;A&quot; AND (&quot;XT2&quot;.&quot;B&quot;=1 OR &quot;XT2&quot;.&quot;B&quot;=2))
</pre>
<p>
<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: Full test case</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv71d8016"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv71d8016",true,"Show","Hide","fast",false); return false;' id='spoilerDiv71d8016_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv71d8016' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
create table xt1 as
select 
   level a
 , mod(level,1000) b
 , lpad(1,300,1) padding 
from dual
connect by level&lt;=1e5;

create index ix_xt1 on xt1(b);

create table xt2 as
select 
   level        a
 , mod(level,5) b
 , lpad(1,50,1) padding 
from dual
connect by level&lt;=1e6;

alter table xt2 
  add constraint uq_xt2
  unique (a)
  using index(create index ix_xt2 on xt2(a,b));

exec dbms_stats.gather_table_stats('','XT1',cascade=&gt;true);
exec dbms_stats.gather_table_stats('','XT2',cascade=&gt;true);

explain plan for 
select *
from xt1,xt2
where 
     xt1.b=10
 and xt1.a=xt2.a
 and xt2.b in (1,2);

@?/rdbms/admin/utlxpls.sql
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
<br />
As you see, in such queries cbo always generating plans with INLIST ITERATOR, and it is reasonably in cases when there are many rows with different values of field B for most values of A, and this number is much larger than number of values in the &#8220;INLIST&#8221;. But in such case as shown, will be better to use index range scan with access by A and filter by B:</p>
<pre class="brush: sql; highlight: [13,20,27]; title: ; notranslate">
SQL&gt; select *
  2  from xt1,xt2
  3  where
  4       xt1.b=10
  5   and xt1.a=xt2.a
  6   and xt2.b in (1,2);

no rows selected

Statistics
----------------------------------------------------------
        ...
        505  consistent gets
SQL&gt; -- without inlist iterator:
SQL&gt; select *
  2  from xt1,xt2
  3  where
  4       xt1.b=10
  5   and xt1.a=xt2.a
  6   and xt2.b+0 in (1,2);

no rows selected

Statistics
----------------------------------------------------------
        ...
        305  consistent gets
</pre>
<p>But how we can do it? I know 5 options:<br />
1. Trace event 10157<br />
2. Rewrite code. for example replacing &#8220;b in (1,2)&#8221; to &#8220;b+0 in (1,2)&#8221;<br />
3. Changing query with &#8220;Advanced query rewrite&#8221; (DBMS_ADVANCED_REWRITE.DECLARE_REWRITE_EQUIVALENCE)<br />
4. Recreating index from xt2(a,b) to xt2(a,1,b)<br />
5. Changing optimizer_mode to &#8220;rule&#8221; through hint or SQL profile/baseline</p>
<p>But unfortunately all of them are inapplicable for the my real problem, because i cannot for some reasons rewrite query or change query with advanced rewrite, cannot recreate/add index, and can&#8217;t change optimizer_mode, because execution plan for the real query will become worst than plan generated with CBO with inlist iterator(some operations aren&#8217;t exists in RBO).</p>
<p>Could anybody suggest any another solution?</p>
]]></content:encoded>
			<wfw:commentRss>http://orasql.org/2013/03/14/unresolved-quiz-avoiding-in-list-iterator/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Deterministic function vs scalar subquery caching. Part 3</title>
		<link>http://orasql.org/2013/03/13/deterministic-function-vs-scalar-subquery-caching-part-3/</link>
		<comments>http://orasql.org/2013/03/13/deterministic-function-vs-scalar-subquery-caching-part-3/#comments</comments>
		<pubDate>Wed, 13 Mar 2013 20:14:17 +0000</pubDate>
		<dc:creator>Sayan Malakshinov</dc:creator>
				<category><![CDATA[deterministic functions]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[scalar subquery caching]]></category>
		<category><![CDATA[oracle undocumented behaviour]]></category>
		<category><![CDATA[query optimizing]]></category>

		<guid isPermaLink="false">http://orasql.org/?p=205</guid>
		<description><![CDATA[In previous parts i already point out that: Both mechanisms are based on hash functions. Deterministic caching depends on fetch size(arraysize) &#8211; results cached only within one fetch call, ssc has no this limitation. Hash collisions depends on the single parameter &#8220;_query_execution_cache_max_size&#8221; for both mechanizms, but they are more frequent in SSC. Deterministic functions does [...]]]></description>
				<content:encoded><![CDATA[<p>In previous parts i already point out that:</p>
<ol>
<li><a href="http://orasql.org/2013/02/10/deterministic-function-vs-scalar-subquery-caching-part-1/" title="Deterministic function vs scalar subquery caching. Part 1" target="_blank">Both mechanisms are based on hash functions.</a></li>
<li><a href="http://orasql.org/2013/02/10/deterministic-function-vs-scalar-subquery-caching-part-1/#topic2">Deterministic caching depends on fetch size(arraysize) &#8211; results cached only within one fetch call, ssc has no this limitation.</a></li>
<li><a href="http://orasql.org/2013/02/10/deterministic-function-vs-scalar-subquery-caching-part-1/#topic3">Hash collisions depends on the single parameter &#8220;_query_execution_cache_max_size&#8221; for both mechanizms, but they are more frequent in SSC.</a></li>
<li><a href="http://orasql.org/2013/02/11/deterministic-function-vs-scalar-subquery-caching-part-2/#topic4">Deterministic functions does not keeps last result as scalar subquery caching</a></li>
<li><a href="http://orasql.org/2013/02/11/deterministic-function-vs-scalar-subquery-caching-part-2/#topic5">Caching of deterministic functions results turns off after a certain number of attempts to get the value from the cache. But SSC always returns results from cache if values already cached.</a></li>
</ol>
<p>Today&#8217;s post is just addition to previous topics:</p>
<p>I wrote about turning caching off after many unsuccessfull attempts to get value from cache, but i didn&#8217;t say what it is the number. In fact caching of deterministic functions also depends on two another hidden parameters:</p>
<pre class="brush: sql; title: ; notranslate">
SQL&gt; @param_ plsql%cach

NAME                                 VALUE        DEFLT    TYPE       DESCRIPTION
------------------------------------ ------------ -------- ---------- ------------------------------------------------------------------
_plsql_cache_enable                  TRUE         TRUE     boolean    PL/SQL Function Cache Enabled
_plsql_minimum_cache_hit_percent     20           TRUE     number     plsql minimum cache hit percentage required to keep caching active
</pre>
<p>First parameter &#8220;<strong>_plsql_cache_enable</strong>&#8221; is just a parameter which enables/disables this caching mechanism.<br />
But the second parameter &#8211; &#8220;<strong>_plsql_minimum_cache_hit_percent</strong>&#8221; &#8211; is responsible for the percentage of unsuccessful attempts which disables caching.</p>
<p>I will show their effects with the example from the previous post:</p>
<pre class="brush: sql; highlight: [6,18,20,23,36,38]; title: ; notranslate">
-- set this parameter to big value for maximizing caching:
alter session set &quot;_query_execution_cache_max_size&quot; = 131072;
-- log table clearing:
truncate table t_params;
-- test with percentage = 50
alter session set &quot;_plsql_minimum_cache_hit_percent&quot;=50;
select sum(f_deterministic(n)) fd
from
  xmltable('1 to 10000,1 to 10000'
           columns n int path '.'
          );
 
select 10000-count(count(*)) &quot;Count of cached results&quot;
from t_params
group by p
having count(*)&gt;1;
/*
Count of cached results
-----------------------
                      0
*/
-- now i change cache hit percentage parameter to 0:
alter session set &quot;_plsql_minimum_cache_hit_percent&quot;=0;
truncate table t_params;
select sum(f_deterministic(n)) fd
from
  xmltable('1 to 10000,1 to 10000'
           columns n int path '.'
          );
 
select 10000-count(count(*)) &quot;Count of cached results&quot;
from t_params
group by p
having count(*)&gt;1;
/*
Count of cached results
-----------------------
                   2039
*/
</pre>
]]></content:encoded>
			<wfw:commentRss>http://orasql.org/2013/03/13/deterministic-function-vs-scalar-subquery-caching-part-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How works optimization of loops in PL/SQL in 11g: Part 1. Deterministic functions</title>
		<link>http://orasql.org/2013/03/13/optimization-of-loops-in-plsql-part-1/</link>
		<comments>http://orasql.org/2013/03/13/optimization-of-loops-in-plsql-part-1/#comments</comments>
		<pubDate>Wed, 13 Mar 2013 01:20:26 +0000</pubDate>
		<dc:creator>Sayan Malakshinov</dc:creator>
				<category><![CDATA[deterministic functions]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[PL/SQL optimization]]></category>
		<category><![CDATA[11.2]]></category>
		<category><![CDATA[11g]]></category>
		<category><![CDATA[pl/sql optimization]]></category>

		<guid isPermaLink="false">http://orasql.org/?p=194</guid>
		<description><![CDATA[As you know, since 10g Oracle can optimize PL/SQL loops with moving code out of loops for reducing number of identical code executions. If you have not read yet about it, I advise you to first read these two articles: 1. &#8220;PLSQL_OPTIMIZE_LEVEL: The optimization strategy of Oracle&#8221; by Saurabh K. Gupta 2. &#8220;PL/SQL optimisation in [...]]]></description>
				<content:encoded><![CDATA[<p>As you know, since 10g Oracle can optimize PL/SQL loops with moving code out of loops for reducing number of identical code executions.<br />
If you have not read yet about it, I advise you to first read these two articles:<br />
1. &#8220;<a href="http://sbhoracle.wordpress.com/2011/10/19/234/" target="_blank">PLSQL_OPTIMIZE_LEVEL: The optimization strategy of Oracle</a>&#8221; by <b>Saurabh K. Gupta</b><br />
2. &#8220;<a href="http://www.oracle-developer.net/display.php?id=314" title="pl/sql optimisation in 10g" target="_blank">PL/SQL optimisation in 10g</a>&#8221; by <b>Adrian Billington</b></p>
<p>But since 11g Oracle also can optimize code with deterministic functions too. For this to happen, code must meet the following conditions:<br />
1. PLSQL_OPTIMIZE_LEVEL greater or equal 2<br />
2. Parameters should not be changed in the loop body. Strictly speaking, there should not be any assignment of parameters.<br />
3. Should not be any implicit conversions of parameters in function call, i.e. all variables/literals must be the same type as input parameters declared.<br />
4. Should not be any call of non-deterministic functions (except some standard sql functions like to_date, to_char, nvl) or procedures in the loop</p>
<p>Note that this rules concerns only same scope level as this loop and not inner loops or another blocks. </p>
<p><span id="more-194"></span><br />
For example we have code like this:</p>
<pre class="brush: sql; title: ; notranslate">
...
for i in 1..100 loop
  n:=deterministic_function(c);
end loop;
...
</pre>
<p>With enabled optimization oracle will rearrange this code to:</p>
<pre class="brush: sql; title: ; notranslate">
...
for i in 1..100 loop
  null;
end loop;
n:=deterministic_function(c);
...
</pre>
<p>We can simply see it with this test case:</p>
<pre class="brush: sql; title: ; notranslate">
create or replace function xt_print_deterministic(p varchar2) return varchar2 deterministic as
begin
  dbms_output.put_line(p);
  return p;
end;
/
create or replace procedure p_test_deterministic as
  v varchar2(10);
begin
  for i in 1..3 loop
    v:=xt_print_deterministic('before');
    for j in 1..10 loop
      v:=i;
      v:=xt_print_deterministic('1');
    end loop;
    v:=xt_print_deterministic('after');
  end loop;  
end;
/
set serverout on;
call p_test_deterministic();
</pre>
<p>After execution it printed:</p>
<pre class="brush: sql; highlight: [1]; title: ; notranslate">
before
after
1
after
1
after
1
</pre>
<p>Note that:<br />
1. &#8216;before&#8217; printed once at start &#8211; it because this line was moved out from outer loop and was executed before it.<br />
2. &#8216;After&#8217; printed three times, because optimization of outer loop was stopped on inner loop.<br />
3. &#8217;1&#8242; printed only three times, because it was moved out from inner cycle and added to end of outer loop.</p>
<p>But see what will happen if we change parameter from varchar2 literal &#8217;1&#8242; to number literal 1:<br />

<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: Hidden text</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv4f4e8017"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv4f4e8017",true,"Show","Hide","fast",false); return false;' id='spoilerDiv4f4e8017_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv4f4e8017' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; highlight: [14]; title: ; notranslate">
create or replace function xt_print_deterministic(p varchar2) return varchar2 deterministic as
begin
  dbms_output.put_line(p);
  return p;
end;
/
create or replace procedure p_test_deterministic as
  v varchar2(10);
begin
  for i in 1..3 loop
    v:=xt_print_deterministic('before');
    for j in 1..10 loop
      v:=i;
      v:=xt_print_deterministic(1);
    end loop;
    v:=xt_print_deterministic('after');
  end loop;  
end;
/
set serverout on;
call p_test_deterministic();
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
</p>
<pre class="brush: sql; title: ; notranslate">
before
after
1
1
1
1
1
1
1
1
1
1
after
1
1
1
1
1
1
1
1
1
1
after
1
1
1
1
1
1
1
1
1
1
</pre>
<p>Optimization of inner loop was disabled, because of implicit conversion, as i said above.</p>
<p>Now change &#8216;after&#8217; to &#8216;after&#8217;||v:</p>
<pre class="brush: sql; highlight: [10]; title: ; notranslate">
create or replace procedure p_test_deterministic as
  v varchar2(10);
begin
  for i in 1..3 loop
    v:=xt_print_deterministic('before');
    for j in 1..10 loop
      v:=i;
      v:=xt_print_deterministic('1');
    end loop;
    v:=xt_print_deterministic('after: '||v);
  end loop;  
end;
/
</pre>
<p>Let&#8217;s see what we have got:</p>
<pre class="brush: sql; title: ; notranslate">
before
1
after: 1
1
after: 1
1
after: 1
</pre>
<p>Everything was the same, but order was changed! It is a quite easy to explain: in the previous example, the order did not matter, because it has no effect to anything. But now oracle knows that result of execution in inner loop is needed for the line after inner loop. So this line moved directly after the loop and before the remaining code of the outer loop.</p>
<p>Previously i showed examples only with literals. Let&#8217;s see that this works also with variables:</p>
<pre class="brush: sql; highlight: [3,7,10]; title: ; notranslate">
SQL&gt; create or replace procedure p_test_deterministic as
  2    v varchar2(10);
  3    p varchar2(10);
  4  begin
  5    for i in 1..3 loop
  6      v:=xt_print_deterministic('before');
  7      p:=i;
  8      for j in 1..10 loop
  9        v:=i;
 10        v:=xt_print_deterministic(p);
 11      end loop;
 12      v:=xt_print_deterministic('after');
 13    end loop;
 14  end;
 15  /

Procedure created.

SQL&gt; exec p_test_deterministic();
before
after
1
after
2
after
3

PL/SQL procedure successfully completed.
</pre>
<p>Example showing that optimization will be disabled if exists non-deterministic function in scope:<br />

<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv42ae8018"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv42ae8018",true,"Show","Hide","fast",false); return false;' id='spoilerDiv42ae8018_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv42ae8018' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
create or replace function xt_print_deterministic(p varchar2) return varchar2 deterministic as
begin
  dbms_output.put_line(p);
  return p;
end;
/
create or replace procedure p_test_deterministic(p in varchar2) as
  v varchar2(30);
begin
  for i in 1..3 loop
    v:=xt_print_deterministic('before');
    for j in 1..10 loop
      v:=xt_print_deterministic(p);
      v:=sys_context('userenv','sid');
    end loop;
    v:=xt_print_deterministic('after');
  end loop;  
end;
/
set serverout on;
exec p_test_deterministic(1);</pre>
<p>Result:</p>
<pre class="brush: sql; title: ; notranslate">
before
1
1
1
1
1
1
1
1
1
1
after
before
1
1
1
1
1
1
1
1
1
1
after
before
1
1
1
1
1
1
1
1
1
1
after
</pre>
<p>
</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>
<br />
And now more funny example &#8211; Try to guess what will be displayed:</p>
<pre class="brush: sql; title: ; notranslate">
create or replace function xt_print_deterministic(p varchar2) return varchar2 deterministic as
begin
  dbms_output.put_line(p);
  return p;
end;
/
create or replace procedure p_test_deterministic(p in varchar2) as
  v varchar2(30);
  a varchar2(30);
begin
  for i in 1..3 loop
    v:=xt_print_deterministic('before');
    for j in 1..10 loop
      v:=xt_print_deterministic(p);
      if p='1' then 
        a:=sys_context('userenv','sid');
      else 
        a:='1';
      end if;
    end loop;
    v:=xt_print_deterministic('after');
  end loop;  
end;
/
set serverout on;
exec p_test_deterministic(1);
exec p_test_deterministic(2);
</pre>

<div class='easySpoilerWrapper' style=''>
<table class='easySpoilerTable' border='0' style='text-align:center;' align='center' bgcolor='FFFFFF' >

<tr style='white-space:normal;'>
<th class='easySpoilerTitleA' style='white-space:normal;font-weight:normal;text-align:left;vertical-align:middle;font-size:100%;color:#000000;'>Spoiler:: Result and explanation</th>
<th class='easySpoilerTitleB'style='text-align:right;vertical-align:middle;font-size:100%; white-space:nowrap;'><a href='' onclick='wpSpoilerSelect("spoilerDiv73f88019"); return false;' class='easySpoilerButtonOther' style='font-size:100%;color:#000000; margin: 3px 0px 3px; padding: 4px; ' align='right'>Select</a><a href='' onclick='wpSpoilerToggle("spoilerDiv73f88019",true,"Show","Hide","fast",false); return false;' id='spoilerDiv73f88019_action' class='easySpoilerButtonBare' value="Show" align='right' style='font-size:100%;color:#000000; margin: 3px 0px 3px 5px; padding: 4px;'>Show</></th>
</tr>
<tr><td class='easySpoilerRow' colspan='2' style=''><div id='spoilerDiv73f88019' class='easySpoilerSpoils'  style='display:none; white-space:wrap; overflow:auto; vertical-align:middle;'>

<pre class="brush: sql; title: ; notranslate">
SQL&gt; exec p_test_deterministic(1);
before
1
1
1
1
1
1
1
1
1
1
after
before
1
1
1
1
1
1
1
1
1
1
after
before
1
1
1
1
1
1
1
1
1
1
after

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.04
SQL&gt; exec p_test_deterministic(2);
before
2
after
before
2
after
before
2
after

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.02
</pre>
<p>I didn&#8217;t expect this, although it very simply explains: &#8216;IF&#8230;ELSE&#8230;END IF&#8217; was moved outside from inner loop, so appeared two branches of execution: with optimized empty inner loop and non-optimized loop with function.<br />

</div></td></tr>
</table>
<div class='easySpoilerConclude' style=''><table class='easySpoilerTable' border='0' style='text-align:center;' frame='box' align='center' bgcolor='FFFFFF'><tr><th class='easySpoilerEnd' style='width:100%;'></th><td class='easySpoilerEnd' style='white-space:nowrap;' colspan='2'></td></tr><tr><td class='easySpoilerGroupWrapperLastRow' colspan='2' style=''></td></tr></table></div>
</div>

<p><em><strong>Instead of conclusion:</strong></em><br />
I&#8217;m absolutly agree with what Steven Feuerstein <a href="http://plsql-challenge.blogspot.ru/2011/11/nuances-of-deterministic-functions-in.html">said</a>: </p>
<blockquote><p>&#8220;So at this point, it looks that the applicability of this new optimization will be fairly narrow.&#8221;</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://orasql.org/2013/03/13/optimization-of-loops-in-plsql-part-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic
Page Caching using disk: enhanced
Object Caching 927/1160 objects using disk: basic

 Served from: orasql.org @ 2013-05-23 16:23:52 by W3 Total Cache -->