I want to form a SQL construct using a stored procedure which would have email_id passed as a variable i.e., "v_created_by" as one of the input parameter.
My code skeleton looks like :
create or replace procedure testing_proc(type varchar, ..., ..., ..., v_created_by varchar)
returns varchar not null
....,
....,
begin
wh_setup := 'CREATE OR REPLACE WAREHOUSE' || ' ' || wh_name || ' ' || 'WITH' || ' '
|| 'WAREHOUSE_SIZE = ' || v_wh_size || ' '
...
...
|| 'SCALING_POLICY= ' || 'STANDARD' || ' '
|| 'COMMENT=' || v_created_by;
execute immediate wh_setup;
return 'successfully created the warehouse :' || ' ' || wh_name;
end;
Whenever I am calling the proc like :
call testing_proc('STD','EDWQA','ANALYST','XSMALL','1','1',300,'somen.swain#GMAIL.COM')
I get the error as :
"Uncaught exception of type 'STATEMENT_ERROR' on line 15 at position 2 :
SQL compilation error: syntax error line 1 at position 199 unexpected '#GMAIL.COM'.
syntax error line 1 at position 199 unexpected '#GMAIL.COM'.
Reference SQL which I am trying to create via procedure is given below:
CREATE WAREHOUSE IF NOT EXISTS dbt_workload
WITH WAREHOUSE_SIZE = 'XSMALL'
WAREHOUSE_TYPE = 'STANDARD'
SCALING_POLICY = 'STANDARD'
COMMENT = '"created for testing"';
Please see the COMMENT keyword over here where it can be used as a tag.
Any pointers on how to address this to ensure I can use this email_id and pass it with comment section would really help.
The comment has to be wrapped with ' as it requires string literal:
COMMENT = '<string_literal>'
Instead:
|| 'COMMENT=' || v_created_by;
to:
|| 'COMMENT=''' || v_created_by || ''';
The input should be validated/trusted before passing it to be run.
Related
I have the need to capture the o/p of "execute immediate" statement and use that o/p variable in incremental steps execution of the proc.
Like the code is :
var_01 := 'SELECT COUNT(1) AS cnt FROM ALL_RESOURCE_MONITOR_MASTER WHERE' || ' '
|| 'account_name = ' ||''''|| lv_acct_name_new ||''''|| ' ' || 'AND' || ' '
|| 'rm_type= ' ||''''|| type || ''''||' ' || 'AND' || ' '
|| 'env= ' ||''''|| env || ''''||' ';
cnt := (execute immediate :var_01);
Now post I get the cnt as populated, then I need to run the below if~else statement:
if (cnt > 0) then
return 'execute the statement';
else
return 'Resource monitor already present hence insert skipped';
end if;
But the problem is when I try to execute this block I am always getting an error like :
SQL compilation error: Invalid expression value (?SqlExecuteImmediateDynamic?) for assignment.
Please do provide your inputs on resolving this. Thanks in advance!!
Unfortunately there is no syntax like EXECTUE <sql> INTO <output_variable_list> USING <input_variable_list> known from different dialects.
EXECUTE IMMEDIATE:
Executes a string that contains a SQL statement or a Snowflake Scripting statement.
EXECUTE IMMEDIATE '<string_literal>'
[ USING (bind_variable_1 [, bind_variable_2 ...] ) ] ;
In this scenario there is no need to use dynamic SQL for checking in metadata table as it could be rewritten to use parametrized if-statement:
CREATE OR REPLACE TABLE ALL_RESOURCE_MONITOR_MASTER
AS
SELECT 'acc1' AS account_name, 'TEST' AS env, 'WAREHOUSE' AS rm_type;
Code:
DECLARE
lv_acct_name_new TEXT := 'acc1';
type TEXT := 'WAREHOUSE';
env TEXT := 'TEST';
BEGIN
IF (EXISTS (SELECT 1
FROM ALL_RESOURCE_MONITOR_MASTER
WHERE account_name = :lv_acct_name_new
AND rm_type = :type
AND env = :env
)) THEN
RETURN 'Executing some code';
ELSE
RETURN 'Resource monitor already present hence insert skipped';
END IF;
END;
CREATE OR REPLACE FUNCTION f_old_transactions (IN p_fromdate date, IN p_todate date, IN p_transtype varchar,IN OUT p_cancelled boolean,
OUT p_transaction_date date,
OUT p_type varchar,
OUT p_description varchar,
OUT p_amount numeric)
RETURNS SETOF record AS
$BODY$
declare lRunQuery text;
declare lTotalRec record;
declare lBranchList text[];
declare lTranstype text[];
BEGIN
select into lTranstype
dt.type
from
v_data_types dt;
lTranstype := regexp_split_to_array(p_transtype, ',');
lrunquery := 'select
it.transaction_date trandate,
dt.type,
it.description,
ita.amount,
it.cancelled
from
import_transaction it
inner join import_transaction_account ita on it.import_transaction_id=ita.import_transaction_id
where
it.transaction_date >= ' || quote_literal(p_fromdate) || '
and it.transaction_date <= ' || quote_literal(p_todate) || '
and dt.type = any(' || quote_literall(p_transtype) || ') and';
if (p_cancelled = TRUE) then
lrunquery := lrunquery || '
it.cancelled = ' || quote_literal(p_cancelled) || '';
else
lrunquery := lrunquery || '
it.cancelled = ' || quote_literal(p_cancelled) || '';
end if;
FOR lTotalrec in
execute lRunQuery
LOOP
p_transaction_date := ltotalrec.trandate;
p_type :=ltotalrec.type;
p_description :=ltotalrec.description;
p_amount :=ltotalrec.amount;
p_cancelled := ltotalrec.cancelled;
return next;
END LOOP;
return ;
end;
$BODY$
LANGUAGE plpgsql IMMUTABLE
COST 100
ROWS 1000;
ALTER FUNCTION f_old_transactions(date,date,varchar,boolean) OWNER TO "CompuLoanPostgres";
select * from f_old_transactions ('01-Jan-2010','31-Dec-2018','Receipt Cash','FALSE')
I'm getting an error that my array value must start with "{". My array I'm trying to create is from a view v_data_type the view consist of only one column with a varchar type.
Can anyone please direct me where the issue in my code is?
Thank you in advance
I don't think you've given us enough information to know for certain what's going wrong. Notably, I have no idea what the tables should look like, either in schema or content. Without that, I can't build a test case in my own DB to debug.
That said, I noticed a couple things, specifically around the lTranstype variable:
You're assigning lTranstype twice. First you SELECT INTO it, and then you immediately assign it to a value unpacked from the p_transtype argument. It's not clear to me what you want in that variable.
When constructing your query later, you include and dt.type = any(' || quote_literall(p_transtype) || '). The problem is that p_transtype is a varchar argument, and you're trying to access it like an array. I suspect you want that to read and dt.type = any(' || quote_literall(lTranstype) || '), but I could be mistaken.
I'm guessing that your type error is coming from that second problem, but it seems like you need to reassess what the different variables in this function are intended for. Good luck.
I am writing a pl/sql procedure in oracle to send automatic email with multiple attachments for that i Wrote a process where i am using following logic :
TYPE attach_info IS RECORD (
attach_name VARCHAR2(100),
data_type VARCHAR2(100) DEFAULT 'text/plain',
attach_content BLOB DEFAULT NULL
);
TYPE array_attachments IS TABLE OF attach_info;
attachments array_attachments := array_attachments();
here I am defining type than like below define array size
attachments.extend(3);
and below code i retrieving attachment info and sent it for sending email
FOR i IN attachments.FIRST .. attachments.LAST
LOOP
-- Attach info
UTL_SMTP.write_raw_data(l_mail_conn, utl_raw.cast_to_raw('--' || l_boundary || UTL_TCP.crlf));
UTL_SMTP.write_raw_data(l_mail_conn, utl_raw.cast_to_raw('Content-Type: ' || attachments(i).data_type
|| ' name="'|| attachments(i).attach_name || '"' || UTL_TCP.crlf));
UTL_SMTP.write_data(l_mail_conn, 'Content-Transfer-Encoding: base64' || UTL_TCP.crlf);
UTL_SMTP.write_raw_data(l_mail_conn, utl_raw.cast_to_raw('Content-Disposition: attachment; filename="'
|| attachments(i).attach_name || '"' || UTL_TCP.crlf || UTL_TCP.crlf));
-- Attach body
FOR j IN 0 .. TRUNC((DBMS_LOB.getlength(attachments(i).attach_content) - 1 )/l_step) LOOP
UTL_SMTP.write_data(l_mail_conn, UTL_RAW.cast_to_varchar2(UTL_ENCODE.base64_encode(DBMS_LOB.substr(attachments(i).attach_content, l_step, j * l_step + 1))));
END LOOP;
UTL_SMTP.write_data(l_mail_conn, UTL_TCP.crlf || UTL_TCP.crlf);
END LOOP;
now i want to make this process as generic to I can use this process many place,
So My question is how can i define this type for attachment, how I populate then and how can I pass this array of attachments in process so i can send them.
You can use the type to create a parameter for a PLSQL function or procedure
procedure send(p_address varchar2,p_subject varchar2, p_attachments array_attachments)
Here is the section of code, I am using ' ' blah ' ' to escape single quotes but I guess its not working:
declare
my_func varchar2(20) :='test_func';
begin
execute immediate 'insert into TABLE_TEST (OUTPUT) select ' || my_func || ' from dual where TABLE_TEST.FUNCTION_NAME like ' 'VALIDATION1_%' ' ';
end;
I am getting the following error:
PLS-00103: Encountered the symbol "VALIDATION1_%" when expecting one of the following:
& = - + ; < / > at in is mod remainder not rem return
returning <an exponent (**)> <> or != or ~= >= <= <> and or
like like2 like4 likec between into using || bulk member
submultiset
The symbol "* was inserted before "VALIDATION1_%" to continue.
It looks like you are trying to escape the single quote with another single quote (which is good), but there is an extra space in between the two. That has to go.
Change
' from dual where TABLE_TEST.FUNCTION_NAME like ' 'VALIDATION1_%' ' '
to
' from dual where TABLE_TEST.FUNCTION_NAME like ''VALIDATION1_%'' '
In cases like this it's much simpler to use the new q syntax for literal strings, e.g.:
execute immediate 'insert into TABLE_TEST (OUTPUT) select ' || my_func ||
q[' from dual where TABLE_TEST.FUNCTION_NAME like 'VALIDATION1_%' ]';
I have a plpgsql function that executes a query, but when i put an array into it it wont parse it, at least it gives me this error:
[FAIL] syntax error at or near "{"
LINE 21: AND c.category_uuid != ANY({"c0857e20-111e-11e0-ac64-0800...
CONTEXT: PL/pgSQL function "get_membercategories" line 22 at FOR over EXECUTE statement
This is the complete line:
AND c.category_uuid != ANY({"c0857e20-111e-11e0-ac64-0800200c9a66"})
This is how my function looks
CREATE OR REPLACE FUNCTION get_membercategories(in_company_uuid uuid, in_parent_uuid uuid, in_start integer, in_limit integer, in_sortby character varying, in_order character varying, in_querystring character varying, IN in_excludestring UUID[], OUT out_status integer, OUT out_status_description character varying, OUT out_value character varying[]) RETURNS record
LANGUAGE plpgsql
AS $$
DECLARE
temp_record RECORD;
altered_parent_uuid UUID;
temp_out_value VARCHAR[];
temp_iterator INTEGER := 0;
temp_parent_uuidstring VARCHAR;
temp_excludestring VARCHAR := '';
BEGIN
IF in_parent_uuid IS NOT NULL THEN
temp_parent_uuidstring := 'AND c.parent_uuid = ''' || in_parent_uuid || '''';
ELSE
temp_parent_uuidstring := 'AND c.parent_uuid IS NULL';
END IF;
IF in_excludestring IS NOT NULL THEN
temp_excludestring := 'AND c.category_uuid != ANY(' || in_excludestring || ')';
END IF;
FOR temp_record IN EXECUTE '
SELECT
c.name,
c.category_uuid,
mc.password,
(
SELECT COUNT(*)
FROM
targetgroupusers tgu
WHERE
tgu.targetgroup_uuid = mc.targetgroup_uuid
) AS receivers
FROM
membercategories AS mc
LEFT JOIN
categories AS c
ON
mc.category_uuid = c.category_uuid
WHERE
c.isdeleted IS NULL
' || temp_excludestring || '
AND
mc.company_uuid = ''' || in_company_uuid || '''
' || in_querystring || '
' || temp_parent_uuidstring || '
ORDER BY
' || in_sortby || ' ' || in_order || '
OFFSET
' || in_start || '
LIMIT
' || in_limit
LOOP
temp_out_value[temp_iterator] = ARRAY[temp_record.category_uuid::VARCHAR(36), temp_record.name::CHARACTER VARYING, temp_record.receivers::CHARACTER VARYING, CASE WHEN temp_record.password IS NOT NULL THEN '1' ELSE '0' END];
temp_iterator = temp_iterator+1;
END LOOP;
out_status := 0;
out_status_description := 'Member categories successfully retrieved';
out_value := temp_out_value;
RETURN;
END$$;
I am clueless at this point, any help is very much appreciated!
Your problem is that the the array gets expanded to an invalid string (as you can see in the error message). The string representation of an array needs to be enclosed into single quotes again and then casted to the approriate array type:
The following should work:
IF in_excludestring IS NOT NULL THEN
temp_excludestring := 'AND c.category_uuid != ANY(''' || in_excludestring::varchar||'''::UUID[])';
END IF;
Note that in_excludestring is explicitely cast to a varchar to force the string representation of an array, enclosed in single quotes to satisfy the "array literal" syntax and then cast back to an UUID array.
The resulting string will look something like this:
category_uuid != ANY ( '{c0857e20-111e-11e0-ac64-0800200c9a66,7fffda0c-11c9-11e0-967c-a300aec7eb54}'::UUID[] )