Simple teradata stored procedure - stored-procedures

The web seems a bit short on working examples for something that should be quite common. A plain Jane example of "Get me some records". This is my first ever Stored proc and all I want is to see some records. Why is that so flipping hard? ;-) I figure that if I can get one example that works, I can tune it from there into something I can really use. This is taken from another example I found on the web. Doesn't compile because CURSOR declaration is a syntax error of some sort.
CREATE PROCEDURE "SCHEMA"."GETRESULTSET (
IN "p1" VARCHAR(30))
DYNAMIC RESULT SETS 1
BEGIN
DECLARE CURSOR cur1 WITH RETURN ONLY TO CLIENT FOR
SELECT partitioninfo FROM SCHEMA.SessionInfo where username = p1;
OPEN cur1;
END;
Anyway, sure could use a clue. I saw an example where the CURSOR was declared separately from the SQL but then there wasn't an example that showed how to get the variable into the SQL when it was declared as a VARCHAR. The example I am working off of was pretty old but it's the best I could find.

A Teradata MACRO would be a better solution for what you have described.
REPLACE MACRO [MyDB].GetResultSet(p1 VARCHAR(30)) AS (
SELECT "Partition"
FROM DBC.SessionInfo
WHERE UserName = :p1;
);
EXEC MyDB.GetResultSet
While a stored procedure could be used to accomplish the task cursor based logic used in other popular database systems (Oracle, SQL Server, etc.) can lead to bad programming habits in Teradata. Generally, processing large cursors in Teradata degrades performance. Many things that you have have used cursor for in other DBMS' are better served to be done with SET based logic where possible.
That being said cursors can be used successfully in Teradata to perform certain tasks that require conditional logic or dynamic SQL processing. I hope this helps and if you have a more concrete example you need help with I'd be happy to offer some suggestions.
Edit:
This DDL for your procedure works against Teradata 13.10:
CREATE PROCEDURE "SCHEMA"."GETRESULTSET" (
IN "p1" VARCHAR(30))
DYNAMIC RESULT SETS 1
BEGIN
DECLARE cur1 CURSOR WITH RETURN ONLY TO CLIENT FOR
SELECT "Partition" FROM "SCHEMA".SessionInfo where username = p1;
OPEN cur1;
END;
The cursor name has to proceed the CURSOR key word. PartitionInfo is not a valid column on DBC.SessionInfo. Not sure if "Schema" gets replaced by MyBatis or not, so you may have to tweak the SELECT statement.

Related

How to have optional OUTPUT parameter

I have a dynamic stored procedure, which I'm using to run multiple select queries. I have defined something like below.
CREATE PROCEDURE DYNAMIC
(IN IN_COLUMN1 VARCHAR(150),
IN IN_COLUMN2 VARCHAR(500),
IN IN_COLUMN3 VARCHAR(500),
IN IN_COLUMN4 CHAR(08),
IN IN_COLUMN5 DATE,
IN IN_COLUMN6 CHAR(05),
OUT OUT_COLUMN1 CHAR(01),
OUT OUT_COLUMN2 DEC(4,0),
OUT OUT_COLUMN3 DEC(4,0),
OUT OUT_COLUMN4 CHAR(04),
OUT OUT_COLUMN5 DATE
The problem here, when I run Query1, I will have input passed from COBOL DB2 program in IN_COLUMN1,IN_COLUMN2,IN_COLUMN3 and OUTPUT will be fetched into OUT_COLUMN1. I will initialize all INPUT in program, Due to the other OUTPUT parameters like OUT_COLUMN2,OUT_COLUMN3,OUT_COLUMN4 and OUT_COLUMN5 will have null, I'm getting SQLCODE "-305".
To fix this I tried to set OUTPUT parameters to default like below and got error while deploying.
OUT OUT_COLUMN2 DEC(4,0) DEFAULT NULL,
Is there any way to handle this. I'm using COBOL to call the stored procedure running in DB2.
Assuming IBM Enterprise COBOL,
To handle null values in COBOL host variables in SQL you need to assign a "null indicator" for each nullable variable.
See: Using host variables in SQL Statements (with examples in COBOL).
The null indicator will typically be negative if the result variable is null.
By default, all parameters to a DB2 for z/OS Native SQL Stored Procedure are nullable. (Db2 for z/OS 12.0.0 - Creating Native SQL Procedures)
For other ways of solving what I perceive is the task at hand,
Whilst I think at least DB2 User-defined Functions may support function overloading, stored procedures does not. That could have been an alternative.
Otherwise might I suggest returning a dynamic result set from your stored procedure? Then it would be up to the caller of the stored procedure to handle different configurations of the result sets, which is totally doable in COBOL.
Regarding UDF Overloading:
"A schema can contain several functions that have the same name but each of which have a different number of parameters or parameters with different data types. Also, a function with the same name, number of parameters, and types of parameters can exist in multiple schemas."
https://www.ibm.com/support/knowledgecenter/SSEPEK_11.0.0/sqlref/src/tpc/db2z_functionresolution.html
Hope it was to some help.

Reading COBOL code with .NET to generate a call graph

I am working on a project to automate COBOL to generate a class diagram. I am developing using a .NET console application. I need help tracking down the procedure name where the perform statement in used in the below example.
**Z-POST-COPYRIGHT.
move 0 to RETURN-CODE
perform Z-WRITE-FILE**
How do I track the procedure name 'Z-Post-COPYRIGHT' where the procedure 'Z-write-file' is called? The only idea I could think of in terms of COBOL is through indentation as the procedure names are always indented. Ideally in the database, the code should track the procedure name after the word 'perform' and procedure under which it is called (in this case it is Z-POST-COPYRIGHT).
I assume you want to do this "on your own" without external tools (a faster approach can be found at the end).
You first have to "know" your source:
which compiler was it compiled with (get a manual for this compiler)
which options were used
Then you have to preparse the source:
include copybooks (doing the given REPLACING rules if any)
if the source is in free-form reference format: concatenate contents of last line and current line if you find a - in column 7
check for REPLACE and change the result accordingly
remove all comments (maybe only * and \ in column 7 in fixed-form reference format or similar (extensions like "variable" format / "terminal" format", ... exist, maybe only inline comments - when in free-form reference-format, otherwise maybe inline comments *> or compiler specific extensions like |) - depending on the further re-engineering you want to do it could be a good idea to extract them and store them at least with a line number reference
The you finally can track the procedure name with the following rule:
go backwards to the last separator period (there are more rules but the rule "at least one line break, another period, a space a comma or a semicolon" [I've never seen the last two in real code but it is possible" should be enough)
check if there is only one word between this separator period and the next
if this word is no reserved COBOL word (this depends on your compiler) it is very likely a procedure name
Start from here and check the output, then fine grade the rule with actual false positives or missing entries.
If you want to do more than only extract the procedure-names for PERFORM and GO TO (you should at least check the sources for PERFROM ... THRU) then this can get to a lot of work...
Faster approach with external tools:
run a COBOL compiler on the complete sources and tell it to do the preparsing only - this way you have the big second point solved already
if you have the option: tell the compiler or an external tool to create a symbol table / cross reference - this will tell you in which line a procedure is and its name (you can simply find the correct procedure by comparing the line)
Just a note: You may want to check GnuCOBOL (formerly OpenCOBOL) for the preparsing and/or generation of symbol tables/cross-reference and/or printcbl for a completely external tool doing preparsing and/or cobxref for a complete cross reference generation.

What is the use of WITH RETURN clause in DB2?

I see several stored procedures in this application I am now responsible for, some of which use this syntax for cursors:
DECLARE cursor1 CURSOR WITH RETURN FOR
...and others that use this syntax for cursors:
DECLARE cursor1 CURSOR FOR
All of these stored procedures are used by Crystal Reports 11.
Please explain to me, what is the difference between these two? They both return rows to Crystal Reports successfully. I am trying to optimize this one stored procedure and I wasn't sure what this clause even does. Thanks for your help.
Did you look in the manual?
Given that you're returning results to an external client, the WITH RETURN TO CLIENT would be a better choice.

Does Delphi 5 have a sorted dictionary container?

I'm new to Delphi 5 and looking for a container (ideally a built-in one) that will do the same job as map does in C++ (i.e. a sorted dictionary). I've done a preliminary Google search but nothing obvious seems to be suggesting itself. Please can anyone point me in the right direction?
Take a look at our TDynArray wrapper.
It's a wrapper around any existing dynamic array (including dynamic array of records), which will add TList-like methods to the dynamic array. With even more features, like search, sorting, hashing, and binary serialization. You can set the array capacity with an external Count variable, so that insertion will be much faster.
type
TGroup: array of integer;
var
Group: TGroup;
GroupA: TDynArray;
i, v: integer;
Test: RawByteString;
begin
GroupA.Init(TypeInfo(TGroup),Group); // associate GroupA with Group
for i := 0 to 1000 do begin
v := i+1000; // need argument passed as a const variable
GroupA.Add(v);
end;
v := 1500;
if GroupA.IndexOf(v)<0 then // search by content
ShowMessage('Error: 1500 not found!');
for i := GroupA.Count-1 downto 0 do
if i and 3=0 then
GroupA.Delete(i); // delete integer at index i
Test := GroupA.SaveTo; // serialization into Test
GroupA.Clear;
GroupA.LoadFrom(Test);
GroupA.Compare := SortDynArrayInteger;
GroupA.Sort; // will sort the dynamic array according to the Compare function
for i := 1 to GroupA.Count-1 do
if Group[i]<Group[i-1] then
ShowMessage('Error: unsorted!');
v := 1500;
if GroupA.Find(v)<0 then // fast binary search
ShowMessage('Error: 1500 not found!');
This example uses an array of integer, but you may use it with an array of records, even containing strings, nested dynamic arrays, or other records.
Works from Delphi 5 up to XE.
I find it even easier to use than generics (e.g. for the auto-serialization feature). ;)
See http://blog.synopse.info/post/2011/03/12/TDynArray-and-Record-compare/load/save-using-fast-RTTI
Well if D5 doesn't contain THashedStringList then maybe this one (from OmniThreadLibrary) does the job:
https://github.com/gabr42/OmniThreadLibrary/blob/master/src/GpStringHash.pas
I cite:
Tested with Delphi 2007. Should work with older versions, too.
Well, your version is definitely older :)
This can be accomplished 'out of the box' in D5 using TList.Sort or TObjectList.Sort - in your case you'd probably want to implement a class along the lines of:
TMyClass
public
Index:integer;
Value:TWhatever;
...
end;
To store in your list, then implement TList.Sort or TObjectList.Sort using your index value for sorting. It will take a bit of work but not terrible. See the D5 help on these classes for implementation details.
Unfortunately there are no generics in D5 so you'll probably have to to a lot of type casting or develop redundant container classes for different types.
This brings back memories. There is another interesting technique that's suitable for ancient versions of Delphi like yours. Read on!
From your description you sound like you want a fairly generic container - ie, one you can use with a variety of types. This cries out for generics (yes, use a new Delphi!) But back in the old days, there used to be a slightly hacky way to implement templates / generics with Delphi pre-2009, using a series of defines and includes. It took a bit of googling, but here's an article on these 'generics' that's much like what I remember. It's from 2001; in those days Delphi 5 was still recent-ish.
The rough idea is this: write a class to do what you want (here, a map from key to value) for a type, and get it working. Then change that file to use a specific name for the type (TMyType, anything really) and strip the file so it's no longer a valid unit, but contains code only. (I think two partial files, actually: one for the interface section, one for implementation.) Include the contents of the file using {$include ...}, so your whole Pascal file is compiled using your definitions and then the contents of the other partial included files which uses those definitions. Neat, hacky, ugly? I don't know, but it works :)
The example article creates a typed object list (ie, a list not of TObject but TMemo, TButton, etc.) You end up with a file that looks like this (copied from the linked article):
unit u_MemoList;
interface
uses
Sysutils,
Classes,
Contnrs,
StdCtrls;
{$define TYPED_OBJECT_LIST_TEMPLATE}
type
_TYPED_OBJECT_LIST_ITEM_ = TMemo;
{$INCLUDE 't_TypedObjectList.tpl'}
type
TMemoList = class(_TYPED_OBJECT_LIST_)
end;
implementation
{$INCLUDE 't_TypedObjectList.tpl'}
end.
You will need to write your own map-like class, although you should be able to base it on this class. I remember that there used to be a set of 'generic' containers floating around the web which may have used this technique, and I would guess map is among them. I'm afraid I don't know where it is or who it was by, and Googling for this kind of thing shows lots of results for modern versions of Delphi. Writing your own might be best.
Edit: I found the same article (same text & content) but better formatted on the Embarcadero Developer Network site.
Good luck!

MySQL stored procedure porting?

I am having a great deal of trouble porting some stored procedures to regular MySQL statements.
We have stuff like this example
http://dev.mysql.com/doc/refman/5.0/en/stored-programs-defining.html
BEGIN
SET #x = 0;
REPEAT SET #x = #x + 1; UNTIL #x > p1 END REPEAT;
END
Where many statements are executed. Several If statements and variable declarations, the whole 9 yards. But for some reason I can't just copy and paste the logic of the stored procedure into MySQL's query browser and execute it nor will it execute in a query execution via a C# program
I tried porting these queries via parameterized queries in C# but I still get a "check the manual error" every time =O
I really need help i can't find an answer anywhere on the internet. Am I completely screwed trying to get sequential execution without stored procedures?
Is the only way to do this to port the logic to the actual program? (I really don't want to do this)
Edit: I have reading comprehension issues. This link says that the looping constructs only work within stored programs, so you are out of luck I think.

Resources