Oracle 10g installation notes on Solaris 10

This article provides some of the issues encountered during an installation of Oracle 10G on Solaris 10. This article is NOT meant to be an installation guide, but rather document some of the "gotchas" that I experienced during my most recent installation of Oracle 10g on Solaris. I performed this initial installation on a Sun V120 w/ 4GB of RAM, and dual 72GB drives and Solaris 10 6/06. The installation that I was performing was geared towards supporting an installation of Lucent Technologies VitalQIP 7.0 product.

Issue #1: Choosing the appropriate Sun Solaris software group to install

My first mistake was made in NOT choosing to simply install the Sun Solaris software group "Entire Solaris Software Group". Instead i tried doing a minimal installation and then attempting to add the other required software packages. I really didn't spend any time on this and instead, opted the easy route. I installed the "Entire Solaris Software Group" because I knew that other software install groups didn't lay down the /usr/ccs/bin/make that is a sun provided make utility. During an installation of Oracle 10g, it performs a re-linking of the client libs based upon what is selected for the installation. The first pass, it failed because it couldn't find the make program. I tried installing GNU make which installs to /usr/local/bin. I created a symbolic link in /usr/css/bin/make pointing to it, but this didn't work either. Lesson learned. Install more software than you think you will need, if you are looking to save time and energy during the installation of Solaris, Oracle, and ultimately QIP. This is only a recommendation. I am certain that one could figure out how to do a minimal software installation and add only those required packages to get the installation to work properly.

Issue #2: Setting kernel parameters in Solaris 10

Configuring kernel parameters has changed dramatically in Solaris 10. Not all parameters are configured in /etc/system as they were with Solaris 8 and 9. The first parameter that I had to set was the noexec_user_stack=1 parameter. This I figured out MUST STILL be set in the /etc/system kernel parameters file. Simply append that file with 'set noexec_user_stack=1' and reboot the system.

The next two parameters that must be set are for the Shared Memory Segements and the Semaphore IDS. I'm still not really sure if i have it optimally set, but the method that I used to set it seems to have worked. First, I set both parameters for the user root by typing the following:

prctl -n project.max-shm-memory -v 4gb -r -i project user.root
prctl -n project.max-sem-ids -v 256 -r -i project user.root

The settings took and to ensure they took I was able to issue the following commd(s) to view the settings:

prctl -n project.max-shm-memory -i project user.root
prctl -n project.sem-ids -i project user.root

I still had issues, so i made the same settings for an additional user based upon some readin g on the internet. So, i created another project/user and made the same kernal parameter changes to that user as well. Here is the sequence of commands that I issued to make that change:

projadd user.oracle
projmod -s -U oracle -K "project.max-shm-memory=(priv,4gb,deny)" user.oracle
projmod -s -U oracle -K "project.max-sem-ids=(priv,256,deny)" user.oracle

At first I made that command w/o the -s. I believe that is to make it save it or make it static. Once issued with the -s, I was able to verify that the /etc/project file was written to with the oracle user. So, this notion of zones, projects, and users is new to me. I have not spent any time learning this and how it all works, but figured I would jot down what steps I took that made my installation ultimately successful. (possibly continued...)

Issue #3: Oracle Passwords

I encountered a small issue that I forgot existed in Oracle. To set up my first database, I opted to use the DBCA assistant in creating the database, instead of during the initial installation of the Oracle software. I chose this route b/c I wanted to save a template and the Shell/SQL scripts to be able to re-create it any later time. During the DBCA wizzard, it asks for the password you want to establish for the built-in accounts, SYS, SYSTEM, DBSNMP etc. I chose a password that started with a number and the wizzard took my input and the program continued to perform the installation and creation of the scripts. Once everything was done and the database was created, I found i couldn't log into the Oracle EM web-based interface. I had to use my still-open SQL session to alter the passwords and set them to alpha-numeric passwords that did NOT start with a numeric. Once I figured that out, everything worked great.

Using the Oracle Instantclient w/ VitalQIP 7.1PR1

The purpose of this article is to show by example how to configure Alcatel-Lucent's VitalQIP IPAM product with Oracle Instantclient. First, why would one want to do this? Well, in some environments, the database software is not permitted to co-exist with application software due to standards and/or for security reasons. In cases where dedicated database servers are required, the Oracle Instantclient comes in handy when installing the Lucent VitalQIP ES components. The Oracle Instantclient for 10g is a much smaller and much easier to install Oracle database client than trying to figure out which pieces of the Oracle server media to use for installing the client portion. Oracle Instantclient consists of about 100Mb of Client libraries, headers, and binary files. It has everything you need for making connections to your dedicated Oracle Database server, and VitalQIP works seemlessly using this client.

Oracle Instant Client 10.2.0.3.0

First, obtain the proper binary releases of the Oracle Instant client from http://technet.oracle.com. For the purposes of my installation, I pulled down the following files for my platform:

09/11/2007 02:31 PM 37,428,605 instantclient-basic-solaris6432-10.2.0.3-20070101.zip
09/11/2007 02:32 PM 1,508,693 instantclient-jdbc-solaris6432-10.2.0.3-20070101.zip
09/11/2007 02:32 PM 280,149 instantclient-odbc-solaris6432-10.2.0.3-20070101.zip
09/11/2007 02:32 PM 602,857 instantclient-sdk-solaris6432-10.2.0.3-20070101.zip
09/11/2007 02:32 PM 834,541 instantclient-sqlplus-solaris6432-10.2.0.3-20070101.zip

Unzip the files to $ORADIR:

unzip -o instant*zip -d $ORADIR 

Clean up the $ORADIR directory structure by removing sub-directories:

cd $ORADIR
mv $ORADIR/instantclient_10_2/* $ORADIR
rm -rf $ORADIR/instantclient_10_2

This moved all files and subdirectories in instantclient_10_2 to $ORADIR. Then I safely removed the instantclient_10_2 directory.

NOTE: you must create the following symbolic link for QIP to work properly

ln -s /export/opt/DNSIora/libclntsh.so.10.1 /export/opt/DNSIora/libclntsh.so

Once the software is installed, create your tnsnames.ora file in the $ORADIR. It should look something like this:

QIP7 = 
   (DESCRIPTION = 
      (ADDRESS_LIST = 
         (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.2.100)(PORT = 1521)) 
      ) 
      (CONNECT_DATA = 
         (SID = QIP7) 
      ) 
   )LISTENER_QIP7=(address=(protocol=tcp)(host=192.168.2.100)(port=1521)
)

You should set the TNS_ADMIN environment variable to the path or directory that contains the tnsnames.ora file.

Next, Install the VitalQIP 7.1 application. The ORACLE_HOME and LD_LIBRARY_PATH environment variables in the $QIPHOME/etc/shrc should both refer to the same path as the TNS_ADMIN path. That's it! Remember to source your environment variables. To test, run a CLI such as qip-getpolicy. You should see output.

Oracle Instant Client cannot be used to perform imports, it can only run an Enterprise Server whose data has already been loaded, i.e. you cannot run qip-import. This is because sqlloader, that is required by the VitalQIP import process, has not been installed as part of the Instant Client distribution.

Parse string into variable using regex in perl

Sometimes when parsing strings in perl you need to be able to parse the string and grab a "word" and store it into a variable all in one shot. Here is a small recipe to accomplish just that...

Suppose we have the following string:

"          dynamic-dhcp range 10.10.10.10 10.10.10.100 {";

and we want to have build variables to hold the starting IP range and the ending IP range of this string. We could search and split this string with the following regex:

if($_ =~ m/^\s+dynamic-dhcp\s+range\s+(\S+)\s+(\S+)\s+/) {
     my $startip = $1;
     my $endip = $2; 

}

This code will parse the string and simultaneously store "10.10.10.10" in the variable $startip, and "10.10.10.100" in the variable $endip.  Additionally, we could perform a test on the captured strings to ensure they are valid IP addresses.  One way you could do this is to use the Net::IP module from CPAN.  Our code, with the check added, might look like the following:

if($_ =~ m/^\s+dynamic-dhcp\s+range\s+(\S+)\s+(\S+)\s+/) {
    my $startip = new Net::IP($1) or die (Net::IP::Error());
    my $endip   = new Net::IP($2) or die (Net::IP::Error());
}

Detect Table rows and cells with JavaScript

This article focuses on the need to identify row and cell indexes of HTML tables for data manipulation and/or Ajax processing. Frequently, I have had to try and identify object properties of information that resides in a table format. For example, suppose we have a table of information, and you are selecting a row, and you want to pass all of that row's cells data as properties to an AJAX call. To get started, I would like to reference a good primer article on http://www.maratz.com/ entitled "Detect Table Row Index with JavaScript". This is really the most important task in attempting to locate cells of a table. You first have to know what row you are working with in the table.

There are some guidelines and assumptions that should be cleared up first. It is strongly suggested that if you are trying to locate the row index of a table, the table should be named with an ID so that you know which table to work with. You could have many different tables in a single web page. So, my first recommendation is to give the table an id that is meaningful and memorable.

Read more ...

IP Address conversion in PHP

The purpose of this technote is to provide a small recipe for manipulating and/or converting IP addresses to decimals and back. I wrote a similar technote on how to do this in the Perl language. I thought it would be just as useful to know how to do the same thing in PHP. PHP has a few built-in functions but use of these functions may not yield the desired results.

The PHP function ip2long( string ip_address) is a built-in function that will return an integer. PHP's Integer type is signed, so many IP addresses will result in a negetive number.

ip2long Example:

<?php
$long_neg = ip2long('192.168.1.1');
$long_pos = ip2long('10.1.1.0');
?>

In this example, $long_neg = -1062731519 and $long_pos = 167837952. A good way to resolve this issue of signed vs unsigned is to make your own function to do it for you. The following function and example are shown below:

ip2dec function

<?php

$long_pos = ip2dec('10.1.1.0');
$long_neg = ip2dec('192.168.1.1');

function ip2dec($ip) {
    return (double)(sprintf("%u", ip2long($ip)));
}
?>

Wow, much different results! $long_pos still eqals 167837952. But look at $long_neg! $long_neg = 3232235777. By the way, this is how the PEAR module Net_IPv4 function Net_IPv4::ip2double does it. The PHP on-line docs also make mention that you may have to use printf or sprintf to get the desired results.

Pear Spreadsheet_Excel_Writer

Recently I attempted to use the PEAR Spreadsheet::Excel::Writer class file to dynamically generate an XLS file from information that was stored in a database. There are really two methods for generating a workbook.

Directly outputting to the browser - This failed for me for unknown reasons. I was getting back unformatted binary data back to the browser window. It was not properly encoding/decoding the mime data.

Outputting directly to a file - This worked just fine. To do this, you simply add the name of the XLS file you desire in the class's constructor.

The following are code snippets that demonstrate the two different ways of outputting data with this class:

Method 1 - output directly to the browser

<?php
require_once 'Spreadsheet/Excel/Writer.php';
 
// Creating a workbook
$workbook = new Spreadsheet_Excel_Writer();
 
// sending HTTP headers
$workbook->send('test.xls');
 
// Creating a worksheet
$worksheet =& $workbook->addWorksheet('My first worksheet');
 
// The actual data
$worksheet->write(0, 0, 'Name');
$worksheet->write(0, 1, 'Age');
 
// my database res
$r = 1;
foreach($res as $row) {
    $worksheet->write($r,0, $row['name']);
    $worksheet->write($r,1, $row['age']);
    $r++;
}
 
// Let's send the file
$workbook->close();
?>

Line #8 is the key to outputting directly to the browser. This sends the xls headers out to the browser, and it is up to the web server and browser to know what application to associate with that Mime Type.

Method 2 - Output directly to an xls file

<?php
require_once 'Spreadsheet/Excel/Writer.php';

// Creating a workbook
$workbook = new Spreadsheet_Excel_Writer("test.xls");

// Creating a worksheet
$worksheet =& $workbook->addWorksheet('My first worksheet');

// The actual data
$worksheet->write(0, 0, 'Name');
$worksheet->write(0, 1, 'Age');

// my database res
$r = 1;
foreach($res as $row) {
    $worksheet->write($r,0, $row['name']);
    $worksheet->write($r,1, $row['age']);
    $r++;
}

// Let's send the file
$workbook->close();

?>

In this example, we pass the name of the xls file to the constructor as an argument. No mime type headers are passed, and the file should be built directly on the system, and not be sent back to the browser.

The first time I attempted method 1, it failed. I got a bunch of binary and control characters sent back to the browser. The fix, was to configure my web server to properly associate the Mime type with an app. The following line MUST be added to the Apache web server's conf file for browser to properly render the output: 

AddType application/x-ms-excel .xls

The web server must be restarted for this change to take affect. Once restarted on my Windows development environment, I was able to directly output Excel files via my server and browser. Great stuff!