Use of LOGINPROPERTY('user', 'PasswordHash) in SQL Server 2008 and 2012 - sql-server

I'm writing a little script to extract the password hashes of SQL Logins on 2008 and 2012 instances. Part of my code looks like this...
SELECT CONVERT (VARCHAR(514), (SELECT CAST (LOGINPROPERTY('sa', 'PasswordHash') AS varbinary(256))), 2)
When I run this in a 2012 instance, it all works fine. But when run on a 2008 instance I get a blank result. I've checked that the SQL login is valid and has a password on the 2008. The online documentation tells me that all the functions are valid between both versions.
What is the difference between the versions?
Regards,
JC

Hash algorythms used:
SQL Server 2012 and above use SHA2-512 (512 bytes hash)
SQL Server 2000 to 2008 R2 use SHA1 (160 bytes hash)
You can also uses this query and DMV:
Select password_hash, * From sys.sql_logins Where name in ('sa')
It gives the same hash that this query:
Select CONVERT (varchar(512), (LOGINPROPERTY('sa', 'PasswordHash') ), 2)
Use this one if you want a varchar starting with 0x
Select CONVERT (varchar(514), (LOGINPROPERTY('sa', 'PasswordHash') ), 1)

Related

Why does SQL Server HASHBYTES work differently from Oracle STANDARD_HASH?

Any idea why the two hashing functions in SQL Server and Oracle yield different results when hashing the non-breaking space character?
Oracle select standard_hash('a ', 'MD5') from dual; results in 25EF28EB5A5BE667C6222418E9E27E8E and doesn't match SQL select HASHBYTES ('MD5','a '); results in CE8F03020C81133B3A082F8051EB9FF6. Note the space after the input 'a' is a non-breaking space character.
Is there any good source that can lay out the differences?
This appears to be a character set or "collation" issue, where Oracle is in UTF-8 and SQL Server is in Latin 1252. My solution was to CONVERT the value to Windows Latin-1252 in Oracle before calculating the hash: select STANDARD_HASH(CONVERT('a ','WE8MSWIN1252'), 'MD5') from dual.
To find my collation/character set I did SELECT collation_name FROM sys.databases WHERE name = 'MY_DB_NAME'; in SQL Server and select * from nls_database_parameters where parameter='NLS_CHARACTERSET'; in Oracle.
First of all you need to establish which one is actually yielding "different" results:
Using your favourite search engine to find online hash generators and testing results.
External Resources
https://passwordsgenerator.net/md5-hash-generator/ - 99020CB24BD13238D907C65CC2B57C03
https://www.md5hashgenerator.com/ - 99020cb24bd13238d907c65cc2b57c03
https://www.miraclesalad.com/webtools/md5.php - 99020cb24bd13238d907c65cc2b57c03
SQL Server
select HASHBYTES ('MD5', 'a ')
SQL Server 2014 SP3 (12.0.6024.0) - 0x99020CB24BD13238D907C65CC2B57C03
SQL Server 2019 (15.0.2080.9) - 0x99020CB24BD13238D907C65CC2B57C03
Oracle (using https://dbfiddle.uk/)
select standard_hash('a ', 'MD5') from dual;
Oracle 21c - 0x99020CB24BD13238D907C65CC2B57C03
Oracle 18c - 0x99020CB24BD13238D907C65CC2B57C03
Oracle 11gR2 - "ORA-00904: "STANDARD_HASH": invalid identifier"
Conclusion
You can see that your Oracle produced answer differs even from other Oracle answers. What version of Oracle are you running? What other options are set, such as collation etc.?

Why does same query on different sql server versions have different execution plans

Given the following query (note the SELECT pKey sub query is dynamically generate in code thus the reason for the sub query):
SELECT COUNT(p.pKey) AS [Value] FROM (
SELECT pKey
FROM [Profile] LEFT OUTER JOIN [Groups] ON gKey = pgKey
WHERE gName = 'Acme' AND pSearch04 = 'ACTIVE'
) p LEFT JOIN(SELECT dlpKey FROM DataLoads WHERE dlprocKey = 60909) d ON p.pKey = d.dlpKey
WHERE d.dlpKey IS NULL
I'm getting very different query plans on the 'same' database (albeit different SQL Server versions).
In one data center we have Microsoft SQL Server 2008 R2 (SP2) – 10.50.4000.0. In another server we have Microsoft SQL Server 2012 (SP2-GDR) (KB3194719) - 11.0.5388.0 (X64). The 2008 has compat level of 90 while the 2012 has compat level 110. This query is generating different plans where 2012 does table scan (times out) and 2008 appears to use an existing index (returns immediately).
The 2012 plan also suggests an index creation that would have a 98% impact while 2008 makes no such suggestion. Note, I don't really want to make an index (on field pSearch04) as suggested because our database is a multi-tennant database and pSearch04 could be completely different data across clients.
I used Red Gate SQL Compare to compare the schemas and it said they were the ‘same’ (just few minor diffs in users).
I tried looking at the saved plans on the 2008 server, and was told to compare the CardinalityEstimatorModelVersion property and/or try the plan comparison option - I had neither of them in my version of SSMS.
Any suggestions as to how I might debug to see why the 2012 seems to generate an execution plan that uses a table scan? My limited SQL DBA skills are at a loss. Examining the table that had the table scan on it, the indexes and relationships are identical (via manual compare vs just using Red Gate).
2008 Execution Plan: https://pastebin.com/zgUTNy2q
2012 Execution Plan: https://pastebin.com/ab2qf5ut
Let me know if there is any additional information I can provide to help solve this.

SQL Server 2005 query uses ? which doesn't work in SQL Server 2012

I'm working on an application which queries live data on SQL Server. The user enters a name within '% %' marks to search. Ie. if the user was to search for the owner of a property such as Noble, they would enter %noble%.
We recently upgraded both the application and the SQL Server that stores the data from SQL Server 2005 to SQL Server 2012.
The existing query and the new query are identical:
SELECT aurtvalm.pcl_num
FROM aurtvalm
INNER JOIN rtpostal ON aurtvalm.ass_num = rtpostal.ass_num
WHERE rtpostal.fmt_nm2 LIKE ?
In the old version, the above query produces 16 results. The exact same query in 2012 version produces an error:
Incorrect Syntax near '?'
Has the use of the ? symbol changed since SQL Server 2005?
That because you have incorrect syntax. You have to use parameter instead of question mark. Something like:
SELECT aurtvalm.pcl_num
FROM aurtvalm
INNER JOIN rtpostal ON aurtvalm.ass_num = rtpostal.ass_num
WHERE rtpostal.fmt_nm2 like #param

What is the purpose of "::" in T-SQL

In (non-English) book on T-SQL (SQL Server 2005) I read about:
SELECT * FROM ::fn_helpcollations()
Though, execution of it without "::"
SELECT * FROM fn_helpcollations()
In my SQL Server 2008 R2 gives exactly the same result.
What does "::" mean in T-SQL?
From MSDN:
However, when you call SQL Server
built-in functions that return a
table, you must add the prefix :: to
the name of the function:
SELECT * FROM ::fn_helpcollations()
Looks like you can omit the :: in SQL Server 2005 and 2008. The :: syntax will be supported for backward compatibility.

Detect Sql Express From TSQL

I need a safe (i.e consistent, robust) way of detecting whether or not the sql server I'm accessing is Sql Express. I think I'd prefer to be able to do this from TSQL, since I already have a connection string and all the libraries I need to execute TSQL (this should help avoid issues with whether or not WMI is installed/running, the user has permissions to access the registry etc).
Does anyone know of a way to do this ?
Thanks.
PS: Basically I want to do this so I can monitor my database size against the 4gb limit and take action when I approach it... but if I'm running on a full Sql Server edition then I don't want the code to worry about it since there is no (practical) hard coded limit. I could put in a manual setting in my program, but it would be much nicer if the code just did the right thing automatically, hence the need to know if the server is the 'Express' edition or not.
Use
SELECT SERVERPROPERTY('EditionID')
or
SELECT SERVERPROPERTY('Edition')
to detect which version of SQLServer is running.
http://msdn.microsoft.com/en-us/library/ms174396.aspx
This will return 0 if it's not, and something non-zero (126 here) if it is:
select charindex('Express Edition',##version)
Example in a boolean context:
if (select charindex('Express Edition',##version)) > 0
begin
print 'Express edition!'
end
else
begin
print 'Not Express edition!'
end
The SERVERPROPERTY function was already mentioned in multiple other answers, but there's a better solution than checking if a string contains "Express Edition": the EngineEdition argument, which returns an int value.
Quote from the link:
EngineEdition
Database Engine edition of the instance of SQL Server installed on the
server.
1 = Personal or Desktop Engine (Not available in SQL Server 2005 and
later versions.)
2 = Standard (This is returned for Standard, Web, and Business
Intelligence.)
3 = Enterprise (This is returned for Evaluation, Developer, and both
Enterprise editions.)
4 = Express (This is returned for Express, Express with Tools and
Express with Advanced Services)
5 = SQL Database
6 - SQL Data Warehouse
Base data type: int
So you can check for Express Edition like this:
if SERVERPROPERTY('EngineEdition') = 4
begin
select 'Express'
end
else
begin
select 'not Express'
end
There are a number of ways:
EXEC sp_server_info 2
Or
SELECT ##version
Or
SELECT serverproperty('ProductVersion')
You Can Also do this:
DECLARE #ver nvarchar(128)
SET #ver = CAST(serverproperty('ProductVersion') AS nvarchar)
SET #ver = SUBSTRING(#ver, 1, CHARINDEX('.', #ver) - 1)
IF ( #ver = '8' )
SELECT 'SQL Server 2000'
ELSE IF ( #ver = '9' )
SELECT 'SQL Server 2005'
ELSE
SELECT 'Unsupported SQL Server Version'
More info at: http://blog.devstone.com/aaron/default,date,2006-12-15.aspx
You can use SERVERPROPERTY('Edition') which will return "Express Edition"
What happens in SQL Server Express if you don't monitor the size, but get to the limit? Are there warnings first? Events in the event log?
If so, then you might do better to allow SQL Server to issue the warnings, and then just listen to them. The same might well apply for a SQL Server Enterprise installation if a disk gets full.

Resources