Tyler Muth’s Blog

Technology with a focus on Oracle, Application Express and Linux

Logger 1.4.0 Released

Posted by Tyler Muth on August 11, 2011

This is just a minor update to logger (project page here) to fix a bug in detecting DB Version 11.2 on RAC.

One important point to note is that in APEX 4.0 (or possibly 4.1), the APEX team removed the “create any context” priv when creating a schema associated with provisioning a workspace. Logger needs this priv. So, this means you won’t be able to simply install logger through the SQL Workshop without granting this priv to the schema owning logger. The biggest impact will be on hosted instances such as apex.oracle.com as you can’t simply ask someone to grant this priv to you (and please don’t try). I will try to see if it’s easy to work around this issue and what the implications are in the next few weeks.

Posted in APEX, Oracle, PLSQL | 3 Comments »

AWR Formatter 1.6 Released

Posted by Tyler Muth on July 12, 2011

I made some minor updates to my previously released Google Chrome Extension called AWR Formatter. Enhancements include:

  • Performance increased by 3x in rendering large AWR reports.
  • Added new tabs to SQL Popup for Query Plan, Color SQL, and AWR SQL Report

The new options in the SQL Popup expose features of the AWR repository that I don’t think many people are aware of, but I think are really useful.

Installation

If you already have it installed, it should update automatically and the version will say 1.6. If you do not have it installed:

I hope to add support for RAC reports soon…

Posted in AWR, Oracle | Tagged: , , , | 25 Comments »

awrload.sql > ORA-12899: value too large for column….

Posted by Tyler Muth on June 15, 2011

Today I tried to load exported AWR data from a recent Exadata POV via $ORACLE_HOME/rdbms/admin/awrload.sql and recieved the following error:

ORA-12899: value too large for column "SYS"."WRH$_ACTIVE_SESSION_HISTORY"."MODULE"

Searched all over and didn’t find an answer (including MOS). The issue was that the data was exported from an 11.2.0.2 database and I was trying to import into 11.2.0.1. I don’t really expect that to work flawlessly, but a better error would have been nice. Patched my local DB up to 11.2.0.2 and everything worked great. Hopefully google will lead someone here and save them some time…

Posted in Oracle | 1 Comment »

AWR Formatter

Posted by Tyler Muth on April 20, 2011

I’ve found myself looking at a lot of AWR Reports lately and doing the same calculations on them over and over. Converting gets / reads / bytes to KB / MB / GB / TB, converting seconds to hours minutes and seconds, etc. So, I wrote a few lines (~25) of JavaScript (using jQuery) to do some of this math for me. Like many projects, it quickly grew and grew. So, 2,000+ lines of JavaScript later, I present to you a google chrome plugin I’ve creatively entitled “AWR Formatter”.

It will not tune your database nor end world hunger, it just makes AWRs a lot easier to read. I did attempt to make some “observations”, but I certainly want to be careful with these. Currently it works with 10.2+ (maybe 10.1) single-node reports. It does not work on RAC / Global reports or on compare period reports but I’m going to start on those soon.

Thanks to Tom Kyte, Graham Wood, Robert Freeman and Tom Roach for your contributions.

Installation

Features (screencast at the end)

  • “Smart Text” conversion of gets / reads / bytes to KB / MB / GB / TB. You can click the orange text to cycle through these units
  • Medium size tables are sortable
  • Large tables are searchable
  • All documented wait events are “hot” and local definitions are included
  • Nicely formatted SQL Full text popup
  • Combined view of key Top SQL sections
  • “Observations” including:
    • Time period of AWR > 60 minutes
    • Hidden / undocumented parameter use
    • Highlight memory recommendations from AWR
  • Link to MOS note for “PX” events
  • Link to documentation for  ”gc” events
  • I/O Graphs of tablespace activity
  • Updates to the extension are delivered automatically as I release new versions
  • I am not collecting any data or sending any data to myself or anywhere else. You can review the code anytime via the instructions in the last paragraph
You can watch a screencast of it in action here. If you need a “demo” AWR Report, you can download this report from an Exadata 1/4 rack. As always, feedback or enhancement requests are welcome. If you want to view the source, just change the file extension from .crx to .zip and unzip it.

Posted in Exadata, Oracle | 42 Comments »

APEX is 57.4x Faster on Exadata

Posted by Tyler Muth on April 12, 2011

…is just about as useful (and accurate) as saying APEX is just as fast on my laptop as it is on Exadata. However, it makes for a great title. Now that I hopefully have your attention, lets talk about the reasons for this post. As many of you know, APEX used to be my primary specialty but I’ve changed roles a bit over the last year at Oracle and my primary focus is now Exadata. I’ve received an increasing number of questions about APEX on Exadata lately so I thought I’d put together some thoughts on them. Additionally, I’ve had a lot of Exadata questions recently that lead me to the conclusion that it’s not as well understood as I thought, at least within the groups of people I regularly interact with. Contrary to popular belief, it’s not a mythological beast powered by ferry dust and unicorn blood. It’s a very well engineered solution that solves a number of exceptionally challenging problems. In my opinion, the more you understand about it, the more you’ll appreciate it.

Does APEX Work on Exadata?

Yep, Exadata is just Oracle. Let me say that again: It’s just Oracle. Exadata runs an 11.2 Database on Linux x64. It’s the exact same binary install if you download those binaries for “generic” Linux x64 11.2 from OTN. So, if your code / app runs on 11.2, it runs on Exadata. There are a few exceptions to this rule for apps that don’t play well with ASM. So, more accurately, if it runs on 11.2 on Linux x64 with ASM and RAC (optional, but desirable), it runs on Exadata. The APEX Dev Team (my old friends and colleagues) did absolutely nothing to port their code to Exadata. I’ve run a number of customer benchmarks with customer’s data and queries and have yet to make a single change to their queries or structures to make them work on Exadata. The only thing I’ve done is to set indexes invisible in Data Warehouse benchmarks, but that was more for fun…more on that later.

What Problems Does Exadata Solve?

The most obvious problem is solves is the I/O bottleneck. While I’m not in the same league as many of the well known performance architects in the Oracle community, I spend a fair amount of time talking to customers about performance problems. In my estimation, the vast majority of the time the performance problems I encounter come down to I/O. Most DBAs (myself included) don’t know near enough about storage. Compounding that problem is the fact that there are often communication “issues” between storage groups and the DBAs.

Lets talk about how we get to data for second. I’ll try and use a Tom Kyte example. Lets take an example of reading a phone book and assume it has an index (paper style) in the back that tells you which names are on which pages. If you wanted to count all of the names in the phonebook, it would be much quicker to just scan through all of the names from beginning to end than it would to go to the index to find each and every name. This is an example of why full table and partition scans are often faster for data warehouse queries than index-based access paths. Flip that around and tell me the phone number for the “Muth’s”, and it would be much faster to look at the index, find out what page the “Mu”’s start on and go to that page. Think of this as an OLTP style query.

So, I/O throughput is particularly important in DSS and Data Warehousing environments because you’re scanning through whole tables and partitions. However, the vast majority of the customers I talk to are running a SAN attached via 2 or 4 Gbps (gigabit per second) Fibre Channel. That connection provides 200 or 400 MB/s (megabytes per second) respectively. If you want to run a full scan on a 200 GB table and you’re connected via 4 Gb FC, some simple math will tell you it will never run faster than 512 seconds or 8.5 minutes Now, compare that to the disk-only 25 GB/s (gigabytes per second) scan rate of an X2-2 full rack with High Performance disks and we can now scan that table in 8 seconds. Our scan rate jumps to 75 GB/s with Flash Cache, but I’ll stick to disk-only numbers for scan operations. It’s easy to see how a query in this example could run 64x faster on Exadata which supports my claim in the title of this post. The results I’ve obtained in POVs I’ve personally worked on have been incredible. On several occasions I’ve had prove to customers that the results were real, especially in the case of I/O intensive operations.

You don’t need to have a 10 TB database to have I/O problems either. The last POV I ran was on a 500 GB data set (including indexes). The database is a shared resource across many organizations and applications. As they’ve built more applications on this database, their indexing strategy hasn’t exactly kept pace. Their top wait events from statspack are mostly I/O related. Additionally, they copy this database nightly to a mirror server that they use for ad-hoc reporting, which as you might expect has even more I/O issues. It’s hard to index for ad-hoc…

What does this have to do with APEX? I’ve seen (and written) plenty of APEX apps that are front-ends to a data warehouse. If you are working with large data sets, doing a lot of aggregation, or allowing a lot of ad-hoc queries, traditional index strategies are often difficult to develop and of marginal value. In many cases like these, the best strategy for performance is to improve the I/O of your system.

So We Don’t Need Indexes Anymore?

I’ve heard this concept from far too many people not to address it. For Data Warehouse / DSS style queries, it is often the case with Exadata that the optimizer will choose a full table or partition scan access path, and consequently not use indexes. In several Data Warehouse POVs I’ve simply set all indexes invisible without negatively impacting performance since the optimizer wasn’t using them anyway. You still need indexes for primary keys, uniqueness, etc, but I think it’s fair to say that implementing a Data Warehouse on Exadata will allow you to eliminate many (dare I say “most) of your indexes. This allows you to reclaim a lot of disk space and certainly makes data loads faster.

However, this concept has nothing to do with OLTP style queries! If you want to retrieve a row based on it’s primary key, which do you think is faster 1) Traversing a few blocks in a b-tree index to find the rowid, then plucking the single-block that contains your row from disk (or RAM) or 2) scanning the whole multi-gigabyte table? We still need / want indexes for OLTP. Dropping all of the indexes on a busy Exadata-hosted OLTP application would be disastrous. This also applies to the APEX builder itself. Those tables are heavily indexed as other than some of the administrative reports, all of the queries are going after a few specific rows to render your page.

But I Thought Storage Indexes Replaced Traditional Indexes

Uh, no. Storage indexes are often mis-understood. They are unique to Exadata and implemented automatically by the storage cells. I actually like to think of them as anti-indexes. They store the high and low values of number and date columns for a storage unit (~1 MB). As we are scanning through the table or partition, and the query has a predicate that filters on one of these columns, we know we can skip all of the blocks in the storage unit if the value we are looking for falls outside of those high and low values. The key word there is “scanning”. They are used in data warehouse style queries, but not OLTP style queries. Clearly, they are no replacement for traditional indexes in OLTP applications.

Many of My APEX Apps are OLTP, Will They Run Faster on Exadata?

Potentially. Even though those apps shouldn’t be doing a lot of table scans, they will often still incur some physical I/O in the form of single-block reads. If the size of your “hot data and indexes” for all of your applications is larger than the RAM you have allocated to your SGA, you’re going to incur physical I/O. The time difference between reading a block from the buffer cache to reading it from disk dramatic. Buffer cache reads should be in the micro-second range whereas reads from disk can take 10’s of milliseconds. Your single block read times essentially fall off a cliff when you go to disk.

Exadata added Flash Cache in the second (V2) and third (X2-2, X2-8) versions. It’s essentially solid state storage (as cards, not disks) in the storage cells that is configured as a write-through (read) cache. So, if you ask for a block and we don’t find it in the SGA, we go to the storage cells. If it’s in Flash, we can return it from there. If not, we grab the block off disk, then optionally copy it to Flash so the next time we need to read that block from “disk” we can return it from Flash instead. The single-block read times from flash are often under a millisecond. It provides a nice step down in access time between RAM and disk. A full rack has 5.3 TB of Flash Cache, so we can cache A LOT of blocks there. I’ve skipped a lot of details here, but I can tell you from the results of several OLTP POVs that I’ve worked on that it plays a very significant role in OLTP performance. There’s a nice white paper on Flash Cache here (PDF).

APEX is Only for Departmental Applications, Why Would I Run it on Exadata?

Anybody connected to the APEX community know that this has a lot more to do with product positioning than it does actual capabilities. There are plenty of enterprise-class APEX apps there. One great example is the new Oracle Store. APEX is a great front-end to database centric applications. Exadata is a great platform for databases. Enough said.

Posted in APEX, Exadata | Tagged: , , | 4 Comments »

jQuery Custom Selector

Posted by Tyler Muth on March 23, 2011

I’m working on a little Google Chrome Extension in my spare time to add a little formatting and bells and whistles to AWR Reports like converting Physical/Logical Reads/Consistent gets and bytes to KB/MB/GB. Also adding sorting and filtering to key tables, as well as making all wait events “hot” with a popup to show there definition, etc. Anyway, I found myself writing the same logic in a jQuery selectors all throughout my code to find the section headings of the report. Essentially, they’re either a p, h2, or h3 that contain text, have no child elements, and are a first-child of body. So, I wrote a custom selector to encapsulate the logic and drastically reduce and simplify my code:

jQuery.expr[':'].topLevelTextElement = function(element, index) {
     // if there is only one child, and it is a text node (<div>hello world</div>, not <div><span>hello world</span></div>)
     if (element.childNodes.length == 1 && element.firstChild.nodeType == 3) {
		// if it's parent is the <body> tag, ie it's not nested several levels deep
		if(element.parentNode.nodeName == 'BODY'){
			return jQuery.trim(element.innerHTML).length > 0;
		}
     }
     return false;
};

Here are some examples of it in action:

// iterate over each element the selector finds and log what type of node (tag) it is.
$(':topLevelTextElement').each(function(){console.log($(this).get(0).nodeName)});
//console output:
//h1
//h2
//h2
//p
//...

// iterate over each h2 element the selector finds and log the text it contains
$('h2:topLevelTextElement').each(function(){console.log($(this).text())});
//console output:
//Main Report
//More RAC Statistics
//Wait Events Statistics

On a related note, if you know JavaScript, CSS, and HTML, writing a Google Chrome Extension is REALLY easy. The documentation and examples are still a little weak. Integrating jQuery, jQuery Plugins, and jQuery UI was also quite easy, but there’s a minor catch for image references in CSS in that relative paths don’t work (easily). You have to use your extension name as an absolute path. I’ll blog about this later. If you need it now, just ask…

Posted in JavaScript / AJAX, jQuery | Tagged: | Leave a Comment »

Oracle Custom Search

Posted by Tyler Muth on November 29, 2010

Like many people reading this blog, google is a tool I use on a daily basis to find answers on Oracle Technology. I use it to search Oracle Documentation, OTN Forums, blogs, etc. There is such a large community of really talented people that you can usually find an answer quickly. However, there are a few problems with googling for Oracle answers. First, I find myself using the site: operator a lot to search Oracle documentation. This works fine, but I still end up with 8i & 9i doc when I would prefer never to see those versions again. There are also a number of sites that use Search Engine Optimization (SEO) techniques to relentlessly inject themselves into my results and I would prefer not to see those sites at all (Please don’t name them here. We all know who they are and I don’t want to deal with lawyers. If you name any specific sites in the comments, I will remove them immediately). There are also some sites which I trust more than others and would like to add a bit of “weight” to those sites in my results.

So, I created a Google Custom Search (http://www.google.com/cse/). I removed the sites I want to avoid, added some categories based on my search habits and customized the colors a bit. You can find my search at:

http://sn.im/orclsearch

Update: You can add my search to your browser’s search bar by navigating to this page and simply clicking a link . Thanks for suggesting it Stew.

Feel free to use mine or create your own, it’s pretty simple. Enjoy!

Posted in Oracle | 8 Comments »

Formatting Output of 11.2 Compression Advisor (DBMS_COMPRESSION)

Posted by Tyler Muth on October 21, 2010

Let me start with a few facts about compression that I feel are a bit confusing or could use better documentation. The Compression Advisor is a package named DBMS_COMPRESSION that allows takes a table as input, then estimates the compression ratio and resulting size in blocks if you compressed the table. You can download a version of it that works in any 9.2+ database from the Advanced Compression page.  However, this will only estimate Advanced Compression / OLTP Compression results. It will NOT estimate the 4 forms of Hybrid Columnar Compression (HCC) which are only available in Exadata. To estimate HCC results, you have to use an 11.2 database as the version of DBMS_COMPRESSION in 11.2 has been enhanced. You don’t need an Exadata machine, just an 11.2 database. For more information on HCC, check out this presentation (PDF, 2.7 MB). When computing HCC estimates in the 11.2 Compression Advisor, it’s important to note that for each type of compression you wish to test, it creates a complete copy of your table or partition. This is very accurate but PAINFULLY slow, so be warned. If you want to know the results of each type of compression for every table in a schema, it will literally recreate a temporary copy of each table 4 times!

Now that we have that out of the way, lets get to the real reason for this post. The 11.2 compression advisor is functional, but it really leaves it up to you to format the output. Typically you would use DBMS_OUTPUT for this, but I wanted a format that I could easily import into a spreadsheet to do some sorting and compute some aggregates. So, I wrote a pipelined function that is a wrapper on DBMS_COMPRESSION which allows you to run it in a SQL statement.  If you run it in SQL Developer, you can easily export the results as XLS.

You can download the code here. A few notes which are in the head of the function as well:

  • Tables and partitions must have at least 1,000,000 rows based on the dbms_compression.comp_ratio_minrows global.
  • Computing HCC compression recreates the entire table or partition, which is very accurate but VERY slow.
    Update: Thanks to Kam Shergill for pointing out the “subset_numrows” in dbms_compression. I’ve added a new parameter called p_subset_numrows.  You can pass in a number of rows such as 1500000 or a percentage such as 50%.  However, the number of rows per segment still has to be above 1000000 for the compression advisor to work.
  • This is an “Invokers Rights” function, so it queries “USER_” dictionary views of the schema that calls the function, not the schema it’s installed in.
  • The p_compression_level parameter is a bitwise parameter based on the table below (which comes from the package spec of DBMS_COMPRESSION). 2+4 will compute OLTP and HCC QUERY HIGH. 2+4+8+16+32 (or 62) will compute ALL levels of compression. Warning!!! Each level of HCC is very slow, so 62 will take forever.
COMP_FOR_OLTP 2
HCC COMP_FOR_QUERY_HIGH 4
HCC COMP_FOR_QUERY_LOW 8
HCC COMP_FOR_ARCHIVE_HIGH 16
HCC COMP_FOR_ARCHIVE_LOW 32

Function Spec:

create or replace function get_compression_stats(
    p_table_name            in varchar2,
    P_compression_level        in number,
    p_subset_num_rows        in varchar2 default '100%',
    p_scratch_tablespace     in varchar2 default 'USERS'
    )
return table_compression_stats 
authid current_user 
pipelined 
is
pragma autonomous_transaction;

Example 1:

-- For the EMPLOYEES_LARGE table, compute all compression estimates (2+4+8+16+32), create the temporary copy of EMPLOYEES_LARGE in the USERS tablespace
select * from table(get_compression_stats('EMPLOYEES_LARGE',2+4+8+16+32,'USERS'));

Example 2:

-- For the ALL_OBJS table, compute compression estimates for HCC COMP_FOR_QUERY_HIGH and COMP_FOR_QUERY_LOW  (4+8), create the temporary copy of ALL_OBJS in the USERS tablespace
select * from table(get_compression_stats('ALL_OBJS',4+8,'USERS'));

Output of Example 2 (HTML “unload” from SQL Developer 3.x. Empty columns removed for width):

TABLE_NAME PARTITION_NAME COMMENTS CURRENT_SIZE_MB NUM_ROWS QUERY_HIGH_MB QUERY_LOW_MB QUERY_HIGH_RATIO QUERY_LOW_RATIO
ALL_OBJS 142 1205180 0.66 0.8 170.7 142.2

Posted in Uncategorized | Leave a Comment »

Synonym Switching Technique and Tools

Posted by Tyler Muth on October 11, 2010

AriaA long time ago (about 7 years), in a land far, far away (Reston, VA), I worked in a group that supported an Oracle internal application called “Aria People”. That group became the APEX development team (managed by Mike Hichwa) and at the time reported to Tim Hoechst. Tom Kyte and his team also worked for Tim at the time and the day to day management of Aria was passed around to various members of Mike and Tom’s team. Aria is a simple employee directory that is wildly popular inside Oracle. You can even download a version of Aria here as an APEX packaged application. I’m not sure who’s idea it was (Tim, Tom, Mike…) but Aria used a very effective technique to refresh its data from our global HR database. The application ran (parsed) as one schema, lets call it PEOPLE_PARSE, and that schema had synonyms that pointed to one of two data schemas, PEOPLE_A and PEOPLE_B. PEOPLE_PARSE didn’t actually own any tables or procedures. PEOPLE_A and PEOPLE_B owned all of the tables and procedures that contained the data (simplified explanation). Each night a PL/SQL package would truncate and refresh one of the schemas. Then when it was complete it would drop and recreate all of the synonyms in PEOPLE_PARSE to point to the most recently refreshed schema. In short, the source of data would alternate between PEOPLE_A and PEOPLE_B every night.  This has a couple of key advantages including the ability to truncate and load one schema while running against the other and the ability to switch back to the previous days data schema if anything went wrong. Tim mentioned many times that we should publish this technique in some form or another as it was relatively simple and exceptionally useful. APEX even uses a modified version of this technique for it’s own upgrades, just with public synonyms.

Seven years later, and I now have a current customer that could potentially benefit from this technique, so I decided to create a utility package to automate it. I see two primary scenarios for the schema layout. The 3 schema layout like Aria uses and a 4+ schema layout that introduces a synonym administrator schema.  The latter would be beneficial if you plan to add many new data schemas, such as a new schema each week or month that is a copy of production data, not just flip back and forth between 2 schemas.

Below is a short summary of the package.  Each procedure can be used independently, such as for 1-time operations or you can use the switch_synonyms procedure which calls all of the other procedures.

create or replace package synonym_util
as
procedure drop_user_views ...
procedure drop_views_for_target ...
procedure drop_user_synonyms ...
procedure drop_synonyms_for_target ...
procedure create_views_for_target ...
procedure grant_object_privs ...
procedure revoke_object_privs ...
procedure create_synonyms ...
function  get_object_owner_for_synonym ...
procedure switch_synonyms ...

Scenario 1

Lets run through Scenario 1 to provide you with an example:

  1. Install the synonym_util package in all 3 schemas
  2. Run the included grants_minimal.sql as sys to give PARSE_SCHEMA just enough privs to function.
  3. Run:
    data_a.synonym_util.grant_object_privs(p_grantee => ‘PARSE_SCHEMA’, p_objects_owner => ‘DATA_A’);
    data_b.synonym_util.grant_object_privs(p_grantee => ‘PARSE_SCHEMA’, p_objects_owner => ‘DATA_B’);
  4. You can now drop the package from DATA_A and DATA_B as we only needed it there for the grants.
  5. Run the following block as PARSE_SCHEMA:
  6. -- The first time you run this it will create synonyms pointed to p_first_schema.
    -- Each subsequent run will look at where the “EMPLOYEES” synonym is pointing,
    -- then flip the synonyms to the other schema.
    synonym_util.switch_synonyms(
    	p_first_schema        => 'DATA_A',
    	p_second_schema       => 'DATA_B',
    	p_synonym_owner       => 'PARSE_SCHEMA',
    	p_reference_synonym   => 'EMPLOYEES');

     

Scenario 2

Lets run through Scenario 2 to provide you with an example of using a SYNONYM_ADMIN schema:

  1. Install the synonym_util package in the SYNONYM_ADMIN schema.
  2. As sys, run the included grants_super_user.sql file.  Warning, you are giving SYNONYM_ADMIN a lot of power, so use with caution.
  3. Run the following code as synonym_admin:
  4. set serveroutput on
    
    begin
        dbms_output.put_line('Old Schema: '||
            synonym_util.get_object_owner_for_synonym(
                p_synonym            => 'EMPLOYEES',
                p_synonym_owner        => 'PARSE_SCHEMA')
        );
    
        synonym_util.switch_synonyms(
            p_first_schema        => 'DATA_A',
            p_second_schema        => 'DATA_B',
            p_synonym_owner        => 'PARSE_SCHEMA',
            p_reference_synonym    => 'EMPLOYEES',
            p_create_views        => 'YES',
            p_object_types      => 'TABLE:VIEW:MATERIALIZED VIEW:FUNCTION:PROCEDURE:PACKAGE:TYPE',
            p_include_grants    => 'YES',
            p_grant_types        => 'SELECT:INSERT:UPDATE:DELETE:EXECUTE'
            );
    
        dbms_output.put_line('New Schema: '||
            synonym_util.get_object_owner_for_synonym(
                p_synonym            => 'EMPLOYEES',
                p_synonym_owner        => 'PARSE_SCHEMA')
        );
    end;
    /

Notes

  • There are schema restriction globals in the package body.  If you plan on using Scenario 2, I strongly suggest you set those globals to restrict use of this utility.
  • This is a “definers rights” package. When owned by a powerful user it can be a security risk.
  • You can download the full package here: synonym_util.zip (5 kb)

Package Spec (for preview)

create or replace package synonym_util
authid definer
as
    -- Drop all views for a given user (p_view_owner)
    procedure drop_user_views(
        p_view_owner     in varchar2 default user);

    -- Drop all views for a given user (p_view_owner) that reference objects in
    -- a target schema (p_target_owner)
    procedure drop_views_for_target(
        p_target_owner    in varchar2,
        p_view_owner     in varchar2 default user);

    -- Drop all synonyms for a given user
    procedure drop_user_synonyms(p_synonym_owner in varchar2 default user);

    -- Drop synonyms for a given user (p_synonym_owner) that point to a "target" schema (p_target_owner)
    procedure drop_synonyms_for_target(
        p_target_owner  in varchar2,
        p_synonym_owner in varchar2 default user,
        p_drop_views    in varchar2 default 'YES' -- YES | NO
        );

    -- Create views in a schema (p_view_owner) that point to objects in a
    -- target schema (p_target_owner).  You can pass in a colon separated list
    -- of object types: 'TABLE:VIEW:MATERIALIZED VIEW'
    procedure create_views_for_target(
        p_target_owner    in varchar2,
        p_view_owner     in varchar2 default user,
        p_object_types  in varchar2 default 'TABLE:VIEW:MATERIALIZED VIEW');

    -- Grant object privs from p_objects_owner to p_grantee.
    -- Package must be owned by p_objects_owner or by a user that has system privs
    procedure grant_object_privs(
        p_grantee        in varchar2,
        p_objects_owner    in varchar2 default user,
        p_object_types    in varchar2 default 'TABLE:VIEW:MATERIALIZED VIEW:FUNCTION:PROCEDURE:PACKAGE:TYPE',
        p_grants        in varchar2 default 'SELECT:INSERT:UPDATE:DELETE:EXECUTE');

    procedure revoke_object_privs(
        p_grantee        in varchar2,
        p_objects_owner    in varchar2 default user);

    -- Create synonyms in a schema (p_synonym_owner) that point to all of the objects
    -- in a target schema (p_objects_owner).
    -- By default it will create VIEWS instead of synonms for TABLES, VIEWS and MATERIALIZED views
    -- as the describe of the view is much more useful than the describe of the synonym.
    -- You can optionionally choose which object types to reference.
    procedure create_synonyms(
        p_objects_owner in varchar2,
        p_synonym_owner in varchar2 default user,
        p_create_views    in varchar2 default 'YES', -- YES | NO
        p_object_types  in varchar2 default 'TABLE:VIEW:MATERIALIZED VIEW:FUNCTION:PROCEDURE:PACKAGE:TYPE');

    -- For a given synonym and synonym owner, return the schema / owner that the synonym points to
    function get_object_owner_for_synonym(
        p_synonym            in varchar2,
        p_synonym_owner        in varchar2 default user)
        return varchar2;

    -- This is the rollup of all or most of the other procedures in this package. It's meant for situations where you
    -- want to switch back and forth between 2 object owner schemas from a synonym schema
    procedure switch_synonyms(
        p_first_schema        in varchar2,
        p_second_schema        in varchar2,
        p_synonym_owner        in varchar2,
        p_reference_synonym    in varchar2,
        p_create_views        in varchar2 default 'YES', -- YES | NO
        p_object_types      in varchar2 default 'TABLE:VIEW:MATERIALIZED VIEW:FUNCTION:PROCEDURE:PACKAGE:TYPE',
        p_include_grants    in varchar2 default 'NO', -- YES | NO
        p_grant_types        in varchar2 default 'SELECT:INSERT:UPDATE:DELETE:EXECUTE' -- 'SELECT:INSERT:UPDATE:DELETE:EXECUTE'
        );

end synonym_util;
/
show errors

scenario_one

Posted in Oracle, PLSQL | 7 Comments »

ODTUG Kaleidoscope 2010

Posted by Tyler Muth on July 1, 2010

I had the great opportunity to attend and work ODTUG this year in Washington, DC. I went into it expecting to work a few of the hands-on labs for APEX and hopefully catch up with a few old friends. However, I really underestimated the value of getting that many brilliant people together. Every session I attended was really well thought out and packed with great information. From the APEX plugin panel to Cary Millsap’s discussion on SQL trace files. I also had a lot of great discussions with people that were not presenting that shared some really creative ideas. Even the questions people were asking in the hands-on labs were really insightful and thought provoking. If you ever get the opportunity, I strongly recommend you attend.

It was also great to finally meet a lot of people face to face that I’ve “worked with” online for years. The Oracle community, especially the APEX corner of it is a exceptional resource and I’m really lucky to be a part of it. I’ve dabbled in other technologies (which shall remain nameless) and tried to learn from their respective communities and I’ve never seen one as friendly and willing to help as ours. On a related note, thanks to everyone for the positive feedback on logger.  I really had no idea there were so many people using it.

Finally, it was really great to hang out with my friends from the APEX team, both old and new. They’re some of the most talented and motivated people I’ve had the pleasure of working with. It’s too bad this event isn’t in DC every year… twice a year ;)

Posted in Uncategorized | Leave a Comment »

 
Follow

Get every new post delivered to your Inbox.

Join 44 other followers