Skip to main content

· 4 min read
Adrian Png

1280 720 The Great Wall of China

Authentication is an essential component of any enterprise application. These days though, it isn't enough to protect your applications with only a username and password. These are easily stolen by key loggers, sniffing non-encrypted HTTP traffic, phishing, hacked Internet services and the list goes on. To make matters worse, many users have a poor habit of reusing passwords that thieves then use to penetrate other systems. I have had my fair share of that experience.

The question is, can we implement two-factor authentication (TFA) in Oracle Application Express (APEX)?

· 2 min read
Adrian Png

Salmon Run - Honour the Dead

Here's my first contribution to the annual ODC Appreciation Day that was initiated by Tim Hall three years ago.

The product feature that I'd like to pay special tribute to this year is Oracle Multimedia (OMM). By now, I believe most would have heard that OMM has been deprecated. Mike Dietrich made special mention of it in a blog post earlier this year, with some clarity as to exactly when we can expect to see this useful feature go away for good.

· 3 min read
Adrian Png

Screenshot of application demonstrating Face Detection API

At Kscope17, I presented a session on various techniques for capturing and manipulating images. For those of who attend either in-person or the follow-up webinar, you might recall I briefly talked about image recognition and how they can be integrated with an Oracle Application Express solution using third-party JavaScript libraries.

· 9 min read
Adrian Png

Photo by John Michael Thompson

It's not unusual for an established principal investigator (PI) to have desks and shelves full of books, journal articles, grant applications, graduate student theses etc. Often, they'd also have a mountain of such material in electronic form and stored on desktop hard drives that sometimes get forgotten. It takes an extremely good memory to remember which articles are relevant to a particular keyword you might be interested in.

Thankfully, there's Oracle Text (and Oracle Application Express (APEX)) to keep you sane!

Setting the Stage

I'm not a researcher myself, so naturally, I don't horde a lot of these materials. For the purpose of this blog post, I will use open data made available, courtesy of the Canadian Government.

The National Sciences and Engineering Council of Canada (NSERC) is one of Canada's federal agencies that is responsible for promoting and providing funding for research in the natural sciences and engineering fields. They publish annual lists of grants that were successfully awarded. You can find them here. I used only one year's (2017) worth of data. There's a lot of research activity going on in the north!

Start off by first creating the necessary data structure to hold the data. I used the Quick SQL tool to quickly generate the necessary DDL script and then create the database.

Quick SQL Shorthand

# settings = { genPK: false, db: 11g }
award
id number /pk
name varchar2(200)
department varchar2(200)
organization_id number
institution varchar2(200)
province varchar2(100)
country varchar2(100)
fiscal_year number
competition_year number
award_amount number
program_id varchar2(50)
program_name varchar2(200)
program_group varchar2(100)
committee_code number
committee_name varchar2(200)
area_of_application_code number
area_of_application_group varchar2(200)
area_of_application varchar2(200)
research_subject_code number
research_subject_group varchar2(200)
research_subject varchar2(200)
application_title varchar2(500)
source varchar2(50)
application_summary varchar2(4000)

Oracle SQL Output

create table award (
id number not null constraint award_id_pk primary key,
name varchar2(200),
department varchar2(200),
organization_id number,
institution varchar2(200),
province varchar2(100),
country varchar2(100),
fiscal_year number,
competition_year number,
award_amount number,
program_id varchar2(50),
program_name varchar2(200),
program_group varchar2(100),
committee_code number,
committee_name varchar2(200),
area_of_application_code number,
area_of_application_group varchar2(200),
area_of_application varchar2(200),
research_subject_code number,
research_subject_group varchar2(200),
research_subject varchar2(200),
application_title varchar2(500),
source varchar2(50),
application_summary varchar2(4000)
)
;

NOTE Change the DB version as required. The default is 12c, but since I am running the database Express Edition (XE), I used 11g.

Filling Up the Repository

The data from NSERC is fairly clean and formatted. The 2017 data that I downloaded however, was a little too large to import using the built-in SQL Workshop tool in APEX. Fortunately, SQL Developer has a rather sophisticated functionality for doing the same, though it wasn't without challenges. I'll leave data importing methods for another day's discussion. For the purpose of this exercise, I did managed to import at least 5,000 records.

Search-Enabling the Table of Grants Awarded

Oracle Text is a very powerful, no-cost feature of the Oracle Database that doesn't get enough attention as it should. There are many interesting concepts and customizations that can be applied and tune the Oracle Text Index. However, creating a basic index is rather straightforward and should not be feared.

My goal:

  • List grant awards that are about fossil fuels and the effects on the environment.
  • The corpus contains applications written in both English and French. Users should be able to search with either language.
  • Users enter search terms using only one text field, but search must include the following columns:
    • application_title
    • application_summary
    • research_subject
    • area_of_application

Required Database Privileges

To work with Oracle Text, the database user requires a few additional privileges that have already been granted to the role CTXAPP. Assigning the user to the role should be all that's needed:

grant ctxapp to dbuser;

Create the Oracle Text Index.

begin
-- Remove any previously created DATASTORE preference with the same name.
begin
ctx_ddl.drop_preference('SEARCH_DATASTORE');
exception
when others then null;
end;

-- Create the DATASTORE preference.
ctx_ddl.create_preference('SEARCH_DATASTORE', 'MULTI_COLUMN_DATASTORE');
ctx_ddl.set_attribute('SEARCH_DATASTORE', 'COLUMNS', 'application_title, application_summary, research_subject, area_of_application');

-- Drop any existing index with the same name.
begin
execute immediate 'drop index award_idx';
exception
when others then null;
end;

-- Create the index.
execute immediate q'[
create index award_idx on award(application_title)
indextype is ctxsys.context
parameters (q'{
DATASTORE SEARCH_DATASTORE
}')
]';
end;
/

The comments in the procedure shown above explains the basic commands needed to create the index. For convenience, they are listed below:

  1. Remove any previously created preference with the same name.
  2. Create the DATASTORE preference.
  3. Drop any existing index with the same name.
  4. Create the index.

As mentioned, there are additional indexing elements that could be used to further optimise and customize the search index, but they are out of scope at this time. This simple setup will already allow some powerful search abilities with minimal query design.

Query the Data

There are different operators to use in the WHERE clause, depending on the index type created. In the example, an index of type CONTEXT was created, thus the query will have to be constructed using the CONTAINS operator.

select
id
, application_title
, application_summary
from award
where 1 = 1
and contains(application_title, '"fossil fuels" and environment', 1) > 0
order by search_score desc;

Oracle provides a long list of CONTAINS query operators that allows users to formulate powerful queries. The example above is a simple boolean search (AND operator) requiring both the phrase "fossil fuels" and word "environment" for a match. A simple misspelling of "environment" would likely yield no results. That's where other operators like fuzzy provide a margin error, allowing returning results even when there are no exact matches. The same operator might even forgive simple nuances like "colour" versus "color". There are also wildcard (%) and other operators that are denoted using special characters that could sometimes spell trouble even for a seasoned Oracle Text user.

To protect the untrained user, it is recommended to pre-process the user input and restructure keywords and options into proper query operator constructs. This isn't always easy, and so, we are fortunate that Roger Ford, Oracle Text's Product Manager, posted a blog and useful utility package for parsing user inputs from a simple text field. The syntax closely resembles Google's search operators and should be familiar with most users. The code is available to download at the end of Ford's article.

After compiling the script, functions such as parser.simpleSearch and parser.andSearch will be available to use. Check the comments in the code for details about each function.

SQL> select parser.andsearch('"fossil fuels" environment') from dual;
-- returns ({fossil fuels}&{environment})

Querying with APEX

With too little screen space on a blog post, it's easier to demonstrate the search results using APEX. The accompanying demo application showcases Oracle Text integration using two different user interface approaches.

The first uses Interactive Grids (IG) that has built-in support for Oracle Text. After creating the IG, click on Attributes and then on the right, scroll down to the Advanced section and select the indexed column as the Oracle Text Index Column attribute.

Setup Oracle Text for Interactive Grids

Interactive Grids allows developers to specify a PL/SQL function for converting simple keyword inputs to well-formed Oracle Text syntax. Go to the application's Shared Components> Component Settings > Interactive Grids and then enter the name of the function to use. We can use one of the functions from Ford's Parser package as they meet the requirement of accepting a single string argument.

Specify a PL/SQL Function for Preprocessing Input String

The second approach uses a Classic Report (CR) that allows more flexibility on how the results are displayed, for example, sorting the results by score (descending) and application title (ascending). The user enters the search keywords in a single text field page item (P2_SEARCH_TERMS) that is then parsed and used with a CONTAINS operator to query the table. The SQL query used is as follows:

select
application_title as search_title
, application_summary as search_desc
, round(score(1), 2) as value_01
, 'Score' as label_01
, q'[javascript:apex.message.alert('Not implemented.');void(0);]' as search_link
from award
where 1 = 1
and contains(application_title, parser.progrelax(:P2_SEARCH_TERMS), 1) > 0

Displaying Oracle Text Search Results Using Classic Reports

Both search interfaces will accept either English or French keywords. However, search results are language-specific. If an English keyword is entered, then only applications submitted in English will be returned. Likewise with French search terms. For a heterogenous search, a thesaurus will be required. The parsing function will also need to be "translation-aware", and either accept or transform queries to use operators such as TR. These translation operators will expand the search keywords to include the specified language's equivalent term.

The ctxload utility provides developers the ability to import a thesaurus contained in a plain-text file. Developers can also script the thesaurus:

declare
l_thes_name varchar2(11) := 'SCIENG_THES';
begin
ctx_thes.create_thesaurus(name => l_thes_name);
ctx_thes.create_phrase(tname => l_thes_name, phrase => 'water');
ctx_thes.create_phrase(tname => l_thes_name, phrase => 'waters');
ctx_thes.create_translation(tname => l_thes_name, phrase => 'water', language => 'FRENCH', translation => 'eau');
ctx_thes.create_translation(tname => l_thes_name, phrase => 'waters', language => 'FRENCH', translation => 'eaux');
end;
/

Unfortunately, Ford's parser library does not support translations, but here's an example query that could be used to demonstrate the translation capability. The search term is "water", and the results will return both English and French applications containing either "water" or "eau":

select
id
, score(1) as search_score
, application_title
, application_summary
from award
where 1 = 1
and contains(application_title, 'tr(water, french, scieng_thes)', 1) > 0
order by search_score desc;

Final Notes

Besides searching large bodies of text, Oracle Text has the ability to index and search binary files such as PDF, HTML, XML and even Microsoft Word documents. Check out a full list of supported document formats.

NOTE: If the document filtering appears not to be working , i.e. a query does not return any expected results, then check that the needed operating system libraries, e.g. compat-libstdc++-33, have been installed. You can test this by running the binary: $ORACLE_HOME/ctx/bin/ctxhx.

Get more background about this thread on the Oracle community forums.

All the technology described and used in this blog post and demo are available to at no cost. That's always a welcomed surprise for any research project.

Software Used

SoftwareCost
Oracle Database 11gR2 XEFREE
Oracle APEX 18.1FREE
SQL Developer 18.2FREE

· 14 min read
Adrian Png

In a flash, it has been almost three years since I left the Centre for Heart Lung Innovation, so it's no surprise that a recent tweet caught my eye and tugged the memory chord. I was introduced to Oracle Application Express (APEX) on August 26, 2010. A year (and a major release) later, I had the opportunity to demonstrate it's capabilities with proof that it could help improve productivity in our research centre. As a sidenote, back then, attendees receive DVDs full of developer software goodies. APEX however, didn't need much, just check out the hands-on lab requirements below.

· 7 min read
Adrian Png

Where Dreams CAME True

That's right! Here's the customary post-Kscope article. This year though, is one Kscope to remember! Along with other Oracle Application Express (APEX) community members, I had the surprise honour of joining the ranks of the Oracle ACE Program. And so I wanted to start off by first thanking newly-minted Oracle ACE Director Opal Alapat. Last year, I had deep suspicions that she was responsible for my ODTUG Volunteer Award. Then came the ACE Associate nomination.

Opal, if you are reading this: THANK YOU!

· 4 min read
Adrian Png

Social Media

Updated June 4, 2018

  • Added settings for social sign-in with Microsoft OAuth2.

The much anticipated Oracle Application Express version 18.1 was announced on May 24, 2018. Since early this year Monty Latiolais has been posting a monthly series of blog posts on Power Ranking Oracle APEX 18.1 New Features. My personal favourite is Social Login, but unfortunately it never made it to the top, even though it should!

· One min read
Adrian Png

Photo by Johnny Brown

In a previous article, I had demonstrated how one could use Vagrant to deploy an OXAR virtual machine directly to Linode.

With Digital Ocean (DO) lowering their prices to match Linode's, I thought it would help the community if I created a similar set of instructions to deploy OXAR on DO. I took this a step further and have provided a branch on the Github repository with a modified Vagrantfile.

· 4 min read
Adrian Png

Old Handwritten Book by Kiwihug}

It's funny how JavaScript's 20th birthday was not as spectacular as it's shorter-named bretheren. When I first learned JavaScript in the late 1990's, I wasn't too excited as I was about Java, for two reasons most web developers know about JavaScript: weakly typed and non-standard browser implementation. The latter has been addressed by ECMA, but does that mean our code can now be more predictable and consistent?

· 7 min read
Adrian Png

Main Ballroom Before the Big Event Starts

The beautiful City of Vancouver (in British Columbia) played host to the North American Node.js Interactive 2017 conference earlier this month. That close to my backyard, it was simply inexcusable not to attend! I wasted no time in getting the support of my employer and am glad I did. Here's a little summary of my experience and what I learned at the two-day conference to share.

· 4 min read
Adrian Png

Photo by Hisham Abo-hamad on Unsplash

Earlier this year (2017), I had the privilege to share with the community, some of the work and experiences I gained helping to build some of the blocks that form the foundation of apex.world. In my presentations, I had shared some of the challenges I had integrating RESTful web services with Oracle Application Express (APEX). A crippling issue involved the use of Oracle Database Express Edition (Oracle XE) and communicating with web services over a secured protocol. The by-product of that experience led to the development of a simple Node.js application, which I named Suez.

· 5 min read
Adrian Png

All Systems Go!

Running a production application on an Oracle APEX instance? Then read on!

Making sure your application is up and running 24/7 doesn't need to be a daunting task, plus it may not even cost you a dime! UptimeRobot provides 50 free monitors that can poll your servers using the smallest interval of 5 minutes. You can easily monitor websites and receive multi-channel notifications of downtime. No excuse!

· 10 min read
Adrian Png

Screen capture of http://www.mail-tester.com/ Results

Before I begin, I just wanted to be absolutely clear that this post has nothing to do with Apple's nifty tool for sending out large email attachments.

In my previous post, I shared an approach for creating your very own Oracle Application Express (APEX) instance on a small budget. Briefly, the solution involves using Vagrant to create a very affordable virtual machine (VM) on Linode's pool of servers and run the OXAR build script, to setup the APEX instance very quickly and painlessly.

However, all that power (and savings) comes with great responsibilty.