I am looking to create a procedure that returns another stored procedure DLL by its name but do not know how to do it exactly. Here is what I have tried so far:
example output
SET TERM ^ ;
CREATE or ALTER PROCEDURE MY_REPORTS (
objid my_id)
returns (
docdate my_datetime)
as
begin
some body
end^
SET TERM ; ^
Your advice is highly appreciated.
You need access to "System Tables" like RDB$PROCEDURES and RDB$PROCEDURE_PARAMETERS.
select p.RDB$PROCEDURE_NAME, p.RDB$PROCEDURE_SOURCE, pr.RDB$PARAMETER_NAME,
pr.RDB$PARAMETER_TYPE, iif(pr.RDB$PARAMETER_TYPE=0,'INPUT','OUTPUT') PARAM_TYPE
from RDB$PROCEDURES p
left join RDB$PROCEDURE_PARAMETERS pr on p.RDB$PROCEDURE_NAME=pr.RDB$PROCEDURE_NAME
where p.RDB$PROCEDURE_NAME='CALCULAVTO'
order by pr.RDB$PARAMETER_TYPE, pr.RDB$PARAMETER_NUMBER
Related
I have a query that is dynamically set up with a parameter.
I query for lines with a varchar field that contains values that can begin with a '!'.
But I get no match of those.
I use SQLServer as the database server.
If I take the sqlcode and run it directly in the database manager it works but not with TFDQuery.
Se the code example below:
myParameter := '!Tommy';
with qryExec do
begin
SQL.Clear ;
SQL.Add('SELECT * FROM myTable T WHERE T.Name='+quotedStr(myParameter));
active := true ;
first;
if Not Eof then
begin
Result := True;
end;
end; //with
I have no idea what's wrong here, so I would be happy if anyone could come with an explanation.
I would suggest using actual parameters which also avoids the possibility of SQL injection. There are also overloaded versions of Open that reduce the housekeeping lines.
FDQuery1.Open('SELECT * FROM myTable T WHERE T.Name= :NAME',['!Tommy'],[ftWideString]);
I'm trying to determine the line in a stored procedure or the last SQL-statement which is causing an error. As a workaround I'm using temporary variables which I manually set to determine in which part of my stored procedure an error occurs.
See the following:
-- Create an ErrorLog table
Create Table SCHEMA.ErrorLog_lrc_test
(
ErrSQLCODE Integer ,
Codepart Char(1),
Type Char(1) ,
MsgText VarChar(1024));
CREATE OR REPLACE PROCEDURE SCHEMA.test_error(IN divisor INT)
LANGUAGE SQL
BEGIN
-- Define variables
DECLARE codepart_var Char(1);
DECLARE test_INT INT;
-- Define sqlcode
DECLARE SQLCODE INTEGER;
--Define Error-Handler
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
INSERT INTO SCHEMA.ErrorLog_lrc_test(ErrSQLCODE, Codepart, TYPE, MsgText)
VALUES(SQLCODE, codepart_var, 'E', SYSPROC.SQLERRM(SQLCODE));
END;
--Define Warning-Handler
DECLARE CONTINUE HANDLER FOR SQLWARNING, NOT FOUND
BEGIN
INSERT INTO SCHEMA.ErrorLog_lrc_test(ErrSQLCODE, Codepart, TYPE, MsgText)
VALUES(SQLCODE, codepart_var, 'W', SYSPROC.SQLERRM(SQLCODE));
END;
-- Set temporary variable to 'a' to get part of code where error occured
SET codepart_var = 'a';
-- Create Error
sELECT 1/divisor into test_INT
FROM SYSIBM.SYSDUMMY1;
SET codepart_var = 'b';
-- Create Error
sELECT 1/divisor into test_INT
FROM SYSIBM.SYSDUMMY1;
SET codepart_var = 'c';
-- Create Not Found (Sqlcode 100)
INSERT INTO SCHEMA.ErrorLog_lrc_test
SELECT NULL, NULL, NULL, NULL FROM "SYSIBM".SYSDUMMY1
WHERE 1 = 0 ;
END
call SCHEMA.test_error(0);
SELECT *
FROM SCHEMA.ErrorLog_lrc_test;
I get the following:
ERRSQLCODE
CODEPART
TYPE
MSGTEXT
-801
a
E
SQL0801N Division by zero was attempted.
-801
b
E
SQL0801N Division by zero was attempted.
100
c
W
SQL0100W No row was found for FETCH, UPDATE or DELETE; or the result of a query is an empty table.
So I am able to get the part of the code where an error or warning occurs, but it would be better to get the line or the SQL statement as I don't want to specify every part of the code with a temporary variable.
I already found this SQLCA --> sqlerrd(3): "...If an error is encountered during the compilation of an SQL routine, trigger, or dynamic compound SQL (inlined or compiled) statement, sqlerrd(3) contains the line number where the error was encountered". For now I didn't manage to make use of SQLCA variables. I don't know how to implement them in DB2 LUW in a stored procedure.
Is there another/better way to log the specific line or SQL-statement in a stored procedure which is causing an error?
My DB2 version is 10.5.0.
Thank you!
If your Db2-server platform is Linux/Unix/Windows, and you are using a recent version, then consider using DBMS_UTILITY.FORMAT_ERROR_BACKTRACE which may help you.
Documentation here. The documentation includes a worked example.
When using this for stored procedures or routines, it is wise to always create those routines with a meaningful specific name with the SPECIFIC clause on the create or replace statement. Otherwise the routine will have a system generated name which will not be meaningful to users when it appears in the output of DBMS_UTILITY.FORMAT_ERROR_BACKTRACE. There are other reasons you should always use a specific name for your routines.
The SQLCA is for calling programs (i.e. the program that calls the stored procedure).
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''')
I am facing this error:
Compilation failed,line 3 (01:07:19)
PLS-00103: Encountered the symbol "," when expecting one of the
following: := ; not null default character
And my Procedure is:
create or replace procedure testing
as
v_ID NUMBER;v_ASSIGNEE_NAME varchar2(55),v_EMAIL varchar2(55),v_PHONE NUMBER;v_FIELD varchar2(50);
begin
select ID,ASSIGNEE_NAME,EMAIL,PHONE,FIELD into
v_ID NUMBER;v_ASSIGNEE_NAME varchar2(55),v_EMAIL varchar2(55),v_PHONE NUMBER;v_FIELD varchar2(50);
FROM ASSIGNEE;
Quite a number of issues in this, see formatted code below. In your declaration of variables you were separating them with a comma, this needs to be a semicolon. Also in your into clause you had included the variable types. The best thing you can do is to format your code so that is easier to read and debug.
create or replace procedure testing as
v_ID NUMBER;
v_ASSIGNEE_NAME varchar2(55);
v_EMAIL varchar2(55);
v_PHONE NUMBER;
v_FIELD varchar2(50);
begin
select ID,ASSIGNEE_NAME,EMAIL,PHONE,FIELD
into v_ID NUMBER, v_ASSIGNEE_NAME, v_EMAIL, v_PHONE NUMBER, v_FIELD
FROM ASSIGNEE;
end;
There were couple of syntactical errors which was preventing you from compiling your code. Below snippet will help you.
CREATE OR REPLACE PROCEDURE testing
AS
v_ID NUMBER;
v_ASSIGNEE_NAME VARCHAR2(55);
v_EMAIL VARCHAR2(55);
v_PHONE NUMBER;
v_FIELD VARCHAR2(50);
BEGIN
SELECT ID,
ASSIGNEE_NAME,
EMAIL,
PHONE,
FIELD
INTO v_ID,
v_ASSIGNEE_NAME,
v_EMAIL,
v_PHONE,
v_FIELD
FROM ASSIGNEE;
END;
Hi I have a requirement where I get list of values to a input parameter in PL/SQL procedure. The size of the input list varies which is dynamic. How to handle this requirement any help?
CREATE OR REPLACE PACKAGE PKG_TEST AS
TYPE X IS TABLE OF VARCHAR2(30);
PROCEDURE XYZ(Y IN X);
END PKG_TEST;
/
The type can be declared as "TABLE OF" OR "VARRAY(10)";
CREATE OR REPLACE PACKAGE BODY PKG_TEST AS
PROCEDURE XYZ(Y IN X) AS
BEGIN
FOR I IN Y.FIRST..Y.LAST
LOOP
DBMS_OUTPUT.PUT_LINE('THE VALUE OF I IS'||Y(I));
END LOOP;
END;
END PKG_TEST;
/
DECLARE
BEGIN
PKG_TEST.XYZ('1','2','3','4');
END;
/
You could use a varchar parameter in sql, each value must be separated by a comma, something like this:
'value1,value2,value3,value4,...,'
So, you can read the values using the function split of sql
I hope that I understood your question