Wednesday, March 4, 2009

Row Level security using TVF SQL Server 2005

In applications Row level security is very important. So what we need to do that user will see only rows of tables which he has permission.
Here are 3 Easy steps

1) Add DataAccess Column to each and every table in your Database.

2) Create TVF for each Table
e.g. Departments
So create TVF :

Create function [dbo].[fnDepartments](@DataAccess nvarchar(50))
returns table
as
return(
Select * from Departments where @DataAccess in ( Select * from dbo.fnsplit(DataAccess,',')) or @DataAccess = 'Any'
)

3) Create dbo.split function in database
(Split Function is not created by me I found it while googling, I mean only split function :) )
Create FUNCTION [dbo].[fnSplit](
@sInputList VARCHAR(8000) -- List of delimited items
, @sDelimiter VARCHAR(8000) = ',' -- delimiter that separates items
) RETURNS @List TABLE (item VARCHAR(8000))
BEGIN
DECLARE @sItem VARCHAR(8000)
WHILE CHARINDEX(@sDelimiter,@sInputList,0) <> 0
BEGIN
SELECT
@sItem=RTRIM(LTRIM(SUBSTRING(@sInputList,1,CHARINDEX(@sDelimiter,@sInputList,0)-1))),
@sInputList=RTRIM(LTRIM(SUBSTRING(@sInputList,CHARINDEX(@sDelimiter,@sInputList,0)+LEN(@sDelimiter),LEN(@sInputList))))
IF LEN(@sItem) > 0
INSERT INTO @List SELECT @sItem
END
IF LEN(@sInputList) > 0
INSERT INTO @List SELECT @sInputList -- Put the last item in
RETURN
END

And now you are ready to use this in your application.
So How you will use this?
When ever you insert a record insert UserID of users separated by comma into DataAccess Column.
eg. 232,111,234
Now when you will access this data using select dont use tables instead use TVF
e.g. Select * from fnDepartments('234')
This way user 234 will access only rows which he has permission. Rest according to your user heirarchy you can add UserIDs to DataAccess.
If you wish to access all rows just pass 'Any' instead of UserID. e.g. fnDepartments('Any')
As TVF returns Table you can use it like table and perform all operations using select like where condition, having, group by,order by etc.
Only thing is you can not perform Insert, Update on TVF. So you will have to use tables directly to insert records( with DataAccess )
For using Stored procedure you can have common parameter for all procedures like @DataAccessID where you will pass UserIDs separated with comma for users you want to allow access Records.

This is very simple and effective way. Though many people have argument over this that TVF performs slower. But for this reason I inserted 6 lac records to table and checked execution time of procedure created on Tables, Views and TVF there was not much of difference or I can say there is no difference. This might be enhanced in SQL Server 2005 so I dont know about SQL server 2000.
Hope this article helps some one to make applications easier and secured.
Please comment on this article and let me know if it helps you. Or you have any suggestions over this.

Regards,
Upendra Kolte

http://www.ingenioustech.co.in/


Blog Flux Directory

Monday, March 2, 2009

C# Translate Numeric Values in Words upto 99lacs including decimals

Use NUM_IN_WORDS function where u want to Translate numeric values in words. Pass numeric value in function it returns string as in words. eg. NUMBER: 2134 ANSWER: Two Thousand One Hundred Thirty Four. Its limit is upto 99Lacs with decimals

public string Num_In_Words(string str_Num) {
// Function to convert numerical value in words
string One_Ch="";
string Chk_Pos="";
string temp="";
string Paise="";
string Rupees="";
string Temp1;
string Num_In_Words="";
int ZeroErr=0;
int DOT=0;
int i;
i = 1;
// temp = str_Num
Paise = "";
Temp1 = "";
for (int L = 1; (L <= str_Num.Length); L++) { Temp1 = str_Num.Substring((L - 1), 1); if ((Temp1 == ".")) { DOT = 1; } else if ((DOT != 1)) { Rupees = (Rupees + Temp1); } else { Paise = (Paise + Temp1); } } // For Rupees temp = Rupees; while ((temp.Length != 0)) { One_Ch = Rupees.Substring((i - 1), 1); // Detecting tens of the number if ((One_Ch != "0")) { switch (temp.Length) { case 7: Num_In_Words = (Num_In_Words + Conv_Word(One_Ch, 7, temp.Substring(1, 1))); Chk_Pos = One_Ch; break; case 6: if ((Chk_Pos == "1")) { Num_In_Words = (Num_In_Words + " Lakhs "); ZeroErr = 1; } else { Num_In_Words = (Num_In_Words + (Conv_Word(One_Ch, 6, "") + " Lakhs ")); ZeroErr = 1; } break; case 5: Num_In_Words = (Num_In_Words + (Conv_Word(One_Ch, 5, temp.Substring(1, 1)) + " ")); Chk_Pos = One_Ch; break; case 4: if ((Chk_Pos == "1")) { Num_In_Words = (Num_In_Words + " Thousand "); } else { Num_In_Words = (Num_In_Words + (Conv_Word(One_Ch, 4, "") + " Thousand ")); } break; case 3: Num_In_Words = (Num_In_Words + (Conv_Word(One_Ch, 3, "") + " Hundred ")); Chk_Pos = ""; break; case 2: Num_In_Words = (Num_In_Words + (Conv_Word(One_Ch, 2, temp.Substring(1, 1)) + " ")); Chk_Pos = One_Ch; break; case 1: if ((Chk_Pos != "1")) { Num_In_Words = (Num_In_Words + Conv_Word(One_Ch, 1, "")); } break; switch (temp.Length) { case 6: if ((temp.Substring(0, 1) == "0")) { Num_In_Words = (Num_In_Words + " Lakhs "); } break; case 4: if ((temp.Substring(0, 1) == "0")) { Num_In_Words = (Num_In_Words + " Thousand "); } break; } } } i = (i + 1); if (Rupees.Length > 0)
{
temp = Rupees.Substring((i - 1));//, temp.Length);
}
}
// Final Output for rupees
// Num_In_Words = (Num_In_Words );
if ((Paise != "")) {
for (int L = 1; (L <= 2); L++) { One_Ch = Paise.Substring((L - 1), 1); switch (L) { case 1: Num_In_Words = (Num_In_Words + (" and " + Conv_Word(One_Ch, 2, Paise.Substring(1, 1)))); Chk_Pos = One_Ch; break; case 2: if (((Chk_Pos != "1") && (Chk_Pos != "0"))) { Num_In_Words = (Num_In_Words + (" " + Conv_Word(One_Ch, 1,""))); } // Final Output for paise Num_In_Words = (Num_In_Words + " decimals"); break; } } } //Num_In_Words = Num_In_Words + " Only."; return Num_In_Words; } public string Conv_Word(string One_Ch, int Pos, string NextChar) { string Conv_Word = ""; // Converting numeric in words // Warning!!! Optional parameters not supported if (((Pos != 2) && ((Pos != 5) && (Pos != 7)))) { switch (One_Ch) { case "1": Conv_Word = "One"; break; case "2": Conv_Word = "Two"; break; case "3": Conv_Word = "Three"; break; case "4": Conv_Word = "Four"; break; case "5": Conv_Word = "Five"; break; case "6": Conv_Word = "Six"; break; case "7": Conv_Word = "Seven"; break; case "8": Conv_Word = "Eight"; break; case "9": Conv_Word = "Nine"; break; } } else { switch (One_Ch) { case "1": switch (NextChar) { case "1": Conv_Word = "Eleven"; break; case "2": Conv_Word = "Twelve"; break; case "3": Conv_Word = "Thirteen"; break; case "4": Conv_Word = "Fourteen"; break; case "5": Conv_Word = "Fifteen"; break; case "6": Conv_Word = "Sixteen"; break; case "7": Conv_Word = "Seventeen"; break; case "8": Conv_Word = "Eighteen"; break; case "9": Conv_Word = "Ninteen"; break; case "0": Conv_Word = "Ten"; break; } break; case "2": Conv_Word = "Twenty"; break; case "3": Conv_Word = "Thirty"; break; case "4": Conv_Word = "Fourty"; break; case "5": Conv_Word = "Fifty"; break; case "6": Conv_Word = "Sixty"; break; case "7": Conv_Word = "Seventy"; break; case "8": Conv_Word = "Eighty"; break; case "9": Conv_Word = "Ninty"; break; case "0": Conv_Word = "Zero"; break; } } return Conv_Word; }


enjoy !!
~ Upendra
Blog Flux Directory

Sunday, March 1, 2009

Visual Studio Macros

Hi
Are you aware with power of visual studio macros. It can help you lot in making your coding very much easier.

Here is small snippet which will help you commenting your page when you start creating page, when you are modifying the code or creating region with comments.

Add following code to visual studio macros.

/// For Starting new Page. Once you have added new page. Go to code window and then click on this macro
Sub PageCreateDetails()
DTE.ActiveDocument.Selection.StartofDocument()
DTE.ActiveDocument.Selection.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstText)
DTE.ActiveDocument.Selection.NewLine()
DTE.ActiveDocument.Selection.LineUp()
DTE.ActiveDocument.Selection.Text = "//*****************************Page Deatils*****************************"
DTE.ActiveDocument.Selection.NewLine()
DTE.ActiveDocument.Selection.Text = "//File Name: " + DTE.ActiveDocument.Name
DTE.ActiveDocument.Selection.NewLine()
DTE.ActiveDocument.Selection.Text = "//Created Date: " + Date.Now
DTE.ActiveDocument.Selection.NewLine()
DTE.ActiveDocument.Selection.Text = "//Created By: " + InputBox("Enter Your Name")
DTE.ActiveDocument.Selection.NewLine()
DTE.ActiveDocument.Selection.Text = "//Page Description: " + InputBox("Page Description")
DTE.ActiveDocument.Selection.NewLine()
DTE.ActiveDocument.Selection.Text = "//*******************************End Page Details***************************"
DTE.ActiveDocument.Selection.EndofDocument()
DTE.ActiveDocument.Selection.EndOfLine()
DTE.ActiveDocument.Selection.LineUp(False, 1)
DTE.ActiveDocument.Selection.NewLine()
DTE.ActiveDocument.Selection.Text = "//Macro Create Methods ****"
DTE.ActiveDocument.Selection.NewLine()
DTE.ActiveDocument.Selection.EndofDocument()
DTE.ActiveDocument.Selection.EndOfLine()
DTE.ActiveDocument.Selection.LineUp(False, 1)
DTE.ActiveDocument.Selection.NewLine()
DTE.ActiveDocument.Selection.Text = "//Macro Generated Events ****"
DTE.ActiveDocument.Selection.NewLine()
DTE.ActiveDocument.Selection.EndofDocument()
DTE.ActiveDocument.Selection.EndofLine()
DTE.ActiveDocument.Selection.NewLine()
DTE.ActiveDocument.Selection.LineDown(False, 2)
DTE.ActiveDocument.Selection.Text = "//***************************Page Modified History*******************************"

End Sub

/// For maintaining details when you modify code.
Sub PageModifyDetails()

DTE.ActiveDocument.Selection.EndofDocument()
DTE.ActiveDocument.Selection.EndofLine()
DTE.ActiveDocument.Selection.NewLine()
DTE.ActiveDocument.Selection.LineUp()
DTE.ActiveDocument.Selection.Text = "//Modified Date:" + Date.Now
DTE.ActiveDocument.Selection.NewLine()
DTE.ActiveDocument.Selection.Text = "//Modified By:" + InputBox("Enter Your Name")
DTE.ActiveDocument.Selection.NewLine()
DTE.ActiveDocument.Selection.Text = "//Details:" + InputBox("Enter Description of changes you have done.")
DTE.ActiveDocument.Selection.NewLine()
DTE.ActiveDocument.Selection.Text = "//--------------------------------------------------------"


End Sub

/// For Creating Region. Select your code and click on this macro

Sub CreateRegion()
'Select Area to put in Region and enter region name
Dim sel As EnvDTE.TextSelection
sel = DTE.ActiveWindow.Selection
Dim RegionName As String
Dim sComment As String
RegionName = InputBox("Region Name", "ingenious Macros")
If (MsgBox("Do you want to enter some comments to region", MsgBoxStyle.YesNo)) = MsgBoxResult.Yes Then
sComment = InputBox("Comments Please:")
sel.Text = "#region " + RegionName + vbCrLf + "//" + sComment + vbCrLf + sel.Text + vbCrLf + "#endregion " + RegionName
Else
sel.Text = "#region " + RegionName + vbCrLf + sel.Text + vbCrLf + "#endregion " + RegionName
End If
End Sub

Regards,
Upendra Kolte