Escaped strings and PL/SQL Dynamic Actions
I had a simple form where the user can select a vendor from a select list (using the Select2 plugin), and the form would retrieve the latest purchase details based on a simple string search of that vendor’s name – for most cases. Sometimes, however, it failed to find anything even though I knew the data was there.
There was a dynamic action that fires on Change of the list item that executes a PL/SQL procedure and retrieves the Total Amount and the Memo:
transaction_pkg.get_suggestion (vendor_name => :P5_VENDOR_NAME ,total_amt => :P5_AMOUNT /*out*/ ,memo => :P5_MEMO); /*out*/
This didn’t work in some cases where a vendor name included special characters, such as
&. This is because the item had Escape special characters set to the default (Yes), which is good practice to protect against Cross-Site Scripting (XSS) attacks. Therefore, the value sent by the dynamic action to my PL/SQL procedure had the special html characters escaped, e.g. “Ben & Jerry’s” was escaped to “
Ben & Jerry's“. I believe APEX uses the apex_escape.html function to do this.
Usually, I would try to rework my code to send a numeric ID instead of a string; but in this particular case the data model does not have surrogate keys for vendors (it’s just a free-text field in the transactions table) so I want to use the name.
If I was doing this properly, I would fix the data model to make vendors first-class entities, instead of using a free-text field. This would allow using a surrogate key for the vendor list and this escaping behaviour would no longer be a problem.
Another alternative here is to use the latest transaction ID as a surrogate key for each vendor; but then I would need to modify the form to translate this back into a vendor name when inserting or updating the table; and this would add unnecessary complexity to this simple form, in my opinion.
Instead, before sending this string to my procedure, I’ve chosen to unescape the data. To do this, I add a call to utl_i18n.unescape_reference:
transaction_pkg.get_suggestion (vendor_name => utl_i18n.unescape_reference(:P5_VENDOR_NAME) ,total_amt => :P5_AMOUNT /*out*/ ,memo => :P5_MEMO); /*out*/
This converts the escaped data back into a plain string, and my simple data matching procedure now works as expected.