/*
**	INSTCAT.SQL
**	Installs catalog stored procedures on the Microsoft SQL Server.
**	Copyright 1992-1995, Microsoft Corp.	All rights reserved.
*/

/*
NOTE:  you MUST change the last row inserted into spt_server_info
to be version number of this file.	the convention is j.nn.bbb, where
jj is the major version number ('6' now), nn is the minor version number
('00' now), and bbb is the build number.
*/

/****************************************************************************/
/* This portion sets up the ability to perform all the functions in this    */
/* script                                                                    */
/****************************************************************************/
use master
go
dump tran master with no_log
go

if exists (select * from sysobjects
	   where name = 'sp_configure' and sysstat & 0xf = 4)
begin
    execute sp_configure 'update',1
end
reconfigure with override
go

/*
** If old versions of tables exist, drop them.
*/
if (exists (select * from sysobjects
		where name = 'MSdatatype_info' and sysstat & 0xf = 3))
    drop table MSdatatype_info
go
if (exists (select * from sysobjects
		where name = 'MSdatatype_info_ext' and sysstat & 0xf = 3))
    drop table MSdatatype_info_ext
go
if (exists (select * from sysobjects
		where name = 'MStable_types' and sysstat & 0xf = 3))
    drop table MStable_types
go
if (exists (select * from sysobjects
		where name = 'MSserver_info' and sysstat & 0xf = 3))
    drop table MSserver_info
go
if (exists (select * from sysobjects
		where name = 'spt_table_types' and sysstat & 0xf = 3))
	drop table spt_table_types	/* no longer used */
go

/*
** If tables or procs already exist, drop them.
*/

if (exists (select * from sysobjects
		where name = 'spt_datatype_info' and sysstat & 0xf = 3))
    drop table spt_datatype_info
go
if (exists (select * from sysobjects
		where name = 'spt_datatype_info_ext' and sysstat & 0xf = 3))
    drop table spt_datatype_info_ext
go
if (exists (select * from sysobjects
		where name = 'spt_server_info' and sysstat & 0xf = 3))
    drop table spt_server_info
go
if (exists (select * from sysobjects
		where name = 'sp_tables' and sysstat & 0xf = 4))
    drop proc sp_tables
go
if (exists (select * from sysobjects
		where name = 'sp_statistics' and sysstat & 0xf = 4))
    drop proc sp_statistics
go
if (exists (select * from sysobjects
		where name = 'sp_columns' and sysstat & 0xf = 4))
    drop proc sp_columns
go
if (exists (select * from sysobjects
		where name = 'sp_fkeys' and sysstat & 0xf = 4))
    drop proc sp_fkeys
go
if (exists (select * from sysobjects
		where name = 'sp_pkeys' and sysstat & 0xf = 4))
    drop proc sp_pkeys
dump tran master with no_log
go

go
if (exists (select * from sysobjects
		where name = 'sp_stored_procedures' and sysstat & 0xf = 4))
    drop proc sp_stored_procedures
go
if (exists (select * from sysobjects
		where name = 'sp_sproc_columns' and sysstat & 0xf = 4))
    drop proc sp_sproc_columns
go
if (exists (select * from sysobjects
		where name = 'sp_table_privileges' and sysstat & 0xf = 4))
    drop proc sp_table_privileges
go
if (exists (select * from sysobjects
		where name = 'sp_column_privileges' and sysstat & 0xf = 4))
	drop proc sp_column_privileges
go
if (exists (select * from sysobjects
		where name = 'sp_server_info' and sysstat & 0xf = 4))
    drop proc sp_server_info
go
if (exists (select * from sysobjects
		where name = 'sp_datatype_info' and sysstat & 0xf = 4))
    drop proc sp_datatype_info
go
if (exists (select * from sysobjects
		where name = 'sp_special_columns' and sysstat & 0xf = 4))
    drop proc sp_special_columns
go
if (exists (select * from sysobjects
		where name = 'sp_databases' and sysstat & 0xf = 4))
	drop proc sp_databases
go

dump tran master with no_log
go

print 'creating table spt_datatype_info_ext'
go
create table spt_datatype_info_ext (
				user_type		smallint	not null,
				create_params	varchar(32) null,
				auto_increment	smallint null)
go

create unique clustered index datatypeinfoextclust on spt_datatype_info_ext(user_type,auto_increment)
go

grant select on spt_datatype_info_ext to public
go


insert into spt_datatype_info_ext
	/* CHAR 	 user_type, create_params, auto_increment */
	values			 (1,	'length' ,0)

insert into spt_datatype_info_ext
	/* VARCHAR	 user_type, create_params, auto_increment */
	values			 (2,	'max length' ,0)

insert into spt_datatype_info_ext
	/* BINARY	 user_type, create_params, auto_increment */
	values			 (3,	'length' ,0)

insert into spt_datatype_info_ext
	/* VARBINARY user_type, create_params, auto_increment */
	values			 (4,	'max length' ,0)

if	(charindex('6.00', @@version) > 0)
begin	/*	Add 6.0 data types */
	insert into spt_datatype_info_ext
		/* DECIMAL user_type, create_params, auto_increment */
		values			 (26,	'precision,scale' ,0)

	insert into spt_datatype_info_ext
		/* NUMERIC user_type, create_params, auto_increment */
		values			 (25,	'precision,scale' ,0)

	insert into spt_datatype_info_ext
		/* DECIMAL IDENTITY user_type, create_params, auto_increment */
		values			 (26,	'precision' ,1)

	insert into spt_datatype_info_ext
		/* NUMERIC IDENTITY user_type, create_params, auto_increment */
		values			 (25,	'precision' ,1)

end
else	/*	Pre 6.0 server, add SYSNAME create param */
	begin
		insert into spt_datatype_info_ext
			/* SYSNAME	 user_type, create_param, auto_increments */
			values			 (18,	'max length' ,0)

	end
go

print 'creating table spt_datatype_info'
go
create table spt_datatype_info (
				ss_dtype		   tinyint		not null,
			    type_name          varchar(32)  not null,
			    data_type          smallint     not null,
			    data_precision     int          null,
				numeric_scale	   smallint 	null,	/* min scale if 6.0 */
			    numeric_radix      smallint     null,
			    length             int          null,
			    literal_prefix     varchar(32)  null,
			    literal_suffix     varchar(32)  null,
			    create_params      varchar(32)  null,
			    nullable           smallint     not null,
			    case_sensitive     smallint     not null,
			    searchable         smallint     not null,
			    unsigned_attribute smallint     null,
			    money              smallint     not null,
			    auto_increment     smallint     null,
				local_type_name    varchar(128) null,
				aux 			   int			null,
				numdec			   tinyint		not null)
go

create unique clustered index datatypeinfoclust on spt_datatype_info(ss_dtype,auto_increment)
go

/*
	There is a complicated set of SQL used to deal with
	the SQL Server Null data types (MONEYn, INTn, etc.)
	ISNULL is the only conditional SQL Server function that can be used
	to differentiate between these types depending on size.

	The aux column in the above table is used to differentiate
	the null data types from the non-null types.

	The aux column contains NULL for the null data types and 0 or delta
	to be added to length to get precision (money types) for the non-null
	data types.

	The following SQL returns the contents of the aux column (0)
	for the non-null data types and returns a variable non-zero
	value for the null data types.

								 " I   I I FFMMDD"
								 " 1   2 4 484848"
	isnull(d.aux,ascii(substring('666AAA@@@CB??GG',
	2*(d.ss_dtype%35+1)+2-8/c.length,1))-60)

	The '2*(d.ss_dtype%35+1)+2-8/c.length' selects a specific character of
	the substring mask depending on the null data type and its size, i.e.
	null MONEY4 or null MONEY8.  The character selected is then converted
	to its binary value and an appropriate bias (i.e. 60) is subtracted to
	return the correct non-zero value.	This value may be used as a
	constant, i.e. ODBC data type, precision, scale, etc., or used as an
	index with a substring to pick out a character string, i.e. type name.

	The comments above the substring mask denote which character is
	selected for each null data type, i.e. In (INTn), Fn (FLOATn),
	Mn (MONEYn) and Dn (DATETIMn).
*/

grant select on spt_datatype_info to public
go

/* Get case sensitivity */
if 'A' = 'A' /* create dummy begin block */
begin
	declare @case smallint

	select @case = 0
	select @case = 1 where 'a' != 'A'

	/* Local Binary */
	insert into spt_datatype_info values
	(  45	  ,'binary',-2		 ,null,null ,null,null,'0x',null,'length',1  ,0   ,2   ,null	,0	  ,null,'binary',0,0)

	/* Local Bit */
	insert into spt_datatype_info values
	(  50	  ,'bit',-7 	  ,	1	,0	  ,2  ,null,null,null,null,0  ,0   ,2	,null	 ,0    ,null,'bit',0,0)

	/* Local Char */
	insert into spt_datatype_info values
	(  47	  ,'char',1 	   ,null,null ,null,null,'''','''','length',1  ,@case,3	,null	 ,0    ,null,'char',0,0)

	/* Local Datetime */
	insert into spt_datatype_info values
	(  61	  ,'datetime',11	   ,23	,3	  ,10 ,16 ,'''','''',null,1	,0	,3	 ,null	  ,0	,null,'datetime',0,0)

	/* Local Smalldatetime */
	insert into spt_datatype_info values
	(  58	  ,'smalldatetime',11		,16  ,0    ,10 ,16 ,'''','''',null,1	,0	 ,3   ,null    ,0	 ,null,'smalldatetime',0,0)

	/* Local Datetimn */
	insert into spt_datatype_info values /* sql server type is 'datetimn' */
	(  111	  ,'smalldatetime',0		,0	 ,0    ,10 ,0  ,'''','''',null,1	,0	 ,3   ,null    ,0	 ,null,'datetime',null,0)

	/* Local Float */
	insert into spt_datatype_info values
	(  62	  ,'float',6		,15  ,null ,10 ,null,null,null,null,1  ,0	,2	 ,0 	  ,0	,0	 ,'float',0,0)

	/* Local RealFloat */
	insert into spt_datatype_info values /* sql server type is 'floatn' */
	(  109	  ,'float        real',0		,0	 ,null ,10 ,0  ,null,null,null,1  ,0   ,2	,0		 ,0    ,0	,'real      float',null,0)

	/* Local Real */
	insert into spt_datatype_info values
	(  59	  ,'real',7 	   ,7	,null ,10 ,null,null,null,null,1  ,0   ,2	,0		 ,0    ,0	,'real',0,0)

	/* Local Smallmoney */
	insert into spt_datatype_info values
	(  122	  ,'smallmoney',3		 ,10  ,4	,10 ,null,'$',null,null,1  ,0	,2	 ,0 	  ,1	,0	 ,'smallmoney',8,0)

	/* Local Int */
	insert into spt_datatype_info values
	(  56	  ,'int',4		  ,10  ,0	 ,10 ,null,null,null,null,1  ,0   ,2   ,0		,0	  ,0   ,'int',0,0)

	/* Local Intn */
	insert into spt_datatype_info values /* sql server type is 'intn' */
	(  38	  ,'smallint     tinyint',0		  ,0   ,0	 ,10 ,0  ,null,null,null,1	,0	 ,2   ,0	   ,0	 ,0   ,'tinyint   smallint',null,0)

	/* Local Money */
	insert into spt_datatype_info values
	(  60	  ,'money',3		,19  ,4    ,10 ,null,'$',null,null,1  ,0   ,2	,0		 ,1    ,0	,'money',13,0)

	/* Local Moneyn */
	insert into spt_datatype_info values	/* sql server type is 'moneyn' */
	(  110	  ,'smallmoney',0		 ,0   ,4	,10 ,0	,'$',null,null,1  ,0   ,2	,0		 ,1    ,0	,'smallmoneymoney',null,0)

	/* Local Smallint */
	insert into spt_datatype_info values
	(  52	  ,'smallint',5 	   ,5	,0	  ,10 ,null,null,null,null,1  ,0   ,2	,0		 ,0    ,0	,'smallint',0,0)

	/* Local Text */
	insert into spt_datatype_info values
	(  35	  ,'text',-1	   ,2147483647,null ,null,2147483647,'''','''',null,1  ,@case,1	 ,null	  ,0	,null,'text',0,0)

	/* Local Varbinary */
	insert into spt_datatype_info values
	(  37	  ,'varbinary',-3		,null,null ,null,null,'0x',null,'max length',1	,0	 ,2   ,null    ,0	 ,null,'varbinary',0,0)

	/* Local Tinyint */
	insert into spt_datatype_info values
	(  48	  ,'tinyint',-6 	  ,3   ,0	 ,10 ,null,null,null,null,1  ,0   ,2   ,1		,0	  ,0   ,'tinyint',0,0)

	/* Local Varchar */
	insert into spt_datatype_info values
	(  39	  ,'varchar',12 	  ,null,null ,null,null,'''','''','max length',1	,@case,3   ,null	,0	  ,null,'varchar',0,0)

	/* Local Image */
	insert into spt_datatype_info values
	(  34	  ,'image',-4		,2147483647,null ,null,2147483647,'0x',null,null,1	,0	 ,0	 ,null	  ,0	 ,null,'image',0,0)

	if	(charindex('6.00', @@version) > 0)
	begin	/*	Add 6.0 data types */
		/* Local Decimaln */
		insert into spt_datatype_info values	/* sql server type is 'decimaln' */
		(  106	  ,'decimal',3	   ,38	,0	 ,10 ,null,null,null,'precision,scale',1	,0	,2	,0		,0	  ,0   ,'decimal',0,1)

		/* Local Numericn */
		insert into spt_datatype_info values	/* sql server type is 'numericn' */
		(  108	  ,'numeric',2	,38  ,0	 ,10 ,null,null,null,'precision,scale',1	 ,0  ,2  ,0 	 ,0    ,0	,'numeric',0,1)

		/* Local Decimal */
		insert into spt_datatype_info values	/* sql server type is 'decimaln' */
		(  55	  ,'decimal',3	   ,38	,0	 ,10 ,null,null,null,'precision,scale',1	,0	,2	,0		,0	  ,0   ,'decimal',0,1)

		/* Local Numeric */
		insert into spt_datatype_info values	/* sql server type is 'numericn' */
		(  63	  ,'numeric',2	,38  ,0	 ,10 ,null,null,null,'precision,scale',1	 ,0  ,2  ,0 	 ,0    ,0	,'numeric',0,1)

		/* Identity attribute data types */

		/* Identity Int */
		insert into spt_datatype_info values
		(  56	  ,'int identity',4		  ,10  ,0	 ,10 ,null,null,null,null,0	,0	 ,2   ,0		,0	  ,1   ,'int identity',0,0)

		/* Identity Smallint */
		insert into spt_datatype_info values
		(  52	  ,'smallint identity',5	   ,5	,0	  ,10 ,null,null,null,null,0  ,0   ,2	,0		 ,0    ,1	,'smallint identity',0,0)

		/* Identity Tinyint */
		insert into spt_datatype_info values
		(  48	  ,'tinyint identity',-6	  ,3   ,0	 ,10 ,null,null,null,null,0	,0	 ,2   ,1		,0	  ,1   ,'tinyint identity',0,0)

		/* Identity Decimaln */
		insert into spt_datatype_info values	/* sql server type is 'decmaln' */
		(  106	  ,'decimal() identity',3	   ,38	,0	 ,10 ,null,null,null,'precision,scale',0	,0	,2	,0		,0	  ,1   ,'decimal() identity',0,1)

		/* Identity Numericn */
		insert into spt_datatype_info values	/* sql server type is 'decmaln' */
		(  108	  ,'numeric() identity',2	,38  ,0	 ,10 ,null,null,null,'precision,scale',0	 ,0  ,2  ,0 	 ,0    ,1	,'numeric() identity',0,1)

		/* Identity Decimal */
		insert into spt_datatype_info values	/* sql server type is 'decmaln' */
		(  55	  ,'decimal() identity',3	   ,38	,0	 ,10 ,null,null,null,'precision,scale',0	,0	,2	,0		,0	  ,1   ,'decimal() identity',0,1)

		/* Identity Numeric */
		insert into spt_datatype_info values	/* sql server type is 'decmaln' */
		(  63	  ,'numeric() identity',2	,38  ,0	 ,10 ,null,null,null,'precision,scale',0	 ,0  ,2  ,0 	 ,0    ,1	,'numeric() identity',0,1)

	end
	else	/*	Pre 6.0 server, remove money length adjustment */
	begin
		update spt_datatype_info set aux=0 where ss_dtype in (122,60)
	end
end
go

dump tran master with no_log
go

print 'creating table spt_server_info'
go
create table spt_server_info (
			  attribute_id		int NOT NULL,
			  attribute_name	varchar(60) NOT NULL,
			  attribute_value	varchar(255) NOT NULL)
go

create unique clustered index serverinfoclust on spt_server_info(attribute_id)
go

insert into spt_server_info
	values (1,'DBMS_NAME','Microsoft SQL Server')
insert into spt_server_info
	values (2,'DBMS_VER',@@version)
insert into spt_server_info
	values (10,'OWNER_TERM','owner')
insert into spt_server_info
	values (11,'TABLE_TERM','table')
insert into spt_server_info
	values (12,'MAX_OWNER_NAME_LENGTH','30')
insert into spt_server_info
	values (13,'TABLE_LENGTH','30')
insert into spt_server_info
	values (14,'MAX_QUAL_LENGTH','30')
insert into spt_server_info
	values (15,'COLUMN_LENGTH','30')
insert into spt_server_info
	values (16,'IDENTIFIER_CASE','MIXED')
insert into spt_server_info
	values (17,'TX_ISOLATION','2')
if	(charindex('6.00', @@version) > 0)
begin	/*	Add 6.0 collation sequence */
	insert into spt_server_info
		select 18,'COLLATION_SEQ',
			'charset='+t2.name+' sort_order='+t1.name
			+' charset_num='+rtrim(convert(char(4),t1.csid))+
			' sort_order_num='+rtrim(convert(char(4),t1.id))
		from syscharsets t1, syscharsets t2, sysconfigures t3
		where t1.csid=t2.id and t1.id=t3.value and t3.config=1123
end
else
begin	/*	Add 4.2x collation sequence */
	insert into spt_server_info
		select 18,"COLLATION_SEQ",
			"charset="+t2.name+" sort_order="+t1.name
			+" charset_num="+rtrim(convert(char(4),t1.csid))+
			" sort_order_num="+rtrim(convert(char(4),t1.id))
		from syscharsets t1, syscharsets t2, sysconfigures t3
		where t1.csid=t2.id and t1.id=t3.value and t3.config=123
end
insert into spt_server_info
	values (19,'SAVEPOINT_SUPPORT','Y')
insert into spt_server_info
	values (20,'MULTI_RESULT_SETS','Y')
insert into spt_server_info
	values (22,'ACCESSIBLE_TABLES','Y')
insert into spt_server_info
	values (100,'USERID_LENGTH','30')
insert into spt_server_info
	values (101,'QUALIFIER_TERM','database')
insert into spt_server_info
	values (102,'NAMED_TRANSACTIONS','Y')
insert into spt_server_info
	values (103,'SPROC_AS_LANGUAGE','Y')
insert into spt_server_info
	values (104,'ACCESSIBLE_SPROC','Y')
insert into spt_server_info
	values (105,'MAX_INDEX_COLS','16')
insert into spt_server_info
	values (106,'RENAME_TABLE','Y')
insert into spt_server_info
	values (107,'RENAME_COLUMN','Y')
insert into spt_server_info
	values (108,'DROP_COLUMN','N')
insert into spt_server_info
	values (109,'INCREASE_COLUMN_LENGTH','N')
insert into spt_server_info
	values (110,'DDL_IN_TRANSACTION','N')
insert into spt_server_info
	values (111,'DESCENDING_INDEXES','N')
insert into spt_server_info
	values (112,'SP_RENAME','Y')
insert into spt_server_info
	values (113,'REMOTE_SPROC','Y')
insert into spt_server_info
	values (500,'SYS_SPROC_VERSION','6.00.120')
go

grant select on spt_server_info to public
go

print 'creating sp_tables'
go

create procedure sp_tables(
			   @table_name		varchar(90)	= null,
			   @table_owner 	varchar(90)	= null,
			   @table_qualifier varchar(90)	= null,
			   @table_type		varchar(100) = null)
as
	declare @type1 varchar(3)
	declare @tableindex int


	/* Special feature #1:	enumerate databases when owner and name
		 are blank but qualifier is explicitly '%'.  */
	if @table_qualifier = '%' and
		@table_owner = '' and
		@table_name = ''
	begin	/* If enumerating databases */
		select
			table_qualifier = name,
			table_owner = convert(varchar(32),null),
			table_name = convert(varchar(32),null),
			table_type = convert(varchar(12),null),
			remarks = convert(varchar(254),null)	/* Remarks are NULL */
		from master..sysdatabases
		where name != 'model'	/* eliminate MODEL database */
		order by table_qualifier
	end

	/* Special feature #2:	enumerate owners when qualifier and name
		 are blank but owner is explicitly '%'.  */
	else if @table_qualifier = '' and
		@table_owner = '%' and
		@table_name = ''
	begin	/* If enumerating owners */
		select distinct
			table_qualifier = convert(varchar(32),null),
			table_owner = user_name(uid),
			table_name = convert(varchar(32),null),
			table_type = convert(varchar(12),null),
			remarks = convert(varchar(254),null)	/* Remarks are NULL */
		from sysobjects
		order by table_owner
	end

	/* Special feature #3:	enumerate table types when qualifier, owner and
		 name are blank but table type is explicitly '%'.	*/
	else if @table_qualifier = '' and
		@table_owner = '' and
		@table_name = '' and
		@table_type = '%'
	begin	/* If enumerating table types */
		select
			table_qualifier = convert(varchar(32),null),
			table_owner = convert(varchar(32),null),
			table_name = convert(varchar(32),null),
			table_type = rtrim(substring('SYSTEM TABLETABLE       VIEW',(colid-1)*12+1,12)),
			remarks = convert(varchar(254),null)	/* Remarks are NULL */
		from sysobjects o, syscolumns c
		where o.id=c.id and o.name='sysusers' and colid<=3
	end

	else
	begin /* end of special features -- do normal processing */
		if @table_qualifier is not null
		begin
			if db_name() != @table_qualifier
			begin
				if @table_qualifier = ''
				begin  /* If empty qualifier supplied */
					/* Force an empty result set */
					select @table_name = ''
					select @table_owner = ''
				end
				else
				begin	/* If qualifier doesn't match current database */
					raiserror 20001 'Table qualifier must be name of current database'
					return
				end
			end
		end
		if @table_type is null
		begin	/* Select all ODBC supported table types */
			select @type1 = 'SUV'
		end
		else
		begin
			/*	TableType is case sensitive if CS server */
			select @type1 = null
			if (charindex('''SYSTEM TABLE''',@table_type) != 0)
				select @type1 = @type1 + 'S'	/* Add System Tables */
			if (charindex('''TABLE''',@table_type) != 0)
				select @type1 = @type1 + 'U'	/* Add User Tables */
			if (charindex('''VIEW''',@table_type) != 0)
				select @type1 = @type1 + 'V'	/* Add Views */
		end
		if @table_name is null
		begin	/*	If table name not supplied, match all */
			select @table_name = '%'
		end
		else
		begin
			if (@table_owner is null) and (charindex('%', @table_name) = 0)
			begin	/* If owner not specified and table is specified */
				if exists (select * from sysobjects
					where uid = user_id()
					and name = @table_name
					and (type = 'U' or type = 'V' or type = 'S'))
				begin	/* Override supplied owner w/owner of table */
					select @table_owner = user_name()
				end
			end
		end
		if @table_owner is null /* If no owner supplied, force wildcard */
			select @table_owner = '%'
		select
			table_qualifier = db_name(),
			table_owner = user_name(o.uid),
			table_name = convert(varchar(32),o.name),	/* make nullable */
			table_type = rtrim(
				substring('SYSTEM TABLE            TABLE       VIEW       ',
					(ascii(o.type)-83)*12+1,12)),	/* 'S'=0,'U'=2,'V'=3 */
			remarks = convert(varchar(254),null)	/* Remarks are NULL */
		from sysusers u, sysobjects o
		where
			o.name like @table_name
			and user_name(o.uid) like @table_owner
			and charindex(substring(o.type,1,1),@type1)! = 0 /* Only desired types */
			and u.uid = user_id() /* constrain sysusers uid for use in subquery */
			and (
				suser_id() = 1	 /* User is the System Administrator */
				or o.uid = user_id()	 /* User created the object */
				/* here's the magic... select the highest precedence of permissions in the order (user,group,public)  */
				or ((select max(((sign(uid)*abs(uid-16383))*2)+(protecttype&1))
					from sysprotects p
					/* outer join to correlate with all rows in sysobjects */
					where p.id =* o.id
						/* get rows for public,current user,user's group */
						and (p.uid = 0 or p.uid = user_id() or p.uid =* u.gid)
						/* check for SELECT,EXECUTE privilege */
						and (action in (193,224)))&1	 /* more magic...normalize GRANT */
					) = 1	/* final magic...compare Grants	  */
			)
		order by table_type, table_qualifier, table_owner, table_name
	end
go

grant execute on sp_tables to public
go

dump tran master with no_log
go

print 'creating sp_statistics'
go

CREATE PROCEDURE sp_statistics (
				 @table_name		varchar(32),
				 @table_owner		varchar(32) = null,
				 @table_qualifier	varchar(32) = null,
				 @index_name		varchar(32) = '%',
				 @is_unique 		char(1) = 'N',
				 @accuracy			char(1) = 'Q')
AS
	DECLARE @indid				int
	DECLARE @lastindid			int
	DECLARE @table_id			int
    DECLARE @full_table_name    char(70)

    if @table_qualifier is not null
    begin
		if db_name() != @table_qualifier
		begin	/* If qualifier doesn't match current database */
			raiserror 20001 'Table qualifier must be name of current database'
			return
		end
    end

	if @accuracy not in ('Q','E')
		begin
			raiserror 20002 'Illegal ''accuracy'' specified -- must be ''Q'' or ''E''.'
			return
		end

    if @@trancount != 0
	begin	/* If inside a transaction */
		raiserror 20003 'The procedure ''sp_statistics'' cannot be executed from within a transaction.'
		return
    end
	create table #TmpIndex(
				table_qualifier varchar(32) NULL,
				table_owner 	varchar(32) NULL,
				table_name		varchar(32) NOT NULL,
			    index_qualifier varchar(32) null,
			    index_name      varchar(32) null,
			    non_unique      smallint null,
				type			smallint NOT NULL,
			    seq_in_index    smallint null,
			    column_name     varchar(32) null,
			    collation       char(1) null,
			    index_id        int null,
			    cardinality     int null,
			    pages           int null,
				status			smallint NOT NULL)
    if @table_owner is null
	begin	/* If unqualified table name */
		SELECT @full_table_name = @table_name
    end
    else
	begin	/* Qualified table name */
		SELECT @full_table_name = @table_owner + '.' + @table_name
    end
	/*	Get Object ID */
    SELECT @table_id = object_id(@full_table_name)

	/*	Start at lowest index id */
	SELECT @indid = min(indid)
    FROM sysindexes
	WHERE id = @table_id
		AND indid > 0
		AND indid < 255

    WHILE @indid != NULL
    BEGIN
		INSERT #TmpIndex	/* Add all columns that are in index */
			SELECT
				DB_NAME(),								/* table_qualifier */
				USER_NAME(o.uid),						/* table_owner	   */
				o.name, 								/* table_name	   */
				o.name, 								/* index_qualifier */
				x.name, 								/* index_name	   */
				0,										/* non_unique	   */
				1,										/* SQL_INDEX_CLUSTERED */
				colid,									/* seq_in_index    */
				INDEX_COL(@full_table_name,indid,colid),/* column_name	   */
				'A',									/* collation	   */
				@indid, 								/* index_id 	   */
				x.rows, 								/* cardinality	   */
				x.dpages,								/* pages		   */
				x.status								/* status			*/
			FROM sysindexes x, syscolumns c, sysobjects o
			WHERE
				x.id = @table_id
				AND x.id = o.id
				AND x.id = c.id
				AND c.colid < keycnt+(x.status&16)/16
				AND x.indid = @indid
		/*
		**	  Now move @indid to the next index.
		*/
		SELECT @lastindid = @indid
		SELECT @indid = NULL

		SELECT @indid = min(indid)
		FROM sysindexes
		WHERE id = @table_id
			AND indid > @lastindid
			AND indid < 255
    END

    UPDATE #TmpIndex
		SET non_unique = 1
		WHERE status&2 != 2 /* If non-unique index */
    UPDATE #TmpIndex
		SET
			type = 3,			/* SQL_INDEX_OTHER */
			cardinality = NULL,
			pages = NULL
		WHERE index_id > 1	/* If non-clustered index */

	/* now add row for table statistics */
	INSERT #TmpIndex
		SELECT
			DB_NAME(),				/* table_qualifier */
			USER_NAME(o.uid),		/* table_owner	   */
			o.name, 				/* table_name	   */
			null,					/* index_qualifier */
			null,					/* index_name	   */
			null,					/* non_unique	   */
			0,						/* SQL_TABLE_STAT  */
			null,					/* seq_in_index    */
			null,					/* column_name	   */
			null,					/* collation	   */
			0,						/* index_id 	   */
			x.rows, 				/* cardinality	   */
			x.dpages,				/* pages		   */
			0						/* status		   */
		FROM sysindexes x, sysobjects o
		WHERE o.id = @table_id
			AND x.id = o.id
			AND (x.indid = 0 or x.indid = 1)	/*	If there are no indexes */
												/*	then table stats are in */
												/*	a row with indid =0		*/

	if @is_unique != 'Y'	/* If all indexes desired */
		SELECT
			table_qualifier,
			table_owner,
			table_name,
			non_unique,
			index_qualifier,
			index_name,
			type,
			seq_in_index,
			column_name,
			collation,
			cardinality,
			pages,
			filter_condition = convert(varchar(128),null)
		FROM #TmpIndex
		WHERE
			index_name like @index_name /* If matching name */
			or index_name is null		/* If SQL_TABLE_STAT row */
		ORDER BY non_unique, type, index_name, seq_in_index
	else					/* If only unique indexes desired */
		SELECT
			table_qualifier,
			table_owner,
			table_name,
			non_unique,
			index_qualifier,
			index_name,
			type,
			seq_in_index,
			column_name,
			collation,
			cardinality,
			pages,
			filter_condition = convert(varchar(128),null)
		FROM #TmpIndex
		WHERE
			(non_unique = 0 			/* If unique */
				or non_unique is NULL)	/* If SQL_TABLE_STAT row */
			and (index_name like @index_name	/* If matching name */
				or index_name is null)	/* If SQL_TABLE_STAT row */
		ORDER BY non_unique, type, index_name, seq_in_index

    DROP TABLE #TmpIndex
go

grant execute on sp_statistics to public
go

dump tran master with no_log
go


print 'creating sp_columns'
go

/*	Procedure for pre-6.0 server */
CREATE PROCEDURE sp_columns (
				 @table_name		varchar(90),
				 @table_owner		varchar(90) = null,
				 @table_qualifier	varchar(90) = null,
				 @column_name		varchar(90) = null )
AS
	DECLARE @full_table_name	char(181)
    DECLARE @table_id int

	if @column_name is null /*	If column name not supplied, match all */
		select @column_name = '%'
    if @table_qualifier is not null
    begin
		if db_name() != @table_qualifier
		begin	/* If qualifier doesn't match current database */
			raiserror 20001 'Table qualifier must be name of current database'
			return
		end
    end
	if @table_name is null
	begin	/*	If table name not supplied, match all */
		select @table_name = '%'
	end
    if @table_owner is null
	begin	/* If unqualified table name */
		SELECT @full_table_name = @table_name
    end
    else
	begin	/* Qualified table name */
		SELECT @full_table_name = @table_owner + '.' + @table_name
    end

	/*	Get Object ID */
    SELECT @table_id = object_id(@full_table_name)
    if ((charindex('%',@full_table_name) = 0) and
		(charindex('_',@full_table_name) = 0)  and
		@table_id != 0)
    begin
		/* this block is for the case where there is no pattern
			 matching required for the table name */
		SELECT	/* INTn, FLOATn, DATETIMEn and MONEYn types */
			table_qualifier = DB_NAME(),
			table_owner = USER_NAME(o.uid),
			table_name = o.name,
			column_name = c.name,
			data_type = d.data_type+convert(smallint,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('666AAA@@@CB??GG',
						2*(d.ss_dtype%35+1)+2-8/c.length,1))
						-60),
			type_name = rtrim(substring(d.type_name,
						1+
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('III<<<MMMI<<A<A',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-60, 13)),
			"precision" = d.data_precision +convert(int,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('???AAAFFFCKFOLS',
						2*(d.ss_dtype%35+1)+2-8/c.length,1))-60),
			length = d.length +convert(int,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('AAA<BB<DDDHLUPP',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-64),
			scale = d.numeric_scale +convert(smallint,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('<<<<<<<<<<<<<<?',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-60),
			radix = d.numeric_radix,
			nullable = convert(smallint, 1),
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = c.type,
			colid = c.colid
		FROM
			syscolumns c,
			sysobjects o,
			master.dbo.spt_datatype_info d
		WHERE
			o.id = @table_id
			AND c.id = o.id
			AND c.type = d.ss_dtype
			AND o.type != 'P'
			AND c.name like @column_name
			AND d.ss_dtype IN (111, 109, 38, 110)	/* Just *N types */
			AND c.usertype < 100					/* No user defined types */
		UNION ALL
		SELECT	/* All other types including user data types */
			table_qualifier = DB_NAME(),
			table_owner = USER_NAME(o.uid),
			table_name = o.name,
			column_name = c.name,
			data_type = convert(smallint,
				/*	Map systypes.type to ODBC type */
				/*		SS-Type 		"	 1 1	    	 1	       "*/
				/*						"33 3030    4 44 5 5 255 556666"*/
				/*						"45 7698    5 78 0 2 256 890123"*/
						ascii(substring('8;<9?H><<<<:<=6<5<A<??@<GC?GB>',
						t.type%34+1,1))-60),
			type_name = t.name,
			"precision" = isnull(d.data_precision, convert(int,c.length))
						+isnull(d.aux, convert(int,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('???AAAFFFCKFOLS',
						2*(d.ss_dtype%35+1)+2-8/c.length,1))-60)),
			length = isnull(d.length, convert(int,c.length)) +convert(int,
						isnull(d.aux,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('AAA<BB<DDDHLUPP',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-64)),
			scale = d.numeric_scale +convert(smallint,
						isnull(d.aux,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('<<<<<<<<<<<<<<?',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-60)),
			radix = d.numeric_radix,
			nullable =	/* set nullability from status flag */
				convert(smallint, convert(bit, c.status&8)),
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = c.type,
			colid = c.colid
		FROM
			syscolumns c,
			sysobjects o,
			master.dbo.spt_datatype_info d,
			systypes t
		WHERE
			o.id = @table_id
			AND c.id = o.id
			AND c.type = d.ss_dtype
			AND o.type != 'P'
			AND c.usertype *= t.usertype
			AND c.name like @column_name
			AND (d.ss_dtype NOT IN (111, 109, 38, 110)	/* No *N types */
				OR c.usertype >= 100)					/* User defined types */
		ORDER BY colid
	end
	else
    begin
		/* this block is for the case where there IS pattern
			 matching done on the table name */
		if @table_owner is null /*	If owner not supplied, match all */
			select @table_owner = '%'
		SELECT	/* INTn, FLOATn, DATETIMEn and MONEYn types */
			table_qualifier = DB_NAME(),
			table_owner = USER_NAME(o.uid),
			table_name = o.name,
			column_name = c.name,
			data_type = d.data_type+convert(smallint,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('666AAA@@@CB??GG',
						2*(d.ss_dtype%35+1)+2-8/c.length,1))
						-60),
			type_name = rtrim(substring(d.type_name,
						1+
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('III<<<MMMI<<A<A',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-60, 13)),
			"precision" = d.data_precision +convert(int,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('???AAAFFFCKFOLS',
						2*(d.ss_dtype%35+1)+2-8/c.length,1))-60),
			length = d.length +convert(int,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('AAA<BB<DDDHLUPP',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-64),
			scale = d.numeric_scale,
			radix = d.numeric_radix,
			nullable = convert(smallint, 1),
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = c.type,
			colid = c.colid
		FROM
			syscolumns c,
			sysobjects o,
			master.dbo.spt_datatype_info d
		WHERE
			o.name like @table_name
			AND user_name(o.uid) like @table_owner
			AND o.id = c.id
			AND c.type = d.ss_dtype
			AND o.type != 'P'
			AND c.name like @column_name
			AND d.ss_dtype IN (111, 109, 38, 110)	/* Just *N types */
			AND c.usertype < 100			/* No User defined types */
		UNION ALL
		SELECT	/* All other types including user data types */
			table_qualifier = DB_NAME(),
			table_owner = USER_NAME(o.uid),
			table_name = o.name,
			column_name = c.name,
			data_type = convert(smallint,
				/*	Map systypes.type to ODBC type */
				/*		SS-Type 		"	 1 1	    	 1	       "*/
				/*						"33 3030    4 44 5 5 255 556666"*/
				/*						"45 7698    5 78 0 2 256 890123"*/
						ascii(substring('8;<9?H><<<<:<=6<5<A<??@<GC?GB>',
						t.type%34+1,1))-60),
			type_name = t.name,
			"precision" = isnull(d.data_precision, convert(int,c.length))
						+isnull(d.aux, convert(int,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('???AAAFFFCKFOLS',
						2*(d.ss_dtype%35+1)+2-8/c.length,1))-60)),
			length = isnull(d.length, convert(int,c.length)) +convert(int,
						isnull(d.aux,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('AAA<BB<DDDHLUPP',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-64)),
			scale = d.numeric_scale +convert(smallint,
						isnull(d.aux,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('<<<<<<<<<<<<<<?',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-60)),
			radix = d.numeric_radix,
			nullable =	/* set nullability from status flag */
				convert(smallint, convert(bit, c.status&8)),
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = c.type,
			colid = c.colid
		FROM
			syscolumns c,
			sysobjects o,
			master.dbo.spt_datatype_info d,
			systypes t
		WHERE
			o.name like @table_name
			AND user_name(o.uid) like @table_owner
			AND o.id = c.id
			AND c.type = d.ss_dtype
			AND o.type != 'P'
			AND c.usertype *= t.usertype
			AND c.name like @column_name
			AND (d.ss_dtype NOT IN (111, 109, 38, 110)	/* No *N types */
				OR c.usertype >= 100)					/* User defined types */
		ORDER BY table_owner, table_name, colid
	end
go

if	(charindex('6.00', @@version) = 0)
begin
	print ''
	print ''
	print 'Warning:'
	print 'you are installing the stored procedures '
	print 'on a pre 6.0 SQL Server.'
	print 'Ignore the following error.'
end
else
	drop proc sp_columns
go

/*	Procedure for 6.0 server */
CREATE PROCEDURE sp_columns (
				 @table_name		varchar(90),
				 @table_owner		varchar(90) = null,
				 @table_qualifier	varchar(90) = null,
				 @column_name		varchar(90) = null )
AS
	DECLARE @full_table_name	char(181)
    DECLARE @table_id int

	if @column_name is null /*	If column name not supplied, match all */
		select @column_name = '%'
    if @table_qualifier is not null
    begin
		if db_name() != @table_qualifier
		begin	/* If qualifier doesn't match current database */
			raiserror (15250, -1,-1,'Table')
			return
		end
    end
	if @table_name is null
	begin	/*	If table name not supplied, match all */
		select @table_name = '%'
	end
    if @table_owner is null
	begin	/* If unqualified table name */
		SELECT @full_table_name = @table_name
    end
    else
	begin	/* Qualified table name */
		SELECT @full_table_name = @table_owner + '.' + @table_name
    end

	/*	Get Object ID */
    SELECT @table_id = object_id(@full_table_name)
    if ((charindex('%',@full_table_name) = 0) and
		(charindex('_',@full_table_name) = 0)  and
		@table_id != 0)
    begin
		/* this block is for the case where there is no pattern
			matching required for the table name */
		SELECT	/* INTn, FLOATn, DATETIMEn and MONEYn types */
			table_qualifier = DB_NAME(),
			table_owner = USER_NAME(o.uid),
			table_name = o.name,
			column_name = c.name,
			data_type = d.data_type+convert(smallint,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('666AAA@@@CB??GG',
						2*(d.ss_dtype%35+1)+2-8/c.length,1))
						-60),
			type_name = rtrim(substring(d.type_name,
						1+
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('III<<<MMMI<<A<A',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-60, 13)),
			"precision" = convert(int,c.prec),
			length = d.length + convert(int,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848' */
						ascii(substring('AAA<BB<DDDHLUPP',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-64),
			scale = convert(smallint, c.scale),
			radix = d.numeric_radix,
			nullable = convert(smallint, 1),
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = c.type,
			colid = c.colid
		FROM
			syscolumns c,
			sysobjects o,
			master.dbo.spt_datatype_info d
		WHERE
			o.id = @table_id
			AND c.id = o.id
			AND c.type = d.ss_dtype
			AND o.type != 'P'
			AND c.name like @column_name
			AND d.ss_dtype IN (111, 109, 38, 110)	/* Just *N types */
			AND c.usertype < 100					/* No user defined types */
		UNION ALL
		SELECT	/* Identity base and decimal/numeric types */
			table_qualifier = DB_NAME(),
			table_owner = USER_NAME(o.uid),
			table_name = o.name,
			column_name = c.name,
			data_type = convert(smallint,
				/*	Map systypes.type to ODBC type */
				/*		SS-Type 		"	 1 1	    	 1	       "*/
				/*						"33 3030    4 44 5 5 255 556666"*/
				/*						"45 7698    5 78 0 2 256 890123"*/
						ascii(substring('8;<9?H><<<<:<=6<5<A<??@<GC?GB>',
						t.type%34+1,1))-60),
			type_name = d.type_name,
			"precision" = convert(int,c.prec),
			length = convert(int,c.length) +
				(convert(int,(c.type & 2)/2) |
				(convert(int,c.type&64)/64))*(c.prec+2 - c.length),
			scale = convert(smallint, c.scale),
			radix = d.numeric_radix,
			nullable =	/* set nullability from status flag */
				convert(smallint, convert(bit, c.status&8)),
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = c.type,
			colid = c.colid
		FROM
			syscolumns c,
			sysobjects o,
			master.dbo.spt_datatype_info d,
			systypes t
		WHERE
			o.id = @table_id
			AND c.id = o.id
			AND c.type = d.ss_dtype
			AND o.type != 'P'
			AND d.auto_increment = (c.status&128)/128
			AND c.usertype = t.usertype
			AND c.name like @column_name
			AND ((c.status&128 = 128			/* Identity types only */
				AND c.usertype < 100)			/* No user defined types */
				OR d.ss_dtype IN (106, 108, 55, 63))	 /* decimal/numeric types */
		UNION ALL
		SELECT	/* All other types including user data types */
			table_qualifier = DB_NAME(),
			table_owner = USER_NAME(o.uid),
			table_name = o.name,
			column_name = c.name,
			data_type = convert(smallint,
				/*	Map systypes.type to ODBC type */
				/*		SS-Type 		"	 1 1	    	 1	       "*/
				/*						"33 3030    4 44 5 5 255 556666"*/
				/*						"45 7698    5 78 0 2 256 890123"*/
						ascii(substring('8;<9?H><<<<:<=6<5<A<??@<GC?GB>',
						t.type%34+1,1))-60),
			type_name = t.name,
			"precision" = isnull(convert(int,c.prec), 2147483647),
			length = isnull(d.length, convert(int,c.length)) +convert(int,
						isnull(d.aux,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('AAA<BB<DDDHLUPP',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-64)),
			scale = convert(smallint, c.scale),
			radix = d.numeric_radix,
			nullable =	/* set nullability from status flag */
				convert(smallint, convert(bit, c.status&8)),
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = c.type,
			colid = c.colid
		FROM
			syscolumns c,
			sysobjects o,
			master.dbo.spt_datatype_info d,
			systypes t
		WHERE
			o.id = @table_id
			AND c.id = o.id
			AND c.type = d.ss_dtype
			AND o.type != 'P'
			AND isnull(d.auto_increment,0) = 0
			AND (c.status&128 = 0			/* No Identity types unless */
				OR c.usertype >= 100)		/* User defined type */
			AND c.usertype *= t.usertype
			AND c.name like @column_name
			AND (d.ss_dtype NOT IN (111, 109, 38, 110)	/* No *N types */
				OR c.usertype >= 100)					/* User defined types */
			AND d.ss_dtype NOT IN (106, 108, 55, 63)	/* No decimal/numeric types */
		ORDER BY colid
	end
	else
    begin
		/* this block is for the case where there IS pattern
			matching done on the table name */
		if @table_owner is null /*	If owner not supplied, match all */
			select @table_owner = '%'
		SELECT	/* INTn, FLOATn, DATETIMEn and MONEYn types */
			table_qualifier = DB_NAME(),
			table_owner = USER_NAME(o.uid),
			table_name = o.name,
			column_name = c.name,
			data_type = d.data_type+convert(smallint,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('666AAA@@@CB??GG',
						2*(d.ss_dtype%35+1)+2-8/c.length,1))
						-60),
			type_name = rtrim(substring(d.type_name,
						1+
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('III<<<MMMI<<A<A',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-60, 13)),
			"precision" = convert(int,c.prec),
			length = d.length + convert(int,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('AAA<BB<DDDHLUPP',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-64),
			scale = convert(smallint, c.scale),
			radix = d.numeric_radix,
			nullable = convert(smallint, 1),
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = c.type,
			colid = c.colid
		FROM
			syscolumns c,
			sysobjects o,
			master.dbo.spt_datatype_info d
		WHERE
			o.name like @table_name AND user_name(o.uid) like @table_owner
			AND o.id = c.id
			AND c.type = d.ss_dtype
			AND o.type != 'P'
			AND c.name like @column_name
			AND d.ss_dtype IN (111, 109, 38, 110)	/* Just *N types */
			AND c.usertype < 100			/* No User defined types */
		UNION ALL
		SELECT	/* Identity base and decimal/numeric types */
			table_qualifier = DB_NAME(),
			table_owner = USER_NAME(o.uid),
			table_name = o.name,
			column_name = c.name,
			data_type = convert(smallint,
				/*	Map systypes.type to ODBC type */
				/*		SS-Type 		"	 1 1	    	 1	       "*/
				/*						"33 3030    4 44 5 5 255 556666"*/
				/*						"45 7698    5 78 0 2 256 890123"*/
						ascii(substring('8;<9?H><<<<:<=6<5<A<??@<GC?GB>',
						t.type%34+1,1))-60),
			type_name = d.type_name,
			"precision" = convert(int,c.prec),
			length = convert(int,c.length) +
				(convert(int,(c.type & 2)/2) |
				(convert(int,c.type&64)/64))*(c.prec+2 - c.length),
			scale = convert(smallint, c.scale),
			radix = d.numeric_radix,
			nullable =	/* set nullability from status flag */
				convert(smallint, convert(bit, c.status&8)),
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = c.type,
			colid = c.colid
		FROM
			syscolumns c,
			sysobjects o,
			master.dbo.spt_datatype_info d,
			systypes t
		WHERE
			o.name like @table_name AND user_name(o.uid) like @table_owner
			AND c.id = o.id
			AND c.type = d.ss_dtype
			AND o.type != 'P'
			AND d.auto_increment = (c.status&128)/128
			AND c.usertype = t.usertype
			AND c.name like @column_name
			AND ((c.status&128 = 128			/* Identity types only */
				AND c.usertype < 100)			/* No user defined types */
				OR d.ss_dtype IN (106, 108, 55, 63))	 /* decimal/numeric types */
		UNION ALL
		SELECT	/* All other types including user data types */
			table_qualifier = DB_NAME(),
			table_owner = USER_NAME(o.uid),
			table_name = o.name,
			column_name = c.name,
			data_type = convert(smallint,
				/*	Map systypes.type to ODBC type */
				/*		SS-Type 		"	 1 1	    	 1	       "*/
				/*						"33 3030    4 44 5 5 255 556666"*/
				/*						"45 7698    5 78 0 2 256 890123"*/
						ascii(substring('8;<9?H><<<<:<=6<5<A<??@<GC?GB>',
						t.type%34+1,1))-60),
			type_name = t.name,
			"precision" = isnull(convert(int,c.prec), 2147483647),
			length = isnull(d.length, convert(int,c.length)) +convert(int,
						isnull(d.aux,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('AAA<BB<DDDHLUPP',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-64)),
			scale = convert(smallint, c.scale),
			radix = d.numeric_radix,
			nullable =	/* set nullability from status flag */
				convert(smallint, convert(bit, c.status&8)),
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = c.type,
			colid = c.colid
		FROM
			syscolumns c,
			sysobjects o,
			master.dbo.spt_datatype_info d,
			systypes t
		WHERE
			o.name like @table_name AND user_name(o.uid) like @table_owner
			AND o.id = c.id
			AND c.type = d.ss_dtype
			AND o.type != 'P'
			AND isnull(d.auto_increment,0) = 0
			AND (c.status&128 = 0			/* No Identity types unless */
				OR c.usertype >= 100)		/* User defined type */
			AND c.usertype *= t.usertype
			AND c.name like @column_name
			AND (d.ss_dtype NOT IN (111, 109, 38, 110)	/* No *N types */
				OR c.usertype >= 100)					/* User defined types */
			AND d.ss_dtype NOT IN (106, 108, 55, 63)	/* No decimal/numeric types */
		ORDER BY table_owner, table_name, colid
	end
go

grant execute on sp_columns to public
go

dump tran master with no_log
go
print 'creating sp_fkeys'
go

/*	Procedure for pre-6.0 server */
CREATE PROCEDURE sp_fkeys(
			   @pktable_name		varchar(32) = null,
			   @pktable_owner		varchar(32) = null,
			   @pktable_qualifier	varchar(32) = null,
			   @fktable_name		varchar(32) = null,
			   @fktable_owner		varchar(32) = null,
			   @fktable_qualifier	varchar(32) = null )
as
    declare	@order_by_pk int

    select  @order_by_pk = 0

    if (@pktable_name is null) and (@fktable_name is null)
	begin	/* If neither primary key nor foreign key table names given */
		raiserror 20004 'PK table name or FK table name must be given.'
		return
    end
    if @fktable_qualifier is not null
    begin
		if db_name() != @fktable_qualifier
		begin	/* If qualifier doesn't match current database */
			raiserror 20001 'Foreign Key Table qualifier must be name of current database'
			return
		end
    end
    if @pktable_qualifier is not null
    begin
		if db_name() != @pktable_qualifier
		begin	/* If qualifier doesn't match current database */
			raiserror 20001 'Primary Key Table qualifier must be name of current database'
			return
		end
    end

    if @pktable_name is null
	begin /*  If table name not supplied, match all */
		select @pktable_name = '%'
		select @order_by_pk = 1
    end
	if @pktable_owner is null	/*	If PK owner not supplied, match all */
		select @pktable_owner = '%'
	if @fktable_name is null	/*	If table name not supplied, match all */
		select @fktable_name = '%'
	if @fktable_owner is null	/*	If FK owner not supplied, match all */
		select @fktable_owner = '%'

    if @@trancount != 0
	begin	/* If inside a transaction */
		raiserror 20003 'The procedure ''sp_fkeys'' cannot be executed from within a transaction.'
		return
    end
	create table #fkeys(
			 pktable_qualifier	varchar(32) NULL,
			 pktable_owner		varchar(32) NULL,
			 pktable_name		varchar(32) NOT NULL,
			 pkcolumn_name		varchar(32) NOT NULL,
			 fktable_qualifier	varchar(32) NULL,
			 fktable_owner		varchar(32) NULL,
			 fktable_name		varchar(32) NOT NULL,
			 fkcolumn_name		varchar(32) NOT NULL,
			 key_seq			smallint NOT NULL)

	/*	SQL Server supports upto 8 PK/FK relationships between 2 tables */
	/*	Process syskeys for each relationship */
	/*	The inserts below adds a row to the temp table for each of the
		8 possible relationships */
    insert into #fkeys
		select
			db_name(),
			user_name(o1.uid),
			object_name(k.depid),
			c2.name,
			db_name(),
			user_name(o2.uid),
			object_name(k.id),
			c1.name,
			1
		from
			syskeys k, syscolumns c1, syscolumns c2,sysobjects o1, sysobjects o2
		where
			c1.id = k.id
			and k.type = 2	/* Foreign type key */
			and c1.colid = k.key1
			and c2.id = k.depid
			and c2.colid = k.depkey1
			and o1.id = k.depid
			and o2.id = k.id
	union
	    select
			db_name(),
			user_name(o1.uid),
			object_name(k.depid),
			c2.name,
			db_name(),
			user_name(o2.uid),
			object_name(k.id),
			c1.name,
			2
		from
			syskeys k, syscolumns c1, syscolumns c2,sysobjects o1, sysobjects o2
		where
			c1.id = k.id
			and k.type = 2	/* Foreign type key */
			and c1.colid = k.key2
			and c2.id = k.depid
			and c2.colid = k.depkey2
			and o1.id = k.depid
			and o2.id = k.id
	union
		select
			db_name(),
			user_name(o1.uid),
			object_name(k.depid),
			c2.name,
			db_name(),
			user_name(o2.uid),
			object_name(k.id),
			c1.name,
			3
		from
			syskeys k, syscolumns c1, syscolumns c2,sysobjects o1, sysobjects o2
		where
			c1.id = k.id
			and k.type = 2	/* Foreign type key */
			and c1.colid = k.key3
			and c2.id = k.depid
			and c2.colid = k.depkey3
			and o1.id = k.depid
			and o2.id = k.id
	union
		select
			db_name(),
			user_name(o1.uid),
			object_name(k.depid),
			c2.name,
			db_name(),
			user_name(o2.uid),
			object_name(k.id),
			c1.name,
			4
		from
			syskeys k, syscolumns c1, syscolumns c2,sysobjects o1, sysobjects o2
		where
			c1.id = k.id
			and k.type = 2	/* Foreign type key */
			and c1.colid = k.key4
			and c2.id = k.depid
			and c2.colid = k.depkey4
			and o1.id = k.depid
			and o2.id = k.id
	union
		select
			db_name(),
			user_name(o1.uid),
			object_name(k.depid),
			c2.name,
			db_name(),
			user_name(o2.uid),
			object_name(k.id),
			c1.name,
			5
		from
			syskeys k, syscolumns c1, syscolumns c2,sysobjects o1, sysobjects o2
		where
			c1.id = k.id
			and k.type = 2	/* Foreign type key */
			and c1.colid = k.key5
			and c2.id = k.depid
			and c2.colid = k.depkey5
			and o1.id = k.depid
			and o2.id = k.id
	union
		select
			db_name(),
			user_name(o1.uid),
			object_name(k.depid),
			c2.name,
			db_name(),
			user_name(o2.uid),
			object_name(k.id),
			c1.name,
			6
		from
			syskeys k, syscolumns c1, syscolumns c2,sysobjects o1, sysobjects o2
		where
			c1.id = k.id
			and k.type = 2	/* Foreign type key */
			and c1.colid = k.key6
			and c2.id = k.depid
			and c2.colid = k.depkey6
			and o1.id = k.depid
			and o2.id = k.id
	union
	    select
			db_name(),
			user_name(o1.uid),
			object_name(k.depid),
			c2.name,
			db_name(),
			user_name(o2.uid),
			object_name(k.id),
			c1.name,
			7
		from
			syskeys k, syscolumns c1, syscolumns c2,sysobjects o1, sysobjects o2
		where
			c1.id = k.id
			and k.type = 2	/* Foreign type key */
			and c1.colid = k.key7
			and c2.id = k.depid
			and c2.colid = k.depkey7
			and o1.id = k.depid
			and o2.id = k.id
	union
	    select
			db_name(),
			user_name(o1.uid),
			object_name(k.depid),
			c2.name,
			db_name(),
			user_name(o2.uid),
			object_name(k.id),
			c1.name,
			8
		from
			syskeys k, syscolumns c1, syscolumns c2,sysobjects o1, sysobjects o2
		where
			c1.id = k.id
			and k.type = 2	/* Foreign type key */
			and c1.colid = k.key8
			and c2.id = k.depid
			and c2.colid = k.depkey8
			and o1.id = k.depid
			and o2.id = k.id

	if @order_by_pk = 1 /*	If order by PK fields */
		select
			pktable_qualifier,
			pktable_owner,
			pktable_name,
			pkcolumn_name,
			fktable_qualifier,
			fktable_owner,
			fktable_name,
			fkcolumn_name,
			key_seq,
			update_rule = convert(smallint, null),
			delete_rule = convert(smallint,null),
			fk_name = convert(varchar(32),null),
			pk_name = convert(varchar(32),null)
		from #fkeys
		where fktable_name like @fktable_name
			and fktable_owner like @fktable_owner
			and pktable_name  like @pktable_name
			and pktable_owner like @pktable_owner
		order by pktable_qualifier, pktable_owner, pktable_name, key_seq
	else		/*	Order by FK fields */
		select
			pktable_qualifier,
			pktable_owner,
			pktable_name,
			pkcolumn_name,
			fktable_qualifier,
			fktable_owner,
			fktable_name,
			fkcolumn_name,
			key_seq,
			update_rule = convert(smallint,null),
			delete_rule = convert(smallint,null),
			fk_name = convert(varchar(32),null),
			pk_name = convert(varchar(32),null)
		from #fkeys
		where fktable_name like @fktable_name
			and fktable_owner like @fktable_owner
			and pktable_name  like @pktable_name
			and pktable_owner like @pktable_owner
		order by fktable_qualifier, fktable_owner, fktable_name, key_seq
go

if	(charindex('6.00', @@version) = 0)
begin
	print ''
	print ''
	print 'Warning:'
	print 'you are installing the stored procedures '
	print 'on a pre 6.0 SQL Server.'
	print 'Ignore the following errors.'
end
else
	drop proc sp_fkeys
go

/*	Procedure for 6.0 server */
CREATE PROCEDURE sp_fkeys(
			   @pktable_name		varchar(32) = null,
			   @pktable_owner		varchar(32) = null,
			   @pktable_qualifier	varchar(32) = null,
			   @fktable_name		varchar(32) = null,
			   @fktable_owner		varchar(32) = null,
			   @fktable_qualifier	varchar(32) = null )
as
	DECLARE @pktable_id			int
	DECLARE @pkfull_table_name	char(70)
	DECLARE @fktable_id			int
	DECLARE @fkfull_table_name	char(70)
	declare	@order_by_pk		int

    select  @order_by_pk = 0

    if (@pktable_name is null) and (@fktable_name is null)
	begin	/* If neither primary key nor foreign key table names given */
		raiserror (15252,-1,-1)
		return
    end

	if @pktable_owner is null
	begin	/* If unqualified primary key table name */
		SELECT @pkfull_table_name = @pktable_name
    end
    else
	begin	/* Qualified primary key table name */
		SELECT @pkfull_table_name = @pktable_owner + '.' + @pktable_name
    end
	/*	Get Object ID */
	SELECT @pktable_id = object_id(@pkfull_table_name)

	if @fktable_owner is null
	begin	/* If unqualified foreign key table name */
		SELECT @fkfull_table_name = @fktable_name
    end
    else
	begin	/* Qualified foreign key table name */
		SELECT @fkfull_table_name = @fktable_owner + '.' + @fktable_name
    end
	/*	Get Object ID */
	SELECT @fktable_id = object_id(@fkfull_table_name)

	if @fktable_name is not null
	begin
		if @fktable_id is null
			SELECT @fktable_id = 0	/* fk table not found, empty result */
    end

	if @pktable_name is null
	begin /*  If table name not supplied, match all */
		select @order_by_pk = 1
	end
	else
	begin
		if @pktable_id is null
		begin
			SELECT @pktable_id = 0	/* pk table not found, empty result */
		end
	end

    if @@trancount != 0
	begin	/* If inside a transaction */
		raiserror(15002,-1,-1,'sp_fkeys')
		return
	end

	create table #fkeys(
			 pkdb_id		int NOT NULL,
			 pktable_id 	int NOT NULL,
			 pkcolid		int NOT NULL,
			 fkdb_id		int NOT NULL,
			 fktable_id		int NOT NULL,
			 fkcolid		int NOT NULL,
			 key_seq		smallint NOT NULL,
			 fk_name		varchar(32) NULL,
			 pk_name		varchar(32) NULL)

	/*	SQL Server supports upto 16 PK/FK relationships between 2 tables */
	/*	Process syskeys for each relationship */
	/*	The inserts below adds a row to the temp table for each of the
		16 possible relationships */
    insert into #fkeys
		select
			r.rkeydbid,
			r.rkeyid,
			r.rkey1,
			r.fkeydbid,
			r.fkeyid,
			r.fkey1,
			1,
			OBJECT_NAME(r.constid),
			i.name
		from
			sysreferences r, sysindexes i
		where	r.rkeyid = i.id
			AND (i.status & 0x800) = 0x800
			AND r.rkeyid between isnull(@pktable_id, 0) and isnull(@pktable_id, 0x7fffffff)
			AND r.fkeyid between isnull(@fktable_id, 0) and isnull(@fktable_id, 0x7fffffff)
	  union
		select
			r.rkeydbid,
			r.rkeyid,
			r.rkey2,
			r.fkeydbid,
			r.fkeyid,
			r.fkey2,
			2,
			OBJECT_NAME(r.constid),
			i.name
		from
			sysreferences r, sysindexes i
		where	r.rkeyid = i.id
			AND (i.status & 0x800) = 0x800
			AND r.rkeyid between isnull(@pktable_id, 0) and isnull(@pktable_id, 0x7fffffff)
			AND r.fkeyid between isnull(@fktable_id, 0) and isnull(@fktable_id, 0x7fffffff)
	  union
		select
			r.rkeydbid,
			r.rkeyid,
			r.rkey3,
			r.fkeydbid,
			r.fkeyid,
			r.fkey3,
			3,
			OBJECT_NAME(r.constid),
			i.name
		from
			sysreferences r, sysindexes i
		where	r.rkeyid = i.id
			AND (i.status & 0x800) = 0x800
			AND r.rkeyid between isnull(@pktable_id, 0) and isnull(@pktable_id, 0x7fffffff)
			AND r.fkeyid between isnull(@fktable_id, 0) and isnull(@fktable_id, 0x7fffffff)
	  union
		select
			r.rkeydbid,
			r.rkeyid,
			r.rkey4,
			r.fkeydbid,
			r.fkeyid,
			r.fkey4,
			4,
			OBJECT_NAME(r.constid),
			i.name
		from
			sysreferences r, sysindexes i
		where	r.rkeyid = i.id
			AND (i.status & 0x800) = 0x800
			AND r.rkeyid between isnull(@pktable_id, 0) and isnull(@pktable_id, 0x7fffffff)
			AND r.fkeyid between isnull(@fktable_id, 0) and isnull(@fktable_id, 0x7fffffff)
	  union
		select
			r.rkeydbid,
			r.rkeyid,
			r.rkey5,
			r.fkeydbid,
			r.fkeyid,
			r.fkey5,
			5,
			OBJECT_NAME(r.constid),
			i.name
		from
			sysreferences r, sysindexes i
		where	r.rkeyid = i.id
			AND (i.status & 0x800) = 0x800
			AND r.rkeyid between isnull(@pktable_id, 0) and isnull(@pktable_id, 0x7fffffff)
			AND r.fkeyid between isnull(@fktable_id, 0) and isnull(@fktable_id, 0x7fffffff)
	  union
		select
			r.rkeydbid,
			r.rkeyid,
			r.rkey6,
			r.fkeydbid,
			r.fkeyid,
			r.fkey6,
			6,
			OBJECT_NAME(r.constid),
			i.name
		from
			sysreferences r, sysindexes i
		where	r.rkeyid = i.id
			AND (i.status & 0x800) = 0x800
			AND r.rkeyid between isnull(@pktable_id, 0) and isnull(@pktable_id, 0x7fffffff)
			AND r.fkeyid between isnull(@fktable_id, 0) and isnull(@fktable_id, 0x7fffffff)
	  union
		select
			r.rkeydbid,
			r.rkeyid,
			r.rkey7,
			r.fkeydbid,
			r.fkeyid,
			r.fkey7,
			7,
			OBJECT_NAME(r.constid),
			i.name
		from
			sysreferences r, sysindexes i
		where	r.rkeyid = i.id
			AND (i.status & 0x800) = 0x800
			AND r.rkeyid between isnull(@pktable_id, 0) and isnull(@pktable_id, 0x7fffffff)
			AND r.fkeyid between isnull(@fktable_id, 0) and isnull(@fktable_id, 0x7fffffff)
	  union
		select
			r.rkeydbid,
			r.rkeyid,
			r.rkey8,
			r.fkeydbid,
			r.fkeyid,
			r.fkey8,
			8,
			OBJECT_NAME(r.constid),
			i.name
		from
			sysreferences r, sysindexes i
		where	r.rkeyid = i.id
			AND (i.status & 0x800) = 0x800
			AND r.rkeyid between isnull(@pktable_id, 0) and isnull(@pktable_id, 0x7fffffff)
			AND r.fkeyid between isnull(@fktable_id, 0) and isnull(@fktable_id, 0x7fffffff)
	  union
		select
			r.rkeydbid,
			r.rkeyid,
			r.rkey9,
			r.fkeydbid,
			r.fkeyid,
			r.fkey9,
			9,
			OBJECT_NAME(r.constid),
			i.name
		from
			sysreferences r, sysindexes i
		where	r.rkeyid = i.id
			AND (i.status & 0x800) = 0x800
			AND r.rkeyid between isnull(@pktable_id, 0) and isnull(@pktable_id, 0x7fffffff)
			AND r.fkeyid between isnull(@fktable_id, 0) and isnull(@fktable_id, 0x7fffffff)
	  union
		select
			r.rkeydbid,
			r.rkeyid,
			r.rkey10,
			r.fkeydbid,
			r.fkeyid,
			r.fkey10,
			10,
			OBJECT_NAME(r.constid),
			i.name
		from
			sysreferences r, sysindexes i
		where	r.rkeyid = i.id
			AND (i.status & 0x800) = 0x800
			AND r.rkeyid between isnull(@pktable_id, 0) and isnull(@pktable_id, 0x7fffffff)
			AND r.fkeyid between isnull(@fktable_id, 0) and isnull(@fktable_id, 0x7fffffff)
	  union
		select
			r.rkeydbid,
			r.rkeyid,
			r.rkey11,
			r.fkeydbid,
			r.fkeyid,
			r.fkey11,
			11,
			OBJECT_NAME(r.constid),
			i.name
		from
			sysreferences r, sysindexes i
		where	r.rkeyid = i.id
			AND (i.status & 0x800) = 0x800
			AND r.rkeyid between isnull(@pktable_id, 0) and isnull(@pktable_id, 0x7fffffff)
			AND r.fkeyid between isnull(@fktable_id, 0) and isnull(@fktable_id, 0x7fffffff)
	  union
		select
			r.rkeydbid,
			r.rkeyid,
			r.rkey12,
			r.fkeydbid,
			r.fkeyid,
			r.fkey12,
			12,
			OBJECT_NAME(r.constid),
			i.name
		from
			sysreferences r, sysindexes i
		where	r.rkeyid = i.id
			AND (i.status & 0x800) = 0x800
			AND r.rkeyid between isnull(@pktable_id, 0) and isnull(@pktable_id, 0x7fffffff)
			AND r.fkeyid between isnull(@fktable_id, 0) and isnull(@fktable_id, 0x7fffffff)
	  union
		select
			r.rkeydbid,
			r.rkeyid,
			r.rkey13,
			r.fkeydbid,
			r.fkeyid,
			r.fkey13,
			13,
			OBJECT_NAME(r.constid),
			i.name
		from
			sysreferences r, sysindexes i
		where	r.rkeyid = i.id
			AND (i.status & 0x800) = 0x800
			AND r.rkeyid between isnull(@pktable_id, 0) and isnull(@pktable_id, 0x7fffffff)
			AND r.fkeyid between isnull(@fktable_id, 0) and isnull(@fktable_id, 0x7fffffff)
	  union
		select
			r.rkeydbid,
			r.rkeyid,
			r.rkey14,
			r.fkeydbid,
			r.fkeyid,
			r.fkey14,
			14,
			OBJECT_NAME(r.constid),
			i.name
		from
			sysreferences r, sysindexes i
		where	r.rkeyid = i.id
			AND (i.status & 0x800) = 0x800
			AND r.rkeyid between isnull(@pktable_id, 0) and isnull(@pktable_id, 0x7fffffff)
			AND r.fkeyid between isnull(@fktable_id, 0) and isnull(@fktable_id, 0x7fffffff)
	  union
		select
			r.rkeydbid,
			r.rkeyid,
			r.rkey15,
			r.fkeydbid,
			r.fkeyid,
			r.fkey15,
			15,
			OBJECT_NAME(r.constid),
			i.name
		from
			sysreferences r, sysindexes i
		where	r.rkeyid = i.id
			AND (i.status & 0x800) = 0x800
			AND r.rkeyid between isnull(@pktable_id, 0) and isnull(@pktable_id, 0x7fffffff)
			AND r.fkeyid between isnull(@fktable_id, 0) and isnull(@fktable_id, 0x7fffffff)
	  union
		select
			r.rkeydbid,
			r.rkeyid,
			r.rkey16,
			r.fkeydbid,
			r.fkeyid,
			r.fkey16,
			16,
			OBJECT_NAME(r.constid),
			i.name
		from
			sysreferences r, sysindexes i
		where	r.rkeyid = i.id
			AND (i.status & 0x800) = 0x800
			AND r.rkeyid between isnull(@pktable_id, 0) and isnull(@pktable_id, 0x7fffffff)
			AND r.fkeyid between isnull(@fktable_id, 0) and isnull(@fktable_id, 0x7fffffff)

	if @order_by_pk = 1 /*	If order by PK fields */
		select
			pktable_qualifier = DB_NAME(f.pkdb_id),
			pktable_owner = USER_NAME(o1.uid),
			pktable_name = o1.name,
			pkcolumn_name = c1.name,
			fktable_qualifier = DB_NAME(f.fkdb_id),
			fktable_owner = USER_NAME(o2.uid),
			fktable_name = o2.name,
			fkcolumn_name = c2.name,
			key_seq,
			update_rule = convert(smallint,1),
			delete_rule = convert(smallint,1),
			fk_name,
			pk_name
		from #fkeys f,
			sysobjects o1, sysobjects o2,
			syscolumns c1, syscolumns c2
		where	o1.id = f.pktable_id
			AND o2.id = f.fktable_id
			AND c1.id = f.pktable_id
			AND c2.id = f.fktable_id
			AND c1.colid = f.pkcolid
			AND c2.colid = f.fkcolid
		order by pktable_qualifier, pktable_owner, pktable_name, key_seq
	else		/*	Order by FK fields */
		select
			pktable_qualifier = DB_NAME(f.pkdb_id),
			pktable_owner = USER_NAME(o1.uid),
			pktable_name = o1.name,
			pkcolumn_name = c1.name,
			fktable_qualifier = DB_NAME(f.fkdb_id),
			fktable_owner = USER_NAME(o2.uid),
			fktable_name = o2.name,
			fkcolumn_name = c2.name,
			key_seq,
			update_rule = convert(smallint,1),
			delete_rule = convert(smallint,1),
			fk_name,
			pk_name
		from #fkeys f,
			sysobjects o1, sysobjects o2,
			syscolumns c1, syscolumns c2
		where	o1.id = f.pktable_id
			AND o2.id = f.fktable_id
			AND c1.id = f.pktable_id
			AND c2.id = f.fktable_id
			AND c1.colid = f.pkcolid
			AND c2.colid = f.fkcolid
		order by fktable_qualifier, fktable_owner, fktable_name, key_seq
go

grant execute on sp_fkeys to public
go
dump tran master with no_log
go

print 'creating sp_pkeys'
go

/*	Procedure for pre-6.0 server */
CREATE PROCEDURE sp_pkeys(
			   @table_name		varchar(32),
			   @table_owner 	varchar(32) = null,
			   @table_qualifier varchar(32) = null )
as
    if @table_qualifier is not null
    begin
		if db_name() != @table_qualifier
		begin	/* If qualifier doesn't match current database */
			raiserror 20001 'Table qualifier must be name of current database'
			return
		end
    end
	if @table_owner is null /*	If owner not supplied, match all */
		select @table_owner = '%'
    if @@trancount != 0
	begin	/* If inside a transaction */
		raiserror 20003 'The procedure ''sp_pkeys'' cannot be executed from within a transaction.'
		return
    end

	create table #pkeys(
			 table_qualifier varchar(32) NULL,
			 table_owner	 varchar(32) NULL,
			 table_name 	 varchar(32) NOT NULL,
			 column_name	 varchar(32) NOT NULL,
			 key_seq		 smallint NOT NULL)

	/*	SQL Server supports upto 8 PK/FK relationships between 2 tables */
	/*	Process syskeys for each relationship */
	/*	The inserts below adds a row to the temp table for each of the
		8 possible relationships */
    insert into #pkeys
		select
			db_name(),
			(select user_name(uid) from sysobjects o where o.id = k.id),
			object_name(k.id),
			c.name,
			1
		from
			syskeys k, syscolumns c
		where
			c.id = k.id
			and k.type = 1	/* Primary type key */
			and c.colid = k.key1
    if (@@rowcount = 0)
		goto done

    insert into #pkeys
		select
			db_name(),
			(select user_name(uid) from sysobjects o where o.id = k.id),
			object_name(k.id),
			c.name,
			2
		from
			syskeys k, syscolumns c
		where
			c.id = k.id
			and k.type = 1	/* Primary type key */
			and c.colid = key2
    if (@@rowcount = 0)
		goto done

    insert into #pkeys
		select
			db_name(),
			(select user_name(uid) from sysobjects o where o.id = k.id),
			object_name(k.id),
			c.name,
			3
		from
			syskeys k, syscolumns c
		where
			c.id = k.id
			and k.type = 1	/* Primary type key */
			and c.colid = key3
    if (@@rowcount = 0)
		goto done

    insert into #pkeys
		select
			db_name(),
			(select user_name(uid) from sysobjects o where o.id = k.id),
			object_name(k.id),
			c.name,
			4
		from
			syskeys k, syscolumns c
		where
			c.id = k.id
			and k.type = 1	/* Primary type key */
			and c.colid = key4
    if (@@rowcount = 0)
		goto done

    insert into #pkeys
		select
			db_name(),
			(select user_name(uid) from sysobjects o where o.id = k.id),
			object_name(k.id),
			c.name,
			5
		from
			syskeys k, syscolumns c
		where
			c.id = k.id
			and k.type = 1	/* Primary type key */
			and c.colid = key5
    if (@@rowcount = 0)
		goto done

    insert into #pkeys
		select
			db_name(),
			(select user_name(uid) from sysobjects o where o.id = k.id),
			object_name(k.id),
			c.name,
			6
		from
			syskeys k, syscolumns c
		where
			c.id = k.id
			and k.type = 1	/* Primary type key */
			and c.colid = key6
    if (@@rowcount = 0)
		goto done

    insert into #pkeys
		select
			db_name(),
			(select user_name(uid) from sysobjects o where o.id = k.id),
			object_name(k.id),
			c.name,
			7
		from
			syskeys k, syscolumns c
		where
			c.id = k.id
			and k.type = 1	/* Primary type key */
			and c.colid = key7
    if (@@rowcount = 0)
		goto done

    insert into #pkeys
		 select
			 db_name(),
			 (select user_name(uid) from sysobjects o where o.id = k.id),
			 object_name(k.id),
			 c.name,
			 8
		 from
			 syskeys k, syscolumns c
		 where
			 c.id = k.id
			 and k.type = 1 /* Primary type key */
			 and c.colid = key8

    done:
    select
	    table_qualifier,
	    table_owner,
	    table_name,
	    column_name,
	    key_seq,
		pk_name = convert(varchar(32),null)
	from #pkeys
	where table_name = @table_name
		and table_owner like @table_owner
	order by table_qualifier, table_owner, table_name, key_seq
go

if	(charindex('6.00', @@version) = 0)
begin
	print ''
	print ''
	print 'Warning:'
	print 'you are installing the stored procedures '
	print 'on a pre 6.0 SQL Server.'
	print 'Ignore the following error.'
end
else
	drop proc sp_pkeys
go

/*	Procedure for 6.0 server */
CREATE PROCEDURE sp_pkeys(
			   @table_name		varchar(32),
			   @table_owner 	varchar(32) = null,
			   @table_qualifier varchar(32) = null )
as
	DECLARE @table_id			int
    DECLARE @full_table_name    char(70)

    if @table_qualifier is not null
    begin
		if db_name() != @table_qualifier
		begin	/* If qualifier doesn't match current database */
			raiserror (15250, -1,-1,'Table')
			return
		end
    end
    if @table_owner is null
	begin	/* If unqualified table name */
		SELECT @full_table_name = @table_name
    end
    else
	begin	/* Qualified table name */
		SELECT @full_table_name = @table_owner + '.' + @table_name
    end
	/*	Get Object ID */
    SELECT @table_id = object_id(@full_table_name)

    select
		table_qualifier = db_name(),
		table_owner = user_name(o.uid),
		table_name = o.name,
		column_name = c.name,
		key_seq = convert(smallint,c1.colid),
		pk_name = i.name
	from
		sysindexes i, syscolumns c, sysobjects o, syscolumns c1
	where
		o.id = @table_id
		and o.id = c.id
		and o.id = i.id
		and (i.status & 0x800) = 0x800
		and c.name = index_col (@full_table_name, i.indid, c1.colid)
		and c1.colid <= i.keycnt	/* create rows from 1 to keycnt */
		and c1.id = @table_id
	order by table_qualifier, table_owner, table_name, key_seq
go

grant execute on sp_pkeys to public
go

dump tran master with no_log
go

print 'creating sp_stored_procedures'
go

create procedure sp_stored_procedures(
						@sp_name		varchar(96) = null,
						@sp_owner		varchar(90) = null,
						@sp_qualifier	varchar(32) = null)
as
	declare @proc_type smallint

    if @sp_qualifier is not null
    begin
		if db_name() != @sp_qualifier
		begin
			if @sp_qualifier = ''
			begin
				/* in this case, we need to return an empty result set */
				/* because the user has requested a database with an empty name */
				select @sp_name = ''
				select @sp_owner = ''
			end else
			begin	/* If qualifier doesn't match current database */
				raiserror 20001 'Procedure qualifier must be name of current database'
				return
			end
		end
    end

    if @sp_name is null
	begin  /*  If procedure name not supplied, match all */
		select @sp_name = '%'
    end
	else begin
		if (@sp_owner is null) and (charindex('%', @sp_name) = 0)
		begin
			if exists (select * from sysobjects
				where uid = user_id()
					and name = @sp_name
					and type = 'P') /* Object type of Procedure */
			begin
				select @sp_owner = user_name()
			end
		end
    end
	if @sp_owner is null	/*	If procedure owner not supplied, match all */
		select @sp_owner = '%'

	select @proc_type=2		/* Return 2 for 4.2 and later servers. */

    select
	    procedure_qualifier = db_name(),
	    procedure_owner = user_name(o.uid),
	    procedure_name = o.name +';'+ ltrim(str(p.number,5)),
		num_input_params = -1,	/* Constant since value unknown */
		num_output_params = -1, /* Constant since value unknown */
		num_result_sets = -1,	/* Constant since value unknown */
		remarks = convert(varchar(254),null),	/* Remarks are NULL */
		procedure_type = @proc_type
	from
	    sysobjects o,sysprocedures p,sysusers u
	where
	    o.name like @sp_name
	    and p.sequence = 0
	    and user_name(o.uid) like @sp_owner
		and o.type = 'P'		/* Object type of Procedure */
	    and p.id = o.id
		and u.uid = user_id()	/* constrain sysusers uid for use in subquery */
		and (suser_id() = 1 	/* User is the System Administrator */
			or o.uid = user_id()	/* User created the object */
		    /* here's the magic... select the highest precedence of permissions in the order (user,group,public)  */
		    or ((select max(((sign(uid)*abs(uid-16383))*2)+(protecttype&1))
			 from sysprotects p
			 /* outer join to correlate with all rows in sysobjects */
			 where p.id =* o.id
			     /*  get rows for public,current user,user's group */
				 and (p.uid = 0 or p.uid = user_id() or p.uid =* u.gid)
			     /* check for SELECT,EXECUTE privilege */
			     and (action in (193,224)))&1    /* more magic...normalize GRANT */
			) = 1	 /* final magic...compare Grants	*/
		)
    order by procedure_qualifier, procedure_owner, procedure_name
go
grant execute on sp_stored_procedures to public
go

dump tran master with no_log
go


print 'creating sp_sproc_columns'
go

/*	Procedure for pre-6.0 server */
CREATE PROCEDURE sp_sproc_columns (
				 @procedure_name		varchar(96) = '%',
				 @procedure_owner		varchar(90) = null,
				 @procedure_qualifier	varchar(32) = null,
				 @column_name			varchar(90) = null )
AS
    DECLARE @group_num int
    DECLARE @semi_position int
	DECLARE @full_procedure_name	char(187)
    DECLARE @procedure_id int

	if @column_name is null /*	If column name not supplied, match all */
		select @column_name = '%'
	if @procedure_qualifier is not null
    begin
		if db_name() != @procedure_qualifier
		begin
			if @procedure_qualifier = ''
			begin
				/* in this case, we need to return an empty result set */
				/* because the user has requested a database with an empty name */
				select @procedure_name = ''
				select @procedure_owner = ''
			end
			else
			begin	/* If qualifier doesn't match current database */
				raiserror 20001 'Procedure qualifier must be name of current database'
				return
			end
		end
    end

	if @procedure_name is null
	begin	/*	If procedure name not supplied, match all */
		select @procedure_name = '%'
	end

	/* first we need to extract the procedure group number, if one exists */
    select @semi_position = charindex(';',@procedure_name)
	if (@semi_position > 0)
	begin	/* If group number separator (;) found */
		select @group_num = convert(int,substring(@procedure_name, @semi_position + 1, 2))
		select @procedure_name = substring(@procedure_name, 1, @semi_position -1)
    end
    else
	begin	/* No group separator, so default to group number of 1 */
		select @group_num = 1
    end

    if @procedure_owner is null
	begin	/* If unqualified procedure name */
		SELECT @full_procedure_name = @procedure_name
    end
    else
	begin	/* Qualified procedure name */
		SELECT @full_procedure_name = @procedure_owner + '.' + @procedure_name
    end

	/*	Get Object ID */
    SELECT @procedure_id = object_id(@full_procedure_name)
    if ((charindex('%',@full_procedure_name) = 0) and
		(charindex('_',@full_procedure_name) = 0)  and
		@procedure_id != 0)
    begin
		/* this block is for the case where there is no pattern
			matching required for the procedure name */
		SELECT	/* INTn, FLOATn, DATETIMEn and MONEYn types */
			procedure_qualifier = DB_NAME(),
			procedure_owner = USER_NAME(o.uid),
			procedure_name = o.name +';'+ ltrim(str(c.number,5)),
			column_name = c.name,
			column_type = convert(smallint, 0),
			data_type = d.data_type+convert(smallint,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('666AAA@@@CB??GG',
						2*(d.ss_dtype%35+1)+2-8/c.length,1))
						-60),
			type_name = rtrim(substring(d.type_name,
						1+
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('III<<<MMMI<<A<A',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-60, 13)),
			"precision" = d.data_precision,
			length = d.length +convert(int,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('AAA<BB<DDDHLUPP',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-64),
			scale = d.numeric_scale,
			radix = d.numeric_radix,
			nullable = convert(smallint, 1),
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = c.type,
			colid = c.colid
		FROM
			syscolumns c,
			sysobjects o,
			master.dbo.spt_datatype_info d,
			systypes t,
			sysprocedures p
		WHERE
			o.id = @procedure_id
			AND c.id = o.id
			AND c.usertype = t.usertype
			AND c.type = d.ss_dtype
			AND c.name like @column_name
			AND d.ss_dtype IN (111, 109, 38, 110)	/* Just *N types */
			AND c.number = @group_num
		UNION
		SELECT		   /* All other types including user data types */
			procedure_qualifier = DB_NAME(),
			procedure_owner = USER_NAME(o.uid),
			procedure_name = o.name +';'+ ltrim(str(c.number,5)),
			column_name = c.name,
			column_type = convert(smallint, 0),
			data_type = convert(smallint,
				/*	Map systypes.type to ODBC type */
				/*		SS-Type 		"	 1 1	    	 1	       "*/
				/*						"33 3030    4 44 5 5 255 556666"*/
				/*						"45 7698    5 78 0 2 256 890123"*/
						ascii(substring('8;<9?H><<<<:<=6<5<A<??@<GC?GB>',
						t.type%34+1,1))-60),
			type_name = t.name,
			"precision" = isnull(d.data_precision, convert(int,c.length))
						+isnull(d.aux, convert(int,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('???AAAFFFCKFOLS',
						2*(d.ss_dtype%35+1)+2-8/c.length,1))-60)),
			length = isnull(d.length, convert(int,c.length)) +convert(int,
						isnull(d.aux,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('AAA<BB<DDDHLUPP',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-64)),
			scale = d.numeric_scale +convert(smallint,
						isnull(d.aux,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('<<<<<<<<<<<<<<?',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-60)),
			radix = d.numeric_radix,
			d.nullable,
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = c.type,
			colid = c.colid
		FROM
			syscolumns c,
			sysobjects o,
			master.dbo.spt_datatype_info d,
			systypes t
		WHERE
			o.id = @procedure_id
			AND c.id = o.id
			AND c.type = d.ss_dtype
			AND c.usertype *= t.usertype
			AND c.name like @column_name
			AND d.ss_dtype NOT IN (111, 109, 38, 110)	/* No *N types */
			AND c.number = @group_num
		UNION ALL
		SELECT		   /* return value row*/
			procedure_qualifier = DB_NAME(),
			procedure_owner = USER_NAME(o.uid),
			procedure_name = o.name +';'+ isnull(ltrim(str(c.number,5)),'1'),
			column_name = convert(varchar(32),'RETURN_VALUE'),
			column_type = convert(smallint, 5),
			data_type = convert(smallint, 4),
			type_name = convert(varchar(32),'int'),
			"precision" = convert(int,10),
			length = convert(int,4),
			scale = convert(smallint,0),
			radix = convert(smallint,10),
			nullable = convert(smallint,0),
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = convert(tinyint,56),
			colid = convert(tinyint,0)
		FROM
			syscolumns c,
			sysobjects o
		WHERE
			o.id = @procedure_id
			AND c.id =* o.id
			AND c.colid = 1
			AND 'RETURN_VALUE' like @column_name
		ORDER BY procedure_qualifier, procedure_owner, procedure_name, colid
	end
	else
    begin
		/* this block is for the case where there IS pattern
			matching done on the procedure name */
		if @procedure_owner is null
			select @procedure_owner = '%'
		SELECT	/* INTn, FLOATn, DATETIMEn and MONEYn types */
			procedure_qualifier = DB_NAME(),
			procedure_owner = USER_NAME(o.uid),
			procedure_name = o.name +';'+ ltrim(str(c.number,5)),
			column_name = c.name,
			column_type = convert(smallint, 0),
			data_type = d.data_type+convert(smallint,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('666AAA@@@CB??GG',
						2*(d.ss_dtype%35+1)+2-8/c.length,1))
						-60),
			type_name = rtrim(substring(d.type_name,
						1+
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('III<<<MMMI<<A<A',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-60, 13)),
			"precision" = isnull(d.data_precision, convert(int,c.length))
						+isnull(d.aux, convert(int,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('???AAAFFFCKFOLS',
						2*(d.ss_dtype%35+1)+2-8/c.length,1))-60)),
			length = d.length +convert(int,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('AAA<BB<DDDHLUPP',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-64),
			scale = d.numeric_scale,
			radix = d.numeric_radix,
			nullable = convert(smallint, 1),
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = c.type,
			colid = c.colid
		FROM
			syscolumns c,
			sysobjects o,
			master.dbo.spt_datatype_info d,
			systypes t
		WHERE
			o.name like @procedure_name
			AND user_name(o.uid) like @procedure_owner
			AND o.id = c.id
			AND c.usertype = t.usertype
			AND c.type = d.ss_dtype
			AND c.name like @column_name
			AND o.type = 'P'						/* Just Procedures */
			AND d.ss_dtype IN (111, 109, 38, 110)	/* Just *N types */
		UNION
		SELECT		   /* All other types including user data types */
			procedure_qualifier = DB_NAME(),
			procedure_owner = USER_NAME(o.uid),
			procedure_name = o.name +';'+ ltrim(str(c.number,5)),
			column_name = c.name,
			column_type = convert(smallint, 0),
			data_type = convert(smallint,
				/*	Map systypes.type to ODBC type */
				/*		SS-Type 		"	 1 1	    	 1	       "*/
				/*						"33 3030    4 44 5 5 255 556666"*/
				/*						"45 7698    5 78 0 2 256 890123"*/
						ascii(substring('8;<9?H><<<<:<=6<5<A<??@<GC?GB>',
						t.type%34+1,1))-60),
			type_name = t.name,
			"precision" = isnull(d.data_precision, convert(int,c.length))
						+isnull(d.aux, convert(int,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('???AAAFFFCKFOLS',
						2*(d.ss_dtype%35+1)+2-8/c.length,1))-60)),
			length = isnull(d.length, convert(int,c.length)) +convert(int,
						isnull(d.aux,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('AAA<BB<DDDHLUPP',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-64)),
			scale = d.numeric_scale +convert(smallint,
						isnull(d.aux,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('<<<<<<<<<<<<<<?',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-60)),
			radix = d.numeric_radix,
			d.nullable,
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = c.type,
			colid = c.colid
		FROM
			syscolumns c,
			sysobjects o,
			master.dbo.spt_datatype_info d,
			systypes t
		WHERE
			o.name like @procedure_name
			AND user_name(o.uid) like @procedure_owner
			AND o.id = c.id
			AND c.type = d.ss_dtype
			AND c.usertype *= t.usertype
			AND o.type = 'P'							/* Just Procedures */
			AND c.name like @column_name
			AND d.ss_dtype NOT IN (111, 109, 38, 110)	/* No *N types */
		UNION ALL
		SELECT		   /* return value row*/
			procedure_qualifier = DB_NAME(),
			procedure_owner = USER_NAME(o.uid),
			procedure_name = o.name +';'+ isnull(ltrim(str(c.number,5)),'1'),
			column_name = convert(varchar(32),'RETURN_VALUE'),
			column_type = convert(smallint, 5),
			data_type = convert(smallint, 4),
			type_name = convert(varchar(32),'int'),
			"precision" = convert(int,10),
			length = convert(int,4),
			scale = convert(smallint,0),
			radix = convert(smallint,10),
			nullable = convert(smallint,0),
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = convert(tinyint,56),
			colid = convert(tinyint,0)
		FROM
			syscolumns c,
			sysobjects o
		WHERE
			o.name like @procedure_name
			AND user_name(o.uid) like @procedure_owner
			AND c.id =* o.id
			AND c.colid = 1
			AND o.type = 'P'						/* Just Procedures */
			AND 'RETURN_VALUE' like @column_name
		ORDER BY procedure_qualifier, procedure_owner, procedure_name, colid
	end
go

if	(charindex('6.00', @@version) = 0)
begin
	print ''
	print ''
	print 'Warning:'
	print 'you are installing the stored procedures '
	print 'on a pre 6.0 SQL Server.'
	print 'Ignore the following error.'
end
else
	drop proc sp_sproc_columns
go

/*	Procedure for 6.0 server */
CREATE PROCEDURE sp_sproc_columns (
				 @procedure_name		varchar(96) = '%',
				 @procedure_owner		varchar(90) = null,
				 @procedure_qualifier	varchar(32) = null,
				 @column_name			varchar(90) = null )
AS
    DECLARE @group_num int
    DECLARE @semi_position int
	DECLARE @full_procedure_name	char(187)
    DECLARE @procedure_id int

	if @column_name is null /*	If column name not supplied, match all */
		select @column_name = '%'
	if @procedure_qualifier is not null
    begin
		if db_name() != @procedure_qualifier
		begin
			if @procedure_qualifier = ''
			begin
				/* in this case, we need to return an empty result set */
				/* because the user has requested a database with an empty name */
				select @procedure_name = ''
				select @procedure_owner = ''
			end
			else
			begin	/* If qualifier doesn't match current database */
				raiserror (15250, -1,-1,'Procedure')
				return
			end
		end
    end

	if @procedure_name is null
	begin	/*	If procedure name not supplied, match all */
		select @procedure_name = '%'
	end

	/* first we need to extract the procedure group number, if one exists */
    select @semi_position = charindex(';',@procedure_name)
	if (@semi_position > 0)
	begin	/* If group number separator (;) found */
		select @group_num = convert(int,substring(@procedure_name, @semi_position + 1, 2))
		select @procedure_name = substring(@procedure_name, 1, @semi_position -1)
    end
    else
	begin	/* No group separator, so default to group number of 1 */
		select @group_num = 1
    end

    if @procedure_owner is null
	begin	/* If unqualified procedure name */
		SELECT @full_procedure_name = @procedure_name
    end
    else
	begin	/* Qualified procedure name */
		SELECT @full_procedure_name = @procedure_owner + '.' + @procedure_name
    end

	/*	Get Object ID */
    SELECT @procedure_id = object_id(@full_procedure_name)
    if ((charindex('%',@full_procedure_name) = 0) and
		(charindex('_',@full_procedure_name) = 0)  and
		@procedure_id != 0)
    begin
		/* this block is for the case where there is no pattern
			matching required for the procedure name */
		SELECT	/* INTn, FLOATn, DATETIMEn and MONEYn types */
			procedure_qualifier = DB_NAME(),
			procedure_owner = USER_NAME(o.uid),
			procedure_name = o.name +';'+ ltrim(str(c.number,5)),
			column_name = c.name,
			column_type = convert(smallint, 1+((c.status/64)&1)),
			data_type = d.data_type+convert(smallint,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('666AAA@@@CB??GG',
						2*(d.ss_dtype%35+1)+2-8/c.length,1))
						-60),
			type_name = rtrim(substring(d.type_name,
						1+
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('III<<<MMMI<<A<A',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-60, 13)),
			"precision" = convert(int,c.prec),
			length = d.length + convert(int,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('AAA<BB<DDDHLUPP',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-64),
			scale = convert(smallint, c.scale),
			radix = d.numeric_radix,
			nullable = convert(smallint, 1),
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = c.type,
			colid = c.colid
		FROM
			syscolumns c,
			sysobjects o,
			master.dbo.spt_datatype_info d,
			systypes t,
			sysprocedures p
		WHERE
			o.id = @procedure_id
			AND c.id = o.id
			AND c.usertype = t.usertype
			AND c.type = d.ss_dtype
			AND isnull(d.auto_increment,0) = 0
			AND c.name like @column_name
			AND d.ss_dtype IN (111, 109, 38, 110)	/* Just *N types */
			AND c.number = @group_num
		UNION ALL
		SELECT	/* decimal/numeric types */
			procedure_qualifier = DB_NAME(),
			procedure_owner = USER_NAME(o.uid),
			procedure_name = o.name +';'+ ltrim(str(c.number,5)),
			column_name = c.name,
			column_type = convert(smallint, 1+((c.status/64)&1)),
			data_type = convert(smallint,
				/*	Map systypes.type to ODBC type */
				/*		SS-Type 		"	 1 1	    	 1	       "*/
				/*						"33 3030    4 44 5 5 255 556666"*/
				/*						"45 7698    5 78 0 2 256 890123"*/
						ascii(substring('8;<9?H><<<<:<=6<5<A<??@<GC?GB>',
						t.type%34+1,1))-60),
			type_name = t.name,
			"precision" = convert(int,c.prec),
			length = convert(int,c.prec) + 2,
			scale = convert(smallint, c.scale),
			radix = d.numeric_radix,
			d.nullable,
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = c.type,
			colid = c.colid
		FROM
			syscolumns c,
			sysobjects o,
			master.dbo.spt_datatype_info d,
			systypes t
		WHERE
			o.id = @procedure_id
			AND c.id = o.id
			AND c.type = d.ss_dtype
			AND isnull(d.auto_increment,0) = 0
			AND c.usertype *= t.usertype
			AND c.name like @column_name
			AND d.ss_dtype IN (106, 108, 55, 63)	 /* decimal/numeric types */
			AND c.number = @group_num
		UNION ALL
		SELECT		   /* All other types including user data types */
			procedure_qualifier = DB_NAME(),
			procedure_owner = USER_NAME(o.uid),
			procedure_name = o.name +';'+ ltrim(str(c.number,5)),
			column_name = c.name,
			column_type = convert(smallint, 1+((c.status/64)&1)),
			data_type = convert(smallint,
				/*	Map systypes.type to ODBC type */
				/*		SS-Type 		"	 1 1	    	 1	       "*/
				/*						"33 3030    4 44 5 5 255 556666"*/
				/*						"45 7698    5 78 0 2 256 890123"*/
						ascii(substring('8;<9?H><<<<:<=6<5<A<??@<GC?GB>',
						t.type%34+1,1))-60),
			type_name = t.name,
			"precision" = isnull(convert(int,c.prec), 2147483647),
			length = isnull(d.length, convert(int,c.length)) +convert(int,
						isnull(d.aux,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('AAA<BB<DDDHLUPP',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-64)),
			scale = convert(smallint, c.scale),
			radix = d.numeric_radix,
			d.nullable,
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = c.type,
			colid = c.colid
		FROM
			syscolumns c,
			sysobjects o,
			master.dbo.spt_datatype_info d,
			systypes t
		WHERE
			o.id = @procedure_id
			AND c.id = o.id
			AND c.type = d.ss_dtype
			AND isnull(d.auto_increment,0) = 0
			AND c.usertype *= t.usertype
			AND c.name like @column_name
			AND d.ss_dtype NOT IN (111, 109, 38, 110, 106, 108, 55, 63)	/* No *N types */
			AND c.number = @group_num
		UNION ALL
		SELECT		   /* return value row*/
			procedure_qualifier = DB_NAME(),
			procedure_owner = USER_NAME(o.uid),
			procedure_name = o.name +';'+ isnull(ltrim(str(c.number,5)),'1'),
			column_name = convert(varchar(32),'RETURN_VALUE'),
			column_type = convert(smallint, 5),
			data_type = convert(smallint, 4),
			type_name = convert(varchar(32),'int'),
			"precision" = convert(int,10),
			length = convert(int,4),
			scale = convert(smallint,0),
			radix = convert(smallint,10),
			nullable = convert(smallint,0),
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = convert(tinyint,56),
			colid = convert(tinyint,0)
		FROM
			syscolumns c,
			sysobjects o
		WHERE
			o.id = @procedure_id
			AND c.id =* o.id
			AND c.colid = 1
			AND 'RETURN_VALUE' like @column_name
		ORDER BY procedure_qualifier, procedure_owner, procedure_name, colid
	end
	else
    begin
		/* this block is for the case where there IS pattern
			matching done on the procedure name */
		if @procedure_owner is null
			select @procedure_owner = '%'
		SELECT	/* INTn, FLOATn, DATETIMEn and MONEYn types */
			procedure_qualifier = DB_NAME(),
			procedure_owner = USER_NAME(o.uid),
			procedure_name = o.name +';'+ ltrim(str(c.number,5)),
			column_name = c.name,
			column_type = convert(smallint, 1+((c.status/64)&1)),
			data_type = d.data_type+convert(smallint,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('666AAA@@@CB??GG',
						2*(d.ss_dtype%35+1)+2-8/c.length,1))
						-60),
			type_name = rtrim(substring(d.type_name,
						1+
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('III<<<MMMI<<A<A',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-60, 13)),
			"precision" = convert(int,c.prec),
			length = d.length + convert(int,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('AAA<BB<DDDHLUPP',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-64),
			scale = convert(smallint, c.scale),
			radix = d.numeric_radix,
			nullable = convert(smallint, 1),
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = c.type,
			colid = c.colid
		FROM
			syscolumns c,
			sysobjects o,
			master.dbo.spt_datatype_info d,
			systypes t
		WHERE
			o.name like @procedure_name
			AND user_name(o.uid) like @procedure_owner
			AND o.id = c.id
			AND c.usertype = t.usertype
			AND isnull(d.auto_increment,0) = 0
			AND c.type = d.ss_dtype
			AND c.name like @column_name
			AND o.type = 'P'						/* Just Procedures */
			AND d.ss_dtype IN (111, 109, 38, 110)	/* Just *N types */
		UNION ALL
		SELECT	/* decimal/numeric types */
			procedure_qualifier = DB_NAME(),
			procedure_owner = USER_NAME(o.uid),
			procedure_name = o.name +';'+ ltrim(str(c.number,5)),
			column_name = c.name,
			column_type = convert(smallint, 1+((c.status/64)&1)),
			data_type = convert(smallint,
				/*	Map systypes.type to ODBC type */
				/*		SS-Type 		"	 1 1	    	 1	       "*/
				/*						"33 3030    4 44 5 5 255 556666"*/
				/*						"45 7698    5 78 0 2 256 890123"*/
						ascii(substring('8;<9?H><<<<:<=6<5<A<??@<GC?GB>',
						t.type%34+1,1))-60),
			type_name = t.name,
			"precision" = convert(int,c.prec),
			length = convert(int,c.prec) + 2,
			scale = convert(smallint, c.scale),
			radix = d.numeric_radix,
			d.nullable,
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = c.type,
			colid = c.colid
		FROM
			syscolumns c,
			sysobjects o,
			master.dbo.spt_datatype_info d,
			systypes t
		WHERE
			o.name like @procedure_name
			AND user_name(o.uid) like @procedure_owner
			AND c.id = o.id
			AND c.type = d.ss_dtype
			AND isnull(d.auto_increment,0) = 0
			AND c.usertype *= t.usertype
			AND o.type = 'P'							/* Just Procedures */
			AND c.name like @column_name
			AND d.ss_dtype IN (106, 108, 55, 63)	 /* decimal/numeric types */
		UNION ALL
		SELECT		   /* All other types including user data types */
			procedure_qualifier = DB_NAME(),
			procedure_owner = USER_NAME(o.uid),
			procedure_name = o.name +';'+ ltrim(str(c.number,5)),
			column_name = c.name,
			column_type = convert(smallint, 1+((c.status/64)&1)),
			data_type = convert(smallint,
				/*	Map systypes.type to ODBC type */
				/*		SS-Type 		"	 1 1	    	 1	       "*/
				/*						"33 3030    4 44 5 5 255 556666"*/
				/*						"45 7698    5 78 0 2 256 890123"*/
						ascii(substring('8;<9?H><<<<:<=6<5<A<??@<GC?GB>',
						t.type%34+1,1))-60),
			type_name = t.name,
			"precision" = isnull(convert(int,c.prec), 2147483647),
			length = isnull(d.length, convert(int,c.length)) +convert(int,
						isnull(d.aux,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('AAA<BB<DDDHLUPP',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-64)),
			scale = convert(smallint, c.scale),
			radix = d.numeric_radix,
			d.nullable,
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = c.type,
			colid = c.colid
		FROM
			syscolumns c,
			sysobjects o,
			master.dbo.spt_datatype_info d,
			systypes t
		WHERE
			o.name like @procedure_name
			AND user_name(o.uid) like @procedure_owner
			AND o.id = c.id
			AND c.type = d.ss_dtype
			AND isnull(d.auto_increment,0) = 0
			AND c.usertype *= t.usertype
			AND o.type = 'P'							/* Just Procedures */
			AND c.name like @column_name
			AND d.ss_dtype NOT IN (111, 109, 38, 110, 106, 108, 55, 63)	/* No *N types */
		UNION ALL
		SELECT		   /* return value row*/
			procedure_qualifier = DB_NAME(),
			procedure_owner = USER_NAME(o.uid),
			procedure_name = o.name +';'+ isnull(ltrim(str(c.number,5)),'1'),
			column_name = convert(varchar(32),'RETURN_VALUE'),
			column_type = convert(smallint, 5),
			data_type = convert(smallint, 4),
			type_name = convert(varchar(32),'int'),
			"precision" = convert(int,10),
			length = convert(int,4),
			scale = convert(smallint,0),
			radix = convert(smallint,10),
			nullable = convert(smallint,0),
			remarks = convert(varchar(254),null),	/* Remarks are NULL */
			ss_data_type = convert(tinyint,56),
			colid = convert(tinyint,0)
		FROM
			syscolumns c,
			sysobjects o
		WHERE
			o.name like @procedure_name
			AND user_name(o.uid) like @procedure_owner
			AND c.id =* o.id
			AND c.colid = 1
			AND o.type = 'P'						/* Just Procedures */
			AND 'RETURN_VALUE' like @column_name
		ORDER BY procedure_qualifier, procedure_owner, procedure_name, colid
	end
go

grant execute on sp_sproc_columns to public
go

print 'creating sp_table_privileges'
go

CREATE PROCEDURE sp_table_privileges (
			@table_name 		varchar(90),
			@table_owner		varchar(90) = null,
			@table_qualifier	varchar(32) = null)
as

    declare @table_id    int,
			@owner_id	 int,
			@full_table_name char(181)
	declare @refconst int

	select @refconst = 1
	if	(charindex('6.00', @@version) = 0)
		select @refconst = NULL

    if @table_qualifier is not null
    begin
		if db_name() != @table_qualifier
		begin	/* If qualifier doesn't match current database */
			raiserror 20001 'Table qualifier must be name of current database'
			return
		end
    end
    if @table_owner is null
	begin	/* If unqualified table name */
		SELECT @full_table_name = @table_name
    end
    else
	begin	/* Qualified table name */
		SELECT @full_table_name = @table_owner + '.' + @table_name
    end
	/*	Get Object ID */
    SELECT @table_id = object_id(@full_table_name)

    if @@trancount != 0
	begin	/* If inside a transaction */
		raiserror 20003 'The procedure ''sp_table_privileges'' cannot be executed from within a transaction.'
		return
    end
	create table #table_priv1(
		table_qualifier			varchar(32) NOT NULL,
		table_owner 			varchar(32) NOT NULL,
		table_name				varchar(32) NOT NULL,
		grantor 				varchar(32) NOT NULL,
		grantee 				varchar(32) NOT NULL,
		select_privilege		int NOT NULL,
		insert_privilege		int NOT NULL,
		update_privilege		int NOT NULL,
		delete_privilege		int NOT NULL,
		references_privilege	int NULL,
		is_grantable			varchar(3) NOT NULL,
		uid 					int NOT NULL,
		gid 					int NOT NULL)

    insert into #table_priv1
		select distinct
			db_name(),
			user_name(o.uid),
			o.name,
			user_name(o.uid),
			u.name,
			0,
			0,
			0,
			0,
			@refconst,
			'no',
			u.uid,
			u.gid
		from sysusers u, sysobjects o
		where o.id = @table_id and u.uid != u.gid
		   and sysstat & 0xf in (1,2,3)	/* only valid for system tables,
		   								** user tables, and views. */

    /*
    ** now add row for table owner
    */
    if exists (
		select *
			from #table_priv1
			where grantor = grantee)
    begin
		update #table_priv1
		set
			select_privilege = 1,
			update_privilege = 1,
			insert_privilege = 1,
			delete_privilege = 1,
			references_privilege = 1,
			is_grantable = 'yes'
		where grantor = grantee
    end
    else
    begin
		insert into #table_priv1
			select	db_name(),
				user_name(o.uid),
				o.name,
				user_name(o.uid),
				user_name(o.uid),
				1,
				1,
				1,
				1,
				@refconst,
				'yes',
				o.uid,
				u.gid
			from sysobjects o, sysusers u
			where o.id = @table_id and u.uid = o.uid
			and sysstat & 0xf in (1,2,3)	/* only valid for system tables,
		   								** user tables, and views. */

    end

    update #table_priv1
	set select_privilege = 1
	where
		exists (
			select * from sysprotects
			where
				id = @table_id
				and (#table_priv1.uid = uid
					or #table_priv1.gid = uid
					or uid = 0)
				and protecttype = 205
				and action = 193)
		and not exists (
			select * from sysprotects
			where
				id = @table_id
				and (#table_priv1.uid = uid
					or #table_priv1.gid = uid
					or uid = 0)
				and protecttype = 206
				and action = 193)

    update #table_priv1
	set insert_privilege = 1
	where
		exists (
			select * from sysprotects
			where
				id = @table_id
				and (#table_priv1.uid = uid
					or #table_priv1.gid = uid
					or uid = 0)
				and protecttype = 205
				and action = 195)
		and not exists (
			select * from sysprotects
			where
				id = @table_id
				and (#table_priv1.uid = uid
					or #table_priv1.gid = uid
					or uid = 0)
				and protecttype = 206
				and action = 195)

    update #table_priv1
	set delete_privilege = 1
	where
		exists (
			select * from sysprotects
			where
				id = @table_id
				and (#table_priv1.uid = uid
					or #table_priv1.gid = uid
					or uid = 0)
				and protecttype = 205
				and action = 196)
		and not exists (select * from sysprotects
			where
				id = @table_id
				and (#table_priv1.uid = uid
					or #table_priv1.gid = uid
					or uid = 0)
				and protecttype = 206
				and action = 196)

    update #table_priv1
	set update_privilege = 1
	where
		exists (
			select * from sysprotects
			where
				id = @table_id
				and (#table_priv1.uid = uid
					or #table_priv1.gid = uid
					or uid = 0)
				and protecttype = 205
				and action = 197)
		and not exists (
			select * from sysprotects
			where
				id = @table_id
				and (#table_priv1.uid = uid
					or #table_priv1.gid = uid
					or uid = 0)
				and protecttype = 206
				and action = 197)

    update #table_priv1
	set references_privilege = 1
	where
		exists (
			select * from sysprotects
			where
				id = @table_id
				and (#table_priv1.uid = uid
					or #table_priv1.gid = uid
					or uid = 0)
				and protecttype = 205
				and action = 26)
		and not exists (
			select * from sysprotects
			where
				id = @table_id
				and (#table_priv1.uid = uid
					or #table_priv1.gid = uid
					or uid = 0)
				and protecttype = 206
				and action = 26)

	create table #table_priv2(
		table_qualifier varchar(32) NULL,
		table_owner 	varchar(32) NULL,
		table_name		varchar(32) NOT NULL,
		grantor 		varchar(32) NULL,
		grantee 		varchar(32) NOT NULL,
		privilege		varchar(32) NOT NULL,
		is_grantable	varchar(3) NULL)

	insert into #table_priv2
		select
			table_qualifier,
			table_owner,
			table_name,
			grantor,
			grantee,
			'SELECT',
			is_grantable
		from #table_priv1
		where select_privilege = 1


	insert into #table_priv2
		select
			table_qualifier,
			table_owner,
			table_name,
			grantor,
			grantee,
			'INSERT',
			is_grantable
		from #table_priv1
		where insert_privilege = 1


	insert into #table_priv2
		select
			table_qualifier,
			table_owner,
			table_name,
			grantor,
			grantee,
			'DELETE',
			is_grantable
		from #table_priv1
		where delete_privilege = 1


	insert into #table_priv2
		select
			table_qualifier,
			table_owner,
			table_name,
			grantor,
			grantee,
			'UPDATE',
			is_grantable
		from #table_priv1
		where update_privilege = 1

	insert into #table_priv2
		select
			table_qualifier,
			table_owner,
			table_name,
			grantor,
			grantee,
			'REFERENCES',
			is_grantable
		from #table_priv1
		where references_privilege = 1


    select * from #table_priv2
	order by privilege
go

grant execute on sp_table_privileges to public
go

dump tran master with no_log
go

print 'creating sp_column_privileges'
go


CREATE PROCEDURE sp_column_privileges (
			@table_name 		varchar(32),
			@table_owner		varchar(32) = null,
			@table_qualifier	varchar(32) = null,
			@column_name		varchar(90) = null)
as

    declare @table_id    int,
	@owner_id    int
    DECLARE @full_table_name    char(70)
    declare @low int                    /* range of userids to check */
    declare @high int
    declare @objid int                  /* id of @name if object */
	declare @owner_name char(32)
	declare @refconst int

    select @low = 0, @high = 32767

	select @refconst = 1
	if	(charindex('6.00', @@version) = 0)
		select @refconst = NULL

	if @column_name is null /*	If column name not supplied, match all */
		select @column_name = '%'

    if @table_qualifier is not null
    begin
		if db_name() != @table_qualifier
		begin	/* If qualifier doesn't match current database */
			raiserror 20001 'Table qualifier must be name of current database'
			return
		end
    end
    if @table_owner is null
	begin	/* If unqualified table name */
		SELECT @full_table_name = @table_name
    end
    else
	begin	/* Qualified table name */
		SELECT @full_table_name = @table_owner + '.' + @table_name
    end
	/*	Get Object ID */
    select @table_id = object_id(@full_table_name)

    if @@trancount != 0
	begin	/* If inside a transaction */
		raiserror 20003 'The procedure ''sp_column_privileges'' cannot be executed from within a transaction.'
		return
    end

    /*
    ** We need to create a table which will contain a row for every row to
    ** be returned to the client.
    */

	create table #column_priv1(
		table_qualifier			varchar(32) NOT NULL,
		table_owner 			varchar(32) NOT NULL,
		table_name				varchar(32) NOT NULL,
		column_name 			varchar(32) NOT NULL,
		grantor 				varchar(32) NOT NULL,
		grantee 				varchar(32) NOT NULL,
		select_privilege		int NOT NULL,
		select_grantable		int NOT NULL,
		insert_privilege		int NOT NULL,
		insert_grantable		int NOT NULL,
		update_privilege		int NOT NULL,
		update_grantable		int NOT NULL,
		references_privilege	int null,
		references_grantable	int null,
		uid 					int NOT NULL,
		gid 					int NOT NULL,
		is_grantable			varchar(3) NOT NULL)

/*
** insert a row for the table owner (who has all permissions)
*/
	select @owner_name = (
		select user_name(uid)
		from sysobjects
		where id = @table_id)

    insert into #column_priv1
		select
			db_name(),
			@owner_name,
			@table_name,
			name,
			@owner_name,
			@owner_name,
			1,
			1,
			1,
			1,
			1,
			1,
			@refconst,
			@refconst,
			user_id(@owner_name),
			0,
			'yes'
		from syscolumns
		where id = @table_id

/*
** now stick a row in the table for every user in the database
** we will need to weed out those who have no permissions later
** (and yes this is a cartesion product: the uid field in sysprotects
** can also have a group id, in which case we need to extend those
** privileges to all group members).
*/

    insert into #column_priv1
		select distinct
			db_name(),
			user_name(o.uid),
			@table_name,
			c.name,
			user_name(o.uid),
			u.name,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			u.uid,
			u.gid,
			'no'
		from sysusers u, syscolumns c, sysobjects o
		where o.id = @table_id
			and c.id = o.id
			and u.gid != u.uid
			and u.name != @owner_name

    /*
    ** we need to create another temporary table to contain all the various
    ** protection information for the table in question
    */
	create table #protects (
				uid 		smallint NOT NULL,
				action		tinyint NOT NULL,
				protecttype tinyint NOT NULL,
				name		varchar(32) NOT NULL)

    insert into #protects
		select
			p.uid,
			p.action,
			p.protecttype,
			isnull(col_name(id, c.number), 'All')
			from
				sysprotects p,
				master.dbo.spt_values c,
				master.dbo.spt_values a,
				master.dbo.spt_values b
			where
				convert(tinyint, substring(isnull(p.columns, 0x1), c.low, 1))
					& c.high != 0
					and c.number <= (
						select count(*)
						from syscolumns
						where id = @table_id)
				and a.type = 'T'
				and a.number = p.action
				and p.action in (193,195,197,26)
				and b.type = 'T'
				and b.number = p.protecttype
				and p.id = @table_id
				and p.uid between @low and @high


    update #column_priv1
	set select_privilege = 1
	where
		exists (
			select * from #protects
			where
				protecttype = 205
				and action = 193
				and (name = #column_priv1.column_name
					or name = 'All')
				and (uid = 0
					or uid = #column_priv1.gid
					or uid = #column_priv1.uid))
		and not exists (
			select * from #protects
			where
				protecttype = 206
				and action = 193
				and (name = #column_priv1.column_name
					or name = 'All')
				and ( uid = 0
					or uid = #column_priv1.gid
					or uid = #column_priv1.uid))

    update #column_priv1
	set insert_privilege = 1
	where
		exists (
			select * from #protects
			where
				protecttype = 205
				and action = 195
				and (name = #column_priv1.column_name
					or name = 'All')
				and (uid = 0
					or uid = #column_priv1.gid
					or uid = #column_priv1.uid))
		and not exists (
			select * from #protects
			where
				protecttype = 206
				and action = 195
				and (name = #column_priv1.column_name
					or name = 'All')
				and (uid = 0
					or uid = #column_priv1.gid
					or uid = #column_priv1.uid))

    update #column_priv1
	set update_privilege = 1
		where
			exists (
				select * from #protects
				where protecttype = 205
				and action = 197
				and (name = #column_priv1.column_name
					or name = 'All')
				and (uid = 0
					or uid = #column_priv1.gid
					or uid = #column_priv1.uid))
			and not exists (
				select * from #protects
					where protecttype = 206
					and action = 197
					and (name = #column_priv1.column_name
						or name = 'All')
					and (uid = 0
						or uid = #column_priv1.gid
						or uid = #column_priv1.uid))

    update #column_priv1
	set references_privilege = 1
		where
			exists (
				select * from #protects
				where protecttype = 205
				and action = 26
				and (name = #column_priv1.column_name
					or name = 'All')
				and (uid = 0
					or uid = #column_priv1.gid
					or uid = #column_priv1.uid))
			and not exists (
				select * from #protects
					where protecttype = 206
					and action = 26
					and (name = #column_priv1.column_name
						or name = 'All')
					and (uid = 0
						or uid = #column_priv1.gid
						or uid = #column_priv1.uid))

	create table #column_priv2(
		table_qualifier varchar(32) NULL,
		table_owner 	varchar(32) NULL,
		table_name		varchar(32) NOT NULL,
		column_name 	varchar(32) NOT NULL,
		grantor 		varchar(32) NULL,
		grantee 		varchar(32) NOT NULL,
		privilege		varchar(32) NOT NULL,
		is_grantable	varchar(3) NULL)

	insert into #column_priv2
		select
			table_qualifier,
			table_owner,
			table_name,
			column_name,
			grantor,
			grantee,
			'SELECT',
			is_grantable
		from #column_priv1
		where select_privilege = 1

	insert into #column_priv2
		select
			table_qualifier,
			table_owner,
			table_name,
			column_name,
			grantor,
			grantee,
			'INSERT',
			is_grantable
		from #column_priv1
		where insert_privilege = 1

	insert into #column_priv2
		select
			table_qualifier,
			table_owner,
			table_name,
			column_name,
			grantor,
			grantee,
			'UPDATE',
			is_grantable
		from #column_priv1
		where update_privilege = 1

	insert into #column_priv2
		select
			table_qualifier,
			table_owner,
			table_name,
			column_name,
			grantor,
			grantee,
			'REFERENCES',
			is_grantable
		from #column_priv1
		where references_privilege = 1

	select * from #column_priv2
	where column_name like @column_name
	order by column_name, privilege
go

grant execute on sp_column_privileges to public
go

dump tran master with no_log
go


print 'creating sp_server_info'
go

create proc sp_server_info (
			@attribute_id  int = null)
as
    if @attribute_id is not null
		select *
		from master.dbo.spt_server_info
		where attribute_id = @attribute_id
    else
		select *
		from master.dbo.spt_server_info
		order by attribute_id
go

grant execute on sp_server_info to public
go

print 'creating sp_datatype_info'
go

/* the messiness of 'data_type' was to get around the problem of
returning the correct lengths for user defined types.  the join
on the type name ensures all user defined types are returned, but
this puts a null in the data_type column.  by forcing an embedded
select and correlating it with the current row in systypes, we get
the correct data_type mapping even for user defined types  (kwg) */

/*	Procedure for pre-6.0 server */
create proc sp_datatype_info
	(@data_type int = 0)
as
	if @data_type = 0
	   		select	/* Real SQL Server data types */
			type_name = t.name,
			d.data_type,
			"precision" = isnull(d.data_precision, convert(int,t.length)),
			d.literal_prefix,
			d.literal_suffix,
			e.create_params,
			d.nullable,
			d.case_sensitive,
			d.searchable,
			d.unsigned_attribute,
			d.money,
			d.auto_increment,
			d.local_type_name,
			minimum_scale = d.numeric_scale,
			maximum_scale = d.numeric_scale,
			t.usertype
		from master.dbo.spt_datatype_info d, master.dbo.spt_datatype_info_ext e, systypes t
		where
			d.ss_dtype = t.type
			and t.usertype *= e.user_type
			and t.usertype not in (80,18)		/* No SYSNAME or TIMESTAMP */
			and t.usertype < 100				/* No user defined types */
			and t.type not in (111,109,38,110)	/* get rid of nullable types */
		UNION ALL
		select	/* SQL Server SYSNAME, TIMESTAMP and user data types */
			type_name = t.name,
			d.data_type,
			"precision" = isnull(d.data_precision, convert(int,t.length)),
			d.literal_prefix,
			d.literal_suffix,
			e.create_params,
			d.nullable,
			d.case_sensitive,
			d.searchable,
			d.unsigned_attribute,
			d.money,
			d.auto_increment,
			t.name,
			minimum_scale = d.numeric_scale,
			maximum_scale = d.numeric_scale,
			t.usertype
		from master.dbo.spt_datatype_info d, master.dbo.spt_datatype_info_ext e, systypes t
		where
			d.ss_dtype = t.type
			and t.usertype *= e.user_type
			and (t.usertype in (80,18)			/* SYSNAME or TIMESTAMP */
				or t.usertype >= 100)			/* User defined types */
			and t.type not in (111,109,38,110)	/* get rid of nullable types */
		order by d.data_type, d.auto_increment, d.money, t.usertype

	else
		select	/* Real SQL Server data types */
			type_name = t.name,
			d.data_type,
			"precision" = isnull(d.data_precision, convert(int,t.length)),
			d.literal_prefix,
			d.literal_suffix,
			e.create_params,
			d.nullable,
			d.case_sensitive,
			d.searchable,
			d.unsigned_attribute,
			d.money,
			d.auto_increment,
			d.local_type_name,
			minimum_scale = d.numeric_scale,
			maximum_scale = d.numeric_scale,
			t.usertype
		from master.dbo.spt_datatype_info d, master.dbo.spt_datatype_info_ext e, systypes t
		where
			data_type = @data_type
			and d.ss_dtype = t.type
			and t.usertype *= e.user_type
			and t.usertype not in (80,18)		/* No SYSNAME or TIMESTAMP */
			and t.usertype < 100				/* No user defined types */
			and t.type not in (111,109,38,110)	/* get rid of nullable types */
		UNION ALL
		select	/* SQL Server SYSNAME, TIMESTAMP and user data types */
			type_name = t.name,
			d.data_type,
			"precision" = isnull(d.data_precision, convert(int,t.length)),
			d.literal_prefix,
			d.literal_suffix,
			e.create_params,
			d.nullable,
			d.case_sensitive,
			d.searchable,
			d.unsigned_attribute,
			d.money,
			d.auto_increment,
			t.name,
			minimum_scale = d.numeric_scale,
			maximum_scale = d.numeric_scale,
			t.usertype
		from master.dbo.spt_datatype_info d, master.dbo.spt_datatype_info_ext e, systypes t
		where
			data_type = @data_type
			and d.ss_dtype = t.type
			and t.usertype *= e.user_type
			and (t.usertype in (80,18)			/* SYSNAME or TIMESTAMP */
				or t.usertype >= 100)			/* User defined types */
			and t.type not in (111,109,38,110)	/* get rid of nullable types */
		order by d.auto_increment, d.money, t.usertype

go

if	(charindex('6.00', @@version) = 0)
begin
	print ''
	print ''
	print 'Warning:'
	print 'you are installing the stored procedures '
	print 'on a pre 6.0 SQL Server.'
	print 'Ignore the following errors.'
end
else
	drop proc sp_datatype_info
go

/*	Procedure for 6.0 server */
create proc sp_datatype_info
	(@data_type int = 0, @dummy int = 0)
as
	if @data_type = 0
	   		select	/* Real SQL Server data types */
			type_name = d.type_name,
			d.data_type,
			"precision" = isnull(convert(int,t.prec+d.numdec*(@@max_precision-convert(int,t.prec))), 2147483647),
			d.literal_prefix,
			d.literal_suffix,
			e.create_params,
			nullable = t.allownulls & (~(isnull(d.auto_increment,0))),
			d.case_sensitive,
			d.searchable,
			d.unsigned_attribute,
			d.money,
			d.auto_increment,
			d.local_type_name,
			minimum_scale = d.numeric_scale,
			maximum_scale = convert(smallint,(t.scale+d.numdec*(@@max_precision-convert(int,t.scale)))*(isnull(d.auto_increment,0)^1)),
			t.usertype
		from master.dbo.spt_datatype_info d, master.dbo.spt_datatype_info_ext e, systypes t
		where
			d.ss_dtype = t.type
			and t.usertype *= e.user_type
			and isnull(d.auto_increment,0) *= e.auto_increment
			and t.usertype not in (80,18,24,10)		/* No SYSNAME, TIMESTAMP, DECIMAL,	NUMERIC*/
			and t.usertype < 100				/* No user defined types */
			and t.type not in (111,109,38,110)	/* get rid of nullable types */
		UNION ALL
		select	/* SQL Server SYSNAME, TIMESTAMP and user data types */
			type_name = t.name,
			d.data_type,
			"precision" = isnull(convert(int,t.prec+d.numdec*(@@max_precision-convert(int,t.prec))), 2147483647),
			d.literal_prefix,
			d.literal_suffix,
			e.create_params,
			nullable = t.allownulls & (~(isnull(d.auto_increment,0))),
			d.case_sensitive,
			d.searchable,
			d.unsigned_attribute,
			d.money,
			d.auto_increment,
			t.name,
			minimum_scale = d.numeric_scale,
			maximum_scale = convert(smallint,(t.scale+d.numdec*(@@max_precision-convert(int,t.scale)))*(isnull(d.auto_increment,0)^1)),
			t.usertype
		from master.dbo.spt_datatype_info d, master.dbo.spt_datatype_info_ext e, systypes t
		where
			d.ss_dtype = t.type
			and isnull(d.auto_increment,0) = 0
			and t.usertype *= e.user_type
			and (t.usertype in (80,18)			/* SYSNAME or TIMESTAMP */
				or t.usertype >= 100)			/* User defined types */
			and t.type not in (111,109,38,110)	/* get rid of nullable types */
		order by d.data_type, d.auto_increment, d.money, t.usertype

	else
		select	/* Real SQL Server data types */
			type_name = d.type_name,
			d.data_type,
			"precision" = isnull(convert(int,t.prec+d.numdec*(@@max_precision-convert(int,t.prec))), 2147483647),
			d.literal_prefix,
			d.literal_suffix,
			e.create_params,
			nullable = t.allownulls & (~(isnull(d.auto_increment,0))),
			d.case_sensitive,
			d.searchable,
			d.unsigned_attribute,
			d.money,
			d.auto_increment,
			d.local_type_name,
			minimum_scale = d.numeric_scale,
			maximum_scale = convert(smallint,(t.scale+d.numdec*(@@max_precision-convert(int,t.scale)))*(isnull(d.auto_increment,0)^1)),
			t.usertype
		from master.dbo.spt_datatype_info d, master.dbo.spt_datatype_info_ext e, systypes t
		where
			data_type = @data_type
			and d.ss_dtype = t.type
			and t.usertype *= e.user_type
			and isnull(d.auto_increment,0) *= e.auto_increment
			and t.usertype not in (80,18,24,10)		/* No SYSNAME, TIMESTAMP, DECIMAL,	NUMERIC*/
			and t.usertype < 100				/* No user defined types */
			and t.type not in (111,109,38,110)	/* get rid of nullable types */
		UNION ALL
		select	/* SQL Server SYSNAME, TIMESTAMP and user data types */
			type_name = t.name,
			d.data_type,
			"precision" = isnull(convert(int,t.prec+d.numdec*(@@max_precision-convert(int,t.prec))), 2147483647),
			d.literal_prefix,
			d.literal_suffix,
			e.create_params,
			nullable = t.allownulls & (~(isnull(d.auto_increment,0))),
			d.case_sensitive,
			d.searchable,
			d.unsigned_attribute,
			d.money,
			d.auto_increment,
			t.name,
			minimum_scale = d.numeric_scale,
			maximum_scale = convert(smallint,(t.scale+d.numdec*(@@max_precision-convert(int,t.scale)))*(isnull(d.auto_increment,0)^1)),
			t.usertype
		from master.dbo.spt_datatype_info d, master.dbo.spt_datatype_info_ext e, systypes t
		where
			data_type = @data_type
			and d.ss_dtype = t.type
			and isnull(d.auto_increment,0) = 0
			and t.usertype *= e.user_type
			and (t.usertype in (80,18)			/* SYSNAME or TIMESTAMP */
				or t.usertype >= 100)			/* User defined types */
			and t.type not in (111,109,38,110)	/* get rid of nullable types */
		order by d.auto_increment, d.money, t.usertype

go


grant execute on sp_datatype_info to public
go

dump tran master with no_log
go

print 'creating sp_special_columns'
go

dump tran master with no_log
go

/*	Procedure for pre-6.0 server */
CREATE PROCEDURE sp_special_columns (
				 @table_name		varchar(32),
				 @table_owner		varchar(32) = null,
				 @table_qualifier	varchar(32) = null,
				 @col_type			char(1) = 'R',
				 @scope				char(1) = 'T',
				 @nullable			char(1) = 'U')
AS
	DECLARE @indid				int
	DECLARE @table_id			int
    DECLARE @full_table_name    char(70)
	DECLARE @msg				char(70)
	DECLARE @scopeout			smallint

	if @col_type not in ('R','V')
		begin
			raiserror 20002 'Illegal ''col_type'' specified -- must be ''R'' or ''V''.'
			return
		end

	if @scope = 'C'
		select @scopeout = 0
	else if @scope = 'T'
		select @scopeout = 1
	else
		begin
			raiserror 20002 'Illegal ''scope'' specified -- must be ''C'' or ''T''.'
			return
		end

	if @nullable not in ('U','O')
		begin
			raiserror 20002 'Illegal ''nullable'' specified -- must be ''U'' or ''O''.'
			return
		end

    if @table_qualifier is not null
	   begin
		  if db_name() != @table_qualifier
		      begin	/* If qualifier doesn't match current database */
				raiserror 20001 'Table qualifier must be name of current database'
			    return
		      end
	   end
    if @table_owner is null
	   begin	/* If unqualified table name */
		  SELECT @full_table_name = @table_name
       end
    else
	   begin	/* Qualified table name */
		  SELECT @full_table_name = @table_owner + '.' + @table_name
       end
	/*	Get Object ID */
	SELECT @table_id = object_id(@full_table_name)

    if @col_type = 'V'
	BEGIN /* if ROWVER, just run that query */
		SELECT
			scope = convert(smallint,NULL),
			column_name = c.name,
			data_type = convert(smallint, -3),
			type_name = t.name,
			"precision" = convert(int,8),
			length = convert(int,8),
			scale = convert(smallint, NULL),
			pseudo_column = convert(smallint,1)
		FROM
			systypes t, syscolumns c, master.dbo.spt_datatype_info d
		WHERE
			c.id = @table_id
			AND c.type = d.ss_dtype
			AND c.usertype = 80 /*	TIMESTAMP */
			AND t.usertype = 80 /*	TIMESTAMP */
		RETURN
	END

	/* ROWID, now find the id of the 'best' index for this table */

	IF @nullable = 'O'	/* Don't include any indexes that contain
						   nullable columns. */

			SELECT @indid = MIN(indid)
				FROM sysindexes i,syscolumns c,syscolumns c2
				WHERE
					i.status&2 = 2		/*	If Unique Index */
		 			AND c.id = i.id
		 			AND c2.id = c.id
		 			AND c2.colid < i.keycnt + (i.status&16)/16
					AND i.id = @table_id
					AND indid > 0		/*	Eliminate Table Row */
					AND c.name = index_col(@table_name,i.indid,c2.colid)
					GROUP BY indid HAVING SUM(c.status&8) = 0

	ELSE	/* Include indexes that are partially nullable. */

		SELECT @indid = MIN(indid)
			FROM sysindexes i
			WHERE
				status&2 = 2		/*	If Unique Index */
				AND id = @table_id
				AND indid > 0		/*	Eliminate Table Row */

	SELECT
		scope = @scopeout,
		column_name = INDEX_COL(@full_table_name,indid,c.colid),
		data_type = d.data_type+convert(smallint,
						isnull(d.aux,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('666AAA@@@CB??GG',
						2*(d.ss_dtype%35+1)+2-8/c2.length,1))
						-60)),
		type_name = rtrim(substring(d.type_name,
						1+isnull(d.aux,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('III<<<MMMI<<A<A',
						2*(d.ss_dtype%35+1)+2-8/c2.length,
						1))-60), 13)),
		"precision" = isnull(d.data_precision, convert(int,c2.length))
						+isnull(d.aux, convert(int,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('???AAAFFFCKFOLS',
						2*(d.ss_dtype%35+1)+2-8/c2.length,1))-60)),
		length = isnull(d.length, convert(int,c2.length)) +convert(int,
						isnull(d.aux,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('AAA<BB<DDDHLUPP',
						2*(d.ss_dtype%35+1)+2-8/c2.length,
						1))-64)),
		scale = d.numeric_scale +convert(smallint,
						isnull(d.aux,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('<<<<<<<<<<<<<<?',
						2*(d.ss_dtype%35+1)+2-8/c2.length,
						1))-60)),
		pseudo_column = convert(smallint,1)
	FROM
		sysindexes x,
		syscolumns c,
		master.dbo.spt_datatype_info d,
		systypes t,
		syscolumns c2	/* Self-join to generate list of index columns and */
						/* to extract datatype names */
	WHERE
		x.id = @table_id
		AND c2.name = INDEX_COL(@full_table_name,@indid,c.colid)
		AND c2.id =x.id
		AND c.id = x.id
		AND c.colid < keycnt+(x.status&16)/16
		AND x.indid = @indid
		AND c2.type = d.ss_dtype
		AND c2.usertype *= t.usertype

go

if	(charindex('6.00', @@version) = 0)
begin
	print ''
	print ''
	print 'Warning:'
	print 'you are installing the stored procedures '
	print 'on a pre 6.0 SQL Server.'
	print 'Ignore the following errors.'
end
else
	drop proc sp_special_columns
go

/*	Procedure for 6.0 server */
CREATE PROCEDURE sp_special_columns (
				 @table_name		varchar(32),
				 @table_owner		varchar(32) = null,
				 @table_qualifier	varchar(32) = null,
				 @col_type			char(1) = 'R',
				 @scope				char(1) = 'T',
				 @nullable			char(1) = 'U')
AS
	DECLARE @indid				int
	DECLARE @table_id			int
    DECLARE @full_table_name    char(70)
	DECLARE @msg				char(70)
	DECLARE @scopeout			smallint

	if @col_type not in ('R','V')
		begin
			raiserror (15251,-1,-1,'col_type','''R'' or ''V''')
			return
		end

	if @scope = 'C'
		select @scopeout = 0
	else if @scope = 'T'
		select @scopeout = 1
	else
		begin
			raiserror (15251,-1,-1,'scope','''C'' or ''T''')
			return
		end

	if @nullable not in ('U','O')
		begin
			raiserror (15251,-1,-1,'nullable','''U'' or ''O''')
			return
		end

    if @table_qualifier is not null
	   begin
		  if db_name() != @table_qualifier
		      begin	/* If qualifier doesn't match current database */
				raiserror (15250, -1,-1,'Table')
			    return
		      end
	   end
    if @table_owner is null
	   begin	/* If unqualified table name */
		  SELECT @full_table_name = @table_name
       end
    else
	   begin	/* Qualified table name */
		  SELECT @full_table_name = @table_owner + '.' + @table_name
       end
	/*	Get Object ID */
	SELECT @table_id = object_id(@full_table_name)

    if @col_type = 'V'
	BEGIN /* if ROWVER, just run that query */
		SELECT
			scope = convert(smallint,NULL),
			column_name = c.name,
			data_type = convert(smallint, -2),
			type_name = t.name,
			"precision" = convert(int,8),
			length = convert(int,8),
			scale = convert(smallint, NULL),
			pseudo_column = convert(smallint,1)
		FROM
			systypes t, syscolumns c, master.dbo.spt_datatype_info d
		WHERE
			c.id = @table_id
			AND c.type = d.ss_dtype
			AND c.usertype = 80 /*	TIMESTAMP */
			AND t.usertype = 80 /*	TIMESTAMP */
		RETURN
	END

	/* ROWID, now find the id of the 'best' index for this table */

	IF @nullable = 'O'	/* Don't include any indexes that contain
						   nullable columns. */

			SELECT @indid = MIN(indid)
				FROM sysindexes i,syscolumns c,syscolumns c2
				WHERE
					i.status&2 = 2		/*	If Unique Index */
		 			AND c.id = i.id
		 			AND c2.id = c.id
		 			AND c2.colid < i.keycnt + (i.status&16)/16
					AND i.id = @table_id
					AND indid > 0		/*	Eliminate Table Row */
					AND c.name = index_col(@table_name,i.indid,c2.colid)
					GROUP BY indid HAVING SUM(c.status&8) = 0

	ELSE	/* Include indexes that are partially nullable. */

		SELECT @indid = MIN(indid)
			FROM sysindexes i
			WHERE
				status&2 = 2		/*	If Unique Index */
				AND id = @table_id
				AND indid > 0		/*	Eliminate Table Row */

	SELECT	/* INTn, FLOATn, DATETIMEn and MONEYn types */
		scope = @scopeout,
		column_name = INDEX_COL(@full_table_name,indid,c2.colid),
		data_type = d.data_type+convert(smallint,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('666AAA@@@CB??GG',
						2*(d.ss_dtype%35+1)+2-8/c.length,1))
						-60),
		type_name = rtrim(substring(d.type_name,
						1+
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('III<<<MMMI<<A<A',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-60, 13)),
		"precision" = convert(int,c.prec),
		length = d.length + convert(int,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('AAA<BB<DDDHLUPP',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-64),
		scale = convert(smallint, c.scale),
		pseudo_column = convert(smallint,1)
	FROM
		sysindexes x,
		syscolumns c,
		master.dbo.spt_datatype_info d,
		systypes t,
		syscolumns c2	/* Self-join to generate list of index columns and */
						/* to extract datatype names */
	WHERE
		x.id = @table_id
		AND c.name = INDEX_COL(@full_table_name,@indid,c2.colid)
		AND c.id = x.id
		AND c2.id = x.id
		AND c2.colid < x.keycnt+(x.status&16)/16
		AND x.indid = @indid
		AND c.type = d.ss_dtype
		AND c.usertype = t.usertype
		AND d.ss_dtype IN (111, 109, 38, 110)	/* Just *N types */
		AND c.usertype < 100					/* No user defined types */
	UNION ALL
	SELECT	/* Identity base and decimal/numeric types */
		scope = @scopeout,
		column_name = INDEX_COL(@full_table_name,indid,c2.colid),
		data_type = convert(smallint,
				/*	Map systypes.type to ODBC type */
				/*		SS-Type 		"	 1 1	    	 1	       "*/
				/*						"33 3030    4 44 5 5 255 556666"*/
				/*						"45 7698    5 78 0 2 256 890123"*/
						ascii(substring('8;<9?H><<<<:<=6<5<A<??@<GC?GB>',
						t.type%34+1,1))-60),
		type_name = d.type_name,
		"precision" = convert(int,c.prec),
		length = convert(int,c.length) +
				(convert(int,(c.type & 2)/2) |
				(convert(int,c.type&64)/64))*(c.prec+2 - c.length),
		scale = convert(smallint, c.scale),
		pseudo_column = convert(smallint,1)
	FROM
		sysindexes x,
		syscolumns c,
		master.dbo.spt_datatype_info d,
		systypes t,
		syscolumns c2	/* Self-join to generate list of index columns and */
						/* to extract datatype names */
	WHERE
		x.id = @table_id
		AND c.name = INDEX_COL(@full_table_name,@indid,c2.colid)
		AND c.id = x.id
		AND c2.id = x.id
		AND c2.colid < x.keycnt+(x.status&16)/16
		AND x.indid = @indid
		AND c.type = d.ss_dtype
		AND d.auto_increment = (c.status&128)/128
		AND c.usertype = t.usertype
		AND ((c.usertype < 100			/* Only base types */
			AND c.status&128 = 128)		/* Identity types only */
			OR d.ss_dtype IN (106, 108, 55, 63))	 /* decimal/numeric types */
	UNION ALL
	SELECT	/* All other types including user data types */
		scope = @scopeout,
		column_name = INDEX_COL(@full_table_name,indid,c2.colid),
		data_type = convert(smallint,
				/*	Map systypes.type to ODBC type */
				/*		SS-Type 		"	 1 1	    	 1	       "*/
				/*						"33 3030    4 44 5 5 255 556666"*/
				/*						"45 7698    5 78 0 2 256 890123"*/
						ascii(substring('8;<9?H><<<<:<=6<5<A<??@<GC?GB>',
						t.type%34+1,1))-60),
		type_name = t.name,
		"precision" = isnull(convert(int,c.prec), 2147483647),
		length = isnull(d.length, convert(int,c.length)) +convert(int,
						isnull(d.aux,
						/*				" I   I I FFMMDD" */
						/*				" 1   2 4 484848" */
						ascii(substring('AAA<BB<DDDHLUPP',
						2*(d.ss_dtype%35+1)+2-8/c.length,
						1))-64)),
		scale = convert(smallint, c.scale),
		pseudo_column = convert(smallint,1)
	FROM
		sysindexes x,
		syscolumns c,
		master.dbo.spt_datatype_info d,
		systypes t,
		syscolumns c2	/* Self-join to generate list of index columns and */
						/* to extract datatype names */
	WHERE
		x.id = @table_id
		AND c.name = INDEX_COL(@full_table_name,@indid,c2.colid)
		AND c.id = x.id
		AND c2.id = x.id
		AND c2.colid < x.keycnt+(x.status&16)/16
		AND x.indid = @indid
		AND c.type = d.ss_dtype
		AND isnull(d.auto_increment,0) = 0
		AND (c.status&128 = 0			/* No Identity types unless */
			OR c.usertype >= 100)		/* User defined type */
		AND c.usertype *= t.usertype
		AND (d.ss_dtype NOT IN (111, 109, 38, 110)	/* No *N types */
			OR c.usertype >= 100)					/* User defined types */
		AND d.ss_dtype NOT IN (106, 108, 55, 63)	/* No decimal/numeric types */
go

grant execute on sp_special_columns to public
go

print 'creating sp_databases'
go

create proc sp_databases
as
	/* Use temporary table to sum up database size w/o using group by */
	create table #databases (
				  database_name varchar(32) NOT NULL,
				  size int NOT NULL)

	/* Insert row for each database */
	insert into #databases
		select
			name,
			(select sum(size) from master.dbo.sysusages
				where dbid = d.dbid)
		from master.dbo.sysdatabases d

	select
		 database_name,
		 database_size = size*2,	/* Convert from 2048 byte pages to K */
		 remarks = convert(varchar(254),null)	/* Remarks are NULL */
	from #databases
	order by database_name
go

grant execute on sp_databases to public
go

if exists (select * from sysobjects where name = 'sp_configure'
			and sysstat & 0xf = 4)
	begin
		exec sp_configure 'allow updates',0
		reconfigure with override
	end
go

if exists (select * from sysobjects where name = 'sp_check_objects'
			and sysstat & 0xf = 4)
	begin
		/* Only supported on 6.0 servers */
		print ''
		print 'Checking objects created by instcat.sql.'

		exec sp_check_objects 'catalog'
	end
go

print ''
print 'inscat.sql completed successfully.'
go

dump tran master with no_log
go
checkpoint
go
