破解加密的SQL Server 2k/2k5存儲(chǔ)過程

2010-08-28 10:52:45來源:西部e網(wǎng)作者:

SQL Server加密存儲(chǔ)過程用到“WITH ENCRYPTION”參數(shù)的時(shí)候,就可以將它加密,這種加密方式是不可逆的,再也不能打開了,嗚嗚~那么我們改怎么樣才能看到原來的代碼而不破壞這個(gè)存儲(chǔ)過程呢?icech在網(wǎng)上找到了兩個(gè)十分十分大牛的人!一個(gè)是j9988,早在2004年就寫了一個(gè)可以破解加密的存儲(chǔ)過程,支持SQL Server 2000非常的好;另一個(gè)是王成輝翻譯老外寫的一個(gè),竟然可以支持SQL Server 2005版本!

如何加密SQL Server存儲(chǔ)過程?

命令如:
CREATE Procedure 存儲(chǔ)過程名(...) WITH ENCRYPTION AS ...

SQLServer2005里使用with encryption選項(xiàng)創(chuàng)建的存儲(chǔ)過程仍然和sqlserver2000里一樣,都是使用XOR進(jìn)行了的加密。和2000不一樣的是,在2005的系統(tǒng)表syscomments里已經(jīng)查不到加密過的密文了。要查密文必須使用DAC(專用管理員連接)連接到數(shù)據(jù)庫后,在系統(tǒng)表sys.sysobjvalues查詢,該表的列imageval存儲(chǔ)了相應(yīng)的密文。具體可以使用下面的查詢:

SELECT imageval FROM sys.sysobjvalues WHERE objid = object_id(@procedure) AND
valclass = 1 AND subobjid = 1

針對(duì)SQL Server 2000的解密存儲(chǔ)過程

create  PROCEDURE sp_decrypt(@objectname varchar(50))
AS
begin
set nocount on
--CSDN:j9988 copyright:2004.07.15
--V3.2
--破解字節(jié)不受限制,適用于SQLSERVER2000存儲(chǔ)過程,函數(shù),視圖,觸發(fā)器
--修正上一版"視圖觸發(fā)器"不能正確解密錯(cuò)誤
--發(fā)現(xiàn)有錯(cuò),請(qǐng)E_MAIL:CSDNj9988@tom.com
begin tran
declare @objectname1 varchar(100),@orgvarbin varbinary(8000)
declare @sql1 nvarchar(4000),@sql2 varchar(8000),@sql3 nvarchar(4000),@sql4 nvarchar(4000)
DECLARE  @OrigSpText1 nvarchar(4000),  @OrigSpText2 nvarchar(4000) , @OrigSpText3 nvarchar(4000), @resultsp nvarchar(4000)
declare  @i int,@status int,@type varchar(10),@parentid int
declare @colid int,@n int,@q int,@j int,@k int,@encrypted int,@number int
select @type=xtype,@parentid=parent_obj from sysobjects where id=object_id(@objectname)

create table  #temp(number int,colid int,ctext varbinary(8000),encrypted int,status int)
insert #temp SELECT number,colid,ctext,encrypted,status FROM syscomments  WHERE id = object_id(@objectname)
select @number=max(number) from #temp
set @k=0

while @k<=@number
begin
if exists(select 1 from syscomments where id=object_id(@objectname) and number=@k)
begin
if @type='P'
set @sql1=(case when @number>1 then 'ALTER PROCEDURE '+ @objectname +';'+rtrim(@k)+' WITH ENCRYPTION AS '
                          else 'ALTER PROCEDURE '+ @objectname+' WITH ENCRYPTION AS '
                          end)

if @type='TR'
begin
declare @parent_obj varchar(255),@tr_parent_xtype varchar(10)
select @parent_obj=parent_obj from sysobjects where id=object_id(@objectname)
select @tr_parent_xtype=xtype from sysobjects where id=@parent_obj
if @tr_parent_xtype='V'
begin
set @sql1='ALTER TRIGGER '+@objectname+' ON '+OBJECT_NAME(@parentid)+' WITH ENCRYPTION INSTERD OF INSERT AS PRINT 1 '
end
else
begin
set @sql1='ALTER TRIGGER '+@objectname+' ON '+OBJECT_NAME(@parentid)+' WITH ENCRYPTION FOR INSERT AS PRINT 1 '
end

end
if @type='FN' or @type='TF' or @type='IF'
set @sql1=(case @type when 'TF' then
'ALTER FUNCTION '+ @objectname+'(@a char(1)) returns @b table(a varchar(10)) with encryption as begin insert @b select @a return end '
when 'FN' then
'ALTER FUNCTION '+ @objectname+'(@a char(1)) returns char(1) with encryption as begin return @a end'
when 'IF' then
'ALTER FUNCTION '+ @objectname+'(@a char(1)) returns table with encryption as return select @a as a'
end)

if @type='V'
set @sql1='ALTER VIEW '+@objectname+' WITH ENCRYPTION AS SELECT 1 as f'

set @q=len(@sql1)
set @sql1=@sql1+REPLICATE('-',4000-@q)
select @sql2=REPLICATE('-',8000)
set @sql3='exec(@sql1'
select @colid=max(colid) from #temp where number=@k
set @n=1
while @n<=CEILING(1.0*(@colid-1)/2) and len(@sql3)<=3996
begin
set @sql3=@sql3+'+@'
set @n=@n+1
end
set @sql3=@sql3+')'
exec sp_executesql @sql3,N'@sql1 nvarchar(4000),@ varchar(8000)',@sql1=@sql1,@=@sql2

end
set @k=@k+1
end

set @k=0
while @k<=@number
begin

if exists(select 1 from syscomments where id=object_id(@objectname) and number=@k)
begin
select @colid=max(colid) from #temp where number=@k
set @n=1

while @n<=@colid
begin
select @OrigSpText1=ctext,@encrypted=encrypted,@status=status FROM #temp  WHERE colid=@n and number=@k

SET @OrigSpText3=(SELECT ctext FROM syscomments WHERE id=object_id(@objectname) and colid=@n and number=@k)
if @n=1
begin
if @type='P'
SET @OrigSpText2=(case when @number>1 then 'CREATE PROCEDURE '+ @objectname +';'+rtrim(@k)+' WITH ENCRYPTION AS '
                       else 'CREATE PROCEDURE '+ @objectname +' WITH ENCRYPTION AS '
                       end)


if @type='FN' or @type='TF' or @type='IF'
SET @OrigSpText2=(case @type when 'TF' then
'CREATE FUNCTION '+ @objectname+'(@a char(1)) returns @b table(a varchar(10)) with encryption as begin insert @b select @a return end '
when 'FN' then
'CREATE FUNCTION '+ @objectname+'(@a char(1)) returns char(1) with encryption as begin return @a end'
when 'IF' then
'CREATE FUNCTION '+ @objectname+'(@a char(1)) returns table with encryption as return select @a as a'
end)

if @type='TR'
begin

if @tr_parent_xtype='V'
begin
set @OrigSpText2='CREATE TRIGGER '+@objectname+' ON '+OBJECT_NAME(@parentid)+' WITH ENCRYPTION INSTEAD OF INSERT AS PRINT 1 '
end
else
begin
set @OrigSpText2='CREATE TRIGGER '+@objectname+' ON '+OBJECT_NAME(@parentid)+' WITH ENCRYPTION FOR INSERT AS PRINT 1 '
end

end

if @type='V'
set @OrigSpText2='CREATE VIEW '+@objectname+' WITH ENCRYPTION AS SELECT 1 as f'

set @q=4000-len(@OrigSpText2)
set @OrigSpText2=@OrigSpText2+REPLICATE('-',@q)
end
else
begin
SET @OrigSpText2=REPLICATE('-', 4000)
end
SET @i=1

SET @resultsp = replicate(N'A', (datalength(@OrigSpText1) / 2))

WHILE @i<=datalength(@OrigSpText1)/2
BEGIN

SET @resultsp = stuff(@resultsp, @i, 1, NCHAR(UNICODE(substring(@OrigSpText1, @i, 1)) ^
                                (UNICODE(substring(@OrigSpText2, @i, 1)) ^
                                UNICODE(substring(@OrigSpText3, @i, 1)))))
 SET @i=@i+1
END
set @orgvarbin=cast(@OrigSpText1 as varbinary(8000))
set @resultsp=(case when @encrypted=1
                    then @resultsp
                    else convert(nvarchar(4000),case when @status&2=2 then uncompress(@orgvarbin) else @orgvarbin end)
               end)
print @resultsp

set @n=@n+1

end

end
set @k=@k+1
end

drop table #temp
rollback tran
end


針對(duì)SQL Server 2005的解密存儲(chǔ)過程

create PROCEDURE [dbo].[sp__windbi$decrypt]
(@procedure sysname = NULL, @revfl int = 1)
AS
/*
王成輝翻譯整理,轉(zhuǎn)貼請(qǐng)注明出自微軟BI開拓者www.windbi.com
目前這個(gè)存儲(chǔ)過程只能解密存儲(chǔ)過程,至于解密函數(shù)、觸發(fā)器、視圖的存儲(chǔ)過程本網(wǎng)站會(huì)進(jìn)一步關(guān)注,調(diào)用形式為:
exec dbo.sp__windbi$decrypt @procedure,0
如果第二個(gè)參數(shù)使用1的話,會(huì)給出該存儲(chǔ)過程的一些提示。
--版本2.0
*/
SET NOCOUNT ON
IF @revfl = 1
BEGIN
PRINT '警告:該存儲(chǔ)過程會(huì)刪除并重建原始的存儲(chǔ)過程。'
PRINT ' 在運(yùn)行該存儲(chǔ)過程之前確保你的數(shù)據(jù)庫有一個(gè)備份。'
PRINT ' 該存儲(chǔ)過程通常應(yīng)該運(yùn)行在產(chǎn)品環(huán)境的一個(gè)備份的非產(chǎn)品環(huán)境下。'
PRINT ' 為了運(yùn)行這個(gè)存儲(chǔ)過程,將參數(shù)@refl的值更改為0。'
RETURN 0
END
DECLARE @intProcSpace bigint, @t bigint, @maxColID smallint,@intEncrypted
tinyint,@procNameLength int
select @maxColID = max(subobjid),@intEncrypted = imageval FROM
sys.sysobjvalues WHERE objid = object_id(@procedure)
GROUP BY imageval
--select @maxColID as 'Rows in sys.sysobjvalues'
select @procNameLength = datalength(@procedure) + 29
DECLARE @real_01 nvarchar(max)
DECLARE @fake_01 nvarchar(max)
DECLARE @fake_encrypt_01 nvarchar(max)
DECLARE @real_decrypt_01 nvarchar(max),@real_decrypt_01a nvarchar(max)
declare @objtype varchar(2),@ParentName nvarchar(max)
select @real_decrypt_01a = ''
--提取對(duì)象的類型如是存儲(chǔ)過程還是函數(shù),如果是觸發(fā)器,還要得到其父對(duì)象的名稱
select @objtype=type,@parentname=object_name(parent_object_id)
from sys.objects where [object_id]=object_id(@procedure)
-- 從sys.sysobjvalues里提出加密的imageval記錄
SET @real_01=(SELECT top 1 imageval FROM sys.sysobjvalues WHERE objid =
object_id(@procedure) and valclass = 1 order by subobjid)
--創(chuàng)建一個(gè)臨時(shí)表
create table #output ( [ident] [int] IDENTITY (1, 1) NOT NULL ,
[real_decrypt] NVARCHAR(MAX) )
--開始一個(gè)事務(wù),稍后回滾
BEGIN TRAN
--更改原始的存儲(chǔ)過程,用短橫線替換
if @objtype='P'
  SET @fake_01='ALTER PROCEDURE '+ @procedure +' WITH ENCRYPTION AS
  '+REPLICATE('-', 40003 - @procNameLength)
else if @objtype='FN'
  SET @fake_01='ALTER FUNCTION '+ @procedure +'() RETURNS INT WITH ENCRYPTION AS BEGIN RETURN 1
  /*'+REPLICATE('*', datalength(@real_01) /2 - @procNameLength)+'*/ END'
else if @objtype='V'
  SET @fake_01='ALTER view '+ @procedure +' WITH ENCRYPTION AS select 1 as col
  /*'+REPLICATE('*', datalength(@real_01) /2 - @procNameLength)+'*/'
else if @objtype='TR'
  SET @fake_01='ALTER trigger '+ @procedure +' ON '+@parentname+' WITH ENCRYPTION AFTER INSERT AS RAISERROR (''N'',16,10)
  /*'+REPLICATE('*', datalength(@real_01) /2 - @procNameLength)+'*/'
EXECUTE (@fake_01)
--從sys.sysobjvalues里提出加密的假的
SET @fake_encrypt_01=(SELECT top 1 imageval FROM sys.sysobjvalues WHERE objid =
object_id(@procedure) and valclass = 1 order by subobjid )
if @objtype='P'
  SET @fake_01='Create PROCEDURE '+ @procedure +' WITH ENCRYPTION AS
  '+REPLICATE('-', 40003 - @procNameLength)
else if @objtype='FN'
  SET @fake_01='CREATE FUNCTION '+ @procedure +'() RETURNS INT WITH ENCRYPTION AS BEGIN RETURN 1
  /*'+REPLICATE('*', datalength(@real_01) /2 - @procNameLength)+'*/ END'
else if @objtype='V'
  SET @fake_01='Create view '+ @procedure +' WITH ENCRYPTION AS select 1 as col
  /*'+REPLICATE('*', datalength(@real_01) /2 - @procNameLength)+'*/'
else if @objtype='TR'
  SET @fake_01='Create trigger '+ @procedure +' ON '+@parentname+' WITH ENCRYPTION AFTER INSERT AS RAISERROR (''N'',16,10)
  /*'+REPLICATE('*', datalength(@real_01) /2 - @procNameLength)+'*/'
--開始計(jì)數(shù)
SET @intProcSpace=1
--使用字符填充臨時(shí)變量
SET @real_decrypt_01 = replicate(N'A', (datalength(@real_01) /2 ))
--循環(huán)設(shè)置每一個(gè)變量,創(chuàng)建真正的變量
--每次一個(gè)字節(jié)
SET @intProcSpace=1
--如有必要,遍歷每個(gè)@real_xx變量并解密
WHILE @intProcSpace<=(datalength(@real_01)/2)
BEGIN
--真的和假的和加密的假的進(jìn)行異或處理
SET @real_decrypt_01 = stuff(@real_decrypt_01, @intProcSpace, 1,
NCHAR(UNICODE(substring(@real_01, @intProcSpace, 1)) ^
(UNICODE(substring(@fake_01, @intProcSpace, 1)) ^
UNICODE(substring(@fake_encrypt_01, @intProcSpace, 1)))))
SET @intProcSpace=@intProcSpace+1
END
--通過sp_helptext邏輯向表#output里插入變量
insert #output (real_decrypt) select @real_decrypt_01
-- select real_decrypt AS '#output chek' from #output --測(cè)試
-- -------------------------------------
--開始從sp_helptext提取
-- -------------------------------------
declare @dbname sysname
,@BlankSpaceAdded int
,@BasePos int
,@CurrentPos int
,@TextLength int
,@LineId int
,@AddOnLen int
,@LFCR int --回車換行的長度
,@DefinedLength int
,@SyscomText nvarchar(4000)
,@Line nvarchar(255)
Select @DefinedLength = 255
SELECT @BlankSpaceAdded = 0 --跟蹤行結(jié)束的空格。注意Len函數(shù)忽略了多余的空格
CREATE TABLE #CommentText
(LineId int
,Text nvarchar(255) collate database_default)
--使用#output代替sys.sysobjvalues
DECLARE ms_crs_syscom CURSOR LOCAL
FOR SELECT real_decrypt from #output
ORDER BY ident
FOR READ ONLY
--獲取文本
SELECT @LFCR = 2
SELECT @LineId = 1
OPEN ms_crs_syscom
FETCH NEXT FROM ms_crs_syscom into @SyscomText
WHILE @@fetch_status >= 0
BEGIN
SELECT @BasePos = 1
SELECT @CurrentPos = 1
SELECT @TextLength = LEN(@SyscomText)
WHILE @CurrentPos != 0
BEGIN
--通過回車查找行的結(jié)束
SELECT @CurrentPos = CHARINDEX(char(13)+char(10), @SyscomText,
@BasePos)
--如果找到回車
IF @CurrentPos != 0
BEGIN
--如果@Lines的長度的新值比設(shè)置的大就插入@Lines目前的內(nèi)容并繼續(xù)
While (isnull(LEN(@Line),0) + @BlankSpaceAdded +
@CurrentPos-@BasePos + @LFCR) > @DefinedLength
BEGIN
SELECT @AddOnLen = @DefinedLength-(isnull(LEN(@Line),0) +
@BlankSpaceAdded)
INSERT #CommentText VALUES
( @LineId,
isnull(@Line, N'') + isnull(SUBSTRING(@SyscomText,
@BasePos, @AddOnLen), N''))
SELECT @Line = NULL, @LineId = @LineId + 1,
@BasePos = @BasePos + @AddOnLen, @BlankSpaceAdded = 0
END
SELECT @Line = isnull(@Line, N'') +
isnull(SUBSTRING(@SyscomText, @BasePos, @CurrentPos-@BasePos + @LFCR), N'')
SELECT @BasePos = @CurrentPos+2
INSERT #CommentText VALUES( @LineId, @Line )
SELECT @LineId = @LineId + 1
SELECT @Line = NULL
END
ELSE
--如果回車沒找到
BEGIN
IF @BasePos <= @TextLength
BEGIN
--如果@Lines長度的新值大于定義的長度
While (isnull(LEN(@Line),0) + @BlankSpaceAdded +
@TextLength-@BasePos+1 ) > @DefinedLength
BEGIN
SELECT @AddOnLen = @DefinedLength -
(isnull(LEN(@Line),0) + @BlankSpaceAdded)
INSERT #CommentText VALUES
( @LineId,
isnull(@Line, N'') + isnull(SUBSTRING(@SyscomText,
@BasePos, @AddOnLen), N''))
SELECT @Line = NULL, @LineId = @LineId + 1,
@BasePos = @BasePos + @AddOnLen, @BlankSpaceAdded =
0
END
SELECT @Line = isnull(@Line, N'') +
isnull(SUBSTRING(@SyscomText, @BasePos, @TextLength-@BasePos+1 ), N'')
if LEN(@Line) < @DefinedLength and charindex(' ',
@SyscomText, @TextLength+1 ) > 0
BEGIN
SELECT @Line = @Line + ' ', @BlankSpaceAdded = 1
END
END
END
END
FETCH NEXT FROM ms_crs_syscom into @SyscomText
END
IF @Line is NOT NULL
INSERT #CommentText VALUES( @LineId, @Line )
select Text from #CommentText order by LineId
CLOSE ms_crs_syscom
DEALLOCATE ms_crs_syscom
DROP TABLE #CommentText
-- -------------------------------------
--結(jié)束從sp_helptext提取
-- -------------------------------------
--刪除用短橫線創(chuàng)建的存儲(chǔ)過程并重建原始的存儲(chǔ)過程
ROLLBACK TRAN
DROP TABLE #output


英文原文:
http://www.derkeiler.com/Newsgroups/microsoft.public.sqlserver.security/2006-08/msg00286.html

SQL 2005 still obfuscates object encryption in a similar manner to SQL 2000.
It is simply an XOR of the encrypted bytes against a known sample to dump
out the real unencrypted bytes. The trick is getting to the the encrypted
bytes. In SQL 2005, instead of querying the SYSCOMMENTS view to get the
binary bytes to decrypt, you need to run the following query from the
dedicated admin connection (DAC) to get the bytes to decrypt:

SELECT imageval FROM sys.sysobjvalues WHERE id = object_id(@procedure) AND
valclass = 1 AND subobjid = 1

where @procedure is the name of the object that you want to decrypt. The
table sys.sysobjvalues is one of those new system tables that is normally
hidden. It is actually easier in SQL 2005 because you don't have to string
together 4000 character blocks from SYSCOMMENTS records like you had to do
in SQL 2000. Code to do the XOR on SQL 2000 is well documented on the web.
I'm including my work below.

This is code that I quickly rolled together from my old SQL 2000 decrypt
code. It isn't perfect yet but should get you down the line. It only does
procedures. It actually wraps the ALTER PROCEDURE in a rolled-back
transaction so it shouldn't be too problematic. Then again my local copy of
SQL Server 2005 only starts with the -f flag this morning ;-). Have fun.

Chuck


CREATE PROCEDURE dbo.sp__procedure$decrypt
(@procedure sysname = NULL, @revfl int = 1)
AS
SET NOCOUNT ON

IF @revfl = 1
BEGIN
PRINT 'CAUTION: THIS PROCEDURE DELETES AND REBUILDS THE ORIGINAL STORED
PROCEDURE.'
PRINT ' MAKE A BACKUP OF YOUR DATABASE BEFORE RUNNING THIS PROCEDURE.'
PRINT ' IDEALLY, THIS PROCEDURE SHOULD BE RUN ON A NON-PRODUCTION COPY
OF THE PROCEDURE.'
PRINT ' To run the procedure, change the @revfl parameter to 0'
RETURN 0
END

DECLARE @intProcSpace bigint, @t bigint, @maxColID smallint,@intEncrypted
tinyint,@procNameLength int
select @maxColID = max(colid),@intEncrypted = encrypted FROM
sys.sysobjvalues WHERE id = object_id(@procedure)
GROUP BY encrypted

--select @maxColID as 'Rows in sys.sysobjvalues'
select @procNameLength = datalength(@procedure) + 29

DECLARE @real_01 nvarchar(max)

DECLARE @fake_01 nvarchar(max)

DECLARE @fake_encrypt_01 nvarchar(max)

DECLARE @real_decrypt_01 nvarchar(max),@real_decrypt_01a nvarchar(max)

select @real_decrypt_01a = ''

-- extract the encrypted imageval rows from sys.sysobjvalues
SET @real_01=(SELECT imageval FROM sys.sysobjvalues WHERE id =
object_id(@procedure) and valclass = 1 and subobjid = 1 )

-- create this table for later use
create table #output ( [ident] [int] IDENTITY (1, 1) NOT NULL ,
[real_decrypt] NVARCHAR(MAX) )

-- We'll begin the transaction and roll it back later
BEGIN TRAN
-- alter the original procedure, replacing with dashes
SET @fake_01='ALTER PROCEDURE '+ @procedure +' WITH ENCRYPTION AS
'+REPLICATE('-', 40003 - @procNameLength)

EXECUTE (@fake_01)

-- extract the encrypted fake imageval rows from sys.sysobjvalues
SET @fake_encrypt_01=(SELECT imageval FROM sys.sysobjvalues WHERE id =
object_id(@procedure) and valclass = 1 and subobjid = 1)


SET @fake_01='CREATE PROCEDURE '+ @procedure +' WITH ENCRYPTION AS
'+REPLICATE('-', 40003 - @procNameLength)
--start counter
SET @intProcSpace=1
--fill temporary variable with with a filler character
SET @real_decrypt_01 = replicate(N'A', (datalength(@real_01) /2 ))

--loop through each of the variables sets of variables, building the real
variable
--one byte at a time.
SET @intProcSpace=1

-- Go through each @real_xx variable and decrypt it, as necessary
WHILE @intProcSpace<=(datalength(@real_01)/2)
BEGIN
--xor real & fake & fake encrypted
SET @real_decrypt_01 = stuff(@real_decrypt_01, @intProcSpace, 1,
NCHAR(UNICODE(substring(@real_01, @intProcSpace, 1)) ^
(UNICODE(substring(@fake_01, @intProcSpace, 1)) ^
UNICODE(substring(@fake_encrypt_01, @intProcSpace, 1)))))
SET @intProcSpace=@intProcSpace+1
END


-- Load the variables into #output for handling by sp_helptext logic

insert #output (real_decrypt) select @real_decrypt_01
-- select real_decrypt AS '#output chek' from #output -- Testing

-- -------------------------------------
-- Beginning of extract from sp_helptext
-- -------------------------------------
declare @dbname sysname
,@BlankSpaceAdded int
,@BasePos int
,@CurrentPos int
,@TextLength int
,@LineId int
,@AddOnLen int
,@LFCR int --lengths of line feed carriage return
,@DefinedLength int
,@SyscomText nvarchar(4000)
,@Line nvarchar(255)


Select @DefinedLength = 255
SELECT @BlankSpaceAdded = 0 --Keeps track of blank spaces at end of lines.
Note Len function ignores trailing blank spaces
CREATE TABLE #CommentText
(LineId int
,Text nvarchar(255) collate database_default)


-- use #output instead of sys.sysobjvalues
DECLARE ms_crs_syscom CURSOR LOCAL
FOR SELECT real_decrypt from #output
ORDER BY ident
FOR READ ONLY


-- Else get the text.

SELECT @LFCR = 2
SELECT @LineId = 1


OPEN ms_crs_syscom

FETCH NEXT FROM ms_crs_syscom into @SyscomText

WHILE @@fetch_status >= 0
BEGIN

SELECT @BasePos = 1
SELECT @CurrentPos = 1
SELECT @TextLength = LEN(@SyscomText)

WHILE @CurrentPos != 0
BEGIN
--Looking for end of line followed by carriage return
SELECT @CurrentPos = CHARINDEX(char(13)+char(10), @SyscomText,
@BasePos)

--If carriage return found
IF @CurrentPos != 0
BEGIN
--If new value for @Lines length will be > then the
--set length then insert current contents of @line
--and proceed.

While (isnull(LEN(@Line),0) + @BlankSpaceAdded +
@CurrentPos-@BasePos + @LFCR) > @DefinedLength
BEGIN
SELECT @AddOnLen = @DefinedLength-(isnull(LEN(@Line),0) +
@BlankSpaceAdded)
INSERT #CommentText VALUES
( @LineId,
isnull(@Line, N'') + isnull(SUBSTRING(@SyscomText,
@BasePos, @AddOnLen), N''))
SELECT @Line = NULL, @LineId = @LineId + 1,
@BasePos = @BasePos + @AddOnLen, @BlankSpaceAdded = 0
END
SELECT @Line = isnull(@Line, N'') +
isnull(SUBSTRING(@SyscomText, @BasePos, @CurrentPos-@BasePos + @LFCR), N'')
SELECT @BasePos = @CurrentPos+2
INSERT #CommentText VALUES( @LineId, @Line )
SELECT @LineId = @LineId + 1
SELECT @Line = NULL
END
ELSE
--else carriage return not found
BEGIN
IF @BasePos <= @TextLength
BEGIN
--If new value for @Lines length will be > then the
--defined length
--
While (isnull(LEN(@Line),0) + @BlankSpaceAdded +
@TextLength-@BasePos+1 ) > @DefinedLength
BEGIN
SELECT @AddOnLen = @DefinedLength -
(isnull(LEN(@Line),0) + @BlankSpaceAdded)
INSERT #CommentText VALUES
( @LineId,
isnull(@Line, N'') + isnull(SUBSTRING(@SyscomText,
@BasePos, @AddOnLen), N''))
SELECT @Line = NULL, @LineId = @LineId + 1,
@BasePos = @BasePos + @AddOnLen, @BlankSpaceAdded =
0
END
SELECT @Line = isnull(@Line, N'') +
isnull(SUBSTRING(@SyscomText, @BasePos, @TextLength-@BasePos+1 ), N'')
if LEN(@Line) < @DefinedLength and charindex(' ',
@SyscomText, @TextLength+1 ) > 0
BEGIN
SELECT @Line = @Line + ' ', @BlankSpaceAdded = 1
END
END
END
END

FETCH NEXT FROM ms_crs_syscom into @SyscomText
END

IF @Line is NOT NULL
INSERT #CommentText VALUES( @LineId, @Line )

select Text from #CommentText order by LineId

CLOSE ms_crs_syscom
DEALLOCATE ms_crs_syscom

DROP TABLE #CommentText

-- -------------------------------------
-- End of extract from sp_helptext
-- -------------------------------------

-- Drop the procedure that was setup with dashes and rebuild it with the
good stuff
-- Version 1.1 mod; makes rebuilding hte proc unnecessary
ROLLBACK TRAN

DROP TABLE #output

GO

SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO

關(guān)鍵詞:SQLServer

贊助商鏈接: