Tag Archives: Oracle

Gladstone Refresher

Whilst the Linux Installfest pauses so that I can try out Fedora KDE, I took the opportunity to do a couple of things with Gladstone, the Oracle pre-installer -to deal with issues arising from me testing a bunch of other distros which I haven’t otherwise touched in a while.

First, Gladstone now works on Centos 6.3 and Scientific Linux 6.3. For some reason, I had forgotten to add these new point-releases to the list of “acceptable distros”. Now fixed.

Second, Gladstone now works on Oracle Enterprise Linux 6.3, using the free update repositories provided by Oracle Corporation. Thanks to Ales for hassling me nicely enough (via the comments pages hereabouts) that I felt it might be useful after all:

Proof that Oracle 11gR2 will install on OEL, courtesy of Gladstone

I have to say I have seldom installed OEL… and I can confidently assert that I am grateful for that, since my eyes would bleed if it were otherwise. Radioactive Red-on-White is the opposite of calm, soothing… or pleasant! Thank God it cools down quite nicely once the thing’s installed and you’re sitting at the Gnome Desktop! But anyway, Gladstone now does for OEL what it does with the other Red Hat Clones -though it assumes you’ve done a “Desktop” installation (Basic Server, the default, doesn’t come with any X or window managers, and Gladstone’s not going to plug that gap).

Third, I realised that whilst Gladstone claimed to work on Linux Mint Debian Edition (LMDE), and did actually do so about 18 months ago, it has been broken for quite a while, since it sought to download a version 18 library for gcc++ which is no longer available. I have thus refreshed the code so that the newest version of that library (version 25) is downloaded instead. Gladstone (and Oracle 11g) therefore works on LMDE once more:

Proof that Oracle 11gR2 will install on Linux Mint, courtesy of Gladstone

Finally, I haven’t touched Ubuntu in a long while, so Gladstone has not worked on anything Ubuntu-ish since version 10.10, which is an eternity ago. Thanks to the installfest, that’s now changed, and Gladstone now prepares Ubuntu 12.04 for running Oracle 11g effectively:

Proof that Oracle 11gR2 will install onUbuntu 12.04, courtesy of Gladstone

The Oracle installations on both Ubuntu and Linux Mint Debian Edition both generate an error at link time, similar to the one experienced at the same point by Fedora. This is a feature of the way newer Linuxes do indirect linking. Gladstone deals with this ahead of time by writing a small shell script to your Desktop. When the linking error happens, you just launch that fix-it shell script (by double-clicking, as yourself) and then you can switch back to the Oracle installer and click ‘Retry’: the thing then sails through to completion without further trouble.

I ran into some interesting problems getting Oracle onto these…, er, “niche distros”, the principle one being that quite often their highly-convenient ability to install in ‘Live’ mode means that they don’t prompt you for everything that a standard installer might. Thus, I inadvertently ended up running LMDE with a DHCP-assigned IP address… which wouldn’t have mattered if the IP address used when Gladstone ran (and wrote into the hosts file) was the same IP address the box got assigned after its Gladstone-triggered reboot. Unfortunately, however, it wasn’t. The net result was that my Oracle installation failed at the point where it tries to start a listener …because it was trying to start it on an IP address which was no longer used by the server.

I’ve therefore added a couple of checks into Gladstone regarding networking. First, it checks you have a live Internet connection by counting packet loss when pinging Google: some packet loss is OK, but 100% loss makes it think no Internet connectivity exists at all and it therefore quits.

Second, it checks if you’re using DHCP. Now this is actually very difficult to do (especially if you try to make it work cross-distro). So difficult, in fact, that it’s actually impossible to do it reliably. You can check for the presence of various lease files, or the contents of various interface files… but no such check can be relied on 100%, especially since you can use tools like ifconfig to switch between a static and a DHCP IP address without causing the contents of those files to change at all. So, Gladstone cheats: it tests for the presence of a DHCP client process (dhclient), and if it finds it running, it will warn you and offer to quit. However, since it’s not a 100%-guaranteed test that DHCP was actually used to acquire your current IP address, you can ignore the warning and continue if you like.

Finally, I took the opportunity to tidy up a host of ‘quirks’. The thing is now a lot more consistent and less prone to flooding your terminal with irrelevant garbage messages.

Anyone experiencing difficulties with the script: let me know and I’ll see what can be done.

Cross-Version Code, he wrote

You may be lucky and work in an all-11g (or all-10g, etc) environment… but I have to manage everything from version 7 upwards. This makes it tricky to write any SQL scripts which can be guaranteed to run in all environments. Try this, for example, in 10g and everything will be fine:

select a.sid, a.serial#, substr(b.sql_text,1,40) as sql, b.hash_value, b.sql_id
from v$session a,
     v$sqlarea b
where a.sql_address=b.address;

But run it against a version 9 (or earlier) database, and you’ll merely get an ORA-00904, because “SQL_ID” is not a column in the V$SQLAREA view in those versions. Of course, I could remove that column from my query entirely: coding to the least-common denominator and mentioning only things which exist in all possible versions… but that would mean missing out on useful information when I run against 10g or 11g databases. Why miss out on knowing stuff when the information is available?

What I want, of course, is one SQL script that can run in 9i, 10g and 11g environments without error, returning me SQL_ID if it’s possible and skipping it if it’s not.

Well, a possible generic query to tell you what version of the database you are running on might look like this:

select
 case when banner like '%9i%' then '9i'
 when banner like '%10g%' then '10g'
 when banner like '%11g%' then '11g'
 else '0'
 end
 from v$version where banner like 'Oracle%';

If the result of that query is selected ‘into’ a variable, we can test that variable’s value in an anonymous PL/SQL block and do conditional execution accordingly. In other words, logically, you’d have this sort of thing:

if v_version = '9i' then
  --run version of SQLAREA query that misses out SQL_ID column;
elsif v_version = '10g' or v_version = '11g' then
  --run version of SQLAREA query that includes the SQL_ID column;
end if;

Of course, at this point, you’re writing an anonymous PL/SQL block and you’ve accordingly lost the ability to have the results of queries effortlessly displayed. The trick there is to declare a refcursor variable, have your query select its results into that variable and then have SQL*Plus print out the contents of the refcursor.

You also can’t mention ‘SQL_ID’ even in the v_version=’10g’ section of the code, because it will be spotted at compile time as being a reference to a column that doesn’t exist on a 9i database. An error will then be thrown before the 9i-flavour of the query even gets a chance to run. The workaround for that is to use dynamic SQL -wrap the code in quotes, basically- so that what is inside the quotes is only evaluated at run-time …and if the logic means one part of your code isn’t actually run, then any “errors” it contains won’t be triggered.

Taking those things into account, then, you might end up with code like this:

set autoprint on
variable y refcursor
declare
 v_version varchar2(5);
 v_sql9 varchar2(4000);
 v_sql10 varchar2(4000);
 p_results sys_refcursor;
begin

v_sql9 := 'select a.sid,
 a.serial#,
 substr(b.sql_text,1,40) as sql,
 b.hash_value
 from v$session a,
 v$sqlarea b
 where a.sql_address=b.address';

v_sql10:= 'select a.sid, 
 a.serial#,
 substr(b.sql_text,1,40) as sql,
 b.hash_value,
 b.sql_id
 from v$session a,
 v$sqlarea b
 where a.sql_address=b.address';

select
 case when banner like '%9i%' then '9i'
 when banner like '%10g%' then '10g'
 when banner like '%11g%' then '11g'
 else '0'
 end
 into v_version
 from v$version where banner like 'Oracle%';

if v_version = '9i' then
 open :y for v_sql9;
elsif v_version = '10g' or v_version = '11g' then
 open :y for v_sql10;
end if;
end;
/

Taking that apart, bit by bit:

set autoprint on
variable y refcursor

Autoprint enables the contents of bind variables to be automatically displayed, once a query has completed. The next line then creates such a variable, called “y”, which is declared to be of type ‘refcursor‘ (essentially, a resultset, containing multiple rows).

declare
 v_version varchar2(5);
 v_sql9 varchar2(4000);
 v_sql10 varchar2(4000);

Here, I simply create three varchar2 variables to hold the contents of the Oracle version, the 9i and the 10g version of the query. The fourth variable is declared as type sys_refcursor, so that multi-row results can be selected into it.

v_sql9 := 'select a.sid,
 a.serial#,
 substr(b.sql_text,1,40) as sql,
 b.hash_value
 from v$session a,
 v$sqlarea b
 where a.sql_address=b.address';

Now I set up the actual values for the version-dependent query variables. Note that they are wrapped in single quotes: this stops the PL/SQL compiler spotting that the v_sql10 one contains a reference to something that doesn’t actually exist in a 9i database. The 9i version omits reference to the SQL_ID column; otherwise, the two are identical.

select
 case when banner like '%9i%' then '9i' [...]

Now comes the version-detection query I mentioned before, only this time it selects its results into the v_version variable previously declared.

if v_version = '9i' then
 open :y for v_sql9;
elsif v_version = '10g' or v_version = '11g' then
 open :y for v_sql10;
end if;

This is the bit of code that does all the work: it executes one of the dynamic SQL statements, depending on the Oracle version detected, selecting its results into the ‘y’ bind variable I declared right at the start. When this query has completed, the contents of ‘y’ will be printed out automatically (because of the autoprint setting I made at the start, too).

Using the one SQL script, therefore, I can now get results from both 9i and 10g databases:

SQL> /
PL/SQL procedure successfully completed.
SID SERIAL# SQL HASH_VALUE SQL_ID
---------- ---------- ---------------------------------------- ---
------ -------------
 306 38043 select 207344822 77s0p3s65rp5q
 295 17502 INSERT /*+ append */ into scott.EMP 2033560799 0qtz8ftw
bb6z
 299 44668 INSERT /*+ append */ into scott.EMP 2033560799 0qtz8ftwmbb6z
 293 9141 INSERT /*+ append */ into scott.EMP 2033560799 0qtz8ftwmbb6z
SQL> /

PL/SQL procedure successfully completed.
 SID SERIAL# SQL HASH_VALUE
---------- ---------- ---------------------------------------- ---
------
 6 1 select con#,type#,condlength,intcols,rob 1937775682
 7 1 select o.owner#,o.name,o.namespace,o.rem 431456802
 213 11205 SELECT /*+ index(ORDER_INFO ORDER_INFO_P 1942381241
 283 56071 declare nm owa.vc_arr; vl owa. 1860200125

My choice of a ‘CASE’ statement means this code isn’t truly cross-version-compatible, because it won’t work in version 7 or 8i, and I haven’t bothered to write any code in this example that handles the ”not 9i, 10g or 11g” situation, though the v_version variable is set to ’0′ in those cases and could be dealt with if needed. But that’s trivial (I could always stick to the decode function if I really wanted to, instead of using “CASE”, for example)… and not something I feel the need to do right now!