Ryans WebLog

  • Code Duplication tool on CodePlex

    Just chatting yesterday about quick wins in code reviews and the subject of de-duping code came up. Even recently I was in a project where two of us implemented the same checking logic at different tiers of the application (replace that with layers if you're into onion architectures). Something that is able to detect clone code would be incredibly useful...... well, it turns out there is a codeplex project: 'Clone Detective' that does just that (thanks to Rupert for putting me onto this). Internally it tokenizes your code, and matches the patterns - allowing you to quickly find repeating sections that are possibly candidates for refactoring even if the local names are different. The tool is available here, and I'd recommend watching the 10 minute video.

    I think it does a great job of finding dupe code - it won't pick out small numbers of lines, for example common foreach loops, so is reasonably noise free and it's not looking at the functionality of the code. This does mean if your code differs by one line you may not match the rest of that block - (which makes perfect sense if that one line is consequential). For example - in the following, the block of recognised code stops at 'purple monkey dishwasher' and the remaining 'matching code' is not matched. This isn't by any means a criticism - I still think this is still a very cool tool.

    A documented dependancy on conQAT means you will need to install a Java Virtual machine and configure the Java Home Directory - currently my install is looking at 'C:\Program Files\Java\jdk1.6.0_07'. It also appears to reset your DevEnv settings - so definately worth exporting and re-importing them after. It also has a great add-in which looks exactly like Solution explorer, but shows the number of dupes in each file. As they might say in some camps: 'Great Job' and 'Im super excited to be able to use this' ;)

    public class CrazyAlgorithm
    {
      public int someOtherAlgorithm(int number)
      {
      
       for (int j = 0; j < 10; j++)
       {
        int i = j * 10;
        number = number + i;
        number = 0;
        Console.WriteLine(number);
       
        using (MemoryStream ms = new MemoryStream())
        {
         byte[] y = BitConverter.GetBytes(number);
         foreach (byte c in y)
         {
          ms.WriteByte(c);
          ms.Position++;
          }
        
         number = y.Rank;
         number++;
        
         number = number + 1;
         }
        }
      
      
       return number;
       }
      }
    public class SomeClass
    {
     
      static int someOtherAlgorithm(int start)
      {
      
       int result = 0;
      
       for (int i = 0; i < 10; i++)
       {
        int j = i * 10;
        result = result + j;
        result = 0;
        Console.WriteLine(result);
        using (MemoryStream ms = new MemoryStream())
        {
         byte[] x = BitConverter.GetBytes(result);
         foreach (byte b in x)
         {
          ms.WriteByte(b);
          ms.Position++;
          }
        
         Console.WriteLine("Purple Monkey Dishwasher");
        
         result = x.Rank;
         result++;
         result = result + 1;
         }
        }
      
       return result;
       }
      }
  • PhotoSynth of Lulworth Cove

    PhotoSynth is absolutley worth checking out - my first synth of Lulworth Cove went incredibly well. Subsequent synths haven't correlated so well. You can check it out here

  • Data Mining Procedure Calls using RegEx and Cloud Data Mining

     

     I recently had an issue where I had a general search procedure which took a comma delimited list of search terms, and I wanted to data mine the combination of the parameter values called in production, to establish things such as most popular searches and poorly performing search options. Itzik BenGan has already written about grouping proc and query calls, but I needed to group the param names and values. The following regEx string allowed me to extract the parameter names and values as an xml fragment from a profiler trace. This can then be cast to xml in Sql 2005 and shredded into a table using XPath that, if you want, you could mine for free using the table analysis feature in the cloud mining project: http://www.sqlserverdatamining.com/cloud/

     

    @(?'Param'[a-z0-9A-Z_]+) = (?:(?:'(?'Value'[^']*?)')|(?'Value'[^']+?))(?:,|$)

     

    Many thanks to Baron Von Garfoot (Rob Garfoot -www.garfoot.com/blog) and Commander B Benbrook (aka Rubert Benbrook - http://phazed.com), who, with impish glee, led me through getting to grips with RegEx using http://www.radsoftware.com.au/regexdesigner/

     

    If you need a snippet to start using it, this will get you out of the gate until I can write something a little sharper that doesn't rely on string concatenation to build an xml fragment.

     

     private static string spParams(string inputString, string ElementName)

        {

     

            string patternMatch = "@(?'Param'[a-z0-9A-Z_]+) = (?:(?:'(?'Value'[^']*?)')|(?'Value'[^']+?))(?:,|$)";

     

            Match m = Regex.Match(inputString, patternMatch);

     

     

            StringBuilder sb = new StringBuilder(100);

            sb.Append("<");

            sb.Append(ElementName);

     

            while (m.Groups.Count != 1)

            {

                string paramName = m.Groups[1].Value;

                string paramValue = m.Groups[2].Value;

     

                paramValue = paramValue.Replace("&", @"&amp;");

                paramValue = paramValue.Replace("%", @"&#37;");

                paramValue = paramValue.Replace("<", @"&lt;");

                paramValue = paramValue.Replace(">", @"&gt;");

     

                string paramString = string.Format(" {0}=\"{1}\" ", paramName, paramValue);

     

                sb.Append(paramString);

                m = m.NextMatch();

            }

     

            sb.Append("/>");

     

            return sb.ToString();

     

        }

  • Shrinking the transaction log beneath its original size in SQL 2000 or 2005

    OK, it's been so long since my last blog that I'm surprised my last blog is still here! I am, however, glad it still is, and whilst this might not be the most revolutionary entry, I hope you find it useful.

    So the scenerio is this: I have a database that has mulitple file groups and I would like to move to another machine with less disk space, or the log has grown too big and needs shrinking below its original size. In SQL 2000, and as far as I could tell, in SQL 2005, its not possible to shrink the log below the size that it was created at. The significance of the multiple file groups is that I can't use sp_attach_single_file_db which could create a new logfile.

    The following works by creating a database 'for attach', which creates a database from existing data files, rebuilding the log if it does not exist. Notice that for SQL 2000|5 I don't actually specify anything for the new log, and nor must SQL be able to find the existing log, otherwise it will just attach the existing on. SQL 2005 improves on the 2000 script by explicitly adding the switch attach_rebuild_log. Watch out though, for both 2000 and 2005 , the new log file will appear in same directory as the datafile so be prepared to move it later.

    So, first create a dummy database:

    create database dbDummy on primary (
    name = 'Primary',
    filename = 'd:\dump\primay.mdf',
    size = 2
    )
    , filegroup FG_User (
    name = 'FG_User_1',
    filename = 'd:\dump\fg_user_1.ndf',
    size = 1
    )
    log on (
    name = 'dummy_log',
    filename = 'd:\dump\dummy_log.ldf',
    size = 5
    )

    This will work for 2000 or 2005. ShrinkFile will not take the log to anything less than 5Mb. Also note that for 2005, the primary data file must at least the size of the model data file or you will receive a warning. Next, we're going to take advantage of the create for attach, so dettach the database. This will work in sql 2000 or 2005:

    sp_detach_db 'dbDummy'

    Now rename the log file so SQL cannot find it (or delete - the choice is yours). If you don't, SQL will use the old log. For SQL 2000, the attach command is:

    create database dbDummy on primary (
    name = 'Primary',
    filename = 'd:\dump\primay.mdf'
    )
    , filegroup FG_User (
    name = 'FG_User_1',
    filename = 'd:\dump\fg_user_1.ndf'
    )
    for attach

    For 2005, the command will be exactly the same, with the exception that instead of for attach, specify for attach_rebuild_log.

    You are now free to expand, move or change the log file as you require.

    ok, dettaching the database is an offline operation, but you do get to resize the log. There is also the option of 'pausing' the sql service to allow connections to drop off one by one, or 'alter database <mydb> set offline with rollback after n'

    -- This Blog is provided 'as-is'

  • Finally! The Follow up on calling procs from views

    Wow - time flies, I really can't beleive its been 3 weeks since I last looked at this blog. To follow up on some of the feedback I got, here is a summarey of the post I was discussing. Its a re-hash of the actual posting from OJ, but it should give you some idea.

    My problem was that any stored proc that uses temp tables wouldn't return a column list when queried from a linked server, which in turn might be used as part of a view. In the following example we have to turn that behaviour of by calling set fmtonly on first. Also, the sp can return as many resultsets it wants. However, only the first will be accepted and redirected by the view. The example shows both of these facts in 'action'.
     
    e.g.
     
    use tempdb
    go
    create proc usp
    as
    set nocount on
    create table #tmp1(OrderID int, CustomerID sysname)
    create table #tmp2(EmployeeID int, Freight money)
     
    insert #tmp1
    select top 1 OrderID,CustomerID
    from Northwind..Orders
     
    insert #tmp2
    select top 1 EmployeeID,Freight
    from Northwind..Orders
     
    select * from #tmp1
    select * from #tmp2
    go
     
    use Northwind
    go
    create view _v
    as
    select *
    from openquery(myserver,'set fmtonly off; exec tempdb..usp')x
    go
    select * from _v
    go
     
    drop view _v
    go
    exec tempdb..sp_executesql N'drop proc usp'
    go
     

    Openquery() opens a new connection for distributed query based on the current_user authentication/profile. By default, every login's default database is master (unless you over-ride it). Thus, the distributed connection will work under master database context. If you want to invoke an user-object (i.e. view/sp/udf/etc) from master
    database, you will have to qualify the database. Note that system objects (stored procedures, functions, etc.) can be called from any database, hence you wouldn't have to qualify them.

    Thanks to all

    Ryan


     

  • opening blog, and comment regarding executing procedures from views

    Hi, this is my opening blog. I intend to use this space to discuss my SQL 2000 exploits, and to build up some blogging experience.

    As an opener, I'd like to describe a scenerio I've seen in news group posts - 'execution of a stored procedure as a view'. The normal work around for this is to use the openrowset provider. However, this only works if the stored procedure in question does not use temporary tables to build its result set. instead you will have to consider encoding the stored procedure as a UDF (this may also have its problems if the proc itself relies on the exec statement)

    I now have an update to this - thanks to OJ on the sql newsgroup for following this one up - its late, so I'll publish the full transcript tomorrow, but in short, if the stored proc does build its result set using a temporary table, then the query text in ht eopenrowset, or openquery provider will look similar to this 'set fmt_only off;exec my_proc'. It turns out that the first 'thing' the provider does when connecting back into SQL is to get a column list using fmtonly, which don't exist until the proc is executed, hence setting this request off. Full example to follow tomorrow.


© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker