anchor.diff:  		</cfscript>
   	</cffunction>
   
  -	<cffunction name="addTableDef" output="false" returntype="void">
  -		<cfargument name="tabledef" type="tabledef" required="true">
  -		<cfset variables.tabledefs[arguments.tabledef.instance.name] = arguments.tabledef/>
  -	</cffunction>
   
   	<cfscript>
   		public tabledef function makeTable( required tabledef tabledef ){
  
positive.code: 			LOCAL.lines = LOCAL.reader.getLineNumber();
  			LOCAL.fileReader.close();
  			LOCAL.reader.close();
  		</cfscript>
  		<!--- Strip out line feeds, tabs and multiple spaces --->
  		<cfset LOCAL.content = "#trim(reReplaceNoCase(arguments.sql,chr(9),' ','all'))#"/>
  		<cfset LOCAL.content = reReplaceNoCase(LOCAL.content,chr(10),' ','all')/>
  		<cfset LOCAL.content = reReplaceNoCase(LOCAL.content,'[[:space:]]{2,2}',' ','all')/>
  		<cfset LOCAL.content = "#lines+1##chr(444)##now()##chr(444)##this.getDSN()##chr(444)##createUUID()##chr(444)##trim(LOCAL.content)##chr(10)#">
  		<cffile action="append" file="#transactionLogFile#" output="#encrypt(LOCAL.content,'0E69C1BB-BABA-4D48-A7C9D60D020485B0')##chr(555)#" addnewline="false" mode="664" charset="utf-8">
  
  
  	</cffunction>
  
  	<cffunction name="execute" hint="I execute database commands that do not return data.  I take an SQL execute command and return 0 for failure, 1 for success, or the last inserted ID if it was an insert." returntype="any" output="false">
  		<cfargument name="sql" required="true" type="string" hint="SQL command to execute.  Can be any valid SQL command.">
  		<cfargument name="writeTransactionLog" required="false" default="#this.getWriteTransactionLog() eq true#" type="boolean" hint="Do you want to write the executed statement to the transaction log?">
  
  		<cfset var ret = 0 />
  		<cfset var exec = "" />
  		<cfset var LOCAL = structNew() />
  		<cfset var result = {}/>
   		<cftry>
  
  				<!---
  					We need to parse the sql
  					statement to find $queryParam()$ calls.  We do this by
  					passing the sql to parseQueryParams, which replaces the
  					$queryParam()$ function call with a pseudo cfqueryparam that
  					we can digest here to build the query.  The returned pseudo
  					cfqueryparam tag is structured as follows:
  
  					<cfqueryparam
  								cfsqltype="sql data type"  <--- this is converted
  																to cfsqltype using
  																getCFSQLType
  								value="actual value" />
  
  					EXAMPLE: $queryParam(value='abc',cfsqltype='varchar')$
  					This can also be done prior to sending the SQL statement to this
  					function by calling the queryParam() function directly.
  					EXAMPLE: #dao.queryParam(value='abc',cfsqltype='varchar')#
  					This direct method is recommended.
  				 --->
  				<!--- First thing to do is replace the <cfqueryparam with a delimiter chr(999) --->
  				<cfset LOCAL.tmpSQL = parseQueryParams(arguments.sql)>
  				<!--- Now we build the query --->
  
  			 	<cfquery datasource="#variables.dsn#" result="LOCAL.result">
  					<!--- The first position of the tmpSQL list will be the first section of SQL code --->
  					#listFirst(preserveSingleQuotes(LOCAL.tmpSQL),chr(998))#
  					<!--- Now, we loop through the rest of the tmpSQL to build the cfqueryparams --->
  					<cfloop list="#listDeleteAt(LOCAL.tmpSQL,1,chr(998))#" delimiters="#chr(998)#" index="LOCAL.idx">
  						<!---
  							This will return the position and length of the cfsqltype
  							We use this to extract the values for the actual cfqueryparam
  						--->
  						<cfset LOCAL.tempCFSQLType = reFindNoCase('cfsqltype\=#chr(777)#(.*?)#chr(777)#',LOCAL.idx,1,true)>
  						<!--- A little regex to extract the value from the queryparam string  --->
  						<cfset LOCAL.value = reReplaceNoCase(PreserveSingleQuotes(LOCAL.idx),'.*value\=#chr(777)#(.*?)#chr(777)#.*','\1','all')>
  						<!--- Strip out any loose hanging special characters used for temporary delimiters (chr(999) and chr(777)) --->
  						<cfset LOCAL.value = reReplaceNoCase(preserveSingleQuotes(LOCAL.value),chr(999),'','all')>
  
  						<!--- We'll look for the list and null attributes to see if they exist and then extract their values --->
  						<cfset LOCAL.tempList = reFindNoCase('list\=#chr(777)#(.*?)#chr(777)#',LOCAL.idx,1,true)>
  						<cfif NOT arrayLen(LOCAL.tempList.pos) GTE 2 OR NOT isBoolean(mid(LOCAL.idx,LOCAL.tempList.pos[2],LOCAL.tempList.len[2]))>
  							<cfset LOCAL.isList = false />
  						<cfelse>
  							<cfset LOCAL.isList = mid(LOCAL.idx,LOCAL.tempList.pos[2],LOCAL.tempList.len[2])/>
  						</cfif>
  						<cfset LOCAL.tempNull = reFindNoCase('null\=#chr(777)#(.*?)#chr(777)#',LOCAL.idx,1,true)>
  						<cfif NOT arrayLen(LOCAL.tempNull.pos) GTE 2 OR NOT isBoolean(mid(LOCAL.idx,LOCAL.tempNull.pos[2],LOCAL.tempNull.len[2]))>
  							<cfset LOCAL.isNull = false />
  						<cfelse>
  							<cfset LOCAL.isNull = mid(LOCAL.idx,LOCAL.tempNull.pos[2],LOCAL.tempNull.len[2])/>
  						</cfif>
  
  						<cfset LOCAL.cfSQLType = mid(LOCAL.idx,LOCAL.tempCFSQLType.pos[2],LOCAL.tempCFSQLType.len[2])/>
  
  						<cfif getUseCFQueryParams()>
  							<!--- Now write the cfqueryparam --->
  							<cfqueryparam
  								cfsqltype="#LOCAL.cfSQLType#"
  								value="#LOCAL.value#"
  								list="#LOCAL.isList#"
  								null="#LOCAL.isNull#">
  						<cfelse>
  							#this.getNonQueryParamFormattedValue(
  													value = LOCAL.value,
  													cfsqltype = LOCAL.cfSQLType,
  													list = LOCAL.isList,
  													null = LOCAL.isNull)#
  
  						</cfif>
  						<!--- Now anything after the closing > should be  --->
  					 	<cfif len(listLast(preserveSingleQuotes(LOCAL.idx),chr(999)))> #listLast(preserveSingleQuotes(LOCAL.idx),chr(999))#</cfif>
  					</cfloop>
  				</cfquery>
  
  				<!--- Grab the last inserted ID if it was an insert --->
  				<cfif refindNoCase('INSERT(.*?)INTO (.*?)\(',LOCAL.tmpSQL)>
  
  					<cfif structkeyExists(LOCAL.result,'GENERATED_KEY')><!--- MySQL --->
  
  						<cfset LOCAL.lastInsertedID = LOCAL.result.GENERATED_KEY/>
  
  					<!--- Some versions of MSSQL call this 'GENERATEDKEY' (-sy) --->
  					<cfelseif structkeyExists(LOCAL.result,'GENERATEDKEY')>
  
  						<cfset LOCAL.lastInsertedID = LOCAL.result.GENERATEDKEY/>
  
  					<cfelseif structkeyExists(LOCAL.result,'IDENTITYCOL')><!--- MSSQL --->
  
  						<cfset LOCAL.lastInsertedID = LOCAL.result.IDENTITYCOL/>
  
  					<cfelseif structkeyExists(LOCAL.result,'ROWID')><!--- Oracle --->
  
  						<cfset LOCAL.lastInsertedID = LOCAL.result.ROWID/>
  
  					<cfelseif structkeyExists(LOCAL.result,'SYB_IDENTITY')><!--- Sybase --->
  
  						<cfset LOCAL.lastInsertedID = LOCAL.result.SYB_IDENTITY/>
  
  					<cfelseif structkeyExists(LOCAL.result,'SERIAL_COL')><!--- Informix --->
  
  						<cfset LOCAL.lastInsertedID = LOCAL.result.SERIAL_COL/>
  
  					<cfelse><!--- Rely on db connector cfc to provide last ID --->
  
  						<cfset LOCAL.lastInsertedID = getLastID()/>
  
  					</cfif>
  
  					<cfset ret = LOCAL.lastInsertedID/>
  
  				<cfelse>
  					<cfset LOCAL.lastInsertedID = 1/>
  					<cfset ret = 1/>
  
  				</cfif>
  
  
  			<!--- Now write to the transaction log --->
  			<cfif arguments.writeTransactionLog>
  				<cfset this.logTransaction(arguments.sql,LOCAL.lastInsertedID)/>
  			</cfif>
  			<cfcatch type="database">
  				<cfif findNoCase('Invalid data',cfcatch.Message)>
  					<cfheader statuscode="500"/>
  					<cfthrow errorcode="801" type="custom.error" detail="Invalid Data Type" message="The value: &quot;#cfcatch.value#&quot; was expected to be of type: &nbsp;#listLast(cfcatch.sql_type,'_')#.  Please correct the values and try again.">
  				<cfelse>
  					<cfrethrow>
  				</cfif>
  			</cfcatch>
  			<cfcatch type="any">
  				<cfthrow errorcode="802-dao.execute" type="custom.error" detail="Unexpected Error" message="There was an unexpected error updating the database.  Please contact your administrator. #cfcatch.message#">
  				<cfset ret = 0/>
  			</cfcatch>
  		</cftry>
  
  		<cfreturn ret />
  
  	</cffunction>
  
  
  
  	<!--- Database Generic Functions --->
  
  	<cffunction name="prepareNonQueryParamValue" returntype="string" output="false" hint="I prepare a parameter value for SQL execution when not using cfqueryparam.  Basically I try to do the same thing as cfqueryparam.">
  		<cfargument name="value" type="string" required="true">
  		<cfargument name="cfsqltype" type="string" required="true">
  		<cfargument name="null" type="boolean" required="true">
  
  		<cfset var LOCAL = {}/>
  
  		<cfif arguments.cfSQLType is "cf_sql_timestamp" or arguments.cfSQLType is "cf_sql_date">
  			<cfif arguments.value is "0000-00-00 00:00">
  				<cfset LOCAL.ret = "'#arguments.value#'"/>
  			<cfelseif isDate(arguments.value)>
  				<cfset LOCAL.ret = createODBCDateTime(arguments.value)/>
  			<cfelse>
  				<cfset LOCAL.ret = "'0000-00-00 00:00'"/>
  			</cfif>
  		<cfelseif arguments.cfSQLType is "cf_sql_integer">
  			<cfset LOCAL.ret = val(arguments.value)/>
  		<cfelseif arguments.cfSQLType is "cf_sql_boolean">
  			<cfset LOCAL.ret = val(arguments.value)/>
  		<cfelseif isSimpleValue(arguments.value)>
  			<cfset LOCAL.ret = "'#arguments.value#'"/>
  		</cfif>
  
  		<cfreturn LOCAL.ret />
  
  	</cffunction>
  
  	<cffunction name="getNonQueryParamFormattedValue"  returntype="string" output="false" hint="I prepare a parameter value for SQL execution when not using cfqueryparam.  Basically I try to do the same thing as cfqueryparam.">
  		<cfargument name="value" type="string" required="true">
  		<cfargument name="cfsqltype" type="string" required="true">
  		<cfargument name="list" type="string" required="true">
  		<cfargument name="null" type="boolean" required="true">
  
  		<cfset var LOCAL = {}/>
  
  		<cfif arguments.list>
  			<cfloop list="#arguments.value#" index="LOCAL.idx">
  				<cfset LOCAL.ret = listAppend(LOCAL.ret,
  					prepareNonQueryParamValue(
  						value = listGetAt(arguments.value,LOCAL.idx),
  						cfsqltype = arguments.cfsqltype,
  						null = arguments.null
  					))/>
  			</cfloop>
  		<cfelse>
  			<cfset LOCAL.ret =
  					prepareNonQueryParamValue(
  						value = arguments.value,
  						cfsqltype = arguments.cfsqltype,
  						null = arguments.null
  					)/>
  		</cfif>
  
  		<cfreturn LOCAL.ret />
  
  	</cffunction>
  
  	<cffunction name="getCFSQLType" returntype="string" hint="I determine the CFSQL type for the passd value and return the proper type as a string to be used in cfqueryparam." output="false">
  		<cfargument name="type" required="true">
  
  		<cfset var int_types = "int,integer,numeric,number,cf_sql_integer">
  		<cfset var string_types = "varchar,char,text,memo,nchar,nvarchar,ntext,cf_sql_varchar">
  		<cfset var date_types = "datetime,date,cf_sql_date">
  		<cfset var decimal_types = "decimal,cf_sql_decimal">
  		<cfset var money_types = "money,cf_sql_money">
  		<cfset var timestamp_types = "timestamp,cf_sql_timestamp">
  		<cfset var double_types = "double,cf_sql_double">
  		<cfset var bit_types = "bit">
  		<!--- Default return = varchar --->
  		<cfset var ret = "cf_sql_varchar">
  
  
  		<cfset var ret = arguments.type/>
  
  		<cfif listFindNoCase(int_types,arguments.type)>
  			<cfset ret = "cf_sql_integer">
  		<cfelseif listFindNoCase(string_types,arguments.type)>
  			<cfset ret = "cf_sql_varchar">
  		<cfelseif listFindNoCase(date_types,arguments.type)>
  			<cfset ret = "cf_sql_date">
  		<cfelseif listFindNoCase(decimal_types,arguments.type)>
  			<cfset ret = "cf_sql_decimal">
  		<cfelseif listFindNoCase(money_types,arguments.type)>
  			<cfset ret = "cf_sql_money">
  		<cfelseif listFindNoCase(double_types,arguments.type)>
  			<cfset ret = "cf_sql_double">
  		<cfelseif listFindNoCase(timestamp_types,arguments.type)>
  			<cfset ret = "cf_sql_timestamp">
  		<cfelseif listFindNoCase(bit_types,arguments.type)>
  			<cfset ret = "cf_sql_bit">
  		</cfif>
  
  		<cfreturn ret />
  	</cffunction>
  
  	<!--- setters --->
  
  	<cffunction name="setUseCFQueryParams" access="public" returntype="void" output="false">
  		<cfargument name="useCFQueryParams" type="boolean" required="true">
  
  		<cfset this.useCFQueryParams = arguments.useCFQueryParams/>
  		<cfset this.conn.useCFQueryParams = arguments.useCFQueryParams/>
  
  	</cffunction>
  
  	<cffunction name="getUseCFQueryParams" access="public" returntype="boolean" output="false">
  
  		<cfreturn this.conn.getUseCFQueryParams() />
  
  	</cffunction>
  
  	<cffunction name="setUpdate" returntype="void" hint="I build a container to be passed to the update function." output="false">
  		<cfargument name="table" required="true" type="string" hint="Table to perform action against.">
  		<cfargument name="key" required="true" type="any" hint="Primary Key Index value.">
  		<cfargument name="col_value" required="true" type="struct" hint="Column and Value pairs as a struct.">
  
  	</cffunction>
  
  	<cffunction name="define" hint="I return the structure of the passed table.  I am MySQL specific." returntype="query" access="public" output="false">
  		<cfargument name="table" required="true" type="string" hint="Table to define.">
  
  		<cfset var def = this.conn.define(arguments.table)>
  
  		<cfreturn def />
  	</cffunction>
  
  	<cffunction name="getColumnType" hint="I return the datatype for the given table.column.  I am MySQL specific." returntype="string" access="public" output="false">
  		<cfargument name="table" required="true" type="string" hint="Table to define.">
  		<cfargument name="column" required="true" type="string" hint="Column to define.">
  
  		<cfset var def = define(arguments.table)>
  		<cfset var col = "">
  		<cfset var ret = "">
  
  		<cfquery name="col" dbtype="query">
  			SELECT * FROM def
  			WHERE field = '#arguments.column#'
  		</cfquery>
  		<cfif find('(',col.type)>
  			<cfset ret = listFirst(col.type,'(')>
  		<cfelse>
  			<cfset ret = col.type>
  		</cfif>
  
  		<cfreturn ret />
  	</cffunction>
  
      <cffunction name="getTables" hint="I return a list of tables for the current database." returntype="query" access="public" output="false">
  
  		<cfset var tables = this.conn.getTables()>
  
  		<cfreturn tables />
  	</cffunction>
  
  	<cffunction name="getColumns" hint="I return a list of columns for the passed table." returntype="string" access="public" output="false">
  		<cfargument name="table" required="true" type="string" hint="Table to define.">
  
  		<cfset var def = new tabledef(tablename=arguments.table,dsn=variables.dsn)/>
  		<cfset var cols = def.getColumns()>
  
  		<cfif !len(trim(cols))>
  			<cfset cols = "*"/>
  		</cfif>
  
  		<cfreturn cols />
  	</cffunction>
  
  	<cffunction name="getPrimaryKey" hint="I get the primary key for the given table. To do this I envoke the getPrimaryKey from the conneted database type." output="false">
  		<cfargument name="table" required="true" type="string">
  
  		<cfreturn this.conn.getPrimaryKey(arguments.table)/>
  
  	</cffunction>
  
  	<cffunction name="getSafeColumnNames" access="public" returntype="string" hint="I take a list of columns and return it as a safe columns list with each column wrapped within ``.  This is MySQL Specific." output="false">
  		<cfargument name="cols" required="true" type="string">
  
  			<cfset var columns = this.conn.getSafeColumnNames( arguments.cols )/>
  
  		<cfreturn columns />
  
  	</cffunction>
  
  	<cffunction name="getSafeColumnName" access="public" returntype="string" hint="I take a single column name and return it as a safe columns list with each column wrapped within ``.  This is MySQL Specific." output="false">
  		<cfargument name="col" required="true" type="string">
  
  		<cfset var ret = this.conn.getSafeColumnName( arguments.col )/>
  
  
  		<cfreturn ret />
  
  	</cffunction>
  
  	<cffunction name="getSafeIdentifierStartChar" access="public" returntype="string" hint="I return the opening escape character for a column name.  This is MySQL Specific." output="false">
  		<cfreturn this.conn.getSafeIdentifierStartChar() />
  	</cffunction>
  
  	<cffunction name="getSafeIdentifierEndChar" access="public" returntype="string" hint="I return the closing escape character for a column name.  This is MySQL Specific." output="false">
  		<cfreturn this.conn.getSafeIdentifierEndChar() />
  	</cffunction>
  
  	<cffunction name="queryParam" hint="I create the values to build the cfqueryparam tag." output="false" returntype="string">
  		<cfargument name="value" type="string" required="true">
  		<cfargument name="cfsqltype" type="string" required="false" default="cf_sql_varchar" hint="This can be a standard RDBS datatype or a cf_sql_type (see getCFSQLType())">
  		<cfargument name="list" type="boolean" required="false" default="false">
  		<cfargument name="null" required="false" type="boolean" default="false">
  
  		<cfset var returnStruct = structNew() />
  		<cfset var returnString = structNew() />
  
  		<cfset returnStruct = queryParamStruct(value=trim(arguments.value),cfsqltype=arguments.cfsqltype,list=arguments.list,null=arguments.null)>
   		<cfset returnString = '#chr(998)#list=#chr(777)##returnStruct.list##chr(777)# null=#chr(777)##returnStruct.null##chr(777)# cfsqltype=#chr(777)##returnStruct.cfsqltype##chr(777)# value=#chr(777)##returnStruct.value##chr(777)##chr(999)#'>
  		<cfreturn returnString />
  	</cffunction>
  
  	<cffunction name="queryParamStruct" hint="I create the values to build the cfqueryparam tag." output="false" returntype="struct">
  		<cfargument name="value" type="string" required="true">
  		<cfargument name="cfsqltype" type="string" required="false" default="cf_sql_varchar" hint="This can be a standard RDBS datatype or a cf_sql_type (see getCFSQLType())">
  		<cfargument name="list" type="boolean" required="false" default="false">
  		<cfargument name="null" required="false" type="boolean" default="false">
  
  		<cfset var returnStruct = structNew() />
  
  		<cfset returnStruct.cfsqltype = reReplaceNoCase(getCFSQLType(arguments.cfsqltype),'\$queryparam','INVALID','all')>
  		<!--- strip out any queryparam calls in the value, this will prevent the ability to submit malicious code through the SQL string --->
  		<cfset returnStruct.value = reReplaceNoCase(arguments.value,'\$queryparam','INVALID','all')>
  		<cfset returnStruct.list = reReplaceNoCase(arguments.list,'\$queryparam','INVALID','all')>
  		<cfset returnStruct.null = reReplaceNoCase(arguments.null,'\$queryparam','INVALID','all')>
  
  		<cfreturn returnStruct />
  	</cffunction>
  
  	<cffunction name="parameterizeSQL" output="true" access="public" returntype="struct" hint="I build a struct containing all of the where clause of the SQL statement, parameterized when possible.  The returned struct will contain an array of each parameterized clause containing the data necessary to build a <cfqueryparam> tag.">
  		<cfargument name="sql" type="string" required="true" hint="SQL statement (or partial SQL statement) which contains tokenized queryParam calls">
  
negative.code: 	<cfproperty name="dbversion" type="string">
  	<cfproperty name="writeTransactionLog" type="boolean">
  	<cfset _resetCriteria() />
  	<cfscript>
  
  		/**
  		* I initialize DAO
  		* @dsn Data Source Name
  		* @dbtype Database Type
  		* @user Data Source User Name
  		* @password Data Source Password
  		* @writeTransactionLog Write transactions to log (for replication)
  		* @transactionLogFile Location to write the transaction log
  		* @useCFQueryParams Determines if execute queries will use cfqueryparam
  		**/
  		public DAO function init( required string dsn, string dbtype = "", string user = "", string password ="", boolean writeTransactionLog = false, string transactionLogFile = "#expandPath('/')#sql_transaction_log.sql", boolean useCFQueryParams = true ){
  
  			//This is the datasource name for the system
  			variables.dsn = arguments.dsn;
  