piątek, 28 lutego 2014

Casting INT, BIGINT, SMALLINT, TINYINT to DECIMAL - a cheatsheet (SQL Server)

Type casting.. some are obvious, some are not.. When you're casting to DECIMAL(p,s) type, you've got to stop and think what scale you need and what precision is enough.

Fast replay

On MSDN: http://msdn.microsoft.com/en-us/library/ms187746.aspx (decimal and numeric in T-SQL)

In following example you have to store decimal like this 98'765.4321.

Your precision is 998'765.4321
Your scale is 4: 98'765.4321.

Another approach:
Take your "max value", which is 5 digits: 98'765.4321.
Add your scale, which is 4:  98'765.4321.
And your precision is 5 + 4 = 9.

So your destination type is DECIMAL(9,4).

In case of negative number, like -98'765.4321 DON'T count the sign. Precision is still 9.


Perfect precision

Now, what is safe precision for casting BIGINT to DECIMAL?

Back to MSDN: http://msdn.microsoft.com/en-US/library/ms187745.aspx (int, bigint, smallint and tiny int in T-SQL).

BIGINT is 8-Bytes data type.
Its range is -2^63 (-9'223'372'036'854'775'808) to 2^63-1 (9'223'372'036'854'775'807).
Now, count digits above..
Or..

So.. 2^63 is ~9.22 x 10^18 which is ~0,922 x 10^19. So required precision is 19. As BIGINT cannot have digits after coma scale is 0. Finally, required type is DECIMAL(19,0).

Fast check

DECLARE @dec19 DECIMAL(19,0)

SET @dec19 = -9223372036854775808 -- OK
SET @dec19 = 9223372036854775807 -- OK

DECLARE @dec18 DECIMAL(18,0)
SET @dec18 = -9223372036854775808 -- Error: Arithmetic overflow error converting numeric to data type numeric.
SET @dec18 = 9223372036854775807 -- Error: Arithmetic overflow error converting numeric to data type numeric.

Which means DECIMAL(19,0) is perfect for casting BIGINT and DECIMAL(18,0) is too short.

Divisibility

Did I say "perfect"?
Let's try to divide DECIMAL(19,0) variable by 1000 and store it as DECIMAL(19,3)..
(scale changed, precision is still the same)

DECLARE @dec190 DECIMAL(19,0)
DECLARE @dec193 DECIMAL(19,3)

SET @dec190 = 9223372036854775807 -- BIGINT max value
SET @dec193 = @dec190 / 1000

SELECT @dec190, @dec193

Works! Results are: 9223372036854775807 and 9223372036854775.807.

Let's have another try.. Divide BIGINT variable by 1000 and store it as DECIMAL(19,3)..

DECLARE @big BIGINT
DECLARE @dec193 DECIMAL(19,3)

SET @big = 9223372036854775807 -- BIGINT max value
SET @dec193 = @big / 1000

SELECT @big, @dec193

Is it good? No. Results are: 9223372036854775807 and 9223372036854775.000. We've lost some data.

So how to make it possible?

Like this?
SET @dec193 = CAST(@big AS DECIMAL(19,3)) / 1000
No. Arithmetic overflow error converting bigint to data type numeric.

Like this?
SET @dec193 = CAST(@big / 1000 AS DECIMAL(19,3))
No. Data after coma still lost.

We need to extend scale (and precision) of source variable to prepare it for a division.
We're about to divide by 1000, which is 10^3. So our goal is to cast source BIGINT variable to DECIMAL(19+3,0+3).. let's call WolframAlpha in here.. (joke!) ..which is DECIMAL(22,3).

We've got the winner:
DECLARE @big BIGINT
DECLARE @dec193 DECIMAL(19,3)

SET @big = 9223372036854775807 -- BIGINT max value
SET @dec193 = CAST(@big AS DECIMAL(22,3)) / 1000

SELECT @big, @dec193

or (less spectacular)..

DECLARE @big BIGINT
DECLARE @dec190 DECIMAL(19,0)
DECLARE @dec193 DECIMAL(19,3)

SET @big = 9223372036854775807 -- BIGINT max value
SET @dec190 = @big
SET @dec193 = @dec190 / 1000

SELECT @big, @dec193

..because it worked earlier in article.

Cheatsheet

And now cheatsheet is coming..

int type max value max value - scietific notation cast to decimal type cast to decimal type - divisible by 1000
BIGINT 2^63-1 ~0.922 x 10^19 DECIMAL(19,0) DECIMAL(22,3)
INT 2^31-1 ~0.215 x 10^10 DECIMAL(10,0) DECIMAL(13,3)
SMALLINT 2^15-1 32767 DECIMAL(5,0) DECIMAL(8,3)
TINYINT 2^8-1 255 DECIMAL(3,0) DECIMAL(6,3)

To be sure..

DECLARE @dec190 DECIMAL(19,0) =  9223372036854775807
DECLARE @dec223 DECIMAL(22,3) =  9223372036854775807.123
DECLARE @dec100 DECIMAL(10,0) =  2147483647
DECLARE @dec133 DECIMAL(13,3) =  2147483647.123
DECLARE @dec50 DECIMAL(5,0) = 32767
DECLARE @dec83 DECIMAL(8,3) = 32767.123
DECLARE @dec30 DECIMAL(3,0) = 255
DECLARE @dec63 DECIMAL(6,3) = 255.123

SELECT @dec190, @dec223, @dec100, @dec133, @dec50, @dec83, @dec30, @dec63

No errors.

That's all folks for today.

piątek, 18 października 2013

Access to (full) shell of Symantec Messaging Gateway (aka Brightmail)

Symantec Messaging Gateway (aka Brightmail) is anti-spam and anti-virus software for internet mail. It's distributed as VMware appliance (or installation disc for dedicated machines).

It's Linux based system but its shell is limited to some maintenance commands specific to product. There are also some limited number of Linux commands available - like ifconfig, route, ping, telnet.

But when it's not enough, when you need access some additional logs, there is a support user with access to full Linux shell.

Here is a receipt how to access this account.


  1. Open a console (on pictures Virtual Machine Console is launched under VMware vShpere Client).
  2. Login as admin with your admin password.
  3. Run set-support command and set temporary password for support user (temporary but product asks for complex password).
  4. Logout (as admin).
  5. Login as support with temporary password.
  6. Enjoy your freedom.









wtorek, 17 września 2013

Restore HP system image to hardware RAID volume (LSI MegaRAID SAS 9271-4i)

When there are no native OEM Windows installation discs included..

This is the story how I succeeded with restoring HP system image to RAID Controller. HP workstation comes only with "their" system image (and restore software) on DVDs and there is no way to restore it to RAID volume directly as there is no RAID controller driver included.

This is full list of hardware used in this case:

  • HP Z420 Workstation
  • LSI MegaRAID SAS 9271-4i 6Gb/s PCIe 3.0 (native LSI, not branded by HP)
  • 2x Intel 530 240GB SATA SSD disks
  • Multi-lane SAS (SFF-8087) to 4x SATA cable
  • HP restore discs with Windows 7 Pro 64-bit






At first I've just tried to connect disks into RAID controller, create RAID1 volume (this is called "virtual disk" in LSI) and to restore system from HP DVD. Failure. PC rebooted after splash screen.

After some hours..

Finally, complete solution


  1. Plug first SSD into SATA (at mobo).
  2. Restore system from HP restore discs into that SSD.
  3. Download and install LSI controller driver (from LSI site).
  4. Plug second SSD to RAID controller (I've used P2 connector on multi-lane cable; they were labelled P1..P4)
  5. Under RAID controller BIOS: Create RAID0 volume using second SSD disk.
  6. Under RAID controller BIOS: Set RAID0 volume as bootable one.
  7. Clone first SSD (connected to SATA at mobo) into second SSD (connected to RAID controller).
  8. Unplug first SSD and try to boot from RAID0 volume.
  9. Reconnect first SSD to RAID controller (I've used P1 connector this time).
  10. Change RAID level from RAID0 to RAID1 adding first SSD to the pool. (LSI need some time to regenerate RAID but it happens in background - you can even reboot).

A word about good software

Cloning was done with Macrium Software FREE Edition (v5.2.6377). It snapshots system partition so you may clone system disk to empty one. Intel gives free edition of Acronis (called as Intel Data Migration Tool), but it does not want to clone into Intel SSD connected under RAID controller (support may help you as branded Acronis in known to have some unlock codes).

poniedziałek, 8 lipca 2013

Normalize WEEKDAY behaviour [T-SQL]

In T-SQL, if you want to get know if it's Friday already, you have to query like this..

SELECT DATEPART(WEEKDAY, GETDAY())

And SQL Server answers with 5. Thanks GOD it's friday! But it's not..

Number given by DATEPART is dependent to SQL connection setting called @@DATEFIRST.
And default @@DATEFIRST is 7, meaning that Sunday is no. 1, Monday is no. 2... and so on..
So Friday is no. 6 in fact, not 5..

Check DATEFIRST by SELECT @@DATEFIRST.

User can trigger this setting by SET DATEFIRST. For example SET DATEFIRST 1, and now Monday is no. 1 and Friday is no. 5.

Ok..

So, DATEFIRST is related to SQL connection and everyone can have different settings. So how to write functions dependent on WEEKDAY? Can we just SET DATEFIRST in function body on ourselves? No, we cannot.

But we can normalize number returned by doing following trick:

SELECT (@@DATEFIRST + DATEPART(WEEKDAY, GETDATE()) - 2) % 7 + 1

Now Monday is no. 1 no matter what DATEFIRST is set to!
And Friday.. Thanks T-SQL it's 5th, again!

piątek, 28 czerwca 2013

Implement GOD MODE for blocking triggers with CONTEXT_INFO [MS SQL]

Sometime you have to implement blocking trigger (for DELETE, INSERT or UPDATE) saving you and your users from changing some important data in database. Blocking trigger - I mean - doing a ROLLBACK when some rules are broken.

But also sometimes you have to DISABLE TRIGGER for some maitenance tasks when you have to fix some data.

But disabling trigger has global effect. At this time no user is protected by entering wrong data into DB.

You may implement some exceptions into blocking trigger.

First (obvious) idea is to make an exception for user logged into SQL Server:

IF SUSER_SNAME() IN ('superuser1', 'DOMAIN\superuser2') RETURN

And RETURN escapes from blocking trigger at its beginning.

But..
If you are "superuser1" you are not protected by trigger at all. And you want to do maintenance only ad-hoc.

Let me introduce CONTEXT_INFO solution.

CONTEXT_INFO is a "key" set to current SQL connection - so it's ad-hoc setting. It gets VARBINARY(128) as value.

Simplest example (from MSDN) is
SET CONTEXT_INFO 0x1256698456
GO
SELECT CONTEXT_INFO()
GO

But who's gonna to remember 0x1256698456 as his very special "key"?

My way - use varchar "key" this way:

DECLARE @my_god_mode VARBINARY(128) = CAST('MY_GOD_MODE' AS VARBINARY(128))
SET CONTEXT_INFO @my_god_mode

If you put (above) into your maintenance script and (following) into blocking trigger- you have a complete solution:

IF CONTEXT_INFO() = CAST('MY_GOD_MODE' AS VARBINARY(128)) RETURN

or in more secret way.. :p

IF CONTEXT_INFO() = 0x4D595F474F445F4D4F4445 RETURN

Last tip - conversions both ways to play:

SELECT CAST('MY_GOD_MODE' AS VARBINARY(128))
SELECT CAST(0x4D595F474F445F4D4F4445 AS VARCHAR)

Have a nice god modding, guys! :)

niedziela, 26 maja 2013

Running ASDM 5.0 for Cisco PIX 515E under Linux/Ubuntu

Cisco ASDM (Adaptive Security Device Manager) is graphical user interface which can be found in Cisco PIX firewalls familiy. ASDM 5.0 is Java application.

Oracle Java (or "Sun Java" in IT prehistory) is not a part of Ubuntu distribution and out-of-the-box installation of Firefox lacks of Java plug-in also.

Additionaly, ASDM 5.0 has compatibility issues with newer JRE editions. Security exceptions are thrown onto Java Console and application refuses to open.

If you have to work with older devices you may find some issues with running their management software. It's not always possible or cost effective to update the firmware (IOS and ASDM) to resolve issues that way.

Here's a complete receipt to install older Java, install ASDM and run it up on Ubuntu system. I guess the receipt is not so distribution specific - so you may try it on other Linux distributions too. Some steps are also common for Windows environment - I'll cover Windows installation on next post.

Environment details

  • Cisco PIX 515E firewall
    • PIX Version 7.0(4)
    • ASDM Version 5.0(4)
  • Ubuntu 13.04 (AMD64)

Let's do it

Prepare working directory

Make a workspace. Let's say - create folder named "pix" under home directory.

mkdir ~/pix

..so you can access it by:

cd ~/pix

(I know it's obvious, sorry.)

Get ASDM

Here is - how to get ASDM in "windows" way. Not sure if there is "linux" way (If you know it - leave a comment).

You may get ASDM installation by loging into PIX page. Assuming your PIX is under 192.168.1.254 open URL https://192.168.1.254. Then log into with admin password.

You should see a screen like that (in fact this is Windows screenshot).


Click on "Download ASDM Launcher.." to get MSI file. MSI is of course MS Windows installation package but inside there is a Java application.

If you have got a problem with downloading MSI file (because this is in fact Windows example or your browser lacks of Java plug-in) you may download MSI file using windows machine and then transfer it onto linux machne OR use a "wget". Assuming your PIX is accessible under 192.168.1.254 and your admin account is "admin".

cd ~/pix
wget --no-check --user=admin --ask-password https://192.168.1.254/admin/asdm50-install.msi

Get Java Runtime

You should proceed to Oracle site (not "java.com"). As it was described at the very beginning ADSM has compatibility issues and cannot work with Java Runtime 1.7. Also Java 1.6 is not perfect.

I found those Java JRE editions to work with ASDM 5.0(4) properly:
With JRE 6.0 Update 10 ASDM starts but refuses to load configuration from PIX. With higher updates main window does not appear after login dialog.
 
I recommend to download ".bin" linux edition. This is self-extracting binnary file which installs into current working directory and does not make any modification to the system. Why this one? First, Oracle does not publish ".deb" packets (only ".rpm"). Second, I guess you don't want to integrate old Java with system.

Please, download jre-1_5_0_22-linux-amd64.bin (assuming you've got 64-bit system).

Get 7zip

We'll need to extract MSI package. It's possible with 7zip. If you have got no 7zip installed, do it so with following command:

sudo apt-get install p7zip-full

Checkpoint

At this point you should have working directory called ~/pix with files inside:
  • asdm50-install.msi
  • jre-1_5_0_22-linux-amd64.bin

Extract ASDM MSI package

cd ~/pix
7z x -oasdm asdm50-install.msi *.jar

This will extract JAR files from MSI package into asdm output subfolder.

Extract / install JRE

At first bin file needs to get execute flag. Then you may run it. Accept the license and Java will extract to subfolder of working directory.

cd ~/pix
chmod a+x jre-1_5_0_22-linux-amd64.bin
./jre-1_5_0_22-linux-amd64.bin

Tip: Press "q" to skip to the end of license. Type "yes" to accept.

Time to run ASDM

How NOT to do it

Java -jar switch won't work. You'll get "Failed to load Main-Class manifest attribute" error.

Fastest way

You need to export CLASSPATH and then run java pointing a main class of ASDM.

cd ~/pix/asdm
export CLASSPATH=`pwd`/asdm-launcher.jar:`pwd`/jploader.jar

You may check your CLASSPATH by:

set | grep CLASSPATH=

Run Java pointing a main class of ASDM

cd ~/pix/jre1.5.0_22/bin
./java com.cisco.pdm.launcher.Launcher &

Congratulations! You've got Cisco PIX ASDM working on Ubuntu.



Script way


Create run-asdm.sh file..

#!/bin/sh
export CLASSPATH=$HOME/pix/asdm/asdm_launcher.jar:$HOME/pix/asdm/jploader.jar
~/pix/jre1.5.0_22/bin/java -classpath $CLASSPATH com.cisco.pdm.launcher.Launcher &

Set execute flag on script..

cd ~/pix
chmod a+x run-asdm.sh

Run it..

cd ~/pix
./run-asdm.sh

Open Champagne! ;)

poniedziałek, 6 maja 2013

BACKUP SERVICE MASTER KEY with date in file name

A service master key is created when SQL Server instance is run for the first time. And it's regeneratred every time you change service account or its password. You should protect it with backup.

Syntax for BACKUP SERVICE MASTER KEY is described here:
http://msdn.microsoft.com/en-us/library/ms190337.aspx

Important notice is it does not allow to overwrite previous file. So you have to delete it before executing statement or use unique file names for every day backup.

This is my simple script to have BACKUP SERVICE MASTER KEY done with date in file name (so it's unique per day). It's compatible with SQL Server 2008 and above (older releases does not allow to set value while declaring variable).

Feel free to use it!


DECLARE @tsql NVARCHAR(512)
DECLARE @holder NVARCHAR(16) = '{DATE}'
DECLARE @path_to_file NVARCHAR(256) = 'D:\sqlbackup\keys\service_master_key_{DATE}.bak'
DECLARE @password NVARCHAR(16) = 'mysecretpassword'
DECLARE @current_day_string NCHAR(8) = CONVERT(NCHAR(8),GETDATE(),112)

SET @path_to_file = REPLACE(@path_to_file, @holder, @current_day_string)
SET @tsql = 'BACKUP SERVICE MASTER KEY TO FILE = '''+@path_to_file+''' ENCRYPTION BY PASSWORD = '''+@password+''''

EXECUTE sp_executesql @tsql