Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 General SQL Server Forums
 Script Library
 udfGetObjectText

Author  Topic 

Transact Charlie
Master Smack Fu Yak Hacker

3451 Posts

Posted - 2012-04-17 : 12:47:18
Ever wanted a function you can use to extract a function or sp's text?

Well here you go... (udfGetObjectText)
Used like:

SELECT [ObjectText] FROM tools.udfGetObjectText(OBJECT_ID('tools.udfGetObjectText')) ORDER BY [LineNumber]

Results:

/* udfGetObjectText *******************************************************************************
*
* Extracts the object text from an object. Returns a table with the text split into lines
* Inlineable for efficient CROSS APPLYing...
*
* Transact Charlie
*
*************************************************************************************************/
CREATE FUNCTION tools.udfGetObjectText ( @objectID INT )
RETURNS TABLE AS RETURN SELECT
so.[name] AS [ObjectName]
, cs.[RowID] AS [LineNumber]
, cs.[SplitText] AS [ObjectText]
FROM
sys.objects AS so
CROSS APPLY (
SELECT CAST([text] AS NVARCHAR(MAX))
FROM syscomments AS sc
WHERE sc.[id] = so.[object_id]
ORDER BY sc.[number]
FOR XML PATH('')
)
AS comments ([c])

CROSS APPLY tools.udfSplit(comments.[c], '#x0D;') AS cs
WHERE
so.[Object_Id] = @objectID

For free, you also get:
A tools schema
A number table (with a quarter of a million rows in it)
A *fast* string splitter function (udfSplit)

If you already have your own number table and string splitter you want to use then edit to suit.

Enjoy

SET NOCOUNT ON
/* Tools SCHEMA **********************************************************************************/
IF NOT EXISTS ( SELECT 1 FROM sys.schemas WHERE [name] = 'tools' )
BEGIN
RAISERROR('Creating tools schema....', 0, 1) WITH NOWAIT
EXEC ('CREATE SCHEMA tools') -- Dynamic because Needs to be the only statement in a batch
END
GO

/* Number Table **********************************************************************************/
IF NOT EXISTS ( SELECT 1 FROM sys.tables WHERE [name] = 'tbNumber' AND [schema_id] = SCHEMA_ID('tools'))
BEGIN
RAISERROR('Creating Number Table....', 0, 1) WITH NOWAIT
CREATE TABLE tools.tbNumber (
[n] [int] NOT NULL
, CONSTRAINT [PK_tbNumber] PRIMARY KEY CLUSTERED ([n])
)
END
GO

/* Number Table Population ***********************************************************************/
RAISERROR('Populating Number Table (1/4 Million Numbers Should be enough)....', 0, 1) WITH NOWAIT
TRUNCATE TABLE tools.tbNumber

; WITH number (n) -- 1 Million Numbers
AS (
SELECT ROW_NUMBER() OVER (ORDER BY a.[n])
FROM
( SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 ) AS a ([n])
CROSS JOIN ( SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 ) AS b ([n])
CROSS JOIN ( SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 ) AS c ([n])
CROSS JOIN ( SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 ) AS d ([n])
CROSS JOIN ( SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 ) AS e ([n])
CROSS JOIN ( SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 ) AS f ([n])
CROSS JOIN ( SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 ) AS g ([n])
CROSS JOIN ( SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 ) AS h ([n])
CROSS JOIN ( SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 ) AS i ([n])
)
INSERT tools.tbNumber ([n])
SELECT [n]
FROM number
GO

/* udfSplit **************************************************************************************/
RAISERROR('Creating udfSplit Function....', 0, 1) WITH NOWAIT

IF NOT EXISTS (SELECT 1 FROM sys.objects WHERE [object_id] = object_id('tools.udfSplit'))
BEGIN
-- Create a dynamic dummy function to alter
EXEC('CREATE FUNCTION tools.udfSplit() RETURNS TABLE AS RETURN (SELECT NULL AS [FOO])')
END
GO
/* udfSplit (A Fast String Splitter) **************************************************************
*
* Uses a number table to *very* quickly split the text (@text). Splits on the delimiter (@d)
* Returns Table of ( [RowID], [SplitText] ). Inlineable for CROSS APPLY etc.
*
* Transact Charlie
*
*************************************************************************************************/
ALTER FUNCTION tools.udfSplit (@text NVARCHAR(MAX), @d NVARCHAR(50))
RETURNS TABLE AS RETURN (
SELECT
[RowID] = ROW_NUMBER() OVER ( ORDER BY [n] ASC )
, [SplitText] = SUBSTRING(
@d + @text + @d
, [n] + LEN(@d)
, CHARINDEX(@d, @d + @text + @d, [n] + LEN(@d)) - [n] - LEN(@d)
)
FROM tools.tbNumber AS n
WHERE [n] <= LEN(@d + @text + @d) - LEN(@d)
AND SUBSTRING(@d + @text + @d, [n], LEN(@d)) = @d
)
GO


/* udfGetObjectText ******************************************************************************/
RAISERROR('Creating udfGetObjectText Function....', 0, 1) WITH NOWAIT

IF NOT EXISTS (SELECT 1 FROM sys.objects WHERE [object_id] = object_id('tools.udfGetObjectText'))
BEGIN
-- Create a dynamic dummy function to alter
EXEC('CREATE FUNCTION tools.udfGetObjectText() RETURNS TABLE AS RETURN (SELECT NULL AS [FOO])')
END
GO
/* udfGetObjectText *******************************************************************************
*
* Extracts the object text from an object. Returns a table with the text split into lines
* Inlineable for efficient CROSS APPLYing...
*
* Transact Charlie
*
*************************************************************************************************/
ALTER FUNCTION tools.udfGetObjectText ( @objectID INT )
RETURNS TABLE AS RETURN SELECT
so.[name] AS [ObjectName]
, cs.[RowID] AS [LineNumber]
, cs.[SplitText] AS [ObjectText]
FROM
sys.objects AS so
CROSS APPLY (
SELECT CAST([text] AS NVARCHAR(MAX))
FROM syscomments AS sc
WHERE sc.[id] = so.[object_id]
ORDER BY sc.[number]
FOR XML PATH('')
)
AS comments ([c])

CROSS APPLY tools.udfSplit(comments.[c], '#x0D;') AS cs
WHERE
so.[Object_Id] = @objectID
GO



/* Testing ***************************************************************************************/
SELECT [ObjectText] FROM tools.udfGetObjectText(OBJECT_ID('tools.udfGetObjectText')) ORDER BY [LineNumber]


I hope it's self explanatory.

Charlie
===============================================================
Msg 3903, Level 16, State 1, Line 1736
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION

Lumbago
Norsk Yak Master

3271 Posts

Posted - 2012-04-19 : 08:06:22
I don't mean to be rude or anything but why not use information_schema instead? Both procs and udf's are in there...

->

SELECT ROUTINE_DEFINITION
FROM INFORMATION_SCHEMA.ROUTINES
WHERE SPECIFIC_NAME = 'myProcOrFunctionName'


And here's another take on the numbers-table. "Samesame but different..."

CREATE VIEW dbo.Numbers
AS

with
a(n) as (select 0 union all select 0 union all select 0),
b(n) as (select 0 from a x cross join a y cross join a z),
c(n) as (select 0 from b x cross join b y cross join b z),
d(n) as (select 0 from c x cross join c y),
e(rowumber) as (select row_number() over (order by n) n from d)
select * from e


- Lumbago
My blog-> http://thefirstsql.com/2011/07/08/how-to-find-gaps-in-identity-columns-at-the-speed-of-light/
Go to Top of Page

Transact Charlie
Master Smack Fu Yak Hacker

3451 Posts

Posted - 2012-04-19 : 08:44:49
quote:
Originally posted by Lumbago

I don't mean to be rude or anything but why not use information_schema instead? Both procs and udf's are in there...

->

SELECT ROUTINE_DEFINITION
FROM INFORMATION_SCHEMA.ROUTINES
WHERE SPECIFIC_NAME = 'myProcOrFunctionName'



Because it truncates the text to NVARCHAR(4000)

Charlie
===============================================================
Msg 3903, Level 16, State 1, Line 1736
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION
Go to Top of Page

robvolk
Most Valuable Yak

15732 Posts

Posted - 2012-04-19 : 09:31:42
How about OBJECT_DEFINITION()? It's not 2000 compatible but protects you against syscomments going away in the future.
Go to Top of Page

Transact Charlie
Master Smack Fu Yak Hacker

3451 Posts

Posted - 2012-04-19 : 10:40:28
Why not OBJECT_DEFINTION()....

Because I didn't know it existed...... Ho Hum....

Amended:

/* udfGetObjectText *******************************************************************************
*
* Extracts the object text from an object. Returns a table with the text split into lines
* Inlineable for efficient CROSS APPLYing...
*
* Transact Charlie
*
*************************************************************************************************/
ALTER FUNCTION [tools].[udfGetObjectText] ( @objectID INT )
RETURNS TABLE AS RETURN SELECT
OBJECT_NAME(@objectID) AS [ObjectName]
, cs.[RowID] AS [LineNumber]
, cs.[SplitText] AS [ObjectText]
FROM
tools.udfSplit(OBJECT_DEFINITION(@objectID), CHAR(13)+CHAR(10)) AS cs


Charlie
===============================================================
Msg 3903, Level 16, State 1, Line 1736
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION
Go to Top of Page
   

- Advertisement -