ColdFusion 4.0.1 introduces a number of new features in the following areas:
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.
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.
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.
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.
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.
<cfmoduleTEMPLATE=template OTHERATTR1=value ATTRIBUTECOLLECTION=structure OTHERATTR2=value>
<cf_myCustomTag OTHERATTR1=value ATTRIBUTECOLLECTION=structure OTHERATTR2=value>
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.
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.
A custom tag invoked by the two examples above may refer to #attributes.x# and #attributes.y# to access the attributes passed via structure.
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.
<cfset zort=StructNew()> <cfset zort.X = "-X-"> <cfset zort.Y = "-Y-"> <cfmodule template="testtwo.cfm" a="blab" attributecollection=#zort# foo="16">
<cfset zort=StructNew()> <cfset zort.X = "-X-"> <cfset zort.Y = "-Y-"> <cf_testtwo a="blab" attributecollection=#zort# foo="16">
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 ---
Two new functions have been added to ColdFusion to support the newly implemented Euro.
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.
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.
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.
LSParseEuroCurrency(currency-string)
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 (£).
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.
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.
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.
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.
QueryAddColumn(query, column-name, array-name)
Name of a query that was created with QueryNew.
The name of the new column.
The name of the array whose elements are to populate the new column.
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.
<!--- 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>
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.
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).
CreateUUID()
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.
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?
The following date/time functions have been added to ColdFusion:
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:
GetTimeZoneInfo()
<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>
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.
DateConvert(conversion-type, date)
Should be either "utc2Local" for converting from UTC to local time or "local2Utc" to convert from local time to UTC.
A valid CFML date.
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>
The DateCompare function now supports a new third parameter, datePart, which can be used to specify the granularity of the comparison.
DateCompare (date1,date2,[datePart="s"])
Date/time object in the period from 100 AD to 9999 AD.
Date/time object in the period from 100 AD to 9999 AD.
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.
The following list functions have been added to ColdFusion:
Returns the number of instances of value in list. The search is case-sensitive.
See also ListCountNoCase, ListFind and ListContains
ListCount(list, value, [delimiters])
List being searched.
Number or string being counted among elements of list.
Set of delimiters used in list.
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.
Returns the number of instances of value in list. The search is case-sensitive.
ListValueCount(list, value, [delimiters])
List being searched.
Number or string being counted among elements of list.
Set of delimiters used in list.
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.
Returns the number of instances of value in list. The search is case-insensitive.
See also ListValueCount, ListFind and ListContains
ListValueCountNoCase(list, value, [delimiters])
List being searched.
Number or string being counted among elements of list.
Set of delimiters used in list.
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.
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
ListQualify(list, qualifier, [delimiters],[elements])
List being searched.
Character that each element will be wrapped with.
Set of delimiters used in list.
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.
Note that the new list is not guaranteed to preserve the delimiters in the original list.
Here's an example of the ListQualify function.
ListCount("Allaire,1","'",",","CHAR")
Returns `Allaire',1
The following structure functions have been added to ColdFusion:
Returns a list of keys in the specified CFML struct.
StructKeyList(structure, [delimiter])
Should be a valid CFML struct.
This is an optional parameter. By default, this is ",".
<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>
Returns an array of keys in the specified struct.
StructKeyArray(structure)
Should be a valid CFML struct.
<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>
Two new profile string functions have been added to ColdFusion:
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.
GetProfileString(IniPath, Section, Entry)
Fully qualified path (drive, directory, filename, and extension) of the initialization file, for example, C:\boot.ini.
The section of the initialization file from which you would like to extract information.
The name of the value that you would like to see.
<!---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>
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.
SetProfileString(IniPath, Section, Entry, Value)
Fully qualified path (drive, directory, filename, and extension) of the initialization file.
The section of the initialization file in which the entry is to be set.
The name of the entry that is to be set.
The value to which to set the entry.
<!---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>
A number of changes to ColdFusion exception handling have been implemented in this release:
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>
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.
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.
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.
These attributes may be specified for any CFTHROW tag.
CFTHROW tags can supply exception detail information.
CFTHROW tags can supply a value for their exception's ERRORCODE variable.
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.
CFTHROW tags may supply a value for this code via the ERRORCODE attribute.
CFCATCH.ERRORCODE has the same value as CFCATCH.SQLSTATE.
Otherwise, the value of CFCATCH.ERRORCODE is the empty string.
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.
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.
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. |
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 TEMPLATE = template OTHERATTR1 = value ATTRIBUTECOLLECTION = structure OTHERATTR2 = value>
<cf_myCustomTag OTHERATTR1 = value ATTRIBUTECOLLECTION = structure OTHERATTR2 = value>
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.
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.
A custom tag invoked by the two examples above may refer to #attributes.x#
and #attributes.y#
to access the attributes passed via structure.
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.
<CFSET zort=StructNew()> <CFSET zort.X = "-X-"> <CFSET zort.Y = "-Y-"> <CFMODULE TEMPLATE = "testtwo.cfm" A = "blab" ATTRIBUTECOLLECTION = #zort# FOO ="16">
<CFSET zort=StructNew()> <CFSET zort.X = "-X-"> <CFSET zort.Y = "-Y-"> <cf_testtwo a="blab" attributecollection=#zort# foo="16">
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 ---
The NAME attribute for the CFAPPLICATION tag is now a required attribute.
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.
SmObjExport -odata.txt
Where data.txt
is the database contents text file name.
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.
SMOracle.exe
executable program, on the Oracle server.
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:
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.
\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.
data.txt
, run "smobjimport -idata.txt
". This should read in the previously created database information. There should be no failures.
The schema -- SQL commands script that sets up the SiteMinder Policy Server database structure.
Pfile, or parameters file, for the SiteMinder database, used by builddb.cmd
.
Command file that creates a new SiteMinder database, destroying the old one if it exists. Calls all the other files.
SQL commands script that makes a new SiteMinder database.
Command file that destroys an existing SiteMinder database, if any.
Executable file automating the Oracle-server side setup. It does the following:
%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) )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.
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
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.
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
SmSampleUsers.mdb
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.
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.
Netscape\Users\default\cert7.db
.
SmLdapSetup.exe
on Windows NT platforms, smldapsetup
on UNIX.
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.
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"
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
.
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)
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.
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.
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.
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.
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.
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
.
There are two new variables available now.
<appname>_<cfid>_<cftoken>
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.
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.
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.
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 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.
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.
ColdFusion Adminstrator Debugging page options no longer have any affect on encrypted ColdFusion application pages. Encrypted pages no longer generate debugging information.
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.