Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Помогите разобраться с багом в процедуре  [new]
RouR
Member

Откуда:
Сообщений: 174
Помогите проанализировать баг.

Есть два слинкованных сервера.

SERV_Int select @@version
Microsoft SQL Server 2005 - 9.00.3175.00 (Intel X86) Jun 14 2007 09:20:57 Copyright (c) 1988-2005 Microsoft Corporation Standard Edition on Windows NT 5.2 (Build 3790: Service Pack 2)


SERV_Ext select @@version
Microsoft SQL Server 2005 - 9.00.4035.00 (X64) Nov 24 2008 16:17:31 Copyright (c) 1988-2005 Microsoft Corporation Standard Edition (64-bit) on Windows NT 6.1 (Build 7601: Service Pack 1)


На SERV_Ext вызывается
[SERV_Int].[base1].[dbo].mysp_createFolder


Код mysp_createFolder
USE [base1]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO



ALTER  procedure [dbo].[mysp_createFolder]
 @objIDstr varchar(40),
 @ownerIDstr varchar(40),
 @userName varchar(50),
 @dirName varchar(200),
 @dirComments varchar(200),
 @Priority int,
 @accessRights varchar(2000) = '',
 @dirID uniqueidentifier = NULL OUTPUT
AS

set nocount on

declare @iReturn int
set @iReturn = 0

declare @objNumber varchar(40), @infoString varchar(300)
 set @objNumber = ''; set @infoString = ''
declare  @tableName varchar(50), @state int
 set @tableName  = ''

-- Получение имени таблицы для проекта 
 set @tableName  = (select TableName from Contents where objID = @objIDstr  )
 if @@error <> 0   Begin  set @iReturn = 1;  goto OnError  End
 if @tableName = '' Begin  set @iReturn = 1; goto OnError End

 set @state = 0
-- Получение состояния проекта 
 set @state = (select state from Contents where objID = @objIDstr  )
 if @@error <> 0   Begin  set @iReturn = 13;  goto OnError  End
 if @state = 0 Begin  set @iReturn = 13; goto OnError End

declare @objContentsTable varchar(100)
 set @objContentsTable = 'Z_' + @tableName + '_contents'
-- Проверка на существование в данном разделе каталога с таким же именем директории
declare @right_most_sibling int, @oldLft int, @return_status int
set @dirID = NULL
declare @whereSQL varchar(1000), @priorityStr varchar(40)
set @priorityStr = CAST( @Priority as varchar );
-- Это для совместимости со старым форматом, получим ID для ROOTа
if @ownerIDstr = '' or @ownerIDstr = 'NULL'  
begin
 exec mysp_getExecVarchar @objContentsTable, 'CAST( ID as varchar(40))', 'ownerID is NULL', @retValue = @ownerIDstr OUTPUT
end
-- Получим rgt значение родителя
set @whereSQL = 'ID = '+char(39)+@ownerIDstr+char(39)
exec mysp_getExecInt @objContentsTable, 'rgt', @whereSQL, @retValue = @right_most_sibling OUTPUT
--print 'owner Right - '+CAST( @right_most_sibling as varchar )
declare @newdirExt int, @dirExt int
set @newdirExt = 0 
set @dirExt = 0
-- Получим dirExt значение родителя
set @whereSQL = 'ID = '+char(39)+@ownerIDstr+char(39)
exec mysp_getExecInt @objContentsTable, 'dirExt', @whereSQL, @retValue = @dirExt OUTPUT

if @state = 3 
/*if @dirExt = 0 -- родитель - это корень, то есть добавляем каталог первого уровня в корень проекта
	set @newdirExt = 6
else 
	if @dirExt = 6 -- родитель - это каталог первого уровня, то есть добавляем каталог
		set @newdirExt = 7
	else*/
	if @dirExt = 7 -- родитель - это каталог первого уровня, то есть добавляем каталог
		set @newdirExt = 7

-- Найдем прежнего child-a с нужным приоритетом и отберем у него lft
set @whereSQL = 'ownerID = '+char(39)+@ownerIDstr+char(39) + ' and priority = '+@priorityStr
set @oldLft = NULL
exec mysp_getExecInt @objContentsTable, 'lft', @whereSQL, @retValue = @oldLft OUTPUT
-- Если вставляем в середину то нужно произвести сдвиг относительно приоритета старого child-a 
if @oldLft is NOT NULL and @oldLft <> 0 SET @right_most_sibling = @oldLft
   else  -- Если вставка не в середину, то проконтролируем правильность значения @Priority
	begin
	 set @whereSQL = 'ownerID = '+char(39)+@ownerIDstr+char(39)
	 exec mysp_getExecInt @objContentsTable, 'count(*)', @whereSQL, @retValue = @Priority OUTPUT
	 set @Priority = @Priority + 1	 
	 set @priorityStr = CAST( @Priority as varchar );
	end
-- Обновим lft и rgt
declare @sqlStr varchar(1024)
set @sqlStr = 'UPDATE '+@objContentsTable+' SET lft = CASE WHEN lft >= '+CAST(@right_most_sibling as varchar)+
                  ' THEN lft + 2 ELSE lft END, rgt = CASE WHEN rgt >= '+ CAST(@right_most_sibling as varchar)+
                  ' THEN rgt + 2 ELSE rgt END WHERE rgt >= '+CAST(@right_most_sibling as varchar) 
--print @sqlStr 
 exec ( @sqlStr )

-- Обновим порядок расположения существующих каталогов
 set @sqlStr = 'update '+@objContentsTable+' set Priority = Priority + 1 where ownerID = '''+@ownerIDstr+''' and Priority >='+CAST( @Priority as varchar )
 exec( @sqlStr )
 if @@error <> 0   Begin  select @iReturn = 12;  goto OnError  End 
 declare @dirIDstr varchar(40)
 set @dirID = newID()
 set @dirIDstr = CAST( @dirID as varchar(40) )
print @dirname
--если добавляется каталог в шаблон Позиций по ГП, то добавляем запись в табл GP_UID
--objID=c03dd7f0-8aae-448d-8edd-543727e680e4&dirid=84b09d33-7f3a-11d6-ba3b-00306e001b40
if @objIDstr  = 'c03dd7f0-8aae-448d-8edd-543727e680e4' and @OwnerIDstr ='84b09d33-7f3a-11d6-ba3b-00306e001b40'
 begin	
    if (@dirName<>'')and (not @dirName like 'принципиальная схема')and (Not @dirName like 'набор сооружений')
    begin
	DECLARE @Par4 int
	Exec [appserver].[applicationdb].dbo.DICTIONARY_INSERT  @dirName , '', 23, @Par4=@Par4 output
	iNSERT INTO [GP_UID]([UID_CurProject], [Num_Group], [UID_SIGNATURE] ) VALUES( @dirID, 0, @Par4)
	end
 end

 set @sqlStr = 'insert into '+@objContentsTable+'( ID, ownerID, dirName, dirComments, Priority,  accessRights, lft, rgt, dirExt ) values ( '''+@dirIDstr+''','
 if @ownerIDstr = '' or @ownerIDstr = 'NULL'  begin set @sqlStr = @sqlStr + ' NULL' end
  else begin set @sqlStr = @sqlStr + '''' + @ownerIDstr + '''' end
 set @sqlStr = @sqlStr + ','''+@dirName+''','''+@dirComments+''','+CAST( @Priority as varchar ) +','''+ @accessRights + ''','+
 CAST(@right_most_sibling as varchar) + ', '+CAST((@right_most_sibling+1) as varchar) + ', '+CAST((@newdirext) as varchar) +')';
--print @sqlStr 
 exec( @sqlStr )
 if @@error <> 0   Begin  select @iReturn = 12;  goto OnError  End 
 exec mysp_fixFolderPriority @objIDstr,  @ownerIDstr

 set @objNumber = (select Number +'.'+Stady from Contents with (NOLOCK)  where objID = @objIDstr)
 set @infoString = @objNumber + ':'+@dirName

EndProc:
 set nocount off
 select @infoString as infoString, @dirID as dirID
 return @iReturn
OnError:
 goto EndProc

Не я автор этого чудища, но тем не менее.

Суть проблемы:
В большинстве случаев процедура работает нормально - выдаёт новый @dirID и return 0 и создаёт запись в соответствующей таблице и ID=@dirID.
Но когда функция вызывается с слинкованого сервера, то в редких случаях процедура выдаёт новый @dirID и return 0, НО не создаёт необходимую запись (или создаёт но откатывается).
Раньше внутри этой процедуры использовались транзакции (SET TRANSACTION ISOLATION LEVEL read uncommitted и всё в один большой BEGIN TRANSACTION @TranName), но обнаружив такое поведение транзакцию убрали, и... проблема осталась.

И как бы вот побороть такой баг?
19 янв 12, 08:00    [11929825]     Ответить | Цитировать Сообщить модератору
 Re: Помогите разобраться с багом в процедуре  [new]
мимо проходящий ))
Guest
Огласите бюджет пожалуйста этой работы.

Тут нужны тестовые базы чтобы проверять для начала.
19 янв 12, 08:10    [11929837]     Ответить | Цитировать Сообщить модератору
 Re: Помогите разобраться с багом в процедуре  [new]
aleks2
Guest
А чо там невозможного и загадочного?
"НО не создаёт необходимую запись (или создаёт но откатывается"
там же IF стоит - вот и не создает.

if @objIDstr  = 'c03dd7f0-8aae-448d-8edd-543727e680e4' and @OwnerIDstr ='84b09d33-7f3a-11d6-ba3b-00306e001b40'
 begin	
    if (@dirName<>'')and (not @dirName like 'принципиальная схема')and (Not @dirName like 'набор сооружений')
...
19 янв 12, 08:21    [11929855]     Ответить | Цитировать Сообщить модератору
 Re: Помогите разобраться с багом в процедуре  [new]
RouR
Member

Откуда:
Сообщений: 174
aleks2,
IF выдаёт false, смотрели проблемные id. проблема где-то дальше.


мимо проходящий,
бюджета нулевой, тестовые базы чтобы проверять... проверять сам буду, на форуме ищу взгляд со стороны, тут что-то простое и незаметное. я так думаю.
19 янв 12, 08:58    [11929936]     Ответить | Цитировать Сообщить модератору
 Re: Помогите разобраться с багом в процедуре  [new]
aleks2
Guest
RouR
aleks2,
IF выдаёт false, смотрели проблемные id. проблема где-то дальше.


Смотрим в книгу - видим фигу.
"IF выдаёт false" - ну дык чего тады дальше то будет?

Не лучше ли ELSE написать и @dirID и @iReturn в ем похерить?
19 янв 12, 09:35    [11930045]     Ответить | Цитировать Сообщить модератору
 Re: Помогите разобраться с багом в процедуре  [new]
RouR
Member

Откуда:
Сообщений: 174
aleks2,

поясню.

проблема не в
Exec [appserver].[applicationdb].dbo.DICTIONARY_INSERT  @dirName , '', 23, @Par4=@Par4 output
	iNSERT INTO [GP_UID]([UID_CurProject], [Num_Group], [UID_SIGNATURE] ) VALUES( @dirID, 0, @Par4)

на проблемных значениях он не должен вызываться, по бизнес-логике.

но должно быть создание
'insert into '+@objContentsTable+'( ID, ownerID, dirName, dirComments, Priority,  accessRights, lft, rgt, dirExt ) values
19 янв 12, 09:47    [11930113]     Ответить | Цитировать Сообщить модератору
 Re: Помогите разобраться с багом в процедуре  [new]
Guf
Member

Откуда: Новосибирск
Сообщений: 659
RouR,

У Вас в процедуре есть такие строчки "--print @sqlStr". Вы пробовали их раскоментировать и выполнять процедуру "на проблемных значениях"?

При некоторых настройках @sqlStr может быть NULL, и @error ничего не покажет.
declare @sqlStr varchar(1024)

При других настройках строка может спокойно обрезться и не выдавать сообщений об ошибках.
19 янв 12, 10:44    [11930495]     Ответить | Цитировать Сообщить модератору
 Re: Помогите разобраться с багом в процедуре  [new]
RouR
Member

Откуда:
Сообщений: 174
Guf,
про CONCAT_NULL_YIELDS_NULL не знал, спасибо.

посмотреть на print @sqlStr ... - вот по логам я могу восстановить значения входных параметров, и с этими значениями процедура отрабатывает нормально (по сути изменилось: новое @dirID=newID(), время запуска, состояние базы, параллельно выполняемые другие запросы, но вот что конкретно как бы поймать)
19 янв 12, 11:11    [11930707]     Ответить | Цитировать Сообщить модератору
 Re: Помогите разобраться с багом в процедуре  [new]
aleks2
Guest
RouR
Guf,
про CONCAT_NULL_YIELDS_NULL не знал, спасибо.

посмотреть на print @sqlStr ... - вот по логам я могу восстановить значения входных параметров, и с этими значениями процедура отрабатывает нормально (по сути изменилось: новое @dirID=newID(), время запуска, состояние базы, параллельно выполняемые другие запросы, но вот что конкретно как бы поймать)


С такими способностями "бессмысленно излагать" вам следует рассмотреть вариант переквалификации в управдомы.
19 янв 12, 14:22    [11932805]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить