Quantcast
Channel: Oracle Bloggers
Viewing all articles
Browse latest Browse all 19780

Obfuscated SQL Contest: James Su's Entry

$
0
0

As promised in the announcement of the winners for the Obfuscated SQL Contest we're dissecting the queries of the winners to make sense from the madness! In this post we'll look at James Su's entry. 

The judges all loved the elegantly simple complexity of this statement. At its core is a query that just selects a blank line made up of tabs and spaces along with the tab character:

SELECT'                                                                                                                                                                                                                                                                                                                                                                                                      '
||'                                                                                                                                                                                                                                                                                                                                                                                    '
||'                      ' S,
chr(9) b 
FROM DUAL

How could this possibly enable us to return the times?

Via cunning string manipulation!

Firstly the query generates 396 rows using "connect by level". In a cool flourish, the number of row is determined using RegExp_Count to find the number of tabs hidden in the string and dividing this by three.

Each row is given a numeric value, assigned using gnarly instr manipulation of the line of spaces and tabs. 

There's three instr sections:

  (INSTR(S,b,1,3*LEVEL-2)-           DECODE(LEVEL,1,0, INSTR(S,b,1,3*LEVEL-3))-1)*25 + --i25  (INSTR(S,b,1,3*LEVEL-1)-INSTR(S,b,1,3*LEVEL-2)-1)*5 + --i5  INSTR(S,b,1,3*LEVEL)-INSTR(S,b,1,3*LEVEL-1)-1 + 32 --i32

The i25 section returns multiple of 25 - 0, 25, 50 or 75, i5 returns multiple of five up to 20 - 0, 5, 10, 15, 20 - and i32 returns numbers in the range 32-36. It then adds these values together. This is then passed into the chr() function, which returns the character corresponding to the ascii value provided.

The result of this are rows containing letters. These are then pivoted to a single row using the ListAgg() operator, which gives the following (formatted for clarity):

SELECT 'BAN - ' || TO_CHAR(A AT TIME ZONE 'ASIA/CALCUTTA', B) || '; ' ||'LON - ' || TO_CHAR(A AT TIME ZONE 'EUROPE/LONDON', B) || '; ' ||'NEW - ' || TO_CHAR(A AT TIME ZONE 'AMERICA/NEW_YORK', B) || '; ' ||'CHI - ' || TO_CHAR(A AT TIME ZONE 'AMERICA/CHICAGO', B) || '; ' ||'DEN - ' || TO_CHAR(A AT TIME ZONE 'AMERICA/DENVER', B) S 
FROM (SELECT SYSTIMESTAMP A,'DD-MON-YYYY HH24:MI:SS' B FROM DUAL) 

Now we can see what's going on!

James has created a query that selects the current time and a date format, then passes these in to to_char to get the appropriate output. 

This SQL statement is executed using the DBMS_XMLGen package. The GetXMLType function accepts a SQL query and returns an XMLType document. The document contains the result of the query. In this case we have (formatted for clarity again):

<ROWSET> <ROW>  <S>
BAN - 12-MAY-2015 14:30:50; 
LON - 12-MAY-2015 10:00:50; 
NEW - 12-MAY-2015 05:00:50; 
CHI - 12-MAY-2015 04:00:50; 
DEN - 12-MAY-2015 03:00:50</S> </ROW></ROWSET> 

From here getting the desired output is simply a matter of using substr to return the times from within the <S> element.

Overall a fantastic solution that scored highly on the "how on earth...?!" factor. The judges felt that the select statement passed into DBMS_XMLGen is a little too simple to take the top spot however.

Great work James! In the next post we'll look at Sean Stuber's entry. 


Viewing all articles
Browse latest Browse all 19780

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>