Как использовать путь длиной более 128 символов в команде DIR «xp_cmdshell»

Я пытаюсь получить список файлов в каталоге, используя путь SQL Server, имеющий более 128 символов. Это не работает.

DECLARE 
@FilePath varchar(256)='D:\...',--Path with a length more than 128 char

@SourceFiles varchar(100)='Test123456789*.txt',
@Query varchar(1000)

If Object_Id('tempdb.dbo.#FirstTable') Is NULL
    CREATE TABLE #FirstTable (Name varchar(256))

SET QUOTED_IDENTIFIER ON
SET @Query ='master.dbo.xp_cmdshell "dir '+ @FilePath + '\' + @SourceFiles +' /b"'

INSERT #FirstTable exec (@Query)
select * from #FirstTable

truncate table #FirstTable

Это дает следующую ошибку:

Идентификатор, который начинается с 'dir D:....', слишком длинный. Максимальная длина 128.


person Husen    schedule 23.11.2016    source источник


Ответы (2)


Ключом к этой проблеме является формулировка сообщения об ошибке (выделено мной):

Идентификатор, начинающийся с

Идентификатор – это имя объекта или элемента в SQL Server, а не литеральная строка. Например, master, dbo и xp_cmdshell — все идентификаторы.

Итак, у вас есть два варианта:

Простое исправление (но не лучшая практика)

Проблема с идентификаторами — это подсказка, указывающая на строку SET QUOTED_IDENTIFIER ON. Простое изменение ON на OFF позволит этому работать. Однако вы получите сообщение об ошибке, если в вашем пути и/или шаблоне имени файла есть пробел (например, C:\Program Files (x86)\ ).

Исправление передового опыта (это все еще довольно просто)

Используйте одинарные кавычки вместо двойных кавычек вокруг команды оболочки. А поскольку вы создаете команду в динамическом SQL, в обоих случаях она должна быть заключена в две одинарные кавычки. Итак, ...xp_cmdshell ''dir ... /b''...

Если в самом пути есть пробелы, то вам нужны двойные кавычки вокруг пути: ...xp_cmdshell ''dir "..." /b''...

Следовательно, полный синтаксис будет таким:

SET @Query ='master.dbo.xp_cmdshell ''dir "'+ @FilePath + '\' + @SourceFiles +'" /b''';

Поместив его в полный исходный код вместе с длинным именем пути и дополнительными SELECT и PRINT, чтобы увидеть, что происходит, вы получите:

DECLARE @FilePath varchar(256)='C:\Users\Solomon\AppData\Local\Microsoft\HelpViewer2.0\TableOfContentsFilterCache\VisualStudio11\en-US',--Path with a length more than 128 char
@SourceFiles varchar(100)='this_is_a_long_file_name.*',
@Query varchar(1000);

IF (OBJECT_ID(N'tempdb.dbo.#FirstTable') IS NULL)
BEGIN
    CREATE TABLE #FirstTable (Name VARCHAR(256));
END;

SET QUOTED_IDENTIFIER ON;
SET @Query ='master.dbo.xp_cmdshell ''dir "'+ @FilePath + '\' + @SourceFiles +'" /b''';

SELECT LEN(@FilePath + '\' + @SourceFiles);
PRINT @Query;

INSERT #FirstTable EXEC(@Query);
  SELECT * FROM #FirstTable;

Запуск без ошибок. Значение @Query, показанное на вкладке «Сообщения», отображается как:

master.dbo.xp_cmdshell 'dir "C:\Users\Solomon\AppData\Local\Microsoft\HelpViewer2.0\TableOfContentsFilterCache\VisualStudio11\en-US\this_is_a_long_file_name.*" /b'

Теперь, до изменений, которые я предложил, была ошибка. Результат исходного кода (с теми же тестовыми значениями):

Вкладка «Результаты»:

129

Вкладка "Сообщения":

master.dbo.xp_cmdshell "dir C:\Users\Solomon\AppData\Local\Microsoft\HelpViewer2.0\TableOfContentsFilterCache\VisualStudio11\en-US\this_is_a_long_file_name.* /b"

Сообщение 103, уровень 15, состояние 4, строка 1
Идентификатор, начинающийся с "dir C:\Users\Solomon\AppData\Local\Microsoft\HelpViewer2.0\TableOfContentsFilterCache\VisualStudio11\en-US\this_is_a_long_file_n", слишком длинная. Максимальная длина 128.

person Solomon Rutzky    schedule 23.11.2016
comment
Если мы используем одинарные кавычки, это не будет рассматриваться как одна команда в xp_cmdshell, поэтому будет отображаться ошибка, поскольку система не может найти указанный путь. - person Husen; 23.11.2016
comment
@Husen Хранимая процедура xp_cmdshell ожидает параметр VARCHAR или NVARCHAR. Вот почему вам нужно заключать в одинарные кавычки полную команду DIR. Поскольку вы форматируете эту команду в самом VARCHAR, вам нужно удвоить их, то есть поместить две одинарные кавычки, чтобы получить одну одинарную кавычку в окончательной строке. - person TT.; 23.11.2016
comment
Я пробовал все перестановки и комбинации в этом. Пожалуйста, проверьте в локальной среде, а затем предложите синтаксис. - person Husen; 23.11.2016
comment
@Husen Я предоставил этот синтаксис, но на случай, если его будет сложно вернуть в код, я обновил свой ответ полным сценарием. Я также добавил полное объяснение ошибки и второй (хотя и не такой хороший) вариант. - person Solomon Rutzky; 23.11.2016
comment
@srutzky Прочтите это ... Интересно, почему ОП подумал, что ему нужно явно установить QUOTED_IDENTIFIER на ON. Я не думаю, что это необходимо для того, что он хочет делать. - person TT.; 23.11.2016
comment
@ТТ. Я предполагаю, что это была попытка заставить работать двойные кавычки. - person Solomon Rutzky; 23.11.2016

Ради интереса я создал каталог C:\Temp\Temporary folder with an unecessarily long name just to be an example etc etc\Temporary folder with an unecessarily long name just to be an example etc etc (163 символа) и поместил в него кучу test*.txt файлов.

В следующем сценарии нет проблем, которые вы описываете.

DECLARE @file_path NVARCHAR(256)='C:\Temp\Temporary folder with an unecessarily long name just to be an example etc etc\Temporary folder with an unecessarily long name just to be an example etc etc';
PRINT LEN(@file_path); -- prints 163
DECLARE @src_files NVARCHAR(100)='test*.txt';
DECLARE @dir_cmd NVARCHAR(4000)='DIR "'+@file_path+'\'+@src_files+'" /b';

CREATE TABLE #dir_table(name NVARCHAR(256));
INSERT INTO #dir_table(name) EXEC xp_cmdshell @dir_cmd;

SELECT*FROM #dir_table; -- result is a bunch of test*.txt files
DROP TABLE #dir_table;
person TT.    schedule 23.11.2016