New Features in ColdFusion Server 4.0.1

ColdFusion 4.0.1 introduces a number of new features in the following areas:

CFML

Advanced Security

Application framework

ColdFusion engine and Administrator

Database

Other new features


TIMEOUT Attribute for CFHTTP

CFHTTP now has a TIMEOUT attribute that allows you to specify a request timeout in seconds. This attribute is applicable to both GET and POST methods.

ColdFusion uses an asynchronous processing model to achieve this functionality. By default, asynchronous processing is ON for every request. This has some important ramifications. We take into account timeout values that are:

The timeout value that is passed in the URL will always override the timeout that gets set in the ColdFusion Administrator. ColdFusion takes the lesser of the values from the TIMEOUT attribute that gets passed in the tag and the timeout value in the Administrator or URL. This ensures that the request will timeout when or before the page does. If no timeout is set in the Administrator or passed in the URL, nor defined in the CFHTTP tag, synchronous processing of the request will occur, and the timeout is infinite.


New TYPE Attribute for CFLOCK

CFLOCK has a new optional TYPE attribute.

<CFLOCK NAME="lockname" 
TIMEOUT="timeout in seconds "
THROWONTIMEOUT="Yes/No" TYPE="ReadOnly/Exclusive">
<!--- CFML to be synchronized --->
</CFLOCK>

A READONLY lock allows more than one request to read shared data. An EXCLUSIVE lock allows only one request to read or write to shared data. Exclusive locks are required to ensure the integrity of these updates, but they have a significant impact on performance. Read-only locks are faster. If you have a performance-sensitive application, you should substitute read-only locks for exclusive locks wherever it is possible, for example, when updating shared data.


Enhanced Scheduling Engine

The ColdFusion scheduling engine has been enhanced with asynchronous operation. This feature improves performance and helps ColdFusion manage scheduled events that have been submitted for execution, but fail to complete. In the past, a single synchronous execution thread was reserved for scheduling. Now, ColdFusion creates as many threads as necessary to submit and execute scheduled events.


New Performance Monitor Configuration File

A new Windows NT Performance Monitor configuration file has been added to ColdFusion that is pre-configured to monitor ColdFusion Server activity. The Performance Monitor configuration file, ColdFusionServer.pmc is installed in cfusion\bin.

To monitor ColdFusion Server activity, click on the ColdFusion Performance Monitor icon in the ColdFusion Server Program group. You can also open the Performance Monitor utility and then open the cfusion/bin/ColdFusionServer.pmc file.


Custom Tag Argument Passing Via CFML Structures

Attributes can be passed to custom tags via the reserved attribute ATTRIBUTECOLLECTION. ATTRIBUTECOLLECTION must reference a structure; the structure's key/value pairs are copied to the custom tag's ATTRIBUTES scope.

Syntax

Semantics

The key/value pairs contained within the structure specified by ATTRIBUTECOLLECTION will be copied into the ATTRIBUTES scope. This has essentially the same effect as specifying these attributes in the custom tag's attribute list.

ATTRIBUTECOLLECTION may be freely mixed with other attributes within the custom tag's attribute list.

ATTRIBUTECOLLECTION is now a reserved attribute name

Custom tag processing now reserves ATTRIBUTECOLLECTION to refer to the structure holding a collection of custom tag attributes. If ATTRIBUTECOLLECTION does not refer to such a collection, the custom tag processor will raise a TEMPLATE exception.

Accessing attribute values within the custom tag

A custom tag invoked by the two examples above may refer to #attributes.x# and #attributes.y# to access the attributes passed via structure.

Setting values with CFASSOCIATE

If the called custom tag uses a CFASSOCIATE tag to save its attributes in the base tag, the attributes passed via structure will be saved as independent attribute values, with no indication that they were aggregated into a structure by the custom tag's caller.

Examples

Via CFMODULE

<cfset zort=StructNew()>
<cfset zort.X = "-X-">
<cfset zort.Y = "-Y-">
<cfmodule template="testtwo.cfm" 
    a="blab" 
    attributecollection=#zort# 
    foo="16">

Via shorthand

<cfset zort=StructNew()>
<cfset zort.X = "-X-">
<cfset zort.Y = "-Y-">
<cf_testtwo a="blab" attributecollection=#zort# foo="16">

Accessing attributes within the custom tag

If testtwo.cfm contains this CFML:

---custom tag ---<br>
  <cfoutput>#attributes.a# #attributes.x# #attributes.y# 
#attributes.foo#</cfoutput>
  <br>--- end custom tag ---

Its output will be:

---custom tag ---
blab -X- 12 16 
--- end custom tag ---

New Euro Currency Functions

Two new functions have been added to ColdFusion to support the newly implemented Euro.

LSEuroCurrencyFormat

Returns a currency value using the convention of the locale and the Euro as the currency symbol. Default value is "local."

Note: The locale is set with the SetLocale function.

Syntax

LSEuroCurrencyFormat(currency-number [, type ])

The LSEuroCurrencyFormat function can display the Euro symbol (a) only on Euro-enabled computers, such as Windows NT 4.0 SP4, that have Euro-enabled fonts installed.

This function is similar to LSCurrencyFormat except that LSEuroCurrencyFormat displays the Euro currency symbol (a) or the international Euro sign (EUR) if you specify the type as local or international , respectively, and the Euro is the accepted currency of the locale.

LSParseEuroCurrency

Converts a locale-specific currency string that contains the Euro symbol (a) or sign (EUR) to a number. Attempts conversion through each of the three default currency formats (none, local, international). Returns the number matching the value of string.

Syntax

LSParseEuroCurrency(currency-string)

Usage

The LSParseEuroCurrency function can read the Euro symbol (a) only on Euro-enabled computers, such as Windows NT 4.0 SP4, that have Euro-enabled fonts installed.

This function is similar to LSParseCurrency except that LSParseEuroCurrency parses only the Euro currency symbol (a) or the international Euro sign (EUR), not other currency symbols such as the dollar sign ($) or the pound sign (£).


New PORT attribute for CFCACHE

The CFCACHE tag now supports the PORT attribute.

Use this optional attribute to specify the port number of the web server from which the page is being requested. The port number defaults to 80. The port number is useful because the CFCACHE code calls CFHTTP. If the port number is specified correctly in the internal call to CFHTTP, the URL of each retrieved document is resolved to preserve links.


Fast Date/Time Processing Changes for Solaris

A new option has been added to the ColdFusion Administrator for Solaris only. When checked, ColdFusion will use a simpler, faster Date/Time parsing routine when evaluating expressions. This will improve performance, but may affect backward compatibility. This does not affect the ParseDateTime function.


New PASSTHROUGH Attribute

A new attribute, PASSTHROUGH, has been added to the CFFORM, CFINPUT, and CFSELECT tags. This attribute allows developers to enter any HTML attributes that are not explicitly allowed in these tags and have the attribute value passed through to the HTML generated for these form tags.


QueryAddColumn Function

The QueryAddColumn function adds a new column to a specified query and populates the column's rows with the contents of a one-dimensional array. The function returns an integer representing the column index in the query. Padding is added, if necessary, on the query columns to ensure that all columns have the same number of rows.

Syntax

QueryAddColumn(query, column-name, array-name)

query

Name of a query that was created with QueryNew.

column-name

The name of the new column.

array-name

The name of the array whose elements are to populate the new column.

Usage

This function is particularly useful to Oracle developers who would like to generate a query object from the arrays of output parameters which Oracle stored procedures can generate.

Example

<!--- This example shows the use of QueryAddColumn --->

<HTML>

<HEAD>
<TITLE>
QueryAddColumn Example
</TITLE>
</HEAD>

<BASEFONT FACE="Arial, Helvetica" SIZE=2>

<BODY  bgcolor="#FFFFD5">

<BODY>

<H3>QueryAddColumn Example</H3>

<P>This example adds three columns to a query object and then populates 
the columns with the contents of three arrays.</P>  

<P>After populating the query, the example shows, in tabular format, the
contents of the columns.</P> 

<!--- make a new query --->
<CFSET myQuery = QueryNew("")>

<!--- create an array --->
<CFSET FastFoodArray = ArrayNew(1)>
<CFSET FastFoodArray[1] = "French Fries">
<CFSET FastFoodArray[2] = "Hot Dogs">
<CFSET FastFoodArray[3] = "Fried Clams">
<CFSET FastFoodArray[4] = "Thick Shakes">

<!--- add a column to the query --->
<CFSET nColumnNumber = QueryAddColumn(myQuery, "FastFood", 
FastFoodArray)>

<!--- create a second array --->
<CFSET FineCuisineArray = ArrayNew(1)>
<CFSET FineCuisineArray[1] = "Lobster">
<CFSET FineCuisineArray[2] = "Flambe">

<!--- add a second column to the query --->
<CFSET nColumnNumber2 = QueryAddColumn(myQuery, "FineCuisine", 
FineCuisineArray)>

<!--- create a third array --->
<CFSET HealthFoodArray = ArrayNew(1)>
<CFSET HealthFoodArray[1] = "Bean Curd">
<CFSET HealthFoodArray[2] = "Yogurt">
<CFSET HealthFoodArray[3] = "Tofu">

<!--- add a third column to the query --->
<CFSET nColumnNumber3 = QueryAddColumn(myQuery, "HealthFood", 
HealthFoodArray)>

<table cellspacing="2" cellpadding="2" border="0">
<tr>
    <th align="left">Fast Food</th>
    <th align="left">Fine Cuisine</th>
    <th align="left">Health Food</th>
</tr>
<CFOUTPUT query="myQuery">
<tr>
    <td>#FastFood#</td>
    <td>#FineCuisine#</td>
    <td>#HealthFood#</td>
</tr>
</CFOUTPUT>
</table>

<P><B>Note:</B> Because there are fewer elements in the Fine Cuisine and 
Health Food arrays, QueryAddColumn 
added padding to the corresponding columns in the query.</P>
 
</BODY>
</HTML>

Changes to the QueryNew Function

The QueryNew function has been modified so that it can accept an empty string argument for a queryname. This facility was added to allow developers to use the resulting query to pass data on to the QueryAddColumn function.


CreateUUID Function

The CreateUUID function returns a new Universally Unique Identifier (UUID) formatted as 'XXXXXXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX' where 'X' stands for a hexadecimal digit (0-9 or A-F).

Syntax

CreateUUID()

Remarks

The UUIDs returned by the CreateUUID function are a 35 character string representations of globally unique 128-bit integers. Use the CreateUUID function when you need an absolutely unique string that you will use as a persistent identifier in a distributed environment. To a very high degree of certainty, this function returns a unique value - no other invocation, on the same or any other system (networked or not), should return the same value.

UUIDs are used by distributed computing frameworks such as DCE/RPC, COM+, and CORBA. With ColdFusion you can use UUIDs as primary table keys for applications where data is stored on a number of shared databases. In such cases, using numeric keys may cause primary key constraint violations during table merges.

Example

Here's an example of the CreateUUID()function.

Create two different UUIDs in a short period of time:<br>
<CFOutput><ul>
    <li>First UUID: #CreateUUID()#</li>
    <li>Second UUID: #CreateUUID()#</li>
</ul></CFOutput>
They are different, aren't they?

New Date/Time Functions

The following date/time functions have been added to ColdFusion:

GetTimeZoneInfo

Returns a structure containing time zone information for the machine on which this function is executed. The structure contains four elements with the following keys:

Syntax

GetTimeZoneInfo()

Example

<cfset info = GetTimeZoneInfo()>
<cfoutput> Total offset is # info.utcTotalOffset#<BR></cfoutput>
<cfoutput> Hour offset is # info.utcHourOffset#<BR></cfoutput>
<cfoutput> Minute offset is # info.utcMinuteOffset#<BR></cfoutput>
<cfoutput> Is DST On? # info.isDSTOn#<BR></cfoutput>

DateConvert

Converts local time to UTC or UTC to local time based on parameters. This function uses the daylight savings settings in the executing machine to compute the daylight savings time if required. Note that these results may not be always accurate outside the United States since the conversions assume US rules for daylight savings settings which may not be valid for the country and timezone in which this is being computed.

Syntax

DateConvert(conversion-type, date)

conversion-type

Should be either "utc2Local" for converting from UTC to local time or "local2Utc" to convert from local time to UTC.

date

A valid CFML date.

Example

Converting current time to UTC and back

<cfset d = Now()>
<cfoutput>Testing with #d#<BR></cfoutput>
<cfset dutc = DateConvert("local2utc",d)>
<cfoutput>UTC is #dutc#<BR></cfoutput>
<cfoutput>Converting back to local</cfoutput>
<cfoutput>Local time is #DateConvert("utc2local",dutc)#<BR></cfoutput>

Converting a specific date-time to UTC and back

<cfset dd= CreateDateTime(1997,12,31,22,20,5)>
<cfoutput>Testing with #dd#<BR></cfoutput>
<cfset dutc = DateConvert("local2utc",dd)>
<cfoutput>UTC is #dutc#<BR></cfoutput>
<cfoutput>Converting back to local</cfoutput>
<cfoutput>Local time is #DateConvert("utc2local",dutc)#<BR></cfoutput>

Changes to DateCompare Function

The DateCompare function now supports a new third parameter, datePart, which can be used to specify the granularity of the comparison.

DateCompare

Syntax

DateCompare (date1,date2,[datePart="s"])

date1

Date/time object in the period from 100 AD to 9999 AD.

date2

Date/time object in the period from 100 AD to 9999 AD.

datePart

Can have the following values:

s - compare date till second

n - compare date till minute

h - compare date till hour

d - compare date till day

m - compare date till month

yyyy - compare date till year

The default is "s" - i.e., if the 3rd parameter is not specified a full date/time comparison is performed.


New List Functions

The following list functions have been added to ColdFusion:

ListCount

Returns the number of instances of value in list. The search is case-sensitive.

See also ListCountNoCase, ListFind and ListContains

Syntax

ListCount(list, value, [delimiters])

list

List being searched.

value

Number or string being counted among elements of list.

delimiters

Set of delimiters used in list.

Example

Here's an example of the ListCount function.

ListCount("John,Tom,Ben,John,Lisa,Mark","John") 

Returns 2, i.e. the number of instances of John in the list.

ListValueCount

Returns the number of instances of value in list. The search is case-sensitive.

Syntax

ListValueCount(list, value, [delimiters])

list

List being searched.

value

Number or string being counted among elements of list.

delimiters

Set of delimiters used in list.

Example

Here's an example of the ListCount function.

ListCount("John,Tom,Ben,John,Lisa,Mark","John") 

Returns 2, i.e., the number of instances of John in the list.

ListValueCountNoCase

Returns the number of instances of value in list. The search is case-insensitive.

See also ListValueCount, ListFind and ListContains

Syntax

ListValueCountNoCase(list, value, [delimiters])

list

List being searched.

value

Number or string being counted among elements of list.

delimiters

Set of delimiters used in list.

Example

Here's an example of the ListCount function.

ListCount("john,Tom,Ben,John,Lisa,Mark,JOHN","John") 

Returns 3, i.e., the number of (case-insensitive) instances of John in the list.

ListQualify

Takes a comma-separated (or otherwise delimited) list and return it with a qualifying character such as single-quotes wrapped around each of the values

Syntax

ListQualify(list, qualifier, [delimiters],[elements])

list

List being searched.

qualifer

Character that each element will be wrapped with.

delimiters

Set of delimiters used in list.

elements

Should be either "ALL" or "CHAR" with the default being "ALL". If "CHAR" was selected, only the non-numeric values would be qualified otherwise every element will be qualified.

Remarks

Note that the new list is not guaranteed to preserve the delimiters in the original list.

Example

Here's an example of the ListQualify function.

ListCount("Allaire,1","'",",","CHAR")

Returns `Allaire',1


New Structure Functions

The following structure functions have been added to ColdFusion:

StructKeyList

Returns a list of keys in the specified CFML struct.

Syntax

StructKeyList(structure, [delimiter])

structure

Should be a valid CFML struct.

delimiter

This is an optional parameter. By default, this is ",".

Example

<cfset s = StructNew()>
<cfscript>
    s.John = "Sales";
    s.Tom = "Development";
    s.Mike = "Marketing";
    s.Bill = "Finance";
</cfscript> 

<cfset l = StructKeyList(s,"*")>
<cfoutput>List is #l#<BR></cfoutput>

StructKeyArray

Returns an array of keys in the specified struct.

Syntax

StructKeyArray(structure)

structure

Should be a valid CFML struct.

Example

<cfset s = StructNew()>
<cfscript>
    s.John = "Sales";
    s.Tom = "Development";
    s.Mike = "Marketing";
    s.Bill = "Finance";
</cfscript> 

<cfset a = StructKeyArray(s)>
<cfloop index="i" from="1" to="#ArrayLen(a)#">
    <cfoutput>Key is #a[i]#<BR></cfoutput>
</cfloop>

New Profile Functions

Two new profile string functions have been added to ColdFusion:

GetProfileString

Returns the value of an entry in an initialization file or an empty string if the value does not exist. An initialization file assigns values to configuration variables, also known as entries, that need to be set when the system boots, the operating system comes up, or an application starts. An initialization file is distinguished from other files by its .ini suffix, for example, boot.ini, Win32.ini, and setup.ini.

Syntax

GetProfileString(IniPath, Section, Entry)

IniPath

Fully qualified path (drive, directory, filename, and extension) of the initialization file, for example, C:\boot.ini.

Section

The section of the initialization file from which you would like to extract information.

Entry

The name of the value that you would like to see.

Example

<!---This example uses GetProfileString to set the 
     timeout value in an initialization file. --->

<HTML>
<HEAD>
<TITLE>GetProfileString Example</TITLE>
</HEAD>

<BODY  bgcolor="#FFFFD5">

<H3>GetProfileString Example</H3>

This example uses GetProfileString to get the value of timeout in an 
initialization file. Enter the full path of your initialization file, 
specify the timeout value, and submit the form.

<!---  This section of code checks to see if the form was submitted.
       If the form was submitted, this section gets the initialization
       path and timeout value of the path and timeout value specified 
       in the form                                                        --->
<CFIF Isdefined("Form.Submit")>

    <CFSET IniPath = #form.iniPath#>

    <CFSET Section = "boot loader">

    <CFSET timeout = GetProfileString(IniPath, Section, "timeout")>
    
    <CFSET default= GetProfileString(IniPath, Section, "default")>
    
    
    <H4>Boot Loader</H4>
    <!--- If you do not have an entry in an initialization file, nothing 
          will be displayed --->
    
    <P>Timeout is set to: <CFOUTPUT>#timeout#</CFOUTPUT>.</P>
    <P>Default directory is: <CFOUTPUT>#default#</CFOUTPUT>.</P>
            
</CFIF>

<FORM ACTION="getprofilestring.cfm" METHOD="POST">
<HR size="2" color="#0000A0">
<table cellspacing="2" cellpadding="2" border="0">
<tr>
    <td>Full Path of Init File</td>
    <td><input type="Text" name="IniPath" value="C:\myboot.ini"></td>
</tr>
<tr>
    <td><input type="Submit" name="Submit" value="Submit"></td>
    <td></td>
</tr>
</table>

</FORM>
<HR size="2" color="#0000A0">

</BODY>
</HTML> 

SetProfileString

Sets the value of a profile entry in an initialization file. This function returns an empty string if the operation succeeds or an error message if the operation fails.

Syntax

SetProfileString(IniPath, Section, Entry, Value)

IniPath

Fully qualified path (drive, directory, filename, and extension) of the initialization file.

Section

The section of the initialization file in which the entry is to be set.

Entry

The name of the entry that is to be set.

Value

The value to which to set the entry.

Example

<!---This example uses SetProfileString to set the 
     timeout value in an initialization file. --->

<HTML>
<HEAD>
<TITLE>SetProfileString Example</TITLE>
</HEAD>

<BODY  bgcolor="#FFFFD5">

<H3>SetProfileString Example</H3>

This example uses SetProfileString to set the value of timeout in an 
initialization file. Enter the full path of your initialization file, 
specify the timeout value, and submit the form.

<!---  This section of code checks to see if the form was submitted.
       If the form was submitted, this section sets the initialization
       path and timeout value to the path and timeout value specified 
       in the form                                                        --->
<CFIF Isdefined("Form.Submit")>

    <CFSET IniPath = #form.iniPath#>

    <CFSET Section = "boot loader">
    
    <CFSET MyTimeout = #form.MyTimeout#>
    
    <CFSET timeout = GetProfileString(IniPath, Section, "timeout")>

    <CFIF timeout Is Not MyTimeout>
        <CFIF MyTimeout Greater Than 0>
            <HR size="2" color="#0000A0">
            <P>Setting the timeout value to <CFOUTPUT>#MyTimeout#</
CFOUTPUT></P>
            <CFSET code = SetProfileString(IniPath, Section, "timeout", 
MyTimeout)>
            <P>Value returned from SetProfileString: <CFOUTPUT>#code#</
CFOUTPUT></P>
        <CFELSE>
            <HR size="2"  color="red">
            <P>Timeout value should be greater than zero in order to 
provide time for user response.</P>
            <HR size="2"  color="red">    
        </CFIF>
    <CFELSE>
        <P>The timeout value in your initialization file is already 
<CFOUTPUT>#MyTimeout#</CFOUTPUT>.</P>    
    </CFIF>

    <CFSET timeout = GetProfileString(IniPath, Section, "timeout")>
    
    <CFSET default= GetProfileString(IniPath, Section, "default")>
    
    
    <H4>Boot Loader</H4>
    <P>Timeout is set to: <CFOUTPUT>#timeout#</CFOUTPUT>.</P>
    <P>Default directory is: <CFOUTPUT>#default#</CFOUTPUT>.</P>
            
</CFIF>

<FORM ACTION="setprofilestring.cfm" METHOD="POST">
<HR size="2" color="#0000A0">
<table cellspacing="2" cellpadding="2" border="0">
<tr>
    <td>Full Path of Init File</td>
    <td><input type="Text" name="IniPath" value="C:\myboot.ini"></td>
</tr>
<tr>
    <td>Timeout</td>
    <td><input type="Text" name="MyTimeout" value="30"></td>
</tr>
<tr>
    <td><input type="Submit" name="Submit" value="Submit"></td>
    <td></td>
</tr>
</table>

</FORM>
<HR size="2" color="#0000A0">

</BODY>
</HTML>

New Exception Handling Features

A number of changes to ColdFusion exception handling have been implemented in this release:

Addition of the EXTENDEDINFO attribute

The EXTENDEDINFO attribute was added to CFTHROW, and a corresponding variable was also added, CFCATCH.EXTENDEDINFO. This variable is available only when CFCATCH.TYPE is APPLICATION or a custom type. It's a simple string variable.

An example:

<CFTRY> 
    <CFTHROW TYPE = "COM.allaire.tempest" 
        EXTENDEDINFO = "ExtendedInfo test">

    <CFCATCH TYPE = "COM.allaire.tempest"> 
        <CFOUTPUT>

            <p>Caught a custom exception, type = #CFCATCH.TYPE#
<br>Extended info = #CFCATCH.EXTENDEDINFO#
</CFOUTPUT> </CFCATCH> </CFTRY>

Capitalization of CFCATCH.TYPE variables

In order to handle custom exception types and to improve error checking, the capitalization of CFCATCH.TYPE has changed. Except for custom error types, CFCATCH error types are no longer mixed case, but all upper case, as in APPLICATION.

Custom exception types

CFTHROW TYPE=""

The new TYPE attribute allows a CFTHROW tag to throw an exception of a specific type, which can be caught by a CFCATCH tag that has a matching TYPE attribute.

A CFTHROW tag without a TYPE attribute will continue to throw a TYPE="Application" exception.

Naming conventions

A naming convention helps avoid conflicting exception types. The convention is similar to Java class naming conventions: domain name in reverse order, followed by major and any minor project identifiers. For example,

<CFTHROW TYPE="COM.Allaire.Superwhambozambo" ERRORCODE="Dodge14B"> 

The predefined exception types, except for TYPE="APPLICATION" are reserved; for example, <CFTHROW TYPE="Database"> will be rejected.

Additional CFTHROW attributes

These attributes may be specified for any CFTHROW tag.

New variables supplied by all CFML-recoverable exceptions

CFCATCH.ERRORCODE

Any exception that is a part of the CFML exception hierarchy (Application, Custom, Database, Expression, Object, Security, or Template) will supply a value for this variable.

Value of CFCATCH.ERRORCODE

Otherwise, the value of CFCATCH.ERRORCODE is the empty string.

Tag context information

CFCATCH.TagContext will be made available within any CFCATCH block. CFCATCH.TagContext consists of an array of structures. Each structure represents one level of the CFML runtime's active tag context at the time when the CFML interpreter detected the exception. The structure at position 1 of the array represents the outermost tag in the stack of tags that were executing when the interpreter detected the exception; the structure at position ArrayLen(CFCATCH.TAGCONTEXT) represents the currently executing tag at the time the interpreter detected the exception. If the interpreter detects an exception while a template is the currently executing PCode node, then the "currently executing tag" will be reported as the CFINCLUDE/CFMODULE/custom tag that initiated template processing.

CFCATCH TYPE="Custom Type"

A CFCATCH tag may now specify a custom type as well as one of the predefined types. For example, to catch the exception thrown above:

<CFCATCH TYPE="COM.Allaire.Superwhambozambo"> 

The type specified in the CFCATCH tag must match the type supplied in the CFTHROW tag exactly; no wildcard matching semantics are presently planned. The type comparison is case-insensitive.

Tag context stack: Attributes

The structures have the following attributes:

ID

The tag's GI, such as, "CFIF."

Note: This attribute is set to "ENCRYPTED" if the template is encrypted.

TEMPLATE

The pathname of the template that contains the tag.

LINE and COLUMN

The tag's line number and column number within the template.


New ATTRIBUTECOLLECTION Attribute for CFMODULE

Attributes can be passed to custom tags via the reserved attribute ATTRIBUTECOLLECTION. The ATTRIBUTECOLLECTION attribute must reference a structure; the structure's key/value pairs are copied to the custom tag's ATTRIBUTES scope.

CFMODULE

<CFMODULE TEMPLATE = template 
    OTHERATTR1 = value 
    ATTRIBUTECOLLECTION = structure 
    OTHERATTR2 = value> 

Shorthand

<cf_myCustomTag OTHERATTR1 = value 
    ATTRIBUTECOLLECTION = structure 
    OTHERATTR2 = value> 

Semantics

The key/value pairs contained within the structure specified by ATTRIBUTECOLLECTION will be copied into the ATTRIBUTES scope. This has essentially the same effect as specifying these attributes in the custom tag's attribute list.

If an attribute's value is specified both by ATTRIBUTECOLLECTION and as an explicit attribute within the custom tag's attribute list, then the attribute will receive the value specified by the explicit attribute. ATTRIBUTECOLLECTION may be freely mixed with other attributes within the custom tag's attribute list.

ATTRIBUTECOLLECTION is now a reserved attribute name

Custom tag processing now reserves ATTRIBUTECOLLECTION to refer to the structure holding a collection of custom tag attributes. If ATTRIBUTECOLLECTION does not refer to such a collection, the custom tag processor will raise a TEMPLATE exception.

Accessing attribute values within the custom tag

A custom tag invoked by the two examples above may refer to #attributes.x# and #attributes.y# to access the attributes passed via structure.

Setting values with CFASSOCIATE

If the called custom tag uses a CFASSOCIATE tag to save its attributes in the base tag, the attributes passed via structure will be saved as independent attribute values, with no indication that they were aggregated into a structure by the custom tag's caller.

Examples

Via CFMODULE:

<CFSET zort=StructNew()>
<CFSET zort.X = "-X-">
<CFSET zort.Y = "-Y-">
<CFMODULE TEMPLATE = "testtwo.cfm" 
    A = "blab" 
    ATTRIBUTECOLLECTION = #zort# 
    FOO ="16">

Via shorthand

<CFSET zort=StructNew()>
<CFSET zort.X = "-X-">
<CFSET zort.Y = "-Y-">
<cf_testtwo a="blab" attributecollection=#zort# foo="16">

Accessing attributes within the custom tag

If testtwo.cfm contains this CFML:

---custom tag ---<br>
  <CFOUTPUT>#attributes.a# #attributes.x# #attributes.y# 
#attributes.foo#</CFOUTPUT>
  <br>--- end custom tag ---

Its output will be:

---custom tag ---
blab -X- 12 16 
--- end custom tag ---

CFAPPLICATION NAME Attribute is Now Required

The NAME attribute for the CFAPPLICATION tag is now a required attribute.


Using SiteMinder with an Oracle Database

In ColdFusion 4.0.1 Advanced Security, you can now store the SiteMinder Policy Server data using a Windows NT Oracle database, rather than the default minimal database SiteMinder is shipped with.

Prerequisites

  1. An installed copy of Oracle -- see the Oracle documentation on how to install this software.
  2. Access to the Oracle Server machine.
  3. An installed copy of SiteMinder Policy Server -- see the SiteMinder documentation for instructions on how to the install that.
  4. If SiteMinder Policy Server is not running on the Oracle Server machine, Oracle Client must be installed on the SiteMinder Policy Server machine.
  5. The SiteMinder Policy database contents text file - this is either the default smpolicy_initial.txt that comes with the SiteMinder Policy server, or, if you have made modifications to the SiteMinder Policies, it should be created by running the following command on the SiteMinder Policy Server machine:
    SmObjExport -odata.txt

    Where data.txt is the database contents text file name.

  6. Disk space on the MS SQL Server machine, about 32 Megabytes for a minimal size database.
  7. The following SiteMinder Oracle text files:
  8. These should be together in a single subdirectory on the Oracle server machine, which will also contain the SiteMinder Oracle database files created during the following process. This directory will be referred to as the SiteMinder Oracle directory. It is best that the path to this directory not contain any spaces.

  9. The SMOracle.exe executable program, on the Oracle server.

Instructions

  1. Run the SMOracle.exe program on the Oracle Server machine. Bring up the MSDOS Command Prompt, cd to the directory that SMOracle.exe is in, and execute it. It takes several command line arguments:
    Usage: SMOracle [-u user] [-p password] [-d directory] [-h 
    oracle_home]
    -u username     Oracle Database Owner name, default: SiteMinder
    -p password     Oracle user password, default: SiteMinder
    -d directory    Absolute path to SiteMinder DB Oracle directory, 
    default: this one
    -h oracle_home  Absolute path to Oracle Home directory, default: 
    C:\ORANT
    

    Be sure to put quotes around any of those arguments that have spaces in them. So, for example, if Oracle home directory on this machine was C:\Oracle\ORANT, and the SiteMinder Oracle Directory (with the builddb.cmd and other above mentioned files) was C:\Program Files\Netegrity\SiteMinder\Oracle, and you wanted the database password "alamagordo", but were happy to leave the default user name "SiteMinder", you would execute:

    C:\>SMOracle -h C:\Oracle\ORANT -d "C:\Program Files\Netegrity\SiteMinder\Oracle" -p alamagordo

    The first output of the program will be the entered username, password, directory, oracle home, and machine name that it will use to create the database. A lot of text and warning messages are to be expected during the Oracle database creation step. What exactly the automated installer program does is described in detail at the end of this documentation - if the program fails due to an unusual local setup, you can try to follow each of these steps manually.

    The remaining steps are all performed on the SiteMinder machine, which is not necessarily the same as the Oracle server.

  2. If necessary, edit the Oracle NET80 configuration file. If the SiteMinder Policy Server is not running on the Oracle server machine, edit the text file tnsnames.ora in the Oracle home \NET80\ADMIN\ subdirectory, to connect to the Oracle server SiteMinder world. Add the lines:
    SiteMinder.world =
      (DESCRIPTION =
        (ADDRESS_LIST =
            (ADDRESS =
              (PROTOCOL = TCP)
              (Host = machine)
              (Port = 1521)
            )
        )
        (CONNECT_DATA = (SID = STMD)
        )
      )
    

    Where machine is the Oracle server computer name. If SiteMinder Policy Server is running on the Oracle server, this step is done by SMOracle.exe.

  3. Set up the ODBC services. On the SiteMinder administering machine, bring up the ODBC Data Source Administrator from Start:Settings:Control Panel:ODBC. Select System DSN. Remove all SiteMinder entries. Now add the Oracle data source: select Add, then select the Oracle ODBC Driver of your choice. In Oracle ODBC Driver Setup, type in "SiteMinder Data Source" as the Data Source Name, "SiteMinder" as the Service Name (or Server Name for an Intersolv Oracle ODBC driver). Ignore the other fields. Hit OK to close the Driver Setup, then the ODBC Data Source Administrator.
  4. Set up SiteMinder to work with the Oracle ODBC service. Bring up the SiteMinder Policy Server Management Console program, SMConsole. Select the ODBC tab at the top. For Policy Store, the default Database, set Data Source Name: Site Minder Data Source, User Name, Password,Verify Password: as the inputs to SmOracle.exe, "SiteMinder" if you allowed them to default. Then cycle through the Other Data Sources; check Use the Policy Store Database for each of them. Click Apply at the bottom.
  5. Restart the SiteMinder services. Still in the SiteMinder Management Console, select the Status tab at the top. Press Stop, then Start, for each of the Running services: Authentication, Authorization, Administration and Accounting (if that is Running). Each should stop and restart without error. Finally select OK to close the Management Console.
  6. Import the database information. From the MSDOS Command Prompt and from the directory with the SiteMinder database contents text file, data.txt, run "smobjimport -idata.txt". This should read in the previously created database information. There should be no failures.

SiteMinder Oracle Files

SiteMinder.ers

The schema -- SQL commands script that sets up the SiteMinder Policy Server database structure.

InitStmd.ORA

Pfile, or parameters file, for the SiteMinder database, used by builddb.cmd.

builddb.cmd

Command file that creates a new SiteMinder database, destroying the old one if it exists. Calls all the other files.

Newdb.sql

SQL commands script that makes a new SiteMinder database.

remdb.cmd

Command file that destroys an existing SiteMinder database, if any.

SMOracle.exe

Executable file automating the Oracle-server side setup. It does the following:

  1. Edits the Oracle NET80 configuration files. These are the text files tnsnames.ora and listener.ora in the Oracle home \NET80\ADMIN\ subdirectory, and they are modified to create a SiteMinder world and listener:
    %ORACLE_HOME%\Net80\Admin\Tnsnames.ora, adds:
    SiteMinder.world =
      (DESCRIPTION =
        (ADDRESS_LIST =
            (ADDRESS =
              (PROTOCOL = TCP)
              (Host = machine)
              (Port = 1521)
            )
        )
        (CONNECT_DATA = (SID = STMD)
        )
      )
    

    Where machine is the Oracle server computer name.

    %ORACLE_HOME%\Net80\Admin\Listener.ora, adds, after: SID_LIST_LISTENER = (SID_LIST = ... (SID_DESC = (GLOBAL_DBNAME = machine) (SID_NAME = STMD) )
  2. Moves the InitStmd.ORA PFILE to a path without spaces. In the last step, by running builddb.cmd, Oracle will create a command file, strstmd.cmd, in the \Database\ subdirectory of the Oracle home directory, to automatically launch the database instance on machine startup. This will contain a single line, similar to
    c:\orant\bin\oradim80.exe -startup -sid STMD -usrpwd siteminder -
    starttype srvc,inst -pfile 'c:\oratest\siteminder\initstmd.ora'
    

    If the path to the PFILE contains any spaces (for example, if it includes '/Program Files/'), the strtstmd.cmd created file will not work (quoting the path doesn't help). This appears to be a problem with the oradim80.exe Oracle program. SMOracle.exe will move the pfile to a path without any spaces, first trying SiteMinder Oracle, then Oracle Home\Database, and if neither of those work, up the Oracle Home\Database path until reaching a directory path without any spaces.

  3. Edits hardwired file paths and login. In the SiteMinder Oracle directory, edits the file path in the following files and lines, replacing D:\OraTest\SiteMinder\ with the full absolute path to the SiteMinder Oracle directory, or to the PFILE, as appropriate, and replacing USERNAME and PASSWORD with the username and password entered on the command line.
    builddb.cmd:24:ORADIM80 -NEW -SID %ORACLE_SID% -INTPWD 
        PASSWORD -STARTMODE AUTO -PFILE
        D:\OraTest\SiteMinder\InitStmd.ORA
    
    builddb.cmd:30:ORADIM80 -STARTUP -SID %ORACLE_SID% -USRPWD 
        PASSWORD -STARTTYPE srvc,inst -PFILE
        D:\OraTest\SiteMinder\InitStmd.ORA
    
    InitStmd.ORA:40: control_files = 'D:\OraTest\SiteMinder\ctl1Stmd.ora'
    
    Newdb.sql:15: connect INTERNAL/PASSWORD
    
    Newdb.sql:18: startup nomount 
        pfile='D:\OraTest\SiteMinder\InitStmd.ora'
    
    Newdb.sql:26: LogFile 'D:\OraTest\SiteMinder\Log1Stmd.ora' 
        Size 500K reuse,
    
    Newdb.sql:27: 'D:\OraTest\SiteMinder\Log2Stmd.ora' Size 500K reuse
    
    Newdb.sql:29: DataFile 'D:\OraTest\SiteMinder\Sys1Stmd.ora' 
        Size 10M reuse autoextend on
    
    Newdb.sql:45: datafile 'D:\OraTest\SiteMinder\usr1Stmd.ora' size 3M 
    reuse autoextend on
    
    Newdb.sql:48: datafile 'D:\OraTest\SiteMinder\rbs1Stmd.ora' size 5M 
    reuse autoextend on
    
    Newdb.sql:51: datafile 'D:\OraTest\SiteMinder\tmp1Stmd.ora' size 2M 
    reuse autoextend on
    
    Newdb.sql:87: create user USERNAME identified by PASSWORD
    
    Newdb.sql:101: connect USERNAME/PASSWORD
    
  4. Makes the Oracle database files. Runs the builddb.cmd file. The script takes a few minutes to complete, and will generate a lot of text, including many Oracle error messages such as "object to be dropped does not exist" which should be ignored (see Chapter 9, Creating a Database, in the Oracle8Enterprise Edition Getting Started for Windows NT documentation). The following files are created in the SiteMinder Oracle directory:
    CTL1STMD.ORA                  SYS1STMD.ORA
    TMP1STMD.ORA                  LOG1STMD.ORA
    USR1STMD.ORA                  LOG2STMD.ORA
    createSiteMinderDatabase.log  RBS1STMD.ORA
    

    as well as strtstmd.cmd in the Database subdirectory of the Oracle home directory (typically C:\Orant\). The SQL output, including any SQL errors, besides being printed to the screen, will be saved in the text file createSiteMinderDatabase.log. All the other created files are binary, and will not be readable with a text editor.


Using an ODBC Data Source for Security Authentication

You can use an ODBC datasource for username/password security authentication. A sample ODBC access database SmSampleUsers.mdb is installed in your cfusion\database directory. If you want to use this sample database to test the ODBC username/password authentication you need to

  1. Create an ODBC datasource for the MSAccess ODBC driver. The datasource name must be SmSampleUsers and the database file is the SmSampleUsers.mdb file.
  2. Use the ColdFusion Administrator to add a User Directory from the Advanced Security page. Select the ODBC namespace and enter SmSampleUsers in the ocation form field.
  3. Associate a user or group to a policy in your security context. Example username/passwords are admin/secret and vlander/firewall. You can find the passwords in the Access database file.

The ODBC username/password requires the SmDsQuery.ini file, which is installed in your ColdFusion bin directory. The file contains the SQL for the SmSampleUsers data source. Each ODBC data source you use for authenticating users requires a section by the same name in this ini file. The section must contain the appropriate SQL statements to authenticate the user. You can use the SmSampleUsers section as an example.


Converting the SiteMinder Policy Server to an LDAP Database

The SiteMinder Policy Server can store policy information in an LDAP database as easily as in the default ODBC database, with no loss of functionality. The LDAP database may use unencrypted communication, or encrypted communication over SSL, the secure sockets layer. This document describes how to convert the policy store to an LDAP database, using the SmLdapSetup command line tool.

Requirements

  1. Installed, running, LDAP database server, such as the Netscape Directory Server.
  2. Administrator access to this server: knowledge of server name or IP address, LDAP port being used, directory root distinguished name, administrator distinguished name, and administrator password.
  3. If the server uses SSL encryption, a client certificate file that can connect to the LDAP server. For the Netscape Navigator web browser, this is usually stored as Netscape\Users\default\cert7.db.
  4. Installed copy of the SiteMinder Policy Server.
  5. The SmLdapSetup program, SmLdapSetup.exe on Windows NT platforms, smldapsetup on UNIX.
  6. The ldapmodify command line tool. This is often shipped with the LDAP server, in Netscape\SuiteSpot\bin\slapd\server\ldapmodify.exe with the Netscape Windows NT server, for example, or the one which ships with SiteMinder may be used.
  7. The smldap.ldif text file. This contains the SiteMinder policy store database schema, in LDIF format. Open the file, replace the text "o=airius.com" with "o=your directory root distinguished name"
  8. If the SiteMinder LDAP Policy Store is to have different policy data in it than is currently in the ODBC SiteMinder Policy Store, this should be available as an SmObjExport format text file. For example, if the smpolicy_initial.txt file has not yet been imported in to the ODBC database, it will be needed to be imported into the LDAP database.

Procedure

Converting the Policy Server to use an LDAP database can be done with the SmLdapSetup command line tool.

Usage: SmLdapSetup <mode> <arguments>
mode:   One of: all reg ldmod switch import revert
args:   -h host -p port -d dn -w pwd -r root -f ldif
        [-t tool] [-i data] [-ssl 1|0 -c cert] [-v]
Modes:
all     Do reg, ldmod, switch, import, in that order.
        If -i not specified, re-imports old database.
reg     Fill in SiteMinder LDAP registry entries.
        Requires host, port, dn, pwd, root, allows ssl, cert.
ldmod   Create SiteMinder LDAP root and schema.
        Arguments as reg, also requires -f ldif, -t tool.
switch  Switch SiteMinder to use LDAP database
        Run after reg and ldmod. No arguments but -v.
import  Read exported policy data (SmObjImport)
        Run after switch. Requires -i data file.
revert  Switch back from using LDAP to ODBC database
        Does not read in any data. No arguments but -v.
Arguments:
-h host Name or IP address of LDAP Server machine
-p port LDAP port number, default 389 if not in registry
-d dn   Distinguished name of admin user
-w pwd  Password matching admin user dn
-r root Existing LDAP base node dn to install to
-f ldif File containing LDAP schema creation commands
-t tool Ldapmodify command line tool, if not in default path
-i data Input SmObjExport policy data file (or keep current)
-ssl 1 or 0     If 1, use SSL connection, and port defaults to 636
-c cert Certificate file for SSL connection
-v      Verbose: all modes - progress comments to standard output
If not specified, host, port, dn, pwd, root, ssl, and cert
default to any current registry entries.

Typically, SmLdapSetup is used in "all" mode, giving the -h host -d dn -w pwd -r root -f ldif arguments. For example:

C:\>smldapsetup all -h mymachine.mycompany.com -d "cn=Directory 
Manager" -w my123password -r "o=airius.com" -f smldap.ldif

Details on the command line arguments follow.

Mode

The first argument to SmLdapSetup is the mode, that is, what the command should do.

all mode is the typical usage. It is used to completely convert the Policy Server to LDAP. The other modes can be used to perform just one of the several steps of this conversion, or to convert the Policy Server to ODBC instead. It does the equivalent of running the program four times, with the modes in the order reg, ldmod, switch, import - except that if the -i data file argument is not specified, all mode will export the current database policy store (to a text file in the current directory called policyData.out) before doing switch, and will import it afterwards, so the LDAP database will have the same policy store data as the database before the switch. If there is no data in the database, the -i data file argument must be given, using the smpolicy_initial.txt file supplied with SiteMinder at least. See below for details on what each of the steps of all mode does. If doing the conversion by parts, the program should be run in the same order of modes that all mode does, otherwise the steps will likely not work.

reg mode only tests the LDAP connection to the server, then, if that succeeds, copies the LDAP connection parameters (host, port, dn, pwd, root, ssl, and cert) to the SiteMinder registry.

ldmod mode connects to the LDAP server, then creates the SiteMinder LDAP nodes and database schema, without populating them with any policy values, or storing the connection parameters in the SiteMinder registry. It requires the same arguments that reg mode does, but also requires the ldapmodify program and the ldif file.

switch mode makes the registry change that actually converts the Policy Server to use LDAP rather than ODBC. It does not prepare the LDAP side, or the other LDAP connection parameters before hand.

import mode does the equivalent of running the SmObjImport program in -f (force) mode, reading in a text policy store data file created by SmObjExport into the current database, whatever that may be.. if running SmLdapSetup by parts, this file must be specified with -i. Again, the smpolicy_initial.txt file supplied with SiteMinder can be imported in this way.

Arguments

The LDAP connection parameters host, port, dn, pwd, root, ssl, and cert are written to the SiteMinder registry by all and reg modes. If any of these parameters are not specified in a call to SmLdapSetup, they will default to the current registry values, if any. These registry values will also be displayed in, and can also be entered using the SiteMinder Policy Server Management Console, SmConsole, using the LDAP tabbed pane.

-h host

This argument can be given as the fully qualified name of the LDAP server (for example: -h ldapserver.mycompany.com), the relative name, if the machines are in the same domain (-h ldapserver), or the IP address (-h 128.0.0.1). This argument defaults to a previously entered registry value, as mentioned above.

-p port

This argument can usually be left to default to the usual LDAP well-known ports: 389 if SSL is not being used, or 636 if SSL is being used. If the server is using a non- standard LDAP port, or if this utility is being used to move to an LDAP database when a different port has already been specified and stored in the registry (such as moving from an LDAP database using SSL to one not using it) then the port must be specified (for example, -p 1236). Instead of defaulting to 389 or 636, this argument will default to a previously entered registry value, as mentioned above, if there is one.

-d dn

This argument is the LDAP distinguished name of a user with the power to create new LDAP directory schema and entries - not necessarily the same as the administrator for the LDAP server itself. Remember to use quotes around this argument if it contains spaces, for example -d "cn=Directory Manager". This argument also defaults to a previously entered registry value, as mentioned above.

-w pwd

This is the password matching the -d LDAP user name argument, above. For example: -w MyPassword123. Again, be sure to use quotes around this argument if it contains spaces. This argument also defaults to a previously entered registry value, as mentioned above.

-r root

This argument is another LDAP distinguished name, this time of the LDAP node to install the SiteMinder policy schema to. This node should be one that already exists; SiteMinder will build its nodes below this one. For example: -r o=airius.com. This argument also defaults to a previously entered registry value, as mentioned above.

-f ldif

This argument should be the absolute or relative path to the smldap.ldif file, from the directory in which SmLdapSetup is being executed. For example: -f ..\SiteMinder\Db\smldap.ldif. This argument is not stored in the registry, but defaults to smldap.ldif in the current directory if not specified.

-t tool

SmLdapSetup will try to set up the database schema by executing the LDIF format commands using the standard LDAP ldapmodify command line utility. One is usually shipped with an LDAP server, and another will come with SiteMinder. If ldapmodify is not in the default executable path (try typing ldapmodify on a command line with no other arguments - if the operating system says something like "Bad command or file name", it is not in the path), then the absolute or relative path to this tool must be given, including the file name and extension if any. For example, -t C:\Netscape\SuiteSpot\bin\slapd\server\ldapmodify.exe.

-i data

If you want the LDAP database to contain different policy data than the current SiteMinder Policy Server database does, or if there is no current SiteMinder Policy Server database, you can specify the absolute or relative path to a SmObjImport format text file here, in all or import modes, and then SmLdapSetup will run SmObjImport on this file after converting the database to LDAP. This argument can be left out in all mode, and then the Policy Server will keep the same data it had before in the previous database. (Specifically, if a -i argument is not specified in all mode, SmLdapSetup will SmObjExport the current database policy data before LDAP conversion, to a file called policyData.out, and SmObjImport this file again into the LDAP database after conversion)

-ssl 1 or 0

Specify -ssl 1 to use an SSL encrypted connection to the LDAP server, and -ssl 0 to not use an SSL connection. This argument will default to "don't use SSL" (-ssl 0), if SSL has never been specified, but this value is stored in the registry, so if you are migrating from a SiteMinder LDAP database which used SSL to one which does not, you will have to specify - ssl 0 (and -p 389, see above) on the command line. This argument may be specified in the SmConsole.

-c cert

This argument is only used with an SSL encrypted (-ssl 1) LDAP connection, but then it must be specified. This must be the full absolute path to the SSL client certificate, usually called cert7.db for the Netscape Navigator web browser, as mentioned in "Requirements," above. Again, this argument defaults to what is stored in the registry, and may be entered or viewed in the SiteMinder Policy Server SmConsole.

-v

Use the -v argument to help debug a run of SmLdapSetup. With -v, the tool will write what it takes as its command line arguments, between defaults, what was entered on the command line, and registry entries, and it will also write as it is performing each step in the LDAP migration. If it reads the admin password from the registry, it will write it in encrypted form, to show that the password has been read, but it will not output it in decrypted form. The other tools SmLdapSetup calls, SmObjImport, SmObjExport, and ldapmodify will also be run with verbose modes with this argument.


New Short-Circuit Boolean Evaluation

The ColdFusion engine now supports a processing behavior known as short-circuit Boolean evaluation. This feature is relevant for ColdFusion expressions that employ AND/OR operators.

Until this release, ColdFusion evaluated both sides of AND/OR expressions, regardless of their results. Now, ColdFusion no longer has to process both sides of AND/OR expressions. Here's how it works. For an AND expression, if the first expression in the AND construct evaluates false, the second expression in it is ignored. The value of the AND expression is false. For an OR expression, if the first expression evaluates to true, the second expression is ignored. The value of the OR expression is true.


New REQUEST Scope

A new reserved variable/scope has been added to ColdFusion 4.0.1. It is a structure named "request." It allows for the convenient storage of data that pertains to the processing of a single page request. The variable is available in all templates: base, includes, and custom tags. You reference variables created in the request scope as:

Request.myvariable

Collaborating custom tags that are not nested in a single tag can exchange data via the request structure. Of course, care must be taken to use unique names. Our recommendation is that data should be stored in structures nested inside a request.


OnRequestEnd.cfm

A template, OnRequestEnd.cfm, can now be specified that will automatically be executed after the called template is executed. An OnRequestEnd.cfm template is expected in the same directory that the Application.cfm file is placed in. An Application.cfm file is first searched for in the template's current directory and then in the parent and ancestor directories by traversing up the file hierarchy. Since traversing up a file hierarchy is a very expensive operation execution of an OnRequestEnd.cfm template is restricted to the case where an OnRequestEnd.cfm file is placed in the same directory as the Application.cfm file of the executing template.

Note that OnRequestEnd.cfm will not be executed in any case if there is an error or exception in the called template or the called template executes the CFABORT or the CFEXIT tag.

Note the correct filename case on Solaris of OnRequestEnd.cfm.


New Application and Session Variables

There are two new variables available now.


Releasing Cached Database Connections

The ColdFusion Administrator Verity Data Source page has a new Release button, that, when pressed, releases all cached data source connections. If a data source is being used by a page request when the release is being processed then it is flagged and released when the page request processing is completed.


New Database Connection Cache Timeout Option

There is a new data source setting in the ColdFusion Administrator ColdFusion data source Setings page called Connection Timeout. You can specify the maximum amount of time after the database connection is made (in minutes) that ColdFusion will cache a connection after it is used.

This is different from the server setting to Limit database connection inactive time. This latter setting is server wide and only releases cached connections that have been inactive (not used) for the specified period of time. The Connection Timeout does not return a connection to the cache after a specified period of time no matter how frequently or infrequently it has been used. The default is "" or 0 which means the connection timeout is never enforced.


CFML Stack Trace Option in the ColdFusion Administrator

The ColdFusion Administrator's Debugging page has a new option: Enable CFML stack trace. This option is provided so that production servers will not expend resources creating a traceback stack by default.

If this setting is disabled, CFCATCH.TAGCONTEXT will be a zero-length array.


DB2 Native Database Driver

In this Beta release, ColdFusion supports DB2 databases with a native database driver. To use the ColdFusion native driver for DB2, you need to install and configure the Client Application Enabler version 5.2 for either Solaris or Windows NT.

Documentation for the DB2 version 5.2 Client Application Enablers can be found in your DB2 product CD set.


Oracle Stored Procedures

Oracle stored procedures do not return result sets in the traditional sense. Consequently, it is not possible to generate a query in ColdFusion using an Oracle stored procedure. However, Oracle allows for the return of arrays of output parameters from their stored procedures in an effort to approximate a result set. We can now leverage this functionality in the Enterprise version of ColdFusion by utilizing the new `Maxrows' attribute of the CFProcParam tag which takes advantage of new functionality in the native Oracle drivers.

The Maxrows attribute of the CFProcParam tag is used to specify a maximum number of array elements which will be populated by the stored procedure. The result, after execution of the stored procedure, is a one dimensional ColdFusion array for each CFProcParam tag specifying the Maxrows attribute. It's best if the user has a general idea of the potential number of rows that the procedure will return so that an appropriate Maxrows can be specified. Specifying a Maxrows value that is too large needlessly utilizes memory. Conversely, specifying a Maxrows value that is too small will result in an abreviated result set.

In order to generate arrays of output parameters, the stored procedure on the Oracle server must have a cursor that is opened and repeatedly called through a loop in the procedure. An efficient method of wrapping up the necessary functionality is through Oracle Packages. An example which uses the Oracle sample table Emp follows.

CREATE OR REPLACE PACKAGE CFDemo AS

   TYPE char_array IS TABLE OF VARCHAR2(20)
       INDEX BY BINARY_INTEGER;
   TYPE num_array IS TABLE OF FLOAT
       INDEX BY BINARY_INTEGER;

   PROCEDURE get_employees(
     dept_number IN     number,    -- department to query
     batch_size  IN     INTEGER,   -- rows at a time
     found       IN OUT INTEGER,   -- rows actually returned
     done_fetch  OUT    INTEGER,   -- all done flag
     emp_name    OUT    char_array,
     job         OUT    char_array,
     sal         OUT    num_array);

END CFDemo;
/

CREATE OR REPLACE PACKAGE BODY CFDemo AS

   CURSOR get_emp (dept_number IN number) IS
       SELECT ename, job, sal FROM emp
           WHERE deptno > dept_number;

   -- Procedure "get_employees" fetches a batch of employee
   -- rows (batch size is determined by the client/caller
   -- of the procedure).  
   -- The procedure opens the cursor if it is not
   -- already open, fetches a batch of rows, and
   -- returns the number of rows actually retrieved. At
   -- end of fetch, the procedure closes the cursor.

   PROCEDURE get_employees(
     dept_number IN     number,
     batch_size  IN     INTEGER,
     found       IN OUT INTEGER,
     done_fetch  OUT    INTEGER,
     emp_name    OUT    char_array,
     job         OUT    char_array,
     sal         OUT    num_array) IS

   BEGIN
       IF NOT get_emp%ISOPEN THEN      -- open the cursor if
           OPEN get_emp(dept_number);  -- not already open
       END IF;

       -- Fetch up to "batch_size" rows into PL/SQL table,
       -- tallying rows found as they are retrieved. When all
       -- rows have been fetched, close the cursor and exit
       -- the loop, returning only the last set of rows found.

       done_fetch := 0;  -- set the done flag FALSE
       found := 0;

       FOR i IN 1..batch_size LOOP
           FETCH get_emp INTO emp_name(i), job(i), sal(i);
           IF get_emp%NOTFOUND THEN    -- if no row was found
               CLOSE get_emp;
               done_fetch := 1;   -- indicate all done
               EXIT;
           ELSE
               found := found + 1;  -- count row
           END IF;
       END LOOP;
   END;
END;

A sample ColdFusion template which can be used to execute the above procedure follows. I have not necessarily output all results since this is dependent on the number of rows in the Emp table. Also, note that I have not used a fancy layout to present the data, I simply show the contents of the array variables and the scalar output parameters. I use the bDone flag to indicate whether all of the rows were returned or not. Since we are using an Oracle package which has global scope, we could, theoretically, leave the cursor open on the server and call the procedure again to retrieve the next set of rows if the first execution did not get all rows. This leads to concurrency issues that the individual user must address. The array index must not exceed the total number of rows that were returned into the array or array bound errors will occur. It's best to check the size of the array using the appropriate array functions before displaying the results.

<CFSTOREDPROC                    PROCEDURE = "CFDemo.get_employees"
                datasource = "my_oracle80_test"
                returncode = no
>

<!---         CFPROCPARAM TAGS --->
<CFPROCPARAM                TYPE = "in"
                CFSQLTYPE = CF_SQL_INTEGER
                value = 1
>

<CFPROCPARAM                TYPE = "in"
                CFSQLTYPE = CF_SQL_INTEGER
                value = 15
>

<CFPROCPARAM                TYPE = "inout"
                CFSQLTYPE = CF_SQL_INTEGER
                variable = NumberReturned
>

<CFPROCPARAM                TYPE = "out"
                CFSQLTYPE = CF_SQL_INTEGER
                variable = bDone
>

<CFPROCPARAM                TYPE = "out"
                CFSQLTYPE = CF_SQL_VARCHAR
                variable = EmployeeName
                maxrows = 15
>

<CFPROCPARAM                TYPE = "out"
                CFSQLTYPE = CF_SQL_VARCHAR
                variable = Job
                maxrows = 15
>

<CFPROCPARAM                TYPE = "out"
                CFSQLTYPE = CF_SQL_FLOAT
                variable = Salary
                maxrows = 15
>

<!--- ... AND CLOSE THE STOREDPROC TAG --->
</CFSTOREDPROC>

<CFOUTPUT>
The bDone flag is: '#bDone#' <br>
The number of records returned is: '#NumberReturned#'<br>
***Array stuff***
<hr>
The employee name is: '#EmployeeName[1]#'<br>
The employee name is: '#EmployeeName[2]#'<br>
The employee name is: '#EmployeeName[3]#'<br>
The employee name is: '#EmployeeName[4]#'<br>
The employee name is: '#EmployeeName[5]#'<br>
<hr>
The employee job is: '#Job[1]#'<br>
The employee job is: '#Job[2]#'<br>
The employee job is: '#Job[3]#'<br>
The employee job is: '#Job[4]#'<br>
The employee job is: '#Job[5]#'<br>
<hr>

The employee salary is: '#Salary[1]#'<br>
The employee salary is: '#Salary[2]#'<br>
The employee salary is: '#Salary[3]#'<br>
The employee salary is: '#Salary[4]#'<br>
The employee salary is: '#Salary[5]#'<br>

</CFOUTPUT>

On the Oracle server side, in the above example, tables of VARCHAR(20) and FLOAT are generated, but in addition to these, tables of types DATE, INTEGER, and NUMERIC may also be specified.

Of note, also, is that we convert NUMBER datatype values to C-Type float which may result in rounding of the NUMERIC value. There is code which prevents the utilization of the Maxrows attribute by any DBTYPE other than ORACLE73 and ORACLE80. In the event that someone tries to use this attribute in conjuction with ODBC for example, an error is thrown.


Fail-Over Support for Windows NT (with SP4)

During ColdFusion installation you have the option of installing Bright Tiger load balancing and high availability support. This feature requires Windows NT Service Pack 4. To configure servers in a cluster for high availability, use the Bright Tiger Explorer.


Changes to Debugging Behavior for Encrypted Pages

ColdFusion Adminstrator Debugging page options no longer have any affect on encrypted ColdFusion application pages. Encrypted pages no longer generate debugging information.


Display Template Path in Error Messages Option

ColdFusion's default error message displays the general identifier of the tag that suffered from an error, but does not display the page's file name. The page's file name is useful for debugging, but may be a security hazard because it displays information about a server's file structure.



New Features and Enhancements in ColdFusion Studio