PL/SQL Return Cursor - plsql

I am trying to define the PL/SQL function
CREATE OR REPLACE FUNCTION B2BOWNER.F_SSC_Page_Map_Select(
p_page_id IN B2BOWNER.SSC_Page_Map.PAGE_ID_NBR%TYPE,
p_page_type IN B2BOWNER.SSC_Page_Map.PAGE_TYPE%TYPE,
p_page_dcpn IN B2BOWNER.SSC_Page_Map.PAGE_DCPN%TYPE)
RETURN MAP_REC
AS
CURSOR MAP_CURSOR IS
SELECT *
FROM B2BOWNER.SSC_PAGE_MAP
WHERE PAGE_ID_NBR = p_page_id AND PAGE_TYPE = p_page_type;
MAP_REC MAP_CURSOR%ROWTYPE;
TABLE_DOES_NOT_EXIST exception;
PRAGMA EXCEPTION_INIT(TABLE_DOES_NOT_EXIST, -942); -- ORA-00942
BEGIN
FOR MAP_REC IN MAP_CURSOR
LOOP
System.out.println("ID: " + MAP_REC.PAGE_ID_NBR + " " + "TYPE: " + MAP_REC.PAGE_TYPE + " " + "DCPN: " + MAP_REC.PAGE_DCPN);
END LOOP;
RETURN MAP_REC;
EXCEPTION
WHEN TABLE_DOES_NOT_EXIST THEN
RETURN -1;
WHEN DUP_VAL_ON_INDEX THEN
RETURN -2;
WHEN INVALID_NUMBER THEN
RETURN -3;
WHEN OTHERS THEN
RETURN -4;
END F_SSC_Page_Map_Select;
SHOW ERRORS PROCEDURE B2BOWNER.F_SSC_Page_Map_Select;
GRANT EXECUTE ON B2BOWNER.F_SSC_Page_Map_Select TO B2B_USER_DBROLE;
and receive the following error
Warning: compiled but with compilation errors
No errors.
Grant complete.
[Warning] ORA-24344: success with compilation error
6/12 PLS-00320: the declaration of the type of this expression is incomplete or malformed
PL/SQL: Compilation unit analysis terminated
(1: 0): Warning: compiled but with compilation errors

A few things. First, the MAP_REC declared in the declaration section is not the same as the MAP_REC used in the cursor FOR loop. This was certainly surprising to me when I first encountered it but it's something we all have to get used to. To do what you're trying to do you'll need to either use the OPEN, FETCH, and CLOSE method of working with a cursor, or else copy the values from the cursor FOR loop variable to the 'declared' variable.
Secondly, you can't return a MAP_REC from this function as MAP_REC is declared inside the function and thus isn't known to the compiler when it processes the function definition. Best to use the specific table ROWTYPE.
Third, later in the code you have RETURN -1, etc, which won't work as a cursor %ROWTYPE variable. I suggest that instead of trying to return 'magic number' values to indicate specific failures you should simply let the exceptions propagate to the caller, who can then handle the exceptions as needed. That's why we have exceptions - to prevent having different error handling schemes for every single subroutine out there.
And finally: this is PL/SQL - we don't System.out.println here. :-)
A possible way to rewrite your code would be:
CREATE OR REPLACE FUNCTION B2BOWNER.F_SSC_Page_Map_Select(
p_page_id IN B2BOWNER.SSC_Page_Map.PAGE_ID_NBR%TYPE,
p_page_type IN B2BOWNER.SSC_Page_Map.PAGE_TYPE%TYPE,
p_page_dcpn IN B2BOWNER.SSC_Page_Map.PAGE_DCPN%TYPE)
RETURN B2BOWNER.SSC_PAGE_MAP%ROWTYPE
AS
CURSOR MAP_CURSOR IS
SELECT *
FROM B2BOWNER.SSC_PAGE_MAP
WHERE PAGE_ID_NBR = p_page_id AND
PAGE_TYPE = p_page_type;
MAP_REC B2BOWNER.SSC_PAGE_MAP%ROWTYPE;
bCursor_open BOOLEAN := FALSE;
BEGIN
OPEN MAP_CURSOR;
bCursor_open := TRUE;
LOOP
FETCH MAP_CURSOR
INTO MAP_REC;
EXIT WHEN MAP_CURSOR%NOT_FOUND;
DBMS_OUTPUT.PUT_LINE('ID: ' || MAP_REC.PAGE_ID_NBR || ' ' || 'TYPE: ' ||
MAP_REC.PAGE_TYPE || ' ' || 'DCPN: ' || MAP_REC.PAGE_DCPN);
END LOOP;
CLOSE MAP_CURSOR;
bCursor_open := FALSE;
RETURN MAP_REC;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error in F_SSC_Page_Map_Select: ' || SQLCODE || ' ' ||
SQLERRM);
IF bCursor_open THEN
CLOSE MAP_CURSOR;
END IF;
RAISE;
END F_SSC_Page_Map_Select;
Best of luck.
Share and enjoy.

Related

PACKAGE BODY MISTAKE

-- PACKAGE SPECIFICATION OR HEADER
CREATE OR REPLACE PACKAGE pkg_Answer2 IS
FUNCTION grade_std(marks NUMBER) RETURN VARCHAR2;
END pkg_Answer2;
/
--PACKAGE BODY
CREATE OR REPLACE PACKAGE BODY pkg_Answer2 IS
--FUNCTION IMPLEMENTATION
FUNCTION grade_std(marks NUMBER) RETURN VARCHAR2 IS
BEGIN
IF marks>90 THEN
RETURN 'A';
ELSIF marks<=90 AND marks>80 THEN
RETURN 'B';
ELSIF marks<=80 AND marks>70 THEN
RETURN 'C';
ELSIF marks<=70 AND marks>60 THEN
RETURN 'D';
ELSIF marks<=60
RETURN 'F';
ELSE
RETURN 'I';
END IF;
END grade_std;
END pkg_Answer2;
PACKAGE BODY IS SHOWING ERROR :
Errors: PACKAGE BODY PKG_ANSWER2
Line/Col: 14/9 PLS-00103: Encountered the symbol "RETURN" when expecting one of the following:
& - + / at mod remainder rem then <an exponent (**)> and or
|| multiset
WHAT DOES IT MEAN BU ENCOUNTER SYMBOL RETURN THUS I AM UNABLE TO CREATE PACKAGE BODY
This is basic debugging, you should not have to ask this on stack overflow. All the information is right in your question.
To find out what is going on:
Open the created package in a tool like sql developer. That tool highlights the line where error occurs (Line 14, as shown in the error)
Check what is happening around line 14...
13 ELSIF marks<=60
14 RETURN 'F';
15 ELSE
the error states "Encountered the symbol "RETURN" when ". This means it cannot compile because a previous expression does not have correct syntax and the word "RETURN" doesn't make any sense there... so check the line before. That is line 13. It does not have the THEN keyword. There is your error.

Catch Precondition Assert_Failure

I'm trying to catch the error in this precondition I have on the main procedure and I'm wondering if it's possible to catch?
Do I need to move this to a different procedure and then call it in main in order to catch it?
with
ada.text_io,
ada.command_line,
ada.strings.bounded,
system.assertions;
procedure main with
pre => (ada.command_line.argument_count > 2)
is
package b_str is new
ada.strings.bounded.generic_bounded_length (max => 255);
use b_str;
input_file : bounded_string;
argument : bounded_string;
i : integer := 1;
begin
while i <= ada.command_line.argument_count loop
argument := to_bounded_string(
ada.command_line.argument(i)
);
ada.text_io.put_line("[" & i'image & "] "
& to_string(argument)
);
i := i + 1;
end loop;
exception
when system.assertions.assert_failure =>
ada.text_io.put_line("Failed precondition");
end main;
I've found my answer:
Exception handlers have an important restriction that you need to be careful about: Exceptions raised in the declarative section are not caught by the handlers of that block.
From: https://learn.adacore.com/courses/intro-to-ada/chapters/exceptions.html
Since exception can not be handled in a declarative section, the action should be moved to a package similar to the one below. Then, call it from a exception handling block of the main procedure. So, your code will not terminate after handling the exception.
with Ada.Command_line;
package Util is
--...
function Command_Argument_Count return Natural
with Pre => Ada.Command_Line.Argument_Count > 2;
--...
end Util;
--...
Exception_Handling_Block:
begin
while i <= Util.Command_Argument_Count loop
argument := to_bounded_string(
ada.command_line.argument(i)
);
ada.text_io.put_line("[" & i'image & "] "
& to_string(argument)
);
i := i + 1;
end loop;
exception
when system.assertions.assert_failure =>
ada.text_io.put_line("Failed precondition");
end Exception_Handling_Block;
--...

Ada error: invalid use of subtype mark in expression or call

I'm stuck here with an error in my Ada program. There is a lot of code and I don't want to copy all of it here, so I hope that the part that I'm sharing is the part from where the problem comes.
task type Producent is
entry Start(Jedzenie: in Typ_Jedzenia; Czas_Produkcji: in Integer);
end Producent;
task type Buffer is
entry Zamow(Jedzenie: in Typ_Jedzenia; Numer: in Integer; Czy_Zatwierdzono: out Boolean);
entry Dostarcz(Zamowienie: in Typ_Zestawu; Numer: out Integer);
end Buffer;
task body Producent is
package Losowa_Produkcja is new
Ada.Numerics.Discrete_Random(Zakres_Czasu_Produkcji);
Generator: Losowa_Produkcja.Generator;
Index_Jedzenia: Integer;
Nr_Produkcji_Jedzenia: Integer := 1;
Produkcja: Integer;
Zatwierdzono: Boolean := False;
begin
accept Start (Jedzenie : in Typ_Jedzenia; Czas_Produkcji : in Integer) do
Losowa_Produkcja.Reset(Generator);
Index_Jedzenia := Jedzenie;
Produkcja := Czas_Produkcji;
end Start;
loop
delay Duration(Losowa_Produkcja.Random(Generator));
Put_Line("Przygotowano " & Nazwa_Jedzenia(Index_Jedzenia) & " numer " & Integer'Image(Nr_Produkcji_Jedzenia));
loop
Buffer.Zamow(Index_Jedzenia, Nr_Produkcji_Jedzenia, Zatwierdzono); <-------- ERROR
if Zatwierdzono = False then
Put_Line("Brak miejsca w kuchni dla " & Nazwa_Jedzenia(Index_Jedzenia) & ". Wstrzymanie");
delay Duration(3.0);
else
Nr_Produkcji_Jedzenia := Nr_Produkcji_Jedzenia + 1;
end if;
exit;
end loop;
end loop;
end Producent;
task body Buffer is
begin
Put_Line("Jestesmy u Buffera");
loop
select
accept Zamow(Jedzenie: in Typ_Jedzenia; Numer: in Integer; Czy_Zatwierdzono: out Boolean) do
Put_Line("Trwa zamawianie...");
end Zamow;
end select;
end loop;
end Buffer;
From my attempts I understand that when I want to call entry Buffer.Zamow(Index_Jedzenia, Nr_Produkcji_Jedzenia, Zatwierdzono); (which is in task Producent) there is an error with 'Zatwierdzono' argument. When I removed this argument from declarations and definitions Zamow() entry worked.
Full error: invalid use of subtype mark in expression or call
What should I change or where is the problem with this boolean Zatwierdzono variable?
Zatwierdzono means Accepted in this case.
Thanks for any ideas.
You have two problems:
Index_Jedzenia := Jedzenie;
In your Start entry is trying to implicitly convert Jedzenie from its type, Typ_Jedzenia, to Integer, the type of Index_Jedzenia. You need some way to convert this.
Additionally on the line you are seeing the error on, the first parameter of that entry is of type Typ_Jedzenia but you are passing in an Integer (Index_Jedzenia is an integer). Again, you can't implicitly convert types like that.
If Typ_Jedzenia is actually an integer, you can explicitly convert them. Otherwise you need to make a conversion function of some type and use that before passing in or assigning to different types.

Ada 95 Check if enter was pressed

I am new to Ada.
How can I check if enter was pressed?
The while loop should be able to check whether the input character is a white space or an enter key.
Furthermore, how can I check the user input type, like the type() or typeof() function in other languages?
FUNCTION ReadValue RETURN Unbounded_String IS
ValueChar : Character;
Result : Unbounded_String := To_Unbounded_String("NULL");
BEGIN
Get(ValueChar);
Skip_Line;
WHILE ValueChar /= ';'LOOP
Get(ValueChar);
IF IsValidNameInput(ValueChar) THEN
Result := Result & ValueChar;
ELSE
exit;
END IF;
END LOOP;
ValueIntegerFlag := CheckValue(Value);
RETURN Result;
END ReadValue;
Read the characters one-at-a-time without special ENTER handling using Get_Immediate instead of Get - ARM A.10.7(9).
You can do checks on the class of the character you’ve just read using Ada.Characters.Handling - ARM A.3.2 - something like
function Is_Valid_Name_Input (Ch : Character) return Boolean is
begin
return Ada.Characters.Handling.Is_Graphic (Ch)
and then not Ada.Characters.Handling.Is_Space (Ch);
end Is_Valid_Name_Input;
(probably not quite what you want, since it makes &*^$$^ a valid name!)
Ada.Characters.Handling.Is_Line_Terminator detects ENTER (on Unix; probably on Windows too).
You can check whether a string corresponds to an integer by trying the conversion and catching the exception when it fails:
function Check_Integer_Value (Str : Unbounded_String) return Boolean is
Dummy : Integer;
begin
Dummy := Integer'Value (To_String (Str));
return True;
exception
when Constraint_Error =>
return False;
end Check_Integer_Value;
With regard to ReadValue:
Don’t initialize Result - it starts off as the empty string (and you really don’t want to start with the string ”NULL”).
It skips the first character input.
What’s that Skip_Line for?
Try something like
function Read_Value return Unbounded_String is
Value_Char : Character;
Result : Unbounded_String;
begin
loop
Get_Immediate (Value_Char);
exit when Value_Char = ';';
if Is_Valid_Name_Input (Value_Char) then
Result := Result & Value_Char;
end if;
end loop;
return Result;
end Read_Value;

Function reading from standard input without any "in" parameters

Perhaps this is simple, and I am just missing some basic information, but I can't seem to find the answer anywhere.
I'm writing a Get_Word function for class, here is the relevant section of the spec file my prof wrote:
function Get_Word return Ustring;
-- return a space-separated word from standard input
procedure Fill_Word_List(Wl : in out Ustring_Vector);
-- read a text file from standard in and add all
-- space-separated words to the word list wl
I've written the Get_Word function, and am trying to test it out with this code:
with Ada.Text_IO; use Ada.Text_Io;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure ngramtest is
Name : String(1..80);
File : File_Type;
Size : Natural;
function Get_Word return String is
-- I'm using a strings instead of Unbounded_Strings for testing purposes.
Word : String(1..80) := (others => ' ');
Char : Character;
File : File_Type;
Eol : Boolean;
I : Integer := 1;
begin
--this code below, when uncommented reveals whether or not the file is open.
--if Is_Open(File) then
-- Word := (1..80 => 'y');
--else
-- Word := (1..80 => 'n');
--end if;
loop
Look_Ahead(File, Char, Eol);
if Eol then
exit;
elsif Char = ' ' then
exit;
else
Get (File, Char);
Word(I) := Char;
I := I + 1;
end if;
end loop;
return Word(1..Word'Last);
end Get_Word;
begin
Put ("Enter filename: ");
Get_Line (Name, Size);
Open (File, Mode => In_File, Name => Name(1..Size));
Put (Get_Word);
Close(File);
end ngramtest;
It compiles, but at runtime I get an exception telling me that the file isn't open, and the commented out section returns "nnnnnn..." meaning that the file is not open within the function.
My question is how am I to read from standard input if i'm not allowed to use in parameters in my function? Without them the function won't be able to access files.
Essentially, how can I "Get_Word"?
Sorry if this is simple, but I'm completely lost.
You need to set your "File" variable to standard input:
File : File_Type := Ada.Text_IO.Standard_Input;

Resources