programming.torensma.net: Code Snippets

Find text inside stored procedures

The following snippet allows you to find all stored procedures containing a specific word or words. I found it to be very helpful to find all references to a table I needed to remove from my database. I order not to break functionality I scanned all procs for references and changed or removed them. Here is the code:

SELECT *
FROM INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_DEFINITION LIKE '%hello%'
AND ROUTINE_TYPE='PROCEDURE'

And here’s a slightly less efficient alternative. It uses SQL-Server 2008′s OBJECT_DEFINITION() function:

SELECT Name
FROM sys.procedures
WHERE OBJECT_DEFINITION(object_id) LIKE '%firstname%'

Find most expensive queries in Microsoft SQL server

A colleague of mine found this little gem of a query (sorry, don’t know the original author). It finds the 20 most expensive queries executed on a SQL server instance, sorted by execution time. CPU load is also returned by the query. Here it is:

SELECT TOP 20
qs.sql_handle,
qs.execution_count,
qs.total_worker_time AS Total_CPU,
total_CPU_inSeconds = --Converted from microseconds
qs.total_worker_time/1000000,
average_CPU_inSeconds = --Converted from microseconds
(qs.total_worker_time/1000000)/ qs.execution_count,
qs.total_elapsed_time,
total_elapsed_time_inSeconds = --Converted from microseconds
qs.total_elapsed_time/1000000,
st.text,
qp.query_plan
FROM
sys.dm_exec_query_stats AS qs
CROSS APPLYsys.dm_exec_sql_text(qs.sql_handle) ASst
CROSS apply sys.dm_exec_query_plan(qs.plan_handle) AS qp
ORDER BY qs.total_worker_time DESC

Some nice programming quotes I came across…

  • Walking on water and developing software from a specification are easy if both are frozen.
    – Edward V. Berard
  • Hofstadter’s Law:
    It always takes longer than you expect, even when you take into account Hofstadter’s Law.
  • Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.
    – Brian Kernighan
  • Some people, when confronted with a problem, think “I know, I’ll use regular expressions.” Now they have two problems.
    – Jamie Zawinski
  • Linux is only free if your time has no value.
    – Jamie Zawinski
  • It works on my machine.
    – Anonymous
  • It worked yesterday.
    – Anonymous
  • If debugging is the process of removing software bugs, then programming must be the process of putting them in.
    – Edsger Dijkstra
  • A computer lets you make more mistakes faster than any other invention in human history, with the possible exceptions of handguns and tequila.
    – Mitch Ratcliffe
  • Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.
    – Antoine de Saint Exupéry
  • Perl – The only language that looks the same before and after RSA encryption.
    – Keith Bostic
  • The trouble with programmers is that you can never tell what a programmer is doing until it’s too late.
    – Seymour Cray
  • Measuring programming progress by lines of code is like measuring aircraft building progress by weight.
    – Bill Gates

Script failed for Trigger ‘Trigger-name’. (Microsoft.SqlServer.Smo))

Scripting a trigger fails in SQL server due to nested comments

It’s a documented bug in SQL server that causes above error message. The error is triggered by nested comment blocks, like this example:

/*

some comments
/* nested comments*/

some more comments
*/

All very well, it’s a documented bug so it shouldn’t be a problem. Microsoft’s solution is plain and effective: don’t use nested comment blocks.

But what if, like in my case, you created the trigger using SQL server 2000′s Enterprise Manager (which does not suffer from the bug) and you’re trying to open the trigger much later using Microsoft’s SQL Server Management Studio? The trigger will fail to open and you’re pretty well stuck.

What is needed now is a way to get to the trigger without opening it directly in the Management Studio. Luckily SQL Server stores all its tables, views, stored procedures and triggers in the database itself. So to get to the trigger we need to know where it is stored.

In this post I described how to display a list of tables, views or other user objects from SQL Server. If we expand the query a little it allows us to get to the contents of the trigger we need:

SELECT o.[name], c.[text]
FROM sysobjects o INNER JOIN
syscomments c ON o.ID=c.ID
WHERE o.xtype = 'TR'

As you can see the contents of triggers is stored in the SYSCOMMENTS table. Note that longer functions, triggers and stored procedures may have multiple entries with the same name in SYSCOMMENTS. You may have to concatenate the text fields of multiple records together to get the complete contents of your function. I found the best way is create a small loop and PRINT the results instead of outputting them to the default grid.

How to display table sizes in SQL server

There are a few ways to retrieve the table sizes (both row count and size in bytes) in SQL server. The simplest is the sp_spaceused stored procedure which takes a table name as argument:

EXEC sp_spaceused 'table_name'

This is all fine, but what if you want to display info about a dozen or more tables? The undocumenten stored procedure sp_MSforeachtable might proof useful here:

EXEC sp_MSforeachtable @command1="EXEC sp_spaceused '?'"

This statement executes the sp_spaceused sp for every table in the connected database. This actually gets the information we want, albeit not in a very readable form. Because the sp is execute for each table, we get a result set for every table. If we want to do some filtering and sorting we’re out of luck here. So we need something more flexible.

The following routine executes the sp_spaceused sp for each table again, but the results are aggregated into a temporary table. Now we get a nice result set that we can actually work with. Here’s the code:

CREATE TABLE #SpaceUsed (name sysname,rows bigint,reserved sysname,data sysname,index_size sysname,unused sysname)

DECLARE @Counter int
DECLARE @Max int
DECLARE @Table sysname

SELECT  name, IDENTITY(int,1,1) ROWID
INTO       #TableCollection
FROM    sysobjects
WHERE xtype = 'U'
ORDER BY lower(name)

SET @Counter = 1
SET @Max = (SELECT Max(ROWID) FROM #TableCollection)

WHILE (@Counter <= @Max)
    BEGIN
        SET @Table = (SELECT name FROM #TableCollection WHERE ROWID = @Counter)
        INSERT INTO #SpaceUsed
        EXECUTE sp_spaceused @Table
        SET @Counter = @Counter + 1
    END

SELECT * FROM #SpaceUsed

DROP TABLE #TableCollection
DROP TABLE #SpaceUsed

Windows 7 – Explorer.exe server execution failed

On my company laptop I have a network drive attached which is not always available. Recently I got annoyed about files not always being there so I decided to disconnect the company drive all together. After restarting I then got EXPLORE.EXE server execution failed and the Windows Explorer no longer started.

Turns out I had some registry settings pointing to my company drive. Changing them to local paths solved my problem. These are the keys in question:

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders\Personal
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\Personal

Make a .NET web service accept GET requests

The usual way to call web service is by using POST requests. But sometimes GET requests are required. To make .NET web services accept their parameters from GET requests, add a ScriptMethod attribute to your web service routine.

First add some libraries:
C#

Using System.Web.Services;
Using System.Web.Services.Protocols;
Using System.Web.Script.Services;

Visual Basic

Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.Web.Script.Services

Then decorate your web service method:
C#:

[WebMethod()]
[ScriptMethod(UseHttpGet=True)]
Public String() WebServiceName(String q, Int count) {
  // Web service implementation
}

Visual Basic:

<WebMethod()> _
<ScriptMethod(UseHttpGet:=True)> _
Public Function WebServiceName(ByVal q As String, ByVal count As Integer) As String()
  ' Web service implementation
End Function

Finally you need to tell your application to accept GET requests in your web.config:

<system.web>
    ...
    <webServices>
        <protocols>
              <add name="HttpGet"/>
        </protocols>
    </webServices>
    ...
</system.web>

One note of warning: GET requests may be easier to hack because the querystring is visible to the user. Use it wisely. On the other hand, POST requests can be tampered with just as well, don’t expect them to be saver!

How to rename a column in a MS-SQL database?

Easy peasy, use the sp_rename stored procedure:

EXEC sp_rename 'TABLENAME.OLD_COLUMNNAME', 'NEW_COLUMNAME', 'COLUMN';

CakePHP: catching errors in Model->query()

In my recent CakePHP application I use some custom SQL queries that I fire at the database using the $model->query($sql) syntax. Works great, until you have an error in your $sql. I tried the obvious error handling with try … catch:

try {
  $this->Model->query('INSERT INTO model WHERE id=invalid');
} catch (exception $ex) {
  // exception never happens
}

But the CakePHP Debugger class already catches the error and does it’s handling; which is writing the error to the browser. In my case I need to act upon an error.

After some trial and error (including hacking the core Cake files, which is really dirty) I came up with this: the Cake Debugger class set an error handler using set_error_handler('someErrorHandlingRoutine'). So i made my own error handing routine, borrowing some from the Debugger class:

class AppController extends Controller {
  function handleError($code, $description, $file = null, $line = null, $context = null) {
    if (error_reporting() == 0 || $code === 2048 || $code === 8192) {
      return;
    }

    // throw error for further handling
    throw new exception(strip_tags($description));
  }
}

What it does is simple and ellegant; throw an exception. Now my $model->query code can be wrapped in a try…catch block and if an exception happens I can act on it.

As you can see I placed my error handler in the app_controller.php. This way it’s easily accessible from all my controllers.

Now before calling $model->query($sql) I set my custom error handler:

// set error handler in controller
set_error_handler(array($this, 'handleError'));

try {
  // execute dangerous sql
  $this->Model->query($sql);
} catch (exception $ex) {
  // custom error handling here...
}

How to: Check if a Microsoft SQL-server database exists?

Here’s an easy, single line statement to check if a database exists in the current SQL-server instance:

IF db_id('db_name') IS NOT NULL

First post from iPhone

Hi all, this is my first post from my iPhone. I’m using the WordPress 2.0 iPhone app (make sure XML-RPC is enabled in your WordPress back-end). Even adding images from the iPhone Camera Roll is easy peasy.

Compute hash of a file

Computing the hash value of a file is quite strait forward. I use the routine below. It opens the file, specifies the hash-algorithm to use and returns the hash of the file. If you rather use MD5 hashes, just change hashAlgorithm into MD5CryptoServiceProvider.

Public Function ComputeFileHash(ByVal fileName As String) As String

  Dim hashAlgorithm As New System.Security.Cryptography.SHA1CryptoServiceProvider()

  Using stmcheck As System.IO.FileStream = System.IO.File.OpenRead(fileName)

    Dim hash As Byte() = hashAlgorithm.ComputeHash(stmcheck)
    Dim computed As String = BitConverter.ToString(hash).Replace("-", "")

    Return computed

  End Using

End Function

SHA1 hashes typically produce 160-bit (20 bytes) messages (16 bytes for MD5). If you want to store the hash value in a database table, make sure the field is wide enough to prevent data from getting truncated. By default the ComputeHash method returns the bytes separated by a hyphen (-). To save space I opted to remove these.

Icon Finder, the Google for icons

1255430950_old-edit-findHere’s a very useful tool: http://www.iconfinder.net/

It allows you to search for icon, and it returns a lot of high quality images. Recommended!

How to: Get the name of the running SQL-server instance

Here’s a script to retrieve the name of the currently running SQL Server instance:

SELECT @@SERVERNAME AS 'ServerName'

Resultset:

ServerName
---------------------------
DEV-SQL

(1 row(s) affected)