<

Resolving Oracle Object Names and Synonym Chains

Published on
23,376 Points
11,576 Views
13 Endorsements
Last Modified:
Awarded
This article started out as an Experts-Exchange question, which then grew into a quick tip to go along with an IOUG presentation for the Collaborate confernce and then later grew again into a full blown article with expanded functionality and legacy-version support.  I hope you enjoy it and find it helpful.

The data dictionary holds a wealth of information about your objects, but sometimes seemingly easy questions are still difficult to answer with a simple query to one of the views.  Somebody once asked me how to determine what object was pointed to by a synonym.  That's easy, just query DBA_SYNONYMS. The question becomes more complicated though if the target object is itself a synonym.  Then you need to use hierarchical queries (i.e. CONNECT BY or recursive WITH clauses.)  Answering this question is made even more difficult by changes in the way synonyms are resolved if the target doesn't exist.  

Prior to 10g this condition would produce an error.  Starting in 10g you can sometimes use a public synonym of the same name to fill in for the missing object.  To this was added a further requirement of displaying the object type of the final object in the synonym chain.

The function below is what I came up with to answer the question.  By default it resolves synonyms by 10g rules.  You can pass in any number less than 10 to change to the pre-10g method.  If a synonym chain resolves to some object in a remote database that's as far as I search and identify the final object as REMOTE.  I also keep track of the synonym chain as it's built, so if a synonym loop is created, it will be detected and identified.  

Since the output is of VARCHAR2 type, there is an implicit upper limit of 32K on the output in pl/sql  or 4K in sql; but I've never encountered a synonym chain that came anywhere close to those limits in a real system.

It was a seemingly easy question that produced an interesting answer that was fun to write.


The Code


CREATE OR REPLACE FUNCTION resolve_name(
    p_object      IN VARCHAR2,
    p_delimiter   IN VARCHAR2 DEFAULT ' ->',
    p_owner       IN VARCHAR2 DEFAULT USER,
    p_version     IN INTEGER DEFAULT 10
)
    RETURN VARCHAR2
IS
    -- Resolve_Name
    --    by Sean D. Stuber
    --
    -- Given an object name, show how that name is resolved through
    -- a chain of private and/or public synonyms to the final object
    -- and show what type of object is resolved.
    -- If no object can be found then return NULL.
    -- If the resolution chain runs into a remote object the returned path
    -- stops at the link and the remote type is undefined
    -- If synonyms loop (causing ORA-01775 errors)
    -- the path to the loop will be returned with the loop identified
    TYPE object_table IS TABLE OF CHAR(1)
                             INDEX BY VARCHAR2(200);

    v_objects object_table;

    FUNCTION recursive_resolve(
        p_object      IN VARCHAR2,
        p_delimiter   IN VARCHAR2,
        p_owner       IN VARCHAR2,
        p_version     IN INTEGER,
        p_first       IN BOOLEAN
    )
        RETURN VARCHAR2
    IS
        v_owner         dba_objects.owner%TYPE;
        v_object        dba_objects.object_name%TYPE;
        v_object_type   dba_objects.object_type%TYPE;
        v_link          dba_synonyms.db_link%TYPE;
        v_temp          VARCHAR2(32767);
        v_dummy         INTEGER;
        v_schema_exists BOOLEAN;
    BEGIN
        -- Check to see if we're recursing into a loop
        IF v_objects.EXISTS('"' || p_owner || '"."' || p_object || '"')
        THEN
            v_temp := p_owner || '.' || p_object || ' (--SYNONYM LOOP--)';
        ELSE
            v_objects('"' || p_owner || '"."' || p_object || '"') := NULL;

            BEGIN
                -- At what type of object are we looking?
                SELECT object_type
                  INTO v_object_type
                  FROM dba_objects
                 WHERE object_name = p_object AND owner = p_owner
                   AND object_type NOT IN
                           ('PACKAGE BODY', 'TYPE BODY', 
                            'TABLE PARTITION', 'TABLE SUBPARTITION');

                v_temp := p_owner || '.' || p_object;

                IF v_object_type = 'SYNONYM'
                THEN
                    -- If it's a synonym then find what the synonym points to
                    -- and call this procedure again to resolve that object
                    -- if the synonym points to a remote object,
                    -- note it and end the search.
                    SELECT table_owner, table_name, db_link
                      INTO v_owner, v_object, v_link
                      FROM dba_synonyms
                     WHERE synonym_name = p_object AND owner = p_owner;

                    v_temp :=
                        v_temp || p_delimiter
                        || CASE
                               WHEN v_link IS NULL
                               THEN
                                   recursive_resolve(
                                       v_object,
                                       p_delimiter,
                                       v_owner,
                                       p_version,
                                       FALSE
                                   )
                               ELSE
                                      v_owner
                                   || '.'
                                   || v_object
                                   || '@'
                                   || v_link
                                   || ' (--REMOTE UNKNOWN--)'
                           END;
                ELSE
                    -- If this object is not a synonym then we've resolved
                    -- to the end, so return the object with its type
                    v_temp := v_temp || ' (' || v_object_type || ')';
                END IF;
            EXCEPTION
                WHEN NO_DATA_FOUND
                THEN
                    -- For first attempt or version is 10 or higher
                    -- when no object is found in given schema
                    -- look for a public synonym of the same name
                    -- Note, 10g after the first level we only do this
                    -- if the synonym points to an existing schema
                    IF (NOT p_first) AND p_version >= 10
                    THEN
                        BEGIN
                            SELECT 1
                              INTO v_dummy
                              FROM dba_users
                             WHERE username = p_owner;

                            v_schema_exists := TRUE;
                        EXCEPTION
                            WHEN NO_DATA_FOUND
                            THEN
                                v_schema_exists := FALSE;
                        END;
                    END IF;

                    IF p_first OR v_schema_exists
                    THEN
                        v_temp :=
                            recursive_resolve(
                                p_object,
                                p_delimiter,
                                'PUBLIC',
                                p_version,
                                FALSE
                            );
                    ELSE
                        -- In versions 9i or lower,  if a synonym points to a
                        -- nonexisting object then the search ends
                        -- In 10g or higher if the synonym points to a schema
                        -- that doesn't exist then the search ends
                        v_temp := NULL;
                    END IF;
            END;
        END IF;

        RETURN v_temp;
    END;
BEGIN
    RETURN recursive_resolve(
               p_object,
               p_delimiter,
               p_owner,
               p_version,
               TRUE
           );
END resolve_name;

Open in new window



Example Usage


Here you can see DBMS_STANDARD is a PUBLIC synonym pointing to an object of the same name owned by SYS.  That object is a package.

SQL> select resolve_name('DBMS_STANDARD') from dual;

RESOLVE_NAME('DBMS_STANDARD')
------------------------------------------------------------------------------

PUBLIC.DBMS_STANDARD ->SYS.DBMS_STANDARD (PACKAGE)

Open in new window


Here the function is used to identify the cause of ORA-01775 looping error

SQL> select * from yyy;
select * from yyy
              *
ERROR at line 1:
ORA-01775: looping chain of synonyms

SQL> select resolve_name('YYY') from dual;

RESOLVE_NAME('YYY')
-------------------------------------------------------------------------

SDS.YYY ->PUBLIC.XXX ->SDS.XXX (--SYNONYM LOOP--)

Open in new window



And finally, here's an example of a tracing a synonym across a dblink.  In this case "C" points to a remote table "CLIENTS" but the function doesn't traverse the remote dictionary so the type of the remote object is unknown and labeled so.

SQL> select resolve_name('C') from dual;

RESOLVE_NAME('C')
--------------------------------------------------------------

PUBLIC.C ->SDS.CLIENTS@MY_HR_DB (--REMOTE UNKNOWN--)

Open in new window

13
Comment
Author:sdstuber
2 Comments
 
LVL 16

Expert Comment

by:Wasim Akram Shaik
Excellent...!!!
you have got tremendous knowledge of oracle..

please continue writing articles.. this will help people like who can make out their oracle concepts clear..

thanks again buddy...!!!
0
 
LVL 74

Author Comment

by:sdstuber
glad you liked it and thank you for voting
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Join & Write a Comment

Via a live example, show how to restore a database from backup after a simulated disk failure using RMAN.
This video shows how to copy an entire tablespace from one database to another database using Transportable Tablespace functionality.
Suggested Courses

Keep in touch with Experts Exchange

Tech news and trends delivered to your inbox every month