#!/bin/ksh # version 6.2, 2004-07-19, Michael Wang . # * Fixed the feature for FULL=Y and ROWS=N implemented in version 4.1. # # version 6.1, 2003-11-05, Michael Wang . # * Implemented inclusion and exclusion of readonly and any tablespaces. # # version 6.0, 2003-11-03, Michael Wang . # * Implemented combination of schema and schema.table:partition backup. # * Temp files renamed from number.* to num_owner.*. Add num_owner to log. # # version 5.2, 2003-10-30, Michael Wang . # * Implemented NUM_COPIES parameter. # * Fixed a few bugs related with remote backup. # # version 5.1, 2002-01-15, Michael Wang . # * Deleted two obsolete lines which causes program to hang. # # version 5.0, 2001-12-08, Michael Wang . # * Oracle 9i support. # * help=y option. # - Consolidate code for by owner backup, full backup with/without rows. # - Better workaround for Solaris 8 and below compress bug (version 3.0.2). # # version 4.11, 2001-06-07, Michael Wang . # * when CDPATH is set, cd may generate output, directed to /dev/null. # oracle:ADEV:816$cd app/.. # /u0/oracle # # version 4.1, 2000-12-04, Michael Wang . # * Per suggestion from Lingam Lakshmaiah, ROWS=Y is not hard coded # in full backup and owner backup, but the default value or specified # value ($EXP_OPTS) is used. However in the case of by owner backup, # the additional logical structure backup will use ROWS=N FULL=Y # regardless ROWS=value specified in $EXP_OPTS. # # version 4.0, 2000-11-04, Michael Wang . # * Make SUBMIT, MKNOD, INIT_D configurable options. # * Fixed the problem when running the script without typing path (as in # orahot.ksh SID) by using dirname. # * Added [[ -d $ORACLE_SID ]] || mkdir $ORACLE_SID for each BKUP_DIRS. # * Cleaned the obsolete ksh syntax as reported by ksh93 -n option: # -eq within [[...]] obsolete, use ((...)) # '=' obsolete, use '==' # * change: sed "1,2 d; $ d" => sed "1,2d; \$d" # Version M 1993-12-28 j does not accept the former form. # * Better handling of trap and log messages when program is killed/failed. # # version 3.141, 2000-10-07, Michael Wang . # * Added options for using compress, gzip, or bzip2 as compression tool. # # version 3.03, 2000-08-06, Michael Wang . # * Chang on ORACLE_HOME= line shown below # OLD => ORACLE_HOME=$(sed -n "s/^$ORACLE_SID:\(.*\):.*$/\1/p" $ORATAB) # NEW => ORACLE_HOME=$(sed -n "s/^$ORACLE_SID:\([^:]*\):.*$/\1/p" $ORATAB) # This accommodates the generalized oratab with more than 3 fields. # # version 3.0.2, 2000-06-19, Michael Wang . # * Added work around for the Sun /bin/compress bug ID 1228643: # $ touch a; compress -c a > a.Z; echo $? # 2 # grep -v "^0$" => egrep -v "^[0|2]$" # # version 3.0.1, 2000-06-16, Michael Wang . # * Added a fix for by owner backup. # # version 3.0, 2000-06-10, Michael Wang . # * Replace the check: _grep "EXP-|ORA-" logfile_ with # _grep "^Export terminated successfully without warnings\.$" logfile_. # "grep" should be replace by "egrep" to understand "EXP-|ORA-" but it won't # filter out "EXP-00067" which is an informational message. # * Added the functionality to backup on remote filesystem by specifying # user@host:/filesystem in the conf file. # # version 2.0, 1999-03-18, Michael Wang . # * Expanded "BY OWNER" export to include OWNER_INCLUDE and OWNER_EXCLUDE # option. Dynamically get system passwd. # # version 1.0, 1999-02-08, Michael Wang . # * Rewrite based on previous version developped in house. "BY OWNER" export # is due to discussion with Stephanie Shen, Satyaki Chatterjee, Sheck Cho, # Gilberto Arroyo, Jose Garcia. Stephanie Shen provided the SQL script. ( : ${.sh.version}; ) 2>/dev/null || { i= unset i for i in /usr/dt/bin/dtksh /usr/local/bin/ksh; do $i -c ": \${.sh.version}" 2>/dev/null && exec $i "$0" "$@" done echo "ksh93 is not found." exit 1 } OPATH=$PATH builtin -d getconf # workaround for ksh93 (m, l, ...) getconf bug PATH=$(PATH=/bin:/usr/bin getconf PATH) PATH=$PATH:/usr/sbin typeset -x PATH function my_getopts { typeset PATH= SEP=: i= typeset -u _I for i; do _I=$i [[ _I == *=* ]] && eval ${_I%%?(:)=*}= unset ${_I%%?(:)=*} case $_I in *[!:]=*) eval $(IFS=$SEP; print ${_I%%=*}=\"${_I#*=}\") ;; *:=*) eval $(IFS=$SEP; print ${_I%%:=*}=\"${i#*:=}\") ;; !(*=*)) SID=$i;; esac done } my_getopts sid:= help= debug= "$@" [[ $DEBUG == Y ]] && set -x [[ $HELP == Y ]] && { PATH=$OPATH whence perldoc >/dev/null || { print "You need to have perldoc in your PATH." exit 1 } j= unset j j=/tmp/${0##*/}.$$.$RANDOM trap "rm -f $j" EXIT INT sed -n "/^##/s:^## \{0,1\}::p" $0 > $j PATH=$OPATH perldoc $j exit 0 } [[ -z "$SID" ]] && { print "ERROR: you must specify ORACLE_SID." exit 1 } typeset -x ORACLE_SID=$SID # $0 could be ".", convert to absolute path PDIR=$(cd $(dirname $0)/.. >/dev/null && pwd -P) LOGDIR=$PDIR/operlog/$ORACLE_SID [[ -d ${LOGDIR%/*} && ! -d ${LOGDIR} ]] && mkdir ${LOGDIR} TMPDIR=$PDIR/temp/$ORACLE_SID [[ -d ${TMPDIR%/*} && ! -d ${TMPDIR} ]] && mkdir ${TMPDIR} CONFILE=$PDIR/etc/oraexport_$ORACLE_SID.cf function chkdir { if [[ -n "$1" ]] then typeset i=$1 else echo "ERROR: No directory specified for chkdir function." return 1 fi typeset j if [[ -d $i ]]; then set -- $(j=$i/foo.$$; echo $j; mkdir $j; ls -d $j; rmdir $j) elif [[ $i == *@*:* ]]; then set -- $(echo $i | sed "s/[@|:]/ /g") u=$1; r=$2; d=$3 set -- $(rsh -l $u $r "j=$d/foo.\$\$; echo \$j; mkdir \$j; ls -d \$j; rmdir \$j") else echo "ERROR: Can not find $i directory." return 1 fi if (( $# == 2 )) && [[ $1 == $2 ]]; then return 0 else echo "ERROR: Can not write in $i directory." return 1 fi } chkdir $LOGDIR || { print "ERROR: in checking $LOGDIR." exit 1 } i= unset i while [[ -z $i || -f $i ]] do [[ -z $i ]] || sleep $(( RANDOM%10 )) i=$LOGDIR/oraexport_$ORACLE_SID.log.$(date +%m%d).$(date +%H%M) done echo "Please check the logfile: $i." exec > $i 2>&1 date chkdir $TMPDIR || { print "ERROR: in checking $TMPDIR." exit 1 } i= unset i for i in $( print SUBMIT print MKNOD print INIT_D print NUM_PROCS print MAX_SECS print PRE_PROCESSING print POST_PROCESSING print NUM_COPIES ); do eval $i= unset $i done if [[ -f $CONFILE ]] then . $CONFILE else print "ERROR: Can not find configuration file: $CONFILE." exit 1 fi : ${SUBMIT:=/usr/local/bin/submit} [[ -x $SUBMIT ]] || { print "ERROR: Can not find SUBMIT=$SUBMIT." exit 1 } : ${MKNOD:=/usr/sbin/mknod} [[ -x $MKNOD ]] || { print "ERROR: Can not find MKNOD=$MKNOD." exit 1 } : ${INIT_D:=/etc/init.d} i= RC_ORACLE= unset i RC_ORACLE RC_ORACLE=$TMPDIR/oracle-$ORACLE_SID rm -rf $RC_ORACLE ( cd $INIT_D && for i in oracle-$ORACLE_SID rc.oracle online; do [[ -f $i ]] && { ln -s $INIT_D/$i $RC_ORACLE; break; } done ) [[ -L $RC_ORACLE ]] || { print "ERROR: cannot find rc.oracle|oracle-$ORACLE_SID|online in $INIT_D." exit 1 } i=${COMPRESS_C%% *} i=${i##*/} if [[ $i == compress ]] then THEZ="Z" elif [[ $i == gzip ]] then THEZ="gz" elif [[ $i == bzip2 ]] then THEZ="bz2" else COMPRESS_C="compress -c"; THEZ="Z" fi [[ -n "$BKUP_DIRS" ]] || { print "ERROR: BKUP_DIRS not defined in $CONFILE." exit 1 } i= j=; unset i j for i in $BKUP_DIRS do j=$i/$ORACLE_SID if [[ $j == *@*:* ]]; then set -- ${j//[@:]/ } { print "set -- ${3}_+([-0-9])_+([:0-9])" print "[[ -d \$1 ]] && {" print " for (( k = 1; k <= \$# - $NUM_COPIES + 1; k++ )); do" print " eval PATH=$PATH rm -r \\$\{\$k\}" print " done" print "}" print "PATH=$PATH mkdir -p $3" } | rsh -l $1 $2 /usr/dt/bin/dtksh else set -- ${j}_+([-0-9])_+([:0-9]) [[ -d $1 ]] && { for (( k = 1; k <= $# - NUM_COPIES + 1; k++ )); do eval rm -r \${$k} done } mkdir -p $j fi chkdir $i/$ORACLE_SID || { echo "ERROR: in checking $i/$ORACLE_SID." exit 1 } done : ${NUM_PROCS:=3} [[ "$NUM_PROCS" == +([0-9]) ]] || { print "ERROR: NUM_PROCS in $CONFILE is not a number." exit 1 } : ${NUM_COPIES:=1} [[ "$NUM_COPIES" == +([0-9]) ]] || { print "ERROR: NUM_COPIES in $CONFILE is not a number." exit 1 } : ${MAX_SECS:=999999} [[ "$MAX_SECS" == +([0-9]) ]] || { print "ERROR: MAX_SECS defined in $CONFILE is not a number." exit 1 } (( MAX_SECS == 0 )) && { print "INFO: EXPORT BACKUP FOR $ORACLE_SID SKIPPED." exit 0 } typeset -u BKUP_BY_OWNER [[ "$BKUP_BY_OWNER" == @(Y|N) ]] || { echo "ERROR: BKUP_BY_OWNER in $CONFILE is neither Y nor N." exit 1 } [[ -z $SYSTEMPASS ]] && { print "ERROR: Failed to get system password." exit 1 } typeset -l EXP_OPTS [[ "$EXP_OPTS" == *=* ]] || { print "ERROR: EXP_OPTS ($EXP_OPTS) in $CONFILE is not in correct format." exit 1 } typeset -u WITH_WARNINGS_OK : ${WITH_WARNINGS_OK:=N} [[ "$WITH_WARNINGS_OK" == @(Y|N) ]] || { echo "ERROR: WITH_WARNINGS_OK is neither Y nor N." exit 1 } ORACLE_HOME= unset ORACLE_HOME typeset -x ORACLE_HOME=$(awk -F: "/^$ORACLE_SID:/ {print \$2; exit}" /var/opt/oracle/oratab) typeset -x LD_LIBRARY_PATH= ISQL=$ORACLE_HOME/bin/svrmgrl [[ -x $ISQL ]] || ISQL=$ORACLE_HOME/bin/sqlplus THE_EXP=$ORACLE_HOME/bin/exp [[ -x $ISQL && -x $THE_EXP ]] || { print "ERROR: Can not find ISQL ($ISQL) or THE_EXP ($THE_EXP)." print "+ Possibly on the other node of the cluster." exit 1 } function gen_tbs { { print "connect / as sysdba" print "select '_''' || owner || '.' || segment_name || ''''" print "from dba_segments" print "where segment_type in ('TABLE','TABLE PARTITION')" [[ $1 == *1* ]] && print "and tablespace_name in ($TBS_INCLUDE)" [[ $1 == *2* ]] && print "and tablespace_name in ($TBS_EXCLUDE)" [[ $1 == *3* ]] && { print "and tablespace_name in" print " ( select tablespace_name from dba_tablespaces" print " where status='READ ONLY' )" } print "/" } | $ORACLE_HOME/bin/sqlplus /nolog | sed -n "s:^_: :p" } [[ -n $OWNER_ONLY && -z $OWNER_INCLUDE ]] && # backward OWNER_INCLUDE=$OWNER_ONLY # compatibility [[ -n $TBS_INCLUDE ]] && OWNER_INCLUDE=$OWNER_INCLUDE$(gen_tbs 1) [[ -n $TBS_EXCLUDE && $TBS_EXCLUDE_RO != [Yy]* ]] && OWNER_EXCLUDE=$OWNER_EXCLUDE$(gen_tbs 2) [[ -z $TBS_EXCLUDE && $TBS_EXCLUDE_RO == [Yy]* ]] && OWNER_EXCLUDE=$OWNER_EXCLUDE$(gen_tbs 3) [[ -n $TBS_EXCLUDE && $TBS_EXCLUDE_RO == [Yy]* ]] && OWNER_EXCLUDE=$OWNER_EXCLUDE$(gen_tbs 23) ksh $RC_ORACLE stat verbose=n || { print "ERROR: Database $ORACLE_SID is down before export backup starts." exit 1 } mkdir $LOGDIR/lock || { print "ERROR: A copy of the script is already running." exit 1 } trap "rmdir $LOGDIR/lock" EXIT INT find $LOGDIR -mtime +60 -name \*log\* -type f -print -exec rm -f {} \; find $TMPDIR \( -type f -o -type p \) -print -exec rm -f {} \; for i in $BKUP_DIRS do if [[ $i == *@*:* ]]; then set -- ${i//[@:]/ } rsh -l $1 $2 "PATH=$PATH find $3/$ORACLE_SID -type f -print -exec rm -f {} \;" else find $i/$ORACLE_SID -type f -print -exec rm -f {} \; fi done cd $TMPDIR [[ $BKUP_BY_OWNER == Y ]] && { > owner.table.sql > owner.table.part.sql fsql=owner.bytes { print "spool owner.bytes.lst" print "set echo on" [[ $ISQL == *sqlplus ]] && { print "set linesize 960" print "set trimspool on" print "connect / as sysdba" } [[ $ISQL == *svrmgrl ]] && print "connect internal" print "SELECT DISTINCT 'THE_OWNER= ' || owner, SUM(bytes) estimated_bytes" print "FROM dba_segments" print "WHERE segment_type in ('TABLE', 'TABLE PARTITION')" function case_print { case $1 in (++) print "AND ( 1 = 2" ;; (+-) print ")" ;; esac } i= j= pos= otp=; unset i j pos otp for i in "++" ${OWNER_INCLUDE//,/ } "+-" "-+" ${OWNER_EXCLUDE//,/ } "--"; do [[ $i == [+-][+-] ]] && pos=$i eval j=$i set -- ${j//[.:]/ } (( otp = $# )) if (( otp == 1 )); then set -- $1 "%" "%" elif (( otp == 2 )); then set -- $1 $2 "%" [[ -s owner.table.sql ]] || { print "select distinct 'tables=' || owner || '.' || segment_name" print "from dba_segments" print "where segment_type in ('TABLE', 'TABLE PARTITION')" print "and owner like '$1'" case_print $pos } >> owner.table.sql elif (( otp == 3 )); then [[ -s owner.table.part.sql ]] || { print "select 'tables=' || owner || '.' || segment_name" print " || ':' || partition_name" print "from dba_segments" print "where segment_type='TABLE PARTITION'" print "and owner like '$1'" print "and segment_name like '$2'" case_print $pos } >> owner.table.part.sql fi [[ -n ${OWNER_INCLUDE} ]] && case_print $i [[ -s owner.table.sql ]] && case_print $i >> owner.table.sql [[ -s owner.table.part.sql ]] && case_print $i >> owner.table.part.sql [[ $i == [+-][+-] ]] || { case $pos in (++) print "OR" ;; (-+) print "AND NOT" ;; esac print "(" print "owner like '$1'" print "and segment_name like '$2'" print "and (partition_name is null or partition_name like '$3')" print ")" } | case $otp in (1) cat ;; (2) tee -a owner.table.sql ;; (3) tee -a owner.table.part.sql ;; esac done [[ -s owner.table.sql ]] && print "/" >> owner.table.sql [[ -s owner.table.part.sql ]] && print "/" >> owner.table.part.sql print "GROUP BY owner" print "ORDER BY SUM(bytes) DESC" print "/" print "spool off" print "spool owner.table.lst" cat owner.table.sql cat owner.table.part.sql print "spool off" print "exit" } > ${fsql}.sql [[ $ISQL == *svrmgrl ]] && $ISQL command="@${fsql}.sql" [[ $ISQL == *sqlplus ]] && $ISQL /nolog @${fsql}.sql grep -E "ORA-|MGR-" owner.bytes.lst && { print "ERROR: In running ${fsql}.sql." exit 1 } awk "/^THE_OWNER=/ {print \$2}" owner.bytes.lst > owner.lst print "FULL_NOROWS.DUMMY" >> owner.lst } [[ $BKUP_BY_OWNER == Y ]] || print "FULL.DUMMY" >> owner.lst num_file= unset num_file (( num_file = $(wc -l < owner.lst) )) (( num_file < 1 )) && { print "ERROR: I have nothing to backup." exit 1 } # To make *.[pid|log|stat] expandable by shell, used by cleanup function > $TMPDIR/000_a.pid SUCCESS_PATTERN="Export terminated successfully without warnings." print "$SUCCESS_PATTERN" > $TMPDIR/000_a.log [[ $WITH_WARNINGS_OK == Y ]] && { SUCCESS_PATTERN="Export terminated successfully without|with warnings." } > $TMPDIR/000_a.stat function cleanup { trap 'print Please wait for cleanup to finish.' EXIT INT (( $1 == 0 )) || echo "Please wait for cleanup to finish." rmdir $LOGDIR/lock typeset i typeset j ( cd $TMPDIR && for i in +([0-9])_*.pid; do j=${i%.pid} [[ -f $j.stat ]] || kill -- -$(< $i) print cat $j.log done ) date (( $1 == 0 )) || print "ERROR: EXPORT BACKUP FOR $ORACLE_SID FAILED." trap '' 0 return 0 } trap "print \"ERROR: program terminated.\"; cleanup 1; exit 1" EXIT INT function find_avail_path { typeset dir THE_DIR avail the_avail (( the_avail = -1 )) for dir; do if [[ $dir == *@*:* ]]; then set -- ${dir//[@:]/ } avail=$(rsh -l $1 $2 "PATH=$PATH df -Pk $3" | awk "/^\// {print \$4}") else avail=$(df -Pk $dir | awk "/^\// {print \$4}") fi (( avail >= the_avail )) && { (( the_avail = avail )) THE_DIR=$dir } done print "$THE_DIR" } typeset -Z3 the_num_file (( the_num_file = 0 )) # number of files submitted (( the_num_stat = 0 )) # number of files finished successfully (( SECONDS = 0 )) while (( the_num_stat < num_file )) do set -- +([0-9])_*.?(p)stat (( the_num_stat = ($# -1)/2 )) set -- +([0-9])_*.pid (( the_num_file = $# - 1 )) (( the_num_proc = the_num_file - the_num_stat )) print "num_file_submit:num_file_finish:num_copy_allow:num_file_total=\c" print "$the_num_file:$the_num_stat:$NUM_PROCS:$num_file" (( SECONDS >= MAX_SECS )) && { print "ERROR: exceeding maximum time ($MAX_SECS seconds)." (( the_num_stat = num_file + 1 )) break } grep -v "^0\$" +([0-9])_*.?(p)stat && { print "ERROR: one of copy sessions has a non-zero exit code." (( the_num_stat = num_file + 1 )) break } i= unset i for i in *.stat; do grep -E "^${SUCCESS_PATTERN}\$" ${i%.stat}.log >/dev/null || { print "ERROR: no successful line in export log ($TMPDIR/${i%.stat}.log)." (( the_num_stat = num_file + 1 )) break 2 } done (( the_num_proc >= NUM_PROCS )) && { print "INFO: $(date +%H:%M:%S) maximum copy session reached, wait." sleep 10 continue } (( the_num_file >= num_file )) && { echo "INFO: $(date +%H:%M:%S) wait for file copying to finish." sleep 10 continue } (( the_num_file++ )) the_owner=$(awk "NR == ${the_num_file} {print \$1}" owner.lst) num_owner=${the_num_file}_${the_owner%.DUMMY} file=${ORACLE_SID}.${the_owner%.DUMMY}.dmp > ${num_owner}.par chmod 700 ${num_owner}.par i=; unset i if [[ $the_owner == FULL?(_NOROWS).DUMMY ]]; then { for i in $EXP_OPTS; do [[ $i == rows=* && ${the_owner} == FULL@(_NOROWS).DUMMY ]] || [[ $i == full=* ]] || print "$i" done print "FILE=${num_owner}.pipe" print "FULL=Y" [[ ${the_owner} == FULL@(_NOROWS).DUMMY ]] && print "ROWS=N" } > ${num_owner}.par else { for i in $EXP_OPTS; do print "$i" done print "FILE=${num_owner}.pipe" i=$(grep "^tables=${the_owner}." owner.table.lst) [[ -n "$i" ]] && print "$i" || print "OWNER=$the_owner" } > ${num_owner}.par fi print "$THE_EXP ${num_owner} with options:" grep -v "userid=" ${num_owner}.par THE_DIR=$(find_avail_path $BKUP_DIRS) THE_PATH=$THE_DIR/$ORACLE_SID rm -rf ${num_owner}.pipe $MKNOD ${num_owner}.pipe p if [[ $THE_PATH == *@*:* ]]; then set -- ${THE_PATH//[@:]/ } u= r= d= unset u r d u=$1; r=$2; d=$3 $SUBMIT -i $num_owner.ppid -l $num_owner.plog -e $num_owner.pstat \ "cat $num_owner.pipe | $COMPRESS_C | rsh -l $u $r \"PATH=$PATH cat > $d/$file.$THEZ\"" else $SUBMIT -i $num_owner.ppid -l $num_owner.plog -e $num_owner.pstat \ "cat $num_owner.pipe | $COMPRESS_C | cat > $THE_PATH/$file.$THEZ" fi # NOT UUOC: workaround for compress bug (see version 3.0.2 notes). $SUBMIT -i $num_owner.pid -l $num_owner.log -e $num_owner.stat \ $THE_EXP PARFILE=${num_owner}.par done ksh $RC_ORACLE stat verbose=n || { print "ERROR: Database $ORACLE_SID is not up after export backup." exit 1 } cleanup 0 status=; unset status (( status = 1 )) (( the_num_stat == num_file )) && { FINISH_DATE= i= j= k=; unset FINISH_DATE i j k FINISH_DATE=$(date +%Y-%m-%d_%H:%M:%S) (( status = 0 )) for i in $BKUP_DIRS; do j=$i/$ORACLE_SID if [[ $j == *@*:* ]]; then set -- ${j//[@:]/ } rsh -l $1 $2 "PATH=$PATH mv $3 ${3}_${FINISH_DATE}; echo \$?" | read k (( k == 0 )) || (( status++ )) else mv ${j} ${j}_${FINISH_DATE} || (( status++ )) fi done } if (( status == 0 )); then print "EXPORT BACKUP FOR $ORACLE_SID FINISHED SUCCESSFULLY." else print "ERROR: EXPORT BACKUP FOR $ORACLE_SID FAILED." fi trap - EXIT exit $status ## =head1 NAME ## ## oraexport.ksh - make Oracle database export backup, with by owner or full backup option. ## ## =head1 SYNOPSIS ## ## oraexport.ksh MySID [debug=y] ## ## oraexport.ksh sid:=MySID [debug=y] ## ## oraexport.ksh help=y ## ## =head1 DESCRIPTION ## ## oraexport.ksh makes a either full export backup, or by owner backup. ## ## Full export is specified with "BKUP_BY_OWNER=N" option in the configuration ## file. It backs up everything to a single file. It can have either ROWS=Y ## or ROWS=N option which is specified in EXP_OPTS parameter, or use whatever ## the Oracle default value. ## ## By owner export is specified with "BKUP_BY_OWNER=Y" option in the ## configuration file. OWNER_INCLUDE or OWNER_EXCLUDE can be specified to ## include and exclude certain schemas, schema.tables, schema.table:partitions ## from the backup. OWNER_INCLUDE and OWNER_EXCLUDE can be both set. For ## Example: ## ## (1) The following is used to exclude SYS, CITATION, TRADE schemas, and ## P2002% and P2003% partitions from SETTLETRADE.SETTLED_TRADES table: ## ## OWNER_EXCLUDE=" ## 'SYS', ## 'CITATION', ## 'TRADE', ## 'SETTLETRADE.SETTLED_TRADES:P2002%', ## 'SETTLETRADE.SETTLED_TRADES:P2003%', ## " ## ## (2) The following is used to only backup CHO schema, MWANG.P table, and ## SETTLETRADE.SETTLED_TRADES:P2004% table partition: ## ## OWNER_INCLUDE="'CHO','MWANG.P','SETTLETRADE.SETTLED_TRADES:P2004%'" ## ## (3) The following is used to backup three schemas, 'MWANG', 'CHO', ## and 'SETTLETRADE', but SETTLETRADE.SETTLED_TRADES table is excluded ## from the backup: ## ## OWNER_INCLUDE="'MWANG','CHO','SETTLETRADE'" ## OWNER_EXCLUDE=" ## 'SETTLETRADE.SETTLED_TRADES', ## " ## ## On top of OWNER_INCLUDE and OWNER_EXCLUDE, you can also use ## TBS_INCLUDE, TBS_EXCLUDE to include and exclude the tables and ## table partitions in the tablespaces specified. ## ## TBS_EXCLUDE_RO=YES|NO is used to exclude or not exclude the ## Read Only tablespaces. ## ## Inside the program, TBS_INCLUDE, TBS_EXCLUDE, and TBS_EXCLUDE_RO ## are converted to owner.table list, and are appended to ## OWNER_INCLUDE, and OWNER_EXCLUDE. ## ## The ROWS option is taken from EXP_OPTS or use the Oracle default. ## ## Each owner's backup is writen to its own file. This allows multiple ## backup processes (NUM_PROCS) to run at the same time, and it can take ## the advantage of using multiple filesystems (BKUP_DIRS) which is dynamically ## balanced. (However, it won't ## help if you have a single schema which is 99% of the database.) ## ## For by owner backup option, an additional export is done with FULL=Y, and ## ROWS=N, and the rest of options from EXP_OPTS. ## ## Other features include: ## ## =over 4 ## ## =item * ## ## You can specify any of the compress utilities which can takes stdin and ## compress to stdout. The large file (>2GB) support on the compress ## utility is I required. ## ## =item * ## ## The backup file systems can be either local or remote. ## ## =item * ## ## The system password is parsed from a configuration file, and is ## protected from world read and ps output. ## ## =item * ## ## Backup processes are cleaned up by signal handler when an exception ## occured. ## ## =item * ## ## You can specify a maximum allowed time (MAX_SECS) or to skip the backup ## (set MAX_SECS to 0). ## ## =item * ## ## Prevent duplicate backup processes from running. ## ## =back ## ## =head1 INSTALLATION ## ## To install, follow the easy 1-2-3 steps: ## ## =over 4 ## ## =item 1. ## ## Create an install directory for export backup /ora_export, ## and under ora_export, create following sub-directories: ## ## script ## etc ## operlog/ ## temp/ ## ## Where SID is the actual ORACLE_SID name. If you have multiple ## SIDs, then just create them under operlog and temp. ## ## =item 2. ## ## cp oraexport.ksh script/oraexport.ksh ## chmod 755 script/oraexport.ksh ## ## =item 3. ## ## Edit etc/oraexport_SID.cf from the sample configuration shown below. If ## you have multiple SIDs, then just create multiple files. ## ## =back ## ## # * ## # * Where do you want the export backup files to go? ## # * Note: it can be a remote directory. ## # * ## ## BKUP_DIRS="/orabkup01/export user@host:/orabkup02/export" ## ## # * ## # * How many simutaneous compress processes you want to run? ## # * Rule of thumb is to set the number to be the same as the n of processors. ## # * Default is 3. ## # * ## ## NUM_PROCS=3 ## ## # * ## # * How many copies you want to keep online? ## # * (If you keep 1 copy, the backup may not finish before file system ## # * backup if the dependency can be set.) ## # * ## ## NUM_COPIES=1 ## ## # * ## # * What is the maximum time you allow the backup to run? ## # * Backup will kill itself exceeding the maximum allowed time. ## # * Default is 999999. ## # * ## ## MAX_SECS=999999 ## ## # * ## # * Do you run schema by schema backup or full backup? ## # * backup with "full=y rows=n" option will be performed for schema backup. ## # * Default is full backup. ## # * ## ## BKUP_BY_OWNER="N" ## ## # * ## # * IF it is schema backup, do you want backup ONLY those specified ## # * schemas, tables, and partitions, exclude those excluded? ## # * ## # * Do you want to include/exclude tables and partitions on certain ## # * tablespaces, read only tablespaces? ## # * ## ## # OWNER_INCLUDE="'CHO','MWANG.P','SETTLETRADE.SETTLED_TRADES:P2004%'" ## # OWNER_EXCLUDE="'SYS','EMG','SETTLETRADE.SETTLED_TRADES'" ## # TBS_INCLUDE="'TRADE_DATA','WEB_DATA'" ## # TBS_EXCLUDE="'USERS','TOOLS'" ## # TBS_EXCLUDE_RO="YES|NO" ## ## # * ## # * What is the system password? ## # * It is assumed the password is specified in a password file by ## # * SYSTEMPASS=. ## # ## # * You can use one of the three forms: ## # ## # * In the first form, the password is derived from password file, ## # * which is derived from ORACLE_HOME, which is derived from ORATAB. ## # ## # * In the second form, the password file is specified directly. ## # ## # * In the third form, the password is specified directly, which I would ## # * not recommend except for quick testing purpose. ## # * ## ## # * ## # * First form: ## # * ## ## ORATAB=/var/opt/oracle/oratab ## ORACLE_HOME=$(awk -F: "/^$ORACLE_SID:/ {print \$2; exit}" /var/opt/oracle/oratab) ## eval $(sed -n "/^SYSTEMPASS=.*/{p; /^/q;}" ${ORACLE_HOME%/product/*}/.ora_${ORACLE_SID}_passwd.ksh) ## ## # * ## # * Second form: ## # * ## ## # eval $(sed -n "/^SYSTEMPASS=.*/{p; /^/q;}" ) ## ## # * ## # * Third form: ## # * ## ## # SYSTEMPASS= ## ## # * ## # * What export options do you use? ## # * ## ## EXP_OPTS="userid=system/$SYSTEMPASS buffer=5000000 compress=n consistent=n constraints=y direct=y grants=y indexes=y recordlength=65000" ## ## # * ## # * What command do you use to compress a file to standard output? ## # * Default is "compress -c". ## # * ## ## COMPRESS_C="/usr/bin/compress -c" ## # COMPRESS_C="/usr/local/bin/gzip -c" ## # COMPRESS_C="/usr/local/bin/bzip2 -c" ## ## # * ## # * What characterset do you use? ## # * Default is US7ASCII ## # * ## ## # export NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1 ## ## # * ## # * By default only "Export terminated successfully without warnings." ## # * is considered as success. With "WITH_WARNINGS_OK=Y" option, ## # * "Export terminated successfully with warnings." is also considered ## # * as success. ## # * ## ## # WITH_WARNINGS_OK=N ## ## # * ## # * Where can you find submit? ## # * /usr/local/bin/submit is the default. ## # * ## ## SUBMIT=/usr/local/bin/submit ## ## # * ## # * What is the directory where you can find rc.oracle? ## # * /etc/init.d is the default. ## # * ## # * The rc.oracle is used to verify if Oracle is up before and after ## # * the backup. If you want to bypass the tests, then define INIT_D as ## # * "NA" (Not Apply). ## # * ## ## INIT_D=/etc/init.d ## ## =head1 SEE ALSO ## ## submit help=y, rc.oracle help=y. ## ## =head1 AUTHOR ## ## Michael Wang > with help from others acknowledged ## in version notes. ## ## This is free software. You may copy or redistribute it under the same ## terms as Perl. However, if you modify it, you need to send the ## modification to the author via email.