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.