ColdFusion Query of Queries Unexpected Data Type Conversion

Posted November 1, 2006 at 4:03 PM by Ben Nadel

Tags: ColdFusion

I cam across a really strange ColdFusion query of query error this morning involving some unexpected data type conversion. The query of query seems to be ignoring BOTH the data type passed in as well as the target field's data type and converts automatically to a date. Let me demonstrate.

First, let me build a simple query using ColdFusion's QueryNew() method:

  • <!---
  • Create new query. Set up column data types
  • to both be VARCHAR.
  • --->
  • <cfset qGirl = QueryNew(
  • "name, date",
  • "VARCHAR, VARCHAR"
  • ) />
  •  
  •  
  • <!--- Add rows. --->
  • <cfset QueryAddRow( qGirl, 3 ) />
  •  
  •  
  • <!---
  • Set row/cell data values. Use JavaCast() to make
  • sure ColdFusion doesn't have to guess at data types.
  • --->
  • <cfset qGirl[ "name" ][ 1 ] = JavaCast( "string", "Libby" ) />
  • <cfset qGirl[ "date" ][ 1 ] = JavaCast( "string", "2006-10-01" ) />
  •  
  • <cfset qGirl[ "name" ][ 2 ] = JavaCast( "string", "Sarah" ) />
  • <cfset qGirl[ "date" ][ 2 ] = JavaCast( "string", "2006-09-01" ) />
  •  
  • <cfset qGirl[ "name" ][ 3 ] = JavaCast( "string", "Cindy" ) />
  • <cfset qGirl[ "date" ][ 3 ] = JavaCast( "string", "2006-08-01" ) />

At this point, I have a 3-row query that has two columns, both of which are VARCHAR fields. When I set the data into the cells, I do so using ColdFusion's JavaCast() method. This takes out any guessing that ColdFusion has to do. We are explicitly telling ColdFusion to use STRING values in the underlying Java record set.

Nothing magical yet. But now, let's try to perform a ColdFusion query of queries getting the first girl based on the date column (NOTE: the date column is a VARCHAR field with String data):

  • <!--- Get first girl. --->
  • <cfquery name="qFirstGirl" dbtype="query">
  • SELECT
  • name,
  • [date]
  • FROM
  • qGirl
  • WHERE
  • [date] =
  • <cfqueryparam
  • value="#qGirl.date#"
  • cfsqltype="CF_SQL_VARCHAR"
  • />
  • </cfquery>

Notice that I am not touching any data myself. I am only passing in the data that is already stored in the query (via qGirl.date). This should return one record containing the first girl in the original query, but, in fact, it returns an empty record set.

So what's the problem. Well, I thought maybe it was JavaCast() call. Even though that is a best practice, I thought maybe it was confusing the record set. So I removed. This did not fix the error. Then, I thought maybe it was the CFQueryParam tag - maybe there was something about it that was messing up the data. So I tried removing it and putting in a literal string:

  • <!--- Get first girl. --->
  • <cfquery name="qFirstGirl" dbtype="query">
  • SELECT
  • name,
  • [date]
  • FROM
  • qGirl
  • WHERE
  • [date] = '#qGirl.date#'
  • </cfquery>

This also did NOT fix it. So, what the heck was going on?!? As a last ditch effort, I tried echoing both the original data field and the passed in data to see what was going on:

  • <!--- Echo back data values. --->
  • <cfquery name="qEcho" dbtype="query">
  • SELECT
  • [date],
  • (
  • <cfqueryparam
  • value="#qGirl.date#"
  • cfsqltype="CF_SQL_VARCHAR"
  • />
  • ) AS target_date
  • FROM
  • qGirl
  • </cfquery>

Notice that I am selecting the existing data (in the qGirl.date column) and creating a calculated column based on the CFQueryParam of the first records date value. This gives me the following CFDump:


 
 
 

 
 
 
 
 

Very interesting! It seems the ColdFusion query of query is totally ignoring the data type that the CFQueryParam is requesting. But, while I can't see it visually, it must also be ignoring the [date] data type as well (otherwise we would be getting a match). It seems to automatically convert the value to a Date/Time stamp just because it "looks" like date/time object.

To test this, I tried passing in data that did not look exactly like a date:

  • <!--- Echo back data values. --->
  • <cfquery name="qEcho" dbtype="query">
  • SELECT
  • [date],
  • (
  • <cfqueryparam
  • value="-#qGirl.date#-"
  • cfsqltype="CF_SQL_VARCHAR"
  • />
  • ) AS target_date
  • FROM
  • qGirl
  • </cfquery>

Notice that the value attribute of the CFQueryParam tag now has "-" in it. This gives us the following CFDump:


 
 
 

 
 
 
 
 

Interesting! Why is it doing this? Why is it ignoring my requests and converting data on it own?

To get around this, I tried to cast the passed in CFQueryParam value to a VARCHAR. But that DIDN'T WORK. What is going on! Finally, I got the whole thing to work if I CAST both values to date:

  • <!--- Get first girl. --->
  • <cfquery name="qFirstGirl" dbtype="query">
  • SELECT
  • name,
  • [date]
  • FROM
  • qGirl
  • WHERE
  • CAST( [date] AS DATE ) =
  • CAST(
  • <cfqueryparam
  • value="#qGirl.date#"
  • cfsqltype="CF_SQL_VARCHAR"
  • />
  • AS DATE
  • )
  • </cfquery>

This finally gives us the desired output:


 
 
 

 
 
 
 
 

This seems like a really whacky behavior.




Reader Comments

Nov 1, 2006 at 11:11 PM // reply »
110 Comments

QofQ has some nice uses and it makes certain things easier, but it is also probably the source of more unexpected behavior and frustration than any other feature.


Nov 2, 2006 at 4:37 AM // reply »
67 Comments

Weird. But none of this surprises me of QoQ, really: it really doesn't take much effort to confuse it.

Have you raised it as a bug?

Good investigation, btw.

--
Adam


Nov 2, 2006 at 7:23 AM // reply »
10,638 Comments

Bug has been reported.

Yeah, ColdFusion query of queries does have some strange things in it, but gosh darnit, it's one of the most bad-ass features of the ColdFusion MX family.


Nov 2, 2006 at 8:28 AM // reply »
67 Comments

If it worked properly, you'd be right. However it's so flaky that it's really only useful for doing the most basic things. It feels like it's only a beta (which is sad, given it's been around since... when did CF5 come out... 2001?).

So I agree than the words "bad" and "ass" (although I'd say "arse") are suitable to describe it. Just not quite the way you meant ;-)

--
Adam

PS: much prefer your "De-spam" approach to all that "captcha" nonsense that's the current trend.


Nov 2, 2006 at 8:57 AM // reply »
48 Comments

It would be interesting to see a getMetaData() for your examples just to confirm the data conversions you are seeing.


Nov 2, 2006 at 12:58 PM // reply »
10,638 Comments

Adam,

Glad you like the de-spamming technique.


Apr 13, 2007 at 2:21 PM // reply »
1 Comments

This may sound really trite... but did you try changing the query equivalency?

from

[date] = '#qGirl.date#'

to

[date] like #qGirl.date#

?

It's just a thought, because date types are not like other data types. They are weird objects, so it's possible that using the = operator doesn't work with them.


Apr 13, 2007 at 2:26 PM // reply »
10,638 Comments

I did not try that [no suggestion is trite ;) ]. I am not sure it can work, though, I cannot be sure until I test it.


Mar 31, 2008 at 3:37 PM // reply »
4 Comments

This is just what I needed! I retrieved a query and modified it using QueryAddColumn:
<cfset ArraySet(MyArray,1,themembers.recordcount,JavaCast("boolean",true))>
<cfset QueryAddColumn(themembers,"Signer","bit",MyArray)>

Notice that I used JavaCast AND set the column type in QueryAddColumn. That wasn't enough. To pull data out I had to do:

<cfquery dbtype="QUERY" name="thequery">
Select * from this.members
where cast(signer as bit) = cast(<cfqueryparam value="true" cfsqltype="cf_sql_bit"> as bit)
</cfquery>

Otherwise it kept telling my column didn't exist.


Apr 1, 2008 at 9:00 AM // reply »
10,638 Comments

@Steve,

It's probably because you were using SELECT *. If you took out the * and wrote in the column names, it probably would work fine without the casting. It's just caching the query structure (my guess).


Feb 24, 2009 at 12:20 AM // reply »
1 Comments

Can I just say that this absolutely saved me! Thank you so much for posting this! This little bug was driving me nuts!


May 27, 2009 at 11:10 AM // reply »
1 Comments

I just stumbled upon this entry after a google search. I was having a single digit integer (which was stored on the database as a varchar) being called a double in a QoQ.

I tried pblecha's suggestion to use a like and unfortunately that did not work. However, I then tried to CAST as VARCHAR and that did work.

Here is the original query:

SELECT frmtm, totm
FROM ProfileStruct.DOWControls
WHERE dow = <cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="#DayValue#">
AND seq = <cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="2">;

And I changed it to:

SELECT frmtm, totm
FROM ProfileStruct.DOWControls
WHERE CAST(dow AS VARCHAR) = <cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="#DayValue#">
AND CAST(seq AS VARCHAR) = <cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="2">;

I was actually having problems with both conditions of the predicate and now they work fine with CAST. For the record, all the fields are stored as VARCHAR2 on an Oracle database. dow is a 3 character representation of the weekday (MON, TUE, WED, ...) and seq is either 1 or 2.

It just shows that there is still a bunch of flakiness with CF7's QoQ.


Jun 1, 2009 at 1:59 PM // reply »
10,638 Comments

@Frank,

Yeah, I would like going forward for QoQ to enforce more appropriate data types. The problem with that, however, is that it is currently quite flexible (you can put *anything* into a query). Forcing more data constraints might break a lot of code. We'll see. At least this error only pops up from time to time.


Aug 14, 2009 at 1:40 AM // reply »
18 Comments

I wish there was a way to change the column data types on the fly. I've been playing around with jQuery AJAX and CFWDDX and I've noticed that when I pass a query object as a WDDX packet and re-construct it using CFWDDX the data types can get all messed up -- specifically when dealing with dates. They get even more messed up if the first row of a query contains a NULL value.


Aug 17, 2009 at 2:17 PM // reply »
10,638 Comments

@David,

Yeah, that would be cool. That's why I like converting query data to array/struct data, so I know how it's all going back and I can do any massaging that needs to be done.


Nov 4, 2009 at 11:56 AM // reply »
1 Comments

I had the exact same problem with a regular query on a varchar data type. I used the CAST() function and it solved the problem, but it only errored when certain strings were passed in. E.G. 'mfrscan' worked fine, but 'mfrbillback' threw sql conversion error. Very strange?


Nov 4, 2009 at 1:03 PM // reply »
10,638 Comments

@Charlie,

Yeah, that is strange - especially with values that are not too different. Query of queries is awesome, but can definitely be frustrating from time to time.


Nov 4, 2009 at 1:33 PM // reply »
18 Comments

@Charlie

Query of Queries is like a 3 year old with ADHD. You should never leave it alone to make any decisions for you. I highly recommend using a combination of JavaCast (when building your QofQ manually) and Cast() in order to ensure the data matches your expectations.


Nov 4, 2009 at 1:35 PM // reply »
10,638 Comments

@David,

Yeah, JavaCast() is awesome; but, I've even had *some* issues with that. Sometimes, ColdFusion just wants to ignore everything about your column and cast data!!


Jan 4, 2010 at 5:23 PM // reply »
5 Comments

I noticed (with CF8) similar QofQ date bizareness, trying to test for date X being before or on now().

If I have a query "foo" and it cfdumps and the "dateX" col looks and smells like a date field, I'd try "SELECT * from foo where cast([dateX] as date) <= cast(<cfqueryparam cfsqltype="CF_SQL_DATE" value="#now()#"/> as date)" with no luck. But what worked? Doing the cast as integer. "SELECT * from foo where cast([dateX] as integer) <= cast(<cfqueryparam cfsqltype="CF_SQL_DATE" value="#now()#"/> as integer)" got me the correct results

Yeah, CF QofQ is very cool, but in a maddening unpredictable way. Argh.


Jan 4, 2010 at 6:49 PM // reply »
10,638 Comments

@Alan,

That's frustrating when not even a CAST() call will fix your problem (or at least, not with the more appropriate data type :)).


Feb 10, 2010 at 12:27 PM // reply »
5 Comments

Ben, I'll pass along another QofQ datatype disaster I went through a couple days ago. An app that uses QofQ started throwing "cannot conver value '' to number" errors for no apparent reason. The QofQ had been CASTed to death, and I could not come to a solution, but did come up with a strange but successful jury-rig.

I seralized the original query with CFWDDX, then deseralized it back to a query again. After that, the subsequent QofQ worked fine. Go figure.

Anyhow, I'm not trying to hijack this thread or anything, but doing a google of "cf query of query" brings this page up so it's become a good resource for QofQ victims. Thanks for your excellent blog.


Feb 10, 2010 at 10:45 PM // reply »
10,638 Comments

@Alan,

Please, never feel bad about contributing to the conversation; every time someone brings up a new point, it's an opportunity for us to learn something new.

The converting "" to numeric, maybe that happens if the value is NULL? Although I think QoQ should handle NULLs properly... although who knows, right??


Feb 24, 2010 at 3:33 PM // reply »
1 Comments

I display usage quarterly for various products in tabular format. I displays products in rows and monthly usage in column. When I query my sql database, I may get 1-3 records based on the entry. I create a coldfusion query which has 0 as usage for all month for a given product. I union both the query and sum up usage grouping date so I will get a record for every month irrespective for data in database. My problem starts while merging data as date format are different in cf query ans sql query. Data do not group due to date difference (sql 2010-10-01 00:00:00.0 do not match with {ts '2010-10-01 00:00:00'}). I cast sql date while merging data and bingo... it works.. thanks for the solution given it this article.

select start, cast(usagedate as Date) as usagedate from sql.qrymaxrow
union all select start, usagedate from cfm.rowscounter


Mar 19, 2010 at 10:21 AM // reply »
10,638 Comments

@Hiren,

Nice use of cast.


Don
Jun 23, 2010 at 8:26 PM // reply »
57 Comments

Hmmmm. My problem seems to fit into this maybe. Stranger things have happened. But this is NOT a QoQ. I am querying an Oracle 10g dtabase with an IN clause which is a query. So maybe it is having the same effect as a QoQ. Basically there is an ID number that can be either digits or a combo of letters and digits. So I do a query that retrieves a list of IDs. I may have B22,699,C22 type of return.

Now I want to get more info for those 3 and so I run the query

Select info
from infotable
where id IN (select ids from idtable)

I get things like "B22 is an invalid identifier"

It shows that the IDs are being put in the query without quotes around them. So I ran that query seperately and tried casting the ID as text but still no go. I tried manually putting single quotes around each one but when I build the string for the query it then puts another set of quotes in.

Any ideas?


Jun 29, 2010 at 10:23 AM // reply »
10,638 Comments

@Don,

Hmm, not sure about that one. I don't have any experience with Oracle, so this may very well be Oracle-specific. I have definitely use the IN with a sub-query inside of it with success. Are the ID in the top query and the IDS in the sub-query the same data type?


Sep 20, 2011 at 9:37 PM // reply »
4 Comments

god, u saved me


Sep 20, 2011 at 10:07 PM // reply »
4 Comments

<cfquery dbtype="query" name="qryCashReceipt">
select cashreceiptid, category + ' - ' as Dspstr1,
'#qryCashReceipt.category# - #DollarFormat(qryCashReceipt.amount)# (#dateformat(qryCashReceipt.createdate,"d/m/yy")#)' as Dspstr2
from qryCashReceipt
</cfquery>

this also work



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 3, 2012 at 10:49 PM
How I Got Node.js Running On A Linux Micro Instance Using Amazon EC2
Wow this was really helpful! Only thing I would add is you need to update your .bash_profile after you edit the secure_path. This is what I did: $ . ~/.bash_profile Otherwise, NPM won't be found. ... read »
Feb 3, 2012 at 10:14 PM
Pushing Base64-Encoded Images Over HTML5 WebSockets With Pusher And ColdFusion
@Ben, Just wanted to let you know that pusher are soon to start limiting sizes on messages. This was the detail that came through in the Feb dispatch: "However, we will soon be limiting the s ... read »
Feb 3, 2012 at 5:05 PM
Regular Expressions Make CSV Parsing In ColdFusion So Much Easier (And Faster)
I tried using your RegEx in my C# program, but it was matching an extra empty-string at the end and so I would end up with an extra field that doesn't exist, so I changed it to this: (^|,)("(?: ... read »
Feb 3, 2012 at 3:47 PM
ColdFusion Supports HTTP Verbs PUT And DELETE (As Well As GET And POST)
Josh Cyr posted this on Twitter just a little bit ago. Thought it was appropriate. http://stackoverflow.com/questions/1619152/how-to-create-rest-urls-without-verbs/1619677#1619677 ... read »
Feb 3, 2012 at 2:28 PM
Changing The Execution Context Of Your Self-Executing Function Blocks In JavaScript
@Michael, You definitely make a good point (and extra points for quoting movies - I love movies). When you use a return() statement to define the object's public API, it does provide a consistent a ... read »
Feb 3, 2012 at 2:04 PM
Changing The Execution Context Of Your Self-Executing Function Blocks In JavaScript
To quote Jurassic Park: "Just because you can doesn't mean you should". I completely, utterly disagree with the thought that this is more readable. Consider the current module pattern: if ... read »
Feb 3, 2012 at 1:10 PM
REST API Design Rulebook By Mark Masse
@Jordan, Yeah, WRML was created by Mark Masse (author of the book). I also found it to be a bit convoluted. I suppose it is intended to allow the Client to be able to programmaticaly respond to cha ... read »
Feb 3, 2012 at 1:08 PM
ColdFusion Supports HTTP Verbs PUT And DELETE (As Well As GET And POST)
@Jason, To be honest, I don't have good answers for that kinds of stuff. And, to the point, that is specifically why I *really* liked the REST API Design Rulebook by Mark Masse - he just cuts throu ... read »