Feeds:
Posts
Comments

Posts Tagged ‘SQL Server 2012’

File table is one of the best features shipped with SQL Server 2012, it is a special type of table which allows us to store files and folders in windows and we can easily access it through windows application & SQL Server without any customization. I have written multiple articles on file table. However, still doing research on this special table. Today, I came across an issue with filetable at the client side once they were doing some activity on it. The issue is when they tried to explore FileTable Directory in a FileTable, the option was disabled as shown below. However I can perform any activity on file table except to explore it.

Explore FileTable Directory.1.1

Now, I cannot explore this file table using explore the filetable directory option. It means that I cannot view the filetable’s files and folder using windows directory. So what is the problem and possible solution ?

Resolution:
I asked the client what activity they did with filetable but they had no clue. So, I started doing my research and finally resolved it by MSDN help. In fact the Filetable’s NON_TRANSACTED_ACCESS has been switched OFF by mistake as shown below.

Explore FileTable Directory.1.2

Wow, I found the problem that has disabled the explore FileTable directory as mentioned above. Now what is the solution ?
Given below is the script that can enable the NON_TRANSACTED_ACCESS that can result in enabling the explore FileTable directory.

--This script is compatible with SQL Server 212 and above.
 ALTER DATABASE SameplDB
    SET FILESTREAM ( NON_TRANSACTED_ACCESS = FULL );
GO

Once you execute the above script, try again to check if the explore FileTable Directory in the FileTable has been enabled or not. This time you will succeed as shown below.

Explore FileTable Directory.1.3

Conclusion:
Whenever, you come across such issue, you must check the NON_TRANSACTED_ACCESS of the particular database in order to fix this issue.

Read Full Post »

In general, upgrading of SQL Server in any latest version is quite complex. However, in my opinion it is NOT at all a rocket science, it is completely based on your planning and understanding about the complexity of your database(s) and its related applications. If you plan and understand it properly, there is no way you cannot make it smooth and up to the mark. In addition, before upgrading it directly on your production database server, you must test it on your test database server like any other application’s deployment and upgrading. But how will I know that is there any problem in my upgrading or NOT ? The solution is one of the best FREE tools that SQL Server provides namely SQL Server Upgrade Advisor. This tool can be downloaded from Microsoft site or it comes with SQL Server 2012 media (Setup files) . The installation of this tool is self explanatory.

SQL Upgrade Advisor

Please note that the database you are planning to upgrade to SQL Server 2012 must have a compatibility of 90 or above. In addition, as much as the gap is between the versions, so is the complexity and problems you can expect. In order to avoid this, it is highly recommended that you should upgrade your SQL Server in a timely manner.  

In this article, I will demonstrate how SQL Server Upgrade Advisor works step by step.

Step 1 : 
Once you install SQL Server 2012 Upgrade Advisor, you will find it in the Start >> Program files as shown below.

upgrade.1.1.1

Step 2 :
Now, it is time to execute the SQL Server Upgrade advisor, it will take you to the first screen, from where you can launch the upgrade Advisor Analysis Wizard. Here you will find the summary about the SQL Server Upgrade Advisor. I strongly recommend that you go through it. Once you review the summary, you need to launch the Upgrade Advsior Analysis Wizard as shown below.

upgrade.1.1

Step 3 :

This is a welcome screen. It will give you the summary of how upgrade Advisor works step by step as shown below. However, you can check mark the Do not show this starting page again in order to avoid this screen recurring, as it is for information ONLY.

upgrade.1.2

Step 4 :

Once you crossed the welcome screen, immediately after that you need to select the components you want to analyse for upgrading. Please make sure that you do NOT  select Notification Services and Data Transformation Services because these two services have been discontinued in the SQL Server 2012. Reporting services you can select if you have installed in that particular server. In my case reporting service was not applicable.

upgrade.1.3

Step 5 :

The next screen will ask you to select the instance and provide the valid credential of that particular instance as shown below.

upgrade.1.4

Step 6 :

The next step is the selection of all or any one databases of the above selected instance that you want to upgrade to SQL Server 2012. Kindly select the appropriate database and press NEXT button.

upgrade.1.5

Step 7 :

Here you need to provide the instance of Analysis services. In addition, you need to provide its credential as well.

upgrade.1.6

Step 8 :

In this step, you need to select the location and the packages of  your integration services. In my case, my SSIS packages are available in the same server so I selected the first option. However, you can select as per your requirement as shown below.

upgrade.1.7

Step 9 :

In this step, SQL upgrade advisor will show you the path of Upgrade advisor report & its log files for your reference.

upgrade.1.8

Step 10 :

Once you press NEXT button, it will start analyzing your selected components on selected databases. It takes 2-30 minutes, depending upon the database size, number of component and performance of your server.

upgrade.1.9

Step 11 :

Once Analysis is done, it will show you a summary report along with the status and a Launch Report button.  Here you need to launch the report, in order to see the results of the SQL Server upgrade analysis for your selected components.

upgrade.1.10

Step 12 :

Once you launch the report, SQL Server Uprade Advisor will show you all the critical issues that you must fix it before or after upgrading. In order to do a smooth migration make sure that you resolve all the given below issues. In my case it is displaying only one issue related to the keyword. In fact I used one word that became a keyword in SQL Server 2012. So I need to replace this keyword.

upgrade.1.12

Step 13 :

Once you select the issue as shown above, it will show where the conflict exactly is. In addition, it will provide all necessary details that you may require at the time of fixing.

upgrade.1.13

 

Let me know about your experience relating to SQL Server upgrade advisor.

Read Full Post »

Whenever we try to take an exclusive access to a database in order to perform any activity like backup restore, it usually fails if any process is still using the database. I received the given below error from my test database while I was restoring the database on it.

kill process.1.1

Opsssss, fortunately, we do have solution by killing the running process to take a lock and perform any activity using a management command namely KILL & a system view sys.sysprocesses. However, what encourages me to write this solution is that sys.sysprocesses will be removed from the future version of SQL Server. So what is the NEW solution ?

Given below is the script, that I developed using sys.dm_exec_sessions.

USE master
GO
DECLARE @SQL_String VARCHAR(MAX)
DECLARE @Database_id INT

--DO NOT forget to change database name in give below statement
SET @Database_id=DB_ID('AdventureWorks2012')
SET @SQL_String=''

SELECT @SQL_String=@SQL_String + 'KILL '
+ COALESCE(CONVERT(VARCHAR(5),[session_id])+ '; ','')
FROM sys.dm_exec_sessions
WHERE database_id =@Database_id

--PRINT @SQL_String
EXEC (@SQL_String)

The above statement kills all the process running on a specific database. But do not forget to CHANGE the database name.
Once the above statement executed successfully, you can perform any activity.

Read Full Post »

Columnstore index is one of the new features shipped with SQL Server 2012. I have written few articles about this type of index and described how it boosts in the performance. Recently, I worked on a huge table having table partitions residing in different file groups. And it seems that it is already optimized using Table partition. However, I tried to create a columnstore Index to further boost its performance and I did succeed.

Let me demonstrate it step by step.

Step 1 :
First of all, you need to create a partition function as shown below. If you already have partition function please SKIP this step.

USE AdventureWorks2012
GO
CREATE PARTITION FUNCTION [PFByDueDate](datetime) AS RANGE RIGHT
FOR VALUES
(
N'2005-05-31T00:00:00', N'2006-05-31T00:00:00' ,
N'2007-05-31T00:00:00', N'2008-05-31T00:00:00' ,
N'2009-05-31T00:00:00'
)
GO

Step 2 :
Secondly, you need to create a partition scheme on the above partition function as shown below. If you already have partition scheme please SKIP this step.

USE AdventureWorks2012
GO
CREATE PARTITION SCHEME [PSDueDateByMonthRange]
AS PARTITION [PFByDueDate]
ALL TO ([PRIMARY])
GO

Step 3 :
Now, it is time to create a table using above created partition scheme to partition the data accordingly as shown below. If you already created a table using partition scheme please SKIP this step.

USE AdventureWorks2012
GO
CREATE TABLE dbo.[PurchaseOrderDetail_Sample]
(
[PurchaseOrderID] [int] NOT NULL,
[PurchaseOrderDetailID] [int] NOT NULL,
[DueDate] [datetime] NOT NULL,
[OrderQty] [smallint] NOT NULL,
[ProductID] [int] NOT NULL,
[UnitPrice] [money] NOT NULL,
[LineTotal] numeric(18,2),
[ReceivedQty] [decimal](8, 2) NOT NULL,
[RejectedQty] [decimal](8, 2) NOT NULL,
[StockedQty] Numeric(18,2),
[ModifiedDate] [datetime] NOT NULL
) ON [PSDueDateByMonthRange]([DueDate]);
GO

Step 4 :
Lets insert some data to test the performance.

--This query may take 2 to 10 minutes depends upon the server.
USE AdventureWorks2012
GO
INSERT INTO dbo.[PurchaseOrderDetail_Sample] WITH(TABLOCK)
SELECT * FROM [Purchasing].[PurchaseOrderDetail]
GO 100

Step 5 :
Once you insert the data, lets build the columnstore index. Remember, once you build the columnstore index you cannot modify the data in the table.

USE AdventureWorks2012
GO
CREATE NONCLUSTERED COLUMNSTORE INDEX
[IX_PurchaseOrderDetail_Sample_ColumnStore]
ON [PurchaseOrderDetail_Sample]
(
UnitPrice,
OrderQty,
ReceivedQty,
ProductID)
GO

Step 6 :
Once you build the columnstore index, lets execute the query and view the result set WITHOUT columnstore index.

--This query will ignore columnstore index
--By using table's option namely IGNORE_NONCLUSTERED_COLUMNSTORE_INDEX
--and will return the result set.
USE AdventureWorks2012
GO
SET STATISTICS TIME ON
SET STATISTICS IO ON
GO
SELECT
ProductID as [Product ID]
, AVG(UnitPrice) as [Average Unit Price]
, SUM(OrderQty) as [Purchase Order Qty]
, AVG(ReceivedQty) as [Received Qty]
FROM [dbo].[PurchaseOrderDetail_Sample]
WHERE [DueDate] Between '2007-01-01' And '2008-12-31'
GROUP BY ProductID
ORDER BY ProductID
OPTION (IGNORE_NONCLUSTERED_COLUMNSTORE_INDEX)
GO
--OUTPUT

SQL Server parse and compile time:
CPU time = 15 ms, elapsed time = 69 ms.

(265 row(s) affected)
Table ‘Worktable’. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘PurchaseOrderDetail_Sample’. Scan count 3, logical reads 4100, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
CPU time = 983 ms, elapsed time = 1158 ms.

Step 7 :
Lets execute the query and view the result set WITH the columnstore index.

USE AdventureWorks2012
GO
SET STATISTICS TIME ON
SET STATISTICS IO ON
GO
SELECT
ProductID as [Product ID]
, AVG(UnitPrice) as [Average Unit Price]
, SUM(OrderQty) as [Purchase Order Qty]
, AVG(ReceivedQty) as [Received Qty]
FROM [dbo].[PurchaseOrderDetail_Sample]
WHERE [DueDate] Between '2007-01-01' And '2008-12-31'
GROUP BY ProductID
ORDER BY ProductID
GO
--OUTPUT

SQL Server parse and compile time:
CPU time = 16 ms, elapsed time = 57 ms.

(271 row(s) affected)
Table ‘Worktable’. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table ‘PurchaseOrderDetail_Sample’. Scan count 1, logical reads 242, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
CPU time = 717 ms, elapsed time = 782 ms.

Conclusion :
As you can observe, there is huge difference between both queries (with and without columnstore index) performance. However, you need to test it in your scenario and implement it accordingly. In addition, kindly read the restrictions & limitation about columnstore index as well.

Read Full Post »

Full-Text Search is one of the best features shipped with SQL Server 2005. It has all the capabilities that we need for the complex searching scenarios. However, Full- Text Search keep getting the new features in each version of SQL Server. In SQL Server 2012, Full-Text search came up with a brilliant feature called Custom proximity search. Given below are the capabilities of the search.

  1. You can define the maximum number of non search terms or maximum distance between first and last search term
  2. You can also define that search must follow the specific order.

Before I embark on the example, I would like to create a sample to demonstrate this excellent feature.
Sample :

USE AdventureWorks2012
GO
--DROP TABLE [dbo].[tbl_Comments]
--GO
CREATE TABLE [dbo].[tbl_Comments]
(
[ID] [int] NOT NULL CONSTRAINT [PK_tbl_comments] PRIMARY KEY CLUSTERED ,
[Comments] [varchar](1000) NULL
)
GO
INSERT INTO [dbo].[tbl_Comments]
VALUES (1,'This is a demonstration of custom proximity term in Full-Text Search at raresql.com')
GO
--OUTPUT

Please note that once you create the sample, you have to create a Full-Text Index for column “Comments” in the above mentioned table. This article will help you to create Full-Text Index.

Example 1 : (Core functionality)
In this example, we will search two words (proximity and raresql) in the comments column in the sample table. The distance between both words is 6. However, we will increase and decrease the distance between words and observe the output.

--First of all, lets put the the distance 6 and observe the output.
USE AdventureWorks2012
GO
SELECT * FROM [tbl_Comments]
WHERE CONTAINS([Comments], 'NEAR((proximity, raresql), 6)')
--OUTPUT

custom proximity.1.1

--lets reduce the the distance from 6 to 5 words and observe the output.
USE AdventureWorks2012
GO
SELECT * FROM [tbl_Comments]
WHERE CONTAINS([Comments], 'NEAR((proximity, raresql), 5)')
--OUTPUT

custom proximity.1.2

As you can see that once you made the distance less than the actual, it is unable to search. Make sure that you provide whether actual distance or more.

Example 2 : (Implement Order)
In this example, we will search again two words (proximity and raresql) in the comments column.
However, we change the order, but it will not affect the result set until unless you will not forcefully implement the order. By default, it does not implement the order in the search.

--First of all, lets put the the distance 6 and reverse the search words.
--However make the sort order to FALSE (By default, it is false, it is optional to write in the code).
USE AdventureWorks2012
GO
SELECT * FROM [tbl_Comments]
WHERE CONTAINS([Comments], 'NEAR((raresql,proximity), 6,FALSE)')
--OUTPUT

custom proximity.1.3

--Lets put the the distance between the word is 6 and reverse the search words.
--However make the order to TRUE.
USE AdventureWorks2012
GO
SELECT * FROM [tbl_Comments]
WHERE CONTAINS([Comments], 'NEAR((raresql,Search), 6,TRUE)')
--OUTPUT

custom proximity.1.4

As you can see that, first of all, I did not implement the ORDER and made it false. In this case it returned the result set because ORDER did not affect the query. However, once I implemented the search order, it did not return the record because the words are in the opposite order in the comments column of the table. Please make a note that some languages follow left to right direction and vice versa. Custom proximity implement the sort search in the same direction.

Example 3 : (Implement Operator)
In custom proximity search, you have limited numbers of operators like AND, OR & AND NOT operator. However, you can use the combination of any of them. Given below are the samples.

--First of all, let try the AND operator.
USE AdventureWorks2012
GO
SELECT * FROM [tbl_Comments]
WHERE CONTAINS([Comments], 'NEAR((raresql,proximity), 6) And Full-Text')
GO
--OUTPUT

custom proximity.1.5

--Lets try OR operator
USE AdventureWorks2012
GO
SELECT * FROM [tbl_Comments]
WHERE CONTAINS([Comments], 'NEAR((raresql,proximity), 5) OR Full-Text')
GO
--OUTPUT

custom proximity.1.7

--Lets implement AND NOT operator.
USE AdventureWorks2012
GO
SELECT * FROM [tbl_Comments]
WHERE CONTAINS([Comments], 'NEAR((raresql,proximity), 6) AND NOT sample')
GO
--OUTPUT

custom proximity.1.6

As you can see, I implemented three different operators and it works accordingly. However you can use any number of combinations according to your business requirements.

Let me know if you have implemented Custom proximity search in the real world.

Read Full Post »

SQL Server upgrade advisor is one of the important tools and it plays a pivotal role when you need to assess the upgrade in your SQL Server. However, I got an error message when installing SQL Server 2012 upgrade advisor. Given below is the screen image of the error message.

SQL Upgrade Advisor Setup.1.1

Let me explain the error and its solution in detail.

Error Message: 
Setup is missing prerequisites:
-Microsoft SQL Server 2012 Transact-SQL ScriptDom, which is not installed by
Upgrade Advisor Setup. To continue, install SQL Server 2012 Transact-SQL
ScriptDom from below hyperlink and then run the Upgrdae Advisor Setup operation
again :

Go to http://go.microsoft.com/fwlink/?linkID=216742

Resolution:
It seems that it is not only the error message but also the solution as well. Let me resolve it step by step.

Step 1 :
First of all, you need to go to the URL as mentioned above in order to fix this bug.

Step 2 :
Once you browse the above link, it will take you to a page where you need to download the instruction to proceed further. However, you can select the Install instruction link shown below to get the list of all SQL Server tools.

SQL Upgrade Advisor Setup.1.2

Step 3 :
Once you browse install instruction, you need to scroll down till you will find Microsoft® SQL Server® 2012 Transact-SQL ScriptDom. It is available for both (x86 & x64) system types as shown below. However make sure the system type of your server before downloading it. Its installation is self explanatory. Once you install it, you can easily install SQL Server 2012 upgrade advisor.

SQL Upgrade Advisor Setup.1.3

Read Full Post »

Filetable is one of the best features shipped with SQL Server 2012. It makes our life easier when you need to manage your files and folders via SQL Server when it actually resides in the file system of windows. However, you can easily access them using windows application and SQL Server as well.

Pre-requisites :

Problem :
Sometimes, you execute a select statement against a filetable using SQL Server Management Studio (SSMS) and it becomes inaccessible and even after spending so much time, the query does not return the result set. However, you can still access it via windows file system. In normal scenario, filetable returns result set in less than few seconds (depending upon the size of filetable). Now what to do ?

Solution :
First of all, I cancelled the query that kept on running for hours. It seemed to me that this filetable had been locked because of some transaction. Just to test this scenario, I executed the same query with no lock table hint and it returned the result set as shown below.

USE SampleDB
GO
SELECT * FROM [dbo].[CVBank] WITH (NOLOCK)
GO
--OUTPUT

indentify filetable lock.1.1

Wow, so the file table was indeed locked. So half of the problem is solved. Now, in order to fix this issue, I need to identify which file(s) is/are being used and due to which, the filetable has been apparently locked.
Given below is the script that will give you the file(s) name being used and due to which, the filetable has been locked. I found this script on MSDN.

USE SampleDB
GO
SELECT opened_file_name
FROM sys.dm_filestream_non_transacted_handles
WHERE fcb_id IN
( SELECT request_owner_id FROM sys.dm_tran_locks );
GO
--OUTPUT

indentify filetable lock.1.2

As mentioned above, I identified the lock held by the filetables and in order to avoid this issue, you can take necessary action to close this file.

Let me know if you come across this situation in real world.

Read Full Post »

In my earlier article, I wrote about how to generate a serial number by using the sequence object for a result set . However, sometimes you need to generate a negative serial number for any result set and you can easily achieve it by adjusting few properties in the sequence object.

Let me explain it step by step to demonstrate the solution.

Step 1 :
First of all, you need to create a sequence object along with some specific negative parameters as shown below.

USE AdventureWorks2012
GO
--DROP SEQUENCE dbo.Seq_Sample
--GO
CREATE SEQUENCE dbo.Seq_Sample
AS int
START WITH -1
INCREMENT BY -1
MINVALUE -3000
MAXVALUE -1
CYCLE ;
GO
--OUTPUT

Step 2 :
In this step, you are ready to use the above sequence object to generate a negative serial number as shown below.

USE AdventureWorks2012
GO
SELECT
NEXT VALUE FOR Seq_Sample AS [Sno], Name
FROM sys.all_objects ;
GO
--OUTPUT

Negative serial number - Sequence.1.1

Step 3 :
In this step, you need to reset the sequence number in order to start the sequence number from -1 each time. Given below is the script.

USE AdventureWorks2012
GO
ALTER SEQUENCE dbo.Seq_Sample
RESTART WITH -1 ;
GO
--OUTPUT

Let me know if you came across this situation and how you fixed it.

Read Full Post »

It is a very common scenario when you need to match a source table and a target table to find the missing (mismatch) rows across the result sets. We usually do it for multiple purposes specially at the time of audit or data migration etc.

Problem :
We usually use logical operators (NOT IN, Exists) to find the difference between two result sets. However, if you need to match each row by each row & each column by each column, it would be very difficult to achieve it via above mentioned logical operators.

Sample :
Let me create a sample to demonstrate the problem and solution.

--This script is compatible with SQL Server 2005
USE [AdventureWorks2012]
GO
--Create a sample table
CREATE TABLE [HumanResources].[Department_Sample](
[DepartmentID] [smallint] NOT NULL,
[Name] [dbo].[Name] NOT NULL,
[GroupName] [dbo].[Name] NOT NULL,
[ModifiedDate] [datetime] NOT NULL,
) ON [PRIMARY]
GO

--Insert records into the sample table from actual table
INSERT INTO [HumanResources].[Department_Sample]
SELECT * FROM [HumanResources].[Department]
GO

--Update a single record in the sample table
--to differentiate it from actual
UPDATE [HumanResources].[Department_Sample]
SET [Name] = 'Business Development'
WHERE DepartmentID=2

--Insert a record in the original table
INSERT INTO [HumanResources].[Department]
([Name]
,[GroupName]
,[ModifiedDate])
VALUES
('IT'
,'Executive General and Administration'
,GETDATE())
GO
--Delete a record from the sample table
DELETE FROM [HumanResources].[Department_Sample]
WHERE [DepartmentID]=11
GO
SELECT * FROM [HumanResources].[Department]
GO
--OUTPUT

find missing result set.1.1

Solution :
As mentioned above, I created a sample table, copied data from original table in it and then modified & inserted the data in the sample table & original table respectively. Now, in order to find the the missing (mismatched) records across the result set, we need to use EXCEPT operator. Given below is the script that will ONLY show the missing rows in the sample table (Target Table).

--This script is compatible with SQL Server 2005
USE AdventureWorks2012
GO
--Source Table
SELECT * FROM [HumanResources].[Department]
EXCEPT
--Target table
SELECT * FROM [HumanResources].[Department_Sample]
GO
--OUTPUT

find missing result set.1.2

Conclusion :
Whenever you need to find the missing (mismatch) row across the result sets, always use EXCEPT operator to make your life easier.

Read Full Post »

Change Data Capture (CDC) is one of the best features shipped with SQL Server 2008. We usually use CDC to record the change of the tables using DML operations for audit purpose. Today, I configured CDC for one of my clients. In order to configure the CDC, first of all, you need to enable it. However, once I tried enabling it but it gave me an error.

Let me explain the error and its solution in detail.

Message Number: 22830

Severity : 16

Error Message: Could not update the metadata that indicates database %s is enabled for Change Data Capture. The failure occurred when executing the command ‘%s’. The error returned was %d: ‘%s’. Use the action and error to determine the cause of the failure and resubmit the request.

Error Generation:
Let me enable the CDC to generate the error.

USE AdventureWorks2012
GO
EXEC sys.sp_cdc_enable_db
GO
--OUTPUT

Msg 22830, Level 16, State 1, Procedure sp_cdc_enable_db_internal, Line 193
Could not update the metadata that indicates database AdventureWorks2012 is enabled for Change Data Capture. The failure occurred when executing the command ‘SetCDCTracked(Value = 1)’. The error returned was 15517: ‘Cannot execute as the database principal because the principal “dbo” does not exist, this type of principal cannot be impersonated, or you do not have permission.’. Use the action and error to determine the cause of the failure and resubmit the request.

Ooopps…… I am unable to enable the CDC. What is the solution ? Let me explain the solution.

Resolution:
If you look at the error message, you will find two error numbers 22830 & 15517. In fact the actual error is 15517 and the reason behind this is, you do not have a valid log in for the database owner of the selected database. The solution I found is from Microsoft support site. Given below is the script.

USE AdventureWorks2012 -- Change the database name
GO
sp_changedbowner 'sa' --Change the valid login name
GO

Once you execute the above statement, you can easily enable the CDC and enjoy the benefit of CDC.

Conclusion:
To conclude, whenever you come across this error, you should change the database owner of the selected database to a valid SQL Server log in.

Read Full Post »

« Newer Posts - Older Posts »