How to get user defined function comment in postgreSQL - database

I'm trying to get function comment where I saved basic info that I need in my program. There are many functions that I have created name of all starts with 'stat_' and i'm retrieving their names using code below.
SELECT routines.routine_name
FROM information_schema.routines
LEFT JOIN information_schema.parameters ON
routines.specific_name=parameters.specific_name
WHERE routines.specific_schema='public' AND routines.routine_name LIKE
'stat_%' ORDER BY routines.routine_name, parameters.ordinal_position;
Now I have all function names, and I need to get their comments.
I could not find solution, if you know please share.

Comments can be retrieved via pg_description by the object id.
SELECT p.proname,
p.proargtypes,
d.description
FROM pg_proc p
LEFT JOIN pg_description d
ON d.objoid = p.oid
WHERE p.proname LIKE 'stat$_%' ESCAPE '$';

SELECT SPECIFIC_NAME AS SpName
FROM information_schema.routines
WHERE routines.specific_schema='public' AND routines.routine_name LIKE 'stat_%'
ORDER BY routines.routine_name
then u can get source of your object by this command:
EXEC sp_helptext 'ObjectName';

Related

SQL: Using XML as input to do an inner join

I have XML coming in as the input, but I'm unclear on how I need to setup the data and statement to get the values from it. My XML is as follows:
<Keys>
<key>246</key>
<key>247</key>
<key>248</key>
</Keys>
And I want to do the following (is simplified to get my point across)
Select *
From Transaction as t
Inner Join #InputXml.nodes('Keys') as K(X)
on K.X.value('#Key', 'INT') = t.financial_transaction_grp_key
Can anyone provide how I would do that? What would my 3rd/4th line in the SQL look like?
Thanks!
From your code I assume this is SQL-Server but you added the tag [mysql]...
For your next question please keep in mind, that it is very important to know your tools (vendor and version).
Assuming T-SQL and [sql-server] (according to the provided sample code) you were close:
DECLARE #InputXml XML=
N'<Keys>
<key>246</key>
<key>247</key>
<key>248</key>
</Keys>';
DECLARE #YourTransactionTable TABLE(ID INT IDENTITY,financial_transaction_grp_key INT);
INSERT INTO #YourTransactionTable VALUES (200),(246),(247),(300);
Select t.*
From #YourTransactionTable as t
Inner Join #InputXml.nodes('/Keys/key') as K(X)
on K.X.value('text()[1]', 'INT') = t.financial_transaction_grp_key;
What was wrong:
.nodes() must go down to the repeating element, which is <key>
In .value() you are using the path #Key, which is wrong on two sides: 1) <key> is an element and not an attribute and 2) XML is strictly case-sensitive, so Key!=key.
An alternative might be this:
WHERE #InputXml.exist('/Keys/key[. cast as xs:int? = sql:column("financial_transaction_grp_key")]')=1;
Which one is faster depends on the count of rows in your source table as well as the count of keys in your XML. Just try it out.
You probably need to parse the XML to a readable format with regex.
I wrote a similar event to parse the active DB from an xmlpayload that was saved on a table. This may or may not work for you, but you should be able to at least get started.
SELECT SUBSTRING(column FROM IF(locate('<key>',column)=0,0,0+LOCATE('<key>',column))) as KEY FROM table LIMIT 1\G

what is the error? (SELECT [Data] FROM Split(#ProductName,','))

The stored procedure that used work with multiple parameters but it stops working.
I am trying to fix the stored procedure that used to work but suddenly create an error 'Invalid object name 'Split''. This is the procedure that someone else wrote so I am not exactly sure what 'Split' is. Is this some sort of command or what?
This is the stored Procedure that used to work but not anymore.
DECLARE #ProductName NVARCHAR(MAX) = '9x95dk36-2727-9401-8948-161740000000,150t3vh6-1230-4449-8846-173120000000'
SELECT
m.[member_id]
, m.external_member_id
, m.last_name
, m.first_name
, m.middle_name
, e.effective_date
,[termination_date]
, REPLACE(bhp.name_full_path,'CW > Medicaid > WI > SSI > ','') AS BHP
, pr.product_name
,pr.product_ID
INTO #ActiveSSIMembers
FROM
[Eligibility] as e
INNER JOIN Product as pr on e.product_id = pr.product_id
INNER JOIN Member as m on e.member_id = m.member_id
INNER JOIN BhpNode as bhp on m.bhp_node_id = bhp.bhp_node_id
WHERE
pr.product_ID IN (SELECT [Data] FROM Split(#ProductName,','))
We need to use multiple parameters for the query.
From the code you have posted, it seems Split is a Table-Valued User-Defined function that takes NVarchar parameter(seperated by ',') and returns rows of split values under the column name Data.
You are missing that user-defined function in your database where this query is being executed. Either this has been removed or you running the query in a different database.
Try navigating to Table-Valued Functions as below and make sure you have a function called Split in there(instead of 'TestFunction' in that image). If not, you can create your our function to split the values and add it to your database.
You can take help from this thread to create one

SQL Server Management Studio, Beginner

So, I have this question:
Use the following query to determine the principle_id values for suzie and jimmy.
select *
from sys.database_principals
where name in ('suzie','jimmy')
Using the principle_id values obtained from the query above; write a SELECT query using the
sys.database_permissions table that lists ALL permissions that have been granted to suzie and jimmy.
Principal id's I got were "5 & 6"
Then I used:
SELECT*
FROM sys.database_permissions
WHERE grantee_principal_id in ('5','6')
Now the question is we're asked now to use the OBJECT_NAME function in your query to show the view names instead of just their
major_id values. I don't quite understand how to use the OBJECT_NAME function, I have been playing around and can't get it. Any hints or help would be greatly appreciated. Thanks!
Are you looking for something like this?
grator_principal_id will return all objects where these principal gave the grant and grantee_Prinicipal_id return all objects where Suzie and Jimmy were granted Details here
SELECT *
,OBJECT_NAME(major_id) AS TheObject
FROM sys.database_permissions
WHERE grantor_principal_id in (select principal_id
from sys.database_principals
where name in ('suzie','jimmy'))

Storing the text of a stored procedure in an XML data type in SQL Server

I need to store the text of all of the stored procedures in a database into an XML data type. When I use, FOR XML PATH, the text within in the stored procedure contains serialized data characters like 
 and
for CRLF and ", etc. I need the text to stored in the xml structure without these characters because the text will need to be used to recreate the stored procedure.
This is the query that I use for FOR XML PATH:
SELECT
[View].name AS "#VName", [Module].definition AS "#VDefinition"
FROM
sys.views AS [View]
INNER JOIN
sys.sql_modules AS [Module] ON [Module].object_id = [View].object_id
FOR XML PATH ('View'), TYPE
I read that I should use CDATA for the text using FOR XML EXPLICIT. However, the output of the when I run the following query and view the XML data, it contains those characters also. I need the text to be in plain text without these characters.
This is my query:
SELECT
1 AS Tag,
0 AS Parent,
NULL AS [Database1!1],
NULL AS [StoredProcedure!2!VName],
NULL AS [StoredProcedure!2!cdata]
UNION ALL
SELECT
2 AS Tag,
1 AS Parent,
NULL,
[StoredProcedure].name as [StoredProcedure!2!!CDATA],
[Module].definition as [StoredProcedure!2!!CDATA]
FROM
sys.procedures AS [StoredProcedure]
INNER JOIN
sys.sql_modules [Module] ON [StoredProcedure].object_id = [Module].object_id
WHERE
[StoredProcedure].name NOT LIKE '%diagram%'
FOR XML EXPLICIT
How can I store the text of a the stored procedures that is in plain text? Or when I parse the xml data type to recreate the stored procedure can I deserialize it so that it does not have those characters?
Ideally, I would like to use FOR XML PATH but if that is not possible I will use FOR XML EXPLICIT.
If you want to store data with special characters within XML, there are two options (plus a joke option)
escaping
CDATA
just to mention: Convert everything to base64 or similar would work too :-)
The point is: You do not need this!
The only reason for CDATA (at least for me) is manually created content (copy'n'paste or typing). Whenever you build your XML automatically, you should rely on the implicitly applied escaping.
Why does it bother you, how the data is looking within the XML?
If you read this properly (not with SUBSTRING or other string based methods), you will get it back in the original look.
Try this:
DECLARE #TextWithSpecialCharacters NVARCHAR(100)=N'€ This is' + CHAR(13) + 'strange <ups, angular brackets! > And Ampersand &&&';
SELECT #TextWithSpecialCharacters FOR XML PATH('test');
returns
€ This is
strange <ups, angular brackets! > And Ampersand &&&
But this...
SELECT (SELECT #TextWithSpecialCharacters FOR XML PATH('test'),TYPE).value('/test[1]','nvarchar(100)');
...returns
€ This is
strange <ups, angular brackets! > And Ampersand &&&
Microsoft decided not even to support this with FOR XML (except EXPLICIT, which is a pain in the neck...)
Read two related answers (by me :-) about CDATA)
https://stackoverflow.com/a/38547537/5089204
https://stackoverflow.com/a/39034049/5089204 (with further links...)
When I use, FOR XML PATH, the text within in the stored procedure contains serialized data characters like 
 and
for CRLF and ", etc.
Yes, because that's how XML works. To take a clearer example, suppose your sproc contained this text:
IF #someString = '<' THEN
then to store it in XML, there must be some kind of encoding applied, since you can't have a bare < in the middle of your XML (I hope you can see why).
The real question is then not 'how do I stop my text being encoded when I store it as XML', but rather (as you guess might be the case):
Or when I parse the xml data type to recreate the stored procedure can I deserialize it so that it does not have those characters?
Yes, this is the approach you should be looking at.
You don't how us how you're getting your text out of the XML at the moment. The key thing to remember is that you can't (or rather shouldn't) treat XML as 'text with extra bits' - you should use methods that understand XML.
If you're extracting the text in T-SQL itself, use the various XQuery options. If in C#, use any of the various XML libraries. Just don't do a substring operation and expect that to work...
An example, if you are extracting in T-SQL:
DECLARE #someRandomText nvarchar(max) = 'I am some arbitrary text, eg a sproc definition.
I contain newlines
And arbitrary characters such as < > &
The end.';
-- Pack into XML
DECLARE #asXml xml = ( SELECT #someRandomText FOR XML PATH ('Example'), TYPE );
SELECT #asXml;
-- Extract
DECLARE #textOut nvarchar(max) = ( SELECT #asXml.value('.', 'nvarchar(max)') ) ;
SELECT #textOut;
But you can find many many tutorials on how to get values out of xml-typed data; this is just an example.
SELECT
1 as Tag,
0 as Parent,
[View].name AS 'StoredProcedure!1!Name',
[Module].definition AS 'StoredProcedure!1!Definition!cdata'
FROM sys.views AS [View]
INNER JOIN sys.sql_modules AS [Module] ON [Module].object_id = [View].object_id
FOR XML EXPLICIT
Sample of the output from Adventureworks2012:
<StoredProcedure Name="vStoreWithContacts">
<Definition><![CDATA[
CREATE VIEW [Sales].[vStoreWithContacts] AS
SELECT
s.[BusinessEntityID]
,s.[Name]
,ct.[Name] AS [ContactType]
,p.[Title]
,p.[FirstName]
,p.[MiddleName]
,p.[LastName]
,p.[Suffix]
,pp.[PhoneNumber]
,pnt.[Name] AS [PhoneNumberType]
,ea.[EmailAddress]
,p.[EmailPromotion]
FROM [Sales].[Store] s
INNER JOIN [Person].[BusinessEntityContact] bec
ON bec.[BusinessEntityID] = s.[BusinessEntityID]
INNER JOIN [Person].[ContactType] ct
ON ct.[ContactTypeID] = bec.[ContactTypeID]
INNER JOIN [Person].[Person] p
ON p.[BusinessEntityID] = bec.[PersonID]
LEFT OUTER JOIN [Person].[EmailAddress] ea
ON ea.[BusinessEntityID] = p.[BusinessEntityID]
LEFT OUTER JOIN [Person].[PersonPhone] pp
ON pp.[BusinessEntityID] = p.[BusinessEntityID]
LEFT OUTER JOIN [Person].[PhoneNumberType] pnt
ON pnt.[PhoneNumberTypeID] = pp.[PhoneNumberTypeID];
]]></Definition>
</StoredProcedure>
<StoredProcedure Name="vStoreWithAddresses">
<Definition><![CDATA[
CREATE VIEW [Sales].[vStoreWithAddresses] AS
SELECT
s.[BusinessEntityID]
,s.[Name]
,at.[Name] AS [AddressType]
,a.[AddressLine1]
,a.[AddressLine2]
,a.[City]
,sp.[Name] AS [StateProvinceName]
,a.[PostalCode]
,cr.[Name] AS [CountryRegionName]
FROM [Sales].[Store] s
INNER JOIN [Person].[BusinessEntityAddress] bea
ON bea.[BusinessEntityID] = s.[BusinessEntityID]
INNER JOIN [Person].[Address] a
ON a.[AddressID] = bea.[AddressID]
INNER JOIN [Person].[StateProvince] sp
ON sp.[StateProvinceID] = a.[StateProvinceID]
INNER JOIN [Person].[CountryRegion] cr
ON cr.[CountryRegionCode] = sp.[CountryRegionCode]
INNER JOIN [Person].[AddressType] at
ON at.[AddressTypeID] = bea.[AddressTypeID];
]]></Definition>
As you note there are no 
 /
/ "/ etc and NewLine characters is represented as new line

Possible to detect cursors (nested cursors) within T-SQL code?

I'm hoping to find a way to sniff out potentially inefficient T-SQL within stored procedures, in this case detecting not just cursors in stored procedures, but preferably nested cursors.
With the script below based on sys.dm_sql_referenced_entities, from a given starting stored procedure I can see a recursive downstream call stack, including a column indicating whether the text CURSOR was found within the procedure definition.
This is helpful, but it isn't capable of telling me:
whether more than one cursor exists within a procedure
whether nested cursors are used (and of course, the truly perfect solution for that would also have to detect a call to stored procedure containing a cursor, from within a cursor)
Being able to do this I think is probably beyond the abilities of querying sys tables, and involves parsing the SQL itself - does anyone know of a technique or tool that could accomplish this, or perhaps an entirely different approach that could tell me the same information.
DECLARE #procname varchar(30)
SET #procname='dbo.some_root_procedure_name'
;WITH CTE([DB],[OBJ],[INDENTED_OBJ],[SCH],[lvl],[indexof_cursor],[referenced_object_definition])
AS
(
SELECT referenced_database_name AS [DB],referenced_entity_name AS [OBJ],
cast(space(0) + referenced_entity_name as varchar(max)) AS [INDENTED_OBJ],
referenced_schema_name AS [SCH],0 AS [lvl]
,charindex('cursor',object_definition(referenced_id)) as indexof_cursor
,object_definition(referenced_id) as [referenced_object_definition]
FROM sys.dm_sql_referenced_entities(#procname, 'OBJECT')
INNER JOIN sys.objects as o on o.object_id=OBJECT_ID(referenced_entity_name)
WHERE o.type IN ('P','FN','IF','TF')
UNION ALL
SELECT referenced_database_name AS [DB],referenced_entity_name AS [OBJ],
cast(space(([lvl]+1)*2) + referenced_entity_name as varchar(max)) AS [INDENTED_OBJ],
referenced_schema_name AS [SCH],[lvl]+1 as [lvl]
,charindex('cursor',object_definition(referenced_id)) as indexof_cursor
,object_definition(referenced_id) as [referenced_object_definition]
FROM CTE as c CROSS APPLY
sys.dm_sql_referenced_entities(c.SCH+'.'+c.OBJ, 'OBJECT') as ref
INNER JOIN sys.objects as o on o.object_id=OBJECT_ID(referenced_entity_name)
WHERE o.type IN ('P','FN','IF','TF') and ref.referenced_entity_name NOT IN (c.OBJ) -- Exit Condition
)
SELECT
*
FROM CTE
EDIT: I am marking this as "solved" even though I think some improvements could be made to the below solution - I think it is "good enough" for most scenarios, but I think a fully recursive solution that can traverse an "infinitely" deep call chain is possible.
Maybe there is a more efficient way, but you could search the procedure code. It's not foolproof though in that it could get some false positives, but you shouldn't miss any. It doesn't ignore comments and variable names so it's quite possible to pick up some extra stuff.
SELECT name, xtype, colid, text
into #CodeBlocks
FROM dbo.sysobjects left join .dbo.syscomments
ON dbo.sysobjects.id = .dbo.syscomments.id
where xtype = 'P'
order by 1
SELECT name,
(SELECT convert(varchar(max),text)
FROM #CodeBlocks t2
WHERE t1.name = t2.name
ORDER BY t2.colid
FOR XML PATH('')
) text
into #AllCode
FROM #CodeBlocks t1
GROUP BY name
select #AllCode.name,
case when InterProc.name is not null then
'Possible Inter-Proc Nesting'
when #AllCode.text like '%CURSOR%FOR%CURSOR%FOR%DEALLOCATE%DEALLOCATE%' then
'Possible Nested Cursor'
when #AllCode.text like '%CURSOR%FOR%CURSOR%FOR%' then
'Possible Multiple Cursor Used'
ELSE
'Possible Cursor Used'
end
from #AllCode
left join #AllCode InterProc
on InterProc.text like '%CURSOR%FOR%'
and #AllCode.text like '%CURSOR%FOR%' + InterProc.name + '%DEALLOCATE%'
where #AllCode.text like '%CURSOR%FOR%'
I found a few nested cursors on our server I didn't know about. Interesting. :)

Resources