Shaun Mccran

My digital playground

26
F
E
B
2009

Differences between cfQueryParam "cf_sql_date" and "cf_sql_timestamp"

I was recently looking at a report generator, and came across a conflict in the mySql query dealing with the date objects.

The report returns a set of records between two dates, using cfqueryparam, but there seemed to be a problem in running the query using certain dates.

Running it from a browser provided differing results from running it directly in a sql interface. So where was the error?

The original code was using the "cf_sql_date" type to pass the date time off to the sql engine. It appears that this data type is not transferred as a date time value, but as an incompatible numeric value, that is not comparable to the mySql datetime I am querying against.

view plain print about
1AND table.ap_startdate >= <cfqueryparam cfsqltype="CF_SQL_DATE" value="#createodbcdate(arguments.rangefrom)#">
2
3AND table.ap_enddate <= <cfqueryparam cfsqltype="CF_SQL_DATE" value="#createodbcdate(arguments.rangeto)#">

There are a wealth of articles online about passing date values into a variety of database technologies, but this Adobe post was very helpful.

This article shows a handy table of cfsqltypes and how they map to different database management systems.

Using something like sql profiler you can clearly see the difference between cf_sql_date and cf_sql_timestamp, where cf_sql_date is being truncated to just a date value (actually evaluates as a numeric value) and a full date time stamp that cf_sql_timestamp generates.

view plain print about
1AND table.ap_startdate >= <cfqueryparam cfsqltype="cf_sql_timestamp" value="#createodbcdate(arguments.rangefrom)#">
2
3AND table.ap_enddate <= <cfqueryparam cfsqltype="cf_sql_timestamp" value="#createodbcdate(arguments.rangeto)#">

Changing the code to the above example completely resolves this issue.

23
F
E
B
2009

Ever needed to make a template 'sleep' for a defined period?

One of the code snippets I've had scattered around is a short java command to make the current thread sleep, for a set period.

Its handy if you want to add a set period of delay to an application, for any reason.

view plain print about
1<cfscript>
2
3thread = createObject("java", "java.lang.Thread");
4thread.sleep(javaCast("long", 5000));
5
6
</cfscript>

It creates the java thread object, and uses the sleep method to pause the thread for whatever numeric value you give it. In this example 5000ms.

23
F
E
B
2009

Non selectable drop down options in forms

I was recently developing an application that had several select fields in a form. The first dynamically populated the second, but with differing sets of data, that needed to be within the same select box, but seperated in some way.

It was only then that I found there is a 'optgroup' html tag for select boxes! This tag is used to group together related options in a select list. It automatically bolds the text, and is unselectable.

view plain print about
1<cfset variables.mylist = "1,2,3,4">
2<cfset variables.mySecondlist = "5,6,7,8">
3
4<cfoutput>
5<select name="number">
6<cfloop list="#variables.mylist#" index="I">
7    <option value="#I#">#I#</option>
8</cfloop>
9
10<optgroup label="Second List"></optgroup>
11
12<cfloop list="#variables.mySecondlist#" index="I">
13    <option value="#I#">#I#</option>
14</cfloop>
15
16</select>
17
18</cfoutput>

Just insert it where you want your category break to be, and assign it some text.

Handy for breaking up large sections of options.

19
F
E
B
2009

Consuming 360 Voices XML data feeds - 360 Voice part 2

www.360voice.com hosts a service where you can interrogate your GamerTag through an XML web feed. They host the service themselves, but also provide an API so that you can remotely call it, and use it however you want. So I thought I'd consume their service using ColdFusion, translate it, and display it here. Firstly I want to try and reduce the service overhead. So I will call the 360 voice service on the first instance of page initialisation, and then write the result to a file. The service only updates once a day, so I can safely assume that caching it daily isn't going to be too out of date. Firstly I've setup some global variables to set the file path location.
view plain print about
1<!--- setup the filename --->
2<cfset variables.filepath = GetBaseTemplatePath()>
3<cfset variables.filepath = replace(variables.filepath, 'include.cfm', '', 'all')>
4<cfset variables.todaysfile = variables.filepath & "tmp\#DateFormat(NOW(), 'dd-mm-yyyy')#.xml">
Then check for the existence of a file with todays date as the name. If the file exists, read it and use it, otherwise make a cfhttp call to the url, passing in any of the filtering url variables that the 360 voice API documents, in this case just my gamer tag.
view plain print about
1<cfif fileExists(variables.todaysfile)>
2    <!--- Read local file --->
3    <cffile action="read" file="#variables.todaysfile#" variable="xmlfile">
4    <cfscript>
5        xmlfile = xmlparse(xmlfile);
6    
</cfscript>    
7<cfelse>
8    <cfhttp url="http://www.360voice.com/api/blog-getentries.asp?tag=ect0z" method="GET" charset="utf-8">
9        <cfhttpparam type="Header" name="Accept-Encoding" value="deflate;q=0">
10        <cfhttpparam type="Header" name="TE" value="deflate;q=0">
11    </cfhttp>
12    <cfscript>
13        xmlfile = xmlparse(cfhttp.filecontent);
14    
</cfscript>    
15    <cffile action="write" file="#variables.todaysfile#" output="#xmlfile#">
16</cfif>
In the code above I am also using two cfhttpparams to deflate the return response from the service, as I was having issue with this in a compressed format. (Read more here). Now that we have the content and we've parsed it out into an XML object we need to search through and pick out the elements we want. First we write out the header details from the parent node of the xml document. Create an Array, and map the contents to the child node you want. In this case the "api.info" node. Doing this allows you to treat the previous XML object as a standard Array, so we can loop over it, and pick out the elements we want.
view plain print about
1<cfset arrHeader = xmlfile.api.info>
2<cfoutput>
3    <cfloop index="i" from="1" to="#ArrayLen(arrHeader)#">
4    <img src="#arrHeader[i].tile.XmlText#" alt="Gamer Icon"> - 360 Voice.com Blog
5    <!--- #arrHeader[i].link.XmlText# --->
6    </cfloop>
7</cfoutput>
Now we will do much the same thing with the blog contents, but using a different XML child Node for the Array.
view plain print about
1<cfset arrEntries = xmlfile.api.blog.XmlChildren>
2<cfoutput>
3    <cfloop index="i" from="1" to="#ArrayLen(arrEntries)#">
4        <b>#arrEntries[i].title.XmlText# -#arrEntries[i].date.XmlText#</b><br/>
5        #arrEntries[i].body.XmlText#
6        <p><br/></p>
7    </cfloop>
8</cfoutput>
Again just loop through the Array, picking out the elements you want. Next I will add pagination, and possible look at some of the other data that 360 voice stores in its API, such as gamer badges etc.... but that's another article.

_UNKNOWNTRANSLATION_ /