Nov 30 2007

APEX to upload a text file and write into a table

Category: APEXittichai @ 9:32 pm

One of the web development projects using Oracle APEX I’m working on is to upload the content of a text file in csv format into database. By default, all files using the “File Browse..” element will be uploaded to the “wwv_flow_files” table which has structure as follows:

SQL> desc wwv_flow_files
Name         Type           Nullable Default Comments
------------ -------------- -------- ------- --------
ID           NUMBER
FLOW_ID      NUMBER
NAME         VARCHAR2(90)
FILENAME     VARCHAR2(400)  Y
TITLE        VARCHAR2(255)  Y
MIME_TYPE    VARCHAR2(48)   Y
DOC_SIZE     NUMBER         Y
DAD_CHARSET  VARCHAR2(128)  Y
CREATED_BY   VARCHAR2(255)  Y
CREATED_ON   DATE           Y
UPDATED_BY   VARCHAR2(255)  Y
UPDATED_ON   DATE           Y
LAST_UPDATED DATE           Y
CONTENT_TYPE VARCHAR2(128)  Y
BLOB_CONTENT BLOB           Y
LANGUAGE     VARCHAR2(30)   Y
DESCRIPTION  VARCHAR2(4000) Y
FILE_TYPE    VARCHAR2(255)  Y
FILE_CHARSET VARCHAR2(128)  Y

Even though the text file contains character data, the uploaded file content will be stored in the “binary format” in a BLOB column named BLOB_CONTENT. Due to nature of BLOB, to read character out, the conversion using “chr” function is required. Please see a good article about this concept and conversion by Natalka Roshak on the orafaq at http://www.orafaq.com/node/895.

I modified the sample script provided in above article to suite my need – reading each line of the text file and insert into a target table.

DECLARE
v_blob_data       BLOB;
v_blob_len        NUMBER;
v_position        NUMBER;
v_raw_chunk       RAW(10000);
v_char      CHAR(1);
c_chunk_len   number       := 1;
v_line        VARCHAR2 (32767)        := NULL;
v_data_array      wwv_flow_global.vc_arr2;
BEGIN
-- Read data from wwv_flow_files
select blob_content into v_blob_data
from wwv_flow_files where name = 'F29800/Data_CSV.csv';

v_blob_len := dbms_lob.getlength(v_blob_data);
v_position := 1;

-- Read and convert binary to char
WHILE ( v_position <= v_blob_len ) LOOP
 v_raw_chunk := dbms_lob.substr(v_blob_data,c_chunk_len,v_position);
 v_char :=  chr(hex_to_decimal(rawtohex(v_raw_chunk)));
 v_line := v_line || v_char;
 v_position := v_position + c_chunk_len;
-- When a whole line is retrieved
 IF v_char = CHR(10) THEN
-- Convert comma to : to use wwv_flow_utilities
   v_line := REPLACE (v_line, ',', ':');
-- Convert each column separated by : into array of data
   v_data_array := wwv_flow_utilities.string_to_table (v_line);
-- Insert data into target table
   EXECUTE IMMEDIATE 'insert into TABLE_X (v1, v2, v3, v4)
    values (:1,:2,:3,:4)'
    USING
      v_data_array(1),
      v_data_array(2),
      v_data_array(3),
      v_data_array(4);
-- Clear out
   v_line := NULL;
  END IF;
 END LOOP;
END;
/

Tags:


Nov 14 2007

Oracle APEX in 11g Installation

Category: 11g,APEX,SQL Developerittichai @ 8:55 pm

Today I installed Oracle 11g (11.1.0.6) on my machine. I did not realize that Oracle APEX is a part of the standard database components.

So after the 11g installation, I just follow simple steps (shown later below) for the post-installation. In order to access the APEX application, either the embedded PL/SQL gateway or Oracle HTTP server with mod_plsql is needed. For simplicity, I’ve decided to go with the former. By using the embedded PL/SQL gateway, it will run using the Oracle XML DB HTTP server which is already in Oracle database, so there is no need to install a separate HTTP server. The Oracle’s document here explains about this as well as provides the detailed information on the post-installation.

To configure the embedded PL/SQL gateway:

1. Go to the $ORACLE_HOME/apex directory.

2. Use SQL/Plus to connect as SYS to 11g database where APEX is installed.

SYS AS SYSDBA@db11r1> @apxconf

PORT
----------8080

Enter values below for the XDB HTTP listener port and the password for the Application Express ADMIN user.
Default values are in brackets [ ].
Press Enter to accept the default value.

Enter a password for the ADMIN user              []admin_password
Enter a port for the XDB HTTP listener [      8080]
...changing HTTP Port

PL/SQL procedure successfully completed.

PL/SQL procedure successfully completed.

Session altered.

...changing password for ADMIN

PL/SQL procedure successfully completed.

Commit complete.

3. Unlock the ANONYMOUS account.

SYS AS SYSDBA@db11r1> ALTER USER ANONYMOUS ACCOUNT UNLOCK;

User altered.

4. Enable Oracle XML DB HTTP server

SYS AS SYSDBA@db11r1> EXEC DBMS_XDB.SETHTTPPORT(8080);

PL/SQL procedure successfully completed.

SYS AS SYSDBA@db11r1> COMMIT;

Commit complete.

5. We’re now ready to access APEX.

http://host:port/apex

http://host:port/apex/apex_admin — for admin page

Port in this case is 8080 which is the default.

Note that the format of URL is a little bit different from when using HTTP server with mod_plsql -

http://host:port/pls/apex

http://host:port/pls/apex/apex_admin — for admin page

Also the SQL Developer 1.1.3 is included under “sqldeveloper” directory of ORACLE HOME. So just double-click at sqldeveloper.exe to launch application.


Tags: ,


Nov 04 2007

RMAN Duplicate

Category: RMANittichai @ 12:29 am

Last week I had a chance to work on RMAN to duplicate the existing 3-node RAC database to another 2-node RAC database. In my case, the 2-node target already has running instances, the task here is to wipe out and copy data from production.

Here is my note. I tried to put some comments to cover in case of when duplicating from a scratch – meaning there is no target database before as well.

Source:
3-node Oracle 10.2.0.3 RAC on Solaris 10: hostA1, hostA2 and hostA3
Database: racA (instance racA1, racA2 and racA3)

Target:
2-node Oracle 10.2.0.3 RAC on Solaris 10: hostB1 and hostB2
Database: racB (instance racB1 and racB2)

1. On source host, backup on source using RMAN (either using catalog or control file to disk or tape). Sample here is shown using control file to disk.

$ORACLE_HOME/bin/rman

RMAN> connect target /
connected to target database: RACA (DBID=2748812654)

run {
allocate channel d1 type disk;
backup format ‘/u1/df_%t_%s_%p’ database
include current controlfile
plus archivelog;
release channel d1;
}

2. Copy all backupset files to one of the target hosts to the same location of backup

$ scp /u1/df* hostB1:/u1/

If this is a new target database, copy the pfile or spfile from source host too.

Also create a password file using orapwd on the target hosts.

3. Modify the initialization parameters.

You can modify the existing spfile directly if the target database exists before. However, I prefer not to touch the original spfile. My suggestion is to create an init file and use that instead. Make sure this new init file will be used everything instance is restarted because during duplicate, database will be restarted by RMAN. To ensure that it will not use the existing spfile, I would recommend renaming it temporarily.

SQL> create pfile=’$ORACLE_HOME/dbs/initracB.ora’ from spfile;

$> mv spfileRACDB.ora spfileRACDB_temp.ora

In initracB.ora
Change
*.cluster_database=false

add convert if names or paths are different
*.db_file_name_convert = (‘/u1/racA’,'/u1/racB’)
*.log_file_name_convert= (‘/u2/racA’,'/u1/racB’)

Due to a bug in note:334899.1, add this
_no_recovery_through_resetlogs=TRUE

4. On target host, create a TNSNAME alias pointing to the source database.

racA =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = hostA1)(PORT = 1521))
(ADDRESS = (PROTOCOL = TCP)(HOST = hostA2)(PORT = 1521))
(ADDRESS = (PROTOCOL = TCP)(HOST = hostA3)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = racA)
(FAILOVER_MODE =
(TYPE = SELECT)
)
)
)

5. Shutdown all instance if up and startup “nomount” only one instance. Leave other instances on other nodes down. The RMAN duplicate will recreate a database instance for one node only.

6. Start RMAN duplicate

$ORACLE_HOME/bin/rman

RMAN> connect target sys/syspassword@racA
connected to target database: RACA (DBID=2748812654)

RMAN> connect auxiliary /
connected to auxiliary database: RACB (DBID=215163916, not open)

RMAN> run {
allocate channel D1 device type disk;
allocate auxiliary channel D2 device type disk;
DUPLICATE TARGET DATABASE TO RACB;
}

You can use “SKIP” option to not duplicate some tablespaces if needed.

If you encountered missing archive files, copy them from source to target on the same path, and re-run RMAN duplicate.

7. Once completed, restart instance to use the original spfile or the one after reverting additional parameters in step #3.

If you try to restart the 2nd instance, it will fail with an error that there is no log thread.

8. Recreate redo logs of thread 2.

ALTER DATABASE ADD LOGFILE THREAD 2
GROUP 4 (‘u01/racB/redo/redo4a’,
‘u02/racB/redo/redo4a’) size 100M,
GROUP 5 (‘u01/racB/redo/redo5a’,
‘u02/racB/redo/redo5a’) size 100M,
GROUP 6 (‘u01/racB/redo/redo6a’,
‘u02/racB/redo/redo6a’) size 100M ;

Then
alter database enable public thread 2;

You now should be able to start the second instance.

9. Add a new temporary file into the temporary tablespace

SQL> alter tablespace temp add tempfile ‘/u1/racB/oradata/temp2.dbf’ size 1024m reuse;

That’s it!!!

Tags: ,