<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      代碼改變世界

      oracle_19c_ru_ojvm_upgrade.sh一鍵升級腳本分享

      2025-09-28 22:43  瀟湘隱者  閱讀(39)  評論(0)    收藏  舉報

      oracle_19c_ru_ojvm_upgrade.sh腳本的初始版本來源于IT邦德的分享,使用原腳本時發現有一些bug,在我的環境中腳本根本跑不通,于是個人在這個腳本的基礎上進行了大量的改進與優化,到當前版本可以說算是完全重構了。我用這個腳本進行了大量的測試驗證(測試環境和UAT環境Oracle 19c數據庫實例打補丁),對于Oracle 19c來說基本上是沒有什么問題. 使用此腳本打補丁相當絲滑與愜意。也確實讓工作效率飛升,可以騰出很多時間做其他事情。腳本的一些思路與想法,閱讀下面代碼即可略知一二,如果有不足的地方,也敬請指教。當然,這個腳本暫時沒有在其他數據庫版本經過測試驗證。難免會一些Bug,個人后續也會不斷地完善、擴充這個腳本。關于這個腳本的一些基本注意事項,詳情請見下面:

      注意事項:

      1. 此腳本只在Linux(REHL)平臺上測試了Oracle 19c數據庫, 雖然經過大量驗證,不保證其它平臺環境也能運行,可能存在Bug,使用前請進行測試驗證,作者不保證腳本沒有任何bug

      2. 使用前,根據實際情況修改相關變量.

      3. REQUIRED_OPATCH_VERSION變量需要指定的opatch版本根據官方文檔資料指定

      4. 腳本目前還只適用于單實例

      5. Oracle 19c早期版本需要先回滾OJVM補丁,然后安裝新的補丁,從Oracle Database 19.17.0開始,官方發布了 RU + OJVM Combination Patch(組合補丁)。在該組合補丁中,OJVM 補丁已被整合進 RU 安裝映像,不再需要先回滾舊的 OJVM 補丁. 腳本里面沒有考慮早期版本升級需要先回滾OJVM補丁情況. 如有需要,請自行完善.

      6. 多實例環境,又分相同數據庫版本和不同數據庫版本,這里腳本暫未實現這個功能, 屬實太復雜的場景會讓腳本變得無比復雜,代碼量繼續飆增.這個腳本代碼行數破千了。如果是相同數據庫版本的多實例,只保留一個實例和監聽服務,其它關閉,然后跑完腳本,最后在啟動其它實例,只需跑datapatch腳本

      7. 腳本的函數prepare_run_sql只是特殊環境需要授權,應該很多人的數據庫環境根本不需要這樣的授權,可以注釋刪除這個函數。

      #!/bin/bash
      
      #########################################################################################
      #                                                                                       #
      # Oracle 19c RU + OJVM 一鍵升級腳本,此腳本初始版本來源于IT邦德,使用原腳本時發現有一些bug#
      # 于是個人在其基礎上進行了大量的調整與改進,這個腳本基本上可以算是完全重構了。          #
      #########################################################################################
      #                                                                                       #
      # ScriptName            :    oracle_19c_ru_ojvm_upgrade.sh                              #
      # Author                :    瀟湘隱者                                                   #
      # CerateDate            :    2025-08-21                                                 #
      # Email                 :    kerry2008code@qq.com                                       #
      #***************************************************************************************#
      # 變量配置                                                                              #
      #---------------------------------------------------------------------------------------#
      # CONNECT_INFO        連接數據庫的方式,默認為系統認證模式(如需適用賬號密碼訪問,調整即可 #
      # ORACLE_SID          ORACLE_SID                                                        #
      # ORACLE_HOME         ORACLE主目錄                                                      #
      # PATCH_DIR           Oracle的補丁文件存放路徑                                          #
      # OPATCH_PATCH        Oracle的opatch補丁文件名                                          #
      # REQUIRED_OPATCH_VERSION 要求的最低opatch版本                                          #
      # RU_PATCH            RU補丁文件名                                                      #
      # OJVM_PATCH          OJVM補丁名                                                        #
      #---------------------------------------------------------------------------------------#
      # 參數說明                                                                              #
      #---------------------------------------------------------------------------------------#
      #     此腳本無須使用參數                                                                #
      #---------------------------------------------------------------------------------------#
      #  Usage:                                                                               #
      #          sh oracle_19c_ru_ojvm_upgrade.sh                                             #
      #      或  ./oracle_19c_ru_ojvm_upgrade.sh                                              #
      #***************************************************************************************#
      # 注意事項:                                                                             #
      #    1. 此腳本只在Linux(REHL)平臺上測試了Oracle 19c數據庫, 雖然經過大量驗證,不保證其它  #
      #       平臺環境也能運行,可能存在Bug,使用前請進行測試驗證,作者不保證腳本沒有任何bug     #
      #    2. 使用前,根據實際情況修改相關變量.                                                #
      #    3. REQUIRED_OPATCH_VERSION變量需要指定的opatch版本根據官方文檔資料指定             #
      #    4. 腳本目前還只適用于單實例                                                        #
      #    5. Oracle 19c早期版本需要先回滾OJVM補丁,然后安裝新的補丁,從Oracle Database 19.17.0 #
      #       開始,官方發布了 RU + OJVM Combination Patch(組合補丁)。在該組合補丁中,OJVM 補丁#
      #       已被整合進 RU 安裝映像,不再需要先回滾舊的 OJVM 補丁. 腳本里面沒有考慮早期版本升#
      #       級需要先回滾OJVM補丁情況. 如有需要,請自行完善.                                  #
      #    6. 多實例環境,又分相同數據庫版本和不同數據庫版本,這里腳本暫未實現這個功能,         #
      #       屬實太復雜的場景會讓腳本變得無比復雜,代碼量繼續飆增.這個腳本代碼行數破千了      #
      #       如果是相同數據庫版本的多實例,只保留一個實例和監聽服務,其它關閉,然后跑完腳本,最后#
      #       在啟動其它實例,只需跑datapatch腳本                                              #
      #***************************************************************************************#
      # Version        Modified Date            Description                                   #
      #***************************************************************************************#
      # V.0.0          2025-08-19              IT邦德的原始腳本                               #
      # V.1.0          2025-08-21              修改/創建此腳本                                #
      # V.1.1          2025-08-25              增加邏輯判斷,fix掉幾個bug                      #
      # V.1.2          2025-08-29              關閉/啟動數據庫實例,關閉/啟動監聽功能封裝成函數#
      #                                        獨立出來,方便簡單調用                          #
      # V.1.3          2025-09-01              打補丁前檢查各個PDB失效對象信息,打完補丁后執行 #
      #                                        重編譯無效對象                                 #
      # V.1.4          2025-09-02              打完補丁,檢查補丁安裝信息                      #
      # V.1.5          2025-09-03              完善部分功能與(19c非租戶環境)執行檢查無        #
      #                                        效對象出錯的Bug                                #
      #########################################################################################
      
      # =============== 安全控制 ===============
      # 嚴格錯誤處理
      #set -euo pipefail  
      #trap "echo 'ERROR: 腳本異常退出,請檢查日志!'; exit 1" ERR
      
      # =============== 配置區(根據實際修改)===============
      # ORACLE_SID
      export ORACLE_SID="gsp"
      # ORACLE_HOME目錄
      export ORACLE_HOME="/opt/oracle19c/product/19.3.0/db_1"
      # 數據庫的連接方式,請根據實際情況調整
      readonly CONNECT_INFO="conn / as sysdba"
      # 數據庫補丁存放的路徑
      readonly PATCH_DIR="/data/soft"
      # OPATCH補丁文件名
      readonly OPATCH_PATCH="p6880880_190000_Linux-x86-64.zip"
      # 要求的最低opatch版本
      readonly REQUIRED_OPATCH_VERSION="12.2.0.1.46"
      # RU補丁文件名
      readonly RU_PATCH="p37960098_190000_Linux-x86-64.zip"
      # OJVM補丁文件名
      readonly OJVM_PATCH="p37847857_190000_Linux-x86-64.zip"
      
      
      # 下面變量基本無須修改
      ROLLBACK_FILE="${PATCH_DIR}/rollback_${ORACLE_SID}_$(date +%Y%m%d).sql"
      LOG_DATE=$(date +%Y%m%d%H%M)
      readonly SUCCESS=0
      readonly FAILURE=1
      LOG_FILE="${PATCH_DIR}/patch_${ORACLE_SID}_${LOG_DATE}.log"
      # Log輸出方式:log或cmd或all
      LOG_OUT_TYPE=all
      LSNR_NAME=""
      DB_VERSION="19"
      IS_MULTI_DB=""
      OS_TYPE=""
      PDB_LIST=""
      
      
      # 記錄腳本的日志信息輸出
      log_info(){
      
          #判斷參數個數
          if [ $# -eq 1 ];then
              local log_msg=$1
              case $LOG_OUT_TYPE in
                  cmd)
                      echo -e "[info]: $(date '+%Y%m%d %H:%M:%S')> ${log_msg}"
                      ;;
                  log)
                      echo -e "[info]: $(date '+%Y%m%d %H:%M:%S')> ${log_msg}" >> "$LOG_FILE"
                      ;;
                  all)
                      # log_info暫時不會發送郵件
                      echo -e "[info]: $(date '+%Y%m%d %H:%M:%S')> ${log_msg}"
                      echo -e "[info]: $(date '+%Y%m%d %H:%M:%S')> ${log_msg}" >> "$LOG_FILE"
                      ;;
                  *)
              esac
          elif [ $# -eq 2 ];then
              local log_msg=$1
              case $2 in
                  cmd)
                      echo -e "[info]: $(date '+%Y%m%d %H:%M:%S')> ${log_msg}"
                      ;;
                  log)
                      echo -e "[info]: $(date '+%Y%m%d %H:%M:%S')> ${log_msg}" >> "$LOG_FILE"
                      ;;
                   all)
                      echo -e "[info]: $(date '+%Y%m%d %H:%M:%S')> ${log_msg}"
                      echo -e "[info]: $(date '+%Y%m%d %H:%M:%S')> ${log_msg}" >> "$LOG_FILE"
                      ;;
                  *)
              esac
          else
              echo -e "[error]: $(date '+%Y%m%d %H:%M:%S')> the number of parameters is incorrect!"
          fi
      }
      
      # 記錄腳本的錯誤信息輸出
      log_error(){
          #判斷參數個數
          if [ $# -eq 1 ];then
              local log_msg=$1
              case $LOG_OUT_TYPE in
                  cmd)
                       echo  -e  "[error]:$(date '+%Y%m%d %H:%M:%S')> ${log_msg}"
                       ;;
                  log)
                       echo  -e  "[error]:$(date '+%Y%m%d %H:%M:%S')> ${log_msg}" >> "$LOG_FILE"
                       ;;
                  all)
                       echo -e "[error]:$(date '+%Y%m%d %H:%M:%S')> ${log_msg}"
                       echo -e "[error]:$(date '+%Y%m%d %H:%M:%S')> ${log_msg}" >> "$LOG_FILE"
                       ;;
                  *)
              esac
          elif [ $# -eq 2 ];then
              local log_msg=$1
              case $2 in
                  cmd)
                       echo  -e  "[error]:$(date '+%Y%m%d %H:%M:%S')> ${log_msg}"
                       ;;
                  log)
                       echo  -e  "[error]:$(date '+%Y%m%d %H:%M:%S')> ${log_msg}" >> "$LOG_FILE"
                       ;;
                  all)
                       echo -e "[error]:$(date '+%Y%m%d %H:%M:%S')> ${log_msg}"
                       echo -e "[error]:$(date '+%Y%m%d %H:%M:%S')> ${log_msg}" >> "$LOG_FILE"
                       ;;
                  *)
              esac
          else
              echo -e "[error]: $(date '+%Y%m%d %H:%M:%S')> the number of parameters is incorrect!"
          fi
      }
      
      precheck() {
      
          log_info "precheck開始預檢..."
          
          # 1. 檢查操作系統
          OS_TYPE=$(uname -a | awk ' { print $1} ')
          log_info "當前操作系統為: "${OS_TYPE}" "
         
          if [ "$OS_TYPE" == "Linux" ];
          then 
              log_info "當前操作系統為 ${OS_TYPE},檢查通過"
          else
              log_info "當前腳本沒有在Linux之外平臺測試過,請謹慎使用!"
          fi 
          
          # 2. 運行腳本的當前用戶檢查/確認
          if [ "$(whoami)" != "oracle" ]; 
          then
              log_error "必須使用oracle用戶執行此腳本!"
              exit ${FAILURE}
          else
              log_info "賬號檢查正常,當前賬號為$(whoami)"
          fi
          
          # 3. Oracle補丁文件檢查是否齊全
          if [[ ! -f ${PATCH_DIR}/${RU_PATCH} || ! -f ${PATCH_DIR}/${OJVM_PATCH} || ! -f ${PATCH_DIR}/${OPATCH_PATCH} ]]; 
          then
              log_error "Oracle相關補丁文件缺失!,請檢查補丁包文件是否齊全"
              exit ${FAILURE}
          else
              log_info "Oracle安裝升級的補丁文件齊全,如下所示:"
              ls -lrt ${PATCH_DIR}/${RU_PATCH}
              ls -lrt ${PATCH_DIR}/${OJVM_PATCH}
              ls -lrt ${PATCH_DIR}/${OPATCH_PATCH}
          fi
          
          # 4. 數據庫監聽服務檢查確認
          local curr_lsn_num
          curr_lsn_num=$(ps -e -o args | grep tnslsnr | grep -v grep |wc -l)
      
          if [ "${curr_lsn_num}" -eq 0 ];
          then
              log_info "當前環境不存在監聽服務或監聽服務已經關閉了"
              read -r  -p "請輸入正確的監聽服務名"  listener_name
              LSNR_NAME=$(listener_name) 
          elif [ "${curr_lsn_num}" -eq 1 ]
          then
             LSNR_NAME=$(ps -e -o args | grep tnslsnr | grep -v grep | awk '{print $2}' | tr "[:upper:]" "[:lower:]")
             log_info "當前監聽名稱為: ${LSNR_NAME}"
          elif [ "${curr_lsn_num}" -gt 1 ];
          then
             log_info "當前環境有多個監聽服務,請指定監聽服務名: "
             read -r  -p "請輸入正確的監聽服務名: "  listener_name
             LSNR_NAME=$(listener_name) 
          fi 
          
          # 5. 數據庫實例的狀態檢查確認
          local curr_db_status
          curr_db_status=$(check_db_status)
          
          
      
          if [ "$curr_db_status" != "OPEN" ]; 
          then
              log_error "數據庫已處于關閉狀態,數據庫必須處于OPEN狀態"
              exit  ${FAILURE}
          else
              IS_MULTI_DB=$(check_db_multitenant)
              log_info "數據庫狀態為: ${curr_db_status} "
          fi
      
      
      
          # 5. OPatch版本檢查
          log_info "Opatch的版本信息如下所示:"
          $ORACLE_HOME/OPatch/opatch version 
      
      
          # 6. 數據庫版本信息
          log_info "數據庫的版本信息如下所示:"
          sqlplus -S /nolog <<EOF
              whenever sqlerror exit sql.sqlcode
              ${CONNECT_INFO}
              set linesize 120
              select banner_full from v\$version;
              exit;
      EOF
      
      
      
          # 7. 檢查失效對象信息
          log_info "數據庫的失效對象檢查."
          check_invalid_obj
          
          # 8. 是否繼續補丁升級
          read -r -n1 -p "Do you want to continue installing patches? please choose the [Y/N]?" answer
              case $answer in
                  Y | y)
                      log_info "precheck預檢結束"
                      ;;
                  N | n)
                      log_info "You have chosen to exit the patch installation."
                      exit ${FAILURE}
                      ;;
                  *)
                      log_error "your choice is wrong!"
                      exit ${FAILURE}
                      ;;
              esac
      }
      
      check_db_version(){
      
      local curr_db_status
      curr_db_status=$(check_db_status)
      
      if [ "${curr_db_status}" == "DOWN" ];
      then
          log_error "the oracle instance is down, please check it"
      else
      
          db_version_sql=$(
      sqlplus -S /nolog  <<EOF |awk -F= "/^a=/ {print \$2}" 
      SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
      ${CONNECT_INFO}
      SELECT 'a='||REGEXP_SUBSTR(VERSION, '^\d+') FROM V\$INSTANCE;
      EXIT
      EOF
               )
      
          if [[ -n "${db_version_sql}"  && "${db_version_sql}" -gt 9 ]];
          then
              DB_VERSION=${db_version_sql}
          else
              log_error "獲取Oracle數據庫版本出錯,請檢查腳本與日志!"
          fi 
      fi
      }
      
      # 檢查數據庫當前狀態
      check_db_status() {
      
          local status=""
          local db_inst_num="0"
      
          db_inst_num=$(ps -ef | grep ora_pmon_${ORACLE_SID} | grep -v grep | wc -l)
          if [ "${db_inst_num}" -eq 0 ]; then
             echo "DOWN"
          else
             status=$(
             sqlplus -S /nolog <<EOF  | awk -F= "/^a=/ {print \$2}" 
             set head off pagesize 0 feedback off linesize 400
             whenever sqlerror exit 1
             ${CONNECT_INFO}
             select 'a='||status from v\$instance;
             exit
      EOF
            )
            echo "${status}" 
          fi
          
          return "${SUCCESS}"
      }
      
      # 檢查數據庫是否多租戶環境
      check_db_multitenant() {
      
          check_db_version
          if [ "${DB_VERSION}" -ge 12 ];
          then 
              IS_PDB_EXIST=$(sqlplus  -S /nolog <<EOF
              ${CONNECT_INFO}
              SET HEADING OFF 
              WHENEVER SQLERROR EXIT SQL.SQLCODE
              SELECT COUNT(*) VALUE FROM CDB_PDBS;
              EXIT
      EOF
              )
              if [ "$IS_PDB_EXIST" -ge 1 ];
              then
                  echo "Y"
              else
                  echo "N"
              fi
          else
              echo "N"
          fi
      }
      
      # 停止監聽服務
      stop_listener() {
      
      if [ "$OS_TYPE" == "Linux" ] ; 
      then 
          #LSNR_NAME=`ps -ef | grep tns | grep $ORACLE_HOME | grep -v grep | awk '{ print $9 }'`
          LSNR_NAME=$(ps -e -o args | grep tnslsnr | grep -v grep | head -1 | awk '{print $2}' | tr "[:upper:]" "[:lower:]")
      elif [ "$OS_TYPE" == "AIX" ] ; 
      then
          #LSNR_NAME=`ps -ef | grep tns | grep $ORACLE_HOME | grep -v grep | awk '{ print $10 }'`
          LSNR_NAME=$(ps -ef | grep tnslsnr | grep -v grep | awk '{print $10 }')
      elif [ "OS_TYPE" == "HP-UX"] ; 
      then
          LSNR_NAME=$(ps -ef | grep tnslsnr | grep -v grep | awk '{print $10 }')
      fi
      
      local curr_lsn_num
      curr_lsn_num=$(ps -ef | grep tnslsnr | grep -v grep |wc -l)
      
      if [ "$curr_lsn_num" -eq 0 ];
      then
          log_info "當前環境數據庫監聽服務已經停止或不存在, 請檢查確認!"
          exit ${FAILURE}
      elif [ "$curr_lsn_num" -eq 1 ];
      then
          lsnrctl stop "$LSNR_NAME"
      elif [ "$curr_lsn_num" -gt 1 ];
      then
          read -r -n1 -p "Do you like shutting down all listening services? please choose the [Y/N]?" answer
              case $answer in
                  Y | y)
                      for lsnr_name_item in ${LSNR_NAME};
                      do
                        lsnrctl stop "$lsnr_name_item"
                      done
                      ;;
                  N | n)
                      read -r  -p "Please specify the listener service to be stopped." curr_lsnr_name
                      lsnrctl stop "$curr_lsnr_name"
                      ;;
                  *)
                      log_error "your choice was wrong!"
                      exit ${FAILURE}
                      ;;
              esac
      fi
      }
      
      # 啟動監聽服務
      start_listener() {
      
          local curr_lsn_num
          local curr_lsnr_name
          
          if [ -z "${LSNR_NAME}" ]; then
              log_error ""${LSNR_NAME}" is null, please check it"
              read -r  -p "Please specify the listener service to be stopped." curr_lsnr_name
              
              lsnrctl start "$curr_lsnr_name"
              
              if [ $? -eq 0 ]; then
                  log_info  "Oracle監聽服務${LSNR_NAME}啟動成功"
              else
                  log_error "Oracle監聽服務${LSNR_NAME}啟動失敗"
                  exit ${FAILURE}
              fi
          else
          
              curr_lsn_num=$(ps -ef | grep tnslsnr | grep "${LSNR_NAME}" | grep -v grep |wc -l)
      
              if [ "$curr_lsn_num" -eq 0 ];
              then
                  lsnrctl start  "${LSNR_NAME}"
                  if [ $? -eq 0 ]; then
                      log_info  "Oracle監聽服務${LSNR_NAME}啟動成功"
                  else
                      log_error "Oracle監聽服務${LSNR_NAME}啟動失敗"
                      exit ${FAILURE}
                  fi
              else
                  log_info "the listener ${LSNR_NAME} is started now"
              fi
          fi
      }
      
      
      shutdown_oracle() {
      
          local curr_db_status
          curr_db_status=$(check_db_status)
          # 此處只適用于Linux,HP-UX環境會報錯,如需適用于HP-UX的話,其用下面注釋代碼
          #local curr_lsn_num=$(ps -ef | grep tnslsnr | grep -v grep |wc -l)
          local curr_lsn_num
          curr_lsn_num=$(ps -e -o args | grep tnslsnr | grep -v grep |wc -l)
      
          if [ "${curr_lsn_num}" -gt 1 ];
          then
              log_info "當前環境中有多個監聽,請新開一個窗口進行檢查,并手工關閉這些監聽服務."
              read -r -n1 -p "數據庫監聽服務已經關閉了嗎,請輸入(Y或N)"  answer
              case $answer in
                  Y | y)
                      log_info "數據庫監聽服務已經關閉!"
                      ;;
                  N | n)
                      log_info "You have chosen to exit the patch installation."
                      exit ${FAILURE}
                      ;;
                  *)
                      log_error "your choice is wrong!"
                      exit ${FAILURE}
                      ;;
              esac
          elif [ "${curr_lsn_num}" -eq 1 ];
          then
              LSNR_NAME=$(ps -e -o args | grep tnslsnr | grep -v grep | awk '{print $2}' | tr "[:upper:]" "[:lower:]")
              log_info "Listener Name: ${LSNR_NAME}"
      
              lsnrctl stop "${LSNR_NAME}"
              if [ $? -eq 0 ];
              then
                  log_info "stop the Listener  ${LSNR_NAME} successed."
              else
                 log_error "stop the listener ${LSNR_NAME} failed ,please check the log"
                 exit ${FAILURE}
              fi
          else
              log_info "the Listener ${LSNR_NAME} is stopped status. it does not need to stop it!"
          fi
          
          
          if [ "${curr_db_status}" == "DOWN" ]; 
          then
              log_info "數據庫已處于關閉狀態,無需關閉數據庫實例!"
              return  ${SUCCESS}
          else 
      
              sqlplus -S /nolog <<EOF
              whenever sqlerror exit sql.sqlcode
              ${CONNECT_INFO}
              shutdown immediate;
              exit;
      EOF
      
      
              if [ $? -eq 0 ];
              then
                  log_info  "Oracle instance shutdown done.\n"
              else
                  log_error "Oracle instance shutdown failed.\n"
                  exit ${FAILURE}
              fi
      
              INSTANCE_STATUS=$(check_db_status)
              
              if [  "$INSTANCE_STATUS" == "DOWN" ];
              then
                  log_info "Oracle instance is shutdown now"
              else
                  log_error "the oracle instance status is ${INSTANCE_STATUS}, pleas check it "
                  exit $FAILURE
              fi
          fi
      }
      
      start_oracle() {
          
          start_listener
          
          curr_db_status=$(check_db_status)
          
          if [ "$curr_db_status" == "DOWN" ]; 
          then
              if [ "${IS_MULTI_DB}" == "Y" ];
              then
                    sqlplus -S /nolog <<EOF
      whenever sqlerror exit sql.sqlcode
      ${CONNECT_INFO}  
      startup;
      alter pluggable database all open;
      alter pluggable database all save state;  
      exit;
      EOF
                    if [ $? -eq 0 ]; then
                        log_info  "Oracle數據庫實例啟動成功"
                    else
                        log_error "Oracle數據庫實例啟動失敗"
                        exit ${FAILURE}
                    fi
              else
                      sqlplus -S /nolog <<EOF
      whenever sqlerror exit sql.sqlcode
      ${CONNECT_INFO}  
      startup;
      exit;
      EOF
      
                    if [ $? -eq 0 ]; then
                        log_info  "Oracle數據庫實例${ORACLE_SID}啟動成功"
                    else
                        log_error "Oracle數據庫實例${ORACLE_SID}啟動失敗"
                        exit ${FAILURE}
                    fi
              fi
          fi
      
          curr_db_status=$(check_db_status)
      
          if [ "${curr_db_status}" != "OPEN" ]
          then
              log_error "Oracle數據庫實例${ORACLE_SID}啟動失敗.\n"
               exit ${FAILURE}
          else
              log_info "Oracle數據庫實例${ORACLE_SID}啟動成功\n"   
          fi
      }
      
      # 返回PDB數據庫列表
      get_pdb_list() {
      
      PDB_LIST=$(sqlplus -S /nolog <<EOF
      ${CONNECT_INFO}
      set pagesize 0 feedback off verify off heading off echo off
      select 'CDB\$ROOT' name from dual union all
      select name from v\$pdbs where open_mode = 'READ WRITE';
      exit;
      EOF
      )
      
      if [ $? -eq 0 ];
      then
          return ${SUCCESS}
      else
          return ${FAILURE}
      fi
      
      }
      # =============== 備份模塊 ===============
      create_backup() {
          log_info ">>> 創建回滾點..."
          sqlplus -S / as sysdba <<EOF > "$ROLLBACK_FILE"
      set serveroutput on
      exec dbms_qopatch.get_sqlpatch_status;
      exit;
      EOF
      
          log_info ">>> 備份重要文件:"
          $ORACLE_HOME/OPatch/opatch lsinventory -detail > ${PATCH_DIR}/inventory_bak_"$(date +%s)".txt
          #cp ${ORACLE_HOME}/sqlpatch/sqlpatch_bundle/* ${PATCH_DIR}/sqlpatch_bak_$(date +%s)/
      }
      
      
      # 版本比較函數(處理形如x.y.z.a的版本格式)
      version_ge() {
          # 比較版本:如果$1 ≥ $2則返回0(成功),否則返回1
          [ "$(printf "%s\n%s" "$2" "$1" | sort -V | head -n1)" = "$2" ]
      }
      
      
      
      opatch_upgrade() {
      
      local -r patch_file=$1
      
      # 定義OPatch路徑
      local -r OPATCH_CMD="${ORACLE_HOME}/OPatch/opatch"
          
      if [ -f "${PATCH_DIR}/${patch_file}" ];
      then
          unzip -o "${PATCH_DIR}/${patch_file}" -d ${PATCH_DIR}
          PATCH_NAME=$(unzip -l "${PATCH_DIR}/${patch_file}" | awk '/\/$/ {print $4}' | cut -d'/' -f1 | sort -u)
      
          cd "${PATCH_DIR}" || exit
          if [ -d "${ORACLE_HOME}/OPatch" ];
          then
               # 備份舊的OPatch目錄
               mv "${ORACLE_HOME}/OPatch"  "${ORACLE_HOME}/OPatch.${LOG_DATE}"
               cp -rp "${PATCH_DIR}/${PATCH_NAME}" "${ORACLE_HOME}/OPatch"
          else
              log_error "error, please check it"
              exit ${FAILURE}
          fi
          
      
      
          # 檢查opatch可執行文件是否存在
          if [ ! -x "${OPATCH_CMD}" ]; then
              log_error "錯誤:OPatch工具不存在或不可執行,路徑:${OPATCH_CMD}"
              exit ${FAILURE}
          fi
      
          # 獲取當前OPatch版本
          log_info "正在檢查OPatch版本..."
          CURRENT_OPATCH_VERSION=$("${OPATCH_CMD}" version | awk '/OPatch Version/ {print $3}')
      
          if [ -z "${CURRENT_OPATCH_VERSION}" ]; then
              log_error "錯誤:無法獲取OPatch版本信息"
              exit ${FAILURE}
          fi
      
          log_info "當前OPatch版本:${CURRENT_OPATCH_VERSION}"
          log_info "要求的最低OPatch版本:${REQUIRED_OPATCH_VERSION}"
      
          # 檢查版本是否符合要求
          if version_ge "${CURRENT_OPATCH_VERSION}" "${REQUIRED_OPATCH_VERSION}"; then
              log_info "OPatch版本符合要求"
              return $SUCCESS
          else
              log_error "OPatch版本不符合要求,請升級至${REQUIRED_OPATCH_VERSION}或更高版本"
              exit ${FAILURE}
          fi
      
      
          "${ORACLE_HOME}"/OPatch/opatch version | grep -q "${OPATCH_VER}" || {
          log_error "錯誤:OPatch版本不滿足要求!"
          exit ${FAILURE}
        }
      fi
          
      }
      # =============== 補丁應用模塊 ===============
      apply_patch() {
      
        local patch_file=$1
        local patch_type=$2
        
        log_info "應用${patch_type}補丁:$(basename "${patch_file}")"
        unzip -o "${PATCH_DIR}/${patch_file}" -d "${PATCH_DIR}"
        #PATCH_NAME=$(basename $patch_file .zip)
        PATCH_NAME=$(unzip -l "${PATCH_DIR}/${patch_file}" | awk '/\/$/ {print $4}' | cut -d'/' -f1 | sort -u)
      
        cd "${PATCH_DIR}/${PATCH_NAME}" || exit
        "${ORACLE_HOME}"/OPatch/opatch prereq CheckConflictAgainstOHWithDetail -ph .
        "${ORACLE_HOME}"/OPatch/opatch apply -silent 
      
        if [ $? -eq 0 ];
        then
                log_info "Oracle RU patch  apply success"
        else
                log_error "Oracle RU patch  apply failed ,please check the log "
                exit ${FAILURE}
        fi
      
      }
      
      data_patch() {
          start_oracle
          $ORACLE_HOME/OPatch/datapatch -verbose
          
          if [ $? -eq 0 ];
          then
              log_info "Oracle PUS patch success"
          else
              log_error "Oracle PUS patch failed ,please check the log "
              exit ${FAILURE}
          fi
              
      }
      
      prepare_run_sql(){
      
      local -r sql_cmd_text="GRANT EXECUTE ON  HTTPURITYPE TO PUBLIC;"
      
      if [ "$IS_MULTI_DB" == "N" ];
      then
      
          sqlplus -S /nolog <<EOF
                         ${CONNECT_INFO}
                          whenever sqlerror exit sql.sqlcode
                          ${sql_cmd_text}
                          exit;
      EOF
      
             if [ $? -eq 0 ];
             then
                 log_info "在$pdb_name中執行SQL結束..."
             else
                  log_error "在$pdb_name中執行SQL: ${sql_cmd_text} 異常"
                  exit ${FAILURE}
             fi
      
      else
      
          if ! get_pdb_list; then
              exit ${FAILURE}
          fi 
          
          # 檢查是否獲取到PDB列表
          if [ -z "$PDB_LIST" ]; then
              log_error "錯誤: 未能獲取到PDB列表,請檢查數據庫連接"
              exit ${FAILURE}
          fi
          
          # 在每個PDB中執行SQL語句
          for pdb_name in  ${PDB_LIST};
          do
              if [ -n "$pdb_name" ]; 
              then
                  log_info "在$pdb_name中執行SQL開始..."
      
                  # 執行SQL語句
                  sqlplus -S /nolog <<EOF
                                  whenever sqlerror exit sql.sqlcode
                                  ${CONNECT_INFO}
                                  ALTER SESSION SET CONTAINER="$pdb_name";
                                  ${sql_cmd_text}
                                  exit;
      EOF
                  
                  if [ $? -eq 0 ];
                  then
                      log_info "在$pdb_name中執行SQL結束..."
                  else
                      log_error "在$pdb_name中執行SQL: ${sql_cmd_text} 異常"
                      exit ${FAILURE}
                  fi
          
              fi
          done
      fi
      
      }
      
      check_invalid_obj() {
      
      local sql_cmd_text=""
      
      
      if [ "$IS_MULTI_DB" == "Y" ];
      then
          
          if ! get_pdb_list; then
              exit ${FAILURE}
          fi 
          
          # 檢查是否獲取到PDB列表
          if [ -z "$PDB_LIST" ]; then
              log_error "錯誤: 未能獲取到PDB列表,請檢查數據庫連接"
              exit ${FAILURE}
          fi
          # 在每個PDB中執行SQL語句
          for pdb_name in  ${PDB_LIST};
          do
              if [ -n "$pdb_name" ]; 
              then
                  sql_cmd_text="
                  ${CONNECT_INFO}
                  whenever sqlerror exit sql.sqlcode
                  set serveroutput on;
                  ALTER SESSION SET CONTAINER="$pdb_name";
                  set linesize 720
                  set pagesize 60
                  col object_name for a40
                  col object_type for a15
                  col owner for a10
                  select object_name,object_type,owner,status from dba_objects where status<>'VALID' order by owner,object_name;
                  exit;"
      
                  log_info "正在 $pdb_name 中執行SQL..."
                  # 執行SQL語句
                  sqlplus -S /nolog <<EOF
                   ${sql_cmd_text}
      EOF
      
                  if [ $? -eq 0 ];
                  then
                      log_info "$pdb_name 中檢查無效對象完成."
                  else
                      log_error "$pdb_name 中檢查無效對象異常."
                      exit $FAILURE
                  fi
              fi
          done
      else
          sql_cmd_text="
          ${CONNECT_INFO}
          whenever sqlerror exit sql.sqlcode
          set serveroutput on;
          set linesize 720
          set pagesize 60
          col object_name for a40
          col object_type for a15
          col owner for a10
          select object_name,object_type,owner,status from dba_objects where status<>'VALID' order by owner,object_name;
          exit;"
      
          log_info "正在 $pdb_name 中執行SQL..."
          # 執行SQL語句
          sqlplus -S /nolog <<EOF
           ${sql_cmd_text}
      EOF
          if [ $? -eq 0 ];
          then
              log_info "$pdb_name 中檢查無效對象完成."
          else
              log_error "$pdb_name 中檢查無效對象異常."
              exit $FAILURE
          fi
      
      fi
      
      }
      
      recompile_invalid_obj() {
      
      local sql_cmd_text=""
      
      
      if [ "$IS_MULTI_DB" == "N" ];
      then
          sql_cmd_text="${CONNECT_INFO}
                        whenever sqlerror exit sql.sqlcode
                        set serveroutput on;
                        @?/rdbms/admin/utlrp.sql
                        exit;"
          # 執行SQL語句
          sqlplus -S /nolog <<EOF
          ${sql_cmd_text}
      EOF
      
          if [ $? -eq 0 ];
          then
              log_info "在$pdb_name 中執行腳本utlrp.sql完成..."
          else
              log_error "在$pdb_name 中執行腳本utlrp.sql出現異常..."
              exit ${FAILURE}
          fi
      else
      
          if ! get_pdb_list; then
              exit ${FAILURE}
          fi 
          
          # 檢查是否獲取到PDB列表
          if [ -z "$PDB_LIST" ]; then
              log_error "錯誤: 未能獲取到PDB列表,請檢查數據庫連接"
              exit ${FAILURE}
          fi
          
          # 在每個PDB中執行SQL語句
          for pdb_name in  ${PDB_LIST};
          do
              if [ -n "$pdb_name" ]; 
              then
                  log_info "正在$pdb_name中執行腳本utlrp.sql開始..."
                  sql_cmd_text="${CONNECT_INFO}
                                whenever sqlerror exit sql.sqlcode
                                set serveroutput on;
                                ALTER SESSION SET CONTAINER="$pdb_name";
                                @?/rdbms/admin/utlrp.sql
                                exit;"
                  # 執行SQL語句
                  sqlplus -S /nolog <<EOF
                  ${sql_cmd_text}
      EOF
       
                  if [ $? -eq 0 ];
                  then
                      log_info "在$pdb_name 中執行腳本utlrp.sql完成..."
                  else
                      log_error "在$pdb_name 中執行腳本utlrp.sql出現異常..."
                      exit ${FAILURE}
                  fi
          
              fi
          done
      fi
      }
      
      check_patch_info() {
      
          log_info "執行檢查補丁信息如下所示:"
              
          # 執行SQL語句
          sqlplus -S /nolog <<EOF
                          whenever sqlerror exit sql.sqlcode
                          ${CONNECT_INFO}
                          ALTER SESSION SET CONTAINER="$pdb_name";
                          set serveroutput on;
                          set linesize 640;
                          set pagesize 40;
                          column action_time for a19
                          column action format a16
                          column version format a26
                          column id for 99
                          column comments format a30
                          column bundle_series format a10
                          select to_char(action_time, 'yyyy-mm-dd hh24:mi:ss') as action_time
                               , action
                               , version
                               , id
                               , comments
                               , bundle_series 
                          from sys.registry\$history
                          order by action_time;
                          
                          set linesize 640;
                          set serveroutput on;
                          col description for a30;    
                          col action_time for a30 ;   
                          select patch_id, patch_uid,action, status,action_time,description from dba_registry_sqlpatch;
                          
                          set linesize 720
                          col version_full for a19
                          col status for a10;
                          col modified for a20;
                          select version,version_full,status,modified
                          from dba_registry;
                          exit;
      EOF
      
          if [ $? -ne 0 ];
          then 
              log_error "執行檢查補丁信息的SQL語句出現錯誤,請檢查確認!"
              exit ${FAILURE}
          fi
      
      }
      
      main() {
      
      
          #執行預檢
          precheck
      
          # 特殊授權
          prepare_run_sql
       
      
          #創建備份
          create_backup
      
          #升級opatch
          opatch_upgrade $OPATCH_PATCH
      
          #關閉數據庫實例
          shutdown_oracle
      
          #應用RU補丁
          apply_patch $RU_PATCH "RU"
      
          #應用OJVM補丁
          apply_patch $OJVM_PATCH "OJVM"
          
          #數據庫data patch
          data_patch
      
          # 最終驗證
          log_info ">>> 驗證補丁狀態:"
          $ORACLE_HOME/OPatch/opatch lspatches
          $ORACLE_HOME/OPatch/opatch lsinventory | grep -E "${RU_PATCH%.*}|${OJVM_PATCH%.*}"
          
          log_info ">>>>>> 升級成功!請執行健康檢查腳本驗證數據庫狀態 <<<<<<"
          check_invalid_obj
          recompile_invalid_obj
          check_patch_info
        
      }
      
      # 執行主函數
      main | tee -a "${LOG_FILE}"
      

      微信公眾號的文章保存時,部分代碼經常會出現部分單詞間的空格被"自動刪除", 所以建議你從下面的原文或
      百度網盤鏈接獲取源代碼

      主站蜘蛛池模板: 日夜啪啪一区二区三区| 柳河县| 欧美videos粗暴| 婷婷色综合成人成人网小说| 丰满的熟妇岳中文字幕| 卢龙县| 国内少妇人妻偷人精品视频| 国产欧美丝袜在线二区| 国产熟妇久久777777| 人妻无码中文专区久久app| 亚洲综合一区二区三区不卡| 国产偷自视频区视频| 毛片网站在线观看| 国产日产精品系列| 日本激情久久精品人妻热| 精品无人乱码一区二区三区的优势| 国内偷自第一区二区三区| 国产97人人超碰caoprom| 国产精品国产三级国产专| 99精品国产高清一区二区麻豆 | 亚洲天堂av日韩精品| 亚洲人午夜精品射精日韩| 免费无码一区无码东京热| 欧美成人VA免费大片视频| 欧美片内射欧美美美妇| 性欧美乱熟妇xxxx白浆| 免费国产拍久久受拍久久| 无码国产精品成人| 国产亚洲一二三区精品| 国语精品国内自产视频| 久久精品免费无码区| 无码av片在线观看免费| 精品欧洲av无码一区二区| 久久国产自偷自偷免费一区| 一区二区三区精品视频免费播放| 亚洲一区二区精品另类| 黑人巨大亚洲一区二区久| 中文字幕精品久久久久人妻红杏1| 玖玖在线精品免费视频| 中文字幕亚洲综合久久青草| 在线看高清中文字幕一区|