In the previous article, I explored the opportunity of using special characters (or emojis) within Extended Event Sessions. Creating a session with these characters in the name is not terribly complicated. However, it is a bit more of a pain on the data review side (as mentioned in the previous article).
Just because it gets to be a little more complicated is seldom a deterrent for somebody such as myself. In fact, many times it is more of a challenge. These challenges are fun. With this particular challenge, and as I promised, we are going to see how we can solve the problems posed by having emojis within the object names (which causes pseudo funky data to be trapped in the session data).
Get the Funk Out!
As was demonstrated in the last article, when we have special characters in the database names and that data is captured in an XE Session, we end up with some smelly funky cheese type data that is fairly unpleasant to our desires. We have to do something quickly with that funky data in order to make it useful.
Unlike funky cheese that may have turned, we are not going to discard this data as being unwanted or un-useful. We still have a use for it. We just need to transform it a little bit before it becomes a little more palatable.
Let’s go back to a query we used to parse the session data from that last article. We need to modify this query to make it more capable of handling this new data experience.
Knowing that we have certain patterns that need to be recognized and altered, we can take advantage of the replace function. The first two patterns to find are: “&#” and then “;“. The next step is a little less known. What do we replace those known patterns with? Well, as it turns out, and as is shown in the above query results window, we know that we are looking for two surrogate code points (High and Low) that represent the character in question. When we do a little TSQL trickery and use NCHAR with those surrogate values, we can render the character to display in the desired format. Let’s see that in query form (it will help that explanation quite a bit).
SELECT NCHAR(55357) + NCHAR(56489);
The results of this query will look like the following.
Easy peasy right? Well, sort of easy. We can easily render that funky data we are seeing in the session details to something more human friendly. However, in order to display that data in human friendly format, we have to execute it in a sort. This means we have to do something a little more with the query – we have to convert some part of the query to a dynamic SQL statement. Here is how we can do that!
DECLARE @DynSQL NVARCHAR(MAX); WITH presel AS ( SELECT event_data.value('(event/@name)', 'varchar(50)') AS event_name, event_data.value('(event/@timestamp)', 'varchar(50)') AS [TIMESTAMP], REPLACE(REPLACE(event_data.value('(event/action[@name="database_name"]/value)', 'varchar(max)'),'&#','NCHAR('),';',') + ') AS DBName FROM( SELECT CONVERT(XML, t2.event_data) AS event_data FROM ( SELECT target_data = convert(XML, target_data) FROM sys.dm_xe_session_targets t INNER JOIN sys.dm_xe_sessions s ON t.event_session_address = s.address WHERE t.target_name = 'event_file' AND s.name = N'') cte1 CROSS APPLY cte1.target_data.nodes('//EventFileTarget/File') FileEvent(FileTarget) CROSS APPLY sys.fn_xe_file_target_read_file(FileEvent.FileTarget.value('@name', 'varchar(1000)'), NULL, NULL, NULL) t2) AS evts(event_data) ) SELECT p.event_name, p.TIMESTAMP, LEFT(p.DBName, LEN(p.DBName) - 2) AS DBName INTO #xedbnames FROM presel p; SELECT @DynSQL = 'SELECT p.event_name, p.TIMESTAMP,' + p.DBName + ' AS DBName FROM #xedbnames p' FROM #xedbnames p EXECUTE (@DynSQL) DROP TABLE #xedbnames;
In this new version of the query, I have a few things going on. First, I am pattern matching and doing a replacement for those aforementioned terms. Next, I am dumping the results into a temp table and removing some extra data (unnecessary stuff due to the pattern matching and replacement). From the temp table, I then build a dynamic query to pull it all together and use that NCHAR trick to put the two surrogate values together to visually represent the character we expect. In the end, I have results that look like this.
Now, from a TSQL query, I have a visual representation of the Database Name that matches what I should be seeing within the SSMS object tree. This makes more logical sense to the person reviewing the data and is far easier to correlate to the correct database.
What about the histogram target that was demonstrated in that other article? Let’s look at the changes for that one as well.
DECLARE @DynSQL NVARCHAR(MAX); WITH presel AS ( SELECT REPLACE(REPLACE(n.value('(value)', 'nvarchar(60)'),'&#','NCHAR('),';',') + ') AS database_name, n.value('(@count)', 'bigint') AS ghost_count FROM (SELECT CAST(target_data as XML) target_data FROM sys.dm_xe_sessions AS s JOIN sys.dm_xe_session_targets t ON s.address = t.event_session_address WHERE s.name = N'' AND t.target_name = 'histogram' ) as tab CROSS APPLY target_data.nodes('HistogramTarget/Slot') as q(n) ) SELECT p.ghost_count, LEFT(p.database_name, LEN(p.database_name) - 2) AS DBName INTO #xedbnames FROM presel p; SELECT @DynSQL = 'SELECT p.ghost_count, ' + p.DBName + ' AS DBName FROM #xedbnames p' FROM #xedbnames p EXECUTE (@DynSQL) DROP TABLE #xedbnames; GO
The results are now similar to those we fetched for the event_file target (similar in display format). Again, this makes it easier to digest for us humans.
Put a bow on it
Playing around with emojis in a database is a fun endeavor. Not only is it fun to play with for personal growth, but it does have some business advantages. We live in an era were these emojis are popping up everywhere and are even being stored long term in many databases. I view it as a great opportunity to improve your skill set and better your career for the future.
Interested in learning about some deep technical information instead? Check these out!
This is the eleventh article in the 2019 “12 Days of Christmas” series. For the full list of articles, please visit this page.