I didn't find much data about the internals of PL/Scope.
I'd like to use it to analyze identifiers in PL/SQL scripts. Does it work only on Oracle 11g instances? Can I reference its dlls to use it on a machine with only ORACLE 9/10 installed?
In a related manner, do I have to execute the script in order for its identifiers to be analyzed?
To answer the easy question first, we do not have to execute the program unit. We have to compile it. That is relatively simple:
SQL> alter session set plscope_settings='IDENTIFIERS:ALL'
2 /
Session altered.
SQL> alter function str_to_number_tokens compile
2 /
Function altered.
SQL> SELECT LPAD(' ', level*2, ' ') || name AS name, type, usage, usage_id, line, col
2 FROM user_identifiers
3 START WITH usage_context_id = 0
4 CONNECT BY PRIOR usage_id = usage_context_id;
NAME TYPE USAGE USAGE_ID LINE COL
------------------------------ ------------------ ----------- ---------- ---------- ----------
STR_TO_NUMBER_TOKENS FUNCTION DECLARATION 1 1 10
STR_TO_NUMBER_TOKENS FUNCTION DEFINITION 2 1 10
P_STRING FORMAL IN DECLARATION 3 2 10
P_SEPARATOR FORMAL IN DECLARATION 4 3 13
P_SEPARATOR FORMAL IN ASSIGNMENT 5 3 13
RETURN_VALUE VARIABLE DECLARATION 6 6 5
REGEX_STR VARIABLE DECLARATION 7 7 5
REGEX_STR VARIABLE ASSIGNMENT 8 10 9
P_SEPARATOR FORMAL IN REFERENCE 9 10 31
REGEX_STR VARIABLE REFERENCE 10 17 46
P_STRING FORMAL IN REFERENCE 11 17 36
REGEX_STR VARIABLE REFERENCE 12 16 47
P_STRING FORMAL IN REFERENCE 13 16 37
REGEX_STR VARIABLE REFERENCE 14 12 57
P_STRING FORMAL IN REFERENCE 15 12 47
RETURN_VALUE VARIABLE ASSIGNMENT 16 14 22
RETURN_VALUE VARIABLE REFERENCE 17 19 16
17 rows selected.
SQL>
(Credit where credit is due, I took that query from my mate Tim Hall's Oracle-Base site)
Incidentally, note that PL/Scope operates on named PL/SQL programs (procedures, functions, packages, etc). It doesn't work on anonymous PL/SQL blocks. I mention this because you talk of "scripts" rather than programs. It won't do anything with a SQL script containing some PL/SQL blocks.
The other thing to bear in mind is that PL/Scope populates tables on the SYSAUX tablespace, and can chew up a lot of storage. That's why it isn't run by default, and it's why we should use it judiciously.
As for backwards compatibility: it is a new feature in 11g, and it is a compiler feature at that. So I doubt whether it is something you could just crowbar into a 10g install.
Won't work on 10g, but you can copy the code to a scratch environment for analysis
You could get an OTN edition of 11g and copy the code in there just for the analysis.
If you think it would get classed as production use, you can get Personal Edition on Windows for a few hundred dollars
Related
I have a list of 20 records mapping year to a number from 2001 to 2021. For a couple of reasons these can not be loaded into a table, and I do not have permissions to create temporary tables. This lookup means I can't just run a single query in oracle - I have to export and join with a script. Is there a way I could just do a lookup in memory? I could do a CASE WHEN statement to handle each of the 20 cases. But is there some other smoother way to check values against a list in Oracle when you can't write to a table in between?
If I understood you correctly, a CTE might help:
SQL> with years as
2 (select 2000 + level as year
3 from dual
4 connect by level <= 21
5 )
6 select year
7 from years
8 /
YEAR
----------
2001
2002
2003
2004
<snip>
2020
2021
21 rows selected.
SQL>
You'd now join years with other tables, e.g.
with years as
...
select y.year, e.hiredate
from years y join employees e on e.year = y.year
where ...
In Oracle Applications 12c release 1 there is a new column that forms part of many primary keys called zd_edition_name. This relates to editions that you can have for keeping the database up during changes. So you would have two editions, you can make changes to the non-live on and then just live swap over when you are done (my limited understanding - I am not a dba).
My questions is how can I get the value of zd_edition_name, since this is now part of the primary key and also because tables like fnd_descr_flex_col_usage_tl would bring back two rows instead of one if you don't pass the value of zd_edition_name.
Also what does the zd stand for?
EBS and Edition Base Redefinition and Online Patching
The column, zd_edition_name, is just a component of the edition based redefinition feature of an Oracle 11G 2 (or greater) database as you have indicated.
Oracle Applications does not leverage this edition based redefinition database feature until 12.2 EBS.
The apps owned synonym will display the run time value, SET1 or SET2. It will be one value. For EBS 12.1, I would expect the run time value to be SET1.
APPS#db> select
2 zd_edition_name
3 from
4 fnd_descr_flex_col_usage_tl
5 group by zd_edition_name;
ZD_EDITION_NAME
SET1
With the editionable view and the table, we do not have that restriction:
APPS#db>SELECT
2 zd_edition_name
3 FROM
4 applsys.fnd_descr_flex_col_usage_tl
5 GROUP BY
6 zd_edition_name;
ZD_EDITION_NAME
SET2
SET1
In EBS 12.2, one could identify the active file system which should have a correspondence with SET1/SET2 through logging in to the Oracle Apps server(s) and echoing the environment variables:
$FILE_EDITION = patch
$RUN_BASE = /u01/R122_EBS/fs1
$PATCH_BASE = /u01/R122_EBS/fs2
By querying the apps owned synonym, this is unnecessary to know the value of ZD_EDITION_NAME (it is a value associated with the run edition which will be the value).
You can view the editionable objects associated with table with a query like this:
APPS#db>VAR b_object_name varchar2(30);
APPS#db>EXEC :b_object_name:= 'FND_DESCR_FLEX_COL_USAGE_TL';
PL/SQL procedure successfully completed.
APPS#db>SELECT
2 ao.owner,
3 ao.object_name,
4 ao.object_type
5 FROM
6 all_objects ao
7 WHERE
8 1 = 1
9 AND owner IN (
10 'APPS',
11 'APPLSYS'
12 )
13 AND ao.object_name IN (
14 :b_object_name,
15 substr(:b_object_name,1,29)
16 || '#'
17 );
OWNER OBJECT_NAME OBJECT_TYPE
APPLSYS FND_DESCR_FLEX_COL_USAGE_TL TABLE
APPLSYS FND_DESCR_FLEX_COL_USAGE_TL# VIEW
APPS FND_DESCR_FLEX_COL_USAGE_TL SYNONYM
Here are list of versions existing in an EBS instance:
APPS#db>SELECT
2 level,
3 de.edition_name,
4 de.parent_edition_name
5 FROM
6 dba_editions de
7 START WITH
8 de.edition_name = 'ORA$BASE'
9 CONNECT BY
10 PRIOR de.edition_name = de.parent_edition_name
11 ORDER BY
12 de.edition_name;
LEVEL EDITION_NAME PARENT_EDITION_NAME
1 ORA$BASE
2 V_20160703_2120 ORA$BASE
3 V_20160708_1723 V_20160703_2120
...
29 V_20180117_1118 V_20171206_1115
30 V_20180130_0107 V_20180117_1118
For an 12.1 EBS environment, I would expect the starting edition, ORA$BASE, to be the only edition.
I've got lots of code inside anonymous blocks and I am worried that the PL/SQL optimizer doesn't optimize that code. Should I move my code from anonymous blocks into packages to make sure the optimizer does all the heavy lifting for me?
The answer to your title question is: Yes. The optimizer optimizes anonymous blocks as well as stored program units. See script at end of answer to verify this statement.
The answer to your second question is: Yes, you should move your code out of anonymous blocks and into packages.
The reason for the second yes has nothing to do with performance, though. It has to do with the challenges of managing a large volume of code. It's much harder to manage code in blocks (script files) than in packages. Plus, when you store the code in a named program unit, you can take fuller advantage of all that Oracle Database does for you regarding code, including dependency management, program invalidation and automatic recompilation, code analysis with PL/Scope.
Now to see that the optimizer really does do its magic on anonymous blocks, consider the following sequence of statements, executed in 12.2.
First, I will set timing on and set the optimization level to the maximum possible (level 2 is the default and does the bulk of the optimizations; level 3 adds subprogram inlining and is recommended by the PL/SQL dev team).
SET TIMING ON
ALTER SESSION SET plsql_optimize_level = 3
/
In this first block, I use a cursor FOR loop to iterate through a whole bunch of rows. The optimizer should automatically compile this into the equivalent of a BULK COLLECT statement (fetching by default 100 rows at a time).
SQL> DECLARE
2 n INT;
3 BEGIN
4 FOR rec IN (SELECT * FROM all_objects)
5 LOOP
6 n := n + 1;
7 END LOOP;
8
9 DBMS_OUTPUT.put_line (n);
10 END;
11 /
Elapsed: 00:00:01.943
So just under 2 seconds. Was it optimized? Let's check via a comparison.
In this second block, I no longer use a cursor FOR loop. Instead I declare a cursor explicitly and then iterate through the rows one at a time. By taking this approach, the optimizer can no longer safely convert this code to bulk fetching and so it is much slower.
SQL> DECLARE
2 n INT;
3
4 CURSOR obj_cur
5 IS
6 SELECT * FROM all_objects;
7
8 r obj_cur%ROWTYPE;
9 BEGIN
10 OPEN obj_cur;
11
12 LOOP
13 FETCH obj_cur INTO r;
14 EXIT WHEN obj_cur%NOTFOUND;
15 n := n + 1;
16 END LOOP;
17
18 CLOSE obj_cur;
19
20 DBMS_OUTPUT.put_line (n);
21 END;
22 /
Elapsed: 00:00:04.648
Lots slower than the first block. Conclusion: anonymous blocks are optimized. And just to drive that point home, let's compare the first block's performance with that of a stored procedure:
SQL> CREATE OR REPLACE PROCEDURE count_objects
2 IS
3 n INT;
4 BEGIN
5 FOR rec IN (SELECT * FROM all_objects)
6 LOOP
7 n := n + 1;
8 END LOOP;
9
10 DBMS_OUTPUT.put_line (n);
11 END;
12 /
SQL> BEGIN
2 count_objects;
3 END;
4 /
Elapsed: 00:00:01.875
Roughly the same. So there you have it: anonymous blocks are optimized just like stored program units. Enjoy!
I'm using Oracle 11.2.0.1.0 and am trying to get the dbms_sql package to work.
However, I keep getting the ORA-29471 error, as shown below:
DECLARE
c INTEGER;
BEGIN
c := dbms_sql.open_cursor();
END;
ORA-29471: DBMS_SQL access denied
ORA-06512: at "SYS.DBMS_SQL", line 1017
ORA-06512: at line 4
The oracle docs say the following about this:
Checks are made when binding and executing. Optionally, checks may be
performed for every single DBMS_SQL subprogram call. The check is:
The current_user is the same on calling the subprogram as it was on calling the most recent parse.
The enabled roles on calling the subprogram must be a superset of the enabled roles on calling the most recent parse.
Consistent with the use of definer's rights subprograms, roles do not
apply. If either check fails, and ORA-29470 error is raised.
As far as I can tell, both conditions don't apply to my code, because the code does not cross schemas.
The Oracle support (requires login) website proposes that I explicitly add the security_level parameter into dbms_sql.open_cursor. Adding any of the values (0/1/2) doesn't solve the issue.
The puzzling thing for me is that I get the error at the dbms_sql.open_cursor, which is where the security level is first defined.
The support website also proposes a workaround that involves setting:
alter system set "_dbms_sql_security_level" = 384 scope=spfile;
I haven't tried that yet. I prefer to think of it as a last resort, because it involves disabling a security layer and it is an unsupported oracle feature. Hardly ideal circumstances for production use. Also, it doesn't really solve the issue at all, just hides it.
How can I solve this error?
The only reason(cannot see another one at this moment) why your code raises the ORA-29471 is you already made dbms_sql inoperable in your session by providing an invalid cursor ID:
/* dbsm_sql detects invalid cursor ID in this session */
SQL> declare
2 c_1 number := 5; -- invalid cursor ID. There is no cursor
3 l_res boolean; -- opened with ID = 5
4 begin
5 l_res := dbms_sql.is_open(c_1);
6 end;
7 /
declare
*
ERROR at line 1:
ORA-29471: DBMS_SQL access denied
ORA-06512: at "SYS.DBMS_SQL", line 1104
ORA-06512: at line 5
/* An attempt to execute this simple anonymous PL/SQL block after
an invalid cursor ID has already been detected by the dbms_sql
in the current session will lead to ORA-29471 error
*/
SQL> declare
2 c_2 number;
3 begin
4 c_2 := dbms_sql.open_cursor();
5 end;
6 /
declare
*
ERROR at line 1:
ORA-29471: DBMS_SQL access denied
ORA-06512: at "SYS.DBMS_SQL", line 1084
ORA-06512: at line 4
Try to execute that code in a newly established session.
A solution could be to have a look into the v$Session view.
If the cursor exists in the list, then it means you can still us it. Then identify it from its sql_id, and you can check. Here you generate the list:
select sql_id, sql_text, count(*) as "OPEN CURSORS", user_name
from v$open_cursor
where user_name <>'SYS'
group by sql_text, user_name
order by count(*) desc;
More here.
I was wondering if there is any analysis on the usage of different data types used in databases? I mean, an analysis that ranks the usage of different data-types, for instance:
Most used
DECIMAL
DATE
....etc in databases (mainly Oracle) ?
If it also includes the types of operations that normally run on this data it would be awesome.
Might not be entirely what you are looking for, but its a starter-
SQL> select data_type, round(avg(data_length),4) avg_length,round(avg(density),4)
avg_density
from user_tab_cols
group by data_type;
DATA_TYPE AVG_LENGTH AVG_DENSITY
------------ ------------- -------------
DATE 7 0.3369
TIMESTAMP(6) 11 1
RAW 32 1
NUMBER 22 0.2429
CHAR 1.0776 0.254
VARCHAR2 34.9129 0.3941
TIMESTAMP(3) 11 0.2408