QUEST_LUCY_COLLECTOR.sql 太厲害了!
CREATE OR REPLACE PACKAGE BODY QUEST_LUCY_COLLECTOR IS
TYPE TYP_ERROR IS RECORD
(
ERROR_TIME TIMESTAMP WITH TIME ZONE( 6 ),
ERROR_MESSAGE VARCHAR2( 4000 ),
ERROR_STACK VARCHAR2( 4000 ),
ERROR_BACKTRACE VARCHAR2( 4000 ),
CALL_STACK VARCHAR2( 4000 )
);
TYPE TYP_ERROR_ARR IS TABLE OF TYP_ERROR INDEX BY PLS_INTEGER;
TYPE TYP_REFRESH_TIMES IS TABLE OF NUMBER INDEX BY VARCHAR2( 30 );
TYPE TYP_DATABASE IS RECORD
(
DBID NUMBER,
DB_UNIQUE_NAME VARCHAR2( 30 ),
NAME VARCHAR2( 9 ),
PLATFORM_NAME VARCHAR2( 101 ),
OPEN_MODE VARCHAR2( 20 )
);
TYPE TYP_INSTANCE IS RECORD
(
INSTANCE_NUMBER NUMBER,
INSTANCE_NAME VARCHAR2( 16 ),
HOST_NAME VARCHAR2( 64 ),
VERSION VARCHAR2( 17 ),
STARTUP_TIME DATE,
STATUS VARCHAR2( 12 ),
THREAD# NUMBER,
INSTANCE_ROLE VARCHAR2( 18 )
);
TYPE TYP_ACTIVE_INSTANCE IS RECORD
(
INST_NUMBER NUMBER,
INST_NAME VARCHAR2( 240 )
);
TYPE TYP_ACTIVE_INSTANCE_ARR IS TABLE OF TYP_ACTIVE_INSTANCE INDEX BY PLS_INTEGER;
TYPE TYP_EVENT IS RECORD
(
EVENT_NAME VARCHAR2( 64 ),
TOTAL_WAITS NUMBER,
TOTAL_TIMEOUTS NUMBER,
TIME_WAITED_MICRO NUMBER
);
TYPE TYP_EVENT_ARR IS TABLE OF TYP_EVENT INDEX BY PLS_INTEGER;
TYPE TYP_DYNAMIC_COMPONENT IS RECORD
(
COMPONENT VARCHAR2( 64 ),
CURRENT_SIZE NUMBER
);
TYPE TYP_DYNAMIC_COMPONENT_ARR IS TABLE OF TYP_DYNAMIC_COMPONENT INDEX BY PLS_INTEGER;
TYPE TYP_IOSTAT_FILE IS RECORD
(
FILETYPE_NAME VARCHAR2( 28 ),
FILE_NAME VARCHAR2( 513 ),
TABLESPACE_NAME VARCHAR2( 30 ),
READ_MEGABYTES NUMBER,
WRITE_MEGABYTES NUMBER,
READ_REQS NUMBER,
WRITE_REQS NUMBER,
READ_SERVICETIME NUMBER,
WRITE_SERVICETIME NUMBER,
SMALL_READ_REQS NUMBER,
SMALL_READ_SERVICETIME NUMBER
);
TYPE TYP_IOSTAT_FILE_ARR IS TABLE OF TYP_IOSTAT_FILE INDEX BY PLS_INTEGER;
TYPE TYP_MEMORY_ADVISORY IS RECORD
(
ADVISORY_NAME VARCHAR2( 30 ),
POOL_NAME VARCHAR2( 20 ),
POOL_BLOCK_SIZE NUMBER,
MEMORY_SIZE_FACTOR NUMBER,
MEMORY_SIZE NUMBER,
ESTD_PHYSICAL_READS NUMBER,
ESTD_TIME NUMBER,
ESTD_OVERALLOC_COUNT NUMBER
);
TYPE TYP_MEMORY_ADVISORY_ARR IS TABLE OF TYP_MEMORY_ADVISORY INDEX BY PLS_INTEGER;
TYPE TYP_PARAMETER IS RECORD
(
NAME VARCHAR2( 80 ),
VALUE VARCHAR2( 4000 ),
ISDEFAULT VARCHAR2( 9 )
);
TYPE TYP_PARAMETER_ARR IS TABLE OF TYP_PARAMETER INDEX BY PLS_INTEGER;
TYPE TYP_STAT IS RECORD
(
STAT_NAME VARCHAR2( 64 ),
VALUE NUMBER
);
TYPE TYP_STAT_ARR IS TABLE OF TYP_STAT INDEX BY PLS_INTEGER;
TYPE TYP_ARCHIVE_DEST IS RECORD
(
DEST_ID NUMBER,
DEST_NAME VARCHAR2( 256 ),
STATUS VARCHAR2( 9 ),
BINDING VARCHAR2( 9 ),
TARGET VARCHAR2( 7 ),
ARCHIVER VARCHAR2( 10 ),
SCHEDULE VARCHAR2( 8 ),
DESTINATION VARCHAR2( 256 ),
DELAY_MINS NUMBER,
PROCESS VARCHAR2( 10 ),
TRANSMIT_MODE VARCHAR2( 12 ),
DB_UNIQUE_NAME VARCHAR2( 30 )
);
TYPE TYP_ARCHIVE_DEST_ARR IS TABLE OF TYP_ARCHIVE_DEST INDEX BY PLS_INTEGER;
TYPE TYP_LOGFILE IS RECORD
(
GROUP# NUMBER,
THREAD# NUMBER,
SEQUENCE# NUMBER,
BYTES NUMBER,
ARCHIVED VARCHAR2( 3 ),
GROUP_STATUS VARCHAR2( 16 ),
FIRST_CHANGE# NUMBER,
FIRST_TIME DATE,
MEMBER_NAME VARCHAR2( 513 ),
MEMBER_STATUS VARCHAR2( 7 )
);
TYPE TYP_LOGFILE_ARR IS TABLE OF TYP_LOGFILE INDEX BY PLS_INTEGER;
TYPE TYP_SNAPSHOT IS RECORD
(
SNAPSHOT_ID NUMBER,
SNAPSHOT_TIME TIMESTAMP WITH TIME ZONE( 6 ),
DATABASE TYP_DATABASE,
INSTANCE TYP_INSTANCE,
ACTIVE_INSTANCE TYP_ACTIVE_INSTANCE_ARR,
SYSTEM_EVENT TYP_EVENT_ARR,
DYNAMIC_COMPONENT TYP_DYNAMIC_COMPONENT_ARR,
IOSTAT_FILE TYP_IOSTAT_FILE_ARR,
燙燙燙燙?|???? MEMORY_ADVISORY TYP_MEMORY_ADVISORY_ARR,
PARAMETER TYP_PARAMETER_ARR,
OSSTAT TYP_STAT_ARR,
PGASTAT TYP_STAT_ARR,
SYS_TIME_MODEL TYP_STAT_ARR,
SYSSTAT TYP_STAT_ARR,
ARCHIVE_DEST TYP_ARCHIVE_DEST_ARR,
LOGFILE TYP_LOGFILE_ARR
);
TYPE TYP_SNAPSHOT_ARR IS TABLE OF TYP_SNAPSHOT INDEX BY PLS_INTEGER;
TYPE TYP_LUCY_SNAPSHOT_TBL IS RECORD
(
SNAPSHOT_ID NUMBER,
SNAPSHOT_TIME TIMESTAMP WITH TIME ZONE( 6 ),
SNAPSHOT_XML CLOB
);
TYPE TYP_LUCY_SNAPSHOT_TBL_ARR IS TABLE OF TYP_LUCY_SNAPSHOT_TBL INDEX BY PLS_INTEGER;
TYPE TYP_VARCHAR2_TABLE IS TABLE OF VARCHAR2( 4000 ) INDEX BY PLS_INTEGER;
TYPE TYP_SCHEDULER_JOB IS RECORD
(
JOB_NAME VARCHAR2( 30 ),
INSTANCE_ID NUMBER,
JOB_ACTION VARCHAR2( 4000 ),
JOB_TYPE VARCHAR2( 16 ),
REPEAT_INTERVAL VARCHAR2( 4000 ),
START_DATE TIMESTAMP WITH TIME ZONE( 6 ),
ENABLED VARCHAR2( 5 ),
LAST_START_DATE TIMESTAMP WITH TIME ZONE( 6 )
);
TYPE TYP_SCHEDULER_JOB_ARR IS TABLE OF TYP_SCHEDULER_JOB INDEX BY VARCHAR2( 30 );
TYPE TYP_DBMS_JOB IS RECORD
(
JOB NUMBER,
LAST_DATE DATE,
NEXT_DATE DATE,
BROKEN VARCHAR2( 1 ),
INTERVAL VARCHAR2( 200 ),
INSTANCE NUMBER
);
TYPE TYP_DBMS_JOB_ARR IS TABLE OF TYP_DBMS_JOB INDEX BY PLS_INTEGER;
FUNCTION GET_OWNER
RETURN VARCHAR2;
GC_PACKAGE_VERSION CONSTANT PLS_INTEGER := 1;
G_ERRORS TYP_ERROR_ARR;
G_SNAPSHOT TYP_SNAPSHOT;
G_REFRESH_TIMES TYP_REFRESH_TIMES;
G_TEMP_REFRESH_TIME TIMESTAMP WITH TIME ZONE( 6 );
G_ORACLE_VERSION NUMBER;
G_INSTANCE_LIST TYP_NUMBER_TABLE;
G_CURRENT_INSTANCE NUMBER;
G_SNAPSHOT_INSTANCE NUMBER;
G_SCHEDULER_JOB_LIST TYP_SCHEDULER_JOB_ARR;
G_SCHEDULER_JOB_LIST_INIT BOOLEAN;
G_DBMS_JOB_LIST TYP_DBMS_JOB_ARR;
G_DBMS_JOB_LIST_INIT BOOLEAN;
G_INDENT_LEVEL PLS_INTEGER;
G_OWNER VARCHAR2( 4000 );
G_USER VARCHAR2( 4000 );
G_GENERATE_SNAPSHOT_ID BOOLEAN;
GC_SPACE_PER_INDENT CONSTANT PLS_INTEGER := 2;
GC_XML_NAMESPACE CONSTANT VARCHAR2( 255 ) := '';
GC_JOB_PREFIX CONSTANT VARCHAR2( 30 ) := 'QUEST_LUCY_JOB';
GC_JOB_ACTION CONSTANT VARCHAR2( 4000 ) := 'BEGIN "' || GET_OWNER || '".quest_lucy_collector.take_snapshot; END;';
GC_REPEAT_MINUTES CONSTANT PLS_INTEGER := 60;
GC_SNAPSHOT_RETENTION_DAYS CONSTANT PLS_INTEGER := 14;
GC_REPEAT_INTERVAL CONSTANT VARCHAR2( 4000 ) := 'FREQ=MINUTELY;INTERVAL=' || TO_CHAR( GC_REPEAT_MINUTES );
GC_DBMS_JOB_INTERVAL CONSTANT VARCHAR2( 4000 ) := 'SYSDATE+(' || GC_REPEAT_MINUTES || ' / (24*60))';
GC_JOB_TYPE CONSTANT VARCHAR2( 16 ) := 'PLSQL_BLOCK';
FUNCTION GET_USER
RETURN VARCHAR2
IS
BEGIN
IF G_USER IS NULL THEN
EXECUTE IMMEDIATE 'SELECT SYS_CONTEXT (''USERENV'', ''SESSION_USER'') FROM dual'
INTO G_USER;
END IF;
RETURN G_USER;
END;
FUNCTION GET_OWNER
RETURN VARCHAR2
IS
L_CALL_STACK VARCHAR2( 4000 );
L_CALL_STACK_LINE VARCHAR2( 4000 );
L_ITERATOR NUMBER;
L_PACKAGE_NAME VARCHAR2( 4000 );
L_OWNER VARCHAR2( 4000 );
BEGIN
IF G_OWNER IS NULL THEN
BEGIN
EXECUTE IMMEDIATE 'BEGIN
:call_stack := DBMS_UTILITY.format_call_stack;
END;'
USING OUT L_CALL_STACK;
EXCEPTION
WHEN OTHERS THEN
L_CALL_STACK := NULL;
END;
IF L_CALL_STACK IS NOT NULL THEN
BEGIN
LOOP
L_ITERATOR := INSTR( L_CALL_STACK, CHR( 10 ) );
EXIT WHEN ( L_ITERATOR IS NULL OR L_ITERATOR = 0 OR L_OWNER IS NOT NULL );
L_CALL_STACK_LINE := SUBSTR( L_CALL_STACK, 1, L_ITERATOR - 1 );
L_CALL_STACK := SUBSTR( L_CALL_STACK, L_ITERATOR + 1 );
IF L_CALL_STACK_LINE LIKE '%package body%' THEN
燙燙燙燙?|???? L_PACKAGE_NAME := SUBSTR( L_CALL_STACK_LINE, INSTR( L_CALL_STACK_LINE, 'package body' ) + LENGTH( 'package body' ) + 1 );
L_OWNER := SUBSTR( L_PACKAGE_NAME, 1, LENGTH( L_PACKAGE_NAME ) - LENGTH( 'QUEST_LUCY_COLLECTOR' ) - 1 );
END IF;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
L_OWNER := NULL;
END;
END IF;
IF L_OWNER IS NULL THEN
L_OWNER := GET_USER;
END IF;
G_OWNER := L_OWNER;
END IF;
RETURN G_OWNER;
END;
PROCEDURE SAVE_EXCEPTION( I_ERROR_MESSAGE IN VARCHAR2 )
IS
L_ERROR TYP_ERROR;
L_ERROR_STACK VARCHAR2( 4000 );
L_ERROR_BACKTRACE VARCHAR2( 4000 );
L_CALL_STACK VARCHAR2( 4000 );
L_TEMP_ERROR_STACK VARCHAR2( 4000 );
BEGIN
L_TEMP_ERROR_STACK := SQLERRM;
BEGIN
EXECUTE IMMEDIATE 'BEGIN
:error_stack := DBMS_UTILITY.format_error_stack;
END;'
USING OUT L_ERROR_STACK;
EXCEPTION
WHEN OTHERS THEN
L_ERROR_STACK := L_TEMP_ERROR_STACK;
END;
BEGIN
EXECUTE IMMEDIATE 'BEGIN
:error_backtrace := DBMS_UTILITY.format_error_backtrace;
END;'
USING OUT L_ERROR_BACKTRACE;
EXCEPTION
WHEN OTHERS THEN
L_ERROR_BACKTRACE := NULL;
END;
BEGIN
EXECUTE IMMEDIATE 'BEGIN
:call_stack := DBMS_UTILITY.format_call_stack;
END;'
USING OUT L_CALL_STACK;
EXCEPTION
WHEN OTHERS THEN
L_CALL_STACK := NULL;
END;
L_ERROR.ERROR_TIME := SYSTIMESTAMP;
L_ERROR.ERROR_MESSAGE := I_ERROR_MESSAGE;
L_ERROR.ERROR_STACK := L_ERROR_STACK;
L_ERROR.ERROR_BACKTRACE := L_ERROR_BACKTRACE;
L_ERROR.CALL_STACK := L_CALL_STACK;
G_ERRORS( G_ERRORS.COUNT + 1 ) := L_ERROR;
G_TEMP_REFRESH_TIME := NULL;
END;
PROCEDURE REMOVE_DBMS_JOB( I_JOB IN NUMBER )
IS
BEGIN
IF GET_OWNER = GET_USER THEN
EXECUTE IMMEDIATE 'BEGIN
DBMS_JOB.remove (:job);
END;'
USING IN I_JOB;
ELSE
EXECUTE IMMEDIATE 'BEGIN
SYS.DBMS_IJOB.remove (:job);
END;'
USING IN I_JOB;
END IF;
END;
PROCEDURE REMOVE_SCHEDULER_JOB( I_JOB_NAME IN VARCHAR2 )
IS
L_JOB_NAME VARCHAR2( 4000 );
BEGIN
L_JOB_NAME := '"' || GET_OWNER || '".' || I_JOB_NAME;
BEGIN
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.drop_job (:job_name);
END;'
USING IN L_JOB_NAME;
EXCEPTION
WHEN OTHERS THEN
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.set_attribute_null (:job_name,
''REPEAT_INTERVAL'');
END;'
USING IN L_JOB_NAME;
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.set_attribute (:job_name,
''AUTO_DROP'',
true);
END;'
USING IN L_JOB_NAME;
END;
END;
FUNCTION GET_ORACLE_VERSION
RETURN NUMBER
IS
L_BANNER VARCHAR2( 80 );
L_VERSION_TEXT VARCHAR2( 80 );
L_FORMAT_MASK VARCHAR2( 80 );
L_VERSION_MAJOR VARCHAR2( 80 );
L_VERSION_MINOR VARCHAR2( 80 );
BEGIN
IF G_ORACLE_VERSION IS NULL THEN
EXECUTE IMMEDIATE 'SELECT banner
FROM v$version
WHERE banner LIKE ''Oracle%'' OR banner LIKE ''Personal Oracle%'''
INTO L_BANNER;
L_VERSION_TEXT := SUBSTR( SUBSTR( L_BANNER, INSTR( L_BANNER, 'Release ' ) + 8 ), 1, INSTR( SUBSTR( L_BANNER, INSTR(燙燙燙燙?|???? L_BANNER, 'Release ' ) + 8 ), ' ' ) - 1 );
L_VERSION_MAJOR := SUBSTR( L_VERSION_TEXT, 1, INSTR( L_VERSION_TEXT, '.', 1, 1 ) - 1 );
L_VERSION_MINOR := SUBSTR( L_VERSION_TEXT, INSTR( L_VERSION_TEXT, '.', 1, 1 ) + 1, INSTR( L_VERSION_TEXT, '.', 1, 2 ) - INSTR( L_VERSION_TEXT, '.', 1, 1 ) - 1 );
L_FORMAT_MASK := RPAD( '9', LENGTH( L_VERSION_MAJOR ), '9' ) || '.' || RPAD( '9', LENGTH( L_VERSION_MINOR ), '9' );
G_ORACLE_VERSION := TO_NUMBER( L_VERSION_MAJOR || '.' || L_VERSION_MINOR, L_FORMAT_MASK );
END IF;
RETURN G_ORACLE_VERSION;
END;
FUNCTION GET_CURRENT_INSTANCE
RETURN NUMBER
IS
BEGIN
IF G_CURRENT_INSTANCE IS NULL THEN
EXECUTE IMMEDIATE 'SELECT USERENV (''INSTANCE'') FROM DUAL'
INTO G_CURRENT_INSTANCE;
END IF;
RETURN G_CURRENT_INSTANCE;
END;
FUNCTION GET_INSTANCE_LIST
RETURN TYP_NUMBER_TABLE
IS
L_TEMP_INSTANCE_LIST TYP_NUMBER_TABLE;
BEGIN
IF G_INSTANCE_LIST.COUNT = 0 THEN
EXECUTE IMMEDIATE 'SELECT inst_number FROM v$active_instances'
INTO L_TEMP_INSTANCE_LIST;
IF L_TEMP_INSTANCE_LIST.COUNT = 0 THEN
L_TEMP_INSTANCE_LIST( 1 ) := GET_CURRENT_INSTANCE;
END IF;
FOR I IN 1..L_TEMP_INSTANCE_LIST.COUNT
LOOP
G_INSTANCE_LIST( L_TEMP_INSTANCE_LIST( I ) ) := L_TEMP_INSTANCE_LIST( I );
END LOOP;
END IF;
RETURN G_INSTANCE_LIST;
END;
FUNCTION GET_SCHEDULER_JOB_LIST
RETURN TYP_SCHEDULER_JOB_ARR
IS
TYPE L_TYP_TEMP_SCHEDULER_JOB_ARR IS TABLE OF TYP_SCHEDULER_JOB INDEX BY PLS_INTEGER;
L_TEMP_SCHEDULER_JOB_LIST L_TYP_TEMP_SCHEDULER_JOB_ARR;
L_OWNER VARCHAR2( 4000 ) := GET_OWNER;
BEGIN
IF NOT G_SCHEDULER_JOB_LIST_INIT THEN
G_SCHEDULER_JOB_LIST.DELETE;
EXECUTE IMMEDIATE 'SELECT job_name,
instance_id,
job_action,
job_type,
repeat_interval,
start_date,
enabled,
last_start_date
FROM all_scheduler_jobs
WHERE owner = :owner
AND job_name LIKE :job_prefix || ''_%'''
INTO L_TEMP_SCHEDULER_JOB_LIST
USING IN L_OWNER, IN GC_JOB_PREFIX;
FOR I IN 1..L_TEMP_SCHEDULER_JOB_LIST.COUNT
LOOP
G_SCHEDULER_JOB_LIST( L_TEMP_SCHEDULER_JOB_LIST( I ).JOB_NAME ) := L_TEMP_SCHEDULER_JOB_LIST( I );
END LOOP;
G_SCHEDULER_JOB_LIST_INIT := TRUE;
END IF;
RETURN G_SCHEDULER_JOB_LIST;
END;
FUNCTION GET_DBMS_JOB_LIST
RETURN TYP_DBMS_JOB_ARR
IS
L_TEMP_DBMS_JOB_LIST TYP_DBMS_JOB_ARR;
L_OWNER VARCHAR2( 4000 ) := GET_OWNER;
L_USER VARCHAR2( 4000 ) := GET_USER;
BEGIN
IF NOT G_DBMS_JOB_LIST_INIT THEN
G_DBMS_JOB_LIST.DELETE;
IF L_OWNER = L_USER THEN
EXECUTE IMMEDIATE 'SELECT job,
last_date,
next_date,
broken,
interval,
instance
FROM user_jobs
WHERE what = :job_action'
INTO L_TEMP_DBMS_JOB_LIST
USING IN GC_JOB_ACTION;
ELSE
EXECUTE IMMEDIATE 'SELECT job,
last_date,
next_date,
broken,
interval,
instance
FROM dba_jobs
WHERE priv_user = :priv_user AND what = :job_action'
INTO L_TEMP_DBMS_JOB_LIST
USING IN L_OWNER, IN GC_JOB_ACTION;
END IF;
FOR I IN 1..L_TEMP_DBMS_JOB_LIST.COUNT
LOOP
IF NOT G_DBMS_JOB_LIST.EXISTS( L_TEMP_DBMS_JOB_LIST( I ).INSTANCE ) THEN
燙燙燙燙?|???? G_DBMS_JOB_LIST( L_TEMP_DBMS_JOB_LIST( I ).INSTANCE ) := L_TEMP_DBMS_JOB_LIST( I );
ELSE
REMOVE_DBMS_JOB( L_TEMP_DBMS_JOB_LIST( I ).JOB );
END IF;
END LOOP;
G_DBMS_JOB_LIST_INIT := TRUE;
END IF;
RETURN G_DBMS_JOB_LIST;
END;
FUNCTION GET_OLDEST_SNAPSHOT_TIME
RETURN TIMESTAMP WITH TIME ZONE
IS
L_SNAPSHOT_TIME TIMESTAMP WITH TIME ZONE( 6 );
BEGIN
EXECUTE IMMEDIATE 'SELECT MIN (snapshot_time)
FROM quest_lucy_snapshot'
INTO L_SNAPSHOT_TIME;
RETURN L_SNAPSHOT_TIME;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not retrieve oldest snapshot time' );
RETURN NULL;
END;
PROCEDURE BEGIN_REFRESH_TIMER
IS
BEGIN
IF G_TEMP_REFRESH_TIME IS NULL THEN
G_TEMP_REFRESH_TIME := SYSTIMESTAMP;
ELSE
RAISE_APPLICATION_ERROR( -20000, 'g_temp_refresh_time was not null' );
END IF;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not begin refresh timer' );
END;
PROCEDURE END_REFRESH_TIMER( I_TIMER_NAME IN VARCHAR2 )
IS
L_INTERVAL INTERVAL DAY TO SECOND( 6 );
BEGIN
IF G_TEMP_REFRESH_TIME IS NOT NULL THEN
L_INTERVAL := SYSTIMESTAMP - G_TEMP_REFRESH_TIME;
G_REFRESH_TIMES( I_TIMER_NAME ) := ROUND( ( ( EXTRACT( DAY FROM ( L_INTERVAL ) ) * 24 * 60 * 60 ) + ( EXTRACT( HOUR FROM ( L_INTERVAL ) ) * 60 * 60 ) + ( EXTRACT( MINUTE FROM ( L_INTERVAL ) ) * 60 ) + ( EXTRACT( SECOND FROM ( L_INTERVAL ) ) ) ) * 1000000, 0 );
G_TEMP_REFRESH_TIME := NULL;
ELSE
RAISE_APPLICATION_ERROR( -20000, 'g_temp_refresh_time was null' );
END IF;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not end refresh timer' );
END;
PROCEDURE WRITE_XML( I_XML IN VARCHAR2 )
IS
L_XML VARCHAR2( 32767 );
BEGIN
L_XML := I_XML || CHR( 10 );
EXECUTE IMMEDIATE 'BEGIN
DBMS_LOB.writeappend ("' || GET_OWNER || '".quest_lucy_collector.g_snapshot_xml,
LENGTH (:l_xml),
:l_xml);
END;'
USING IN L_XML;
END;
FUNCTION GET_INDENT
RETURN VARCHAR2
IS
BEGIN
RETURN RPAD( ' ', G_INDENT_LEVEL * GC_SPACE_PER_INDENT, ' ' );
END;
PROCEDURE WRITE_XML_BEGIN_TAG( I_ELEMENT_NAME IN VARCHAR2, I_INCLUDE_REFRESH_TIME IN BOOLEAN := FALSE )
IS
L_ELEMENT VARCHAR2( 32767 );
L_REFRESH_TIME NUMBER;
BEGIN
L_ELEMENT := GET_INDENT || ' IF I_INCLUDE_REFRESH_TIME THEN
BEGIN
L_REFRESH_TIME := G_REFRESH_TIMES( I_ELEMENT_NAME );
EXCEPTION
WHEN NO_DATA_FOUND THEN
L_REFRESH_TIME := 0;
END;
L_ELEMENT := L_ELEMENT || ' RefreshTimeMicro="' || TO_CHAR( L_REFRESH_TIME, 'TM9', 'NLS_NUMERIC_CHARACTERS=''.,''' ) || '"';
END IF;
L_ELEMENT := L_ELEMENT || '>';
G_INDENT_LEVEL := G_INDENT_LEVEL + 1;
WRITE_XML( L_ELEMENT );
END;
PROCEDURE WRITE_XML_END_TAG( I_ELEMENT_NAME IN VARCHAR2 )
IS
L_ELEMENT VARCHAR2( 32767 );
BEGIN
G_INDENT_LEVEL := G_INDENT_LEVEL - 1;
L_ELEMENT := GET_INDENT || '' || I_ELEMENT_NAME || '>';
WRITE_XML( L_ELEMENT );
END;
PROCEDURE WRITE_XML_ELEMENT( I_ELEMENT_NAME IN VARCHAR2, I_ELEMENT_VALUE IN VARCHAR2 )
IS
L_ELEMENT VARCHAR2( 32767 );
L_ELEMENT_VALUE VARCHAR2( 32767 );
BEGIN
IF I_ELEMENT_NAME IS NOT NULL THEN
L_ELEMENT_VALUE := REPLACE( I_ELEMENT_VALUE, CHR( 38 ), CHR( 38 ) || 'amp;' );
L_ELEMENT_VALUE := REPLACE( L_ELEMENT_VALUE, ' L_ELEMENT := GET_INDENT || '';
L_ELEMENT := L_ELEMENT || L_ELEMENT_VALUE;
L_ELEMENT := L_ELEMENT || '' || I_ELEMENT_NAME || '>';
WRITE_XML( L_ELEMENT );燙燙燙燙?|????
END IF;
END;
PROCEDURE WRITE_XML_ELEMENT( I_ELEMENT_NAME IN VARCHAR2, I_ELEMENT_VALUE IN NUMBER )
IS
BEGIN
IF I_ELEMENT_VALUE IS NOT NULL THEN
WRITE_XML_ELEMENT( I_ELEMENT_NAME, TO_CHAR( I_ELEMENT_VALUE, 'TM9', 'NLS_NUMERIC_CHARACTERS=''.,''' ) );
END IF;
END;
PROCEDURE WRITE_XML_ELEMENT( I_ELEMENT_NAME IN VARCHAR2, I_ELEMENT_VALUE IN TIMESTAMP WITH TIME ZONE )
IS
BEGIN
WRITE_XML_ELEMENT( I_ELEMENT_NAME, TO_CHAR( I_ELEMENT_VALUE, 'YYYY-MM-DD"T"HH24:MI:SS.FFTZH:TZM' ) );
END;
PROCEDURE WRITE_XML_ELEMENT( I_ELEMENT_NAME IN VARCHAR2, I_ELEMENT_VALUE IN DATE )
IS
BEGIN
WRITE_XML_ELEMENT( I_ELEMENT_NAME, TO_CHAR( I_ELEMENT_VALUE, 'YYYY-MM-DD"T"HH24:MI:SS' ) );
END;
PROCEDURE WRITE_XML_STATS( I_STATS_NAME IN VARCHAR2, STATS IN TYP_STAT_ARR )
IS
BEGIN
IF STATS.COUNT > 0 OR G_REFRESH_TIMES.EXISTS( I_STATS_NAME ) THEN
WRITE_XML_BEGIN_TAG( I_STATS_NAME, TRUE );
FOR I IN 1..STATS.COUNT
LOOP
WRITE_XML_BEGIN_TAG( 'Stat' );
WRITE_XML_ELEMENT( 'StatName', STATS( I ).STAT_NAME );
WRITE_XML_ELEMENT( 'Value', STATS( I ).VALUE );
WRITE_XML_END_TAG( 'Stat' );
END LOOP;
WRITE_XML_END_TAG( I_STATS_NAME );
END IF;
END;
PROCEDURE WRITE_XML_ERRORS
IS
BEGIN
IF G_ERRORS.COUNT > 0 THEN
WRITE_XML_BEGIN_TAG( 'Errors' );
FOR I IN 1..G_ERRORS.COUNT
LOOP
WRITE_XML_BEGIN_TAG( 'Error' );
WRITE_XML_ELEMENT( 'ErrorTime', G_ERRORS( I ).ERROR_TIME );
WRITE_XML_ELEMENT( 'ErrorMessage', G_ERRORS( I ).ERROR_MESSAGE );
WRITE_XML_ELEMENT( 'ErrorStack', G_ERRORS( I ).ERROR_STACK );
WRITE_XML_ELEMENT( 'ErrorBacktrace', G_ERRORS( I ).ERROR_BACKTRACE );
WRITE_XML_ELEMENT( 'CallStack', G_ERRORS( I ).CALL_STACK );
WRITE_XML_END_TAG( 'Error' );
END LOOP;
WRITE_XML_END_TAG( 'Errors' );
G_ERRORS.DELETE;
END IF;
END;
PROCEDURE WRITE_XML_DATABASE
IS
BEGIN
IF G_SNAPSHOT.DATABASE.DBID IS NOT NULL THEN
WRITE_XML_BEGIN_TAG( 'DatabaseInformation', TRUE );
WRITE_XML_ELEMENT( 'Id', G_SNAPSHOT.DATABASE.DBID );
WRITE_XML_ELEMENT( 'UniqueName', G_SNAPSHOT.DATABASE.DB_UNIQUE_NAME );
WRITE_XML_ELEMENT( 'Name', G_SNAPSHOT.DATABASE.NAME );
WRITE_XML_ELEMENT( 'PlatformName', G_SNAPSHOT.DATABASE.PLATFORM_NAME );
WRITE_XML_ELEMENT( 'OpenMode', G_SNAPSHOT.DATABASE.OPEN_MODE );
WRITE_XML_END_TAG( 'DatabaseInformation' );
END IF;
END;
PROCEDURE WRITE_XML_INSTANCE
IS
BEGIN
IF G_SNAPSHOT.INSTANCE.INSTANCE_NUMBER IS NOT NULL THEN
WRITE_XML_BEGIN_TAG( 'InstanceInformation', TRUE );
WRITE_XML_ELEMENT( 'Id', G_SNAPSHOT.INSTANCE.INSTANCE_NUMBER );
WRITE_XML_ELEMENT( 'Name', G_SNAPSHOT.INSTANCE.INSTANCE_NAME );
WRITE_XML_ELEMENT( 'HostName', G_SNAPSHOT.INSTANCE.HOST_NAME );
WRITE_XML_ELEMENT( 'Version', G_SNAPSHOT.INSTANCE.VERSION );
WRITE_XML_ELEMENT( 'StartupTime', G_SNAPSHOT.INSTANCE.STARTUP_TIME );
WRITE_XML_ELEMENT( 'Status', G_SNAPSHOT.INSTANCE.STATUS );
WRITE_XML_ELEMENT( 'Thread', G_SNAPSHOT.INSTANCE.THREAD# );
WRITE_XML_ELEMENT( 'InstanceRole', G_SNAPSHOT.INSTANCE.INSTANCE_ROLE );
WRITE_XML_END_TAG( 'InstanceInformation' );
END IF;
END;
PROCEDURE WRITE_XML_ACTIVE_INSTANCE
IS
BEGIN
IF G_SNAPSHOT.ACTIVE_INSTANCE.COUNT > 0 OR G_REFRESH_TIMES.EXISTS( 'ActiveInstances' ) THEN
WRITE_XML_BEGIN_TAG( 'ActiveInstances', TRUE );
FOR I IN 1..G_SNAPSHOT.ACTIVE_INSTANCE.COUNT
LOOP
WRITE_XML_BEGIN_TAG( 'ActiveInstance' );
WRITE_XML_ELEMENT( 'Number', G_SNAPSHOT.ACTIVE_INSTANCE( I ).INST_NUMBER );
WRITE_XML_ELEMENT( 'Name', G_SNAPSHOT.ACTIVE_INSTANCE( I ).INST_NAME );
燙燙燙燙?|???? WRITE_XML_END_TAG( 'ActiveInstance' );
END LOOP;
WRITE_XML_END_TAG( 'ActiveInstances' );
END IF;
END;
PROCEDURE WRITE_XML_SYSTEM_EVENTS
IS
BEGIN
IF G_SNAPSHOT.SYSTEM_EVENT.COUNT > 0 OR G_REFRESH_TIMES.EXISTS( 'SystemEvents' ) THEN
WRITE_XML_BEGIN_TAG( 'SystemEvents', TRUE );
FOR I IN 1..G_SNAPSHOT.SYSTEM_EVENT.COUNT
LOOP
WRITE_XML_BEGIN_TAG( 'SystemEvent' );
WRITE_XML_ELEMENT( 'Name', G_SNAPSHOT.SYSTEM_EVENT( I ).EVENT_NAME );
WRITE_XML_ELEMENT( 'TotalWaits', G_SNAPSHOT.SYSTEM_EVENT( I ).TOTAL_WAITS );
WRITE_XML_ELEMENT( 'TotalTimeouts', G_SNAPSHOT.SYSTEM_EVENT( I ).TOTAL_TIMEOUTS );
WRITE_XML_ELEMENT( 'TimeWaited', G_SNAPSHOT.SYSTEM_EVENT( I ).TIME_WAITED_MICRO );
WRITE_XML_END_TAG( 'SystemEvent' );
END LOOP;
WRITE_XML_END_TAG( 'SystemEvents' );
END IF;
END;
PROCEDURE WRITE_XML_DYN_COMPONENTS
IS
BEGIN
IF G_SNAPSHOT.DYNAMIC_COMPONENT.COUNT > 0 OR G_REFRESH_TIMES.EXISTS( 'DynamicComponents' ) THEN
WRITE_XML_BEGIN_TAG( 'DynamicComponents', TRUE );
FOR I IN 1..G_SNAPSHOT.DYNAMIC_COMPONENT.COUNT
LOOP
WRITE_XML_BEGIN_TAG( 'DynamicComponent' );
WRITE_XML_ELEMENT( 'Name', G_SNAPSHOT.DYNAMIC_COMPONENT( I ).COMPONENT );
WRITE_XML_ELEMENT( 'CurrentSize', G_SNAPSHOT.DYNAMIC_COMPONENT( I ).CURRENT_SIZE );
WRITE_XML_END_TAG( 'DynamicComponent' );
END LOOP;
WRITE_XML_END_TAG( 'DynamicComponents' );
END IF;
END;
PROCEDURE WRITE_XML_IOSTAT_FILE
IS
BEGIN
IF G_SNAPSHOT.IOSTAT_FILE.COUNT > 0 OR G_REFRESH_TIMES.EXISTS( 'IostatFiles' ) THEN
WRITE_XML_BEGIN_TAG( 'IostatFiles', TRUE );
FOR I IN 1..G_SNAPSHOT.IOSTAT_FILE.COUNT
LOOP
WRITE_XML_BEGIN_TAG( 'IostatFile' );
WRITE_XML_ELEMENT( 'FiletypeName', G_SNAPSHOT.IOSTAT_FILE( I ).FILETYPE_NAME );
WRITE_XML_ELEMENT( 'FileName', G_SNAPSHOT.IOSTAT_FILE( I ).FILE_NAME );
WRITE_XML_ELEMENT( 'TablespaceName', G_SNAPSHOT.IOSTAT_FILE( I ).TABLESPACE_NAME );
WRITE_XML_ELEMENT( 'ReadMegabytes', G_SNAPSHOT.IOSTAT_FILE( I ).READ_MEGABYTES );
WRITE_XML_ELEMENT( 'WriteMegabytes', G_SNAPSHOT.IOSTAT_FILE( I ).WRITE_MEGABYTES );
WRITE_XML_ELEMENT( 'ReadReqs', G_SNAPSHOT.IOSTAT_FILE( I ).READ_REQS );
WRITE_XML_ELEMENT( 'WriteReqs', G_SNAPSHOT.IOSTAT_FILE( I ).WRITE_REQS );
WRITE_XML_ELEMENT( 'ReadServicetime', G_SNAPSHOT.IOSTAT_FILE( I ).READ_SERVICETIME );
WRITE_XML_ELEMENT( 'WriteServicetime', G_SNAPSHOT.IOSTAT_FILE( I ).WRITE_SERVICETIME );
WRITE_XML_ELEMENT( 'SmallReadReqs', G_SNAPSHOT.IOSTAT_FILE( I ).SMALL_READ_REQS );
WRITE_XML_ELEMENT( 'SmallReadServicetime', G_SNAPSHOT.IOSTAT_FILE( I ).SMALL_READ_SERVICETIME );
WRITE_XML_END_TAG( 'IostatFile' );
END LOOP;
WRITE_XML_END_TAG( 'IostatFiles' );
END IF;
END;
PROCEDURE WRITE_XML_MEMORY_ADVISORY
IS
BEGIN
IF G_SNAPSHOT.MEMORY_ADVISORY.COUNT > 0 OR G_REFRESH_TIMES.EXISTS( 'MemoryAdvisories' ) THEN
WRITE_XML_BEGIN_TAG( 'MemoryAdvisories', TRUE );
FOR I IN 1..G_SNAPSHOT.MEMORY_ADVISORY.COUNT
LOOP
WRITE_XML_BEGIN_TAG( 'MemoryAdvisory' );
WRITE_XML_ELEMENT( 'AdvisoryName', G_SNAPSHOT.MEMORY_ADVISORY( I ).ADVISORY_NAME );
WRITE_XML_ELEMENT( 'PoolName', G_SNAPSHOT.MEMORY_ADVISORY( I ).POOL_NAME );
WRITE_XML_ELEMENT( 'PoolBlockSize', G_SNAPSHOT.MEMORY_ADVISORY( I ).POOL_BLOCK_SIZE );
WRITE_XML_ELEMENT( 'MemorySizeFactor', G_SNAPSHOT.MEMORY_ADVISORY( I ).MEMORY_SIZE_FACTOR );
WRITE_XML_ELEMENT( 'MemorySize', G_SNAPSHOT.MEMORY_ADVISORY( I ).MEMORY_SIZE );
WRITE_XML_ELEMENT( 'EstdPhysicalReads', G_SNAPSHOT.MEMORY_ADVISORY( I ).ESTD_PHYSICAL_READS );
燙燙燙燙?|???? WRITE_XML_ELEMENT( 'EstdTime', G_SNAPSHOT.MEMORY_ADVISORY( I ).ESTD_TIME );
WRITE_XML_ELEMENT( 'EstdOverallocCount', G_SNAPSHOT.MEMORY_ADVISORY( I ).ESTD_OVERALLOC_COUNT );
WRITE_XML_END_TAG( 'MemoryAdvisory' );
END LOOP;
WRITE_XML_END_TAG( 'MemoryAdvisories' );
END IF;
END;
PROCEDURE WRITE_XML_PARAMETER
IS
BEGIN
IF G_SNAPSHOT.PARAMETER.COUNT > 0 OR G_REFRESH_TIMES.EXISTS( 'Parameters' ) THEN
WRITE_XML_BEGIN_TAG( 'Parameters', TRUE );
FOR I IN 1..G_SNAPSHOT.PARAMETER.COUNT
LOOP
WRITE_XML_BEGIN_TAG( 'Parameter' );
WRITE_XML_ELEMENT( 'Name', G_SNAPSHOT.PARAMETER( I ).NAME );
WRITE_XML_ELEMENT( 'Value', G_SNAPSHOT.PARAMETER( I ).VALUE );
WRITE_XML_ELEMENT( 'IsDefault', G_SNAPSHOT.PARAMETER( I ).ISDEFAULT );
WRITE_XML_END_TAG( 'Parameter' );
END LOOP;
WRITE_XML_END_TAG( 'Parameters' );
END IF;
END;
PROCEDURE WRITE_XML_ARCHIVE_DEST
IS
BEGIN
IF G_SNAPSHOT.ARCHIVE_DEST.COUNT > 0 OR G_REFRESH_TIMES.EXISTS( 'ArchiveDests' ) THEN
WRITE_XML_BEGIN_TAG( 'ArchiveDests', TRUE );
FOR I IN 1..G_SNAPSHOT.ARCHIVE_DEST.COUNT
LOOP
WRITE_XML_BEGIN_TAG( 'ArchiveDest' );
WRITE_XML_ELEMENT( 'Id', G_SNAPSHOT.ARCHIVE_DEST( I ).DEST_ID );
WRITE_XML_ELEMENT( 'Name', G_SNAPSHOT.ARCHIVE_DEST( I ).DEST_NAME );
WRITE_XML_ELEMENT( 'Status', G_SNAPSHOT.ARCHIVE_DEST( I ).STATUS );
WRITE_XML_ELEMENT( 'Binding', G_SNAPSHOT.ARCHIVE_DEST( I ).BINDING );
WRITE_XML_ELEMENT( 'Target', G_SNAPSHOT.ARCHIVE_DEST( I ).TARGET );
WRITE_XML_ELEMENT( 'Archiver', G_SNAPSHOT.ARCHIVE_DEST( I ).ARCHIVER );
WRITE_XML_ELEMENT( 'Schedule', G_SNAPSHOT.ARCHIVE_DEST( I ).SCHEDULE );
WRITE_XML_ELEMENT( 'Destination', G_SNAPSHOT.ARCHIVE_DEST( I ).DESTINATION );
WRITE_XML_ELEMENT( 'DelayMins', G_SNAPSHOT.ARCHIVE_DEST( I ).DELAY_MINS );
WRITE_XML_ELEMENT( 'Process', G_SNAPSHOT.ARCHIVE_DEST( I ).PROCESS );
WRITE_XML_ELEMENT( 'TransmitMode', G_SNAPSHOT.ARCHIVE_DEST( I ).TRANSMIT_MODE );
WRITE_XML_ELEMENT( 'DbUniqueName', G_SNAPSHOT.ARCHIVE_DEST( I ).DB_UNIQUE_NAME );
WRITE_XML_END_TAG( 'ArchiveDest' );
END LOOP;
WRITE_XML_END_TAG( 'ArchiveDests' );
END IF;
END;
PROCEDURE WRITE_XML_LOGFILE
IS
BEGIN
IF G_SNAPSHOT.LOGFILE.COUNT > 0 OR G_REFRESH_TIMES.EXISTS( 'Logfiles' ) THEN
WRITE_XML_BEGIN_TAG( 'Logfiles', TRUE );
FOR I IN 1..G_SNAPSHOT.LOGFILE.COUNT
LOOP
WRITE_XML_BEGIN_TAG( 'Logfile' );
WRITE_XML_ELEMENT( 'Group', G_SNAPSHOT.LOGFILE( I ).GROUP# );
WRITE_XML_ELEMENT( 'Thread', G_SNAPSHOT.LOGFILE( I ).THREAD# );
WRITE_XML_ELEMENT( 'Sequence', G_SNAPSHOT.LOGFILE( I ).SEQUENCE# );
WRITE_XML_ELEMENT( 'Bytes', G_SNAPSHOT.LOGFILE( I ).BYTES );
WRITE_XML_ELEMENT( 'Archived', G_SNAPSHOT.LOGFILE( I ).ARCHIVED );
WRITE_XML_ELEMENT( 'GroupStatus', G_SNAPSHOT.LOGFILE( I ).GROUP_STATUS );
WRITE_XML_ELEMENT( 'FirstChange', G_SNAPSHOT.LOGFILE( I ).FIRST_CHANGE# );
WRITE_XML_ELEMENT( 'FirstTime', G_SNAPSHOT.LOGFILE( I ).FIRST_TIME );
WRITE_XML_ELEMENT( 'MemberName', G_SNAPSHOT.LOGFILE( I ).MEMBER_NAME );
WRITE_XML_ELEMENT( 'MemberStatus', G_SNAPSHOT.LOGFILE( I ).MEMBER_STATUS );
WRITE_XML_END_TAG( 'Logfile' );
END LOOP;
WRITE_XML_END_TAG( 'Logfiles' );
END IF;
END;
PROCEDURE WRITE_SNAPSHOT_XML
IS
BEGIN
WRITE_XML_BEGIN_TAG( 'OracleSnapshot' );
WRITE_XML_ELEMENT( 'Id', G_SNAPSHOT.SNAPSHOT_ID );
WRITE_XML_ELEMENT( 'Time', G_SNAPSHOT.SNAPSHOT_TIME );
WRITE_XML_ELEMENT( 'PackageVersion', GC_PACKAGE_VERSION );
WRITE_XML_DATABASE;
WRITE_XML_INSTANCE;
燙燙燙燙?|???? WRITE_XML_ACTIVE_INSTANCE;
WRITE_XML_SYSTEM_EVENTS;
WRITE_XML_DYN_COMPONENTS;
WRITE_XML_IOSTAT_FILE;
WRITE_XML_MEMORY_ADVISORY;
WRITE_XML_PARAMETER;
WRITE_XML_STATS( 'OsStats', G_SNAPSHOT.OSSTAT );
WRITE_XML_STATS( 'PgaStats', G_SNAPSHOT.PGASTAT );
WRITE_XML_STATS( 'SysTimeModels', G_SNAPSHOT.SYS_TIME_MODEL );
WRITE_XML_STATS( 'SysStats', G_SNAPSHOT.SYSSTAT );
WRITE_XML_ARCHIVE_DEST;
WRITE_XML_LOGFILE;
WRITE_XML_ERRORS;
WRITE_XML_END_TAG( 'OracleSnapshot' );
END;
FUNCTION GET_NEXT_SNAPSHOT_ID
RETURN NUMBER
IS
L_SNAPSHOT_ID NUMBER;
BEGIN
EXECUTE IMMEDIATE 'LOCK TABLE "' || GET_OWNER || '".quest_lucy_snapshot IN EXCLUSIVE MODE';
EXECUTE IMMEDIATE 'SELECT NVL (MIN (snapshot_id), 0) - 1 FROM "' || GET_OWNER || '".quest_lucy_snapshot'
INTO L_SNAPSHOT_ID;
RETURN L_SNAPSHOT_ID;
END;
PROCEDURE CREATE_SEQUENCE
IS
BEGIN
EXECUTE IMMEDIATE 'CREATE SEQUENCE "' || GET_OWNER || '".QUEST_LUCY_SEQ_SNAPSHOT_ID
INCREMENT BY 1
START WITH 1
NOCACHE';
END;
FUNCTION GET_QUEST_LUCY_SEQ_SNAPSHOT_ID
RETURN NUMBER
IS
L_SNAPSHOT_ID NUMBER;
BEGIN
EXECUTE IMMEDIATE 'SELECT "' || GET_OWNER || '".quest_lucy_seq_snapshot_id.NEXTVAL FROM DUAL'
INTO L_SNAPSHOT_ID;
RETURN L_SNAPSHOT_ID;
END;
FUNCTION NEW_SNAPSHOT_ID
RETURN NUMBER
IS
L_SNAPSHOT_ID NUMBER;
BEGIN
IF G_GENERATE_SNAPSHOT_ID THEN
BEGIN
L_SNAPSHOT_ID := GET_QUEST_LUCY_SEQ_SNAPSHOT_ID;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get snapshot ID from sequence' );
BEGIN
CREATE_SEQUENCE;
L_SNAPSHOT_ID := GET_QUEST_LUCY_SEQ_SNAPSHOT_ID;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not create the sequence' );
BEGIN
L_SNAPSHOT_ID := GET_NEXT_SNAPSHOT_ID;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get snapshot ID from table' );
L_SNAPSHOT_ID := NULL;
END;
END;
END;
ELSE
L_SNAPSHOT_ID := NULL;
END IF;
RETURN L_SNAPSHOT_ID;
END;
FUNCTION GET_DATABASE_REC
RETURN TYP_DATABASE
IS
L_DATABASE TYP_DATABASE;
L_PLATFORM_COL VARCHAR2( 100 );
L_DB_UNIQUE_NAME_COL VARCHAR2( 100 );
BEGIN
BEGIN_REFRESH_TIMER;
IF GET_ORACLE_VERSION < 10 THEN
L_PLATFORM_COL := 'DBMS_UTILITY.port_string';
L_DB_UNIQUE_NAME_COL := 'name';
ELSE
L_PLATFORM_COL := 'platform_name';
L_DB_UNIQUE_NAME_COL := 'db_unique_name';
END IF;
EXECUTE IMMEDIATE 'SELECT dbid,
' || L_DB_UNIQUE_NAME_COL || ',
name,
' || L_PLATFORM_COL || ',
open_mode
FROM gv$database
WHERE inst_id = :inst_id'
INTO L_DATABASE
USING IN G_SNAPSHOT_INSTANCE;
END_REFRESH_TIMER( 'DatabaseInformation' );
RETURN L_DATABASE;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get DatabaseInformation' );
RETURN L_DATABASE;
END;
FUNCTION GET_INSTANCE_REC
RETURN TYP_INSTANCE
IS
L_INSTANCE TYP_INSTANCE;
BEGIN
BEGIN_REFRESH_TIMER;
EXECUTE IMMEDIATE 'SELECT instance_number,
instance_name,
host_name,
version,
startup_time,
status,
thread#,
instance_role
FROM gv$instance
WHERE inst_id = :inst_id'
INTO L_INSTANCE
燙燙燙燙?|???? USING IN G_SNAPSHOT_INSTANCE;
END_REFRESH_TIMER( 'InstanceInformation' );
RETURN L_INSTANCE;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get InstanceInformation' );
RETURN L_INSTANCE;
END;
FUNCTION GET_ACTIVE_INSTANCE_REC
RETURN TYP_ACTIVE_INSTANCE_ARR
IS
L_ACTIVE_INSTANCE TYP_ACTIVE_INSTANCE_ARR;
BEGIN
BEGIN_REFRESH_TIMER;
EXECUTE IMMEDIATE 'SELECT inst_number,
CASE
WHEN INSTR (inst_name, CHR (0)) = 0 THEN inst_name
ELSE SUBSTR (inst_name, 1, INSTR (inst_name, CHR (0)) - 1)
END
FROM v$active_instances'
INTO L_ACTIVE_INSTANCE;
END_REFRESH_TIMER( 'ActiveInstances' );
RETURN L_ACTIVE_INSTANCE;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get ActiveInstances' );
RETURN L_ACTIVE_INSTANCE;
END;
FUNCTION GET_SYSTEM_EVENT_REC
RETURN TYP_EVENT_ARR
IS
L_SYSTEM_EVENT TYP_EVENT_ARR;
BEGIN
BEGIN_REFRESH_TIMER;
EXECUTE IMMEDIATE 'SELECT event,
total_waits,
total_timeouts,
time_waited_micro / 1000
FROM gv$system_event
WHERE inst_id = :inst_id'
INTO L_SYSTEM_EVENT
USING IN G_SNAPSHOT_INSTANCE;
END_REFRESH_TIMER( 'SystemEvents' );
RETURN L_SYSTEM_EVENT;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get SystemEvents' );
RETURN L_SYSTEM_EVENT;
END;
FUNCTION GET_DYNAMIC_COMPONENT_REC
RETURN TYP_DYNAMIC_COMPONENT_ARR
IS
L_DYNAMIC_COMPONENT TYP_DYNAMIC_COMPONENT_ARR;
L_DYN_COMPONENT_TAB VARCHAR2( 100 );
BEGIN
BEGIN_REFRESH_TIMER;
IF GET_ORACLE_VERSION < 10 THEN
NULL;
ELSE
IF GET_ORACLE_VERSION < 11 THEN
L_DYN_COMPONENT_TAB := 'gv$sga_dynamic_components';
ELSE
L_DYN_COMPONENT_TAB := 'gv$memory_dynamic_components';
END IF;
EXECUTE IMMEDIATE 'SELECT component, current_size
FROM ' || L_DYN_COMPONENT_TAB || '
WHERE inst_id = :inst_id'
INTO L_DYNAMIC_COMPONENT
USING IN G_SNAPSHOT_INSTANCE;
END IF;
END_REFRESH_TIMER( 'DynamicComponents' );
RETURN L_DYNAMIC_COMPONENT;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get DynamicComponents' );
RETURN L_DYNAMIC_COMPONENT;
END;
FUNCTION GET_IOSTAT_FILE_REC
RETURN TYP_IOSTAT_FILE_ARR
IS
L_IOSTAT_FILE TYP_IOSTAT_FILE_ARR;
BEGIN
BEGIN_REFRESH_TIMER;
IF GET_ORACLE_VERSION < 11 THEN
EXECUTE IMMEDIATE 'SELECT ''Data File'' filetype_name,
df.file_name,
ts.tablespace_name,
( (fs.phyblkrd) * ts.block_size) / 1024 / 1024 read_megabytes,
( (fs.phyblkwrt) * ts.block_size) / 1024 / 1024 write_megabytes,
fs.phyrds read_reqs,
fs.phywrts write_reqs,
fs.readtim * 10 read_servicetime,
fs.writetim * 10 write_servicetime,
fs.singleblkrds small_read_reqs,
fs.singleblkrdtim * 10 small_read_servicetime
FROM gv$filestat fs, dba_data_files df, dba_tablespaces ts
WHERE fs.inst_id = :inst_id
AND fs.file# = df.file_id
AND ts.tablespace_name = df.tablespace_name
UNION ALL
SELECT ''Temp File'' filetype_name,
tf.file_name,
ts.tablespace_name,
( (fs.phyblkrd) * ts.block_size) / 1024 / 1024 read_megabytes,
( (fs.phyblkwrt) * ts.block_size) / 1024 / 1024 write_megabytes,
fs.phyrds read_reqs,
fs.phywrts write_reqs,
燙燙燙燙?|???? fs.readtim * 10 read_servicetime,
fs.writetim * 10 write_servicetime,
fs.singleblkrds small_read_reqs,
fs.singleblkrdtim * 10 small_read_servicetime
FROM gv$tempstat fs, dba_temp_files tf, dba_tablespaces ts
WHERE fs.inst_id = :inst_id
AND tf.file_id = fs.file#
AND ts.tablespace_name = tf.tablespace_name
UNION ALL
SELECT ''Control File'' filetype_name,
NULL file_name,
NULL tablespace_name,
NULL read_megabytes,
NULL write_megabytes,
SUM (total_waits) read_reqs,
NULL write_reqs,
ROUND (SUM (time_waited_micro) / 1000) read_servicetime,
NULL write_servicetime,
SUM (total_waits) small_read_reqs,
ROUND (SUM (time_waited_micro) / 1000) small_read_servicetime
FROM gv$system_event
WHERE inst_id = :inst_id
AND event IN
(''control file parallel write'', ''control file sequential read'')
UNION ALL
SELECT ''Log File'' filetype_name,
NULL file_name,
NULL tablespace_name,
NULL read_megabytes,
NULL write_megabytes,
SUM (total_waits) read_reqs,
NULL write_reqs,
ROUND (SUM (time_waited_micro) / 1000) read_servicetime,
NULL write_servicetime,
SUM (total_waits) small_read_reqs,
ROUND (SUM (time_waited_micro) / 1000) small_read_servicetime
FROM gv$system_event
WHERE inst_id = :inst_id
AND event IN
(''log file single write'',
''log file parallel write'',
''log file sequential read'')'
INTO L_IOSTAT_FILE
USING IN G_SNAPSHOT_INSTANCE, IN G_SNAPSHOT_INSTANCE, IN G_SNAPSHOT_INSTANCE, IN G_SNAPSHOT_INSTANCE;
ELSE
EXECUTE IMMEDIATE 'SELECT ios.filetype_name,
df.file_name,
df.tablespace_name,
ios.small_read_megabytes + ios.large_read_megabytes read_megabytes,
ios.small_write_megabytes + ios.large_write_megabytes write_megabytes,
ios.small_read_reqs + ios.large_read_reqs read_reqs,
ios.small_write_reqs + ios.large_write_reqs write_reqs,
ios.small_read_servicetime + ios.large_read_servicetime
read_servicetime,
ios.small_write_servicetime + ios.large_write_servicetime
write_servicetime,
ios.small_read_reqs,
ios.small_read_servicetime
FROM gv$iostat_file ios, dba_data_files df
WHERE ios.inst_id = :inst_id
AND ios.filetype_name = ''Data File''
AND df.file_id = ios.file_no
UNION ALL
SELECT ios.filetype_name,
tf.file_name,
tf.tablespace_name,
ios.small_read_megabytes + ios.large_read_megabytes read_megabytes,
ios.small_write_megabytes + ios.large_write_megabytes write_megabytes,
ios.small_read_reqs + ios.large_read_reqs read_reqs,
ios.small_write_reqs + ios.large_write_reqs write_reqs,
ios.small_read_servicetime + ios.large_read_servicetime
read_servicetime,
ios.small_write_servicetime + ios.large_write_servicetime
write_servicetime,
ios.small_read_reqs,
ios.small_read_servicetime
FROM gv$iostat燙燙燙燙?|????_file ios, dba_temp_files tf
WHERE ios.inst_id = :inst_id
AND ios.filetype_name = ''Temp File''
AND tf.file_id = ios.file_no
UNION ALL
SELECT ios.filetype_name,
NULL file_name,
NULL tablespace_name,
ios.small_read_megabytes + ios.large_read_megabytes read_megabytes,
ios.small_write_megabytes + ios.large_write_megabytes write_megabytes,
ios.small_read_reqs + ios.large_read_reqs read_reqs,
ios.small_write_reqs + ios.large_write_reqs write_reqs,
ios.small_read_servicetime + ios.large_read_servicetime
read_servicetime,
ios.small_write_servicetime + ios.large_write_servicetime
write_servicetime,
ios.small_read_reqs,
ios.small_read_servicetime
FROM gv$iostat_file ios
WHERE ios.inst_id = :inst_id
AND ios.filetype_name NOT IN (''Temp File'', ''Data File'')'
INTO L_IOSTAT_FILE
USING IN G_SNAPSHOT_INSTANCE, IN G_SNAPSHOT_INSTANCE, IN G_SNAPSHOT_INSTANCE;
END IF;
END_REFRESH_TIMER( 'IostatFiles' );
RETURN L_IOSTAT_FILE;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get IostatFiles' );
RETURN L_IOSTAT_FILE;
END;
FUNCTION GET_MEMORY_ADVISORY_REC
RETURN TYP_MEMORY_ADVISORY_ARR
IS
L_MEMORY_ADVISORY TYP_MEMORY_ADVISORY_ARR;
L_DBCACHE_ESTD_TIME_COL VARCHAR2( 100 );
L_PGA_ESTD_TIME_COL VARCHAR2( 100 );
BEGIN
BEGIN_REFRESH_TIMER;
IF GET_ORACLE_VERSION < 10 THEN
L_DBCACHE_ESTD_TIME_COL := 'NULL';
ELSE
L_DBCACHE_ESTD_TIME_COL := 'dbca.estd_physical_read_time';
END IF;
IF GET_ORACLE_VERSION < 11 THEN
L_PGA_ESTD_TIME_COL := 'NULL';
ELSE
L_PGA_ESTD_TIME_COL := 'pga.estd_time';
END IF;
EXECUTE IMMEDIATE 'SELECT ''DBCACHE'' advisory_name,
dbca.name pool_name,
dbca.block_size pool_block_size,
dbca.size_factor memory_size_factor,
dbca.size_for_estimate memory_size,
dbca.estd_physical_reads estd_physical_reads,
' || L_DBCACHE_ESTD_TIME_COL || ' estd_time,
NULL estd_overalloc_count
FROM gv$db_cache_advice dbca
WHERE dbca.inst_id = :inst_id
UNION ALL
SELECT ''PGA'',
'' '',
0,
pga.pga_target_factor,
pga.pga_target_for_estimate / 1024 / 1024,
pga.estd_extra_bytes_rw,
' || L_PGA_ESTD_TIME_COL || ' estd_time,
pga.estd_overalloc_count
FROM gv$pga_target_advice pga
WHERE pga.inst_id = :inst_id'
INTO L_MEMORY_ADVISORY
USING IN G_SNAPSHOT_INSTANCE, IN G_SNAPSHOT_INSTANCE;
END_REFRESH_TIMER( 'MemoryAdvisories' );
RETURN L_MEMORY_ADVISORY;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get MemoryAdvisories' );
RETURN L_MEMORY_ADVISORY;
END;
FUNCTION GET_PARAMETER_REC
RETURN TYP_PARAMETER_ARR
IS
L_PARAMETER TYP_PARAMETER_ARR;
BEGIN
BEGIN_REFRESH_TIMER;
EXECUTE IMMEDIATE 'SELECT name, VALUE, isdefault
FROM gv$system_parameter
WHERE inst_id = :inst_id'
INTO L_PARAMETER
USING IN G_SNAPSHOT_INSTANCE;
END_REFRESH_TIMER( 'Parameters' );
RETURN L_PARAMETER;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get Parameters' );
RETURN L_PARAMETER;
END;
FUNCTION GET_OSSTAT_REC
RETURN TYP_STAT_ARR
IS
L_OSSTAT TYP_STAT_ARR;
BEGIN
BEGIN_REFRESH_TI燙燙燙燙?|????MER;
IF GET_ORACLE_VERSION < 10 THEN
NULL;
ELSE
EXECUTE IMMEDIATE 'SELECT stat_name, VALUE
FROM gv$osstat
WHERE inst_id = :inst_id'
INTO L_OSSTAT
USING IN G_SNAPSHOT_INSTANCE;
END IF;
END_REFRESH_TIMER( 'OsStats' );
RETURN L_OSSTAT;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get OsStats' );
RETURN L_OSSTAT;
END;
FUNCTION GET_PGASTAT_REC
RETURN TYP_STAT_ARR
IS
L_PGASTAT TYP_STAT_ARR;
BEGIN
BEGIN_REFRESH_TIMER;
EXECUTE IMMEDIATE 'SELECT name, VALUE
FROM gv$pgastat
WHERE inst_id = :inst_id'
INTO L_PGASTAT
USING IN G_SNAPSHOT_INSTANCE;
END_REFRESH_TIMER( 'PgaStats' );
RETURN L_PGASTAT;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get PgaStats' );
RETURN L_PGASTAT;
END;
FUNCTION GET_SYS_TIME_MODEL_REC
RETURN TYP_STAT_ARR
IS
L_SYS_TIME_MODEL TYP_STAT_ARR;
BEGIN
BEGIN_REFRESH_TIMER;
IF GET_ORACLE_VERSION < 10 THEN
NULL;
ELSE
EXECUTE IMMEDIATE 'SELECT stat_name, VALUE / 1000 VALUE
FROM gv$sys_time_model
WHERE inst_id = :inst_id'
INTO L_SYS_TIME_MODEL
USING IN G_SNAPSHOT_INSTANCE;
END IF;
END_REFRESH_TIMER( 'SysTimeModels' );
RETURN L_SYS_TIME_MODEL;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get SysTimeModels' );
RETURN L_SYS_TIME_MODEL;
END;
FUNCTION GET_SYSSTAT_REC
RETURN TYP_STAT_ARR
IS
L_SYSSTAT TYP_STAT_ARR;
BEGIN
BEGIN_REFRESH_TIMER;
EXECUTE IMMEDIATE 'SELECT name, VALUE
FROM gv$sysstat
WHERE inst_id = :inst_id'
INTO L_SYSSTAT
USING IN G_SNAPSHOT_INSTANCE;
END_REFRESH_TIMER( 'SysStats' );
RETURN L_SYSSTAT;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get SysStats' );
RETURN L_SYSSTAT;
END;
FUNCTION GET_ARCHIVE_DEST_REC
RETURN TYP_ARCHIVE_DEST_ARR
IS
L_ARCHIVE_DEST TYP_ARCHIVE_DEST_ARR;
L_DB_UNIQUE_NAME_COL VARCHAR2( 100 );
BEGIN
BEGIN_REFRESH_TIMER;
IF GET_ORACLE_VERSION < 10 THEN
L_DB_UNIQUE_NAME_COL := 'NULL';
ELSE
L_DB_UNIQUE_NAME_COL := 'db_unique_name';
END IF;
EXECUTE IMMEDIATE 'SELECT dest_id,
dest_name,
status,
binding,
target,
archiver,
schedule,
destination,
delay_mins,
process,
transmit_mode,
' || L_DB_UNIQUE_NAME_COL || ' db_unique_name
FROM gv$archive_dest
WHERE inst_id = :inst_id AND status <> ''INACTIVE'''
INTO L_ARCHIVE_DEST
USING IN G_SNAPSHOT_INSTANCE;
END_REFRESH_TIMER( 'ArchiveDests' );
RETURN L_ARCHIVE_DEST;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get ArchiveDests' );
RETURN L_ARCHIVE_DEST;
END;
FUNCTION GET_LOGFILE_REC
RETURN TYP_LOGFILE_ARR
IS
L_LOGFILE TYP_LOGFILE_ARR;
BEGIN
BEGIN_REFRESH_TIMER;
EXECUTE IMMEDIATE 'SELECT l.group#,
l.thread#,
l.sequence#,
l.bytes,
l.archived,
l.status group_status,
l.first_change#,
l.first_time,
f.MEMBER member_name,
f.status member_status
FROM gv$log l, gv$logfile f
WHERE l.inst_id = :inst_id AND f.inst_id = :inst_id AND l.group# = f.group#'
INTO L_LOGFILE
USING IN G_SNAPSH燙燙燙燙?|????OT_INSTANCE, IN G_SNAPSHOT_INSTANCE;
END_REFRESH_TIMER( 'Logfiles' );
RETURN L_LOGFILE;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get Logfiles' );
RETURN L_LOGFILE;
END;
PROCEDURE SAVE_SNAPSHOT
IS
BEGIN
WRITE_SNAPSHOT_XML;
EXECUTE IMMEDIATE 'INSERT INTO "' || GET_OWNER || '".quest_lucy_snapshot (snapshot_id, snapshot_time, snapshot_xml)
VALUES (:snapshot_id, :snapshot_time, :snapshot_xml)'
USING IN G_SNAPSHOT.SNAPSHOT_ID, IN G_SNAPSHOT.SNAPSHOT_TIME, IN G_SNAPSHOT_XML;
COMMIT;
END;
PROCEDURE POPULATE_SNAPSHOT( I_INST_ID IN NUMBER := NULL )
IS
BEGIN
G_SNAPSHOT_INSTANCE := NVL( I_INST_ID, GET_CURRENT_INSTANCE );
G_SNAPSHOT.SNAPSHOT_ID := NEW_SNAPSHOT_ID;
G_SNAPSHOT.SNAPSHOT_TIME := SYSTIMESTAMP;
G_SNAPSHOT.DATABASE := GET_DATABASE_REC;
G_SNAPSHOT.INSTANCE := GET_INSTANCE_REC;
G_SNAPSHOT.ACTIVE_INSTANCE := GET_ACTIVE_INSTANCE_REC;
G_SNAPSHOT.SYSTEM_EVENT := GET_SYSTEM_EVENT_REC;
G_SNAPSHOT.DYNAMIC_COMPONENT := GET_DYNAMIC_COMPONENT_REC;
G_SNAPSHOT.IOSTAT_FILE := GET_IOSTAT_FILE_REC;
G_SNAPSHOT.MEMORY_ADVISORY := GET_MEMORY_ADVISORY_REC;
G_SNAPSHOT.PARAMETER := GET_PARAMETER_REC;
G_SNAPSHOT.OSSTAT := GET_OSSTAT_REC;
G_SNAPSHOT.PGASTAT := GET_PGASTAT_REC;
G_SNAPSHOT.SYS_TIME_MODEL := GET_SYS_TIME_MODEL_REC;
G_SNAPSHOT.SYSSTAT := GET_SYSSTAT_REC;
G_SNAPSHOT.ARCHIVE_DEST := GET_ARCHIVE_DEST_REC;
G_SNAPSHOT.LOGFILE := GET_LOGFILE_REC;
END;
PROCEDURE RESET_VARS
IS
BEGIN
G_SNAPSHOT := NULL;
EXECUTE IMMEDIATE 'BEGIN
"' || GET_OWNER || '".quest_lucy_collector.g_snapshot_xml := empty_clob;
DBMS_LOB.createtemporary ("' || GET_OWNER || '".quest_lucy_collector.g_snapshot_xml, TRUE);
END;';
G_INDENT_LEVEL := 0;
G_REFRESH_TIMES.DELETE;
G_TEMP_REFRESH_TIME := NULL;
G_SCHEDULER_JOB_LIST.DELETE;
G_SCHEDULER_JOB_LIST_INIT := FALSE;
G_DBMS_JOB_LIST.DELETE;
G_DBMS_JOB_LIST_INIT := FALSE;
G_INSTANCE_LIST.DELETE;
G_CURRENT_INSTANCE := NULL;
G_SNAPSHOT_INSTANCE := NULL;
G_OWNER := NULL;
G_USER := NULL;
G_SNAPSHOT_ID_LIST.DELETE;
G_GENERATE_SNAPSHOT_ID := TRUE;
END;
PROCEDURE ENABLE_ROLES
IS
L_PASSWORD_ROLE_ARR TYP_VARCHAR2_TABLE;
L_PASSWORD_ROLE_LIST VARCHAR2( 4000 );
BEGIN
BEGIN
EXECUTE IMMEDIATE 'SELECT r.role
FROM user_role_privs urp, dba_roles r
WHERE r.role = urp.granted_role AND password_required = ''YES'''
INTO L_PASSWORD_ROLE_ARR;
FOR I IN 1..L_PASSWORD_ROLE_ARR.COUNT
LOOP
IF I > 1 THEN
L_PASSWORD_ROLE_LIST := L_PASSWORD_ROLE_LIST || ',';
END IF;
L_PASSWORD_ROLE_LIST := L_PASSWORD_ROLE_LIST || '"' || L_PASSWORD_ROLE_ARR( I ) || '"';
END LOOP;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not retrieve list of password protected roles.' );
L_PASSWORD_ROLE_LIST := NULL;
END;
BEGIN
IF L_PASSWORD_ROLE_LIST IS NOT NULL THEN
EXECUTE IMMEDIATE 'SET ROLE ALL EXCEPT ' || L_PASSWORD_ROLE_LIST;
ELSE
EXECUTE IMMEDIATE 'SET ROLE ALL';
END IF;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not enable roles.' );
END;
END;
PROCEDURE GET_SAVED_SNAPSHOTS
IS
BEGIN
EXECUTE IMMEDIATE 'DECLARE
TYPE ltyp_snapshot_rows IS TABLE OF "' || GET_OWNER || '".quest_lucy_snapshot%ROWTYPE
INDEX BY PLS_INTEGER;
l_snapshots ltyp_snapshot_rows;
BEGIN
SELECT *
BULK COLLECT INTO l_snapshots
FROM "' || GET_OWNER || '".quest_lucy_snapshot
FOR UPDATE;
燙燙燙燙?|???? FOR i IN 1 .. l_snapshots.COUNT
LOOP
DBMS_LOB.append ("' || GET_OWNER || '".quest_lucy_collector.g_snapshot_xml,
l_snapshots (i).snapshot_xml);
"' || GET_OWNER || '".quest_lucy_collector.g_snapshot_id_list (i) :=
l_snapshots (i).snapshot_id;
END LOOP;
END;';
END;
PROCEDURE DELETE_SNAPSHOTS
IS
BEGIN
FORALL I IN 1..G_SNAPSHOT_ID_LIST.COUNT
EXECUTE IMMEDIATE 'DELETE FROM "' || GET_OWNER || '".quest_lucy_snapshot
WHERE snapshot_id = :snapshot_id'
USING IN G_SNAPSHOT_ID_LIST( I );
END;
FUNCTION IS_TABLE_CREATED
RETURN BOOLEAN
IS
L_NUM_ROWS NUMBER;
L_OWNER VARCHAR2( 4000 ) := GET_OWNER;
BEGIN
EXECUTE IMMEDIATE 'SELECT COUNT (*)
FROM all_tables
WHERE owner = :owner
AND table_name = ''QUEST_LUCY_SNAPSHOT'''
INTO L_NUM_ROWS
USING IN L_OWNER;
IF L_NUM_ROWS > 0 THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
END;
PROCEDURE CREATE_TABLE
IS
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE "' || GET_OWNER || '".QUEST_LUCY_SNAPSHOT
(
SNAPSHOT_ID NUMBER (*, 0),
SNAPSHOT_TIME TIMESTAMP (6) WITH TIME ZONE NOT NULL,
SNAPSHOT_XML CLOB
)';
EXECUTE IMMEDIATE 'ALTER TABLE "' || GET_OWNER || '".QUEST_LUCY_SNAPSHOT ADD CONSTRAINT QUEST_LUCY_SNAPSHOT_PK PRIMARY KEY (SNAPSHOT_ID)';
END;
FUNCTION IS_SCHEDULER_JOB_OK( I_SCHEDULER_JOB IN TYP_SCHEDULER_JOB, I_INSTANCE IN NUMBER )
RETURN BOOLEAN
IS
BEGIN
IF I_SCHEDULER_JOB.INSTANCE_ID IS NULL OR I_SCHEDULER_JOB.INSTANCE_ID != I_INSTANCE THEN
RETURN FALSE;
END IF;
IF I_SCHEDULER_JOB.JOB_TYPE IS NULL OR I_SCHEDULER_JOB.JOB_ACTION IS NULL OR I_SCHEDULER_JOB.JOB_TYPE != GC_JOB_TYPE OR I_SCHEDULER_JOB.JOB_ACTION != GC_JOB_ACTION THEN
RETURN FALSE;
END IF;
IF I_SCHEDULER_JOB.REPEAT_INTERVAL IS NULL OR I_SCHEDULER_JOB.REPEAT_INTERVAL != GC_REPEAT_INTERVAL THEN
RETURN FALSE;
END IF;
IF I_SCHEDULER_JOB.START_DATE IS NULL OR I_SCHEDULER_JOB.START_DATE > SYSTIMESTAMP THEN
RETURN FALSE;
END IF;
RETURN TRUE;
END;
FUNCTION IS_DBMS_JOB_OK( I_DBMS_JOB IN TYP_DBMS_JOB )
RETURN BOOLEAN
IS
BEGIN
IF I_DBMS_JOB.INTERVAL IS NULL OR I_DBMS_JOB.INTERVAL != GC_DBMS_JOB_INTERVAL THEN
RETURN FALSE;
END IF;
RETURN TRUE;
END;
FUNCTION IS_ALL_SCHEDULER_JOBS_OK
RETURN BOOLEAN
IS
L_SCHEDULER_JOB_LIST TYP_SCHEDULER_JOB_ARR;
L_INSTANCE_LIST TYP_NUMBER_TABLE;
L_INSTANCE_ITERATOR PLS_INTEGER;
L_JOB_NAME VARCHAR2( 30 );
BEGIN
L_INSTANCE_LIST := GET_INSTANCE_LIST;
L_SCHEDULER_JOB_LIST := GET_SCHEDULER_JOB_LIST;
L_INSTANCE_ITERATOR := L_INSTANCE_LIST.FIRST;
WHILE L_INSTANCE_ITERATOR IS NOT NULL
LOOP
L_JOB_NAME := GC_JOB_PREFIX || '_' || L_INSTANCE_LIST( L_INSTANCE_ITERATOR );
IF NOT L_SCHEDULER_JOB_LIST.EXISTS( L_JOB_NAME ) THEN
RETURN FALSE;
END IF;
IF NOT IS_SCHEDULER_JOB_OK( L_SCHEDULER_JOB_LIST( L_JOB_NAME ), L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ) THEN
RETURN FALSE;
END IF;
IF L_SCHEDULER_JOB_LIST( L_JOB_NAME ).ENABLED IS NULL OR L_SCHEDULER_JOB_LIST( L_JOB_NAME ).ENABLED != 'TRUE' THEN
RETURN FALSE;
END IF;
IF L_SCHEDULER_JOB_LIST( L_JOB_NAME ).START_DATE < ( SYSTIMESTAMP - NUMTODSINTERVAL( GC_REPEAT_MINUTES * 2, 'MINUTE' ) ) AND ( L_SCHEDULER_JOB_LIST( L_JOB_NAME ).LAST_START_DATE IS NULL OR L_SCHEDULER_JOB_LIST( L_JOB_NAME ).LAST_START_DATE < ( SYSTIMESTAMP - NUMTODSINTERVAL( GC_REPEAT_MINUTES * 2, 'MINUTE' ) ) ) THEN
RETURN FALSE;
END IF;
L_INSTANCE_ITER燙燙燙燙?|????ATOR := L_INSTANCE_LIST.NEXT( L_INSTANCE_ITERATOR );
END LOOP;
RETURN TRUE;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not determine if scheduler jobs are OK' );
RETURN FALSE;
END;
FUNCTION IS_ALL_DBMS_JOBS_OK
RETURN BOOLEAN
IS
L_INSTANCE_LIST TYP_NUMBER_TABLE;
L_DBMS_JOB_LIST TYP_DBMS_JOB_ARR;
L_INSTANCE_ITERATOR PLS_INTEGER;
BEGIN
L_INSTANCE_LIST := GET_INSTANCE_LIST;
L_DBMS_JOB_LIST := GET_DBMS_JOB_LIST;
L_INSTANCE_ITERATOR := L_INSTANCE_LIST.FIRST;
WHILE L_INSTANCE_ITERATOR IS NOT NULL
LOOP
IF NOT L_DBMS_JOB_LIST.EXISTS( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ) THEN
RETURN FALSE;
END IF;
IF NOT IS_DBMS_JOB_OK( L_DBMS_JOB_LIST( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ) ) THEN
RETURN FALSE;
END IF;
IF L_DBMS_JOB_LIST( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ).BROKEN IS NULL OR L_DBMS_JOB_LIST( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ).BROKEN = 'Y' THEN
RETURN FALSE;
END IF;
IF L_DBMS_JOB_LIST( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ).LAST_DATE IS NULL OR L_DBMS_JOB_LIST( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ).LAST_DATE < ( SYSDATE - ( ( GC_REPEAT_MINUTES * 2 ) / ( 24 * 60 ) ) ) THEN
RETURN FALSE;
END IF;
L_INSTANCE_ITERATOR := L_INSTANCE_LIST.NEXT( L_INSTANCE_ITERATOR );
END LOOP;
RETURN TRUE;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not determine if dbms jobs are OK' );
RETURN FALSE;
END;
PROCEDURE SETUP_SCHEDULER_JOB
IS
L_JOB_NAME VARCHAR2( 30 );
L_FULL_JOB_NAME VARCHAR2( 100 );
L_SCHEDULER_JOB_LIST TYP_SCHEDULER_JOB_ARR;
L_INSTANCE_ITERATOR PLS_INTEGER;
L_INSTANCE_LIST TYP_NUMBER_TABLE;
BEGIN
L_INSTANCE_LIST := GET_INSTANCE_LIST;
L_SCHEDULER_JOB_LIST := GET_SCHEDULER_JOB_LIST;
L_INSTANCE_ITERATOR := L_INSTANCE_LIST.FIRST;
WHILE L_INSTANCE_ITERATOR IS NOT NULL
LOOP
L_JOB_NAME := GC_JOB_PREFIX || '_' || L_INSTANCE_LIST( L_INSTANCE_ITERATOR );
L_FULL_JOB_NAME := '"' || GET_OWNER || '".' || L_JOB_NAME;
IF L_SCHEDULER_JOB_LIST.EXISTS( L_JOB_NAME ) THEN
IF NOT IS_SCHEDULER_JOB_OK( L_SCHEDULER_JOB_LIST( L_JOB_NAME ), L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ) THEN
G_SCHEDULER_JOB_LIST_INIT := FALSE;
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.set_attribute (
:job_name,
''INSTANCE_ID'',
:instance);
END;'
USING IN L_FULL_JOB_NAME, IN L_INSTANCE_LIST( L_INSTANCE_ITERATOR );
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.set_attribute (:job_name,
''JOB_TYPE'',
:job_type);
END;'
USING IN L_FULL_JOB_NAME, IN GC_JOB_TYPE;
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.set_attribute (:job_name,
''JOB_ACTION'',
:job_action);
END;'
USING IN L_FULL_JOB_NAME, IN GC_JOB_ACTION;
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.set_attribute (:job_name,
''REPEAT_INTERVAL'',
:repeat_interval);
END;'
USING IN L_FULL_JOB_NAME, IN GC_REPEAT_INTERVAL;
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.set_attribute (:job_name,
''START_DATE'',
燙燙燙燙?|???? SYSTIMESTAMP);
END;'
USING IN L_FULL_JOB_NAME;
END IF;
ELSE
G_SCHEDULER_JOB_LIST_INIT := FALSE;
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.create_job (
job_name => :job_name,
job_type => :job_type,
job_action => :job_action,
start_date => SYSTIMESTAMP,
repeat_interval => :repeat_interval,
enabled => FALSE,
auto_drop => FALSE);
END;'
USING IN L_FULL_JOB_NAME, IN GC_JOB_TYPE, IN GC_JOB_ACTION, IN GC_REPEAT_INTERVAL;
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.set_attribute (
:job_name,
''INSTANCE_ID'',
:instance);
END;'
USING IN L_FULL_JOB_NAME, IN L_INSTANCE_LIST( L_INSTANCE_ITERATOR );
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.enable (:job_name);
END;'
USING IN L_FULL_JOB_NAME;
END IF;
L_INSTANCE_ITERATOR := L_INSTANCE_LIST.NEXT( L_INSTANCE_ITERATOR );
END LOOP;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not create scheduler jobs' );
END;
PROCEDURE SETUP_DBMS_JOB
IS
L_JOB_NO NUMBER;
L_INSTANCE_LIST TYP_NUMBER_TABLE;
L_DBMS_JOB_LIST TYP_DBMS_JOB_ARR;
L_INSTANCE_ITERATOR PLS_INTEGER;
L_NLS_ENV VARCHAR2( 4000 );
L_OWNER VARCHAR2( 4000 ) := GET_OWNER;
L_USER VARCHAR2( 4000 ) := GET_USER;
BEGIN
L_INSTANCE_LIST := GET_INSTANCE_LIST;
L_DBMS_JOB_LIST := GET_DBMS_JOB_LIST;
L_INSTANCE_ITERATOR := L_INSTANCE_LIST.FIRST;
WHILE L_INSTANCE_ITERATOR IS NOT NULL
LOOP
IF NOT ( L_DBMS_JOB_LIST.EXISTS( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ) AND IS_DBMS_JOB_OK( L_DBMS_JOB_LIST( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ) ) ) THEN
IF L_DBMS_JOB_LIST.EXISTS( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ) THEN
REMOVE_DBMS_JOB( L_DBMS_JOB_LIST( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ).JOB );
END IF;
EXECUTE IMMEDIATE 'BEGIN
DBMS_JOB.submit (
job => :job_no,
what => :job_action,
next_date => SYSDATE,
INTERVAL => :dbms_job_interval,
INSTANCE => :instance);
END;'
USING OUT L_JOB_NO, IN GC_JOB_ACTION, IN GC_DBMS_JOB_INTERVAL, IN L_INSTANCE_LIST( L_INSTANCE_ITERATOR );
IF L_OWNER != L_USER THEN
BEGIN
EXECUTE IMMEDIATE 'SELECT nls_env
FROM user_jobs
WHERE job = :job_no'
INTO L_NLS_ENV
USING IN L_JOB_NO;
EXECUTE IMMEDIATE 'BEGIN
SYS.DBMS_IJOB.change_env (job => :job_no,
luser => :luser,
puser => :puser,
cuser => :cuser,
nlsenv => :nlsenv);
END;'
USING IN L_JOB_NO, IN L_USER, IN L_OWNER, IN L_OWNER, IN L_NLS_ENV;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not change job user' );
REMOVE_DBMS_JOB( L_JOB_NO );
END;
END IF;
G_DBMS_JOB_LIST_INIT := FALSE;
END IF;
L_INSTANCE_ITERATOR := L_INSTANCE_LIST.NEXT( L_INSTAN燙燙燙燙?|????CE_ITERATOR );
END LOOP;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not create dbms jobs' );
END;
PROCEDURE REMOVE_ALL_DBMS_JOB
IS
L_DBMS_JOB_LIST TYP_DBMS_JOB_ARR;
L_DBMS_JOB_ITERATOR PLS_INTEGER;
BEGIN
L_DBMS_JOB_LIST := GET_DBMS_JOB_LIST;
L_DBMS_JOB_ITERATOR := L_DBMS_JOB_LIST.FIRST;
WHILE L_DBMS_JOB_ITERATOR IS NOT NULL
LOOP
REMOVE_DBMS_JOB( L_DBMS_JOB_LIST( L_DBMS_JOB_ITERATOR ).JOB );
L_DBMS_JOB_ITERATOR := L_DBMS_JOB_LIST.NEXT( L_DBMS_JOB_ITERATOR );
END LOOP;
END;
PROCEDURE REMOVE_ALL_SCHEDULER_JOB
IS
L_SCHEDULER_JOB_LIST TYP_SCHEDULER_JOB_ARR;
L_JOB_ITERATOR VARCHAR2( 30 );
BEGIN
L_SCHEDULER_JOB_LIST := GET_SCHEDULER_JOB_LIST;
L_JOB_ITERATOR := L_SCHEDULER_JOB_LIST.FIRST;
WHILE L_JOB_ITERATOR IS NOT NULL
LOOP
REMOVE_SCHEDULER_JOB( L_SCHEDULER_JOB_LIST( L_JOB_ITERATOR ).JOB_NAME );
L_JOB_ITERATOR := L_SCHEDULER_JOB_LIST.NEXT( L_JOB_ITERATOR );
END LOOP;
END;
PROCEDURE REMOVE_ALL_JOB
IS
BEGIN
IF GET_ORACLE_VERSION > 11 THEN
REMOVE_ALL_SCHEDULER_JOB;
END IF;
REMOVE_ALL_DBMS_JOB;
END;
PROCEDURE POPULATE_WRITE_ALL
IS
L_INSTANCE_LIST TYP_NUMBER_TABLE;
L_INSTANCE_ITERATOR PLS_INTEGER;
BEGIN
L_INSTANCE_LIST := GET_INSTANCE_LIST;
L_INSTANCE_ITERATOR := L_INSTANCE_LIST.FIRST;
WHILE L_INSTANCE_ITERATOR IS NOT NULL
LOOP
POPULATE_SNAPSHOT( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) );
WRITE_SNAPSHOT_XML;
L_INSTANCE_ITERATOR := L_INSTANCE_LIST.NEXT( L_INSTANCE_ITERATOR );
END LOOP;
END;
PROCEDURE TAKE_SNAPSHOT
IS
L_IS_TABLE_CREATED BOOLEAN := FALSE;
L_OLDEST_SNAPSHOT_TIME TIMESTAMP WITH TIME ZONE( 6 );
BEGIN
G_ERRORS.DELETE;
ENABLE_ROLES;
RESET_VARS;
G_INDENT_LEVEL := 2;
L_IS_TABLE_CREATED := IS_TABLE_CREATED;
IF NOT L_IS_TABLE_CREATED THEN
BEGIN
CREATE_TABLE;
L_IS_TABLE_CREATED := IS_TABLE_CREATED;
EXCEPTION
WHEN OTHERS THEN
REMOVE_ALL_JOB;
END;
END IF;
IF L_IS_TABLE_CREATED THEN
L_OLDEST_SNAPSHOT_TIME := GET_OLDEST_SNAPSHOT_TIME;
IF L_OLDEST_SNAPSHOT_TIME < ( SYSTIMESTAMP - NUMTODSINTERVAL( GC_SNAPSHOT_RETENTION_DAYS, 'DAY' ) ) THEN
REMOVE_ALL_JOB;
END IF;
POPULATE_SNAPSHOT;
SAVE_SNAPSHOT;
END IF;
RESET_VARS;
END;
FUNCTION GET_SNAPSHOTS( I_SCHEDULE_COLLECTOR IN NUMBER := 1 )
RETURN CLOB
IS
PRAGMA AUTONOMOUS_TRANSACTION;
L_USE_SAVED_SNAPSHOTS BOOLEAN := FALSE;
L_SNAPSHOT_ARR TYP_SNAPSHOT_ARR;
L_IS_TABLE_CREATED BOOLEAN := FALSE;
L_SCHEDULER_JOB_LIST TYP_SCHEDULER_JOB_ARR;
L_DBMS_JOB_LIST TYP_DBMS_JOB_ARR;
BEGIN
G_ERRORS.DELETE;
ENABLE_ROLES;
RESET_VARS;
WRITE_XML_BEGIN_TAG( 'OracleUpload xmlns="' || GC_XML_NAMESPACE || '"' );
WRITE_XML_BEGIN_TAG( 'OracleSnapshots' );
IF I_SCHEDULE_COLLECTOR = 1 THEN
L_IS_TABLE_CREATED := IS_TABLE_CREATED;
IF NOT L_IS_TABLE_CREATED THEN
BEGIN
CREATE_TABLE;
L_IS_TABLE_CREATED := IS_TABLE_CREATED;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not create table' );
END;
END IF;
IF L_IS_TABLE_CREATED THEN
IF GET_ORACLE_VERSION > 11 THEN
SETUP_SCHEDULER_JOB;
IF IS_ALL_SCHEDULER_JOBS_OK THEN
L_USE_SAVED_SNAPSHOTS := TRUE;
ELSE
SETUP_DBMS_JOB;
IF IS_ALL_DBMS_JOBS_OK THEN
L_USE_SAVED_SNAPSHOTS := TRUE;
END IF;
END IF;
BEGIN
L_SCHEDULER_JOB_LIST :=燙燙燙燙?|???? GET_SCHEDULER_JOB_LIST;
L_DBMS_JOB_LIST := GET_DBMS_JOB_LIST;
IF L_SCHEDULER_JOB_LIST.COUNT > 0 AND L_DBMS_JOB_LIST.COUNT > 0 AND IS_ALL_SCHEDULER_JOBS_OK THEN
REMOVE_ALL_DBMS_JOB;
END IF;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not check if there are dbms and scheduler jobs' );
END;
ELSE
SETUP_DBMS_JOB;
IF IS_ALL_DBMS_JOBS_OK THEN
L_USE_SAVED_SNAPSHOTS := TRUE;
END IF;
END IF;
GET_SAVED_SNAPSHOTS;
DELETE_SNAPSHOTS;
IF NOT L_USE_SAVED_SNAPSHOTS THEN
POPULATE_WRITE_ALL;
END IF;
ELSE
POPULATE_WRITE_ALL;
END IF;
ELSE
G_GENERATE_SNAPSHOT_ID := FALSE;
POPULATE_WRITE_ALL;
END IF;
WRITE_XML_END_TAG( 'OracleSnapshots' );
WRITE_XML_ERRORS;
WRITE_XML_END_TAG( 'OracleUpload' );
COMMIT;
RETURN G_SNAPSHOT_XML;
END;
PROCEDURE DROP_OBJECTS
IS
PRAGMA AUTONOMOUS_TRANSACTION;
TABLE_NOT_EXISTS EXCEPTION;
SEQUENCE_NOT_EXISTS EXCEPTION;
PRAGMA EXCEPTION_INIT( TABLE_NOT_EXISTS, -942 );
PRAGMA EXCEPTION_INIT( SEQUENCE_NOT_EXISTS, -2289 );
BEGIN
RESET_VARS;
REMOVE_ALL_JOB;
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE "' || GET_OWNER || '".QUEST_LUCY_SNAPSHOT';
EXCEPTION
WHEN TABLE_NOT_EXISTS THEN
NULL;
END;
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE "' || GET_OWNER || '".QUEST_LUCY_SEQ_SNAPSHOT_ID';
EXCEPTION
WHEN SEQUENCE_NOT_EXISTS THEN
NULL;
END;
COMMIT;
END;
END QUEST_LUCY_COLLECTOR;
/
TYPE TYP_ERROR IS RECORD
(
ERROR_TIME TIMESTAMP WITH TIME ZONE( 6 ),
ERROR_MESSAGE VARCHAR2( 4000 ),
ERROR_STACK VARCHAR2( 4000 ),
ERROR_BACKTRACE VARCHAR2( 4000 ),
CALL_STACK VARCHAR2( 4000 )
);
TYPE TYP_ERROR_ARR IS TABLE OF TYP_ERROR INDEX BY PLS_INTEGER;
TYPE TYP_REFRESH_TIMES IS TABLE OF NUMBER INDEX BY VARCHAR2( 30 );
TYPE TYP_DATABASE IS RECORD
(
DBID NUMBER,
DB_UNIQUE_NAME VARCHAR2( 30 ),
NAME VARCHAR2( 9 ),
PLATFORM_NAME VARCHAR2( 101 ),
OPEN_MODE VARCHAR2( 20 )
);
TYPE TYP_INSTANCE IS RECORD
(
INSTANCE_NUMBER NUMBER,
INSTANCE_NAME VARCHAR2( 16 ),
HOST_NAME VARCHAR2( 64 ),
VERSION VARCHAR2( 17 ),
STARTUP_TIME DATE,
STATUS VARCHAR2( 12 ),
THREAD# NUMBER,
INSTANCE_ROLE VARCHAR2( 18 )
);
TYPE TYP_ACTIVE_INSTANCE IS RECORD
(
INST_NUMBER NUMBER,
INST_NAME VARCHAR2( 240 )
);
TYPE TYP_ACTIVE_INSTANCE_ARR IS TABLE OF TYP_ACTIVE_INSTANCE INDEX BY PLS_INTEGER;
TYPE TYP_EVENT IS RECORD
(
EVENT_NAME VARCHAR2( 64 ),
TOTAL_WAITS NUMBER,
TOTAL_TIMEOUTS NUMBER,
TIME_WAITED_MICRO NUMBER
);
TYPE TYP_EVENT_ARR IS TABLE OF TYP_EVENT INDEX BY PLS_INTEGER;
TYPE TYP_DYNAMIC_COMPONENT IS RECORD
(
COMPONENT VARCHAR2( 64 ),
CURRENT_SIZE NUMBER
);
TYPE TYP_DYNAMIC_COMPONENT_ARR IS TABLE OF TYP_DYNAMIC_COMPONENT INDEX BY PLS_INTEGER;
TYPE TYP_IOSTAT_FILE IS RECORD
(
FILETYPE_NAME VARCHAR2( 28 ),
FILE_NAME VARCHAR2( 513 ),
TABLESPACE_NAME VARCHAR2( 30 ),
READ_MEGABYTES NUMBER,
WRITE_MEGABYTES NUMBER,
READ_REQS NUMBER,
WRITE_REQS NUMBER,
READ_SERVICETIME NUMBER,
WRITE_SERVICETIME NUMBER,
SMALL_READ_REQS NUMBER,
SMALL_READ_SERVICETIME NUMBER
);
TYPE TYP_IOSTAT_FILE_ARR IS TABLE OF TYP_IOSTAT_FILE INDEX BY PLS_INTEGER;
TYPE TYP_MEMORY_ADVISORY IS RECORD
(
ADVISORY_NAME VARCHAR2( 30 ),
POOL_NAME VARCHAR2( 20 ),
POOL_BLOCK_SIZE NUMBER,
MEMORY_SIZE_FACTOR NUMBER,
MEMORY_SIZE NUMBER,
ESTD_PHYSICAL_READS NUMBER,
ESTD_TIME NUMBER,
ESTD_OVERALLOC_COUNT NUMBER
);
TYPE TYP_MEMORY_ADVISORY_ARR IS TABLE OF TYP_MEMORY_ADVISORY INDEX BY PLS_INTEGER;
TYPE TYP_PARAMETER IS RECORD
(
NAME VARCHAR2( 80 ),
VALUE VARCHAR2( 4000 ),
ISDEFAULT VARCHAR2( 9 )
);
TYPE TYP_PARAMETER_ARR IS TABLE OF TYP_PARAMETER INDEX BY PLS_INTEGER;
TYPE TYP_STAT IS RECORD
(
STAT_NAME VARCHAR2( 64 ),
VALUE NUMBER
);
TYPE TYP_STAT_ARR IS TABLE OF TYP_STAT INDEX BY PLS_INTEGER;
TYPE TYP_ARCHIVE_DEST IS RECORD
(
DEST_ID NUMBER,
DEST_NAME VARCHAR2( 256 ),
STATUS VARCHAR2( 9 ),
BINDING VARCHAR2( 9 ),
TARGET VARCHAR2( 7 ),
ARCHIVER VARCHAR2( 10 ),
SCHEDULE VARCHAR2( 8 ),
DESTINATION VARCHAR2( 256 ),
DELAY_MINS NUMBER,
PROCESS VARCHAR2( 10 ),
TRANSMIT_MODE VARCHAR2( 12 ),
DB_UNIQUE_NAME VARCHAR2( 30 )
);
TYPE TYP_ARCHIVE_DEST_ARR IS TABLE OF TYP_ARCHIVE_DEST INDEX BY PLS_INTEGER;
TYPE TYP_LOGFILE IS RECORD
(
GROUP# NUMBER,
THREAD# NUMBER,
SEQUENCE# NUMBER,
BYTES NUMBER,
ARCHIVED VARCHAR2( 3 ),
GROUP_STATUS VARCHAR2( 16 ),
FIRST_CHANGE# NUMBER,
FIRST_TIME DATE,
MEMBER_NAME VARCHAR2( 513 ),
MEMBER_STATUS VARCHAR2( 7 )
);
TYPE TYP_LOGFILE_ARR IS TABLE OF TYP_LOGFILE INDEX BY PLS_INTEGER;
TYPE TYP_SNAPSHOT IS RECORD
(
SNAPSHOT_ID NUMBER,
SNAPSHOT_TIME TIMESTAMP WITH TIME ZONE( 6 ),
DATABASE TYP_DATABASE,
INSTANCE TYP_INSTANCE,
ACTIVE_INSTANCE TYP_ACTIVE_INSTANCE_ARR,
SYSTEM_EVENT TYP_EVENT_ARR,
DYNAMIC_COMPONENT TYP_DYNAMIC_COMPONENT_ARR,
IOSTAT_FILE TYP_IOSTAT_FILE_ARR,
燙燙燙燙?|???? MEMORY_ADVISORY TYP_MEMORY_ADVISORY_ARR,
PARAMETER TYP_PARAMETER_ARR,
OSSTAT TYP_STAT_ARR,
PGASTAT TYP_STAT_ARR,
SYS_TIME_MODEL TYP_STAT_ARR,
SYSSTAT TYP_STAT_ARR,
ARCHIVE_DEST TYP_ARCHIVE_DEST_ARR,
LOGFILE TYP_LOGFILE_ARR
);
TYPE TYP_SNAPSHOT_ARR IS TABLE OF TYP_SNAPSHOT INDEX BY PLS_INTEGER;
TYPE TYP_LUCY_SNAPSHOT_TBL IS RECORD
(
SNAPSHOT_ID NUMBER,
SNAPSHOT_TIME TIMESTAMP WITH TIME ZONE( 6 ),
SNAPSHOT_XML CLOB
);
TYPE TYP_LUCY_SNAPSHOT_TBL_ARR IS TABLE OF TYP_LUCY_SNAPSHOT_TBL INDEX BY PLS_INTEGER;
TYPE TYP_VARCHAR2_TABLE IS TABLE OF VARCHAR2( 4000 ) INDEX BY PLS_INTEGER;
TYPE TYP_SCHEDULER_JOB IS RECORD
(
JOB_NAME VARCHAR2( 30 ),
INSTANCE_ID NUMBER,
JOB_ACTION VARCHAR2( 4000 ),
JOB_TYPE VARCHAR2( 16 ),
REPEAT_INTERVAL VARCHAR2( 4000 ),
START_DATE TIMESTAMP WITH TIME ZONE( 6 ),
ENABLED VARCHAR2( 5 ),
LAST_START_DATE TIMESTAMP WITH TIME ZONE( 6 )
);
TYPE TYP_SCHEDULER_JOB_ARR IS TABLE OF TYP_SCHEDULER_JOB INDEX BY VARCHAR2( 30 );
TYPE TYP_DBMS_JOB IS RECORD
(
JOB NUMBER,
LAST_DATE DATE,
NEXT_DATE DATE,
BROKEN VARCHAR2( 1 ),
INTERVAL VARCHAR2( 200 ),
INSTANCE NUMBER
);
TYPE TYP_DBMS_JOB_ARR IS TABLE OF TYP_DBMS_JOB INDEX BY PLS_INTEGER;
FUNCTION GET_OWNER
RETURN VARCHAR2;
GC_PACKAGE_VERSION CONSTANT PLS_INTEGER := 1;
G_ERRORS TYP_ERROR_ARR;
G_SNAPSHOT TYP_SNAPSHOT;
G_REFRESH_TIMES TYP_REFRESH_TIMES;
G_TEMP_REFRESH_TIME TIMESTAMP WITH TIME ZONE( 6 );
G_ORACLE_VERSION NUMBER;
G_INSTANCE_LIST TYP_NUMBER_TABLE;
G_CURRENT_INSTANCE NUMBER;
G_SNAPSHOT_INSTANCE NUMBER;
G_SCHEDULER_JOB_LIST TYP_SCHEDULER_JOB_ARR;
G_SCHEDULER_JOB_LIST_INIT BOOLEAN;
G_DBMS_JOB_LIST TYP_DBMS_JOB_ARR;
G_DBMS_JOB_LIST_INIT BOOLEAN;
G_INDENT_LEVEL PLS_INTEGER;
G_OWNER VARCHAR2( 4000 );
G_USER VARCHAR2( 4000 );
G_GENERATE_SNAPSHOT_ID BOOLEAN;
GC_SPACE_PER_INDENT CONSTANT PLS_INTEGER := 2;
GC_XML_NAMESPACE CONSTANT VARCHAR2( 255 ) := '';
GC_JOB_PREFIX CONSTANT VARCHAR2( 30 ) := 'QUEST_LUCY_JOB';
GC_JOB_ACTION CONSTANT VARCHAR2( 4000 ) := 'BEGIN "' || GET_OWNER || '".quest_lucy_collector.take_snapshot; END;';
GC_REPEAT_MINUTES CONSTANT PLS_INTEGER := 60;
GC_SNAPSHOT_RETENTION_DAYS CONSTANT PLS_INTEGER := 14;
GC_REPEAT_INTERVAL CONSTANT VARCHAR2( 4000 ) := 'FREQ=MINUTELY;INTERVAL=' || TO_CHAR( GC_REPEAT_MINUTES );
GC_DBMS_JOB_INTERVAL CONSTANT VARCHAR2( 4000 ) := 'SYSDATE+(' || GC_REPEAT_MINUTES || ' / (24*60))';
GC_JOB_TYPE CONSTANT VARCHAR2( 16 ) := 'PLSQL_BLOCK';
FUNCTION GET_USER
RETURN VARCHAR2
IS
BEGIN
IF G_USER IS NULL THEN
EXECUTE IMMEDIATE 'SELECT SYS_CONTEXT (''USERENV'', ''SESSION_USER'') FROM dual'
INTO G_USER;
END IF;
RETURN G_USER;
END;
FUNCTION GET_OWNER
RETURN VARCHAR2
IS
L_CALL_STACK VARCHAR2( 4000 );
L_CALL_STACK_LINE VARCHAR2( 4000 );
L_ITERATOR NUMBER;
L_PACKAGE_NAME VARCHAR2( 4000 );
L_OWNER VARCHAR2( 4000 );
BEGIN
IF G_OWNER IS NULL THEN
BEGIN
EXECUTE IMMEDIATE 'BEGIN
:call_stack := DBMS_UTILITY.format_call_stack;
END;'
USING OUT L_CALL_STACK;
EXCEPTION
WHEN OTHERS THEN
L_CALL_STACK := NULL;
END;
IF L_CALL_STACK IS NOT NULL THEN
BEGIN
LOOP
L_ITERATOR := INSTR( L_CALL_STACK, CHR( 10 ) );
EXIT WHEN ( L_ITERATOR IS NULL OR L_ITERATOR = 0 OR L_OWNER IS NOT NULL );
L_CALL_STACK_LINE := SUBSTR( L_CALL_STACK, 1, L_ITERATOR - 1 );
L_CALL_STACK := SUBSTR( L_CALL_STACK, L_ITERATOR + 1 );
IF L_CALL_STACK_LINE LIKE '%package body%' THEN
燙燙燙燙?|???? L_PACKAGE_NAME := SUBSTR( L_CALL_STACK_LINE, INSTR( L_CALL_STACK_LINE, 'package body' ) + LENGTH( 'package body' ) + 1 );
L_OWNER := SUBSTR( L_PACKAGE_NAME, 1, LENGTH( L_PACKAGE_NAME ) - LENGTH( 'QUEST_LUCY_COLLECTOR' ) - 1 );
END IF;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
L_OWNER := NULL;
END;
END IF;
IF L_OWNER IS NULL THEN
L_OWNER := GET_USER;
END IF;
G_OWNER := L_OWNER;
END IF;
RETURN G_OWNER;
END;
PROCEDURE SAVE_EXCEPTION( I_ERROR_MESSAGE IN VARCHAR2 )
IS
L_ERROR TYP_ERROR;
L_ERROR_STACK VARCHAR2( 4000 );
L_ERROR_BACKTRACE VARCHAR2( 4000 );
L_CALL_STACK VARCHAR2( 4000 );
L_TEMP_ERROR_STACK VARCHAR2( 4000 );
BEGIN
L_TEMP_ERROR_STACK := SQLERRM;
BEGIN
EXECUTE IMMEDIATE 'BEGIN
:error_stack := DBMS_UTILITY.format_error_stack;
END;'
USING OUT L_ERROR_STACK;
EXCEPTION
WHEN OTHERS THEN
L_ERROR_STACK := L_TEMP_ERROR_STACK;
END;
BEGIN
EXECUTE IMMEDIATE 'BEGIN
:error_backtrace := DBMS_UTILITY.format_error_backtrace;
END;'
USING OUT L_ERROR_BACKTRACE;
EXCEPTION
WHEN OTHERS THEN
L_ERROR_BACKTRACE := NULL;
END;
BEGIN
EXECUTE IMMEDIATE 'BEGIN
:call_stack := DBMS_UTILITY.format_call_stack;
END;'
USING OUT L_CALL_STACK;
EXCEPTION
WHEN OTHERS THEN
L_CALL_STACK := NULL;
END;
L_ERROR.ERROR_TIME := SYSTIMESTAMP;
L_ERROR.ERROR_MESSAGE := I_ERROR_MESSAGE;
L_ERROR.ERROR_STACK := L_ERROR_STACK;
L_ERROR.ERROR_BACKTRACE := L_ERROR_BACKTRACE;
L_ERROR.CALL_STACK := L_CALL_STACK;
G_ERRORS( G_ERRORS.COUNT + 1 ) := L_ERROR;
G_TEMP_REFRESH_TIME := NULL;
END;
PROCEDURE REMOVE_DBMS_JOB( I_JOB IN NUMBER )
IS
BEGIN
IF GET_OWNER = GET_USER THEN
EXECUTE IMMEDIATE 'BEGIN
DBMS_JOB.remove (:job);
END;'
USING IN I_JOB;
ELSE
EXECUTE IMMEDIATE 'BEGIN
SYS.DBMS_IJOB.remove (:job);
END;'
USING IN I_JOB;
END IF;
END;
PROCEDURE REMOVE_SCHEDULER_JOB( I_JOB_NAME IN VARCHAR2 )
IS
L_JOB_NAME VARCHAR2( 4000 );
BEGIN
L_JOB_NAME := '"' || GET_OWNER || '".' || I_JOB_NAME;
BEGIN
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.drop_job (:job_name);
END;'
USING IN L_JOB_NAME;
EXCEPTION
WHEN OTHERS THEN
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.set_attribute_null (:job_name,
''REPEAT_INTERVAL'');
END;'
USING IN L_JOB_NAME;
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.set_attribute (:job_name,
''AUTO_DROP'',
true);
END;'
USING IN L_JOB_NAME;
END;
END;
FUNCTION GET_ORACLE_VERSION
RETURN NUMBER
IS
L_BANNER VARCHAR2( 80 );
L_VERSION_TEXT VARCHAR2( 80 );
L_FORMAT_MASK VARCHAR2( 80 );
L_VERSION_MAJOR VARCHAR2( 80 );
L_VERSION_MINOR VARCHAR2( 80 );
BEGIN
IF G_ORACLE_VERSION IS NULL THEN
EXECUTE IMMEDIATE 'SELECT banner
FROM v$version
WHERE banner LIKE ''Oracle%'' OR banner LIKE ''Personal Oracle%'''
INTO L_BANNER;
L_VERSION_TEXT := SUBSTR( SUBSTR( L_BANNER, INSTR( L_BANNER, 'Release ' ) + 8 ), 1, INSTR( SUBSTR( L_BANNER, INSTR(燙燙燙燙?|???? L_BANNER, 'Release ' ) + 8 ), ' ' ) - 1 );
L_VERSION_MAJOR := SUBSTR( L_VERSION_TEXT, 1, INSTR( L_VERSION_TEXT, '.', 1, 1 ) - 1 );
L_VERSION_MINOR := SUBSTR( L_VERSION_TEXT, INSTR( L_VERSION_TEXT, '.', 1, 1 ) + 1, INSTR( L_VERSION_TEXT, '.', 1, 2 ) - INSTR( L_VERSION_TEXT, '.', 1, 1 ) - 1 );
L_FORMAT_MASK := RPAD( '9', LENGTH( L_VERSION_MAJOR ), '9' ) || '.' || RPAD( '9', LENGTH( L_VERSION_MINOR ), '9' );
G_ORACLE_VERSION := TO_NUMBER( L_VERSION_MAJOR || '.' || L_VERSION_MINOR, L_FORMAT_MASK );
END IF;
RETURN G_ORACLE_VERSION;
END;
FUNCTION GET_CURRENT_INSTANCE
RETURN NUMBER
IS
BEGIN
IF G_CURRENT_INSTANCE IS NULL THEN
EXECUTE IMMEDIATE 'SELECT USERENV (''INSTANCE'') FROM DUAL'
INTO G_CURRENT_INSTANCE;
END IF;
RETURN G_CURRENT_INSTANCE;
END;
FUNCTION GET_INSTANCE_LIST
RETURN TYP_NUMBER_TABLE
IS
L_TEMP_INSTANCE_LIST TYP_NUMBER_TABLE;
BEGIN
IF G_INSTANCE_LIST.COUNT = 0 THEN
EXECUTE IMMEDIATE 'SELECT inst_number FROM v$active_instances'
INTO L_TEMP_INSTANCE_LIST;
IF L_TEMP_INSTANCE_LIST.COUNT = 0 THEN
L_TEMP_INSTANCE_LIST( 1 ) := GET_CURRENT_INSTANCE;
END IF;
FOR I IN 1..L_TEMP_INSTANCE_LIST.COUNT
LOOP
G_INSTANCE_LIST( L_TEMP_INSTANCE_LIST( I ) ) := L_TEMP_INSTANCE_LIST( I );
END LOOP;
END IF;
RETURN G_INSTANCE_LIST;
END;
FUNCTION GET_SCHEDULER_JOB_LIST
RETURN TYP_SCHEDULER_JOB_ARR
IS
TYPE L_TYP_TEMP_SCHEDULER_JOB_ARR IS TABLE OF TYP_SCHEDULER_JOB INDEX BY PLS_INTEGER;
L_TEMP_SCHEDULER_JOB_LIST L_TYP_TEMP_SCHEDULER_JOB_ARR;
L_OWNER VARCHAR2( 4000 ) := GET_OWNER;
BEGIN
IF NOT G_SCHEDULER_JOB_LIST_INIT THEN
G_SCHEDULER_JOB_LIST.DELETE;
EXECUTE IMMEDIATE 'SELECT job_name,
instance_id,
job_action,
job_type,
repeat_interval,
start_date,
enabled,
last_start_date
FROM all_scheduler_jobs
WHERE owner = :owner
AND job_name LIKE :job_prefix || ''_%'''
INTO L_TEMP_SCHEDULER_JOB_LIST
USING IN L_OWNER, IN GC_JOB_PREFIX;
FOR I IN 1..L_TEMP_SCHEDULER_JOB_LIST.COUNT
LOOP
G_SCHEDULER_JOB_LIST( L_TEMP_SCHEDULER_JOB_LIST( I ).JOB_NAME ) := L_TEMP_SCHEDULER_JOB_LIST( I );
END LOOP;
G_SCHEDULER_JOB_LIST_INIT := TRUE;
END IF;
RETURN G_SCHEDULER_JOB_LIST;
END;
FUNCTION GET_DBMS_JOB_LIST
RETURN TYP_DBMS_JOB_ARR
IS
L_TEMP_DBMS_JOB_LIST TYP_DBMS_JOB_ARR;
L_OWNER VARCHAR2( 4000 ) := GET_OWNER;
L_USER VARCHAR2( 4000 ) := GET_USER;
BEGIN
IF NOT G_DBMS_JOB_LIST_INIT THEN
G_DBMS_JOB_LIST.DELETE;
IF L_OWNER = L_USER THEN
EXECUTE IMMEDIATE 'SELECT job,
last_date,
next_date,
broken,
interval,
instance
FROM user_jobs
WHERE what = :job_action'
INTO L_TEMP_DBMS_JOB_LIST
USING IN GC_JOB_ACTION;
ELSE
EXECUTE IMMEDIATE 'SELECT job,
last_date,
next_date,
broken,
interval,
instance
FROM dba_jobs
WHERE priv_user = :priv_user AND what = :job_action'
INTO L_TEMP_DBMS_JOB_LIST
USING IN L_OWNER, IN GC_JOB_ACTION;
END IF;
FOR I IN 1..L_TEMP_DBMS_JOB_LIST.COUNT
LOOP
IF NOT G_DBMS_JOB_LIST.EXISTS( L_TEMP_DBMS_JOB_LIST( I ).INSTANCE ) THEN
燙燙燙燙?|???? G_DBMS_JOB_LIST( L_TEMP_DBMS_JOB_LIST( I ).INSTANCE ) := L_TEMP_DBMS_JOB_LIST( I );
ELSE
REMOVE_DBMS_JOB( L_TEMP_DBMS_JOB_LIST( I ).JOB );
END IF;
END LOOP;
G_DBMS_JOB_LIST_INIT := TRUE;
END IF;
RETURN G_DBMS_JOB_LIST;
END;
FUNCTION GET_OLDEST_SNAPSHOT_TIME
RETURN TIMESTAMP WITH TIME ZONE
IS
L_SNAPSHOT_TIME TIMESTAMP WITH TIME ZONE( 6 );
BEGIN
EXECUTE IMMEDIATE 'SELECT MIN (snapshot_time)
FROM quest_lucy_snapshot'
INTO L_SNAPSHOT_TIME;
RETURN L_SNAPSHOT_TIME;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not retrieve oldest snapshot time' );
RETURN NULL;
END;
PROCEDURE BEGIN_REFRESH_TIMER
IS
BEGIN
IF G_TEMP_REFRESH_TIME IS NULL THEN
G_TEMP_REFRESH_TIME := SYSTIMESTAMP;
ELSE
RAISE_APPLICATION_ERROR( -20000, 'g_temp_refresh_time was not null' );
END IF;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not begin refresh timer' );
END;
PROCEDURE END_REFRESH_TIMER( I_TIMER_NAME IN VARCHAR2 )
IS
L_INTERVAL INTERVAL DAY TO SECOND( 6 );
BEGIN
IF G_TEMP_REFRESH_TIME IS NOT NULL THEN
L_INTERVAL := SYSTIMESTAMP - G_TEMP_REFRESH_TIME;
G_REFRESH_TIMES( I_TIMER_NAME ) := ROUND( ( ( EXTRACT( DAY FROM ( L_INTERVAL ) ) * 24 * 60 * 60 ) + ( EXTRACT( HOUR FROM ( L_INTERVAL ) ) * 60 * 60 ) + ( EXTRACT( MINUTE FROM ( L_INTERVAL ) ) * 60 ) + ( EXTRACT( SECOND FROM ( L_INTERVAL ) ) ) ) * 1000000, 0 );
G_TEMP_REFRESH_TIME := NULL;
ELSE
RAISE_APPLICATION_ERROR( -20000, 'g_temp_refresh_time was null' );
END IF;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not end refresh timer' );
END;
PROCEDURE WRITE_XML( I_XML IN VARCHAR2 )
IS
L_XML VARCHAR2( 32767 );
BEGIN
L_XML := I_XML || CHR( 10 );
EXECUTE IMMEDIATE 'BEGIN
DBMS_LOB.writeappend ("' || GET_OWNER || '".quest_lucy_collector.g_snapshot_xml,
LENGTH (:l_xml),
:l_xml);
END;'
USING IN L_XML;
END;
FUNCTION GET_INDENT
RETURN VARCHAR2
IS
BEGIN
RETURN RPAD( ' ', G_INDENT_LEVEL * GC_SPACE_PER_INDENT, ' ' );
END;
PROCEDURE WRITE_XML_BEGIN_TAG( I_ELEMENT_NAME IN VARCHAR2, I_INCLUDE_REFRESH_TIME IN BOOLEAN := FALSE )
IS
L_ELEMENT VARCHAR2( 32767 );
L_REFRESH_TIME NUMBER;
BEGIN
L_ELEMENT := GET_INDENT || ' IF I_INCLUDE_REFRESH_TIME THEN
BEGIN
L_REFRESH_TIME := G_REFRESH_TIMES( I_ELEMENT_NAME );
EXCEPTION
WHEN NO_DATA_FOUND THEN
L_REFRESH_TIME := 0;
END;
L_ELEMENT := L_ELEMENT || ' RefreshTimeMicro="' || TO_CHAR( L_REFRESH_TIME, 'TM9', 'NLS_NUMERIC_CHARACTERS=''.,''' ) || '"';
END IF;
L_ELEMENT := L_ELEMENT || '>';
G_INDENT_LEVEL := G_INDENT_LEVEL + 1;
WRITE_XML( L_ELEMENT );
END;
PROCEDURE WRITE_XML_END_TAG( I_ELEMENT_NAME IN VARCHAR2 )
IS
L_ELEMENT VARCHAR2( 32767 );
BEGIN
G_INDENT_LEVEL := G_INDENT_LEVEL - 1;
L_ELEMENT := GET_INDENT || '' || I_ELEMENT_NAME || '>';
WRITE_XML( L_ELEMENT );
END;
PROCEDURE WRITE_XML_ELEMENT( I_ELEMENT_NAME IN VARCHAR2, I_ELEMENT_VALUE IN VARCHAR2 )
IS
L_ELEMENT VARCHAR2( 32767 );
L_ELEMENT_VALUE VARCHAR2( 32767 );
BEGIN
IF I_ELEMENT_NAME IS NOT NULL THEN
L_ELEMENT_VALUE := REPLACE( I_ELEMENT_VALUE, CHR( 38 ), CHR( 38 ) || 'amp;' );
L_ELEMENT_VALUE := REPLACE( L_ELEMENT_VALUE, ' L_ELEMENT := GET_INDENT || '';
L_ELEMENT := L_ELEMENT || L_ELEMENT_VALUE;
L_ELEMENT := L_ELEMENT || '' || I_ELEMENT_NAME || '>';
WRITE_XML( L_ELEMENT );燙燙燙燙?|????
END IF;
END;
PROCEDURE WRITE_XML_ELEMENT( I_ELEMENT_NAME IN VARCHAR2, I_ELEMENT_VALUE IN NUMBER )
IS
BEGIN
IF I_ELEMENT_VALUE IS NOT NULL THEN
WRITE_XML_ELEMENT( I_ELEMENT_NAME, TO_CHAR( I_ELEMENT_VALUE, 'TM9', 'NLS_NUMERIC_CHARACTERS=''.,''' ) );
END IF;
END;
PROCEDURE WRITE_XML_ELEMENT( I_ELEMENT_NAME IN VARCHAR2, I_ELEMENT_VALUE IN TIMESTAMP WITH TIME ZONE )
IS
BEGIN
WRITE_XML_ELEMENT( I_ELEMENT_NAME, TO_CHAR( I_ELEMENT_VALUE, 'YYYY-MM-DD"T"HH24:MI:SS.FFTZH:TZM' ) );
END;
PROCEDURE WRITE_XML_ELEMENT( I_ELEMENT_NAME IN VARCHAR2, I_ELEMENT_VALUE IN DATE )
IS
BEGIN
WRITE_XML_ELEMENT( I_ELEMENT_NAME, TO_CHAR( I_ELEMENT_VALUE, 'YYYY-MM-DD"T"HH24:MI:SS' ) );
END;
PROCEDURE WRITE_XML_STATS( I_STATS_NAME IN VARCHAR2, STATS IN TYP_STAT_ARR )
IS
BEGIN
IF STATS.COUNT > 0 OR G_REFRESH_TIMES.EXISTS( I_STATS_NAME ) THEN
WRITE_XML_BEGIN_TAG( I_STATS_NAME, TRUE );
FOR I IN 1..STATS.COUNT
LOOP
WRITE_XML_BEGIN_TAG( 'Stat' );
WRITE_XML_ELEMENT( 'StatName', STATS( I ).STAT_NAME );
WRITE_XML_ELEMENT( 'Value', STATS( I ).VALUE );
WRITE_XML_END_TAG( 'Stat' );
END LOOP;
WRITE_XML_END_TAG( I_STATS_NAME );
END IF;
END;
PROCEDURE WRITE_XML_ERRORS
IS
BEGIN
IF G_ERRORS.COUNT > 0 THEN
WRITE_XML_BEGIN_TAG( 'Errors' );
FOR I IN 1..G_ERRORS.COUNT
LOOP
WRITE_XML_BEGIN_TAG( 'Error' );
WRITE_XML_ELEMENT( 'ErrorTime', G_ERRORS( I ).ERROR_TIME );
WRITE_XML_ELEMENT( 'ErrorMessage', G_ERRORS( I ).ERROR_MESSAGE );
WRITE_XML_ELEMENT( 'ErrorStack', G_ERRORS( I ).ERROR_STACK );
WRITE_XML_ELEMENT( 'ErrorBacktrace', G_ERRORS( I ).ERROR_BACKTRACE );
WRITE_XML_ELEMENT( 'CallStack', G_ERRORS( I ).CALL_STACK );
WRITE_XML_END_TAG( 'Error' );
END LOOP;
WRITE_XML_END_TAG( 'Errors' );
G_ERRORS.DELETE;
END IF;
END;
PROCEDURE WRITE_XML_DATABASE
IS
BEGIN
IF G_SNAPSHOT.DATABASE.DBID IS NOT NULL THEN
WRITE_XML_BEGIN_TAG( 'DatabaseInformation', TRUE );
WRITE_XML_ELEMENT( 'Id', G_SNAPSHOT.DATABASE.DBID );
WRITE_XML_ELEMENT( 'UniqueName', G_SNAPSHOT.DATABASE.DB_UNIQUE_NAME );
WRITE_XML_ELEMENT( 'Name', G_SNAPSHOT.DATABASE.NAME );
WRITE_XML_ELEMENT( 'PlatformName', G_SNAPSHOT.DATABASE.PLATFORM_NAME );
WRITE_XML_ELEMENT( 'OpenMode', G_SNAPSHOT.DATABASE.OPEN_MODE );
WRITE_XML_END_TAG( 'DatabaseInformation' );
END IF;
END;
PROCEDURE WRITE_XML_INSTANCE
IS
BEGIN
IF G_SNAPSHOT.INSTANCE.INSTANCE_NUMBER IS NOT NULL THEN
WRITE_XML_BEGIN_TAG( 'InstanceInformation', TRUE );
WRITE_XML_ELEMENT( 'Id', G_SNAPSHOT.INSTANCE.INSTANCE_NUMBER );
WRITE_XML_ELEMENT( 'Name', G_SNAPSHOT.INSTANCE.INSTANCE_NAME );
WRITE_XML_ELEMENT( 'HostName', G_SNAPSHOT.INSTANCE.HOST_NAME );
WRITE_XML_ELEMENT( 'Version', G_SNAPSHOT.INSTANCE.VERSION );
WRITE_XML_ELEMENT( 'StartupTime', G_SNAPSHOT.INSTANCE.STARTUP_TIME );
WRITE_XML_ELEMENT( 'Status', G_SNAPSHOT.INSTANCE.STATUS );
WRITE_XML_ELEMENT( 'Thread', G_SNAPSHOT.INSTANCE.THREAD# );
WRITE_XML_ELEMENT( 'InstanceRole', G_SNAPSHOT.INSTANCE.INSTANCE_ROLE );
WRITE_XML_END_TAG( 'InstanceInformation' );
END IF;
END;
PROCEDURE WRITE_XML_ACTIVE_INSTANCE
IS
BEGIN
IF G_SNAPSHOT.ACTIVE_INSTANCE.COUNT > 0 OR G_REFRESH_TIMES.EXISTS( 'ActiveInstances' ) THEN
WRITE_XML_BEGIN_TAG( 'ActiveInstances', TRUE );
FOR I IN 1..G_SNAPSHOT.ACTIVE_INSTANCE.COUNT
LOOP
WRITE_XML_BEGIN_TAG( 'ActiveInstance' );
WRITE_XML_ELEMENT( 'Number', G_SNAPSHOT.ACTIVE_INSTANCE( I ).INST_NUMBER );
WRITE_XML_ELEMENT( 'Name', G_SNAPSHOT.ACTIVE_INSTANCE( I ).INST_NAME );
燙燙燙燙?|???? WRITE_XML_END_TAG( 'ActiveInstance' );
END LOOP;
WRITE_XML_END_TAG( 'ActiveInstances' );
END IF;
END;
PROCEDURE WRITE_XML_SYSTEM_EVENTS
IS
BEGIN
IF G_SNAPSHOT.SYSTEM_EVENT.COUNT > 0 OR G_REFRESH_TIMES.EXISTS( 'SystemEvents' ) THEN
WRITE_XML_BEGIN_TAG( 'SystemEvents', TRUE );
FOR I IN 1..G_SNAPSHOT.SYSTEM_EVENT.COUNT
LOOP
WRITE_XML_BEGIN_TAG( 'SystemEvent' );
WRITE_XML_ELEMENT( 'Name', G_SNAPSHOT.SYSTEM_EVENT( I ).EVENT_NAME );
WRITE_XML_ELEMENT( 'TotalWaits', G_SNAPSHOT.SYSTEM_EVENT( I ).TOTAL_WAITS );
WRITE_XML_ELEMENT( 'TotalTimeouts', G_SNAPSHOT.SYSTEM_EVENT( I ).TOTAL_TIMEOUTS );
WRITE_XML_ELEMENT( 'TimeWaited', G_SNAPSHOT.SYSTEM_EVENT( I ).TIME_WAITED_MICRO );
WRITE_XML_END_TAG( 'SystemEvent' );
END LOOP;
WRITE_XML_END_TAG( 'SystemEvents' );
END IF;
END;
PROCEDURE WRITE_XML_DYN_COMPONENTS
IS
BEGIN
IF G_SNAPSHOT.DYNAMIC_COMPONENT.COUNT > 0 OR G_REFRESH_TIMES.EXISTS( 'DynamicComponents' ) THEN
WRITE_XML_BEGIN_TAG( 'DynamicComponents', TRUE );
FOR I IN 1..G_SNAPSHOT.DYNAMIC_COMPONENT.COUNT
LOOP
WRITE_XML_BEGIN_TAG( 'DynamicComponent' );
WRITE_XML_ELEMENT( 'Name', G_SNAPSHOT.DYNAMIC_COMPONENT( I ).COMPONENT );
WRITE_XML_ELEMENT( 'CurrentSize', G_SNAPSHOT.DYNAMIC_COMPONENT( I ).CURRENT_SIZE );
WRITE_XML_END_TAG( 'DynamicComponent' );
END LOOP;
WRITE_XML_END_TAG( 'DynamicComponents' );
END IF;
END;
PROCEDURE WRITE_XML_IOSTAT_FILE
IS
BEGIN
IF G_SNAPSHOT.IOSTAT_FILE.COUNT > 0 OR G_REFRESH_TIMES.EXISTS( 'IostatFiles' ) THEN
WRITE_XML_BEGIN_TAG( 'IostatFiles', TRUE );
FOR I IN 1..G_SNAPSHOT.IOSTAT_FILE.COUNT
LOOP
WRITE_XML_BEGIN_TAG( 'IostatFile' );
WRITE_XML_ELEMENT( 'FiletypeName', G_SNAPSHOT.IOSTAT_FILE( I ).FILETYPE_NAME );
WRITE_XML_ELEMENT( 'FileName', G_SNAPSHOT.IOSTAT_FILE( I ).FILE_NAME );
WRITE_XML_ELEMENT( 'TablespaceName', G_SNAPSHOT.IOSTAT_FILE( I ).TABLESPACE_NAME );
WRITE_XML_ELEMENT( 'ReadMegabytes', G_SNAPSHOT.IOSTAT_FILE( I ).READ_MEGABYTES );
WRITE_XML_ELEMENT( 'WriteMegabytes', G_SNAPSHOT.IOSTAT_FILE( I ).WRITE_MEGABYTES );
WRITE_XML_ELEMENT( 'ReadReqs', G_SNAPSHOT.IOSTAT_FILE( I ).READ_REQS );
WRITE_XML_ELEMENT( 'WriteReqs', G_SNAPSHOT.IOSTAT_FILE( I ).WRITE_REQS );
WRITE_XML_ELEMENT( 'ReadServicetime', G_SNAPSHOT.IOSTAT_FILE( I ).READ_SERVICETIME );
WRITE_XML_ELEMENT( 'WriteServicetime', G_SNAPSHOT.IOSTAT_FILE( I ).WRITE_SERVICETIME );
WRITE_XML_ELEMENT( 'SmallReadReqs', G_SNAPSHOT.IOSTAT_FILE( I ).SMALL_READ_REQS );
WRITE_XML_ELEMENT( 'SmallReadServicetime', G_SNAPSHOT.IOSTAT_FILE( I ).SMALL_READ_SERVICETIME );
WRITE_XML_END_TAG( 'IostatFile' );
END LOOP;
WRITE_XML_END_TAG( 'IostatFiles' );
END IF;
END;
PROCEDURE WRITE_XML_MEMORY_ADVISORY
IS
BEGIN
IF G_SNAPSHOT.MEMORY_ADVISORY.COUNT > 0 OR G_REFRESH_TIMES.EXISTS( 'MemoryAdvisories' ) THEN
WRITE_XML_BEGIN_TAG( 'MemoryAdvisories', TRUE );
FOR I IN 1..G_SNAPSHOT.MEMORY_ADVISORY.COUNT
LOOP
WRITE_XML_BEGIN_TAG( 'MemoryAdvisory' );
WRITE_XML_ELEMENT( 'AdvisoryName', G_SNAPSHOT.MEMORY_ADVISORY( I ).ADVISORY_NAME );
WRITE_XML_ELEMENT( 'PoolName', G_SNAPSHOT.MEMORY_ADVISORY( I ).POOL_NAME );
WRITE_XML_ELEMENT( 'PoolBlockSize', G_SNAPSHOT.MEMORY_ADVISORY( I ).POOL_BLOCK_SIZE );
WRITE_XML_ELEMENT( 'MemorySizeFactor', G_SNAPSHOT.MEMORY_ADVISORY( I ).MEMORY_SIZE_FACTOR );
WRITE_XML_ELEMENT( 'MemorySize', G_SNAPSHOT.MEMORY_ADVISORY( I ).MEMORY_SIZE );
WRITE_XML_ELEMENT( 'EstdPhysicalReads', G_SNAPSHOT.MEMORY_ADVISORY( I ).ESTD_PHYSICAL_READS );
燙燙燙燙?|???? WRITE_XML_ELEMENT( 'EstdTime', G_SNAPSHOT.MEMORY_ADVISORY( I ).ESTD_TIME );
WRITE_XML_ELEMENT( 'EstdOverallocCount', G_SNAPSHOT.MEMORY_ADVISORY( I ).ESTD_OVERALLOC_COUNT );
WRITE_XML_END_TAG( 'MemoryAdvisory' );
END LOOP;
WRITE_XML_END_TAG( 'MemoryAdvisories' );
END IF;
END;
PROCEDURE WRITE_XML_PARAMETER
IS
BEGIN
IF G_SNAPSHOT.PARAMETER.COUNT > 0 OR G_REFRESH_TIMES.EXISTS( 'Parameters' ) THEN
WRITE_XML_BEGIN_TAG( 'Parameters', TRUE );
FOR I IN 1..G_SNAPSHOT.PARAMETER.COUNT
LOOP
WRITE_XML_BEGIN_TAG( 'Parameter' );
WRITE_XML_ELEMENT( 'Name', G_SNAPSHOT.PARAMETER( I ).NAME );
WRITE_XML_ELEMENT( 'Value', G_SNAPSHOT.PARAMETER( I ).VALUE );
WRITE_XML_ELEMENT( 'IsDefault', G_SNAPSHOT.PARAMETER( I ).ISDEFAULT );
WRITE_XML_END_TAG( 'Parameter' );
END LOOP;
WRITE_XML_END_TAG( 'Parameters' );
END IF;
END;
PROCEDURE WRITE_XML_ARCHIVE_DEST
IS
BEGIN
IF G_SNAPSHOT.ARCHIVE_DEST.COUNT > 0 OR G_REFRESH_TIMES.EXISTS( 'ArchiveDests' ) THEN
WRITE_XML_BEGIN_TAG( 'ArchiveDests', TRUE );
FOR I IN 1..G_SNAPSHOT.ARCHIVE_DEST.COUNT
LOOP
WRITE_XML_BEGIN_TAG( 'ArchiveDest' );
WRITE_XML_ELEMENT( 'Id', G_SNAPSHOT.ARCHIVE_DEST( I ).DEST_ID );
WRITE_XML_ELEMENT( 'Name', G_SNAPSHOT.ARCHIVE_DEST( I ).DEST_NAME );
WRITE_XML_ELEMENT( 'Status', G_SNAPSHOT.ARCHIVE_DEST( I ).STATUS );
WRITE_XML_ELEMENT( 'Binding', G_SNAPSHOT.ARCHIVE_DEST( I ).BINDING );
WRITE_XML_ELEMENT( 'Target', G_SNAPSHOT.ARCHIVE_DEST( I ).TARGET );
WRITE_XML_ELEMENT( 'Archiver', G_SNAPSHOT.ARCHIVE_DEST( I ).ARCHIVER );
WRITE_XML_ELEMENT( 'Schedule', G_SNAPSHOT.ARCHIVE_DEST( I ).SCHEDULE );
WRITE_XML_ELEMENT( 'Destination', G_SNAPSHOT.ARCHIVE_DEST( I ).DESTINATION );
WRITE_XML_ELEMENT( 'DelayMins', G_SNAPSHOT.ARCHIVE_DEST( I ).DELAY_MINS );
WRITE_XML_ELEMENT( 'Process', G_SNAPSHOT.ARCHIVE_DEST( I ).PROCESS );
WRITE_XML_ELEMENT( 'TransmitMode', G_SNAPSHOT.ARCHIVE_DEST( I ).TRANSMIT_MODE );
WRITE_XML_ELEMENT( 'DbUniqueName', G_SNAPSHOT.ARCHIVE_DEST( I ).DB_UNIQUE_NAME );
WRITE_XML_END_TAG( 'ArchiveDest' );
END LOOP;
WRITE_XML_END_TAG( 'ArchiveDests' );
END IF;
END;
PROCEDURE WRITE_XML_LOGFILE
IS
BEGIN
IF G_SNAPSHOT.LOGFILE.COUNT > 0 OR G_REFRESH_TIMES.EXISTS( 'Logfiles' ) THEN
WRITE_XML_BEGIN_TAG( 'Logfiles', TRUE );
FOR I IN 1..G_SNAPSHOT.LOGFILE.COUNT
LOOP
WRITE_XML_BEGIN_TAG( 'Logfile' );
WRITE_XML_ELEMENT( 'Group', G_SNAPSHOT.LOGFILE( I ).GROUP# );
WRITE_XML_ELEMENT( 'Thread', G_SNAPSHOT.LOGFILE( I ).THREAD# );
WRITE_XML_ELEMENT( 'Sequence', G_SNAPSHOT.LOGFILE( I ).SEQUENCE# );
WRITE_XML_ELEMENT( 'Bytes', G_SNAPSHOT.LOGFILE( I ).BYTES );
WRITE_XML_ELEMENT( 'Archived', G_SNAPSHOT.LOGFILE( I ).ARCHIVED );
WRITE_XML_ELEMENT( 'GroupStatus', G_SNAPSHOT.LOGFILE( I ).GROUP_STATUS );
WRITE_XML_ELEMENT( 'FirstChange', G_SNAPSHOT.LOGFILE( I ).FIRST_CHANGE# );
WRITE_XML_ELEMENT( 'FirstTime', G_SNAPSHOT.LOGFILE( I ).FIRST_TIME );
WRITE_XML_ELEMENT( 'MemberName', G_SNAPSHOT.LOGFILE( I ).MEMBER_NAME );
WRITE_XML_ELEMENT( 'MemberStatus', G_SNAPSHOT.LOGFILE( I ).MEMBER_STATUS );
WRITE_XML_END_TAG( 'Logfile' );
END LOOP;
WRITE_XML_END_TAG( 'Logfiles' );
END IF;
END;
PROCEDURE WRITE_SNAPSHOT_XML
IS
BEGIN
WRITE_XML_BEGIN_TAG( 'OracleSnapshot' );
WRITE_XML_ELEMENT( 'Id', G_SNAPSHOT.SNAPSHOT_ID );
WRITE_XML_ELEMENT( 'Time', G_SNAPSHOT.SNAPSHOT_TIME );
WRITE_XML_ELEMENT( 'PackageVersion', GC_PACKAGE_VERSION );
WRITE_XML_DATABASE;
WRITE_XML_INSTANCE;
燙燙燙燙?|???? WRITE_XML_ACTIVE_INSTANCE;
WRITE_XML_SYSTEM_EVENTS;
WRITE_XML_DYN_COMPONENTS;
WRITE_XML_IOSTAT_FILE;
WRITE_XML_MEMORY_ADVISORY;
WRITE_XML_PARAMETER;
WRITE_XML_STATS( 'OsStats', G_SNAPSHOT.OSSTAT );
WRITE_XML_STATS( 'PgaStats', G_SNAPSHOT.PGASTAT );
WRITE_XML_STATS( 'SysTimeModels', G_SNAPSHOT.SYS_TIME_MODEL );
WRITE_XML_STATS( 'SysStats', G_SNAPSHOT.SYSSTAT );
WRITE_XML_ARCHIVE_DEST;
WRITE_XML_LOGFILE;
WRITE_XML_ERRORS;
WRITE_XML_END_TAG( 'OracleSnapshot' );
END;
FUNCTION GET_NEXT_SNAPSHOT_ID
RETURN NUMBER
IS
L_SNAPSHOT_ID NUMBER;
BEGIN
EXECUTE IMMEDIATE 'LOCK TABLE "' || GET_OWNER || '".quest_lucy_snapshot IN EXCLUSIVE MODE';
EXECUTE IMMEDIATE 'SELECT NVL (MIN (snapshot_id), 0) - 1 FROM "' || GET_OWNER || '".quest_lucy_snapshot'
INTO L_SNAPSHOT_ID;
RETURN L_SNAPSHOT_ID;
END;
PROCEDURE CREATE_SEQUENCE
IS
BEGIN
EXECUTE IMMEDIATE 'CREATE SEQUENCE "' || GET_OWNER || '".QUEST_LUCY_SEQ_SNAPSHOT_ID
INCREMENT BY 1
START WITH 1
NOCACHE';
END;
FUNCTION GET_QUEST_LUCY_SEQ_SNAPSHOT_ID
RETURN NUMBER
IS
L_SNAPSHOT_ID NUMBER;
BEGIN
EXECUTE IMMEDIATE 'SELECT "' || GET_OWNER || '".quest_lucy_seq_snapshot_id.NEXTVAL FROM DUAL'
INTO L_SNAPSHOT_ID;
RETURN L_SNAPSHOT_ID;
END;
FUNCTION NEW_SNAPSHOT_ID
RETURN NUMBER
IS
L_SNAPSHOT_ID NUMBER;
BEGIN
IF G_GENERATE_SNAPSHOT_ID THEN
BEGIN
L_SNAPSHOT_ID := GET_QUEST_LUCY_SEQ_SNAPSHOT_ID;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get snapshot ID from sequence' );
BEGIN
CREATE_SEQUENCE;
L_SNAPSHOT_ID := GET_QUEST_LUCY_SEQ_SNAPSHOT_ID;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not create the sequence' );
BEGIN
L_SNAPSHOT_ID := GET_NEXT_SNAPSHOT_ID;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get snapshot ID from table' );
L_SNAPSHOT_ID := NULL;
END;
END;
END;
ELSE
L_SNAPSHOT_ID := NULL;
END IF;
RETURN L_SNAPSHOT_ID;
END;
FUNCTION GET_DATABASE_REC
RETURN TYP_DATABASE
IS
L_DATABASE TYP_DATABASE;
L_PLATFORM_COL VARCHAR2( 100 );
L_DB_UNIQUE_NAME_COL VARCHAR2( 100 );
BEGIN
BEGIN_REFRESH_TIMER;
IF GET_ORACLE_VERSION < 10 THEN
L_PLATFORM_COL := 'DBMS_UTILITY.port_string';
L_DB_UNIQUE_NAME_COL := 'name';
ELSE
L_PLATFORM_COL := 'platform_name';
L_DB_UNIQUE_NAME_COL := 'db_unique_name';
END IF;
EXECUTE IMMEDIATE 'SELECT dbid,
' || L_DB_UNIQUE_NAME_COL || ',
name,
' || L_PLATFORM_COL || ',
open_mode
FROM gv$database
WHERE inst_id = :inst_id'
INTO L_DATABASE
USING IN G_SNAPSHOT_INSTANCE;
END_REFRESH_TIMER( 'DatabaseInformation' );
RETURN L_DATABASE;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get DatabaseInformation' );
RETURN L_DATABASE;
END;
FUNCTION GET_INSTANCE_REC
RETURN TYP_INSTANCE
IS
L_INSTANCE TYP_INSTANCE;
BEGIN
BEGIN_REFRESH_TIMER;
EXECUTE IMMEDIATE 'SELECT instance_number,
instance_name,
host_name,
version,
startup_time,
status,
thread#,
instance_role
FROM gv$instance
WHERE inst_id = :inst_id'
INTO L_INSTANCE
燙燙燙燙?|???? USING IN G_SNAPSHOT_INSTANCE;
END_REFRESH_TIMER( 'InstanceInformation' );
RETURN L_INSTANCE;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get InstanceInformation' );
RETURN L_INSTANCE;
END;
FUNCTION GET_ACTIVE_INSTANCE_REC
RETURN TYP_ACTIVE_INSTANCE_ARR
IS
L_ACTIVE_INSTANCE TYP_ACTIVE_INSTANCE_ARR;
BEGIN
BEGIN_REFRESH_TIMER;
EXECUTE IMMEDIATE 'SELECT inst_number,
CASE
WHEN INSTR (inst_name, CHR (0)) = 0 THEN inst_name
ELSE SUBSTR (inst_name, 1, INSTR (inst_name, CHR (0)) - 1)
END
FROM v$active_instances'
INTO L_ACTIVE_INSTANCE;
END_REFRESH_TIMER( 'ActiveInstances' );
RETURN L_ACTIVE_INSTANCE;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get ActiveInstances' );
RETURN L_ACTIVE_INSTANCE;
END;
FUNCTION GET_SYSTEM_EVENT_REC
RETURN TYP_EVENT_ARR
IS
L_SYSTEM_EVENT TYP_EVENT_ARR;
BEGIN
BEGIN_REFRESH_TIMER;
EXECUTE IMMEDIATE 'SELECT event,
total_waits,
total_timeouts,
time_waited_micro / 1000
FROM gv$system_event
WHERE inst_id = :inst_id'
INTO L_SYSTEM_EVENT
USING IN G_SNAPSHOT_INSTANCE;
END_REFRESH_TIMER( 'SystemEvents' );
RETURN L_SYSTEM_EVENT;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get SystemEvents' );
RETURN L_SYSTEM_EVENT;
END;
FUNCTION GET_DYNAMIC_COMPONENT_REC
RETURN TYP_DYNAMIC_COMPONENT_ARR
IS
L_DYNAMIC_COMPONENT TYP_DYNAMIC_COMPONENT_ARR;
L_DYN_COMPONENT_TAB VARCHAR2( 100 );
BEGIN
BEGIN_REFRESH_TIMER;
IF GET_ORACLE_VERSION < 10 THEN
NULL;
ELSE
IF GET_ORACLE_VERSION < 11 THEN
L_DYN_COMPONENT_TAB := 'gv$sga_dynamic_components';
ELSE
L_DYN_COMPONENT_TAB := 'gv$memory_dynamic_components';
END IF;
EXECUTE IMMEDIATE 'SELECT component, current_size
FROM ' || L_DYN_COMPONENT_TAB || '
WHERE inst_id = :inst_id'
INTO L_DYNAMIC_COMPONENT
USING IN G_SNAPSHOT_INSTANCE;
END IF;
END_REFRESH_TIMER( 'DynamicComponents' );
RETURN L_DYNAMIC_COMPONENT;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get DynamicComponents' );
RETURN L_DYNAMIC_COMPONENT;
END;
FUNCTION GET_IOSTAT_FILE_REC
RETURN TYP_IOSTAT_FILE_ARR
IS
L_IOSTAT_FILE TYP_IOSTAT_FILE_ARR;
BEGIN
BEGIN_REFRESH_TIMER;
IF GET_ORACLE_VERSION < 11 THEN
EXECUTE IMMEDIATE 'SELECT ''Data File'' filetype_name,
df.file_name,
ts.tablespace_name,
( (fs.phyblkrd) * ts.block_size) / 1024 / 1024 read_megabytes,
( (fs.phyblkwrt) * ts.block_size) / 1024 / 1024 write_megabytes,
fs.phyrds read_reqs,
fs.phywrts write_reqs,
fs.readtim * 10 read_servicetime,
fs.writetim * 10 write_servicetime,
fs.singleblkrds small_read_reqs,
fs.singleblkrdtim * 10 small_read_servicetime
FROM gv$filestat fs, dba_data_files df, dba_tablespaces ts
WHERE fs.inst_id = :inst_id
AND fs.file# = df.file_id
AND ts.tablespace_name = df.tablespace_name
UNION ALL
SELECT ''Temp File'' filetype_name,
tf.file_name,
ts.tablespace_name,
( (fs.phyblkrd) * ts.block_size) / 1024 / 1024 read_megabytes,
( (fs.phyblkwrt) * ts.block_size) / 1024 / 1024 write_megabytes,
fs.phyrds read_reqs,
fs.phywrts write_reqs,
燙燙燙燙?|???? fs.readtim * 10 read_servicetime,
fs.writetim * 10 write_servicetime,
fs.singleblkrds small_read_reqs,
fs.singleblkrdtim * 10 small_read_servicetime
FROM gv$tempstat fs, dba_temp_files tf, dba_tablespaces ts
WHERE fs.inst_id = :inst_id
AND tf.file_id = fs.file#
AND ts.tablespace_name = tf.tablespace_name
UNION ALL
SELECT ''Control File'' filetype_name,
NULL file_name,
NULL tablespace_name,
NULL read_megabytes,
NULL write_megabytes,
SUM (total_waits) read_reqs,
NULL write_reqs,
ROUND (SUM (time_waited_micro) / 1000) read_servicetime,
NULL write_servicetime,
SUM (total_waits) small_read_reqs,
ROUND (SUM (time_waited_micro) / 1000) small_read_servicetime
FROM gv$system_event
WHERE inst_id = :inst_id
AND event IN
(''control file parallel write'', ''control file sequential read'')
UNION ALL
SELECT ''Log File'' filetype_name,
NULL file_name,
NULL tablespace_name,
NULL read_megabytes,
NULL write_megabytes,
SUM (total_waits) read_reqs,
NULL write_reqs,
ROUND (SUM (time_waited_micro) / 1000) read_servicetime,
NULL write_servicetime,
SUM (total_waits) small_read_reqs,
ROUND (SUM (time_waited_micro) / 1000) small_read_servicetime
FROM gv$system_event
WHERE inst_id = :inst_id
AND event IN
(''log file single write'',
''log file parallel write'',
''log file sequential read'')'
INTO L_IOSTAT_FILE
USING IN G_SNAPSHOT_INSTANCE, IN G_SNAPSHOT_INSTANCE, IN G_SNAPSHOT_INSTANCE, IN G_SNAPSHOT_INSTANCE;
ELSE
EXECUTE IMMEDIATE 'SELECT ios.filetype_name,
df.file_name,
df.tablespace_name,
ios.small_read_megabytes + ios.large_read_megabytes read_megabytes,
ios.small_write_megabytes + ios.large_write_megabytes write_megabytes,
ios.small_read_reqs + ios.large_read_reqs read_reqs,
ios.small_write_reqs + ios.large_write_reqs write_reqs,
ios.small_read_servicetime + ios.large_read_servicetime
read_servicetime,
ios.small_write_servicetime + ios.large_write_servicetime
write_servicetime,
ios.small_read_reqs,
ios.small_read_servicetime
FROM gv$iostat_file ios, dba_data_files df
WHERE ios.inst_id = :inst_id
AND ios.filetype_name = ''Data File''
AND df.file_id = ios.file_no
UNION ALL
SELECT ios.filetype_name,
tf.file_name,
tf.tablespace_name,
ios.small_read_megabytes + ios.large_read_megabytes read_megabytes,
ios.small_write_megabytes + ios.large_write_megabytes write_megabytes,
ios.small_read_reqs + ios.large_read_reqs read_reqs,
ios.small_write_reqs + ios.large_write_reqs write_reqs,
ios.small_read_servicetime + ios.large_read_servicetime
read_servicetime,
ios.small_write_servicetime + ios.large_write_servicetime
write_servicetime,
ios.small_read_reqs,
ios.small_read_servicetime
FROM gv$iostat燙燙燙燙?|????_file ios, dba_temp_files tf
WHERE ios.inst_id = :inst_id
AND ios.filetype_name = ''Temp File''
AND tf.file_id = ios.file_no
UNION ALL
SELECT ios.filetype_name,
NULL file_name,
NULL tablespace_name,
ios.small_read_megabytes + ios.large_read_megabytes read_megabytes,
ios.small_write_megabytes + ios.large_write_megabytes write_megabytes,
ios.small_read_reqs + ios.large_read_reqs read_reqs,
ios.small_write_reqs + ios.large_write_reqs write_reqs,
ios.small_read_servicetime + ios.large_read_servicetime
read_servicetime,
ios.small_write_servicetime + ios.large_write_servicetime
write_servicetime,
ios.small_read_reqs,
ios.small_read_servicetime
FROM gv$iostat_file ios
WHERE ios.inst_id = :inst_id
AND ios.filetype_name NOT IN (''Temp File'', ''Data File'')'
INTO L_IOSTAT_FILE
USING IN G_SNAPSHOT_INSTANCE, IN G_SNAPSHOT_INSTANCE, IN G_SNAPSHOT_INSTANCE;
END IF;
END_REFRESH_TIMER( 'IostatFiles' );
RETURN L_IOSTAT_FILE;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get IostatFiles' );
RETURN L_IOSTAT_FILE;
END;
FUNCTION GET_MEMORY_ADVISORY_REC
RETURN TYP_MEMORY_ADVISORY_ARR
IS
L_MEMORY_ADVISORY TYP_MEMORY_ADVISORY_ARR;
L_DBCACHE_ESTD_TIME_COL VARCHAR2( 100 );
L_PGA_ESTD_TIME_COL VARCHAR2( 100 );
BEGIN
BEGIN_REFRESH_TIMER;
IF GET_ORACLE_VERSION < 10 THEN
L_DBCACHE_ESTD_TIME_COL := 'NULL';
ELSE
L_DBCACHE_ESTD_TIME_COL := 'dbca.estd_physical_read_time';
END IF;
IF GET_ORACLE_VERSION < 11 THEN
L_PGA_ESTD_TIME_COL := 'NULL';
ELSE
L_PGA_ESTD_TIME_COL := 'pga.estd_time';
END IF;
EXECUTE IMMEDIATE 'SELECT ''DBCACHE'' advisory_name,
dbca.name pool_name,
dbca.block_size pool_block_size,
dbca.size_factor memory_size_factor,
dbca.size_for_estimate memory_size,
dbca.estd_physical_reads estd_physical_reads,
' || L_DBCACHE_ESTD_TIME_COL || ' estd_time,
NULL estd_overalloc_count
FROM gv$db_cache_advice dbca
WHERE dbca.inst_id = :inst_id
UNION ALL
SELECT ''PGA'',
'' '',
0,
pga.pga_target_factor,
pga.pga_target_for_estimate / 1024 / 1024,
pga.estd_extra_bytes_rw,
' || L_PGA_ESTD_TIME_COL || ' estd_time,
pga.estd_overalloc_count
FROM gv$pga_target_advice pga
WHERE pga.inst_id = :inst_id'
INTO L_MEMORY_ADVISORY
USING IN G_SNAPSHOT_INSTANCE, IN G_SNAPSHOT_INSTANCE;
END_REFRESH_TIMER( 'MemoryAdvisories' );
RETURN L_MEMORY_ADVISORY;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get MemoryAdvisories' );
RETURN L_MEMORY_ADVISORY;
END;
FUNCTION GET_PARAMETER_REC
RETURN TYP_PARAMETER_ARR
IS
L_PARAMETER TYP_PARAMETER_ARR;
BEGIN
BEGIN_REFRESH_TIMER;
EXECUTE IMMEDIATE 'SELECT name, VALUE, isdefault
FROM gv$system_parameter
WHERE inst_id = :inst_id'
INTO L_PARAMETER
USING IN G_SNAPSHOT_INSTANCE;
END_REFRESH_TIMER( 'Parameters' );
RETURN L_PARAMETER;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get Parameters' );
RETURN L_PARAMETER;
END;
FUNCTION GET_OSSTAT_REC
RETURN TYP_STAT_ARR
IS
L_OSSTAT TYP_STAT_ARR;
BEGIN
BEGIN_REFRESH_TI燙燙燙燙?|????MER;
IF GET_ORACLE_VERSION < 10 THEN
NULL;
ELSE
EXECUTE IMMEDIATE 'SELECT stat_name, VALUE
FROM gv$osstat
WHERE inst_id = :inst_id'
INTO L_OSSTAT
USING IN G_SNAPSHOT_INSTANCE;
END IF;
END_REFRESH_TIMER( 'OsStats' );
RETURN L_OSSTAT;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get OsStats' );
RETURN L_OSSTAT;
END;
FUNCTION GET_PGASTAT_REC
RETURN TYP_STAT_ARR
IS
L_PGASTAT TYP_STAT_ARR;
BEGIN
BEGIN_REFRESH_TIMER;
EXECUTE IMMEDIATE 'SELECT name, VALUE
FROM gv$pgastat
WHERE inst_id = :inst_id'
INTO L_PGASTAT
USING IN G_SNAPSHOT_INSTANCE;
END_REFRESH_TIMER( 'PgaStats' );
RETURN L_PGASTAT;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get PgaStats' );
RETURN L_PGASTAT;
END;
FUNCTION GET_SYS_TIME_MODEL_REC
RETURN TYP_STAT_ARR
IS
L_SYS_TIME_MODEL TYP_STAT_ARR;
BEGIN
BEGIN_REFRESH_TIMER;
IF GET_ORACLE_VERSION < 10 THEN
NULL;
ELSE
EXECUTE IMMEDIATE 'SELECT stat_name, VALUE / 1000 VALUE
FROM gv$sys_time_model
WHERE inst_id = :inst_id'
INTO L_SYS_TIME_MODEL
USING IN G_SNAPSHOT_INSTANCE;
END IF;
END_REFRESH_TIMER( 'SysTimeModels' );
RETURN L_SYS_TIME_MODEL;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get SysTimeModels' );
RETURN L_SYS_TIME_MODEL;
END;
FUNCTION GET_SYSSTAT_REC
RETURN TYP_STAT_ARR
IS
L_SYSSTAT TYP_STAT_ARR;
BEGIN
BEGIN_REFRESH_TIMER;
EXECUTE IMMEDIATE 'SELECT name, VALUE
FROM gv$sysstat
WHERE inst_id = :inst_id'
INTO L_SYSSTAT
USING IN G_SNAPSHOT_INSTANCE;
END_REFRESH_TIMER( 'SysStats' );
RETURN L_SYSSTAT;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get SysStats' );
RETURN L_SYSSTAT;
END;
FUNCTION GET_ARCHIVE_DEST_REC
RETURN TYP_ARCHIVE_DEST_ARR
IS
L_ARCHIVE_DEST TYP_ARCHIVE_DEST_ARR;
L_DB_UNIQUE_NAME_COL VARCHAR2( 100 );
BEGIN
BEGIN_REFRESH_TIMER;
IF GET_ORACLE_VERSION < 10 THEN
L_DB_UNIQUE_NAME_COL := 'NULL';
ELSE
L_DB_UNIQUE_NAME_COL := 'db_unique_name';
END IF;
EXECUTE IMMEDIATE 'SELECT dest_id,
dest_name,
status,
binding,
target,
archiver,
schedule,
destination,
delay_mins,
process,
transmit_mode,
' || L_DB_UNIQUE_NAME_COL || ' db_unique_name
FROM gv$archive_dest
WHERE inst_id = :inst_id AND status <> ''INACTIVE'''
INTO L_ARCHIVE_DEST
USING IN G_SNAPSHOT_INSTANCE;
END_REFRESH_TIMER( 'ArchiveDests' );
RETURN L_ARCHIVE_DEST;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get ArchiveDests' );
RETURN L_ARCHIVE_DEST;
END;
FUNCTION GET_LOGFILE_REC
RETURN TYP_LOGFILE_ARR
IS
L_LOGFILE TYP_LOGFILE_ARR;
BEGIN
BEGIN_REFRESH_TIMER;
EXECUTE IMMEDIATE 'SELECT l.group#,
l.thread#,
l.sequence#,
l.bytes,
l.archived,
l.status group_status,
l.first_change#,
l.first_time,
f.MEMBER member_name,
f.status member_status
FROM gv$log l, gv$logfile f
WHERE l.inst_id = :inst_id AND f.inst_id = :inst_id AND l.group# = f.group#'
INTO L_LOGFILE
USING IN G_SNAPSH燙燙燙燙?|????OT_INSTANCE, IN G_SNAPSHOT_INSTANCE;
END_REFRESH_TIMER( 'Logfiles' );
RETURN L_LOGFILE;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not get Logfiles' );
RETURN L_LOGFILE;
END;
PROCEDURE SAVE_SNAPSHOT
IS
BEGIN
WRITE_SNAPSHOT_XML;
EXECUTE IMMEDIATE 'INSERT INTO "' || GET_OWNER || '".quest_lucy_snapshot (snapshot_id, snapshot_time, snapshot_xml)
VALUES (:snapshot_id, :snapshot_time, :snapshot_xml)'
USING IN G_SNAPSHOT.SNAPSHOT_ID, IN G_SNAPSHOT.SNAPSHOT_TIME, IN G_SNAPSHOT_XML;
COMMIT;
END;
PROCEDURE POPULATE_SNAPSHOT( I_INST_ID IN NUMBER := NULL )
IS
BEGIN
G_SNAPSHOT_INSTANCE := NVL( I_INST_ID, GET_CURRENT_INSTANCE );
G_SNAPSHOT.SNAPSHOT_ID := NEW_SNAPSHOT_ID;
G_SNAPSHOT.SNAPSHOT_TIME := SYSTIMESTAMP;
G_SNAPSHOT.DATABASE := GET_DATABASE_REC;
G_SNAPSHOT.INSTANCE := GET_INSTANCE_REC;
G_SNAPSHOT.ACTIVE_INSTANCE := GET_ACTIVE_INSTANCE_REC;
G_SNAPSHOT.SYSTEM_EVENT := GET_SYSTEM_EVENT_REC;
G_SNAPSHOT.DYNAMIC_COMPONENT := GET_DYNAMIC_COMPONENT_REC;
G_SNAPSHOT.IOSTAT_FILE := GET_IOSTAT_FILE_REC;
G_SNAPSHOT.MEMORY_ADVISORY := GET_MEMORY_ADVISORY_REC;
G_SNAPSHOT.PARAMETER := GET_PARAMETER_REC;
G_SNAPSHOT.OSSTAT := GET_OSSTAT_REC;
G_SNAPSHOT.PGASTAT := GET_PGASTAT_REC;
G_SNAPSHOT.SYS_TIME_MODEL := GET_SYS_TIME_MODEL_REC;
G_SNAPSHOT.SYSSTAT := GET_SYSSTAT_REC;
G_SNAPSHOT.ARCHIVE_DEST := GET_ARCHIVE_DEST_REC;
G_SNAPSHOT.LOGFILE := GET_LOGFILE_REC;
END;
PROCEDURE RESET_VARS
IS
BEGIN
G_SNAPSHOT := NULL;
EXECUTE IMMEDIATE 'BEGIN
"' || GET_OWNER || '".quest_lucy_collector.g_snapshot_xml := empty_clob;
DBMS_LOB.createtemporary ("' || GET_OWNER || '".quest_lucy_collector.g_snapshot_xml, TRUE);
END;';
G_INDENT_LEVEL := 0;
G_REFRESH_TIMES.DELETE;
G_TEMP_REFRESH_TIME := NULL;
G_SCHEDULER_JOB_LIST.DELETE;
G_SCHEDULER_JOB_LIST_INIT := FALSE;
G_DBMS_JOB_LIST.DELETE;
G_DBMS_JOB_LIST_INIT := FALSE;
G_INSTANCE_LIST.DELETE;
G_CURRENT_INSTANCE := NULL;
G_SNAPSHOT_INSTANCE := NULL;
G_OWNER := NULL;
G_USER := NULL;
G_SNAPSHOT_ID_LIST.DELETE;
G_GENERATE_SNAPSHOT_ID := TRUE;
END;
PROCEDURE ENABLE_ROLES
IS
L_PASSWORD_ROLE_ARR TYP_VARCHAR2_TABLE;
L_PASSWORD_ROLE_LIST VARCHAR2( 4000 );
BEGIN
BEGIN
EXECUTE IMMEDIATE 'SELECT r.role
FROM user_role_privs urp, dba_roles r
WHERE r.role = urp.granted_role AND password_required = ''YES'''
INTO L_PASSWORD_ROLE_ARR;
FOR I IN 1..L_PASSWORD_ROLE_ARR.COUNT
LOOP
IF I > 1 THEN
L_PASSWORD_ROLE_LIST := L_PASSWORD_ROLE_LIST || ',';
END IF;
L_PASSWORD_ROLE_LIST := L_PASSWORD_ROLE_LIST || '"' || L_PASSWORD_ROLE_ARR( I ) || '"';
END LOOP;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not retrieve list of password protected roles.' );
L_PASSWORD_ROLE_LIST := NULL;
END;
BEGIN
IF L_PASSWORD_ROLE_LIST IS NOT NULL THEN
EXECUTE IMMEDIATE 'SET ROLE ALL EXCEPT ' || L_PASSWORD_ROLE_LIST;
ELSE
EXECUTE IMMEDIATE 'SET ROLE ALL';
END IF;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not enable roles.' );
END;
END;
PROCEDURE GET_SAVED_SNAPSHOTS
IS
BEGIN
EXECUTE IMMEDIATE 'DECLARE
TYPE ltyp_snapshot_rows IS TABLE OF "' || GET_OWNER || '".quest_lucy_snapshot%ROWTYPE
INDEX BY PLS_INTEGER;
l_snapshots ltyp_snapshot_rows;
BEGIN
SELECT *
BULK COLLECT INTO l_snapshots
FROM "' || GET_OWNER || '".quest_lucy_snapshot
FOR UPDATE;
燙燙燙燙?|???? FOR i IN 1 .. l_snapshots.COUNT
LOOP
DBMS_LOB.append ("' || GET_OWNER || '".quest_lucy_collector.g_snapshot_xml,
l_snapshots (i).snapshot_xml);
"' || GET_OWNER || '".quest_lucy_collector.g_snapshot_id_list (i) :=
l_snapshots (i).snapshot_id;
END LOOP;
END;';
END;
PROCEDURE DELETE_SNAPSHOTS
IS
BEGIN
FORALL I IN 1..G_SNAPSHOT_ID_LIST.COUNT
EXECUTE IMMEDIATE 'DELETE FROM "' || GET_OWNER || '".quest_lucy_snapshot
WHERE snapshot_id = :snapshot_id'
USING IN G_SNAPSHOT_ID_LIST( I );
END;
FUNCTION IS_TABLE_CREATED
RETURN BOOLEAN
IS
L_NUM_ROWS NUMBER;
L_OWNER VARCHAR2( 4000 ) := GET_OWNER;
BEGIN
EXECUTE IMMEDIATE 'SELECT COUNT (*)
FROM all_tables
WHERE owner = :owner
AND table_name = ''QUEST_LUCY_SNAPSHOT'''
INTO L_NUM_ROWS
USING IN L_OWNER;
IF L_NUM_ROWS > 0 THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
END;
PROCEDURE CREATE_TABLE
IS
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE "' || GET_OWNER || '".QUEST_LUCY_SNAPSHOT
(
SNAPSHOT_ID NUMBER (*, 0),
SNAPSHOT_TIME TIMESTAMP (6) WITH TIME ZONE NOT NULL,
SNAPSHOT_XML CLOB
)';
EXECUTE IMMEDIATE 'ALTER TABLE "' || GET_OWNER || '".QUEST_LUCY_SNAPSHOT ADD CONSTRAINT QUEST_LUCY_SNAPSHOT_PK PRIMARY KEY (SNAPSHOT_ID)';
END;
FUNCTION IS_SCHEDULER_JOB_OK( I_SCHEDULER_JOB IN TYP_SCHEDULER_JOB, I_INSTANCE IN NUMBER )
RETURN BOOLEAN
IS
BEGIN
IF I_SCHEDULER_JOB.INSTANCE_ID IS NULL OR I_SCHEDULER_JOB.INSTANCE_ID != I_INSTANCE THEN
RETURN FALSE;
END IF;
IF I_SCHEDULER_JOB.JOB_TYPE IS NULL OR I_SCHEDULER_JOB.JOB_ACTION IS NULL OR I_SCHEDULER_JOB.JOB_TYPE != GC_JOB_TYPE OR I_SCHEDULER_JOB.JOB_ACTION != GC_JOB_ACTION THEN
RETURN FALSE;
END IF;
IF I_SCHEDULER_JOB.REPEAT_INTERVAL IS NULL OR I_SCHEDULER_JOB.REPEAT_INTERVAL != GC_REPEAT_INTERVAL THEN
RETURN FALSE;
END IF;
IF I_SCHEDULER_JOB.START_DATE IS NULL OR I_SCHEDULER_JOB.START_DATE > SYSTIMESTAMP THEN
RETURN FALSE;
END IF;
RETURN TRUE;
END;
FUNCTION IS_DBMS_JOB_OK( I_DBMS_JOB IN TYP_DBMS_JOB )
RETURN BOOLEAN
IS
BEGIN
IF I_DBMS_JOB.INTERVAL IS NULL OR I_DBMS_JOB.INTERVAL != GC_DBMS_JOB_INTERVAL THEN
RETURN FALSE;
END IF;
RETURN TRUE;
END;
FUNCTION IS_ALL_SCHEDULER_JOBS_OK
RETURN BOOLEAN
IS
L_SCHEDULER_JOB_LIST TYP_SCHEDULER_JOB_ARR;
L_INSTANCE_LIST TYP_NUMBER_TABLE;
L_INSTANCE_ITERATOR PLS_INTEGER;
L_JOB_NAME VARCHAR2( 30 );
BEGIN
L_INSTANCE_LIST := GET_INSTANCE_LIST;
L_SCHEDULER_JOB_LIST := GET_SCHEDULER_JOB_LIST;
L_INSTANCE_ITERATOR := L_INSTANCE_LIST.FIRST;
WHILE L_INSTANCE_ITERATOR IS NOT NULL
LOOP
L_JOB_NAME := GC_JOB_PREFIX || '_' || L_INSTANCE_LIST( L_INSTANCE_ITERATOR );
IF NOT L_SCHEDULER_JOB_LIST.EXISTS( L_JOB_NAME ) THEN
RETURN FALSE;
END IF;
IF NOT IS_SCHEDULER_JOB_OK( L_SCHEDULER_JOB_LIST( L_JOB_NAME ), L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ) THEN
RETURN FALSE;
END IF;
IF L_SCHEDULER_JOB_LIST( L_JOB_NAME ).ENABLED IS NULL OR L_SCHEDULER_JOB_LIST( L_JOB_NAME ).ENABLED != 'TRUE' THEN
RETURN FALSE;
END IF;
IF L_SCHEDULER_JOB_LIST( L_JOB_NAME ).START_DATE < ( SYSTIMESTAMP - NUMTODSINTERVAL( GC_REPEAT_MINUTES * 2, 'MINUTE' ) ) AND ( L_SCHEDULER_JOB_LIST( L_JOB_NAME ).LAST_START_DATE IS NULL OR L_SCHEDULER_JOB_LIST( L_JOB_NAME ).LAST_START_DATE < ( SYSTIMESTAMP - NUMTODSINTERVAL( GC_REPEAT_MINUTES * 2, 'MINUTE' ) ) ) THEN
RETURN FALSE;
END IF;
L_INSTANCE_ITER燙燙燙燙?|????ATOR := L_INSTANCE_LIST.NEXT( L_INSTANCE_ITERATOR );
END LOOP;
RETURN TRUE;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not determine if scheduler jobs are OK' );
RETURN FALSE;
END;
FUNCTION IS_ALL_DBMS_JOBS_OK
RETURN BOOLEAN
IS
L_INSTANCE_LIST TYP_NUMBER_TABLE;
L_DBMS_JOB_LIST TYP_DBMS_JOB_ARR;
L_INSTANCE_ITERATOR PLS_INTEGER;
BEGIN
L_INSTANCE_LIST := GET_INSTANCE_LIST;
L_DBMS_JOB_LIST := GET_DBMS_JOB_LIST;
L_INSTANCE_ITERATOR := L_INSTANCE_LIST.FIRST;
WHILE L_INSTANCE_ITERATOR IS NOT NULL
LOOP
IF NOT L_DBMS_JOB_LIST.EXISTS( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ) THEN
RETURN FALSE;
END IF;
IF NOT IS_DBMS_JOB_OK( L_DBMS_JOB_LIST( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ) ) THEN
RETURN FALSE;
END IF;
IF L_DBMS_JOB_LIST( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ).BROKEN IS NULL OR L_DBMS_JOB_LIST( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ).BROKEN = 'Y' THEN
RETURN FALSE;
END IF;
IF L_DBMS_JOB_LIST( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ).LAST_DATE IS NULL OR L_DBMS_JOB_LIST( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ).LAST_DATE < ( SYSDATE - ( ( GC_REPEAT_MINUTES * 2 ) / ( 24 * 60 ) ) ) THEN
RETURN FALSE;
END IF;
L_INSTANCE_ITERATOR := L_INSTANCE_LIST.NEXT( L_INSTANCE_ITERATOR );
END LOOP;
RETURN TRUE;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not determine if dbms jobs are OK' );
RETURN FALSE;
END;
PROCEDURE SETUP_SCHEDULER_JOB
IS
L_JOB_NAME VARCHAR2( 30 );
L_FULL_JOB_NAME VARCHAR2( 100 );
L_SCHEDULER_JOB_LIST TYP_SCHEDULER_JOB_ARR;
L_INSTANCE_ITERATOR PLS_INTEGER;
L_INSTANCE_LIST TYP_NUMBER_TABLE;
BEGIN
L_INSTANCE_LIST := GET_INSTANCE_LIST;
L_SCHEDULER_JOB_LIST := GET_SCHEDULER_JOB_LIST;
L_INSTANCE_ITERATOR := L_INSTANCE_LIST.FIRST;
WHILE L_INSTANCE_ITERATOR IS NOT NULL
LOOP
L_JOB_NAME := GC_JOB_PREFIX || '_' || L_INSTANCE_LIST( L_INSTANCE_ITERATOR );
L_FULL_JOB_NAME := '"' || GET_OWNER || '".' || L_JOB_NAME;
IF L_SCHEDULER_JOB_LIST.EXISTS( L_JOB_NAME ) THEN
IF NOT IS_SCHEDULER_JOB_OK( L_SCHEDULER_JOB_LIST( L_JOB_NAME ), L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ) THEN
G_SCHEDULER_JOB_LIST_INIT := FALSE;
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.set_attribute (
:job_name,
''INSTANCE_ID'',
:instance);
END;'
USING IN L_FULL_JOB_NAME, IN L_INSTANCE_LIST( L_INSTANCE_ITERATOR );
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.set_attribute (:job_name,
''JOB_TYPE'',
:job_type);
END;'
USING IN L_FULL_JOB_NAME, IN GC_JOB_TYPE;
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.set_attribute (:job_name,
''JOB_ACTION'',
:job_action);
END;'
USING IN L_FULL_JOB_NAME, IN GC_JOB_ACTION;
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.set_attribute (:job_name,
''REPEAT_INTERVAL'',
:repeat_interval);
END;'
USING IN L_FULL_JOB_NAME, IN GC_REPEAT_INTERVAL;
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.set_attribute (:job_name,
''START_DATE'',
燙燙燙燙?|???? SYSTIMESTAMP);
END;'
USING IN L_FULL_JOB_NAME;
END IF;
ELSE
G_SCHEDULER_JOB_LIST_INIT := FALSE;
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.create_job (
job_name => :job_name,
job_type => :job_type,
job_action => :job_action,
start_date => SYSTIMESTAMP,
repeat_interval => :repeat_interval,
enabled => FALSE,
auto_drop => FALSE);
END;'
USING IN L_FULL_JOB_NAME, IN GC_JOB_TYPE, IN GC_JOB_ACTION, IN GC_REPEAT_INTERVAL;
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.set_attribute (
:job_name,
''INSTANCE_ID'',
:instance);
END;'
USING IN L_FULL_JOB_NAME, IN L_INSTANCE_LIST( L_INSTANCE_ITERATOR );
EXECUTE IMMEDIATE 'BEGIN
DBMS_SCHEDULER.enable (:job_name);
END;'
USING IN L_FULL_JOB_NAME;
END IF;
L_INSTANCE_ITERATOR := L_INSTANCE_LIST.NEXT( L_INSTANCE_ITERATOR );
END LOOP;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not create scheduler jobs' );
END;
PROCEDURE SETUP_DBMS_JOB
IS
L_JOB_NO NUMBER;
L_INSTANCE_LIST TYP_NUMBER_TABLE;
L_DBMS_JOB_LIST TYP_DBMS_JOB_ARR;
L_INSTANCE_ITERATOR PLS_INTEGER;
L_NLS_ENV VARCHAR2( 4000 );
L_OWNER VARCHAR2( 4000 ) := GET_OWNER;
L_USER VARCHAR2( 4000 ) := GET_USER;
BEGIN
L_INSTANCE_LIST := GET_INSTANCE_LIST;
L_DBMS_JOB_LIST := GET_DBMS_JOB_LIST;
L_INSTANCE_ITERATOR := L_INSTANCE_LIST.FIRST;
WHILE L_INSTANCE_ITERATOR IS NOT NULL
LOOP
IF NOT ( L_DBMS_JOB_LIST.EXISTS( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ) AND IS_DBMS_JOB_OK( L_DBMS_JOB_LIST( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ) ) ) THEN
IF L_DBMS_JOB_LIST.EXISTS( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ) THEN
REMOVE_DBMS_JOB( L_DBMS_JOB_LIST( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) ).JOB );
END IF;
EXECUTE IMMEDIATE 'BEGIN
DBMS_JOB.submit (
job => :job_no,
what => :job_action,
next_date => SYSDATE,
INTERVAL => :dbms_job_interval,
INSTANCE => :instance);
END;'
USING OUT L_JOB_NO, IN GC_JOB_ACTION, IN GC_DBMS_JOB_INTERVAL, IN L_INSTANCE_LIST( L_INSTANCE_ITERATOR );
IF L_OWNER != L_USER THEN
BEGIN
EXECUTE IMMEDIATE 'SELECT nls_env
FROM user_jobs
WHERE job = :job_no'
INTO L_NLS_ENV
USING IN L_JOB_NO;
EXECUTE IMMEDIATE 'BEGIN
SYS.DBMS_IJOB.change_env (job => :job_no,
luser => :luser,
puser => :puser,
cuser => :cuser,
nlsenv => :nlsenv);
END;'
USING IN L_JOB_NO, IN L_USER, IN L_OWNER, IN L_OWNER, IN L_NLS_ENV;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not change job user' );
REMOVE_DBMS_JOB( L_JOB_NO );
END;
END IF;
G_DBMS_JOB_LIST_INIT := FALSE;
END IF;
L_INSTANCE_ITERATOR := L_INSTANCE_LIST.NEXT( L_INSTAN燙燙燙燙?|????CE_ITERATOR );
END LOOP;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not create dbms jobs' );
END;
PROCEDURE REMOVE_ALL_DBMS_JOB
IS
L_DBMS_JOB_LIST TYP_DBMS_JOB_ARR;
L_DBMS_JOB_ITERATOR PLS_INTEGER;
BEGIN
L_DBMS_JOB_LIST := GET_DBMS_JOB_LIST;
L_DBMS_JOB_ITERATOR := L_DBMS_JOB_LIST.FIRST;
WHILE L_DBMS_JOB_ITERATOR IS NOT NULL
LOOP
REMOVE_DBMS_JOB( L_DBMS_JOB_LIST( L_DBMS_JOB_ITERATOR ).JOB );
L_DBMS_JOB_ITERATOR := L_DBMS_JOB_LIST.NEXT( L_DBMS_JOB_ITERATOR );
END LOOP;
END;
PROCEDURE REMOVE_ALL_SCHEDULER_JOB
IS
L_SCHEDULER_JOB_LIST TYP_SCHEDULER_JOB_ARR;
L_JOB_ITERATOR VARCHAR2( 30 );
BEGIN
L_SCHEDULER_JOB_LIST := GET_SCHEDULER_JOB_LIST;
L_JOB_ITERATOR := L_SCHEDULER_JOB_LIST.FIRST;
WHILE L_JOB_ITERATOR IS NOT NULL
LOOP
REMOVE_SCHEDULER_JOB( L_SCHEDULER_JOB_LIST( L_JOB_ITERATOR ).JOB_NAME );
L_JOB_ITERATOR := L_SCHEDULER_JOB_LIST.NEXT( L_JOB_ITERATOR );
END LOOP;
END;
PROCEDURE REMOVE_ALL_JOB
IS
BEGIN
IF GET_ORACLE_VERSION > 11 THEN
REMOVE_ALL_SCHEDULER_JOB;
END IF;
REMOVE_ALL_DBMS_JOB;
END;
PROCEDURE POPULATE_WRITE_ALL
IS
L_INSTANCE_LIST TYP_NUMBER_TABLE;
L_INSTANCE_ITERATOR PLS_INTEGER;
BEGIN
L_INSTANCE_LIST := GET_INSTANCE_LIST;
L_INSTANCE_ITERATOR := L_INSTANCE_LIST.FIRST;
WHILE L_INSTANCE_ITERATOR IS NOT NULL
LOOP
POPULATE_SNAPSHOT( L_INSTANCE_LIST( L_INSTANCE_ITERATOR ) );
WRITE_SNAPSHOT_XML;
L_INSTANCE_ITERATOR := L_INSTANCE_LIST.NEXT( L_INSTANCE_ITERATOR );
END LOOP;
END;
PROCEDURE TAKE_SNAPSHOT
IS
L_IS_TABLE_CREATED BOOLEAN := FALSE;
L_OLDEST_SNAPSHOT_TIME TIMESTAMP WITH TIME ZONE( 6 );
BEGIN
G_ERRORS.DELETE;
ENABLE_ROLES;
RESET_VARS;
G_INDENT_LEVEL := 2;
L_IS_TABLE_CREATED := IS_TABLE_CREATED;
IF NOT L_IS_TABLE_CREATED THEN
BEGIN
CREATE_TABLE;
L_IS_TABLE_CREATED := IS_TABLE_CREATED;
EXCEPTION
WHEN OTHERS THEN
REMOVE_ALL_JOB;
END;
END IF;
IF L_IS_TABLE_CREATED THEN
L_OLDEST_SNAPSHOT_TIME := GET_OLDEST_SNAPSHOT_TIME;
IF L_OLDEST_SNAPSHOT_TIME < ( SYSTIMESTAMP - NUMTODSINTERVAL( GC_SNAPSHOT_RETENTION_DAYS, 'DAY' ) ) THEN
REMOVE_ALL_JOB;
END IF;
POPULATE_SNAPSHOT;
SAVE_SNAPSHOT;
END IF;
RESET_VARS;
END;
FUNCTION GET_SNAPSHOTS( I_SCHEDULE_COLLECTOR IN NUMBER := 1 )
RETURN CLOB
IS
PRAGMA AUTONOMOUS_TRANSACTION;
L_USE_SAVED_SNAPSHOTS BOOLEAN := FALSE;
L_SNAPSHOT_ARR TYP_SNAPSHOT_ARR;
L_IS_TABLE_CREATED BOOLEAN := FALSE;
L_SCHEDULER_JOB_LIST TYP_SCHEDULER_JOB_ARR;
L_DBMS_JOB_LIST TYP_DBMS_JOB_ARR;
BEGIN
G_ERRORS.DELETE;
ENABLE_ROLES;
RESET_VARS;
WRITE_XML_BEGIN_TAG( 'OracleUpload xmlns="' || GC_XML_NAMESPACE || '"' );
WRITE_XML_BEGIN_TAG( 'OracleSnapshots' );
IF I_SCHEDULE_COLLECTOR = 1 THEN
L_IS_TABLE_CREATED := IS_TABLE_CREATED;
IF NOT L_IS_TABLE_CREATED THEN
BEGIN
CREATE_TABLE;
L_IS_TABLE_CREATED := IS_TABLE_CREATED;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not create table' );
END;
END IF;
IF L_IS_TABLE_CREATED THEN
IF GET_ORACLE_VERSION > 11 THEN
SETUP_SCHEDULER_JOB;
IF IS_ALL_SCHEDULER_JOBS_OK THEN
L_USE_SAVED_SNAPSHOTS := TRUE;
ELSE
SETUP_DBMS_JOB;
IF IS_ALL_DBMS_JOBS_OK THEN
L_USE_SAVED_SNAPSHOTS := TRUE;
END IF;
END IF;
BEGIN
L_SCHEDULER_JOB_LIST :=燙燙燙燙?|???? GET_SCHEDULER_JOB_LIST;
L_DBMS_JOB_LIST := GET_DBMS_JOB_LIST;
IF L_SCHEDULER_JOB_LIST.COUNT > 0 AND L_DBMS_JOB_LIST.COUNT > 0 AND IS_ALL_SCHEDULER_JOBS_OK THEN
REMOVE_ALL_DBMS_JOB;
END IF;
EXCEPTION
WHEN OTHERS THEN
SAVE_EXCEPTION( 'Could not check if there are dbms and scheduler jobs' );
END;
ELSE
SETUP_DBMS_JOB;
IF IS_ALL_DBMS_JOBS_OK THEN
L_USE_SAVED_SNAPSHOTS := TRUE;
END IF;
END IF;
GET_SAVED_SNAPSHOTS;
DELETE_SNAPSHOTS;
IF NOT L_USE_SAVED_SNAPSHOTS THEN
POPULATE_WRITE_ALL;
END IF;
ELSE
POPULATE_WRITE_ALL;
END IF;
ELSE
G_GENERATE_SNAPSHOT_ID := FALSE;
POPULATE_WRITE_ALL;
END IF;
WRITE_XML_END_TAG( 'OracleSnapshots' );
WRITE_XML_ERRORS;
WRITE_XML_END_TAG( 'OracleUpload' );
COMMIT;
RETURN G_SNAPSHOT_XML;
END;
PROCEDURE DROP_OBJECTS
IS
PRAGMA AUTONOMOUS_TRANSACTION;
TABLE_NOT_EXISTS EXCEPTION;
SEQUENCE_NOT_EXISTS EXCEPTION;
PRAGMA EXCEPTION_INIT( TABLE_NOT_EXISTS, -942 );
PRAGMA EXCEPTION_INIT( SEQUENCE_NOT_EXISTS, -2289 );
BEGIN
RESET_VARS;
REMOVE_ALL_JOB;
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE "' || GET_OWNER || '".QUEST_LUCY_SNAPSHOT';
EXCEPTION
WHEN TABLE_NOT_EXISTS THEN
NULL;
END;
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE "' || GET_OWNER || '".QUEST_LUCY_SEQ_SNAPSHOT_ID';
EXCEPTION
WHEN SEQUENCE_NOT_EXISTS THEN
NULL;
END;
COMMIT;
END;
END QUEST_LUCY_COLLECTOR;
/
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29876893/viewspace-1662922/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- C# 中居然也有切片語法糖,太厲害了C#
- 厲害了,word黑客捕手!黑客
- 太厲害了!解決了我對編譯的絕大部分問題!編譯
- 厲害了,JavaScript 新提案:array.groupBy()JavaScript
- 厲害了,ECMAScript 新提案:JSON模組JSON
- 微服務基礎——厲害了!API閘道器微服務API
- 厲害了我的哥!跑步界新銳:DTRun,TechGoGo
- 厲害了!用 Python 製作出來的地球儀!Python
- 厲害了,一個自動掃雷遊戲專案!遊戲
- 用 Span 對 C# 程式中三大記憶體區域進行統一訪問 ,太厲害了!C#記憶體
- 雷軍厲害了我的哥 小米松果處理器來了
- 厲害了,Servlet3的非同步處理機制Servlet非同步
- 厲害了!100多個API介面分享!熱門、常用的都有API
- 厲害了,一個更智慧的 JavaScript 對映器:array.flatMap()JavaScript
- 這個應用魔方厲害了,讓軟體開發者效率提升10倍
- 中國頂級程式設計師圖鑑,最後一個厲害了!程式設計師
- 厲害了量子計算機!瞧瞧它是如何“秒殺”其他計算機計算機
- 厲害了!這個工具幫助你生成朋友圈轉發截圖
- 高中生寫的Fuchsia OS系統編譯的文章,真是厲害了編譯
- 這屆AI程式設計師厲害了,還沒出校門就被預定?AI程式設計師
- 厲害了,Laravel-china 開通部落格了 快來圍觀下Laravel
- 厲害了!哈佛大學的研究讓機器人為心臟供血機器人
- 厲害了!5G 將在未來實現的五大進步!!!
- 厲害了,我用“深度學習”寫了個老闆探測器(附原始碼)深度學習原始碼
- 測試開發都這麼厲害了?為啥不直接轉業務開發?
- 厲害了!Adobe新出Firefly影片模型,2分鐘速成高畫質大片模型
- 厲害了!網際網路公司各崗位真實工作內容大起底!
- 厲害了,騰訊云云巢榮獲信通院“雲原生技術創新案例”獎!
- 厲害了!12秒將百萬資料透過EasyExcel匯入MySQL資料庫中ExcelMySql資料庫
- 厲害了!AWS 這個獎,助力中國與全球一起促進機器學習的科研落地!機器學習
- 神操作!一行程式碼搞定一款遊戲?厲害了程式設計師!行程遊戲程式設計師
- 三篇論文入選國際頂會SIGMOD,厲害了騰訊雲資料庫資料庫
- 【公告】PSRC 11月獎勵榜單 | Top1 月入4w+,厲害了!
- 飛在空中的倉庫再配合無人機送貨,沃爾瑪新專利厲害了無人機
- 厲害了我的+Winter可充電智慧鞋墊:能自動加熱手機操控
- 厲害了,2019-2020中國網際網路趨勢報告
- 厲害了,Lightroom Classic 2023新增ai智慧技術,輕鬆移除影像雜色!OOMAI
- 厲害了網頁掃碼,所有方法都給你總結到這了!趕緊收藏網頁