Posted on

Editioning Implementation – Planning

How many editions ?
The answer here is 2. Or 3 if you count ORA$BASE, which I will be ignoring in these discussions, so 2.
What schemas will contain editioned objects ?
Create this view in your private account to help you analyze the existing schemas. You will probably need an explicit grant to dba_objects, or use all_objects instead.
CREATE OR REPLACE VIEW editioned_users_obj_cnt AS
SELECT owner, object_type, COUNT(*) obj_count FROM dba_objects o
 WHERE owner NOT LIKE ‘%SYS%’
   AND owner NOT IN (‘PUBLIC’, ‘XDB’, ‘DBSNMP’, ‘ORACLE_OCM’, ‘ORDDATA’, ‘ORDPLUGINS’, ‘OUTLN’, ‘SCOTT’, ‘DIP’, ‘OPS$ORACLE’, ‘ORACLE’)
   AND object_type IN (‘FUNCTION’, ‘PACKAGE’, ‘PROCEDURE’, ‘TABLE’, ‘TRIGGER’, ‘TYPE’, ‘VIEW’)
 GROUP BY owner, object_type ORDER BY owner, object_type;
Once you have that, query and investigate whether you want/need all of them to be editioned. If in doubt, the answer is probably yes.
This query will show all the schemas you should probably edition:
SELECT DISTINCT owner, editions_enabled FROM editioned_users_obj_cnt JOIN dba_users ON (username = owner);
Naming conventions
editions – pick 2 names, I don’t think they should reflect an order. Colors work well, let’s say “RED” and “BLACK”
tables vs editioning views – We will append an underscore to each table name. If that makes the table name too long, we will change the final char to an underscore. Any remaining name conflicts will be resolved manually. This SQL will generate the new table names, it calls the old table name the “EV _NAME” (Editioning View):
SELECT owner, table_name ev_name, table_name || ‘_’ new_table_name FROM dba_tables
 WHERE owner IN (SELECT owner FROM editioned_users_obj_cnt) AND length(table_name) < 30
UNION
SELECT owner, table_name ev_name, substr(table_name, 1, 29) || ‘_’ new_table_name FROM dba_tables
 WHERE owner IN (SELECT owner FROM editioned_users_obj_cnt) AND length(table_name) = 30;
This SQL will show any namespace collisions with the new tables names that were generated. If it returns no rows, there are no issues.
SELECT owner, substr(table_name, 1, 29) || ‘_’ new_table_name, COUNT(*)  FROM dba_tables
 WHERE owner IN (SELECT owner FROM editioned_users_obj_cnt) AND length(table_name) = 30
 GROUP BY owner, substr(table_name, 1, 29) || ‘_’ HAVING COUNT(*) > 1;
Will you use cross edition triggers
For now, no. This can be revisited later if needed, but it removes a lot of extra training and confusion to say no at this point.
Handling DML changes to live systems
All DML done during deploy windows must be backward compatible with the former (live while we are releasing) code. Violations of this must be noted and a custom plan made for dealing with 2 code versions running against the same data. If aware of this pitfall, developers can usually code around this.
Cleanup tasks
We will drop or otherwise cleanup any invalid objects. This can be handled well ahead of time, with some monitoring in place to keep it clean.

Wherever possible, we will find code dependencies on synonyms and make the reference explicit. This SQL identifies dependencies on synonyms inside the database:

SELECT DISTINCT t.owner,t.name,t.type object_type,s.owner synonym_owner,s.synonym_name,s.table_owner || ‘.’ || s.table_name real_object
  FROM dba_dependencies t JOIN dba_synonyms s ON

    (s.owner = t.referenced_owner AND s.synonym_name = t.referenced_name AND t.referenced_type = ‘SYNONYM’)
 WHERE t.owner NOT LIKE ‘%SYS%’ AND t.owner NOT IN (‘PUBLIC’, ‘DBSNMP’, ‘ORACLE_OCM’, ‘XDB’, ‘ORDPLUGINS’, ‘CSMIG’) AND
       t.referenced_owner NOT IN (‘PUBLIC’) AND s.db_link IS NULL AND t.type NOT IN (‘SYNONYM’)
 ORDER BY t.owner, t.type, t.name;

Posted on

Editioning – Implementation Overview

This is the overall  plan for implementing editioning in a database.
  1. Planning steps
  2. Create Editions
  3. Replace Public Synonyms
  4. Enable schemas for editioning
  5. Save all triggers on the tables to be editioned
  6. Converting tables to Editioning Views
  7. Moving Triggers
  8. Stabilizes all editioned objects across editions
  9. Switch the default to one of the new edtions
  10. Implement no-downtime code deploys

Planning steps

How many editions ?
What schemas will contain editioned objects ?
Naming conventions

  • editions
  • tables vs editioning views – example would be to append an underscore to each table name

Will you use cross edition triggers ?
Handling DML changes to live systems
Cleanup tasks

  • drop any invalid objects (or make them valid if you need to keep them)
  • (optional) find code dependencies on synonyms and make the reference explicit if possible

Create Editions
Script this and test it thoroughly in your dev database
Be certain to build them in the same order and with the same names in all your databases
Don’t worry about instantiating anything, no users are enabled for editions yet, so nothing will edition

Replace Public Synonyms
Only need to drop the public synonyms that point to objects that belong to the schemas to be editioned (as determined in the planning step above)
Script a method of creating private synonyms for all schemas that can access these objects. Create those private synonyms before dropping the public ones.
Recompile any invalid objects – these go invalid when you create the private synonyms that override the publicones
Finally, drop the public synonyms and recheck for invalid objects

Enable schemas for editioning
Using the list from your planning, alter the users to turn on their editioned flag
You can query dba_users to confirm they are all enabled for editioning
Recompile everything. Here is where having no invalid objects to start makes this faster and cleaner. If something won’t recompile, fix it now.

Save all triggers on the tables to be editioned
Make sure you can recreate the trigger exactly as they are now, before you rename any tables.
After the table rename, the triggers will point to the new names, that is why you must grab the source now, or ensure it is otherwise available for creating the triggers from scratch

Converting tables to Editioning Views
You will need to rename each table where you wish to use editioning views. This is normally all the tables owned by the editioned schemas.
If the existing table name is the max number of characters, you need to modify it in some way if you wish to append an underscore
Script this also (seeing a theme here?), where for each table you rename it and create an EV as select * from the (changed) tablename
Again recompile everything – doing the recompiles in between help you debug issues with this, once you have the scripts proven, you might skip the interim compiles to save time on your production implementation, Depending on how good you feel about it

Moving Triggers
First, you must drop all the triggers on the underlying tables
Run the trigger create SQL you saved or otherwise made available, before the renames
Verify the triggers all match what they were before. They will still point to the same “table”, though that is now an editioning view

Stabilizes all editioned objects across editions
Starting in the lowest child edition, compile each editioned object into that edition, checking for invalid objects and fixing as needed
Repeat for the other editions
Run queries to compare counts of the various editions

Switch the default to one of the new edtions
Alter the default edition and any cluster ready services to point to one of the new editoins
Test with new connections to the DB

Implement no-downtime code deploys
Script this for safety and convenience
It is critical that you check the current edition and ensure you never deploy to the default edition

Want more details for these tasks? I am composing detailed instructions and some actual code for future posts.

I also reserve the right to come back to edit and add to this as I go through my next implementation. This was all written from memory and nothing jogs ones memory like repeating the process a second time.