UPDATED!!
(See comments)
My first (public) script for Oracle :-) [beers]
This script will (hopefully) do:
- List all the objects on the database for each SID/SCHEMA given
- Dump the metadata of each object in a different file
- Upload everything to the svn
If you’re asking why? you must deal more with programmers :-P
This will add a second line of defense to the expdp CONTENT=METADATA_ONLY
classic script.
The script runs standalone on the server which is running the instance (using OS credentials).
Script code:
#!/bin/bash # Get ALL METADATA script ######################################################################## # # VARIABLES # ######################################################################## # colors LIGHTGREEN="\033[1;32m" LIGHTRED="\033[1;31m" WHITE="\033[0;37m" RESET="\033[0;00m" # time things NOW=$(date +%Y%m%d-%H%M) TODAY=$(date +%Y%m%d) SCHEMA[0]="SCHEMANAME" #SCHEMA[1]="SCHEMANAME2" DBSID[0]="SID01" # DBSID[1]="SID02" OUTPUTPATH[0]="/backup/${DBSID[0]}/metadata/${SCHEMA[0]}" SVNADDRESS[0]="svn://1.1.1.1/trunk/Oracle/Metadata/${DBSID[0]}/${SCHEMA[0]}" # Parameters file ENVFILE[0]="/home/oracle/entorn_${DBSID[0]}" # AUTOCONFIG, DO NOT TOUCH declare -a OBJECTTYPE # OBJECT TYPE FOR QUERYING THE DBA_OBJECTS TABLE OBJECTTYPE[0]="TABLE" OBJECTTYPE[1]="VIEW" OBJECTTYPE[2]="INDEX" OBJECTTYPE[3]="PACKAGE" OBJECTTYPE[4]="PROCEDURE" OBJECTTYPE[5]="FUNCTION" OBJECTTYPE[6]="TRIGGER" OBJECTTYPE[7]="TYPE" OBJECTTYPE[8]="SEQUENCE" OBJECTTYPE[9]="MATERIALIZED VIEW" OBJECTTYPE[10]="SYNONYM" OBJECTTYPE[11]="DIRECTORY" OBJECTTYPE[12]="EDITION" OBJECTTYPE[13]="SCHEDULE" OBJECTTYPE[14]="QUEUE" # OBJECT NAME FOR GET_DDL FUNCTION OBJECTTYPENAME[0]="TABLE" OBJECTTYPENAME[1]="VIEW" OBJECTTYPENAME[2]="INDEX" OBJECTTYPENAME[3]="PACKAGE" OBJECTTYPENAME[4]="PROCEDURE" OBJECTTYPENAME[5]="FUNCTION" OBJECTTYPENAME[6]="TRIGGER" OBJECTTYPENAME[7]="TYPE" OBJECTTYPENAME[8]="SEQUENCE" OBJECTTYPENAME[9]="MATERIALIZED VIEW" OBJECTTYPENAME[10]="SYNONYM" OBJECTTYPENAME[11]="DIRECTORY" OBJECTTYPENAME[12]="EDITION" OBJECTTYPENAME[13]="SCHEDULE" OBJECTTYPENAME[14]="AQ_QUEUE" AUXFILE=/tmp/auxfile.${NOW} AUXFILE2=/tmp/auxfile2.${NOW} SQLGENERATOR="$(dirname $0)/logs/$(basename $0 .sh)_loader_${NOW}.sql" REPORTLOG="$(dirname $0)/logs/$(basename $0 .sh)_${NOW}.log" ERRFILE="$(dirname $0)/logs/$(basename $0 .sh)_${NOW}.err" REPORTADDRESS="dodger@ciberterminal.net" REPORTTHIS="" export BASE_PATH=${PATH} export DB_HOME="/u01/app/oracle/product/11.2.0/db" ######################################################################## # # / VARIABLES # ######################################################################## ######################################################################## # # FUNCTIONS # ######################################################################## usage() { printf "%s${LIGHTRED}USAGE:${RESET} $0 sync|nosync|help Will output the whole metadata structure of the SCHEMA(s) ${LIGHTGREEN}${SCHEMA[@]}${RESET} In the directories (respectibely): $(for ((i=0; i<=${#SCHEMA[@]}; i++)) ; do echo "${LIGHTGREEN}${OUTPUTPATH[$i]}${RESET}" ; done) If nosync is specified then the data is not uploaded to the svn\n" # VERY INITIAL CHECKS } logreport() { local LOGTHIS="$*" echo "[$(date)] $(hostname) : ${LOGTHIS}" >> ${REPORTLOG} } check_db_locally() { # If the db is not running locally, skip the rest DBSTATUS=$(sqlplus '/ as sysdba' <<EOF set HEAD OFF select STATUS from V\$INSTANCE / exit EOF ) [[ "${DBSTATUS}" =~ ORA-01034 ]] && return 1 return 0 } exec_query() { local QUERY="$*" sqlplus / as sysdba 1>&2 >/dev/null <<EOF SET LINESIZE 9999 SET ECHO OFF SET HEAD OFF SET FEEDBACK OFF SET HEADING OFF SET COLSEP ";" spool ${AUXFILE} ; ${QUERY} spool off exit EOF cat ${AUXFILE} | egrep -v "^SYS(TEM|)@.*>|^$" > ${AUXFILE2} cat ${AUXFILE2} > ${AUXFILE} cat ${AUXFILE} } upload_to_svn() { local let DBINDEX=$1 local let RES=0 [ -d "${OUTPUTPATH[$DBINDEX]}-tmp" ] && rm -fr "${OUTPUTPATH[$DBINDEX]}-tmp" mkdir "${OUTPUTPATH[$DBINDEX]}-tmp" svn co "${SVNADDRESS[$DBINDEX]}" "${OUTPUTPATH[$DBINDEX]}-tmp" # Deleting old files from SVN cd ${OUTPUTPATH[$DBINDEX]}-tmp for DELETETHIS in $(find ./ -type f -name "*sql") ; do if [ ! -f ${OUTPUTPATH[$DBINDEX]}/${DELETETHIS} ] ; then svn rm --force ${DELETETHIS} fi done cd ${OLDPWD} # /Deleting cp -pfr ${OUTPUTPATH[$DBINDEX]}/ ${OUTPUTPATH[$DBINDEX]}-tmp/ svn add --force ${OUTPUTPATH[$DBINDEX]}-tmp/* svn ci -m "Import ${NOW}" ${OUTPUTPATH[$DBINDEX]}-tmp/ let RES=$? return ${RES} } ######################################################################## # # / FUNCTIONS # ######################################################################## ######################################################################## # # MAIN # ######################################################################## echo "col TXT FORMAT A9000" >> ${SQLGENERATOR} # exec > ${REPORTLOG} # exec 2> ${ERRFILE} OPS="${1,,}" [[ ! "${OPS}" =~ ^(help|sync|nosync)$ ]] && usage && exit 0 for ((i=0; i<${#SCHEMA[@]} ; i++)); do OBJNAME="" if [ -f ${ENVFILE[$i]} ] ; then . ${ENVFILE[$i]} else echo "Parameters file does not exists" exit 2 fi # MANDATORY!!!! DO-NOT-DELETE check_db_locally # If the database is not running locally, skip it!!! [ $? -ne 0 ] && logreport "${DBSID[$i]} Not Running locally." && continue # MANDATORY!!!! > ${SQLGENERATOR} for ((j=0; j<${#OBJECTTYPE[@]}; j++)); do QUERY="select DISTINCT OBJECT_NAME from DBA_OBJECTS where OBJECT_TYPE in ( '${OBJECTTYPE[$j]}' ) and owner = '${SCHEMA[$i]}' AND TEMPORARY = 'N' ORDER BY 1;" [ ! -d ${OUTPUTPATH[$i]}/${OBJECTTYPE[$j]// /_} ] && mkdir -p ${OUTPUTPATH[$i]}/${OBJECTTYPE[$j]// /_} exec_query "${QUERY}" | while read LINE ; do OBJNAME="$(echo "${LINE}" | awk -F\; '{gsub(/ +$/,"",$1);printf $1}')" printf "%s spool ${OUTPUTPATH[$i]}/${OBJECTTYPE[$j]// /_}/${OBJNAME//\$/#}.sql\n" >> ${SQLGENERATOR} printf "%s select DBMS_METADATA.GET_DDL('${OBJECTTYPENAME[$j]}','${OBJNAME}','${SCHEMA[$i]}') || ';' TXT FROM DUAL ;\n" >> ${SQLGENERATOR} printf "%s spool off\n" >> ${SQLGENERATOR} done done rm -f ${AUXFILE2} ${AUXFILE} sqlplus '/ as sysdba' 1>&2 >/dev/null <<EOF SET LINESIZE 9000 SET ECHO OFF SET HEAD OFF SET FEEDBACK OFF SET HEADING OFF spool ${AUXFILE} ; @${SQLGENERATOR} spool off exit EOF RES=$? rm -f ${AUXFILE2} ${AUXFILE} ${SQLGENERATOR} if [ ${RES} -eq 0 ] ; then REPORTTHIS="${REPORTTHIS}$(date) : [OK] Generating SQL metadata of ${DBSID[$i]}:${SCHEMA[$i]}\n" if [[ "${OPS}" = "sync" ]] ; then upload_to_svn_new ${i} RES=$? if [ ${RES} -eq 0 ] ; then REPORTTHIS="${REPORTTHIS}$(date) : [OK] Uploading metadata of ${DBSID[$i]}:${SCHEMA[$i]} to SVN\n" else REPORTTHIS="${REPORTTHIS}$(date) : [FAIL] Uploading metadata of ${DBSID[$i]}:${SCHEMA[$i]} to SVN\n" fi fi else REPORTTHIS="$(date) : [FAIL] Generating SQL metadata of ${DBSID[$i]}:${SCHEMA[$i]}\n" fi done if [[ "${REPORTTHIS}" ]] ; then if [[ "${REPORTTHIS}" =~ .*FAIL.* ]] ; then printf "%s${REPORTTHIS}" | mail -s "$(hostname) : Oracle incredible Metadata script report [FAIL]" -a ${ERRFILE} -a ${REPORTLOG} ${REPORTADDRESS} else printf "%s${REPORTTHIS}" | mail -s "$(hostname) : Oracle incredible Metadata script report [OK]" ${REPORTADDRESS} fi fi exit ${EXITCODE} ######################################################################## # # / MAIN # ########################################################################
Main variables:
- SCHEMA : ARRAY with the schemas to look into
- DBSID : DB SID for the SCHEMA of the same index
- OUTPUTPATH : Output path for the sql scripts
- SVNADDRESS : SVN server (and address) where the script will upload the scripts.
- ENVFILE : ARRAY with the location of the parameters file for each instance
- OBJECTTYPE : ARRAY with the list of object classes to dump
- OBJECTTYPENAME : ARRAY with the list of object NAME (corresponding with the OBJECTTYPE array), sometimes the name and the for GET_DDL is different.
- REPORTADDRESS : The script will send info here :-)
- DB_HOME : Your DB_HOME :-P
The script will create 1 sql file for each object with the following pattern for the name:
${OUTPUTPATH}/${OBJECTTYPE}/
You can disable the upload to svn by commenting out the lines indicated on the script :-)
cheers
Great job! Congratulations!
Just a little possible “improvement”:
Why don’t you query the DBA_TYPES to fill up the array of object_types.
Like that, user-defined types would be included too!
Regards.
I’ll do :-)
I’ve also detected a “feature” like devolpers call to their bugs :-P
I’ll update the script next bussines day!
Well, I’ve corrected some errors in the script :-)
Now the svn part works as it should :-P
The part of the DBA_TYPES (I think it should be DBA_OBJECTS), I first tryed to generate the array of objects types dynamically but there are a lot of unused objects… So I decided to make a list and that’s all.