Archive for the ‘Programming’ Category

SQL Injection Attacks on the Rise

Saturday, August 22nd, 2009

According to a recent article at Dark Reading, SQL injection attacks are on the rise. Surprisingly it’s not due to a new technique, increasing success, or great ingenuity. Instead, it’s just old standby methods being used in great numbers due to simplicity and the possibility of valuable results.

Source: Tech Insight: SQL Injection Demystified, Dark Reading

Ten Things to Help SQL Beginners

Thursday, June 11th, 2009

In a recent post at TechRepublic, some beginner SQL tips were listed. They include definitions and examples for DISTINCT, GROUP BY, various aggregate functions, and other basic commands. The article focuses on Jet, but many tips apply to other SQL products too.

Source: 10+ tips for working smarter with SQL, TechRepublic

Using OUTPUT with UPDATE

Sunday, June 7th, 2009

As seen in earlier posts, a very useful clause in SQL Server 2005 and beyond is OUTPUT. Here is an example within an UPDATE statement.

Here’s our table structure:

IF EXISTS (SELECT * FROM sys.tables WHERE name = 'users')
BEGIN
  DROP TABLE [users];
END;

CREATE TABLE [users] (
  [user_id] INT PRIMARY KEY IDENTITY(1,1),
  username VARCHAR(16),
  [password] VARCHAR(16),
  email VARCHAR(128)
);

Here is a changeUserName procedure to update a user’s username, using an OUTPUT clause:

CREATE PROC changeUserName
  @user_ip varchar(15),
  @password varchar(16),
  @username_old varchar(16),
  @username_new varchar(16)
AS

  SET NOCOUNT ON;

  CREATE TABLE #updatedUser(
    user_id INT,
    username_old VARCHAR(16),
    username_new VARCHAR(16));

  UPDATE [users]
    SET [username] = @username_new
  OUTPUT DELETED.user_id, DELETED.username, INSERTED.username
    INTO #updatedUser(user_id, username_old, username_new)
  WHERE [users].username = @username_old
    AND CAST([users].[password] AS VARBINARY(16))
      = CAST(@password AS VARBINARY(16));

  SET NOCOUNT OFF;

  SELECT user_id, username_old, username_new
    FROM #updatedUser;

  DROP TABLE #updatedUser;

Here is an example of that procedure in action:

EXEC [addUser] @user_ip = '192.168.1.2',
  @username = 'john',
  @password = 'john!password',
  @email = 'john@yahoo.com';

user_id
-----------
1

EXEC [changeUserName]
  @user_ip = '192.168.1.1',
  @username_old = 'john',
  @username_new = 'john_new',
  @password='john!password';

user_id     old_username     new_username
------- ---------------- ----------------
1           john         john_new

Don’t Forget the OUTPUT Clause

Tuesday, May 26th, 2009

One of the more useful clauses available in SQL Server 2005 and beyond is OUTPUT, but it is rarely seen in use. Here is a quick example of how to use it within an INSERT statement.

Let’s setup our table structure first:

IF EXISTS (SELECT * FROM sys.tables WHERE name = 'users')
BEGIN
  DROP TABLE [users];
END;

CREATE TABLE [users] (
  [user_id] INT PRIMARY KEY IDENTITY(1,1),
  username VARCHAR(16),
  [password] VARCHAR(16),
  email VARCHAR(128)
);

IF EXISTS (SELECT * FROM sys.tables WHERE name = 'login_activity')
BEGIN
  DROP TABLE [login_activity];
END;

CREATE TABLE [login_activity] (
  user_id INT,
  user_ip VARCHAR(15),
  login_username VARCHAR(16),
  login_success BIT,
  login_time DATETIME
);

Let’s assume we want an addUser procedure to create a user, log in said user, and return the new user’s user_id. Here is how we could do that with the OUTPUT clause:

CREATE PROC addUser
  @user_ip VARCHAR(15),
  @username VARCHAR(16),
  @password VARCHAR(16),
  @email VARCHAR(128)
AS

SET NOCOUNT ON;

CREATE TABLE #new_user(user_id INT);

INSERT INTO users (username, [password], email)
OUTPUT inserted.[user_id] INTO #new_user(user_id)
VALUES (@username, @password, @email);

INSERT INTO login_activity(user_id, login_ip, login_username,
  login_success, login_time)
SELECT user_id, @username, @user_ip, 1, CURRENT_TIMESTAMP
FROM #new_user;

SET NOCOUNT OFF;

SELECT user_id
FROM new_user;
EXEC [addUser] @user_ip = '192.168.1.1',
  @username = 'bob',
  @password = 'bob!password',
  @email = 'bob@gmail.com';

user_id
-----------
1

EXEC [addUser] @user_ip = '192.168.1.2',
  @username = 'john',
  @password = 'john!password',
  @email = 'john@yahoo.com';

user_id
-----------
2

Paging Stored Procedure in MS SQL, By Page

Sunday, May 24th, 2009

MS SQL has the TOP clause, and it works very similar to MySQL’s LIMIT clause. However, the TOP clause in MS SQL provides no sort of OFFSET equivalent. Thus the TOP clause is virtually useless for a proper paging control. Let’s see one way we can work around that limitation:

For reference, here are the CREATE and INSERT statements for the [users] table used in this example.

CREATE TABLE [users] (
  user_id INT PRIMARY KEY,
  username VARCHAR(16),
  password VARCHAR(16),
  email VARCHAR(128)
);

INSERT INTO [users] (user_id, username, password, email)
SELECT 1, 'bob', 'bob!password', 'bob@gmail.com'
UNION ALL
SELECT 2, 'john', 'john!password', 'john@yahoo.com'
UNION ALL
SELECT 3, 'kim', 'kim!password', 'kim@msn.com'
UNION ALL
SELECT 4, 'rachel', 'rachel!password', 'rachel@aol.com'
UNION ALL
SELECT 5, 'frank', 'frank!password', 'frank@email.com';

Now, let’s create a stored procedure to search our [users] table. It takes three paramaters. The @email paramater is a full or partial e-mail to search. @page is the page to be displayed, and @per_page is the number of results per page.

CREATE PROC searchUsersByEmail
  @email VARCHAR(128),
  @page SMALLINT,
  @per_page SMALLINT
AS

SET @last_page = (@nbr_results - 1) / @per_page + 1;

SELECT
  @nbr_results = COUNT(*)
FROM [users] AS u
WHERE u.email LIKE '%' + @email + '%';

SET @last_page = @nbr_results / @per_page; 

IF (@page = 1)
BEGIN
  -- Special first page case:
  SELECT TOP (@per_page)
    u.user_id,
    u.username,
    u.email
  FROM [users] AS u
  WHERE u.email LIKE '%' + @email + '%'
  ORDER BY u.email ASC;
END;
ELSE IF (@page = @last_page)
BEGIN
  -- Special last page case:
  SELECT s0.*
  FROM (
    SELECT TOP (@nbr_results - (@last_page - 1) * @per_page)
      u.user_id,
      u.username,
      u.email
    FROM [users] AS u
    WHERE u.email LIKE '%' + @email + '%'
    ORDER BY u.email DESC
  ) AS s0
  ORDER BY s0.email ASC;
END;
ELSE IF (@page > @last_page)
BEGIN
  -- Error / Empty set case, replace with error if desired.
  SELECT
    u.user_id,
    u.username,
    u.email
  FROM [users] AS u
  WHERE 1 = 0;
END;
ELSE
BEGIN
  -- All other cases:
  SELECT s1.*
  FROM (
    SELECT TOP (@per_page) s0.*
    FROM (
      SELECT TOP (@page * @per_page)
        u.user_id,
        u.username,
        u.email
      FROM [users] AS u
      WHERE u.email LIKE '%' + @email + '%'
      ORDER BY u.email ASC
    ) AS s0
    ORDER BY s0.email DESC
  ) AS s1
  ORDER BY s1.email ASC;
END;

Now let’s test our search procedure by searching for all e-mails with “.com”:

[searchUsersByEmail] @email = '.com', @page = 1, @per_page = 3;

user_id     username email
----------- -------- ----------------
1           bob      bob@gmail.com
5           frank    frank@email.com
2           john     john@yahoo.com

[searchUsersByEmail] @email = '.com', @page = 2, @per_page = 3;

user_id     username email
----------- -------- ----------------
3           kim      kim@msn.com
4           rachel   rachel@aol.com

That’s it. Now you have a functional procedure in MS SQL as an alternative to MySQL’s LIMIT x OFFSET y clause.

Link MySQL to 64-bit MS SQL Server

Wednesday, May 20th, 2009

The key to adding a MySQL instance as a linked server within 64-bit MS SQL Server is finding an appropriate x64 ODBC provider. Microsoft had previously depreciated and eliminated this feature for the 64-bit version of SQL Server.

They recently reversed their decision, and claim no new plans to depreciate this provider. However, the link is slightly hidden. Here it is: http://www.microsoft.com/downloads/details.aspx?FamilyID=000364db-5e8b-44a8-b9be-ca44d18b059b&displaylang=en