Data Blocks: Smallest logical component of oracle database.It consists of number of bytes of disk space in OS. Usually in units of 2kb,4kb,8kb(Default),16kb or 32kb.
DB_BLOCK_SIZE gives your current block size.
Remember, Oracle will read the disk in terms of blocks. If you a have name of 4kb stored in a 32kb block, oracle will read the entire 32kb to retrieve your name. Also, OS also has disk block size and reads data in terms of disk block, Typically your oracle block size should be a multiple of disk block size.
System Tablespace is always created with standard block size. In addition to standard you can create 4 non standard block size for your tablespace.Data block contains row data portion (data stored in table or index) , free space prortion (space left for new data),overhad and header portion (for maintenance).
Extents: Two or more contiguous (touching each other) data blocks. It is a unit of space allocation
Segements: Set of extents to form a logical structure like table or index
Tablspace: Set of one or more data files containing related segments
In order to see data contained in a block, you need to dump it in OS
Select OWNER,SEGMENT_NAME,segment_type,tablespace_name,
header_file,header_block from dba_segments
where segment_name = 'CASES'
Alter System dump datafile header_file BLOCK header_block
Alter system dump datafile 15 block 1339
Go to UDUMP directory, the latest *.trc file will contain the binary dump of the block
Wednesday, November 19, 2008
Wednesday, November 12, 2008
Oracle: SQL to retrieve table and column comments
For the whole database
Select ut.owner,ut.table_name,ut.comments Table_Comments,uc.column_name,uc.comments Column_Comments
from dba_tab_comments ut, dba_col_comments uc,dba_tab_columns utc
where ut.owner = uc.owner
and uc.owner = utc.owner
and ut.table_name = uc.table_name
and ut.owner = 'Your_Owner_Name'
and uc.table_name = utc.table_name
and uc.column_name = utc.column_name
order by owner,ut.table_name
For the Schema
Select ut.table_name,ut.comments Table_Comments,uc.column_name,uc.comments Column_Comments,data_type
from USER_tab_comments ut, user_col_comments uc,user_tab_columns utc
where ut.table_name = uc.table_name
and uc.table_name = utc.table_name
and uc.column_name = utc.column_name
order by ut.table_name
Select ut.owner,ut.table_name,ut.comments Table_Comments,uc.column_name,uc.comments Column_Comments
from dba_tab_comments ut, dba_col_comments uc,dba_tab_columns utc
where ut.owner = uc.owner
and uc.owner = utc.owner
and ut.table_name = uc.table_name
and ut.owner = 'Your_Owner_Name'
and uc.table_name = utc.table_name
and uc.column_name = utc.column_name
order by owner,ut.table_name
For the Schema
Select ut.table_name,ut.comments Table_Comments,uc.column_name,uc.comments Column_Comments,data_type
from USER_tab_comments ut, user_col_comments uc,user_tab_columns utc
where ut.table_name = uc.table_name
and uc.table_name = utc.table_name
and uc.column_name = utc.column_name
order by ut.table_name
Tuesday, November 4, 2008
FlashVars in Flex 3
To pass values from the host to swf file, follow the following steps
1) Open the html or aspx file where you have flex swf file embedded.
2) You will see 2 AC_FL_RunContent sections
3) Look at the line in Red, I am passing the value Hello World to the swf file
AC_FL_RunContent(
"src", "FlashV",
"FlashVars", "MMredirectURL=Hello World",
"width", "100%",
"height", "100%",
"align", "middle",
"id", "FlashV",
"quality", "high",
"bgcolor", "#869ca7",
"name", "FlashV",
"allowScriptAccess","sameDomain",
"type", "application/x-shockwave-flash",
"pluginspage", "http://www.adobe.com/go/getflashplayer"
);
-------------------
Now in mxml file, on ApplicationComplete, call a function
applicationComplete="Init()"
private function Init():void
{
var o:Object = this.loaderInfo.parameters;
Alert.show(o.MMredirectURL.toString());
}
1) Open the html or aspx file where you have flex swf file embedded.
2) You will see 2 AC_FL_RunContent sections
3) Look at the line in Red, I am passing the value Hello World to the swf file
AC_FL_RunContent(
"src", "FlashV",
"FlashVars", "MMredirectURL=Hello World",
"width", "100%",
"height", "100%",
"align", "middle",
"id", "FlashV",
"quality", "high",
"bgcolor", "#869ca7",
"name", "FlashV",
"allowScriptAccess","sameDomain",
"type", "application/x-shockwave-flash",
"pluginspage", "http://www.adobe.com/go/getflashplayer"
);
-------------------
Now in mxml file, on ApplicationComplete, call a function
applicationComplete="Init()"
private function Init():void
{
var o:Object = this.loaderInfo.parameters;
Alert.show(o.MMredirectURL.toString());
}
Saturday, November 1, 2008
Friday, October 31, 2008
Indian Gods
Thursday, October 30, 2008
Oracle: How to Shrink Tablespaces
Thanks to asktom article
Run the below sql as sys. This will give list of datafiles and possible savings.
You can then run the generated alter database datafile... statements to shrink
the datafiles.
----------- maxshrink.sql ----------------------------------
set verify off
column file_name format a50 word_wrapped
column smallest format 999,990 heading "Smallest|Size|Poss."
column currsize format 999,990 heading "Current|Size"
column savings format 999,990 heading "Poss.|Savings"
break on report
compute sum of savings on report
column value new_val blksize
select value from v$parameter where name = 'db_block_size'
/
select file_name,
ceil( (nvl(hwm,1)*&&blksize)/1024/1024 ) smallest,
ceil( blocks*&&blksize/1024/1024) currsize,
ceil( blocks*&&blksize/1024/1024) -
ceil( (nvl(hwm,1)*&&blksize)/1024/1024 ) savings
from dba_data_files a,
( select file_id, max(block_id+blocks-1) hwm
from dba_extents
group by file_id ) b
where a.file_id = b.file_id(+)
/
column cmd format a75 word_wrapped
select 'alter database datafile '''||file_name||''' resize ' ||
ceil( (nvl(hwm,1)*&&blksize)/1024/1024 ) || 'm;' cmd
from dba_data_files a,
( select file_id, max(block_id+blocks-1) hwm
from dba_extents
group by file_id ) b
where a.file_id = b.file_id(+)
and ceil( blocks*&&blksize/1024/1024) -
ceil( (nvl(hwm,1)*&&blksize)/1024/1024 ) > 0
/
----------------------------------------------------------
Run the below sql as sys. This will give list of datafiles and possible savings.
You can then run the generated alter database datafile... statements to shrink
the datafiles.
----------- maxshrink.sql ----------------------------------
set verify off
column file_name format a50 word_wrapped
column smallest format 999,990 heading "Smallest|Size|Poss."
column currsize format 999,990 heading "Current|Size"
column savings format 999,990 heading "Poss.|Savings"
break on report
compute sum of savings on report
column value new_val blksize
select value from v$parameter where name = 'db_block_size'
/
select file_name,
ceil( (nvl(hwm,1)*&&blksize)/1024/1024 ) smallest,
ceil( blocks*&&blksize/1024/1024) currsize,
ceil( blocks*&&blksize/1024/1024) -
ceil( (nvl(hwm,1)*&&blksize)/1024/1024 ) savings
from dba_data_files a,
( select file_id, max(block_id+blocks-1) hwm
from dba_extents
group by file_id ) b
where a.file_id = b.file_id(+)
/
column cmd format a75 word_wrapped
select 'alter database datafile '''||file_name||''' resize ' ||
ceil( (nvl(hwm,1)*&&blksize)/1024/1024 ) || 'm;' cmd
from dba_data_files a,
( select file_id, max(block_id+blocks-1) hwm
from dba_extents
group by file_id ) b
where a.file_id = b.file_id(+)
and ceil( blocks*&&blksize/1024/1024) -
ceil( (nvl(hwm,1)*&&blksize)/1024/1024 ) > 0
/
----------------------------------------------------------
Monday, October 27, 2008
Oracle: Startup process
Oracle Startup Process
When you start Oracle, it looks for the files in the following order
1) ORACLE_HOME\DATABASE\SPFILE.ora
2) If above file is not found, it look for spfile.ora in the same directory.
3) If the above files are not found, it looks for init.ora
create spfile from pfile ='C:\oracle\product\10.2.0\db_1\database\initorcldb.ora';
create pfile from spfile;
create pfile='C:\oracle\product\10.2.0\db_1\database\mypfile.ora' from spfile
Startup pfile= 'C:\oracle\product\10.2.0\db_1\database\initORCLDB.ora';
You cannot use spfile with startup command
startup spfile --> wont work
however, you can edit init.ora and add a parameter SPFILE='C:\oracle\product\10.2.0\db_1\database\SPFILEORCLDB.ORA'
and then say startup pfile = ...
Startup NOMOUNT
1) Control files are not read
2) Data files are not open
3) Background processes are started, SGA is allocated to Oracle by OS.
4) Instance is running by itself
Startup MOUNT
1) Oracle associates Instance with the database
2) Oracle opens and reads control files and gets names and location of data files and redo log files
Alter database mount
or
Startup Mount
Startup OPEN
1) Last stage of startup process.
2) Oracle reads all the data files and online redo logs, verifies that the database is consistent
3) If the files are not consistent, background process performs media recovery automatically.
2) Now all users can connect to database.
Alter database Open
Startup --> Mounts and Opens the database
Startup Restrict
1) No other users can connect to database other than you.
2) All new logins to the database are prevented
3) Existing logins will work.
Read Only
Startup Mount
Alter database open Read only
Shutdown or Shutdown Normal
1) No new user connections are allowed
2) Oracle waits for all users to exit their sessions, before shutting down the database.
3) No instance recovery is needed, as Oracle will write all redo log buffers to disk and database will be consistent
3) Oracle closes data files, terminates background process and sga is deallocated
Shutdown Transactional
1) Oracle waits for all active transactions to complete
2) Oracle will not wait for all users to log out their sessions.
3) New connections are not permitted, existing users cannot start new transaction
4) As long as no pending transactions, oracle will shutdown
5) No instance recovery is needed
Shutdown Immediate
1) All active transactions are rolled back
2) Disconnects all active users
3) This process is not immediate as it has to rollback all existing transactions
4) No new connections are permitted
5) No instance recovery needed
Shutdown Abort
1) Existing connections are terminated. Doesn't care about rolling back
2) Redo logs buffers are not written to disk
3) Upon restart, Oracle performs instance recovery.
Dropping Database
1) Connect as sys
2) Startup restrict mount
3) select name from v$database --> Just to check
4) Drop Database
When you start Oracle, it looks for the files in the following order
1) ORACLE_HOME\DATABASE\SPFILE
2) If above file is not found, it look for spfile.ora in the same directory.
3) If the above files are not found, it looks for init
create spfile from pfile ='C:\oracle\product\10.2.0\db_1\database\initorcldb.ora';
create pfile from spfile;
create pfile='C:\oracle\product\10.2.0\db_1\database\mypfile.ora' from spfile
Startup pfile= 'C:\oracle\product\10.2.0\db_1\database\initORCLDB.ora';
You cannot use spfile with startup command
startup spfile --> wont work
however, you can edit init.ora and add a parameter SPFILE='C:\oracle\product\10.2.0\db_1\database\SPFILEORCLDB.ORA'
and then say startup pfile = ...
Startup NOMOUNT
1) Control files are not read
2) Data files are not open
3) Background processes are started, SGA is allocated to Oracle by OS.
4) Instance is running by itself
Startup MOUNT
1) Oracle associates Instance with the database
2) Oracle opens and reads control files and gets names and location of data files and redo log files
Alter database mount
or
Startup Mount
Startup OPEN
1) Last stage of startup process.
2) Oracle reads all the data files and online redo logs, verifies that the database is consistent
3) If the files are not consistent, background process performs media recovery automatically.
2) Now all users can connect to database.
Alter database Open
Startup --> Mounts and Opens the database
Startup Restrict
1) No other users can connect to database other than you.
2) All new logins to the database are prevented
3) Existing logins will work.
Read Only
Startup Mount
Alter database open Read only
Shutdown or Shutdown Normal
1) No new user connections are allowed
2) Oracle waits for all users to exit their sessions, before shutting down the database.
3) No instance recovery is needed, as Oracle will write all redo log buffers to disk and database will be consistent
3) Oracle closes data files, terminates background process and sga is deallocated
Shutdown Transactional
1) Oracle waits for all active transactions to complete
2) Oracle will not wait for all users to log out their sessions.
3) New connections are not permitted, existing users cannot start new transaction
4) As long as no pending transactions, oracle will shutdown
5) No instance recovery is needed
Shutdown Immediate
1) All active transactions are rolled back
2) Disconnects all active users
3) This process is not immediate as it has to rollback all existing transactions
4) No new connections are permitted
5) No instance recovery needed
Shutdown Abort
1) Existing connections are terminated. Doesn't care about rolling back
2) Redo logs buffers are not written to disk
3) Upon restart, Oracle performs instance recovery.
Dropping Database
1) Connect as sys
2) Startup restrict mount
3) select name from v$database --> Just to check
4) Drop Database
Friday, September 26, 2008
Oracle: How to shrink table
How to shrink oracle tables
Alter table table_name enable row movement;
Alter table table_name shrink space;
To find out size of any table
Select segment_name,bytes/1024/1024 size_in_MB
from user_segments
where segment_name = 'your_table_name'
Alter table table_name enable row movement;
Alter table table_name shrink space;
To find out size of any table
Select segment_name,bytes/1024/1024 size_in_MB
from user_segments
where segment_name = 'your_table_name'
Oracle: How to shrink table
How to shrink oracle tables
Alter table table_name enable row movement;
Alter table table_name shrink space;
To find out size of any table
Select segment_name,bytes/1024/1024 size_in_MB
from user_segments
where segment_name = 'your_table_name'
Alter table table_name enable row movement;
Alter table table_name shrink space;
To find out size of any table
Select segment_name,bytes/1024/1024 size_in_MB
from user_segments
where segment_name = 'your_table_name'
Thursday, September 11, 2008
Oracle: How to move data files from c:\ to d:\
Some times you may want to move your oracle data files from c:\ to another drive due to lack of space. Here is how you do it. In my example, my database is SUPPDB and it was created on default c:\
Connect as sys
Alter database backup controlfile to trace;
Go to udump folder (under admin\database_name\udump),open the latest *.trc files
and you will find 2 sets of sql's to recreate the control files.
Use option 1, if you have all your online redo log files
use option 2, if you don't have all your online redo log files.
Stop all services (like dbconsole ) accessing oracle database
Shutdown;
--wait for shutdown to complete.This way you ensure your online log files are up to date.Do not issue shutdown immediate or shutdown abort)
Now, move all your database files (like SYSTEM01.DBF,UNDOTBS01.DBF,SYSAUX01.DBF,USERS01.DBF,REDO01.LOG tablspace files )to the destination directory. In my example, I simply copied the files from c:\ to d:\...
Change the path for the above files in the create controlfile statement as shown
below.
Connect as sys
STARTUP NOMOUNT;
CREATE CONTROLFILE REUSE DATABASE "SUPPDB" NORESETLOGS NOARCHIVELOG
MAXLOGFILES 16
MAXLOGMEMBERS 3
MAXDATAFILES 100
MAXINSTANCES 8
MAXLOGHISTORY 584
LOGFILE
GROUP 1 'D:\Oracle\SUPPDB\Oradata\REDO01.LOG' SIZE 50M,
GROUP 2 'D:\Oracle\SUPPDB\Oradata\REDO02.LOG' SIZE 50M,
GROUP 3 'D:\Oracle\SUPPDB\Oradata\REDO03.LOG' SIZE 50M
DATAFILE
'D:\Oracle\SUPPDB\Oradata\SYSTEM01.DBF',
'D:\Oracle\SUPPDB\Oradata\UNDOTBS01.DBF',
'D:\Oracle\SUPPDB\Oradata\SYSAUX01.DBF',
'D:\Oracle\SUPPDB\Oradata\USERS01.DBF',
'D:\ORACLE\SUPPDB\ORADATA\apple_DATA.DBF',
'D:\ORACLE\SUPPDB\ORADATA\apple_INDX.DBF',
'D:\ORACLE\SUPPDB\ORADATA\orange_DATA.DBF',
'D:\ORACLE\SUPPDB\ORADATA\orange_INDX.DBF'
CHARACTER SET WE8MSWIN1252;
RECOVER DATABASE;
--It's ok to get an ora message saying no recovery needed, its not an error message.
ALTER DATABASE OPEN;
--Create a new TEMPFILE
ALTER TABLESPACE TEMP ADD TEMPFILE 'D:\Oracle\SUPPDB\Oradata\TEMP01.DBF'
SIZE 271581184 REUSE AUTOEXTEND ON NEXT 655360 MAXSIZE 32767M;
If you choose option 2
Connect as sys
STARTUP NOMOUNT;
CREATE CONTROLFILE REUSE DATABASE "SUPPDB" RESETLOGS NOARCHIVELOG
MAXLOGFILES 16
MAXLOGMEMBERS 3
MAXDATAFILES 100
MAXINSTANCES 8
MAXLOGHISTORY 584
LOGFILE
GROUP 1 'D:\Oracle\SUPPDB\Oradata\REDO01.LOG' SIZE 50M,
GROUP 2 'D:\Oracle\SUPPDB\Oradata\REDO02.LOG' SIZE 50M,
GROUP 3 'D:\Oracle\SUPPDB\Oradata\REDO03.LOG' SIZE 50M
DATAFILE
'D:\Oracle\SUPPDB\Oradata\SYSTEM01.DBF',
'D:\Oracle\SUPPDB\Oradata\UNDOTBS01.DBF',
'D:\Oracle\SUPPDB\Oradata\SYSAUX01.DBF',
'D:\Oracle\SUPPDB\Oradata\USERS01.DBF',
'D:\ORACLE\SUPPDB\ORADATA\apple_DATA.DBF',
'D:\ORACLE\SUPPDB\ORADATA\apple_INDX.DBF',
'D:\ORACLE\SUPPDB\ORADATA\orange_DATA.DBF',
'D:\ORACLE\SUPPDB\ORADATA\orange_INDX.DBF'
CHARACTER SET WE8MSWIN1252;
RECOVER DATABASE USING BACKUP CONTROLFILE;
--At this point, I was prompted to enter my archive log files which doesn't exist.
--I pointed to my redo02.log file and it solved the problem. You may have to try all --the 3 Redo log files one by one
ALTER DATABASE OPEN RESETLOGS;
ALTER TABLESPACE TEMP ADD TEMPFILE 'C:\ORACLE\ORADATA\SUPPDB\TEMP01.DBF'
SIZE 271581184 REUSE AUTOEXTEND ON NEXT 655360 MAXSIZE 32767M;
Connect as sys
Alter database backup controlfile to trace;
Go to udump folder (under admin\database_name\udump),open the latest *.trc files
and you will find 2 sets of sql's to recreate the control files.
Use option 1, if you have all your online redo log files
use option 2, if you don't have all your online redo log files.
Stop all services (like dbconsole ) accessing oracle database
Shutdown;
--wait for shutdown to complete.This way you ensure your online log files are up to date.Do not issue shutdown immediate or shutdown abort)
Now, move all your database files (like SYSTEM01.DBF,UNDOTBS01.DBF,SYSAUX01.DBF,USERS01.DBF,REDO01.LOG tablspace files )to the destination directory. In my example, I simply copied the files from c:\ to d:\...
Change the path for the above files in the create controlfile statement as shown
below.
Connect as sys
STARTUP NOMOUNT;
CREATE CONTROLFILE REUSE DATABASE "SUPPDB" NORESETLOGS NOARCHIVELOG
MAXLOGFILES 16
MAXLOGMEMBERS 3
MAXDATAFILES 100
MAXINSTANCES 8
MAXLOGHISTORY 584
LOGFILE
GROUP 1 'D:\Oracle\SUPPDB\Oradata\REDO01.LOG' SIZE 50M,
GROUP 2 'D:\Oracle\SUPPDB\Oradata\REDO02.LOG' SIZE 50M,
GROUP 3 'D:\Oracle\SUPPDB\Oradata\REDO03.LOG' SIZE 50M
DATAFILE
'D:\Oracle\SUPPDB\Oradata\SYSTEM01.DBF',
'D:\Oracle\SUPPDB\Oradata\UNDOTBS01.DBF',
'D:\Oracle\SUPPDB\Oradata\SYSAUX01.DBF',
'D:\Oracle\SUPPDB\Oradata\USERS01.DBF',
'D:\ORACLE\SUPPDB\ORADATA\apple_DATA.DBF',
'D:\ORACLE\SUPPDB\ORADATA\apple_INDX.DBF',
'D:\ORACLE\SUPPDB\ORADATA\orange_DATA.DBF',
'D:\ORACLE\SUPPDB\ORADATA\orange_INDX.DBF'
CHARACTER SET WE8MSWIN1252;
RECOVER DATABASE;
--It's ok to get an ora message saying no recovery needed, its not an error message.
ALTER DATABASE OPEN;
--Create a new TEMPFILE
ALTER TABLESPACE TEMP ADD TEMPFILE 'D:\Oracle\SUPPDB\Oradata\TEMP01.DBF'
SIZE 271581184 REUSE AUTOEXTEND ON NEXT 655360 MAXSIZE 32767M;
If you choose option 2
Connect as sys
STARTUP NOMOUNT;
CREATE CONTROLFILE REUSE DATABASE "SUPPDB" RESETLOGS NOARCHIVELOG
MAXLOGFILES 16
MAXLOGMEMBERS 3
MAXDATAFILES 100
MAXINSTANCES 8
MAXLOGHISTORY 584
LOGFILE
GROUP 1 'D:\Oracle\SUPPDB\Oradata\REDO01.LOG' SIZE 50M,
GROUP 2 'D:\Oracle\SUPPDB\Oradata\REDO02.LOG' SIZE 50M,
GROUP 3 'D:\Oracle\SUPPDB\Oradata\REDO03.LOG' SIZE 50M
DATAFILE
'D:\Oracle\SUPPDB\Oradata\SYSTEM01.DBF',
'D:\Oracle\SUPPDB\Oradata\UNDOTBS01.DBF',
'D:\Oracle\SUPPDB\Oradata\SYSAUX01.DBF',
'D:\Oracle\SUPPDB\Oradata\USERS01.DBF',
'D:\ORACLE\SUPPDB\ORADATA\apple_DATA.DBF',
'D:\ORACLE\SUPPDB\ORADATA\apple_INDX.DBF',
'D:\ORACLE\SUPPDB\ORADATA\orange_DATA.DBF',
'D:\ORACLE\SUPPDB\ORADATA\orange_INDX.DBF'
CHARACTER SET WE8MSWIN1252;
RECOVER DATABASE USING BACKUP CONTROLFILE;
--At this point, I was prompted to enter my archive log files which doesn't exist.
--I pointed to my redo02.log file and it solved the problem. You may have to try all --the 3 Redo log files one by one
ALTER DATABASE OPEN RESETLOGS;
ALTER TABLESPACE TEMP ADD TEMPFILE 'C:\ORACLE\ORADATA\SUPPDB\TEMP01.DBF'
SIZE 271581184 REUSE AUTOEXTEND ON NEXT 655360 MAXSIZE 32767M;
Oracle: How to move data files from c:\ to d:\
Some times you may want to move your oracle data files from c:\ to another drive due to lack of space. Here is how you do it. In my example, my database is SUPPDB and it was created on default c:\
Connect as sys
Alter database backup controlfile to trace;
Go to udump folder (under admin\database_name\udump),open the latest *.trc files
and you will find 2 sets of sql's to recreate the control files.
Use option 1, if you have all your online redo log files
use option 2, if you don't have all your online redo log files.
Stop all services (like dbconsole ) accessing oracle database
Shutdown;
--wait for shutdown to complete.This way you ensure your online log files are up to date.Do not issue shutdown immediate or shutdown abort)
Now, move all your database files (like SYSTEM01.DBF,UNDOTBS01.DBF,SYSAUX01.DBF,USERS01.DBF,REDO01.LOG tablspace files )to the destination directory. In my example, I simply copied the files from c:\ to d:\...
Change the path for the above files in the create controlfile statement as shown
below.
Connect as sys
STARTUP NOMOUNT;
CREATE CONTROLFILE REUSE DATABASE "SUPPDB" NORESETLOGS NOARCHIVELOG
MAXLOGFILES 16
MAXLOGMEMBERS 3
MAXDATAFILES 100
MAXINSTANCES 8
MAXLOGHISTORY 584
LOGFILE
GROUP 1 'D:\Oracle\SUPPDB\Oradata\REDO01.LOG' SIZE 50M,
GROUP 2 'D:\Oracle\SUPPDB\Oradata\REDO02.LOG' SIZE 50M,
GROUP 3 'D:\Oracle\SUPPDB\Oradata\REDO03.LOG' SIZE 50M
DATAFILE
'D:\Oracle\SUPPDB\Oradata\SYSTEM01.DBF',
'D:\Oracle\SUPPDB\Oradata\UNDOTBS01.DBF',
'D:\Oracle\SUPPDB\Oradata\SYSAUX01.DBF',
'D:\Oracle\SUPPDB\Oradata\USERS01.DBF',
'D:\ORACLE\SUPPDB\ORADATA\apple_DATA.DBF',
'D:\ORACLE\SUPPDB\ORADATA\apple_INDX.DBF',
'D:\ORACLE\SUPPDB\ORADATA\orange_DATA.DBF',
'D:\ORACLE\SUPPDB\ORADATA\orange_INDX.DBF'
CHARACTER SET WE8MSWIN1252;
RECOVER DATABASE;
--It's ok to get an ora message saying no recovery needed, its not an error message.
ALTER DATABASE OPEN;
--Create a new TEMPFILE
ALTER TABLESPACE TEMP ADD TEMPFILE 'D:\Oracle\SUPPDB\Oradata\TEMP01.DBF'
SIZE 271581184 REUSE AUTOEXTEND ON NEXT 655360 MAXSIZE 32767M;
If you choose option 2
Connect as sys
STARTUP NOMOUNT;
CREATE CONTROLFILE REUSE DATABASE "SUPPDB" RESETLOGS NOARCHIVELOG
MAXLOGFILES 16
MAXLOGMEMBERS 3
MAXDATAFILES 100
MAXINSTANCES 8
MAXLOGHISTORY 584
LOGFILE
GROUP 1 'D:\Oracle\SUPPDB\Oradata\REDO01.LOG' SIZE 50M,
GROUP 2 'D:\Oracle\SUPPDB\Oradata\REDO02.LOG' SIZE 50M,
GROUP 3 'D:\Oracle\SUPPDB\Oradata\REDO03.LOG' SIZE 50M
DATAFILE
'D:\Oracle\SUPPDB\Oradata\SYSTEM01.DBF',
'D:\Oracle\SUPPDB\Oradata\UNDOTBS01.DBF',
'D:\Oracle\SUPPDB\Oradata\SYSAUX01.DBF',
'D:\Oracle\SUPPDB\Oradata\USERS01.DBF',
'D:\ORACLE\SUPPDB\ORADATA\apple_DATA.DBF',
'D:\ORACLE\SUPPDB\ORADATA\apple_INDX.DBF',
'D:\ORACLE\SUPPDB\ORADATA\orange_DATA.DBF',
'D:\ORACLE\SUPPDB\ORADATA\orange_INDX.DBF'
CHARACTER SET WE8MSWIN1252;
RECOVER DATABASE USING BACKUP CONTROLFILE;
--At this point, I was prompted to enter my archive log files which doesn't exist.
--I pointed to my redo02.log file and it solved the problem. You may have to try all --the 3 Redo log files one by one
ALTER DATABASE OPEN RESETLOGS;
ALTER TABLESPACE TEMP ADD TEMPFILE 'C:\ORACLE\ORADATA\SUPPDB\TEMP01.DBF'
SIZE 271581184 REUSE AUTOEXTEND ON NEXT 655360 MAXSIZE 32767M;
Connect as sys
Alter database backup controlfile to trace;
Go to udump folder (under admin\database_name\udump),open the latest *.trc files
and you will find 2 sets of sql's to recreate the control files.
Use option 1, if you have all your online redo log files
use option 2, if you don't have all your online redo log files.
Stop all services (like dbconsole ) accessing oracle database
Shutdown;
--wait for shutdown to complete.This way you ensure your online log files are up to date.Do not issue shutdown immediate or shutdown abort)
Now, move all your database files (like SYSTEM01.DBF,UNDOTBS01.DBF,SYSAUX01.DBF,USERS01.DBF,REDO01.LOG tablspace files )to the destination directory. In my example, I simply copied the files from c:\ to d:\...
Change the path for the above files in the create controlfile statement as shown
below.
Connect as sys
STARTUP NOMOUNT;
CREATE CONTROLFILE REUSE DATABASE "SUPPDB" NORESETLOGS NOARCHIVELOG
MAXLOGFILES 16
MAXLOGMEMBERS 3
MAXDATAFILES 100
MAXINSTANCES 8
MAXLOGHISTORY 584
LOGFILE
GROUP 1 'D:\Oracle\SUPPDB\Oradata\REDO01.LOG' SIZE 50M,
GROUP 2 'D:\Oracle\SUPPDB\Oradata\REDO02.LOG' SIZE 50M,
GROUP 3 'D:\Oracle\SUPPDB\Oradata\REDO03.LOG' SIZE 50M
DATAFILE
'D:\Oracle\SUPPDB\Oradata\SYSTEM01.DBF',
'D:\Oracle\SUPPDB\Oradata\UNDOTBS01.DBF',
'D:\Oracle\SUPPDB\Oradata\SYSAUX01.DBF',
'D:\Oracle\SUPPDB\Oradata\USERS01.DBF',
'D:\ORACLE\SUPPDB\ORADATA\apple_DATA.DBF',
'D:\ORACLE\SUPPDB\ORADATA\apple_INDX.DBF',
'D:\ORACLE\SUPPDB\ORADATA\orange_DATA.DBF',
'D:\ORACLE\SUPPDB\ORADATA\orange_INDX.DBF'
CHARACTER SET WE8MSWIN1252;
RECOVER DATABASE;
--It's ok to get an ora message saying no recovery needed, its not an error message.
ALTER DATABASE OPEN;
--Create a new TEMPFILE
ALTER TABLESPACE TEMP ADD TEMPFILE 'D:\Oracle\SUPPDB\Oradata\TEMP01.DBF'
SIZE 271581184 REUSE AUTOEXTEND ON NEXT 655360 MAXSIZE 32767M;
If you choose option 2
Connect as sys
STARTUP NOMOUNT;
CREATE CONTROLFILE REUSE DATABASE "SUPPDB" RESETLOGS NOARCHIVELOG
MAXLOGFILES 16
MAXLOGMEMBERS 3
MAXDATAFILES 100
MAXINSTANCES 8
MAXLOGHISTORY 584
LOGFILE
GROUP 1 'D:\Oracle\SUPPDB\Oradata\REDO01.LOG' SIZE 50M,
GROUP 2 'D:\Oracle\SUPPDB\Oradata\REDO02.LOG' SIZE 50M,
GROUP 3 'D:\Oracle\SUPPDB\Oradata\REDO03.LOG' SIZE 50M
DATAFILE
'D:\Oracle\SUPPDB\Oradata\SYSTEM01.DBF',
'D:\Oracle\SUPPDB\Oradata\UNDOTBS01.DBF',
'D:\Oracle\SUPPDB\Oradata\SYSAUX01.DBF',
'D:\Oracle\SUPPDB\Oradata\USERS01.DBF',
'D:\ORACLE\SUPPDB\ORADATA\apple_DATA.DBF',
'D:\ORACLE\SUPPDB\ORADATA\apple_INDX.DBF',
'D:\ORACLE\SUPPDB\ORADATA\orange_DATA.DBF',
'D:\ORACLE\SUPPDB\ORADATA\orange_INDX.DBF'
CHARACTER SET WE8MSWIN1252;
RECOVER DATABASE USING BACKUP CONTROLFILE;
--At this point, I was prompted to enter my archive log files which doesn't exist.
--I pointed to my redo02.log file and it solved the problem. You may have to try all --the 3 Redo log files one by one
ALTER DATABASE OPEN RESETLOGS;
ALTER TABLESPACE TEMP ADD TEMPFILE 'C:\ORACLE\ORADATA\SUPPDB\TEMP01.DBF'
SIZE 271581184 REUSE AUTOEXTEND ON NEXT 655360 MAXSIZE 32767M;
Tuesday, September 2, 2008
Oracle: How to find number of redo log switch
Following query outputs redo log switch/day broken down to each hour. If you see too many switches at any point of time, think about increasing redo log size
select to_char(first_time,'YYYY-MM-DD') day,
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'00',1,0)),'99')
"00",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'01',1,0)),'99')
"01",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'02',1,0)),'99')
"02",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'03',1,0)),'99')
"03",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'04',1,0)),'99')
"04",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'05',1,0)),'99')
"05",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'06',1,0)),'99')
"06",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'07',1,0)),'99')
"07",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'08',1,0)),'99')
"08",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'09',1,0)),'99')
"09",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'10',1,0)),'99')
"10",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'11',1,0)),'99')
"11",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'12',1,0)),'99')
"12",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'13',1,0)),'99')
"13",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'14',1,0)),'99')
"14",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'15',1,0)),'99')
"15",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'16',1,0)),'99')
"16",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'17',1,0)),'99')
"17",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'18',1,0)),'99')
"18",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'19',1,0)),'99')
"19",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'20',1,0)),'99')
"20",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'21',1,0)),'99')
"21",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'22',1,0)),'99')
"22",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'23',1,0)),'99')
"23"
from v$log_history
group by to_char(first_time,'YYYY-MM-DD')
select to_char(first_time,'YYYY-MM-DD') day,
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'00',1,0)),'99')
"00",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'01',1,0)),'99')
"01",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'02',1,0)),'99')
"02",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'03',1,0)),'99')
"03",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'04',1,0)),'99')
"04",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'05',1,0)),'99')
"05",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'06',1,0)),'99')
"06",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'07',1,0)),'99')
"07",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'08',1,0)),'99')
"08",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'09',1,0)),'99')
"09",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'10',1,0)),'99')
"10",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'11',1,0)),'99')
"11",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'12',1,0)),'99')
"12",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'13',1,0)),'99')
"13",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'14',1,0)),'99')
"14",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'15',1,0)),'99')
"15",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'16',1,0)),'99')
"16",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'17',1,0)),'99')
"17",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'18',1,0)),'99')
"18",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'19',1,0)),'99')
"19",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'20',1,0)),'99')
"20",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'21',1,0)),'99')
"21",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'22',1,0)),'99')
"22",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'23',1,0)),'99')
"23"
from v$log_history
group by to_char(first_time,'YYYY-MM-DD')
Oracle: How to find number of redo log switch
Following query outputs redo log switch/day broken down to each hour. If you see too many switches at any point of time, think about increasing redo log size
select to_char(first_time,'YYYY-MM-DD') day,
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'00',1,0)),'99')
"00",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'01',1,0)),'99')
"01",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'02',1,0)),'99')
"02",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'03',1,0)),'99')
"03",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'04',1,0)),'99')
"04",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'05',1,0)),'99')
"05",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'06',1,0)),'99')
"06",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'07',1,0)),'99')
"07",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'08',1,0)),'99')
"08",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'09',1,0)),'99')
"09",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'10',1,0)),'99')
"10",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'11',1,0)),'99')
"11",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'12',1,0)),'99')
"12",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'13',1,0)),'99')
"13",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'14',1,0)),'99')
"14",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'15',1,0)),'99')
"15",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'16',1,0)),'99')
"16",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'17',1,0)),'99')
"17",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'18',1,0)),'99')
"18",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'19',1,0)),'99')
"19",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'20',1,0)),'99')
"20",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'21',1,0)),'99')
"21",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'22',1,0)),'99')
"22",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'23',1,0)),'99')
"23"
from v$log_history
group by to_char(first_time,'YYYY-MM-DD')
select to_char(first_time,'YYYY-MM-DD') day,
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'00',1,0)),'99')
"00",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'01',1,0)),'99')
"01",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'02',1,0)),'99')
"02",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'03',1,0)),'99')
"03",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'04',1,0)),'99')
"04",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'05',1,0)),'99')
"05",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'06',1,0)),'99')
"06",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'07',1,0)),'99')
"07",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'08',1,0)),'99')
"08",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'09',1,0)),'99')
"09",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'10',1,0)),'99')
"10",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'11',1,0)),'99')
"11",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'12',1,0)),'99')
"12",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'13',1,0)),'99')
"13",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'14',1,0)),'99')
"14",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'15',1,0)),'99')
"15",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'16',1,0)),'99')
"16",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'17',1,0)),'99')
"17",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'18',1,0)),'99')
"18",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'19',1,0)),'99')
"19",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'20',1,0)),'99')
"20",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'21',1,0)),'99')
"21",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'22',1,0)),'99')
"22",
to_char(sum(decode(substr(to_char(first_time,'HH24'),1,2),'23',1,0)),'99')
"23"
from v$log_history
group by to_char(first_time,'YYYY-MM-DD')
Oracle: How to increase redo log size
Below is list of sql's to increase the size of redo log files. In order to increase the size, you need to create new redo log files, check point the old one and drop the old one. Replace the path to match your redo location.
In this example, I am creating 3 more redolog files with group number 4,5 and 6 and dropping the old ones.
Log in as sys
Select * from v$log --- Get max group no
Max log files you can have in your database can be got from
Select * from v$controlfile_record_section
where type ='REDO LOG'
Alter database add logfile group 4 'c:\oracle\oradata\orcldb\redo04.log'
size 250M reuse;
Alter database add logfile group 5 'c:\oracle\oradata\orcldb\redo05.log'
size 250M reuse;
Alter database add logfile group 6 'g:\oracle\oradata\orcldb\redo06.log'
size 250M reuse;
Now switch log file 3 times to make these new files online.
Alter system switch logfile;
Alter system switch logfile;
Alter system switch logfile;
force checkpoint to write all contents to data files.
Alter system checkpoint;
Drop the old log files.
Alter database drop logfile group 1;
Alter database drop logfile group 2;
Alter database drop logfile group 3;
In this example, I am creating 3 more redolog files with group number 4,5 and 6 and dropping the old ones.
Log in as sys
Select * from v$log --- Get max group no
Max log files you can have in your database can be got from
Select * from v$controlfile_record_section
where type ='REDO LOG'
Alter database add logfile group 4 'c:\oracle\oradata\orcldb\redo04.log'
size 250M reuse;
Alter database add logfile group 5 'c:\oracle\oradata\orcldb\redo05.log'
size 250M reuse;
Alter database add logfile group 6 'g:\oracle\oradata\orcldb\redo06.log'
size 250M reuse;
Now switch log file 3 times to make these new files online.
Alter system switch logfile;
Alter system switch logfile;
Alter system switch logfile;
force checkpoint to write all contents to data files.
Alter system checkpoint;
Drop the old log files.
Alter database drop logfile group 1;
Alter database drop logfile group 2;
Alter database drop logfile group 3;
Oracle: How to increase redo log size
Below is list of sql's to increase the size of redo log files. In order to increase the size, you need to create new redo log files, check point the old one and drop the old one. Replace the path to match your redo location.
In this example, I am creating 3 more redolog files with group number 4,5 and 6 and dropping the old ones.
Log in as sys
Select * from v$log --- Get max group no
Max log files you can have in your database can be got from
Select * from v$controlfile_record_section
where type ='REDO LOG'
Alter database add logfile group 4 'c:\oracle\oradata\orcldb\redo04.log'
size 250M reuse;
Alter database add logfile group 5 'c:\oracle\oradata\orcldb\redo05.log'
size 250M reuse;
Alter database add logfile group 6 'g:\oracle\oradata\orcldb\redo06.log'
size 250M reuse;
Now switch log file 3 times to make these new files online.
Alter system switch logfile;
Alter system switch logfile;
Alter system switch logfile;
force checkpoint to write all contents to data files.
Alter system checkpoint;
Drop the old log files.
Alter database drop logfile group 1;
Alter database drop logfile group 2;
Alter database drop logfile group 3;
In this example, I am creating 3 more redolog files with group number 4,5 and 6 and dropping the old ones.
Log in as sys
Select * from v$log --- Get max group no
Max log files you can have in your database can be got from
Select * from v$controlfile_record_section
where type ='REDO LOG'
Alter database add logfile group 4 'c:\oracle\oradata\orcldb\redo04.log'
size 250M reuse;
Alter database add logfile group 5 'c:\oracle\oradata\orcldb\redo05.log'
size 250M reuse;
Alter database add logfile group 6 'g:\oracle\oradata\orcldb\redo06.log'
size 250M reuse;
Now switch log file 3 times to make these new files online.
Alter system switch logfile;
Alter system switch logfile;
Alter system switch logfile;
force checkpoint to write all contents to data files.
Alter system checkpoint;
Drop the old log files.
Alter database drop logfile group 1;
Alter database drop logfile group 2;
Alter database drop logfile group 3;
Monday, August 25, 2008
Oracle: How to capture errors using "Log Errors Into" Clause
1) Create an error table to capture the errors from Insert, Update and Delete. To create this table,use Oracle's built in create_error_log function
Exec dbms_errlog.create_error_log("SOURCE_TABLE")
SOURCE_TABLE: Replace SOURCE_TABLE with name of your table. By default, error table will be prefixed by "ERR$_"
If you want to create a error table with a different name,
Exec dbms_errlog.create_error_log("SOURCE_TABLE","ERROR_TABLE_NAME")
By Default Error table will contain all columns from source table.
If your source_table contains long or blob columns, you need to skip them in the error table
Exec dbms_errlog.create_error_log("SOURCE_TABLE", skip_unsupported =>true)
Example: Insert into table_name ( col1,col2....) Values (Col1,Col2....)
log errors into err$_table_name
reject limit unlimited;
Update table_name
Set Col1 = ....
Where.....
log errors into err$_table_name
reject limit unlimited;
Delete table_name
Where.....
log errors into err$_table_name
reject limit unlimited;
If you don't use reject limit unlimited your transaction will fail and only 1 record will be inserted in the err$ table.
Exec dbms_errlog.create_error_log("SOURCE_TABLE")
SOURCE_TABLE: Replace SOURCE_TABLE with name of your table. By default, error table will be prefixed by "ERR$_"
If you want to create a error table with a different name,
Exec dbms_errlog.create_error_log("SOURCE_TABLE","ERROR_TABLE_NAME")
By Default Error table will contain all columns from source table.
If your source_table contains long or blob columns, you need to skip them in the error table
Exec dbms_errlog.create_error_log("SOURCE_TABLE", skip_unsupported =>true)
Example: Insert into table_name ( col1,col2....) Values (Col1,Col2....)
log errors into err$_table_name
reject limit unlimited;
Update table_name
Set Col1 = ....
Where.....
log errors into err$_table_name
reject limit unlimited;
Delete table_name
Where.....
log errors into err$_table_name
reject limit unlimited;
If you don't use reject limit unlimited your transaction will fail and only 1 record will be inserted in the err$ table.
Oracle: How to capture errors using "Log Errors Into" Clause
1) Create an error table to capture the errors from Insert, Update and Delete. To create this table,use Oracle's built in create_error_log function
Exec dbms_errlog.create_error_log('SOURCE_TABLE')
SOURCE_TABLE: Replace SOURCE_TABLE with name of your table. By default, error table will be prefixed by "ERR$_"
If you want to create a error table with a different name,
Exec dbms_errlog.create_error_log("SOURCE_TABLE","ERROR_TABLE_NAME")
By Default Error table will contain all columns from source table.
If your source_table contains long or blob columns, you need to skip them in the error table
Exec dbms_errlog.create_error_log("SOURCE_TABLE", skip_unsupported =>true)
Example: Insert into table_name ( col1,col2....) Values (Col1,Col2....)
log errors into err$_table_name
reject limit unlimited;
Update table_name
Set Col1 = ....
Where.....
log errors into err$_table_name
reject limit unlimited;
Delete table_name
Where.....
log errors into err$_table_name
reject limit unlimited;
If you don't use reject limit unlimited your transaction will fail and only 1 record will be inserted in the err$ table.
Exec dbms_errlog.create_error_log('SOURCE_TABLE')
SOURCE_TABLE: Replace SOURCE_TABLE with name of your table. By default, error table will be prefixed by "ERR$_"
If you want to create a error table with a different name,
Exec dbms_errlog.create_error_log("SOURCE_TABLE","ERROR_TABLE_NAME")
By Default Error table will contain all columns from source table.
If your source_table contains long or blob columns, you need to skip them in the error table
Exec dbms_errlog.create_error_log("SOURCE_TABLE", skip_unsupported =>true)
Example: Insert into table_name ( col1,col2....) Values (Col1,Col2....)
log errors into err$_table_name
reject limit unlimited;
Update table_name
Set Col1 = ....
Where.....
log errors into err$_table_name
reject limit unlimited;
Delete table_name
Where.....
log errors into err$_table_name
reject limit unlimited;
If you don't use reject limit unlimited your transaction will fail and only 1 record will be inserted in the err$ table.
Tuesday, August 19, 2008
Oracle: How to convert CLOB to BLOB
CREATE OR REPLACE Procedure Convert_Clob_To_Blob( clobvalue in clob , blobValue in out blob)
as
Position pls_integer := 1;
Temp_Buffer raw(32767);
Length_To_Copy int ;
clob_Length pls_integer := dbms_lob.getLength(clobValue);
begin
dbms_lob.open(BlobValue,dbms_lob.lob_readwrite);
--Length_To_Copy := least(1000,(clob_Length - Position) + 1);
While (Position <= clob_Length ) loop
Length_To_Copy := least(1000,(clob_Length - Position) + 1);
Temp_Buffer := utl_raw.cast_to_raw(dbms_lob.substr(clobValue,Length_To_Copy,Position));
If utl_raw.length(Temp_Buffer) > 0 then
dbms_lob.writeappend(BlobValue,utl_raw.length(Temp_Buffer),Temp_Buffer);
end if;
Position := Position + Length_To_Copy;
--Length_To_Copy := least(1000,(clob_Length - Position) + 1);
end loop;
dbms_lob.close(BlobValue);
end;
/
In order to test the above code look at this example.Lets assume you have a table called TABLE_NAME with a clob column called CLOB_COLUMN
Declare
b blob;
Begin
For cTemp in ( Select clob_column from table_name ) loop
Begin
b := null;
Insert into TABLE_NAME2(BLOB_COLUMN) values (empty_blob())
returning BLOB_COLUMN into b;
Convert_Clob_To_Blob (cTemp.clob_column,b);
end;
end loop;
Commit;
end;
/
Oracle: How to convert CLOB to BLOB
CREATE OR REPLACE Procedure Convert_Clob_To_Blob( clobvalue in clob , blobValue in out blob)
as
Position pls_integer := 1;
Temp_Buffer raw(32767);
Length_To_Copy int ;
clob_Length pls_integer := dbms_lob.getLength(clobValue);
begin
dbms_lob.open(BlobValue,dbms_lob.lob_readwrite);
--Length_To_Copy := least(1000,(clob_Length - Position) + 1);
While (Position <= clob_Length ) loop
Length_To_Copy := least(1000,(clob_Length - Position) + 1);
Temp_Buffer := utl_raw.cast_to_raw(dbms_lob.substr(clobValue,Length_To_Copy,Position));
If utl_raw.length(Temp_Buffer) > 0 then
dbms_lob.writeappend(BlobValue,utl_raw.length(Temp_Buffer),Temp_Buffer);
end if;
Position := Position + Length_To_Copy;
--Length_To_Copy := least(1000,(clob_Length - Position) + 1);
end loop;
dbms_lob.close(BlobValue);
end;
/
In order to test the above code look at this example.Lets assume you have a table called TABLE_NAME with a clob column called CLOB_COLUMN
Declare
b blob;
Begin
For cTemp in ( Select clob_column from table_name ) loop
Begin
b := null;
Insert into TABLE_NAME2(BLOB_COLUMN) values (empty_blob())
returning BLOB_COLUMN into b;
Convert_Clob_To_Blob (cTemp.clob_column,b);
end;
end loop;
Commit;
end;
/
Thursday, August 14, 2008
Oracle: How to retrieve DDL of any object
Select dbms_metadata.get_ddl('TABLE','TABLE_NAME') from dual
Some key parameters for get_ddl
object_type - The type of object to be retrieved. ex: TABLE, TABLESPACE,INDEX etc
object_name - Name of the object.
object_schema- Schema containing the object. Defaults to the caller's schema.
ex: Select dbms_metadata.get_ddl ('TABLE','EMPLOYEE','SCOTT') from dual
Some key parameters for get_ddl
object_type - The type of object to be retrieved. ex: TABLE, TABLESPACE,INDEX etc
object_name - Name of the object.
object_schema- Schema containing the object. Defaults to the caller's schema.
ex: Select dbms_metadata.get_ddl ('TABLE','EMPLOYEE','SCOTT') from dual
Oracle: How to retrieve DDL of any object
Select dbms_metadata.get_ddl('TABLE','TABLE_NAME') from dual
Some key parameters for get_ddl
object_type - The type of object to be retrieved. ex: TABLE, TABLESPACE,INDEX etc
object_name - Name of the object.
object_schema- Schema containing the object. Defaults to the caller's schema.
ex: Select dbms_metadata.get_ddl ('TABLE','EMPLOYEE','SCOTT') from dual
Some key parameters for get_ddl
object_type - The type of object to be retrieved. ex: TABLE, TABLESPACE,INDEX etc
object_name - Name of the object.
object_schema- Schema containing the object. Defaults to the caller's schema.
ex: Select dbms_metadata.get_ddl ('TABLE','EMPLOYEE','SCOTT') from dual
Tuesday, August 12, 2008
Monday, August 11, 2008
Toad: Debug menu grayed out (cannot debug any procedure)
Even if you have Toad XPert Edition or Toad with DBA Module, I sometime find the debug menu grayed out. Even If I create a new proceudre, It's still grayed out. If you get this issue, try the following and reconnect.
Issue Debug Connect Sesstion to your user as SYS or System.
Grant DEBUG CONNECT SESSION TO schema_owner
Replace Schema_Owner with your user name.
Log out and Log back in, Now Toad Debug menu will be available.
Another workaround is to give DBA Privs which is not recommended.
Issue Debug Connect Sesstion to your user as SYS or System.
Grant DEBUG CONNECT SESSION TO schema_owner
Replace Schema_Owner with your user name.
Log out and Log back in, Now Toad Debug menu will be available.
Another workaround is to give DBA Privs which is not recommended.
Toad: Debug menu grayed out (cannot debug any procedure)
Even if you have Toad XPert Edition or Toad with DBA Module, I sometime find the debug menu grayed out. Even If I create a new proceudre, It's still grayed out. If you get this issue, try the following and reconnect.
Issue Debug Connect Sesstion to your user as SYS or System.
Grant DEBUG CONNECT SESSION TO schema_owner
Replace Schema_Owner with your user name.
Log out and Log back in, Now Toad Debug menu will be available.
Another workaround is to give DBA Privs which is not recommended.
Issue Debug Connect Sesstion to your user as SYS or System.
Grant DEBUG CONNECT SESSION TO schema_owner
Replace Schema_Owner with your user name.
Log out and Log back in, Now Toad Debug menu will be available.
Another workaround is to give DBA Privs which is not recommended.
Friday, August 8, 2008
Wednesday, August 6, 2008
Oracle: How to generate N sequential numbers
How to generate N sequential numbers using sql
select level from
dual
connect by level < N
Replace N by whatever number you want.
select level from dual connect by level <> 50
select level from
dual
connect by level < N
Replace N by whatever number you want.
select level from dual connect by level <> 50
Oracle: How to generate N sequential numbers
How to generate N sequential numbers using sql
select level from
dual
connect by level < N
Replace N by whatever number you want.
select level from dual connect by level <> 50
select level from
dual
connect by level < N
Replace N by whatever number you want.
select level from dual connect by level <> 50
LDAP: In a nutshell
LDAP Lightweight Directory Access Protocol (Based on X 500 Standard)
LDAP --> Protocol to retrieve data stored in information directory, which is heavily optimized for read performance.
LDAP --> Allows you to securely delegate read and modification authority based on your specific needs using ACIs (collectively, an ACL, or Access Control List).
LDAP --> Tree Structure
Top level node called base DN (Distinguished Name)
Base DN in one of the 3 formats (for foobar company in US)
o="company name",c=Country
ex: o="foobar,Inc", c=US
(not preferred now a days,as no place to put website name)
o="website of the company"
ex: o=foobar.com (most common as straight forward)
dc=compnay, dc = com
ex: dc=foobar,dc=com
(used nowadays, Microsoft Acive Directory uses this format)
Here o=>organisation, c=>country,dc=>domain components
Under root base DN, Create nodes that logically seperate your data.
For Historic reasons (X500),These logical components are set up as OU,CN
OU=>Origanizational Unit
CN=>Common Name
All entires in LDAP have a unique DN and this DN is composed of 2 parts, RDN(Relative) and lcoation within the ldap direcotry where the record resides.
RDN is the portion of your DN that is not related to the directory tree structure.
Most entries stored in ldap will have a name, they are stored as CN
Most objects stored in LDAP will use CN value as RDN
So, If I want to store recipie for Oatmeal raisin
ex:
dc=foobar, dc=com
- ou=recipie
-- cn=oatmeal raisin
So, the full DN for the LDAP record is (Remeber it read it backwards) cn=oatmeal raisin,ou=recipie,dc=foobar,dc=com
Typically to store employee logins either CN is used store their name or UID is used to store the login
ex: dc=abclondon,dc=com
-ou=london
--cn="ramesh manni" or uid="rmanni" ----> name-based or login-based
LDAP stores all information for a given record as key-value pairs
ex:
dn: cn=Oatmeal Deluxe, ou=recipes, dc=foobar, dc=com
cn: Instant Oatmeal Deluxe
recipeCuisine: breakfast
recipeIngredient: 1 packet instant oatmeal
recipeIngredient: 1 cup water
recipeIngredient: 1 pinch salt
recipeIngredient: 1 tsp brown sugar
recipeIngredient: 1/4 apple, any type
Searches against these attribute/value pairs are case insensitive excpet for passwords
LDAP --> Protocol to retrieve data stored in information directory, which is heavily optimized for read performance.
LDAP --> Allows you to securely delegate read and modification authority based on your specific needs using ACIs (collectively, an ACL, or Access Control List).
LDAP --> Tree Structure
Top level node called base DN (Distinguished Name)
Base DN in one of the 3 formats (for foobar company in US)
o="company name",c=Country
ex: o="foobar,Inc", c=US
(not preferred now a days,as no place to put website name)
o="website of the company"
ex: o=foobar.com (most common as straight forward)
dc=compnay, dc = com
ex: dc=foobar,dc=com
(used nowadays, Microsoft Acive Directory uses this format)
Here o=>organisation, c=>country,dc=>domain components
Under root base DN, Create nodes that logically seperate your data.
For Historic reasons (X500),These logical components are set up as OU,CN
OU=>Origanizational Unit
CN=>Common Name
All entires in LDAP have a unique DN and this DN is composed of 2 parts, RDN(Relative) and lcoation within the ldap direcotry where the record resides.
RDN is the portion of your DN that is not related to the directory tree structure.
Most entries stored in ldap will have a name, they are stored as CN
Most objects stored in LDAP will use CN value as RDN
So, If I want to store recipie for Oatmeal raisin
ex:
dc=foobar, dc=com
- ou=recipie
-- cn=oatmeal raisin
So, the full DN for the LDAP record is (Remeber it read it backwards) cn=oatmeal raisin,ou=recipie,dc=foobar,dc=com
Typically to store employee logins either CN is used store their name or UID is used to store the login
ex: dc=abclondon,dc=com
-ou=london
--cn="ramesh manni" or uid="rmanni" ----> name-based or login-based
LDAP stores all information for a given record as key-value pairs
ex:
dn: cn=Oatmeal Deluxe, ou=recipes, dc=foobar, dc=com
cn: Instant Oatmeal Deluxe
recipeCuisine: breakfast
recipeIngredient: 1 packet instant oatmeal
recipeIngredient: 1 cup water
recipeIngredient: 1 pinch salt
recipeIngredient: 1 tsp brown sugar
recipeIngredient: 1/4 apple, any type
Searches against these attribute/value pairs are case insensitive excpet for passwords
Monday, August 4, 2008
Oracle: Regular Expression: Examples
How to split strings like "ABC Company (XXX)" into "ABC Company", "XXX"
Select col1, regexp_substr(col1,'[^(]*') Comp_Name,
ltrim(regexp_substr(col1,'\([^)]*'),'(') comp_code
from ( Select 'ABC Company (XXX)' col1 from dual ).
Script does 3 things
1) For name, It takes everything till it hits '('
2) For Code, it takes everything from '(' [you need to escape open paranthesis symbol], till it finds the closing parenthesis ')'.
3) Ltrim is to remove the Open parenthesis in the code.
Select col1, regexp_substr(col1,'[^(]*') Comp_Name,
ltrim(regexp_substr(col1,'\([^)]*'),'(') comp_code
from ( Select 'ABC Company (XXX)' col1 from dual ).
Script does 3 things
1) For name, It takes everything till it hits '('
2) For Code, it takes everything from '(' [you need to escape open paranthesis symbol], till it finds the closing parenthesis ')'.
3) Ltrim is to remove the Open parenthesis in the code.
Oracle: Regular Expression: Examples
How to split strings like "ABC Company (XXX)" into "ABC Company", "XXX"
Select col1, regexp_substr(col1,'[^(]*') Comp_Name,
ltrim(regexp_substr(col1,'\([^)]*'),'(') comp_code
from ( Select 'ABC Company (XXX)' col1 from dual ).
Script does 3 things
1) For name, It takes everything till it hits '('
2) For Code, it takes everything from '(' [you need to escape open paranthesis symbol], till it finds the closing parenthesis ')'.
3) Ltrim is to remove the Open parenthesis in the code.
Select col1, regexp_substr(col1,'[^(]*') Comp_Name,
ltrim(regexp_substr(col1,'\([^)]*'),'(') comp_code
from ( Select 'ABC Company (XXX)' col1 from dual ).
Script does 3 things
1) For name, It takes everything till it hits '('
2) For Code, it takes everything from '(' [you need to escape open paranthesis symbol], till it finds the closing parenthesis ')'.
3) Ltrim is to remove the Open parenthesis in the code.
Regular Expression: How to split comma seperated values using sql
Lets create a table first and insert few comma seperated rows.
1) create table tab1 (owner number, cars varchar2(200));
2) insert into tab1 (
select 1, 'Ford,Toyota,Nissan' from dual union all
select 2, 'Lexus,Mercedes,BMW,Infiniti' from dual union all
select 3, 'Ferrari' from dual union all
select 4, 'Porsche,Lotus,Lamborghini,Maserati,Aston Martin' from dual union all
select 5, 'Maybach,Bentley' from dual);
3) select owner, cars str from tab1;
Now here is the sql to split.
select owner, car
from ( select owner, regexp_substr(str, '[^,]+', 1, level) car,
level lv, lag(level, 1, 0) over (partition by owner order by level) lg
from ( select owner, cars str from tab1 )
connect by regexp_substr(str, '[^,]+', 1, level) is not null
)
where lv != lg;
Replace"," in [^,] with your delimiter
1) create table tab1 (owner number, cars varchar2(200));
2) insert into tab1 (
select 1, 'Ford,Toyota,Nissan' from dual union all
select 2, 'Lexus,Mercedes,BMW,Infiniti' from dual union all
select 3, 'Ferrari' from dual union all
select 4, 'Porsche,Lotus,Lamborghini,Maserati,Aston Martin' from dual union all
select 5, 'Maybach,Bentley' from dual);
3) select owner, cars str from tab1;
Now here is the sql to split.
select owner, car
from ( select owner, regexp_substr(str, '[^,]+', 1, level) car,
level lv, lag(level, 1, 0) over (partition by owner order by level) lg
from ( select owner, cars str from tab1 )
connect by regexp_substr(str, '[^,]+', 1, level) is not null
)
where lv != lg;
Replace"," in [^,] with your delimiter
Thursday, July 31, 2008
Regular Expression
Regular Expression Glossary
Table 1: Anchoring Metacharacters
Table 2: Quantifiers, or Repetition Operators
Table 3: Predefined POSIX Character Classes
Table 4: Alternate Matching and Grouping of Expressions
Table 1: Anchoring Metacharacters
Metacharacter | Description |
^ | Anchor the expression to the start of a line |
$ | Anchor the expression to the end of a line |
Table 2: Quantifiers, or Repetition Operators
Quantifier | Description |
* | Match 0 or more times |
? | Match 0 or 1 time |
+ | Match 1 or more times |
{m} | Match exactly m times |
{m,} | Match at least m times |
{m, n} | Match at least m times but no more than n times |
Character Class | Description |
[:alpha:] | Alphabetic characters |
[:lower:] | Lowercase alphabetic characters |
[:upper:] | Uppercase alphabetic characters |
[:digit:] | Numeric digits |
[:alnum:] | Alphanumeric characters |
[:space:] | Space characters (nonprinting), such as carriage return, newline, vertical tab, and form feed |
[:punct:] | Punctuation characters |
[:cntrl:] | Control characters (nonprinting) |
[:print:] | Printable characters |
Metacharacter | Description | |
| | Alternation | Separates alternates, often used with grouping operator () |
( ) | Group | Groups subexpression into a unit for alternations, for quantifiers, or for backreferencing (see "Backreferences" section) |
[char] | Character list | Indicates a character list; most metacharacters inside a character list are understood as literals, with the exception of character classes, and the ^ and - metacharacters |
Table 5: The REGEXP_LIKE Operator
Syntax | Description |
[, match_parameter]) | source_string supports character datatypes (CHAR, VARCHAR2, CLOB, NCHAR, NVARCHAR2, and NCLOB but not LONG). The pattern parameter is another name for the regular expression. match_parameter allows optional parameters such as handling the newline character, retaining multiline formatting, and providing control over case-sensitivity. |
Table 6: The REGEXP_INSTR Function
Syntax | Description |
[, start_position [, occurrence [, return_option [, match_parameter]]]]) | This function looks for a pattern and returns the first position of the pattern. Optionally, you can indicate the start_position you want to begin the search. The occurrence parameter defaults to 1 unless you indicate that you are looking for a subsequent occurrence. The default value of the return_option is 0, which returns the starting position of the pattern; a value of 1 returns the starting position of the next character following the match. |
Table 7: Explanation of 5-digit + 4 Zip-Code Expression
Syntax | Description |
Empty space that must be matched | |
[:digit:] | POSIX numeric digit class |
] | End of character list |
{5} | Repeat exactly five occurrences of the character list |
( | Start of subexpression |
- | A literal hyphen, because it is not a range metacharacter inside a character list |
[ | Start of character list |
[:digit:] | POSIX [:digit:] class |
[ | Start of character list |
] | End of character list |
{4} | Repeat exactly four occurrences of the character list |
) | Closing parenthesis, to end the subexpression |
? | The ? quantifier matches the grouped subexpression 0 or 1 time thus making the 4-digit code optional |
$ | Anchoring metacharacter, to indicate the end of the line |
Table 8: The REGEXP_SUBSTR Function
Syntax | Description |
[, position [, occurrence [, match_parameter]]]) | The REGEXP_SUBSTR function returns the substring that matches the pattern. |
Table 9: The REGEXP_REPLACE Function
Syntax | Description |
[, replace_string [, position [,occurrence, [match_parameter]]]]) | This function replaces the matching pattern with a specified replace_string, allowing complex search-and-replace operations. |
Table 10: Backreference Metacharacter
Metacharacter | Description | |
\digit | Backslash | Followed by a digit between 1 and 9, the backslash matches the preceding digit-th parenthesized subexpression. (Note: The backslash has another meaning in regular expressions; depending on the context it can also mean the Escape character |
Table 11: Explanation of Pattern-Swap Regular Expression
Regular-Expression Item | Description |
( | Start of first subexpression |
. | Match any single character except a newline |
* | Repetition operator, matches previous . metacharacter 0 to n times |
) | End of first subexpression; result of the match is captured in \1 (In this example, it's Ellen.) |
Empty space that needs to be present | |
( | Start of the second subexpression |
. | Match any single character except a newline |
* | Repetition operator matches the previous . metacharacter 0 to n times |
) | End of second subexpression; result of this match is captured in \2 (In this example, it stores Hildi.) |
Empty space | |
( | Start of third subexpression |
. | Match any single character except a newline |
* | Repetition operator matches . metacharacter 0 to n times |
) | End of third subexpression; result of this match is captured in \3 (In this example, it holds Smith.) |
Table 12: Explanation of the Social Security Number Regular Expression
Regular-Expression Item | Description |
^ | Start of line character (Regular expression cannot have any leading characters before the match.) |
( | Start subexpression and list alternates separated by the | metacharacter |
[ | Start of character list |
[:digit:] | POSIX numeric digit class |
] | End of character list |
{3} | Repeat exactly three occurrences of character list |
- | A hyphen |
[ | Start of character list |
[:digit:] | POSIX numeric digit class |
] | End of character list |
{2} | Repeat exactly two occurrences of character list |
- | Another hyphen |
[ | Start of character list |
[:digit:] | POSIX numeric digit class |
] | End of character list |
{4} | Repeat exactly four occurrences of character list |
| | Alternation metacharacter; ends the first choice and starts the next alternate expression |
[ | Start of character list |
[:digit:] | POSIX numeric digit class. |
] | End of character list |
{9} | Repeat exactly nine occurrences of character list |
) | Ending parenthesis, to close the subexpression group used for alternation |
$ | Anchoring metacharacter, to indicate the end of the line; no extra characters can follow the pattern |
Saturday, July 26, 2008
Remember them...
My childhood heros
Bahadur
ஈருà®®்பு கை à®®ாயாவி
Thanks to Lion comics/Muthu Comics
Check out this site http://thecomiclinks.blogspot.com/
Bahadur
ஈருà®®்பு கை à®®ாயாவி
Thanks to Lion comics/Muthu Comics
Check out this site http://thecomiclinks.blogspot.com/
Tuesday, July 22, 2008
TELNET: How to use TELNET to test SMTP address
Open Command prompt.Type
Telnet smtp_address port
telnet baby.london.com 25
220 axxx.xx-inc.com ESMTP Service (Lotus Domino Release 6.5.4FP1) ready at Tue, 22 Jul 2008 13:04:57 -0400
ehlo test.com
250-axxx.xx-inc.com Hello test.com ([10.202.10.125]), pleased to meet you
250-HELP
250-SIZE 38154240
250 PIPELINING
MAIL FROM:Admin@test.com
250 Admin@test.com... Sender OK
RCPT TO:RxxxI@Cxxxx.COM
250 Rxxx@Cxxxxxx.COM... Recipient OK
DATA
354 Enter message, end with "." on a line by itself
Subject:test message from telnet. (now hit enter twice)
test message hello mrrame (once done,type a . in the next line and press enter)
.
250 Message accepted for delivery
Now you should get an email
Telnet smtp_address port
telnet baby.london.com 25
220 axxx.xx-inc.com ESMTP Service (Lotus Domino Release 6.5.4FP1) ready at Tue, 22 Jul 2008 13:04:57 -0400
ehlo test.com
250-axxx.xx-inc.com Hello test.com ([10.202.10.125]), pleased to meet you
250-HELP
250-SIZE 38154240
250 PIPELINING
MAIL FROM:Admin@test.com
250 Admin@test.com... Sender OK
RCPT TO:RxxxI@Cxxxx.COM
250 Rxxx@Cxxxxxx.COM... Recipient OK
DATA
354 Enter message, end with "." on a line by itself
Subject:test message from telnet. (now hit enter twice)
test message hello mrrame (once done,type a . in the next line and press enter)
.
250 Message accepted for delivery
Now you should get an email
Monday, July 21, 2008
Oracle: Listener.ora / tnsnames.ora / Sqlnet.ora
TNSNames.ora
This file sits on client side. It provides an alias for the client to refer the database.This file will mention the protocol (TCP), Host (database server name) and the port number (default 1521)
SQLNet.ora
This file also sits on the client side. This file contains client side network configuration
parameters. You can specify
1) client domain to append to unqualified names
2) prioritize naming methods
3) Enable logging & Tracing
Listener.Ora
From 9i this file is optional. By default Oracle uses "LISTENER" to listen to the default port 1521. Usually contains
1) Listener name
2) Protocol address that it is acceptiong connection requests
3) Service its listening (SID_LIST_LISTENER).This is optional from 9i
Friday, July 18, 2008
How to capture %ERRORLEVEL% value
In Windows OS, Application's return value is stored in a system variable %ERRORLEVEL%
Sample Code //filename.cs
using System;
namespace Test
{
class TEST
{
static int Main(string[] args)
{
Console.WriteLine("Hello");
foreach(string s in args)
{ Console.WriteLine(s);
}
Console.ReadLine();
return -1;
}
}
}
Compile the above file ex: csc /t:exe filename.cs
Create a batch file with the following content
@echo off
rem testing application
@if "%ERRORLEVEL%" == "0" goto success
:fail
echo This application has failed!
echo return value = %ERRORLEVEL%
goto end
:success
echo This application has succeeded!
echo return value = %ERRORLEVEL%
goto end
:end
echo All Done.
ECHO "END"
Now run the exe and the batch file.
Sample Code //filename.cs
using System;
namespace Test
{
class TEST
{
static int Main(string[] args)
{
Console.WriteLine("Hello");
foreach(string s in args)
{ Console.WriteLine(s);
}
Console.ReadLine();
return -1;
}
}
}
Compile the above file ex: csc /t:exe filename.cs
Create a batch file with the following content
@echo off
rem testing application
@if "%ERRORLEVEL%" == "0" goto success
:fail
echo This application has failed!
echo return value = %ERRORLEVEL%
goto end
:success
echo This application has succeeded!
echo return value = %ERRORLEVEL%
goto end
:end
echo All Done.
ECHO "END"
Now run the exe and the batch file.
Wednesday, July 16, 2008
Oracle: How to use CURSOR Expression in PL/SQL
CREATE OR REPLACE Procedure aaa as
Cursor cCtry Is Select countrykey,countrycode ,cursor (Select casereference from cases c where c.countrykey = t.countrykey )
from tablecountry t;
nCtrykey tablecountry.countrykey%type;
sCtryCode tablecountry.countrycode%type ;
caseee sys_refcursor;
type tCase_ref is table of cases.casereference%type index by pls_integer;
tCaseRef tCase_ref;
begin
Open cCtry;
loop
Fetch cCtry into nCtrykey,sCtryCode,caseee;
exit when cCtry%notfound;
fetch caseee bulk collect into tCaseRef;
for i in tCaseRef.first.. tCaseRef.last loop
null;
--Do Something
end loop;
end loop;
Close cCtry;
end;
/
Windows Explorer: How to show REGISTER in right click Menu
Save the content below as filename.reg format and double click. This will allow Right click Register dll files.
---Copy from next line (not this line) ---
REGEDIT4
[HKEY_CLASSES_ROOT\.exe]
@="exefile"
[HKEY_CLASSES_ROOT\.dll]
@="dllfile"
[HKEY_CLASSES_ROOT\.ocx]
@="ocxfile"
[HKEY_CLASSES_ROOT\.olb]
@="olbfile"
[HKEY_CLASSES_ROOT\exefile\shell\Register\command]
@="%1 /register"
[HKEY_CLASSES_ROOT\dllfile\shell\Register\command]
@="regsvr32.exe %1"
[HKEY_CLASSES_ROOT\ocxfile\shell\Register\command]
@="regsvr32.exe %1"
[HKEY_CLASSES_ROOT\olbfile\shell\Register\command]
@="regsvr32.exe %1"
[HKEY_CLASSES_ROOT\dllfile\shell\Silent Register\command]
@="regsvr32.exe /s %1"
[HKEY_CLASSES_ROOT\ocxfile\shell\Silent Register\command]
@="regsvr32.exe /s %1"
[HKEY_CLASSES_ROOT\olbfile\shell\Silent Register\command]
@="regsvr32.exe /s %1"
[HKEY_CLASSES_ROOT\exefile\shell\UnRegister\command]
@="%1 /unregister"
[HKEY_CLASSES_ROOT\dllfile\shell\UnRegister\command]
@="regsvr32.exe /u %1"
[HKEY_CLASSES_ROOT\ocxfile\shell\UnRegister\command]
@="regsvr32.exe /u %1"
[HKEY_CLASSES_ROOT\olbfile\shell\UnRegister\command]
@="regsvr32.exe /u %1"
[HKEY_CLASSES_ROOT\dllfile\shell\Silent UnRegister\command]
@="regsvr32.exe /u /s %1"
[HKEY_CLASSES_ROOT\ocxfile\shell\Silent UnRegister\command]
@="regsvr32.exe /u /s %1"
[HKEY_CLASSES_ROOT\olbfile\shell\Silent UnRegister\command]
@="regsvr32.exe /u /s %1"
---Do not Copy this line ---
---Copy from next line (not this line) ---
REGEDIT4
[HKEY_CLASSES_ROOT\.exe]
@="exefile"
[HKEY_CLASSES_ROOT\.dll]
@="dllfile"
[HKEY_CLASSES_ROOT\.ocx]
@="ocxfile"
[HKEY_CLASSES_ROOT\.olb]
@="olbfile"
[HKEY_CLASSES_ROOT\exefile\shell\Register\command]
@="%1 /register"
[HKEY_CLASSES_ROOT\dllfile\shell\Register\command]
@="regsvr32.exe %1"
[HKEY_CLASSES_ROOT\ocxfile\shell\Register\command]
@="regsvr32.exe %1"
[HKEY_CLASSES_ROOT\olbfile\shell\Register\command]
@="regsvr32.exe %1"
[HKEY_CLASSES_ROOT\dllfile\shell\Silent Register\command]
@="regsvr32.exe /s %1"
[HKEY_CLASSES_ROOT\ocxfile\shell\Silent Register\command]
@="regsvr32.exe /s %1"
[HKEY_CLASSES_ROOT\olbfile\shell\Silent Register\command]
@="regsvr32.exe /s %1"
[HKEY_CLASSES_ROOT\exefile\shell\UnRegister\command]
@="%1 /unregister"
[HKEY_CLASSES_ROOT\dllfile\shell\UnRegister\command]
@="regsvr32.exe /u %1"
[HKEY_CLASSES_ROOT\ocxfile\shell\UnRegister\command]
@="regsvr32.exe /u %1"
[HKEY_CLASSES_ROOT\olbfile\shell\UnRegister\command]
@="regsvr32.exe /u %1"
[HKEY_CLASSES_ROOT\dllfile\shell\Silent UnRegister\command]
@="regsvr32.exe /u /s %1"
[HKEY_CLASSES_ROOT\ocxfile\shell\Silent UnRegister\command]
@="regsvr32.exe /u /s %1"
[HKEY_CLASSES_ROOT\olbfile\shell\Silent UnRegister\command]
@="regsvr32.exe /u /s %1"
---Do not Copy this line ---
Tuesday, July 15, 2008
JavaScript: Create Advanced Web Applications With Object-Oriented Techniques Author: Ray Djajadinata
This article discusses:
| This article uses the following technologies: JavaScript |
Contents
JavaScript Objects Are Dictionaries
JavaScript Functions Are First Class
Constructor Functions but No Classes
Prototypes
Static Properties and Methods
Closures
Simulating Private Properties
Inheriting from Classes
Simulating Namespaces
Should You Code JavaScript This Way?
Putting It into Perspective
JavaScript Functions Are First Class
Constructor Functions but No Classes
Prototypes
Static Properties and Methods
Closures
Simulating Private Properties
Inheriting from Classes
Simulating Namespaces
Should You Code JavaScript This Way?
Putting It into Perspective
Recently I interviewed a software developer with five years experience in developing Web applications. She’d been doing JavaScript for four and a half years, she rated her JavaScript skill as very good, and—as I found out soon after—she actually knew very little about JavaScript. I didn’t really blame her for that, though. JavaScript is funny that way. It’s the language a lot of people (including myself, until recently!) assume they’re good at, just because they know C/C++/C# or they have some prior programming experience.
In a way, that assumption is not entirely groundless. It is easy to do simple things with JavaScript. The barrier to entry is very low; the language is forgiving and doesn’t require you to know a lot of things before you can start coding in it. Even a non-programmer can probably pick it up and write some useful scripts for a homepage in a matter of hours.
Indeed, until recently, I’d always been able to get by with whatever little JavaScript I knew, armed only with the MSDN® DHTML reference and my C++/C# experience. It was only when I started working on real-world AJAX applications that I realized how inadequate my JavaScript actually was. The complexity and interactivity of this new generation of Web applications requires a totally different approach to writing JavaScript code. These are serious JavaScript applications! The way we’ve been writing our throwaway scripts simply doesn’t cut it anymore.
Object-oriented programming (OOP) is one popular approach that’s used in many JavaScript libraries to make a codebase more manageable and maintainable. JavaScript supports OOP, but it does so in a very different manner from the way popular Microsoft® .NET Framework compliant languages like C++, C#, or Visual Basic® do it, so developers who have been working extensively with those languages may find doing OOP in JavaScript strange and counter-intuitive at first. I wrote this article to discuss in depth how the JavaScript language really supports object-oriented programming and how you can use this support to do object-oriented development effectively in JavaScript. Let’s start by talking about (what else?) objects.
JavaScript Objects Are Dictionaries
In C++ or C#, when we’re talking about objects, we’re referring to instances of classes or structs. Objects have different properties and methods, depending on which templates (that is, classes) they are instantiated from. That’s not the case with JavaScript objects. In JavaScript, objects are just collections of name/value pairs—think of a JavaScript object as a dictionary with string keys. We can get and set the properties of an object using either the familiar "." (dot) operator, or the "[]" operator, which is typically used when dealing with a dictionary. The following snippet
var userObject = new Object();
userObject.lastLoginTime = new Date();
alert(userObject.lastLoginTime);
var userObject = {}; // equivalent to new Object()
userObject[“lastLoginTime”] = new Date();
alert(userObject[“lastLoginTime”]);
var userObject = { “lastLoginTime”: new Date() };
alert(userObject.lastLoginTime);
Note how similar it is to the C# 3.0 object initializers. Also, those of you familiar with Python will recognize that the way we instantiate userObject in the second and third snippets is exactly how we’d specify a dictionary in Python. The only difference is that a JavaScript object/dictionary only accepts string keys, rather than hashable objects like a Python dictionary would.
These examples also show how much more malleable JavaScript objects are than C++ or C# objects. Property lastLoginTime doesn’t have to be declared beforehand—if userObject doesn’t have a property by that name, it will simply be added to userObject. This isn’t surprising if you remember that a JavaScript object is a dictionary—after all, we add new keys (and their respective values) to dictionaries all the time.
So, there we have object properties. How about object methods? Again, JavaScript is different from C++/C#. To understand object methods, I first need to take a closer look at JavaScript functions.
JavaScript Functions Are First Class
In many programming languages, functions and objects are usually considered two different things. In JavaScript, this distinction is blurred—a JavaScript function is really an object with executable code associated with it. Consider an ordinary function like this:
function func(x) {
alert(x);
}
func(“blah”);
var func = function(x) {
alert(x);
};
func(“blah2”);
var func = new Function(“x”, “alert(x);”);
func(“blah3”);
This shows that a function is really just an object that supports a function call operation. That last way of defining a function using the Function constructor is not commonly used, but it opens up interesting possibilities because, as you may notice, the body of the function is just a String parameter to the Function constructor. That means you can construct arbitrary functions at run time.
To demonstrate further that a function is an object, you can set or add properties to a function, just like you would to any other JavaScript objects:
function sayHi(x) {
alert(“Hi, “ + x + “!”);
}
sayHi.text = “Hello World!”;
sayHi[“text2”] = “Hello World... again.”;
alert(sayHi[“text”]); // displays “Hello World!”
alert(sayHi.text2); // displays “Hello World... again.”
As objects, functions can also be assigned to variables, passed as arguments to other functions, returned as the values of other functions, stored as properties of objects or elements of arrays, and so on. Figure 1 provides an example of this.
Figure 1 Functions Are First-Class in JavaScript
// assign an anonymous function to a variable var greet = function(x) { alert(“Hello, “ + x); }; greet(“MSDN readers”); // passing a function as an argument to another function square(x) { return x * x; } function operateOn(num, func) { return func(num); } // displays 256 alert(operateOn(16, square)); // functions as return values function makeIncrementer() { return function(x) { return x + 1; }; } var inc = makeIncrementer(); // displays 8 alert(inc(7)); // functions stored as array elements var arr = []; arr[0] = function(x) { return x * x; }; arr[1] = arr[0](2); arr[2] = arr[0](arr[1]); arr[3] = arr[0](arr[2]); // displays 256 alert(arr[3]); // functions as object properties var obj = { “toString” : function() { return “This is an object.”; } }; // calls obj.toString() alert(obj);
With that in mind, adding methods to an object is as easy as choosing a name and assigning a function to that name. So I define three methods in the object by assigning anonymous functions to the respective method names:
var myDog = {
“name” : “Spot”,
“bark” : function() { alert(“Woof!”); },
“displayFullName” : function() {
alert(this.name + “ The Alpha Dog”);
},
“chaseMrPostman” : function() {
// implementation beyond the scope of this article
}
};
myDog.displayFullName();
myDog.bark(); // Woof!
The use of the "this" keyword inside the function displayFullName should be familiar to the C++/C# developers among us—it refers to the object through which the method is called ( developers who use Visual Basic should find it familiar, too—it’s called "Me" in Visual Basic). So in the example above, the value of "this" in the displayFullName is the myDog object. The value of "this" is not static, though. Called through a different object, the value of "this" will also change to point to that object as Figure 2 demonstrates.
Figure 2 “this” Changes as the Object Changes
function displayQuote() { // the value of “this” will change; depends on // which object it is called through alert(this.memorableQuote); } var williamShakespeare = { “memorableQuote”: “It is a wise father that knows his own child.”, “sayIt” : displayQuote }; var markTwain = { “memorableQuote”: “Golf is a good walk spoiled.”, “sayIt” : displayQuote }; var oscarWilde = { “memorableQuote”: “True friends stab you in the front.” // we can call the function displayQuote // as a method of oscarWilde without assigning it // as oscarWilde’s method. //”sayIt” : displayQuote }; williamShakespeare.sayIt(); // true, true markTwain.sayIt(); // he didn’t know where to play golf // watch this, each function has a method call() // that allows the function to be called as a // method of the object passed to call() as an // argument. // this line below is equivalent to assigning // displayQuote to sayIt, and calling oscarWilde.sayIt(). displayQuote.call(oscarWilde); // ouch!
The last line in Figure 2 shows an alternative way of calling a function as a method of an object. Remember, a function in JavaScript is an object. Every function object has a method named call, which calls the function as a method of the first argument. That is, whichever object we pass into call as its first argument will become the value of "this" in the function invocation. This will be a useful technique for calling the base class constructor, as we’ll see later.
One thing to remember is never to call functions that contain "this" without an owning object. If you do, you will be trampling over the global namespace, because in that call, "this" will refer to the Global object, and that can really wreak havoc in your application. For example, below is a script that changes the behavior of JavaScript’s global function isNaN. Definitely not recommended!
alert(“NaN is NaN: “ + isNaN(NaN));
function x() {
this.isNaN = function() {
return “not anymore!”;
};
}
// alert!!! trampling the Global object!!!
x();
alert(“NaN is NaN: “ + isNaN(NaN));
So we’ve seen ways to create an object, complete with its properties and methods. But if you notice all the snippets above, the properties and methods are hardcoded within the object definition itself. What if you need more control over the object creation? For example, you may need to calculate the values of the object’s properties based on some parameters. Or you may need to initialize the object’s properties to the values that you’ll only have at run time. Or you may need to create more than one instance of the object, which is a very common requirement.
In C#, we use classes to instantiate object instances. But JavaScript is different since it doesn’t have classes. Instead, as you’ll see in the next section, you take advantage of the fact that functions act as constructors when used together with the "new" operator.
Constructor Functions but No Classes
The strangest thing about JavaScript OOP is that, as noted, JavaScript doesn’t have classes like C# or C++ does. In C#, when you do something like this:
Dog spot = new Dog();
function DogConstructor(name) {
this.name = name;
this.respondTo = function(name) {
if(this.name == name) {
alert(“Woof”);
}
};
}
var spot = new DogConstructor(“Spot”);
spot.respondTo(“Rover”); // nope
spot.respondTo(“Spot”); // yeah!
var spot = new DogConstructor(“Spot”);
What the "new" operator does is simple. First, it creates a new empty object. Then, the function call that immediately follows is executed, with the new empty object set as the value of "this" within that function. In other words, the line above with the "new" operator can be thought of as similar to the two lines below:
// create an empty object
var spot = {};
// call the function as a method of the empty object
DogConstructor.call(spot, “Spot”);
// Think of this as class Dog
function Dog(name) {
// instance variable
this.name = name;
// instance method? Hmmm...
this.respondTo = function(name) {
if(this.name == name) {
alert(“Woof”);
}
};
}
var spot = new Dog(“Spot”);
In the Dog definition above, I defined an instance variable called name. Every object that is created using Dog as its constructor function will have its own copy of the instance variable name (which, as noted earlier, is just an entry into the object’s dictionary). This is expected; after all, each object does need its own copies of instance variables to carry its state. But if you look at the next line, every instance of Dog also has its own copy of the respondTo method, which is a waste; you only need one instance of respondTo to be shared among Dog instances! You can work around the problem by taking the definition of respondTo outside Dog, like this:
function respondTo() {
// respondTo definition
}
function Dog(name) {
this.name = name;
// attached this function as a method of the object
this.respondTo = respondTo;
}
This way, all instances of Dog (that is, all instances created with the constructor function Dog) can share just one instance of the method respondTo. But as the number of methods grow, this becomes harder and harder to maintain. You end up with a lot of global functions in your codebase, and things only get worse as you have more and more "classes," especially if their methods have similar names. There’s a better way to achieve this using the prototype objects, which are the topic of the next section.
Prototypes
The prototype object is a central concept in object-oriented programming with JavaScript. The name comes from the idea that in JavaScript, an object is created as a copy of an existing example (that is, a prototype) object. Any properties and methods of this prototype object will appear as properties and methods of the objects created from that prototype’s constructor. You can say that these objects inherit their properties and methods from their prototype. When you create a new Dog object like this
var buddy = new Dog(“Buddy“);
In JavaScript, every function has a property named "prototype" that refers to a prototype object. This prototype object in turn has a property named "constructor," which refers back to the function itself. It’s sort of a circular reference; Figure 3 illustrates this cyclic relationship better.
Figure 3 Every Function’s Prototype Has a Constructor Property
Now, when a function (in the example above, Dog) is used to create an object with the "new" operator, the resulting object will inherit the properties of Dog.prototype. In Figure 3, you can see that the Dog.prototype object has a constructor property that points back to the Dog function. Consequently, every Dog object (that inherits from Dog.prototype) will also appear to have a constructor property that points back to the Dog function. The code in Figure 4 confirms this. This relationship between constructor function, prototype object, and the object created with them is depicted in Figure 5.
Figure 4 Objects Appear to Have Their Prototype’s Properties
var spot = new Dog(“Spot”); // Dog.prototype is the prototype of spot alert(Dog.prototype.isPrototypeOf(spot)); // spot inherits the constructor property // from Dog.prototype alert(spot.constructor == Dog.prototype.constructor); alert(spot.constructor == Dog); // But constructor property doesn’t belong // to spot. The line below displays “false” alert(spot.hasOwnProperty(“constructor”)); // The constructor property belongs to Dog.prototype // The line below displays “true” alert(Dog.prototype.hasOwnProperty(“constructor”));
Figure 5 Instances Inherit from Their Prototype
Some of you may have noticed the calls to hasOwnProperty and isPrototypeOf method in Figure 4. Where do these methods come from? They don’t come from Dog.prototype. In fact, there are other methods like toString, toLocaleString, and valueOf that we can call on Dog.prototype and instances of Dog, but which don’t come from Dog.prototype at all. It turns out that just like the .NET Framework has System.Object, which serves as the ultimate base class for all classes, JavaScript has Object.prototype, which is the ultimate base prototype for all prototypes. (The prototype of Object.prototype is null.)
In this example, remember that Dog.prototype is an object. It is created with a call to the Object constructor function, although it is not visible:
Dog.prototype = new Object();
So just like instances of Dog inherit from Dog.prototype, Dog.prototype inherits from Object.prototype. This makes all instances of Dog inherit Object.prototype’s methods and properties as well.
Every JavaScript object inherits a chain of prototypes, all of which terminate with Object.prototype. Note that this inheritance you’ve seen so far is inheritance between live objects. It is different from your usual notion of inheritance, which happens between classes when they are declared. Consequently, JavaScript inheritance is much more dynamic. It is done using a simple algorithm, as follows: when you try to access a property/method of an object, JavaScript checks if that property/method is defined in that object. If not, then the object’s prototype will be checked. If not, then that object’s prototype’s prototype will be checked, and so on, all the way to Object.prototype. Figure 6 illustrates this resolution process.
0) this.src=small; if (current.indexOf(small) > 0)this.src=large;">
Figure 6 Resolving toString() Method in the Prototype Chain (Click the image for a larger view)
The way JavaScript resolves properties access and method calls dynamically has some consequences:
- Changes made to a prototype object are immediately visible to the objects that inherit from it, even after these objects are created.
- If you define a property/method X in an object, a property/method of the same name will be hidden in that object’s prototype. For instance, you can override Object.prototype’s toString method by defining a toString method in Dog.prototype.
- Changes only go in one direction, from prototype to its derived objects, but not vice versa.
Figure 7 illustrates these consequences. Figure 7 also shows how to solve the problem of unnecessary method instances as encountered earlier. Instead of having a separate instance of a function object for every object, you can make the objects share the method by putting it inside the prototype. In this example, the getBreed method is shared by rover and spot—until you override the toString method in spot, anyway. After that, spot has its own version of the getBreed method, but the rover object and subsequent objects created with new GreatDane will still share that one instance of the getBreed method defined in the GreatDane.prototype object.
Figure 7 Inheriting from a Prototype
function GreatDane() { } var rover = new GreatDane(); var spot = new GreatDane(); GreatDane.prototype.getBreed = function() { return “Great Dane”; }; // Works, even though at this point // rover and spot are already created. alert(rover.getBreed()); // this hides getBreed() in GreatDane.prototype spot.getBreed = function() { return “Little Great Dane”; }; alert(spot.getBreed()); // but of course, the change to getBreed // doesn’t propagate back to GreatDane.prototype // and other objects inheriting from it, // it only happens in the spot object alert(rover.getBreed());
Static Properties and Methods
Sometimes you need properties or methods that are tied to classes instead of instances—that is, static properties and methods. JavaScript makes this easy, since functions are objects whose properties and methods can be set as desired. Since a constructor function represents a class in JavaScript, you can add static methods and properties to a class simply by setting them in the constructor function like this:
function DateTime() { }
// set static method now()
DateTime.now = function() {
return new Date();
};
alert(DateTime.now());
The syntax for calling the static methods in JavaScript is virtually identical to how you’d do it in C#. This shouldn’t come as a surprise since the name of the constructor function is effectively the name of the class. So you have classes, and you have public properties/methods, and static properties/methods. What else do you need? Private members, of course. But JavaScript doesn’t have native support for private members (nor for protected, for that matter). All properties and methods of an object are accessible to anyone. There is a way to have private members in your class, but to do so you first need to understand closures.
Closures
I didn’t learn JavaScript of my own volition. I had to pick it up quickly because I realized that I was ill-prepared to work on a real-world AJAX application without it. At first, I felt like I had gone down a few levels in the programmer hierarchy. (JavaScript! What would my C++ friends say?) But once I got over my initial resistance, I realized that JavaScript was actually a powerful, expressive, and compact language. It even boasts features that other, more popular languages are only beginning to support.
One of JavaScript’s more advanced features is its support for closures, which C# 2.0 supports through its anonymous methods. A closure is a runtime phenomenon that comes about when an inner function (or in C#, an inner anonymous method) is bound to the local variables of its outer function. Obviously, it doesn’t make much sense unless this inner function is somehow made accessible outside the outer function. An example will make this clearer.
Let’s say you need to filter a sequence of numbers based on a simple criterion that only numbers bigger than 100 can pass, while the rest are filtered out. You can write a function like the one in Figure 8.
Figure 8 Filtering Elements Based on a Predicate
function filter(pred, arr) { var len = arr.length; var filtered = []; // shorter version of new Array(); // iterate through every element in the array... for(var i = 0; i < val =" arr[i];" somerandomnumbers =" [12," numbersgreaterthan100 =" filter("> 100) ? true : false; }, someRandomNumbers); // displays 234, 236, 632 alert(numbersGreaterThan100);
But now you want to create a different filtering criterion, let’s say this time only numbers bigger than 300. You can do something like this:
var greaterThan300 = filter(
function(x) { return (x > 300) ? true : false; },
someRandomNumbers);
And then maybe you need to filter numbers that are bigger than 50, 25, 10, 600, and so on, but then, being the smart person you are, you realize that they’re all the same predicate, "greater than." Only the number is different. So you can factor the number out with a function like this
function makeGreaterThanPredicate(lowerBound) {
return function(numberToCheck) {
return (numberToCheck > lowerBound) ? true : false;
};
}
var greaterThan10 = makeGreaterThanPredicate(10);
var greaterThan100 = makeGreaterThanPredicate(100);
alert(filter(greaterThan10, someRandomNumbers));
alert(filter(greaterThan100, someRandomNumbers));
Watch the inner anonymous function returned by the function makeGreaterThanPredicate. That anonymous inner function uses lowerBound, which is an argument passed to makeGreaterThanPredicate. By the usual rules of scoping, lowerBound goes out of scope when makeGreaterThanPredicate exits! But in this case, that inner anonymous function still carries lowerBound with it, even long after makeGreaterThanPredicate exits. This is what we call closure—because the inner function closes over the environment (that is, the arguments and local variables of the outer function) in which it is defined.
Closures may not seem like a big deal at first. But used properly, they open up interesting new possibilities in the way you can translate your ideas into code. One of the most interesting uses of closures in JavaScript is to simulate private variables of a class.
Simulating Private Properties
OK, so let’s see how closures can help in simulating private members. A local variable in a function is normally not accessible from outside the function. After the function exits, for all practical purposes that local variable is gone forever. However, when that local variable is captured by an inner function’s closure, it lives on. This fact is the key to simulating JavaScript private properties. Consider the following Person class:
function Person(name, age) {
this.getName = function() { return name; };
this.setName = function(newName) { name = newName; };
this.getAge = function() { return age; };
this.setAge = function(newAge) { age = newAge; };
}
The arguments name and age are local to the constructor function Person. The moment Person returns, name and age are supposed to be gone forever. However, they are captured by the four inner functions that are assigned as methods of a Person instance, in effect making name and age live on, but only accessible strictly through these four methods. So you can do this:
var ray = new Person(“Ray”, 31);
alert(ray.getName());
alert(ray.getAge());
ray.setName(“Younger Ray”);
// Instant rejuvenation!
ray.setAge(22);
alert(ray.getName() + “ is now “ + ray.getAge() +
“ years old.”);
Private members that don’t get initialized in the constructor can be local variables of the constructor function, like this:
function Person(name, age) {
var occupation;
this.getOccupation = function() { return occupation; };
this.setOccupation = function(newOcc) { occupation =
newOcc; };
// accessors for name and age
}
Person.prototype.somePublicMethod = function() {
// doesn’t work!
// alert(this.name);
// this one below works
alert(this.getName());
};
Douglas Crockford is widely known as the first person to discover (or perhaps publish) the technique of using closures to simulate private members. His Web site, javascript.crockford.com, contains a wealth of information on JavaScript—any developer interested in JavaScript should check it out.
Inheriting from Classes
OK, you’ve seen how constructor functions and prototype objects allow you to simulate classes in JavaScript. You’ve seen that the prototype chain ensures that all objects have the common methods of Object.prototype. You’ve seen how you can simulate private members of a class using closures. But something is missing here. You haven’t seen how you can derive from your class; that’s an everyday activity in C#. Unfortunately, inheriting from a class in JavaScript is not simply a matter of typing a colon like in C#; it takes more than that. On the other hand, JavaScript is so flexible that there are a lot of ways of inheriting from a class.
Let’s say, for example, you have a base class Pet, with one derived class Dog, as in Figure 9. How do you go about this in JavaScript? The Pet class is easy. You’ve seen how you can do this:
Figure 9 Classes
// class Pet
function Pet(name) {
this.getName = function() { return name; };
this.setName = function(newName) { name = newName; };
}
Pet.prototype.toString = function() {
return “This pet’s name is: “ + this.getName();
};
// end of class Pet
var parrotty = new Pet(“Parrotty the Parrot”);
alert(parrotty);
Now what if you want to create a class Dog, which derives from Pet? As you can see in Figure 9, Dog has an extra property, breed, and it overrides Pet’s toString method (note that convention for JavaScript is to use camel casing for methods and properties names, instead of Pascal casing as is recommended with C#). Figure 10 shows how it is done.
Figure 10 Deriving from the Pet Class
// class Dog : Pet // public Dog(string name, string breed) function Dog(name, breed) { // think Dog : base(name) Pet.call(this, name); this.getBreed = function() { return breed; }; // Breed doesn’t change, obviously! It’s read only. // this.setBreed = function(newBreed) { name = newName; }; } // this makes Dog.prototype inherits // from Pet.prototype Dog.prototype = new Pet(); // remember that Pet.prototype.constructor // points to Pet. We want our Dog instances’ // constructor to point to Dog. Dog.prototype.constructor = Dog; // Now we override Pet.prototype.toString Dog.prototype.toString = function() { return “This dog’s name is: “ + this.getName() + “, and its breed is: “ + this.getBreed(); }; // end of class Dog var dog = new Dog(“Buddy”, “Great Dane”); // test the new toString() alert(dog); // Testing instanceof (similar to the is operator) // (dog is Dog)? yes alert(dog instanceof Dog); // (dog is Pet)? yes alert(dog instanceof Pet); // (dog is Object)? yes alert(dog instanceof Object);
The prototype-replacement trick used sets the prototype chain properly, so instanceof tests work as expected if you were using C#. Also, the privileged methods still work as expected.
Simulating Namespaces
In C++ and C#, namespaces are used to minimize the probability of name collisions. In the .NET Framework, namespaces help differentiate Microsoft.Build.Task.Message class from System.Messaging.Message, for example. JavaScript doesn’t have any specific language features to support namespaces, but it’s easy to simulate a namespace using objects. Let’s say you want to create a JavaScript library. Instead of defining functions and classes globally, you can wrap them in a namespace like this:
var MSDNMagNS = {};
MSDNMagNS.Pet = function(name) { // code here };
MSDNMagNS.Pet.prototype.toString = function() { // code };
var pet = new MSDNMagNS.Pet(“Yammer”);
One level of namespace may not be unique, so you can create nested namespaces:
var MSDNMagNS = {};
// nested namespace “Examples”
MSDNMagNS.Examples = {};
MSDNMagNS.Examples.Pet = function(name) { // code };
MSDNMagNS.Examples.Pet.prototype.toString = function() { // code };
var pet = new MSDNMagNS.Examples.Pet(“Yammer”);
// MSDNMagNS.Examples and Pet definition...
// think “using Eg = MSDNMagNS.Examples;”
var Eg = MSDNMagNS.Examples;
var pet = new Eg.Pet(“Yammer”);
alert(pet);
If you take a look at the source code of the Microsoft AJAX Library, you’ll see that the library’s authors use a similar technique to implement namespaces (take a look at the implementation of the static method Type.registerNamespace). See the sidebar "OOP and ASP.NET AJAX" for more information.
Should You Code JavaScript This Way?
You’ve seen that JavaScript supports object-oriented programming just fine. Although it was designed as a prototype-based language, it is flexible and powerful enough to accommodate the class-based programming style that is typically found in other popular languages. But the question is: should you code JavaScript this way? Should you code in JavaScript the way you code in C# or C++, coming up with clever ways to simulate features that aren’t there? Each programming language is different, and the best practices for one language may not be the best practices for another.
In JavaScript, you’ve seen that objects inherit from objects (as opposed to classes inheriting from classes). So it is possible that making a lot of classes using a static inheritance hierarchy is not the JavaScript way. Maybe, as Douglas Crockford says in his article "Prototypal Inheritance in JavaScript", the JavaScript way of programming is to make prototype objects, and use the simple object function below to make new objects, which inherit from that original object:
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
This is all good, but it is undeniable that the majority of developers worldwide are more familiar with class-based programming. Class-based programming is here to stay, in fact. According to the upcoming edition 4 of ECMA-262 specification (ECMA-262 is the official specification for JavaScript), JavaScript 2.0 will have true classes. So JavaScript is moving towards being a class-based language. However, it will probably take years for JavaScript 2.0 to reach widespread use. In the meantime, it’s important to know the current JavaScript well enough to read and write JavaScript code in both prototype-based style and class-based style.
Putting It into Perspective
With the proliferation of interactive, client-heavy AJAX applications, JavaScript is quickly becoming one of the most useful tools in a .NET developer’s arsenal. However, its prototypal nature may initially surprise developers who are more used to languages such as C++, C#, or Visual Basic. I have found my JavaScript journey a rewarding experience, although not entirely without frustration along the way. If this article can help make your experience smoother, then I’m happy, for that’s my goal.
OOP and ASP.NET AJAX
OOP as implemented in ASP.NET AJAX is a little different from the canonical implementation discussed in this article. There are two main reasons for that: the ASP.NET AJAX version offers more possibilities for reflection (which is necessary for declarative syntaxes such as xml-script and for parameter validation), and ASP.NET AJAX aims at translating to JavaScript some additional constructs that are familiar to developers using .NET, such as properties, events, enumerations, and interfaces.
In its current widely available version, JavaScript lacks a few key concepts of OOP that .NET developers are familiar with, and ASP.NET AJAX emulates most of those.
Classes can have property accessors based on a naming convention (example to follow), as well as multicast events following a pattern that closely mirrors that provided by .NET. Private variables are based on the convention that members starting with an underscore are private. Truly private variables are rarely necessary, and this policy enables those variables to be inspected from a debugger. Interfaces are also introduced to enable type checking scenarios beyond the usual duck-typing (a type scheme based on the concept that if something walks like a duck and quacks like a duck, it’s a duck, or at least it can be treated like one).
Classes and Reflection
In JavaScript, there is no way to know the name of a function. Even if this was possible, it wouldn’t help us in most situations as a class constructor is typically built by assigning an anonymous function to a namespaced variable. What really constitutes the type name is the fully qualified name of this variable, which is equally inaccessible and of which the constructor function itself knows nothing. To work around this limitation and have rich reflection over JavaScript classes, ASP.NET AJAX requires the names of types to be registered.
The reflection APIs in ASP.NET AJAX work over any type, whether it’s built-in, a class, an interface, a namespace, or even an enumeration, and they include .NET Framework-like functions like isInstanceOfType and inheritsFrom to inspect the class hierarchy at run time. ASP.NET AJAX also does some type checking in debug mode where it makes sense to help developers catch bugs earlier.
Registering Class Hierarchies and Calling Base
To define a class in ASP.NET AJAX, you need to assign its constructor to a variable (notice how the constructor calls base): And finally you register the class:
MyNamespace.MyClass = function() {
MyNamespace.MyClass.initializeBase(this);
this._myProperty = null;
}
Then, you need to define the class members itself in its prototype:
MyNamespace.MyClass.prototype = {
get_myProperty: function() { return this._myProperty;},
set_myProperty: function(value) { this._myProperty = value; },
doSomething: function() {
MyNamespace.MyClass.callBaseMethod(this, “doSomething”);
/* do something more */
}
}
MyNamespace.MyClass.registerClass(
“MyNamespace.MyClass “, MyNamespace.BaseClass);
Bertrand Le Roy is a Software Design Engineer II on the ASP.NET AJAX team.
Subscribe to:
Posts (Atom)