Try/Catch/Throw Routines Within CFML, you have tags specifically designed to enable you to handle errors and to continue processing your application pages. The try/catch block is one way in which you might choose to handle an error generated within one of your ColdFusion templates. You would use try/catch blocks anywhere within your application where an error from which you could recover might occur. Before we begin with an example of how you would use this functionality in a real-world application, let's take a quick look at the types of error handling tags available within ColdFusion MX (see Table 9.1). Table 9.1. ColdFusion MX Error Handling Tags Error | Handling Tag General Use of Tag | CFTRY | Within a CFML template, CFTRY tags are used to surround specific segments of code that can generate an error. When used in conjunction with the CFCATCH tag, CFTRY enables you to specify a second piece of code to run only when the code within the CFTRY block has failed to execute properly. | CFCATCH | CFCATCH is always used within a CFTRY block. You use CFCATCH to specify a piece of code that you want to run if the code contained within the CFTRY block has failed and a certain error type was generated . You can have multiple CFCATCH blocks with different catch types within a single CFTRY block. There are various catch types available to you in ColdFusion MX: application database template security object missinginclude expression lock custom_type any A catch type of any is always the default and is used when no other catch type is specified. In addition to these basic types, there are a number of extended error types that you can use with your CFCATCH blocks to obtain more granular control over your application flow. These advanced exception types are covered in detail later in this chapter. | CFTHROW | The CFTHROW tag enables you to purposefully throw an error of a specified type within your code that could consequently cause a specific catch type to run. | CFRETHROW | The CFRETHROW tag forces your error handling routine to exit the currently executing CFCATCH block and throw a new exception of the same type so that error handling can continue. This is useful when the specific catch block in which the error is first sent is not written specifically to deal with the type thrown. With the CFRETHROW tag, you can rethrow an error of the same type to enable a higher-level error handler to deal with it. | CFFINALLY | The CFFINALLY tag, new to ColdFusion MX, enables you to specify a section of code within any CFCATCH block that you want to be executed no matter what happens. Even if an error isn't thrown, any content in the CFFINALLY block will still execute. If an error is thrown and the CFCATCH block is called into use, content in the CFFINALLY block will execute after the CFCATCH tag has finished running the code contained within its block. | Try/Catch Now that we've taken a look at all the error handling tags available to you in ColdFusion MX, let's examine how we might use some of them. First, let's take a look at how we might want to implement a simple try/catch block in our ColdFusion code. Suppose we want to run a database query that retrieves a list of cars from a database. The table that holds the names of the car models is called models. This should be a simple enough query, assuming that we don't do something silly like spell our table name modeels; but what if we do? That's where the try/catch block takes over to help us out. Examine the following code, noting the fact that we are misspelling the table name models: <cftry> <cfquery name="GetCars" datasource="request.dsn"> SELECT * FROM modells </cfquery> <cfcatch type="database"> There was an unfortunate database error. Please try again. </cfcatch> </cftry> In code, when the database error is encountered, an error is thrown. Without the try/catch block, the error would be sent back to the user in the standard, unfriendly error format that relays either an open database connectivity (ODBC) or native driver error message. Although this type of error message is fine (and sometimes necessary) for the developer of the application to see, it won't mean much to the end user. Generally, he or she will be much happier with the "There was an unfortunate database error" type of message. When using CFCATCH within a CFTRY block, you will also have catch variables available to you. These variables are populated whenever a catch type is encountered, and they can be used to provide more information about the specific type of error that was encountered. Table 9.2 examines the different variables available to you when you are using CFCATCH to trap errors. Table 9.2. CFCATCH Error Variables Variable Name | Description | CFCATCH.TYPE | This variable stores the exception type encountered. The contents of this variable will be the same as the exception type specified in the CFCATCH block. | CFCATCH.MESSAGE | This variable will contain the diagnostic message generated by the particular exception encountered. If there was no message associated with the encountered exception, this variable will remain as an empty string. | CFCATCH.DETAIL | This variable holds a detailed message about the encountered exception as generated by the ColdFusion engine. This variable can be useful if you're trying to determine at precisely which point in your code the exception was encountered. | CFCATCH.TAGCONTEXT | This variable contains stack information about the name and position of tags in the tag stack. For this variable to contain information, you must have stack tracing enabled in the ColdFusion Administrator. | CFCATCH.NATIVEERRORCODE | When you're dealing with database connections, any error will generally result in a common error code. This variable will store that error code information, provided that the catch is of type database. If no error code is available, the variable will read -1. | CFCATCH.SQLSTATE | The SQLState associated with the exception is reported in this variable. Much like the NativeErrorCode variable, this variable will exist only when the catch is of type database. If no SQLState is reported with the specific error code being generated, this value will report a value of -1. | CFCATCH.ERRNUMBER | This value will contain the internal expression error number associated with the error when the catch is of type expression. | CFCATCH.MISSINGFILENAME | This value is useful when the catch is of type missinginclude. The value of this variable will include the name of the missing included file. | CFCATCH.LOCKNAME | When a catch type is defined as lock and your application code generates an exception as a result of a named lock, this variable will report the name of the named lock that generated the error. | CFCATCH.LOCKOPERATION | With the catch type of lock, this value will specify the type of error encountered when trying to create a lock for a specific segment of code. | CFCATCH.ERRORCODE | When the catch type is set to custom, this variable is used to send back a custom error string associated with the error encountered. | CFCATCH.EXTENDEDINFO | When the catch type is set to any, this variable is used to hold a custom error to be sent back to the user. | In many cases, you'll want to use these catch variables as a way to troubleshoot the actual reason for the error. The output presented to the user typically will be a generic, user-friendly, "error has occurred" type message. In such cases, the CFCATCH variables enable you to continue to present user-friendly error messages to the end user while still getting to the root cause of the trouble by carefully examining the content of the variables. Using CFTHROW In the earlier examples in this chapter, we looked at how to make use of a simple try/catch block to catch a database error as a result of a typographical error we made when we queried a specific database table. Now, let's look at a scenario in which we might want to purposefully throw an error within our application. Suppose that we had a CFML template that required a UserID be passed in before we allowed processing to continue. In that case, we might want to use a try/catch routine to make sure that the UserID passed in was valid; otherwise, we might want to send a specific message back to the user telling him or her that something went wrong. The following code demonstrates this concept in action: <cftry> <cfif NOT isDefined("UserId")> <cfthrow message="I threw an error when I checked for ID"> </cfif> <cfcatch type="any"> An error occurred </cfcatch> In this code, you see that we're checking to make sure that a UserID is defined. If it's not, we want our catch block to tell our user that "An error occurred." However, we want to know that "I threw an error when I checked for ID" occurred, which is what we're using the CFTHROW tag for in this instance. The CFTHROW tag can take various attributes, all of which are outlined in Table 9.3. Table 9.3. CFTHROW Attributes Attribute | Description | TYPE | This is an optional attribute that enables you to enter a custom throw type or to use the predefined application type. | MESSAGE | This is the message that you want to use to describe what has happened that has caused the throw section to run. | DETAIL | This is an optional attribute that enables you to specify a detailed description of the reason why you are throwing the error. | ERRORCODE | This attribute is optional and can be used to generate a custom error code that you are supplying. | EXTENDEDINFO | This attribute is optional and can be used to generate custom error information that you are supplying. | |