| 3 | | <cffunction name="getTableDefinition" access="private" hint="I return the definition for a table." output="false" returntype="struct"> |
| 4 | | <cfargument name="name" hint="I am the name of the table to get the definition for." required="yes" type="string" /> |
| 5 | | <cfset var TimedCache = getTimedCache() /> |
| 6 | | <cfset var q = StructNew() /> |
| 7 | | <cfset var fkName = "" /> |
| 8 | | |
| 9 | | <cfif TimedCache.exists("def_" & arguments.name)> |
| 10 | | <cfset q = TimedCache.getValue("def_" & arguments.name) /> |
| 11 | | <cfelse> |
| 12 | | <!--- use db-native techniques to inspect the database ---> |
| 13 | | <cfstoredproc datasource="#getDsn()#" procedure="sp_tables"> |
| 14 | | <cfprocparam cfsqltype="cf_sql_varchar" scale="384" value="#arguments.name#" /> |
| 15 | | <cfprocresult name="q.table" resultset="1" /> |
| 16 | | </cfstoredproc> |
| 17 | | |
| 18 | | <!--- before we go any further, check to make sure the name is a real table ---> |
| 19 | | <cfif NOT q.table.recordCount> |
| 20 | | <cfthrow type="reactor.InvalidTableName" |
| 21 | | message="Invalid Name Argument" |
| 22 | | detail="The name argument must be a valid table or view name which exists in the database." /> |
| 23 | | </cfif> |
| 24 | | |
| 25 | | <cfstoredproc datasource="#getDsn()#" procedure="sp_pkeys"> |
| 26 | | <cfprocparam cfsqltype="cf_sql_varchar" scale="384" value="#arguments.name#" /> |
| 27 | | <cfprocresult name="q.primaryKey" resultset="1" /> |
| 28 | | </cfstoredproc> |
| 29 | | |
| 30 | | <cfstoredproc datasource="#getDsn()#" procedure="sp_columns"> |
| 31 | | <cfprocparam cfsqltype="cf_sql_varchar" scale="384" value="#arguments.name#" /> |
| 32 | | <cfprocresult name="q.columns" resultset="1" /> |
| 33 | | </cfstoredproc> |
| 34 | | |
| 35 | | <!--- find out which tables are referred to by this table ---> |
| 36 | | <cfquery name="q.foreignKeys" datasource="#getDsn()#"> |
| | 3 | <cffunction name="getReferencingKeys" access="public" hint="I return a query of external table's keys referencing this table." output="false" returntype="query"> |
| | 4 | <cfargument name="name" hint="I am the name of the table inspect." required="yes" type="string" /> |
| | 5 | <cfset var TimedCache = getTimedCache() /> |
| | 6 | <cfset var qReferencingKey = 0 /> |
| | 7 | |
| | 8 | <cfif TimedCache.exists("referencingKey_" & arguments.name)> |
| | 9 | <cfset qReferencingKey = TimedCache.getValue("referencingKey_" & arguments.name) /> |
| | 10 | <cfelse> |
| | 11 | <cfquery name="qReferencingKey" datasource="#getDsn()#"> |
| | 12 | SELECT so.name as fkName, |
| | 13 | forTab.name as foreignTableName, |
| | 14 | thsTab.name as thisTableName, |
| | 15 | forCol.name as foreignColumnName, |
| | 16 | thsCol.name as thisColumnName, |
| | 17 | thsTab.name + '.' + thsCol.name + '->' + forTab.name + '.' + forCol.name as asString |
| | 18 | FROM SysForeignKeys as sfk JOIN SysObjects as so |
| | 19 | ON sfk.constid = so.id |
| | 20 | JOIN SysObjects as forTab |
| | 21 | ON sfk.rkeyid = forTab.id |
| | 22 | JOIN SysObjects as thsTab |
| | 23 | ON sfk.fkeyid = thsTab.id |
| | 24 | JOIN SysColumns as forCol |
| | 25 | ON sfk.rkeyid = forCol.id AND sfk.rkey = forCol.colid |
| | 26 | JOIN SysColumns as thsCol |
| | 27 | ON sfk.fkeyid = thsCol.id AND sfk.fkey = thsCol.colid |
| | 28 | WHERE forTab.name = <cfqueryparam cfsqltype="cf_sql_varchar" scale="128" value="#arguments.name#" /> |
| | 29 | ORDER BY sfk.constid |
| | 30 | </cfquery> |
| | 31 | |
| | 32 | <!--- cache the results ---> |
| | 33 | <cfset TimedCache.setValue("referencingKey_" & arguments.name, qReferencingKey) /> |
| | 34 | </cfif> |
| | 35 | |
| | 36 | <!--- return the data ---> |
| | 37 | <cfreturn qReferencingKey /> |
| | 38 | </cffunction> |
| | 39 | |
| | 40 | <cffunction name="getForeignKeys" access="public" hint="I return a query of foreign key information on the table." output="false" returntype="query"> |
| | 41 | <cfargument name="name" hint="I am the name of the table inspect." required="yes" type="string" /> |
| | 42 | <cfset var TimedCache = getTimedCache() /> |
| | 43 | <cfset var qForeignKey = 0 /> |
| | 44 | |
| | 45 | <cfif TimedCache.exists("foreignKey_" & arguments.name)> |
| | 46 | <cfset qForeignKey = TimedCache.getValue("foreignKey_" & arguments.name) /> |
| | 47 | <cfelse> |
| | 48 | <cfquery name="qForeignKey" datasource="#getDsn()#"> |
| 57 | | <cfquery name="q.referencingKeys" datasource="#getDsn()#"> |
| 58 | | SELECT so.name as fkName, |
| 59 | | forTab.name as foreignTableName, |
| 60 | | thsTab.name as thisTableName, |
| 61 | | forCol.name as foreignColumnName, |
| 62 | | thsCol.name as thisColumnName, |
| 63 | | thsTab.name + '.' + thsCol.name + '->' + forTab.name + '.' + forCol.name as asString |
| 64 | | FROM SysForeignKeys as sfk JOIN SysObjects as so |
| 65 | | ON sfk.constid = so.id |
| 66 | | JOIN SysObjects as forTab |
| 67 | | ON sfk.rkeyid = forTab.id |
| 68 | | JOIN SysObjects as thsTab |
| 69 | | ON sfk.fkeyid = thsTab.id |
| 70 | | JOIN SysColumns as forCol |
| 71 | | ON sfk.rkeyid = forCol.id AND sfk.rkey = forCol.colid |
| 72 | | JOIN SysColumns as thsCol |
| 73 | | ON sfk.fkeyid = thsCol.id AND sfk.fkey = thsCol.colid |
| 74 | | WHERE forTab.name = <cfqueryparam cfsqltype="cf_sql_varchar" scale="128" value="#arguments.name#" /> |
| 75 | | ORDER BY sfk.constid |
| 76 | | </cfquery> |
| 77 | | |
| 78 | | <!--- cache the results ---> |
| 79 | | <cfset TimedCache.setValue("def_" & arguments.name, q) /> |
| 80 | | </cfif> |
| 81 | | |
| 82 | | <!--- return the data ---> |
| 83 | | <cfreturn q /> |
| | 69 | <!--- cache the results ---> |
| | 70 | <cfset TimedCache.setValue("foreignKey_" & arguments.name, qForeignKey) /> |
| | 71 | </cfif> |
| | 72 | |
| | 73 | <!--- return the data ---> |
| | 74 | <cfreturn qForeignKey /> |
| | 75 | </cffunction> |
| | 76 | |
| | 77 | <cffunction name="getPrimaryKeyColumnList" access="public" hint="I return a list of columns in the primary on the table." output="false" returntype="string"> |
| | 78 | <cfargument name="name" hint="I am the name of the table inspect." required="yes" type="string" /> |
| | 79 | <cfset var TimedCache = getTimedCache() /> |
| | 80 | <cfset var qPrimaryKey = 0 /> |
| | 81 | <cfset var columnList = "" /> |
| | 82 | |
| | 83 | <cfif TimedCache.exists("primaryKey_" & arguments.name)> |
| | 84 | <cfset columnList = TimedCache.getValue("primaryKey_" & arguments.name) /> |
| | 85 | <cfelse> |
| | 86 | <cfstoredproc datasource="#getDsn()#" procedure="sp_pkeys"> |
| | 87 | <cfprocparam cfsqltype="cf_sql_varchar" scale="384" value="#arguments.name#" /> |
| | 88 | <cfprocresult name="qPrimaryKey" resultset="1" /> |
| | 89 | </cfstoredproc> |
| | 90 | |
| | 91 | <!--- cache the results ---> |
| | 92 | <cfset columnList = ValueList(qPrimaryKey.column_name) /> |
| | 93 | <cfset TimedCache.setValue("primaryKey_" & arguments.name, columnList) /> |
| | 94 | </cfif> |
| | 95 | |
| | 96 | <!--- return the data ---> |
| | 97 | <cfreturn columnList /> |
| | 98 | </cffunction> |
| | 99 | |
| | 100 | <cffunction name="getColumns" access="public" hint="I return a query of column information on the table." output="false" returntype="query"> |
| | 101 | <cfargument name="name" hint="I am the name of the table inspect." required="yes" type="string" /> |
| | 102 | <cfset var TimedCache = getTimedCache() /> |
| | 103 | <cfset var qColumns = 0 /> |
| | 104 | |
| | 105 | <cfif TimedCache.exists("columns_" & arguments.name)> |
| | 106 | <cfset qColumns = TimedCache.getValue("columns_" & arguments.name) /> |
| | 107 | <cfelse> |
| | 108 | <cfstoredproc datasource="#getDsn()#" procedure="sp_columns"> |
| | 109 | <cfprocparam cfsqltype="cf_sql_varchar" scale="384" value="#arguments.name#" /> |
| | 110 | <cfprocresult name="qColumns" resultset="1" /> |
| | 111 | </cfstoredproc> |
| | 112 | |
| | 113 | <!--- cache the results ---> |
| | 114 | <cfset TimedCache.setValue("columns_" & arguments.name, qColumns) /> |
| | 115 | </cfif> |
| | 116 | |
| | 117 | <!--- return the data ---> |
| | 118 | <cfreturn qColumns /> |
| | 119 | </cffunction> |
| | 120 | |
| | 121 | <cffunction name="getTable" access="public" hint="I return a query of generic information on the table. If the table doesn't exist I throw an error." output="false" returntype="query"> |
| | 122 | <cfargument name="name" hint="I am the name of the table inspect." required="yes" type="string" /> |
| | 123 | <cfset var TimedCache = getTimedCache() /> |
| | 124 | <cfset var qTable = 0 /> |
| | 125 | |
| | 126 | <cfif TimedCache.exists("table_" & arguments.name)> |
| | 127 | <cfset qTable = TimedCache.getValue("table_" & arguments.name) /> |
| | 128 | <cfelse> |
| | 129 | <cfstoredproc datasource="#getDsn()#" procedure="sp_tables"> |
| | 130 | <cfprocparam cfsqltype="cf_sql_varchar" scale="384" value="#arguments.name#" /> |
| | 131 | <cfprocresult name="qTable" resultset="1" /> |
| | 132 | </cfstoredproc> |
| | 133 | |
| | 134 | <!--- before we go any further, check to make sure the name is a real table ---> |
| | 135 | <cfif NOT qTable.recordCount> |
| | 136 | <cfthrow type="reactor.InvalidTableName" |
| | 137 | message="Invalid Name Argument" |
| | 138 | detail="The name argument must be a valid table or view name which exists in the database." /> |
| | 139 | </cfif> |
| | 140 | |
| | 141 | <!--- cache the results ---> |
| | 142 | <cfset TimedCache.setValue("table_" & arguments.name, qTable) /> |
| | 143 | </cfif> |
| | 144 | |
| | 145 | <!--- return the data ---> |
| | 146 | <cfreturn qTable /> |
| | 147 | </cffunction> |
| | 148 | |
| | 149 | <cffunction name="getTableDefinition" access="private" hint="I return the definition for a table." output="false" returntype="struct"> |
| | 150 | <cfargument name="name" hint="I am the name of the table to get the definition for." required="yes" type="string" /> |
| | 151 | <cfset var definition = StructNew() /> |
| | 152 | |
| | 153 | <cfset definition.table = getTable(arguments.name) /> |
| | 154 | <cfset definition.columns = getColumns(arguments.name) /> |
| | 155 | <cfset definition.columnList = ValueList(definition.columns.column_name) /> |
| | 156 | <cfset definition.primaryKeyColumnList = getPrimaryKeyColumnList(arguments.name) /> |
| | 157 | <cfset definition.foreignKeys = getForeignKeys(arguments.name) /> |
| | 158 | <cfset definition.foreignKeysColumnList = ValueList(definition.foreignKeys.foreignColumnName) /> |
| | 159 | <cfset definition.referencingKeys = getReferencingKeys(arguments.name) /> |
| | 160 | <cfset definition.baseTable = getBaseTable(arguments.name, definition.primaryKeyColumnList, definition.foreignKeys) /> |
| | 161 | <cfset definition.baseTableColumns = getColumns(definition.baseTable) /> |
| | 162 | <cfset definition.baseTablePrimaryKeyColumnList = getPrimaryKeyColumnList(definition.baseTable) /> |
| | 163 | |
| | 164 | <!--- return the data ---> |
| | 165 | <cfreturn definition /> |
| | 272 | |
| | 273 | <cfif TimedCache.exists("base_" & arguments.name)> |
| | 274 | <cfset arguments.name = TimedCache.getValue("base_" & arguments.name) /> |
| | 275 | <cfelse> |
| | 276 | <!--- loop over the foreign keys ---> |
| | 277 | <cfloop query="arguments.foreignKeys"> |
| | 278 | <!--- check to see if we're starting a new fk set ---> |
| | 279 | <cfif currentFkName IS NOT arguments.foreignKeys.fkName> |
| | 280 | <!--- reset some variables ---> |
| | 281 | <!--- set the foreign key name. we'll use this to check to see if we're still on the same foreign key as we loop over the fk query ---> |
| | 282 | <cfset currentFkName = arguments.foreignKeys.fkName /> |
| | 283 | <!--- get a list of all columns in the primary key ---> |
| | 284 | <cfset pkColumnList = arguments.primaryKeyColumnList /> |
| | 285 | </cfif> |
| | 286 | |
| | 287 | <!--- Check to see if the columns in the foreign key named #currentFkName# represent all of the columns in the primary key columns. ---> |
| | 288 | |
| | 289 | <!--- if the FK column name exists in the primary key then delete it from the list. ---> |
| | 290 | <cfset listLoc = ListFindNoCase(pkColumnList, arguments.foreignKeys.thisColumnName) /> |
| | 291 | <cfif listLoc> |
| | 292 | <cfset pkColumnList = ListDeleteAt(pkColumnList, listLoc) /> |
| | 293 | </cfif> |
| | 294 | |
| | 295 | <!--- if we don't have any items left in the primary key column list then all of the columns in the primary key are part of the foreign key to another table. ---> |
| | 296 | <cfif NOT Len(pkColumnList)> |
| | 297 | <!--- the foreign table is a "super" table for this table ---> |
| | 298 | <cfset arguments.name = arguments.foreignKeys.foreignTableName /> |
| | 299 | <cfbreak /> |
| | 300 | </cfif> |
| | 301 | </cfloop> |
| 187 | | <!--- loop over the foreign keys ---> |
| 188 | | <cfloop query="foreignKeys"> |
| 189 | | <!--- check to see if we're starting a new fk set ---> |
| 190 | | <cfif currentFkName IS NOT foreignKeys.fkName> |
| 191 | | <!--- reset some variables ---> |
| 192 | | <!--- set the foreign key name. we'll use this to check to see if we're still on the same foreign key as we loop over the fk query ---> |
| 193 | | <cfset currentFkName = foreignKeys.fkName /> |
| 194 | | <!--- get a list of all columns in the primary key ---> |
| 195 | | <cfset primaryKeyColumnList = ValueList(primarykey.column_name) /> |
| 196 | | </cfif> |
| 197 | | |
| 198 | | <!--- Check to see if the columns in the foreign key named #currentFkName# represent all of the columns in the primary key columns. ---> |
| 199 | | |
| 200 | | <!--- if the FK column name exists in the primary key then delete it from the list. ---> |
| 201 | | <cfset listLoc = ListFindNoCase(primaryKeyColumnList, foreignKeys.thisColumnName) /> |
| 202 | | <cfif listLoc> |
| 203 | | <cfset primaryKeyColumnList = ListDeleteAt(primaryKeyColumnList, listLoc) /> |
| 204 | | </cfif> |
| 205 | | |
| 206 | | <!--- if we don't have any items left in the primary key column list then all of the columns in the primary key are part of the foreign key to another table. ---> |
| 207 | | <cfif NOT Len(primaryKeyColumnList)> |
| 208 | | <!--- the foreign table is a "super" table for this table ---> |
| 209 | | <cfset arguments.name = foreignKeys.foreignTableName /> |
| 210 | | <cfbreak /> |
| 211 | | </cfif> |
| 212 | | </cfloop> |
| | 303 | <!--- cache the results ---> |
| | 304 | <cfset TimedCache.setValue("base_" & arguments.name, arguments.name) /> |
| | 305 | </cfif> |