Отправить целое число как varbinary в SQL Trigger - PullRequest
0 голосов
/ 11 июня 2018

Я использую этот код для установки context_info в SQL-триггере

string strUser = _app.Settings.User;
string strInt = "";

// strInt += '\x0100'; => becomes 1 in trigger
strInt += '\x0000';
strInt += '\x0200'; //=> becomes two in the trigger
strInt += '\u0000';
strInt += '\u0300';//=> becomes 3 in the trigger

// strInt += '\x0000'; 
// strInt += '\x0210'; //=> becomes 4098 in the trigger( 4096=1 + 2=2)
// strInt += '\x0000'; 
// strInt += '\u1300';//=> becomes 19 in the trigger


// strInt += '\x0200'; // = 131072
// strInt += '\x0000'; 
// strInt += '\u0100';// = 65536
// strInt += '\u0000';

//strInt += '\x0000'; 
//strInt += '\x0003'; //768
//strInt += '\u0000';
//strInt += '\u0002'; //512

string strUser = "myself";
string strContextValue = strInt + strUser + "$";
string strContext = "declare @context_info varbinary(120) set @context_info =  CONVERT(varbinary(120), N'" + strContextValue + "') set context_info @context_info";

 SqlCommand scContext = new SqlCommand(strContext, conn, tran);
 scContext.ExecuteNonQuery();

В триггере первые 8 символов интерпретируются как два числа:

declare @ctxt varbinary(128)
select @ctxt=context_info from master.dbo.sysprocesses where spid = @@spid
set @session=substring(@ctxt,1,4)
set @contextid=substring(@ctxt,5,4)

Я неавтор триггера, поэтому я не могу его изменить, но было бы здорово, если бы вы объяснили мне, что за магия здесь происходит?Как можно гарантировать, что первые 8 символов являются числами?Как мне кодировать два интергера так, чтобы они стали длиной 4 символа в SQL-триггере?

Я уже много раз кодировал, но не могу посмотреть сквозь него.

КогдаЯ загружаю правильно записанные (из другого приложения) данные обратно в ac # DataTable. Я могу получить правильное значение чисел, выполнив:

 byte[] binaryString = (byte[])dataTable.Rows[0][2];
 string x = Encoding.ASCII.GetString(binaryString);

 string strSubX2 = x.Substring(3, 4);
 int iResult = BitConverter.ToInt32(Encoding.Unicode.GetBytes(strSubX2), 0);

1 Ответ

0 голосов
/ 16 июня 2018

Похоже, ваше замешательство происходит из-за неправильного понимания, что такое varbinary.varbinary - это строка байтов, а не символов.Это даже не строка, это массив байтов.

varbinary может быть представлен в виде строки шестнадцатеричных значений, а константы varbinary в коде T-SQL представлены в виде шестнадцатеричных строк.Два шестнадцатеричных символа на байт.

Функция SUBSTRING в T-SQL может работать со строками (varchar) и байтами (varbinary).

Синтаксис

SUBSTRING (выражение, начало, длина)

Значения для начала и длины должны быть указаны в количестве символов для ntext, char, или varchar типы данных и байты для text, image, binary или varbinary типов данных.

Итак, следующие TКод триггера -SQL

declare @ctxt varbinary(128)
select @ctxt=context_info from master.dbo.sysprocesses where spid = @@spid
set @session=substring(@ctxt,1,4)

берет первые 4 байта ( не символы ) из массива байтов @ctxt и присваивает их переменной @session.Какой тип @session?Скорее всего, это int.

Запустите этот пример кода в SSMS, и вы увидите шестнадцатеричное представление некоторых целых чисел:

DECLARE @T TABLE (I int);
INSERT INTO @T VALUES
(0),
(1),
(3),
(19),
(255),
(256),
(512),
(768),
(4098),
(65535),
(65536),
(131072),
(1234567890),
(-1),
(-65535);

SELECT
    I, CONVERT(varbinary(120), I) AS BinI
FROM @T;

Результат

+------------+------------+
|     I      |    BinI    |
+------------+------------+
|          0 | 0x00000000 |
|          1 | 0x00000001 |
|          3 | 0x00000003 |
|         19 | 0x00000013 |
|        255 | 0x000000FF |
|        256 | 0x00000100 |
|        512 | 0x00000200 |
|        768 | 0x00000300 |
|       4098 | 0x00001002 |
|      65535 | 0x0000FFFF |
|      65536 | 0x00010000 |
|     131072 | 0x00020000 |
| 1234567890 | 0x499602D2 |
|         -1 | 0xFFFFFFFF |
|     -65535 | 0xFFFF0001 |
+------------+------------+

Ваш код C # в вопросе не имеет особого смысла.Включение strInt + strUser в CONVERT(varbinary(120), N'" + strContextValue + "') не имеет смысла.

Код C # должен создавать двоичный массив.Код триггера T-SQL предполагает, что первые 4 байта этого массива равны @session, следующие 4 байта - @contextid. байтов, а не символов .

Итак, если вы хотите передать, скажем, 131072 десятичный как @session, 1234567890 десятичный как @contextid, плюс myself$ строкав качестве дополнительной информации вы должны запустить следующий код T-SQL:

declare @context_info varbinary(128); -- note 128 length here
set @context_info = 0x00020000;
-- note, there are no quotes around the constants, they are numbers, not strings
set @context_info = @context_info + 0x499602D2;
set @context_info = @context_info + CONVERT(varbinary(120), N'myself$');
-- note 120 length here, first 8 bytes are used by two integers
set context_info @context_info;

Запустите этот код в SSMS, но замените последнюю строку на SELECT @context_info;, чтобы увидеть, что он делает.Вы получите следующий результат:

+------------------------------------------------+
|                (No column name)                |
+------------------------------------------------+
| 0x00020000499602D26D007900730065006C0066002400 |
+------------------------------------------------+

Вы можете увидеть двоичное представление двух целых чисел плюс двоичное представление текстовой строки Unicode.

В C # вы создаете этот код путем объединения шестнадцатеричного числапредставление целых чисел.Обратите внимание, что вы не должны заключать 0x00020000 и 0x499602D2 в кавычки или CONVERT(varbinary, ...).Вы должны заключить только строку myself$ в CONVERT(varbinary, ...).

Код C # должен выглядеть примерно так:

string strUser = "myself$";
int iSession = 131072;
int iContextID = 1234567890;

StringBuilder sb = new StringBuilder();
sb.Append("declare @context_info varbinary(120);");
sb.Append("set @context_info = 0x");
sb.Append(iSession.ToString("X8"));
sb.Append(";");
sb.Append("set @context_info = @context_info + 0x");
sb.Append(iContextID.ToString("X8"));
sb.Append(";");
sb.Append("set @context_info = @context_info + CONVERT(varbinary(120), N'");
sb.Append(strUser);
sb.Append("');");
sb.Append("set context_info @context_info;");

string strContext = sb.ToSTring();

SqlCommand scContext = new SqlCommand(strContext, conn, tran);
scContext.ExecuteNonQuery();

См. Также C # convert integerзаговорить и обратно

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...