sp_CreateUserDefinedType.txt 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. CREATE PROCEDURE sp_CreateUserDefinedType
  2. @Action VARCHAR(50) = NULL,
  3. @UserDefinedType VARCHAR(200) = NULL,
  4. @Definition NVARCHAR(MAX) = NULL
  5. AS
  6. BEGIN
  7. -- Run this proc without any parameters for help on it.
  8. DECLARE @SQL NVARCHAR(MAX);
  9. DECLARE @ProcCount INT;
  10. DECLARE @ProcLoop INT;
  11. DECLARE @ProcSQLCount INT;
  12. DECLARE @ProcSQLLoop INT;
  13. DECLARE @ProcID INT;
  14. DECLARE @ProcName SYSNAME;
  15. DECLARE @CreatedTransaction BIT;
  16. DECLARE @ErrorMessage NVARCHAR(4000);
  17. DECLARE @ErrorSeverity INT;
  18. DECLARE @ErrorState INT;
  19. DECLARE @ErrorNumber INT;
  20. DECLARE @ErrorLine INT;
  21. SET NOCOUNT ON;
  22. DECLARE @Info TABLE
  23. (
  24. Info VARCHAR(500)
  25. )
  26. DECLARE @Procs TABLE
  27. (
  28. ID INT IDENTITY(1,1),
  29. ProcID INT,
  30. ProcName SYSNAME
  31. )
  32. DECLARE @ProcSQL TABLE
  33. (
  34. ProcID INT,
  35. ProcSQL NVARCHAR(MAX),
  36. SortOrder INT
  37. )
  38. IF ISNULL(@Action,'') NOT IN ('CREATE','LIST','ALTER','FORCE','DROP','KILL')
  39. BEGIN
  40. INSERT INTO @Info (Info) VALUES ('sp_CreateUserDefinedType @Action,@UserDefinedType,@Definition');
  41. INSERT INTO @Info (Info) VALUES ('This proc solves the problem of what if');
  42. INSERT INTO @Info (Info) VALUES ('you want to change a user defined type');
  43. INSERT INTO @Info (Info) VALUES ('and a procedure is currently using it.');
  44. INSERT INTO @Info (Info) VALUES ('Creates, drops, or alters a user defined type');
  45. INSERT INTO @Info (Info) VALUES ('@Action can be one of the following values:');
  46. INSERT INTO @Info (Info) VALUES ('CREATE - Drop/Creates a new user defined type.');
  47. INSERT INTO @Info (Info) VALUES (' Only works if no proc is using it.');
  48. INSERT INTO @Info (Info) VALUES ('LIST - Lists all the procedures');
  49. INSERT INTO @Info (Info) VALUES (' using this user defined type.');
  50. INSERT INTO @Info (Info) VALUES ('DROP - Drops the type IF it`s not being used.');
  51. INSERT INTO @Info (Info) VALUES ('KILL - Drops the type AND all procs using it.');
  52. INSERT INTO @Info (Info) VALUES ('ALTER - Drops all the procs using');
  53. INSERT INTO @Info (Info) VALUES (' it, drops the type, creates the new');
  54. INSERT INTO @Info (Info) VALUES (' type, then recreates the new procedures.');
  55. INSERT INTO @Info (Info) VALUES ('FORCE - Similar to ALTER, except:');
  56. INSERT INTO @Info (Info) VALUES (' 1. ALTER will fail if the change would');
  57. INSERT INTO @Info (Info) VALUES (' cause a stored proc to fail to compile.');
  58. INSERT INTO @Info (Info) VALUES (' 2. If this user defined type would cause a');
  59. INSERT INTO @Info (Info) VALUES (' proc to not compile, FORCE drops that');
  60. INSERT INTO @Info (Info) VALUES (' proc, then lists it.');
  61. INSERT INTO @Info (Info) VALUES ('Check out other cool tools like');
  62. INSERT INTO @Info (Info) VALUES ('sp_ColumnsInATable')
  63. INSERT INTO @Info (Info) VALUES ('sp_DropColumn')
  64. INSERT INTO @Info (Info) VALUES ('sp_Find')
  65. INSERT INTO @Info (Info) VALUES ('sp_FindColumn')
  66. INSERT INTO @Info (Info) VALUES ('sp_FindInProc')
  67. INSERT INTO @Info (Info) VALUES ('sp_FindInAllProcs')
  68. INSERT INTO @Info (Info) VALUES ('sp_List')
  69. INSERT INTO @Info (Info) VALUES ('sp_varinsp')
  70. SELECT Info from @Info;
  71. RETURN;
  72. END;
  73. SET @ProcCount = 0;
  74. SET @CreatedTransaction = 0;
  75. BEGIN TRY
  76. IF TYPE_ID(@UserDefinedType) IS NOT NULL
  77. BEGIN
  78. -- Get the procedures that use this
  79. INSERT INTO @Procs(ProcID,ProcName)
  80. select distinct so.id,so.name
  81. from sysobjects as so
  82. inner join syscolumns as sc
  83. on so.id = sc.id
  84. inner join systypes as t
  85. on sc.xusertype = t.xusertype
  86. where so.xtype='P'
  87. and t.name = @UserDefinedType;
  88. SET @ProcCount = @@ROWCOUNT;
  89. IF @Action IN ('CREATE','DROP') AND @ProcCount > 0
  90. BEGIN
  91. INSERT INTO @Info (Info) VALUES ('Type '+@UserDefinedType);
  92. INSERT INTO @Info (Info) VALUES ('already exists and is being');
  93. INSERT INTO @Info (Info) VALUES ('used by the following procs:');
  94. INSERT INTO @Info (Info)
  95. SELECT ProcName
  96. FROM @Procs
  97. ORDER BY ProcName;
  98. SELECT Info FROM @Info;
  99. RETURN;
  100. END
  101. IF @Action = 'LIST'
  102. BEGIN
  103. -- List the procs using that user defined type.
  104. IF @ProcCount = 0
  105. BEGIN
  106. SELECT 'There are no procs using ' + @UserDefinedType as Info;
  107. END ELSE
  108. BEGIN
  109. INSERT INTO @Info (Info) VALUES ('Procs using '+@UserDefinedType);
  110. INSERT INTO @Info (Info)
  111. SELECT ProcName
  112. FROM @Procs
  113. ORDER BY ProcName;
  114. SELECT Info FROM @Info;
  115. END;
  116. RETURN;
  117. END
  118. IF @Action <> 'KILL'
  119. BEGIN
  120. -- Get the sql of the procedures.
  121. INSERT INTO @ProcSQL (ProcID,ProcSQL,SortOrder)
  122. SELECT id,[Text],sc.colid
  123. FROM syscomments as sc
  124. WHERE id in (SELECT ProcID FROM @Procs);
  125. END;
  126. BEGIN TRAN
  127. SET @CreatedTransaction = 1;
  128. -- Drop the procedures.
  129. SET @ProcLoop = 1;
  130. WHILE @ProcLoop <= @ProcCount
  131. BEGIN
  132. SELECT @SQL = N'DROP PROCEDURE '+ProcName
  133. ,@ProcName = ProcName
  134. FROM @Procs
  135. WHERE ID = @ProcLoop;
  136. EXEC sp_executesql @SQL;
  137. SET @ProcLoop = @ProcLoop + 1;
  138. END;
  139. -- Drop the old user defined type.
  140. SET @SQL = N'DROP TYPE '+@UserDefinedType;
  141. exec sp_executesql @SQL;
  142. END ELSE
  143. BEGIN
  144. IF @Action = 'LIST'
  145. BEGIN
  146. SELECT 'User defined type '+@UserDefinedType+' doesn`t exist.' as Info;
  147. RETURN;
  148. END;
  149. END;
  150. IF @CreatedTransaction = 0
  151. BEGIN
  152. BEGIN TRAN
  153. SET @CreatedTransaction = 1;
  154. END;
  155. -- Create the new user defined type.
  156. IF @Action IN ('CREATE','FORCE','ALTER') AND LEN(@Definition) > 0
  157. BEGIN
  158. EXEC sp_executesql @Definition;
  159. IF @ProcCount > 0
  160. BEGIN
  161. -- Recreate the procedures.
  162. SET @ProcLoop = 1;
  163. WHILE @ProcLoop <= @ProcCount
  164. BEGIN
  165. -- Get the proc sql.
  166. SELECT @ProcID = ProcID
  167. ,@ProcName = ProcName
  168. FROM @Procs AS P
  169. WHERE P.ID = @ProcLoop;
  170. SELECT @ProcSQLCount = COUNT(*)
  171. FROM @ProcSQL
  172. WHERE ProcID = @ProcID;
  173. SET @SQL = N'';
  174. SET @ProcSQLLoop = 1;
  175. WHILE @ProcSQLLoop <= @ProcSQLCount
  176. BEGIN
  177. SELECT @SQL = @SQL + ProcSQL
  178. FROM @ProcSQL
  179. WHERE ProcID = @ProcID
  180. AND SortOrder = @ProcSQLLoop;
  181. SET @ProcSQLLoop = @ProcSQLLoop + 1;
  182. END;
  183. IF @Action = 'FORCE'
  184. BEGIN
  185. -- Try to recreate the stored proc.
  186. -- If there's an error, report the
  187. -- error and leave the proc dropped.
  188. BEGIN TRY
  189. EXEC sp_executesql @SQL;
  190. END TRY
  191. BEGIN CATCH
  192. SET @ErrorNumber = ERROR_NUMBER();
  193. SET @ErrorLine = ERROR_LINE();
  194. SET @ErrorMessage = 'Error rebuilding proc ' + @ProcName + ':' + CONVERT(VARCHAR,@ErrorNumber) + ':' + ERROR_MESSAGE() + ' on line ' + CONVERT(VARCHAR,@ErrorLine);
  195. INSERT INTO @Info (Info)
  196. VALUES (@ErrorMessage)
  197. END CATCH
  198. END ELSE
  199. BEGIN
  200. -- If the proc fails, the entire transaction gets rolled back.
  201. EXEC sp_executesql @SQL;
  202. END;
  203. SET @ProcLoop = @ProcLoop + 1;
  204. END;
  205. END;
  206. END;
  207. COMMIT TRAN;
  208. SET @CreatedTransaction = 0;
  209. IF @Action = 'FORCE'
  210. BEGIN
  211. SELECT @ProcCount = COUNT(*) FROM @Info;
  212. IF ISNULL(@ProcCount,0) = 0
  213. BEGIN
  214. INSERT INTO @Info (Info) VALUES('Completed with no errors');
  215. END ELSE
  216. BEGIN
  217. SELECT Info FROM @Info;
  218. END;
  219. END;
  220. END TRY
  221. BEGIN CATCH
  222. SET @ErrorNumber = ERROR_NUMBER();
  223. SET @ErrorLine = ERROR_LINE();
  224. SET @ErrorMessage = 'Error ' + CONVERT(VARCHAR,@ErrorNumber) + ':' + ERROR_MESSAGE() + ' on line ' + CONVERT(VARCHAR,@ErrorLine);
  225. SET @ErrorSeverity = ERROR_SEVERITY();
  226. SET @ErrorState = ERROR_STATE();
  227. IF @CreatedTransaction = 1
  228. BEGIN
  229. ROLLBACK TRAN;
  230. END
  231. RAISERROR(@ErrorMessage,@ErrorSeverity,@ErrorState);
  232. END CATCH;
  233. END
  234. GO