NZSQL/CODE - How to use PRINT in Netezza - sql

We are using Aginity Workbench for Netezza SQL and I was wondering if anyone knows of a equivalent in NZSQL for the TSQL "PRINT" function?
We use it for printing errors when someone tries to execute a query that would rewrite data when it shouldnt, and the only solution I am finding is using netezza command line "-t".
Thanks in advance!

You can use RAISE to do this, as documented here.
Here is an example:
CREATE OR REPLACE PROCEDURE RAISE_DEMO()
RETURNS VARCHAR(ANY)
EXECUTE AS OWNER
LANGUAGE NZPLSQL AS
BEGIN_PROC
DECLARE
MYNAME varchar;
BEGIN
MYNAME := 'SCOTT';
RAISE NOTICE 'Hello, %', MYNAME;
END;
END_PROC;
TESTDB.ADMIN(ADMIN)=> call raise_demo();
NOTICE: Hello, SCOTT
RAISE_DEMO
------------
(1 row)
If you change NOTICE to EXCEPTION, then the execution will stop.
CREATE OR REPLACE PROCEDURE RAISE_DEMO()
RETURNS VARCHAR(ANY)
EXECUTE AS OWNER
LANGUAGE NZPLSQL AS
BEGIN_PROC
DECLARE
MYNAME varchar;
BEGIN
MYNAME := 'SCOTT';
RAISE EXCEPTION 'Hello, %, this is an exception', MYNAME;
RAISE NOTICE 'You should not see this message';
END;
END_PROC;
TESTDB.ADMIN(ADMIN)=> call raise_demo();
ERROR: Hello, SCOTT, this is an exception
TESTDB.ADMIN(ADMIN)=>
This behavior is in documented in the link I provided at the top.

Related

Generated string to SQL request in snowflake

I am actually trying to find a solution for my issue. The problem is this one :
A function generate a string, this string is a SQL request, and I want to use snowflake to "read" and execute this SQL request.
Do you have a solution for this kind of problem please ?
I still continue to try to find a solution if I find it I will put it here.
Here is my problem with more information about it.
create or replace function var_test(arg1 varchar)
returns varchar as
$$
'CREATE OR REPLACE TABLE ENV_EUT.EUT.TABLE_TEST_ALEXIS_' || arg1 || '(a varchar);'
$$
;
SELECT var_test('3') AS num_table;
With this request, i get back a table with 1 column and a value in this column :
CREATE OR REPLACE TABLE ENV_EUT.EUT.TABLE_TEST_ALEXIS_3(a varchar);
My problem now is I don't succeed to execute the string in this table. Do you see a way to do this please ? Best regards
Thank you all
Check out Snowflake Scripting.
https://docs.snowflake.com/en/developer-guide/snowflake-scripting/index.html
You can declare a statement as a variable and execute it.
See also: execute immediate
https://docs.snowflake.com/en/sql-reference/sql/execute-immediate.html
-- very simple sproc
create or replace procedure myprocedure(arg1 string)
returns varchar
language sql
as
$$
-- declare variables
declare
smt string;
begin
-- construct statement
smt := 'CREATE OR REPLACE TABLE TEST_ALEXIS_' || arg1 || ' (a varchar)';
-- execute statement
execute immediate smt;
-- message to return on success
return 'Successfully executed statement: ' || smt;
-- message to return on exception
exception
when statement_error then
return object_construct('Error type', 'STATEMENT_ERROR',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
end;
$$
;
-- call sproc to create table
call myprocedure('TEST');

plpgsql in EDB: SPL procedure with SPL-style OUT parameter or a function cannot be invoked using CALL in PL/pgSQL

I'm trying to run natively correct plpgsql code in EDB environment. Unfortunately there is a problem. Interestingly, the first run does not generate an error. Restarts generate an error, but after a few repetitions, there is no error again.
In PosgreSQL, the syntax DOES NOT CAUSE any problems.
Below is an example:
CREATE OR REPLACE PROCEDURE test1()
AS $procedure$
DECLARE
BEGIN
null;
END;
$procedure$
LANGUAGE plpgsql
;
CREATE OR REPLACE PROCEDURE test2()
AS $procedure$
DECLARE
BEGIN
call test1();
END;
$procedure$
LANGUAGE plpgsql
;
CREATE OR REPLACE PROCEDURE test3()
AS $procedure$
DECLARE
BEGIN
call test2();
END;
$procedure$
LANGUAGE plpgsql
;
And now try to run it in postgresql way and EDB way:
--run it few times as edb - error occurs randomly
begin
test3();
end;
--once again as plpgs - no error occurs but... check last call
do
$$
begin
CALL test3();
end;
$$
--once again as plpgs with exception block. - now error occurs same as edb call
do
$$
declare
v_sqlstate text;
v_message text;
v_context text;
begin
CALL test3();
EXCEPTION
WHEN OTHERS THEN
GET STACKED DIAGNOSTICS v_sqlstate = returned_sqlstate,v_message = message_text,v_context = pg_exception_context;
RAISE NOTICE 'sqlstate: %,message: %,context: %', v_sqlstate,v_message,v_context;
end;
$$
Error is:
ERROR: SPL procedure with SPL-style OUT parameter or a function cannot be invoked using CALL in PL/pgSQL
HINT: You might want to use SELECT instead.
CONTEXT: PL/pgSQL function test3() line 4 at CALL
edb-spl function inline_code_block line 2 at procedure/function invocation statement
SQL state: 42809
What am I missing???
I find that this might be a bug fixed in EPAS 13.8 (DB-1818).
https://www.enterprisedb.com/docs/epas/13/epas_rel_notes/epas13_8_12_rel_notes/
I guess you may try your test in this or later new minor version.
Best Regards.

Why is RAISE NOTICE not working in Redshift?

I tried running the following command in the Redshift Query Editor within the console:
RAISE NOTICE 'hello world';
It gives an error:
ERROR: syntax error at or near "RAISE" Position: 1
I've tried the command in both upper and lower case, and have also tried running it from DBeaver in case it was an issue with the console itself. I've also tried it as RAISE INFO. None of these were successful. I have admin permissions on the cluster and am able to run other commands successfully. What might be causing this?
It's a part of PL/pgSQL procedural language used in AWS Redshift stored procedures too. So, you can use it only within stored procedures
You can follow the basic example
CREATE PROCEDURE update_value() AS $$
DECLARE
value integer := 20;
BEGIN
RAISE NOTICE 'Value here is %', value; -- Value here is 20
value := 50;
--
-- Create a subblock
--
DECLARE
value integer := 80;
BEGIN
RAISE NOTICE 'Value here is %', value; -- Value here is 80
END;
RAISE NOTICE 'Value here is %', value; -- Value here is 50
END;
$$ LANGUAGE plpgsql;
and run it with
call update_value();

Oracle dynamic SQL: UDF within execute immediate

I am trying to make some of my code dynamic. While typing the question how to use UDFs in dynamic SQL, I figured out the answer:
One can call the UDF from outside!
This works:
Update my_table
Set col1 = get_some_value(col2,col2)
Where 1 = 1;
This did not work:
Execute Immediate '
Update my_table
Set col1 = get_some_value(col2,col3)
Where 1 = 1
';
But this works:
Execute Immediate '
Update my_table
Set col1 = my_package_name.get_some_value(col2,col3)
Where 1 = 1
';
I am using Oracle Database 12c Enterprise Edition Release 12.1.0.2.0
In case you have an idea, how to skip the call from outside, feel free to let me know.
Many greeetings,
Peter
Check your grants and make sure you either include explicit schema owner in the quoted call, use a synonym, or connect directly as schema owner.
Remember that stored procedures execute normally with the privileges of the code creator, so you should make certain that the username you use to run the execute immediate has direct grant (not via a role) access to execute the function.
This works fine in Oracle 12c when logged in as schema owner:
create function myfunc(p_text in varchar2) return varchar2 is
begin
return initcap(p_text);
end;
/
begin
execute immediate 'update emp set ename = myfunc(ename)';
end;
/
select ename from emp;
Returns:
King
Blake
Clark
...
EDIT:
Based on the additional information that function and calling procedure are in the same package, it is likely that the problem is merely naming and scope.
When using execute immediate, the statement is parsed and executed at runtime, by Oracle's SQL engine, with very limited context of the surrounding code.
In short, the payload of execute immediate doesn't know it's running in a package.
Here's a demo that should clear things up a bit.
create or replace package mytest as
function public_func(p_text in varchar2) return varchar2;
procedure demo;
end;
/
create or replace package body mytest as
-------------------------------------------------------------------------------
function public_func(p_text in varchar2) return varchar2 is
begin
return initcap(p_text);
end;
-------------------------------------------------------------------------------
function private_func(p_text in varchar2) return varchar2 is
begin
return lower(p_text);
end;
-------------------------------------------------------------------------------
procedure demo is
begin
-- Test 1 should fail because the function name is not fully qualified
begin
execute immediate 'update emp set ename = public_func(ename)';
exception when others then
dbms_output.put_line('Test1: ' || SQLERRM);
end;
-- Test 2 should pass
begin
execute immediate 'update emp set ename = mytest.public_func(ename)';
exception when others then
dbms_output.put_line('Test2: ' || SQLERRM);
end;
-- Test 3 should fail because the private function is not visible
begin
execute immediate 'update emp set ename = mytest.private_func(ename)';
exception when others then
dbms_output.put_line('Test3: ' || SQLERRM);
end;
end;
end;
/
Here's the results:
SQL> set serveroutput on;
SQL> begin
2 mytest.demo;
3 end;
4 /
Test1: ORA-00904: "PUBLIC_FUNC": invalid identifier
Test3: ORA-00904: "MYTEST"."PRIVATE_FUNC": invalid identifier
PL/SQL procedure successfully completed.
SQL>
For test 1, the SQL engine is looking for something called "public_func" and can't find it. This make sense because you could have two packages that each have something called "public_func" in them. The SQL engine does not know that it is being invoked from within a package.
Test 2 is what you did, and it works as expected.
For test 3, a function is called that exists only within the package body. Normally, other procedures in the package can see private functions, but since this is interpreted at runtime and the SQL engine doesn't know it's being called within the scope of the package, this call fails as well.

Writing Errors to File in Postgresql

I want to write errors to a file in Postgresql, so whenever error occurs in a function it writes to a file, so I have captured the error and I pass on the error to another function and the return of that function is written to a file. Below is a sample function,
CREATE OR REPLACE FUNCTION test(TEXT)
RETURNS VOID
STRICT
LANGUAGE plpgsql
AS $$
declare STATEMENT TEXT;
declare sql_code TEXT;
BEGIN
BEGIN
EXECUTE 'DROP TABLE ' || $1;
EXCEPTION WHEN others THEN
sql_code := SQLERRM;
STATEMENT := 'COPY (select * from test1('''||sql_code||''')) to ''/tmp/errors.txt''';
EXECUTE STATEMENT;
RETURN;
END;
RAISE NOTICE 'Dropped table successfully %', $1;
RETURN;
END;
$$;
CREATE OR REPLACE FUNCTION test1(TEXT)
RETURNS TEXT
STRICT
LANGUAGE plpgsql
AS $$
declare error TEXT;
BEGIN
error := $1;
RETURN STATEMENT;
END;
$$;
This thing works fine but I want to know if there is any good way to capture the error and log it to a file ? Please suggest.
Changing logging levels would be preferable though there may be good reasons to prevent this.
Failing that you could write a secondary logging routine in, say, pl/perlu, or pl/python, which could write to a file. Just be careful that you don't overwrite your data files O.o.....