Sunday 15 May 2011

Creating a backup for Oracle database

I decided to write a simple script to backup the database while it is still running

This mean that I need to backup:

  • control files
  • datafiles
  • logfiles
  • startup files (spfile)
Note!! Before you execute this script make sure that your database is in Archive mode

First of all lets create a directories for the files

echo "Created By Michael Shapira"
rm files.txt
1> /dev/null 2> /dev/null
mkdir datafiles
mkdir contfiles
mkdir logfiles
mkdir startupfiles

”files.txt” will hold the commands to be executed 

echo "cp $ORACLE_HOME/dbs/spfileorcl2.ora startupfiles" >> files.txt

copy spfile to startup directory


set serveroutput on
spool files.txt

select 'cp ' || name || ' contfiles'
from v $controlfile /
SELECT 'cp ' || member || ' logfiles'
FROM V $LOGFILE / DECLARE cursor c_tablespace is
select tablespace_name name
FROM dba_tablespaces
where contents <> 'TEMPORARY';


cursor c_tableFiles(p_space_name VARCHAR2) is(
select file_name, tablespace_name
from dba_data_files
where tablespace_name = p_space_name);
BEGIN
dbms_output.put_line(
'sqlplus "/as sysdba" << EOF');
for r_names in c_tablespace loop
begin
dbms_output.put_line(
'alter tablespace ' || r_names.name ||
' begin backup;');
for r in c_tableFiles(r_names.name) loop
dbms_output.put_line(
'! cp ' || r.file_name || ' datafiles');
end loop;
dbms_output.put_line(
'alter tablespace ' || r_names.name ||
' end backup;');
exception
when OTHERS then
null;
end;
end loop;
dbms_output.put_line(
'exit');
dbms_output.put_line(
'/');
dbms_output.put_line(
'EOF');
end;
/
spool
off
exit

Spool copy command of control and logfiles to “files.txt”. Next loop existing tablespaces (but not temporary ) alter them to begin backup. Copy relevant datafile to datafiles directory and stop backup on this tablespace


FILE=files.txtcat $FILE | grep -v '^[ ]*\\n\\'  > $FILE.tmpcat $FILE.tmp | sed -e 's/^[ \t]*//' | sed '/^$/d' > $FILE. $FILE

remove empty lines and align all code to the left in the files.txt. Execute set of commands in “files.txt”. This will actually do all work


jar -Mcvf db_backup.zip contfiles logfiles startupfiles datafilesrm -rf  $FILE* contfiles logfiles startupfiles datafiles

zip all directories and delete temporary files


That is all. Attached complete source and example of files.txt


 


files.txt (1.28 kb)


backup_db.sh (1.71 kb)

Problem looping files under UNIX

I was writing some script under korn shell which suppose to loop X directory and search for the files with “prog” extension. The script is very simple

for file in "*.prog"
do
   echo $file
done;

 


Just to clarify, where was no prog files in this directory while I executed it!!! But, the result of the script was


*prog


I was shocked!!. I tried to execute the same script under “bash" and result were the same. For some reason UNIX was thinking that I do have “prog” file in my directory, but I didn’t. Finally I found how to do it safely. Use the following piece of code





for file in `ls *.prog 2> /dev/null`
do  
   echo $file
done;

This one worked just fine.


If any one knows what is the reason for this strange behavior , please comment it

Creating "Value Set" for the framework Documents - Oracle Application

Ok. So here is the task. I need to create a "Value Set" of Framework documents. So far so good, bacause I have a nice package called jdr_utils with a nice function "listDocuments".

But the problem is that procedure outputs the results into dbms_output.put_line and "Value Set" can be based on  table or view only.

So what do I need to do. Read the output of dmbs_output, and insert it into some table or view

Step 1: Reading from dbms_output.

Well, reading from  dbms_output in not so tricky, bacause we have a function called dbms_output.get_lines. Here is the code:

declare
l_outtab dbms_output.chararr;
l_fetchln
INTEGER := 90000;
begin
jdr_utils.listDocuments(p_document_prefix, true);
dbms_output.get_lines(l_outtab, l_fetchln);
end;

using this code l_outtab array holds all output lines and l_fetchln holds the number of fetched lines


 


Step 2: Creating view


Now we need to build a view, which holds lines from  l_fetchln array. For this, we will use pipelined function.


First we need to create the types for our pipelines function


create or replace type XXPCK_JDR_DOCUMENTS_ITEM as object
(
document
varchar2(400)
)
/
create or replace type JDR_OEF_DOCUMENTS_TAB
as table of JDR_OEF_DOCUMENTS_ITEM


now lets modify the the script above to loop over result array and pipe each row


create or replace function Get_Oef_Documents(p_document_prefix varchar2) return JDR_OEF_DOCUMENTS_TAB pipelined is
l_outtab dbms_output.chararr;
l_fetchln
INTEGER := 90000;
begin
jdr_utils.listDocuments(p_document_prefix,true);
dbms_output.get_lines(l_outtab, l_fetchln);
--read from standart output
FOR i IN 2 .. l_fetchln LOOP
pipe row (JDR_OEF_DOCUMENTS_ITEM(document => l_outtab(i)));
END LOOP;
return;
end Get_Oef_Documents;


However, according to the company policy, it if forbidden to compile functions and procedurs in the apps schema. No problem!!!. We will compile it under JDR schema. The following Metalink note holds


the list of all grants and synonyms that we need to create in order to use jdr_utils in non apps schema Note:399780.1.


The only thing that should be done after this, is giving grants on our function to apps and create a synonym




  • grant all on get_oef_documents to apps


  • create synonym app.get_oef_documents for jdr.get_oef_documents

Finally we can create a view in the apps schema


create or replace view jdr_oef_documents as
select document
from table(Get_Oef_Documents('/')).

That is all. Now we can use this view as a source for our "Value Set" inside Oracle Application

Invoiking Web-Services with pure PL/SQL and building LOV from the result

Recently I had to find a way to build a LOV for all issues inside Serena's Mashup system.

I found that Serena have a Web-Service interface. I downloaded it and was able to extract the exact SOAP envelop that I need to send to Mashup

Here is the full code:

create function Build_Mashup_Lov return XX_MASHUP_USSUES_TAB pipelined is
      l_mashup_host     varchar2(200);
      l_mashup_user     varchar2(200);
      l_mashup_pass     varchar2(200);
      l_mashup_table    varchar2(200); --points to the mashup table id
      soap_request      varchar2(30000);
      soap_respond      varchar2(32767);
      http_req          utl_http.req;
      http_resp         utl_http.resp;
      l_clob            CLOB;
      resp              XMLType;
      i                 integer;
      /*-----
      * This cursor returns a VARRAY of XMLTypes or XMLSequenceType
      * given a base XMLType and an XPath search string.
      -------*/
      CURSOR crsrNodeList(cv_doc XMLType,
                          cv_path VARCHAR2) IS
                          SELECT    XMLSequence(extract(cv_doc, cv_path)) XML
                           FROM dual;
      /* XMLSequenceType Object the will contain an array of XMLType Objects */
      nodeList XMLSequenceType;
   begin
      --get mashup host url
      select profile_option_value
      into   l_mashup_host
      from   fnd_profile_options_vl v, 
             FND_PROFILE_OPTION_VALUES t
      where  v.profile_option_name='XXPCK_CCS_HOST'
      and    v.profile_option_id = t.profile_option_id
      and    level_id=10001;
     
     
      select profile_option_value
      into   l_mashup_table
      from   fnd_profile_options_vl v, 
             FND_PROFILE_OPTION_VALUES t
      where  v.profile_option_name='XXPCK_CCS_TABLE'
      and    v.profile_option_id = t.profile_option_id and  level_id=10001;
    
      select profile_option_value
      into   l_mashup_pass
      from   fnd_profile_options_vl v, 
             FND_PROFILE_OPTION_VALUES t
       where v.profile_option_name='XXPCK_CCS_PASS'
       and   v.profile_option_id = t.profile_option_id
        and  level_id=10001;
       
      select profile_option_value
      into   l_mashup_user
      from   fnd_profile_options_vl v, 
             FND_PROFILE_OPTION_VALUES t
       where v.profile_option_name='XXPCK_CCS_USER_NAME'
       and   v.profile_option_id = t.profile_option_id
       and   level_id=10001;
      
      soap_request:= '<?xml version = "1.0" encoding = "UTF-8"?>
                      <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:aewebservices70">
                       <soapenv:Header/>
                       <soapenv:Body>
                          <urn:GetItemsByQuery>
                             <!--Optional:-->
                             <urn:auth>
                                <!--Optional:-->
                                <urn:userId>'||l_mashup_user||'</urn:userId>
                                <!--Optional:-->
                                <urn:password>'||l_mashup_pass||'</urn:password>
                                <!--Optional:-->
                                <urn:hostname>'||l_mashup_host||'</urn:hostname>
                             </urn:auth>
                             <urn:tableID>'||l_mashup_table||'</urn:tableID>
                                   </urn:GetItemsByQuery>
                       </soapenv:Body>
                      </soapenv:Envelope>
                             ';
       DBMS_LOB.createtemporary(l_clob, FALSE);
     
       http_req:= utl_http.begin_request
                  ( l_mashup_host
                  , 'POST'
                  , 'HTTP/1.1'
                  );
        utl_http.set_header(http_req, 'Content-Type', 'text/xml'); -- since we are dealing with plain text in XML documents
        utl_http.set_header(http_req, 'Content-Length', length(soap_request));
        utl_http.set_header(http_req, 'SOAPAction', ''); -- required to specify this is a SOAP communication
        utl_http.write_text(http_req, soap_request);
        http_resp:= utl_http.get_response(http_req);
        BEGIN
          LOOP
            UTL_HTTP.read_text(http_resp, soap_respond, 32767);
            --strip namespace
            soap_respond:=replace(replace(soap_respond,'SOAP-ENV:',''),'ae:','');
            soap_respond:=replace(soap_respond,'xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"','');
            DBMS_LOB.writeappend (l_clob, LENGTH(soap_respond), soap_respond);
           
           
           
          END LOOP;
            utl_http.end_response(http_resp);
            --read CLOB to XML
            resp := sys.xmltype.createXML(l_clob);
     
        EXCEPTION
          WHEN UTL_HTTP.end_of_body THEN
            begin
             --read CLOB to XML
             resp := sys.xmltype.createXML(l_clob);
            OPEN crsrNodeList(resp, '/Envelope/Body/GetItemsByQueryResponse/return');
               FETCH crsrNodeList
               INTO nodeList;
            CLOSE crsrNodeList;
           --loop nodelist
           FOR x IN 1 .. nodeList.count() LOOP
             pipe row (XX_MASHUP_USSUE_ITEM(issue_title  => nodelist(x).extract('return/title/text()').getStringVal(),
                                            issue_number => nodelist(x).extract('return/genericItem/itemName/text()').getStringVal(),
                                            issue_id     => nodelist(x).extract('return/genericItem/itemID/text()').getStringVal()));
             
           END LOOP;
            UTL_HTTP.end_response(http_resp);
            DBMS_LOB.freetemporary(l_clob);
           
            return;
           
            exception
               when others then
                  UTL_HTTP.end_response(http_resp);
                  DBMS_LOB.freetemporary(l_clob);
            end;
        END; -- end read respond text
       
    EXCEPTION
    WHEN utl_http.end_of_body THEN
      utl_http.end_response(http_resp);
   end  Build_Mashup_Lov;

Lets examine it .

First of all I am extracting credentials values and Web-Service URL from profiles. After this, building SOAP XML

DBMS_LOB.createtemporary(l_clob, FALSE);

Creating temporary CLOB object , that will hold the response from the server

http_req:= utl_http.begin_request
                  ( l_mashup_host
                  , 'POST'
                  , 'HTTP/1.1'
                  );
        utl_http.set_header(http_req, 'Content-Type', 'text/xml'); -- since we are dealing with plain text in XML documents
        utl_http.set_header(http_req, 'Content-Length', length(soap_request));
        utl_http.set_header(http_req, 'SOAPAction', ''); -- required to specify this is a SOAP communication
        utl_http.write_text(http_req, soap_request);
        http_resp:= utl_http.get_response(http_req);

Create URL request with proper Context and get the response. We cannot read the response entierly to the CLOB, so we need to loop

the response and read each time the maximun amount of textual data. We are not interested in the namespace, so lets strip it. Append

textual data to the CLOB object

LOOP
            UTL_HTTP.read_text(http_resp, soap_respond, 32767);
            --strip namespace
            soap_respond:=replace(replace(soap_respond,'SOAP-ENV:',''),'ae:','');
            soap_respond:=replace(soap_respond,'xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"','');
            DBMS_LOB.writeappend (l_clob, LENGTH(soap_respond), soap_respond);
END LOOP;

Create XML object from CLOB. We need it , since the response is also in the XML format and we can use build in XML engine inside PL/SQL

to extract required data

resp := sys.xmltype.createXML(l_clob);

We will use XPATH expression to extract data we need from specific elements

OPEN crsrNodeList(resp, '/Envelope/Body/GetItemsByQueryResponse/return');
   FETCH crsrNodeList   INTO nodeList;
CLOSE crsrNodeList;

All we need to do now is to loop "nodelist" object and use pipe to return it as table 

FOR x IN 1 .. nodeList.count() LOOP
  pipe row (XX_MASHUP_USSUE_ITEM(issue_title  => nodelist(x).extract('return/title/text()').getStringVal(),
                                                      issue_number => nodelist(x).extract('return/genericItem/itemName/text()').getStringVal(),
                                                      issue_id     => nodelist(x).extract('return/genericItem/itemID/text()').getStringVal()));
             
END LOOP;

In order to use it now all I need to do is call


select *
from table(Build_Mashup_Lov)
  

 


 


 


 


 


Using PL/SQL to create OA user and attach "System Administrator" responsibility

I faced several times when I had a full access to the DB, but could not access Oracle Application, because I had no user.

So I decided to write a function which will create a new user and attach it new responsibility

First of all, you need to compile a function which attaching the responsibility to specific user. Here is the source code

create or replace procedure Attach_Responsibility(p_resp_key varchar2,
p_user_id
number) is
l_respons_id
number;
l_resp_appl
number;
begin
begin
select t.responsibility_id
into l_respons_id
from fnd_responsibility_vl t
where t.responsibility_key=p_resp_key;
select t.application_id
into l_resp_appl
from fnd_responsibility_vl t
where t.responsibility_key=p_resp_key;
exception
when no_data_found then
dbms_output.put_line(
'Cannot get responsibility_id or application_id for SYSTEM_ADMINISTRATOR');
when others then
dbms_output.put_line(sqlerrm);
end; fnd_user_resp_groups_api.insert_assignment(user_id => p_user_id
,responsibility_id
=> l_respons_id --System Administrator
,responsibility_application_id => l_resp_appl
--,security_group_id => 0
,start_date => SYSDATE - 1000
,end_date
=> SYSDATE+1000
,description
=> 'Description');
commit;
end Attach_Responsibility;

And now the script that will create new user and call the function above to attach him X responsibility


declare
l_user_exists
number;
l_user_name fnd_user.
user_name%type := 'MYNEWUSER';
l
varchar2(1000);
l_user_id
number;
l_respons_id
number;
l_resp_appl
number;
begin
select count(1)
into l_user_exists
from fnd_user
where user_name = l_user_name;
dbms_output.put_line(
'User exist: '||l_user_exists);
if l_user_exists = 0 then
fnd_user_pkg.CreateUser(x_user_name
=> l_user_name,
x_owner
=> 'CUST',
x_unencrypted_password
=> 'welcome!1');
commit;
select user_id
into l_user_id
from fnd_user
where user_name=l_user_name;
dbms_output.put_line(
'User ID ['||l_user_name||']'||l_user_id);
else
select user_id
into l_user_id
from fnd_user
where user_name=l_user_name;
fnd_user_pkg.UpdateUser(x_user_name
=> l_user_name,
x_owner
=> 'CUST',
x_unencrypted_password
=> 'WELCOME1');
end if;
commit;
Attach_Responsibility(
'SYSTEM_ADMINISTRATOR',
l_user_id);
Attach_Responsibility(
'APPLICATION_DEVELOPER',
l_user_id);
end;

User's name is MYNEWUSER

l_user_name    fnd_user.user_name%type := 'MYNEWUSER';

check if user already exists


select count(1)
into l_user_exists
from fnd_user
where user_name = l_user_name;

if user exists, change the password to WELCOME!1


fnd_user_pkg.UpdateUser(x_user_name => l_user_name,
x_owner
=> 'CUST',
x_unencrypted_password
=> 'WELCOME!1');

if it doesn't exists, create with initial password WELCOME!1


fnd_user_pkg.CreateUser(x_user_name => l_user_name,
x_owner
=> 'CUST',
x_unencrypted_password
=> 'WELCOME!1');

After user created all we need to do is attach related responsibility. In this case we are going to attach "System Administrator" and "Application Developer" responsibilities


Attach_Responsibility('SYSTEM_ADMINISTRATOR',
l_user_id);
Attach_Responsibility(
'APPLICATION_DEVELOPER',
l_user_id);

The mystery of the whitespace

Recently I had to write a program which taked a printer name as a command line parameter and spools the file to this printer.

Printer name if "Hp Office  5200". As you can see there are 2 whitespaces between "Office" and "5200". Well, I didn't manage to print. I got all the time "Invalid Printer Name"

exception. Finally I noticed that double whitespace is trancated to single whitespace. I made a research on the net and it appears to be that putting the string into double quots should

preserve the string. Well, it is not. I run some tests on Unix and Window

Unix:

X=`echo Hello From        Michael` echo $X Output: Hello From Michael X=`echo "Hello From       Michael"` echo $X Output: Hello From Michael

So double whitespace dissapeaded in both cases. Now on Windows Platform

set X="Hello   From    Michael"  echo %X%

Output: Hello  From  Michael.    Double whitespace preserved!!!!!!

So I decided to write small Java class that executes "Windows" command line command


import java.io.*;
public class CmdExec { public static void main(String argv[]) {
try {
String line;
String str
= "cmd /c echo "+argv[0];
Process p
= Runtime.getRuntime().exec(str);
BufferedReader input
=
new BufferedReader
(
new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
System.out.println(line);
}
input.close();
}
catch (Exception err) {
err.printStackTrace();
}
}
}

java  CmdExec "Hello  From  Michael"

Output : Hello From Michael. Double whitespace dissapeared!!!!!

This explains the strange thing with Printer Name.

I had to say, that till now I didn't find a way to pass the printer name in the safe way

Using Java "URL" object to read text and binary data

Just a little example of "URL" object.

To read text data from remote page (for example), use the following piece of code

URL pollingUrl = new URL("http:\\www.google.com");
BufferedReader in
= new BufferedReader(new InputStreamReader( pollingUrl.openStream()));
String inputLine
="";
while (true)
{
inputLine
= in.readLine();
if (inputLine == null)
break;//end of HTML page
}// end while
in.close();
Just open a stream to specific url and use Buffered Reader to read the response, line by line. Very simple. However,

remember that response text is transfered in the html format. So if you need specific information you need to parse it.

Now if you want to download the file to your disk. The idea is the same, just instead of Buffered Reader we use DataInputStream object

FileOutputStream fout = new FileOutputStream("c:\myFile",true);
URL fileURL
= new URL("http://host/myFile.dat");
DataInputStream dis
= new DataInputStream(fileURL.openStream());
int c = dis.read();
while (c != -1 )
{
c
= dis.read(); fout.write(c);
} fout.close();dis.close();
We read bytes from InputStream and in the same time writing it to the disk

Don't forget to close your streams!!

Using servlet to download the file from Oracle Instance

As part of the project I am working on , I had to find a way to download the file from OA. I will demostrate here a way to do it on R12 instance

First of all we need to write a servlet.

Here is the code:

 

import java.io.*;

import javax.servlet.*;
import javax.servlet.http.*;

public class DownloadFile extends HttpServlet
{

//I assumed that OA is running on Unix under Korn shell and .profile file used to source the instance


private String doCommand(String cmd) throws IOException, InterruptedException
{
int exitCode = 0;
int c;
BufferedReader b;
String [] params
= new String[]{"/bin/ksh", "-c", ". profile 1> /dev/null;set -e;" + cmd};
Process subProc
= Runtime.getRuntime().exec(params);
StringBuffer sb
= new StringBuffer();

b
= new BufferedReader(new InputStreamReader(subProc.getInputStream()));

c
= b.read();

while (c != -1)
{
sb.append((
char)c);
c
= b.read();
}

b.close();

exitCode
= subProc.waitFor();
if (exitCode != 0)
{
sb
= new StringBuffer();
b
= new BufferedReader(new InputStreamReader(subProc.getErrorStream()));
c
= b.read();
while (c != -1)
{
sb.append((
char)c);
c
= b.read();
}
//end while
System.out.println("Output from 'doCommand' "+ sb.toString());
return sb.toString();
}
else
{

System.out.println(
"Output from 'doCommand' "+ sb.toString());
return sb.toString();
}
}

public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{ PrintWriter requestOutput
= null;
String resolvedFile
=null;
try
{
String file
= request.getParameter("fileName");
resolvedFile
= doCommand("echo "+file).trim();
File documentFile
= new File(resolvedFile);
FileInputStream fin
= new FileInputStream(documentFile);
if (resolvedFile.indexOf('/')!=-1)
resolvedFile
= resolvedFile.substring(resolvedFile.lastIndexOf('/')+1) ;
response.setHeader(
"Content-disposition", "attachment; filename=" + resolvedFile);
response.setContentType(
"application/octet-stream");
response.setContentLength((
int)documentFile.length());
requestOutput
= response.getWriter();
int c;
c
= fin.read();
while (c != -1) {
requestOutput.write(c);
c
= fin.read();


}
fin.close();
}
catch (Exception e)
{
if (requestOutput == null)
{
response.setContentType(
"text/html");
requestOutput
= response.getWriter();
}
requestOutput.write(
"Error trying to get file : ");
requestOutput.write(e.toString());
requestOutput.write(
"");
}
requestOutput.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
doGet(request, response);
}
}


Compile the file. Put it under $OA_JAVA on Application Node

Now we need to add servlet definition to OA web service configuration file. It is usually located under  $ORA_CONFIG_HOME/10.1.3/j2ee/oacore/application-deployments/oacore/html/orion-web.xml

Add the following to the servlet section


<servlet>
<servlet-name>DownloadFile</servlet-name>
<display-name>DownloadFile</display-name>
<servlet-class>DownloadFile</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DownloadFile</servlet-name>
<url-pattern>/DownloadFile</url-pattern>
</servlet-mapping>

Save the file and restart OC4J service.

Now you can download any file located on the Application node simply by running http://<instance url>:<instance port>/OA_HTML/DownloadFile?fileName=/path_to_your_file. You can also use instance variables inside  the path, like http://<instance url>:<instance port>/OA_HTML/DownloadFile?fileName=$APPL_TOP/admin/myFile.txt

Adding custom TOP in R12

Recently I tried to add new custom top to my R12 instance. In 11i all I had to do is to add my top to adovars.env file, but when I did it on R12 instance it didn't work. After some research I managed to add my top by running the following:

echo "xxpck   $APPL_TOP" >> $APPL_TOP/admin/topfile.txt

run autoconfig

enjoy!!!

Using PL/SQL to generate Apps Initialize command



You don't need to enter the instance anymore to extract Apps Initialize command.

Just run the following code . Replace USERNAME_HERE by your username

declare
l_user_id fnd_user.
user_id%type;
l_responsibility_id fnd_responsibility_tl.responsibility_id
%type;
l_application_id fnd_responsibility_tl.application_id
%type;
begin
select t.user_id
into l_user_id
from fnd_user t
where t.user_name = 'USERNAME_HERE';
select t.responsibility_id, t.application_id
into l_responsibility_id, l_application_id
from fnd_responsibility_tl t
where t.responsibility_name like 'RESPONSIBILITY_NAME_HERE' and
t.language
= 'US';
fnd_global.apps_initialize(l_user_id,
l_responsibility_id,
l_application_id);
dbms_output.put_line(
'begin fnd_global.apps_initialize' ||
' (user_id => ' || l_user_id || ', resp_id => ' ||
l_responsibility_id
|| ', resp_appl_id => ' ||
l_application_id
|| '); end;');
end;

JDBC and LC_ALL variable

  I was visiting recently one of our customer’s site . Customer complaint about one module which didn’t work for him. Finally I found that the problem is with the following piece of code

PreparedStatement  stmt = _dbConn.prepareStatement(“select decode(attr,‘ATTRIBUTE1’,’COLUMN’,null) from xx_entities”);
 stmt.setString(1, packageName);
 stmt.setInt(2, packageLineNum);
 rs= (ResultSet)stmt.executeQuery();
 StringBuffer result= new StringBuffer();
 result.append("<parameters>");
 while (rs.next())
        result.append("<argument><name>"+rs.getString("param_name")+"</name><value>"+rs.getString("column_value")+"</value></argument>");
 result.append("</parameters>");
        return result.toString();

  The funny part what SQL statement was running just fine from any SQL client and retuned good result, but when running from java the ResultSet object was always empty!! I always got "<parameters></parameters>”


After straggling for several hours, one of my colleagues found the solution. He told me "Hei, check the LC_ALL variable” , and so I did. The value was “ru_RU.cp1251”. As soon as I changed it to “en-US” it worked immediately.