FlywayException: Incomplete statement - stored-procedures

I can't get Flyway 7.7.3 to parse the HyperSQL CREATE PROCEDURE statement below. Though it used to work I guess, with an older version, as this is a 2018 script that I'm trying to resurrect.
CREATE PROCEDURE proc_findByLastname(IN name VARCHAR(30)) READS SQL DATA
DYNAMIC RESULT SETS 1
BEGIN ATOMIC
DECLARE persons_by_lastname_cursor CURSOR FOR
SELECT * FROM persons WHERE last_name = name;
OPEN persons_by_lastname_cursor;
END;
I unsuccessfully tried to inline the different lines, to get rid of the "DYNAMIC RESULT SETS 1" line, and couldn't understand what I read from inside the parser in step-by-step debug mode neither.
This is the complete trace :
Caused by: org.flywaydb.core.api.FlywayException: Unable to parse statement in db/migration/V2__procedure.sql at line 1 col 1. See https://flywaydb.org/documentation/knownparserlimitations for more information: Incomplete statement at line 1 col 1...
The referred limitations doesn't seem to apply: I tried to change the variable's name.
I also tried to change the delimiter, still no luck!
DELIMITER /;
CREATE PROCEDURE proc_findByLastname(IN lastname VARCHAR(30)) READS SQL DATA
DYNAMIC RESULT SETS 1
BEGIN ATOMIC
DECLARE persons_by_lastname_cursor CURSOR FOR
SELECT * FROM persons WHERE last_name = lastname;
OPEN persons_by_lastname_cursor;
END/;

Related

Can we execute list command or stored procedure inside a UDF or UDTF in snowflake?

Problem statement: we want to restrict the direct access to all the external STAGES to all the USER'S or DEVELOPER'S. We wanted these STAGES to be accessed through stored procedure or table UDF using LIST command.
We have following two working solutions :
Solution 1
Write a stored procedure and return a list command result set as single array or varchar with column delimiter (i.e. | ) and record delimiter (i.e. new line character)
Run view after calling above stored procedure using RESULT_SCAN(), LAST_QUERY_ID() and LATERAL SPLIT_TO_TABLE() functions to show the result as flattened row level output similar to original LIST command.
LIMITATIONS
As the view is using LAST_QUERY_ID and RESULT_SCAN functions its mandatory to call the SP before the select on view every time otherwise select on view will fail.
Solution 2
Write a stored procedure and create volatile table inside it to store the list command result.
Run the select query on the volatile table created from the above stored procedure.
Both above solutions are working fine for us but with stored procedure approach the result can't be seen as tabular format with a single call to the stored procedure. As snowflake doesn't supports PL/SQL function like "dbms_output.put_line()" .
It's always a 2-step solution.
Call stored procedure
View result from that stored procedure output using RESULT_SCAN(), LAST_QUERY_ID() functions or creating table inside the stored procedure and run query on the created table after stored procedure execution is complete.
Expected solution
We want to view the output of a stored procedure or UDF in a single call with similar representation like any other query output in Snowflake Web UI worksheets.
We want to know if there is any possibility to use LIST command in snowflake UDF or UDTF any LANGUAGE like SQL or JAVASCRIPT will work for us.
Or else if we can call a stored procedure (i.e. explained in above two solutions) inside a UDF this will also suffice our need.
Please let us know if there is any possible solution for the any of the above expected output.
I did not completely understand the requirement, but are you trying to do something like below
CREATE OR REPLACE PROCEDURE LIST_EXTERNAL_STAGE(stage_name varchar)
RETURNS VARIANT
LANGUAGE JAVASCRIPT
EXECUTE AS CALLER
AS
$$
var return_stage_rows = [];
var snowstmt = snowflake.createStatement({
sqlText: 'LIST '+ STAGE_NAME
});
var query_result = snowstmt.execute();
var end_of_table = snowstmt.getRowCount();
var counter = 0;
while (counter <= end_of_table) {
query_result.next();
return_stage_rows.push(query_result.getColumnValue(1),query_result.getColumnValue(2),query_result.getColumnValue(3),query_result.getColumnValue(4))
counter += 1;
}
return return_stage_rows;
$$;
call LIST_EXTERNAL_STAGE('#EMPLOYEE_STAGE');

How to return Cursor as OUT parameter in DB2 for z/OS

I'm using DB2 for z/OS as my database. I have written one stored procedure in DB2 where it will return some result set. Currently I have declared one cursor and calling OPEN Cur at the end of the stored procedure. I,m calling my procedure from Java and I'm getting the result set using ResultSet resultSet = callableStatement.getResultSet();My SP is working for few hundred records. But getting failed when table contains millions of data:
Caused by: com.ibm.db2.jcc.am.SqlException: DB2 SQL Error:
SQLCODE=-904, SQLSTATE=57011, SQLERRMC=00C90084;00000100;DB2-MANAGED
SPACE WITHOUT SECONDARY ALLOCATION OR US, DRIVER=4.24.92
I want to know
Is it possible to return Cursor as OUT parameter in my SP ?
What is the difference between taking data using OPEN curs way and CURSOR as OUT parameter ?
How to solve issue when data is huge ?
Will CURSOR as OUT parameter solve the issue ?
EDITED (SP detail):
DYNAMIC RESULT SET 1
P1: BEGIN
-- Declare cursor
DECLARE cursor1 CURSOR WITH RETURN FOR
select a.TABLE_A_ID as TABLE_A_ID,
b.TABLE_B_ID as TABLE_B_ID
from TABLE_A a
left join TABLE_C c on
a.TABLE_A_ID = c.TABLE_A_ID
inner join TABLE_B b on
b.CONTXT_ID = a.CONTXT_ID
AND b.CONTXT_POINT_ID = a.CONTXT_POINT_ID
AND b.CONTXT_ART_ID = a.CONTXT_ART_ID
where c.TABLE_A_ID is null ;
OPEN cursor1;
Refer to the documentation here for suggestions for handling this specific condition. Consider each suggestion.
Talk with your DBA for Z/OS and decide on the best course of action in your specific circumstances.
As we cannot see your stored-procedure source code, more than one option might exist, especially if the queries in the stored-procedures are unoptimised.
While usually it's easier to allocate more temporary space for the relevant tablespace(s) at the Db2-server end, that may simply temporarily mask the issue rather than fix it. But if the stored-procedure has poor design or unoptimised queries, then fix that first.
An SQL PL procedure can return a CURSOR as an output parameter, but that cursor is usable by the calling SQL PL code. It may not be usable by Java.
You ask "how to solve issue when data is huge", although you don't define in numbers the meaning of huge. It is a relative term. Code your SQL procedure properly, index every query in that procedure properly and verify the access plans carefully. Return the smallest possible number of rows and columns in the result-set.

SAP HANA Stored Procedure output types and how to reuse / capture output in SQLScript

In SAP HANA i can create a procedure with in and output parameters. Even without output parameter the procedure can output a table.
I notice three versions of output in stored procedures:
a select at the end of the procedure - without declaring the structure.
an output parameter out parameter varhcar(100)
an implicit table definition returns table (var1 varchar(10)) after function parameter and before keyword LANGUAGE SQLSCRIPT
What is the difference of these and how can I reuse each of these output parameters in other stored procedures?
The only one I am aware of is
call procedure(input1, input1, outputVar)
Unfortunately I don't know how to bound an SQL result to output parameters without creating a physical table.
Reason for this question
Issue 1
Function callBuildJoinOn returns empty result. Due to that loop in SP_BUILD_JOIN_ON is not executed - but the list is build in split string (both tested)
Proceedure callBuildJoinOn
...
in colTable1 nvarchar(200)
out columnsTable1 "SCHEMA"."package::TT.STRING_LIST"
call "SCHEMA"."package::SP_SPLIT_STRING"(colTable1, columnsTable1);
call "SCHEMA"."package::SP_BUILD_JOIN_ON"(:columnsTable1, :columnsTable2, :joinOn);
SP_BUILD_JOIN_ON
columnsTable1 "SCHEMA"."package::TT.STRING_LIST"
declare cursor columnList for
select * from :columnsTable1;
for col as columnList do
joinOn := joinOn || 'a.' || col.item;
end for;
Why split in two functions?
Declare of cursor results in compiler error if after a call statement
There is even a fourth option to get to a result set from a HANA SQLScript procedure: the result view (not supported anymore as of HANA2).
But let's not stir up more confusion.
The different options can be used in different scenarios:
Procedure IN/OUT parameters are used to get data into and results out of procedures. The OUT parameters can either be bound to other SQLScript variables (when you call the procedure from another procedure), or a HANA client can read the result sets that get created for each OUT parameter of type TABLE). For example, a JDCB client would find multiple result sets after the procedure execution and would fetch those.
Table functions, that are functions that return a table, can be used just like tables or views:
SELECT * FROM <tablefunction>( in_param1, in_param2, ...);
This provides an easy option to read back whole tables from functions or to simulate parameterised views.
The remaining option you mentioned is the so-called "default result set". This really is only useful for consumption in the SQL editor or in a HANA client that fetches all result sets after procedure execution. The default result set cannot be bound to any SQLScript variable and cannot be referenced in SQL commands.
Problem was that joinOn was defined as output parameter: out joinOn nvarchar(1000)
this resulted that:
the variable was null
the variable was not populated: joinOn := joinOn || 'a.' || col.item; resulted in null !
Solution
Change out to inout
initialize parameter joinOn := ''

Calc field doesn't post

Hi I want to post calc field(cemi) to table (sql). when I calc all field the last field doesn't post on sql table. because last field (cemi) type fkcalc how can I post fkcalc type field to sql table Thanks in advance!
procedure TForm1.ADOQuery1CalcFields(DataSet: TDataSet);
begin
ADOQuery1.FieldValues['cemi']:=
((ADOQuery1.FieldValues['boyuk1'] + ADOQuery1.FieldValues['boyuk2'] +
ADOQuery1.FieldValues['boyuk3'])*0.35)+((ADOQuery1.FieldValues['kicik1'] +
ADOQuery1.FieldValues['kicik2'])*0.25) +(ADOQuery1.FieldValues['qara1']*0.30);
end;
I'm not quite sure what you mean by
the last field doesn't post on sql table
If the "last field" you are referring to is your "Cemi" one and that is a column which is in the table on your SQL Server, it will not get posted back there if you have defined it as a calculated field in your AdoQuery1 in the Object Inspector. Fields with a FieldKind of fkCalculated are local to the AdoQuery.
Just assigning a value to the calculated field is sufficient to "post" it locally to the AdoQuery, as I imagine you know. What you want to do to debug your problem (because readers like me cannot debug it fr you) is to more easily see what value, if any, is being assigned to it.
From that point of view, your code is suffering from "premature optimisation" which will make it difficult for you to see what is going wrong. Try this instead:
In your ADOQuery1CalcFields, declare a local variable for each of the fields you are accessing, including the calculated one. Choose the variable types to suit the fields:
var
Boyuk1 : Double; // or Integer, etc
[...]
Cemi : Double;
Assign values to the local variables, using the AsXXXX (type) of the fields:
Cemi := 0;
if not AdoQuery1.FieldByName('Boyuk1').IsNull then
Cemi := Cemi + AdoQuery1.FieldByName('Boyuk1').AsFloat;
[etc]
That way, at least you'll be able to see the point at which the calculation goes wrong (if it does).
I've used FieldByName().AsFloat, rather than FieldValues[], because FieldValues[] is a Variant, which can be Null, and you don't want that when you are assigning values to it which mat themselves be variants.
Also
Check that AutoCalcFields is set to True for AdoQuery1.
Put a debugger breakpoint on the first line of ADOQuery1CalcFields. Compile and run and check that the breakpoint hits - if it doesn't, there's your answer. Single-step the debugger through each line of the procedure, and, after the final line, use Ctrl-F7 to evaluate the value of AdoQuery1.FieldByName('Cemi').AsFloat.

How to view the content of a resultset in Toad from a stored procedure with unknown number of columns?

In Tsql I can execute a stored procedure in Query Analyzer and view the content of a resultset right there query analyzer window without know anything about the query structure (tables, columns, ...)
--Tsql sample
exec myproc parm1, parm2, parm3
Now I am working with PLsql and Toad (which I am relatively new at for Toad). I need to view the content of a resultset of a convoluted stored procedure, and I don't know what the number of columns is -- let alone their data types (this proc is composed of several freaky subqueries -- which I can view individually, but they get pivoted, and the number of columns varies in the final resultset). How can I view the content of this resultset in Toad when I execute the procedure when I don't know how many columns there are or their data types?
Below is code that I have mustered together for viewing the content of a result set of stored procedures where I know how many columns there are and their data types ahead of time. In my code sample below I use a sys_refcursor that I named x_out and I also create a temporary table to store the content of the resultset for additional viewing. Is there a way I can do this when I don't know how many columns there are in the resultset? How to do this with PLsql -- Toad?
create global temporary table tmpResult (fld1 number, fld2 varchar(50), fld3 date);
declare
x_out sys_refcursor;
tmpfld1 number;
tmpfld2 varchar2(50);
tmpfld3 date;
BEGIN
myschema.mypkg.myproc(parm1, parm2, x_out);
LOOP
FETCH x_out INTO tmpfld1, tmpfld2, tmpfld3;
DBMS_OUTPUT.Put_Line ('fld1:-- '||tmpfld1||': fld2:-- '||tmpfld2||': fld3:-- '||tmpfld3);
-- I also insert the result set to a temp table for additional viewing of the data from the stored procedure
Insert Into tmpResult values(tmpfld1, tmpfld2, tmpfld3);
EXIT WHEN x_out%NOTFOUND;
END LOOP;
END;
Toad can automatically retrieve the cursor for you. You have a few options, #3 perhaps is the easiest if you just want to see the data.
If you have the myschema.mypkg loaded in the Editor you can hit F11 to execute it. In the dialog that shows select your package member to the left and select the Output Options tab. Check the option to fetch cursor results or use the DBMS Output options. Click OK and the package executes. Depending on your Toad version you'll see a grid at the bottom of Editor for your results or you'll see a PL/SQL results tab. If you see the latter double click the (CURSOR) value in the output column for your output argument. I suggest using the fetch option as long as your dataset isn't so large that it will cause Out of Memory errors.
Locate your package in the Schema Browser and rt-click, Execute Package. You'll see the same dialog as mentioned in #1. Follow the remaining steps there.
Use a bind variable from an anonymous block. Using your example you'd want something like this...
declare
x_out sys_refcursor;
begin
myschema.mypkg.myproc(parm1, parm2, x_out);
:retval := x_out;
end;
Execute this with F9 in the Editor. In the Bind Variable popup set the datatype of retval to Cursor. Click OK. Your results are then shown in the data grid. Again if your dataset is very large you may run out of memory here.
StackOverflow not letting me post this other solution:
I try posting part of this other solution (if SOF lets me) - this the 2nd half of the other way:
BEGIN
myschema.mypkg.myproc(parm1, parm2, parm3 x_out);
FOR rec_ IN get_columns LOOP
DBMS_OUTPUT.put_line(rec_.name || ': ' || rec_.VALUE);
END LOOP;
END;
and here is the 1st half of the other way:
DECLARE
x_out SYS_REFCURSOR;
CURSOR get_columns IS
...
You should bind the cursor to ":data_grid" in order to show SP result in Toad Data Grid pane.
Call Store Procedure in PL/SQL Script:
Run with F9 not F5
Toad is the best I know when it comes to DB IDE.
Press "F9" and bind it. That is all

Resources