views:

1096

answers:

5

How can I get the location of the tnsnames.ora file by code, in a machine with the Oracle client installed?

Is there a windows registry key indicating the location of this file?

A: 

According to the net that depends on the version of Oracle and the working directory of the SQL*Plus process. This first link tells you the environment variable that specifies the base path for some versions (7, 8, 9i) of Oracle. If you use a different one, I'm sure there's a similar way to get to the system directory.

If you spread versions of these files all over the place though and rely on the "look for a local tnsnames.ora first" behaviour of the client, then I guess you're out of luck.

Benjamin Podszun
That link is somewhat out of date, but the behaviour is roughly the same all the way up the latest version (11g).
Colin Pickard
+4  A: 

On Windows, the most likely locations are either %ORACLE_HOME%/network/admin or %TNS_ADMIN% (or the TNS_ADMIN registry setting). These two cover almost every installation.

Of course it is possible to have a working Oracle client without this file. Oracle has bewildering array of networking options, and there are plenty of ways to achieve a working setup with using TNSNAMES. Depending on what you are trying to achieve here, your first port of call might be the sqlnet.ora file, which is also found in %ORACLE_HOME%/network/admin. This should contain a line that looks something like this:

NAMES.DIRECTORY_PATH= (LDAP, TNSNAMES, HOSTNAME)

TNSNAMES means it will use the TNSNAMES.ora file (second in this case). LDAP and HOSTNAME are alternate ways of resolving the database. If there is no TNSNAMES the TNSNAMES.ora file will be ignored if it exists in the right place.

In C# / .NET this should get you the environment variables:

Environment.GetEnvironmentVariable("ORACLE_HOME");

Environment.GetEnvironmentVariable("TNS_ADMIN");

Colin Pickard
@Colin, Unfortunately these variables are not always set by oracle client. i am using oracle 11g.
RRUZ
Are you using the Instant Client or the regular client?
Colin Pickard
I believe the Instant Client does not create %ORACLE_HOME% or tnsnames.ora by default
Colin Pickard
Under Windows you have to look into the registry HKLM\Software\Oracle - you will find there the oracle home path, just be aware there could be more than one oracle homes, Oracle allows to install more than one version each in its own home.
ldsandon
A: 

I'm not a C# or a Windows guy for that matter so hopefully this helps. The tnsnames.ora file should be located in:

ORACLE_HOME\network\admin

If an alternate location has been specified, it should be available via the TNS_ADMIN registry key.

See this link for more information on how Oracle handles tns names on Windows.

RC
A: 
List<string> logicalDrives = Directory.GetLogicalDrives().ToList();
            List<string> result = new List<string>();
            foreach (string drive in logicalDrives)
            {
                Console.WriteLine("Searching " + drive);
                DriveInfo di = new DriveInfo(drive);
                if(di.IsReady)
                    result = Directory.GetFiles(drive, "tnsnames.ora", SearchOption.AllDirectories).ToList();
                if (0 < result.Count) return;
            }
            foreach (string file in result) { Console.WriteLine(result); }
GxG
This lists *every* copy of tnsnames.ora. It does not show which one is in use.
Colin Pickard
you didn't specify that...
GxG
Not my question, but you are right, it is not clear. In practice, determining which tnsnames.ora is in use is normally important, but I thought your answer was still a useful contribution, with the caveat I added, so I have given you an upvote to counter the downvote you recieved.
Colin Pickard
+5  A: 

Some years ago I had the same problem.
Back then I had to support Oracle 9 and 10 so the code only takes care of those versions, but maybe it saves you from some research. The idea is to:

  • search the registry to determine the oracle client version
  • try to find the ORACLE_HOME
  • finally get the tnsnames from HOME

public enum OracleVersion
{
    Oracle9,
    Oracle10,
    Oracle0
};

private OracleVersion GetOracleVersion()
{
    RegistryKey rgkLM = Registry.LocalMachine;
    RegistryKey rgkAllHome = rgkLM.OpenSubKey(@"SOFTWARE\ORACLE\ALL_HOMES");

    /* 
     * 10g Installationen don't have an ALL_HOMES key
     * Try to find HOME at SOFTWARE\ORACLE\
     * 10g homes start with KEY_
     */
    string[] okeys = rgkLM.OpenSubKey(@"SOFTWARE\ORACLE").GetSubKeyNames();
    foreach (string okey in okeys)
    {
        if (okey.StartsWith("KEY_"))
            return OracleVersion.Oracle10;
    }

    if (rgkAllHome != null)
    {
        string strLastHome = "";
        object objLastHome = rgkAllHome.GetValue("LAST_HOME");
        strLastHome = objLastHome.ToString();
        RegistryKey rgkActualHome = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\ORACLE\HOME" + strLastHome);
        string strOraHome = "";
        object objOraHome = rgkActualHome.GetValue("ORACLE_HOME");
        string strOracleHome = strOraHome = objOraHome.ToString();
        return OracleVersion.Oracle9;
    }
    return OracleVersion.Oracle0;
}

private string GetOracleHome()
{
    RegistryKey rgkLM = Registry.LocalMachine;
    RegistryKey rgkAllHome = rgkLM.OpenSubKey(@"SOFTWARE\ORACLE\ALL_HOMES");
    OracleVersion ov = this.GetOracleVersion();

    switch(ov)
    {
        case OracleVersion.Oracle10:
            {
                string[] okeys = rgkLM.OpenSubKey(@"SOFTWARE\ORACLE").GetSubKeyNames();
                foreach (string okey in okeys)
                {
                    if (okey.StartsWith("KEY_"))
                    {
                        return rgkLM.OpenSubKey(@"SOFTWARE\ORACLE\" + okey).GetValue("ORACLE_HOME") as string;
                    }
                }
                throw new Exception("No Oracle Home found");
            }
        case OracleVersion.Oracle9:
            {
                string strLastHome = "";
                object objLastHome = rgkAllHome.GetValue("LAST_HOME");
                strLastHome = objLastHome.ToString();
                RegistryKey rgkActualHome = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\ORACLE\HOME" + strLastHome);
                string strOraHome = "";
                object objOraHome = rgkActualHome.GetValue("ORACLE_HOME");
                string strOracleHome = strOraHome = objOraHome.ToString();
                return strOraHome;
            }
        default:
            {
                throw new Exception("No supported Oracle Installation found");
            }
    }
}

public string GetTNSNAMESORAFilePath()
{
    string strOracleHome = GetOracleHome();
    if (strOracleHome != "")
    {
        string strTNSNAMESORAFilePath = strOracleHome + @"\NETWORK\ADMIN\TNSNAMES.ORA";
        if (File.Exists(strTNSNAMESORAFilePath))
        {
            return strTNSNAMESORAFilePath;
        }
        else
        {
            strTNSNAMESORAFilePath = strOracleHome + @"\NET80\ADMIN\TNSNAMES.ORA";
            if (File.Exists(strTNSNAMESORAFilePath))
            {
                return strTNSNAMESORAFilePath;
            }
            else
            {
                throw new SystemException("Could not find tnsnames.ora");
            }
        }
    }
    else
    {
        throw new SystemException("Could not determine ORAHOME");
    }
}
weichsel
+1 looks like a reasonable place to start. Of course, catering for non-standard installations and the various resolving options as well as things like the Instant Client will probably give you grey hairs.
Colin Pickard
You should try and use the environment variables before the registry in GetOracleHome() though.
Colin Pickard
Thankfully I no longer have to play catch-up with Oracle anymore as someone else is maintaining this code now :) But checking the environment before querying the registry sounds good.
weichsel