Tyler Muth’s Blog

Technology with a focus on Oracle, Application Express and Linux

The Best Unix-like Windows Command Prompt

Posted by Tyler Muth on November 30, 2009

If you follow this blog you know that my laptop is Windows 7 but I live my life in Linux Servers.  As such, I’m a big fan of the bash shell.  I’ve been running Cygwin on my laptops for as long as I can remember to get all of my favorite Linux commands on Windows.  However, the Windows Command Prompt has always felt a little clunky.  I’ve been using Console2 for a while, which I really like but when you combine it with Cygwin on Windows 7, it hangs a lot which is NOT what I want from a shell. I love the feel of Putty when ssh-ing to a Linux / Unix machine, but something about running sshd on my laptop felt like overkill.

Then I discovered PuttyCyg. Essentially it’s a one-off port of Putty that in addition to ssh, lets you connect to your local installation of Cygwin.  Make sure you read the FAQ on that page.  Note the additional option highlighted in yellow:

The main quirk I ran into was with sqlplus and rman.  Just like on Linux / Unix, it lacks the up-arrow functionality which I can’t live without.  So, make sure you also install rlwrap when installing Cygwin.  Then, in your ~/.bashrc file add the following aliases:

alias sqlplus='rlwrap sqlplus'
alias rman='rlwrap rman'
To summarize:
  1. Download and install Cygwin.  Make sure you include the rlwrap package.
  2. Create the 2 aliases in your ~/.bashrc file so sqlplus and RMAN use rlwrap.
  3. Download and unzip PuttyCyg.
  4. Optionally create a shortcut to PuttyCyg in your start menu with the following syntax (substituting your actual directories):
"C:\Program Files\puttycyg-20071202\putty.exe" -cygterm -

Now when you run PuttyCyg you have a Putty client connected to your local Windows machine.  Command Prompt bliss…

Posted in Uncategorized | Tagged: , , | 3 Comments »

Logger 1.2.0 Released

Posted by Tyler Muth on November 23, 2009

I just posted the latest version of logger, my PL/SQL logging utility to https://logger.samplecode.oracle.com/.  There are a number of new features as well as bug fixes, many of which were suggested by other people in the comments of my previous blog post on logger.  You can view the new features and fixes in the “Change Log” section at the bottom of the logger home page. Thanks again for your feedback.

On a related note, to post to the discussion forums for logger you have to request the role of “observer” for the project.  I’ve set this to automatically approve everyone so it’s instantaneous.  It’s not my choice and I’m trying to get this speed-bump removed, but for now it’s just the way it is… sorry.  I have an Announcements forum which is locked-down so only I can post to.  My thought was that if you were interested you could subscribe to that Discussion forum to receive emails when a new version is released or a major bug is identified, yet not get a bunch of “noise” from other people posting questions.

Posted in Uncategorized | 1 Comment »

Oracle 11g DB on Windows 7 – Success

Posted by Tyler Muth on November 15, 2009

Short Version

Tried to install Oracle Database 11.1.0.7 32-bit on Windows 7 32-bit. Failed at Network Configuration section. I found that in my case, the issue was that I installed in a path with spaces in it (c:\program files\oracle\….). Un-installed. Reinstalled in c:\oracle\product\11.1.0.7. Success!!!

Longer Version

OK, I admit it, I’ve been running Windows 7 since the first beta was released and I love it. Yes, my blog title has “Linux” in it, and I love Linux too, but I’ve had a few issues with Linux on a laptop in front of customers and that’s something I can’t afford to do. See, my laptop needs to be really agile. I plug it into a different networks, projectors, multiple monitors, I put a Verizon Air card in it, I plug lots of peripherals into it. Linux has failed me in each of those areas on more than one occasion. On the other hand, the fact that Linux is (in my mind) very consistent, stable, and almost completely unwilling to change is EXACTLY why I LOVE it for servers. Every “system” I currently manage is running Linux (which I chose from the start). It’s my appliance OS. I have scripted, nightly RMAN backups and auto-start scripts so these systems are 99% hands off. The only time they’ve been down is when one of pseudo-data centers has gone completely dark for network and power upgrades. They’re all internal, so I’m a bit more relaxed about OS patches, which means I basically ssh into them once every few months to apply patches. That’s it. OK, that was waaaaaayyyyy too much info to qualify why I’m running Windows on my laptop. On a related note, hey Apple, I’m happy to blog about my experience switching to say, a MacBook Pro….

Anyway, I got a bit off topic. Sorry. So I’m running Windows 7 RC1, build 7100, 32-bit. I downloaded the Windows 2008 Server version of Oracle, v. 11.1.0.7 since Server 2k8 is a similar code base to Windows 7. After I got stuck on the network configuration, I checked the install logs, but there wasn’t anything helpful there. So, I ran netca from the command-line and got error that said something about “error at c:\program blah blah blah”. It was obvious that it truncated the path at the first space. So, once I installed in a path with no spaces, everything went fine.

OHS 10.1.3.3 Had Issues Too

I downloaded Oracle HTTP Server 10.1.3.3 as well since that’s my preferred APEX configuration (no, I haven’t tried the new listener on Windows 7 yet, just Linux). The installation got stuck on the configuration section, so I eventually killed the process. However, it appeared that everything installed correctly so I created a DAD, ran opmnctl startall, and presto, APEX was ready to go. OK, I left out the part about dropping the default 11.1 APEX version and installing APEX 3.2.1, but that’s not really important here.

Hopefully this helps someone out there. I’ll take a look and see if there are bugs filed on these issues and file them if I don’t find anything. Windows 7 isn’t supported by Oracle yet, but it can’t hurt to let them know…

Posted in 11g, Oracle, Windows 7 | Leave a Comment »

Logger, A PL/SQL Logging and Debugging Utility

Posted by Tyler Muth on November 3, 2009

I’ve been gradually building out a logging utility for PL/SQL over the last year or so. It’s been a huge help on some complicated projects, especially in APEX Applications with a lot of AJAX. I’m sure most people reading this have been stuck on a problem, created a logging table, and sprinkled a few inserts in their code to see what’s going on and when. It’s amazing how much faster you resolve these issues if the table is already there and the inserts are now just a short procedure call. Anyone that’s ever used Firebug probably can’t imagine it without console.log() or console.dir(). Yes, you can use dbms_output.put_line or htp.p, but those fall over pretty quick in a web environment with HTTP Posts or worse, a lot of AJAX Posts / Gets. Additionally, if you’re a Tom Kyte groupie, you’ve probably heard him talk about the value of instrumentation more than once.

Now that you know the “why”, lets talk about what Logger is.  It’s just a couple of tables and a PL/SQL package that make all of this easier for you.  I’ll give you a brief summary of features here, but for full details you should go to the project page at https://logger.samplecode.oracle.com.  So, the super short demo is:

logger@orcl> exec logger.log('hello world');

PL/SQL procedure successfully completed.

logger@orcl> select * from logger_logs_terse;

     ID LOGGER_LEVEL TIME_AGO             TEXT
------- ------------ -------------------- ---------------------
     48           16 35 seconds ago       hello world

Features Include:

  • Easily Enable / Disable all logging
  • Minimal Overhead.  There’s even a NO-OP version of the package that you can use for production if you’re really paranoid. It’s just a stub of the logger package that doesn’t write to or depend on any tables (or any other objects).
  • Automatically purges debug messages older than 7 days.  This is completely configurable
  • Ability to time blocks of code
  • Log sys_context(‘userenv’,”) variables
  • Log APEX Item Names and Values
  • Automatically captures key session information such as module, action, client_identifier including APEX session ID, timestamp, call stack.

I’d like to thank all of the community members that tested and contributed ideas for logger including:

I would love to get more feedback from the community as well.  You can either comment here, or use one of the 3 discussion forums I created for logger listed on the project page just above the download link.

The Fastest Way to Store / Retrieve a Cross Session Variable

Posted in APEX, Oracle, PLSQL | Tagged: , , | 25 Comments »

The Fastest Way to Store / Retrieve a Cross Session Variable

Posted by Tyler Muth on October 20, 2009

I’m working on a logging / debugging utility in my spare time that allows a developer to set the logging level. Currently I’m using Conditional Compilation to completely remove all logging code as this was the fastest way I could think of to do it. After talking it over with Tom Kyte, he brought up a very important point that since this technique relies on recompiling the logging package, this will invalidate any code that calls it which could be undesirable (potentially disastrous) in a production environment. His solution? Use Function Result Cache if the logger is installed in an 11g Database which should be plenty fast and not require recompilation to change the logging level.

If I’ve learned anything from Tom it’s the concept of “prove it”, so I set out to find the quickest way to store a cross session variable that will be heavily used in an application. In addition, was function result cache really fast enough given the huge benefit of the solution?

Update: John Scott posted a great suggestion in the comments of using a Global Application Context as there is no Database version / edition dependency issue and it does not require recompilation.  I added it to the test and it appears to be the new winner!  Thanks John!

I’ll post the results first since the test code is a bit lengthy. Each result is the time it took to check the variable 100,000 times.:

----------------------------------------------------------------
Simple Loop:                                     0.00247 seconds
No-op Procedure Call:                            0.06028 seconds
Procedure Call with simple IF-THEN:              0.05350 seconds
Procedure Call with Package Globals IF-THEN:     0.05019 seconds
Procedure with standard select:                  8.50581 seconds
Procedure with Query Result Cache:               9.50794 seconds
Function Result Cache:                           0.75690 seconds
Package Globals:                                 0.06700 seconds
Global Application Context:                      0.33737 seconds

As you can see, Function Result Cache is about 14 times slower than the current solution which results in a NO OP.  However, if we step back and look at this objectively, it’s still REALLY fast and as Tom said, “faster than fast enough”.  If we divide 0.7 by 100,000 we get the time per call to this function which is 0.000007.  Lets say we’re using this in an APEX environment and we call the logging package 100 times per page view which in my opinion is very generous.  Lets also assume our average page view time is 0.3 seconds.   (0.0007 / 0.3 ) * 100 = 0.23% overhead added to our application. In my opinion, 5% overhead would be a fair price to pay for an application that is instrumented with debug code.  This way when (not if) something goes wrong, the time to diagnose the problem should be substantially less. 0.23% isn’t even worth talking about.  The benefit of instrumentation FAR outweighs the overhead.

Here’s my test script (11g Database only):

set serveroutput on

-- grant create any context to user;

create or replace context test_global_ctx using set_global_ctx accessed globally;

create or replace function time_diff(
    p_start    in  timestamp,
    p_end      in  timestamp)
return varchar2
is
    l_return number;
begin
    l_return :=  extract(second from (p_end-p_start))+
           (extract(minute from (p_end-p_start))*60)+
           (extract(hour from (p_end-p_start))*60*60);

    return to_char(l_return,'9990D00000');
end time_diff;
/

drop table some_table;

create table some_table(
	object_name	varchar2(30),
	object_owner varchar2(30)
)
/

create unique index some_tab_index on some_table(object_name,object_owner)
/

insert into some_table
    select level object_name, level object_owner
      from dual
   connect by level <= 20;

begin
    dbms_stats.gather_table_stats(
        ownname => user,
        tabname  => 'SOME_TABLE',
        estimate_percent => 100);
end;
/

create or replace package globals_test
as

	g_one	constant varchar2(255)   := 'One';
	g_two	constant varchar2(255)   := 'Two';
	g_three	constant varchar2(255)   := 'Three';

end globals_test;
/
show errors

create or replace procedure test1
is
begin
	null;
end;
/

create or replace procedure test1_2
is
begin
	if 1 = 1 then
		null;
	end if;
end;
/

create or replace procedure test1_3
is
begin
	if globals_test.g_one = 'One' then
		null;
	end if;
end;
/

create or replace procedure test2(p_name in varchar2)
is
	l_owner varchar2(30);
begin
	select object_owner into l_owner from some_table where object_name = p_name;
end;
/

create or replace procedure test3(p_name in varchar2)
is
	l_owner varchar2(30);
begin
	for c1 in (select /*+ result_cache */ object_owner from some_table where object_name = p_name)
    loop
        l_owner := c1.object_owner;
    end loop; --c1
end;
/

create or replace function test4(p_name in varchar2)
	return varchar2
	result_cache
	relies_on(some_table)
is
	l_owner varchar2(30);
begin
	for c1 in (select object_owner from some_table where object_name = p_name)
    loop
        l_owner := c1.object_owner;
    end loop; --c1

	return l_owner;
end;
/

create or replace procedure test5
is
	l_dummy varchar2(30);
begin
	l_dummy := globals_test.g_one;
end;
/

create or replace procedure set_global_ctx(
    p_var   in varchar2)
is
begin
    dbms_session.set_context(
        namespace  => 'test_global_ctx',
        attribute  => 'foo',
        value      => p_var);
end;
/

accept DUMMY prompt "Ready to run tests which will take a while.  Press ENTER to continue..."
prompt
prompt  

declare
    l_start     timestamp;
	l_object_name	varchar2(30);
	l_return varchar2(30);
	l_loop_size	pls_integer := 100000;

    function format_title(p_title in varchar2)
    return varchar2
    is
    begin
        return rpad(p_title,45);
    end format_title;
begin
	l_start := current_timestamp;
	for i in 1..l_loop_size
	loop
		null;
	end loop; --i
	dbms_output.put_line('----------------------------------------------------------------');
	dbms_output.put_line(format_title('Simple Loop: ')||
                           time_diff(l_start,current_timestamp)|| ' seconds');

	l_start := current_timestamp;
	for i in 1..l_loop_size
	loop
		test1;
	end loop; --i
	dbms_output.put_line(format_title('No-op Procedure Call: ')||
                           time_diff(l_start,current_timestamp)|| ' seconds');

	l_start := current_timestamp;
	for i in 1..l_loop_size
	loop
		test1_2;
	end loop; --i
	dbms_output.put_line(format_title('Procedure Call with simple IF-THEN: ')||
                           time_diff(l_start,current_timestamp)|| ' seconds');

	l_start := current_timestamp;
	for i in 1..l_loop_size
	loop
		test1_3;
	end loop; --i
	dbms_output.put_line(format_title('Procedure Call with Package Globals IF-THEN: ')||
                           time_diff(l_start,current_timestamp)|| ' seconds');

	select object_name into l_object_name from some_table where rownum = 1;
	l_start := current_timestamp;
	for i in 1..l_loop_size
	loop
		test2(l_object_name);
	end loop; --i
	dbms_output.put_line(format_title('Procedure with standard select: ')||
                           time_diff(l_start,current_timestamp)|| ' seconds');

	l_start := current_timestamp;
	for i in 1..l_loop_size
	loop
		test3(l_object_name);
	end loop; --i
	dbms_output.put_line(format_title('Procedure with Query Result Cache: ')||
                           time_diff(l_start,current_timestamp)|| ' seconds');

	l_start := current_timestamp;
	for i in 1..l_loop_size
	loop
		l_return := test4(l_object_name);
	end loop; --i
	dbms_output.put_line(format_title('Function Result Cache: ')||
                           time_diff(l_start,current_timestamp)|| ' seconds');

	l_start := current_timestamp;
	for i in 1..l_loop_size
	loop
		test5;
	end loop; --i
	dbms_output.put_line(format_title('Package Globals: ')||
                           time_diff(l_start,current_timestamp)|| ' seconds');	

    set_global_ctx('bar');
    l_start := current_timestamp;
    for i in 1..l_loop_size
	loop
		l_return :=  sys_context('test_global_ctx using','foo');
	end loop; --i
	dbms_output.put_line(format_title('Global Application Context: ')||
                           time_diff(l_start,current_timestamp)|| ' seconds');
end;
/

Posted in Oracle, PLSQL | Tagged: , , | 19 Comments »

APEX “Application Process” Bookmarklet

Posted by Tyler Muth on October 12, 2009

If you’re an APEX developer and doing a lot of AJAX work, you probably spend a lot of time clicking between pages and the “Application Process” section of APEX.   In APEX 3.1 and 3.2 it takes 2 clicks on links that are on very different parts of the page.  Unless you do this a lot, you probably think I’m crazy for complaining about this, but if you are doing a lot of AJAX development, it’s enough to drive you insane.  I even kept a separate browser (Safari) open just for App Processes.

Solution:  I wrote a super simple bookmarklet that reduces this to one click.  Since WordPress.com is blocking my ability to post a link with JavaScript code in it, you’ll have to manually create a new bookmark on your web browsers bookmark toolbar using the following for the URL:

javascript:location.href="f?p=4000:4207:"+$v('pInstance')

Now, once you’ve logged into the APEX builder that bookmark will take you straight to the Application Process section using the same APEX session.

Posted in APEX, Application Express, Oracle | 2 Comments »

jApex – A jQuery Plugin for APEX

Posted by Tyler Muth on August 19, 2009

In a previous post I proclaimed that jQuery Selectors Will Change Your Life.  While working on an AJAX centric APEX project, I wanted to use jQuery selectors to post data from an APEX page to an application process so I wrote a jQuery plugin. Over the course of this project the plugin has grown into something that I think the community would find useful.  Essentially it serves the same purpose as Carl Backstrom’s htmldb_get() function, but adds the power of jQuery selectors.  Carl was actually the one that introduced me to jQuery, and I’m sure he would have written something similar, only much better and in half the time.

I think the best way to introduce it is with a few quick examples.  I have a full set of working examples on apex.oracle.com here, but lets start with some simple examples to give you an idea of how it works.

APEX Items

The following code sends every item on an APEX page to the application process “SOME_APP_PROCESS”. It will then popup an alert with the results from the application process. Note that we did not have to specify each item individually, the jQuery selector (documented here) grabs them all.

var options = {
 appProcess: 'SOME_APP_PROCESS',
 pageItems: $(':input'),
 success:
   function(data){
     alert(data);
 }
};

$.jApex.ajax(options);

If we want to send all items inside a div with ID “employeeDiv” and send the results to the Firebug console:

var options = {
 appProcess: 'SOME_APP_PROCESS',
 pageItems: $('#employeeDiv :input'),
 success:
   function(data){
     console.log(data);
 }
};

$.jApex.ajax(options);

Want to send the items P1_NAME, P1_EMAIL, P1_PHONE?

var options = {
 appProcess: 'SOME_APP_PROCESS',
 pageItems: $('#P1_NAME, #P1_EMAIL, #P1_PHONE'),
 success:
   function(data){
   console.log(data);
 }
};

$.jApex.ajax(options);

Other Features

  • You can also send data to the x01-x10 parameters.  There are several examples of this in my sample app.
  • I had already written code to support sending arrays to the f01-f50 parameters used by Tabular Forms.  I really don’t like Tabular Forms and rarely, if ever use them.  However, I figured someone would want / request this functionality so I enhanced it a bit to better support Tabular Forms.  Keep in mind this functionality has not been tested much, so use at your own risk.

Tips

  • $ is the alias for jQuery
  • jQuery plugins almost always have 1 parameter that is object.  Each property of the object is analogous to a traditional JavaScript (or for that matter PL/SQL) parameter.
  • Parameters  can be objects, arrays, scalars or even functions.  Most people are used to scalars, so passing a function in as parameter / property can really be confusing at first.

Download

You can download the jQuery plugin and the example APEX application here.

Posted in APEX, JavaScript / AJAX | Tagged: , , | 10 Comments »

“Pretty” Date Format Function

Posted by Tyler Muth on June 26, 2009

I’m not sure who originally wrote this function (probably Tom Kyte), but I needed it yesterday and couldn’t find it. Thankfully Chris Beck tracked it down in some other code I wrote.  I made a few enhancements, but the bulk of the function is the same.  The output is almost identical to the “SINCE” date format available in Application Express.  So, if you pass in a date in the past to this function, the result will be similar to “25 seconds ago”, “1 minute ago”, “5 months ago”, etc.

Function

create or replace function date_text_format (p_date in date)
return varchar2
as
	x	varchar2(255);
begin
	x := 	case
				when sysdate-p_date < 1/1440
					then round(24*60*60*(sysdate-p_date)) || ' seconds'
				when sysdate-p_date < 1/24
					then round(24*60*(sysdate-p_date)) || ' minutes'
				when sysdate-p_date < 1
					then round(24*(sysdate-p_date)) || ' hours'
				when sysdate-p_date < 14
					then trunc(sysdate-p_date) || ' days'
				$IF $$BRITISH $THEN
					when mod(trunc(sysdate-p_date),14) = 0
						then trunc(sysdate-p_date) / 14 || ' fortnights'
				$END
				when sysdate-p_date < 60
					then trunc((sysdate-p_date)/7) || ' weeks'
				when sysdate-p_date < 365
					then round(months_between(sysdate,p_date)) || ' months'
				else round(months_between(sysdate,p_date)/12,1) || ' years'
		   end;
	x:= regexp_replace(x,'(^1 [[:alnum:]]{4,10})s','\1');
	x:= x || ' ago';
	return x;
end date_text_format;
/

Examples

select date_text_format(sysdate - 3/86400) the_date from dual;
select date_text_format(sysdate - 5/1440) the_date from dual;
select date_text_format(sysdate - 1/24) the_date from dual;
select date_text_format(sysdate - 3.141549) the_date from dual;
select date_text_format(sysdate - 15) the_date from dual;
select date_text_format(sysdate - 120) the_date from dual;
select date_text_format(sysdate - 365) the_date from dual;
--------------------------------------------------------------------
3 seconds ago
5 minutes ago
1 hour ago
3 days ago
2 weeks ago
4 months ago
1 year ago

Posted in Oracle, PLSQL, Uncategorized | Tagged: | 10 Comments »

Octagonal Peg in a Hexagonal Hole (APEX Backward Compatibility)

Posted by Tyler Muth on June 4, 2009

I was going to title this post “Hacking away at an APEX 3.2 app until you can wedge it into a 3.1 instance”, but I shortened it to the current title.  This week I went to import an application I built in APEX 3.2 for an internal customer, only to find that their APEX instance was still on 3.1.  They support a ton of mission critical apps on that instance so upgrading wasn’t an option, no matter how hard I begged.  So, I began the tedious task of editing the export file until I was able to import it.

Just to be clear, this process is NOT SUPPORTED in any way, shape or form by Oracle or myself, so proceed with caution. DON’T EVEN THINK of calling support with issues introduced by this technique. If you start down this path, you are on your own! I’m posting this to try and help some of the more advanced developers in this community and I do not want to introduce a support nightmare for Oracle Support or the APEX Dev Team.

Import Hacking the Slow Way

I started by trying the import in SQL*Plus as it’s much faster and more informative than the web interface for repetitive imports.  The key things that change from version to version of APEX are the procedures and their parameters of WWV_FLOW_API.  Once I edited the SECURITY_GROUP_ID, SET_VERSION, and FLOW_ID (more on these later), I began the Import > Find Error > Edit File > Repeat sequence. One thing that really helps here is a text editor that supports split-screen, synchronized scrolling such as Notepad++ or UltraEdit.  Notepad++ screenshot here.  After a few minutes I came to the conclusion that there has to be a better way.

Import Hacking the Faster Way

I started by querying the ALL_ARGUMENTS view and saving the results in my own table:

create table apex_api_parameters as
	select '3.2' version, object_name,argument_name
	  from all_arguments
	 where package_name='WWV_FLOW_API'
	   and owner = 'APEX_030200'
/

I repeated this step in each database to get the WWV_FLOW_API procedures and parameters for APEX 3.2 and 3.1.  Now I can use SQL set operations to compare them:

select object_name
  from apex_api_parameters
 where version = '3.2'
 minus
select object_name
  from apex_api_parameters
 where version = '3.1'
with common_objects as (
			select object_name
			  from apex_api_parameters
			 where version = '3.2'
		 intersect
			select object_name
			  from apex_api_parameters
			 where version = '3.1')
 select p.object_name,p.argument_name
   from apex_api_parameters p,common_objects c
  where version = '3.2'
	and p.object_name = c.object_name
  minus
 select p.object_name, p.argument_name
   from apex_api_parameters p,common_objects c
  where version = '3.1'
    and p.object_name = c.object_name

Based on the results of the first query, I know the procedures in WWV_FLOW_API that exist in 3.2 but not in 3.1.  These almost always equate to new features.  If I were comparing 3.1 to 3.0 I would see the CREATE_WORKSHEET procedure which equates to interactive reports. The second query shows the parameters to procedures that exist in 3.2 but not in 3.1.

Step by Step Hacking

  1. Make a backup copy of the app you plan to edit.
  2. Using the APEX Application Builder in the newer (source) instance, edit the application to remove any major features that you know don’t exist in the older (target) instance, such as interactive reports.
  3. Export your application from the source instance.
  4. In the target instance, create a new, 1 page dummy application and export it.
  5. Use the SECURITY_GROUP_ID, SET_VERSION, and FLOW_ID from the dummy application in your actual application.
  6. Run my Parameter Diff application (below) and keep it open to use in the next two steps.
  7. Continue editing the application export file to remove any procedures that are not supported in the target instance.
  8. Now find all of the unsupported parameters for existing procedures and delete them.
  9. Test your import.  Repeat steps 7-9 if needed.

To make this process easier, I created an APEX app with all of the API parameters from 3.2, 3.1, 3.0, and 2.2.  You can see it in action here, or download it here.  Keep in mind the supporting objects to 8,000+ inserts, so it may take a minute or two to install.  Happy hacking!!!

Posted in APEX, Application Express, Oracle | Tagged: , , | 7 Comments »

Rope Memory

Posted by Tyler Muth on February 27, 2009

I watched the Discovery Science series “Moon Machines” a few weeks ago, as I’m pretty much obsessed with all things space or flying. In the “Navigation Computer” episode, there was a section about the memory they used for the Apollo machines that I found fascinating. They actually sent their programs off to a factory to have them woven into a “rope” of 1’s and 0’s!!!  This makes punch-cards look convenient.

Check out the video on YouTube from about 3:00 to 6:00 min:

Posted in Uncategorized | 5 Comments »