I want to add the value of a variable to the error text, but got an error due to syntax.
DECLARE VALUE VARCHAR;
--doing some checks
SIGNAL SQLSTATE '99'
SET MESSAGE_TEXT = 'Value is not valid: ''' || VALUE || ''';
{0:0} An unexpected token "|| ''" was found following "valid'". Expected tokens may include: "".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.28.11
The SIGNAL statement supports either a string constant or a string variable in the right part of the SET statement as described in the documentation. No expressions are allowed there.
BEGIN
DECLARE V_VALUE VARCHAR (20) DEFAULT 'SOME VALUE';
DECLARE V_MSG VARCHAR (70);
SET V_MSG = 'Value is not valid: ''' || V_VALUE || '''';
SIGNAL SQLSTATE '75099' SET MESSAGE_TEXT = V_MSG;
END#
Related
I am creating one stored procedure loading data from one DB to another DB using Netezza sql stored proc but getting one weird error. I tried all possibilities but couldn't fix this.
ERROR: CLI execute error: NOTICE: plpgsql: ERROR during compile of SP_data_load near line 1 : ERROR: syntax
error, unexpected , expecting BEGIN at or near ":"
stored procedure beginning looks like below.
CREATE OR REPLACE PROCEDURE SP_data_load
(DATE,
CHARACTER VARYING (128),
BIGINT,
BIGINT)
RETURNS INTEGER
EXECUTE AS OWNER
LANGUAGE NZPLSQL
AS
BEGIN_PROC
DECLARE
p_procdt ALIAS FOR $1;
p_edh_db ALIAS FOR $2;
p_sas_ts ALIAS FOR $3;
p_count ALIAS FOR $4;
p_proc_name CONSTANT VARCHAR (128)
:= 'SP_data_load' ;
v_count BIGINT := 0;
p_raise_message VARCHAR (1024);
v_edh_db VARCHAR (128);
v_CalendarDay VARCHAR (8);
v_current_ts VARCHAR (20);
v_row_count BIGINT;
v_count_before_del BIGINT;
v_count_before_ins BIGINT;
v_count_after BIGINT;
BEGIN
AUTOCOMMIT OFF IF p_count IS NOT NULL THEN v_count : =
p_count;
END
I have this stored procedure :
CREATE OR REPLACE PROCEDURE SP_ObtenerSecuencialFactura(INOUT p_secuencial INT)
LANGUAGE PLPGSQL
AS
$$
BEGIN
SELECT MAX("CODIGOFACTURA") + 1 INTO p_secuencial FROM "FACTURA";
IF p_secuencial IS NULL THEN
p_secuencial := 1;
END IF;
END
$$
And the calling:
DECLARE secuencial INT;
CALL SP_ObtenerSecuencialFactura(secuencial);
RAISE NOTICE '%', secuencial;
But I get this error when I call that stored procedure:
ERROR: syntax error at or near "INT"
LINE 1: DECLARE secuencial INT;
What's wrong? I was finding examples but only exist with functions.
This is the solution:
DO
$$
DECLARE secuencial INT;
BEGIN
CALL SP_ObtenerSecuencialFactura(secuencial);
RAISE NOTICE '%', secuencial;
END
$$
NOTICE: 1
DO
Query returned successfully in 85 msec.
PostgreSQL use PL/pgSQL like Oracle with PL/SQL, so, to call a Store Procedure with OUTIN parameter, we need envolved the calling and the variable in Anonymous Block with "do" and "$$"
DO in PostgreSQL
I have a Stored Procedure with a input param, which is a multi valued parameter of Varchar.
The passed parameters are passed to the IN Clause of the query.
I am unable to figure out how to handle that in the stored procedure.
Till now , I have this (this is the snippet of the actual stored procedure) :
CREATE OR replace PROCEDURE <SCHEMA>.Some_Proc
(
IN V_INDSTRY_DESCRPTN VARCHAR (2000)
)
DYNAMIC RESULT SETS 1
BEGIN
DECLARE WHERE_CLAUSE VARCHAR(5000) DEFAULT '';
DECLARE OUTER_CLAUSE VARCHAR(2000) DEFAULT '';
DECLARE V_SQL VARCHAR(10000) DEFAULT '';
DECLARE CSR_RSLT_SET CURSOR WITH RETURN FOR S1;
IF (V_INDSTRY_DESCRPTN != 'ALL') THEN
SET WHERE_CLAUSE = WHERE_CLAUSE || 'AND industry.INDSTRY_DESCRPTN in ( '''||V_INDSTRY_DESCRPTN||''')' ;
END IF;
SET V_SQL ='<SOME QUERY>'
/*some other logic goes here*/
PREPARE S1 FROM V_SQL;
OPEN CSR_RSLT_SET;
END
I am calling the procedure like this :
CALL <SCHEMA>.Some_Proc ('industry1')
1)how do I send multiple values in the same parameter?
CALL <SCHEMA>.Some_Proc ("'industry1','industry2'") gives a compilation error
2)how do I handle the multi-valued parameter within the procedure.
Try this as is:
--#SET TERMINATOR #
CREATE OR REPLACE PROCEDURE TEST_MULTIVALUE(P_TABSCHEMAS VARCHAR(128))
DYNAMIC RESULT SETS 1
BEGIN
DECLARE L_STMT VARCHAR(200);
DECLARE C1 CURSOR WITH RETURN FOR S1;
SET L_STMT = 'SELECT TABSCHEMA, TABNAME FROM SYSCAT.TABLES WHERE TABSCHEMA IN ('||P_TABSCHEMAS||')';
CALL DBMS_OUTPUT.PUT_LINE(L_STMT);
PREPARE S1 FROM L_STMT;
OPEN C1;
END#
SET SERVEROUTPUT ON#
CALL TEST_MULTIVALUE('''SYSCAT''')#
CALL TEST_MULTIVALUE('''SYSCAT'', ''SYSSTAT''')#
For those who are afraid of sql injections
We tokenize the input parameter with strings separated by comma producing a table of strings.
CREATE OR REPLACE PROCEDURE TEST_MULTIVALUE_STATIC(P_TABSCHEMAS VARCHAR(128))
DYNAMIC RESULT SETS 1
BEGIN
DECLARE C1 CURSOR WITH RETURN FOR
SELECT TABSCHEMA, TABNAME
FROM SYSCAT.TABLES T
WHERE EXISTS
(
SELECT 1
FROM XMLTABLE
(
'for $id in tokenize($s, "\s*,\s*") return <i>{string($id)}</i>'
passing P_TABSCHEMAS as "s"
COLUMNS
TOK VARCHAR(128) PATH '.'
) P
WHERE P.TOK=T.TABSCHEMA
);
OPEN C1;
END
#
CALL TEST_MULTIVALUE_STATIC('SYSCAT')#
CALL TEST_MULTIVALUE_STATIC('SYSCAT, SYSSTAT')#
I guess your question actually is, how to escape single quotes inside a character literal (surrounded by single quotes) in the standard-compliant SQL. The answer is, by doubling them:
CALL <SCHEMA>.Some_Proc ('''industry1'',''industry2''')
Getting following error while assigning value to declared clob variable in stored procedure. Same thing works when I run query on SQL Developer.
This is the query which currently I'm using in my stored procedure:
SELECT
RTRIM(XMLAGG(XMLELEMENT(E, col1, chr(10)).EXTRACT('//text()')).GetClobVal(),',')
INTO CLOB_VAR
FROM Table1**
I don't understand why it causes an error like numeric or value error.
Error report -
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at "XXXXXX.TMP_STORED_PROC", line 39
ORA-06512: at line 1
06502. 00000 - "PL/SQL: numeric or value error%s"
*Cause: An arithmetic, numeric, string, conversion, or constraint error
occurred. For example, this error occurs if an attempt is made to
assign the value NULL to a variable declared NOT NULL, or if an
attempt is made to assign an integer larger than 99 to a variable
declared NUMBER(2).
*Action: Change the data, how it is manipulated, or how it is declared so
that values do not violate constraints.
Stored procedure:
create or replace PROCEDURE TMP_STORE_PROC () IS
CLOB_TEXT CLOB;
start_timestamp TIMESTAMP WITH TIME ZONE := SYSTIMESTAMP;
ERR_CODE VARCHAR2(20);
ERR_MSG VARCHAR2(500);
BEGIN
SAVEPOINT startTransaction;
SELECT RTRIM(XMLAGG(XMLELEMENT(E, col1, chr(10)).EXTRACT('//text()')).GetClobVal(),',') INTO CLOB_TEXT FROM Table1
DBMS_OUTPUT.PUT_LINE('################ String length -- '||TO_CHAR(CLOB_TEXT));
COMMIT;
NULL;
EXCEPTION
WHEN OTHERS THEN
ERR_CODE := SQLCODE;
ERR_MSG := SQLERRM;
DBMS_OUTPUT.PUT_LINE('Stored procedure failed in execution. Error Message : '||ERR_CODE||' -- MSG -- '||ERR_MSG);
ROLLBACK TO startTransaction;
RAISE;
END;
Replace
DBMS_OUTPUT.PUT_LINE('################ String length -- '||TO_CHAR(CLOB_TEXT));
with the following
DBMS_OUTPUT.put_line ( '################ String length -- ' || length(clob_text));
Procedure
CREATE OR REPLACE PROCEDURE tmp_store_proc
IS
clob_text CLOB;
start_timestamp TIMESTAMP WITH TIME ZONE := SYSTIMESTAMP;
err_code VARCHAR2 (20);
err_msg VARCHAR2 (500);
BEGIN
SAVEPOINT starttransaction;
SELECT RTRIM (
XMLAGG (XMLELEMENT (e, col1, CHR (10)).EXTRACT ('//text()')).getclobval (),
',')
INTO clob_text
FROM table1;
DBMS_OUTPUT.put_line (
'################ String length -- ' || LENGTH (clob_text));
COMMIT;
NULL;
EXCEPTION
WHEN OTHERS
THEN
err_code := SQLCODE;
err_msg := SQLERRM;
DBMS_OUTPUT.put_line (
'Stored procedure failed in execution. Error Message : '
|| err_code
|| ' -- MSG -- '
|| err_msg);
ROLLBACK TO starttransaction;
RAISE;
END;
Execute the procedure by
exec tmp_store_proc
Output
########## String length -- 18224744
If you would like to print CLOB, then have a look at this
I have defined a variable
define myStrings = "'abc','def'"
which I later need to use inside a procedure block and convert into a table of varchars
declare
type varcharListType is table of varchar(200);
myList varcharListType;
begin
myList := varcharListType(&myStrings);
.
.
.
end;
/
I am attempting to use either the variable or the table inside an IN clause in a create query within the procedure block
execute immediate 'create table tmp_foo '
|| 'as select * from bar '
|| 'where bar_val in (&myStrings) ';
I have tried using the REPLACE function also
myNewStrings := replace(&myStrings, '''' , '''''');
but I get an exception related to abc and def not being defined.
ISSUE:
I am getting a syntax exception because the quotes around abc and def in myString are not escaped. The value "'abc','def'" must be 'defined' rather then 'declared' so it is substituted later.
QUESTION:
Is it possible to 'define' a variable in such a way that I can use it both as table type values and also a string in the execute immediate statement?
TO REPRODUCE:
Create
create table bar (bar_id number not null, bar_val varchar2(20),
constraint bar_pk primary key (bar_id)
enable
);
Insert
insert into bar (bar_id, bar_val)
values (1, 'abc'),
(2, 'def'),
(3, 'ghi');
SAMPLE PROCEDURE
set verify off;
set serveroutput on;
define myStrings = "'abc','def'"
declare
type varcharListType is table of varchar(20);
myList varcharListType;
begin
myList := varcharListType(&myStrings);
execute immediate 'create table tmp_foo '
|| 'as select * from bar '
|| 'where bar_val in (&myStrings) ';
for i in myList.FIRST..myList.LAST loop
dbms_output.put_line('VALUE: ' || myList(i));
end loop;
end;
/
set serveroutput off;
set verify on;
The below is the approch I would take, Note the use of tablen in the loop, this is because the DBMS_UTILITY.COMMA_TO_TABLE procedure adds a null value at the end of the table.
Hope you find this helpfull
declare
myStrings varchar2(100) := '''abc'',''def''';
myList dbms_utility.uncl_array;
tablen number :=0;
begin
DBMS_UTILITY.COMMA_TO_TABLE ( replace(myStrings, '''', ''), tablen, myList);
execute immediate 'create table tmp_foo '
|| 'as select * from bar '
|| 'where bar_val in (' ||myStrings||')';
for i in myList.FIRST..tablen loop
dbms_output.put_line('VALUE: ' || myList(i));
end loop;
end;
/
Thanks to #ShaunPeterson for inspiring the solution to this issue. While it solve the issue directly it provided the correct approach so all +1s should go to him.
Where his answer fell short was that he 'declared' myStrings rather then 'defining' it.
declare
myStrings varchar2(100) := '''abc'',''def''';
NOT
define myStrings = "'abc','def'"
Herein lay the crux of the issue. In PL/SQL variables that are 'declared' for a procedure block like myStringsVar below are not substituted like 'defined' variables are. As per the OP the requirement was that 'myStrings' was first 'defined' then later transformed for use in a procedure block.
Therefore the resulting solution looks like this:
define myStrings = "''abc'',''def''"
declare
myStringsVar varchar2(100) := '&myStrings';
myList dbms_utility.uncl_array;
tablen number :=0;
begin
DBMS_UTILITY.COMMA_TO_TABLE ( replace(myStringsVar, '''', ''), tablen, myList);
execute immediate 'create table tmp_foo '
|| 'as select * from bar '
|| 'where bar_val in (' || myStringsVar||')';
for i in myList.FIRST..tablen loop
dbms_output.put_line('VALUE: ' || myList(i));
end loop;
end;
/