Friday, November 14, 2025

#!/bin/bash ################################################################################ # Oracle 19c RAC Database Administration - Restore Point Management Functions # Description: Guaranteed restore point management for Data Guard environments # Created: 2025-11-02 # Updated: 2025-11-14 - Integrated with database loading fix ################################################################################ ################################################################################ # Function: manage_restore_points # Description: Interactive restore point management menu # Parameters: $1 - Database name # Returns: 0 on success, 1 on failure ################################################################################ manage_restore_points() { local db_name=$1 log_message "INFO" "Starting restore point management for $db_name" while true; do clear echo "==========================================" echo "Restore Point Management" echo "Database: $db_name" echo "==========================================" echo "" echo "1. List Restore Points" echo "2. Create Restore Point" echo "3. Create Guaranteed Restore Point" echo "4. Drop Restore Point" echo "5. Flashback Database to Restore Point" echo "6. Propagate Restore Point to Standby" echo "7. View Restore Point Details" echo "0. Return to Main Menu" echo "" echo "==========================================" echo "" read -p "Enter your choice [0-7]: " choice case $choice in 1) list_restore_points "$db_name" ;; 2) create_restore_point "$db_name" "NO" ;; 3) create_restore_point "$db_name" "YES" ;; 4) drop_restore_point "$db_name" ;; 5) flashback_to_restore_point "$db_name" ;; 6) propagate_restore_point_to_standby "$db_name" ;; 7) view_restore_point_details "$db_name" ;; 0) log_message "INFO" "Exiting restore point management" return 0 ;; *) echo "" echo "ERROR: Invalid choice" sleep 2 ;; esac if [[ $choice -ne 0 ]]; then echo "" read -p "Press Enter to continue..." fi done } ################################################################################ # Function: list_restore_points # Description: List all restore points ################################################################################ list_restore_points() { local db_name=$1 echo "" echo "==========================================" echo "Restore Points for $db_name" echo "==========================================" echo "" sqlplus -s / as sysdba << EOF SET LINESIZE 200 SET PAGESIZE 100 COLUMN name FORMAT A30 COLUMN scn FORMAT 999999999999999 COLUMN time FORMAT A20 COLUMN guarantee_flashback_database FORMAT A10 HEADING "GUARANTEED" COLUMN storage_size FORMAT 999,999,999,999 HEADING "STORAGE_MB" SELECT name, scn, TO_CHAR(time, 'YYYY-MM-DD HH24:MI:SS') as time, guarantee_flashback_database, ROUND(storage_size/1024/1024, 2) as storage_size FROM v\$restore_point ORDER BY time DESC; EXIT; EOF log_message "INFO" "Listed restore points for $db_name" } ################################################################################ # Function: create_restore_point # Description: Create a restore point # Parameters: $1 - Database name # $2 - Guarantee flashback (YES/NO) ################################################################################ create_restore_point() { local db_name=$1 local guarantee=$2 echo "" echo "==========================================" echo "Create Restore Point" echo "==========================================" echo "" # Check if flashback is enabled local flashback_on=$(sqlplus -s / as sysdba << EOF SET HEADING OFF SET FEEDBACK OFF SET PAGESIZE 0 SELECT flashback_on FROM v\$database; EXIT; EOF ) flashback_on=$(echo "$flashback_on" | xargs) if [[ "$flashback_on" != "YES" ]] && [[ "$guarantee" == "YES" ]]; then echo "ERROR: Flashback Database is not enabled" echo "Cannot create guaranteed restore point without flashback database" log_message "ERROR" "Flashback database not enabled on $db_name" return 1 fi # Get restore point name local default_name="RP_$(date '+%Y%m%d_%H%M%S')" echo "Default name: $default_name" read -p "Enter restore point name [default: $default_name]: " rp_name if [[ -z "$rp_name" ]]; then rp_name=$default_name fi # Confirm creation echo "" echo "Restore Point Details:" echo " Name: $rp_name" echo " Guaranteed: $guarantee" echo " Database: $db_name" echo "" read -p "Create this restore point? (yes/no): " confirm if [[ ! "$confirm" =~ ^[Yy][Ee][Ss]$ ]]; then echo "Restore point creation cancelled" return 0 fi echo "" echo "Creating restore point..." # Create restore point if [[ "$guarantee" == "YES" ]]; then sqlplus -s / as sysdba << EOF WHENEVER SQLERROR EXIT 1 CREATE RESTORE POINT ${rp_name} GUARANTEE FLASHBACK DATABASE; EXIT; EOF else sqlplus -s / as sysdba << EOF WHENEVER SQLERROR EXIT 1 CREATE RESTORE POINT ${rp_name}; EXIT; EOF fi if [[ $? -eq 0 ]]; then echo "✓ Restore point created successfully: $rp_name" log_message "SUCCESS" "Restore point created: $rp_name (guaranteed: $guarantee)" # Show details echo "" echo "Restore Point Details:" sqlplus -s / as sysdba << EOF SET LINESIZE 200 SELECT name, scn, TO_CHAR(time, 'YYYY-MM-DD HH24:MI:SS') as time, guarantee_flashback_database FROM v\$restore_point WHERE name = '${rp_name}'; EXIT; EOF else echo "✗ Failed to create restore point" log_message "ERROR" "Failed to create restore point: $rp_name" return 1 fi return 0 } ################################################################################ # Function: drop_restore_point # Description: Drop a restore point ################################################################################ drop_restore_point() { local db_name=$1 echo "" echo "==========================================" echo "Drop Restore Point" echo "==========================================" echo "" # List existing restore points echo "Existing Restore Points:" echo "------------------------" sqlplus -s / as sysdba << EOF SET LINESIZE 200 COLUMN name FORMAT A30 SELECT name, TO_CHAR(time, 'YYYY-MM-DD HH24:MI:SS') as time, guarantee_flashback_database as guaranteed FROM v\$restore_point ORDER BY time DESC; EXIT; EOF echo "" read -p "Enter restore point name to drop: " rp_name if [[ -z "$rp_name" ]]; then echo "No restore point name provided" return 0 fi # Verify restore point exists local exists=$(sqlplus -s / as sysdba << EOF SET HEADING OFF SET FEEDBACK OFF SET PAGESIZE 0 SELECT COUNT(*) FROM v\$restore_point WHERE name = '${rp_name}'; EXIT; EOF ) exists=$(echo "$exists" | xargs) if [[ $exists -eq 0 ]]; then echo "ERROR: Restore point '$rp_name' not found" return 1 fi # Confirm deletion echo "" echo "WARNING: This will permanently remove the restore point: $rp_name" read -p "Are you sure? (yes/no): " confirm if [[ ! "$confirm" =~ ^[Yy][Ee][Ss]$ ]]; then echo "Operation cancelled" return 0 fi echo "" echo "Dropping restore point..." sqlplus -s / as sysdba << EOF WHENEVER SQLERROR EXIT 1 DROP RESTORE POINT ${rp_name}; EXIT; EOF if [[ $? -eq 0 ]]; then echo "✓ Restore point dropped successfully: $rp_name" log_message "SUCCESS" "Restore point dropped: $rp_name" else echo "✗ Failed to drop restore point" log_message "ERROR" "Failed to drop restore point: $rp_name" return 1 fi return 0 } ################################################################################ # Function: flashback_to_restore_point # Description: Flashback database to a restore point ################################################################################ flashback_to_restore_point() { local db_name=$1 echo "" echo "==========================================" echo "Flashback Database to Restore Point" echo "==========================================" echo "" echo "⚠ WARNING: This is a critical operation!" echo "" # Check database role local db_role=$(sqlplus -s / as sysdba << EOF SET HEADING OFF SET FEEDBACK OFF SET PAGESIZE 0 SELECT database_role FROM v\$database; EXIT; EOF ) db_role=$(echo "$db_role" | xargs) echo "Current database role: $db_role" echo "" if [[ "$db_role" == "PRIMARY" ]]; then echo "⚠ WARNING: Flashback on PRIMARY database affects entire Data Guard configuration" echo "" fi # List restore points echo "Available Restore Points:" echo "-------------------------" sqlplus -s / as sysdba << EOF SET LINESIZE 200 SELECT name, scn, TO_CHAR(time, 'YYYY-MM-DD HH24:MI:SS') as time, guarantee_flashback_database FROM v\$restore_point ORDER BY time DESC; EXIT; EOF echo "" read -p "Enter restore point name: " rp_name if [[ -z "$rp_name" ]]; then echo "No restore point name provided" return 0 fi # Verify restore point exists local exists=$(sqlplus -s / as sysdba << EOF SET HEADING OFF SET FEEDBACK OFF SET PAGESIZE 0 SELECT COUNT(*) FROM v\$restore_point WHERE name = '${rp_name}'; EXIT; EOF ) exists=$(echo "$exists" | xargs) if [[ $exists -eq 0 ]]; then echo "ERROR: Restore point '$rp_name' not found" return 1 fi # Final confirmation echo "" echo "==========================================" echo "FLASHBACK CONFIRMATION" echo "==========================================" echo "Database: $db_name" echo "Restore Point: $rp_name" echo "" echo "This operation will:" echo " 1. Shutdown the database" echo " 2. Mount the database" echo " 3. Flashback to restore point" echo " 4. Open database with RESETLOGS" echo "" echo "⚠ All data changes after the restore point will be LOST!" echo "" read -p "Type 'FLASHBACK' to proceed: " confirm if [[ "$confirm" != "FLASHBACK" ]]; then echo "Operation cancelled" return 0 fi echo "" echo "Performing flashback operation..." log_message "INFO" "Starting flashback database to $rp_name" # Execute flashback sqlplus -s / as sysdba << EOF WHENEVER SQLERROR EXIT 1 PROMPT Shutting down database... SHUTDOWN IMMEDIATE; PROMPT Starting database in MOUNT mode... STARTUP MOUNT; PROMPT Executing flashback database... FLASHBACK DATABASE TO RESTORE POINT ${rp_name}; PROMPT Opening database with RESETLOGS... ALTER DATABASE OPEN RESETLOGS; EXIT; EOF if [[ $? -eq 0 ]]; then echo "" echo "✓ Flashback completed successfully" echo "" echo "Database has been restored to restore point: $rp_name" echo "" if [[ "$db_role" == "PRIMARY" ]]; then echo "IMPORTANT: Reinstate standby databases in Data Guard configuration" echo "" echo "For each standby database, execute:" echo " 1. Connect to standby" echo " 2. SHUTDOWN IMMEDIATE;" echo " 3. STARTUP MOUNT;" echo " 4. FLASHBACK DATABASE TO RESTORE POINT $rp_name;" echo " 5. ALTER DATABASE OPEN;" echo " 6. Restart MRP: ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT;" echo "" fi log_message "SUCCESS" "Flashback database completed: $rp_name" else echo "✗ Flashback operation failed" log_message "ERROR" "Flashback database failed: $rp_name" return 1 fi return 0 } ################################################################################ # Function: propagate_restore_point_to_standby # Description: Ensure restore point is propagated to standby databases ################################################################################ propagate_restore_point_to_standby() { local db_name=$1 echo "" echo "==========================================" echo "Propagate Restore Point to Standby" echo "==========================================" echo "" # Check database role local db_role=$(sqlplus -s / as sysdba << EOF SET HEADING OFF SET FEEDBACK OFF SET PAGESIZE 0 SELECT database_role FROM v\$database; EXIT; EOF ) db_role=$(echo "$db_role" | xargs) if [[ "$db_role" != "PRIMARY" ]]; then echo "ERROR: This operation must be run on PRIMARY database" echo "Current role: $db_role" return 1 fi # List restore points echo "Available Restore Points:" echo "-------------------------" sqlplus -s / as sysdba << EOF SET LINESIZE 200 SELECT name, TO_CHAR(time, 'YYYY-MM-DD HH24:MI:SS') as time FROM v\$restore_point ORDER BY time DESC; EXIT; EOF echo "" read -p "Enter restore point name to propagate: " rp_name if [[ -z "$rp_name" ]]; then echo "No restore point name provided" return 0 fi echo "" echo "Checking restore point status..." # Get restore point SCN local rp_scn=$(sqlplus -s / as sysdba << EOF SET HEADING OFF SET FEEDBACK OFF SET PAGESIZE 0 SELECT scn FROM v\$restore_point WHERE name = '${rp_name}'; EXIT; EOF ) rp_scn=$(echo "$rp_scn" | xargs) if [[ -z "$rp_scn" ]]; then echo "ERROR: Restore point '$rp_name' not found" return 1 fi echo "Restore point SCN: $rp_scn" echo "" echo "To verify on standby database:" echo " 1. Connect to standby database" echo " 2. SELECT * FROM v\$restore_point WHERE name = '${rp_name}';" echo "" echo "If not present, ensure:" echo " - Redo transport is working" echo " - MRP is applying redo" echo " - There are no archive log gaps" echo "" # Check Data Guard status echo "Data Guard Transport Status:" echo "----------------------------" sqlplus -s / as sysdba << EOF SET LINESIZE 200 SELECT dest_name, status, error FROM v\$archive_dest_status WHERE dest_name LIKE 'LOG_ARCHIVE_DEST_%' AND status != 'INACTIVE'; EXIT; EOF log_message "INFO" "Checked restore point propagation for $rp_name" } ################################################################################ # Function: view_restore_point_details # Description: View detailed information about restore points ################################################################################ view_restore_point_details() { local db_name=$1 echo "" echo "==========================================" echo "Restore Point Details" echo "==========================================" echo "" sqlplus -s / as sysdba << EOF SET LINESIZE 200 SET PAGESIZE 100 COLUMN name FORMAT A30 COLUMN scn FORMAT 999999999999999 COLUMN time FORMAT A20 COLUMN database_incarnation# FORMAT 9999 HEADING "INCARN" COLUMN guarantee_flashback_database FORMAT A10 HEADING "GUARANTEED" COLUMN storage_size FORMAT 999,999,999,999 HEADING "STORAGE_MB" SELECT name, scn, TO_CHAR(time, 'YYYY-MM-DD HH24:MI:SS') as time, database_incarnation#, guarantee_flashback_database, ROUND(storage_size/1024/1024, 2) as storage_size FROM v\$restore_point ORDER BY time DESC; PROMPT PROMPT Flashback Database Status: PROMPT ========================== SELECT flashback_on, log_mode, TO_CHAR(oldest_flashback_time, 'YYYY-MM-DD HH24:MI:SS') as oldest_flashback_time, TO_CHAR(oldest_flashback_scn) as oldest_flashback_scn FROM v\$database; PROMPT PROMPT Fast Recovery Area Usage: PROMPT ========================= SELECT space_limit/1024/1024/1024 as space_limit_gb, space_used/1024/1024/1024 as space_used_gb, space_reclaimable/1024/1024/1024 as space_reclaimable_gb, number_of_files, ROUND((space_used/space_limit)*100, 2) as percent_used FROM v\$recovery_file_dest; EXIT; EOF log_message "INFO" "Viewed restore point details for $db_name" } ################################################################################ # Function: cleanup_old_restore_points # Description: Clean up old restore points ################################################################################ cleanup_old_restore_points() { local db_name=$1 local days_old=${2:-7} echo "" echo "==========================================" echo "Cleanup Old Restore Points" echo "==========================================" echo "" echo "Removing restore points older than $days_old days..." echo "" # List old restore points local old_rps=$(sqlplus -s / as sysdba << EOF SET HEADING OFF SET FEEDBACK OFF SET PAGESIZE 0 SELECT name FROM v\$restore_point WHERE time < SYSDATE - $days_old AND guarantee_flashback_database = 'YES'; EXIT; EOF ) if [[ -z "$old_rps" ]]; then echo "No old restore points found" return 0 fi echo "Old restore points to be removed:" echo "$old_rps" echo "" read -p "Proceed with cleanup? (yes/no): " confirm if [[ ! "$confirm" =~ ^[Yy][Ee][Ss]$ ]]; then echo "Cleanup cancelled" return 0 fi # Drop each restore point while IFS= read -r rp_name; do rp_name=$(echo "$rp_name" | xargs) if [[ -n "$rp_name" ]]; then echo "Dropping: $rp_name" sqlplus -s / as sysdba << EOF DROP RESTORE POINT ${rp_name}; EXIT; EOF if [[ $? -eq 0 ]]; then echo " ✓ Dropped: $rp_name" log_message "INFO" "Dropped old restore point: $rp_name" else echo " ✗ Failed: $rp_name" log_message "ERROR" "Failed to drop restore point: $rp_name" fi fi done <<< "$old_rps" echo "" echo "Cleanup completed" } ################################################################################ # Export functions ################################################################################ export -f manage_restore_points export -f list_restore_points export -f create_restore_point export -f drop_restore_point export -f flashback_to_restore_point export -f cleanup_old_restore_points log_message "INFO" "Restore point management functions loaded"