четверг, 18 января 2018 г.

Округление в MS SQL Server, money и float

Небольшая особенность, с которой приходится иногда сталкиваться в MS SQL - разный подход к округлению функцией round для типов данных money и float. Проявляется это в том случае,   когда (N+1)-й знак = 5, а последующие знаки равны нулю (подразумевается, что округление идет до N знаков после запятой).
Так вот, money - округляется по правилам математического округления, в большую сторону, а вот float  - в меньшую!

например, результатом выполнения select round (cast (11.385 as float), 2,0) будет  11.38
В то время, как select round (cast (11.385 as money), 2,0) выдаст ожидаемые 11.39


четверг, 6 апреля 2017 г.

MSSQL листинг процессов и текста запросов / MS SQL Server process and query text listing

/*  Simple script to show all running processes of MS SQL Server and query text of each process */ 

Довольно типичная задача, однако как всегда в нужный момент не оказалось под рукой скрипта, который бы представил информацию в удобном виде. А именно, отобразить все процессы с их блокирующими процессами и текстом запроса.

Для получения текстов запроса  используется DBCC inputbuffer, тут могут быть неточности , т.к. по прошествии времени в буфере уже может быть другой текст запроса, не соответствующий sql_statement из sys.dm_exec_requests.

Но для запросов, которые являются блокирующими и выполняются долго, это как раз очень актуально.

create table #processes ( session_id int, status nvarchar(32), blocked_by int, waittype nvarchar(60), wait_resource nvarchar(256),
wait_sec float, cpu_time int, logical_reads bigint, reads bigint, writes bigint, elapsed_sec float, statement_text nvarchar(max),
command_text nvarchar(4000), command nvarchar (32), login_name nvarchar(128), host_name nvarchar(128),
program_name nvarchar(256), last_request_end_time datetime, login_time datetime, open_transaction_count int )

create table #dbcc_result(spid int, eventtype nvarchar(128), parameters int, eventinfo nvarchar(max))

insert into #processes
 ( session_id, status, blocked_by, waittype, wait_resource,
wait_sec, cpu_time, logical_reads, reads, writes, elapsed_sec, statement_text,
command_text, command, login_name, host_name,
program_name, last_request_end_time, login_time, open_transaction_count)
SELECT   s.session_id, 
            r.status, 
            r.blocking_session_id, 
            r.wait_type, 
            wait_resource, 
            r.wait_time / (1000.0), 
            r.cpu_time, 
            r.logical_reads, 
            r.reads, 
            r.writes, 
            r.total_elapsed_time / (1000.0), 
            Substring(st.TEXT,(r.statement_start_offset / 2) + 1, 
                    ((CASE r.statement_end_offset 
                        WHEN -1 
                        THEN Datalength(st.TEXT) 
                        ELSE r.statement_end_offset 
                        END - r.statement_start_offset) / 2) + 1) AS statement_text, 
            Coalesce(Quotename(Db_name(st.dbid)) + N'.' + Quotename(Object_schema_name(st.objectid,st.dbid)) + N'.' + Quotename(Object_name(st.objectid,st.dbid)), 
                    '') AS command_text, 
            r.command, 
            s.login_name, 
            s.host_name, 
            s.program_name, 
            s.last_request_end_time, 
            s.login_time, 
            r.open_transaction_count 
FROM     sys.dm_exec_sessions AS s 
            JOIN sys.dm_exec_requests AS r 
            ON r.session_id = s.session_id 
            CROSS APPLY sys.Dm_exec_sql_text(r.sql_handle) AS st 
WHERE    r.session_id != @@SPID 

declare @spid int = 0, @sql varchar(4000)

declare commands CURSOR LOCAL FORWARD_ONLY STATIC   for 

select session_id from #processes
open commands
 fetch next from commands into @spid

    WHILE @@FETCH_STATUS = 0

    BEGIN
set @sql  = 'DBCC inputbuffer(' + cast(@spid as varchar(5))+')'
insert #dbcc_result(eventtype , parameters , eventinfo ) 
EXEC(@sql) 
update #dbcc_result set spid = @spid where spid is null

fetch next from commands 

into @spid
end

select   p.*, dr.eventinfo from #processes p

join #dbcc_result dr on dr.spid = p.session_id



drop table #processes
drop table #dbcc_result


вторник, 17 марта 2015 г.

Снова Proxmox. Доступ к виртуальной машине через VNC

Просто оставлю ссылку на полезный материал:
Описывается метод организации доступа к конкретной виртуальной машине через VNC-клиент. Это для тех, кого утомила штатная веб-консоль Proxmox.
Опробовано лично на версии 3.3. и клиенте Tiger-VNC под Windows.

понедельник, 6 октября 2014 г.

Миграция почты с одного сервера на другой

В какой-то момент в нашей организации стал вопрос переноса почты на вновь созданный сервер под управлением Exchange 2010. Исходные условия  -  удаленный почтовый сервер с доступом к нему по imap  и Exchange 2010 SP1 с доступом к нему как угодно.
Вариант 1-й - миграция с помощью pst-файлов(подготовленных при помощи Microsoft Outlook на клиентских машинах)  провалилась практически сразу же, когда оказалось, что Exchnge практически гарантированно выдает ошибку при импорте ящика объемом более 1 Гигабайта. 
Второй вариант - использовать вспомогательный сервер Exchange 2007 и утилиту Microsoft Transporter Suite, специально предназначенную для миграции данных в Exchange(под 2010 сервером она не работает) тоже не сработала. Microsoft Transporter  читал письма по imap группами по 10 писем (команда вида fetch 1,2,..,10), а сервер этого упорно не понимал. При этом fetch с указанием номера одного письма спокойно проходил. Точно так же, как чтение утилитой Microsoft transporter с другого сервера тоже шло на ура.
Временным решением показалась утилита Aid4Mail - как перенос imap-imap, но при объеме в сотню с лишним почтовых ящиков хотелось как-то больше автоматизации. плюс, часто при переносе при помощи Aid4Mail некоторые письма не переносились из-за непонятных ошибок(чем именно были вызваны эти ошибки - я разобрался уже позже).
Итоговое решение пришло не сразу. На утилиту imapsync я обратил внимание еще в самом начале поисков, но отсутствие свободной версии на офсайте как-то отпугнуло(хотя 50 евро за этот продукт - на самом деле очень демократичная цена). Но при более внимательном поиске обнаруживаем, что "все уже украдено до нас" - https://fedorahosted.org/released/imapsync/  .
Сначала я попробовал линуксовую версию - результат удовлетворил более чем. Но так как я все-таки в первую очередь виндузятник, то не мог не попробовать виндовую версию, которой тоже остался доволен  - и скоростью переноса, и соответствием исходного и конечного набора данных.  При использовании этой утилиты благодаря подробным логам и пришло понимание того, почему при помощи Aid4Mail не переносились некоторые письма -  они превышали допустимый размер, указанный на сервере Exchange. 
Вкратце, команда переноса при помощи imapsync выглядела так:

imapsync.exe --host1 imap.server1.ru --user1 username1 --password1 password1 --host2 imap.server2.ru --port2 993 --ssl2 --user2 username2 --password2 password2 --authmech2  PLAIN >>pathtologfile.log 

Здесь несложно догадаться, что исходный сервер работает по стандартному 143 порту без использования SSL, а сервер Exchange настроен на 993 порт с использованием SSL. Также отмечу, что использования механизма аутентификации  PLAIN  было необходимостью в случае авторизации пользователя на imap-сервере Microsoft Exchange.
Теперь же, переходим к самому интересному - к автоматизации процесса. Здесь сразу затрону механизм авторизации. В Exchange есть такая возможность - дать конкретному пользователю права на доступ к любому почтовому ящику. Это свойство можно использовать при входе на imap-сервер. Т.е., если у нас есть пользователь adminuser, с правами доступа к почтовому ящику пользователя user1, то мы можем зайти в почтовый ящик пользователя user1, не указывая его пароль, Получится примерно так --user2 domain/adminuser/username --password2 adminuserpassword --authmech2 LOGIN. Вот тут прокатило только так - с authmech LOGIN, почему  - не знаю, просто сработало эмпирически.
Теперь ,собственно автоматизация на Powershell:
Делаем CSV в формате  user1;password1;user2 (так и пишем в первой строке файла). Здесь user1/password1 - пара логин/пароль на исходном почтовом сервере. User2  - имя пользователя на конечном почтовом сервере Exchange, пароль нам не важен, у нас есть логин/пароль административного пользователя с доступом ко всем почтовым ящикам.
В итоге получается такой скрипт (лог пишется для каждого пользователя в отдельный файл):
$mail=import-csv d:\imapsync\sync.csv -Delimiter ';'
foreach ($stroka in $mail) 
{ $user1=$stroka.user1
$password1=$stroka.password1
$user2=$stroka.user2
& D:\imapsync\imapsync.exe --host1 imap.server1.ru --user1 $user1 --password1 $password1 --host2 imap.server2.ru --port2 993 --ssl2 --user2 domainname/adminuser/$user2 -password2 password2 --authmech2 LOGIN | Out-File -filepath d:\imapsync\logs\$user1.log -Append -NoClobber

}

четверг, 15 мая 2014 г.

Proxmox: загрузка бэкапов через веб-интерфейс

Снова столкнулся с тем, что в достаточно широко распространенном программном продукте не работает из коробки та функция, которая по логике должна бы работать.
На этот раз речь пойдет о среде виртуализации Proxmox и загрузке бэкапов виртуальных машин через веб-интерфейс. Итак, имеем следующие входные данные: на машине свежеустановленный Proxmox версии 3.2, на нем развернуто помимо хранилища Local еще и хранилище Backup с типом контента ISO, Backups, Templates. Задача  - перенести бэкапы виртуальных машин с другого гипервизора. Естественно, руки потянулись для этой цели использовать веб-интерфейс: выбираем наше хранилище Backup, жмем Upload, выбираем тип контента VZDump backup file, выбираем нужный файл, жмем Upload, смотрим на проценты загрузки и по итогу получаем сообщение об ошибке:
 Error 400: Parameter verification failed.
content: upload content type 'backup' not allowed
Собственно, я сразу не стал разбираться, почему так, и воспользовался консолью и самбой для решения этой задачи. Примерно то же самое(пойти обходным путем) рекомендует баг-трекер Proxmox'а(use scp to copy the file to the right directory). Но обсуждение этой проблемы вывело меня на верное решение.
Открываем для редактирования следующий скрипт: /usr/share/perl5/PVE/API2/Storage/Status.pm.
Находим там следующий фрагмент:
if ($content eq 'iso') {
if ($filename !~ m![^/]+\.[Ii][Ss][Oo]$!) {
raise_param_exc({ filename => "missing '.iso' extension" });
}
$path = PVE::Storage::get_iso_dir($cfg, $param->{storage});
} elsif ($content eq 'vztmpl') {
if ($filename !~ m![^/]+\.tar\.gz$!) {
raise_param_exc({ filename => "missing '.tar.gz' extension" });
}
$path = PVE::Storage::get_vztmpl_dir($cfg, $param->{storage});
} else {
raise_param_exc({ content => "upload content type '$content' not allowed" });
}

Как видим, по дефолту доступны для загрузки только ISO образы и шаблоны, при загрузке отличного от этих типов контента получаем знакомое сообщение об ошибке.
Исправляем:

if ($content eq 'iso') {
if ($filename !~ m![^/]+\.[Ii][Ss][Oo]$!) {
raise_param_exc({ filename => "missing '.iso' extension" });
}
$path = PVE::Storage::get_iso_dir($cfg, $param->{storage});
} elsif ($content eq 'vztmpl') {
if ($filename !~ m![^/]+\.tar\.gz$!) {
raise_param_exc({ filename => "missing '.tar
.gz' extension" });
}
$path = PVE::Storage::get_vztmpl_dir($cfg, $param->{storage});
} elsif ($content eq 'backup') {
if ($filename !~ m![^/]+\.vma\.lzo$!) {
raise_param_exc({ filename => "missing '.vma.lzo' extension" });
}
$path = PVE::Storage::get_backup_dir($cfg, $param->{storage});
} else {
raise_param_exc({ content => "upload content type '$content' not allowed" });
}

Я добавил для себя проверку на расширение vma.lzo,  поскольку все мои бэкапы были сделаны именно в этом формате, но при желании можно добавить и  vma.gz, а можно и вообще отказаться от проверки на расширение.
Перезагружаем Proxmox - и таки да, загрузка бэкапов через веб-интерфейс работает. 

четверг, 21 ноября 2013 г.

Двусторонняя печать в 1С 8.3

С некоторым удивлением обнаружил, что из 1С версии 8.3 двусторонняя печать не работает в привычном режиме, просто выбрав в настройках нужного принтера  двустороннюю печать, так как это работает в той же 1С 8.2 (да и в любой нормальной программе).
Легкое погугливание подсказало, что проблема действительно кроется в 1С данной версии, и 1С тут на самом деле причем (это уже не гугление, это я от себя).
А решение очень простое  - заходим в Файл - Параметры страницы. И уже там находим двустороннюю печать  изменяем "Нет" на нужное значение (Поворот либо переворот страницы). Ну заодно и выбираем нужный принтер и правильно указываем его настройки.

вторник, 5 ноября 2013 г.

Злобный вирус через Skype

Злобный вирус через Skype

За последние несколько дней Skype заполонила рассылка файла вида invoice_******.pdf.exe, который, понятное дело является вирусом. Естественно, что многие пользователи его открыли, естественно, что вирус запустился. Симптомы вируса следующие: пользователь начинает рассылать файл invoice_******.pdf.exe своим контактам в skype, скайп не показывает всплывающие уведомления о приходящих сообщениях, дублирует сообщения или же просто не отображает историю сообщений. Так же ко всему прочему не запускается Google Chrome.
То, что большинство антивирусов (Kaspersky, Microsoft Essential, ESET NOD32, AVZ и прочие троян-ремуверы) этот вирус не детектят, сюрпризом не стало. Удивительным стало то, что кроме нескольких тредов на community.skype.com и на virusinfo тема решения вопроса практически нигде не раскрыта, а описания работы вируса и шагов по его лечению спустя практически неделю после его массового распространения.
Сразу отмечу, что те меры, которые описываются в указанных тредах(прогнать полную проверку каким-то антивирусом, переустановить скайп, удалив все данные из \профиль пользователя\appdata\roaming\skype, а так же удалив из  \профиль пользователя\appdata\local\temp собственно файл invoice_******.pdf.exe) в полной мере не помогают. Пользователь перестает рассылать файл, но по-прежнему не запускается Google Chrome, и существует проблема с отображением сообщений в чате скайпа. Мой коллега дополнил картину симптоматики  - вирус отправляет какую-то информацию сюда:
https://8isd19h5s3pft.dmf.su/ping.html?r=1328019076 
https://b76eiq5x1jugnrtd
https://dmf.su/ping.html
https://dmf.su/ping.html 
https://gva.cc/ping.htm
https://gva.cc/ping.html
https://gva.cc/ping.html 
https://oul.su/ping.html
https://oul.su/ping.html 
https://pmr.cc/ping.html
https://pmr.cc/ping.html 
https://vng.su/ping.html

А так же блокирует запуск некоторых утилит, вроде различных просмотрщиков автозапуска и реестра. Одна из таких утилит - regshot, которая  позволяет сделать снимки реестра и отслеживать изменения его состояния. В процессе определения наличия вируса это весьма помогало.
По сути, вирус запускается в профиле пользователя, подхватившего зараженный файл, из ветки реестра  HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run, создавая там ключ с произвольным именем и путем к исполняемому файлу.  Но если зайти в редактор реестра, то ничего подобного заметить не получится, вирус отслеживает обращения к реестру и вовремя удаляет себя из автозагрузки, если обнаруживает запущенные средства мониторинга реестра.
Так же запускаемый из автозагрузки процесс быстро цепляет свой код к произвольному исполняемому файлу(чаще всего, к какой-нибудь виндовой консольной утилите), поэтому удалив подозрительный исполняемый файл из какой-нибудь папки в профиле пользователя, вы от вируса не избавитесь.
Поэтому достаточно вылогиниться, зайти под другим пользователем, запустить regedit, сделать "Файл - загрузить куст", в качестве куста выбрать файл ntuser.dat в профиле пользователя, который подхватил заразу и очистить ветку   HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run от явно лишнего исполняемого файла. В случае, когда заражена административная учетная запись, помогло зайти под ней в безопасном режиме. Ну и удалить собственно, исполняемый файл.
Дальше лучше полностью переустановить скайп с очисткой %профиль пользователя%\appdata\roaming\skype, поскольку там могут остаться нежелательные .exe  файлы(пусть и не запускаемые из автозагрузки). Но особо нетерпеливым можно ограничиться удалением файла 
%профиль пользователя%\appdata\roaming\skype\%учетная запись skype%\main.db и перезапуском скайпа. Тогда начнут правильно отображаться сообщения в чате и уведомления о новых сообщениях.