Reading in a record from a file in Ada? - ada

Whenever I go to read in record from a file in Ada, I always get an error. The goal of the program is to read (from a file) an integer which is how many items needed to be recorded, in a last name consisting of (at most) 12 letters, a first name consisting of (at most) 12 letters, and a float value, then store those into a record.
This was from AdaGIDE:
record2.adb:32:04: invalid parameter list in call (use -gnatf for details)
My code:
with Ada.Text_IO, Ada.float_Text_IO, ada.Integer_Text_IO;
use Ada.Text_IO, Ada.float_Text_IO, ada.Integer_Text_IO;
procedure Record2 is
TYPE Testrec IS
record
test1 : string (1..12);
test2 : string (1..12);
test3 : float;
END RECORD;
T: Testrec;
Lt: Integer;
numitem: integer;
random1: Ada.Text_IO.File_Type;
begin -- Record2
Ada.Text_IO.Open(File => random1, Mode => Ada.Text_IO.In_File, Name => "info1.dat");
Get_Line(File => random1, Item => Testrec, Last => Lt);
Put(T.test1);
Put(T.Test2);
Put(T.Test3);
end Record2;
info1.dat's contents (no extra spaces or lines, just from "L" to "0":
LastName FirstName 4.00
My problems is the Get_Line, that I know. LastName is padded with spaces, filling the 12 characters, the same goes for FirstName. Then the float is taken for its value in general. What exactly am I doing wrong?

Basically, you're using Get_Line, which reads strings, to attempt to read an instance of a record.
Since this looks like a homework assignment (which is okay), I'll give you a hint:
Try reading the fields individually.
That's not enough to totally solve your problem, but it'll get you further, from which point you can try to work out the rest.

Related

expression is of wrong type for function

CREATE OR REPLACE FUNCTION k_w_b_salary(k IN NUMBER, b IN BOOLEAN)
RETURN EMP.ENAME%TYPE IS
names name_table;
BEGIN
IF (b = true) THEN
SELECT ENAME BULK COLLECT INTO names
FROM
(SELECT *
FROM EMP
ORDER BY SAL ASC)
WHERE ROWNUM <= k;
RETURN names;
ELSIF (b = false) THEN
SELECT ENAME BULK COLLECT INTO names
FROM
(SELECT *
FROM EMP
ORDER BY SAL DESC)
WHERE ROWNUM <= k;
RETURN names;
END IF;
END;
And I get this error:
12/9 PL/SQL: Statement ignored
12/16 PLS-00382: expression is of wrong type
20/9 PL/SQL: Statement ignored
20/16 PLS-00382: expression is of wrong type
I have this function that tries to find the best/worst paid employees. But i get the above error.
I think it's something to do with the ROWNUM but I am not sure.
I think the lines the error points out are not the lines with the error.
I had this function writen differently and the lines in the error where pointing to the ROWNUM <= k lines.
I have tried putting a fixed number there (<= 3) for example and I got the same error.
I have no idea what else to try, i can't really understand why this is not working.
It's not obvious to me why this is not working. I think it should work fine but obviously it dousen't.
The code for the table i use is :
CREATE OR REPLACE TYPE name_table IS TABLE OF VARCHAR2(10);
Any help is appreciated!
In the function declaration, you said
RETURN EMP.ENAME%TYPE
I assume the data type of column ENAME in table EMP is some sort of string (VARCHAR2(40) or similar) - right?
In the declarations section, you declare a variable names of data type name_table. You didn't show us the definition of the name_table type (that must be given outside the function, not in it); we can probably assume it is a nested table of some sort. Right? [EDIT - I take that back; you did show us your definition of name_table, at the end of your question.]
In the end, your function returns names. Which is of type name_table. But you said the function returns something else: EMP.ENAME%TYPE. In particular, you said the function returns a scalar data type, but you are returning a collection.
This will not work even if the collection has a single element. A table with a single "record" is not the same data type as the "record" itself - even if an actual table has a single "record" in it.
(And, much more so, when the table has three records in it!)
Rather: It seems that you want a table function: one that returns a table of things. If so, then declare the function that way. Perhaps you want the function to
RETURN NAME_TABLE
(at the top, in the function declaration)

Printing arrays elements using recursion

I am learning Ada programming language and I can admit that it's strongly typed. In this code, I am trying to ask the user to enter 4 integers and then by using recursion, print out these numbers. However, I am facing trouble writing a recursion subprogram for it and wonder if I can get any suggestions on how to write it correctly?
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure Dugga is
Y: Natural;
type arr is
array (1..4) of Natural;
A:arr;
function Recurs(Item: in Natural) return Natural is
begin
if Item >= 1 then
return Get(Item ); --Error: Context requires function call, found procedure name
end if;
end Recurs;
begin
Y:=Recurs(arr); --Error: expected type "Standard.Integer. Found type: arr
end Dugga;
Warnings: Program_error may be raised at run time
"return" statement missing following this statement
Error: Missing argument for parameter "Item" in call to get
You appear to be confused about what a recursive subprogram is. A recursive subprogram calls itself unless a termination condition is reached.
If your subprogram calls itself before printing the array element the array elements will be printed in reverse order. If your subprogram calls itself after printing the array element the array elements will be printed in the order they are entered.
with Ada.Text_Io; use Ada.Text_IO;
procedure Main is
subtype Idx is integer range 1..4;
type Arr is array (Idx) of Integer;
procedure Print(Nums : Arr; Index : Idx) is
begin
Put (Nums(Index)'Image);
if Index = Nums'Last then
New_Line;
else
Print(Nums, Index + 1);
end if;
end Print;
A : Arr := (1, 2, 3, 4);
begin
Print(A, A'First);
end Main;
The program above declares an array type and creates an instance of that array type.
The procedure Print is a recursive procedure that prints the value of an array at the specified index value. The procedure then checks the index value. If the index value is the last index value for the array the procedure calls New_Line, otherwise it calls Print with second parameter being Index + 1.
For any recursive algorithm you need to have some sort of control logic (IF, CASE, etc.) that decides between calling the function again with a different input (and returning that result with the potential result of this call) or otherwise returning a final value.
A couple of things.
You say our end game is to use recursion to "print" the values, so your recursive operation only needs to be a procedure. It doesn't need to return anything, it just needs to print something each time it runs. One way to do this is print the first element of the array and then recall the procedure with just the remaining elements. If there are no elements, don't print anything and leave the procedure.
In order to do this, I would recommend passing in the whole array instead of a single value (like your version does). Each time you recursively call the function, you shorten the array until there is no array left. To do this though, you need to adjust your array type to be any potential size, not just 1..4, so that you can use that to end the recursion.
Start with making an array type:
type Natural_Array is array (Positive range <>) of Natural;
Now change the specification of your function to a procedure that uses that type.
procedure Recurse(Numbers: in Natural_Array);
The last part is implementing the recursion:
procedure Recurse(Numbers: in Natural_Array) is
begin
-- See if the array has any elements first
if Numbers'Length > 0 then
-- There are elements in the array, so print the
-- first one. This is why we use Numbers'First
-- as the index
Put_Line(Numbers(Numbers'First)'Image);
-- Now that we printed the first number, lets
-- only pass in the remaining elements in the array
-- here. This is where the "recursion" happens
-- as it calls this function again with a reduced
-- input set. Eventually we'll pass in an
-- empty array once the last element is printed
-- above.
Recurse(Numbers(Numbers'First+1..Numbers'Last));
else
-- Here there weren't any eleemnts in the array
-- left, so lets just end the recursion by
-- doing nothing
null;
end if;
end Recurse;
Here's the full compilable example:
with Ada.Text_IO; use Ada.Text_IO;
procedure Hello is
type Natural_Array is array (Positive range <>) of Natural;
procedure Recurse(Numbers: in Natural_Array) is
begin
-- See if the array has any elements first
if Numbers'Length > 0 then
-- There are elements in the array, so print the
-- first one. This is why we use Numbers'First
-- as the index
Put_Line(Numbers(Numbers'First)'Image);
-- Now that we printed the first number, lets
-- only pass in the remaining elements in the array
-- here. This is where the "recursion" happens
-- as it calls this function again with a reduced
-- input set. Eventually we'll pass in an
-- empty array once the last element is printed
-- above.
Recurse(Numbers(Numbers'First+1..Numbers'Last));
else
-- Here there weren't any eleemnts in the array
-- left, so lets just end the recursion by
-- doing nothing
null;
end if;
end Recurse;
A : Natural_Array(1..4) := (1,2,3,4);
begin
Recurse(A);
end Hello;

Reading 'bad' Sqlite data with FireDAC

I just learned that the Sqlite Manager plug-in for Firefox will go away in November, so I've been trying to recreate its functionality in Delphi: open Sqlite databases, enter SQL queries. I'm running Tokyo.
My problem comes with Sqlite fields defined as 'date.' While Sqlite allows specification of data types, it allows pretty much anything to be put in any field. FireDAC handles bad entries in integer or float fields ('bar' becomes 0, '32foo' becomes 32), but it hiccups on fields described as 'date.'
For example, I have a table:
CREATE TABLE "someTable" ("id" INTEGER, "s" text(10), "d" date)
With this data:
INSERT INTO "someTable" VALUES ("1","good date","2017-09-09");
INSERT INTO "someTable" VALUES ("2","bad date","2017-09-0b");
INSERT INTO "someTable" VALUES ("3","empty d","");
INSERT INTO "someTable" VALUES ("4","null date",null);
Opening FDQuery q1 with SQL = "select * from someTable", a bad date (such as the second record) raises an EConvertError ("Invalid argument to date encode"). I tried to get around it by adding a maprule (q1 is a FDQuery):
with q1.FormatOptions do begin
OwnMapRules := True;
with MapRules.Add do begin
SourceDataType := dtDate;
TargetDataType := dtAnsiString;
sizemin := 10;
sizemax := 256;
PrecMin := -1;
PrecMax := -1;
ScaleMin := -1;
ScaleMax := -1;
end;
end;
However, that raises an EFDException:
[FireDAC][DatS]-32. Variable length column overflow. Value length - [10], column maximum length - [0].
What am I missing?
Why do I get "Invalid argument to date encode" exception when fetching tuple containing invalid DATE type field value?
The problem is that FireDAC expects DATE data type values represented as a string in fixed format YYYY-MM-DD where all members must be integers. Internally used FDStr2Int function doesn't use any detection of invalid input and works directly with ASCII ordinary values shifted by the 0 char, so input like e.g. GHIJ-KL-MN results in year 25676, month 298, day 320 after parsing. And just these misinterpreted values are then passed to the EncodeDate function, which fails for such values with the exception you've mentioned:
Invalid argument to date encode
The above happens inside the GetData method (ParseDate nested function). One possible way for fixing this issue on FireDAC's side could be using safer function TryEncodeDate instead of a direct encoding attempt. Similar problem is with TIME data type string value.

how to get a unqiue result sets in PL/SQL cursor?

I want use this procedure to display the username and moblephone number,the result sets is this when I use select :
declare enter image description here
when the procedure runs,I get this :
enter image description here
error ORA-01722: invalid number
ORA-06512: at "ABPROD.SHAREPOOL", line 24.
when I use unique or distinct in the cursor,nothing display.
the code source :
create or replace procedure sharepool (assignment in varchar2,myorgname in varchar2) is
rightid T_CLM_AP30_RIGHT.RIGHT_ID%type;
orgid t_clm_ap30_org.org_id%type;
begin
select t.right_id into rightid from T_CLM_AP30_RIGHT t where t.rightdesc=trim(assignment);
dbms_output.put_line(rightid||trim(myorgname)||assignment);
select t.org_id into orgid from t_clm_ap30_org t where t.orgname=trim(myorgname);
dbms_output.put_line(orgid);
declare
cursor namelist is select distinct a.username,a.mobile from t_clm_ap30_user a, T_CLM_AP30_RIGHT_AUTH t where a.user_id=t.user_id and t.right_id=rightid and t.poolorgrange=orgid ;
begin
for c in namelist
loop
dbms_output.put_line(c.username||' '||c.mobile);
end loop;
end;
end sharepool;
INVALID_NUMBER errors indicate a failed casting of a string to a number. That means one of your join conditions is comparing a string column with a number column, and you have values in the string column which cannot be cast to a number.
ORA-06512: at "ABPROD.SHAREPOOL", line 24
Line 24 doesn't align with the code you've posted, presumably lost in translation from your actual source. Also you haven't posted table descriptions so we cannot tell which columns to look at.
So here is a guess.
One (or more) of these joins has an implicit numeric conversion:
where a.user_id = t.user_id
and t.right_id = rightid
and t.poolorgrange = orgid
That is, either t_clm_ap30_user.user_id is numeric and T_CLM_AP30_RIGHT_AUTH.user_id is not, or vice versa. Or T_CLM_AP30_RIGHT_AUTH.right_id is numeric and T_CLM_AP30_RIGHT.right_id is not, or vice versa. Or T_CLM_AP30_RIGHT_AUTH.poolorgrange is numeric and t_clm_ap30_org.org_id is not, or vice versa.
Only you can figure this out, because only you can see your schema. Once you have identified the join where you have a string column being compared to a numeric column you need to query that column to find the data which cannot be converted to a number.
Let's say that T_CLM_AP30_RIGHT_AUTH.poolorgrange is the rogue string. You can see which are the troublesome rows with this query:
select * from T_CLM_AP30_RIGHT_AUTH
where translate (poolorgrange, 'x1234567890', 'x') is not null;
The translate() function strips out digits. So anything which is left can't be converted to a number.
"T_CLM_AP30_RIGHT_AUTH.poolorgrange is varchar2,and t_clm_ap30_org.org_id is numeric ."
You can avoid the error by explicitly casting the t_clm_ap30_org.org_id to a string:
select distinct a.username, a.mobile
from t_clm_ap30_user a,
T_CLM_AP30_RIGHT_AUTH t
where a.user_id = t.user_id
and t.right_id = rightid
and t.poolorgrange = to_char(orgid) ;
Obviously you're not going to get matches on those alphanumeric values but the query will run.

PLS-00487 Error-Invalid reference to Variable 'CHAR'

I'm designing a function that is part of a larger package. The function is intended to take a District Code and return a collection of unique IDs for 10-15 stores that are assigned to that district. The function is intended to return a collection that can be queried like a table, i.e., using the TABLE function in a SQL statement.
I've created the following Types:
Schema Level type:
create or replace TYPE HDT_CORE_ORGIDS AS TABLE OF CHAR(20);
and a Type inside the Package
TYPE CORE_ORGIDS IS TABLE OF CHAR(20) INDEX BY BINARY_INTEGER;
Here's the function code:
FUNCTION FindDistrictOrgs(
ParamOrgCode VARCHAR2
)
RETURN HDT_CORE_ORGIDS
AS
ReturnOrgs HDT_CORE_ORGIDS := HDT_CORE_ORGIDS();
FDOTemp HDT_CORE_MAIN.CORE_ORGIDS;
i BINARY_INTEGER := 0;
CURSOR FDOCurr IS
SELECT org.id AS OrgID
FROM tp2.tpt_company org
WHERE LEVEL = 2
START WITH org.name = ParamOrgCode
CONNECT BY PRIOR org.id = org.parent_id;
BEGIN
OPEN FDOCurr;
LOOP
i := i +1;
FETCH FDOCurr INTO FDOTemp(i);
EXIT WHEN FDOCurr%NOTFOUND;
END LOOP;
IF FDOTemp.EXISTS(FDOTemp.FIRST) THEN
ReturnOrgs.EXTEND(FDOTemp.LAST);
FOR x IN FDOTemp.FIRST .. FDOTemp.LAST LOOP
ReturnOrgs(x) := FDOTemp(x).OrgID;
END LOOP;
END IF;
CLOSE FDOCurr;
RETURN ReturnOrgs;
END FindDistrictOrgs ;
I'm getting the PLS-00487:Invalid Reference to variable 'CHAR' at the line:
ReturnOrgs(x) := FDOTemp(x).OrgID;
I've double-checked at the value returned by the SQL (the org.id AS OrgID) is of the CHAR(20 BYTE) datatype.
So...what's causing the error?
Any help is appreciated! :)
OrgID is the alias you gave the column in your cursor, it has no meaning to the collection. Since both collections are of simple types you should just be doing:
ReturnOrgs(x) := FDOTemp(x);
The syntax you're using is implying FDOTemp is a collection of objects and you're trying to reference the OrgID attribute of an object; but since CHAR isn't an object type, this errors. The error message even makes some sense when viewed like that, though it's not terribly helpful if you don't already know what's wrong... and not entirely helpful when you do.
Incidentally, you could use a bulk collect to populate the collection without the cursor or loops, or the extra collection:
SELECT org.id
BULK COLLECT INTO ReturnOrgs
FROM tp2.tpt_company org
WHERE LEVEL = 2
START WITH org.name = ParamOrgCode
CONNECT BY PRIOR org.id = org.parent_id;
RETURN ReturnOrgs;

Resources