home *** CD-ROM | disk | FTP | other *** search
/ Enter 2001 April / EnterCD4.iso / Update / SQL Server SP3 / sql70sp3i.exe / INSTALL / sp2_serv.sql < prev    next >
Encoding:
Text (UTF-16)  |  2000-03-28  |  244.2 KB  |  3,744 lines

  1. /*------------------------------------------------------------------------------
  2.  
  3. SP2_SERV.SQL
  4.  
  5. THIS SCRIPT TAKES THE SERVER-SIDE SYSTEM-PROCS FROM 7.0 SP1 to SP2.
  6.  
  7. Changes in this file are organized as follows (please maintain):
  8.     System Tables (UPGRADE.SQL)
  9.     System Messages (MESSAGES.SQL / MSGWORK.SQL / SERVMSGS.SQL)
  10.     Engine System Procs (U_TABLES.SQL / PROCSYST.SQL / ODSOLE.SQL)
  11.     Schema Procs (OLEDBSCH.SQL / ANSIVIEW.SQL)
  12.     ODBC/OLEDB Catalog Procs (INSTCAT.SQL)
  13.     SEM SQLDMO System Procs (SQLDMO.SQL)
  14.  
  15. Changes to these scripts should NOT be placed in this file:
  16.     Starfighter Procs (XPSTAR.SQL / INSTMSDB.SQL / SQLTRACE.SQL / WEB.SQL)
  17.     Doc's Samples (INSTPUBS.SQL / INSTNWND.SQL)
  18.     Replication Procs (REPLSYS.SQL / REPLCOM.SQL / REPLTRAN.SQL / REPLMERG.SQL)
  19. These components will maintain separate upgrade scripts.
  20.  
  21. Notes:
  22. + Catalog-updates and sp_MS_upd_sysobj_category are enabled for the entire
  23.     file.  Do not disable or re-enable them.  Please do not change set options.
  24.  
  25. ------------------------------------------------------------------------------*/
  26.  
  27.  
  28. --------------------------------------------------------------------------------
  29. -- VERIFY Server is started in single-user-mode (catalog-updates enables), and
  30. --    start marking of system-objects.
  31. --------------------------------------------------------------------------------
  32. execute sp_configure 'allow updates',1
  33. go
  34.  
  35. reconfigure with override
  36. go
  37.  
  38. exec sp_MS_upd_sysobj_category 1
  39. go
  40.  
  41. --------------------------------------------------------------------------------
  42. --    System Tables (UPGRADE.SQL)
  43. --------------------------------------------------------------------------------
  44.  
  45. -- Bug 55162
  46. -- Sort order 98: LCID = 0x415, NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH | NORM_IGNORECASE
  47. delete from syscharsets where id=98
  48. go
  49. insert syscharsets (type, id, csid, status, name, description, binarydefinition)
  50.     values (2001, 98, 4, 0, N'polish_ci', N'Windows Polish case insensitive sort order for code page 1250',
  51.     0x800000001504000001000300)
  52. go
  53.  
  54.  
  55. --------------------------------------------------------------------------------
  56. --    System Messages (MESSAGES.SQL / MSGWORK.SQL / SERVMSGS.SQL) English
  57. --------------------------------------------------------------------------------
  58. DELETE sysmessages
  59.     where error in
  60.     (948, 1931, 2731, 3106, 3132, 3168, 3169, 16927, 21287,18773)
  61. go
  62.  
  63. insert into master..sysmessages (error ,severity ,dlevel ,description ,msglangid)
  64.     values
  65.     (948,14,0,'Database ''%.*ls'' cannot be upgraded. Database is version %d. This server supports version  %d.' ,1033)
  66.  
  67. insert into master..sysmessages (error ,severity ,dlevel ,description ,msglangid)
  68.     values
  69.     (1931,16,0,'Create %S_MSG is not allowed when the database has ''pending upgrade'' enabled.' ,1033)
  70.  
  71. insert into master..sysmessages (error ,severity ,dlevel ,description ,msglangid) 
  72.     values
  73.     (2731, 16, 1, 'The width of column ''%.*ls'' is %d. This width is not valid.' ,1033)
  74.  
  75. insert into master..sysmessages (error ,severity ,dlevel ,description ,msglangid)
  76.     values
  77.     (3132,16,0,'The media set for database ''%ls'' has %d family members, but only %d are provided. All members must be provided.' ,1033)
  78.  
  79. insert into master..sysmessages (error ,severity ,dlevel ,description ,msglangid)
  80.     values
  81.     (3168,16,0,'The backup of the system database on device %ls cannot be restored because it was created by a version of the server (%u) different from this version (%u).' ,1033)
  82.  
  83. insert into master..sysmessages (error ,severity ,dlevel ,description ,msglangid)
  84.     values
  85.     (3169,16,0,'The backed-up database has on-disk structure version %d. The server supports version %d and cannot restore or upgrade this database.' ,1033)
  86.  
  87. insert into master..sysmessages (error ,severity ,dlevel ,description ,msglangid)
  88.     values
  89.     (16927, 16, 0,'The fetch operation cannot be used with text, ntext, or image data types.', 1033)
  90.  
  91. insert into master..sysmessages (error ,severity ,dlevel ,description ,msglangid)
  92.     values
  93.     (21287, 16, 0,'Cannot clean up the meta data for publication ''%s'' because other publications are using one or more articles in this publication.', 1033)
  94.  
  95. insert into master..sysmessages (error ,severity ,dlevel ,description ,msglangid)
  96.     values
  97.     (18773, 16, 0,'Could not locate text information records for column %d during command construction.', 1033)
  98.  
  99. go
  100.  
  101.  
  102. --------------------------------------------------------------------------------
  103. --    System Messages (MESSAGES.SQL / MSGWORK.SQL / SERVMSGS.SQL) Localized
  104. --------------------------------------------------------------------------------
  105.  
  106.  
  107.  
  108. --------------------------------------------------------------------------------
  109. --    Engine System Procs (U_TABLES.SQL / PROCSYST.SQL / ODSOLE.SQL)
  110. --------------------------------------------------------------------------------
  111. -- Allow for log shipping to next release server.
  112. delete spt_values where type ='D' and name='pending upgrade'
  113. go
  114. insert spt_values (name, number, type)
  115.     values ('pending upgrade', 16384, 'D')
  116. go
  117. update spt_values set number = 4218397
  118. where type = 'D' and name = 'ALL SETTABLE OPTIONS'
  119. go
  120.  
  121. -- BUG 56868
  122. if (exists (select * from sysobjects
  123.         where name = 'sp_change_users_login' and type = 'P '))
  124.     drop proc sp_change_users_login
  125. go
  126. CREATE PROCEDURE sp_change_users_login
  127.     @Action               varchar(10)       -- REPORT / UPDATE_ONE / AUTO_FIX
  128.    ,@UserNamePattern      sysname  = Null
  129.    ,@LoginName            sysname  = Null
  130. AS
  131.     -- SETUP RUNTIME OPTIONS / DECLARE VARIABLES --
  132.     set nocount on
  133.     declare @exec_stmt nvarchar(430)
  134.  
  135.     declare @ret            int,
  136.             @FixMode        char(5),
  137.             @cfixesupdate   int,        -- count of fixes by update
  138.             @cfixesaddlogin int,        -- count of fixes by sp_addlogin
  139.             @dbname         sysname,
  140.             @loginsid       varbinary(85),
  141.             @110name        sysname
  142.  
  143.     -- SET INITIAL VALUES --
  144.     select  @dbname         = db_name(),
  145.             @cfixesupdate   = 0,
  146.             @cfixesaddlogin = 0
  147.  
  148.     -- ERROR IF IN USER TRANSACTION --
  149.     if @@trancount > 0
  150.     begin
  151.         raiserror(15289,-1,-1)
  152.         return (1)
  153.     end
  154.  
  155.     -- INVALIDATE USE OF SPECIAL LOGIN/USER NAMES --
  156.     if @LoginName = 'sa'
  157.     begin
  158.         raiserror(15287,-1,-1,@LoginName)
  159.         return (1)
  160.     end
  161.     if lower(@UserNamePattern) in ('dbo','guest','INFORMATION_SCHEMA')
  162.     begin
  163.         raiserror(15287,-1,-1,@UserNamePattern)
  164.         return (1)
  165.     end
  166.  
  167.     -- HANDLE REPORT --
  168.     if upper(@Action) = 'REPORT'
  169.     begin
  170.  
  171.         -- VALIDATE PARAMS --
  172.         if @UserNamePattern IS NOT Null or @LoginName IS NOT Null
  173.         begin
  174.             raiserror(15290,-1,-1,@Action,@UserNamePattern,@LoginName)
  175.             return (1)
  176.         end
  177.  
  178.         -- GENERATE REPORT --
  179.         select UserName = name, UserSID = sid from sysusers
  180.             where issqluser = 1 and (sid is not null and sid <> 0x0)
  181.                     and suser_sname(sid) is null
  182.             order by name
  183.         return (0)
  184.     end
  185.  
  186.     -- HANDLE UPDATE_ONE --
  187.     if upper(@Action) = 'UPDATE_ONE'
  188.     begin
  189.  
  190.         -- CHECK PERMISSIONS --
  191.         if not is_member('db_owner') = 1
  192.         begin
  193.             raiserror(15288,-1,-1,'SA or DBO',@Action)
  194.             return (1)
  195.         end
  196.  
  197.         -- ERROR IF PARAMS NULL --
  198.         if @UserNamePattern IS Null or @LoginName IS Null
  199.         begin
  200.             raiserror(15290,-1,-1,@Action,@UserNamePattern,@LoginName)
  201.             return (1)
  202.         end
  203.  
  204.         -- VALIDATE PARAMS --
  205.         -- Can ONLY remap SQL Users to SQL Logins!  Should be no need
  206.         --  for re-mapping NT logins, and if you try, you'll mess up
  207.         --  the user status bits! (see samsmith)
  208.         if not exists (select name from sysusers where
  209.                 name = @UserNamePattern             -- match user name
  210.             and issqluser = 1)                      -- must be sql user
  211.         begin
  212.             raiserror(15291,-1,-1,'User',@UserNamePattern)
  213.             return (1)
  214.         end
  215.         select @loginsid = sid from master.dbo.syslogins where
  216.                 loginname = @LoginName              -- match login name
  217.             and isntname = 0                        -- cannot use nt logins
  218.         if @loginsid is null
  219.         begin
  220.             raiserror(15291,-1,-1,'Login',@LoginName)
  221.             return (1)
  222.         end
  223.  
  224.         -- ERROR IF SID ALREADY IN USE IN DATABASE --
  225.         if exists (select sid from sysusers where sid = @loginsid
  226.                     and name <> @UserNamePattern)
  227.         begin
  228.             raiserror(15063,-1,-1)
  229.             return (1)
  230.         end
  231.  
  232.         -- CHANGE THE USERS LOGIN (SID) --
  233.         update sysusers set sid = @loginsid, updatedate = getdate()
  234.                 where name = @UserNamePattern and issqluser = 1
  235.                 and sid <> @loginsid
  236.  
  237.         -- FINALIZATION: REPORT AND EXIT --
  238.         if @@error <> 0 or @@rowcount <> 1
  239.             raiserror(15295,-1,-1, 0)
  240.         else
  241.             raiserror(15295,-1,-1, 1)
  242.         return (0)
  243.     end
  244.  
  245.     -- ERROR IF NOT AUTO_FIX --
  246.     if upper(@Action) <> 'AUTO_FIX'
  247.     begin
  248.         raiserror(15286,-1,-1,@Action)
  249.         return (1)
  250.     end
  251.  
  252.     -- HANDLE AUTO_FIX --
  253.     -- CHECK PERMISSIONS --
  254.     if not is_srvrolemember('sysadmin') = 1
  255.     begin
  256.         raiserror(15288,-1,-1,'SA or DBO',@Action)
  257.         return (1)
  258.     end
  259.  
  260.     -- VALIDATE PARAMS --
  261.     if @UserNamePattern IS Null or @LoginName IS NOT Null
  262.     begin
  263.         raiserror(15290,-1,-1,@Action,@UserNamePattern,@LoginName)
  264.         return (1)
  265.     end
  266.  
  267.     -- LOOP THRU ORPHANED USERS --
  268.     -- declare the cursor explicity global so that the cursor
  269.     -- exists at the end of the exec stmt regardless of the database
  270.     -- option value for 'default to local cursor'
  271.     select @exec_stmt = 'DECLARE Cursor110_Users cursor global for
  272.             select name from sysusers
  273.             where name = N' + quotename( @UserNamePattern , '''')+ '
  274.                 and issqluser = 1 and suser_sname(sid) is null'
  275.     EXECUTE (@exec_stmt)
  276.     OPEN Cursor110_Users
  277.  
  278.     WHILE (110=110)
  279.     begin
  280.         FETCH next from Cursor110_Users into @110name
  281.         if (@@fetch_status <> 0)
  282.         begin
  283.             DEALLOCATE Cursor110_Users
  284.             BREAK
  285.         end
  286.  
  287.         -- IS NAME ALREADY IN USE? --
  288.         -- if suser_sid(@110name) is null
  289.         if not exists(select * from master.dbo.syslogins where loginname = @110name)
  290.         begin
  291.  
  292.             -- ADD LOGIN --
  293.             execute @ret = sp_addlogin @110name, Null, @dbname
  294.             if @ret <> 0 or suser_sid(@110name) is null
  295.             begin
  296.                 raiserror(15497,16,1,@110name)
  297.                 deallocate Cursor110_Users
  298.                 return (1)
  299.             end
  300.             select @FixMode = '1AddL'
  301.             raiserror(15293,-1,-1,@110name)
  302.         end
  303.         ELSE
  304.         begin
  305.             Select @FixMode = '2UpdU'
  306.             Raiserror(15292,-1,-1,@110name)
  307.         end
  308.  
  309.         -- REPORT ERROR & CONTINUE IF DUPLICATE SID IN DB --
  310.         select @loginsid = suser_sid(@110name)
  311.         if user_sid(@loginsid) is not null
  312.         begin
  313.             raiserror(15331,-1,-1,@110name,@loginsid)
  314.             CONTINUE
  315.         end
  316.  
  317.         -- UPDATE SYSUSERS ROW --
  318.         update sysusers set sid = @loginsid, updatedate = getdate() where name = @110name
  319.         if @@error <> 0
  320.         begin
  321.             raiserror(15498,17,127)
  322.             deallocate Cursor110_Users
  323.             return (1)
  324.         end
  325.  
  326.  
  327.         if @FixMode = '1AddL'
  328.             Select @cfixesaddlogin = @cfixesaddlogin + 1
  329.         else
  330.             Select @cfixesupdate = @cfixesupdate + 1
  331.     end -- loop 110
  332.  
  333.     -- REPORT AND RETURN SUCCESS --
  334.     raiserror(15295,-1,-1,@cfixesupdate)
  335.     raiserror(15294,-1,-1,@cfixesaddlogin)
  336.     return (0) -- sp_change_users_login
  337. go
  338.  
  339. grant execute on sp_change_users_login to public
  340. go
  341.  
  342.  
  343. --BUGS 54274, 55554, 55297, and 55152
  344. if object_id('sp_bindefault','P') IS NOT NULL
  345.     drop procedure sp_bindefault
  346. if object_id('sp_bindrule','P') IS NOT NULL
  347.     drop procedure sp_bindrule
  348. if object_id('sp_unbindefault','P') IS NOT NULL
  349.     drop procedure sp_unbindefault
  350. if object_id('sp_unbindrule','P') IS NOT NULL
  351.     drop procedure sp_unbindrule
  352. go
  353.  
  354. raiserror(15339,-1,-1,'sp_bindefault')
  355. go
  356. create procedure sp_bindefault --- 1996/08/30 20:04
  357. @defname nvarchar(776),            /* name of the default */
  358. @objname nvarchar(517),            /* table or usertype name */
  359. @futureonly varchar(15) = NULL        /* flag to indicate extent of binding */
  360. as
  361.  
  362. declare @defid int            /* id of the default to bind */
  363. declare @futurevalue varchar(15)    /* the value of @futureonly that causes
  364.                     ** the binding to be limited */
  365. declare
  366.     @vc1            nvarchar(517)
  367.     ,@tab_id        integer
  368.     ,@parent_obj    integer
  369.     ,@cur_tab_id    integer
  370.     ,@colid            smallint
  371.     ,@xtype            tinyint
  372.     ,@xusertype        smallint
  373.     ,@col_status    tinyint
  374.     ,@col_default int
  375.     ,@identity binary(1)
  376.     
  377. declare
  378.     @UnqualDef            sysname
  379.     ,@QualDef1            sysname
  380.     ,@QualDef2            sysname
  381.     ,@QualDef3            sysname
  382.  
  383.     ,@UnqualObj            sysname
  384.     ,@QualObj1            sysname
  385.     ,@QualObj2            sysname
  386.     ,@QualObj3            sysname
  387.  
  388. set cursor_close_on_commit    off
  389. set nocount            on
  390.  
  391. select @futurevalue = 'futureonly'    /* initialize @futurevalue */
  392. select @identity = 0X80 /* identity columns*/
  393.  
  394. /*
  395. **  When a default or rule is bound to a user-defined datatype, it is also
  396. **  bound, by default, to any columns of the user datatype that are currently
  397. **  using the existing default or rule as their default or rule.  This default
  398. **  action may be overridden by setting @futureonly = @futurevalue when the
  399. **  procedure is invoked.  In this case existing columns with the user
  400. **  datatype won't have their existing default or rule changed.
  401. */
  402.  
  403. -- get name parts --
  404. select @UnqualDef = parsename(@defname, 1),
  405.         @QualDef1 = parsename(@defname, 2),
  406.         @QualDef2 = parsename(@defname, 3),
  407.         @QualDef3 = parsename(@defname, 4)
  408.  
  409. select @UnqualObj = parsename(@objname, 1),
  410.         @QualObj1 = parsename(@objname, 2),
  411.         @QualObj2 = parsename(@objname, 3),
  412.         @QualObj3 = parsename(@objname, 4)
  413.  
  414. IF (@UnqualDef is NULL OR @QualDef3 is not null)
  415.    begin
  416.    raiserror(15253,-1,-1,@defname)
  417.    return (1)
  418.    end
  419.  
  420. IF (@UnqualObj is NULL OR @QualObj3 is not null)
  421.    begin
  422.    raiserror(15253,-1,-1,@objname)
  423.    return (1)
  424.    end
  425.  
  426.  
  427. ------------------  Verify database.
  428.  
  429. if ((@QualObj2 is not null and @QualObj1 is null)
  430.     or (@QualDef2 is not null and @QualDef2 <> db_name()))
  431.     begin
  432.         raiserror(15076,-1,-1)
  433.         return (1)
  434.     end
  435.  
  436. /*
  437. **  Check that the @futureonly argument, if supplied, is correct.
  438. */
  439. if (@futureonly IS NOT NULL)
  440.     if (@futureonly <> @futurevalue)
  441.         begin
  442.             raiserror(15100,-1,-1)
  443.             return (1)
  444.         end
  445.  
  446. /*
  447. **  Check to see that the default exists and get its id.
  448. */
  449. select @defid = id, @parent_obj = parent_obj from sysobjects
  450.             where id = object_id(@defname)
  451.                 and xtype='D '    -- default object 6
  452.  
  453. if @defid is NULL
  454.     begin
  455.         raiserror(15016,-1,-1,@UnqualDef)
  456.         return (1)
  457.     end
  458.  
  459.  
  460. if @parent_obj > 0
  461.     begin
  462.         raiserror(15050,-1,-1,@defname)
  463.         return(1)
  464.     end
  465.  
  466. /*
  467. **  If @objname is of the form tab.col then we are binding to a column.
  468. **  Otherwise its a datatype.  In the column case, we need to extract
  469. **  and verify the table and column names and make sure the user owns
  470. **  the table that is getting the default bound. We also need to ensure
  471. **  that we don't overwrite any DRI style defaults.
  472. */
  473. if @QualObj1 is not null
  474. begin
  475.     if (@QualObj2 is not null)
  476.         select @vc1 = QuoteName(@QualObj2) + '.' + QuoteName(@QualObj1)
  477.     else
  478.         select @vc1 = QuoteName(@QualObj1)
  479.  
  480.     select    @tab_id = o.id,        @colid = c.colid,
  481.             @xtype = c.xtype,    @col_status = c.status,
  482.             @col_default = c.cdefault
  483.     from sysobjects o, syscolumns c
  484.     where c.id = object_id(@vc1,'local')
  485.             and c.name = @UnqualObj
  486.             and o.id = c.id
  487.             and o.xtype='U '
  488.  
  489.     /*Check that table and column exist*/
  490.      if @tab_id is null
  491.     begin
  492.         raiserror(15104,-1,-1,@QualObj1,@UnqualObj)
  493.         return (1)
  494.     end
  495.  
  496.     /*
  497.     **  If the column type is timestamp, disallow the bind.
  498.     **  Defaults can't be bound to timestamp columns.
  499.     */
  500.     if type_name(@xtype) = 'timestamp'
  501.     begin
  502.         raiserror(15101,-1,-1)
  503.         return (1)
  504.     end
  505.  
  506.     /*
  507.     **  If the column category is identity, disallow the bind.
  508.     **  Defaults can't be bound to identity columns.
  509.     */
  510.     if @col_status & @identity = @identity
  511.     begin
  512.         raiserror(15102,-1,-1)
  513.         return (1)
  514.     end
  515.  
  516.    /*
  517.    **  Check to see if the column was created with or altered
  518.    **  to have a DRI style default value.
  519.    */
  520.     if @col_default > 0
  521.         if exists
  522.          (select    *
  523.             from    sysobjects o
  524.             where    @col_default       = o.id
  525.             and        @tab_id             = o.parent_obj)
  526.         begin
  527.             raiserror(15103,-1,-1)
  528.             return (1)
  529.         end
  530.  
  531.     BEGIN TRANSACTION txn_bindefault_1
  532.  
  533.         /*
  534.         **  Since binding a default is a schema change, update schema count
  535.         **  for the object in the sysobjects table.
  536.         */
  537.  
  538.         dbcc LockObjectSchema(@vc1) --- Undocu. Locks out other schema changes until commit, and increments sysobjects.schema_ver.
  539.  
  540.         update syscolumns set cdefault = @defid where id = @tab_id and colid = @colid
  541.  
  542.     COMMIT TRANSACTION txn_bindefault_1
  543.  
  544.     raiserror(15511,-1,-1)
  545.  
  546. end
  547. else
  548. begin
  549.     /*
  550.     **  We're binding to a user type.  In this case, the @objname
  551.     **  is really the name of the user datatype.
  552.     **  When we bind to a user type, any existing columns get changed
  553.     **  to the new binding unless their current binding is not equal
  554.     **  to the current binding for the usertype or if they set the
  555.     **  @futureonly parameter to @futurevalue.
  556.     */
  557.     declare @olddefault int    /* current default for type */
  558.  
  559.     /*
  560.     **  Get the current default for the datatype.
  561.     */
  562.  
  563.     select @xusertype = xusertype, @olddefault = tdefault
  564.         from systypes where name = @UnqualObj and xusertype > 256
  565.         AND (is_member('db_owner') = 1 OR is_member('db_ddladmin') = 1 OR is_member(user_name(uid))=1)
  566.  
  567.     if @xusertype is null
  568.         begin
  569.             raiserror(15105,-1,-1)
  570.             return (1)
  571.         end
  572.  
  573.     update systypes
  574.         set tdefault = @defid
  575.             from systypes
  576.         where xusertype = @xusertype
  577.  
  578.  
  579.     raiserror(15512,-1,-1)
  580.  
  581.     /*
  582.     **  need the new binding.
  583.     */
  584.     if isnull(@futureonly, ' ') <> @futurevalue
  585.     begin
  586.  
  587.         declare csr3_t1 insensitive cursor for
  588.           select
  589.             distinct
  590.                  c.id
  591.                  ,c.colid
  592.             from     syscolumns    c JOIN sysobjects o ON c.id = o.id AND o.xtype = 'U '
  593.             where     c.xusertype    = @xusertype
  594.             and    (c.cdefault    = @olddefault    OR
  595.                  c.cdefault    = 0
  596.                 )
  597.             order by c.id
  598.                   for read only
  599.  
  600.         open csr3_t1
  601.  
  602.         BEGIN TRANSACTION txn_bindefault_3
  603.  
  604.         fetch next from csr3_t1 into
  605.              @tab_id,
  606.              @colid
  607.  
  608.         WHILE @@fetch_status = 0
  609.         begin
  610.  
  611.             select @vc1 = quotename(user_name(OBJECTPROPERTY(@tab_id,'OwnerId'))) + '.'
  612.                         + quotename(object_name(@tab_id))
  613.  
  614.             dbcc LockObjectSchema(@vc1) --- Undocu. Locks out other schema changes until commit, and increments sysobjects.schema_ver.
  615.  
  616.             select @cur_tab_id = @tab_id
  617.  
  618.             while @cur_tab_id = @tab_id and @@fetch_status = 0
  619.             begin
  620.  
  621.                 update syscolumns
  622.                 set cdefault = @defid
  623.                 from syscolumns c
  624.                 where c.id = @tab_id
  625.                 and c.colid = @colid
  626.  
  627.                 fetch next from csr3_t1 into
  628.                      @tab_id,
  629.                      @colid
  630.             end
  631.  
  632.         end --loop 3
  633.  
  634.         COMMIT TRANSACTION txn_bindefault_3
  635.  
  636.         deallocate csr3_t1
  637.  
  638.         raiserror(15513,-1,-1)
  639.     end
  640. end
  641.  
  642. return (0) -- sp_bindefault
  643. go
  644.  
  645. raiserror(15339,-1,-1,'sp_bindrule')
  646. go
  647. create procedure sp_bindrule --- 1996/08/14 15:02
  648. @rulename nvarchar(776),            /* name of the rule */
  649. @objname nvarchar(517),            /* table or usertype name */
  650. @futureonly varchar(15) = NULL        /* column name */
  651. as
  652.  
  653. declare @ruleid int            /* id of the rule to bind */
  654. declare @futurevalue varchar(15)    /* the value of @futureonly that causes
  655.                     ** the binding to be limited */
  656.  
  657. declare
  658.     @vc1            nvarchar(517)
  659.     ,@tab_id        integer
  660.     ,@cur_tab_id    integer
  661.     ,@colid            smallint
  662.  
  663.     ,@xtype            smallint
  664.     ,@xusertype        smallint
  665.  
  666. declare
  667.     @UnqualRule        sysname
  668.     ,@QualRule1        sysname
  669.     ,@QualRule2        sysname
  670.     ,@QualRule3        sysname
  671.  
  672.     ,@UnqualObj        sysname
  673.     ,@QualObj1        sysname
  674.     ,@QualObj2        sysname
  675.     ,@QualObj3        sysname
  676.  
  677. set cursor_close_on_commit    off
  678. set nocount on
  679.  
  680. select @futurevalue = 'futureonly'    /* initialize @futurevalue */
  681.  
  682. /*
  683. **  When a default or rule is bound to a user-defined datatype, it is also
  684. **  bound, by default, to any columns of the user datatype that are currently
  685. **  using the existing default or rule as their default or rule.  This default
  686. **  action may be overridden by setting @futureonly = @futurevalue when the
  687. **  procedure is invoked.  In this case existing columns with the user
  688. **  datatype won't have their existing default or rule changed.
  689. */
  690.  
  691. -- get name parts --
  692. select @UnqualRule = parsename(@rulename, 1),
  693.         @QualRule1 = parsename(@rulename, 2),
  694.         @QualRule2 = parsename(@rulename, 3),
  695.         @QualRule3 = parsename(@rulename, 4)
  696.  
  697. select @UnqualObj = parsename(@objname, 1),
  698.         @QualObj1 = parsename(@objname, 2),
  699.         @QualObj2 = parsename(@objname, 3),
  700.         @QualObj3 = parsename(@objname, 4)
  701.  
  702. IF (@UnqualRule is NULL OR @QualRule3 is not null)
  703.    begin
  704.    raiserror(15253,-1,-1,@rulename)
  705.    return (1)
  706.    end
  707.  
  708. IF (@UnqualObj is NULL OR @QualObj3 is not null)
  709.    begin
  710.    raiserror(15253,-1,-1,@objname)
  711.    return (1)
  712.    end
  713.  
  714.  
  715. ------------------  Verify database.
  716.  
  717. if ((@QualObj2 is not null and @QualObj1 is null)
  718.     or (@QualRule2 is not null and @QualRule2 <> db_name()))
  719.     begin
  720.         raiserror(15077,-1,-1)
  721.         return (1)
  722.     end
  723.  
  724. /*
  725. **  Check that the @futureonly argument, if supplied, is correct.
  726. */
  727. if (@futureonly IS NOT NULL)
  728.     begin
  729.         if (@futureonly <> @futurevalue)
  730.             begin
  731.                 raiserror(15106,-1,-1)
  732.                 return (1)
  733.             end
  734.     end
  735.  
  736. /*
  737. **  Check to see that the rule exists and get its id.
  738. */
  739. select @ruleid = id from sysobjects
  740.             where id = object_id(@rulename)
  741.                 and xtype='R ' --rule object 7
  742.  
  743. if @ruleid is NULL
  744.     begin
  745.         raiserror(15017,-1,-1,@rulename)
  746.         return (1)
  747.     end
  748.  
  749. /*
  750. **  If @objname is of the form tab.col then we are binding to a column.
  751. **  Otherwise its a datatype.  In the column case, we need to extract
  752. **  and verify the table and column names and make sure the user owns
  753. **  the table that is getting the rule bound.
  754. */
  755. if @QualObj1 is not null
  756. begin
  757.     if (@QualObj2 is not null)
  758.         select @vc1 = QuoteName(@QualObj2) + '.' + QuoteName(@QualObj1)
  759.     else
  760.         select @vc1 = QuoteName(@QualObj1)
  761.  
  762.     select @tab_id = o.id, @colid = c.colid, @xtype = c.xtype
  763.     from sysobjects o, syscolumns c
  764.     where c.id = object_id(@vc1,'local')
  765.             and c.name = @UnqualObj
  766.             and o.id = c.id
  767.             and o.xtype='U '
  768.  
  769.     /*Check that table and column exist*/
  770.      if @tab_id is null
  771.     begin
  772.         raiserror(15104,-1,-1,@QualObj1,@UnqualObj)
  773.         return (1)
  774.     end
  775.  
  776.     /*
  777.     **  If the column type is image, text, or timestamp, disallow the bind.
  778.     **  Rules can't be bound to image, text, or timestamp columns.
  779.     **  The types are checked in case
  780.     **  there is a user-defined datatype that is an image or text.
  781.     **  User-defined datatypes mapping to timestamp are not allowed
  782.     **  by sp_addtype.
  783.     */
  784.     if type_name(@xtype) in ('text', 'ntext', 'image', 'timestamp')
  785.         begin
  786.             raiserror(15107,-1,-1)
  787.             return (1)
  788.         end
  789.  
  790.     BEGIN TRANSACTION txn_bindrule_1
  791.  
  792.         dbcc LockObjectSchema(@vc1) --- Undocu. Locks out other schema changes until commit, and increments sysobjects.schema_ver.
  793.  
  794.         update syscolumns set domain = @ruleid
  795.             where id = @tab_id and colid = @colid
  796.  
  797.     COMMIT TRANSACTION txn_bindrule_1
  798.  
  799.     raiserror(15514,-1,-1)
  800.  
  801. end
  802. else
  803. begin
  804.     /*
  805.     **  We're binding to a user type.  In this case, the @objname
  806.     **  is really the name of the user datatype.
  807.     **  When we bind to a user type, any existing columns get changed
  808.     **  to the new binding unless their current binding is not equal
  809.     **  to the current binding for the usertype or if they set the
  810.     **  @futureonly parameter to @futurevalue.
  811.     */
  812.     declare @oldrule int            /* current rule for type */
  813.  
  814.     /*
  815.     **  Get the current rule for the datatype.
  816.     */
  817.     select @oldrule = domain, @xtype = xtype, @xusertype = xusertype
  818.         from systypes where name = @UnqualObj and xusertype > 256
  819.         AND (is_member('db_owner') = 1 OR is_member('db_ddladmin') = 1 OR is_member(user_name(uid))=1)
  820.  
  821.     if @oldrule is null
  822.         begin
  823.             raiserror(15105,-1,-1)
  824.             return (1)
  825.         end
  826.  
  827.     /*
  828.     **  If the column type is image, text, or timestamp, disallow the bind.
  829.     **  Rules can't be bound to image or text columns.
  830.     */
  831.     if type_name(@xtype) in ('text', 'ntext', 'image', 'timestamp')
  832.         begin
  833.             raiserror(15107,-1,-1)
  834.             return (1)
  835.         end
  836.  
  837.     update systypes set domain = @ruleid
  838.             from systypes
  839.         where xusertype = @xusertype
  840.  
  841.  
  842.     raiserror(15515,-1,-1)
  843.  
  844.     /*
  845.     **  Now see if there are any columns with the usertype that
  846.     **  need the new binding.
  847.     */
  848.     if isnull(@futureonly, ' ') <> @futurevalue
  849.     begin
  850.         declare csr_bindrule_1 insensitive cursor for
  851.           select
  852.             distinct
  853.                  c.id
  854.                 ,c.colid
  855.             from     syscolumns c JOIN sysobjects o ON c.id = o.id AND o.xtype = 'U '
  856.             where     c.xusertype    = @xusertype
  857.             and    (c.domain    = @oldrule    OR
  858.                  c.domain    = 0
  859.                 )
  860.             order by c.id
  861.                   for read only
  862.  
  863.         open csr_bindrule_1
  864.  
  865.         BEGIN TRANSACTION txn_bindrule_2
  866.  
  867.         fetch next from csr_bindrule_1 into
  868.             @tab_id
  869.             ,@colid
  870.  
  871.         WHILE @@fetch_status = 0
  872.         begin
  873.  
  874.             select @vc1 = quotename(user_name(OBJECTPROPERTY(@tab_id,'OwnerId'))) + '.'
  875.                         + quotename(object_name(@tab_id))
  876.  
  877.             dbcc LockObjectSchema(@vc1) --- Undocu. Locks out other schema changes until commit, and increments sysobjects.schema_ver.
  878.  
  879.             select @cur_tab_id = @tab_id
  880.  
  881.             while @cur_tab_id = @tab_id and @@fetch_status = 0
  882.             begin
  883.                 /*
  884.                 **  Update syscolumns with new binding.
  885.                 */
  886.                 update syscolumns
  887.                     set domain = @ruleid
  888.                     where id = @tab_id and colid = @colid
  889.  
  890.                 fetch next from csr_bindrule_1 into
  891.                      @tab_id
  892.                     ,@colid
  893.             end
  894.  
  895.         end --loop 3
  896.  
  897.         deallocate csr_bindrule_1
  898.  
  899.         COMMIT TRANSACTION txn_bindrule_2
  900.  
  901.         raiserror(15516,-1,-1)
  902.     end
  903. end
  904. return (0) -- sp_bindrule
  905. go
  906.  
  907. raiserror(15339,-1,-1,'sp_unbindefault')
  908. go
  909. create procedure sp_unbindefault --- 1996/08/13 13:34
  910. @objname nvarchar(776),         /* table/column or datatype name */
  911. @futureonly varchar(15) = NULL   /* flag to indicate extent of binding */
  912. as
  913.  
  914. declare @futurevalue varchar(15) /* the value of @futureonly that causes
  915.                ** the binding to be limited */
  916.  
  917. declare
  918.     @vc1            nvarchar(517)
  919. declare
  920.     @tab_id            integer
  921.     ,@cur_tab_id    integer
  922.     ,@colid            integer
  923.     ,@cdefault        integer
  924.     ,@olddefault    integer
  925.     ,@xusertype        smallint
  926.  
  927.     ,@UnqualObj        sysname
  928.     ,@QualObj1        sysname
  929.     ,@QualObj2        sysname
  930.     ,@QualObj3        sysname
  931.  
  932. set cursor_close_on_commit    off
  933. select @futurevalue = 'futureonly'  /* initialize @futurevalue */
  934.  
  935. /*
  936. **  When a default or rule is bound to a user-defined datatype, it is also
  937. **  bound, by default, to any columns of the user datatype that are currently
  938. **  using the existing default or rule as their default or rule.  This default
  939. **  action may be overridden by setting @futureonly = @futurevalue when the
  940. **  procedure is invoked.  In this case existing columns with the user
  941. **  datatype won't have their existing default or rule changed.
  942. */
  943.  
  944. -- get name parts --
  945. select @UnqualObj = parsename(@objname, 1),
  946.         @QualObj1 = parsename(@objname, 2),
  947.         @QualObj2 = parsename(@objname, 3),
  948.         @QualObj3 = parsename(@objname, 4)
  949.  
  950. IF (@UnqualObj is NULL OR @QualObj3 is not null)
  951.    begin
  952.    raiserror(15253,-1,-1,@objname)
  953.    return (1)
  954.    end
  955.  
  956.  
  957. ------------------  Verify database.
  958.  
  959. if (@QualObj2 is not null and @QualObj1 is null)
  960.     begin
  961.         raiserror(15084,-1,-1)
  962.         return (1)
  963.     end
  964.  
  965. /*
  966. **  If @objname is of the form tab.col then we are unbinding a column.
  967. **  Otherwise its a datatype.  In the column case, we need to extract
  968. **  and verify the table and column names and make sure the user owns
  969. **  the table that is getting the default unbound.
  970. */
  971. if @QualObj1 is not null
  972. begin
  973.     if (@QualObj2 is not null)
  974.         select @vc1 = QuoteName(@QualObj2) + '.' + QuoteName(@QualObj1)
  975.     else
  976.         select @vc1 = QuoteName(@QualObj1)
  977.  
  978.    /*
  979.    **  Find it and unbind it.
  980.    */
  981.    select @tab_id = c.id, @colid = c.colid, @cdefault = c.cdefault
  982.    from syscolumns c, sysobjects o
  983.       where c.id = o.id
  984.          and c.name = @UnqualObj
  985.          and o.id = object_id(@vc1,'local')
  986.          and o.xtype = 'U '
  987.  
  988.     if @tab_id is null
  989.     begin
  990.          raiserror(15104,-1,-1,@QualObj1,@UnqualObj)
  991.          return(1)
  992.     end
  993.  
  994.     if @cdefault = 0
  995.     begin
  996.         raiserror(15236,-1,-1,@objname)
  997.         return(1)
  998.     end
  999.  
  1000.     if exists
  1001.     (select    *
  1002.         from    sysobjects o
  1003.         where    @cdefault    = o.id
  1004.             and    @tab_id        = o.parent_obj)
  1005.         begin
  1006.             raiserror(15049,-1,-1, @objname)
  1007.             return (1)
  1008.         end
  1009.  
  1010.     BEGIN TRANSACTION txn_unbindefault_1
  1011.  
  1012.          /*
  1013.          **  Since binding a default is a schema change,
  1014.          **  update schema count
  1015.          **  for the object in the sysobjects table.
  1016.          */
  1017.         dbcc LockObjectSchema(@vc1) --- Undocu. Locks out other schema changes until commit, and increments sysobjects.schema_ver.
  1018.  
  1019.         update syscolumns set cdefault = 0
  1020.             from syscolumns where id = @tab_id and colid = @colid
  1021.  
  1022.     COMMIT TRANSACTION txn_bindefault_1
  1023.  
  1024.     raiserror(15519,-1,-1)
  1025.     return (0)
  1026.  
  1027. end
  1028.  
  1029. else
  1030.  
  1031. begin
  1032.    /*
  1033.    **  We're unbinding to a user type.  In this case, the @objname
  1034.    **  is really the name of the user datatype.
  1035.    **  When we unbind to a user type, any existing columns get changed
  1036.    **  to the new binding unless their current binding is not equal
  1037.    **  to the current binding for the usertype or if they set the
  1038.    **  @futureonly parameter to @futurevalue.
  1039.    */
  1040.  
  1041.    /*
  1042.    **  Get the current default for the datatype.
  1043.    */
  1044.    select @olddefault = tdefault, @xusertype = xusertype
  1045.         from systypes where name = @UnqualObj and xusertype > 256
  1046.         AND (is_member('db_owner') = 1 OR is_member('db_ddladmin') = 1 OR is_member(user_name(uid))=1)
  1047.  
  1048.    if @olddefault is null
  1049.       begin
  1050.          raiserror(15036,-1,-1,@UnqualObj)
  1051.          return (1)
  1052.       end
  1053.  
  1054.    if @olddefault = 0
  1055.       begin
  1056.          raiserror(15237,-1,-1,@UnqualObj)
  1057.          return (1)
  1058.       end
  1059.  
  1060.    update systypes set tdefault = 0
  1061.       from systypes
  1062.       where xusertype = @xusertype
  1063.  
  1064.    raiserror(15520,-1,-1)
  1065.  
  1066.    /*
  1067.    **  Now see if there are any columns with the usertype that
  1068.    **  need the new binding.
  1069.    */
  1070.    if isnull(@futureonly, ' ') <> @futurevalue
  1071.    begin
  1072.         declare csr_unbindefault_1 insensitive cursor for
  1073.             select
  1074.             distinct
  1075.                  c.id
  1076.                 ,c.colid
  1077.             from     syscolumns c JOIN sysobjects o ON c.id = o.id AND o.xtype = 'U '
  1078.                  where  c.xusertype = @xusertype
  1079.                     and c.cdefault = @olddefault
  1080.             order by c.id
  1081.                     for read only
  1082.  
  1083.         open csr_unbindefault_1
  1084.  
  1085.         fetch next from csr_unbindefault_1 into
  1086.             @tab_id
  1087.             ,@colid
  1088.  
  1089.         BEGIN TRANSACTION txn_unbindefault_2
  1090.  
  1091.             while @@fetch_status = 0
  1092.             begin
  1093.  
  1094.                 select @vc1 = quotename(user_name(OBJECTPROPERTY(@tab_id,'OwnerId'))) + '.'
  1095.                 + quotename(object_name(@tab_id))
  1096.  
  1097.                 dbcc LockObjectSchema(@vc1) --- Undocu. Locks out other schema changes until commit, and increments sysobjects.schema_ver.
  1098.  
  1099.                 select @cur_tab_id = @tab_id
  1100.  
  1101.                 while @cur_tab_id = @tab_id and @@fetch_status = 0
  1102.                 begin
  1103.                       update syscolumns set cdefault = 0
  1104.                     from syscolumns
  1105.                     where id = @tab_id and colid = @colid
  1106.  
  1107.                     fetch next from csr_unbindefault_1 into
  1108.                         @tab_id
  1109.                         ,@colid        
  1110.                 end
  1111.             end --loop 3      /*
  1112.  
  1113.         COMMIT TRANSACTION txn_unbindefault_2
  1114.  
  1115.         deallocate csr_unbindefault_1
  1116.  
  1117.         raiserror(15521,-1,-1)
  1118.     end
  1119. end
  1120.  
  1121. return (0) -- sp_unbindefault
  1122. go
  1123.  
  1124. raiserror(15339,-1,-1,'sp_unbindrule')
  1125. go
  1126. create procedure sp_unbindrule --- 1996/08/13 13:33
  1127. @objname nvarchar(776),         /* table/column or datatype name */
  1128. @futureonly varchar(15) = NULL      /* flag to indicate extent of binding */
  1129. as
  1130.  
  1131. declare @oldrule int /* current rule for type */
  1132. declare @tabname sysname     /* name of table */
  1133. declare @colname sysname     /* name of column */
  1134. declare @futurevalue varchar(15) /* the value of @futureonly that causes
  1135.                            ** the binding to be limited */
  1136.  
  1137. declare
  1138.     @vc1            nvarchar(517)
  1139. declare
  1140.      @obj_id        integer
  1141.     ,@cur_tab_id    integer
  1142.     ,@colid            integer
  1143.     ,@domain        integer
  1144.     ,@xusertype        smallint
  1145.  
  1146.     ,@owner_name    sysname
  1147.     ,@obj_name        sysname
  1148.  
  1149.     ,@UnqualObj            sysname
  1150.     ,@QualObj1            sysname
  1151.     ,@QualObj2            sysname
  1152.     ,@QualObj3            sysname
  1153.  
  1154. set cursor_close_on_commit    off
  1155.  
  1156. select @futurevalue = 'futureonly'  /* initialize @futurevalue */
  1157.  
  1158. /*
  1159. **  When a default or rule is bound to a user-defined datatype, it is also
  1160. **  bound, by default, to any columns of the user datatype that are currently
  1161. **  using the existing default or rule as their default or rule.  This default
  1162. **  action may be overridden by setting @futureonly = @futurevalue when the
  1163. **  procedure is invoked.  In this case existing columns with the user
  1164. **  datatype won't have their existing default or rule changed.
  1165. */
  1166.  
  1167. -- get name parts --
  1168. select @UnqualObj = parsename(@objname, 1),
  1169.         @QualObj1 = parsename(@objname, 2),
  1170.         @QualObj2 = parsename(@objname, 3),
  1171.         @QualObj3 = parsename(@objname, 4)
  1172.  
  1173. IF (@UnqualObj is NULL OR @QualObj3 is not null)
  1174.    begin
  1175.    raiserror(15253,-1,-1,@objname)
  1176.    return (1)
  1177.    end
  1178.  
  1179.  
  1180. ------------------  Verify database.
  1181.  
  1182. if (@QualObj2 is not null and @QualObj1 is null)
  1183.     begin
  1184.         raiserror(15084,-1,-1)
  1185.         return (1)
  1186.     end
  1187.  
  1188. /*
  1189. **  If @objname is of the form tab.col then we are unbinding a column.
  1190. **  Otherwise its a datatype.  In the column case, we need to extract
  1191. **  and verify the table and column names and make sure the user owns
  1192. **  the table that is getting the default unbound.
  1193. */
  1194. if @QualObj1 is not null
  1195. begin
  1196.     if (@QualObj2 is not null)
  1197.         select @vc1 = QuoteName(@QualObj2) + '.' + QuoteName(@QualObj1)
  1198.     else
  1199.         select @vc1 = QuoteName(@QualObj1)
  1200.  
  1201.     select    @obj_id = c.id,    @colid = c.colid,    @domain = c.domain
  1202.         from syscolumns c, sysobjects o
  1203.     where c.id = o.id
  1204.     and c.name = @UnqualObj
  1205.     and o.id = object_id(@vc1,'local')
  1206.     and o.xtype = 'U '
  1207.  
  1208.     if @obj_id is null
  1209.     begin
  1210.         raiserror(15104,-1,-1,@QualObj1,@UnqualObj)
  1211.         return (1)
  1212.     end
  1213.  
  1214.     if @domain = 0
  1215.     begin
  1216.         raiserror(15238,-1,-1,@objname)
  1217.         return (1)
  1218.     end
  1219.  
  1220.     BEGIN TRANSACTION txn_unbindrule_1
  1221.  
  1222.         /*
  1223.         **  Update schema count
  1224.         **  for the object in the sysobjects table.
  1225.         */
  1226.  
  1227.         dbcc LockObjectSchema(@vc1) -- Locks Object and increments schema_ver.
  1228.  
  1229.         update syscolumns set domain = 0
  1230.             from syscolumns c where id = @obj_id and colid = @colid
  1231.  
  1232.     COMMIT TRANSACTION txn_unbindrule_1
  1233.  
  1234.     raiserror(15522,-1,-1)
  1235.  
  1236. end
  1237. else
  1238. begin
  1239.  
  1240.     select @oldrule = domain, @xusertype = xusertype
  1241.         from systypes where name = @UnqualObj and xusertype > 256
  1242.         AND (is_member('db_owner') = 1 OR is_member('db_ddladmin') = 1 OR is_member(user_name(uid))=1)
  1243.  
  1244.     if @xusertype is null
  1245.     begin
  1246.         raiserror(15036,-1,-1,@UnqualObj)
  1247.         return (1)
  1248.     end
  1249.  
  1250.     if @oldrule = 0
  1251.     begin
  1252.         raiserror(15239,-1,-1,@UnqualObj)
  1253.         return (1)
  1254.     end
  1255.  
  1256.     update systypes set domain = 0
  1257.     from systypes
  1258.     where xusertype = @xusertype
  1259.  
  1260.     raiserror(15523,-1,-1)
  1261.  
  1262.     if isnull(@futureonly, ' ') <> @futurevalue
  1263.     begin
  1264.  
  1265.         declare csr_unbindrule_1 insensitive cursor for
  1266.         select
  1267.             distinct
  1268.              o.id
  1269.             ,user_name(o.uid)
  1270.             ,o.name
  1271.             ,c.colid
  1272.         from    syscolumns c
  1273.             ,sysobjects o
  1274.          where o.id = c.id and o.xtype = 'U '
  1275.             and c.xusertype = @xusertype
  1276.             and c.domain = @oldrule
  1277.         order by o.id
  1278.             for read only
  1279.  
  1280.         open csr_unbindrule_1
  1281.  
  1282.  
  1283.         BEGIN TRANSACTION txn_unbindrule_2
  1284.  
  1285.             fetch next from csr_unbindrule_1 into
  1286.             @obj_id
  1287.             ,@owner_name
  1288.             ,@obj_name
  1289.             ,@colid
  1290.  
  1291.             while @@fetch_status = 0
  1292.             begin
  1293.  
  1294.                 select @vc1 = quotename(@owner_name) + '.' + quotename(@obj_name)
  1295.  
  1296.                 dbcc LockObjectSchema(@vc1) --- Undocu. Locks out other schema changes until commit, and increments sysobjects.schema_ver.
  1297.  
  1298.                 select @cur_tab_id = @obj_id
  1299.  
  1300.                 while @cur_tab_id = @obj_id and @@fetch_status = 0
  1301.                 begin
  1302.                       update syscolumns set domain = 0
  1303.                     from syscolumns
  1304.                     where id = @obj_id and colid = @colid
  1305.  
  1306.                     fetch next from csr_unbindrule_1 into
  1307.                     @obj_id
  1308.                     ,@owner_name
  1309.                     ,@obj_name
  1310.                     ,@colid    
  1311.                 end
  1312.             end
  1313.  
  1314.         COMMIT TRANSACTION txn_unbindrule_2
  1315.         deallocate csr_unbindrule_1
  1316.         raiserror(15524,-1,-1)
  1317.  
  1318.     end
  1319. end
  1320.  
  1321. return (0)    --sp_unbindrule
  1322. go
  1323.  
  1324. grant execute on sp_bindefault to public
  1325. grant execute on sp_bindrule to public
  1326. grant execute on sp_unbindefault to public
  1327. grant execute on sp_unbindrule to public
  1328. go
  1329.  
  1330. -- Bug 55324
  1331. ------------------------------ sp_changedbowner -------------------------------
  1332. if object_id('sp_changedbowner','P') IS NOT NULL
  1333.     drop procedure sp_changedbowner
  1334. go
  1335. raiserror(15339,-1,-1,'sp_changedbowner')
  1336. go
  1337. create procedure sp_changedbowner
  1338.     @loginame       sysname,        -- login to become dbo
  1339.     @map            varchar(5) = NULL    -- True to map aliases, else drop
  1340. as
  1341.     -- SETUP RUNTIME OPTIONS / DECLARE VARIABLES --
  1342.     set nocount on
  1343.     declare @ret        int,
  1344.             @newsid     varbinary(85),
  1345.             @status     smallint
  1346.  
  1347.     -- CHECK PERMISSIONS (Note: All sysadmins are dbo) --
  1348.     if is_member('db_owner') = 0
  1349.     begin
  1350.         raiserror(15108,-1,-1)
  1351.         return(1)
  1352.     end
  1353.  
  1354.     -- CANT CHANGE OWNER OF MASTER/MODEL/TEMPDB --
  1355.     if db_name() in ('master', 'model', 'tempdb')
  1356.     begin
  1357.         raiserror(15109,-1,-1)
  1358.         return(1)
  1359.     end
  1360.  
  1361.     -- CHECK LOGIN NAME IS VALID (NT/SQL USER ONLY!) --
  1362.     select @newsid = sid, @status = 2 from master.dbo.syslogins
  1363.                     where loginname = @loginame and isntname = 0
  1364.     if @newsid is null
  1365.         select @status = 14, @newsid = get_sid('\U'+@loginame, NULL)
  1366.     if @newsid is null
  1367.     begin
  1368.         raiserror(15007,-1,-1,@loginame)
  1369.         return (1)
  1370.     end
  1371.  
  1372.     -- CHECK IF LOGIN ALREADY ALIASED IN DB --
  1373.     if exists (select sid from sysusers where isaliased = 1 and sid = @newsid)
  1374.     begin
  1375.         raiserror(15111,-1,-1)
  1376.         return (1)
  1377.     end
  1378.  
  1379.     -- CHECK IF LOGIN ALREADY KNOWN TO DATABASE --
  1380.     if exists (select sid from sysusers where sid = @newsid)
  1381.     begin
  1382.         raiserror(15110,-1,-1)
  1383.         return (1)
  1384.     end
  1385.  
  1386.     -- MAKE THE FOLLOWING REMOVE/REMAP/DELETES ATOMIC --
  1387.     begin transaction
  1388.  
  1389.     -- REMAP DBO TO NEW SID --
  1390.     update sysusers set sid = @newsid, status = @status, updatedate = getdate()
  1391.             where name = 'dbo'
  1392.  
  1393.     -- REMOVE OTHER DBO-ALIASES IF REMAPPING NOT REQUESTED --
  1394.     if lower(@map) <> 'true'
  1395.     begin
  1396.         delete from sysusers where isaliased = 1 and altuid = user_id('dbo')
  1397.         raiserror(15500,-1,-1)
  1398.     end
  1399.     else
  1400.         raiserror(15499,-1,-1)     -- nothing to do to <remap>
  1401.  
  1402.     -- REFLECT NEW OWNER IN SYSDATABASES --
  1403.     update master.dbo.sysdatabases set sid = @newsid where dbid = db_id()
  1404.     commit transaction
  1405.  
  1406.     -- CHECKPOINT DATABASE TO FORCE CHANGES TO IN-MEMORY STRUCTURE --
  1407.     checkpoint
  1408.     raiserror(15501,-1,-1)
  1409.     return (0) -- sp_changedbowner
  1410. go
  1411. grant execute on sp_changedbowner to public
  1412. go
  1413.  
  1414.  
  1415. -- Bug 55748
  1416. if object_id('sp_addtype','P') IS NOT NULL
  1417.     drop procedure sp_addtype
  1418. if object_id('sp_droptype','P') IS NOT NULL
  1419.     drop procedure sp_droptype
  1420. if object_id('sp_check_removable','P') IS NOT NULL
  1421.     drop procedure sp_check_removable
  1422. if object_id('sp_check_removable_sysusers','P') IS NOT NULL
  1423.     drop procedure sp_check_removable_sysusers
  1424. if object_id('sp_addrole','P') IS NOT NULL
  1425.     drop procedure sp_addrole
  1426. go
  1427.  
  1428. raiserror(15339,-1,-1,'sp_addtype')
  1429. go
  1430. create procedure sp_addtype --- 1996/04/08 00:00
  1431. @typename sysname,        -- name of user-defined type
  1432. @phystype sysname,        -- physical system type of user-defined type
  1433. @nulltype varchar(8) = null,    -- nullability of new type
  1434. @owner sysname = null    -- Owner of type (default is caller)
  1435. as
  1436.  
  1437. declare @len int        -- length of user type
  1438. declare @type tinyint        -- typeid of physical type
  1439. declare @tlen smallint        -- length of physical type
  1440. declare @typeid smallint    -- user typeid of physical type
  1441. declare @nonull bit        -- default is getansinull()
  1442. declare @prec int        -- precision of the datatype
  1443. declare @scale int        -- scale of the datatype
  1444. declare @tprec tinyint        -- precision of the datatype read from systypes
  1445. declare @tscale tinyint        -- scale of the datatype read from systypes
  1446. declare @tname sysname  -- typename from systypes
  1447. declare @tstat tinyint      -- typestat from systypes
  1448. declare @orig_phystype    sysname
  1449.  
  1450. select @orig_phystype = @phystype
  1451. select @nulltype = rtrim(lower(@nulltype))
  1452. select @typename = rtrim(@typename)
  1453. select @phystype = lower(rtrim(@phystype))
  1454.  
  1455. -- VALIDATE THE @owner NAME (and verify caller can use this name)
  1456. declare @uid smallint
  1457. if @owner is null
  1458.     select @uid = user_id()
  1459. else
  1460.     select @uid = uid from sysusers where name = @owner
  1461.         and isaliased = 0 AND uid NOT IN (0,3,4) --public/INFO_SCHEMA/etc can't own type
  1462. if @uid is null OR
  1463.     (is_member('db_owner')=0 AND
  1464.      is_member('db_ddladmin')=0 AND
  1465.      is_member(user_name(@uid))=0)
  1466. begin
  1467.     raiserror(15600, -1, -1, 'sp_addtype')
  1468.     return 1
  1469. end
  1470.  
  1471. -- TYPES BASED ON BIT CAN BE NULL IN SPHINX,
  1472. --    BUT MAKE NOT-NULL THE DFLT FOR BCKWRD-COMPAT
  1473. if lower(@phystype) = 'bit' and @nulltype is null
  1474.                 -- If user didn't specify nullability,
  1475.                 -- make sure it doesn't get set to nullable
  1476.                 -- by getansinull()
  1477.         select @nulltype = 'not null'
  1478.  
  1479. /*
  1480. **  Should the user type allow NULLs?
  1481. */
  1482. if @nulltype is null
  1483.     select @nonull = abs(getansinull()-1)
  1484. else if @nulltype = 'null'
  1485.     select @nonull = 0
  1486. else if @nulltype in ('not null','nonull')
  1487.     select @nonull = 1
  1488. else
  1489.     begin
  1490.         raiserror(15085,-1,-1)
  1491.         return (1)
  1492.     end
  1493.  
  1494. /*
  1495. **  Check to see that the @typename is valid.
  1496. */
  1497. declare @returncode int
  1498. execute @returncode = sp_validname @typename
  1499. if @returncode <> 0
  1500.     return(1)
  1501.  
  1502. /*
  1503. **  Check to see if the user type already exists or a system type
  1504. **  whose name = lower(@typename) (or a synomym) already exists.
  1505. */
  1506. if exists (select * from systypes where name = @typename)
  1507.         or lower(@typename)
  1508.         in ('character','character varying','char varying',
  1509.             'integer','dec','binary varying')
  1510.  
  1511.     begin
  1512.         raiserror(15029,-1,-1,@typename)
  1513.         return (1)
  1514.     end
  1515.  
  1516. /*
  1517. **  Check to see if the user type has been reserved for future use.
  1518. */
  1519. if @typename in ('variant','bigint')
  1520.     begin
  1521.         raiserror(15075,-1,-1,@typename)
  1522.         return (1)
  1523.     end
  1524.  
  1525. /*
  1526. ** Can't supply length with sysname type.
  1527. */
  1528. if @phystype like 'sysname%(%'
  1529.     begin
  1530.         raiserror(15270,-1,-1)
  1531.         return(1)
  1532.     end
  1533.  
  1534. /*
  1535. ** initialize the length to be NULL first.
  1536. */
  1537. select @len = NULL
  1538.  
  1539. /*
  1540. ** If precision and scale were given with the type - extract them
  1541. */
  1542. if @phystype like '_%(_%,_%)'
  1543. begin
  1544.     select @prec = convert(int, substring(@phystype,
  1545.         charindex('(',@phystype) + 1,
  1546.         charindex(',',@phystype) - 1 - charindex('(',@phystype)))
  1547.  
  1548.     select @scale = convert(int, substring(@phystype,
  1549.         charindex(',',@phystype) + 1,
  1550.         charindex(')',@phystype) - 1 - charindex(',',@phystype)))
  1551.     /*
  1552.     ** Extract the physical type name
  1553.     */
  1554.     select @phystype = substring(@phystype, 1,
  1555.            charindex('(', @phystype) - 1)
  1556. end
  1557. else
  1558.  
  1559. /*
  1560. **  If a length was given with the user datatype, extract it.
  1561. */
  1562. if @phystype like '_%(%)'
  1563. begin
  1564.     select @len = convert(int, substring(@phystype,
  1565.         charindex('(',@phystype) + 1,
  1566.         charindex(')',@phystype) - 1 - charindex('(',@phystype)))
  1567.  
  1568.     /*
  1569.     ** Extract the physical type name
  1570.     */
  1571.     select @phystype = substring(@phystype, 1,
  1572.            charindex('(', @phystype) - 1)
  1573. end
  1574.  
  1575. select @phystype = rtrim(@phystype)
  1576.  
  1577. if @phystype='character'
  1578.     select @phystype='char'
  1579. else if @phystype='character varying'
  1580.     select @phystype='varchar'
  1581. else if @phystype='char varying'
  1582.     select @phystype='varchar'
  1583. else if @phystype='integer'
  1584.     select @phystype='int'
  1585. else if @phystype='dec'
  1586.     select @phystype='decimal'
  1587. else if @phystype='binary varying'
  1588.     select @phystype='varbinary'
  1589.  
  1590. /*
  1591. **  Make sure that the physical type exists and get its characteristics.
  1592. **  System physical types have a xusertype < 256 and are owned by the
  1593. **  dbo (userid = 1).
  1594. */
  1595. select @type = xtype, @tlen = length,
  1596.     @tprec = xprec, @tscale = xscale, @tstat = status, @tname = name
  1597. from systypes
  1598.     where xusertype < 256 and name = @phystype and uid = 1
  1599.  
  1600. if @type is null
  1601. begin
  1602.     raiserror(15036,-1,-1,@orig_phystype)
  1603.     return (1)
  1604. end
  1605.  
  1606. /*
  1607. **  Disallow user-defined datatypes on timestamps.  This is done because
  1608. **  a timestamp is not a basic type but is really a binary.  There is,
  1609. **  therefore, no way to tell if a user-defined datatype is mapped to
  1610. **  a binary or a timestamp.  Timestamps can't have rules or defaults.
  1611. */
  1612. if @phystype = 'timestamp'
  1613. begin
  1614.     raiserror(15038,-1,-1)
  1615.     return (1)
  1616. end
  1617.  
  1618. /*
  1619. **  Check if the NULL status of the user type is consistent with the NULL status
  1620. **  of the physical type.  Here are the possible cases.
  1621. **
  1622. **           physical type
  1623. **          NULLs      NONULLs
  1624. **            -----------------
  1625. ** user    NULLs    |  ok    |  no
  1626. ** type NONULLs    |  ok    |  ok
  1627. */
  1628. -- NOT NECESSARY: bit and timestamp both already special-cased
  1629. /**********
  1630. if @nonull = 0 and 1 = 0
  1631.     begin
  1632.         raiserror(15037,-1,-1,@orig_phystype)
  1633.         return (1)
  1634.     end
  1635. **********/
  1636.  
  1637. /* Decide about precision, scale, length
  1638. ** First check from NUMERIC, DECIMAL
  1639. */
  1640. if @tname in ('numeric','decimal')
  1641. begin
  1642.     /* Type is NUMERIC or DECIMAL */
  1643.  
  1644.     if @len > 0
  1645.         begin
  1646.             /* Length is really the precision
  1647.             ** Since no scale is specified then scale
  1648.             ** is minimum(Default, precision). Default = 4
  1649.             */
  1650.             select @prec = @len
  1651.             select @scale = 0
  1652.         end
  1653.     else
  1654.         if (@prec is NULL)
  1655.             begin
  1656.                 select @prec = 18
  1657.                 select @scale = 0
  1658.             end
  1659.  
  1660.     if (@prec > 38) or (@prec < 1)
  1661.         begin
  1662.             raiserror(15086,-1,-1)
  1663.             return (1)
  1664.         end
  1665.  
  1666.     if (@scale > @prec) or (@scale < 0)
  1667.         begin
  1668.             /*
  1669.             ** Illegal scale specified -- must be less than precision
  1670.             ** and positive.
  1671.             */
  1672.             raiserror(15087,-1,-1)
  1673.             return (1)
  1674.         end
  1675.  
  1676.     /* Compute length from precision */
  1677.     if (@prec <= 9)
  1678.         select @len = 5
  1679.  
  1680.     if (@prec > 9) and (@prec <= 19)
  1681.         select @len = 9
  1682.  
  1683.     if (@prec > 19) and (@prec <= 28)
  1684.         select @len = 13
  1685.  
  1686.     if (@prec > 28) and (@prec <= 38)
  1687.         select @len = 17
  1688.  
  1689. end
  1690. else
  1691.  
  1692. /*
  1693. **  Typeids 1 (char), 2 (varchar), 3 (binary) and 4 (varbinary) are the
  1694. **  only ones which allow a length to be specified.
  1695. */
  1696. if @tname not in ('binary', 'varbinary', 'char', 'varchar', 'nchar', 'nvarchar')
  1697.     begin
  1698.         /*
  1699.         **  We can't use a length and we got one.
  1700.         */
  1701.         if @len > 0
  1702.             begin
  1703.                 raiserror(15088,-1,-1)
  1704.                 return (1)
  1705.             end
  1706.  
  1707.         /*
  1708.         **  Use the fixed length of the physical type.
  1709.         */
  1710.         select @len = @tlen
  1711.         select @prec = @tprec
  1712.         select @scale = @tscale
  1713.     end
  1714. else
  1715.     begin
  1716.         /*
  1717.         **  We need a length and we didn't get one.
  1718.         */
  1719.         if @len is null
  1720.             begin
  1721.                 raiserror(15091,-1,-1)
  1722.                 return (1)
  1723.             end
  1724.  
  1725.         -- need to adjust length for unicode (watch out for overflow!)
  1726.         if @tname in ('nchar', 'nvarchar') and (@len & 0x80000000) != 0x80000000
  1727.             select @len = @len * 2
  1728.         if @len <= 0 or @len > 8000
  1729.             begin
  1730.                 raiserror(15092,-1,-1)
  1731.                 return (1)
  1732.             end
  1733.  
  1734.         select @prec = @tprec
  1735.         select @scale = @tscale
  1736.     end
  1737.  
  1738. /*
  1739. **  Finally, get the maximum existing user type so we use it + 1 for this
  1740. **  new type.
  1741. */
  1742. select @typeid = max(xusertype)
  1743.     from systypes
  1744.  
  1745. /*
  1746. **  There are no user defined types yet so use the first number (256).
  1747. */
  1748. if @typeid < 256
  1749.     select @typeid = 256
  1750.  
  1751. -- Set null status bit
  1752. if @nonull = 1
  1753.     select @tstat = @tstat | 0x01
  1754. else
  1755.     select @tstat = @tstat & 0xFE
  1756.  
  1757. insert systypes (name, xtype, status, xusertype, length, xprec, xscale,
  1758.             tdefault, domain, uid, reserved)
  1759.     select @typename, @type, @tstat, @typeid + 1, @len, @prec, @scale,
  1760.             0, 0, @uid, 0
  1761.  
  1762. raiserror(15449,-1,-1)
  1763.  
  1764. return (0) -- sp_addtype
  1765. go
  1766.  
  1767. raiserror(15339,-1,-1,'sp_droptype')
  1768. go
  1769. create procedure sp_droptype --- 1996/04/08 00:00
  1770. @typename sysname            /* the user type to drop */
  1771. as
  1772.  
  1773. declare @typeid smallint        /* the typeid of the usertype to drop */
  1774.  
  1775. /*
  1776. **  Initialize @typeid so we can tell if we can't find it.
  1777. */
  1778. select @typeid = 0
  1779.  
  1780. /*
  1781. **  Find the user type with @typename.  It must be a user type (xusertype > 256)
  1782. **  and it must be owned by the person (or special role) running the procedure.
  1783. */
  1784. select @typeid = xusertype
  1785.     from systypes
  1786.         where name = @typename and xusertype > 256
  1787.         AND (is_member('db_owner') = 1 OR is_member('db_ddladmin') = 1 OR is_member(user_name(uid))=1)
  1788.  
  1789. if @typeid = 0
  1790.     begin
  1791.         raiserror(15105,-1,-1)
  1792.         return (1)
  1793.     end
  1794.  
  1795. /*
  1796. **  Check to see if the type is being used.  If it is, it can't be dropped.
  1797. */
  1798. if exists (select * from syscolumns where xusertype = @typeid)
  1799.     begin
  1800.         raiserror(15180,-1,-1)
  1801.  
  1802.         /*
  1803.         **  Show where it's being used.
  1804.         */
  1805.         select object = o.name, type = o.xtype, owner = u.name,
  1806.             [column] = c.name, datatype = t.name
  1807.         from syscolumns c, systypes t, sysusers u, sysobjects o
  1808.         where c.xusertype = @typeid
  1809.             and t.xusertype = @typeid
  1810.             and o.uid = u.uid
  1811.             and c.id = o.id
  1812.         order by object, [column]
  1813.  
  1814.         return (1)
  1815.     end
  1816.  
  1817. /*
  1818. **  Everything is consistent so drop the type.
  1819. */
  1820. delete from systypes where xusertype = @typeid
  1821.  
  1822. raiserror(15467,-1,-1)
  1823.  
  1824. return (0) -- sp_droptype
  1825. go
  1826.  
  1827. raiserror(15339,-1,-1,'sp_check_removable')
  1828. go
  1829. create procedure sp_check_removable @autofix varchar(4)
  1830. as
  1831.  
  1832. declare @dbosid varbinary (86)
  1833. declare @dbname sysname
  1834. declare @exec_stmt nvarchar(540)
  1835. declare @fgname sysname
  1836.  
  1837. select @dbname=db_name()
  1838.  
  1839. /* Verify that SA owns the database. */
  1840.  
  1841. select @dbosid = sid from master..sysdatabases where name = @dbname
  1842. if @dbosid <> 0x01
  1843.     if @autofix='auto'
  1844.     begin
  1845.         -- changing DBO to SA
  1846.         update sysdatabases set sid = 0x01
  1847.             where name = @dbname
  1848.         update sysusers set sid = 0x01
  1849.             where uid = 1
  1850.     end
  1851.     else
  1852.     begin
  1853.         raiserror(15258,-1,-1, @dbname)
  1854.         return(1)
  1855.     end
  1856.  
  1857.     -- USE CORRECT non-dbo/guest CHECKING
  1858.     declare @ret int
  1859.     exec @ret = sp_check_removable_sysusers @autofix
  1860.     if @ret <> 0
  1861.         return 1
  1862.  
  1863.     -- Run UPDATE STATISTICS on all user tables if there are
  1864.     -- no user defined filegroups
  1865.     if @autofix='auto' and
  1866.         (select count(*) from sysfilegroups) = 1
  1867.     begin
  1868.         select @exec_stmt = N'USE ' + quotename( @dbname , '[')
  1869.         + N' exec sp_updatestats '
  1870.         exec (@exec_stmt)
  1871.     end
  1872.  
  1873.     exec('dump tran '+@dbname+' with no_log')
  1874.  
  1875.     if (select count(*) from sysfilegroups) > 1
  1876.     begin
  1877.         if @autofix='auto'
  1878.         begin
  1879.             -- Mark any non-primary filegroups as READONLY
  1880.             DECLARE fgcursor INSENSITIVE CURSOR
  1881.             FOR SELECT groupname FROM sysfilegroups fg
  1882.                 WHERE fg.groupid > 1 -- not primary
  1883.                 AND fg.status & 0x8 = 0 -- not already readonly
  1884.                 AND (SELECT count (*) FROM sysfiles f WHERE
  1885.                 f.groupid = fg.groupid) > 0 -- has some files
  1886.             OPEN fgcursor
  1887.             FETCH NEXT FROM fgcursor INTO @fgname
  1888.             WHILE (@@FETCH_STATUS <> -1)
  1889.             BEGIN
  1890.                 SELECT @exec_stmt = 'ALTER DATABASE '
  1891.                 + quotename( @dbname , '[')
  1892.                 + ' MODIFY FILEGROUP '
  1893.                 + quotename( @fgname , '[')
  1894.                 + ' READONLY'
  1895.                 EXEC (@exec_stmt)
  1896.                 FETCH NEXT FROM fgcursor INTO @fgname
  1897.             END
  1898.             CLOSE fgcursor
  1899.             DEALLOCATE fgcursor
  1900.         end
  1901.         else
  1902.         begin
  1903.             if exists (SELECT groupname FROM sysfilegroups fg
  1904.                 WHERE fg.groupid > 1 -- not primary
  1905.                 AND fg.status & 0x8 = 0 -- not already readonly
  1906.                 AND (SELECT count (*) FROM sysfiles f WHERE
  1907.                 f.groupid = fg.groupid) > 0) -- has some files
  1908.             begin
  1909.                 raiserror(15358,-1,-1)
  1910.                 SELECT groupname FROM sysfilegroups fg
  1911.                     WHERE fg.groupid > 1 -- not primary
  1912.                     AND fg.status & 0x8 = 0 -- not already readonly
  1913.                 return (-1)
  1914.             end
  1915.         end
  1916.     
  1917.  
  1918.     end
  1919. return(0)
  1920. go
  1921.  
  1922. raiserror(15339,-1,-1,'sp_check_removable_sysusers')
  1923. go
  1924. -----------------------------------------------------
  1925. -- NOTE: FOR INTERNAL USE ONLY (sp_certify_removable)
  1926. --      DO NOT DOCUMENT OR USE!
  1927. -----------------------------------------------------
  1928. create procedure sp_check_removable_sysusers
  1929.     @autofix    varchar(4)      -- true or other
  1930. as
  1931.     -- CHECK FOR DATABASE OWNED BY SQL USER --
  1932.     if exists (select name from sysusers where name = 'dbo' and issqluser = 1 and sid <> suser_sid('sa'))
  1933.     begin
  1934.         if @autofix <> 'auto'
  1935.         begin
  1936.             raiserror(15258,-1,-1)
  1937.             return(1)
  1938.         end
  1939.  
  1940.         -- MAKE SA THE DBO --
  1941.         raiserror(15502,-1,-1)
  1942.         update sysusers set sid = suser_sid('sa'), status = 2, updatedate = getdate()
  1943.                 where name = 'dbo'
  1944.     end
  1945.  
  1946.     -- CHECK FOR PERMISSIONS GRANTED TO or BY SQL USERS --
  1947.     if exists (select grantee from syspermissions where grantee in
  1948.                 (select uid from sysusers u where issqluser = 1 and u.uid > 4))
  1949.     OR exists (select grantor from syspermissions where grantor in
  1950.                 (select uid from sysusers u where issqluser = 1 and u.uid > 4))
  1951.     begin
  1952.         if @autofix = 'auto'
  1953.             PRINT 'CANNOT AUTO-AUTOFIX GRANT-WITH-GRANT CHAINS'
  1954.         raiserror(15053,-1,-1)
  1955.         return(1)
  1956.     end
  1957.  
  1958.     -- CHECK FOR OBJECTS OWNED BY SQL USERS --
  1959.     if exists (select uid from sysobjects where uid in
  1960.                 (select uid from sysusers u where issqluser = 1 and u.uid > 4))
  1961.     begin
  1962.         if @autofix <> 'auto'
  1963.         begin
  1964.             raiserror(15053,-1,-1)
  1965.             return(1)
  1966.         end
  1967.  
  1968.         -- ASSIGN DBO AS OWNER OF OTHER OBJECTS (MAY FAIL WITH DUPL!) --
  1969.         raiserror(15503,-1,-1)
  1970.         update sysobjects set uid = 1 where uid in
  1971.                 (select uid from sysusers u where issqluser = 1 and u.uid > 4)
  1972.         if @@error <> 0
  1973.             return (1)
  1974.     end
  1975.  
  1976.     -- CHECK FOR TYPES OWNED BY SQL USERS --
  1977.     if exists (select uid from systypes where uid in
  1978.                 (select uid from sysusers u where issqluser = 1 and u.uid > 4))
  1979.     begin
  1980.         if @autofix <> 'auto'
  1981.         begin
  1982.             raiserror(15053,-1,-1)
  1983.             return(1)
  1984.         end
  1985.  
  1986.         -- ASSIGN DBO AS OWNER OF TYPES --
  1987.         raiserror(15503,-1,-1)
  1988.         update systypes set uid = 1 where uid in
  1989.                 (select uid from sysusers u where issqluser = 1 and u.uid > 4)
  1990.     end
  1991.  
  1992.     -- CHECK FOR ROLES OWNED BY SQL USERS --
  1993.     if exists (select altuid from sysusers where (issqlrole = 1 or isapprole = 1) and
  1994.         altuid in (select uid from sysusers u where u.issqluser = 1 and u.uid > 4))
  1995.     begin
  1996.         if @autofix <> 'auto'
  1997.         begin
  1998.             raiserror(15053,-1,-1)
  1999.             return(1)
  2000.         end
  2001.  
  2002.         -- ASSIGN DBO AS OWNER OF TYPES --
  2003.         raiserror(15503,-1,-1)
  2004.         update sysusers set altuid = 1, updatedate = getdate()
  2005.             where (issqlrole = 1 or isapprole = 1) and
  2006.             altuid in (select uid from sysusers u where u.issqluser = 1 and u.uid > 4)
  2007.     end
  2008.  
  2009.     -- CHECK FOR SQL LOGINS AS USERS --
  2010.     if exists (select uid from sysusers where issqluser = 1 and uid > 4)
  2011.     begin
  2012.         if @autofix <> 'auto'
  2013.         begin
  2014.             raiserror(15254,-1,-1)
  2015.             return(1)
  2016.         end
  2017.  
  2018.         -- DELETE SQL USERS AND DEPENDENT ALIASES --
  2019.         raiserror(15504,-1,-1)
  2020.         delete from sysusers where issqluser = 1 and uid > 4
  2021.         delete from sysusers where isaliased = 1 and user_name(altuid) is null
  2022.     end
  2023.  
  2024.     -- CHECK FOR SQL LOGINS ALIASED --
  2025.     if exists (select uid from sysusers where isaliased = 1 and isntname = 0)
  2026.     begin
  2027.         if @autofix <> 'auto'
  2028.         begin
  2029.             raiserror(15254,-1,-1)
  2030.             return(1)
  2031.         end
  2032.  
  2033.         -- DELETE ALIASED SQL USERS --
  2034.         raiserror(15504,-1,-1)
  2035.         delete from sysusers where isaliased = 1 and isntname = 0
  2036.     end
  2037.  
  2038.     -- Success
  2039.     return 0
  2040. go
  2041.  
  2042. raiserror(15339,-1,-1,'sp_addrole')
  2043. go
  2044. create procedure sp_addrole
  2045.     @rolename   sysname,        -- name of new role
  2046.     @ownername  sysname = 'dbo' -- name of owner of new role
  2047. as
  2048.     -- SETUP RUNTIME OPTIONS / DECLARE VARIABLES --
  2049.     set nocount on
  2050.     declare @ret        int,    -- return value of sp call
  2051.             @uid        smallint,
  2052.             @owner      smallint
  2053.  
  2054.     -- CHECK PERMISSIONS --
  2055.     if (not is_member('db_securityadmin') = 1) and
  2056.        (not is_member('db_owner') = 1)
  2057.     begin
  2058.         raiserror(15000,-1,-1)
  2059.         return (1)
  2060.     end
  2061.  
  2062.     -- DISALLOW USER TRANSACTION --
  2063.     set implicit_transactions off
  2064.     if (@@trancount > 0)
  2065.     begin
  2066.         raiserror(15002,-1,-1,'sp_addrole')
  2067.         return (1)
  2068.     end
  2069.  
  2070.         -- RESOLVE OWNER NAME --
  2071.     select @owner = uid from sysusers where name = @ownername
  2072.                     and isaliased = 0 AND uid NOT IN (0,3,4) --public/INFO_SCHEMA/etc can't own role
  2073.     if @owner is null
  2074.     begin
  2075.         raiserror(15008,-1,-1,@ownername)
  2076.         return (1)
  2077.     end
  2078.  
  2079.     -- VALIDATE ROLE NAME --
  2080.     execute @ret = sp_validname @rolename
  2081.     if @ret <> 0
  2082.         return (1)
  2083.     if (charindex('\', @rolename) > 0)
  2084.     begin
  2085.         raiserror(15006,-1,-1,@rolename)
  2086.         return (1)
  2087.     end
  2088.  
  2089.     -- ERROR IF SYSUSERS NAME ALREADY EXISTS --
  2090.     if user_id(@rolename) is not null
  2091.     begin
  2092.         if exists (select name from sysusers where issqlrole = 1 and name = @rolename)
  2093.             raiserror(15363,-1,-1,@rolename)
  2094.         else
  2095.             raiserror(15023,-1,-1,@rolename)
  2096.  
  2097.         return (1)
  2098.     end
  2099.  
  2100.     -- OBTAIN NEW ROLE UID (RESERVE 16384-16399) --
  2101.     if user_name(16400) IS NULL
  2102.         select @uid = 16400
  2103.     else
  2104.         select @uid = min(uid)+1 from sysusers
  2105.             where uid >= 16400 and uid < (32767 - 1)    -- stay in role range
  2106.                 and user_name(uid+1) is null            -- uid not in use
  2107.     if @uid is null
  2108.     begin
  2109.         raiserror(15065,-1,-1)
  2110.         return (1)
  2111.     end
  2112.  
  2113.     -- INSERT THE ROW INTO SYSUSERS --
  2114.     insert into sysusers values
  2115.         (@uid, 0, @rolename, NULL, 0x00, getdate(), getdate(), @owner, NULL)
  2116.  
  2117.     -- FINALIZATION: PRINT/RETURN SUCCESS --
  2118.     if @@error <> 0
  2119.         return (1)
  2120.     raiserror(15424,-1,-1)
  2121.     return (0) -- sp_addrole
  2122. go
  2123.  
  2124. grant execute on sp_addtype to public
  2125. grant execute on sp_droptype to public
  2126. grant execute on sp_addrole to public
  2127. go
  2128.  
  2129. --------------------------------------------------------------------------------
  2130. --    Schema Procs (OLEDBSCH.SQL / ANSIVIEW.SQL)
  2131. --------------------------------------------------------------------------------
  2132.  
  2133.  
  2134. --------------------------------------------------------------------------------
  2135. --    ODBC/OLEDB Catalog Procs (INSTCAT.SQL)
  2136. --------------------------------------------------------------------------------
  2137.  
  2138. -- BUG 55811 and 56158 (Ported from Shiloh fix)
  2139.  
  2140. if (exists (select * from sysobjects
  2141.         where name = 'sp_statistics' and type = 'P '))
  2142.     drop proc sp_statistics
  2143. go
  2144.  
  2145. if (exists (select * from sysobjects
  2146.         where name = 'sp_pkeys' and type = 'P '))
  2147.     drop proc sp_pkeys
  2148. go
  2149.  
  2150. -- BUG 57054
  2151. if (exists (select * from sysobjects
  2152.         where name = 'sp_fkeys' and type = 'P '))
  2153.     drop proc sp_fkeys
  2154. go
  2155.  
  2156. -- sp_pkeys
  2157. CREATE PROCEDURE sp_pkeys(
  2158.                @table_name        sysname,
  2159.                @table_owner     sysname = null,
  2160.                @table_qualifier sysname = null )
  2161. as
  2162.     DECLARE @table_id            int
  2163.     DECLARE @full_table_name    varchar(255) /* 2*128 + 1 */
  2164.  
  2165.     if @table_qualifier is not null
  2166.     begin
  2167.         if db_name() <> @table_qualifier
  2168.         begin    /* If qualifier doesn't match current database */
  2169.             raiserror (15250, -1,-1)
  2170.             return
  2171.         end
  2172.     end
  2173.     if @table_owner is null
  2174.     begin    /* If unqualified table name */
  2175.         SELECT @full_table_name = quotename(@table_name)
  2176.     end
  2177.     else
  2178.     begin    /* Qualified table name */
  2179.         if @table_owner = ''
  2180.         begin    /* If empty owner name */
  2181.             SELECT @full_table_name = quotename(@table_owner)
  2182.         end
  2183.         else
  2184.         begin
  2185.             SELECT @full_table_name = quotename(@table_owner) +
  2186.                 '.' + quotename(@table_name)
  2187.         end
  2188.     end
  2189.     /*    Get Object ID */
  2190.     SELECT @table_id = object_id(@full_table_name)
  2191.  
  2192.     select
  2193.         TABLE_QUALIFIER = convert(sysname,db_name()),
  2194.         TABLE_OWNER = convert(sysname,user_name(o.uid)),
  2195.         TABLE_NAME = convert(sysname,o.name),
  2196.         COLUMN_NAME = convert(sysname,c.name),
  2197.         KEY_SEQ =
  2198.             case
  2199.                 when c.name = index_col(@full_table_name, i.indid,  1) then 1
  2200.                 when c.name = index_col(@full_table_name, i.indid,  2) then 2
  2201.                 when c.name = index_col(@full_table_name, i.indid,  3) then 3
  2202.                 when c.name = index_col(@full_table_name, i.indid,  4) then 4
  2203.                 when c.name = index_col(@full_table_name, i.indid,  5) then 5
  2204.                 when c.name = index_col(@full_table_name, i.indid,  6) then 6
  2205.                 when c.name = index_col(@full_table_name, i.indid,  7) then 7
  2206.                 when c.name = index_col(@full_table_name, i.indid,  8) then 8
  2207.                 when c.name = index_col(@full_table_name, i.indid,  9) then 9
  2208.                 when c.name = index_col(@full_table_name, i.indid, 10) then 10
  2209.                 when c.name = index_col(@full_table_name, i.indid, 11) then 11
  2210.                 when c.name = index_col(@full_table_name, i.indid, 12) then 12
  2211.                 when c.name = index_col(@full_table_name, i.indid, 13) then 13
  2212.                 when c.name = index_col(@full_table_name, i.indid, 14) then 14
  2213.                 when c.name = index_col(@full_table_name, i.indid, 15) then 15
  2214.                 when c.name = index_col(@full_table_name, i.indid, 16) then 16
  2215.             end,
  2216.         PK_NAME = convert(sysname,i.name)
  2217.     from
  2218.         sysindexes i, syscolumns c, sysobjects o
  2219.     where
  2220.         o.id = @table_id
  2221.         and o.id = c.id
  2222.         and o.id = i.id
  2223.         and (i.status & 0x800) = 0x800
  2224.         and (c.name = index_col (@full_table_name, i.indid,  1) or
  2225.              c.name = index_col (@full_table_name, i.indid,  2) or
  2226.              c.name = index_col (@full_table_name, i.indid,  3) or
  2227.              c.name = index_col (@full_table_name, i.indid,  4) or
  2228.              c.name = index_col (@full_table_name, i.indid,  5) or
  2229.              c.name = index_col (@full_table_name, i.indid,  6) or
  2230.              c.name = index_col (@full_table_name, i.indid,  7) or
  2231.              c.name = index_col (@full_table_name, i.indid,  8) or
  2232.              c.name = index_col (@full_table_name, i.indid,  9) or
  2233.              c.name = index_col (@full_table_name, i.indid, 10) or
  2234.              c.name = index_col (@full_table_name, i.indid, 11) or
  2235.              c.name = index_col (@full_table_name, i.indid, 12) or
  2236.              c.name = index_col (@full_table_name, i.indid, 13) or
  2237.              c.name = index_col (@full_table_name, i.indid, 14) or
  2238.              c.name = index_col (@full_table_name, i.indid, 15) or
  2239.              c.name = index_col (@full_table_name, i.indid, 16)
  2240.             )
  2241.     order by 1, 2, 3, 5
  2242. go
  2243.  
  2244. grant execute on sp_pkeys to public
  2245. go
  2246.  
  2247. -- sp_statitics
  2248. CREATE PROCEDURE sp_statistics (
  2249.                  @table_name        sysname,
  2250.                  @table_owner        sysname = null,
  2251.                  @table_qualifier    sysname = null,
  2252.                  @index_name        sysname = '%',
  2253.                  @is_unique         char(1) = 'N',
  2254.                  @accuracy            char(1) = 'Q')
  2255. AS
  2256.     set nocount on
  2257.     DECLARE @indid                int
  2258.     DECLARE @lastindid            int
  2259.     DECLARE @table_id            int
  2260.     DECLARE @full_table_name    nvarchar(257)
  2261.  
  2262.     create table #TmpIndex(
  2263.         TABLE_QUALIFIER sysname NULL,
  2264.         TABLE_OWNER     sysname NULL,
  2265.         TABLE_NAME        sysname NOT NULL,
  2266.         INDEX_QUALIFIER sysname null,
  2267.         INDEX_NAME        sysname null,
  2268.         NON_UNIQUE        smallint null,
  2269.         TYPE            smallint NOT NULL,
  2270.         SEQ_IN_INDEX    smallint null,
  2271.         COLUMN_NAME     sysname null,
  2272.         COLLATION        char(1) null,
  2273.         index_id        int null,
  2274.         CARDINALITY     int null,
  2275.         PAGES            int null,
  2276.         status            int NOT NULL)
  2277.  
  2278.     if @table_qualifier is not null
  2279.     begin
  2280.         if db_name() <> @table_qualifier
  2281.         begin    /* If qualifier doesn't match current database */
  2282.             raiserror (15250, -1,-1)
  2283.             return
  2284.         end
  2285.     end
  2286.  
  2287.     if @accuracy not in ('Q','E')
  2288.         begin
  2289.             raiserror (15251,-1,-1,'accuracy','''Q'' or ''E''')
  2290.             return
  2291.         end
  2292.  
  2293.     if @table_owner is null
  2294.     begin    /* If unqualified table name */
  2295.         SELECT @full_table_name = quotename(@table_name)
  2296.     end
  2297.     else
  2298.     begin    /* Qualified table name */
  2299.         if @table_owner = ''
  2300.         begin    /* If empty owner name */
  2301.             SELECT @full_table_name = quotename(@table_owner)
  2302.         end
  2303.         else
  2304.         begin
  2305.             SELECT @full_table_name = quotename(@table_owner) +
  2306.                 '.' + quotename(@table_name)
  2307.         end
  2308.     end
  2309.     /*    Get Object ID */
  2310.     SELECT @table_id = object_id(@full_table_name)
  2311.  
  2312.     /*    Start at lowest index id */
  2313.     SELECT @indid = min(indid)
  2314.     FROM sysindexes
  2315.     WHERE not (@table_id is null)
  2316.         AND id = @table_id
  2317.         AND indid > 0
  2318.         AND indid < 255
  2319.  
  2320.     /* Create a temp table to correct the ordinal position of the columns */
  2321.     create table #TmpColumns
  2322.     (ordinal int identity(1,1),
  2323.      colid   smallint not null)
  2324.  
  2325.     /* Load columns into the temp table */
  2326.     insert into #TmpColumns (colid)
  2327.     select c.colid
  2328.     from syscolumns c
  2329.     where c.id = @table_id
  2330.     order by c.colid
  2331.     
  2332.     WHILE @indid is not NULL
  2333.     BEGIN
  2334.         INSERT #TmpIndex    /* Add all columns that are in index */
  2335.             SELECT
  2336.                 DB_NAME(),                        /* TABLE_QUALIFIER */
  2337.                 USER_NAME(o.uid),                    /* TABLE_OWNER       */
  2338.                 o.name,                         /* TABLE_NAME       */
  2339.                 o.name,                         /* INDEX_QUALIFIER */
  2340.                 x.name,                         /* INDEX_NAME       */
  2341.                 case                            /* NON_UNIQUE       */
  2342.                     WHEN x.status&2 <> 2 then 1            /* Nonunique index */
  2343.                     else 0                        /* Unique index    */
  2344.                 end,
  2345.                 case                            /* TYPE        */
  2346.                     when @indid > 1 then 3                /* Non-Clustered   */
  2347.                     else 1                        /* Clustered index */
  2348.                 end,
  2349.                 tc.ordinal,                        /* SEQ_IN_INDEX    */
  2350.                 INDEX_COL(@full_table_name, indid, tc.ordinal),        /* COLUMN_NAME       */
  2351.                 'A',                            /* COLLATION       */
  2352.                 @indid,                         /* index_id        */
  2353.                 case                            /* CARDINALITY       */
  2354.                     when @indid > 1 then NULL            /* Non-Clustered   */
  2355.                     else x.rows                     /* Clustered index */
  2356.                 end,
  2357.                 case                            /* PAGES       */
  2358.                     when @indid > 1 then NULL            /* Non-Clustered   */
  2359.                     else x.dpages                    /* Clustered index */
  2360.                 end,
  2361.                 x.status                        /* status       */
  2362.             FROM sysindexes x, syscolumns c, sysobjects o, #TmpColumns tc
  2363.             WHERE
  2364.                 not (@table_id is null)
  2365.                 AND x.id = @table_id
  2366.                 AND x.id = o.id
  2367.                 AND x.id = c.id
  2368.                 AND tc.colid = c.colid
  2369.                 AND tc.ordinal < keycnt+(x.status&18)/18    /* all but Unique Clust indices have an extra key */
  2370.                 AND INDEX_COL(@full_table_name, indid, tc.ordinal) IS NOT NULL
  2371.                 AND indid = @indid
  2372.                 AND (x.status&2 = 2
  2373.                     OR @is_unique <> 'Y')
  2374.                 AND (x.status&32) = 0
  2375.         /*
  2376.         **      Now move @indid to the next index.
  2377.         */
  2378.         SELECT @lastindid = @indid
  2379.         SELECT @indid = NULL
  2380.  
  2381.         SELECT @indid = min(indid)
  2382.         FROM sysindexes
  2383.         WHERE not (@table_id is null)
  2384.             AND id = @table_id
  2385.             AND indid > @lastindid
  2386.             AND indid < 255
  2387.     END
  2388.  
  2389.     /* now add row for table statistics */
  2390.     INSERT #TmpIndex
  2391.         SELECT
  2392.             DB_NAME(),                /* TABLE_QUALIFIER */
  2393.             USER_NAME(o.uid),            /* TABLE_OWNER       */
  2394.             o.name,                 /* TABLE_NAME       */
  2395.             null,                    /* INDEX_QUALIFIER */
  2396.             null,                    /* INDEX_NAME       */
  2397.             null,                    /* NON_UNIQUE       */
  2398.             0,                    /* SQL_TABLE_STAT  */
  2399.             null,                    /* SEQ_IN_INDEX    */
  2400.             null,                    /* COLUMN_NAME       */
  2401.             null,                    /* COLLATION       */
  2402.             0,                    /* index_id        */
  2403.             x.rows,                 /* CARDINALITY       */
  2404.             x.dpages,                /* PAGES       */
  2405.             0                    /* status       */
  2406.         FROM sysindexes x, sysobjects o
  2407.         WHERE not (@table_id is null)
  2408.             AND o.id = @table_id
  2409.             AND x.id = o.id
  2410.             AND (x.indid = 0 or x.indid = 1)    /*    If there are no indexes */
  2411.                                 /*    then table stats are in */
  2412.                                 /*    a row with indid =0    */
  2413.  
  2414.     SELECT
  2415.         TABLE_QUALIFIER,
  2416.         TABLE_OWNER,
  2417.         TABLE_NAME,
  2418.         NON_UNIQUE,
  2419.         INDEX_QUALIFIER,
  2420.         INDEX_NAME,
  2421.         TYPE,
  2422.         SEQ_IN_INDEX,
  2423.         COLUMN_NAME,
  2424.         COLLATION,
  2425.         CARDINALITY,
  2426.         PAGES,
  2427.         FILTER_CONDITION = convert(varchar(128),null)
  2428.     FROM #TmpIndex
  2429.     WHERE
  2430.         INDEX_NAME like @index_name     /* If matching name      */
  2431.         or INDEX_NAME is null        /* If SQL_TABLE_STAT row */
  2432.     ORDER BY 4, 7, 6, 8
  2433.  
  2434.     DROP TABLE #TmpIndex, #TmpColumns
  2435. go
  2436.  
  2437. grant execute on sp_statistics to public
  2438. go
  2439.  
  2440. /*    Procedure for 7.0 and later servers */
  2441. CREATE PROCEDURE sp_fkeys(
  2442.                @pktable_name        sysname = null,
  2443.                @pktable_owner        sysname = null,
  2444.                @pktable_qualifier    sysname = null,
  2445.                @fktable_name        sysname = null,
  2446.                @fktable_owner        sysname = null,
  2447.                @fktable_qualifier    sysname = null )
  2448. as
  2449.     set nocount on
  2450.     DECLARE @pktable_id            int
  2451.     DECLARE @pkfull_table_name    nvarchar(257) /* 2*128 + 1 */
  2452.     DECLARE @fktable_id            int
  2453.     DECLARE @fkfull_table_name    nvarchar(257) /* 2*128 + 1 */
  2454.     declare    @order_by_pk        int
  2455.  
  2456.     /* select 'XXX starting table creation' */
  2457.  
  2458.     create table #fkeysall(
  2459.             rkeyid int NOT NULL,
  2460.             rkey1 int NOT NULL,
  2461.                 rkey2 int NOT NULL,
  2462.                 rkey3 int NOT NULL,
  2463.                 rkey4 int NOT NULL,
  2464.                 rkey5 int NOT NULL,
  2465.                 rkey6 int NOT NULL,
  2466.                 rkey7 int NOT NULL,
  2467.                 rkey8 int NOT NULL,
  2468.                 rkey9 int NOT NULL,
  2469.                 rkey10 int NOT NULL,
  2470.                 rkey11 int NOT NULL,
  2471.                 rkey12 int NOT NULL,
  2472.                 rkey13 int NOT NULL,
  2473.                 rkey14 int NOT NULL,
  2474.                 rkey15 int NOT NULL,
  2475.                 rkey16 int NOT NULL,
  2476.             fkeyid int NOT NULL,
  2477.             fkey1 int NOT NULL,
  2478.                 fkey2 int NOT NULL,
  2479.                 fkey3 int NOT NULL,
  2480.                 fkey4 int NOT NULL,
  2481.                 fkey5 int NOT NULL,
  2482.                 fkey6 int NOT NULL,
  2483.                 fkey7 int NOT NULL,
  2484.                 fkey8 int NOT NULL,
  2485.                 fkey9 int NOT NULL,
  2486.                 fkey10 int NOT NULL,
  2487.                 fkey11 int NOT NULL,
  2488.                 fkey12 int NOT NULL,
  2489.                 fkey13 int NOT NULL,
  2490.                 fkey14 int NOT NULL,
  2491.                 fkey15 int NOT NULL,
  2492.                 fkey16 int NOT NULL,
  2493.             constid int NOT NULL,
  2494.             name sysname NOT NULL)
  2495.  
  2496.     create table #fkeys(
  2497.             pktable_id        int NOT NULL,
  2498.             pkcolid         int NOT NULL,
  2499.             fktable_id        int NOT NULL,
  2500.             fkcolid         int NOT NULL,
  2501.             KEY_SEQ         smallint NOT NULL,
  2502.             fk_id            int NOT NULL,
  2503.             PK_NAME            sysname NOT NULL)
  2504.  
  2505.     create table #fkeysout(
  2506.             PKTABLE_QUALIFIER sysname NULL,
  2507.             PKTABLE_OWNER sysname NULL,
  2508.             PKTABLE_NAME sysname NOT NULL,
  2509.             PKCOLUMN_NAME sysname NOT NULL,
  2510.             FKTABLE_QUALIFIER sysname NULL,
  2511.             FKTABLE_OWNER sysname NULL,
  2512.             FKTABLE_NAME sysname NOT NULL,
  2513.             FKCOLUMN_NAME sysname NOT NULL,
  2514.             KEY_SEQ smallint NOT NULL,
  2515.             UPDATE_RULE smallint NULL,
  2516.             DELETE_RULE smallint NULL,
  2517.             FK_NAME sysname NULL,
  2518.             PK_NAME sysname NULL,
  2519.             DEFERRABILITY smallint null)
  2520.  
  2521.     /* select 'XXX starting parameter analysis' */
  2522.  
  2523.     select  @order_by_pk = 0
  2524.  
  2525.     if (@pktable_name is null) and (@fktable_name is null)
  2526.     begin    /* If neither primary key nor foreign key table names given */
  2527.         raiserror (15252,-1,-1)
  2528.         return
  2529.     end
  2530.     if @fktable_qualifier is not null
  2531.     begin
  2532.         if db_name() <> @fktable_qualifier
  2533.         begin    /* If qualifier doesn't match current database */
  2534.             raiserror (15250, -1,-1)
  2535.             return
  2536.         end
  2537.     end
  2538.     if @pktable_qualifier is not null
  2539.     begin
  2540.         if db_name() <> @pktable_qualifier
  2541.         begin    /* If qualifier doesn't match current database */
  2542.             raiserror (15250, -1,-1)
  2543.             return
  2544.         end
  2545.     end
  2546.  
  2547.     if @pktable_owner is null
  2548.     begin    /* If unqualified primary key table name */
  2549.         SELECT @pkfull_table_name = quotename(@pktable_name)
  2550.     end
  2551.     else
  2552.     begin    /* Qualified primary key table name */
  2553.         if @pktable_owner = ''
  2554.         begin    /* If empty owner name */
  2555.             SELECT @pkfull_table_name = quotename(@pktable_owner)
  2556.         end
  2557.         else
  2558.         begin
  2559.             SELECT @pkfull_table_name = quotename(@pktable_owner) +
  2560.                 '.' + quotename(@pktable_name)
  2561.         end
  2562.     end
  2563.  
  2564.     if @fktable_owner is null
  2565.     begin    /* If unqualified foreign key table name */
  2566.         SELECT @fkfull_table_name = quotename(@fktable_name)
  2567.     end
  2568.     else
  2569.     begin    /* Qualified foreign key table name */
  2570.         if @fktable_owner = ''
  2571.         begin    /* If empty owner name */
  2572.             SELECT @fkfull_table_name = quotename(@fktable_owner)
  2573.         end
  2574.         else
  2575.         begin
  2576.             SELECT @fkfull_table_name = quotename(@fktable_owner) +
  2577.                 '.' + quotename(@fktable_name)
  2578.         end
  2579.     end
  2580.  
  2581.     SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
  2582.     begin tran
  2583.  
  2584.     /*    Get PK Object ID */
  2585.     SELECT @pktable_id = object_id(@pkfull_table_name)
  2586.  
  2587.     /*    Get FK Object ID */
  2588.     SELECT @fktable_id = object_id(@fkfull_table_name)
  2589.  
  2590.     if @fktable_name is not null
  2591.     begin
  2592.         if @fktable_id is null
  2593.             SELECT @fktable_id = 0    /* fk table not found, empty result */
  2594.     end
  2595.  
  2596.     if @pktable_name is null
  2597.     begin /*  If table name not supplied, match all */
  2598.         select @order_by_pk = 1
  2599.     end
  2600.     else
  2601.     begin
  2602.         if @pktable_id is null
  2603.         begin
  2604.             SELECT @pktable_id = 0    /* pk table not found, empty result */
  2605.         end
  2606.     end
  2607.  
  2608.     /*    SQL Server supports upto 16 PK/FK relationships between 2 tables */
  2609.     /*    Process syskeys for each relationship */
  2610.     /*  First, attempt to get all 16 keys for each rel'ship, then sort
  2611.         them out with a 16-way "insert select ... union select ..." */
  2612.  
  2613.     /* select 'XXX starting data analysis' */
  2614.  
  2615.     insert into #fkeysall
  2616.         select
  2617.             r.rkeyid,
  2618.             r.rkey1, r.rkey2, r.rkey3, r.rkey4,
  2619.                 r.rkey5, r.rkey6, r.rkey7, r.rkey8,
  2620.                 r.rkey9, r.rkey10, r.rkey11, r.rkey12,
  2621.                 r.rkey13, r.rkey14, r.rkey15, r.rkey16,
  2622.             r.fkeyid,
  2623.             r.fkey1, r.fkey2, r.fkey3, r.fkey4,
  2624.                 r.fkey5, r.fkey6, r.fkey7, r.fkey8,
  2625.                 r.fkey9, r.fkey10, r.fkey11, r.fkey12,
  2626.                 r.fkey13, r.fkey14, r.fkey15, r.fkey16,
  2627.             r.constid,
  2628.             i.name
  2629.         from
  2630.             sysreferences r, sysobjects o, sysindexes i
  2631.         where    r.constid = o.id
  2632.             AND o.xtype = 'F'
  2633.             AND r.rkeyindid = i.indid
  2634.             AND r.rkeyid = i.id
  2635.             AND r.rkeyid between isnull(@pktable_id, 0)
  2636.                             and isnull(@pktable_id, 0x7fffffff)
  2637.             AND r.fkeyid between isnull(@fktable_id, 0)
  2638.                             and isnull(@fktable_id, 0x7fffffff)
  2639.  
  2640.     /* select count (*) as 'XXX countall' from #fkeysall */
  2641.  
  2642.     insert into #fkeys
  2643.             select rkeyid, rkey1, fkeyid, fkey1, 1, constid, name
  2644.             from #fkeysall
  2645.         union all
  2646.             select rkeyid, rkey2, fkeyid, fkey2, 2, constid, name
  2647.             from #fkeysall
  2648.         union all
  2649.             select rkeyid, rkey3, fkeyid, fkey3, 3, constid, name
  2650.             from #fkeysall
  2651.         union all
  2652.             select rkeyid, rkey4, fkeyid, fkey4, 4, constid, name
  2653.             from #fkeysall
  2654.         union all
  2655.             select rkeyid, rkey5, fkeyid, fkey5, 5, constid, name
  2656.             from #fkeysall
  2657.         union all
  2658.             select rkeyid, rkey6, fkeyid, fkey6, 6, constid, name
  2659.             from #fkeysall
  2660.         union all
  2661.             select rkeyid, rkey7, fkeyid, fkey7, 7, constid, name
  2662.             from #fkeysall
  2663.         union all
  2664.             select rkeyid, rkey8, fkeyid, fkey8, 8, constid, name
  2665.             from #fkeysall
  2666.         union all
  2667.             select rkeyid, rkey9, fkeyid, fkey9, 9, constid, name
  2668.             from #fkeysall
  2669.         union all
  2670.             select rkeyid, rkey10, fkeyid, fkey10, 10, constid, name
  2671.             from #fkeysall
  2672.         union all
  2673.             select rkeyid, rkey11, fkeyid, fkey11, 11, constid, name
  2674.             from #fkeysall
  2675.         union all
  2676.             select rkeyid, rkey12, fkeyid, fkey12, 12, constid, name
  2677.             from #fkeysall
  2678.         union all
  2679.             select rkeyid, rkey13, fkeyid, fkey13, 13, constid, name
  2680.             from #fkeysall
  2681.         union all
  2682.             select rkeyid, rkey14, fkeyid, fkey14, 14, constid, name
  2683.             from #fkeysall
  2684.         union all
  2685.             select rkeyid, rkey15, fkeyid, fkey15, 15, constid, name
  2686.             from #fkeysall
  2687.         union all
  2688.             select rkeyid, rkey16, fkeyid, fkey16, 16, constid, name
  2689.             from #fkeysall
  2690.  
  2691.     /* select count (*) as 'XXX count' from #fkeys */
  2692.  
  2693.     insert into #fkeysout
  2694.         select
  2695.             PKTABLE_QUALIFIER = convert(sysname,db_name()),
  2696.             PKTABLE_OWNER = convert(sysname,USER_NAME(o1.uid)),
  2697.             PKTABLE_NAME = convert(sysname,o1.name),
  2698.             PKCOLUMN_NAME = convert(sysname,c1.name),
  2699.             FKTABLE_QUALIFIER = convert(sysname,db_name()),
  2700.             FKTABLE_OWNER = convert(sysname,USER_NAME(o2.uid)),
  2701.             FKTABLE_NAME = convert(sysname,o2.name),
  2702.             FKCOLUMN_NAME = convert(sysname,c2.name),
  2703.             KEY_SEQ,
  2704.             UPDATE_RULE = convert(smallint,1),
  2705.             DELETE_RULE = convert(smallint,1),
  2706.             FK_NAME = convert(sysname,OBJECT_NAME(fk_id)),
  2707.             PK_NAME,
  2708.             DEFERRABILITY = 7    /* SQL_NOT_DEFERRABLE */
  2709.         from #fkeys f,
  2710.             sysobjects o1, sysobjects o2,
  2711.             syscolumns c1, syscolumns c2
  2712.         where    o1.id = f.pktable_id
  2713.             AND o2.id = f.fktable_id
  2714.             AND c1.id = f.pktable_id
  2715.             AND c2.id = f.fktable_id
  2716.             AND c1.colid = f.pkcolid
  2717.             AND c2.colid = f.fkcolid
  2718.  
  2719.     commit tran
  2720.  
  2721.     /* select count (*) as 'XXX countout' from #fkeysout */
  2722.  
  2723.     if @order_by_pk = 1 /*    If order by PK fields */
  2724.         select
  2725.             PKTABLE_QUALIFIER, PKTABLE_OWNER, PKTABLE_NAME, PKCOLUMN_NAME,
  2726.             FKTABLE_QUALIFIER, FKTABLE_OWNER, FKTABLE_NAME, FKCOLUMN_NAME,
  2727.             KEY_SEQ, UPDATE_RULE, DELETE_RULE, FK_NAME, PK_NAME, DEFERRABILITY
  2728.         from #fkeysout
  2729.         order by 1,2,3,9
  2730.     else        /*    Order by FK fields */
  2731.         select
  2732.             PKTABLE_QUALIFIER, PKTABLE_OWNER, PKTABLE_NAME, PKCOLUMN_NAME,
  2733.             FKTABLE_QUALIFIER, FKTABLE_OWNER, FKTABLE_NAME, FKCOLUMN_NAME,
  2734.             KEY_SEQ, UPDATE_RULE, DELETE_RULE, FK_NAME, PK_NAME, DEFERRABILITY
  2735.         from #fkeysout
  2736.         order by 5,6,7,9
  2737. go
  2738.  
  2739. grant execute on sp_fkeys to public
  2740. go
  2741.  
  2742. CHECKPOINT
  2743. go
  2744.  
  2745.  
  2746. --------------------------------------------------------------------------------
  2747. --    SQLDMO System Procedures (SQLDMO.SQL)
  2748. --------------------------------------------------------------------------------
  2749. if exists (select * from master..sysobjects where (OBJECTPROPERTY(id, N'IsProcedure') = 1 or OBJECTPROPERTY(id, N'IsExtendedProc') = 1) and name = N'sp_MStablekeys')
  2750.     drop procedure sp_MStablekeys
  2751. go
  2752. if exists (select * from master..sysobjects where (OBJECTPROPERTY(id, N'IsProcedure') = 1 or OBJECTPROPERTY(id, N'IsExtendedProc') = 1) and name = N'sp_MSforeachdb')
  2753.     drop procedure sp_MSforeachdb
  2754. go
  2755. if exists (select * from master..sysobjects where (OBJECTPROPERTY(id, N'IsProcedure') = 1 or OBJECTPROPERTY(id, N'IsExtendedProc') = 1) and name = N'sp_MSforeachtable')
  2756.     drop procedure sp_MSforeachtable
  2757. go
  2758. if exists (select * from master..sysobjects where (OBJECTPROPERTY(id, N'IsProcedure') = 1 or OBJECTPROPERTY(id, N'IsExtendedProc') = 1) and name = N'sp_MSloginmappings')
  2759.     drop procedure sp_MSloginmappings
  2760. go
  2761. if exists (select * from master..sysobjects where (OBJECTPROPERTY(id, N'IsProcedure') = 1 or OBJECTPROPERTY(id, N'IsExtendedProc') = 1) and name = N'sp_MSobjectprivs')
  2762.     drop procedure sp_MSobjectprivs
  2763. go
  2764. if exists (select * from master..sysobjects where (OBJECTPROPERTY(id, N'IsProcedure') = 1 or OBJECTPROPERTY(id, N'IsExtendedProc') = 1) and name = N'sp_MSscriptdb_worker')
  2765.     drop procedure sp_MSscriptdb_worker
  2766. go
  2767. if exists (select * from master..sysobjects where (OBJECTPROPERTY(id, N'IsProcedure') = 1 or OBJECTPROPERTY(id, N'IsExtendedProc') = 1) and name = N'sp_MSdbuseraccess')
  2768.     drop procedure sp_MSdbuseraccess
  2769. go
  2770.  
  2771. /*******************************************************************************/
  2772. print N''
  2773. print N'Creating sp_MStablekeys'
  2774. print N''
  2775. go
  2776.  
  2777. create procedure sp_MStablekeys
  2778. @tablename nvarchar(776) = null, @colname nvarchar(258) = null, @type int = null, @keyname nvarchar(517) = null, @flags int = null
  2779. as
  2780.     /* This proc returns the table's DRI keys.  @type is the type(s) of key(s) to return. */
  2781.     /* Make sure @type is only the key types (DRI_PRIMARYKEY, DRI_UNIQUE, DRI_REFERENCE). */
  2782.     if (@type is null)
  2783.         select @type = 0x000e
  2784.     else
  2785.         select @type = @type & 0x000e
  2786.  
  2787.     /* Flags usage:  For daVinci, to pass call thru to sp_MStablerefs. */
  2788.     if (@flags is null)
  2789.         select @flags = 0
  2790.  
  2791.     set nocount on
  2792.     create table #spkeys
  2793.     (
  2794.         cType                tinyint            NOT NULL,    /* key Type */
  2795.         cName                nvarchar(258)        NOT NULL,    /* key Name */
  2796.         cFlags                int                NULL,        /* e.g., 1 = clustered for PK/Unique */
  2797.         cColCount            int                NULL,        /* number of columns (or column pairs) in the key */
  2798.         cFillFactor            tinyint            NULL,        /* Fill factor of index creation */
  2799.         cRefTable            nvarchar(520)        NULL,        /* owner-qual Referenced table name for FKs */
  2800.         cRefKey                nvarchar(260)        NULL,        /* name of referenced key in referenced table */
  2801.             -- Note:  cConstID replaces the column list used in 6.0, for speed.
  2802.             -- The output set MUST replace this with either index_col(@tablename, cIndexID, 1-16) and NULL * 16
  2803.             -- (for PK/UQ) UNION col_name(r.fkeyid, r.fkey1-16) and col_name(r.rkeyid, r.rkey1-16), for SQLDMO,
  2804.             -- and these MUST BE nvarchar(132) for alignment in the SQLDMO cache structure!
  2805.         cConstID            int                NULL,        /* Reference constraint ID, if Foreign Key  */
  2806.         cIndexID            int                NULL,        /* ID of this key's index, if PK/UQ */
  2807.         cGroupName        sysname        NULL,        /* FileGroup name of this key, if PK/UQ */
  2808.         cDisabled        int                NULL,        /* 0 if enabled, 1 if disabled */
  2809.         cPrimaryFG        int                NULL,        /* 1 if primary FG, 0 otherwise */
  2810.     )
  2811.  
  2812.     declare @cType int, @cName nvarchar(258), @cFlags int, @cRefTable nvarchar(520), @fillfactor tinyint
  2813.     declare @objid int, @constid int, @indid int, @keycnt int, @q1 nvarchar(2000), @q2 nvarchar(2000), @objtype int, @groupname sysname
  2814.     declare @haskeytypes int, @wantkeytypes int
  2815.    declare @cDisabled int, @PrimaryFG int
  2816.  
  2817.     /* First see if @keyname was defined, and override @tablename and @type if so. */
  2818.     if (@keyname is not null)
  2819.     begin
  2820.          select @objid = id, @type = power(2, status & 0x0f) from sysconstraints where constid = object_id(@keyname)
  2821.          if (@objid is null)    begin
  2822.             RAISERROR (15001, -1, -1, @keyname)
  2823.             return 1
  2824.          end
  2825.          /* Now get the tablename for the index_col below */
  2826.          select @tablename = N'[' + REPLACE(user_name(uid), N']', N']]') + N']' + N'.' + N'[' + REPLACE(name, N']', N']]') + N']' from sysobjects where id = @objid
  2827.     end else begin
  2828.         /* Want all keys for this table (of @type type). */
  2829.         select @objid = id, @objtype = (case when OBJECTPROPERTY(id, N'IsTable') = 1 then 1 else 0 end), @haskeytypes = category & 0x0604
  2830.             from sysobjects where id = object_id(@tablename)
  2831.         if (@objid is null)    begin
  2832.             RAISERROR (15001, -1, -1, @tablename)
  2833.             return 1
  2834.         end
  2835.         if (@objtype <> 1)    begin
  2836.             RAISERROR (15218, -1, -1, @tablename)
  2837.             return 1
  2838.         end
  2839.         if @colname is not null and not exists (select * from syscolumns where id = @objid and name = @colname) begin
  2840.             RAISERROR (15253, -1, -1, @colname, @tablename)
  2841.             return 1
  2842.         end
  2843.  
  2844.         /* Skip cursor opening if we don't have any keys (of the type wanted); return a set anyway, for the cache. */
  2845.         if (@haskeytypes = 0)
  2846.             goto ReturnSet
  2847.  
  2848.         /* Map from the input bitmask to the category bitmask */
  2849.         select @wantkeytypes = 0
  2850.         if ((@type & power(2, 1)) <> 0)
  2851.             select @wantkeytypes = @wantkeytypes | 0x200
  2852.         if ((@type & power(2, 2)) <> 0)
  2853.             select @wantkeytypes = @wantkeytypes | 0x400
  2854.         if ((@type & power(2, 3)) <> 0)
  2855.             select @wantkeytypes = @wantkeytypes | 0x4
  2856.         if ((@haskeytypes & @wantkeytypes) = 0)
  2857.             goto ReturnSet
  2858.     end
  2859.  
  2860.     /* Preprocessor won't replace within quotes so have to use str(). */
  2861.     declare @sysgenname nvarchar(12), @pkstr nvarchar(12), @uqstr nvarchar(12), @fkstr nvarchar(12), @objtypebits nvarchar(12)
  2862.     select @sysgenname = ltrim(str(convert(int, 0x00020000)))
  2863.     select @pkstr = ltrim(str(convert(int, 1)))
  2864.     select @uqstr = ltrim(str(convert(int, 2)))
  2865.     select @fkstr = ltrim(str(convert(int, 3)))
  2866.     select @objtypebits = ltrim(str(convert(int, 0x0f)))
  2867.  
  2868.     /* Other ints we need strings for */
  2869.     declare @objidstr nvarchar(12), @typestr nvarchar(12)
  2870.     select @objidstr = ltrim(str(@objid))
  2871.     select @typestr = ltrim(str(@type))
  2872.  
  2873.     /* Qualifying key name. */
  2874.     declare @qualkeyname nvarchar(100)
  2875.     select @qualkeyname = null
  2876.     if (@keyname is not null) begin
  2877.       select @qualkeyname = N' and constid = object_id(''' + @keyname + N''')'
  2878.    end
  2879.  
  2880.     /*********************/
  2881.     /* Main cursor loop. */
  2882.     /*********************/
  2883. /*      exec(N'declare hC insensitive cursor for select constid, status & ' + @objtypebits + N', status & ' + @sysgenname +  */
  2884.     exec(N'declare hC cursor global for select constid, status & ' + @objtypebits + N', status & ' + @sysgenname +
  2885.             N' from sysconstraints where id = ' + @objidstr + N' and (' + @typestr + N' & power(2, status & 0x0f) != 0) ' + @qualkeyname)
  2886.     open hC
  2887.     fetch hC into @constid, @cType, @cFlags
  2888.     while (@@fetch_status >= 0) begin
  2889.         if (object_name(@constid) is null) begin
  2890.             raiserror 55555 N'Assert failed:  object_name(@constid) is null in sp_MStablekeys (pk/uq)'
  2891.             return 1
  2892.         end
  2893.  
  2894.         /* DRI_PRIMARYKEY, DRI_UNIQUE */
  2895.         if (@cType in (1, 2)) begin
  2896.             /* Get the index id enforcing this constraint. */
  2897.             select @indid = i.indid, @cName = o.name, @fillfactor = i.OrigFillFactor,
  2898.                     @cFlags = @cFlags | (case indid when 1 then 0x00000001 else 0 end),        /* test for clustered index */
  2899.                /* clustered index keys are part of non-clustered index key list, which cause incorrect sysindexes.keycnt */
  2900.                     @keycnt = case indid when 1 then keycnt else (select count(x.id) from sysindexkeys x where i.indid = x.indid and x.id = @objid) end,
  2901.                @groupname = f.groupname,
  2902.                @PrimaryFG = FILEGROUPPROPERTY( f.groupname, N'IsPrimaryFG' )
  2903.                 from sysindexes i, sysobjects o, sysfilegroups f
  2904.             /* Use '=' instead of 'LIKE' in comparision, so we can handle wide card character correctly */
  2905.                 where o.id = @constid and i.name = o.name and i.status & 0x1800 <> 0 and i.groupid = f.groupid
  2906.             if (@indid is null) begin
  2907.                 raiserror 77777 N'Assert failed:  @indid is null in sp_MStablekeys (pk/uq)'
  2908.                 return 1
  2909.             end
  2910.  
  2911.             /* Load our temp table. */
  2912.             insert #spkeys values (@cType, @cName, @cFlags, @keycnt, @fillfactor, null, null, null, @indid, @groupname, 0, @PrimaryFG)
  2913.         end
  2914.  
  2915.         /* DRI_REFERENCE */
  2916.         else if (@cType in (3)) begin
  2917.             /* Get the key column information from sysreferences. */
  2918.          select @keycnt = r.keycnt, @cName = object_name(r.constid), @cRefTable = N'[' + user_name(o.uid) + N']' + N'.' + N'[' + o.name + N']',
  2919.                @cDisabled = OBJECTPROPERTY( r.constid, N'CnstIsDisabled' )
  2920.             from sysreferences r, sysobjects o where r.constid = @constid and o.id = r.rkeyid
  2921.  
  2922.             /* Follow r.rkeyindid back to sysindexes to get the ref key name. */
  2923.             declare @cRefKey nvarchar(132)
  2924.             select @cRefKey = i.name, @cFlags = c.status from sysreferences r, sysindexes i, sysconstraints c
  2925.                 where c.constid = r.constid and r.constid = @constid
  2926.                 and i.id = r.rkeyid and i.indid = r.rkeyindid and i.status & 0x1800 <> 0
  2927.  
  2928.             /* Load our temp table. */
  2929.             insert #spkeys values (@cType, @cName, @cFlags, @keycnt, null, @cRefTable, @cRefKey, @constid, null, null, @cDisabled, 0)
  2930.         end        /* Key type */
  2931.  
  2932.         /* Get the next row. */
  2933.         fetch hC into @constid, @cType, @cFlags
  2934.     end            /* PRIMARY/UNIQUE */
  2935.     deallocate hC
  2936.  
  2937.     /* Now output the data */
  2938. ReturnSet:
  2939.     set nocount off
  2940.     select cType, cName, cFlags, cColCount, cFillFactor, cRefTable, cRefKey,
  2941.             cKeyCol1 = convert(nvarchar(132), index_col(@tablename, cIndexID, 1)),
  2942.             cKeyCol2 = convert(nvarchar(132), index_col(@tablename, cIndexID, 2)),    
  2943.             cKeyCol3 = convert(nvarchar(132), index_col(@tablename, cIndexID, 3)),
  2944.             cKeyCol4 = convert(nvarchar(132), index_col(@tablename, cIndexID, 4)),
  2945.             cKeyCol5 = convert(nvarchar(132), index_col(@tablename, cIndexID, 5)),
  2946.             cKeyCol6 = convert(nvarchar(132), index_col(@tablename, cIndexID, 6)),    
  2947.             cKeyCol7 = convert(nvarchar(132), index_col(@tablename, cIndexID, 7)),
  2948.             cKeyCol8 = convert(nvarchar(132), index_col(@tablename, cIndexID, 8)),
  2949.             cKeyCol9 = convert(nvarchar(132), index_col(@tablename, cIndexID, 9)),
  2950.             cKeyCol10 = convert(nvarchar(132), index_col(@tablename, cIndexID, 10)),
  2951.             cKeyCol11 = convert(nvarchar(132), index_col(@tablename, cIndexID, 11)),
  2952.             cKeyCol12 = convert(nvarchar(132), index_col(@tablename, cIndexID, 12)),
  2953.             cKeyCol13 = convert(nvarchar(132), index_col(@tablename, cIndexID, 13)),
  2954.             cKeyCol14 = convert(nvarchar(132), index_col(@tablename, cIndexID, 14)),    
  2955.             cKeyCol15 = convert(nvarchar(132), index_col(@tablename, cIndexID, 15)),
  2956.             cKeyCol16 = convert(nvarchar(132), index_col(@tablename, cIndexID, 16)),
  2957.             cRefCol1 = convert(nvarchar(132), null),
  2958.             cRefCol2 = convert(nvarchar(132), null),
  2959.             cRefCol3 = convert(nvarchar(132), null),
  2960.             cRefCol4 = convert(nvarchar(132), null),
  2961.             cRefCol5 = convert(nvarchar(132), null),
  2962.             cRefCol6 = convert(nvarchar(132), null),
  2963.             cRefCol7 = convert(nvarchar(132), null),
  2964.             cRefCol8 = convert(nvarchar(132), null),
  2965.             cRefCol9 = convert(nvarchar(132), null),
  2966.             cRefCol10 = convert(nvarchar(132), null),
  2967.             cRefCol11 = convert(nvarchar(132), null),
  2968.             cRefCol12 = convert(nvarchar(132), null),
  2969.             cRefCol13 = convert(nvarchar(132), null),
  2970.             cRefCol14 = convert(nvarchar(132), null),
  2971.             cRefCol15 = convert(nvarchar(132), null),
  2972.             cRefCol16 = convert(nvarchar(132), null),
  2973.             cIndexID,
  2974.             cGroupName,
  2975.          cDisabled,
  2976.           cPrimaryFG
  2977.         from #spkeys where cType in (1, 2)
  2978.             and (@colname is null or
  2979.                 index_col(@tablename, cIndexID, 1) = @colname or
  2980.                 index_col(@tablename, cIndexID, 2) = @colname or
  2981.                 index_col(@tablename, cIndexID, 3) = @colname or
  2982.                 index_col(@tablename, cIndexID, 4) = @colname or
  2983.                 index_col(@tablename, cIndexID, 5) = @colname or
  2984.                 index_col(@tablename, cIndexID, 6) = @colname or
  2985.                 index_col(@tablename, cIndexID, 7) = @colname or
  2986.                 index_col(@tablename, cIndexID, 8) = @colname or
  2987.                 index_col(@tablename, cIndexID, 9) = @colname or
  2988.                 index_col(@tablename, cIndexID, 10) = @colname or
  2989.                 index_col(@tablename, cIndexID, 11) = @colname or
  2990.                 index_col(@tablename, cIndexID, 12) = @colname or
  2991.                 index_col(@tablename, cIndexID, 13) = @colname or
  2992.                 index_col(@tablename, cIndexID, 14) = @colname or
  2993.                 index_col(@tablename, cIndexID, 15) = @colname or
  2994.                 index_col(@tablename, cIndexID, 16) = @colname
  2995.             )
  2996.         UNION
  2997.         select c.cType, c.cName, c.cFlags, c.cColCount, c.cFillFactor, c.cRefTable, c.cRefKey,
  2998.             cKeyCol1 = convert(nvarchar(132), col_name(r.fkeyid, r.fkey1)),
  2999.             cKeyCol2 = convert(nvarchar(132), col_name(r.fkeyid, r.fkey2)),
  3000.             cKeyCol3 = convert(nvarchar(132), col_name(r.fkeyid, r.fkey3)),
  3001.             cKeyCol4 = convert(nvarchar(132), col_name(r.fkeyid, r.fkey4)),
  3002.             cKeyCol5 = convert(nvarchar(132), col_name(r.fkeyid, r.fkey5)),
  3003.             cKeyCol6 = convert(nvarchar(132), col_name(r.fkeyid, r.fkey6)),
  3004.             cKeyCol7 = convert(nvarchar(132), col_name(r.fkeyid, r.fkey7)),
  3005.             cKeyCol8 = convert(nvarchar(132), col_name(r.fkeyid, r.fkey8)),
  3006.             cKeyCol9 = convert(nvarchar(132), col_name(r.fkeyid, r.fkey9)),
  3007.             cKeyCol10 = convert(nvarchar(132), col_name(r.fkeyid, r.fkey10)),
  3008.             cKeyCol11 = convert(nvarchar(132), col_name(r.fkeyid, r.fkey11)),
  3009.             cKeyCol12 = convert(nvarchar(132), col_name(r.fkeyid, r.fkey12)),
  3010.             cKeyCol13 = convert(nvarchar(132), col_name(r.fkeyid, r.fkey13)),
  3011.             cKeyCol14 = convert(nvarchar(132), col_name(r.fkeyid, r.fkey14)),
  3012.             cKeyCol15 = convert(nvarchar(132), col_name(r.fkeyid, r.fkey15)),
  3013.             cKeyCol16 = convert(nvarchar(132), col_name(r.fkeyid, r.fkey16)),
  3014.             cRefCol1 = convert(nvarchar(132), col_name(r.rkeyid, r.rkey1)),
  3015.             cRefCol2 = convert(nvarchar(132), col_name(r.rkeyid, r.rkey2)),    
  3016.             cRefCol3 = convert(nvarchar(132), col_name(r.rkeyid, r.rkey3)),
  3017.             cRefCol4 = convert(nvarchar(132), col_name(r.rkeyid, r.rkey4)),
  3018.             cRefCol5 = convert(nvarchar(132), col_name(r.rkeyid, r.rkey5)),
  3019.             cRefCol6 = convert(nvarchar(132), col_name(r.rkeyid, r.rkey6)),
  3020.             cRefCol7 = convert(nvarchar(132), col_name(r.rkeyid, r.rkey7)),
  3021.             cRefCol8 = convert(nvarchar(132), col_name(r.rkeyid, r.rkey8)),
  3022.             cRefCol9 = convert(nvarchar(132), col_name(r.rkeyid, r.rkey9)),
  3023.             cRefCol10 = convert(nvarchar(132), col_name(r.rkeyid, r.rkey10)),
  3024.             cRefCol11 = convert(nvarchar(132), col_name(r.rkeyid, r.rkey11)),
  3025.             cRefCol12 = convert(nvarchar(132), col_name(r.rkeyid, r.rkey12)),
  3026.             cRefCol13 = convert(nvarchar(132), col_name(r.rkeyid, r.rkey13)),
  3027.             cRefCol14 = convert(nvarchar(132), col_name(r.rkeyid, r.rkey14)),
  3028.             cRefCol15 = convert(nvarchar(132), col_name(r.rkeyid, r.rkey15)),
  3029.             cRefCol16 = convert(nvarchar(132), col_name(r.rkeyid, r.rkey16)),
  3030.             cIndexID,
  3031.             cGroupName,
  3032.          cDisabled,
  3033.           cPrimaryFG
  3034.         from #spkeys c, sysreferences r where c.cType = 3 and r.constid = c.cConstID
  3035.             and (@colname is null or
  3036.                 col_name(r.fkeyid, r.fkey1) = @colname or
  3037.                 col_name(r.fkeyid, r.fkey2) = @colname or
  3038.                 col_name(r.fkeyid, r.fkey3) = @colname or
  3039.                 col_name(r.fkeyid, r.fkey4) = @colname or
  3040.                 col_name(r.fkeyid, r.fkey5) = @colname or
  3041.                 col_name(r.fkeyid, r.fkey6) = @colname or
  3042.                 col_name(r.fkeyid, r.fkey7) = @colname or
  3043.                 col_name(r.fkeyid, r.fkey8) = @colname or
  3044.                 col_name(r.fkeyid, r.fkey9) = @colname or
  3045.                 col_name(r.fkeyid, r.fkey10) = @colname or
  3046.                 col_name(r.fkeyid, r.fkey11) = @colname or
  3047.                 col_name(r.fkeyid, r.fkey12) = @colname or
  3048.                 col_name(r.fkeyid, r.fkey13) = @colname or
  3049.                 col_name(r.fkeyid, r.fkey14) = @colname or
  3050.                 col_name(r.fkeyid, r.fkey15) = @colname or
  3051.                 col_name(r.fkeyid, r.fkey16) = @colname
  3052.             )
  3053.         order by cType, cName
  3054.  
  3055.     if (@flags & 1 <> 0)
  3056.         exec sp_MStablerefs @tablename, N'actualkeycols', N'foreign'
  3057.  
  3058. go
  3059. /* End sp_MStablekeys */
  3060.  
  3061. /*-----------------------------------------------------*/
  3062. /*-----------------------------------------------------*/
  3063. print N''
  3064. print N'Creating sp_MSforeachdb'
  3065. print N''
  3066. go
  3067.  
  3068. /*
  3069.  * The following table definition will be created by SQLDMO at start of each connection.
  3070.  * We don't create it here temporarily because we need it in Exec() or upgrade won't work.
  3071.  */
  3072.  
  3073. create proc sp_MSforeachdb
  3074.     @command1 nvarchar(2000), @replacechar nchar(1) = N'?', @command2 nvarchar(2000) = null, @command3 nvarchar(2000) = null,
  3075.     @precommand nvarchar(2000) = null, @postcommand nvarchar(2000) = null
  3076. as
  3077.     /* This proc returns one or more rows for each accessible db, with each db defaulting to its own result set */
  3078.     /* @precommand and @postcommand may be used to force a single result set via a temp table. */
  3079.  
  3080.     /* Preprocessor won't replace within quotes so have to use str(). */
  3081.     declare @inaccessible nvarchar(12), @invalidlogin nvarchar(12), @dbinaccessible nvarchar(12)
  3082.     select @inaccessible = ltrim(str(convert(int, 0x03e0), 11))
  3083.     select @invalidlogin = ltrim(str(convert(int, 0x40000000), 11))
  3084.     select @dbinaccessible = N'0x80000000'        /* SQLDMODbUserProf_InaccessibleDb; the negative number doesn't work in convert() */
  3085.  
  3086.     if (@precommand is not null)
  3087.         exec(@precommand)
  3088.  
  3089.     declare @origdb nvarchar(128)
  3090.     select @origdb = db_name()
  3091.  
  3092.     /* If it's a single user db and there's an entry for it in sysprocesses who isn't us, we can't use it. */
  3093.    /* Create the select */
  3094.     exec(N'declare hCForEach cursor global for select name from master..sysdatabases d ' +
  3095.             N' where (d.status & ' + @inaccessible + N' = 0)' +
  3096.             N' and ((DATABASEPROPERTY(d.name, ''issingleuser'') = 0 and (has_dbaccess(d.name) = 1)) or ' +
  3097.             N' ( DATABASEPROPERTY(d.name, ''issingleuser'') = 1 and not exists ' +
  3098.             N' (select * from master..sysprocesses p where dbid = d.dbid and p.spid <> @@spid)))' )
  3099.  
  3100.     declare @retval int
  3101.     select @retval = @@error
  3102.     if (@retval = 0)
  3103.         exec @retval = sp_MSforeach_worker @command1, @replacechar, @command2, @command3
  3104.  
  3105.     if (@retval = 0 and @postcommand is not null)
  3106.         exec(@postcommand)
  3107.  
  3108.    declare @tempdb nvarchar(258)
  3109.    SELECT @tempdb = REPLACE(@origdb, N']', N']]')
  3110.    exec (N'use ' + N'[' + @tempdb + N']')
  3111.  
  3112.     return @retval
  3113. go
  3114. /* End sp_MSforeachdb */
  3115.  
  3116. /*-----------------------------------------------------*/
  3117. /*-----------------------------------------------------*/
  3118. print N''
  3119. print N'Creating sp_MSforeachtable'
  3120. print N''
  3121. go
  3122.  
  3123. create proc sp_MSforeachtable
  3124.     @command1 nvarchar(2000), @replacechar nchar(1) = N'?', @command2 nvarchar(2000) = null,
  3125.    @command3 nvarchar(2000) = null, @whereand nvarchar(2000) = null,
  3126.     @precommand nvarchar(2000) = null, @postcommand nvarchar(2000) = null
  3127. as
  3128.     /* This proc returns one or more rows for each table (optionally, matching @where), with each table defaulting to its own result set */
  3129.     /* @precommand and @postcommand may be used to force a single result set via a temp table. */
  3130.  
  3131.     /* Preprocessor won't replace within quotes so have to use str(). */
  3132.     declare @mscat nvarchar(12)
  3133.     select @mscat = ltrim(str(convert(int, 0x0002)))
  3134.  
  3135.     if (@precommand is not null)
  3136.         exec(@precommand)
  3137.  
  3138.     /* Create the select */
  3139.    exec(N'declare hCForEach cursor global for select ''['' + REPLACE(user_name(uid), N'']'', N'']]'') + '']'' + ''.'' + ''['' + REPLACE(object_name(id), N'']'', N'']]'') + '']'' from sysobjects o '
  3140.          + N' where OBJECTPROPERTY(o.id, N''IsUserTable'') = 1 ' + N' and o.category & ' + @mscat + N' = 0 '
  3141.          + @whereand)
  3142.     declare @retval int
  3143.     select @retval = @@error
  3144.     if (@retval = 0)
  3145.         exec @retval = sp_MSforeach_worker @command1, @replacechar, @command2, @command3
  3146.  
  3147.     if (@retval = 0 and @postcommand is not null)
  3148.         exec(@postcommand)
  3149.  
  3150.     return @retval
  3151. go
  3152. /* End sp_MSforeachtable */
  3153.  
  3154. /*******************************************************************************/
  3155.  
  3156. print N''
  3157. print N'Creating sp_MSloginmappings'
  3158. print N''
  3159. go
  3160.  
  3161. create proc sp_MSloginmappings
  3162.     @loginname nvarchar(258) = null, @flags int = 0
  3163. as
  3164.     /*
  3165.      * @flags bits:
  3166.      *        0x01    - current db only
  3167.      */
  3168.     /*
  3169.      * Added @dbname so dbo can see everyone in current database.
  3170.      * Use hacky 4.21 syntax so it will run there, instead of a case..when.
  3171.      */
  3172.     declare @checkmultilogin int
  3173.     select @checkmultilogin = 1
  3174.     if ((@flags & 0x01 <> 0) and user_id() = 1)
  3175.         select @checkmultilogin = 0
  3176.  
  3177.     declare @logincount int
  3178.     select @logincount = 0
  3179.     if (@loginname is not null)
  3180.         select @logincount = count(*) from syslogins where loginname = @loginname
  3181.  
  3182.     /* Gotta be sa or dbo to see other than just current login. */
  3183.     declare @numlogins int, @whereloginname nvarchar(258), @name nvarchar(258), @retval int
  3184.     if (@loginname is null)
  3185.         select @numlogins = 2
  3186.     else
  3187.         select @numlogins = count(*) from syslogins where loginname = @loginname
  3188.  
  3189.     if (@numlogins = 0) begin
  3190.         RAISERROR (15007, -1, -1, @loginname)        /* Login not found */
  3191.         return 1
  3192.     end
  3193.     if (@checkmultilogin <> 0) begin
  3194.       /* We do not want to allow everybody to execute this SP */
  3195.         if (is_member(N'db_ddladmin') <> 1 and is_member(N'db_owner') <> 1 and is_member(N'db_accessadmin') <> 1 and is_member(N'db_securityadmin') <> 1 and (@numlogins > 1 or suser_sid() <> suser_sid(@loginname))) begin
  3196.             RAISERROR (14301, -1, -1, N'')                /* Only sa can see other than the current login */
  3197.             return 1
  3198.         end
  3199.     end
  3200.     if (@loginname is not null)
  3201.         select @whereloginname = N' and loginname = ''' + @loginname + N''''
  3202.    else
  3203.       select @whereloginname = N' '
  3204.  
  3205.     /*
  3206.      * This proc returns a result set with one or more rows for each database for which a login is a user or aliased to one.
  3207.      * If loginname is specified, the results are limited to that login.  First load a temp table with all logins that are
  3208.      * in a db, then add those which aren't mapped to any db.
  3209.      */
  3210.     create table #loginmappings(
  3211.         LoginName            nvarchar(128)        NULL,
  3212.         DBName                nvarchar(128)        NULL,
  3213.         UserName            nvarchar(128)        NULL,
  3214.         AliasName            nvarchar(128)        NULL
  3215.     )
  3216.     if (@flags & 0x01 <> 0) begin
  3217.         INSERT #loginmappings select l.loginname, db_name(), u.name, null from master..syslogins l, sysusers u where l.sid = u.sid and l.loginname is not NULL
  3218.         /*
  3219.          * We only allow multi-db on a 6.x server because dynamic exec() didn't exist before then,
  3220.          * hence there is no way to loop thru every database.  This is caught in SQLDMO so no
  3221.          * need for error message here; we'll just return no result sets.
  3222.          */
  3223.     end else begin
  3224.         exec @retval = sp_MSforeachdb
  3225.             N'use [?] INSERT #loginmappings select l.loginname, db_name(), u.name, null from master..syslogins l, sysusers u where l.sid = u.sid and l.loginname is not NULL'
  3226.         if (@retval <> 0)
  3227.             return 1
  3228.         insert #loginmappings select l.loginname, null, null, null from master..syslogins l where l.loginname not in (select LoginName from #loginmappings) and l.loginname is not NULL
  3229.     end
  3230.  
  3231.     /*
  3232.      * Now bring them out by loginname, each in its own result set.
  3233.      * If this is for all logins, we'll return all logins; if for curdb,
  3234.      * only those in #loginmappings (i.e. only those mapped in curdb).
  3235.      */
  3236.     exec(N'declare hCForEachLogin cursor global for select loginname from master..syslogins where loginname is not NULL ' + @whereloginname + N' order by loginname')
  3237.     if (@@error = 0)
  3238.         open hCForEachLogin
  3239.     if (@@error <> 0)
  3240.         return @@error
  3241.     fetch hCForEachLogin into @name
  3242.     while (@@fetch_status >= 0) begin
  3243.       /* Use '=' instead of 'LIKE' in comparision, so we can handle wide card character correctly */
  3244.         if ((@flags & 0x01 = 0) or exists (select * from #loginmappings where LoginName = @name))
  3245.             select * from #loginmappings where LoginName = @name
  3246.         fetch hCForEachLogin into @name
  3247.     end /* FETCH_SUCCESS */
  3248.     close hCForEachLogin
  3249.     deallocate hCForEachLogin
  3250.     return @@error
  3251. go
  3252. /* End sp_MSloginmappings */
  3253.  
  3254. /*******************************************************************************/
  3255. print N''
  3256. print N'Creating sp_MSobjectprivs'
  3257. print N''
  3258. go
  3259.  
  3260. create proc sp_MSobjectprivs
  3261.     @objname nvarchar(776) = null,
  3262.     @mode nvarchar(10) = N'object',    
  3263.     @objid int = null,                
  3264.     @srvpriv int = null,            
  3265.     @prottype int = null,            
  3266.     @grantee nvarchar(258) = null,        
  3267.    @flags int = 0,
  3268.    @rollup int = 0
  3269. as
  3270.  
  3271.     create table #objs(
  3272.         id  int NOT NULL
  3273.     )
  3274.  
  3275.     /* Temp table will hold output for final select */
  3276.     create table #output (
  3277.         action      int  NOT NULL,
  3278.         colid       int  NULL,
  3279.         uid         int  NOT NULL,
  3280.         protecttype int  NOT NULL,
  3281.         id          int  NOT NULL,
  3282.         grantor     int
  3283.     )
  3284.  
  3285.     create table #tmp(
  3286.         action   int   NOT NULL,
  3287.         uid      int   NOT NULL,
  3288.     )
  3289.  
  3290.    /* mode    : 'object', 'user' or 'column'*/
  3291.    /*
  3292.     * Note:  This was expanded for 6.5 due to changes in sysprotects.columns usage, affecting
  3293.     * CPermission::ListPrivilegeColumns.  The following additional parameters are for this.
  3294.     */
  3295.    /* objid   : ID of the object we're querying */
  3296.    /* srvpriv : privilege that we're querying for (e.g. select) */
  3297.    /* prottype: Protect type, e.g. GRANT/REVOKE */
  3298.    /* grantee : Grantee name. */
  3299.  
  3300.    /*** @flags added for DaVinci uses.  If the bit isn't set, use 6.5 ***/
  3301.    /*** sp_MSobjectprivs '%s'                                         ***/
  3302.  
  3303.    /* 7.5: mode 'column', and grantee != null, we want user column level permissions for CTable/CView::ListUserColumnPermissions */
  3304.    /*      @rollup added to indicate special rollup result set for column level permission, set to 1 to roll up */
  3305.  
  3306.     /* @flags is for daVinci */
  3307.     if (@flags is null)
  3308.         select @flags = 0
  3309.  
  3310.     /* If @objid is not null, this is for the new query for perm cols. */
  3311.     if (@objid is not null) begin
  3312.         select u.name, o.name, a = col_name(p.id, a.number), a.low, a.high, a.number
  3313.             from master.dbo.spt_values a, sysprotects p, sysobjects o, sysusers u
  3314.             where p.id = @objid and p.action = @srvpriv and p.protecttype = @prottype
  3315.             and p.uid = user_id(@grantee)
  3316.             and p.columns != 0x01 and o.id = p.id and u.uid = o.uid
  3317.                 and convert(tinyint, substring(isnull(p.columns, 0x01), a.low, 1)) &
  3318.                     -- 6.5 changed so that the bit 0 position is an "invert the bits" indicator:
  3319.                     --        when 0, behaviour is the same as in prior versions, and other bits
  3320.                     --            indicate columns with the specified privilege
  3321.                     --        when 1, the other bits are indicate columns lacking the specified privilege
  3322.                     a.high <> (case when (substring(isnull(p.columns, 0x00), 1, 1) & 1 = 0) then 0 else a.high end)
  3323.                     and col_name(p.id, a.number) is not null
  3324.                     and a.type = N'P' and a.number <= (select count(*) from syscolumns where id = @objid) order by a
  3325.         return 0
  3326.     end
  3327.  
  3328.     set nocount on
  3329.  
  3330.     /*
  3331.      * To get around a 4.21 subquery bug where returning count(*) of 0 (for proc cols)
  3332.      * causes the result set to return no rows, we need two passes; one to get the
  3333.      * objects, and another to explicitly use a value (@cols) instead of a subquery.
  3334.      */
  3335.     declare @id int, @uid int, @cols int
  3336.     select @id = null, @uid = null
  3337.     if (@mode like N'us%') begin
  3338.        select @uid = user_id(@objname)
  3339.    end else if (@mode like N'col%') and (@objname is null) and (@grantee is not null) begin
  3340.       /* 7.5, special path to get column level permissions from all objects on the specified user */
  3341.       select @uid = user_id(@grantee)
  3342.     end else begin
  3343.       select @id = object_id(@objname)
  3344.    end
  3345.     if (@id is null and @uid is null) begin
  3346.         RAISERROR (15001, -1, -1, @objname)
  3347.         return 1
  3348.     end
  3349.  
  3350.     /* Get a temp list of objects we're interested in.  Do not include repl_* users. */
  3351.    /* This is the original code */
  3352.    insert #objs select distinct p.id from sysprotects p
  3353.        where (@id is null or p.id = @id)
  3354.           and (@uid is null or p.uid = @uid)
  3355.        and p.action in (193, 195, 196, 197, 224, 26) and p.uid not in (16382, 16383)
  3356.  
  3357.     /* Use a "fake cursor" by deleting successive id's from #objs, as this must run on 4.21 */
  3358.     select @id = min(id) from #objs
  3359.     while (@id is not null) begin
  3360.         select @cols = count(*) from syscolumns c where c.id = @id
  3361.  
  3362.         insert #output select p.action, a.number, p.uid, p.protecttype, p.id, p.grantor
  3363.             from master.dbo.spt_values a, sysprotects p
  3364.             where convert(tinyint, substring( isnull(p.columns, 0x01), a.low, 1)) & a.high !=0
  3365.             and (p.id = @id)
  3366.             and (@uid is null or p.uid = @uid)
  3367.             and a.number <= @cols
  3368.             and a.type = N'P'
  3369.  
  3370.       declare @count int, @whataction int, @whatid int, @dup int
  3371.  
  3372.       /* First pass to correct duplicates */
  3373.       select @count = count(*) from #output where id = @id and colid = 0 and protecttype = 205
  3374.       if ( @count > 0 ) begin
  3375.          /* We might have duplicate rows for permission on single coulmn(s) at this point */
  3376.          /* Use a fake cursor to remove the duplicates first. */
  3377.          insert #tmp select action, uid from #output where id = @id and colid = 0 and protecttype = 205
  3378.          select @whataction = min(action) from #tmp
  3379.          select @whatid = uid from #tmp where action = @whataction
  3380.          while (@whataction is not null) begin
  3381.             if (@mode like N'col%') and (@objname is null) and (@grantee is not null) begin
  3382.                /* Special case for column level permissions on all objects for the specified user */
  3383.                delete #output where (@whatid = uid) and (colid = 0) and (protecttype = 205)
  3384.             end else begin
  3385.                delete #output where (@whatid = uid) and (colid <> 0) and (protecttype = 205)
  3386.             end
  3387.             delete #tmp where @whatid = uid
  3388.             select @whataction = min(action) from #tmp
  3389.             select @whatid = uid from #tmp where action = @whataction
  3390.          end
  3391.          delete #tmp
  3392.       end
  3393.  
  3394.       /* Second pass to correct protect type */
  3395.       select @count = count(*) from #output where id = @id and colid = 0
  3396.       if ( @count > 0 ) begin
  3397.          /* use another fake cursor to correct the protecttype */
  3398.          /* if there are multiple rows in #output for the same id and action, and if colid = 0 exist, then other rows should have 206, not 205 */
  3399.          insert #tmp select action, uid from #output where id = @id and colid = 0
  3400.          select @whataction = min(action) from #tmp
  3401.          select @whatid = uid from #tmp where action = @whataction
  3402.          while (@whataction is not null) begin
  3403.                update #output set protecttype = 206 where id = @id and colid <> 0 and @whataction = action and @whatid = uid
  3404.                delete #tmp where action = @whataction and @whatid = uid
  3405.                select @whataction = min(action) from #tmp
  3406.                select @whatid = uid from #tmp where action = @whataction
  3407.          end
  3408.          delete #tmp
  3409.       end
  3410.  
  3411.         /* Increment our "fake cursor" column and get the next one. */
  3412.         delete #objs where id = @id
  3413.         select @id = min(id) from #objs
  3414.     end
  3415.  
  3416.     /*
  3417.      * Organize so that the non-collist privileges are returned first.. this allows
  3418.      * scripting to combine them.  sysprotects.action is tinyint, so the hibyte won't conflict.
  3419.      */
  3420.  
  3421.     update #output set action = action | 0x10000000 where colid <> 0
  3422.  
  3423.     /*
  3424.      * Order output by uid so Public will script before other groups (we need to script privs for public before
  3425.      * other groups, before users; otherwise sysprotects doesn't hold onto things right).  Sub-order is by object id
  3426.      * so we know when we're done with one object and onto the next, then by protecttype to group all GRANTs and
  3427.      * REVOKEs together, and lastly by action (including ORDER_ACTION_BIT so scripting can be more efficient)
  3428.      * because we may have multiple rows for columns.
  3429.      */
  3430.  
  3431.     set nocount off
  3432.    if (@mode not like N'col%') begin
  3433.       /* Mode is not 'column', do the regular stuff */
  3434.        select p.action & ~convert(int, 0x10000000), N'column' = col_name(p.id, p.colid), p.uid, N'username' = user_name(p.uid),
  3435.                p.protecttype, o.name, N'owner' = user_name(o.uid), p.id, N'grantor' = user_name(p.grantor)
  3436.              from #output p, sysobjects o
  3437.              where o.id = p.id
  3438.              order by p.uid, p.id, p.protecttype, p.action
  3439.    end else
  3440.    /* Below are spcial cases for column level permissions */
  3441.    if (@objname is null) and (@grantee is not null) and (@rollup = 0) begin
  3442.       /* 7.5, special path to get column level permissions from all objects on the specified user */
  3443.       select N'ObjectName' = o.name, N'Owner' = user_name(o.uid), N'ColumnName' = col_name(p.id, p.colid), o.sysstat & 0x0f, p.id,
  3444.              p.action & ~convert(int, 0x10000000), p.protecttype
  3445.              from #output p, sysobjects o
  3446.              where p.id = o.id and p.uid = user_id(@grantee) and col_name(p.id, p.colid) is not null
  3447.              order by p.uid, p.id, p.protecttype, p.action
  3448.     end else if (@grantee is not null) and (@rollup = 0) begin
  3449.       /* 7.5, mode 'column', and grantee != null, we want column level permissions on this object for this user */
  3450.       select N'column' = col_name(p.id, p.colid), N'owner' = user_name(o.uid), N'username' = user_name(p.uid), o.sysstat & 0x0f, p.id,
  3451.              p.action & ~convert(int, 0x10000000), p.protecttype
  3452.              from #output p, sysobjects o
  3453.              where o.id = p.id and p.uid = user_id(@grantee) and col_name(p.id, p.colid) is not null
  3454.              order by p.uid, p.id, p.protecttype, p.action
  3455.    end else if (@grantee is null) and (@rollup = 0) begin
  3456.       /* 7.5, mode 'column', and grantee = null, we want column level permissions on this object for all users */
  3457.       select N'column' = col_name(p.id, p.colid), N'owner' = user_name(o.uid), N'username' = user_name(p.uid), o.sysstat & 0x0f, p.id,
  3458.              p.action & ~convert(int, 0x10000000), p.protecttype
  3459.              from #output p, sysobjects o
  3460.              where o.id = p.id and col_name(p.id, p.colid) is not null
  3461.              order by p.uid, p.id, p.protecttype, p.action
  3462.    end else if (@objname is null) and (@grantee is not null) and (@rollup <> 0) begin
  3463.       /* 7.5, roll up version of the special path to get column level permissions from all objects on the specified user */
  3464.       select distinct N'ObjectName' = o.name, N'owner' = user_name(o.uid),
  3465.              N'Select' = (case when ((p.action & ~convert(int, 0x10000000))=193) then 1 else 0 end),
  3466.              N'Update' = (case when ((p.action & ~convert(int, 0x10000000))=197) then 1 else 0 end),
  3467.              N'Type' = p.protecttype
  3468.              from #output p, sysobjects o
  3469.              where p.id = o.id and p.uid = user_id(@grantee) and col_name(p.id, p.colid) is not null
  3470.              order by o.name
  3471.    end else if (@grantee is null) and (@rollup <> 0) begin
  3472.       /* 7.5, roll up version of the special path to return column level permissions on this object for all users */
  3473.       select distinct N'UserName' = user_name(p.uid),
  3474.              N'Select' = (case when ((p.action & ~convert(int, 0x10000000))=193) then 1 else 0 end),
  3475.              N'Update' = (case when ((p.action & ~convert(int, 0x10000000))=197) then 1 else 0 end),
  3476.              N'Type' = p.protecttype
  3477.              from #output p, sysobjects o
  3478.              where o.id = p.id and col_name(p.id, p.colid) is not null
  3479.              order by user_name(p.uid)
  3480.    end
  3481. go
  3482. /* End sp_MSobjectprivs */
  3483.  
  3484. /*******************************************************************************/
  3485. print N''
  3486. print N'Creating sp_MSscriptdb_worker'
  3487. print N''
  3488. go
  3489. create procedure sp_MSscriptdb_worker
  3490. as
  3491.     set nocount on
  3492.  
  3493.    declare @PageSize int;
  3494.    select @PageSize = (low/1024) from master..spt_values where number = 1 and type = N'E'
  3495.  
  3496.     create table #tempFG
  3497.     (
  3498.      cDefault     int,                                  /* 1 for default FG, 0 for user defined */
  3499.      cDBFile      int,                                  /* 1 for DB file, 0 for Log file */
  3500.       cSize        int,                                  /* in 8K page */
  3501.       cMaxSize     int,
  3502.       cGrowth      int,
  3503.      cGrowthType  int,                                  /* 1 for GrowthInMB, 0 for GrowthInPercent */
  3504.      cFGName      nvarchar(132) NOT NULL,      /* FG name */
  3505.       cName        nchar(132) NOT NULL,         /* Logical */
  3506.       cFileName    nchar(264) NOT NULL,        /* Physical */
  3507.     )
  3508.  
  3509.    /* Default FileGroup first, which should cover all the log files */
  3510.    /* This one to pick up all the db files in Primary file group, while group id = 1 */
  3511.    insert #tempFG select 1, 1, (o.size * @PageSize)/1024, (case when (o.maxsize < 1) then o.maxsize else (o.maxsize * @PageSize)/1024 end), o.growth, (case when (o.status & 0x100000 = 0) then 1 else 0 end), g.groupname, o.name, o.filename from sysfiles o, sysfilegroups g where g.groupid = 1 and g.groupid = o.groupid and (o.status & 0x40) = 0
  3512.    /* This one to pick up all the log files in Primary file group, while group id = 0, note that group id 0 does not exist in sysfilegroups */
  3513.    insert #tempFG select 1, 0, (o.size * @PageSize)/1024, (case when (o.maxsize < 1) then o.maxsize else (o.maxsize * @PageSize)/1024 end), o.growth, (case when (o.status & 0x100000 = 0) then 1 else 0 end), N'PRIMARY', o.name, o.filename from sysfiles o where o.groupid = 0 and (o.status & 0x40) <> 0
  3514.    /* Other FileGroups, we should have DBFiles, no log files */
  3515.  
  3516.     create table #tempID
  3517.    (
  3518.         cGroupID int
  3519.     )
  3520.    insert #tempID select groupid from sysfilegroups where groupid <> 1
  3521.  
  3522.    declare @FGid int
  3523.     exec(N'declare hC cursor global for select cGroupID from #tempID')
  3524.     open hC
  3525.     fetch hC into @FGid
  3526.     while (@@fetch_status >= 0) begin
  3527.       insert #tempFG select 0, 1, (o.size * @PageSize)/1024, (case when (o.maxsize < 1) then o.maxsize else (o.maxsize * @PageSize)/1024 end), o.growth, (case when (o.status & 0x100000 = 0) then 1 else 0 end), g.groupname, o.name, o.filename from sysfiles o, sysfilegroups g where g.groupid = @FGid and g.groupid = o.groupid and (o.status & 0x40) = 0
  3528.       fetch hC into @FGid
  3529.    end
  3530.     deallocate hC
  3531.  
  3532.    select * from #tempFG
  3533.    DROP TABLE #tempFG
  3534.  
  3535. go
  3536. /* End sp_MSscriptdb_worker */
  3537.  
  3538. /*******************************************************************************/
  3539. /* exec sp_MSdbuseraccess 'perm', 'dbname' -- selecting priv bit from specified db                       */
  3540. /* exec sp_MSdbuseraccess 'db', 'dbname'   -- select databases, need to change db if dbname is specified */
  3541. /* exec sp_MSdbuseraccess 'init', 'dbname' -- noop                                                       */
  3542. /*******************************************************************************/
  3543. print N''
  3544. print N'Creating sp_MSdbuseraccess'
  3545. print N''
  3546. go
  3547.  
  3548. create proc sp_MSdbuseraccess
  3549.     @mode nvarchar(10) = N'perm', @qual nvarchar(128) = N'%'
  3550. as
  3551.  
  3552.    set nocount on
  3553.  
  3554.    declare @accessbit int
  3555.     if (lower(@mode) like N'perm%') begin
  3556.       /* verify */
  3557.       declare @id int, @stat int, @inval int
  3558.       select @id = dbid, @stat = status from master..sysdatabases where name = @qual
  3559.       if (@id is null) begin
  3560.          RAISERROR (15001, -1, -1, @qual)
  3561.          return 1
  3562.       end
  3563.  
  3564.       /* Can we access this db? */
  3565.       declare @single int
  3566.       select @single = DATABASEPROPERTY( @qual, N'issingleuser' )
  3567. /*      if ((@single <> 0) or ((@stat & SQLDMODBStat_Inaccessible) <> 0)) begin  */
  3568.       if ((@single <> 0) or
  3569.          (DATABASEPROPERTY(@qual, N'isdetached') <> 0) or
  3570.          (DATABASEPROPERTY(@qual, N'isshutdown') <> 0) or
  3571.          (DATABASEPROPERTY(@qual, N'issuspect') <> 0) or
  3572.          (DATABASEPROPERTY(@qual, N'isoffline') <> 0) or
  3573.          (DATABASEPROPERTY(@qual, N'isinload') <> 0) or
  3574.          (DATABASEPROPERTY(@qual, N'isinrecovery') <> 0) or
  3575.          (DATABASEPROPERTY(@qual, N'isnotrecovered') <> 0)) begin
  3576.          select @inval = 0x80000000
  3577.          select @inval
  3578.          return 0
  3579.       end
  3580.       select @accessbit = has_dbaccess(@qual)
  3581.       if ( @accessbit <> 1) begin
  3582.          select @inval = 0x40000000
  3583.          select @inval
  3584.          return 0
  3585.       end
  3586.  
  3587.       /** OK, we can access this db, need to go to the specified database to get priv bit **/
  3588.       declare @dbTempname nvarchar(258)
  3589.       declare @tempindex int
  3590.       SELECT @dbTempname = REPLACE(@qual, N']', N']]')
  3591.       exec (N'[' + @dbTempname + N']' + N'..sp_MSdbuserpriv ')
  3592.       return 0
  3593.    end
  3594.  
  3595.    /* If 'db', we want to know if what kind of access we have to the specified databases */
  3596.    /* If we are not in master, then we are selecting single database, we want to correct role bit to save round trip */
  3597.    if (lower(@mode) like N'db%') begin
  3598.       /* Make sure we're either in master or only doing it to current db. */
  3599.       declare @dbrole int
  3600.       select @dbrole = 0x0000
  3601.  
  3602.       if (db_id() <> 1)
  3603.          select @qual = db_name()
  3604.  
  3605.       /* If dbname contains ', double it for the cursor, since cursor statement is inside of '' */
  3606.       declare @qual2 nvarchar(128)
  3607.       SELECT @qual2 = REPLACE(@qual, N'''', N'''''')
  3608.  
  3609.       /* Preprocessor won't replace within quotes so have to use str(). */
  3610.       declare @invalidlogin nvarchar(12)
  3611.       select @invalidlogin = ltrim(str(convert(int, 0x40000000), 11))
  3612.       declare @inaccessible nvarchar(12)
  3613.       select @inaccessible = ltrim(str(convert(int, 0x80000000), 11))
  3614.  
  3615.       /* We can't 'use' a database with a version below the minimum. */
  3616.       /* SQL6.0 minimum is 406; SQL65 requires 408.  SQL70 database version is 408 now, it might change later */
  3617.       declare @mindbver smallint
  3618.       if (@@microsoftversion >= 0x07000000)
  3619.          select @mindbver = 408
  3620.       else
  3621.          select @mindbver = 406
  3622.  
  3623.       create table #TmpDbUserProfile (
  3624.          dbid        int NOT NULL PRIMARY KEY,
  3625.          accessperms int NOT NULL
  3626.          )
  3627.  
  3628.       /* Select all matching databases -- we want an entry even for inaccessible ones. */
  3629.       declare @dbid smallint, @dbidstr nvarchar(12), @dbstat int, @dbname nvarchar(258), @dbver smallint
  3630.       declare @dbbits int, @dbbitstr nvarchar(12)
  3631.  
  3632.       /* !!! work around here, if name contains '[', LIKE operator can't find it, since LIKE operator it treating '[' as a wild char */
  3633.       /* !!! but @qual2 might be '%', then = operator does not work */
  3634.       declare @temp int
  3635.       select @tempindex = charindex(N'[', @qual2)
  3636.       if (@tempindex <> 0)
  3637.          exec(N'declare hCdbs cursor global for select name, dbid, status, version from master..sysdatabases where name = N''' + @qual2 + N'''')
  3638.       else
  3639.          exec(N'declare hCdbs cursor global for select name, dbid, status, version from master..sysdatabases where name like N''' + @qual2 + N'''')
  3640.  
  3641.       open hCdbs
  3642.  
  3643.       /* Loop for each database, and if it's accessible, recursively call ourselves to add it. */
  3644.       fetch hCdbs into @dbname, @dbid, @dbstat, @dbver
  3645.       while (@@fetch_status >= 0) begin
  3646.          /* Preprocessor won't replace within quotes so have to use str(). */
  3647.          select @dbidstr = ltrim(str(convert(int, @dbid)))
  3648.  
  3649.          /* If it's a single user db and there's an entry for it in sysprocesses who isn't us, we can't use it. */
  3650.          declare @single_lockedout int
  3651.          select @single_lockedout = DATABASEPROPERTY( @dbname, N'issingleuser' )
  3652.          if (@single_lockedout <> 0)
  3653.             select @single_lockedout = 0 where not exists
  3654.                (select * from master..sysprocesses p where dbid = @dbid and p.spid <> @@spid)
  3655.  
  3656.          /* First see if the db is accessible (not in load, recovery, offline, single-use with another user besides us, etc.) */
  3657. /*         if ((@single_lockedout <> 0) or ((@dbstat & SQLDMODBStat_Inaccessible) <> 0) or (@dbver < @mindbver)) begin   */
  3658.          if ((@single_lockedout <> 0) or
  3659.             (@dbver < @mindbver) or
  3660.             (DATABASEPROPERTY(@dbname, N'isdetached') <> 0) or
  3661.             (DATABASEPROPERTY(@dbname, N'isshutdown') <> 0) or
  3662.             (DATABASEPROPERTY(@dbname, N'issuspect') <> 0) or
  3663.             (DATABASEPROPERTY(@dbname, N'isoffline') <> 0) or
  3664.             (DATABASEPROPERTY(@dbname, N'isinload') <> 0) or
  3665.             (DATABASEPROPERTY(@dbname, N'isinrecovery') <> 0) or
  3666.             (DATABASEPROPERTY(@dbname, N'isnotrecovered') <> 0) ) begin
  3667.             /* Inaccessible, but we can set dbo if we're sa or suser_id() is db owner sid. */
  3668.             exec (N'insert #TmpDbUserProfile values (' + @dbidstr + N', ' + @inaccessible + N')')
  3669.             end
  3670.          else begin
  3671.             /* Find out whether the current user has access to the database */
  3672.             select @accessbit = has_dbaccess(@dbname)
  3673.             if ( @accessbit <> 1) begin
  3674.                exec (N'insert #TmpDbUserProfile values (' + @dbidstr + N', ' + @invalidlogin + N')')
  3675.                end
  3676.             else begin
  3677.                /* Yes, current user does have access to this database, we are not trying to get priv at this point */
  3678.                select @dbbits = 0x01ff
  3679.                select @dbbitstr = ltrim(convert(nvarchar(12), @dbbits))
  3680.                exec (N'insert #TmpDbUserProfile values (' + @dbidstr + N', ' + @dbbitstr + N')')
  3681.                end
  3682.             end
  3683.  
  3684.          fetch hCdbs into @dbname, @dbid, @dbstat, @dbver
  3685.       end /* while FETCH_SUCCESS */
  3686.       close hCdbs
  3687.       deallocate hCdbs
  3688.  
  3689.       /* 1. If on all databases, then dbrole is dummy, need to get it later */
  3690.       /* 2. Do not double the ' character(s) in database name */
  3691.       /* 3. To speed up connection, accessperms column only indicate whether the login user can access the db, it does not contain */
  3692.       /*    permission info, we will retrieve the permission info through sp_MSdbuserpriv when necessary */
  3693.       /* !!! work around here, if name contains '[', LIKE operator can't find it, since LIKE operator it treating '[' as a wild char */
  3694.       /* !!! but @qual2 might be '%', then = operator does not work */
  3695.       if (@tempindex <> 0)
  3696.          select o.name, o.version, o.crdate, suser_sname(o.sid), o.dbid, lSize = 0, NonDbo = 0, Status = o.status, spaceavail = 0,
  3697.             LogOnSepDev = 1, o.category, t.accessperms, @dbrole, DatabaseProperty(o.name, 'isfulltextenabled'), o.status2 from master..sysdatabases o left outer join #TmpDbUserProfile t on t.dbid = o.dbid where o.name = @qual order by o.name
  3698.       else
  3699.          select o.name, o.version, o.crdate, suser_sname(o.sid), o.dbid, lSize = 0, NonDbo = 0, Status = o.status, spaceavail = 0,
  3700.             LogOnSepDev = 1, o.category, t.accessperms, @dbrole, DatabaseProperty(o.name, 'isfulltextenabled'), o.status2 from master..sysdatabases o left outer join #TmpDbUserProfile t on t.dbid = o.dbid where o.name like @qual order by o.name
  3701.       DROP TABLE #TmpDbUserProfile
  3702.       return 0
  3703.    end
  3704. go
  3705. /* End sp_MSdbuseraccess */
  3706.  
  3707. grant execute on sp_MStablekeys to public
  3708. go
  3709. grant execute on sp_MSforeachdb to public
  3710. go
  3711. grant execute on sp_MSforeachtable to public
  3712. go
  3713. grant execute on sp_MSloginmappings to public
  3714. go
  3715. grant execute on sp_MSobjectprivs to public
  3716. go
  3717. grant execute on sp_MSscriptdb_worker to public
  3718. go
  3719. grant execute on sp_MSdbuseraccess to public
  3720. go
  3721.  
  3722. CHECKPOINT
  3723. go
  3724.  
  3725. --------------------------------------------------------------------------------
  3726. --    End of SQLDMO System Procedures (SQLDMO.SQL)
  3727. --------------------------------------------------------------------------------
  3728.  
  3729.  
  3730. --------------------------------------------------------------------------------
  3731. -- END OF FILE: Turn off marking of system objects.
  3732. --    DO NOT ADD ANYTHING AFTER THIS POINT
  3733. --------------------------------------------------------------------------------
  3734. exec sp_MS_upd_sysobj_category 2
  3735. go
  3736.  
  3737. exec sp_configure 'allow updates',0
  3738. go
  3739.  
  3740. reconfigure with override
  3741. go
  3742.  
  3743.  
  3744.