Note: Technical Talk being moved to:
www.nazimcricket.com/wiki


Wednesday, 31 December 2008

Excellent Find

I recently visited a large second-hand bookstore in Sydney. On my previous visit there, after hours of searching, I came across one cricket book which was signed by Mike Atherton. Hoping to repeat the experience, I walked in and wouldn't you know it, the first book I picked up turned out to be signed by Dennis Lillee and priced at a meagre $10.

Encouraged by my success, I went through a few more and within minutes found a real gem. A book signed by Garry Sobers, personalised to some guy but priced at only $15, it was an awesome find.

I did find one other book, signed by Kerry O'Keefe, but I decided to leave it as it was in average condition and on the other side of the signed page was a long and rather intimate note from the previous owner's girlfriend. Felt a bit creepy to buy something so personal.

Friday, 12 December 2008

Bradman Museum

Last week I had an opportunity to visit the Bradman Museum in Bowral.

The experience was not as fulfilling as I had hoped. The museum is quite small, as is the attached oval and the displays whilst nice are not particularly special. A number of items are quite commonly available modern pieces, which was especially disappointing.

To top things off, no photography is allowed in the museum, so what little there was to see could not be captured for future enjoyment.

Another issue to bear in mind is that if you happen to be travelling with family or friends who aren't interested in cricket, I'm afraid they will find little to captivate their attention in town, whilst you're in the museum.

To compare notes I'll need to revisit Bradman's birthplace in Cootamundra, but from memory, whilst the museum setup there is not as elegant as Bowral's, the pieces of memorabilia are certainly more fascinating.

Friday, 28 November 2008

PeopleSoft - Find Menu Path

PDF document containing a handy mod-pl/sql based stored procedure to find the PeopleSoft Menu Path, using a Page, Process or Component as the search criteria.
path.pdf

Friday, 21 November 2008

PeopleTools - Running Multiple Installs

Running multiple versions of PeopleTools from the same PC can sometimes be problematic. This is caused by the fact that each version's Configuration Manager writes to the exact same Registry Entry on the computer, namely "ConnectId" and "ConnectPswd".

For installs where the "people" credentials are the same across different PeopleTools installs, this of course is not a problem. The only thing is that the last Configuration Manager invoked has it's settings written to the Registry, which can be a little annoying.

To get around this, it's important to set the desired ConnectId and ConnectPswd prior to invoking PeopleTools. Obviously this would be tedious for users to do manually, as they would have to start up Configuration Manager and type in the correct credentials for the version of PeopleTools they wish to run. It would also, of course be a significant security risk if they knew the people password.

Therefore, I have created a batch file which I have placed in each PeopleTools version's bin directory. When invoked it calls the Configuration Manager, imports the configuration file containing the correct (encrypted) people credentials for that version, i.e. sets the Registry entries, and then invokes the Application Designer executable.

So instead of users double-clicking the Application Designer executable, I get them to run my batch file instead.

rem invoke Configuration Manager and Import Configuration Settings File
pscfg -import:c:\path\file.cfg -quiet

rem invoke Application Designer
pside

Thursday, 20 November 2008

Oracle OEM Mining

It can be quite useful to mine the tables stored in the Oracle Enterprise Manager repository.

To check the size of your databases in gigabytes, simply run:

select target_name
     , to_char (sum (file_size) / 1024 / 1024 / 1024, '999,999.99') sze
  from mgmt$db_datafiles_all
group by target_name
order by 2 desc;

Friday, 14 November 2008

Oracle - Toad vs OEM: Statistics

Something I've learnt (the hard way) is that statistics generation using Toad is inferior to Oracle Enterprise Manager. Main reason is that Toad tends to lean towards using the analyze command rather than the dbms_gather.statistics package. For my money, the following method seems to be the panacea of all table statistics issues:
dbms_stats.gather_table_stats( 
ownname=> 'OWNERNAME', 
tabname=> 'TABLENAME' , 
estimate_percent=> DBMS_STATS.AUTO_SAMPLE_SIZE, 
cascade=> TRUE);

Thursday, 6 November 2008

Oracle Table and Index Sizes

A useful query to check your large tables and indexes.

In this case, I'm checking those with a combined size of 1gb.

select y.table_name
     , x.tbl_size
     , y.idx_size
     , (tbl_size + idx_size) ttl_mb
  from (select segment_name
             , sum (bytes / 1024) / 1024 tbl_size
             , segment_type
          from dba_segments
         where segment_type in ('TABLE') 
           and owner = '{OWNER}'
        group by segment_name, segment_type) x
     , (select table_name
             , sum (bytes / 1024) / 1024 idx_size
             , segment_type
          from dba_segments a
             , dba_indexes b
         where a.segment_type in ('INDEX')
           and a.owner = '{OWNER}'
           and a.tablespace_name = b.tablespace_name
           and a.segment_name = b.index_name
          group by segment_type, table_name) y
 where x.segment_name = y.table_name 
   and (tbl_size + idx_size) > {1000}
order by tbl_size + idx_size desc;

Another method, applicable to auto segment space managed segments is to use the dbms_space package in lieu of going through dba_segments. In this case, however, I do use dba_segments as a join in order to get a count of the extents.

Unfortunately this method provided some inaccurate results in a locally managed environment.

set serveroutput on

DECLARE

su NUMBER;
sa NUMBER;
cp NUMBER;
v_kount NUMBER;
v_stmt VARCHAR2(1000);


cursor tbl_space is
select a.table_name
, a.tablespace_name
, a.owner
, sum(b.extents) num_extents
from dba_tables a
, dba_segments b
where a.table_name = b.segment_name
and a.owner = b.owner
and a.owner in ('{OWNER}')
group by a.table_name, a.tablespace_name, a.owner;

cursor idx_space is
select a.index_name
, a.tablespace_name
, a.owner
, sum(b.extents) num_extents
from dba_indexes a
, dba_segments b
where a.index_name = b.segment_name
and a.owner = b.owner
and a.owner in ('{OWNER}')
group by a.index_name, a.tablespace_name, a.owner;



BEGIN

dbms_output.enable(1000000);

dbms_output.put_line('DT_COLLECTED' || ',' || 'OWNER' || ',' || 'OBJECT_NAME' || ',' || 'OBJECT_TYPE' || ',' || 'OBJECT_TBSPC' || ',' || 'ALLOCATED_MB' || ',' || 'USED_MB' || ',' || 'PERCENT_USED' || ',' || 'NUM_EXTENTS' || ',' || 'ROW_COUNT');

for i in tbl_space loop

v_stmt := 'select count(*) from ' || i.owner || '.' || i.table_name;

execute immediate v_stmt into v_kount;

dbms_space.object_space_usage(i.owner, i.table_name, 'TABLE', NULL, su, sa, cp);

dbms_output.put_line(sysdate || ',' || i.owner || ',' || i.table_name|| ',' || 'TABLE'|| ',' || i.tablespace_name || ',' || TO_CHAR(sa/1024/1024,'999999.99')|| ',' || TO_CHAR(su/1024/1024,'999999.99')|| ',' || to_char((su / sa)*100,'99.99') || '%'|| ',' || i.num_extents|| ',' || v_kount);

end loop;

for i in idx_space loop

dbms_space.object_space_usage(i.owner, i.index_name, 'INDEX', NULL, su, sa, cp);

dbms_output.put_line(sysdate || ',' || i.owner || ',' || i.index_name || ',' || 'INDEX' || ',' || i.tablespace_name || ',' || TO_CHAR(sa/1024/1024,'999999.99') || ',' || TO_CHAR(su/1024/1024,'999999.99') || ',' || to_char((su / sa)*100,'99.99') || '%' || ',' || i.num_extents || ',' || 0);

end loop;

END;
/

Saturday, 1 November 2008

Random Image Generator

On my website I have been using a third party PHP random image generator which scrolls through my /images folder and displays a random image.

This has been working fine except that my images are stored in multiple folders and as a result I've been missing out on displaying quite a few of these. Also, I don't have any control in terms of turning the random image returned into a hyperlink to the page containing it etc.

To solve this problem, I decided I would use the power of SQL to return a random image, rather than use PHP.

Basically, I have a number of tables in my database, all of which contain a couple of common fields:

  • IMAGE - Stores the directory and name of the Image.
  • URL - Stores the URL of the page on which the image appears.

    I achieved what I was after in a couple of very simple steps:

    Created a View to bring all the IMAGE and URL information into one place:

    CREATE OR REPLACE VIEW IMAGE_VW (IMAGE, URL) AS 
    SELECT IMAGE, URL FROM TABLEA
    UNION
    SELECT IMAGE, URL FROM TABLEB;
    Implemented the following SQL and PHP code:
    <?php
    
    $queryx  = "SELECT IMAGE, URL FROM IMAGES_VW ORDER BY RAND() LIMIT 1";
    $resultx = mysql_query($queryx);
    
    while($row = mysql_fetch_row($resultx))
    {
        $IMAGE = $row[0];
        $URL = $row[1];
     
        echo "<a href=$URL><img src=$IMAGE></a>";
    
    }
    
    ?>
  • Sunday, 26 October 2008

    Geoff Lawson Sacking

    The sacking of Geoff Lawson by the Pakistan Cricket Board has left me fuming. When Lawson was selected over Dav Whatmore, I was amazed to say the least. He just didn't seem to be the right choice and nothing Lawson has done to-date has changed my opinion on that.

    However, the manner in which he has been sacked is reprehensible. First the new PCB Chairman Ijaz Butt announces in a press conference that Lawson is useless. He then goes on to say that whilst he isn't impressed by Lawson, he will support him for the remainder of his contract (August 2009) and then out of the blue he sacks the man.

    According to reports, Lawson met with Butt-head, agreed to a follow up meeting and then heard about his sacking from the media. When he attempted to contact the Chairman to clarify his position, he was stone-walled.

    In justification of their unprofessional behaviour, statements such as these have been made:

    "Lawson had not even attempted to meet the chairman even once since he took over,” said the official. “We felt it reflected poorly on his attitude that he didn’t want to meet the chairman and explain what he wanted and where he wanted the team to go.”

    When told that Lawson was upset that the chairman had not made any effort to meet him, the official asked simply: “Why should it be that way round? He is the chairman. The coach should seek him out.”

    This high and mighty Chairman had no problem "summoning" several people to his office, including the current captain, yet he did not have the common decency to extend the same courtesy to the coach? What a load of garbage.

    The Pakistan Cricket Board and it's new officials are an absolute disgrace and I for one fervently hope that Lawson is able to sue the pants off them (not that it would matter to these egotistical jerks).

    Phew .... I did say I was fuming, didn't I? :-)

    Saturday, 18 October 2008

    How Times Have Changed

    Cricket civilises people and creates good gentlemen. I want everyone to play cricket in Zimbabwe; I want ours to be a nation of gentlemen. Robert Mugabe

    Friday, 17 October 2008

    PeopleSoft Shutdown Process Scheduler

    Had a very specific task today, which I thought would be good to document for future reference. Others may also find some parts of it useful.

    Background:
    We have a PeopleSoft Reporting database (PeopleTools Version 8.43.16) which suffers constantly from rogue nvision and excel processes hanging around on the Windows process schedulers for days on end.

    The database is refreshed nightly from our Production environment and any reports running at the time of refresh need to be cleared out. Simply shutting down the Windows process scheduler is not always sufficient to address the issue, as Excel spreadsheets in particular may be left hanging around.

    The other side-effect is inspite the process scheduler being shutdown, some reports get left with a status of "Processing" on the process monitor. These can later on impede other jobs in the queue.

    3rd Party Utilities:
    Implemented my solution with the aid of the following utilities:

  • SCHEDULED TASK MANAGER from Microsoft.
  • SQLPLUS from Oracle.
  • PSADMIN from PeopleSoft.
  • PSKILL from SysInternals.
  • BAT2EXE Shareware.

    Implemented Solution - Summary:
    Created a batchfile which:

  • Executes a sqlplus script. This script parses the specified windows process scheduler server name and updates the process monitor tables, placing all reports which have a status of "Initiated" or "Processing" to a status of "Cancelled". Results of this are written to a logfile.
  • Invokes psadmin to shutdown the process scheduler.
  • Uses pskill to eliminate any Excel or Nvision processes.
  • Invokes psadmin to start up the process scheduler.
  • Invokes psadmin to verify the status of the process scheduler and writes this to a logfile.

    To Finish Off:

  • Converted the batchfile to an executable using BAT2EXE. This was done to mask the credentials used in the call to the sqlplus script.
  • Created a Scheduled Task to run the executable nightly with the windows process scheduler server name used as a variable. This allows me the flexibility of rolling the script out to various windows process scheduler servers.

    Implemented Solution - Syntax:
    The batchfile contains the following lines of code:

    sqlplus username/password@DATABASE @sqlscript.sql %1% > logfile.log
    psadmin -p stop -d DATABASE
    pskill EXCEL.exe
    pskill psnvs.exe
    psadmin -p start -d DATABASE
    psadmin -p status -d DATABASE > logfile2.log

    The sqlplus script contains the following lines of code:

    def server=&1
    update psprcsrqst set runstatus=8 where runstatus in (6,7) and servernamerun='&1';
    update psprcsque set runstatus=8 where runstatus in (6,7) and servernamerun='&&1';
    commit;
    exit;

    The scheduled task manager calls the executable as follows:

    {path}\executablename servername_variable
  • Thursday, 2 October 2008

    SQLPLUS Ignore Ampersands

    In SQLPLUS when an ampersand (&) is encountered, Oracle treats it as a value prompt. For example, if you try to execute the following statement: INSERT INTO DEPARTMENT (DEPARTMENT_NAME) VALUES ('Finance & Treasury'); SQLPLUS will return a prompt: Enter value for treasury: To have SQLPLUS ignore the ampersand, use the following command prior to executing your query:
    SET DEFINE OFF
    INSERT INTO DEPARTMENT (DEPARTMENT_NAME) VALUES ('Finance & Treasury');

    Wednesday, 1 October 2008

    Lookup SQL Error on Unix

    command is:
    oerr ORA 99999

    PeopleSoft Monitor Message

    These queries replicate the Monitor Message Page.

    Message Instance

    SELECT A.CHNLNAME AS "Channel Name"
         , SUM(C.APMSG_XTB_0) AS "Error"
         , SUM(C.APMSG_XTB_1) AS "New"
         , SUM(C.APMSG_XTB_2) AS "Started"
         , SUM(C.APMSG_XTB_3) AS "Working"
         , SUM(C.APMSG_XTB_4) AS "Done"
         , SUM(C.APMSG_XTB_5) AS "Retry"
         , SUM(C.APMSG_XTB_6) AS "Timeout"
         , SUM(C.APMSG_XTB_7) AS "Edited"
         , SUM(C.APMSG_XTB_8) AS "Canceled"
      FROM PSAPMSGPUBHDR A
         , PSAPMSGXTB C
    WHERE A.PUBSTATUS = C.APMSG_XTB_STAT
    GROUP BY A.CHNLNAME
    ORDER BY A.CHNLNAME;

    Publication Contract

    SELECT A.CHNLNAME AS "Channel Name"
         , SUM(C.APMSG_XTB_0) AS "Error"
         , SUM(C.APMSG_XTB_1) AS "New"
         , SUM(C.APMSG_XTB_2) AS "Started"
         , SUM(C.APMSG_XTB_3) AS "Working"
         , SUM(C.APMSG_XTB_4) AS "Done"
         , SUM(C.APMSG_XTB_5) AS "Retry"
         , SUM(C.APMSG_XTB_6) AS "Timeout"
         , SUM(C.APMSG_XTB_7) AS "Edited"
         , SUM(C.APMSG_XTB_8) AS "Cancelled"
      FROM PSAPMSGPUBCON A
         , PSAPMSGPUBHDR B
         , PSAPMSGXTB C
     WHERE A.PUBID = B.PUBID
       AND A.PUBNODE = B.PUBNODE
       AND A.CHNLNAME = B.CHNLNAME
       AND A.PUBCONSTATUS = C.APMSG_XTB_STAT
    GROUP BY A.CHNLNAME
    ORDER BY A.CHNLNAME;

    Subscription Contract

    SELECT A.CHNLNAME AS "Channel Name"
         , SUM(C.APMSG_XTB_0) AS "Error"
         , SUM(C.APMSG_XTB_1) AS "New"
         , SUM(C.APMSG_XTB_2) AS "Started"
         , SUM(C.APMSG_XTB_3) AS "Working"
         , SUM(C.APMSG_XTB_4) AS "Done"
         , SUM(C.APMSG_XTB_5) AS "Retry"
         , SUM(C.APMSG_XTB_6) AS "Timeout"
         , SUM(C.APMSG_XTB_7) AS "Edited"
         , SUM(C.APMSG_XTB_8) AS "Canceled"
      FROM PSAPMSGSUBCON A
         , PSAPMSGPUBHDR B
         , PSAPMSGXTB C
     WHERE A.PUBID = B.PUBID
       AND A.PUBNODE = B.PUBNODE
       AND A.CHNLNAME = B.CHNLNAME
       AND A.SUBCONSTATUS = C.APMSG_XTB_STAT
    GROUP BY A.CHNLNAME
    ORDER BY A.CHNLNAME;

    Note: You could use the field LASTUPDDTTM to filter by "Days"

    Saturday, 20 September 2008

    Windows Services

    Reference I find useful, as some servers at my workplace have hidden Control Panel options. To invoke Control Panel > Administrative Tools > Services, run:
    c:\windows\system32\services.msc

    Wednesday, 17 September 2008

    UNION [ALL], INTERSECT, MINUS Operators

    The UNION operator is useful when you want to draw information from two or more tables that all have the same structure.

    Take for example two tables AUSTRALIA_CRICKET containing a few players from the Australian Cricket Team and KOLKATA_CRICKET containing a few players from the IPL Kolkata Cricket Team.

    SQL> SELECT * FROM AUSTRALIA_CRICKET;
    
    FIRST_NAME           LAST_NAME
    -------------------- --------------------
    Ricky                Ponting
    Michael              Clarke
    Stuart               Clark
    Brad                 Haddin
    Brett                Lee
    
    5 rows selected.
    

    SQL> SELECT * FROM KOLKATA_CRICKET; FIRST_NAME LAST_NAME -------------------- -------------------- Sourav Ganguly Shoaib Akhtar Ricky Ponting Brendon McCullum Chris Gayle 5 rows selected.

    You can see from the results that Ricky Ponting is a player common to both tables.

    To return data from both these tables, you could write:

    SQL> SELECT * FROM AUSTRALIA_CRICKET
      2  UNION
      3  SELECT * FROM KOLKATA_CRICKET;
    
    FIRST_NAME                     LAST_NAME
    ------------------------------ -----------------------
    Brad                           Haddin
    Brendon                        McCullum
    Brett                          Lee
    Chris                          Gayle
    Michael                        Clarke
    Ricky                          Ponting
    Shoaib                         Akhtar
    Sourav                         Ganguly
    Stuart                         Clark
    
    9 rows selected.

    You'll note Ricky Ponting was returned only once using the UNION syntax.

    This is what happens if you change the UNION to UNION ALL:

    SQL> SELECT * FROM AUSTRALIA_CRICKET
      2  UNION ALL
      3  SELECT * FROM KOLKATA_CRICKET;
    
    FIRST_NAME           LAST_NAME
    -------------------- --------------------
    Ricky                Ponting
    Michael              Clarke
    Stuart               Clark
    Brad                 Haddin
    Brett                Lee
    Sourav               Ganguly
    Shoaib               Akhtar
    Ricky                Ponting
    Brendon              McCullum
    Chris                Gayle
    
    10 rows selected.
    This time Ricky Ponting appears twice. Once for each table.

    If you want only rows that appear in all tables, you would use the INTERSECT operation:

    SQL> SELECT * FROM AUSTRALIA_CRICKET
      2  INTERSECT
      3  SELECT * FROM KOLKATA_CRICKET;
    
    FIRST_NAME           LAST_NAME
    -------------------- --------------------
    Ricky                Ponting
    
    1 row selected.
    To round things off, if you wish to return data from the first table only, excluding data common between the two tables, you would use the MINUS operation:
    SQL> SELECT * FROM AUSTRALIA_CRICKET
      2  MINUS
      3  SELECT * FROM KOLKATA_CRICKET;
    
    FIRST_NAME           LAST_NAME
    -------------------- --------------------
    Brad                 Haddin
    Brett                Lee
    Michael              Clarke
    Stuart               Clark
    
    4 rows selected.
    Or ... in Reverse:
    SQL> SELECT * FROM KOLKATA_CRICKET
      2  MINUS
      3  SELECT * FROM AUSTRALIA_CRICKET;
    
    FIRST_NAME           LAST_NAME
    -------------------- --------------------
    Brendon              McCullum
    Chris                Gayle
    Shoaib               Akhtar
    Sourav               Ganguly
    
    4 rows selected.

    Tuesday, 16 September 2008

    PeopleSoft Scheduled Jobsets

    A useful query to lookup "Active" scheduled jobsets.

    select SCHEDULENAME
         , JOBNAMESRC
         , TO_CHAR(STARTDATETIME,'HH24:MI') TM
         , A.RECURNAME
         , RUNMONDAY
         , RUNTUESDAY
         , RUNWEDNESDAY
         , RUNTHURSDAY
         , RUNFRIDAY
         , RUNSATURDAY
         , RUNSUNDAY
      from ps_schdldefn a
         , psxlatitem b
         , ps_prcsrecur c
     where a.schedulestatus=b.fieldvalue
       and a.recurname = c.recurname
       and b.fieldname='SCHEDULESTATUS'
       and b.xlatshortname='Active'
    order by TM;
    The numeric values in the RUN{DAY} columns indicates what days of the week the jobs are scheduled to run.

    Tuesday, 9 September 2008

    Oracle Process Details

    A useful query to check database processes:

    select s.sid
         , p.pid
         , p.spid
         , s.process
         , s.status
         , s.username
         , s.osuser
         , s.program
         , a.name
         , s.client_info
         , s.module
         , to_char(s.logon_time,'yyyy-mm-dd hh24:mi:ss')
         , to_char(sysdate - (s.last_call_et /86400),'yyyy-mm-dd hh24:mi:ss')
      from v$session s
         , v$process p
         , audit_actions a
     where s.paddr = p.addr
       and s.command = a.action
     order by s.status;
    Field Key
  • Oracle Session ID
  • Oracle Process ID
  • OS Process ID
  • OS Client Process ID
  • Status of Session
  • Oracle Username
  • OS Username
  • OS Program Name
  • Command in Progress
  • Client Info from DBMS_APPLICATION_INFO.SET_CLIENT_INFO proc
  • Module Info from DBMS_APPLICATION_INFO.SET_MODULE proc
  • Time of Logon
  • Last Call
  • Monday, 8 September 2008

    Accessing TSM through java client on UNIX

    Thanks to a tip from my mate Ken W.

    Invoke TSM Java client on AIX 5.2:

  • Start up a x-terminal program such as x-win
  • Set the display using syntax export DISPLAY={ipaddress}:0.0
  • Set Java Path e.g. export PATH=$PATH:/{java directory path}
  • Start TSM dsmj
  • Friday, 22 August 2008

    Oracle Apex Installation

    Steps for Installation of Application Express using Oracle 10g Express Edition Database and Apex 3.1.1 on Windows XP - SP2.
    Pre-requisites ....


  • Download Oracle 10g Express Database for Windows (OracleXE.exe) from Oracle's website.




  • Download Oracle Application Express for Windows (apex_3.1.1.zip) from Oracle's website. Install the Database ....




  • Install the Oracle Database by double clicking on the OracleXE.exe.




  • Accept the License Agreement.




  • Define the Installation Directory. The default is c:\oraclexe




  • Set a System password. In my case I've used oracle as the password.




  • Review the summary information. The destination folder is c:\oraclexe, port for the database listener is 1521 and port for the http listener is 8080. Click to continue the installation process.




  • Click Finish at the end of the installation process. Configure a Database user for installation and administration of Apex. This user will require sysdba privileges ....




  • Go to the database Home Page All Programs > Oracle Database 10g Express Edition - Go to Database Homepage (Note: This is started up if the option is checked at the end of the database installation).




  • At the database login page enter Username as sys and password as set earlier oracle.




  • After successful login, select the Administration link, then select the Database Users link. Click on the Create button.




  • On the Create User page specify the username e.g. admin and password e.g. oracle. Confirm the password oracle.




  • The default tablespace is USERS and temporary tablespace will be TEMP. These need not be changed.




  • Specify the User Privilege Roles to be Connect, Resource, DBA.




  • Select the check all button for the directly granted system privileges section. Install Application Express ....




  • Extract the apex_3.1.1.zip file to a desired location for the Apex Software. In my case, I have chosen to keep it with the Database Home. Therefore my extract is to c:\oraclexe\. The extract will create a folder/directory called apex with a number of sub-directories under it.




  • Start a DOS session Start > Run > cmd and change directory to the Apex home (cd c:\oraclexe\apex).




  • Invoke sqlplus from the DOS prompt and login as the Database user created in the previous step i.e. sqlplus admin/oracle as sysdba .




  • This will take you to a sqlplus prompt SQL>. At the prompt, type in command SQL>SHOW PARAMETER SHARED_POOL_SIZE. Set the shared pool size to 100MB using the command SQL>ALTER SYSTEM SET SHARED_POOL_SIZE='100M' SCOPE=BOTH;.




  • Check if the value was set correctly by repeating the command SQL>SHOW PARAMETER SHARED_POOL_SIZE.




  • Commence installation of Apex by issuing the following command at the sqlprompt SQL>@apexins oracle USERS USERS TEMP /i/. This command runs a sql script called apexins.sql and passes in the parameters: Tablespace for the Apex application user (USERS), Tablespace for the Apex files user (USER), name of the Temporary Tablespace (TEMP) and virtual directory for the images folder (/i/).




  • The installation will take some time to complete and at the end of it you will be disconnected from the database.




  • Go to the Application Express homepage http://localhost:8080/apex/apex_admin and log in with username admin and password oracle. One Last Thing ....
    If after installation you cannot see any images on the page, you can reset the prefix /i/ by running sql c:\oraclexe\apex\utilities\reset_image_prefix.sql. In my case, I was unable to get the prefix to work correctly, so I ran the following command SQL>@reset_image_prefix at the prompt Enter the Application Express image prefix [/i/] I typed in my full path i.e. c:\oraclexe\apex\images/ (Note the path ends with "/" which is a requirement of apex). I then left all other prompts blank and the script ran successfully and images were viewable to me.




  • Footnote:  I'm told that you need to change the application images directory alias in the application properties too.

    Tuesday, 19 August 2008

    DOS - Append DateTime to Filename

    In DOS, you can append the date/time to a filename as follows:

    SET DAY=%DATE:~4,2%
    SET MTH=%DATE:~7,2%
    SET YR=%DATE:~10,4%
    SET HR=%TIME:~0,2%
    SET HR0=%TIME:~0,1%
    IF "%HR0%"==" " SET HR=0%TIME:~1,1%
    SET MIN=%TIME:~3,2%
    SET SEC=%TIME:~6,2%
    SET MYDATE=%YR%%MTH%%DAY%-%HR%%MIN%%SEC%
    The above construct sets the date and time formats and can be adjusted according to whatever format is desired

    The variable MYDATE can then be appended to the file as follows:

    C:\dir > filename_%MYDATE%
    Resulting in something like:
    filename_20080819-165818

    Oracle - Playing Around with Views

    Just mucking about with some SQL to see what tables are referenced in views:

    select name
      from dba_dependencies 
     where type='VIEW'
       and referenced_name in ('EMP','DEPT','BONUS');
    To narrow this down further to views which use all three tables, we could add:
    
    select name
      from (
    select name
      from dba_dependencies 
     where type='VIEW'
       and referenced_name in ('EMP','DEPT','BONUS')
               )
    having count(*) = 3 -- Same count as the number of tables
    group by name;
    To then check the actual SQL script for the views returned here, we could add:
    select view_name
         , text
      from dba_views
     where view_name in 
    ( 
    select name
      from (
    select name
      from dba_dependencies 
     where type='VIEW'
       and referenced_name in ('EMP','DEPT','BONUS')
               )
    having count(*) = 3
    group by name  
    )
    I am sure there are better ways of doing these, but there you have it, a simple SQL to get more information about views and the tables used by them.

    Sunday, 17 August 2008

    Oracle Create Table

    To create a table identical to another table, yet without any of the data, simply use the following syntax:
    CREATE {TABLENAMEA} AS (SELECT * FROM {TABLENAMEB} WHERE 1=2);

    Friday, 15 August 2008

    Oracle Append DateTime to spool file

    How to append the date/time to an output spool file in SQLPLUS:

    SQL>column dttm new_value v_dttm noprint;
    The above construct is used to select a value into a user variable

    SQL>select to_char(sysdate,'yyyymmddhh24miss') dttm from dual;
    Here we see the user variable data being passed in, i.e. the date and time format. Note I have not used spaces, colons etc in between my date and time strings as sometimes these can lead to SP-0332 Spooling Errors.

    SQL>spool filename_&v_dttm..log
    Note the two fullstops (..) are deliberate

    Tuesday, 12 August 2008

    Oracle Send Mail Procedure

    A useful way of sending email through Oracle.

    Parameters such as the SMTP host servername, SMTP port may be entered in as default values or be passed in for greater flexibility

    CREATE OR REPLACE PROCEDURE SEND_MAIL
    (  p_smtp_host in varchar2 default {'smtp_host'} 
     , p_smtp_port in number default {smtp_port}
     , p_sender in varchar2 default null
     , p_recipient in varchar2 default null
     , p_subject in varchar2 default null
     , p_message in varchar2 default null
    ) IS
    
    connection UTL_SMTP.CONNECTION;
    
    BEGIN
    
     connection := utl_smtp.open_connection( p_smtp_host, p_smtp_port );
    
      utl_smtp.helo( connection, p_smtp_host );
      utl_smtp.mail( connection, p_sender );
      utl_smtp.rcpt( connection, p_recipient );
      utl_smtp.data( connection, 'Subject: ' || p_subject  || utl_tcp.crlf ||       p_message );
      utl_smtp.quit( connection );
    
    EXCEPTION
    WHEN OTHERS THEN
     dbms_output.put_line(SQLERRM);
    
    END;
    /

    The procedure may be called using syntax as follows.
    Note: Parameters which are passed in with default values on the SEND_MAIL procedure, e.g. p_smtp_host and p_smtp_port may be excluded from this call
    .

    exec send_mail  ( p_smtp_host => 'smtp_host', -
                      p_smtp_port => smtp_port, -
                      p_sender    => 'sender@sender_address', -
                      p_recipient => 'recipient@recipient_address', -
                      p_subject   => 'Subject Line - Cricket Site', -
                      p_message   => 'Message Body - Check out www.nazimcricket.com' -
                    );

    Thursday, 7 August 2008

    Grenada Loves Warnie

    Mobile companies aren't the only ones who adore Shane Warne!

    First there was this homage (on stamps) for being one of Wisden's Cricketers of the Century.

    Now he's being revered on an entire stamp issue. Designed by artist Phillip Howe. These are, in my opinion, simply spectacular.

    I must obtain a copy for my collection soon.

    Here is a sample.

    PeopleSoft Processes by Department

    A query to see how many jobs are run per department through the process scheduler.
    select d.deptid
         , d.descr
         , count(*) kount
      from ps_job a
         , psopralias b
         , psprcsrqst c
         , ps_dept_tbl d
     where a.emplid = b.emplid
       and b.oprid = c.oprid
       and a.deptid = d.deptid
       and a.effdt = (select max(effdt)
                        from ps_job
                       where emplid = a.emplid)
       and d.effdt = (select max(effdt)
                        from ps_dept_tbl
                       where d.deptid = deptid)
    group by d.descr, d.deptid
    order by count(*) desc;

    Wednesday, 6 August 2008

    PeopleSoft Customisations/Migrations

    Here is one way of keeping tabs of customised projects and migrations across various PeopleSoft environments.

    I have used database links to simultaneously query multiple databases. In this case:

    DEV (Development) TST (Testing) UAT (User Acceptance Testing) PRD (Production) RPT (Reporting)

    The DEV environment is the benchmark as I have assumed this is where the project begins its life.

    The SQL queries the DEV environment first and compares to see if the project exists in the other environments. Where it does, it displays the LASTUPDDTTM and the LASTUPDOPRID, which I'm interpreting to be the migrator of the project. Where the project does not exist, I'm displaying the text "Not Migrated".

    In order to pick up customised projects only, I'm filtering out projects last updated by the PPLSOFT user, which signifies it as being Vanilla.

    One final detail is that I'm using Outer Joins to ensure I pick up all projects from DEV.

    SELECT A.PROJECTNAME
         , A.PROJECTDESCR
         , TO_CHAR(A.LASTUPDDTTM,'YYYY-MM-DD') || ' - ' || A.LASTUPDOPRID PSDEV
         , DECODE(B.PROJECTNAME,A.PROJECTNAME, TO_CHAR(B.LASTUPDDTTM,'YYYY-MM-DD') || ' - ' || B.LASTUPDOPRID,'Not Migrated') PSTST
         , DECODE(C.PROJECTNAME,A.PROJECTNAME, TO_CHAR(C.LASTUPDDTTM,'YYYY-MM-DD') || ' - ' || C.LASTUPDOPRID,'Not Migrated') PSUAT
         , DECODE(D.PROJECTNAME,A.PROJECTNAME, TO_CHAR(D.LASTUPDDTTM,'YYYY-MM-DD') || ' - ' || D.LASTUPDOPRID,'Not Migrated') PSPRD
         , DECODE(E.PROJECTNAME,A.PROJECTNAME, TO_CHAR(E.LASTUPDDTTM,'YYYY-MM-DD') || ' - ' || E.LASTUPDOPRID,'Not Migrated') PSRPT
         , A.DESCRLONG
         , TRUNC(A.LASTUPDDTTM) DEVUPDTM
         , TRUNC(B.LASTUPDDTTM) TSTUPDTM
         , TRUNC(C.LASTUPDDTTM) UATUPDTM
         , TRUNC(D.LASTUPDDTTM) PRDUPDTM
         , TRUNC(E.LASTUPDDTTM) RPTUPDTM
      FROM PSPROJECTDEFN@PSDEV A
         , PSPROJECTDEFN@PSTST B
         , PSPROJECTDEFN@PSUAT C
         , PSPROJECTDEFN@PSPRD D
         , PSPROJECTDEFN@PSRPT E
     WHERE A.PROJECTNAME = B.PROJECTNAME (+)
       AND A.PROJECTNAME = C.PROJECTNAME (+)
       AND A.PROJECTNAME = D.PROJECTNAME (+)
       AND A.PROJECTNAME = E.PROJECTNAME (+)
       AND A.LASTUPDOPRID <> 'PPLSOFT';
    Note: I have also included the LASTUPDDTTM separately in the select statement as they can be handy to perform some date calculations, example the number of jobs migrated to a certain environment between a date range. The same of course can be achieved by grabbing the LASTUPDDTTM from the decode statement, but it saves having to perform substrings and date conversions on that string.

    TIP: If you've run the query a few times and hit a limit on the number of database links open, you could always get around this by performing a Commit. There are Oracle documents available supporting the notion of using commits against Select statements across database links.

    Windows Memory Problems

    Been having tons of issues with my PC running into memory problems on a daily basis, attributed to the high number of applications I need to have open at any given time. Like most organisations, throwing more memory at the problem is not always feasible, so I've deployed a tip sent to me by Ken W.

    (Applies to Windows XP - SP2)

    Using regedit Change the key: HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\SubSystems

    %SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,3072,512 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=winsrv:ConServerDllInitialization,2 ProfileControl=Off MaxRequestThreads=16

    to

    %SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,16384,512 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=winsrv:ConServerDllInitialization,2 ProfileControl=Off MaxRequestThreads=16

    A quick reboot and we suddenly get a whole lot more out of our memory.

    Note: Use Registry Hacks at your own risk. The default settings are there for a reason, so don't blame it on some blogger who is willing to take a chance!

    Tuesday, 5 August 2008

    PeopleSoft Messaging Query

    A useful query to check which message nodes and associated "Active" Transactions exist.
    SELECT X.MSGNODENAME
         , Y.RQSTMSGNAME
         , Y.TRXTYPE
         , Y.EFFDT
         , Y.EFF_STATUS
      FROM PSMSGNODEDEFN X
         , (SELECT *
              FROM PSNODETRX A
             WHERE A.EFFDT = (SELECT MAX(A_ED.EFFDT) 
                                FROM PSNODETRX A_ED
                               WHERE A.RQSTMSGNAME = A_ED.RQSTMSGNAME
               AND A_ED.EFFDT <= SYSDATE)
               AND A.EFF_STATUS = 'A') Y
    WHERE X.MSGNODENAME = Y.MSGNODENAME(+)
    ORDER BY 1;

    Monday, 4 August 2008

    PeopleSoft TPESVCFAIL error

    The following error is sometimes seen at the login prompt:

    CHECK APPSERVER LOGS. THE SITE BOOTED WITH INTERNAL DEFAULT SETTINGS, BECAUSE OF: bea.jolt.ApplicationException: TPESVCFAIL - application level service failure.

    This basically means that there is a problem with the user account used to retrieve the web profile from the database. By default this account is set as PTWEBSERVER.

    To rectify this error check the PSOPRDEFN table (or the Security > User Profile section through the front end) to see if the PTWEBSERVER account is perhaps locked or has an incorrect password etc.

    Note: This user is configured in the webserver configuration.properties file, however passwords are usually encrypted differently between the file and the psoprdefn table, so no correlation may be found.

    Changing this can be as simple as:

  • Changing the configuration.properties file as follows:
    WebUserId=PTWEBSERVER WebPassword=PTWEBSERVER (this is okay to be in plain text.

  • Using datamover, run the following SQL:
    update psoprdefn set OPERPSWD = 'PTWEBSERVER', encrypted = 0 where oprid = 'PTWEBSERVER';
    encrypt_password PTWEBSERVER;
  • Saturday, 26 July 2008

    Oracle Apex Password Reset

    You can reset the Oracle Application Express internal Admin password via this Apex supplied SQL - apxxepwd.sql

    Wednesday, 23 July 2008

    Handy values for Oracle Date Functions

    1 / 24 one hour 1 / 1440 one minute 1 / 86400 one second

    One way to test the use of the above:

    SQL>ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS';
    SQL>SELECT SYSDATE FROM DUAL;
    SQL>SELECT SYSDATE+1/86400 FROM DUAL;
    SQL>SELECT SYSDATE+1/1440 FROM DUAL;
    SQL>SELECT SYSDATE+1/24 FROM DUAL;

    Wednesday, 16 July 2008

    Spending Money

    There are quite a few examples of legal tender printed with collectors in mind, for example a collection of "Proof" Coins honouring Sir Donald Bradman.

    It's rare though to find them being produced for general circulation. Some nice examples are the Bradman 20 cent coin from Australia and the 50 cent Jonty Rhodes coin from South Africa. Also a 10 pound note from the Bank of England showing a cricket scene from Dicken's Pickwick Papers is pretty cool.

    In my collection so far I have the following coins/medals Coins 'n More. Some I'm still trying to get hold of are World Cup commemoratives from Sri Lanka and India.

    Interesting Memorabilia

    Received a complimentary copy of a wonderful book, which I have advertised through my website. It contains the signature of every living New Zealand cricketer dating back to the 1930's as well as tons of illustrations, statistics etc etc in an attractive leather bound volume. Check out some scans of the signatures on my website Immortals and follow the links to the publisher if you wish to secure a copy for yourself.

    PeopleSoft Status Lookups

    Some useful queries joining the PSXLATITEM table to look up Process Monitor:

    Run Status:

    SELECT XLATSHORTNAME
         , FIELDVALUE
      FROM PSXLATITEM
     WHERE FIELDNAME='RUNSTATUS'
    ORDER BY TO_CHAR(FIELDVALUE,'00');
    Distribution Status:
    SELECT XLATSHORTNAME
         , FIELDVALUE
      FROM PSXLATITEM
     WHERE FIELDNAME='DISTSTATUS'
    ORDER BY TO_CHAR(FIELDVALUE,'00');
    Output Destination Type:
    SELECT XLATLONGNAME
         , FIELDVALUE
      FROM PSXLATITEM
     WHERE FIELDNAME='OUTDESTTYPE'
    ORDER BY TO_CHAR(FIELDVALUE,'00');
    Output Destination Format:
    SELECT XLATLONGNAME
         , FIELDVALUE
      FROM PSXLATITEM
     WHERE FIELDNAME='OUTDESTFORMAT'
    ORDER BY TO_CHAR(FIELDVALUE,'00');

    PeopleSoft BBL Rogues

    A tip from my friend David H.

    To check on a unix server if a suspect pid is registering on the PeopleSoft Bulletin Board, run the following command:

    tmadmin < bbi.in | grep {pid}

    If the pid is not known to the BBL, you can use the unix kill command to get rid of it, or through tmadmin utility run bbclean.

    Tuesday, 15 July 2008

    Checking for Overdue Jobs in PeopleSoft

    The following SQL is a little untidy as it's copied from a mod/plsql stored procedure I created to check for overdue jobs on the process scheduler. Being web-based, the orignal uses a Meta Refresh tag every 30 seconds to keep a proactive check on all Queued jobs in the next 60 minutes and alerts if any are overdue by more than a couple of minutes.
    SELECT CASE WHEN sdate > 0 THEN to_char(trunc(sysdate)+sdate,'hh24:MI:SS') 
                ELSE
                '--:--:--'
                END OVERDUE
         , PRCSINSTANCE
         , PRCSTYPE
         , PRCSNAME
         , SERVERNAMERQST
         , SERVERNAMERUN
         , OPRID
         , RUNDTTM
         , XLATSHORTNAME            
      FROM (
    SELECT SYSDATE -  A.RUNDTTM sdate 
         , A.PRCSINSTANCE
         , A.PRCSTYPE
         , A.PRCSNAME
         , A.SERVERNAMERQST
         , A.SERVERNAMERUN
         , A.OPRID
         , A.RUNDTTM
         , X.XLATSHORTNAME
      FROM PSPRCSRQST A
         , PSOPRDEFN B
         , PSPRCSPRFL C
         , PSXLATITEM X
     WHERE B.OPRID = A.OPRID
       AND B.PRCSPRFLCLS = C.CLASSID
       AND A.RUNSTATUS = X.FIELDVALUE
       AND A.RUNSTATUS = 5
       AND X.FIELDNAME = 'RUNSTATUS'
       AND A.RUNDTTM < SYSDATE + 60/1440
     order by A.RUNDTTM);

    Monday, 14 July 2008

    Oracle Database Cloning

    To make a clone of an Oracle database from a standby database, you would need to follow these high-level steps:

  • Open Standby Database in Read Only Mode.
  • Generate dynamic script to copy files: SQL> select 'scp ' || name || ' ' || replace (name,'{SOURCEDBNAME}','{TARGETDBNAME}') as filename from v$datafile;
  • Create a copy of the controlfile SQL>ALTER DATABASE BACKUP CONTROLFILE TO TRACE;
  • Modify the controlfile for later use. We generally make the following changes: orig: CREATE CONTROLFILE REUSE DATABASE {SOURCEDBNAME} NORESETLOGS FORCE LOGGING ARCHIVELOG; mods: CREATE CONTROLFILE SET DATABASE {TARGETDBNAME} RESETLOGS FORCE LOGGING NOARCHIVELOG; Also Search and Replace {SOURCEDBNAME} with {TARGETDBNAME}.
  • Shutdown the Source and Target Databases.
  • Execute the dynamic script to copy files.
  • Recreate the controlfile on the Target Database SQL> STARTUP NOMOUNT Execute the modified controlfile script.
  • Open the Target Database SQL> ALTER DATABASE OPEN RESETLOGS;
  • Rename the Target Database SQL> ALTER DATABASE RENAME GLOBAL_NAME TO {TARGETDBNAME};
  • Open the Standby Database in recover mode.
  • PeopleSoft Jobs Stuck in Posting Mode

    Every now and again the jobs run on the process scheduler will get stuck in "Posting" mode. Restarting the process scheduler or changing the status flag in psprcsrqst will usually do the trick, but sometimes this doesn't work either and PeopleSoft carries on trying to post the jobs.

    The secret is to check the PS_CDM_TRANSFER and PS_CDM_LIST tables. This is where the jobs for posting are handed over. The following query will reveal what is stuck.

    select b.prcsinstance
         , b.prcsname
         , b.prcstype
         , c.xlatshortname
         , a.transferinstance
         , a.servernamerun
         , a.transferstatus
         , a.nexttransferdttm
         , a.transferattemptcnt
      from ps_cdm_transfer a
         , ps_cdm_list b
         , psxlatitem c
     where a.transferinstance = b.transferinstance
       and b.diststatus = c.fieldvalue
       and c.fieldname='DISTSTATUS';
    From the above SQL we can try and narrow down to a particular process which may be having trouble posting, by checking the distribution agent log and the webserver log of the report repository.

    A sledgehammer approach could be to clear out the transfer table and place all processes with a distribution status of "Posting" to "Not Posted". This enables the option to Re-send Content the process via the Process Monitor. The SQLs to achieve this may look like:

    update psprcsrqst set diststatus=4 where diststatus=7;
    update psprcsque set diststatus=4 where diststatus=7;
    truncate table ps_cdm_transfer;
    
    The Re-send Content task can also be done via PL/SQL, but is not recommended as it allocates a single TRANSFERINSTANCE number to all of the stuck processes, which I don't think is an ideal situation. It may make further troubleshooting difficult and could possibly cause additional load on the distribution agent as it may submit the whole lot of the processes as one large job?? In any event, it's interesting to see the script you could use in conjunction with the above steps:
    declare
    
    cursor prcs is
    select prcsinstance
      from psprcsrqst
     where diststatus=4; -- Not Posted
    
    begin
    
     for i in prcs loop
    
     update psprcsrqst set diststatus=7 where prcsinstance=i.prcsinstance;
    
     update psprcsque set diststatus=7 where prcsinstance=i.prcsinstance;
    
     update ps_cdm_list set diststatus=8, transferinstance=0 where  prcsinstance=i.prcsinstance;
    
     commit;
    
     end loop;
    
    end;
    /
    
    Another basic place to check is the Distribution tab under the Servers Definition page. Often the transfer method e.g. HTTP is overlooked there and this could cause the distribution to fail even if the Report Node is configured correctly.

    Saturday, 12 July 2008

    Troubleshoot PeopleSoft Integration Broker

    I've always been daunted by the process of troubleshooting EIP messaging failures. In particular messages from EXTernal sources. Not sure why, but the integration error logs don't seem to provide enough information and I always end up spending hours trying to figure out what's going wrong.

    Well, I think I've simply been over-thinking the process and hence have over-complicated the task too much. The last couple of occasions I was able to fix things quite nicely and did so by following some very simple steps:

    Step 1. Check the integrationGateway.properties file which lives on the webserver. Use Beyond Compare or some other such program to compare differences with an environment which is working. Make sure all entries are correct, especially the various gateways are set correctly.

    If any changes are made, load the integrationGateway.properties file up through the PeopleSoft gateway page. Make sure to click "Apply" to Refresh this file.

    Step 2. Check the gateway URL on the PeopleSoft gateways page.

    Step 3. Check the PSMSGNODEDEFN table entries. Pay particular attention to the IBPASSWORD values to ensure they are correct. This can be tricky as they are encrypted, but have to make sure the password here is identical to the password on the external system.

    Step 4. Perform ping tests via the Monitor Message pages.

    These four simple steps seem to address majority of all issues.

    Oracle Autonomous Transactions

    Working as a Database Administrator, I always discover new things and seeing as this blog has been a waste of space so far, I figure I may as well start using it to jot down notes from work. At least I'll end up with a good knowledge repository of things I would like to store away for future reference.

    The task at hand was to create a web-based stored procedure which would enable people from our Security team to add database users themselves, rather than forward on calls to the ever-busy DBAs.

    So I started out by creating a mod/plsql stored procedure on an admin database, which would use database links to connect to the target database where the account needs to be created.

    Problem Encountered:
    Oracle does not allow DDL commands to run across a dblink.

    Solution
    Use the dblink to execute another stored procedure on the target, which would run the DDL commands.

    Pretty straight forward at this point. Then comes the kicker ...

    I needed to add an OUT parameter to the target procedure, so I could pass a message back to the calling source procedure advising the success/failure of the procedure at the target.

    Problem Encountered:
    Oracle Bug: where a combination of dblink, OUT parameter and DDLs are NOT allowed. According to MetaLink this would be rectified in version 11, but was hardly of any use to me at this point.

    Solution:
    Autonomous Transactions. Stumbled upon the use of Autonomous Transactions, which as I understand them, allow procedures to execute autonomously from the calling procedure. By running something like:

    execute immediate 'DECLARE PRAGMA AUTONOMOUS TRANSACTION BEGIN END;';

    I was able to have my cake and eat it too!

    I Luv Cricket ..... but .....

    I can never think of anything to talk about on the subject. The idea of this blog was to share heaps of knowledge and entertain visitors with trivia, jokes and anecdotes, but I guess I just don't have the knack of stringing words together.

    I was contemplating doing myself a favour and deleting the blog. Then I thought, I may as well keep it going (boo, hiss, bad decision) and just use it for a variety of purposes. So starting today Nazim's Cricket Blog will contain 90% less cricket!