Open Office XML an ISO Standard?

I guess it was unavoidable. Open Office XML looks like it garnered enough votes to become an ISO standard. Open Office XML is Microsoft's document format of choice that is used in Office 2007. Those .docx files...OOXML. Time to get started on that ODF (Open Document Format) CFC I have been thinking about. :^)

CFQueryparam and NULLs

This topic is far from new, but I think it deserves another mention. The cfqueryparam tag has an optional attribute, null, that allows you to pass a NULL value to the database. Note, this is a SQL NULL, not the empty string that replaces a NULL value in ColdFusion. The ColdFusion docs state that the attribute accepts either a yes or no value. However, like many other tags in ColdFusion, a boolean works just fine, and has the benefit of creating easier to read code. I find

view plain print about
1<cfqueryparam value="#mystring#" cfsqltype="cf_sql_varchar" maxlength="5" null="#NOT len(mystring)#">
is clearer and easier to read than
view plain print about
1<cfqueryparam value="#mystring#" cfsqltype="cf_sql_varchar" maxlength="5" null="#yesNoFormat(NOT len(mystring))#">

CF by CF

I usually do not get the opportunity to use cffile to write files to the file system. Today, however, I got the chance to use action="write" while working on the beginnings of a code generator. The proof-of-concept code creates a CF file in a specific directory, much in the way Fusebox 5 generates its parsed files (in fact, Fusebox was my inspiration). The code generator uses a Java StringBuffer to store the contents of the file before writing it to the file system:

view plain print about
1<!--- Line feeds need a carriage return and a line feed character --->
2<cfset variables.crlf = chr(13) & chr(10)>
3<!--- A Java StringBuffer is more efficient than using a string variable. --->
4<cfset variables.contentBuffer = createObject("java", "java.lang.StringBuffer").init()>
5<!--- Add the contents of the file to the buffer. --->
6<cfset variables.contentBuffer.append('<cfset variables.message = "CF generated me!">').append(variables.crlf)>
7<cfset variables.contentBuffer.append('<cfoutput>##variables.message##</cfoutput>')>

Note the double pound signs inside the cfoutput tags. If I did not escape the pound signs by doubling them, CF would think variables.message is an actual variable that needed to be parsed. Once the content buffer contains the full contents of the file, cffile swings into action to create the physical CFM file:
view plain print about
1<!--- cffile needs an absolute path, so place the file in the current directory. --->
2<cfset variables.filePath = getDirectoryFromPath(expandPath("*.*"))>
3<cffile action="write" file="#variables.path#/myfile.cfm" output="#variables.contentBuffer.toString()#">
Opening up myfile.cfm we see:
view plain print about
1<cfset variables.message = "CF generated me!">
2<cfoutput>#variables.message#</cfoutput>

Query of Queries and an Insert

A good friend of mine, and fellow CFer, came to me with an interesting situation yesterday. She was trying to insert the contents of a query resultset into a database table. To do this she tried to use a query of queries, which failed with the message "Query Of Queries syntax error. Encountered "INSERT.[sic]" Exact code changed to protect the innocent:

view plain print about
1<cfquery name="update" dbtype="query">
2    INSERT INTO article_info (id, title)
3    SELECT id, title
4    FROM articles_query
5</cfquery>
where article_query is a dynamically created query object and article_info is a physical database table.

One aspect of the problem is that query of queries does not support SQL statements other than SELECT. The ColdFusion docs make this point, but not explicitly, when defining query of queries:

A query that retrieves data from a record set is called a Query of Queries. After you generate a record set, you can interact with its results as if they were database tables by using Query of Queries. Livedocs - ColdFusion 8 - Using Query of Queries

Another part of the problem is the dbtype="query" attribute in the query. This tells ColdFusion that we are working with a query of queries. Since article_info is not a query object, CF will not find it in memory.

The solution we worked out is to loop over the query object and build the single INSERT statement she wanted using a series of SELECT...UNION ALL statements:

view plain print about
1<cfquery name="update" datasource="#dsn#">
2    INSERT INTO article_info (id, title)
3    <cfoutput query="articles_query">
4        SELECT #id#, '#title#'
5        <cfif currentrow LT article_info.recordcount>UNION ALL</cfif>
6    </cfoutput>
7</cfquery>

The result of the output loop creates an INSERT statement that looks like:

view plain print about
1INSERT INTO article_info (id, title)
2SELECT 1, 'Article One' UNION ALL
3SELECT 1, 'Article Two' UNION ALL
4...
5SELECT 10, 'Article Ten'

I understand on the surface why query of queries only support SELECT queries. A query object does not always originate from a database - tags such as cfdirectory and cfsearch create query objects. I'm still curious, however, about the inner workings of query of queries. Is it possible in theory to allow an INSERT or DELETE statement?

To Pound Or Not to Pound

ColdFusion is very easy to start learning. As a tag-based language, it is very approachable to anyone who is comfortable with HTML. One area where many CF novices have trouble, though, is with improper use of the pound sign (#), that little mark that tells the ColdFusion server to return the value of a variable. Novice CFers often overuse the pound sign, surrounding a variable name when it is not needed or even desirable.

I believe proper use of the pound sign can be distilled down to two basic rules. Pound signs are needed only in the following circumstances:

  • If the variable name is surrounded in quotes
  • If you want to write the value of the variable to the screen/document/email
The first rule is where many CF novices trip up. When working with a variable name inside a tag, pound signs are often not needed. Here are a few examples, with corrections, of improper pound sign usage (I have seen all of these when conducting code reviews):

view plain print about
1IMPROPER:
2<cfset #myvar# = 1>
3
4PROPER:
5<cfset myvar = 1>
6
7IMPROPER:
8<cfset myvar = #listLen(mylist)#>
9<cfset myvar = #listLen(#mylist#)#>
10
11PROPER:
12<cfset myvar = listLen(mylist)>

Debugging With CFLOG

Debugging in ColdFusion has always meant, for me, liberal use of the cfdump and cfabort tags. However, this tried and true technique does not always work.

I came across one such situation the other day while working with a Java applet for viewing Crystal Reports. When I attempted to view a report, I received a blank viewer window. The problem was, my report was not loading. Just looking at the code didn't help, I needed to step through the code and see where the problem lay.

One of the applet parameters is the path to the template that interacts with a COM object that makes up the backend reporting engine. Without going into too much detail, the parameter looks something like:

view plain print about
1<param name="ReportName" value="reportServer.cfm" />

Since the template is called by the applet, the output from a cfdump tag will not appear on the screen.

Enter cflog. I placed a cflog tag in various places throughout the reportServer.cfm template to try to figure out where the error that caused the report not to load was thrown. I started with log messages to trace the flow of the request through the various code methods. For example:

view plain print about
1<cflog file="reportviewer" text="Entering parseQueryString()">

helped me figure out if the query string was being parsed to retrieve configuration data. I also placed one at the end of the parseQueryString() method.

I ran the page, then checked the ColdFusion log files (%cfusion%\logs) to see if a log file named reportviewer.log existed and what sort of information it contained. Sure enough, the program was entering, but not exiting parseQueryString(). I had incorrectly initialized several variables.

The above method works great for simple values. However, one of the most useful aspects of cfdump is how easy it is to view complex values. cflog, however, cannot simply write an array to a log file. Instead, the complex value needs to be translated into a string. WDDX helps with that task:

view plain print about
1<!--- FAILS: cflog cannot directly write complex values to a log --->
2<cfset myArray = arrayNew(1)>
3...
4<cflog file="reportserver" text="#myArray#>
5
6<!--- SUCCESS: Serialize the array, then write the WDDX packet to a log --->
7<cfset myArray = arrayNew(1)>

8...
9<cfwddx action="
cfml2wddx" input="#myArray#" output="wddxPacket">
10<cflog file="
reportserver" text="#wddxPacket#">

Unless you are very good a reading XML (and who isn't) you will need to take the WDDX string out of the log and manipulate it to view its contents. Hint: cfdump :)

It's A Mac

I do a lot of my personal development work on a notebook computer. Except for some graphic and publication design work a few jobs ago, I have always used a PC running Windows. However, I have (mostly) fond memories of using OS 9 and OS X, so I decided to take the plunge and replace my aging Sony Vaio, running Windows XP Pro, with a MacBook Pro running Leopard, OS 10.5.

The experience in the Apple Store in Tysons Corner was certainly not what I expected. Since it was midday on a Saturday, it was rather busy. Regardless, I was approached at least three times while I was checking out the Macbooks. My questions were answered, I checked out right at the display table, and walked out with a 2.4GHz MacBook Pro. Very relaxed, very easy.

Adding the notebook to my wireless network was a snap. Soon I was downloading and installing everything I need to develop on the Mac: Firefox, Eclipse, CFEclipse, etc. I hit a major snag with ColdFusion 8, which does not come with a connector for Apache 2. After much Googling and several installation attempts, I finally had success following along with Matthew Wallace's video guide. Thanks, Matthew, for a great resource.

189 Days

Nothing like a new job to help distract me from keeping my writing promise to myself. Ok, so that is not a good excuse, but I'm sticking with it.

Keep tuned, I have plenty to blog about.

CFStack Part 2 - Push, Peek, Pop

Continuing from my last post about stacks, let's take a look at what needs to be done to add, look at, and remove an item from a stack.

Push

Adding an item is done through the push method:

view plain print about
1<cffunction name="push" displayname="push" hint="I push an item to the top of the stack." access="public" output="false" returntype="Any">
2    <cfargument name="item" type="Any" required="true" />
3    <cfset var local = structNew() />
4    
5    <cfset arrayPrepend(getStackData(), arguments.item) />
6    
7    <cfreturn arguments.item />
8</cffunction>

A quick note. The getStackData method is a simple helper method that returns the current stack array.

Since the stack is an array, the built-in arrayPrepend function in ColdFusion makes it easy to add an item to the top of the stack. ArrayPrepend adds an element to the first position in an array, and pushes any other array elements down one position.

Peek

Now that the stack has data, we can use the peek method to take a look at the top item:

view plain print about
1<cffunction name="peek" displayname="peek" hint="I look at and return the object at the top of the stack." access="public" output="false" returntype="Any">
2    <cfset var local = structNew() />
3    <cfset local.result = "" />
4    <cfset local.stack = getStackData()>
5    
6    <cfif NOT empty()>
7        <cfset local.result = local.stack[1] />
8    </cfif>
9    
10    <cfreturn local.result />
11</cffunction>

This method uses another helper methods, empty(), which returns true if the stack array is empty.

Since we are looking for the first item on the stack, ColdFusion again makes it simple to grab the first element of the stack array. Remember, ColdFusion is not zero-based, so the array element at position 1 is the top element.

Pop

Removing the item at the top of the stack is accomplished with the pop method:

view plain print about
1<cffunction name="pop" displayname="pop" hint="I remove and return the object at the top of the stack." access="public" output="false" returntype="Any">
2    <cfset var local = structNew() />
3    <cfset local.result = peek() />
4    
5    <cfset arrayDeleteAt(getStackData(), 1) />
6    
7    <cfreturn local.result />
8</cffunction>

The pop method both removes the the top element from the stack array, done here with the ColdFusion arrayDeleteAt function, and returns that element to the calling code.

The push, peek, and pop methods are the most often used methods when working with a stack. Since a stack, by definition, only exposes its top item, these three methods add, examine, and remove this element.

A Stack of CF - What is a Stack?

I was rereading Java for ColdFusion Developers (by Eben Hewitt) the other day and came across the concept of a stack. So, in the spirit of "well, why not do it in CF too," I decided to create a small utility CFC that contains the basic functionality found in the java.util.Stack class.

The Wikipedia article defines a stack as "a temporary abstract data type and data structure based on the principle of Last In First Out (LIFO)." One real-world example of a stack is a roll of coins. Closed on one end, you can only add or subtract coins from the top of the stack.

After looking at the Sun Java API for the Stack class, I decided on the following basic structure for my Stack CFC:

view plain print about
1<cfcomponent displayname="Stack" output="false">
2    
3    <cfset instance = structNew() />
4    
5    <!--- Constructor --->
6    <cffunction name="init" displayname="init" hint="I am the constructor. I create an empty stack." access="public" output="false" returntype="Stack">
7        <cfset instance.stack_data = arrayNew(1) />
8        <cfreturn this />
9    </cffunction>
10    
11    <!--- Public Methods --->
12    <cffunction name="empty" displayname="empty" hint="I test to see if the stack is empty. I return true if the stack is empty." access="public" output="false" returntype="boolean">
13        ...
14    </cffunction>
15
16    <cffunction name="peek" displayname="peek" hint="I look at and return the object at the top of the stack." access="public" output="false" returntype="Any">
17        ...
18    </cffunction>
19
20    <cffunction name="pop" displayname="pop" hint="I remove and return the object at the top of the stack." access="public" output="false" returntype="Any">
21        ...
22    </cffunction>
23
24    <cffunction name="push" displayname="push" hint="I push an item to the top of the stack." access="public" output="false" returntype="Any">
25        <cfargument name="item" type="Any" required="true" />
26        ...
27    </cffunction>
28
29    <cffunction name="search" displayname="search" hint="I return the stack position for an object." access="public" output="false" returntype="numeric">
30        <cfargument name="item" type="Any" required="true" />
31        ...
32    </cffunction>
33    
34    <cffunction name="getElementCount" displayname="getElementCount" hint="I return the number of elements in the stack." access="public" output="false" returntype="numeric">
35        ...
36    </cffunction>
37
38    <!--- Private Methods --->
39    <cffunction name="getStackData" displayname="getStackName" hint="I return the stack array." access="private" output="false" returntype="array">
40        ...
41    </cffunction>
42</cfcomponent>

An array makes the most sense to me for storing the contents of a stack, so the init method creates an empty array instance variable to initialize the stack. I prefer to create a structure called "instance" within my CFCs to handle instance data. Fully scoped, the stucture's name is variables.instance.

I'll walk through the remainder of the CFC in future posts.

Previous Entries / More Entries