When CFQueryParam is NOT Required
Unlike a simple RegEx, cfqueryparam actually tells the database that this is a parameter which stops injected SQL from being executed even if it includes the traditional SQL characters for ending a command and adding a drop table (or whatever).
However, if you think about it, the only time this is really important is if you are saving to a string based field (varchar, nvarchar, text, ntext, char, nchar, etc.). For bits, floats, integers, datetimes and other relatively constrained data types, it is perfectly valid to just use a RegEx to strip any unacceptable characters before calling the db script.
I personally tend to prefer this approach as I'd rather get my own error from my validation library than having to catch, parse and handle the error thrown by the db library (as an aside, does anyone have sample code that will catch common database errors thrown by a cfquery in a try/catch block and parse them so you can throw something useful in terms of the element of the SQL that the db didn't like? I *think* this is a hard problem to solve but am not sure - heck I don't even know if the syntax of the error message is consistent across db drivers).
Not to say you *shouldn't* use cfqueryparam, but just that you don't necessarily have to except for when saving to string type fields (varchar, nvarchar, text, ntext, char, nchar, etc.). Of course this means you MUST validate every field before saving it to a db, but with custom data types and a simple validation library this is should be a default behavior for all of your fields all of the time as it takes almost no effort.
Any thoughts/opinions?!



Agreed 100%. I mentioned the performance benefits of using cfqueryparam, but I'm always leery of premature optimization, so I wouldn't use cfqueryparam for performance reasons unless I found a performance bottleneck with my db queries.
And in case you're wondering why I wouldn't just use cfqueryparam all the time, it is a pain when you're generating code as I haven't been able to "eval" it so I have to actually generate queries, write them to the file system and then call them (unless I'm missing something). Obviously this is only a one time hit, but I really don't like having the extra code lying around bulking up the code base unless I need it.
To be fair I haven't really tried to find a way to run cfqueryparam in dynamically concatenated SQL, so if anyone has figured that out, please let me know, but I don't believe it's "eval"'able which is a pain given how I create my code!
Often I end up having to generate my SQL as a array, broken down by each param I want to enter... so I end up build an array of Structs with describes my SQL, and then inside my <cfquery> tag, I loop around my query and push out my query.
It works, but it does feel like a bit of a double handle. Not much else you can do however.
http://transfer.riaforge.org/index.cfm?event=page....
Check out line 43. I think this proves that the expressiveness of a language DOES affect how easy it is to solve problems in, but this is a pretty cool little snippet for dynamic cfqueryparams.
Thanks Mark!
That's very cool, but why not just set all the attribute values as variables in the cfqueryparam? I mean, it looks like the CASE statement's only purpose is to set the proper cfsqltype. Just curious if I'm missing something....
/ejt
The problem to solve: write a cfquery that will save any object with n-attributes using cfqueryparam for each attribute. Can't think how to do that other than using Marks approach.
Am I missing something?
DataMgr actually exposes this approach using the runSQLArray() method. You could obviously take that code out and use it independently.
Interesting to see that Mark an I came upon similar solutions separately.
Interesting! I guess not surprising just because there are only so many possible solutions out there. It is like using inheritance for extending generated components - one of those good ideas that seems to keep on getting re-invented!
Pretty much all of the Transfer SQL stuff works by breaking things down so that they can be later re-evaluated.
You don't really have a choice.
What alternative methods are there, if you want to use cfqueryparam?