I followed https://dwgeek.com/redshift-stored-procedure-return-result-set-working-example.html/ step of creating a stored procedure using a temporary table but facing the error above.
CREATE OR REPLACE PROCEDURE sample_return_table(tmp_table INOUT varchar(256))
AS '
DECLARE
row record;
BEGIN
EXECUTE ' DROP table if exists ' || tmp_table;
EXECUTE ' CREATE temp TABLE ' || tmp_table || ' AS SELECT DISTINCT table_schema FROM information_schema.tables ';
END;
'
LANGUAGE plpgsql;
Error:
[Amazon](500310) Invalid operation: syntax error at or near "DROP"
Position: 132; [SQL State=42601, DB Errorcode=500310]
1 statement failed.
May I know what is the issue ?
Here is a sample Stored Procedure from Overview of stored procedures in Amazon Redshift:
CREATE OR REPLACE PROCEDURE test_sp1(f1 int, f2 varchar)
AS $$
BEGIN
RAISE INFO 'f1 = %, f2 = %', f1, f2;
END;
$$ LANGUAGE plpgsql;
Notice that use of $$ to identify the content of the procedure, whereas your code is using '.
The problem with using ' is that it is also being used inside the procedure (eg just before DROP) and is therefore confusing Redshift.
Try changing to an unused sequence (such as $$) to avoid this problem.
Related
I need to remove (by means of a function) possible non-latin characters (chinese, japanese, ...) by means of a regex expression from a Postgres database table.
I have tried all solutions I could find online, but nothing seems to work.
CREATE OR REPLACE FUNCTION public.function_104(param text)
RETURNS void
LANGUAGE plpgsql
AS $function$
BEGIN
EXECUTE 'UPDATE public.' || quote_ident(param) || ' SET "name" = REGEXP_REPLACE("name", [^x00-x7F]+, " ")';
END
$function$
I keep running into following error message :
psycopg2.errors.SyntaxError: syntax error at or near "["
LINE 1: ..._roads_free_1 SET "name" = REGEXP_REPLACE("name", [^x00-x7F]...
^
QUERY: UPDATE public.gis_osm_roads_free_1 SET "name" = REGEXP_REPLACE("name", [^x00-x7F]+, " ")
CONTEXT: PL/pgSQL function afri_terra_104(text) line 6 at EXECUTE
```
You must put the regex between single quotes, as well as the replacement text. Since it is a dynamic query, you must escape the single quotes by doubling them:
CREATE OR REPLACE FUNCTION public.function_104(param text)
RETURNS void
LANGUAGE plpgsql
AS $function$
BEGIN
EXECUTE 'UPDATE public.' || quote_ident(param) ||
' SET "name" = REGEXP_REPLACE("name", ''[^x00-x7F]+'', '' '')';
END
$function$;
insert into t104(name) values('abcé');
INSERT 0 1
select function_104('t104');
function_104
--------------
(1 row)
select * from t104;
name
------
abc
(1 row)
CREATE OR REPLACE PROCEDURE proc_test1(p_1 varchar)
LANGUAGE plpgsql
AS $$
DECLARE
V_TEST integer := 0;
BEGIN
select count(*)
from mytab
into V_TEST
WHERE X =P_1;
RAISE NOTICE 'COUNT IS:(%)',V_TEST;
EXCEPTION
WHEN OTHERS THEN
null;
END;
$$
;
In Amazon Redshift, can I not call this stored proc in this way ?
call proc_test1(p_1 => 'x')
also, why does RAISE with a semicolon fails ? the below error handler says RAISE; - the error i get is invalid operation: syntax error at or near ;
CREATE OR REPLACE PROCEDURE risk.proc_test1(p_1 varchar)
LANGUAGE plpgsql
AS $$
DECLARE
V_TEST integer := 0;
BEGIN
select count(*)
from risk.mytab
into V_TEST
WHERE X =P_1;
RAISE NOTICE 'COUNT IS:(%)',V_TEST;
EXCEPTION
WHEN OTHERS THEN
RAISE;
END;
$$
;
call proc_test1(p_1 => 'x')
Are you asking about the syntax of calls, or are you asking about named parameters?
The doc doesn't mention it so no it isn't supported.
https://docs.aws.amazon.com/redshift/latest/dg/r_CALL_procedure.html
I guess with regards to the RAISE error, you are missing required parameters
https://docs.aws.amazon.com/redshift/latest/dg/c_PLpgSQL-statements.html#r_PLpgSQL-messages-errors
RAISE level 'format' [, variable [, ...]];
All of these things are in the documentation.
My goal is to create a stored procedure that loops through a select statement that will identify tables requiring a vacuum. I will call it from Lambda if I can get it to work. These are my ideas and code so far.
CREATE OR REPLACE PROCEDURE vac_an (rs_out INOUT refcursor)
AS $$
BEGIN
OPEN rs_out FOR SELECT 'VACUUM FULL ' + "schema" + '.' + "table" + ';' AS command
FROM svv_table_info
WHERE (unsorted > 5 OR empty > 5)
AND size < 716800;
END;
$$ LANGUAGE plpgsql;
This is a start. It compiles, but it would not execute the actual command that the cursor builds, which is:
VACUUM FULL SCHEMA.TABLE;
I guess I could call it with this:
CALL sample_cursor_test ();
My second line of thinking was something like this:
CREATE PROCEDURE vac_an()
AS $$
DECLARE
tlist RECORD;
BEGIN
FOR tlist IN EXECUTE 'SELECT 'VACUUM FULL ' + "schema" + '.' + "table" + ';' AS command FROM svv_table_info WHERE (unsorted > 5 OR empty > 5) AND size < 716800;'
LOOP
EXECUTE tlist;
END LOOP;
END;
$$ LANGUAGE plpgsql;
However that gives me :
ERROR: missing "LOOP" at end of SQL expression
Where: compile of PL/pgSQL function "vac_an" near line 4
I feel like the code is almost there I just need to loop through this cursor:
SELECT 'VACUUM FULL ' + "schema" + '.' + "table" + ';' AS command
FROM svv_table_info
WHERE (unsorted > 5 OR empty > 5)
AND size < 716800;
And execute the output line by line.
Can you please help?
You cannot call VACUUM from within a transaction, which means you cannot call VACUUM from within a procedure, since a procedure is inherently a transaction.
I am trying to see if there is any way to remove carriage and new lines from all the varchar columns in a table using one statement.
I know that we can do this for a single column using something like below
select regexp_replace(field, E'[\\n\\r]+', ' ', 'g' )
In that case I need have one for every column, which I don't want to do unless there is any easy way.
Appreciate your help!
You can do this either creating a plpgsql function to execute dynamic SQL, or directly run it via DO, as the following example (replace my_table with the name of your table`):
do $$declare _q text; _table text = '<mytable>';
begin
select 'update '||attrelid::regclass::text||E' set\n'||
string_agg(' '||quote_ident(attname)||$q$ = regexp_replace($q$||quote_ident(attname)||$q$, '[\n\r]+', ' ', 'g')$q$, E',\n' order by attnum)
into _q
from pg_attribute
where attnum > 0 and atttypid::regtype::text in ('text', 'varchar')
group by attrelid
having attrelid = _table::regclass;
raise notice E'Executing:\n\n%', _q;
-- uncomment this line when happy with the query:
-- execute _q;
end;$$;
in the following piece of code, I see that when my 'description' is something like:
" ' ' ", I have a problem updating the description to the sqlite record.
How do i handle the ' character. thanks!
sql = wxString::Format(
"UPDATE event SET event_description='%s' WHERE id=%d",
description.c_str(),
event_id);
rc = sqlite3_exec((sqlite3 *)_theDB, sql.c_str(), NULL, 0, &sqlError);
The OP answered his own question:
check this out FAQ we need to replace the occurences of ' with '' in the string
Doubling up all the single quotes in the description string is one way to do it. This way you can avoid malicious descriptions (see Bobby Tables).
' '
becomes:
'' ''
And more importantly, the potentially dangerous description:
' WHERE 1=1 DELETE FROM Event --
becomes the harmless:
'' WHERE 1=1 DELETE FROM Event --
Another (safer) way, is to use prepared statements.