Downloading OTN software using wget

One of my most frequently-visited posts is "Retrieving Oracle patches with wget." Recently, a commenter on that post asked about using wget to download software from Oracle Technet (OTN). It's a little complicated to use wget to download from OTN, because there are cookies involved. This post discusses how to extract the relevant cookies from Firefox and Google Chrome, and use those cookies with wget to retrieve files. If you manage to wade through my excessive exposition, there's even a script at the end that you might find useful.

First things first: This is not a new idea. Pythian's Marc Fielding wrote an excellent article a long time ago about using wget and the text-based browser lynx to download files from OTN. His article is the reason that I even knew this was possible; I'm just expanding on the concept to include other browsers. If you have lynx installed on your server, you can stop reading this post, go read Marc's post instead, and you're all set. In fact, it's a good idea to read Marc's article anyway, because I'm going to reference it a few times in this post.

Overview and assumptions

As you've read from Marc's article (you did go to read that, right?), the basic process to set up downloads from OTN with wget is as follows:

  1. Authenticate to OTN with your username and password. You need to do this for cookies to be set properly. No workarounds or backdoors here, you have to sign in.
  2. Navigate to the relevant page in the Downloads section for the software to be downloaded
  3. Click the radio button to accept the license agreement. This is necessary to reveal the download links so you can copy the URL to feed to wget. Again, no backdoors, no workarounds.
  4. Copy the URLs of the files you want to download
  5. Extract the cookies created during your browser session into a text file.
  6. Invoke wget with the --load-cookies option to download the desired files.

By now, you might be thinking, "If it's that easy, why is the scroll bar next to this post so long?" The answer is that step 5 is somewhat involved.

I'm going to assume a few things. First, we'll be working with either Firefox or Google Chrome, because they store their cookies in similar ways. Safari uses XML to store cookies, and Internet Explorer is just an abomination ;-) , so they're beyond the scope of this post. My second assumption is that you don't need help with steps 1-4 above. We're going to jump right into extracting cookies from Firefox and Chrome.

Update, 25-Apr-2010: Here's one last opportunity to stop reading and start doing. If you're a Firefox user, and not averse to using plugins in your browser, you could install a plugin like Cookie Exporter to extract cookies to a properly-formatted text file. Also, notwithstanding my crack about IE, I have read that it's possible to export IE's cookies in the correct format without having to resort to any special shenanigans. I had intended to point out both of these things in my original post, but instead I launched right into the SQLite discussion below. Sorry about that; the editing department has been sternly reprimanded.

Extracting cookies

Lynx very conveniently exports its cookies to a text file, in the format expected by wget (the classic "Netscape cookies.txt" spec). Firefox and Chrome, on the other hand, save cookies in a SQLite database file. So, I guess that's it, right? Cookies locked up in some goofy binary file. Not going to be able to get those out. Guess I'm out of luck.

Oh. Wait. I do database stuff. There's hope!

The first thing to do is to install a SQLite client. Instructions are beyond the scope of this post, but you can download precompiled binaries of the sqlite3 command-line client from the SQLite site. If you're a Mac user, you're in luck: sqlite3 should already be installed in /usr/bin.

The next step is to locate the cookies database file for your browser. For Firefox, it should be cookies.sqlite in your default profile directory, and for Chrome, it should be the file creatively named Cookies in your profile directory. If you're really stuck, and are running Linux or OS X, you should be able to find the location by issuing lsof | grep -i cookies while your browser is running.

Here's an example of what the cookies look like in the SQLite database in Firefox:

zathras:~ jpiwowar$ sqlite3 /Users/jpiwowar/Library/Application\ Support/Firefox/Profiles/ftpzvxjz.default/cookies.sqlite
SQLite version 3.6.10
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .schema moz_cookies
CREATE TABLE moz_cookies (id INTEGER PRIMARY KEY, name TEXT, value TEXT, host TEXT, path TEXT,expiry INTEGER, lastAccessed INTEGER, isSecure INTEGER, isHttpOnly INTEGER);
sqlite> select *
...> from moz_cookies
...> where name like 'ORA_UCM%'
...> ;
1271476327342462|ORA_UCM_INFO|3~70969please_dont_copy_my_cookies|.oracle.com|/|1303012327|1271477696515030|0|0
1271476327343576|ORA_UCM_VER|%200|.oracle.com|/|1303012327|1271477696515030|0|0
1271476327344121|ORA_UCM_SRVC|no_really_just_use_your_own|.oracle.com|/|1303012327|1271477696515030|0|0

The name of the cookies table in Firefox is moz_cookies. At the time of this post, the OTN cookies needed for this exercise have names starting with ORA_UCM. The name of the SQLite table in the Chrome cookies database is simply 'cookies'. You'll note that some of the column names are also different:

zathras:~ jpiwowar$ sqlite3 /Users/jpiwowar/Library/Application\ Support/Chromium/Default/Cookies
SQLite version 3.6.10
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .schema cookies
CREATE TABLE cookies (creation_utc INTEGER NOT NULL UNIQUE PRIMARY KEY,host_key TEXT NOT NULL,name TEXT NOT NULL,value TEXT NOT NULL,path TEXT NOT NULL,expires_utc INTEGER NOT NULL,secure INTEGER NOT NULL,httponly INTEGER NOT NULL,last_access_utc INTEGER NOT NULL);

Of course, a simple "select *" from the cookies table is not going to produce a usable cookies file to use with wget. The cookies.txt spec requires 7 tab-, not pipe-, separated fields, and the expiration timestamp for Chrome cookies is in an unusual format. Rather than take up even more space in this post, I've written a shell script, OTNcookies.sh (it'll probably download as .txt, not .sh), that performs the work of extracting the cookies in the proper format. Here's a quick overview of the script:

  • Takes two arguments: the first (required) is the location of the cookies database file, and the second (optional) is the name of the text file containing the exported cookies.
  • Determines the type of cookie database (Firefox or Chrome)
  • Runs an appropriate query to extract the cookies to the text file specified by the user, or to a default output file.
  • Tries to accommodate for spaces in filenames and directories, but you will need to escape spaces in the file names that you pass to the script

As with any script you grab from the Intertubes, please exercise caution. This isn't designed to do anything malicious or damaging, but that doesn't mean you couldn't do something silly with it (like, say, running it as root and overwriting critical system files with cookies. Wouldn't that be embarrassing? Yes, but it would be your fault, not mine :) )

Here's a sample run of the OTNcookies script:

zathras:~ jpiwowar$ OTNcookies.sh /Users/jpiwowar/Library/Application\ Support/Firefox/Profiles/ftpzvxjz.default/cookies.sqlite /var/tmp/FFcookies.txt
Looks like Firefox.
OTN cookies written to /var/tmp/FFcookies.txt

After extracting the cookies, it's a simple matter of invoking wget with the load-cookies option, as documented in Marc's article.

zathras:~ jpiwowar$ wget --load-cookies=/var/tmp/FFcookies.txt http://download.oracle.com/otn/mac/instantclient/10204/instantclient-basic-10.2.0.4.0-macosx-x86.zip

--2010-04-22 17:00:39--  http://download.oracle.com/otn/mac/instantclient/10204/instantclient-basic-10.2.0.4.0-macosx-x86.zip
Resolving download.oracle.com... 208.111.133.52, 208.111.133.54
Connecting to download.oracle.com|208.111.133.52|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 34109360 (33M) [application/zip]
Saving to: `instantclient-basic-10.2.0.4.0-macosx-x86.zip'<br />10% [===>                                   ] 3,563,808    545K/s  eta 65s

A final note: The cookie file should be re-usable, so you don't need to regenerate one for each file you want to download. The cookies will expire eventually, however, at the time indicated in the expiry or expires_utc field. At that point, you'll need to go through the whole process again, starting with logging in to OTN to create new cookies.

Happy downloading!

Using the rpm “queryformat” option to display package architecture

Here's one from the "learned something new today" files. When installing Oracle products on 64-bit versions of Linux, it's a common requirement to have both 32- and 64-bit versions of certain packages installed (that's not the "learned something new" part). The default output for the rpm query command, rpm -q, doesn't show the architecture of the queried package (that's not new, either). For example, installing Oracle RDBMS 11gR1 on RHEL4 or OEL4 requires both 32- and 64-bit versions of the libaio and glibc-devel (not the full list of package requirements; I'm just trying to keep the example short). A typical rpm query would show the following output:

[jpiwowar@testsrv ~]$ rpm -q libaio glibc-devel
libaio-0.3.105-2
glibc-devel-2.3.4-2.39
glibc-devel-2.3.4-2.39

It's probably safe to assume that those two glibc-devel entries cover the 32- and 64-bit versions, but where's the second libaio? The easy answer is to append the architecture string to the name of the package, but that results in a pretty quiet failure for the package that's not installed:

[jpiwowar@testsrv ~]$ rpm -q libaio.x86_64
libaio-0.3.105-2
[jpiwowar@testsrv ~]$ echo $?
0
[jpiwowar@testsrv ~]$ rpm -q libaio.i386
[jpiwowar@testsrv ~]$ echo $?
0

My new favorite trick (finally, the "learned something new" part!) is to use the --queryformat (or --qf) option to display the architecture of an installed package:

[jpiwowar@testsrv ~]$ rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE} %{ARCH}\n' libaio glibc-devel
libaio-0.3.105-2 x86_64
glibc-devel-2.3.4-2.39 i386
glibc-devel-2.3.4-2.39 x86_64

It's not perfect, but it makes it a bit easier to spot which version of a package (32-bit libaio, in this case) is missing in a long list of required packages. I'm a bit embarrassed to admit that I didn't know about this option until recently, but if it's new to me, maybe it's new to you too. :-)

References

A sampling of R12 AOL and database object changes

From time to time, a post appears in the OTN E-Business Suite Forums of the following form:

We are planning our upgrade to R12, and need to know how many new tables/forms/views/etc there are in the new version. Where are the documents that list these changes?

In these cases, forum posters are usually directed (quite appropriately) to review the upgrade manuals and Release Content documents for R12, which probably contain pieces of the answer to the question. To the best of my knowledge, however, there is no comprehensive, monolithic list of schema changes that occur in the course of an R12 upgrade. One significant reason is the resource burden involved in maintaining a such a list. The upgrade process has so many start and end points. Are you upgrading from 11.0.x? 11.5.8? 11.5.10? Which family packs and CUs are applied? Are you upgrading to to 12.0.6? 12.1.1? 12.1.2? Keeping track of all of those permutations, while perhaps possible, would accomplish little beyond crushing the spirit of a small army of interns.

This is not the question we're looking for; you can go about your business...

An even bigger reason to not be concerned about the number of schema changes in the R12 upgrade: it doesn't seem to be particularly useful information. I can't think of any "effort estimate" metric that would benefit from know knowing the number of new tables, forms, etc. that have been changed, added, or removed. Even knowing that specific tables and forms have disappeared or changed isn't very helpful. After all, you're going to be running thorough tests of any custom reports and forms, anyway, as well as testing to see what common user activities are impacted by the upgrade. Right? (Please say, "right!") We found out pretty quickly, for example, that there were some tables used by our custom reports that had been emptied; the data had been moved to another schema, and our custom reports returned no rows. Good times, and a simple "does this table still exist in R12?" test would not have caught that new feature.

After such a long setup, you must know where this is going. During a long ago (2007-2008) R12 upgrade project, I actually ran some queries comparing the contents of a few key tables (ALL_OBJECTS, FND_APPLICATION, etc) before and after the upgrade. I'll present the results of those queries below. Perhaps someone can find some use for them that I was unable to divine.

Data of dubious utility

Anyone who's read more than two posts here knows that I disclaim like there's no tomorrow. This post is no different:

  • The data presented is for an 11.5.10.2 system upgraded to 12.0.3. Your mileage will vary, because no one's upgrading to 12.0.3 these days. At least, I hope not.
  • This data is based on notes and SQLPLUS spool files that are over 2 years old by now, which is not exactly "fresh." Since I no longer have the source data, I can't even do a useful sanity check to be sure I extracted it all correctly. Where possible (i.e. salvageable from my logs), I have included the text of my queries, primarily so readers can understand how I generated the data. There is no doubt substantial room for improvement. Many of the queries are slapdash jobs, since I was just doing informal research. Nonetheless, I believe in showing my work, even if it's sometimes embarrassing. :)
  • If you read Oracle documentation that contradicts anything that you see here, you should definitely trust those docs. Furthermore, if your own investigations contradict what you see here, you should trust your own work. :)

After all of that, if you're still on board, follow the links below to jump to the relevant sections. If you get any interesting nuggets out of these lists, then I'm glad I could help. Otherwise, you could just summarize the answer to the "how many changes" question as, "Whoa, lots." :-)

Applications
Concurrent Programs
Forms
Profile Options
Database Objects

Applications

The following tables summarize the number of new and removed applications, as well as an attempt at listing the applications that are marked obsolete, but not actually removed. The major assumption is that the application_id does not change between versions, though I didn't do much to confirm that assumption. The absence of a "removed" table suggests that I didn't find any deleted application_ids, but I don't rule out the possibility that I was just lazy. :)

New applications

SQL>select application_short_name
 2       , application_name
 3    from r12_application_tl r12 join r12_application using (application_id)
 4   where application_id not in
 5                        (
 6                         select application_id
 7                           from r11_application r11
 8                        )
 9   order by 1
10  /
APPLICATION_SHORT_NAME APPLICATION_NAME
CDR Oracle Clinical Data Repository
CLA APAC Consulting Localizations
CLE EMEA Consulting Localizations
CLJ Japan Consulting Localizations
CLL LAD Consulting Localizations
CSN Call Center
DEM01 Team 01 Order Entry Demo
DUMMY_GMO Obsolete Process Operations
GMO Manufacturing Execution System for Process Manufacturing
IBW Oracle Web Analytics
IPM Oracle Imaging Process Management
IRC iRecruitment
ITA Information Technology Audit
JMF Supply Chain Localizations
OKC_REP_TXT_INDEX_OPTIMIZE Optimize Contracts Repository Text index
OKC_REP_TXT_INDEX_SYNC Build/syncronize Contracts Repository Text index
OUC University Curriculum
PSR Public Sector Receivables
RRC Retail Core
RRS Site Management
TEST test

Renamed applications

SQL>select application_short_name
 2       , r12.application_name new_name
 3       , r11.application_name old_name
 4    from r12_application_tl r12 join r12_application using (application_id)
 5         join r11_application_tl r11 using (application_id)
 6   where not regexp_like(r12.application_name,'obsolete','i')
 7     and r11.application_name &lt;&gt; r12.application_name
 8  /
APPLICATION_SHORT_NAME NEW_NAME OLD_NAME
ICX Oracle iProcurement Self-Service Web Applications
FEM Enterprise Performance Foundation Strategic Enterprise
Management
IBY Payments iPayment
IGS Student System Student Systems
ASP Oracle Sales for Handhelds Field Sales/Palm Devices
CSE Asset Tracking Enterprise Install Base
XNB Oracle Telecommunications Billing Integrator eBusiness
Billing
GCS Financial Consolidation Hub Global Consolidation System
FPA Project Portfolio Analysis Portfolio Analyzer
HCP Healthcare Intelligence Healthcare Portal
PFT Oracle Profitability Manager Performance Analyzer

Obsolete applications

SQL>select application_short_name
 2       , application_name
 3    from r12_application_tl join r12_application using (application_id)
 4   where regexp_like(application_name,'obsolete','i')
 5   order by 1
 6  /
APPLICATION_SHORT_NAME APPLICATION_NAME
ABM Activity Based Management (Obsolete)
AHM Hosting Manager(Obsolete)
AMF Fulfillment Services (Obsolete)
BIC Customer Intelligence (obsolete)
CSS Support (obsolete)
CUE Billing Connect (obsolete)
CUN Network Logistics - NATS (obsolete)
DUMMY_GMO Obsolete Process Operations
EAA SEM Exchange (obsolete)
FPT Banking Center (obsolete)
IBA iMarketing (Obsolete)
IMT iMeeting (obsolete)
IPD Product Development (obsolete)
ME Controlled Availability Product(Obsolete)
OKB Contracts for Subscriptions (Obsolete)
OKO Contracts for Sales (Obsolete)
OKP Contracts for Procurement (Obsolete)
OKR Contracts for Rights (Obsolete)
OZP Trade Planning (Obsolete)
OZS iClaims (Obsolete)
RCM Regulatory Capital Manager (obsolete)
RHX Advanced Planning Foundation(obsolete)
RLA Release Management Integration Kit (Obsolete)
VEH Automotive Integration Kit (Obsolete)
XNC Sales for Communications (Obsolete)
XNI Install Base Intelligence (Obsolete)
XNM Marketing for Communications (Obsolete)
XNS Service for Communications (obsolete)

Concurrent Programs

In addition to new concurrent programs introduced in R12, a handful were removed, renamed, or marked obsolete. I also generated a longer list that broke down the counts by application, and another that listed each changed concurrent program individually. In the interest of saving space (and formatting pain), I've just offered the summary data here, followed by the query.

PROG_COUNT PROG_STATUS
1587 New
31 Obsolete
87 Removed
294 Renamed
SQL>select count(r12c.concurrent_program_id) prog_count
  2  	 , 'New' prog_status
  3   from r12_application_tl r12a join r12_concurrent_programs r12c
  4        using (application_id)
  5  where not exists
  6  	   (
  7  	    select application_id
  8  	         , concurrent_program_id
  9  	      from r11_concurrent_programs r11c
 10  	     where r11c.application_id = application_id
 11  	       and r12c.concurrent_program_id = r11c.concurrent_program_id
 12  	    )
 13  group by 'New'
 14  union all
 15  select  count(r11c.concurrent_program_id) prog_count
 16  	  , 'Removed' Status
 17    from r11_application_tl r11a join r11_concurrent_programs r11c
 18  	    using (application_id)
 19   where not exists
 20  	    (
 21  	     select application_id
 22  		  , concurrent_program_id
 23  	       from r12_concurrent_programs r12c
 24  	      where r12c.application_id = application_id
 25  		and r11c.concurrent_program_id = r12c.concurrent_program_id
 26  	    )
 27  group by 'Removed'
 28  union all
 29  select  count(r12c.user_concurrent_program_name) prog_count
 30  	  , 'Obsolete' prog_status
 31    from r12_application_tl r12a
 32  	    join
 33  	    r12_concurrent_programs_tl r12c
 34  	    using (application_id)
 35  	    join r11_concurrent_programs_tl r11c
 36  	    using (application_id, concurrent_program_id)
 37   where regexp_like(r12c.user_concurrent_program_name,'obsolete','i')
 38  	and r12c.user_concurrent_program_name &lt;&gt; r11c.user_concurrent_program_name
 39  group by 'Obsolete'
 40  union all
 41  select  count(r12c.user_concurrent_program_name) prog_count
 42  	  , 'Renamed' prog_status
 43    from r12_application_tl r12a
 44  	    join
 45  	    r12_concurrent_programs_tl r12c
 46  	    using (application_id)
 47  	    join r11_concurrent_programs_tl r11c
 48  	    using (application_id, concurrent_program_id)
 49   where not regexp_like(r12c.user_concurrent_program_name,'obsolete','i')
 50  	and r12c.user_concurrent_program_name &lt;&gt; r11c.user_concurrent_program_name
 51  group by 'Renamed'
 52  order by 2
 53  /

Forms

Here's a count by application of new and removed forms. We didn't have much in the way of customized forms, so I didn't drill down to form names, but the queries would be easy enough to modify if needed.

SQL>select r12a.application_name
  2       , count(r12f.user_form_name) new_forms
  3    from r12_application_tl r12a join r12_form_tl r12f
  4         using (application_id)
  5   where not exists
  6         (
  7          select application_id
  8               , form_id
  9            from r11_form_tl r11f
 10           where r11f.application_id = application_id
 11             and r12f.form_id = r11f.form_id
 12         )
 13  group by r12a.application_name
 14  order by 2 desc
 15  /
APPLICATION_NAME NEW_FORMS
Asia/Pacific Localizations 114
Subledger Accounting 17
Process Manufacturing Process Execution 7
Student System 7
General Ledger 7
Field Service 6
Inventory 6
Process Manufacturing Financials 5
Marketing 5
Process Manufacturing Product Development 5
Bills of Material 4
Depot Repair 4
Advanced Supply Chain Planning 4
Supply Chain Localizations 4
Financial Aid 3
Public Sector Budgeting 3
Public Sector Financials International 3
Receivables 3
Cash Management 2
Enterprise Asset Management 2
Process Manufacturing Regulatory Management 2
Treasury 2
Shipping Execution 2
Warehouse Management 2
Payables 2
E-Business Tax 2
Install Base 2
Federal Financials 2
Assets 2
Process Manufacturing Systems 2
Process Manufacturing Inventory 1
Property Manager 1
XML Gateway 1
Shop Floor Management 1
Application Object Library 1
Manufacturing Execution System for Process Manufacturing 1
Collections 1
Regional Localizations 1
Oracle Telecommunications Billing Integrator 1
Purchasing 1

SQL>select r11a.application_name
  2       , count(r11f.user_form_name) deleted_forms
  3    from r11_application_tl r11a join r11_form_tl r11f
  4         using (application_id)
  5   where not exists
  6         (
  7          select application_id
  8               , form_id
  9            from r12_form_tl r12f
 10           where r12f.application_id = application_id
 11             and r11f.form_id = r12f.form_id
 12         )
 13  group by r11a.application_name
 14  order by 2 desc
 15  /
APPLICATION_NAME DELETED_FORMS
Public Sector Budgeting 7
Project Contracts 4
Grants Accounting 3
Quality 3
Financial Aid 3
Common Modules-AK 1

Profile Options

Summary data for new and removed profile options, with additional information here. Some profile options marked obsolete as well, but if there were any renamed, either I didn't run the query or the results weren't very interesting:

SQL>select count(distinct application_id) affected_apps
  2  	  , count(1) new_options
  3    from r12_profile_options r12
  4   where not exists
  5  	    (
  6  	     select 1
  7  	       from r11_profile_options r11
  8  	      where r12.application_id = r11.application_id
  9  		and r12.profile_option_id = r11.profile_option_id
 10  	    )
 11  /
AFFECTED_APPS NEW_OPTIONS
115 963

SQL>select count(distinct application_id) affected_apps
  2  	  , count(1) removed_options
  3    from r11_profile_options r11
  4   where not exists
  5  	    (
  6  	     select 1
  7  	       from r12_profile_options r12
  8  	      where r12.application_id = r11.application_id
  9  		and r12.profile_option_id = r11.profile_option_id
 10  	    )
 11  /
AFFECTED_APPS REMOVED_OPTIONS
32 260

SQL>select application_short_name
  2       , user_profile_option_name obsolete_option
  3    from r12_profile_options_tl
  4         join r12_profile_options
  5         using (profile_option_name)
  6         join r12_application
  7         using (application_id)
  8   where regexp_like(user_profile_option_name,'obsolete','i')
  9   order by 1
 10  /
APPLICATION_SHORT_NAME OBSOLETE_OPTION
AK AK: Loaders input directory - Obsolete
AK AK: Loaders output directory - Obsolete
AR HZ: Report Error on Obsolete Columns
CS Knowledge: OBSOLETED PROFILE - CS_KB_NEAR_REALTIME_INDEXIN
CSS OBSOLETE: Automated Escalation Task Owner Role
CSS OBSOLETE: Automated Escalation Task Assignee Role
CSS OBSOLETE: Automated Escalation Task Template Name
CSS OBSOLETE: Automated Escalation Notification Role
CSS OBSOLETE: Default Notification Condition
CSS OBSOLETE: Knowledge Base Status
CSS OBSOLETE: Knowledge Base Set Type
CSS OBSOLETE: Product Reporting Category Set
CSS OBSOLETE: Platform Category Set
GMA GML: (this profile can be deleted) **obsolete**
ICX Obsolete
IGS IGS: JTF Resource - Obsolete
IGS IGS: JTF Result - Obsolete
IGS IGS: Degree Audit Organization Types --Obsolete
IGS IGS: Degree Audit Program Major Definitions --Obsolete
IGS IGS: Degree Audit Student List --Obsolete
IGS IGS: Degree Audit Student Alternate ID Type --Obsolete
IGS IGS: Degree Audit Debug Option --Obsolete
IGS IGS: Degree Audit Major Unit Set Category --Obsolete
IGS IGS: Degree Audit Preferred Address Usage --Obsolete
IGS IGS: Degree Audit What If Unit Set Titles --Obsolete
IGS IGS: Degree Audit Track Unit Set Category --Obsolete
IGS IGS: Degree Audit Institution Alternate Identifier Types --Obsolete
IGS IGS: Degree Audit Minor Unit Set Category --Obsolete
IGS IGS: JTF Outcome - Obsolete
IGS IGS: AMS Category Type - Obsolete
IGS IGS: AMS Category Sub Type - Obsolete
IGS IGS: JTF Reason - Obsolete
JL Obsolete in R12 - JLBR Automatically Populate Payment Batch Name
SQLGL GL AHE: Saving Allowed (Obsolete)

Database Objects

How many new database objects? A ton. How many deleted database objects? A lot, but less than a ton. Breakdown by application would probably be instructive, since many of those tables and packages are likely in support of new applications.

SQL>select r12.object_type
  2  	  , count(object_name) new_objects
  3    from r12_objects r12
  4   where not exists
  5  	    (
  6  	     select 1
  7  	       from r11_objects r11
  8  	      where r12.owner = r11.owner
  9  		and r12.object_name = r11.object_name
 10  		and r12.object_type = r11.object_type
 11  	     )
 12  group by r12.object_type
 13  order by 1
 14  /
OBJECT_TYPE NEW_OBJECTS
EVALUATION CONTEXT 2
INDEX 6901
INDEX PARTITION 497
INDEX SUBPARTITION 48
JAVA CLASS 28
LOB 271
LOB PARTITION 14
LOB SUBPARTITION 48
MATERIALIZED VIEW 104
PACKAGE 4687
PACKAGE BODY 4635
PROCEDURE 2
QUEUE 11
RULE 2
RULE SET 6
SEQUENCE 1393
SYNONYM 8801
TABLE 4562
TABLE PARTITION 1311
TABLE SUBPARTITION 48
TRIGGER 749
TYPE 402
TYPE BODY 76
VIEW 2903
XML SCHEMA 3
SQL>select r11.object_type
  2  	  , count(object_name) removed_objects
  3    from r11_objects r11
  4   where not exists
  5  	    (
  6  	     select 1
  7  	       from r12_objects r12
  8  	      where r12.owner = r11.owner
  9  		and r12.object_name = r11.object_name
 10  		and r12.object_type = r11.object_type
 11  	     )
 12  group by r11.object_type
 13  order by 1
 14  /
OBJECT_TYPE REMOVED_OBJECTS
INDEX 2577
INDEX PARTITION 48
JAVA CLASS 296
JAVA RESOURCE 39
LOB 119
MATERIALIZED VIEW 9
PACKAGE 2279
PACKAGE BODY 2237
PROCEDURE 1
QUEUE 6
SEQUENCE 282
SYNONYM 1326
TABLE 922
TABLE PARTITION 12
TRIGGER 322
TYPE 14
VIEW 2593

Friday mumblings: VanOUG, 11gR2, and EBS

At the first meeting of the newly-reconstituted Vancouver Oracle Users Group this past week, we were treated to three great presentations by Caleb Small and Dan Morgan. They've made the content of their presentations available on the VanOUG web site (these links go to PDFs, if that sort of thing bugs you, consider yourself warned):

I'm not going to go into a full recap of the presentations, but they were all full of really cool information. This post is an attempt to collect some of my mental notes, mostly cast in the context of one of my favorite topics, Oracle Applications.

11gR2 HA Best Practices

Caleb's presentation was very thorough and well-constructed. Dan gave him grief for boring the audience, but I think there was just so much new content to absorb that people were too busy processing to ask many questions on the fly. ;) Here are some one-liners from my notebook (anything that looks like an opinion is my commentary/interpretation, not Caleb's):

  • Lots more "moving parts" in 11gR2 Grid Infrastructure, clear "separation of duties" across three privileged OS accounts.
  • Service startup order is a little different now
  • Cluster status utilities show a lot more information, but need to learn to not rely upon crsstat as much
  • Proper networking configuration of 11gR2 GI not for the faint of heart. ;-)
  • Increased memory requirements will make this tougher to virtualize; I'm going to need a bigger laptop.
  • ACFS looks interesting; I wonder if it will be a valid option for an (shared application tier filesystem) for Oracle Applications. (Turns out the answer is "not currently planned," based on this exchange I had w/ Steven Chan on his blog later in the week).

11g New Features

There's a lot of really neat stuff going on in this presentation. I'd like to call out small nugget that, while far from the most important, is still pretty interesting on the surface: "deferred segment creation." When a table is created, no extents are actually allocated until rows are inserted. Seems like an odd feature, but one touted benefit is for large ERP systems like SAP and Oracle Applications, where lots of tables are created that may never be used, depending on what products are implemented. Those thousands of initial extents can certainly add up to real storage, and a more cluttered data dictionary. I can't speak to SAP implementations, but I don't see it as a huge win for EBS customers, given that:

  1. This feature is available only when tables are created, which means the benefit will only really be available when Oracle starts shipping Oracle Applications install media with an 11gR2 database. Anyone upgrading to the 11gR2 database will still be stuck with those empty extents.
  2. Given the overall footprint of an EBS database, the storage savings isn't such a big deal. For example, here's the potential savings from eliminating "empty" tables from an R12 Vision database:
      SYSTEM@R12VIS(11.1.0.7)>select sum(bytes)/1024/1024 potential_savings
    2  from dba_segments s
    3  where exists (select table_name
    4                  from dba_tables
    5                 where num_rows = 0
    6                   and table_name = s.segment_name
    7               )
    8  /
    
    POTENTIAL_SAVINGS
    -----------------
    3850.36719
    

    3.5(ish) GB out of 200GB is okay, I guess, but not a huge deal for a system that's only going to keep growing. FWIW, I'm going to wave my hands and pretend that the fact that a Vision database has way more populated tables than a "fresh-install" EBS database is balanced by the fact that my quick query doesn't account for the possibility that table stats are stale and some of those tables are actually populated. ;-)

Of course, it's possible that I'm missing the point. It wouldn't be the first time! Maybe it really comes down more to a less-cluttered data dictionary. I mean, it can't be about tablespace fragmentation, since we're not supposed to care about that anymore, right?

Edition Based Redefinition (EBR)

This seemed like an interesting feature when I first heard about it last autumn, but I'll confess that I didn't quite comprehend the power of EBR until seeing Dan's demo (parts 1, 2, and 3 are on his Morgan's Library site, with part 4 still in the works). Setting aside the obvious benefits for home-grown applications, the potential benefits in an Oracle Applications environment are huge. Consider:

  1. There's already an option to create a staged Applications System to shorten patch downtime windows, allowing administrators to run the "copy" and "generate" portions of large EBS patches prior to applying the patch to production. With EBR, it could be possible to stage the "database" portion of a patch as well, and switch to a new default edition at patch time. You'd probably still want to do the database staging at a quiet time in the database, of course, but daring souls could accomplish "almost-no-downtime" patching if EBR were worked into the Oracle Applications patching framework. Wicked.
  2. EBR might even make it possible to truly have EBS patches that could be rolled back. The current patching process already backs up files that are replaced. Thoughtful application of cross-edition triggers might make it possible to revert to a previous edition without loss of data if a patch needs to be backed out. Granted, the process would have to be demonstrated to be pretty bullet-proof before I'd try it in production, but it could save restoring test and dev systems from backup in the event that a patch doesn't work out as expected.

Just as I might be missing the point about deferred segment creation's advantages in EBS, I might be guilty of over-extended enthusiasm with respect to edition based redefinition. Or maybe I've decided to turn this into a science fiction blog. ;-) It's sure to be far more complicated to implement EBR in an Oracle Applications context than I'm implying above, and this is only speculation on my part, not anything that's actually promised by Oracle. Still, a nerd can dream...

Thanks again to Caleb and Dan for the great presentations, and for your continued support in getting the user group launched!

Vancouver Oracle Users Group (VanOUG) meeting set for 9 March

A while ago, I wrote about the (re)formation of the Vancouver Oracle Users Group (VanOUG). Wheels are now in motion to make this a reality; the first meeting has been scheduled for 9 March, 2010, conveniently after all of the Olympic hullabaloo. I received the following message recently with details about the agenda and meeting location, and I'm sharing in case you aren't already on the 100+-member mailing list. If you're a Vancouver-area Oracle professional in search of an Oracle user group, please make space in your schedule to attend this meeting. As noted in the meeting announcement, you will need to register prior to the meeting so that security at the site knows to expect you. Visit the VanOUG events page to register.

Disclosure/disclaimer: I don't represent VanOUG; I'm just an interested member trying to get the word out.

Thanks to the overwhelming response from the local Oracle community, we
are moving forward with the initial meeting of the Vancouver Group on
Tuesday March 9, 2010. Over 120 people have already signed up, and many
have indicated willingness to participate as directors and sponsors of the
group.

Dan Morgan and Caleb Small will chair this initial meeting, and provide
informative presentations on Oracle 11gR2 new features and best practices
including RAC and ASM. Unilogik Systems, Inc. is the meeting sponsor and
will provide a light dinner of pizza, pop and juice.

Following the networking and presentations, an organizational meeting will
be held for those that wish to be involved in the group's leadership. The
future direction of the group will be discussed at this meeting.

Please check the VANOUG.ORG website for full details.

DATE: Tuesday March 9, 2010
TIME: 5:00pm - 8:00pm
LOCATION:
Okanagan Room at BC Liquor Distribution Branch (BC LDB)
3200 East Broadway (Rupert and Broadway)
Parking is located on the East side of the Distribution Centre

TO REGISTER: simply reply to this email with your request

LDB Security requires attendee list before the meeting so you MUST
register in advance!

AGENDA:
5:00 Networking and light dinner
5:30 Presentation - Daniel Morgan (see below)
6:15 Break (and a word from our sponsor)
6:30 Presentation - Caleb Small (see below)
7:15 Discussion of group leadership and future direction

11g NEW FEATURES YOU WON'T HEAR ABOUT FROM ORACLE, Daniel Morgan

We know Oracle will tell us some things about each new release of their
flagship database ... but not everything we need to know.

At our first official meeting ACE Director Daniel Morgan will live demo,
in SQL*Plus many of the most important new 11gR1 and 11gR2 features and
give us source code for the demos.

11gR2 HIGH AVAILABILITY BEST PRACTICES, Caleb Small

11gR2 brings significant changes to Oracle RAC and Clusterware, now called
Grid Infrastructure. It also introduces ACFS, which stands for ASM Cluster
File System, and a completely different approach to handling the OCR and
Voting Disk. Other changes include the new Single Client Access Name
(SCAN) IP, a new required grid user, Cluster Time Synchronization Service,
Grid Naming Service, and some very interesting network configuration
requirements.

Caleb is a senior consultant, mentor and educator responsible for numerous
production RAC installations. Come and hear about theses changes and new
features from a completely practical perspective.

32-bit to 64-bit database migration tips: OLAP upgrade

A while ago, I had the opportunity to migrate an E-Business Suite database (Apps version 12.0.4, database version 10.2.0.4) from 32-bit Linux to 64-bit Linux. It's a straightforward process, outlined in My Oracle Support Note 471566.1: Migrating Oracle E-Business Suite R12 from Linux 32-bit to Linux 64-bit. Performing one of the critical migration steps, upgrading OLAP analytical workspaces (AWs), requires some careful reading, starting with the primary migration document for the database tier: Note 456197.1: Using Oracle E-Business Suite Release 12 with a Database Tier Only Platform on Oracle 10g Release 2. This document directs you to Note 352306.1: Upgrading OLAP from 32 to 64 bits, which covers the migration process for OLAP workspaces: export and delete from the the 32-bit system, then recreate on the 64-bit system and import the contents. The remainder of this blog post includes some embellishment of those four steps, from my migration notes. Examples were recreated on my test database; please don't look for these workspace names in an actual EBS database.

Please note that I'm by no means an OLAP expert; if you have your own observations or experiences to share, including corrections to any errors I might have made, please leave a comment. The last thing I want to do is spread misinformation! And, as always, remember: test systems exist for a reason, and instructions from Oracle Support should trump anything you read in this blog entry :-)

"No objects to export" error when exporting AWs

The export process is explained thoroughly in Note 352306.1. You may encounter the following error, however, when attempting to export an empty workspace:

BEGIN dbms_aw.execute('export all to eif file ''EXPORT_DIR/AWTEST.eif'''); END;
*
ERROR at line 1:
ORA-33390: There are no objects to export.
ORA-06512: at "SYS.DBMS_AW", line 93
ORA-06512: at "SYS.DBMS_AW", line 122
ORA-06512: at line 1

An export file will not be created, since there's no data in the workspace. Nonetheless, you will still need to recreate the AW in the 64-bit database, which leads us to the next section...

Before deleting AWs

In addition to gathering the OLAP workspace's name, schema, and tablespace, make sure that you make a note of how the AW is partitioned. This will allow you to more faithfully reconstruct the AW in the 64-bit database. Again, the basics can be found in Note 352306.1, except for a discussion of workspace partitioning. According to the documentation for DBMS_AW.AW_CREATE, by default, analytic workspaces are created with 8 partitions. Querying dba_segments seemed to tell a different story:

SYSTEM@mactest(10.2.0.4)>select segment_name
2    , segment_type
3    , count(*)
4   from dba_segments
5   where segment_name= 'AW$TESTDEFAULT'
6   group by segment_name
7   , segment_type;

SEGMENT_NAME                   SEGMENT_TYPE           COUNT(*)
------------------------------ -------------------- ----------
AW$TESTDEFAULT                 TABLE SUBPARTITION           16

This initially confused me, until I found that the table created for the default workspace is actually comprised of two partitions, each comprised of 8 subpartitions. Apparently, "partition" means different things to different people:

SYSTEM@mactest(10.2.0.4)>select table_name
2  , partition_name
3  , subpartition_count sub
4  from all_tab_partitions
5  where table_name = 'AW$TESTDEFAULT';

TABLE_NAME           PARTITION_NAME        SUB
-------------------- -------------- ----------
AW$TESTDEFAULT       PTN1                    8
AW$TESTDEFAULT       PTNN                    8

So, before you delete the AWs in the 32-bit database, be sure to consult the data dictionary. In most cases, you'll probably see segment count of 16 in dba_segments (implying a default partitioning scheme). But there are exceptions...

There's always one goofball

One of those exceptions came when my query to get a count of AW segments returned a 1. Naturally, I was expecting an even number, so this came as a surprise. At first, I thought this might be a special case when specifying partnum=>1 when creating the workspace:

SYSTEM@mactest(10.2.0.4)>exec dbms_aw.aw_create('JPTEST.TEST1PART','USERS',1);
PL/SQL procedure successfully completed.

SYSTEM@mactest(10.2.0.4)>select segment_name
2  , segment_type
3  ,count(*)
4  from dba_segments
5  where segment_name = 'AW$TEST1PART'
6  group by segment_name
7  , segment_type
8  /

SEGMENT_NAME                   SEGMENT_TYPE           COUNT(*)
------------------------------ -------------------- ----------
AW$TEST1PART                   TABLE SUBPARTITION            2

Then it occurred to me that zero is also a number... ;-)

SYSTEM@mactest(10.2.0.4)>exec dbms_aw.aw_create('JPTEST.TEST0PART','USERS',0);
PL/SQL procedure successfully completed.

SYSTEM@mactest(10.2.0.4)>select segment_name
2  , segment_type
3  ,count(*)
4  from dba_segments
5  where segment_name = 'AW$TEST0PART'
6  group by segment_type
7  , segment_name
8  /

SEGMENT_NAME                   SEGMENT_TYPE           COUNT(*)
------------------------------ -------------------- ----------
AW$TEST0PART                   TABLE                         1

Please recall: Note 352306.1 recommends using the Analytic Workspace Manager (AWM) tool to recreate the AWs in the 64-bit database. If you want to create the AWs manually, I suggest engaging with Oracle Support to get their approval. The preceding examples are provided only for illustration of what's going on when the AW is created.

Importing AWs

I don't really have much to add here, other than:

  1. If you had any empty AWs in the 32-bit system, you won't have anything to import for those workspaces, though hopefully you recreated them in the 64-bit system
  2. Isn't this process the sort of thing that cries out to be scripted? Would I really resort to such cheap, obvious devices to foreshadow my next post? I would indeed!

Keeping OPatch up-to-date: an object lesson

I just did something silly while applying the January 2010 PSU to an 11gR1 ORACLE_HOME, and thought I'd share, in case someone else is Googling for the error message.

[oracle@dbserv patches]$ cd 9209238
[oracle@dbserv 9209238]$ opatch apply

Invoking OPatch 11.1.0.6.2
Oracle Interim Patch Installer version 11.1.0.6.2
Copyright (c) 2007, Oracle Corporation. All rights reserved.

(some OPatch output snipped)

ApplySession failed: Patch ID is null.
System intact, OPatch will not attempt to restore the system

OPatch failed with error code 73

A closer look at the installation prereqs reveals the following statement: "You must use the OPatch utility version 11.1.0.6.7 or later," which I confess that I missed the first time around. D'oh. After installing the latest version of OPatch, the "opatch apply" command worked as expected.

Lessons reinforced:

  1. Even if you think you're up-to-date on prerequisites, triple-checking is a good idea
  2. Even humble tools like the OPatch utility can change pretty frequently
  3. Test systems are useful for testing your patching process, not just patches themselves

(Everyone join in, now: "Thanks, Mr. Obvious, you're a life saver!") :-P

Accessing EBS R12 forms when the HTML interface is unavailable

Astute readers of my last post may have taken a short break from the riveting drama to wonder, "hey, wait, if you couldn't access the EBS home page, how did you change the profile option to fix the EBS home page?" Well, okay, if you've been using Oracle Apps for a while, this is probably not a mystery, but I might have some EBS learners onboard thanks to the ORACLENERD series. For the sake of completeness, I feel compelled to offer this tidbit:

To launch the E-Business Suite R12 Forms interface directly, use the URL http://yourhost:port/forms/frmservlet. This will present a small login window where you can provide your EBS credentials. After that, you will need to select your responsibility from a list of values, and the appropriate forms menu will appear. A few additional things to consider:

  • This method of accessing Forms is primarily intended to verify that the Forms server is functioning properly. Oracle does not recommend (or support) direct access to Forms as a normal mode of operation. Use sparingly, as a last resort.
  • You need to supply login credentials for a user that has permission to authenticate locally to Oracle Applications. This is not normally a big deal, since it's the default configuration, but if your EBS instance is integrated with Single Sign-On, be aware that you can't connect to Forms directly with an SSO-only account.
  • If your HTML interface is broken, as mine was, selecting an option from the Forms-based menu that would normally launch the HTML interface is likely to produce disappointing results.

Despite Oracle's warning to not use the Forms interface this way without specific guidance from Support, it seemed far better than writing an update statement against the FND_PROFILE_OPTION_VALUES table at 1AM. ;-)

Resolving an EBS login problem

I was asked to investigate an EBS login page failure on a production system last night. Well, actually, I was asked if I had any crazy ideas, since someone else was already working the problem with Oracle Support. Management thought a fresh pair of eyes might help, as the East Coast eyes that had been looking were getting tired. The solution turned out to be somewhat obscure, but I'm throwing it up here in case it helps a desperate, flailing Googler in the future.

Symptoms and observations

  • R12 landing page (Navigator) was returning the dreaded, generic "You have encountered an unexpected error. Please contact the System Administrator for assistance" error.
  • As far as anyone knew, there hadn't been any changes, patches, or service restarts; the system had just spontaneously stopped working. (Don't you just hate that?)
  • SSO and non-SSO logins were authenticating users, but no work could be done because the EBS home page was inaccessible.
  • Web services had already been restarted, to no avail
  • AOL/J diagnostic tests were passing, implying that this wasn't a systemic Java problem

Investigation and resolution

My first thought was that there were corrupt JSPs (probably because I had my last blog post on the brain), but the application server log files were not consistent with that problem. Then I noticed that the other troubleshooters had activated FND Diagnostics, which had the benefit of adding a "Click here for exception details" link. Knowing that this often leads to a mostly-unintelligible (to me, anyway) Java stack trace, I didn't have high hopes, but I had a look. Surprisingly, I found something interesting:

java.lang.NumberFormatException: For input string: "200000000000"
   at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
   at java.lang.Integer.parseInt(Integer.java:459)
   at java.lang.Integer.valueOf(Integer.java:553)
   at oracle.apps.fnd.framework.server.OAUtility.getProfileVoMaxFetchSize(OAUtility.java:245)

So, Java was having trouble chewing on a really large number, and it looks like it was getting that value from a system profile option. A quick look at recently-changed profile options (query here) revealed:

applmgr@prodsys:~> sqlplus apps @last_profile_changes
SQL*Plus: Release 10.1.0.5.0 - Production on Wed Jan 20 02:45:27 2010
Copyright (c) 1982, 2005, Oracle. All rights reserved.
Enter password:
Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Enter value for number_of_items: 4
Profile Option  Option Level  Value           Set on    Scoldee
--------------- ------------- --------------- --------- ---------------
FND: Diagnostic Site          Y               20-JAN-10 SYSADMIN
s
GL Journals: La User          LESS            19-JAN-10 XXXXXX
st Find Window
State
FND: View Objec Site          200000000000    19-JAN-10 XXXXXX
t Max Fetch Siz
e
GL Journals: La User          LESS            19-JAN-10 XXXXXXXX
st Find Window
State

As is often the case, the key part of the phrase, "no changes as far as anyone knew" was the last five words. ;-) That number (200000000000) is several orders of magnitudes larger than typical values of "FND: View Object Max Fetch Size," and after resetting it to something more sane, the system became usable again. Whew!

Compiling JSPs in EBS? Try being selective first.

From time to time, the cached JSP class files used by the E-Business Suite web server can become missing or invalid, resulting in blank pages or "page not found" errors in the EBS HTML interface, or pages not displaying expected behavior. Most often, this occurs after patching or cloning, and the standard advice is to manually recompile all JSPs, either via the adadmin utility or by directly invoking the ojspCompile.pl script from the command line:

[applvis@londo ~]$ $FND_TOP/patch/115/bin/ojspCompile.pl --compile --flush -p 2
logfile set: /u01/ebs/R12VIS/inst/apps/R12VIS_londo/logs/appl/rgf/ojsp/ojspc_error.log
starting...(compiling all)
using 10i internal ojsp ver: 10
synchronizing dependency file:
loading deplist...8048
enumerating jsps...8048
updating dependency...0
initializing compilation:
eliminating children...5979 (-2069)
translating and compiling:
translating jsps...<b>5979/5979 in 8m16s</b>
compiling jsps...<b>5979/5979 in 11m14s</b>
Finished!

20 minutes to compile 6000 JSPs? Even if your system is faster than mine (which it probably is), that's a lot of time and effort for what may be just a few files. If you already know which JSPs are broken, you can save time by using the -s flag to the osjpCompile.pl script to specify just those files.

For example, in early versions of Oracle Applications Release 12, the initial login page was not always created correctly, resulting in failures during post-upgrade validation tests (see My Oracle Support Doc 435550.1).  As far as I know, this condition has been corrected in Release 12.1, and may also have been corrected in 12.0.4, but when we upgraded to 12.0.3, I was able to save 15-20 minutes during my downtime window by selectively compiling the offending JSPs:

[applvis@londo ~]$ $FND_TOP/patch/115/bin/ojspCompile.pl --compile -s 'RF.jsp,AppsLocalLogin.jsp' --flush -p 2
logfile set: /u01/ebs/R12VIS/inst/apps/R12VIS_londo/logs/appl/rgf/ojsp/ojspc_error.log
starting...(compiling all)
using 10i internal ojsp ver: 10
quick compile:
files to compile...2
translating and compiling:
translating jsps...<b>2/2 in 1s</b>
compiling jsps...<b>2/2 in 3s</b>
Finished!

I wish I could say I got to sleep that much earlier, but upgrade weekends don't always work that way. ;-) Still, I was glad to have the time savings.

This isn't always a viable option, of course. Depending on your circumstances, there may be so many JSPs in need of recompilation that trying to be selective isn't worth the effort. If you can see from the application server log files that only a few JSPs are failing, however, then you might be able to save yourself some time, and your users some disruption, by only compiling the files that are necessary to fix the problem.

Hope everyone out there is enjoying a bit of holiday-season relaxation, and that 2010 brings good things. Happy New Year!