Ed Stevens, DBA

February 27, 2011

tnsping – what it is, what it isn’t

Filed under: TNS — Ed Stevens @ 4:48 pm

Before continuing our exploration of various tns connection errors, let’s take a quick look at the oracle utility ‘tnsping’. We’ll see what it does, what it doesn’t do, and explode a few myths along the way.

The tnsping utility is used to determine if a service on an Oracle Net network can be reached. A complete description of its use is found in the Net Services Administrators Guide, located with the rest of the Oracle documentation at tahiti.oracle.com.  TNSPING serves, for sqlnet, much the same purpose as does ‘ping’ for the underlying network stack.

Let’s take a look at a simple case. Given this entry in my tnsnames.ora . . .

C:\>type C:\oracle\product\10.2.0\client_1\NETWORK\ADMIN\tnsnames.ora
# tnsnames.ora Network Configuration File: C:\oracle\product\10.2.0\client_1\net
work\admin\tnsnames.ora
# Generated by Oracle configuration tools.
#===========================
larry =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = vmlnx01)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = vlnxora1)
    )
  )


C:\>

. . . let’s run some tests.

C:\>tnsping larry

TNS Ping Utility for 32-bit Windows: Version 10.2.0.4.0 - Production on 27-FEB-2
011 16:21:22

Copyright (c) 1997,  2007, Oracle.  All rights reserved.

Used parameter files:
C:\oracle\product\10.2.0\client_1\network\admin\sqlnet.ora

Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)
(HOST = vmlnx01)(PORT = 1521))) (CONNECT_DATA = (SERVICE_NAME = vlnxora1)))
OK (20 msec)

And we think, “Aha!” I can connect! Well, maybe. Maybe not. I’ll get to that later. First, let’s look at what all we can learn from what we see here.

C:\>tnsping larry

TNS Ping Utility for 32-bit Windows: Version 10.2.0.4.0 - Production on 27-FEB-2
011 14:46:56

Copyright (c) 1997,  2007, Oracle.  All rights reserved.

Used parameter files:
C:\oracle\product\10.2.0\client_1\network\admin\sqlnet.ora

Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)
(HOST = vmlnx01)(PORT = 1521))) (CONNECT_DATA = (SERVICE_NAME = vlnxora1)))
OK (20 msec)

C:\>

The first thing we learn, from line 3, is that we are running Oracle client 10.2.0.4. Note that this is the version of the client, not the database. They do not have to be the same, and this tells us only about the client.

C:\>tnsping larry

TNS Ping Utility for 32-bit Windows: Version 10.2.0.4.0 - Production on 27-FEB-2
011 14:46:56

Copyright (c) 1997,  2007, Oracle.  All rights reserved.

Used parameter files:
C:\oracle\product\10.2.0\client_1\network\admin\sqlnet.ora

Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)
(HOST = vmlnx01)(PORT = 1521))) (CONNECT_DATA = (SERVICE_NAME = vlnxora1)))
OK (20 msec)

C:\>

From lines 8-9, we see that the network parameter file (sqlnet.ora) used by this client is at C:\oracle\product\10.2.0\client_1\network\admin. This is also a very strong indication that the tnsnames.ora file is also located in that directory.  However, there are other influences on the location of tnsnames.ora. See my post on that subject, here.

C:\>tnsping larry

TNS Ping Utility for 32-bit Windows: Version 10.2.0.4.0 - Production on 27-FEB-2
011 14:46:56

Copyright (c) 1997,  2007, Oracle.  All rights reserved.

Used parameter files:
C:\oracle\product\10.2.0\client_1\network\admin\sqlnet.ora

Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)
(HOST = vmlnx01)(PORT = 1521))) (CONNECT_DATA = (SERVICE_NAME = vlnxora1)))
OK (20 msec)

C:\>

From line 11, we see that we are using the TNSNAMES adapter to resolve the alias. (The alias was ‘vlnxora1′). This adapter was chosen based on the value of the NAMES.DIRECTORY_PATH parameter in the sqlnet.ora file.

C:\>tnsping larry

TNS Ping Utility for 32-bit Windows: Version 10.2.0.4.0 - Production on 27-FEB-2
011 14:46:56

Copyright (c) 1997,  2007, Oracle.  All rights reserved.

Used parameter files:
C:\oracle\product\10.2.0\client_1\network\admin\sqlnet.ora

Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)
(HOST = vmlnx01)(PORT = 1521))) (CONNECT_DATA = (SERVICE_NAME = vlnxora1)))
OK (20 msec)

C:\>

Lines 12 and 13 show us how sqlnet resolved the alias, or “connect identifier”, into a connect descriptor. We see that the request was routed using the tcp network protocol (PROTOCOL = TCP), to server vlmnx01 (HOST = vmlnx01), and placed at that server on port 1521. This information was gathered from the tnsnames.ora entry for ‘larry’, shown above.

And from line 14 we see that the response time was 20 milliseconds. Well, not quite. According to the Net Administrators Guide, tnsping “displays an estimate of the round trip time” (emphasis mine).

We also see that it requested a connection to (SERVICE_NAME = vlnxora1). Or did it? What does the listener show?

[oracle@vmlnx01 admin]$ lsnrctl status

LSNRCTL for Linux: Version 10.2.0.4.0 - Production on 27-FEB-2011 15:27:35

Copyright (c) 1991, 2007, Oracle.  All rights reserved.

Connecting to (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521))
STATUS of the LISTENER
------------------------
Alias                     LISTENER
Version                   TNSLSNR for Linux: Version 10.2.0.4.0 - Production
Start Date                27-FEB-2011 15:27:26
Uptime                    0 days 0 hr. 0 min. 9 sec
Trace Level               off
Security                  ON: Local OS Authentication
SNMP                      OFF
Listener Log File         /ora00/app/oracle/product/10.2.0/db_1/network/log/listener.log
Listening Endpoints Summary...
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=vmlnx01.vmdomain)(PORT=1521)))
The listener supports no services
The command completed successfully
[oracle@vmlnx01 admin]$

Hmm. Line 20 says “The listener supports no services”. How can this be? Wasn’t our tnsping successful? What does a real connection request do?

C:\>sqlplus scott/tiger@vlnxora1

SQL*Plus: Release 10.2.0.4.0 - Production on Sun Feb 27 15:32:18 2011

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.

ERROR:
ORA-12514: TNS:listener does not currently know of service requested in connect
descriptor

Of course the listener “does not currently know of service requested”. At the moment, the listener does not know of any services at all.  By the way, I made sure the listener did not know of any services. My listener relies on dynamic database registration, and I had stopped the database before starting this test.  Not only does the listener not know of any services, there is no database running at all.  I could just as easily specified SERVICE_NAME=FUBAR, or SERVICE_NAME=BTZLFLX and received the same result.

And if the listener is not running at all? Let’s stop the listener . . .

[oracle@vmlnx01 ~]$ lsnrctl stop

LSNRCTL for Linux: Version 10.2.0.4.0 - Production on 27-FEB-2011 15:40:41

Copyright (c) 1991, 2007, Oracle.  All rights reserved.

Connecting to (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521))
The command completed successfully

[oracle@vmlnx01 ~]$ lsnrctl status

LSNRCTL for Linux: Version 10.2.0.4.0 - Production on 27-FEB-2011 15:40:50

Copyright (c) 1991, 2007, Oracle.  All rights reserved.

Connecting to (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521))
TNS-12541: TNS:no listener
 TNS-12560: TNS:protocol adapter error
  TNS-00511: No listener
   Linux Error: 111: Connection refused
[oracle@vmlnx01 ~]$

. . .then test tnsping again

C:\>tnsping larry

TNS Ping Utility for 32-bit Windows: Version 10.2.0.4.0 - Production on 27-FEB-2
011 15:42:27

Copyright (c) 1997,  2007, Oracle.  All rights reserved.

Used parameter files:
C:\oracle\product\10.2.0\client_1\network\admin\sqlnet.ora

Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)
(HOST = vmlnx01)(PORT = 1521))) (CONNECT_DATA = (SERVICE_NAME = vlnxora1)))
TNS-12541: TNS:no listener

As we would expect, tnsping reports that there is no listener.

Conclusion

While tnsping is a very useful tool for diagnosing a variety of connection problems, we must be very clear about one important point:  it tells us absolutely nothing about the state of a database instance.  This is not a shortcoming of tnsping.  We just need to understand that it is a tool for diagnosing sqlnet issues, and sqlnet is not the database.

February 26, 2011

ora-12154/tns-03505

Filed under: TNS — Ed Stevens @ 8:03 pm

Continuing the discussion of “why can’t I connect to my database?”, I’d like to focus on one particular error – ora-12154. For this discussion and demonstration we will use Oracle’s sqlplus command processor as our client, but the principles apply to any client program that uses sqlnet to connect to the database.

There are actually several mechanisms for connecting to an Oracle database, but by far the most common is via the Oracle Call Interface (OCI), passing the connect request via Oracle’s Transparent Network Substrate (TNS), commonly referred to as “sqlnet”.

Hardly a day goes by that someone doesn’t post a problem on OTN, reporting they are getting an ora-12154 trying to connect to their database. And invariably they are sent on a wild goose chase, checking everything that can go wrong anywhere along the network stack. And yet, ora-12154 means one thing, and one thing only: The client side of sqlnet could not find the specified connect identifier. Period. And the official description of the error, returned by the Oracle utility “oerr” spells it out:

[oracle@vmlnx01 ~]$ oerr ora 12154
12154, 00000, "TNS:could not resolve the connect identifier specified"
// *Cause:  A connection to a database or other service was requested using
// a connect identifier, and the connect identifier specified could not
// be resolved into a connect descriptor using one of the naming methods
// configured. For example, if the type of connect identifier used was a
// net service name then the net service name could not be found in a
// naming method repository, or the repository could not be
// located or reached.

Or more succinctly: “A connection … was requested using a connect identifier (which) could not be resolved into a connect descriptor.” So what is the connect identifier? Let’s take the classic, textbook example of a simple client connection request:

c:> sqlplus scott/tiger@orcl

By the rules Oracle uses to parse the command line, the “@” symbol is used to mark the beginning of the connect identifier. So in this example, the connect identifier is “orcl”, and an ora-12154 means an entry for “orcl” could not be resolved to a “connect descriptor” – the IP address, port number, and service name necessary to properly route the request across the network to the Oracle listener. There are several methods available to make this name resolution, but by far the most common is the use of “local naming”  – the tnsnames.ora file. This file serves no other purpose, so you should have it fixed firmly in your mind that it is used only by the client process. The only reason this file exists on the database server is because the server can also run client processes.

With this preliminary information out of the way, let’s dig in and see how many ways we can create (and conversely, fix) an ora-12154. Let’s first look at a good configuration, then we’ll start taking it apart. My database is running on an Oracle Enterprise Linux server, while my client is running on my laptop, under Windows XP-Pro. My tnsnames.ora looks like this:

# tnsnames.ora Network Configuration File: C:\oracle\product\10.2.0\client_1\net
work\admin\tnsnames.ora
# Generated by Oracle configuration tools.
#===========================
mytestdb =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = vmlnx01)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = vlnxora1)
    )
  )

Make a connection to the database, just to show that everything is in order.

C:\>sqlplus scott/tiger@mytestdb

SQL*Plus: Release 10.2.0.4.0 - Production on Sat Feb 26 15:14:38 2011

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.

Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL>

Right out of the textbook! So what could go wrong, to generate an ora-12154?

Wrong naming method

The first thing sqlnet has to do is determine what naming method is being used – exactly how it is to resolve the connect identifier to an IP address, port, and service name. To do this, it looks in the file ‘sqlnet.ora’ (on the client machine, of course!) for the parameter NAMES.DIRECTORY_PATH. If we intend to use local naming, we must set this parameter appropriately:

NAMES.DIRECTORY_PATH= (TNSNAMES)

(Note: the string ‘TNSNAMES’ as a value for this parameter is not the name of the file.  It is the name of the method to be used for name resolution.  The name of the file used for this method is always tnsnames.ora.)

Let’s set it to some other value (albeit a valid one) . . .

C:\>type C:\oracle\product\10.2.0\client_1\NETWORK\ADMIN\sqlnet.ora
# sqlnet.ora Network Configuration File: C:\oracle\product\10.2.0\client_1\netwo
rk\admin\sqlnet.ora

SQLNET.AUTHENTICATION_SERVICES= (NTS)
NAMES.DIRECTORY_PATH= (LDAP)

. . . and observe the behavior

C:\>sqlplus scott/tiger@mytestdb

SQL*Plus: Release 10.2.0.4.0 - Production on Sat Feb 26 15:27:46 2011

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.

ERROR:
ora-12154: TNS:could not resolve the connect identifier specified

In this example, we told sqlnet to use LDAP naming services to resolve the connect identifier, but LDAP is not available in my test environment, thus it was not able to resolve “mytestdb”.  Lesson: If you want to use local naming, you must specify such in the SQLNET.AUTHENTICATION_SERVICES parameter in the client’s sqlnet.ora file. Let’s fix the problem, then move on:

C:\>type C:\oracle\product\10.2.0\client_1\NETWORK\ADMIN\sqlnet.ora
# sqlnet.ora Network Configuration File: C:\oracle\product\10.2.0\client_1\netwo
rk\admin\sqlnet.ora

SQLNET.AUTHENTICATION_SERVICES= (NTS)
NAMES.DIRECTORY_PATH= (TNSNAMES)

C:\>sqlplus scott/tiger@mytestdb

SQL*Plus: Release 10.2.0.4.0 - Production on Sat Feb 26 15:52:33 2011

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.

Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL>

Can’t locate tnsames.ora

The entire subject of locating tnsnames.ora was covered in “Help! I can’t connect to my database (part duex)“. For now, I will create the simplest means of not being able to locate the file – I’ll rename it to something else . . .

C:\>cd C:\oracle\product\10.2.0\client_1\NETWORK\ADMIN

C:\oracle\product\10.2.0\client_1\NETWORK\ADMIN>ren tnsnames.ora tnsnames.sav

C:\oracle\product\10.2.0\client_1\NETWORK\ADMIN>dir tnsnames.ora
 Volume in drive C has no label.
 Volume Serial Number is 04C2-AD70

 Directory of C:\oracle\product\10.2.0\client_1\NETWORK\ADMIN

File Not Found

C:\oracle\product\10.2.0\client_1\NETWORK\ADMIN>

. . . and observe the result:

C:\oracle\product\10.2.0\client_1\NETWORK\ADMIN>sqlplus scott/tiger@mytestdb

SQL*Plus: Release 10.2.0.4.0 - Production on Sat Feb 26 15:57:14 2011

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.

ERROR:
ora-12154: TNS:could not resolve the connect identifier specified

Of course, we fix it by providing a (valid) tnsnames.ora file:

C:\oracle\product\10.2.0\client_1\NETWORK\ADMIN>ren tnsnames.sav tnsnames.ora

C:\oracle\product\10.2.0\client_1\NETWORK\ADMIN>sqlplus scott/tiger@mytestdb

SQL*Plus: Release 10.2.0.4.0 - Production on Sat Feb 26 15:58:37 2011

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.

Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL>

Can’t find connect descriptor in tnsnames.ora

We’ve told sqlnet to use tnsnames, and we’ve made sure sqlnet can find tnsnames.ora. But what if the connect identifier we provide cannot be found in the tnsnames.ora? And more importantly, what can cause it to not be found?

Of course, the simplest reason would be that we just gave it the wrong string. In our example file (shown above), we had a single entry, with the connect identifier of ‘mytestdb’. If we provide a different connect identifier it will, of course fail – again with ora-12154:

C:\>sqlplus scott/tiger@fubar

SQL*Plus: Release 10.2.0.4.0 - Production on Sat Feb 26 16:05:48 2011

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.

ERROR:
ora-12154: TNS:could not resolve the connect identifier specified

But there is another factor that comes into play at this point. There is an optional parameter that can be set in sqlnet.ora that we have not yet discussed. Before looking in tnsnames.ora, sqlnet will check to see if the parameter NAMES.DEFAULT_DOMAIN has been set. If it has, it’s value will be appended to the connect descriptor supplied by the user – before searching tnsames.ora for the result. Let’s add that parameter to our existing sqlnet.ora . . .

C:\>type C:\oracle\product\10.2.0\client_1\NETWORK\ADMIN\sqlnet.ora
# sqlnet.ora Network Configuration File: C:\oracle\product\10.2.0\client_1\netwo
rk\admin\sqlnet.ora

SQLNET.AUTHENTICATION_SERVICES= (NTS)
NAMES.DIRECTORY_PATH= (TNSNAMES)
NAMES.DEFAULT_DOMAIN=acme.com

. . . and observe the result

C:\>sqlplus scott/tiger@mytestdb

SQL*Plus: Release 10.2.0.4.0 - Production on Sat Feb 26 16:13:42 2011

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.

ERROR:
ora-12154: TNS:could not resolve the connect identifier specified

There are two ways to fix this error. Obviously, we can revert back to our previous configuration by removing the NAMES.DEFAULT_DOMAIN parameter from sqlnet.ora. The other would be to add the domain name to the entry in tnsnames.ora.

C:\>type C:\oracle\product\10.2.0\client_1\NETWORK\ADMIN\tnsnames.ora
# tnsnames.ora Network Configuration File: C:\oracle\product\10.2.0\client_1\net
work\admin\tnsnames.ora
#===========================
mytestdb.acme.com =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = vmlnx01)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = vlnxora1)
    )
  )

C:\>sqlplus scott/tiger@mytestdb

SQL*Plus: Release 10.2.0.4.0 - Production on Sat Feb 26 16:30:57 2011

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.

Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL>

tns-03505

That pretty well covers every means of creating an ora-12154 when using local naming. What about the tns-03505 error? Actually, tns-3505 is exactly the same error as ora-12154, with all the same causes and resolutions. The only difference I’ve been able to discover is that tns-03505 is produced when using the ‘tnsping’ utility. Why Oracle chose to code tnsping this way I don’t know, and I’ve been unable to find definitive documentation on this difference but my own testing bears it out.

Using sqlplus . . .

C:\>sqlplus scott/tiger@fubar

SQL*Plus: Release 10.2.0.4.0 - Production on Sat Feb 26 16:44:33 2011

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.

ERROR:
ora-12154: TNS:could not resolve the connect identifier specified

Enter user-name:

And using tnsping . . .

C:\>tnsping fubar

TNS Ping Utility for 32-bit Windows: Version 10.2.0.4.0 - Production on 26-FEB-2
011 16:44:42

Copyright (c) 1997,  2007, Oracle.  All rights reserved.

Used parameter files:
C:\oracle\product\10.2.0\client_1\network\admin\sqlnet.ora

tns-03505: Failed to resolve name

C:\>

(Thanks to Sybrand Bakker for pointing out this distinction).

I will discuss ‘tnsping’, it’s use, what it does and does not do, in another post.

This’n'that

There is one often overlooked ‘gotcha’ in all this. Remember that when sqlnet is parsing out the connect string, it uses the ‘@’ sign as a meta-character to mark the beginning of the connect descriptor. So if we have this:

c:>sqlplus scott/tiger@orcl

everything is just fine. But suppose there is an ‘@’ sign someplace unexpected. What happens if someone constructs a complex password that includes it?

c:> sqlplus scott/P@ssW0rd@orcl

In this case, sqlnet will take the ‘P’ as the password, and take ‘ssW0rd@orcl’ as the connect descriptor.  By now, you can guess the result.

Conclusion

In this post I have attempted to demonstrate every possible cause of an ora-12154 error, as relates to use of tnsnames.ora, for address resolution of a connect descriptor. There is one overriding factor here that should be obvious from the very description of the error, regardless of the naming method used: ora-12154 is a client side problem. It has absolutely nothing to do with anything on the server. It has nothing to do with the listener; it has nothing to do with the database. If you are faced with a ora-12154, you can monkey around with your database and/or listener “until the cows come home” and you will not solve your problem.

Stay tuned for more discussion of sqlnet connection  problems.

February 16, 2011

Help! I can’t connect to my database (part duex)

Filed under: TNS — Ed Stevens @ 1:31 pm

Basic Client TNS (sqlnet) configuration

Continuing the discussion of “Why can’t I connect to my database?”, I want to dig deeper into each of the potential errors in order of their possible occurrence. That will be a rather lengthy journey, so I want to start with the configuration of TNS on the client side of the connection. Since the vast majority of connection problems are presented by people using Windows as the client, all examples here will be from a Windows perspective. What a shame! Unix is actually much simpler …

Before plunging into the details of connecting to a database, we need to know the key configuration files used by TNS on the client, and how to locate them – or more accurately, how TNS locates them!  There are two of these files, named “sqlnet.ora” and “tnsnames.ora”. Technically, sqlnet.ora is not required, because every essential parameter it can contain has a default value.  So sqlnet.ora may not even exist on your system, but I consider it best practice to create it with key information – even if it is default values – just to remove any ambiguity when troubleshooting a problem. Full documentation of every parameter in sqlnet.ora can be found in the Net Services Reference, found with the rest of the Oracle documentation set at tahiti.oracle.com.  One would also be well advised to spend some time in the Net Services Administrator’s Guide, paying attention to how the sqlnet architecture relates to the standard network OSI stack.

Of course, the TNS software needs to know how to locate these files, and has two methods of doing so. The first is to look in the default location, which is %ORACLE_HOME%\network\admin.  So if you have

ORACLE_HOME=C:\oracle\product\10.2.0\client_1

your sqlnet config files will be located in C:\oracle\product\10.2.0\client_1\network\admin.  If you have performed multiple installations of Oracle, you have probably created multiple ORACLE_HOME directories and so would have multiple copies of the sqlnet config files – one for each ORACLE_HOME.

This default location of ORACLE_HOME\network\admin can be overridden by use of the environment variable TNS_ADMIN. For example, if you have

TNS_ADMIN=c:\oranet

TNS will try to find the configuration files in c:\oranet.  Only if they are not found there will it look in the default location.

So how does TNS even determine the value of ORACLE_HOME and/or TNS_ADMIN?  In a proper operating system (any *nix system) it would simply check the environment variables assigned to that process.  But since we’re dealing here with Windows, we also have to check the registry.  So let’s look at some examples to see the effect of various settings. We can check the result by using the Oracle utility ‘tnsping’.  I won’t go into the details of tnsping here.  Suffice it to say that one of the things it does (almost as an aside) is report where it found sqlnet.ora.  It also shows the address information it got from tnsnames.ora.  We can use those two bits of information to see exactly which copy of a file it is using.

Here’s the setup.  I have a laptop running Windows XP-Pro.  On it I have installed a standard Oracle 10.2 client, with ORACLE_HOME established at C:\oracle\product\10.2.0\client_1.  This is my working client setup that I use every day at the office.  For this demo, I’m going to simulate a second ORACLE_HOME by creating C:\oracle\product\10.2.0\client_2\network\, and two directories outside of ORACLE_HOME, c:\oranet\admin_3 and c:\oranet\admin_4.

First, let’s look at my current setup.  Checking the registry (HKLM\software\oracle) we see that ORACLE_HOME is set to c:\oracle\product\10.2\client_1

And checking the environment at the command line, we see there is NOT a setting for ORACLE_HOME, leaving the registry as the only influencing factor.

C:\> echo %ORACLE_HOME%
%ORACLE_HOME%

Now, let’s see what tnsping says about where it finds the config files:

C:\>tnsping vlnxora1

TNS Ping Utility for 32-bit Windows: Version 10.2.0.4.0 - Production on 15-FEB-2
011 18:27:09

Copyright (c) 1997,  2007, Oracle.  All rights reserved.

Used parameter files:
C:\oracle\product\10.2.0\client_1\network\admin\sqlnet.ora

Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)
(HOST = vmlnx01)(PORT = 1521))) (CONNECT_DATA = (SERVICE_NAME = vlnxora1)))
OK (40 msec)

C:\>

The key thing to observe here is the lines

Used parameter files:
C:\oracle\product\10.2.0\client_1\network\admin\sqlnet.ora

This tells us which sqlnet.ora file was found and used.  We see that in this case, TNS was looking for its configuration files exactly where we expected – %ORACLE_HOME%\network\admin.  Also notice in line 13, “SERVICE_NAME =  vlnxora1″.  In my setup, that service name is unique to the tnsnames file at that location.  So we can know that both the sqlnet.ora and tnsnames.ora files were located at the same place.

Now let’s try some overrides.  We’ll set ORACLE_HOME as an environment variable at the command prompt and try it:

C:\>set ORACLE_HOME=C:\oracle\product\10.2.0\client_2

C:\>echo %ORACLE_HOME%
C:\oracle\product\10.2.0\client_2

C:\>tnsping vlnxora1

TNS Ping Utility for 32-bit Windows: Version 10.2.0.4.0 - Production on 16-FEB-2
011 10:40:52

Copyright (c) 1997,  2007, Oracle.  All rights reserved.

Used parameter files:
C:\oracle\product\10.2.0\client_2\network\admin\sqlnet.ora

Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)
(HOST = vmlnx01)(PORT = 1521))) (CONNECT_DATA = (SERVICE_NAME = vlnxora2)))
TNS-12557: TNS:protocol adapter not loadable

C:\>

Now we see that ORACLE_HOME in the registry (client_1) was overridden by the value in the environment – client_2.  Don’t worry about the TNS-12557 error.  That is a result of the  fact that ORACLE_HOME now points to a directory that has no binaries — remember I just set it up as a test for locating sqlnet.ora and tnsnames.ora.  It is not a fully functional ORACLE_HOME.

TNS_ADMIN

Next let’s introduce the TNS_ADMIN variable.  Just like ORACLE_HOME, it can be set in the registry, or in the command processor environment.  For our next test, we’ll use the registry.  Here I’ve added TNS_ADMIN to HKLM\software\oracle

Testing again:

C:\>tnsping vlnxora1

TNS Ping Utility for 32-bit Windows: Version 10.2.0.4.0 - Production on 16-FEB-
011 10:53:31

Copyright (c) 1997,  2007, Oracle.  All rights reserved.

Used parameter files:
c:\oranet\admin_3\sqlnet.ora

Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP
(HOST = vmlnx01)(PORT = 1521))) (CONNECT_DATA = (SERVICE_NAME = vlnxora3)))
TNS-12557: TNS:protocol adapter not loadable

C:\>

We see that the setting of TNS_ADMIN in the registry overrides ORACLE_HOME in both the registry and the command processor environment.

As one last test, we will add TNS_ADMIN to the command processor environment. This is on top of all of our previous settings:

C:\>set TNS_ADMIN=C:\oranet\admin_4

C:\>echo %TNS_ADMIN%
C:\oranet\admin_4

C:\>tnsping vlnxora1

TNS Ping Utility for 32-bit Windows: Version 10.2.0.4.0 - Production on 16-FEB-2
011 10:57:12

Copyright (c) 1997,  2007, Oracle.  All rights reserved.

Used parameter files:
C:\oranet\admin_4\sqlnet.ora

Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)
(HOST = vmlnx01)(PORT = 1521))) (CONNECT_DATA = (SERVICE_NAME = vlnxora4)))
TNS-12557: TNS:protocol adapter not loadable

C:\>

And we see that once again the environment setting overrides the registry, and TNS_ADMIN overrides ORACLE_HOME.

Conclusion

The above demonstrations reveal the various settings that control how TNS locates its configuration file (sqlnet.ora) and name resolution file (tnsnames.ora) on a Windows client.  It should also be noted that the same rules apply in a *nix environment, except that there is no registry; in a unix environment, all of the settings are controlled by the environment variables.  So unix will have far fewer variables to consider when trying to troubleshoot a connection problem.

I started to do some further testing to see how TNS would handle a situation where one of the files was not in the preferred location.   Needless to say, with two files to be located, two variables to indicate the location (ORACLE_HOME and TNS_ADMIN) and two places those variables could be defined (registry and session environment), the possible combinations explode geometrically.   Life is too short.

This still leaves the question of whether or not to introduce the TNS_ADMIN setting.  The answer, like most everything is …. “it depends”.  If you have a simple client installation with a single ORACLE_HOME, there is no reason to set TNS_ADMIN.  However, if you have multiple client products, each with its own ORACLE_HOME (say, you install the base client, then install SQL Devloper) you are faced with maintaining two separate tnsnames files.  There are various ways to approach this problem, but the simplest is to simply pick one, and set TNS_ADMIN to point to it.  As I demonstrated above, if using TNS_ADMIN, the files don’t even have to be in any ORACLE_HOME directory.  I’d even argue that this is preferable, as it makes it very clear to anyone examining the system that there is no implied linkage between your TNS config files and any particular ORACLE_HOME.

Next up:  ora-12154 and tns-03505

Film at eleven.

February 9, 2011

Help! I can’t connect to my database …

Filed under: TNS — Ed Stevens @ 5:05 pm

Some of the most frequently asked questions on OTN deal with problems trying to connect to the database.  Tracing the problem isn’t rocket science, but I often see people not paying attention to (or not trusting) specific error messages and riding off in all directions at once.  A computers will always do exactly what it is told.  The problem comes in that we often don’t really know everything we’re telling it.  So let me try to explain a little about how Oracle handles a request to “connect me to my database” and actually locates a database running on a machine on the other side of the planet (or even on the very machine from which the request originated!)

Before digging in, let’s talk about a very simple concept that an amazing number of people struggle with.  For purposes of the current discussion there are two “entities”, or processes, involved.  First there is the server process.  Depending on one’s semantic precision and the context in which the term is used, the “server” could refer to the database, the database instance, the database server process, or the physical computer on which any of these execute.  In terms of network routing it all comes back to a specific box with a specific IP address.  The second process is the client process.  That is the process that is requesting the connection to (and services from) the database.  Again, depending on one’s semantic precision and context, the term “client” could refer to a process or a physical computer, but for our purposes it means the process.  And this process could be running on any computer, including (understand this) the same computer that is acting as the server.  In this case, it is still a client and the fact that it is running on the server computer is totally coincidental and irrelevant.

So let’s say you are using sqlplus.  You issue this statement to start it and connect to your database:

C:> sqlplus scott/tiger@larry

Of course, the first thing that will happen really has nothing to do with Oracle.  First, the OS must locate an executable called ‘sqlplus’, load it, and pass it the rest of the command line (scott/tiger@larry) do with as it sees fit.  And what sqlplus sees fit is to ask TNS to make a connection to “larry”, using the userid ”scott” and the password “tiger” as its authentication credentials.  So TNS has to figure out what is meant by “larry”.  By default it will do this by looking in a file called tnsnames.ora.  Since we are still at the client making the request, this file must be found on the client machine.  By default it will be found in $ORACLE_HOME/network/admin.

Let’s make it easy and suppose our tnsnames file has this entry:

larry =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = myhost)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = curley)
)
)

TNS will look in your tnsnames.ora for an entry called ‘larry’. Finding it, a request is sent through the normal OS network stack to (PORT = 1521) on (HOST = myhost) using (PROTOCOL = TCP), asking for a connection to (SERVICE_NAME = curley).  Notice where it got this information from the entry in the tnsnames file.  (This entry is known as the “connect identifier”.) Also notice that what is going on here is the resolution of an alias (“larry”) to an actual destination.  In this respect the tnsnames.ora file serves the same purpose for sqlnet as the OS’s “hosts” file serves for the standard network stack.

Where is (HOST = myhost) on the network?  When the request gets passed from TNS to the standard network stack, the name ‘myhost’ will get resolved to an IP address, either via a local ‘hosts’ file, via DNS, or possibly other less used mechanisms.  You can also hard-code the ip address (HOST = 123.456.789.101) in the tnsnames.ora.

Once the ip address is determined, the standard networking process delivers the message to the designated port (PORT = 1521) on the designated host/ip address. Hopefully, there is an Oracle database listener on “myhost” configured to listen on the specified port, and that listener knows about SERVICE_NAME = curley. If so, the listener will spawn a server process to act as the intermediary between your client and the database instance. Communication to that server process will be on a different port, selected by the listener.  At that point the listener is out of the process and continues to await other connection requests coming in on its configured port.

What can go wrong?

First, there may not be an entry for ‘larry’ in your tnsnames.  In that case you get “ORA-12154: TNS:could not resolve the connect identifier specified”.  I’ll expand on the various reasons “larry” may not have been found at a later date, but make no mistake, if you receive a ORA-12154, it is an absolute certainty your request never got past this point.  You are wasting your time trying to solve this by looking at your listener.  If you can’t place a telephone call because you don’t know the number (can’t find your telephone directory – aka “tnsnames.ora” – or can’t find the party you are looking for listed in it – no entry for larry) you don’t look for problems at the telephone switchboard.

Maybe the entry for “larry” was found, but “myhost” couldn’t be resolved to an IP address (say there was no entry for “myhost” in the local hosts file).  This will result in “ORA-12545: Connect failed because target host or object does not exist”

Maybe there was an entry for “myserver” in the local hosts file, but it specified a bad IP address.  This will result in “ORA-12545: Connect failed because target host or object does not exist”

Maybe the IP was good, but there is no listener running:  “ORA-12541: TNS:no listener”

Maybe the IP was good, there is a listener at myhost, but it is listening on a different port. “ORA-12560: TNS:protocol adapter error”

Maybe the IP was good, there is a listener at myhost, it is listening on the specified port, but doesn’t know about SERVICE_NAME = curley.  “ORA-12514: TNS:listener does not currently know of service requested in connect descriptor”

Ok, that is how we get *from* the client connection request *to* the listener.  What about the listener’s part of all this?

The listener is very simple.  It runs on the server (not the client) and it’s job is to listen for connection requests and make the connection (server process) between the client and the database instance.  Once that connection is made, the listener is out of the picture. If you were to kill the listener, all existing connections would continue.

The listener is configured with the listener.ora file, but if that file doesn’t exist, the listener is quite capable of starting up with all default values.  One common mistake with the listener configuration is to specify “HOST=localhost” or “HOST=127.0.01″.  This is a NONROUTABLE ip address.  LOCALHOST and ip address 127.0.0.1 always mean “this machine on which I am sitting”.  So, *all* computers are known as “localhost” or “127.0.0.1″.  If you specify this address in your listener configuration, the listener will only be capable of receiving requests from the machine on which it is running.  If you specified that address in your tnsnames file, the request would be routed to the machine on which the requesting client resides.  Probably not what you want.

From here I have a few ideas for future posts, each focusing on potential complications at each step of the process.  Another post will use actual examples to deconstruct (break) a working TNS connection request, to demonstrate and prove the various factors.

“Film at eleven”.

Hello world!

Filed under: Uncategorized — Ed Stevens @ 1:29 am

You may be asking, “Why yet another Oracle blog?”  To be honest, I’m still asking myself that question.  But, I’ve had several people who’ve seen my comments on OTN urge me to start a blog to collect all that “wisdom”  (!?!?) into one place.  So . . . why not?

I’ll try to post about once a week, mostly demonstration and explanation of things that seem to get a lot of questions but also an occasional opinion piece (aka “rant”) about IT and the people in it.  My closest and oldest friend says I’ve been a curmudgeon all my life, so I guess you can expect a curmudgeon’s viewpoint.

So standby.  As they used to say as a teaser to the evening news, “Film at eleven.”

Theme: Rubric. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.