Does TRUNCATE invalid package?

Every wondered in an Oracle Database if a TRUNCATE of a table would invalidate the dependent PL/SQL.????

Well the answer is NO.

Try out this code.

Create a table
create table tim_testing_truncate (x number, vc varchar2(100));

Now create a package with dependency to this table.
create or replace package tim_testing_truncate_pkg
as
procedure abc(p_x IN tim_testing_truncate.x%TYPE);
end tim_testing_truncate_pkg;
/
create or replace package body tim_testing_truncate_pkg
as
procedure abc(p_x IN tim_testing_truncate.x%TYPE)
IS
begin
execute immediate 'truncate table tim_testing_truncate';
end;
end tim_testing_truncate_pkg;
/

Now run the code
begin
tim_testing_truncate_pkg.abc(1);
end;
/

Now have a look at use_objects…

select * from user_objects where object_name like 'TIM_TESTING%' order by last_ddl_time asc;

What you’ll see is the status is still valid and the DDL time is still before the running of the procedure ABC.

TIM_TESTING_TRUNCATE TABLE 07/09/2015 13:20:26 07/09/2015 13:20:26 VALID
TIM_TESTING_TRUNCATE_PKG PACKAGE 07/09/2015 13:20:31 07/09/2015 13:20:31 VALID
TIM_TESTING_TRUNCATE_PKG PACKAGE BODY 07/09/2015 13:20:32 07/09/2015 13:20:32 VALID

Camping Fabulous, Ostia

Having been camping, we’ll living it up in a cabin, we struggled to find ….. tea towels.

Well we found a shop. Achilia is a little area near the camp. There is a shop there a little like the NZ  $2 shop, selling all sorts.  Here we found tea towels and also ice cube trays and freezer blocks to go with cooler bag from home.

That’s all for now.

Looking to Fake APP_USER in SQL Developer???

So, you are looking to check some code in SQL Developer but not wanting to use APEX and you need access to APP_USER.

First you need login into the schema that is the parsing user.  Next set the security group in  APEX.  Lastly set the G_USER variable in the APEX_APPLICATION package to the value you want and the app_id.

begin
apex_util.set_security_group_id 
    (p_security_group_id => APEX_UTIL.FIND_SECURITY_GROUP_ID('<WORKSPACE_NAME>'));
APEX_APPLICATION.G_USER := '<Username>';
APEX_APPLICATION.G_FLOW_ID := ;
END;
/

Now run this SQL, what you should see is the value set above.

SELECT V('APP_USER') FROM DUAL;

All done.

Application Express Show Hide using a checkbox

Have a look at the screen shot below. Using Click of the item and a JavaScript expression, $(‘#P141_ITEM_0’).prop(‘checked’). The ID for the item when APEX creates the item is two levels. The name of the item in APEX is P141_ITEM, the thing cliicked in the INPUT with the P141_ITEM_0,

<fieldset tabindex="-1" id="P141_ITEM" class="checkbox_group">
<legend class="hideMeButHearMe">Include Fx</legend>
<input type="checkbox" id="P141_ITEM_0" name="p_v04" value="Y"></fieldset>

This finds the value of “checked” from the item and does the show and hide.
Image

UTL_HTTP and ORA-12541

I recently hit this error while developing an OAuth client using PL/SQL in the database.

The solution turned out to be straight forward…. but could I find the answer using my favourite search engine? Nope.

If you get this error, the first thing to think about is whether you want your request to follow any redirects from the web server(s). By default, UTL_HTTP will attempt to follow 3 levels of redirect. If you don’t want to follow any redirects, include the following call before you perform the request.

  utl_http.set_follow_redirect(0);

In my case, this stopped the error and return a NULL response.
The other issue I had was wanting to read the HTML response when there was nothing to read, e.g. when the HTTP response code was not 200.
Below is a pseudo-code version of the example code given in the package specification for UTL_HTTP. I have modified the code, my extras are in bold.

DECLARE
  req utl_http.req;
  resp utl_http.resp;
  resp_name  VARCHAR2(256);
  resp_value VARCHAR2(1024);
  value VARCHAR2(32767);
  l_wallet_location VARCHAR2(200) := 'c:\oracle_home\mywallet';
BEGIN
  utl_http.set_follow_redirect(0);
  utl_http.set_wallet('file:'||g_wallet_location);
  
  req := utl_http.begin_request('http://www.google.com');
  resp := utl_http.get_response(req);

  FOR i IN 1..utl_http.get_header_count(resp) LOOP
    utl_http.get_header(resp, i, resp_name, resp_value);
    dbms_output.put_line(resp_name || ': ' || resp_value);
  END LOOP;

  if resp.status_code = 200 then

  LOOP
    utl_http.read_line(resp, value, TRUE);
    dbms_output.put_line(value);
  END LOOP;
  utl_http.end_response(resp);

EXCEPTION
    WHEN utl_http.end_of_body THEN
      utl_http.end_response(resp);
END;
/

These changes have allowed me to understand the original ORA-12541 error and what is really happening with the HTTP response from the web server.

I hope this helps someone else.

Application Express and Janrain

APEX and Janrain Authentication Scheme

We had a requirement to allow authentication to Application Express (APEX) using external identity providers, like Google and Yahoo!. The solution turns out to be reasonably straight forward and uses a service provided by Janrain, called Janrain Engage (formerly RPX).

How it works

The APEX application’s login page has the Sign-in Widget from Janrain.

As shown here, the user is presented with a selection of identity providers like Google and Yahoo!, the exact list is configurable.

A registered user will select their preferred provider and login against the provider’s website handled by Janrain. Once authenticated, Janrain posts a token to a URL in the APEX application. This URL is a procedure available to APEX_PUBLIC_USER and retrieves the identity by making an API call to Janrain’s auth_info with the private RPX API Key. The user’s “verifiedEmail” is used as the identity key.  This key is used to set the APEX login name “APP_USER” and to identify the user.

A page sentry is used as part of the Application’s Authentication Scheme to allow for deep linking.  This allows users to be email a link to any page in the application. The initial application/page is passed to the login page as a return path.

After this, it is down to the application to limit what the user can see based on who they are logged in as.

What is needed

This is a list of the things required to make this work

  • Page Sentry that redirects to Login page and allows deep linking
  • Janrain account with a defined application
  • Janrain token receiving procedure
  • APEX Login page hosting the Sign-in Widget
  • PL/JSON by jkrogsboell, lewiscunningham
  • Authentication Scheme called RPX

Page Sentry that redirects to Login page and allows deep linking

A page sentry is part of the authentication scheme and is executed before a page is rendered. As you can see from the code below, the following happens:

  • the APEX session id is retrieved from the cookie
  • the session is validated
  • If valid, the global variable g_instance is set and true is returned
  • If not valid, the browser is sent a redirect where the URL is the login page

The redirect includes two variables, the original application and page. These values are used by the login page to redirect the user back once the authentication is complete.

FUNCTION PAGE_SENTRY
RETURN BOOLEAN
IS
    l_username VARCHAR2(512);
    l_session_id NUMBER;
BEGIN
    IF USER != 'APEX_PUBLIC_USER' THEN
        RETURN false;
    END IF;
     l_session_id := wwv_flow_custom_auth_std.get_session_id_from_cookie;
     -- check application session cookie.
     IF wwv_flow_custom_auth_std.is_session_valid THEN
         apex_application.g_instance := l_session_id;
         l_username := wwv_flow_custom_auth_std.get_username;
         wwv_flow_custom_auth.define_user_session(
             p_user => l_username, p_session_id => l_session_id);
         RETURN true;
     ELSE
         OWA_UTIL.REDIRECT_URL('f?p=RPXAUTH:LOGIN:'||
             nv('APP_SESSION')||
             '::::RETURN_APP_ID,RETURN_PAGE_ID:'||
             v('APP_ID')||
             ','||v('APP_PAGE_ID'));
     END IF;
     RETURN false;
END page_sentry;

Janrain account with a defined application

Establish an account with Janrain and select the drop down called My Applications.  There is an option to “Create Application”. This opens to the following.

Use the basic application for now (shown here). Choose a name, this can be any name and will become the sub-domain of rpxnow.com.  This name will appear on the screen to the users.

Janrain token receiving procedure

This procedure will be posted to by Janrain once the authentication with the chosen provider is complete. This procedure has two parameters, P and TOKEN. The TOKEN is a posted value and the P parameter is part of the token URL defined in the IFRAME Sign-in Widget.

PROCEDURE rpx_return(
    p IN VARCHAR2,
    token IN VARCHAR2)
AS
BEGIN
    OWA_UTIL.REDIRECT_URL('f?p='||p||'::::P101_RPX_TOKEN:'||TOKEN);
END rpx_return;

APEX Login page hosting the Sign-in Widget

The login page has two regions, one for the Janrain sign-in Widget and the other is shown to the user once they have logged in.  There is one button and a page process and some page item to capture details.

Janrain Region

This HTML region displays the Sign-in Widget IFRAME captured from Janrain (this is done using the Deployment->Sign-in Widget wizard). The token URL is the address of the Janrain token receiving procedure described above. I made this region conditional on the token being NULL.

The token URL needs to include the application and page IDs of the Login page and the session ID as the parameter P (look familiar?).  An example is this:

http://<yourhost>:<port>/pls/apex/rpx_return?p=RPXAUTH:LOGIN:&APP_SESSION.

I have used the application/page aliases for my Login page.

After Janrain authentication, this URL is posted the TOKEN.  The procedure simply redirects the browser back to the login page passing the token as a parameter. This region is now hidden.

Fetching the ID

This is the part where the identification details are captured from Janrain.  Example code is available from Janrain as part of the Sign-in Wizard.  I have written the Oracle PL/SQL equivalent.

FUNCTION FETCH_ID(
    TOKEN IN VARCHAR2)
RETURN VARCHAR2
AS
    req UTL_HTTP.REQ;
    resp UTL_HTTP.RESP;
    v_value VARCHAR2(1024); -- URL to post to
    V_WALLET_LOCATION VARCHAR2(200) := '';
    v_url VARCHAR2(200) := 'https://rpxnow.com/api/v2/auth_info';
    v_param VARCHAR2(500);
    v_param_length NUMBER;
    RPXAPIKEY VARCHAR2(100) := 'youAPIKey from Janrain';
BEGIN
    IF TOKEN IS NULL THEN
        RETURN NULL;
    END IF;
    v_param := 'token='||token||'&apiKey='||rpxApiKey||'&format=json';
    utl_http.set_wallet('file:'||v_wallet_location);
    v_param_length := LENGTH(v_param);
    req := UTL_HTTP.BEGIN_REQUEST (url=> v_url, method => 'POST');
    UTL_HTTP.SET_HEADER(req, 'User-Agent', 'Mozilla/4.0');
    UTL_HTTP.SET_HEADER (r => req,
                        name => 'Content-Type',
                        value => 'application/x-www-form-urlencoded');
    UTL_HTTP.SET_HEADER (r => req,
                        name => 'Content-Length',
                        value => v_param_length);
    UTL_HTTP.WRITE_TEXT (r => req,
                        data => v_param);
    resp := UTL_HTTP.GET_RESPONSE(req);
    UTL_HTTP.READ_LINE(RESP, V_VALUE, true);
    UTL_HTTP.END_RESPONSE(RESP);
    RETURN (v_value);
END fetch_id;

HTTPS is used to secure the fetching of the identify information, the only challenge here is getting the wallet created and holding the required ROOT of the certificate used by Janrain. I’ve used an auto login wallet, hence no password setting.

This returns the identity in JSON format.  Here is an example of the returned data.

{“profile”:{“googleUserId”:”123123123132132″, “verifiedEmail”:”fred.flintstone@example.com”, “name”:{“givenName”:”Fred”, “familyName”:”Flintstone”, “formatted”:”Fred Flintstone”}, “displayName”:”fred.flintstone”, “preferredUsername”:”fred.flintstone”, “providerName”:”Google”, “identifier”:”https:\/\/www.google.com\/accounts\/o8\/id?id=AaBbCcDdEeFfGg3344FfGgGg”, “email”:”fred.flintstone@example.com”},”stat”:”ok”}

I set a page item called P101_RPX_ID to the return value of the FETCH_ID function above.

Welcome Region

This conditional HTML region displays a “Welcome” message to the end user and shows a button called “Proceed to the application”. This button invokes an “On Submit – After Computation and Validations” page process called PostLogin.  It does the following:

begin
    wwv_flow_custom_auth_std.post_login(
        p_uname => rpx.get_username(:P101_RPX_ID),
        p_session_id => nv('APP_SESSION'),
        p_flow_page => v('RETURN_APP_ID')||':'||v('RETURN_PAGE_ID'),
        p_preserve_case => true);
end;

This sets the APP_USER for the session and redirects the browser back to the original page.  This allows for deep linking.

PL/JSON by jkrogsboell, lewiscunningham

I have used PL/JSON to decode the JSON formatted identity from RPX. It is available here on SourceForge. Note the dot notation of the path to the variable I’m using.

function get_username(
    p_json_text in varchar2)
return varchar2
is
    jsonObj       json;
BEGIN
    if p_json_text is not null
    then
        jsonObj := json(p_json_text);
        return JSON_EXT.GET_STRING(JSONOBJ,'profile.verifiedEmail');
    end if;
    return null;
end get_username;

Authentication Scheme called RPX

This has a “Page Sentry Function” defined as “return page_sentry;”. As we were planning to have multiple applications sharing the same RPX authentication, I set the “Cookie Name” to RPX.  This allows the session to be shared between all applications in the same workspace.

That is it

I hope some of the information held here is useful to someone else.