Forum OpenACS Development: very annoying gotcha overloading functions in nspostgres...

grrr.... it's taken me way too long to sort out why this wasn't working...

We have a PL/pgSQL function that attaches keywords to assets in the database, and were trying to use postgres's function overloading so that you could pass either an asset name or the asset_id to the relevant function and have it do the Right Thing.

Calling o2_keyword_map (:filename, :keyword) worked fine, but when attaching many keywords to one asset I'd rather not have to look up the asset_id from the filename every time, but o2_keyword_map (:asset_id, :keyword) would barf claiming that no such asset existed.

It turns out that the bind variable emulation in nspostgres works by turning everything into a string, and letting PG cast stuff to the correct type if necessary. So when we're passing in an asset_id instead of a filename the actual call that gets delivered to PG is o2_keyword_map ('40519','tism'), which instead of going to o2_asset_map (integer, varchar) instead matches o2_asset_map (varchar, varchar), tries to look up an asset called '40519', and fails.

The easy workaround is to explicitly cast the asset_id to an integer in the PL/pgSQL call, but I can't help wondering if there's a better way.

Yes, this is a known gotcha of the bind variable emulation  and would still be a problem if PG handled bind variables itself, if you think about it a bit.  For PG would still treat the bind variables as being a string when doing its overload resolution.

The value of using bind variable emulation, beyond being able to share queries with Oracle when they're SQL92 compliant, is that it defeats attempts at SQL smuggling.

How to fix it?  Can't, really.

Collapse
Posted by russ m on
I wouldn't think of going without nspostgres' faux-bind variables, the benefits are large and obvious. I wondered briefly if using the new bind variable support in postgres (libpq's PQexecParams()) would help, and realised that on it's own it wouldn't.

The one thing that sprung to mind, and I'm not entirely convinced it would be worth the effort, is to give nspostgres enough brains to work out the likely type of each bind variable and treat it appropriately - a bunch of regexps or some such to match against permissable formats of PG's known datatypes. On the plus side it would remove this gotcha and be a useful step towards shifting from PQexec()to PQexecParams(), on the minus side it would slow nspostgres down, need to be kept in sync with any datatype changes in PG, and requires programmer time that I don't have spare... :)

/me adds entry to bottom third of TODO list...