Oracle_scripte/Alberto/xplan_print_plan.sql
2014-09-17 13:25:02 +02:00

605 lines
26 KiB
SQL

--------------------------------------------------------------------------------
-- Author: Alberto Dell'Era
-- Copyright: (c) 2008, 2009, 2010, 2012, 2013 Alberto Dell'Era http://www.adellera.it
--------------------------------------------------------------------------------
procedure extract_tag_value( p_xml clob, p_tag_name varchar2, p_tag_text out varchar2)
is
l_start int;
l_end int;
l_start_marker varchar2(30) := '<' || p_tag_name;
l_end_marker varchar2(30) := '</' || p_tag_name || '>' ;
l_next_chars varchar2(2 char);
begin
l_start := dbms_lob.instr (p_xml, l_start_marker, 1);
if l_start = 0 or l_start is null then
return;
end if;
l_start := l_start + length(l_start_marker);
l_next_chars := dbms_lob.substr (p_xml, 2, l_start);
if l_next_chars is null or l_next_chars = '/>' then
return;
end if;
l_start := l_start + 1;
l_end := dbms_lob.instr (p_xml, l_end_marker, l_start);
if l_end = 0 or l_end is null then
print ('error: end marker not found for tag '||p_tag_name);
return;
end if;
if l_end - l_start > 32767 then
print ('error: tag too long for tag '||p_tag_name);
return;
end if;
p_tag_text := dbms_lob.substr (p_xml, l_end - l_start, l_start);
end extract_tag_value;
function extract_tag(
p_xml varchar2,
p_tag_name varchar2,
p_occurrence int,
p_attributes out varchar2,
p_value out varchar2)
return boolean
is
l_start_section varchar2(30) := '<' || p_tag_name || ' ';
l_end_tag varchar2(30) := '</' || p_tag_name || '>';
l_start int;
l_end_start_tag int;
l_end int;
begin
l_start := instr (p_xml, l_start_section, 1, p_occurrence);
if l_start = 0 or l_start is null then
return false;
end if;
l_start := l_start + length(l_start_section);
l_end_start_tag := instr (p_xml, '>', l_start);
if l_end_start_tag = 0 or l_end_start_tag is null then
print ('xml error: xml misformat for tag ' || p_tag_name);
return false;
end if;
if substr(p_xml, l_end_start_tag-1, 1) = '/' then
-- <pippo x="xx" />
p_attributes := substr (p_xml, l_start, (l_end_start_tag-1) - l_start );
p_value := null;
else
-- <pippo x="xx" >value</pippo>
p_attributes := substr (p_xml, l_start, l_end_start_tag - l_start );
l_end := instr (p_xml, l_end_tag, l_end_start_tag+1);
if l_end = 0 or l_end is null then
print ('xml error: xml misformat 2 for tag ' || p_tag_name);
return false;
end if;
p_value := substr (p_xml, l_end_start_tag+1, l_end - l_end_start_tag - 1);
end if;
return true;
end extract_tag;
function get_attribute( p_attributes_str varchar2, p_name varchar2 )
return varchar2
is
l_pos int; l_start int; l_end int;
begin
l_pos := instr (p_attributes_str, p_name||'="');
if l_pos = 0 then return null; end if;
l_start := instr (p_attributes_str, '"', l_pos);
if l_start = 0 then return '??'; end if;
l_start := l_start + 1;
l_end := instr (p_attributes_str, '"', l_start);
if l_end = 0 then return '???'; end if;
return substr (p_attributes_str, l_start, l_end - l_start);
end get_attribute;
procedure print_peeked_binds(p_other_xml clob)
is
l_peeked_binds_values long;
l_peeked_binds_types long;
l_peeked_str long;
l_bind_num int;
l_nam varchar2(30 char);
l_dty int;
l_frm int;
l_mxl int;
l_value_hex long;
l_value_raw long raw;
l_value long;
l_type varchar2(100);
l_value_varchar2 varchar2(32767);
l_value_nvarchar2 nvarchar2(32767);
l_value_number number;
l_value_date date;
l_value_timestamp timestamp;
&COMM_IF_LT_10G. l_value_binary_float binary_float;
&COMM_IF_LT_10G. l_value_binary_double binary_double;
l_value_rowid rowid;
l_bind_attributes long;
l_bind_found boolean;
begin
if p_other_xml is null then
return;
end if;
extract_tag_value ( p_other_xml, 'peeked_binds', l_peeked_str);
if l_peeked_str is null then
return;
end if;
if 1=0 then
print ('peeked binds : original peeked bind xml section:"'||l_peeked_str||'"');
--return;
end if;
-- format: <bind nam=":X" pos="1" dty="1" csi="873" frm="1" mxl="32">58</bind>
-- or <bind nam=":X" pos="1" dty="1" csi="873" frm="1" mxl="32"/> (for nulls)
-- max is the MaXLength in bytes
l_bind_num := 1;
l_peeked_binds_values := 'peeked binds values:';
l_peeked_binds_types := 'peeked binds types :';
loop
l_bind_found := extract_tag( l_peeked_str, 'bind', l_bind_num, l_bind_attributes, l_value_hex );
--print('peeked binds : attrs=['||l_bind_attributes||'] val=['||l_value_hex||']');
exit when not l_bind_found;
begin
l_value_raw := hextoraw (l_value_hex);
exception
when others then
raise_application_error (-20089, 'l_value_hex="'||l_value_hex||'" '||sqlerrm);
end;
l_nam := get_attribute (l_bind_attributes, 'nam');
l_mxl := to_number (get_attribute (l_bind_attributes, 'mxl'));
l_dty := to_number (get_attribute (l_bind_attributes, 'dty'));
l_frm := trim(get_attribute (l_bind_attributes, 'frm'));
-- For dty codes, see "Call Interface Programmer's Guide", "Datatypes"
-- Also, "select text from dba_views where view_name = 'USER_TAB_COLS'" gives
-- a decode function to interpret them. charsetform is the "frm" in the xml string.
-- Generally frm=2 means NLS charset.
if l_dty = 1 and l_frm = '1' then -- varchar2
dbms_stats.convert_raw_value (l_value_raw, l_value_varchar2);
l_value := ''''||l_value_varchar2||'''';
l_type := 'varchar2('||l_mxl||')';
elsif l_dty = 1 and l_frm = '2' then -- nvarchar2
dbms_stats.convert_raw_value_nvarchar (l_value_raw, l_value_nvarchar2);
l_value := ''''||l_value_nvarchar2||'''';
l_type := 'nvarchar2('||l_mxl||')';
elsif l_dty = 2 then -- number
dbms_stats.convert_raw_value (l_value_raw, l_value_number);
l_value := nvl (to_char(l_value_number), 'null');
l_type := 'number('||l_mxl||')';
elsif l_dty = 12 then -- date
dbms_stats.convert_raw_value (l_value_raw, l_value_date);
l_value := nvl (to_char (l_value_date, 'yyyy/mm/dd hh24:mi:ss'), 'null');
l_type := 'date';
elsif l_dty = 23 then -- raw
l_value := nvl (to_char(l_value_hex), 'null');
l_type := 'raw('||l_mxl||')';
elsif l_dty = 69 then -- rowid (not fully tested)
dbms_stats.convert_raw_value_rowid (l_value_raw, l_value_rowid);
l_value := nvl (rowidtochar (l_value_rowid), 'null');
l_type := 'rowid';
elsif l_dty = 96 and l_frm = '1' then -- char
dbms_stats.convert_raw_value (l_value_raw, l_value_varchar2);
l_value := ''''||l_value_varchar2||'''';
l_type := 'char('||l_mxl||')';
elsif l_dty = 96 and l_frm = '2' then -- nchar
dbms_stats.convert_raw_value_nvarchar (l_value_raw, l_value_nvarchar2);
l_value := ''''||l_value_nvarchar2||'''';
l_type := 'nchar('||l_mxl||')';
&COMM_IF_LT_10G. elsif l_dty = 100 then -- binary_float
&COMM_IF_LT_10G. dbms_stats.convert_raw_value (l_value_raw, l_value_binary_float);
&COMM_IF_LT_10G. l_value := to_char (l_value_binary_float);
&COMM_IF_LT_10G. l_type := 'binary_float';
&COMM_IF_LT_10G. elsif l_dty = 101 then -- binary_double
&COMM_IF_LT_10G. dbms_stats.convert_raw_value (l_value_raw, l_value_binary_double);
&COMM_IF_LT_10G. l_value := to_char (l_value_binary_double);
&COMM_IF_LT_10G. l_type := 'binary_double';
elsif l_dty = 180 then -- timestamp
l_value := '(hex)'||l_value_hex; -- found no way to convert in 10.2
l_type := 'timestamp';
elsif l_dty = 181 then -- timestamp with time zone
l_value := '(hex)'||l_value_hex; -- found no way to convert in 10.2
l_type := 'timestamp with time zone';
elsif l_dty = 182 then -- interval year to month
l_value := '(hex)'||l_value_hex; -- found no way to convert in 10.2
l_type := 'interval year to month';
elsif l_dty = 183 then -- interval day to second
l_value := '(hex)'||l_value_hex; -- found no way to convert in 10.2
l_type := 'interval day to second';
elsif l_dty = 231 then -- timestamp with local time zone
l_value := '(hex)'||l_value_hex; -- found no way to convert in 10.2
l_type := 'timestamp with local time zone';
else
l_value := '(hex)'||l_value_hex;
l_type := '[dty='||l_dty||' frm='||l_frm||' mxl='||l_mxl||']';
end if;
l_peeked_binds_values := l_peeked_binds_values || ' ' || l_nam || ' = ' || l_value|| ',';
l_peeked_binds_types := l_peeked_binds_types || ' ' || l_nam || ' = ' || l_type || ',';
l_bind_num := l_bind_num + 1;
end loop;
l_peeked_binds_values := rtrim (l_peeked_binds_values, ',');
l_peeked_binds_types := rtrim (l_peeked_binds_types , ',');
print (l_peeked_binds_values);
print (l_peeked_binds_types);
end print_peeked_binds;
procedure print_notes(p_other_xml clob)
is
l_xml long;
l_info_num int;
l_info_found boolean;
l_notes long;
l_info_attributes varchar2(200);
l_info_value varchar2(1000);
l_info_type varchar2(200);
begin
if p_other_xml is null then
return;
end if;
if dbms_lob.getlength( p_other_xml) > 32767 then
print('print_notes: warning: cannot look for notes, other_xml too long');
return;
end if;
l_xml := dbms_lob.substr (p_other_xml, 32767, 1);
l_info_num := 1;
loop
l_info_found := extract_tag( l_xml, 'info', l_info_num, l_info_attributes, l_info_value );
--print('print_notes : attrs=['||l_info_attributes||'] val=['||l_info_value||']');
exit when not l_info_found;
l_info_type := get_attribute( l_info_attributes, 'type' );
if l_info_type not in ( 'plan_hash', 'db_version', 'parse_schema', 'plan_hash_2' ) then
l_notes := l_notes || l_info_type || '=' || l_info_value || ' ';
end if;
l_info_num := l_info_num + 1;
end loop;
if l_notes is not null then
print('notes : ' || l_notes );
end if;
end print_notes;
function adapt_projection(p_txt varchar2)
return varchar2
is
l_buf varchar2(4000) := replace( replace(p_txt, '"', ''), ' ', '');
l_open int := 1;
l_clos int;
begin
loop
l_open := instr(l_buf, '[', l_open);
exit when l_open = 0 or l_open is null;
l_clos := instr(l_buf, ']', l_open+1);
exit when l_clos = 0 or l_clos is null;
l_buf := substr(l_buf, 1, l_open-1) || substr(l_buf, l_clos+1);
end loop;
return substr(l_buf, 1, 1000);
end adapt_projection;
function adapt_predicate(p_txt varchar2)
return varchar2
is
l_buf varchar2(4000) := replace(p_txt, '"', '');
begin
return l_buf;
end adapt_predicate;
procedure print_plan (
p_inst_id sys.gv_$sql.inst_id%type,
p_address sys.gv_$sql.address%type,
p_hash_value sys.gv_$sql.hash_value%type,
p_child_number sys.gv_$sql.child_number%type,
p_executions int,
p_first_load_time date,
p_last_load_time date,
p_last_active_time date default null, -- null if not 10gR2+
p_sql_plan_baseline varchar2 default null -- null if not 11g+
)
is
type access_predicates_t is table of sys.gv_$sql_plan.access_predicates%type index by binary_integer;
type filter_predicates_t is table of sys.gv_$sql_plan.filter_predicates%type index by binary_integer;
type others_t is table of sys.gv_$sql_plan.other %type index by binary_integer;
type base_table_object_ids_t is table of varchar2(1) index by varchar2(30);
l_access_predicates access_predicates_t;
l_filter_predicates filter_predicates_t;
l_others others_t;
l_base_table_object_ids base_table_object_ids_t;
l_base_object_id_char varchar2(30);
l_plan scf_state_t;
l_plan2 scf_state_t;
l_plan3 scf_state_t;
l_col_tag varchar2(10 char);
l_execs int;
l_other_tag sys.gv_$sql_plan.other_tag%type;
l_id_min int := 1e6;
l_id_max int := -1;
l_id_string varchar2(10 char);
l_tmp varchar2(1000 char);
&COMM_IF_LT_10G. l_sql_id sys.gv_$sql.sql_id%type;
l_cursor sys_refcursor;
l_dbms_xplan_tag varchar2(10 char);
l_dbms_xplan_format varchar2(50 char);
begin
if '&PLAN_LAST_OR_NULL.' = 'LAST_' then
l_col_tag := 'last';
l_execs := 1;
l_dbms_xplan_tag := ' LAST';
elsif '&PLAN_AVG_PER_EXEC.' = 'Y' then
l_col_tag := '/exec';
l_execs := p_executions;
else
l_col_tag := 'raw';
l_execs := 1; -- a trick, of course
end if;
if l_execs <= 0 then
l_execs := null;
end if;
for s in (select /*+ xplan_exec_marker */ -- 10.2.0.3 columns
-- p.address,
-- p.hash_value,
&COMM_IF_LT_10G. p.sql_id,
&COMM_IF_LT_10G. p.plan_hash_value,
&COMM_IF_LT_10GR2. p.child_address,
p.child_number,
-- p.timestamp,
p.operation,
p.options,
p.object_node,
p.object#,
p.object_owner,
p.object_name,
&COMM_IF_LT_10G. p.object_alias,
&COMM_IF_LT_10G. p.object_type,
p.optimizer,
p.id,
p.parent_id,
p.depth,
p.position,
p.search_columns,
p.cost,
p.cardinality,
p.bytes,
p.other_tag,
p.partition_start,
p.partition_stop,
p.partition_id,
p.other,
p.distribution,
p.cpu_cost,
p.io_cost,
p.temp_space,
&COMM_IF_NO_PREDS. p.access_predicates,
&COMM_IF_NO_PREDS. p.filter_predicates,
&COMM_IF_LT_10G. p.projection,
--time
&COMM_IF_LT_10G. p.qblock_name,
&COMM_IF_LT_10G. p.remarks,
&COMM_IF_LT_10GR2. p.other_xml,
s.executions,
s.&PLAN_LAST_OR_NULL.starts as starts,
s.&PLAN_LAST_OR_NULL.output_rows as output_rows,
s.&PLAN_LAST_OR_NULL.cr_buffer_gets as cr_buffer_gets,
s.&PLAN_LAST_OR_NULL.cu_buffer_gets as cu_buffer_gets,
s.&PLAN_LAST_OR_NULL.disk_reads as disk_reads,
s.&PLAN_LAST_OR_NULL.disk_writes as disk_writes,
s.&PLAN_LAST_OR_NULL.elapsed_time as elapsed_time,
s.policy,
s.estimated_optimal_size,
s.estimated_onepass_size,
s.last_memory_used,
s.last_execution,
s.last_degree,
s.total_executions,
s.optimal_executions,
s.onepass_executions,
s.multipasses_executions,
s.active_time,
s.max_tempseg_size,
s.last_tempseg_size
from sys.gv_$sql_plan p, sys.gv_$sql_plan_statistics_all s
where p.inst_id = p_inst_id
and s.inst_id(+) = p_inst_id
and p.address = p_address
and p.hash_value = p_hash_value
and p.child_number = p_child_number
and s.address(+) = p_address
and s.hash_value(+) = p_hash_value
and s.child_number(+) = p_child_number
and p.id = s.id(+)
order by p.id)
loop
if s.id < l_id_min then l_id_min := s.id; end if;
if s.id > l_id_max then l_id_max := s.id; end if;
&COMM_IF_LT_10G. l_sql_id := s.sql_id;
&COMM_IF_LT_10G. if s.id = 1 then
&COMM_IF_LT_10GR2. print_peeked_binds (s.other_xml);
&COMM_IF_LT_10GR2. print_notes (s.other_xml);
&COMM_IF_LT_10G. if p_sql_plan_baseline is not null then print('sql plan baseline : '||p_sql_plan_baseline); end if;
&COMM_IF_LT_10G. end if;
l_base_object_id_char := to_char(get_cache_base_table_object_id (s.object#));
if l_base_object_id_char is not null then
l_base_table_object_ids (l_base_object_id_char) := 'X';
if :OPT_TABINFOS = 'BOTTOM' then
m_all_referenced_object_ids(l_base_object_id_char) := 'X';
end if;
end if;
scf_add_elem (l_plan, 'CR+CU', (s.cr_buffer_gets + s.cu_buffer_gets) / l_execs, p_sep_mid => l_col_tag);
&COMM_IF_NO_SELF scf_add_self (l_plan, 'CR+CU+', p_self_src => 'CR+CU');
scf_add_elem (l_plan, 'Ela', s.elapsed_time / l_execs, p_sep_mid => l_col_tag, p_sep_bot=>'usec');
&COMM_IF_NO_SELF scf_add_self (l_plan, 'Ela+', p_self_src => 'Ela');
scf_add_elem (l_plan, 'Starts', s.starts / l_execs, p_sep_mid => l_col_tag);
scf_add_elem (l_plan, 'Id' , s.id , p_is_auxil => 'Y', p_self_is_id => 'Y');
scf_add_elem (l_plan, 'pId', s.parent_id, p_is_auxil => 'Y', p_self_is_pid => 'Y', p_is_hidden => 'Y');
/* scf_add_elem (l_plan, 'pId', s.parent_id); -- TEMP!!
scf_add_elem (l_plan, 'remarks', s.remarks); -- TEMP!!
scf_add_elem (l_plan, 'depth', s.depth); -- TEMP!!
scf_add_elem (l_plan, 'position', s.position); -- TEMP!!
scf_add_elem (l_plan, 'qblock', s.qblock_name); -- TEMP!!
scf_add_elem (l_plan, 'optim', s.optimizer); -- TEMP!!
scf_add_elem (l_plan, 'object#', s.object#); -- TEMP!!*/
scf_add_elem (l_plan, 'Operation', lpad (' ', s.depth) || s.operation||' '||s.options );
scf_add_elem (l_plan, 'Name', s.object_name);
scf_add_elem (l_plan, 'Table', get_cache_obj_name (get_cache_base_table_object_id (s.object#)));
scf_add_elem (l_plan, 'TQ', s.object_node);
scf_add_elem (l_plan, 'Erows', s.cardinality);
scf_add_elem (l_plan, 'Arows', s.output_rows / l_execs, p_sep_mid => l_col_tag);
scf_add_elem (l_plan, 'Cost', s.cost);
scf_add_elem (l_plan, 'IoCost', s.io_cost);
scf_add_elem (l_plan, 'Psta', replace (s.partition_start, 'ROW LOCATION', 'ROWID') );
scf_add_elem (l_plan, 'Psto', replace (s.partition_stop , 'ROW LOCATION', 'ROWID') );
scf_add_elem (l_plan, 'IdP', s.partition_id);
l_other_tag := s.other_tag;
l_other_tag := replace (l_other_tag, 'SERIAL_FROM_REMOTE' , 'S->R');
l_other_tag := replace (l_other_tag, 'PARALLEL_FROM_SERIAL' , 'S->P');
l_other_tag := replace (l_other_tag, 'PARALLEL_TO_SERIAL' , 'P->S');
l_other_tag := replace (l_other_tag, 'PARALLEL_TO_PARALLEL' , 'P->P');
l_other_tag := replace (l_other_tag, 'PARALLEL_COMBINED_WITH_PARENT', 'PCWP');
l_other_tag := replace (l_other_tag, 'PARALLEL_COMBINED_WITH_CHILD' , 'PCWC');
scf_add_elem (l_plan, 'OT', l_other_tag);
scf_add_elem (l_plan, 'Distr', replace (replace (s.distribution, ' (RANDOM)', '(RAND)'),' (ORDER)', '(ORDER)'));
--scf_add_elem (l_plan, 'obj alias', s.object_alias);
--scf_add_elem (l_plan, 'qb_name', s.qblock_name);
&COMM_IF_NO_PREDS. if s.access_predicates is not null then l_access_predicates(s.id) := adapt_predicate(s.access_predicates); end if;
&COMM_IF_NO_PREDS. if s.filter_predicates is not null then l_filter_predicates(s.id) := adapt_predicate(s.filter_predicates); end if;
if s.other is not null then l_others(s.id) := s.other; end if;
scf_add_elem (l_plan2, 'Id' , s.id , p_is_auxil => 'Y', p_self_is_id => 'Y');
scf_add_elem (l_plan2, 'pId', s.parent_id, p_is_auxil => 'Y', p_self_is_pid => 'Y', p_is_hidden => 'Y');
scf_add_elem (l_plan2, 'Starts', s.starts / l_execs, p_sep_mid => l_col_tag);
scf_add_elem (l_plan2, 'CR', s.cr_buffer_gets / l_execs, p_sep_mid => l_col_tag);
&COMM_IF_NO_SELF scf_add_self (l_plan2, 'CR+', p_self_src => 'CR');
scf_add_elem (l_plan2, 'CU', s.cu_buffer_gets / l_execs, p_sep_mid => l_col_tag);
&COMM_IF_NO_SELF scf_add_self (l_plan2, 'CU+', p_self_src => 'CU');
scf_add_elem (l_plan2, 'diskR', s.disk_reads / l_execs, p_sep_mid => l_col_tag);
&COMM_IF_NO_SELF scf_add_self (l_plan2, 'diskR+', p_self_src => 'diskR');
scf_add_elem (l_plan2, 'diskW', s.disk_writes / l_execs, p_sep_mid => l_col_tag);
&COMM_IF_NO_SELF scf_add_self (l_plan2, 'diskW+', p_self_src => 'diskW');
scf_add_elem (l_plan2, 'E0ram', s.estimated_optimal_size, p_sep_bot=>'KB');
scf_add_elem (l_plan2, 'E1ram', s.estimated_optimal_size, p_sep_bot=>'KB');
scf_add_elem (l_plan2, 'Aram', s.last_memory_used, p_sep_mid => 'last', p_sep_bot=>'KB');
scf_add_elem (l_plan2, 'Policy', s.policy);
scf_add_elem (l_plan2, 'A01M', s.last_execution, p_sep_mid => 'last');
l_tmp := null;
if s.optimal_executions > 0 or s.onepass_executions > 0 or s.multipasses_executions > 0 then
l_tmp := s.optimal_executions||'/'||s.onepass_executions||'/'||s.multipasses_executions;
end if;
scf_add_elem (l_plan2, '0/1/M', l_tmp, p_sep_bot=>'#');
scf_add_elem (l_plan2, 'ActTim', s.active_time*10, p_sep_mid => 'avg', p_sep_bot=>'msec');
scf_add_elem (l_plan2, 'ETmpSpc', s.temp_space/1024, p_sep_bot=>'KB');
scf_add_elem (l_plan2, 'ATmpSpcM', s. max_tempseg_size/1024, p_sep_mid => 'max' , p_sep_bot=>'KB');
scf_add_elem (l_plan2, 'ATmpSpcL', s.last_tempseg_size/1024, p_sep_mid => 'last', p_sep_bot=>'KB');
&COMM_IF_LT_10G. if :OPT_PLAN_DETAILS = 'Y' then
&COMM_IF_LT_10G. scf_add_elem (l_plan3, 'Id', s.id, p_is_auxil => 'Y');
&COMM_IF_LT_10G. scf_add_elem (l_plan3, 'Qb_name', s.qblock_name);
&COMM_IF_LT_10G. scf_add_elem (l_plan3, 'ObjAlias', s.object_alias);
&COMM_IF_LT_10G. scf_add_elem (l_plan3, 'ObjType', s.object_type);
&COMM_IF_LT_10G. scf_add_elem (l_plan3, 'Obj', get_cache_obj_name(s.object#));
&COMM_IF_LT_10G. scf_add_elem (l_plan3, 'BaseObj', get_cache_obj_name(get_cache_base_table_object_id (s.object#)));
--&COMM_IF_LT_10G. scf_add_elem (l_plan3, 'Obj#', s.object#);
--&COMM_IF_LT_10G. scf_add_elem (l_plan3, 'BaseObj#', get_cache_base_table_object_id (s.object#));
&COMM_IF_LT_10G. scf_add_elem (l_plan3, 'Projection', adapt_projection(s.projection));
&COMM_IF_LT_10G. scf_add_elem (l_plan3, 'Remarks', s.remarks);
&COMM_IF_LT_10G. end if;
end loop;
scf_print_output (l_plan, 'no plan found.', 'only aux plan infos found.');
-- filter and access predicates
for id in l_id_min .. l_id_max loop
l_id_string := '.'|| to_char (id, '990');
if l_access_predicates.exists(id) then
print (l_id_string||' - access[ '||l_access_predicates(id)||' ]');
l_id_string := rpad ('.', length (l_id_string));
end if;
if l_filter_predicates.exists(id) then
print (l_id_string||' - filter[ '||l_filter_predicates(id)||' ]');
l_id_string := rpad ('.', length (l_id_string));
end if;
end loop;
-- VPD policies
for po in ( select object_owner, object_name, predicate, policy_function_owner, policy
from sys.gv_$vpd_policy
where inst_id = p_inst_id
and sql_hash = p_hash_value
&COMM_IF_LT_10G. and sql_id = l_sql_id
and child_number = p_child_number
order by object_owner, object_name)
loop
print('. --- - VPD POLICY on '||po.object_owner||'.'||po.object_name||' : ['||po.predicate||'] applied by function '||po.policy_function_owner||'.'||po.policy);
end loop;
-- PX Slave SQL
if l_others.count > 0 then
print ('---- PX Slave SQL:');
for id in l_id_min .. l_id_max loop
l_id_string := '.'|| to_char (id, '990');
if l_others.exists(id) then
print (l_id_string||' - ['||l_others(id)||']');
l_id_string := rpad ('.', length (l_id_string));
end if;
end loop;
end if;
&COMM_IF_LT_10G. ash_print_stmt_profile (
&COMM_IF_LT_10G. p_inst_id => p_inst_id , p_sql_id => l_sql_id,
&COMM_IF_LT_10G. p_child_number => p_child_number ,
&COMM_IF_LT_10G. p_first_load_time => p_first_load_time, p_last_load_time => p_last_load_time, p_last_active_time => p_last_active_time);
scf_print_output (l_plan2, 'no plan details found.', 'only aux plan details found.',
p_note => 'note: stats Aram, A01M, 0/1/M, ActTim do not seem to be always accurate.' );
scf_print_output (l_plan3, '', '');
-- output from dbms_xplan.display_cursor
&COMM_IF_NO_DBMS_XPLAN. if l_sql_id is not null then
&COMM_IF_NO_DBMS_XPLAN. l_dbms_xplan_format := 'ADVANCED'||l_dbms_xplan_tag;
&COMM_IF_NO_DBMS_XPLAN. print ('===== dbms_xplan.display_cursor ('||l_dbms_xplan_format||'):');
&COMM_IF_NO_DBMS_XPLAN. open l_cursor for
&COMM_IF_NO_DBMS_XPLAN. select /*+ xplan_exec_marker */ plan_table_output
&COMM_IF_NO_DBMS_XPLAN. from table (dbms_xplan.display_cursor (l_sql_id, p_child_number, l_dbms_xplan_format));
&COMM_IF_NO_DBMS_XPLAN. loop
&COMM_IF_NO_DBMS_XPLAN. fetch l_cursor into l_tmp;
&COMM_IF_NO_DBMS_XPLAN. if l_cursor%notfound then
&COMM_IF_NO_DBMS_XPLAN. close l_cursor;
&COMM_IF_NO_DBMS_XPLAN. exit;
&COMM_IF_NO_DBMS_XPLAN. end if;
&COMM_IF_NO_DBMS_XPLAN. print (l_tmp);
&COMM_IF_NO_DBMS_XPLAN. end loop;
&COMM_IF_NO_DBMS_XPLAN. end if;
-- print sql-level optimizer env
optim_env_print_sql_pars (p_address => p_address, p_hash_value => p_hash_value, p_child_number => p_child_number);
-- table infos from data dictionary
if :OPT_TABINFOS = 'Y' then
declare
l_curr_id varchar2(20);
begin
l_curr_id := l_base_table_object_ids.first;
loop
exit when l_curr_id is null;
print_cache_table_infos (l_curr_id);
l_curr_id := l_base_table_object_ids.next (l_curr_id);
end loop;
end;
end if;
end print_plan;