What does this code line is doing - stored-procedures

In reference to my question,
Converting a big stored procedure into a view
In SP i have this code line,
#countCrates = COUNT(DISTINCT ISNULL(countCratesAddress, 'EMPTY')) , #FirstCrateAddres = MIN(countCratesAddress)
Not sure what it's doing or how to debug it.

Somewhere in the SP, this variable is assigned to some values or select "countCratesAddress".
Then its used.
The Breakdown is:
> #FirstCrateAddres = MIN(countCratesAddress).
** get minimum of countCratesAddress and assign to the variable '#FirstCrateAddres'
> COUNT(DISTINCT ISNULL(countCratesAddress, 'EMPTY')).
** if "countCratesAddress" is null, replace it with the word "EMPTY" then take the COUNT of
what comes back from the DISTINCT of "countCratesAddress"

Related

FlywayException: Incomplete statement

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/;

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.

Informix function returns without reason

So I have the following informix procedure
CREATE FUNCTION selectSollmandant(INOUT sollmandat SOLLMANDAT_ROW, inkassodatum INT8) RETURNING SMALLINT
DEFINE ret SMALLINT;
LET ret = 0;
trace "Entering select sollmandat " || sollmandat.vers_schein_nr;
PREPARE sollStmt FROM "SELECT s::SOLLMANDAT_ROW FROM sollmandat s WHERE vers_schein_nr = ? ORDER BY lfdnr desc";
DECLARE _sollmCsr CURSOR FOR sollStmt;
IF SQLCODE != 0 THEN
CALL print_to_proto("DECLARE letztZahlCsr " || SQLCODE);
RETURN 0;
END IF;
TRACE "log =========== 1";
OPEN _sollmCsr USING sollmandat.vers_schein_nr;
TRACE "log =========== 2" || SQLCODE;
IF SQLCODE != 0 THEN
TRACE "log =========== 3" || SQLCODE;
CALL print_to_proto("OPEN sollmandat " || SQLCODE);
RETURN 0;
END IF;
TRACE "sollmandant iban is =========== 4" || SQLCODE;
WHILE (1=1) LOOP .... end loop and return...
Problem is that my function returns before reaching the while loop and it never hits log2, log 3 or log 4.
Can you please help me? I don't see what I am missing.
Thanks for the help.
I managed to solve the issue, but before I get into how i did it I want to try and clarify what the above posted code means actually.
CLARIFICATION
Ok so the SOLLMANDAT_ROW is a ROW_TYPE that I defined (think of it a struct like data object for stored procedures). The above mentioned function is part of a big a big UDR and we use data row for easier data manipulation. The function should select some row out of my sollmadant table and store the row in my custom defined SOLLMANDAT_ROW.
In order to be able to store the selected rows in ROW_TYPES, the row must be explicilty casted to the that specific row type, hence the syntax SELECT s::SOLLMANDAT_ROW FROM....
ACTUAL SOLUTION
It turned out that the problem was cursor relate, you see , in the context in which i was running the function, the queried table was a synonym, and my code was breaking at the OPEN cursor statement. What I did in order to get pass the issue was to refer to my row data like this:
SELECT ROW([row colums gere ])::SOLLMANDAT_ROW [rest of select statement]
After making this change, the function is behaving as it should.
I don't really know why informix does not "like" the syntax of my first select when trying to store rows from synonym tables into specific custom row types. And if anybody can provide a explanation I would be very grateful.
I hope this post will be helpful to others, and I thank you for your time.

What does this SQL statement do in this Informix 4GL code?

I am missing something. Please can someone tell me how this works?
let rpt.chgkey = null
select cuschage.chgkey from cuschage where cuschage.cuschnum in
(select shtwrd_no from crbookid where
crbookid.book_no = rpt.book_no and crbookid.line_no <= 3)
let scratch = rpt.chgkey
call make_charge_section(scratch) returning rpt.chgkey
if rpt.chgkey is not null then
print
column 1, ESC, "(s0p12h0s3b4099T", ESC, "&a0.5R"
print
column 70, rpt.chgkey using "<<<<<<<<<"
end if
Hmmm...that SELECT statement is close to pointless. You normally* execute a SELECT statement to get data into variables, but there is no INTO clause to put the returned value into.
Given that the SELECT does nothing with rpt.chgkey, the value in scratch is NULL. The function make_charge_section is called with this value (NULL), and the result is saved in rpt.chgkey; the CALL is equivalent to:
LET rpt.chgkey = make_charge_section(scratch)
or you can do without the scratch variable and write:
LET rpt.chgkey = make_charge_section(rpt.chgkey)
(and you can do that with the CALL notation too).
Thereafter, you display some weird control sequence to your terminal — I'm not going to try and work out which terminal or what it does; are you sure you can't achieve the same effect with I4GL itself? And then you display the new (non-null) value of rpt.chgkey.
So, the big unknowns here are 'why is the SELECT statement written without an INTO clause', and 'what does make_charge_section() do when given a NULL value as input'?
* The 'abnormal' uses of a SELECT without INTO would depend on you detecting errors in the SQL. How that happens depends on what you've got the WHENEVER ERROR setting set to.

ISQL Perform instruction: after editadd editupdate of table vs. after add update of table

INFORMIX-SQL 7.3 Perform Screens:
According to documentation, in an "after editadd editupdate of table" control block, its instructions are executed before the row is added or updated to the table, whereas in an "after add update of table" control block, its instructions are executed after the row has been added or updated to the table. Supposedly, this would mean that any instructions which would alter values of field-tags linked to table.columns would not be committed to the table, but field-tags linked to displayonly fields will change?
However, when using "after add update of table", I placed instructions which alter values for field-tags linked to table.columns and their displayed and committed values also changed! I would have thought that an "after add update of table" would only alter displayonly fields.
TABLES
customer
transaction
branch
interest
dates
ATTRIBUTES
[...]
q = transaction.trx_type, INCLUDE=("E","C","V","P","T"), ...;
tb = transaction.trx_int_table,
LOOKUP f1 = ta_days1_f,
t1 = ta_days1_t,
i1 = ta_int1,
[...]
JOINING *interest.int_table, ...;
[...]
INSTRUCTIONS
customer MASTER OF transaction
transaction MASTER OF customer
delimiters ". ";
AFTER QUERY DISPLAY ADD UPDATE OF transaction
if z = "E" then let q = "E"
if z = "C" then let q = "C"
if z = "1" then let q = "E"
[...]
END
Is 'z' a column in the transaction table?
Is the trouble that the value in 'z' is causing a change in the value of 'q' (aka transaction.trx_type), and the modified value is being stored in the database?
Is the value in 'z' part of the transaction table?
Have you verified that the value in the DB is indeed changed - using the Query Language option or a simple (default) form?
It might look as if it is because the instruction is also used AFTER DISPLAY, so when the values are retrieved from the DB, the value displayed in 'q' would be the mapped values corresponding to the value stored in 'z'. You would have to inspect the raw data to hide that mapping.
If this is not the problem, please:
Amend the question to show where 'z' comes from.
Also describe exactly what you do and see.
Confirm that the data in the database, as opposed to on the screen, is amended.
Please can you see whether this table plus form behaves the same for you as it does for me?
Table Transaction
CREATE TABLE TRANSACTION
(
trx_id SERIAL NOT NULL,
trx_type CHAR(1) NOT NULL,
trx_last_type CHAR(1) NOT NULL,
trx_int_table INTEGER NOT NULL
);
Form
DATABASE stores
SCREEN SIZE 24 BY 80
{
trx_id [f000]
trx_type [q]
trx_last_type [z]
trx_int_table [f001 ]
}
END
TABLES
transaction
ATTRIBUTES
f000 = transaction.trx_id;
q = transaction.trx_type, UPSHIFT, AUTONEXT,
INCLUDE=("E","C","V","P","T");
z = transaction.trx_last_type, UPSHIFT, AUTONEXT,
INCLUDE=("E","C","V","P","T","1");
f001 = transaction.trx_int_table;
INSTRUCTIONS
AFTER ADD UPDATE DISPLAY QUERY OF transaction
IF z = "E" THEN LET q = "E"
IF z = "C" THEN LET q = "C"
IF z = "1" THEN LET q = "E"
END
Experiments
[The parenthesized number is automatically generated by IDS/Perform.]
Add a row with data (1), V, E, 23.
Observe that the display is: 1, E, E, 23.
Exit the form.
Observe that the data in the table is: 1, V, E, 23.
Reenter the form and query the data.
Update the data to: (1), T, T, 37.
Observe that the display is: 1, T, T, 37.
Exit the form.
Observe that the data in the table is: 1, T, T, 37.
Reenter the form and query the data.
Update the data to: (1), P, 1, 49
Observe that the display is: 1, E, 1, 49.
Exit the form.
Observe that the data in the table is: 1, P, 1, 49.
Reenter the form and query the data.
Observe that the display is: 1, E, 1, 49.
Choose 'Update', and observe that the display changes to: 1, P, 1, 49.
I did the 'Observe that the data in the table is' steps using:
sqlcmd -d stores -e 'select * from transaction'
This generated lines like these (reflecting different runs):
1|V|E|23
1|P|1|49
That is my SQLCMD program, not Microsoft's upstart of the same name. You can do more or less the same thing with DB-Access, except it is noisier (13 extraneous lines of output) and you would be best off writing the SELECT statement in a file and providing that as an argument:
$ echo "select * from transaction" > check.sql
$ dbaccess stores check
Database selected.
trx_id trx_type trx_last_type trx_int_table
1 P 1 49
1 row(s) retrieved.
Database closed.
$
Conclusions
This is what I observed on Solaris 10 (SPARC) using ISQL 7.50.FC1; it matches what the manual describes, and is also what I suggested in the original part of the answer might be the trouble - what you see on the form is not what is in the database (because of the INSTRUCTIONS section).
Do you see something different? If so, then there could be a bug in ISQL that has been fixed since. Technically, ISQL 7.30 is out of support, I believe. Can you upgrade to a more recent version than that? (I'm not sure whether 7.32 is still supported, but you should really upgrade to 7.50; the current release is 7.50.FC4.)
Transcribing commentary before deleting it:
Up to a point, it is good that you replicate my results. The bad news is that in the bigger form we have different behaviour. I hope that ISQL validates all limits - things like number of columns etc. However, there is a chance that they are not properly validated, given the bug, or maybe there is a separate problem that only shows with the larger form. So, you need to ensure you have a supported version of the product and that the problem reproduces in it. Ideally, you will have a smaller version of the table (or, at least, of the form) that shows the problem, and maybe a still smaller (but not quite as small as my example) version that shows the absence of the problem.
With the test case (table schema and Perform screen that shows the problem) in hand, you can then go to IBM Tech Support with "Look - this works correctly when the form is small; and look, it works incorrectly when the form is large". The bug should then be trackable. You will need to include instructions on how to reproduce the bug similar to those I gave you. And there is no problem with running two forms - one simple and one more complex and displaying the bug - in parallel to show how the data is stored vs displayed. You could describe the steps in terms of 'Form A' and 'Form B', with Form A being Absolutely OK and Form B being Believed to be Buggy. So, add a record with certain values in Form B; show what is displayed in Form B after; show what is stored in the database in Form A after too; show that they are not different when they should be.
Please bear in mind that those who will be fixing the issue have less experience with the product than either you or me - so keep it as simple as possible. Remove as many attributes as you can; leave comments to identify data types etc.

Resources