|Do you know where your variables are?|
As a general rule, you need to use regular-expressions to verify that all of your parameters conform to the expected format, and you need to be sure that they are, in fact, scalars. (Multiple occurrences of the same token in a GET-string can create an array-type value in some cases.)
Note that your patterns should describe exactly what you will accept. Don't try to write patterns to filter-out or to recognize what you wish to reject. “Think positive.” The pattern should consider not only character-types but also plausible length-ranges. If the patterns occur consistently throughout the application, put all of them into their own library unit that you can “use.”
You also need to be sure that the values come from the correct source... GET or POST.
Finally, consider using verification strings on, say, your hotlinks. This is a GET-parameter that you've added to the URL, consisting of (say...) an SHA1 hash of the URL-value, perhaps the session-id, and an unknown-to-the-attacker random string. If your program gets a URL-reference that does not contain a valid verification string, the request is rejected. (Naturally, there's plenty of CPAN material available to do this.)
This approach will work regardless of what kind of back-end database (or other data store) that you intend to use. If these tests are put in a central location at the dispatching heart of the application, they will apply consistently throughout the code and thus protect all of it.
In reply to Re: Preventing SQL injection attacks: Placeholders are enough for MySQL, Postgresql and SQLite