Перегляд стека виклику процедур в SQL Server, Інші СУБД, Бази даних, статті

При виникненні помилок (та й не тільки), розробникам хочеться бачити стек виклику процедур.
І розробники баз даних – не виняток.
Але на жаль, T-SQL зокрема і MSSQL Server вцелом не надають нам такою щасливою можливості.
 

Виявляється все не так погано …


Межно і самим зробити. 😉


Обмеження нижченаведеного рішення (стосується тексту процедур, звернення до яких хочеться бачити в стеку):



Втім, дані обмеження пов’язані з небажанням (сподіваюся, зрозумілим) застосовувати в даному прикладіскладний парсинг T-SQL.
Ну і звичайно, ніхто не заважає поміняти даний код з урахуванням застосовуваних правил і традицій форматування свого коду.


Використання:



  1. Запускаємо скрипт

  2. Виконуємо _Context.UpdateProcedures
    (В якості параметра можна передати ім’я схеми, тоді будуть порушені тільки процедури даної схеми)

  3. У процедурах дивимося вміст стека конструкцією
    select * from _Context.Stack()

Обсдужденіе рішення тут: http://www.sql.ru/forum/actualthread.aspx?tid=665929&pg=-1


Ну і саме рішення:


– Схема

if schema_id(“_Context”) is null exec(“create schema _Context”)

go

if object_id(“_Context.Push”) is not null drop procedure _Context.Push

go

– Процедура, яка змінює контекст

create procedure _Context.Push

      @ID int

as

begin

      declare

            @level   int,

            @Context varbinary(128)

           

      select

            @Context = isnull(context_info(), convert(varbinary(128), replicate(convert(binary(1), 0x00), 128))),

            @level = (@@NESTLEVEL – 1) * 4

 

      set @Context = substring(@Context, 1, @level) + convert(binary(4), @ID) + substring(@Context, @level + 5, 128)

      set context_info @Context  

end

go

– Опорна таблиця з числами для “парсинга” контексту

if object_id(“_Context.Numbers”) is not null drop table _Context.Numbers

go

create table _Context.Numbers(Number int primary key)

go

– Заповнюємо значеннями від 1 до 32

insert into _Context.Numbers(Number)

select sv.number

from master.dbo.spt_values sv (nolock)

where sv.[type] = “P”

and sv.number > 0

and sv.number <= 32

go

if object_id(“_Context.Stack”) is not null drop function _Context.Stack

go

– Функція перегляду стека

create function _Context.Stack()

returns table

as

return

      (

      select

            stack_level,

            “[“+object_schema_name(proc_id)+”].[“+object_name(proc_id)+”]” as procedure_name

      from

            (

            select

                  n.Number as stack_level,

                  convert(int, substring(context_info(), n.Number*4+1, 4)) as proc_id

            from _Context.Numbers n (nolock)

            where n.Number <= @@NESTLEVEL

      ) q

      )

go

if object_id(“_Context.UpdateProcedures”) is not null drop procedure _Context.UpdateProcedures

go

– Процедура, що додає зміна стека у вже існуючі

create procedure _Context.UpdateProcedures

      @SchemaName sysname = null

as

begin

      declare

            @procid int,

            @definition  nvarchar(max),

            @_definition nvarchar(max),

            @CRLF        char(2),

            @create_pos  int,

            @as_pos      int

           

      set @CRLF = char(13)+char(10)

     

      declare curs cursor local static forward_only for

            select

                  procid,

                  object_definition(procid)

            from

                  (

                  select

                        object_id(“[“+r.ROUTINE_SCHEMA + “].[“+r.ROUTINE_NAME+”]”) as procid

                  from INFORMATION_SCHEMA.ROUTINES r

                  where r.ROUTINE_ENGINE=”PROCEDURE”

                  and isnull(@SchemaName, r.ROUTINE_SCHEMA) = r.ROUTINE_SCHEMA

– Не змінюємо “себе”

                  and not(r.ROUTINE_SCHEMA=”_Context” and r.ROUTINE_NAME=”Push”)

                  ) q

      open curs

      while 1=1

      begin

            fetch next from curs into @procid, @_definition

            if @@FETCH_STATUS <> 0 break

 

            select

                  @create_pos = 0,

                  @definition = upper(@_definition)

 

– Шукаємо перше входження CREATE PROCEDURE

            if substring(@definition, 1, 17) = “CREATE PROCEDURE “

                  set @create_pos = 1

            else

            begin

                  set @create_pos = charindex(@CRLF+”CREATE PROCEDURE “, @definition) + 2

            end

            if @create_pos > 0

            begin

                  set @as_pos = charindex(@CRLF+”AS”+@CRLF, @definition, @create_pos + 17)

                  if @as_pos > 0

                  begin

– Перевіряємо, чи немає вже за AS exec _Context.Push @ @ RPOCID

– Якщо немає – міняємо текст процедури

                        if substring(@definition, @as_pos+6, 29) <> “EXEC _CONTEXT.PUSH @@PROCID”+@CRLF

                        begin

                             set @_definition = stuff(@_definition, @as_pos+6, 0, “exec _Context.Push @@PROCID”+@CRLF)

                             set @_definition = stuff(@_definition, @create_pos, 6, “alter”)

                             begin try

                                   exec(@_definition)

                             end try

                             begin catch

                                   print @_definition

                              end catch

                        end

                  end

            end

      end

end

go

if object_id(“_Context.pLevA”) is not null drop procedure _Context.pLevA

go

– В даній процедурі чомусь хочеться бачити стек виклику

create procedure _Context.pLevA

as

begin

      select * from _Context.Stack()

      select “level a” as [level]

end

go

– Процедура, що викликає ту, в якій хочеться бачити стек

if object_id(“_Context.pLevB”) is not null drop procedure _Context.pLevB

go

create procedure _Context.pLevB

as

exec _Context.pLevA

select “level b” as [level]

go

if object_id(“_Context.pLevC”) is not null drop procedure _Context.pLevC

go

– Процедура, що викликає процедуру, яка викликає ту, в якій хочеться бачити стек

create procedure _Context.pLevC

as

exec _Context.pLevB

select “level c” as [level]

go

– Додаємо Push в існуючі процедури

exec _Context.UpdateProcedures _Context

go

– Перевіряємо

exec _Context.pLevC

go

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*