Thursday, June 02, 2005
CreateROUserLike.sql - Create read only user like
With this PL/SQL script I created, you can now create a read only version of a database user. This script will create the user with the extension "_RO" on the read/write user name. After it creates the user, it will grant EXECUTE on FUNCTION, PROCEDURE, PACKAGE and PACKAGE BODY object types and SELECT on others. Because a DATABASE LINK can't have a synonym or special grants, it recreates these in the read only user's schema.
Wednesday, May 18, 2005
Project idea: Open source performance tuning software
My idea has these features:
This project would be done in .NET with possible porting to MONO later on. This would mean that it would need to be limited in what it uses in the way of Microsoft based assemblies. This should be exciting plus free! Just gotta check with Oracle about the STATSPACK queries. But in thinking, this tool would rely on STATSPACK to be installed. So using the queries form the report shouldn't be a problem. Plus, being OSS there shouldn't be a licensing issue.
Next question, what should I use for a local data store? DB4O is an OSS non-relational database used by numerous companies, but will it work for this application? Are there other options similar to Access or DB4O?
- Use STATSPACK queries to gather and review statisitcs.
- Store results locally for quicker review.
- Realtime performance stats gathering.
- More to come...
This project would be done in .NET with possible porting to MONO later on. This would mean that it would need to be limited in what it uses in the way of Microsoft based assemblies. This should be exciting plus free! Just gotta check with Oracle about the STATSPACK queries. But in thinking, this tool would rely on STATSPACK to be installed. So using the queries form the report shouldn't be a problem. Plus, being OSS there shouldn't be a licensing issue.
Next question, what should I use for a local data store? DB4O is an OSS non-relational database used by numerous companies, but will it work for this application? Are there other options similar to Access or DB4O?
Wednesday, March 30, 2005
Oracle's Redo Log
An interesting article regarding Redo Logs:
Oracle's Redo Log
Oracle's Redo Log
The redo log makes it possible to replay SQL statements. Before Oracle changes data in a datafile it writes these changes to the redo log. If something happens to one of the datafiles, a backed up datafile can be restored and the redo, that was written since, replied, which brings the datafile to the state it had before it became unavailable. The same technique is also used in a data guard environment (standby databases): One database (the primary database) records all changes and sends them to the standby databases. These standby databases in turn apply (reply) the arrived redo which keeps the synchronized with the primary database.
Monday, February 14, 2005
Automated alert log archive
Here's a set of scripts (package, PL/SQL and Korn) that when set in place and activated with a Unix cron job, will archive the alert log in a gzipped file. (Note: formatting is messed up in Blogger. Notice that missing pipe characters are missing.)
First, put this in place as a package:
First, put this in place as a package:
CREATE OR REPLACE PACKAGE alert_log AS
PROCEDURE bdump_dir_setup;
PROCEDURE build_possible_alert_log_names;
PROCEDURE build_alertlog_name;
PROCEDURE check_alertlog_name;
PROCEDURE read(in_date_offset IN NUMBER);
PROCEDURE archive;
PROCEDURE remove(in_date_offset IN NUMBER, number_of_days IN NUMBER);
PROCEDURE list(in_date_offset IN NUMBER);
PROCEDURE INIT_ALERT_LOG;
END alert_log;
/
CREATE OR REPLACE PACKAGE BODY alert_log AS
bdump_dir VARCHAR2(500);
alertlist VARCHAR2(4000);
SID VARCHAR2(100);
comma VARCHAR2(1);
alertfile VARCHAR2(255);
itexists NUMBER;
fileat BFILE;
pointa INTEGER;
pointb INTEGER;
v_length INTEGER;
r_char10 RAW(4);
char10 VARCHAR2(1) := CHR(10);
startdate VARCHAR2(100);
r_startdate RAW(100);
buffer VARCHAR2(800);
buffer2 VARCHAR2(800);
vexists BOOLEAN;
vfile_length NUMBER;
vblocksize NUMBER;
date_offset NUMBER;
date_file VARCHAR2(255);
cursor_id INTEGER;
return_val INTEGER;
file_type UTL_FILE.FILE_TYPE;
sql_statement VARCHAR2(500);
PROCEDURE bdump_dir_setup IS
BEGIN
EXECUTE IMMEDIATE 'SELECT value '
' FROM v$parameter '
' WHERE name = ''background_dump_dest'''
INTO bdump_dir;
EXECUTE IMMEDIATE 'CREATE DIRECTORY BDUMP_DIR '
' AS '''
bdump_dir
'''';
END bdump_dir_setup;
PROCEDURE build_alertlog_name IS
BEGIN
alertlist := NULL;
comma := NULL;
EXECUTE IMMEDIATE 'SELECT value '
' FROM v$parameter '
' WHERE name = ''db_name'''
INTO SID;
build_possible_alert_log_names;
EXECUTE IMMEDIATE 'SELECT value '
' FROM v$parameter '
' WHERE name = ''instance_name'''
INTO SID;
build_possible_alert_log_names;
EXECUTE IMMEDIATE 'SELECT substr(global_name,1,'
' instr(global_name,''.'',-1)-1) '
' FROM global_name'
INTO SID;
build_possible_alert_log_names;
r_char10 := UTL_RAW.cast_to_raw(char10);
END build_alertlog_name;
PROCEDURE check_alertlog_name IS
BEGIN
pointa := 1;
LOOP
pointb := INSTR(alertlist, ',', pointa, 1);
v_length := pointb - pointa;
alertfile := SUBSTR(alertlist, pointa, v_length);
pointa := pointb + 1;
itexists :=
DBMS_LOB.fileexists(BFILENAME('BDUMP_DIR', alertfile));
IF itexists = 1 THEN
pointb := 0;
EXIT;
END IF;
END LOOP;
END check_alertlog_name;
PROCEDURE build_possible_alert_log_names IS
BEGIN
alertlist := alertlist comma 'alert_'
LOWER(SID) '.log';
comma := ',';
alertlist := alertlist comma UPPER(SID)
'ALRT.LOG';
END build_possible_alert_log_names;
PROCEDURE READ(in_date_offset IN NUMBER) IS
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
build_alertlog_name;
check_alertlog_name;
date_offset := in_date_offset;
IF date_offset = 0 THEN
date_file := alertfile;
ELSE
date_file :=
TO_CHAR(SYSDATE - date_offset, 'YYYYMMDD')
'_'
alertfile;
END IF;
UTL_FILE.fgetattr('BDUMP_DIR',
date_file,
vexists,
vfile_length,
vblocksize);
IF vexists THEN
fileat := BFILENAME('BDUMP_DIR', date_file);
DBMS_LOB.fileopen(fileat, DBMS_LOB.file_readonly);
startdate := TO_CHAR(TRUNC(SYSDATE), 'Dy Mon DD');
r_startdate := UTL_RAW.cast_to_raw(startdate);
pointa := DBMS_LOB.INSTR(fileat, r_startdate, 1, 1);
IF pointa = 0 THEN
EXECUTE IMMEDIATE 'SELECT TO_CHAR(TRUNC(SYSDATE),''Dy Mon '' '
' DECODE(SUBSTR(TO_CHAR(TRUNC(SYSDATE),''DD''),1,1),0,'' '')'
' SUBSTR(TO_CHAR(TRUNC(SYSDATE),''DD''),2,1)'
' FROM dual'
INTO startdate;
r_startdate := UTL_RAW.cast_to_raw(startdate);
pointa := DBMS_LOB.INSTR(fileat, r_startdate, 1, 1);
END IF;
IF pointa != 0 THEN
LOOP
pointb := DBMS_LOB.INSTR(fileat, r_char10, pointa, 1);
EXIT WHEN pointb = 0;
v_length := pointb - pointa;
buffer := DBMS_LOB.SUBSTR(fileat, v_length, pointa);
buffer2 := UTL_RAW.cast_to_varchar2(buffer);
DBMS_OUTPUT.put_line(buffer2);
pointa := pointb + 1;
END LOOP;
END IF;
DBMS_LOB.fileclose(fileat);
END IF;
END READ;
PROCEDURE ARCHIVE IS
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
build_alertlog_name;
check_alertlog_name;
UTL_FILE.frename('BDUMP_DIR',
alertfile,
'BDUMP_DIR',
TO_CHAR(SYSDATE, 'YYYYMMDD')
'_' alertfile);
SELECT directory_path
INTO bdump_dir
FROM all_directories
WHERE directory_name = 'BDUMP_DIR';
init_alert_log;
DBMS_OUTPUT.put_line('Archived to: '
' bdump_dir '/'
' TO_CHAR(SYSDATE, 'YYYYMMDD')
' '_' alertfile);
END ARCHIVE;
PROCEDURE remove(in_date_offset IN NUMBER,
number_of_days IN NUMBER) IS
BEGIN
build_alertlog_name;
check_alertlog_name;
FOR date_offset IN(in_date_offset - number_of_days)
.. in_date_offset LOOP
date_file :=
TO_CHAR(SYSDATE - date_offset, 'YYYYMMDD') '_'
alertfile;
UTL_FILE.fgetattr('BDUMP_DIR',
date_file,
vexists,
vfile_length,
vblocksize);
IF vexists THEN
UTL_FILE.fremove('BDUMP_DIR', date_file);
DBMS_OUTPUT.put_line(date_file ' - REMOVED');
END IF;
END LOOP;
END remove;
PROCEDURE LIST(in_date_offset IN NUMBER) IS
BEGIN
build_alertlog_name;
check_alertlog_name;
FOR date_offset IN 0 .. in_date_offset LOOP
IF date_offset = 0 THEN
date_file := alertfile;
UTL_FILE.fgetattr('BDUMP_DIR',
date_file,
vexists,
vfile_length,
vblocksize);
IF vexists THEN
DBMS_OUTPUT.put_line( 'OffSet : '
date_offset
', '
date_file
' '
vfile_length);
END IF;
END IF;
date_file :=
TO_CHAR(SYSDATE - date_offset, 'YYYYMMDD') '_'
alertfile;
UTL_FILE.fgetattr('BDUMP_DIR',
date_file,
vexists,
vfile_length,
vblocksize);
IF vexists THEN
DBMS_OUTPUT.put_line( 'OffSet : '
date_offset
', '
date_file
' '
vfile_length);
END IF;
END LOOP;
END LIST;
PROCEDURE INIT_ALERT_LOG IS
BEGIN
build_alertlog_name;
--check_alertlog_name;
-- ******************************************************
-- Open the alert log file for write access
-- ******************************************************
file_type := utl_file.fopen('BDUMP_DIR',alertfile,'W');
-- ******************************************************
-- Write the custom message to the alert log file
-- ******************************************************
utl_file.put_line(file_type,
'Alert log initialized by '
'HP_ALERT_LOG.INIT_ALERT_LOG on '
SYSDATE);
-- ******************************************************
-- Close the alert log file
-- ******************************************************
utl_file.fclose(file_type);
END INIT_ALERT_LOG;
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
END alert_log;
/
Now, save the following as a PL/SQL script:set serveroutput on;
exec alert_log.archive;
exit;
Finally, save this to a Korn shell script file executable by oracle Unix user only:#!/bin/ksh
USER=psgPASS=psg4admin
ORATAB=/etc/oratab
# Set path if path not set (if called from /etc/rc)
case $PATH in
"") PATH=/bin:/usr/bin:/etc
export PATH
;;
esac
SAVE_PATH=$PATH
# Save LD_LIBRARY_PATHSAVE_LLP=$LD_LIBRARY_PATH
## Loop for every entry in oratab file and and try to shut down# that ORACLE#
cat $ORATAB while read LINE
do
case $LINE in
\#*) ;; #comment-line in oratab
*)
# Proceed only if third field is 'Y'.
if [ "$(echo $LINE awk -F: '{print $3}' -)" = "Y" ] ; then
ORACLE_SID=$(echo $LINE awk -F: '{print $1}' -)
if [ "$ORACLE_SID" = '*' ] ; then
ORACLE_SID=""
fi
# Called programs use same database ID
export ORACLE_SID
ORACLE_HOME=$(echo $LINE awk -F: '{print $2}' -)
# Called scripts use same home directory
export ORACLE_HOME
# Put $ORACLE_HOME/bin into PATH and export.
PATH=$ORACLE_HOME/bin:/bin:/usr/bin:/etc:$SAVE_PATH
export PATH
# add for bug 652997
LD_LIBRARY_PATH=${SAVE_LLP}:${ORACLE_HOME}/lib
export LD_LIBRARY_PATH
PFILE=${ORACLE_HOME}/dbs/init${ORACLE_SID}.ora
BDUMP_DIR=$(sqlplus $USER/$PASS @runAlertLogRead grep Archive cut -f3 -d' ')
gzip $BDUMP_DIR
PATH=$SAVE_PATH
fi
;;
esac
done
As the final step, add the Korn shell script to a cron job. This can then be run at regular intervals.
Subscribe to:
Posts (Atom)