Stuck with CFMX? XML trouble? Try this.

Crimson, the XML engine used by CFMX/CF6/CF6.1/whatever was old when CFMX came out. It was last updated in 2000 and abandoned with multiple bugs acknowledged and unfixed. We were running into issues with it in my current contract in mid-may (couple of boxes using CFMX because someone thinks they might have something customized that will break in 8 or 9) and I was asked to find a solution. A few false starts because the problem was unpredictable and simply stripping out extra whitespace seemed at first to fix the problem. Basically, the old XML parser reads your XML in chunks of, IIRC, 8000 characters. if the chunk ends inside a CDATA tag, it breaks. So by stripping whitespace we might have been moving the position of the cdata and making it not fail.

But to actually fix the problem, once it was finally diagnosed… difficult search, but happily, it turns out Brandon Purcell had the answer — you can change Coldfusion MX’s XML parser to use Xerces.

One minor update to his post:

 

SQL Coalesce

Have you guys ever seen the Coalesce command in SQL? I’d never heard of it til today, and it looks really useful.

Say you have a table of business contact information and you want to contact a user from it; but some of the businesses don’t have specific contacts, just a position; and some don’t have either…

SELECT COALESCE(ContactName,ContactPosition,BusinessName) as theContact FROM foo

If ContactName is null, theContact will be the value of ContactPosition. If that’s also null, it will be the value of BusinessName. Simple. handy. wish I’d known it 5 years ago.

Data truncated at ~32k… how to get CLOBbered

It was the strangest thing. A query using Coldfusion to a SQL 2005 server, extracting among other things, a large chunk of XML which needed to be parsed and transformed with XSL.

It worked fine most of the time… but occasionally there would be very large XML strings, and they would get cut off at 32k in length.

So, of course, I assume the database column is only that large and the data is being truncated on entry to it.

The DBA mentions that it’s an n-something data type and I immediately assume that’s the problem… darn 16 byte alphabets…

I ask him to convert it to VarChar(MAX).

The problem? Goes away. No more truncation.

I think nothing more of it… including not noticing that even the fields that were previously truncated now work. (probably because I was only parsing one day’s worth of data at a time)

Flash forward a few months… we bring it into production. Bam. Same problem, only much worse because there’s more data.

And now, because it’s in production and the database is from a vendor product, changing the db field is a huge deal.

A week or so goes by with it truncating as we talk to the vendor.

And then I think to myself… what the hell column type has a 32k limit? it’s 8k or frigging huge, with nothing in between. This is what I get for starting my database experience with MySQL… TEXT data type there is 65,535 characters; halve that for it being in unicode, and it’s about 32k. But we’re not working with MySQL here….

So I go hunting. Is it a limit in a stored procedure on insert? I can’t tell.. no acces to the procedures. Or even the database, really.

I finally whip out my CF_DBINFO tag and take a look at the table structure. It’s NText and lists the size as some huge number, way more than 32k. Weird.

I run a query to get the max length of the field and discover that len() is invalid for text fields. I research more and discover that you use datalength() for those. Again… way more than 32k. So where’s the problem???

It’s not my code… that’s a straightforward select. And why did it start working when we changed data types?

I started wondering if maybe our driver didn’t fully support SQL 2005. We had to switch from the default SQL driver that coldfusion uses because the default one doesn’t support SSL and we require encrypted connections. Would that bite us in the arse?

Yes and no. By default, the driver handles data over a given amount as a LOB… it sends it in chunks. But we didn’t have the DSN set to look for LOBs, so it would get the first 32k chunk and assume that was all.

One checkbox (CLOB – Enable Long Text Retrieval) in CF Administrator later… and everything’s magically working.

Oh, and to some extent, I was right… it appears the driver doesn’t fully understand SQL 2005. It only uses CLOBs on TEXT and NTEXT fields… VarChar(MAX) is exempted, despite being the same thing effectively. That’s why the dev system started working when we switched the data type.

So… lesson of the day… Don’t get CLOBbered. Check the box.

Night Sounds in Puerto Rico

Found this sitting in the sound recorder app on my phone. It’s a 16 second clip of what it sounds like at night in Puerto Rico, up in the jungly mountains. Specifically, it was recorded at the Casa Grande Mountain Retreat.

New Tricks

I’ve been a coldfusion developer for over 9 years now, and tinkered with web design for at least 12. It’s pretty rare for me to find something I’ve never used before and didn’t know existed in HTML… but today, I did.

The OPTGROUP tag is how you make non-selectable headings in select lists. I guess for some reason I always assumed that was done with javascript or CSS, but no, it’s a simple tag.

Proper Ordered List Hierarchy

In case I ever need it again, this is the CSS to force a “proper” ordered list hierarchy all the way to 6 layers deep. (pro tip – if it’s 6 layers deep, you’re doing something wrong)

<style type=”text/css”>
???? OL { list-style-type:upper-roman }
???? OL OL { list-style-type:upper-alpha }
???? OL OL OL { list-style-type:decimal }
???? OL OL OL OL { list-style-type:lower-roman }
???? OL OL OL OL OL { list-style-type:lower-alpha }
???? OL OL OL OL OL OL { list-style-type:lower-greek }
</style>

long time no post — excuse = homeownership

Oddly, hunting for a house and buying one is a bit time consuming.

All in all, I looked at about a dozen homes before deciding on one. It’s a 105 year old Queen Anne, a couple blocks from the river. I moved in a month or so ago and I’m still not completely settled in. It’s about 2200 finished square feet, technically 4 bedrooms 1.75 baths (but one bedroom is set up as a laundry room and I’m using another as an office). There’s also a great third floor/attic that’s finishable (and big enough that I could probably add a loft to it), and a 450 square foot 1 bedroom/1 bathroom “mother-in-law suite” over the “carriage house”, which I’m renting to a ND divinity student. On one side of the house is the neighborhood association building. On the other side — a pair of nuns. Across… ????a street that leads straight down to the river. ????Behind, the 2 car “carriage house”, and an alley, and a couple of houses that are currently being restored by the neighborhood association. So overall a pretty quiet location, if you ignore that the street is a fairly busy one and the hospital’s less than a mile away. Big yard for being in such an old section of town. I’ve been here almost a month now. Enjoying it thus far. We’ll see how it goes :)

And now, back to the regularly scheduled neglect of blog.

Coldfusion: DNS Reverse Lookup

I have no idea why this information was so difficult to find, but I’m posting it here in case I ever need it again.

To do a reverse lookup in coldfusion:

<cfscript>
rawIP = createObject(“java”, “java.net.InetAddress”).getByName(‘#ipaddress#’).getAddress();
hostname = createObject(“java”, “java.net.InetAddress”).getByAddress(‘#rawIP#’).getHostName();
chostname = createObject(“java”, “java.net.InetAddress”).getByAddress(‘#rawIP#’).getCanonicalHostName();
</cfscript>

Note — this is slow. If you’re doing them in bulk, you may need to go in small batches or set a higher timeout.

Also, this was perhaps useful: http://api.hostip.info/get_html.php?ip=#ipaddress#&position=true — returns the country, city, state, and geotag info for an IP address, where available.

Distance in CF — Mostly useless, but fun

Assumption: table named locations that has a location name and the location’s latitude & longitude as a single field, with lat and lon comma separated, both in signed degrees format.

This is an intentional cartesian join… so if you have a lot of locations, use with care.

<cfquery datasource=”MyDSN” name=”getDist”>
SELECT DISTINCT????????????
???????????? a.latlon AS thestart,
???????????? a.locName AS startname,
???????????? b.latlon AS theend,
???????????? b.locName AS endname
FROM???????????????? locations a
CROSS JOIN???????????? locations b
WHERE???????????????? a.locName<> b.locName
ORDER BY???????????????? a.locName, b.locName
</cfquery>

<cfoutput query=”getDist” group=”startname”>
<h4>#getDist.startname# to…</h4>
<ul><cfoutput>
<li>#getDist.endname# — #3963.0*acos(sin(listfirst(thestart)/57.295779513082323)*sin(listfirst(theend) / 57.295779513082323)+ cos(listfirst(thestart) / 57.295779513082323)*cos(listfirst(theend) / 57.295779513082323)*cos((listlast(theend) – listlast(thestart)) / 57.295779513082323))# Miles
</li>
</cfoutput>
</ul>
</cfoutput>

———————

This is based on a snippet of SQL code someone forwarded to me which was signed “RBarryYoung, 31-Jan-2009″ — so credit to RBarryYoung for it. :)