DOWNLOAD THE CODE:
Download the Code 41845.zip

The SQL Server installation program runs regular .sql script files to create the special UDFs, so you can create them, too. The characteristics of special UDFs are that

  • they're created in the master database
  • they have the owner system_function_schema
  • their names begin with fn_
  • their names are all lowercase, even in a case-insensitive environment

However, if you try creating a function that has all these characteristics, you'll get an error message saying that the owner system_function_schema doesn't exist or that you don't have permissions to create an object with that owner. The system_function_schema user does exist in the master database's sysusers table, but you're not usually allowed to use it. Investigating the installation script files produces the missing key—you need to turn on the allow updates server configuration option to get permission to create your special UDFs, specifying the system_function_schema user as the owner. But be sure to turn the allow updates option off immediately afterward so that SQL Server won't accept direct changes to system tables.

Run the script that Listing 1, page 23, shows to create the special scalar UDF fn_removepattern(), which you can use to remove all occurrences of a pattern from a given character string. The function accepts three arguments: @str is the input character string, @pattern is the pattern you want to locate, and @deletelength is the number of characters you want to delete from the positions the pattern is in. You need to format the @pattern argument the same way you format patterns for the LIKE predicate or the PAT- INDEX() function. (For details, see SQL Server Books OnlineBOL—under LIKE.)

The reason for requesting the @deletelength parameter and not having the function's code calculate the length of the searched pattern is that the pattern length doesn't necessarily match the length of the substrings that you want to remove. For example, you might want to locate all occurrences of the pattern '%bc%' and remove the two characters bc. In that case, you'd specify 2 in the @deletelength argument. The fn_removepattern() function uses the PATINDEX() function to locate the pattern within the input character string, then uses the STUFF() function to remove characters from it repeatedly until it doesn't find the pattern anymore. To test the fn_removepattern() function, run the following code from any database:

SELECT fn_removepattern
('abcabcabcabcabc', '%bc%', 2)

You get 'aaaaa' as a result.

To use table columns as arguments for the function, run the following query:

SELECT CustomerID, Address,
fn_removepattern(Address, '%[^0-9]%', 1) AS AddrNumsOnly
FROM Northwind.dbo.Customers

Examine the abridged results that Figure 1 shows and notice in the result column AddrNumsOnly that the function removed all the non-numeric characters from the Address column.

As an example of creating a table-valued special UDF, run the code that Listing 2 shows to create the fn_nums() function, which returns a table containing the requested number of consecutive integers, starting with 1. The function first inserts the value 1 into the table variable @Nums. It then enters a loop and uses an INSERT SELECT statement in each iteration. The statement takes the existing rows from @Nums, adds a factor equal to the current number of rows in @Nums to the column n, and inserts the result back into @Nums. This loop multiplies the number of rows in @Nums in each iteration, stopping when the value of column n reaches the requested number of integers. The INSERT loop is efficient because it involves very few INSERT statements. To test the fn_nums() function, run the following query, which requests a table containing the numbers 1 through 10:

SELECT * FROM ::fn_nums(10)

This query returns the results that Figure 2 shows.

Prev. page     1 [2] 3     next page



You must log on before posting a comment.

If you don't have a username & password, please register now.

Reader Comments

nice one, it must be traducted to an other language like frensh, dautch,...

brik

Fantastic! This article helps me tremendously in my DBA and Developer job. Thank you. David

David Nguyen

>OPENQUERY() is allowed within a UDF, and because SQL >Server doesn't examine the character string you provided >to the function as an argument, you can use OPENQUERY() to modify data on the linked server. >>You can even refer to your local server as a linked server by turning on the Data Access server option:

Hi. BOL says "Loopback linked servers cannot be used in a distributed transaction." So in this case we can't use UDF's with OPENROWSET inside explicit transaction. But very often we have to do this And it's the bad news :(

GloryEE

Thanks to Ben and all those others who delve inside SQL Server to retrieve these nuggets for us.

Si

Hi,

This article has been so useful in knowing of the special UDF's and there backdoor in doing DML operations. However this article should have even focussed on the execution of system stored procedures like sp_help, sp_helpdb. Are this special kind of stored procs the same way as special UDF's that can be executed from across databases. If so could you please send me those articles to my emailid mentioned.

Thanks a lot, Sreevani

sreevani

The article is realy nice BUT it left me with one opened question. You wrote that there is no way to use the system_function_schema user as the owner of a function and that you investigating the installation script files and dicovered that you need to turn on the allow updates server configuration option to get permission to do so. As far as I know the allow updates server configuration option allows direct changes to system tables so why does it make the option to create functions with system_function_schema allowed, it's not a direct syste, table change (or maybe it is)??

Thanks, Ahuva

yaffa@random-logic.com

Article Rating 4 out of 5

Perfect! Just what I was searching for! One possible correction though. You suggest turning on the Data Access server option as follows:

EXEC sp_server option [server_name], 'Data Access', true

I could not get this to work and, on a hunch, rephrased it to:

EXEC sp_serveroption [server_name], 'Data Access', true

...with much better results!

[Itzik: Yes, you are right. It should be sp_serveroption and not sp_server option. Thanks!]

ksbrownjr

Article Rating 5 out of 5

 
 

ADS BY GOOGLE