Oracle NLS_LANG for language/territory/character set

Recently I had an Oracle problem at work.
I kept postponing to look with care at this problem till today.

Problem
All accented characters as à, á, é, í, ó, ú, â, ê, î, ô, û, ã, õ, etc and other ones as ç (cedilla), º, ª (ordinal indicators), were being replaced by erroneous characters as this example in the header of a stored procedure:

=================================================================
-- Revis¿o : 'N¡ã 0
-- Descri¿¿o: // description here
-- Data   : 03/29/2010
-- Autor  : CHEMTECH
=================================================================

This problem gets worse if you have something as

SELECT CONTRACT.NUM_CONTRACT,
           'N¡ã' || TO_CHAR(CONTRACT.NUM_CONTRACT) || ' - ' ||

The result of the above SQL query is used in the UI, that is, the user will see the wrong characters ¡ã instead of º. If you commit this thing in the repository you mess everything up. You see what I mean…

Questioning
At first I thought the problem was the database encoding settings.

I and only I was getting crazy characters. My development group has more 3 people and no one was having this problem. This clearly should be a UI configuration, that is, how the data is shown on my machine.

A little bit of research on the net took me to Oracle’s NLS_LANG FAQ.

This is what NLS_LANG stands for/does:

A locale is a set of information addressing linguistic and cultural requirements that corresponds to a given language and country. Traditionally, the data associated with a locale provides support for formatting and parsing of dates, times, numbers, and currencies, etc. Providing current and correct locale data has historically been the responsibility of each platform owner or vendor, leading to inconsistencies and errors in locale data.

Setting the NLS_LANG environment parameter is the simplest way to specify locale behavior for Oracle software. It sets the language and territory used by the client application and the database server. It also indicates the client's character set, which corresponds to the character set for data to be entered or displayed by a client program.

I started reading the FAQ (top bottom approach) and tried the following query:

SELECT * FROM NLS_SESSION_PARAMETERS;

which gave me this result:

NLS_SESSION_PARAMETERS on my development machine
Figure 1 - NLS_SESSION_PARAMETERS on my development machine

As you see NLS_LANGUAGE and NLS_TERRITORY are set to AMERICAN and AMERICA respectively on my machine.

I asked Thiago Arakaki a coworker of mine to execute the same SQL query on his dev box. To my surprise and delight this was the screen he got:

NLS_SESSION_PARAMETERS on Thiago's development machine
Figure 2 - NLS_SESSION_PARAMETERS on Thiago Arakaki’s development machine 

As you see NLS_LANGUAGE and NLS_TERRITORY are set to BRAZILIAN PORTUGUESE and BRAZIL respectively on his machine.

This clearly pointed what could be the cause of the problem I was having.

I couldn’t understand why my machine had a different NLS_LANGUAGE and NLS_TERRITORY.

I read the FAQ a little bit more and got to this part Where to set the NLS_LANG in Windows.

I checked Windows registry to make sure the NLS_LANG subkey was set correctly on Oracle home. I got this:

NLS_LANG subkey on Windows RegistryFigure 3 - NLS_LANG subkey on Windows Registry

For my surprise it was correct. Look at NLS_LANG. It has BRAZILIAN PORTUGUESE_BRAZIL.WE8MSWIN1252 just like Thiago Arakaki’s dev box.

So why do I still was getting wrong characters inside Allround Automations PL/SQL Developer when working on the same database that Thiago also uses? Aha, that’s the question this post tries to clarify if you come to get in this same situation.

Reading the FAQ a little bit more… :o) I saw that you could also set NLS_LANG as a System or User Environment Variable, in System properties. So I went there to check if I already had such a thingy set on my machine. Again for my surprise this thingy was there. I don’t remember if/when I created this variable.

The only thing I thought at the moment was the interference that some previous installations of Oracle could’ve caused on my machine. Today I’m using Oracle express but in the past I installed the full Oracle server. I can’t state for sure what created the NLS_LANG var on my Windows System variables.

The screen I got was something like this:

 NLS_LANG variable on Windows System variables
Figure 4 - NLS_LANG variable on Windows System variables

I had AMERICAN set for the NLS_LANG variable.

Solution
I then changed the system variable NLS_LANG to BRAZILIAN PORTUGUESE_BRAZIL.WE8MSWIN1252. Clicked OK. Closed PL/SQL. Opened PL/SQL and issued the SQL query described on the beginning of this post and could see that the NLS_LANGUAGE and NLS_TERRITORY rows had changed appropriately to BRAZILIAN PORTUGUESE and BRAZIL respectively. After that I started to get the right characters throughout the database.

Great! Problem solved.