thoughts on programming and computer related stuff RSS 2.0
# Thursday, October 23, 2008

Checking if a email addresses is valid in SQL can be very convinient from time to time. Here are two ways to do it in SQL, and a bit about them.

 

Here is a full SQL way to do this:

 

Create function VALIDEMAIL(@s varchar(255)) 
--Returns true if the string is a valid email address.
returns bit
as
BEGIN
DECLARE @u VARCHAR(60), @v VARCHAR(60), @x VARCHAR(60), @i int, @j int, @result bit
SET @result=1
set @s = rtrim(ltrim(@s))
SET @i=len(@s)-CHARINDEX('@',reverse(@s))+1
if @i <= 1 or len(@s) < 5
begin
  set @result = 0
  goto done
end
SET @u=LEFT(@s,@i-1)
SET @j=len(@s)-CHARINDEX('.',reverse(@s))+1
SET @v=RIGHT(@s,LEN(@s)-@j)
if @j < 3 or @j < @i
begin
  set @result = 0
  goto done
end
SET @x=substring(@s,@i+1,@j-@i-1)
IF LEN(@x)<2
 BEGIN
 SET @result=0
 GOTo done
 END
IF (LEN(@x)=3) AND (@x NOT LIKE '[a-zA-Z][a-zA-Z][a-zA-Z]'Collate  Latin1_General_BIN)
 BEGIN
 SET @result=0
 GOTo done
 END
IF (LEN(@x)=2) AND (@x NOT LIKE '[a-zA-Z][a-zA-Z]' Collate  Latin1_General_BIN)
 BEGIN
 SET @result=0
 GOTo done
 END
SET @i=1
WHILE (@i<LEN(@u))
 BEGIN
 IF SUBSTRING(@u,@i,1) NOT LIKE '[a-zA-Z0-9_\-.+=/!#$&''*%?^`{|}"@\\ ]' escape '\' Collate  Latin1_General_BIN
  BEGIN
  SET @result=0
  GOTo done
  END
 SET @i=@i+1
 END
SET @i=1
WHILE (@i<LEN(@v))
 BEGIN
 IF SUBSTRING(@v,@i,1) NOT LIKE '[a-zA-Z]' Collate Latin1_General_BIN
  BEGIN
  SET @result=0
  GOTo done
  END
 SET @i=@i+1
 END
SET @i=1
WHILE (@i<LEN(@x))
 BEGIN
 IF SUBSTRING(@x,@i,1) NOT LIKE N'[a-zA-Z\-.0-9]' escape '\' Collate  Latin1_General_BIN
  BEGIN
  SET @result=0
     goto done
  END
 SET @i=@i+1
 END
done:
return @result
END
GO

Here is another way, where you insert .NET CLR code in the database. Here I use the .NET RegEx.Ismatch, so I can use it for tons of other stuff as well with the right input.


using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
using System.Text.RegularExpressions;

namespace SQLSignature
{
    public class SqlFunctions
    {

        [SqlFunction(IsDeterministic = true, DataAccess = DataAccessKind.None)]
        public static SqlBoolean fn_RegexIsMatch(SqlString input, SqlString pattern)
        {
            return (SqlBoolean)Regex.IsMatch(input.Value, pattern.Value);
        }

    }
}
In SQL:
CREATE ASSEMBLY SQLSignature
FROM 'C:\CLR Assemblies\Performance\SQLFunctions\bin\SQLFunctions.dll';
GO
-- Create fn_SQLSigCLR and fn_RegexReplace functions
CREATE FUNCTION dbo.fn_RegexIsMatch(@input AS NVARCHAR(MAX),@pattern AS NVARCHAR(MAX))RETURNS BIT 
WITH RETURNS NULL ON NULL INPUT 
EXTERNAL NAME SQLSignature.SQLFunctions.fn_RegexIsMatch;
GO
This can be run with a command like:

    select *
    from [AW].[person].emailaddress as p
    where dbo.fn_RegexIsMatch(RTRIM(LTRIM(lower(P.emailaddress))),
'^[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$')=1

I did some timings on the two functions and as you can see below there are big differences. The .NET CLR one is almost 8 times faster(cpu time) than the T-SQL one. It's also a whole lot easier to read, and can be used for all other RegEx's needed. You do however need to get out of management studio to make it, and 1.5 seconds is for processing almost 20000 email addresses still should be fast enough for most uses.

SET STATISTICS TIME ON

    select *
    from [AW].[person].emailaddress as p
    where dbo.VALIDEMAIL(P.emailaddress)=1

    select *
    from [AW].[person].emailaddress as p
    where dbo.fn_RegexIsMatch(RTRIM(LTRIM(lower(P.emailaddress))),
'^[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$')=1 (19929 row(s) affected) SQL Server Execution Times: CPU time = 1466 ms, elapsed time = 1911 ms. (19972 row(s) affected) SQL Server Execution Times: CPU time = 203 ms, elapsed time = 380 ms.
It's pretty cool to see that .NET performs good within SQL as well. I am primarily a .NET developer but do have to use SQL quite a bit as well, but the fact that .NET outperforms SQL both in readability and speed inside SQL on some actions make my job a lot easier.


Thursday, October 23, 2008 8:48:20 AM (GMT Standard Time, UTC+00:00)  #    Comments [1] - Trackback
.NET | T-SQL
# Wednesday, September 03, 2008

All most every ASP.NET website I have seen, uses Databinder.Eval(Container.DataItem, "colum1") in repeaters to get the data passed in and show it on screen. The problem with Databinder.Eval is that it uses reflection to evaluate the item. This is time consuming and unnecessary, so instead, one should use casting to obtain the same effect. Try not to do it this way:

<asp:repeater id="rptAccounts" runat="server">
    <itemtemplate>
        <%# Databinder.Eval(Container.DataItem, "colum1") %> <br />
    </itemtemplate>
</asp:repeater>

But use this one instead:

<asp:repeater id="rptAccounts" runat="server">
    <itemtemplate>
        <%# ((BusinessObjects.Object)Container.DataItem).Column1 %> <br />
    </itemtemplate>
</asp:repeater>

This will also give you a compiler warning if the members of a class should change, and
not just runtime fail such as the first example. If you are not using business
objects, but a DataTable, you can  cast
to datarow and get the column right out of there like this:


<asp:repeater id="rptAccounts" runat="server">     <itemtemplate>         <%# ((DataRow)Container.DataItem)["Column1"] %> <br />     </itemtemplate> </asp:repeater>

This both increases speed and makes the application more robust to runtime errors. A win-win situation:)



Wednesday, September 03, 2008 6:42:36 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
.NET | ASP.NET
# Monday, September 01, 2008

Third party applications are great, and its very often smart to use open source or buy modules you need before making your own. However a lot of third party applications do create some problems. One is that prices and functionality can change and new, better and cheaper products come to surface.

 

Therefore, you do not want to be to dependent on these applications, so if you find another tool that does the same thing even better, you should be able to switch it out easy. A good way to do this is to create a interface and a factory pattern, and refer to the interface in your code and let the factory class decide what tool to use.  You can also use this pattern to ease mocking of objects. And let the factory return a mock object if you are unit testing.


Example in C#:

using System;

namespace Logger
{
    // An interface is created
    interface iLog
    {
        bool Log(string s);
    }
    //An implementation using enterprise libraries logging
    class EntLog : iLog 
    {
        public bool Log(string s)
        {
            //Implement logic to save to log
            return false;
        }
    }

    //An implementation using log4net to save logs.
    class log4net : iLog
    {
        public bool Log(string s)
        {
            //Implement logic to save to log
            return false;
        }
    }

    // A factory class
    class LogFactory
    {
        // Creates an object, of the right type.
        public static iLog CreateLog(){
            return new log4net();
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            // Get the log object to use.
            iLog logger = LogFactory.CreateLog();
            //Print the type of logger used
            Console.Out.WriteLine(logger.GetType());
            // Log a message and write the result
            Console.Out.WriteLine(logger.Log("Something is happening"));
            Console.ReadKey();
        }
    }
}

To change this to use entLog instead of log4net, all you have to do is change the object created in the logfactory.  To add a new logger, all you have to do is create a new class to implement Ilog and change the creator to return the new logger. The creator could also have a constructor that takes an input, so that you can decide in the class using the log what kind of log you want to use.

 

Monday, September 01, 2008 11:33:16 AM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
.NET | Patterns
# Saturday, August 23, 2008

In .NET there is a String.IsNullOrEmpty, but there is no similar thing on an Array. There should be, and there is a solution is in the new extension methods. This one works for all collections.

using System.Collections;

namespace MyExtensions
{
  public static class CollectionExtensions
  {
    public static bool IsNullOrEmpty(this ICollection col)
    {
      return (col == null || col.Count == 0);
    }
  }
}

Saturday, August 23, 2008 8:58:13 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
.NET
# Friday, August 22, 2008

Last week I had a problem where I needed a hierarchical chain of results. I had to get results of all organisations above my organsiation in a hierarcy. I knew how I would do this by recursion in C#, but had no idea how to get it done in SQL. But asking a bit around, and searching the web I got a really nice solution using the to me new WITH-command. And it seems quite fast aswell. Here is a SQL script with some testdata:

Create table #Relations 
(
  ID int PRIMARY KEY,
  ChildId int,
  name varchar(50)
)
insert into #Relations values (5, 4, 'Me')
insert into #Relations values (4, 3, 'Father')
insert into #Relations values (3, 2, 'Grandpa')
insert into #Relations values (2, 1, 'Great Grandpa')
insert Into #Relations  values (1, null, 'Great Old Grandpa')

declare @startid int
set @startid = 5

;WITH Names AS
(
--Gets the starting line
SELECT * FROM #Relations where id = @startid
UNION ALL
SELECT r.* FROM #Relations r
INNER JOIN names n ON n.ChildId=r.id
)
select * from names

Here are the results. As you can see, it works;)

ID ChildId name
---------- ----------- --------------------------------------------------
5 4 Me
4 3 Father
3 2 Grandpa
2 1 Great Grandpa
1 NULL Great Old Grandpa
(5 row(s) affected)

Friday, August 22, 2008 11:38:13 AM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
T-SQL
# Friday, August 15, 2008
Ever needed to see who has files checked out? Here's a way to do it command line style.
tf status /user:* $/serverpath /r /s:http://server:8080

An example that works in my environment:
tf status /user:* $/sportsadmin/main /r /s:http://n3srvno04:8080

You do need to open Visual Studio Command Prompt to have the command tf.exe in path.

Friday, August 15, 2008 2:17:21 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
Team Foundation Server | Visual Studio
# Tuesday, August 12, 2008
The project I'm currently working on has a large codebase and it takes a while with precompilation and everything if I press F5 to start the project every time. I therefore started to attach and detach the debugger manually every time I needed to debug. This saves me tons of time since I don't have to log in and out of the application and find the place I need to debug every time something has to be debugged. A former coworker(http://www.labraaten.com/) also made this nice little macro to attach to w3wp.exe(aspnet_wp.exe in XP) automatically. Saves me even more time.

Imports System
Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics
Public Module Module1
    Public Sub Attach_ASPNET_WP()
        Attach("w3wp.exe")
        Attach("iexplore.exe")
    End Sub

    Public Sub Attach(ByVal processName As String)
        For Each process As EnvDTE.Process In DTE.Debugger.LocalProcesses
            If process.Name.IndexOf(processName) <> -1 Then
                process.Attach()
            End If
        Next
    End Sub
End Module

I have added this macro as a shortcut that triggers every time I hit ALT-I. This can be set by pressing tools, Options, keyboard, locating your macro and add the shortcut.

Tuesday, August 12, 2008 1:18:07 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
.NET | Visual Studio
# Sunday, August 10, 2008
I am one of those who still from time to time get to use MS SourceSafe. This week I had a problem with some production code. To make a long story short, I had to rollback the code to see if our code was the source of the problem. However no labels or anything was made.

That's when I found out that using the sourcesafe command line tool, one could get the source as it was on a specific date. Here's how it's done:

First you need to set the an environmental variable named SSDIR to the location of the sourcesafe database. In Windows Vista, this is done by selecting properties on my computer, selecting Advanced System Settings, and the selecting Environmental Variables on the Advanced tab.

Second you have to open a command prompt and locate the SS.exe file which should be located in the sourcesafe-folder. I then created a new folder for where I wanted my new files and then I wrote something like: "c:\program files\source safe\win32\ss get $/Project/location to . -vd30/04/2007 -R"

I believe the date format changes depending on the country selected in your system settings.

This trick did magic and I was able to find out that our code was not the source of the problems experienced in the production environment.

Sunday, August 10, 2008 4:22:26 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
.NET | Source Safe
Navigation
Archive
<October 2008>
SunMonTueWedThuFriSat
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010
Gaute Magnussen
Sign In
Statistics
Total Posts: 17
This Year: 0
This Month: 0
This Week: 0
Comments: 1
Themes
Pick a theme:
All Content © 2010, Gaute Magnussen
DasBlog theme 'Business' created by Christoph De Baene (delarou)