فشل مهام عميل SQL Server المهام تحتوي على الخطوات المهمة التي تستخدم الرموز المميزة بعد تثبيت SQL Server 2005 Service Pack 1

الخطأ رقم: 426808 (سقلبودت)
الخطأ رقم: 426808 (SQL بو عيب تعقب)الخطأ #: 53050 (تعديل المحتوى)

الأعراض

بعد تثبيت Microsoft SQL Server 2005 Service Pack 1 (SP1)، تواجه السلوك التالي:
  • فشل مهام عميل SQL Server المهام تحتوي على الخطوات المهمة التي تستخدم الرموز المميزة.
  • تتلقى رسالة الخطأ التالية:
    خطوة مهمة تحتوي على واحد أو أكثر من الرموز المميزة. SQL Server 2005 Service Pack 1 أو الإصدارات الأحدث، يجب أن تحدث كافة الخطوات المهمة مع الرموز المميزة ماكرو قبل تشغيل المهمة.
ملاحظة: تحدث هذه المشكلة مع الإصدارات الأحدث أو 2046 البناء SQL Server 2005.

السبب

في SQL Server 2005 SP1، تم تغيير بناء الرمز المميز خطوة مهمة عميل SQL Server. الآن، يجب عليك تضمين ماكرو هروب بكافة الرموز المميزة المستخدمة في خطوات مهمة. إذا لم تقم بتضمين ماكرو هروب، ستفشل تلك الخطوات المهمة. يسرد الجدول التالي وحدات الماكرو الهروب.
الهروب الماكروالوصف
$(ESCAPE_SQUOTE (توكينامي))يلغي هذا الماكرو الفاصلة العليا (') في سلسلة استبدال الرمز المميز. استبدال الماكرو علامة اقتباس أحادية واحد بصيغ اثنين.
$(ESCAPE_DQUOTE (توكينامي))يلغي هذا الماكرو علامات اقتباس ('') في سلسلة استبدال الرمز المميز. استبدال الماكرو علامة اقتباس واحد بعلامتي اقتباس.
$(ESCAPE_RBRACKET (توكينامي))يلغي هذا الماكرو أقواس الأيمن (]) في سلسلة استبدال الرمز المميز. استبدال الماكرو قوس واحد بين أقواس اليمنى.
$(ESCAPE_NONE (توكينامي))استبدال الماكرو رمز دون الإفلات من الأحرف في السلسلة. يتم توفير هذا الماكرو لدعم التوافق في بيئات حيث يتوقع سلاسل استبدال الرمز المميز فقط من المستخدمين الموثوق بهم.
على سبيل المثال، قد يحتوي على خطوة مهمة التالية عبارة SQL للعمليات التي تستخدم الرمز المميز A DBN :
CREATE DATABASE [$(A-DBN)]
في هذا المثال، يجب عليك تحديث الرمز المميز بناء الجملة لبناء الجملة التالي:
CREATE DATABASE [$(ESCAPE_RBRACKET(A-DBN))]
يختلف هذا التغيير السابق سلوك SQL Server 2005، وحدات الماكرو الهروب لا يلزم فيها.

الحل

لحل هذه المشكلة، قم بتحديث الكل أو وظائف معينة استخدام الرموز المميزة لبناء الجملة الجديد الرمز المميز. للقيام بذلك، استخدم sp_AddEscapeNoneToJobStepTokens الإجراء المخزن. يمكنك إنشاء هذا الإجراء المخزن باستخدام البرنامج النصي SQL للعمليات التالية.

ملاحظة: تأكد من بناء SQL Server 2005 SP1 الذي تقوم بتثبيته 2046 أو بناء لاحقة. بالإضافة إلى ذلك، يجب أن تكون عضوا من مسؤول النظام sysadmin إصلاح دور خادم تشغيل البرنامج النصي.
      -- This script is used to automatically edit SQL Agent job steps so that-- unescaped tokens are prefaced with the ESCAPE_NONE syntax that was added in
-- SQL Server 2005 SP1.

if (@@microsoftversion < 0x90007FE)
BEGIN
RAISERROR('This script should only be run on at least SQL Server 2005 SP1.', 20, 127) WITH LOG
return
END

use msdb
go

if exists (select * from sys.objects where name = N'fn_PrefaceTokensWithEscapeNone' and type = 'FN')
drop function fn_PrefaceTokensWithEscapeNone
go

-- This function manipulates @commands so that all bare tokens
-- are prefaced with ESCAPE_NONE.
create function fn_PrefaceTokensWithEscapeNone(@commands nvarchar(max)) RETURNS nvarchar(max)
AS
BEGIN
if (@commands IS NULL)
BEGIN
return @commands
END

-- In order to let this script run under SQLCMD mode, we define
-- the special "$(" variable start string by concatenation so that
-- sqlcmd mode does not think that we are defining one of its variables.
declare @strVariableStart nchar(2)
select @strVariableStart = N'$' + N'('

declare @idxTokenStart int
select @idxTokenStart = CHARINDEX(@strVariableStart, @commands)
while (@idxTokenStart != 0 and @idxTokenStart is not null)
BEGIN
declare @idxCloseParen int
select @idxCloseParen = CHARINDEX(N')', SUBSTRING(@commands, @idxTokenStart, LEN(@commands)))
-- Error checking. If there is no close parenthesis, return.
if (0 = @idxCloseParen)
BEGIN
return @commands
END

-- Deduce the token variable.
declare @tokenLen int
select @tokenLen = @idxCloseParen - LEN(@strVariableStart) - 1
declare @token nvarchar(max)
select @token = SUBSTRING(@commands, @idxTokenStart + LEN(@strVariableStart), @tokenLen)

-- Verify if @token contains a mis-matched number of open and
-- close parens. This behavior could happen if invalid syntax is
-- in a comment block. If so, skip to the next token.
declare @idx int
declare @cOpenParens int
declare @cCloseParens int

select @cOpenParens = 0
select @idx = CHARINDEX(N'(', @token);
while (@idx != 0)
BEGIN
select @cOpenParens = @cOpenParens + 1
select @idx = CHARINDEX(N'(', @token, @idx + 1);
END

select @cCloseParens = 0
select @idx = CHARINDEX(N')', @token);
while (@idx != 0)
BEGIN
select @cCloseParens = @cCloseParens + 1
select @idx = CHARINDEX(N')', @token, @idx + 1);
END

-- Special case for the WMI token.
if (N'WMI(' = SUBSTRING(@token, 1, LEN(N'WMI(')))
BEGIN
select @cOpenParens = @cOpenParens - 1
END

if ((@cOpenParens = @cCloseParens) and
(N'ESCAPE_NONE(' != SUBSTRING(@token, 1, LEN(N'ESCAPE_NONE('))) and
(N'ESCAPE_SQUOTE(' != SUBSTRING(@token, 1, LEN(N'ESCAPE_SQUOTE('))) and
(N'ESCAPE_DQUOTE(' != SUBSTRING(@token, 1, LEN(N'ESCAPE_DQUOTE('))) and
(N'ESCAPE_RBRACKET(' != SUBSTRING(@token, 1, LEN(N'ESCAPE_RBRACKET('))))
BEGIN
select @commands = STUFF(@commands, @idxTokenStart + LEN(@strVariableStart), @tokenLen, N'ESCAPE_NONE(' + @token + N')')
END
select @idxTokenStart = CHARINDEX(@strVariableStart, @commands, @idxTokenStart + 1)
END

return @commands

END
go

if exists (select * from sys.objects where name = N'sp_AddEscapeNoneToJobStepTokens' and type = 'P')
drop procedure sp_AddEscapeNoneToJobStepTokens
go

-- This procedure allows you to update jobs so that bare tokens
-- are prefaced with ESCAPE_NONE. By default, all jobs are updated.
-- You can optionally specify @job_name, @job_id, or @owner_name
-- to limit the jobs that will be affected.
CREATE PROCEDURE sp_AddEscapeNoneToJobStepTokens
(
@job_name nvarchar(128) = null,
@job_id uniqueidentifier = null,
@owner_name nvarchar(256) = null
)
AS


-- Find the jobs to update. These jobs must match all of the input
-- criteria, unless all of the inputs are null. In this case,
-- examine all jobs. The jobs must also be jobs created locally,
-- such as sysjobs.originating_server_id = 0. These jobs should not be a job that we run
-- because another server told us to. Furthermore, if the job
-- is local but it is meant to be run on a target server, we send an
-- update for the job.
declare @jobsToUpdate TABLE (job_id uniqueidentifier not null)

insert into @jobsToUpdate
select job_id
from sysjobs
where originating_server_id = 0 -- local jobs
and ((COALESCE(@job_name, sysjobs.name) = sysjobs.name) and
(COALESCE(@job_id, sysjobs.job_id) = sysjobs.job_id) and
(COALESCE(@owner_name, suser_sname(sysjobs.owner_sid)) = suser_sname(sysjobs.owner_sid)))

-- Now find the job steps to update, creating the new command by using
-- fn_PrefaceTokensWithEscapeNone.
declare @jobStepsToUpdate TABLE (job_id uniqueidentifier not null,
step_id int not null,
command_old nvarchar(max) null,
command_new nvarchar(max) null,
output_file_old nvarchar(max) null,
output_file_new nvarchar(max) null)

insert into @jobStepsToUpdate
(job_id, step_id, command_old, command_new, output_file_old, output_file_new)
select job_id, step_id, command, dbo.fn_PrefaceTokensWithEscapeNone(command), output_file_name, dbo.fn_PrefaceTokensWithEscapeNone(output_file_name)
from sysjobsteps
where sysjobsteps.job_id =
(select job_id
from @jobsToUpdate
where job_id = sysjobsteps.job_id)

-- Now we update the actual job step commands. We do this first before
-- we push out the updated jobs to the target servers so the
-- target servers actually get the updated version.
declare @updated_job_id uniqueidentifier
declare @updated_job_step_id int
declare @updated_job_step_command nvarchar(max)
declare @updated_job_step_output_file nvarchar(max)

declare job_steps_cursor CURSOR FOR
select job_id, step_id, command_new, output_file_new
from @jobStepsToUpdate
order by job_id, step_id

OPEN job_steps_cursor
FETCH NEXT from job_steps_cursor into @updated_job_id, @updated_job_step_id, @updated_job_step_command, @updated_job_step_output_file
WHILE (@@FETCH_STATUS <> -1)
BEGIN
IF (@@FETCH_STATUS <> -2)
BEGIN
EXEC sp_update_jobstep @job_id = @updated_job_id, @step_id = @updated_job_step_id, @command = @updated_job_step_command, @output_file_name = @updated_job_step_output_file
END
FETCH NEXT from job_steps_cursor into @updated_job_id, @updated_job_step_id, @updated_job_step_command, @updated_job_step_output_file
END

CLOSE job_steps_cursor
DEALLOCATE job_steps_cursor


-- For multiserver jobs, call the sp_post_msx_operation stored procedure to update
-- all the target servers. Note that the sp_post_msx_operation stored procedure is safe
-- to call because it verifies whether the job is really a multiserver job.
declare jobs_cursor CURSOR FOR
select job_id
from @jobsToUpdate

OPEN jobs_cursor
FETCH NEXT from jobs_cursor into @updated_job_id
WHILE (@@FETCH_STATUS <> -1)
BEGIN
IF (@@FETCH_STATUS <> -2)
BEGIN
EXEC sp_post_msx_operation @operation = 'UPDATE', @job_id = @updated_job_id
END
FETCH NEXT from jobs_cursor into @updated_job_id
END

CLOSE jobs_cursor
DEALLOCATE jobs_cursor

-- List the jobs that we ran on, including the previous command
-- text. We list all of the job steps, even the ones that we did not
-- update. Otherwise, a jumble of job steps from
-- different jobs run together and the output is not
-- useful.
select N'Warning - Jobs Updated' = N'The following job steps and job output file names were analyzed and potentially updated to add the ESCAPE_NONE macro before any job tokens that were not already escaped. Please review the modified job steps and replace ESCAPE_NONE with the correct escape macro.'

select suser_sname(jobs.owner_sid) as N'Job owner',
jobs.name as N'Job name',
jobs.job_id,
jobStepsUpdated.step_id,
N'Modified' = CASE WHEN jobStepsUpdated.command_new != jobStepsUpdated.command_old or jobStepsUpdated.output_file_new != jobStepsUpdated.output_file_old THEN 1 ELSE 0 END,
N'Command' = jobStepsUpdated.command_new,
N'Previous Command' = jobStepsUpdated.command_old,
N'Output file' = jobStepsUpdated.output_file_new,
N'Previous Output file' = jobStepsUpdated.output_file_old
from sysjobs as jobs, @jobsToUpdate as jobsUpdated, @jobStepsToUpdate as jobStepsUpdated
where jobsUpdated.job_id = jobs.job_id and jobsUpdated.job_id = jobStepsUpdated.job_id
order by 'Job name', jobStepsUpdated.step_id
go


بعد تشغيل البرنامج النصي، يتم إنشاء إجراء مخزن sp_AddEscapeNoneToJobStepTokens . بشكل افتراضي، سيتم تحديث كافة المهام إذا قمت بتشغيل هذا الإجراء المخزن دون أية معلمات. إذا كنت تريد تحديث وظائف معينة فقط، يجب تحديد القيم غير الصفرية لإحدى المعلمات الثلاث التالية على الأقل:
  • @job_name
  • @job_id
  • @owner_name
على سبيل المثال، يمكنك استخدام بناء الجملة التالي:
  • قم بتحديث كافة المهام:
    EXEC sp_AddEscapeNoneToJobStepTokens
  • تحديث وظيفة عن طريق تحديد اسم مهمة:
    EXEC sp_AddEscapeNoneToJobStepTokens 'MyJob'
  • تحديث المهام التي يملكها مالك نفسه:
    EXEC sp_AddEscapeNoneToJobStepTokens null,null,'JobOwner'
إضافة البرنامج النصي هذا الماكرو ESCAPE_NONE إلى كافة الخطوات المهمة التي تحتوي على رموز مميزة. بعد تشغيل هذا البرنامج النصي، نوصي بأن تقوم بمراجعة الخطوات المهمة الخاصة بك استخدام رموز مميزة في أقرب وقت ممكن. ثم استبدال الماكرو ESCAPE_NONE مع واحد من الهروب وحدات الماكرو الأخرى التي تناسب السياق خطوة مهمة.

ملاحظة: إذا كنت تعمل في بيئة خادم (بورصة طوكيو) الهدف أو ملقم رئيسي (المركبة)، يجب تشغيل هذا البرنامج النصي على المركبة وفي بورصة طوكيو للتأكد من أن الوظائف الرئيسية في بورصة طوكيو يتم تحديثها بشكل صحيح.

لمزيد من المعلومات حول كيفية تحديث المهام استخدام بناء الجملة الجديد وكيفية استخدام وحدات الماكرو الهروب لتمكين استبدال الرمز المميز في خطوات مهمة عميل SQL Server، راجع الموضوع "استخدام رموز مميزة في خطوات مهمة" في كتب SQL Server 2005 (نيسان/أبريل 2006) أو الإصدارات الأحدث من كتب SQL Server 2005.

الحالة

أقرت Microsoft أن هذه مشكلة في منتجات Microsoft المسردة في قسم "ينطبق على".

المراجع

لمزيد من المعلومات حول كيفية استخدام العلامات المميزة في خطوات مهمة، قم بزيارة موقع شبكة مطوري Microsoft (MSDN) التالي على الويب:
خصائص

رقم الموضوع: 915845 - آخر مراجعة: 15‏/01‏/2017 - المراجعة: 1

تعليقات