I know this isn't central to your point, but I thought I'd say it anyway. These days I have taken to doing:
sql = "SELECT * FROM products WHERE TRUE"
....
if upc:
sql += ' AND upc LIKE %?%'
....
This saves having to worry about "AND" and "WHERE", and the extra "WHERE TRUE" results in the same execution plan (thus the same performance).