Snowflake UDF calling "Show Shares" function - share

Is it possible to issue a "Show Shares" function call in either a FUNCTION or PROCEDURE in Snowflake? Since there isn't a metadata object in the Informational schema to query information about shares we are looking for a way to create a UDF to obtain this metadata and act on the results.
When attempting to execute the following code:
CREATE OR REPLACE PROCEDURE get_share_metadata()
RETURNS VARIANT
LANGUAGE javascript
AS
$$
var x=snowflake.execute( { sqlText: "SHOW SHARES" } );
$$
;
call get_share_metadata();
The following error is returned:
Execution error in store procedure GET_SHARE_METADATA: Stored procedure execution error: Unsupported statement type 'SHOW SHARE'. At Snowflake.execute, line 2 position 20

You can execute a SHOW .... command inside of a stored procedure ONLY if the procedure is setup to be EXECUTE AS CALLER.
When executing as caller, the role executing the procedure must have privileges to execute the commands within the procedure.
Examples:
SHOW SHARES is only accessible to the ACCOUNTADMIN role (technically any role can run the command successfully but results are limited to only the accountadmin).
SHOW USERS is only able to be successfully executed with any role that has the MANAGE GRANTS privilege on the account.
Documentation:
https://docs.snowflake.net/manuals/sql-reference/stored-procedures-usage.html#label-owners-rights-stored-procedures

I am not sure about function vs. stored procedure for this, but depending on what you're trying to do, have you looked into just using RESULT_SCAN?
SHOW SHARES;
SELECT * FROM TABLE(RESULT_SCAN(last_query_id()));

Related

DB2oC (DB2 on Cloud) : Facing "attempted to modify data but was not defined as MODIFIES SQL DATA" error

I have created very simple function in DB2oC as below, which has one UPDATE sql statement and one SELECT sql statement along with MODIFIES SQL DATA. But still I get the below error, though I have specified MODIFIES SQL DATA. I did GRANT ALL on that TEST table to my user id and also did GRANT EXECUTE ON FUNCTION to my user id on safe side. Can you please help to explain on what could be the issue?
I have simply invoked the function using SELECT statement like below:
SELECT TESTSCHEMA.MAIN_FUNCTION() FROM TABLE(VALUES(1));
SQL Error [38002]: User defined routine "TESTSCHEMA.MAIN_FUNCTION"
(specific name "SQL201211013006981") attempted to modify data but was
not defined as MODIFIES SQL DATA.. SQLCODE=-577, SQLSTATE=38002,
DRIVER=4.27.25
CREATE OR REPLACE FUNCTION MAIN_FUNCTION()
RETURNS VARCHAR(20)
LANGUAGE SQL
MODIFIES SQL DATA
BEGIN
DECLARE val VARCHAR(20);
UPDATE TEST t SET t.CONTENT_TEXT = 'test value' WHERE t.ID = 1;
select CONTENT_TEXT into val from TEST where ID = 1;
return val;
end;
Appreciate your help.
For the modifies SQL data clause , the usage of the function is restricted on Db2-LUW.
These restrictions do not apply for user defined functions that do not modify data.
For your specific example, that UDF will operate when used as the sole expression on the right hand side of an assignment statement in a compound-SQL compiled statemnent.
For example:
create or replace variable my_result varchar(20) default null;
begin
set my_result = main_function();
end#
Consider using stored procedures to modify table contents, instead of user defined functions.
You could avoid using a function, and just use a single "change data statement"
SELECT CONTENT_TEXT
FROM NEW TABLE(
UPDATE TEST t
SET t.CONTENT_TEXT = 'test value'
WHERE t.ID = 1
)

Calling external program from PostgreSQL trigger

I would like to execute external program (such as .net c# console) when PostgreSQL trigger is fired. How can I achieve it?
Postgres cannot normally run external programs for security reasons.
The typical solution is to use NOTIFY and have a daemon LISTEN to it. There are solutions for every major scripting language out there ...
Examples for Java from #Craig: How to refresh JPA entities when backend database changes asynchronously?
Relevant manual page for PHP.
Since Postgres 9.3 there is a solution for invoking external programs. It is - for security reasons - limited to superusers and IMHO intended for exporting data, rather than doing a "notification on trigger":
COPY (SELECT 1) TO PROGRAM '/bin/touch /tmp/created_by_postgres'
If you want to actually export data to the invoked programm, you can provide any SELECT or a table name instead of SELECT 1. The query results will then be passed to the invoked program via its standard input.
You can find documentation of the feature in the Postgres docs:
http://www.postgresql.org/docs/9.3/static/sql-copy.html
You can execute external scripts from inside trigger function with an "untrusted" language, like plpythonu.
More details here: https://www.postgresql.org/docs/current/plpython.html
Trigger function example:
CREATE FUNCTION execute_python_script()
RETURNS trigger
AS $$
begin
import subprocess
result = subprocess.run(['/path/to/your/bin/python', '/some_folder/some_sub_folder/script.py'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
end;
$$
LANGUAGE plpythonu;
Trigger example:
CREATE TRIGGER trigger_name
AFTER INSERT ON table
EXECUTE PROCEDURE execute_python_script();

Use Stored Procedure to "EXECUTE AS USER" and Apply to Calling Context (Session)

I'm using SQL Server 2008 R2 on a Windows 7 box. I have created a stored procedure to run the SQL command EXECUTE AS USER:
CREATE PROCEDURE dbo.ImpersonateUser
AS
BEGIN
EXECUTE AS USER = 'UserName';
END
Then, I'm trying to see if I am impersonating the user...
PRINT CURRENT_USER;
EXEC ImpersonateUser;
PRINT CURRENT_USER
...and the result is...
dbo
dbo
...when I want it to be...
dbo
UserName
This doesn't work, of course, because the EXECUTE AS USER statement is only valid inside the stored procedure ImpersonateUser. My question is this: Is it possible for the stored procedure ImpersonateUser to affect the calling context (session)? I want to encapsulate (and hide) other logic in the stored procedure.
It is not possible. Any EXECUTE AS change is automatically reverted at the end of a procedure.
Other things that dont live past the scope of the procedure are changes using the SET command and #TempObjects.
However, what you could do is encapsulate the logic that needs to be executed under the different security context in a procedure and then call that from within the procedure that changes the context. Something like:
CREATE PROCEDURE dbo.CallWithImpersonateUser
#ProcedureName
AS
BEGIN
EXECUTE AS USER = 'UserName';
EXEC #ProcedureName;
END;
Answer by Sebastian is correct, but still you have to grant impersonate for calling user.
Syntax can be found here
GRANT IMPERSONATE ON LOGIN::[login_to_be_impersonated] to [login1];
GO

How do I store a set of queries inside PostgreSQL so I can easily run it again?

I want to save a set of queries (multiple SQL updates) as a single element that I can execute using pgAdmin3 (PostgreSQL 9.1).
I know that I can save single SELECTS as views but how about multiple UPDATE queries?
Example:
BEGIN;
UPDATE ...;
UPDATE ...;
COMMIT;
Update: What I looking for is a step-by-step guide of adding a stored procedure using the GUI, not running a SQL query that creates it.
So far, I encountered two problems with "New function...": the return type is required and found that NULL is not acceptable, so tried integer. Also, set the type to SQL but I don't know what exactly to write inside the SQL tab, whatever I try the OK button is still disabled and the statusbar says: Please enter function source code.
Do you know or did you try stored procedure (well, stored-procedure-like functions) ?
http://www.postgresql.org/docs/9.1/interactive/plpgsql-structure.html
To call it
select <name of function>(<param1>, <param2>) as result;
Here is the missing guide for a basic SQL stored procedure, one that does return 1.
right click on Functions and choose New Function...
complete name as my_procedure, return type as integer, language as sql
select Definition tab and write SELECT 1;
done
It would be nice to know if you can create queries that are returning nothing.

Execute triggers function of another schema on the actual chema

my problem is easy to explain with an example: I have a 'common' schema (the public one?) where I store common data between a clustered application.
For every instance of my application, I have a role (used as the application user).
And i have a common role, app_users, with read-only privileges on the common schema, and every application role is a member of app_users.
Now my problem is: how can i set a trigger on the app_a scheme that execute a function (procedure) in the common scheme, but affect the (and only the) app_a tables?
I mean:
// common_scheme, dummy function to emulate the mysql on update = now()
CREATE OR REPLACEFUNCTION update_etime() RETURNS TRIGGER AS $$
BEGIN
NEW.etime = date_part('epoch'::text, now())::int;
RETURN NEW;
END;
$$ language plpgsql;
// now, in the app_foo scheme, i have the table:
CREATE TABLE foo_table (fid serial not null primary key unique, label char(25));
// and the trigger:
CREATE TRIGGER foo_table_update_etime BEFORE UPDATE ON foo_talbe FOR EACH ROW EXECUTE PROCEDURE update_etime();
// ERROR: function update_etime() does not exist
CREATE TRIGGER foo_table_update_etime BEFORE UPDATE ON foo_talbe FOR EACH ROW EXECUTE PROCEDURE common_scheme.update_etime();
// ERROR: function common_scheme.update_etime() does not exist
The user that will access app_foo has the execute privilege on update_etime() function in common_schema.
Any idea?
I've googled around but the only solution I fount to call functions from other schemas is something like execute 'select * from ' || schema_name || '.table_name'; but i dont think this will do the trick in my case, becose the function must work with the 'local' scheme.
Your second set of syntax should work... the one with "EXECUTE PROCEDURE common_scheme.update_etime();"
If it isn't finding the function, I'd guess that you either have created it in a different schema than you think it is in, or you haven't created it at all (and note, your example create syntax has a bug, no space between "replace" and "function", which would cause an error when trying to create the function. Try doing a:
\df *.update_etime
As superuser to verify the function exists and is in the location you think it is in. HTH.