We all know that Oracle has limit of 30 bytes for object names table names columns and bla-bla, I have been searching the net for hours for a solution but I couldn't find anything and eventually I gave up.
We are developing an application that uses both MySQL and Oracle, everything was working fine until we starting implementing Oracle, we encountered problems regarding to the table and stored procedures names.
I can't change the names of the tables because the application is already running on client servers.
Any solution? Maybe some property to tell oracle to make the limit larger than 30.
SQL Translator Profiles in Oracle 12c may help the application pretend that Oracle supports object names of a decent length. This could allow you to change the database without modifying the application.
Below is a trivial example of translating a greater-than-30-byte name into a short name:
SQL> create table short_table_name(a varchar2(100));
Table created.
SQL> insert into short_table_name values ('Success');
1 row created.
SQL> begin
2 dbms_sql_translator.create_profile('LONG_OBJECT_NAMES');
3 dbms_sql_translator.register_sql_translation(
4 profile_name => 'LONG_OBJECT_NAMES',
5 sql_text => 'select * from because_30_bytes_just_isnt_enough_sometimes',
6 translated_text => 'select * from short_table_name');
7 end;
8 /
PL/SQL procedure successfully completed.
SQL> alter session set sql_translation_profile = LONG_OBJECT_NAMES;
Session altered.
SQL> alter session set events = '10601 trace name context forever, level 32';
Session altered.
SQL> select * from because_30_bytes_just_isnt_enough_sometimes;
A
----------------------------------------------------------------------------------------------------
Success
This may work but I can think of a dozen reasons why it is a bad idea. Only consider this as a last resort.
Related
Is it possible to add a metadata field at column-level (in the Oracle Data Dictionary)?
The purpose would be to hold a flag identifying where individual data items in a table have been anonymised.
I'm an analyst (not a DBA) and I'm using Oracle SQL Developer which surfaces (and enables querying of) the COLUMN_NAME, DATA_TYPE, NULLABLE, DATA_DEFAULT, COLUMN_ID, and COMMENTS metadata fields of our Oracle DB (see pic).
I'd be looking to add another metadata field at this level (essentially, to add a second 'COMMENTS' field) to hold the 'Anonymisation' flag, to support easy querying of our flagged-anonymised data.
If it's possible (and advisable / supportable), I'd be grateful for any advice for describing the steps required to enable this, which I can then discuss with our Developer and DBA.
Short answer: NO.
But where could you keep that information?
In your data model.
Oracle provides a free data modeling solution, Oracle SQL Developer Data Modeler. It provides the ability to mark table/view columns as sensitive or PII.
Those same models can be stored back in your database so they can be accessed via SQL.
Once you've marked up all of your sensitive attributes/columns, and store it back into the database, you can query it back out.
Disclaimer: I work for Oracle, I'm the product manager for Data Modeler.
[TL;DR] Don't do it. Find another way.
If it's advisable
NO
Never modify the data dictionary; (unless Oracle support tells you to) you are likely to invalidate your support contract with Oracle and may break the database and make it unusable.
If it's possible
Don't do this.
If you really want to try it then still don't.
If you really, really want to try it then find a database you don't care about (the don't care about bit is important!) and log on as a SYSDBA user and:
ALTER TABLE whichever_data_dictionary_table ADD anonymisation_flag VARCHAR2(10);
Then you can test whether the database breaks (and it may not break immediately but at some point later), but if it does then you almost certainly will not get any support from Oracle in fixing it.
Did we say, "Don't do it"... we mean it.
As you already know, you shouldn't do that.
But, nothing prevents you from creating your own table which will contain such an info.
For example:
SQL> CREATE TABLE my_comments
2 (
3 table_name VARCHAR2 (30),
4 column_name VARCHAR2 (30),
5 anonymisation VARCHAR2 (10)
6 );
Table created.
Populate it with some data:
SQL> insert into my_comments (table_name, column_name)
2 select table_name, column_name
3 from user_tab_columns
4 where table_name = 'DEPT';
3 rows created.
Set the anonymisation flag:
SQL> update my_comments set anonymisation = 'F' where column_name = 'DEPTNO';
1 row updated.
When you want to get such an info (along with some more data from user_tab_columns, use (outer) join:
SQL> select u.table_name, u.column_name, u.data_type, u.nullable, m.anonymisation
2 from user_tab_columns u left join my_comments m on m.table_name = u.table_name
3 and m.column_name = u.column_name
4 where u.column_name = 'DEPTNO';
TABLE_NAME COLUMN_NAME DATA_TYPE N ANONYMISATION
---------- --------------- ------------ - ---------------
DEPT DEPTNO NUMBER N F
DSV DEPTNO NUMBER N
DSMV DEPTNO NUMBER Y
EMP DEPTNO NUMBER Y
SQL>
Advantages: you won't break the database & you'll have your additional info.
Drawbacks: you'll have to maintain the table manually.
PostgreSQL supports a RETURNING clause, for instance as in
UPDATE some_table SET x = 'whatever' WHERE conditions RETURNING x, y, z
and MSSQL supports a variant of that syntax with the OUTPUT clause.
However Oracle "RETURNING INTO" seems intended to placing values in variables, from within the context of a stored procedure.
Is there a way to have an SQL equivalent to the one above that would work in Oracle, without involving a stored procedure ?
Note: I am looking for a pure-SQL solution if there exists one, not one that is language-specific, or would require special handling in the code. The actual SQL is dynamic, the code that makes the call is database-agnostic, with only the SQL being adapted.
Oracle does not directly support using the DML returning clause in a SELECT statement, but you can kind of fake that behavior by using a WITH function. Although the below code uses PL/SQL, the statement is still a pure SQL statement and can run anywhere a regular SELECT statement can run.
SQL> create table some_table(x varchar2(100), y number);
Table created.
SQL> insert into some_table values('something', 1);
1 row created.
SQL> commit;
Commit complete.
SQL> with function update_and_return return number is
2 v_y number;
3 --Necessary to avoid: ORA-14551: cannot perform a DML operation inside a query
4 pragma autonomous_transaction;
5 begin
6 update some_table set x = 'whatever' returning y into v_y;
7 --Necessary to avoid: ORA-06519: active autonomous transaction detected and rolled back
8 commit;
9 return v_y;
10 end;
11 select update_and_return from dual;
12 /
UPDATE_AND_RETURN
-----------------
1
Unfortunately there are major limitations with this approach that may make it impractical for non-trivial cases:
The DML must be committed within the statement.
The WITH function syntax requires both client and server versions of 12.1 and above.
Returning multiple columns or rows will require more advanced features. Multiple rows will require the function to return a collection, and the SELECT portion of the statement will have to use the TABLE function. Multiple columns will require a new type for each different result set. If you're lucky, you can use one of the built-in types, like SYS.ODCIVARCHAR2LIST. Otherwise you may need to create your own custom types.
You can do it in SQL, not need to pl/sql, and this depends on your tool and/or language. Here's an example in sqlplus:
SQL> create table t0 as select * from dual;
Table created.
SQL> var a varchar2(2)
SQL> update t0 set dummy='v' returning dummy into :a;
1 row updated.
SQL> print a
A
--------------------------------
v
Description
I have an Oracle stored procedure that has been running for 7 or so years both locally on development instances and on multiple client test and production instances running Oracle 8, then 9, then 10, and recently 11. It has worked consistently until the upgrade to Oracle 11g. Basically, the procedure opens a reference cursor, updates a table then completes. In 10g the cursor will contain the expected results but in 11g the cursor will be empty. No DML or DDL changed after the upgrade to 11g. This behavior is consistent on every 10g or 11g instance I've tried (10.2.0.3, 10.2.0.4, 11.1.0.7, 11.2.0.1 - all running on Windows).
The specific code is much more complicated but to explain the issue in somewhat realistic overview: I have some data in a header table and a bunch of child tables that will be output to PDF. The header table has a boolean (NUMBER(1) where 0 is false and 1 is true) column indicating whether that data has been processed yet.
The view is limited to only show rows in that have not been processed (the view also joins on some other tables, makes some inline queries and function calls, etc). So at the time when the cursor is opened, the view shows one or more rows, then after the cursor is opened an update statement runs to flip the flag in the header table, a commit is issued, then the procedure completes.
On 10g, the cursor opens, it contains the row, then the update statement flips the flag and running the procedure a second time would yield no data.
On 11g, the cursor never contains the row, it's as if the cursor does not open until after the update statement runs.
I'm concerned that something may have changed in 11g (hopefully a setting that can be configured) that might affect other procedures and other applications. What I'd like to know is whether anyone knows why the behavior is different between the two database versions and whether the issue can be resolved without code changes.
Update 1: I managed to track the issue down to a unique constraint. It seems that when the unique constraint is present in 11g the issue is reproducible 100% of the time regardless of whether I'm running the real world code against the actual objects or the following simple example.
Update 2: I was able to completely eliminate the view from the equation. I have updated the simple example to show the problem exists even when querying directly against the table.
Simple Example
CREATE TABLE tbl1
(
col1 VARCHAR2(10),
col2 NUMBER(1)
);
INSERT INTO tbl1 (col1, col2) VALUES ('TEST1', 0);
/* View is no longer required to demonstrate the problem
CREATE OR REPLACE VIEW vw1 (col1, col2)
AS
SELECT col1, col2
FROM tbl1
WHERE col2 = 0;
*/
CREATE OR REPLACE PACKAGE pkg1
AS
TYPE refWEB_CURSOR IS REF CURSOR;
PROCEDURE proc1 (crs OUT refWEB_CURSOR);
END pkg1;
CREATE OR REPLACE PACKAGE BODY pkg1
IS
PROCEDURE proc1 (crs OUT refWEB_CURSOR)
IS
BEGIN
OPEN crs FOR
SELECT col1
FROM tbl1
WHERE col1 = 'TEST1'
AND col2 = 0;
UPDATE tbl1
SET col2 = 1
WHERE col1 = 'TEST1';
COMMIT;
END proc1;
END pkg1;
Anonymous Block Demo
DECLARE
crs1 pkg1.refWEB_CURSOR;
TYPE rectype1 IS RECORD (
col1 vw1.col1%TYPE
);
rec1 rectype1;
BEGIN
pkg1.proc1 ( crs1 );
DBMS_OUTPUT.PUT_LINE('begin first test');
LOOP
FETCH crs1
INTO rec1;
EXIT WHEN crs1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(rec1.col1);
END LOOP;
DBMS_OUTPUT.PUT_LINE('end first test');
END;
/* After creating this index, the problem is seen */
CREATE UNIQUE INDEX unique_col1 ON tbl1 (col1);
/* Reset data to initial values */
TRUNCATE TABLE tbl1;
INSERT INTO tbl1 (col1, col2) VALUES ('TEST1', 0);
DECLARE
crs1 pkg1.refWEB_CURSOR;
TYPE rectype1 IS RECORD (
col1 vw1.col1%TYPE
);
rec1 rectype1;
BEGIN
pkg1.proc1 ( crs1 );
DBMS_OUTPUT.PUT_LINE('begin second test');
LOOP
FETCH crs1
INTO rec1;
EXIT WHEN crs1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(rec1.col1);
END LOOP;
DBMS_OUTPUT.PUT_LINE('end second test');
END;
Example of what the output on 10g would be:
begin first test
TEST1
end first test
begin second test
TEST1
end second test
Example of what the output on 11g would be:
begin first test
TEST1
end first test
begin second test
end second test
Clarification
I can't remove the COMMIT because in the real world scenario the procedure is called from a web application. When the data provider on the front end calls the procedure it will issue an implicit COMMIT when disconnecting from the database anyways. So if I remove the COMMIT in the procedure then yes, the anonymous block demo would work but the real world scenario would not because the COMMIT would still happen.
Question
Why is 11g behaving differently? Is there anything I can do other than re-write the code?
This appears to be a bug discovered fairly recently. Metalink Bug 1045196 describes the exact problem. Hopefully a patch will be released soon. For those of you who can't get past the Metalink wall here are a few details:
Metalink
Bug 10425196: PL/SQL RETURNING REF CURSOR ACTS DIFFERENTLY ON 11.1.0.6 VS 10.2.0.5
Type: Defect
Severity: 2 - Severe Loss of Service
Status: Code Bug
Created: 22-Dec-2010
DIAGNOSTIC ANALYSIS from original case submission:
- 10.2.0.4 Windows Expected Behavior
- 10.2.0.5 Solaris Expected Behavior
- 11.1.0.6 Solaris Un-Expected Behavior
- 11.1.0.7 Windows Un-Expected Behavior
- 11.2.0.1 Solaris Un-Expected Behavior
- 11.2.0.2 Solaris Un-Expected Behavior
FURTHER DETAILS I can confirm:
- 10.2.0.3 Windows Expected Behavior
- 11.2.0.1 Windows Un-Expected Behavior
Additional Details
Changing the OPTIMIZER_FEATURES_ENABLE='10.2.0.4' parameter does not resolve the problem. So it seems to be related more to a design change in the 11g database engine rather than an optimizer tweak.
Code Workaround
This appears to be a result of the use of the index when querying the table and not the act of updating the table and/or committing. Using my example above, here are two ways to ensure the query does not use the index. Both may affect the performance of the query.
Affecting the performance of the query might be temporarily acceptable until a patch is released but I believe that using FLASHBACK as #Edgar Chupit suggested could affect the performance of the entire instance (or may not be available on some instances) so that option may not be acceptable for some. Either way, at this point in time code changes appear to be the only known workaround.
Method 1: Change your code to wrap the column in a function to prevent the unique index on this one column from being used. In my case this is acceptable because although the column is unique it will never contain lower case characters.
SELECT col1
FROM tbl1
WHERE UPPER(col1) = 'TEST1'
AND col2 = 0;
Method 2: Change your query to use a hint preventing the index from being used. You might expect the NO_INDEX(unique_col1) hint to work, but it does not. The RULE hint does not work. You can use the FULL(tbl1) hint but it's likely that this may slow down your query more than using method 1.
SELECT /*+ FULL(tbl1) */ col1
FROM tbl1
WHERE col1 = 'TEST1'
AND col2 = 0;
Oracle's Response and Proposed Workaround
Oracle support has finally responded with the following Metalink update:
Oracle Support - July 20, 2011 5:51:19 AM GMT-07:00 [ODM Proposed Solution(s)]
Development has reported this will be a significant issue to fix and
has suggested that the following workaround be applied:
edit init.ora/spfile with the following undocumented parameter:
"_row_cr" = false
Oracle Support - July 20, 2011 5:49:20 AM GMT-07:00 [ODM Cause Justification]
Development has determined this to be a defect
Oracle Support - July 20, 2011 5:48:27 AM GMT-07:00 [ODM Cause Determination]
Cause has been traced to a row source cursor optimization
Oracle Support - July 20, 2011 5:47:27 AM GMT-07:00 [ODM Issue Verification]
Development has confirmed this to be an issue in 11.2.0.1
After some further correspondence it sounds as though this isn't being treated as a bug so much as a design decision moving forward:
Oracle Support - July 21, 2011 5:58:07 AM GMT-07:00 [ODM Proposed Solution Justif]
From 10.2.0.5 onward (which includes 11.2.0.2) we have an optimization called
ROW CR it is only applicable to queries which use an unique index to
determine the row in the table.
A brief overview of this optimization is that we try to avoid rollbacks while
constructing a CR block if the present block has no uncommitted changes.
So the difference seen in 11.2.0.2 is because of this optimization. The
suggested workaround is to turn off of this optimization so that things will
work exactly as they used to work in 10.2.0.4
In our case, given our client environments and since it is isolated to a single stored procedure we will continue to use our code workaround to prevent any unknown instance-wide side effects from affecting other applications and users.
This is indeed strange issue, thanks for sharing!
It really looks like a behavior change in Oracle starting with Oracle 11.1 and there is even confirmed bug with similar issue on metalink (bug#10425196). Unfortunately at the moment there is no much information available on metalink on subject mater, but I've also opened SR with Oracle asking to provide more information.
While at the moment I can not provide you an explanation why it happens and if there is a (hidden) parameter that can reverse this behavior back to 10g style, I think I can provide you with workaround. You can use Oracle flashback query functionality to force Oracle to retrieve data as to expected point in time.
If you change your code as follows:
OPEN crs FOR
SELECT col1
>>> FROM vw1 as of scn dbms_flashback.get_system_change_number
WHERE col1 = 'TEST1';
then result should be the same as in 10g.
And this is simplified version of original test case:
SQL> drop table tbl1;
Table dropped
SQL> create table tbl1(col1 varchar2(10), col2 number);
Table created
SQL> create unique index tbl1_idx on tbl1(col1);
Index created
SQL> insert into tbl1(col1,col2) values('TEST1',0);
1 row inserted
SQL> DECLARE
2 cursor web_cursor is
3 SELECT col1
4 FROM tbl1
5 WHERE col2 = 0 and col1 = 'TEST1';
6
7 rec1 web_cursor%rowtype;
8 BEGIN
9 OPEN web_cursor;
10
11 UPDATE tbl1
12 SET col2 = 1
13 WHERE col1 = 'TEST1';
14
15 -- different result depending on commit!
16 commit;
17
18 DBMS_OUTPUT.PUT_LINE('Start');
19 LOOP
20 FETCH web_cursor
21 INTO rec1;
22
23 EXIT WHEN web_cursor%NOTFOUND;
24
25 DBMS_OUTPUT.PUT_LINE(rec1.col1);
26 END LOOP;
27 DBMS_OUTPUT.PUT_LINE('Finish');
28 END;
29 /
Start
Finish
PL/SQL procedure successfully completed
If you comment out commit on line 16 than the output will be:
Start
TEST1
Finish
PL/SQL procedure successfully completed
From Metalink (aka Oracle Support)
Status bug 10425196 : 92 - Closed, Not a Bug
PROBLEM:
When calling a stored procedure that returns a REF CURSOR, different behavior
is seen in 10.2.0.5 and earlier vs 11.1.0.6 and later databases.
Sequence Of Events
Call stored procedure passing in a Ref Cursor
Open Ref Cursor against TableA
Update some data inside TableA from inside the stored procedure
COMMIT the update
Procedure execution ends returning Ref Cursor back to caller
10.2.0.5 and Earlier
The returned cursor does not see the updated data as it was opened prior to
the data being updated. This is the expected behavior.
11.1.0.6 and Later
The returned cursor sees the updated data and returns the updated data which
is different than the 10.2.0.5 and earlier behavior.
DIAGNOSTIC ANALYSIS:
10.2.0.4 Windows Expected Behavior
10.2.0.5 Solaris Expected Behavior
11.1.0.6 Solaris Un-Expected Behavior
11.1.0.7 Windows Un-Expected Behavior
11.2.0.1 Solaris Un-Expected Behavior
11.2.0.2 Solaris Un-Expected Behavior
RELATED BUGS:
None found.
If it is necessary, you can revert back to the pre-10.2.0.5 behavior setting the following startup parameter and restart the database.
_row_cr = false
When I navigate through the Oracle application with my application user and the right responsibility, I see the data.
I use the "record history" menu to see which table/view is used by application.
So, I got PA_EXPEND_ITEMS_ADJUST2_V.
When I'm connected with apps user in a sqlplus session,
SELECT * FROM PA_EXPEND_ITEMS_ADJUST2_V
gives me 0 rows.
I guess that there's something is misconfigurated with the apps but what ?
How may I view the rows of PA_EXPEND_ITEMS_ADJUST2_V using apps user in a sqlplus session ?
How may I see the data in the Oracle view like I see it through the application ?
There is probably some row-level security happening here. Possibly based on views, possibly the built-in RLS/FGAC/VPD (or whatever acronym they give it with that version). That's where the database rewrites the query behind the scenes to add in filters.
Generally there are based on SYS_CONTEXT values.
In Oracle Applications you have to execute the APPS.FND_GLOBAL.apps_initialize procedure to have the same context in a SQL*Plus session. I use the following script to start a session:
SET SERVEROUTPUT ON
DECLARE
l_user_id NUMBER;
l_resp_id NUMBER;
l_app_id NUMBER;
l_resp_name VARCHAR2(100) := '<Name of your responsibility>';
l_login VARCHAR2(30) := '<USERLOGIN>'
BEGIN
SELECT user_id INTO l_user_id FROM fnd_user WHERE user_name = l_login;
SELECT application_id, responsibility_id
INTO l_app_id, l_resp_id
FROM fnd_responsibility_vl
WHERE responsibility_name = l_resp_name;
apps.fnd_global.apps_initialize(l_user_id, l_resp_id, l_app_id);
dbms_output.put_line('l_user_id = '||l_user_id);
dbms_output.put_line('l_resp_id = '||l_resp_id);
dbms_output.put_line('l_app_id = '||l_app_id);
END;
/
You will need to log into oracle with the same user ( or a user with the same rights/roles ) as what the application is using.
You need to talk to your DBA.
Another possibility (apart from row-level security, which may be involved) is that the view is based on one or more global temporary tables - which means you won't see the data unless you query from within the same session that inserts it.
Or, perhaps, the app is deleting the data after it's finished with it ;)
Is there a option to see if existing table/record from a Oracle database is updated?
From a monitoring perspective (not intended to find previous changes), you have several options including but not limited to triggers, streams, and a column with a default value of sysdate. A trigger will allow you to execute a bit of programming logic (stored directly in the trigger or in an external database object) whenever the record changes (insert, update, delete). Streams can be used to track changes by monitoring the redo logs. One of the easiest may be to add a date column with a default value of sysdate.
Are you talking about within a transaction or outside of it?
Within our program we can use things like SQL%ROWCOUNT to see whether our DML succeeded...
SQL> set serveroutput on size unlimited
SQL> begin
2 update emp
3 set job = 'SALESMAN', COMM=10
4 where empno = 8083;
5 dbms_output.put_line('Number of records updated = '||sql%rowcount);
6 end;
7 /
Number of records updated = 1
PL/SQL procedure successfully completed.
SQL>
Alternatively we might test for SQL%FOUND (or SQL%NOTFOUND).
From outside the transaction we can monitor ORA_ROWSCN to see whether a record has changed.
SQL> select ora_rowscn from emp
2 where empno = 8083
3 /
ORA_ROWSCN
----------
83828715
SQL> update emp
2 set comm = 25
3 where empno = 8083
4 /
1 row updated.
SQL> commit
2 /
Commit complete.
SQL> select ora_rowscn from emp
2 where empno = 8083
3 /
ORA_ROWSCN
----------
83828780
SQL>
By default ORA_ROWSCN is set at the block level. If you want to track it at the lower level your need to create the table with the ROWDEPENCIES keyword.
These are ad hoc solutions. If you want to proactive monitoring then you need to implementing some form of logging. Using triggers to write log records is a common solution. If you have Enterprise Edition you should consider using Fine Grained Auditing: Dan Morgan's library has a useful demo of how to use FGA to track changes.
You can see if a table definition has change by querying the last_ddl_time from the user_objects view.
Without using triggers or materialized logs (which would be a total hack) there is no way I know of to see when any particular row in a table has been updated.