DatabaseProcApplicationCreatedLinks
sybsystemprocssp_helprotect  31 Aug 14Defects Dependencies

1     
2     /* Sccsid = "%Z% generic/sproc/%M% %I% %G%" */
3     /*	4.8	1.1	06/14/90	sproc/src/help */
4     /*
5     ** Messages for "sp_helprotect"         17673
6     **
7     ** 17431, "true"
8     ** 17432, "false"
9     ** 17460, "Object must be in the current database."
10    ** 17232, "No user with the specified name exists in the current database."
11    ** 17673, "All"
12    ** 17674, "No such object or user exists in the database."
13    ** 17675, "Illegal string found where the keyword grant is expected."
14    ** 17676, "This may be a temporary object. Please execute procedure from your
15    **         temporary database."
16    ** 17677, "sp_helprotect [name [, username [, 'grant' [,'none'|'granted'|'enabled'|role_name [,permission_name]]]]]"
17    ** 17678, "Illegal role name '%1!' specified."
18    ** 18349, "@rolename = 'enabled' option is allowed only for the current user."
19    ** 18350, "An error was encountered in processing the group-level permissions."
20    ** 18351, "An error was encountered in processing the user-level permissions."
21    ** 18900, "Implicit grant to public for SQLJ functions."
22    ** 19610, "%1! is an invalid permission name."
23    */
24    create procedure sp_helprotect
25        @name varchar(767) = NULL, /* name of object or user to check */
26        @username varchar(255) = NULL, /* name of user to restrict check	*/
27        @option varchar(10) = NULL, /* keyword grant implies with grant option */
28        @rolename varchar(255) = NULL, /* the role to be taken into account when 
29        ** calculating the permissions. Can be set to
30        ** "granted", "enabled", "none" , NULL or a 
31        ** specific rolename
32        */
33        @permission_name varchar(30) = NULL /* name of permission to
34                                         ** restrict check
35                                         */
36    as
37    
38        declare @low int /* range of userids to check */
39        declare @high int
40        declare @olow int /* range of objectids to check */
41        declare @ohigh int
42        declare @invalid_uid int
43        declare @objid int /* id of @name if object */
44        declare @msg varchar(1024)
45        declare @msg_true varchar(9) /* msg for "true" equivalent */
46        declare @msg_false varchar(9) /* msg for "false" equivalent */
47        declare @is_user int /* whether name specified is a username */
48        declare @user_suid int /* user's suid if a username is 
49        ** specified 
50        */
51        declare @attr_udr_class int /* value of UDR_CLASS in sysattributes */
52        declare @attr_udr_role_hierarchy int /* value of attribute in sysattributes
53        ** for rows corresponding to role 
54        ** hierarchy
55        */
56        declare @cur_id int /* for holding object_id from cursor fetch */
57        declare @cur_uid int /* for holding uid from cursor fetch */
58        declare @cur_action smallint /* for holding action from cursor fetch */
59        declare @cur_protype tinyint /* for holding protection type from fetch */
60        declare @cur_grantor int /* for holding grantor from cursor fetch */
61        declare @cur_number int /* for holding column number from cursor fetch*/
62        declare @group_name varchar(255) /* group that the user belongs to */
63        declare @tmpstr varchar(255) /* rolename */
64        declare @rolelist varchar(255) /* list of roles from show_role() */
65        declare @maxsysrolenum int
66        declare @permission_number int
67        declare @cmd varchar(3000)
68        declare @dbcc_action int
69        declare @lowercase_permission_name varchar(30)
70    
71        if @@trancount = 0
72        begin
73            set chained off
74        end
75    
76        set transaction isolation level 1
77        select @attr_udr_class = class
78        from master.dbo.sysattributes
79        where object_type = "UR"
80    
81        select @maxsysrolenum = 31
82    
83        select @attr_udr_role_hierarchy = 2
84        select @is_user = 0
85        select @permission_number = 0
86        /*
87        ** dbcc_action used to distinguish between actions
88        ** that use pseudo object ids
89        */
90        select @dbcc_action = 317
91    
92        /*
93        **  Check to see that the object names are local to the current database.
94        */
95        if @name like "%.%.%" and
96            substring(@name, 1, charindex(".", @name) - 1) != db_name()
97        begin
98            /* 17460, "Object must be in the current database." */
99            raiserror 17460
100           return (1)
101       end
102   
103       /*  If this is a temporary table; object does not belong to 
104       **  this database; (we should be in our temporary database)
105       */
106       if (@name like "#%" and db_name() != db_name(tempdb_id()))
107       begin
108           /* 
109           ** 17676, "This may be a temporary object. Please execute 
110           ** procedure from your temporary database."
111           */
112           raiserror 17676
113           return (1)
114       end
115   
116       /*
117       ** Check if the grant keyword is correct
118       */
119       if (@option is not null and lower(@option) != "grant")
120       begin
121           /*
122           ** 17675, "Illegal string found where the keyword grant is expected."
123           */
124           raiserror 17675
125           return (1)
126       end
127   
128       /* Trim blanks for rolename */
129       select @tmpstr = lower(ltrim(rtrim(@rolename)))
130   
131       /*
132       ** Check if the rolename parameter is correct
133       */
134       if (@rolename is not NULL) and
135           (@tmpstr != "granted") and
136           (@tmpstr != "enabled") and
137           (@tmpstr != "none") and
138           (role_id(@rolename) is NULL)
139       begin
140           /*
141           ** 17678, "Illegal rolename '%1!' specified"
142           */
143           raiserror 17678, @rolename
144           return (1)
145       end
146   
147   
148   
149       /*
150       **  Initialize the range of user ids to check.  We will either check all
151       **  users (the initial values) or just one in particular (@low = @high)
152       **  NOTE: @low has been set to @@minuserid - 1 because the valid uid range is 
153       **  @@minuserid to @@maxuserid.  
154       **  For objects set the range from -MAXINT to MAXINT. There are no
155       **  global variables in the server to represent that, so use @@maxuserid.
156       */
157       select @invalid_uid = @@minuserid - 1 /* uid outside -ve range */
158   
159       select @low = @invalid_uid, @high = @@maxuserid
160   
161       /*
162       ** Initialize the range of object ids to include. There are
163       ** some special negative object ids (such as the object id which
164       ** represents execution of a DBCC command), so the range extends
165       ** across the entire set of +ve and -ve integer values.
166       */
167       select @olow = - @@maxuserid, @ohigh = @@maxuserid
168   
169   
170       /*
171       **  There are two cases handled by this procedure.  If the first parameter
172       **  is an object (table, view, procedure) then @name is taken as an object
173       **  name and the procedure will figure out permissions for the object.
174       **
175       **  If the first parameter is not one of the objects mentioned it will be
176       **  taken as user name and all the permissions for the user or group name
177       **  will be shown.
178       */
179   
180       if @name is not NULL
181       begin
182   
183           /*
184           **  Check to see if it's an object.
185           */
186           if exists (select *
187                   from sysobjects
188                   where id = object_id(@name)
189                       and (sysstat & 15 = 1 /* system table */
190                           or sysstat & 15 = 2 /* view */
191                           or sysstat & 15 = 3 /* user table */
192                           or sysstat & 15 = 4 /* procedure */
193                           or sysstat & 15 = 10 /* SQL UDF */
194                           or sysstat & 15 = 15)) /* encryption key */
195           begin
196               /*
197               **  Set @olow and @ohigh so the search will be restricted to
198               **  a particular object.
199               */
200               select @olow = id, @ohigh = id
201               from sysobjects
202               where id = object_id(@name)
203           end
204   
205           /* If this is a sqlj function then advise the user that the 
206           ** permission is implicitly public.
207           */
208           else if exists (select *
209                   from sysobjects
210                   where id = object_id(@name)
211                       and sysstat & 15 = 12) /*sqlj function*/
212           begin
213               /*
214               ** 18900, "Implicit grant to public for SQLJ functions."
215               */
216               execute sp_getmessage 18900, @msg output
217               print @msg
218               return (1)
219           end
220   
221           else
222           begin
223               /*
224               **  Since @name is not an object let's try it as a user.
225               */
226   
227               /*
228               **  Set @low and @high so the search will be restricted to
229               **  a particular user.
230               */
231               select @low = uid, @high = uid from sysusers
232               where name = @name
233               /*
234               **  Now check if it is a role.
235               **  If not, then return.
236               */
237               if (role_id(@name) is not NULL)
238               begin
239                   /*
240                   ** It is possible the role does not
241                   ** exist in sysusers yet. Setting @high to 
242                   ** @invalid_uid will restrict the search
243                   ** in sysusers to zero rows.
244                   */
245                   if (@low = @invalid_uid)
246                   begin
247                       select @high = @low
248                   end
249   
250                   /* Assume it is only a role */
251                   select @rolename = @name
252                   select @name = NULL
253                   select @username = NULL
254                   select @option = NULL
255               end
256   
257               else if (@low = @invalid_uid)
258               begin
259                   /*
260                   ** 17674, "No such object or user exists in the 
261                   ** database."
262                   */
263                   raiserror 17674
264                   return (1)
265               end
266           end
267       end
268   
269       if @username is not NULL
270       begin
271           /* Re-initialize @low to validate @username */
272           select @low = @invalid_uid
273   
274           select @low = uid from sysusers where name = @username
275           /*
276           **  @username isn't valid.
277           */
278           if @low = @invalid_uid
279           begin
280               /* 17232, "No user with the specified name exists in the current database." */
281               raiserror 17232
282               return (1)
283           end
284           else
285           begin
286               /*
287               ** If we already have a userid in @high, then they
288               ** specified a user in @name as well.  The two
289               ** had better be the same.
290               */
291               if @high != @@maxuserid
292               begin
293                   if @low != @high
294                   begin
295                       /* 
296                       ** 17677, "sp_helprotect [name [, username
297                       ** [, 'grant' [,'none'|'granted'|'enabled'|
298                       ** role_name [,permission_name]]]]]"
299                       */
300                       raiserror 17677
301                       return (1)
302                   end
303               end
304               else
305               begin
306                   select @high = @low
307               end
308           end
309       end
310   
311       if @permission_name is not NULL
312       begin
313           select @lowercase_permission_name = lower(@permission_name)
314           if exists (select * from master.dbo.spt_values
315                   where lower(name) = @lowercase_permission_name and type = "T")
316           begin
317               select @permission_number = number from master.dbo.spt_values
318               where lower(name) = @lowercase_permission_name and type = "T"
319           end
320           else
321           begin
322               /*
323               ** 19610, "%1! is an invalid permission name."
324               */
325               raiserror 19610, @permission_name
326               return (1)
327           end
328       end
329   
330       /* 
331       ** Check if this is for a specific user, role or group. If this is for a 
332       ** specific user, @high will be set to uid of that user instead of @@maxuserid.
333       */
334       if @high != @@maxuserid
335       begin
336   
337           /* check if this is for a specific user */
338           if exists (select * from sysusers where uid = @high and uid != gid)
339           begin
340               select @is_user = 1
341               select @user_suid = suid from sysusers where uid = @high
342           end
343           else
344               select @is_user = 0
345       end
346   
347       set nocount on
348   
349       create table #sysprotects1(id int, uid int, action smallint,
350           protecttype tinyint, grantor int, number int)
351   
352       create table #sysprotects2(id int, col_count int)
353   
354       insert into #sysprotects2(id, col_count)
355       select id, count(*) from syscolumns group by id
356   
357       /*
358       ** If the permissions are asked for a user, the logic below takes 
359       ** the roles and groups also into account when calculating the permissions.
360       ** The way the roles are to be taken into account depends on the value of
361       ** the rolename parameter which can have following different values:
362       ** 	rolename = "none" - roles are completly ignored
363       **	rolename = "granted"  - all roles granted to the user are taken into account
364       **	rolename = "enabled" - only enabled roles are taken into account -
365       **				this works only for the current user.
366       **	rolename =  - only the specified role is taken into account
367       **
368       ** As far as the groups are concerned, the group's permissions are always 
369       ** taken into account when computing the final permission.
370       **
371       ** The logic used to implement this is as follows:
372       **	part1 - get all the roles and groups that are to be considered 
373       **		for computing the permissions for the user.
374       **	part2 - compute the permissions for all the roles and put them in
375       **		one table, compute the permissions for all the groups and
376       **		put them in another table and compute the permissions for
377       **		the individual user itself and put them in yet another table.
378       **	part3 - Compute the effective permissions for the user using the
379       **		permissions table created for the roles, groups and the user.
380       */
381   
382       if (@is_user = 1)
383       begin
384           /* to compute the individual user's permissions, the roles possessed
385           ** by the user and the groups that the user belongs to must also be
386           ** taken into account.
387           */
388   
389           /*
390           ** Part 1: get all the roles and groups that are to be considered
391           ** for computing the permissions for the user.
392           */
393   
394           create table #rolenames(name varchar(255))
395   
396           /*
397           ** step1: parse the rolenames parameter
398           */
399   
400           /*
401           ** allow rolename = "enabled" only for current user
402           */
403           if (@rolename = "enabled" and @user_suid != suser_id())
404           begin
405               /*
406               ** 18349, "@rolename = 'enabled' option is allowed only for 
407               ** the current user."
408               */
409               raiserror 18349
410               return (1)
411           end
412   
413           /*
414           ** set the rolename parameter appropriately if not specified
415           */
416           if (@rolename is NULL)
417           begin
418               /*
419               ** for current user the default corresponds to all 
420               ** enabled roles, wheras for other user the default 
421               ** corresponds to all granted roles
422               */
423               if (@user_suid = suser_id())
424                   select @rolename = "enabled"
425               else
426                   select @rolename = "granted"
427           end
428   
429           /*
430           ** since role hierarchies are to be flattened at this point,
431           ** first create an intermediate temporary table to hold all 
432           ** the first-level roles 
433           */
434           create table #intmdt_role_set(name varchar(255))
435           /*
436           ** Create another table to store the list of granted user-defined
437           ** roles; we will call proc_role() on these.
438           */
439           create table #intmdt2_role_set(name varchar(255))
440           /*
441           ** step2: depending on the value of @rolename, populate 
442           ** the rolenames table
443           */
444           if (@rolename = "granted" or @rolename = "enabled")
445           begin
446   
447               /*
448               ** If the option is set to "enabled", put all the roles that
449               ** are currently granted to the user and enabled by the user
450               ** into the temporary table.
451               */
452               if (@rolename = "enabled")
453               begin
454                   /* Start by getting system roles */
455                   select @rolelist = show_role()
456                   insert into #intmdt_role_set
457                   select r.name from master.dbo.syssrvroles r,
458                       master.dbo.sysloginroles l
459                   where l.suid = @user_suid
460                       and l.srid = r.srid
461                       and charindex(r.name, @rolelist) > 0
462                   /*
463                   ** Get the user-defined roles for this user.  We will
464                   ** then call proc_role() on these to determine which
465                   ** are active.
466                   */
467                   insert into #intmdt2_role_set
468                   select r.name from master.dbo.syssrvroles r,
469                       master.dbo.sysloginroles l
470                   where l.suid = @user_suid
471                       and l.srid = r.srid
472                       and r.srid > @maxsysrolenum
473                   /*
474                   ** Now do the call to proc_role() to insert active
475                   ** user-defined roles into #intmdt_role_set
476                   */
477                   insert into #intmdt_role_set
478                   select i.name from #intmdt2_role_set i
479                   where proc_role(i.name) = 1
480               end
481               /*
482               ** Otherwise, put all the roles that are granted to the 
483               ** user into the temporary table
484               */
485               else
486                   insert into #intmdt_role_set
487                   select r.name from master.dbo.syssrvroles r,
488                       master.dbo.sysloginroles l
489                   where l.suid = @user_suid
490                       and l.srid = r.srid
491   
492           end
493           else if @rolename != "none"
494           begin
495               /* The rolename parameter refers to a specific role */
496               insert into #intmdt_role_set values (@rolename)
497           end
498   
499           /* expand the rolenames table if required */
500           if exists (select * from #intmdt_role_set)
501           begin
502               /*
503               ** to be able to expand the first-level role set into 
504               ** the expanded role set, we need two more temporary tables
505               */
506               create table #cum_role_set(name varchar(255))
507               create table #temp_role_set(name varchar(255))
508   
509               /*
510               ** The following while loop does the flattening of the role
511               ** hierarchy tree corresponding to the first level roles
512               ** contained in #indmdt_role_set. The processing in the loop
513               ** goes as follows:
514               **
515               ** the start conditions are:
516               **	#intmdt_role_set contains the base set of roles
517               ** 	#cum_role_set is empty
518               **	#temp_role_set is empty
519               ** the loop processing is:
520               **	- select the roles that are contained by the roles
521               **	  in #intmdt_role_set and put them in #temp_role_set.
522               **	- copy roles from #intmdt_role_set into #cum_role_set
523               **	  if they are not already there in #cum_role_set.
524               **	- move roles from #temp_role_set into #intmdt_role_set.
525               ** the loop exit condition is:
526               **	#intmdt_role_set becomes empty.
527               **	at that point, #cum_role_set contains the expanded
528               **	list of roles
529               */
530   
531               while exists (select * from #intmdt_role_set)
532               begin
533                   /*
534                   ** select the roles that are contained by the roles
535                   ** in #intmdt_role_set and put them in #temp_role_set.
536                   ** Note that for the role-hierarchy type rows in
537                   ** sysattributes, the object field contains the roleid
538                   ** of the parent role and the object_info1 field 
539                   ** contains the roleid of the child role.
540                   */
541                   insert into #temp_role_set
542                   select role_name(object_info1)
543                   from master.dbo.sysattributes a,
544                       #intmdt_role_set b
545                   where a.class = @attr_udr_class
546                       and a.attribute = @attr_udr_role_hierarchy
547                       and a.object = role_id(b.name)
548   
549                   /* copy from #intmdt_role_set to #cum_role_set */
550                   /* Adaptive Server has expanded all '*' elements in the following statement */ insert into #cum_role_set
551                   select #intmdt_role_set.name from #intmdt_role_set
552                   where name not in (select name from #cum_role_set)
553   
554                   delete from #intmdt_role_set
555   
556                   /* copy from #temp_role_set to #intmdt_role_set */
557                   /* Adaptive Server has expanded all '*' elements in the following statement */ insert into #intmdt_role_set
558                   select #temp_role_set.name from #temp_role_set
559   
560                   delete from #temp_role_set
561               end
562   
563               /* 
564               ** At this point, the completly flattened role set is in
565               ** #cum_role_set - copy them over to #rolenames
566               */
567               insert into #rolenames select distinct name
568               from #cum_role_set
569           end
570   
571           /*
572           ** step3: populate the @groupnames table
573           */
574   
575           /*
576           ** create the #groupnames table
577           */
578           create table #groupnames(name varchar(255))
579   
580           /* the user is always a member of the public group */
581           insert into #groupnames values ("public")
582   
583           /* if user belongs to any other group, insert that too */
584           select @group_name = user_name(gid) from sysusers
585           where suid = @user_suid
586           if @group_name is not null
587           begin
588               insert into #groupnames values (@group_name)
589           end
590   
591           /*
592           ** part 2 : Generate protection data for each kind of grantee
593           */
594   
595           /*
596           ** step 1: create three tables, one for each kind of grantee
597           */
598   
599           create table #role_permissions(id int, uid int, action smallint,
600               protecttype tinyint, grantor int, number int)
601   
602           create table #group_permissions(id int, uid int, action smallint,
603               protecttype tinyint, grantor int, number int)
604   
605           create table #user_permissions(id int, uid int, action smallint,
606               protecttype tinyint, grantor int, number int)
607   
608           /*
609           ** step 2: Generate the permission information for each of the
610           ** roles contained in the #roles table
611           */
612   
613           insert into #role_permissions(id, uid, action, protecttype, grantor, number)
614           select distinct
615               p.id, p.uid, p.action, p.protecttype, p.grantor, c.number
616           from sysprotects p, master.dbo.spt_values c
617           where convert(tinyint, substring(isnull(p.columns, 0x1), c.low, 1))
618               & c.high != 0
619               and c.type = "P" and c.number <= 1024
620               and p.uid in (select user_id(name) from #rolenames)
621               and p.id between @olow and @ohigh
622           /*
623           ** step 3: Generate permission information for each of the groups
624           ** present in #groupnames table
625           */
626           insert into #group_permissions(id, uid, action, protecttype, grantor, number)
627           select distinct
628               p.id, p.uid, p.action, p.protecttype, p.grantor, c.number
629           from sysprotects p, master.dbo.spt_values c
630           where convert(tinyint, substring(isnull(p.columns, 0x1), c.low, 1))
631               & c.high != 0
632               and c.type = "P" and c.number <= 1024
633               and p.uid in (select user_id(name) from #groupnames)
634               and p.id between @olow and @ohigh
635   
636           /*
637           ** step 4 : Generate permission information for the user himself
638           */
639           insert into #user_permissions(id, uid, action, protecttype, grantor, number)
640           select distinct
641               p.id, p.uid, p.action, p.protecttype, p.grantor, c.number
642           from sysprotects p, master.dbo.spt_values c
643           where convert(tinyint, substring(isnull(p.columns, 0x1), c.low, 1))
644               & c.high != 0
645               and c.type = "P" and c.number <= 1024
646               and p.uid = @high
647               and p.id between @olow and @ohigh
648   
649           /*
650           ** part 3: Generate the final permission information
651           **
652           ** The logic for determining the final permissions for a user,
653           ** the logic that is also used inside the server to actually decide
654           ** whether to allow a particular access to a user or not, is as
655           ** follows:
656           **	if (there is a grant row found where the grantee is one
657           **	   of the roles possessed by the user)
658           **	then
659           **		the user has the access
660           **	else
661           **		if (there is a grant row found where the grantee is 
662           **		   the user himself)
663           **		then
664           **			the user has the access
665           **		else
666           **			if (there is a grant row found against the
667           **			    group that the user belongs to)
668           **					and
669           **			    (there is no revoke found against the
670           **			     user himself)
671           **			then
672           **				the user has the access
673           **			else
674           **				the user does not have the access
675           **			fi
676           **		fi
677           **	fi
678           **
679           **	Note that if the access applies at column level, the logic
680           **	needs to be applied to each column of the object
681           */
682   
683           /*
684           ** step1: create a table to hold the final permission information
685           */
686           create table #final_permissions(id int, uid int, action smallint,
687               protecttype tinyint, grantor int, number int)
688   
689   
690           /*
691           ** step2: Select all rows from $role_permissions table and put them
692           ** in #final_permissions since the roles permissions override all
693           ** other permissions.
694           */
695           /* Adaptive Server has expanded all '*' elements in the following statement */ insert into #final_permissions select #role_permissions.id, #role_permissions.uid, #role_permissions.action, #role_permissions.protecttype, #role_permissions.grantor, #role_permissions.number from #role_permissions
696   
697           /*
698           ** step3 : Select all grant (or grant_w_grant) rows from the user's
699           ** permissions table and put them in #final_permissions table since 
700           ** we know that there cannot be any revokes against roles (which can
701           ** override these grants), and user's permissions overrides the
702           ** group's permissions
703           */
704           /* Adaptive Server has expanded all '*' elements in the following statement */ insert into #final_permissions select #user_permissions.id, #user_permissions.uid, #user_permissions.action, #user_permissions.protecttype, #user_permissions.grantor, #user_permissions.number from #user_permissions
705           where protecttype = 0 or protecttype = 1
706   
707           /*
708           ** step 4: process rows in #group_permissions table
709           */
710   
711           declare group_cursor cursor for select id, uid, action,
712               protecttype, grantor, number from #group_permissions
713           where protecttype = 0 or protecttype = 1
714   
715           open group_cursor
716   
717           fetch group_cursor into @cur_id, @cur_uid, @cur_action,
718               @cur_protype, @cur_grantor, @cur_number
719   
720           while (@@sqlstatus = 0)
721           begin
722               /* if the row is for non-column level object */
723               if not exists (select id from #sysprotects2 where id = @cur_id)
724               begin
725                   /* if no revoke found in #user_permissions */
726                   if not exists (select * from #user_permissions
727                           where (id = @cur_id)
728                               and (action = @cur_action)
729                               and (protecttype = 2))
730                   begin
731                       insert into #final_permissions values (
732                           @cur_id, @cur_uid, @cur_action,
733                           @cur_protype, @cur_grantor, @cur_number)
734                   end
735               end
736   
737               else
738               /* if the object is a column level object */
739               begin
740                   /* If all permission has been granted to the group 
741                   ** and some permissions have been revoked from the
742                   ** user
743                   */
744                   if (col_name(@cur_id, @cur_number) is null
745                           and exists (select * from #user_permissions
746                               where id = @cur_id
747                                   and action = @cur_action
748                                   and protecttype = 2
749                                   and col_name(@cur_id, number) is not null))
750                   begin
751                       /* 
752                       ** for each column of the object for which 
753                       ** there is no revoke row in #user_permission
754                       ** insert a grant row in #final_permissions
755                       */
756                       insert into #final_permissions
757                       select @cur_id, @cur_uid, @cur_action,
758                           @cur_protype, @cur_grantor, c.number
759                       from master.dbo.spt_values c, #sysprotects2 p
760                       where (c.type = "P")
761                           and (c.number <= p.col_count)
762                           and (c.number > 0)
763                           and (p.id = @cur_id)
764                           and c.number not in (select number from
765                                   #user_permissions u where
766                                   (u.id = @cur_id)
767                                   and (u.action = @cur_action)
768                                   and (u.protecttype = 2))
769                   end
770                   /* otherwise, the current row fetched by the cursor
771                   ** is for a specific column - insert the current row in 
772                   ** #final_permissions if there is no revoke for
773                   ** the specified column in #user_permissions
774                   */
775                   else
776                   begin
777                       if not exists (select * from #user_permissions
778                               where id = @cur_id
779                                   and action = @cur_action
780                                   and ((number = @cur_number) or
781                                       col_name(@cur_id, number) is null)
782                                   and protecttype = 2)
783                       begin
784                           insert into #final_permissions values (
785                               @cur_id, @cur_uid, @cur_action,
786                               @cur_protype, @cur_grantor, @cur_number)
787                       end
788                   end
789               end /* end of processing for column-level objects */
790   
791               fetch group_cursor into @cur_id, @cur_uid, @cur_action,
792                   @cur_protype, @cur_grantor, @cur_number
793   
794           end /* of while sqlstatus = 0 */
795   
796           if (@@sqlstatus = 1)
797           begin
798               /*
799               ** 18350, "An error was encountered in processing 
800               ** the group-level permissions."
801               */
802               execute sp_getmessage 18350, @msg output
803               print @msg
804               return (1)
805           end
806   
807           close group_cursor
808   
809           deallocate cursor group_cursor
810   
811           /*
812           ** step 5: process revoke rows in #user_permissions table
813           */
814   
815   
816           declare user_cursor cursor for select id, uid, action,
817               protecttype, grantor, number from #user_permissions
818           where protecttype = 2
819   
820           open user_cursor
821   
822           fetch user_cursor into @cur_id, @cur_uid, @cur_action,
823               @cur_protype, @cur_grantor, @cur_number
824   
825           while (@@sqlstatus = 0)
826           begin
827               /* if the row is for non-column level object */
828               if not exists (select id from #sysprotects2 where id = @cur_id)
829               begin
830                   /* if no grant found in #role_permissions */
831                   if not exists (select * from #role_permissions
832                           where (id = @cur_id)
833                               and (action = @cur_action)
834                               and (protecttype = 0 or protecttype = 1))
835                   begin
836                       insert into #final_permissions values (
837                           @cur_id, @cur_uid, @cur_action,
838                           @cur_protype, @cur_grantor, @cur_number)
839                   end
840               end
841   
842               /* the object is a column level object */
843               else
844               begin
845                   /* 
846                   ** If permission on all columns have been revoked 
847                   ** from the user and if some permissions have been
848                   ** granted to any of the roles
849                   */
850                   if (col_name(@cur_id, @cur_number) is null
851                           and exists (select * from #role_permissions
852                               where id = @cur_id
853                                   and action = @cur_action
854                                   and (protecttype = 0 or protecttype = 1)
855                                   and col_name(@cur_id, number) is not null))
856                   begin
857                       /* 
858                       ** for each column of the object for which 
859                       ** there is no grant row in #role_permission
860                       ** insert a revoke row in #final_permissions
861                       */
862                       insert into #final_permissions
863                       select @cur_id, @cur_uid, @cur_action,
864                           @cur_protype, @cur_grantor, c.number
865                       from master.dbo.spt_values c, #sysprotects2 p
866                       where (c.type = "P")
867                           and (c.number <= p.col_count)
868                           and (c.number > 0)
869                           and (p.id = @cur_id)
870                           and c.number not in (select number from
871                                   #role_permissions u where
872                                   (u.id = @cur_id)
873                                   and (u.action = @cur_action)
874                                   and (u.protecttype = 1 or
875                                       u.protecttype = 0))
876                   end
877                   /* otherwise, the current row fetched by the cursor
878                   ** is for a specific column - insert the current row in 
879                   ** #final_permissions if there is no grant for
880                   ** the specified column in #role_permissions
881                   */
882                   else
883                   begin
884                       if not exists (select * from #role_permissions
885                               where id = @cur_id
886                                   and action = @cur_action
887                                   and ((number = @cur_number) or
888                                       col_name(@cur_id, number) is null)
889                                   and protecttype = 1 or protecttype = 0)
890                       begin
891                           insert into #final_permissions values (
892                               @cur_id, @cur_uid, @cur_action,
893                               @cur_protype, @cur_grantor, @cur_number)
894                       end
895                   end /* end of else for if(col_name(...)) is null */
896               end /* end of else for if(column-level object) */
897   
898               fetch user_cursor into @cur_id, @cur_uid, @cur_action,
899                   @cur_protype, @cur_grantor, @cur_number
900   
901           end /* end of while */
902   
903   
904           if (@@sqlstatus = 1)
905           begin
906               /*
907               ** 18351, "An error was encountered in processing 
908               ** the user-level permissions."
909               */
910               execute sp_getmessage 18351, @msg output
911               print @msg
912               return (1)
913           end
914   
915           close user_cursor
916   
917           deallocate cursor user_cursor
918   
919           if @permission_number != 0
920           begin
921               /* Adaptive Server has expanded all '*' elements in the following statement */ insert into #sysprotects1 select #final_permissions.id, #final_permissions.uid, #final_permissions.action, #final_permissions.protecttype, #final_permissions.grantor, #final_permissions.number from #final_permissions
922               where action = @permission_number
923           end
924           else
925           begin
926               /* Adaptive Server has expanded all '*' elements in the following statement */ insert into #sysprotects1 select #final_permissions.id, #final_permissions.uid, #final_permissions.action, #final_permissions.protecttype, #final_permissions.grantor, #final_permissions.number from #final_permissions
927           end
928   
929       end /* end of @is_user = 1 */
930       else
931       begin
932           select @cmd = "insert into #sysprotects1 (id, uid, action, 
933   	protecttype, grantor, number)
934   	select distinct
935   		p.id, p.uid, p.action, p.protecttype,
936   		p.grantor, c.number
937   		from sysprotects p, master.dbo.spt_values c
938   		where (~isnull (convert(tinyint, substring(p.columns, c.low, 1)), 0) & c.high != 0
939   			and c.number <= (select col_count from #sysprotects2 where id = p.id))
940   			and c.type = 'P'
941   			and c.number <= 1024
942   			and p.columns is not null
943   			and convert(tinyint, substring(p.columns, 1, 1)) & 0x1 != 0
944   			and (convert(tinyint, substring(p.columns, 1, 1)) & 0xfe != 0
945   				or substring(p.columns, 2, 1) is not null)
946   			and p.id between @olow and @ohigh
947   			and p.uid between @low and @high"
948           if @permission_number != 0
949               select @cmd = @cmd + " and p.action = @permission_number"
950           exec (@cmd)
951   
952           select @cmd = "insert into #sysprotects1 (id, uid, action, 
953   	protecttype, grantor, number)
954   	select distinct
955   		p.id, p.uid, p.action, p.protecttype,
956   		p.grantor, c.number
957   		from sysprotects p, master.dbo.spt_values c
958   		where convert(tinyint, substring(isnull(p.columns, 0x1), c.low, 1))
959   			& c.high != 0
960   			and c.type = 'P'
961   			and c.number <= 1024
962   			and (p.columns is null
963   				or convert(tinyint, substring(p.columns, 1, 1)) & 0x1 = 0
964   				or (convert(tinyint, substring(p.columns, 1, 1)) & 0xfe = 0
965   					and substring(p.columns, 2, 1) is null))
966   			and p.id between @olow and @ohigh
967   			and p.uid between @low and @high"
968           if @permission_number != 0
969               select @cmd = @cmd + " and p.action = @permission_number"
970           exec (@cmd)
971       end
972   
973       /*
974       ** 17431, "true"
975       ** 17432, "false"
976       */
977       exec sp_getmessage 17431, @msg_true output
978       exec sp_getmessage 17432, @msg_false output
979   
980       /* 17673, "All" */
981       exec sp_getmessage 17673, @msg out
982   
983       /* Collect the information about object name */
984       create table #temp_obj(id int, number int, objname varchar(30))
985       /* 
986       ** The population of #temp is split into two queries to reduce the joins in 
987       ** each query in order to improve performance.
988       */
989       insert into #temp_obj
990       select distinct p.id, p.number, o.name
991       from #sysprotects1 p, sysobjects o
992       where p.id = o.id
993   
994       /* 
995       ** #temp populates valid column names for valid column IDs. 
996       ** There exist pad columns in some system tables which do not appear
997       ** in syscolumns. The #temp_obj table is populated with rows from these columns 
998       ** IDs through #sysprotects1. These rows are removed in #temp.
999       ** 
1000      */
1001      create table #temp(id int, number int, objname varchar(30), colname varchar(30) null)
1002      insert into #temp
1003      select t.id, t.number, t.objname, c.name
1004      from #temp_obj t, syscolumns c
1005      where t.number = c.colid and t.id = c.id
1006      union
1007      select t.id, t.number, t.objname, null
1008      from #temp_obj t
1009      where t.number = 0
1010  
1011      /*
1012      ** #temp is empty if the only granted permissions in sysprotects are
1013      ** non-object permissions, or permissions on dbcc commands or builtins.
1014      ** Insert a dummy row in #temp if empty. This is needed because #temp is
1015      ** used in a natural join with #sysprotects1 to display the final permissions
1016      ** output.
1017      */
1018      if not exists (select 1 from #temp)
1019      begin
1020          insert into #temp values (0, 0, "dummy", "dummy")
1021      end
1022  
1023      if @option is NULL
1024      begin
1025          /*
1026          ** print all the privileges
1027          ** on normal columns. 
1028          ** If there is no valid column name for 
1029          ** a record in the #sysprotects1 p table
1030          ** and p.number=0, that means privilege is 
1031          ** granted to all columns
1032          ** For spt_values.name like 'Create Table', 'Create Rule', ....,
1033          ** there is no object in sysobjects table. #sysprotects1 p has
1034          ** p.id = 0 and p.number = 0 for them. Pseduo objects such as 
1035          ** DBCC commands have a negative object ID.
1036          */
1037  
1038  
1039          begin
1040              select distinct
1041                  grantor = user_name(p.grantor),
1042                  grantee = user_name(p.uid),
1043                  type = substring(b.name, 1, 8),
1044                  action = case
1045                      when (p.id < 0 and p.action = @dbcc_action)
1046                      then col_name(p.id, p.number)
1047                      else a.name
1048                  end,
1049                  object = case
1050                      when ((p.id < 0 and p.action = @dbcc_action)
1051                              or p.id = 0)
1052                      then ""
1053                      when (p.id < 0 and p.action <> @dbcc_action)
1054                      then col_name(p.id, p.number)
1055                      else t.objname
1056                  end,
1057                  column = case
1058                      when ((p.number = 0) and (p.id >= 0)) then @msg
1059                      when (p.id < 0) then ""
1060                      else t.colname
1061                  end,
1062                  grantable = upper(@msg_false)
1063              into #sphelprotect1rs
1064              from #sysprotects1 p, master.dbo.spt_values a,
1065                  master.dbo.spt_values b, #temp t
1066              where a.type = "T"
1067                  and a.number = p.action
1068                  and b.type = "T"
1069                  and b.number = (p.protecttype + 204)
1070                  and ((p.id = 0 and p.number = 0)
1071                      or (p.id = t.id and p.number = t.number)
1072                      or (p.id < 0))
1073  
1074              union
1075  
1076              select distinct
1077                  grantor = user_name(p.grantor),
1078                  grantee = user_name(p.uid),
1079                  type = substring(b.name, 1, 8),
1080                  action = case
1081                      when (p.id < 0
1082                              and p.action = @dbcc_action)
1083                      then col_name(p.id, p.number)
1084                      else a.name
1085                  end,
1086                  object = case
1087                      when ((p.id < 0
1088                                  and p.action = @dbcc_action)
1089                              or p.id = 0)
1090                      then ""
1091                      when (p.id < 0
1092                              and p.action <> @dbcc_action)
1093                      then col_name(p.id, p.number)
1094                      else t.objname
1095                  end,
1096                  column = case
1097                      when ((p.number = 0) and (p.id >= 0)) then @msg
1098                      when (p.id < 0) then ""
1099                      else t.colname
1100                  end,
1101                  grantable = upper(@msg_true)
1102              from #sysprotects1 p, master.dbo.spt_values a,
1103                  master.dbo.spt_values b, #temp t
1104              where a.type = "T"
1105                  and a.number = p.action
1106                  and b.type = "T"
1107                  and b.number = (p.protecttype + 205)
1108                  and p.protecttype = 0
1109                  and ((p.id = 0 and p.number = 0)
1110                      or (p.id = t.id and p.number = t.number)
1111                      or (p.id < 0))
1112  
1113              exec sp_autoformat @fulltabname = #sphelprotect1rs,
1114                  @orderby = "order by grantor, grantee, type, action, object, column"
1115              drop table #sphelprotect1rs
1116          end
1117      end
1118      else
1119      begin
1120  
1121          /*
1122          ** print only the grantable privileges
1123          */
1124  
1125          select distinct
1126              grantor = user_name(p.grantor),
1127              grantee = user_name(p.uid),
1128              type = substring(b.name, 1, 8),
1129              action = case
1130                  when (p.id < 0
1131                          and p.action = @dbcc_action)
1132                  then col_name(p.id, p.number)
1133                  else a.name
1134              end,
1135              object = case
1136                  when ((p.id < 0
1137                              and p.action = @dbcc_action)
1138                          or p.id = 0)
1139                  then ""
1140                  when (p.id < 0
1141                          and p.action <> @dbcc_action)
1142                  then col_name(p.id, p.number)
1143                  else t.objname
1144              end,
1145              column = case
1146                  when ((p.number = 0) and (p.id >= 0)) then @msg
1147                  when (p.id < 0) then ""
1148                  else t.colname
1149              end,
1150              grantable = upper(@msg_true)
1151          into #sphelprotect2rs
1152          from #sysprotects1 p, master.dbo.spt_values a,
1153              master.dbo.spt_values b, #temp t
1154          where a.type = "T"
1155              and a.number = p.action
1156              and b.type = "T"
1157              and b.number = (p.protecttype + 205)
1158              and p.protecttype = 0
1159              and ((p.id = 0 and p.number = 0)
1160                  or (p.id = t.id and p.number = t.number)
1161                  or (p.id < 0))
1162  
1163          exec sp_autoformat @fulltabname = #sphelprotect2rs,
1164              @orderby = "order by grantor, grantee, type, action, object, column"
1165          drop table #sphelprotect2rs
1166      end
1167      return (0)
1168  


exec sp_procxmode 'sp_helprotect', 'AnyMode'
go

Grant Execute on sp_helprotect to public
go
DEFECTS
 QJWI 5 Join or Sarg Without Index 617
 QJWI 5 Join or Sarg Without Index 630
 QJWI 5 Join or Sarg Without Index 643
 MEST 4 Empty String will be replaced by Single Space 1052
 MEST 4 Empty String will be replaced by Single Space 1059
 MEST 4 Empty String will be replaced by Single Space 1090
 MEST 4 Empty String will be replaced by Single Space 1098
 MEST 4 Empty String will be replaced by Single Space 1139
 MEST 4 Empty String will be replaced by Single Space 1147
 MINU 4 Unique Index with nullable columns master..sysattributes master..sysattributes
 MINU 4 Unique Index with nullable columns sybsystemprocs..sysprotects sybsystemprocs..sysprotects
 MTYP 4 Assignment type mismatch @rolename: varchar(255) = varchar(767) 251
 MTYP 4 Assignment type mismatch objname: varchar(30) = longsysname(255) 990
 MTYP 4 Assignment type mismatch colname: varchar(30) = longsysname(255) 1003
 MUSP 4 Unquoted String Parameter sybsystemprocs..sp_autoformat: @fulltabname 1113
 MUSP 4 Unquoted String Parameter sybsystemprocs..sp_autoformat: @fulltabname 1163
 QPUI 4 Join or Sarg with Un-Rooted Partial Index Use SARG Candidate index: sysattributes.csysattributes unique clustered
(class, attribute, object_type, object, object_info1, object_info2, object_info3, object_cinfo)
Intersection: {object_type}
79
 QPUI 4 Join or Sarg with Un-Rooted Partial Index Use SARG Candidate index: spt_values.spt_valuesclust clustered
(number, type)
Intersection: {type}
315
 QPUI 4 Join or Sarg with Un-Rooted Partial Index Use SARG Candidate index: spt_values.spt_valuesclust clustered
(number, type)
Intersection: {type}
318
 QPUI 4 Join or Sarg with Un-Rooted Partial Index Use SARG Candidate index: spt_values.spt_valuesclust clustered
(number, type)
Intersection: {type}
1066
 QPUI 4 Join or Sarg with Un-Rooted Partial Index Use SARG Candidate index: spt_values.spt_valuesclust clustered
(number, type)
Intersection: {type}
1068
 QPUI 4 Join or Sarg with Un-Rooted Partial Index Use SARG Candidate index: spt_values.spt_valuesclust clustered
(number, type)
Intersection: {type}
1104
 QPUI 4 Join or Sarg with Un-Rooted Partial Index Use SARG Candidate index: spt_values.spt_valuesclust clustered
(number, type)
Intersection: {type}
1106
 QPUI 4 Join or Sarg with Un-Rooted Partial Index Use SARG Candidate index: spt_values.spt_valuesclust clustered
(number, type)
Intersection: {type}
1154
 QPUI 4 Join or Sarg with Un-Rooted Partial Index Use SARG Candidate index: spt_values.spt_valuesclust clustered
(number, type)
Intersection: {type}
1156
 QTYP 4 Comparison type mismatch Comparison type mismatch: smallint vs int 545
 QTYP 4 Comparison type mismatch smallint = int 545
 QTYP 4 Comparison type mismatch Comparison type mismatch: smallint vs int 546
 QTYP 4 Comparison type mismatch smallint = int 546
 QTYP 4 Comparison type mismatch Comparison type mismatch: tinyint vs int 705
 QTYP 4 Comparison type mismatch Comparison type mismatch: tinyint vs int 713
 QTYP 4 Comparison type mismatch Comparison type mismatch: tinyint vs int 729
 QTYP 4 Comparison type mismatch Comparison type mismatch: tinyint vs int 748
 QTYP 4 Comparison type mismatch Comparison type mismatch: tinyint vs int 768
 QTYP 4 Comparison type mismatch Comparison type mismatch: tinyint vs int 782
 QTYP 4 Comparison type mismatch Comparison type mismatch: tinyint vs int 818
 QTYP 4 Comparison type mismatch Comparison type mismatch: tinyint vs int 834
 QTYP 4 Comparison type mismatch Comparison type mismatch: tinyint vs int 854
 QTYP 4 Comparison type mismatch Comparison type mismatch: tinyint vs int 874
 QTYP 4 Comparison type mismatch Comparison type mismatch: tinyint vs int 875
 QTYP 4 Comparison type mismatch Comparison type mismatch: tinyint vs int 889
 QTYP 4 Comparison type mismatch Comparison type mismatch: smallint vs int 922
 QTYP 4 Comparison type mismatch Comparison type mismatch: int vs smallint 1005
 QTYP 4 Comparison type mismatch Comparison type mismatch: smallint vs int 1045
 QTYP 4 Comparison type mismatch Comparison type mismatch: smallint vs int 1050
 QTYP 4 Comparison type mismatch Comparison type mismatch: smallint vs int 1053
 QTYP 4 Comparison type mismatch Comparison type mismatch: int vs smallint 1067
 QTYP 4 Comparison type mismatch Comparison type mismatch: smallint vs int 1082
 QTYP 4 Comparison type mismatch Comparison type mismatch: smallint vs int 1088
 QTYP 4 Comparison type mismatch Comparison type mismatch: smallint vs int 1092
 QTYP 4 Comparison type mismatch Comparison type mismatch: int vs smallint 1105
 QTYP 4 Comparison type mismatch Comparison type mismatch: tinyint vs int 1108
 QTYP 4 Comparison type mismatch Comparison type mismatch: smallint vs int 1131
 QTYP 4 Comparison type mismatch Comparison type mismatch: smallint vs int 1137
 QTYP 4 Comparison type mismatch Comparison type mismatch: smallint vs int 1141
 QTYP 4 Comparison type mismatch Comparison type mismatch: int vs smallint 1155
 QTYP 4 Comparison type mismatch Comparison type mismatch: tinyint vs int 1158
 TNOU 4 Table with no unique index master..spt_values master..spt_values
 TNOU 4 Table with no unique index master..sysloginroles master..sysloginroles
 CUNU 3 Cursor not updated: cursor should contain 'for read only' clause group_cursor 711
 CUNU 3 Cursor not updated: cursor should contain 'for read only' clause user_cursor 816
 MBLI 3 Integer Value of Binary Literal is Platform Dependant 617
 MBLI 3 Integer Value of Binary Literal is Platform Dependant 630
 MBLI 3 Integer Value of Binary Literal is Platform Dependant 643
 MDYN 3 Proc uses Dynamic SQL but is not flagged with Dynamic Ownership Chain 24
 MGTP 3 Grant to public master..spt_values  
 MGTP 3 Grant to public master..sysattributes  
 MGTP 3 Grant to public master..syssrvroles  
 MGTP 3 Grant to public sybsystemprocs..sp_helprotect  
 MGTP 3 Grant to public sybsystemprocs..syscolumns  
 MGTP 3 Grant to public sybsystemprocs..sysobjects  
 MGTP 3 Grant to public sybsystemprocs..sysprotects  
 MGTP 3 Grant to public sybsystemprocs..sysusers  
 MNEJ 3 'Not Equal' join 338
 MNER 3 No Error Check should check return value of exec 216
 MNER 3 No Error Check should check @@error after insert 354
 MNER 3 No Error Check should check @@error after insert 456
 MNER 3 No Error Check should check @@error after insert 467
 MNER 3 No Error Check should check @@error after insert 477
 MNER 3 No Error Check should check @@error after insert 486
 MNER 3 No Error Check should check @@error after insert 496
 MNER 3 No Error Check should check @@error after insert 541
 MNER 3 No Error Check should check @@error after insert 550
 MNER 3 No Error Check should check @@error after delete 554
 MNER 3 No Error Check should check @@error after insert 557
 MNER 3 No Error Check should check @@error after delete 560
 MNER 3 No Error Check should check @@error after insert 567
 MNER 3 No Error Check should check @@error after insert 581
 MNER 3 No Error Check should check @@error after insert 588
 MNER 3 No Error Check should check @@error after insert 613
 MNER 3 No Error Check should check @@error after insert 626
 MNER 3 No Error Check should check @@error after insert 639
 MNER 3 No Error Check should check @@error after insert 695
 MNER 3 No Error Check should check @@error after insert 704
 MNER 3 No Error Check should check @@error after insert 731
 MNER 3 No Error Check should check @@error after insert 756
 MNER 3 No Error Check should check @@error after insert 784
 MNER 3 No Error Check should check return value of exec 802
 MNER 3 No Error Check should check @@error after insert 836
 MNER 3 No Error Check should check @@error after insert 862
 MNER 3 No Error Check should check @@error after insert 891
 MNER 3 No Error Check should check return value of exec 910
 MNER 3 No Error Check should check @@error after insert 921
 MNER 3 No Error Check should check @@error after insert 926
 MNER 3 No Error Check should check return value of exec 977
 MNER 3 No Error Check should check return value of exec 978
 MNER 3 No Error Check should check return value of exec 981
 MNER 3 No Error Check should check @@error after insert 989
 MNER 3 No Error Check should check @@error after insert 1002
 MNER 3 No Error Check should check @@error after insert 1020
 MNER 3 No Error Check should check @@error after select into 1040
 MNER 3 No Error Check should check return value of exec 1113
 MNER 3 No Error Check should check @@error after select into 1125
 MNER 3 No Error Check should check return value of exec 1163
 MUCO 3 Useless Code Useless Brackets 100
 MUCO 3 Useless Code Useless Brackets 106
 MUCO 3 Useless Code Useless Brackets 113
 MUCO 3 Useless Code Useless Brackets 119
 MUCO 3 Useless Code Useless Brackets 125
 MUCO 3 Useless Code Useless Brackets 144
 MUCO 3 Useless Code Useless Brackets 218
 MUCO 3 Useless Code Useless Brackets 237
 MUCO 3 Useless Code Useless Brackets 245
 MUCO 3 Useless Code Useless Brackets 257
 MUCO 3 Useless Code Useless Brackets 264
 MUCO 3 Useless Code Useless Brackets 282
 MUCO 3 Useless Code Useless Brackets 301
 MUCO 3 Useless Code Useless Brackets 326
 MUCO 3 Useless Code Useless Brackets 382
 MUCO 3 Useless Code Useless Brackets 403
 MUCO 3 Useless Code Useless Brackets 410
 MUCO 3 Useless Code Useless Brackets 416
 MUCO 3 Useless Code Useless Brackets 423
 MUCO 3 Useless Code Useless Brackets 444
 MUCO 3 Useless Code Useless Brackets 452
 MUCO 3 Useless Code Useless Brackets 720
 MUCO 3 Useless Code Useless Brackets 744
 MUCO 3 Useless Code Useless Brackets 796
 MUCO 3 Useless Code Useless Brackets 804
 MUCO 3 Useless Code Useless Brackets 825
 MUCO 3 Useless Code Useless Brackets 850
 MUCO 3 Useless Code Useless Brackets 904
 MUCO 3 Useless Code Useless Brackets 912
 MUCO 3 Useless Code Useless Brackets 1045
 MUCO 3 Useless Code Useless Brackets 1050
 MUCO 3 Useless Code Useless Brackets 1053
 MUCO 3 Useless Code Useless Brackets 1058
 MUCO 3 Useless Code Useless Brackets 1059
 MUCO 3 Useless Code Useless Brackets 1081
 MUCO 3 Useless Code Useless Brackets 1087
 MUCO 3 Useless Code Useless Brackets 1091
 MUCO 3 Useless Code Useless Brackets 1097
 MUCO 3 Useless Code Useless Brackets 1098
 MUCO 3 Useless Code Useless Brackets 1130
 MUCO 3 Useless Code Useless Brackets 1136
 MUCO 3 Useless Code Useless Brackets 1140
 MUCO 3 Useless Code Useless Brackets 1146
 MUCO 3 Useless Code Useless Brackets 1147
 MUCO 3 Useless Code Useless Brackets 1167
 MUIN 3 Column created using implicit nullability 349
 MUIN 3 Column created using implicit nullability 352
 MUIN 3 Column created using implicit nullability 394
 MUIN 3 Column created using implicit nullability 434
 MUIN 3 Column created using implicit nullability 439
 MUIN 3 Column created using implicit nullability 506
 MUIN 3 Column created using implicit nullability 507
 MUIN 3 Column created using implicit nullability 578
 MUIN 3 Column created using implicit nullability 599
 MUIN 3 Column created using implicit nullability 602
 MUIN 3 Column created using implicit nullability 605
 MUIN 3 Column created using implicit nullability 686
 MUIN 3 Column created using implicit nullability 984
 MUIN 3 Column created using implicit nullability 1001
 QAFM 3 Var Assignment from potentially many rows 77
 QAFM 3 Var Assignment from potentially many rows 317
 QAFM 3 Var Assignment from potentially many rows 584
 QCTC 3 Conditional Table Creation 394
 QCTC 3 Conditional Table Creation 434
 QCTC 3 Conditional Table Creation 439
 QCTC 3 Conditional Table Creation 506
 QCTC 3 Conditional Table Creation 507
 QCTC 3 Conditional Table Creation 578
 QCTC 3 Conditional Table Creation 599
 QCTC 3 Conditional Table Creation 602
 QCTC 3 Conditional Table Creation 605
 QCTC 3 Conditional Table Creation 686
 QCTC 3 Conditional Table Creation 1040
 QCTC 3 Conditional Table Creation 1125
 QDIS 3 Check correct use of 'select distinct' 614
 QDIS 3 Check correct use of 'select distinct' 627
 QDIS 3 Check correct use of 'select distinct' 640
 QDIS 3 Check correct use of 'select distinct' 990
 QDIS 3 Check correct use of 'select distinct' 1040
 QDIS 3 Check correct use of 'select distinct' 1076
 QDIS 3 Check correct use of 'select distinct' 1125
 QGWO 3 Group by/Distinct/Union without order by 567
 QGWO 3 Group by/Distinct/Union without order by 614
 QGWO 3 Group by/Distinct/Union without order by 627
 QGWO 3 Group by/Distinct/Union without order by 640
 QGWO 3 Group by/Distinct/Union without order by 990
 QGWO 3 Group by/Distinct/Union without order by 1003
 QGWO 3 Group by/Distinct/Union without order by 1040
 QGWO 3 Group by/Distinct/Union without order by 1076
 QGWO 3 Group by/Distinct/Union without order by 1125
 QISO 3 Set isolation level 76
 QJWT 3 Join or Sarg Without Index on temp table 547
 QJWT 3 Join or Sarg Without Index on temp table 552
 QJWT 3 Join or Sarg Without Index on temp table 620
 QJWT 3 Join or Sarg Without Index on temp table 633
 QJWT 3 Join or Sarg Without Index on temp table 761
 QJWT 3 Join or Sarg Without Index on temp table 764
 QJWT 3 Join or Sarg Without Index on temp table 867
 QJWT 3 Join or Sarg Without Index on temp table 870
 QJWT 3 Join or Sarg Without Index on temp table 992
 QJWT 3 Join or Sarg Without Index on temp table 1005
 QJWT 3 Join or Sarg Without Index on temp table 1067
 QJWT 3 Join or Sarg Without Index on temp table 1069
 QJWT 3 Join or Sarg Without Index on temp table 1071
 QJWT 3 Join or Sarg Without Index on temp table 1105
 QJWT 3 Join or Sarg Without Index on temp table 1107
 QJWT 3 Join or Sarg Without Index on temp table 1110
 QJWT 3 Join or Sarg Without Index on temp table 1155
 QJWT 3 Join or Sarg Without Index on temp table 1157
 QJWT 3 Join or Sarg Without Index on temp table 1160
 QNAJ 3 Not using ANSI Inner Join 457
 QNAJ 3 Not using ANSI Inner Join 468
 QNAJ 3 Not using ANSI Inner Join 487
 QNAJ 3 Not using ANSI Inner Join 543
 QNAJ 3 Not using ANSI Inner Join 616
 QNAJ 3 Not using ANSI Inner Join 629
 QNAJ 3 Not using ANSI Inner Join 642
 QNAJ 3 Not using ANSI Inner Join 759
 QNAJ 3 Not using ANSI Inner Join 865
 QNAJ 3 Not using ANSI Inner Join 991
 QNAJ 3 Not using ANSI Inner Join 1004
 QNAJ 3 Not using ANSI Inner Join 1064
 QNAJ 3 Not using ANSI Inner Join 1102
 QNAJ 3 Not using ANSI Inner Join 1152
 QNUA 3 Should use Alias: Column object_info1 should use alias a 542
 QNUA 3 Should use Alias: Table #rolenames 620
 QNUA 3 Should use Alias: Table #groupnames 633
 QPRI 3 Join or Sarg with Rooted Partial Index Use SARG Candidate index: sysattributes.csysattributes unique clustered
(class, attribute, object_type, object, object_info1, object_info2, object_info3, object_cinfo)
Intersection: {class, attribute}
545
 QPRI 3 Join or Sarg with Rooted Partial Index Use SARG Candidate index: sysprotects.csysprotects unique clustered
(id, action, grantor, uid, protecttype)
Intersection: {id}
621
 QPRI 3 Join or Sarg with Rooted Partial Index Use SARG Candidate index: sysprotects.csysprotects unique clustered
(id, action, grantor, uid, protecttype)
Intersection: {id}
634
 QPRI 3 Join or Sarg with Rooted Partial Index Use SARG Candidate index: sysprotects.csysprotects unique clustered
(id, action, grantor, uid, protecttype)
Intersection: {uid, id}
646
 QSWV 3 Sarg with variable @lowercase_permission_name, Candidate Index: spt_values.spt_valuesclust clustered(number, type) U 315
 QSWV 3 Sarg with variable @lowercase_permission_name, Candidate Index: spt_values.spt_valuesclust clustered(number, type) U 318
 QSWV 3 Sarg with variable @user_suid, Candidate Index: sysloginroles.csysloginroles clustered(suid) F 459
 QSWV 3 Sarg with variable @user_suid, Candidate Index: sysloginroles.csysloginroles clustered(suid) F 470
 QSWV 3 Sarg with variable @maxsysrolenum, Candidate Index: syssrvroles.csyssrvroles unique clustered(srid) F 472
 QSWV 3 Sarg with variable @user_suid, Candidate Index: sysloginroles.csysloginroles clustered(suid) F 489
 QSWV 3 Sarg with variable @user_suid, Candidate Index: sysusers.csysusers clustered(suid) F 585
 QTJ1 3 Table only appears in inner join clause 544
 QTLO 3 Top-Level OR 705
 QTLO 3 Top-Level OR 713
 QTLO 3 Top-Level OR 885
 QUNI 3 Check Use of 'union' vs 'union all' 1003
 QUNI 3 Check Use of 'union' vs 'union all' 1040
 VNRD 3 Variable is not read @name 252
 VUNU 3 Variable is not used @objid 43
 CUPD 2 Updatable Cursor Marker (updatable by default) 711
 CUPD 2 Updatable Cursor Marker (updatable by default) 816
 MDYS 2 Dynamic SQL Marker 950
 MDYS 2 Dynamic SQL Marker 970
 MSUB 2 Subquery Marker 186
 MSUB 2 Subquery Marker 208
 MSUB 2 Subquery Marker 314
 MSUB 2 Subquery Marker 338
 MSUB 2 Subquery Marker 723
 MSUB 2 Subquery Marker 726
 MSUB 2 Subquery Marker 745
 MSUB 2 Subquery Marker 764
 MSUB 2 Subquery Marker 777
 MSUB 2 Subquery Marker 828
 MSUB 2 Subquery Marker 831
 MSUB 2 Subquery Marker 851
 MSUB 2 Subquery Marker 870
 MSUB 2 Subquery Marker 884
 MTR1 2 Metrics: Comments Ratio Comments: 43% 24
 MTR2 2 Metrics: Cyclomatic Complexity Cyclo: 119 = 130dec - 13exi + 2 24
 MTR3 2 Metrics: Query Complexity Complexity: 546 24
 PRED_QUERY_COLLECTION 2 {l=master..sysloginroles, s=master..syssrvroles} 0 457
 PRED_QUERY_COLLECTION 2 {l=master..sysloginroles, s=master..syssrvroles} 0 468
 PRED_QUERY_COLLECTION 2 {l=master..sysloginroles, s=master..syssrvroles} 0 487

DEPENDENCIES
PROCS AND TABLES USED
reads table master..spt_values (1)  
read_writes table tempdb..#sysprotects2 (1) 
read_writes table tempdb..#rolenames (1) 
read_writes table tempdb..#cum_role_set (1) 
read_writes table tempdb..#temp (1) 
read_writes table tempdb..#intmdt2_role_set (1) 
read_writes table tempdb..#role_permissions (1) 
read_writes table tempdb..#group_permissions (1) 
read_writes table tempdb..#groupnames (1) 
reads table master..sysattributes (1)  
read_writes table tempdb..#user_permissions (1) 
reads table sybsystemprocs..sysusers  
writes table tempdb..#sphelprotect1rs (1) 
reads table master..sysloginroles (1)  
reads table sybsystemprocs..sysprotects  
reads table master..syssrvroles (1)  
reads table sybsystemprocs..sysobjects  
reads table sybsystemprocs..syscolumns  
read_writes table tempdb..#sysprotects1 (1) 
calls proc sybsystemprocs..sp_autoformat  
   reads table master..systypes (1)  
   calls proc sybsystemprocs..sp_namecrack  
   calls proc sybsystemprocs..sp_autoformat  
   reads table tempdb..syscolumns (1)  
   reads table tempdb..systypes (1)  
   read_writes table tempdb..#colinfo_af (1) 
   reads table master..syscolumns (1)  
writes table tempdb..#sphelprotect2rs (1) 
read_writes table tempdb..#intmdt_role_set (1) 
calls proc sybsystemprocs..sp_getmessage  
   reads table master..syslanguages (1)  
   reads table master..sysmessages (1)  
   reads table sybsystemprocs..sysusermessages  
   calls proc sybsystemprocs..sp_validlang  
      reads table master..syslanguages (1)  
read_writes table tempdb..#final_permissions (1) 
read_writes table tempdb..#temp_role_set (1) 
read_writes table tempdb..#temp_obj (1)