Oracle object array initialization collection - arrays

I am trying to create an array of oracle object type and I am getting some initialization related error.
Below is the sample code
CREATE OR REPLACE TYPE rectangle AS OBJECT
(
-- The type has 3 attributes.
length NUMBER,
width NUMBER,
area NUMBER,
-- Define a constructor that has only 2 parameters.
CONSTRUCTOR FUNCTION rectangle(length NUMBER, width NUMBER)
RETURN SELF AS RESULT
);
CREATE OR REPLACE TYPE BODY rectangle AS
CONSTRUCTOR FUNCTION rectangle(length NUMBER, width NUMBER)
RETURN SELF AS RESULT
AS
BEGIN
SELF.length := length;
SELF.width := width;
SELF.area := length * width;
RETURN;
END;
END;
To run below is the sample script
set serveroutput on
DECLARE
r1 rectangle;
r2 rectangle;
type rect_arr is table of rectangle;
m_rect rect_arr;
BEGIN
m_rect.extend;
m_rect(1) := rectangle(10,20);
sop(m_rect(1).area);
END;
Below is the error on console----- I know it is related to initialization error, and tried various constructor and member function solutions but none help.
Error report:
ORA-06531: Reference to uninitialized collection
ORA-06512: at line 7
06531. 00000 - "Reference to uninitialized collection"
*Cause: An element or member function of a nested table or varray
was referenced (where an initialized collection is needed)
without the collection having been initialized.
*Action: Initialize the collection with an appropriate constructor
or whole-object assignment.

m_rect rect_arr := rect_arr();

Related

Eiffel: compilation error `Source of assignment is not compatible with target`

With complete void check set in compiler I've got a Variable is not properly set compilation error on following case which for me is right (in my mind). It says that the source of assignment is not compatible with target. What am I missing here??? (DB_SERVICE.load_from_primary_key...)
Class DB_SERVICE
deferred class
DB_SERVICE [G -> DB_ENTITY create make_from_db_result end]
inherit
ACTION
redefine
start,
execute
end
LOGGABLE
rename
make as make_from_loggable
end
feature -- Creation
make (a_db_connection: attached DB_CONNECTION)
require
valid_db_connection: a_db_connection.is_connected
do
make_from_loggable
db_connection := a_db_connection
create last_items.make (100)
create last_column_names.make_empty
ensure
db_connection_setted: a_db_connection = db_connection and db_connection.is_connected
end
feature -- Access
item: detachable G
db_connection: DB_CONNECTION
last_items: HASH_TABLE[like item, INTEGER] -- content of last resultset
last_column_names: ARRAY[STRING] -- Column names of last resultset
feature -- status_report
load_from_primary_key (primary_key: INTEGER)
-- Loads given item into item otherwise item will be Void
require
attached db_connection.base_selection
local
l_db_result: DB_RESULT
do
if attached db_connection.base_selection as bs then
bs.query ("SELECT * FROM " + ({attached like item}).out + " WHERE " + {attached like item}.Primary_key_db_column_name + "=" + primary_key.out)
if bs.is_ok then
bs.load_result
create item.make_from_db_result(last_column_names, bs.cursor)
else
item := Void --HERE is the compiler complaining!
logger.write_critical ("Error while retreiving " + ({like item}).out + " from DB")
end
else
item := Void
logger.write_error ("base_selection is void")
end
end
end -- class
Class COMPANY_SERVICE
class
COMPANY_SERVICE
inherit
DB_SERVICE[COMPANY]
redefine
make
end
...
Class COMPANY
class
COMPANY
inherit
DB_ENTITY
rename
primary_key as id,
set_primary_key as set_id,
Primary_key_db_column_name as Id_db_column_name
redefine
make,
make_from_db_result,
out
end
create
make,
make_from_db_result
....
The type declaration detachable G indicates that if the corresponding actual generic is a reference type, the variable of that type could be detachable. In that case it would be OK to assign Void to such a variable. However, it's also possible that the actual generic is an expanded type. Prefixing an expanded type with detachable has no effect, the type remains the same and the variable cannot be assigned Void.
As an example, let's consider a simpler case, when there is no formal generic constraint for the parameter G. An actual generic could be STRING, and the variable item has a type detachable STRING. In this case, it's OK to assign Void to item.
Now, if the actual generic is INTEGER, the variable has a type detachable INTEGER that is equivalent to INTEGER. Assigning Void to a variable of this type makes no sense and is not permitted by the language rules.
The variable item still can be set to Void if the actual generic parameter is a reference type. For that, a local variable with the same type can be declared and its value can be assigned to item:
local
default_item: like item
do
item := default_item

Constraint error with private part, arrays and pointers

I am trying to do a typical Get procedure with this features:
Header:
procedure Get (M:Map; Key: in Key_Type; Value: out Value_Type; Success: out Boolean) is
private part:
type Cell is record
Key: Key_Type;
Value: Value_Type;
Full:Boolean:= False;
end record
type Cell_Array is array (1..50) of Cell;
type Cell_Array_A is access Cell_Array;
type Map is record
P_Array: Cell_Array_A;
Length:Natural=0;
Indice:Natural;
end record
My first condition on my Get procedure has the following aspect:
for k in 1..NumClien loop
if M.P_Array(k).Key = Key then
...
But when I try to execute it, it always gives me the following error:
Lower_Layer.Inet(Receiver_Task): Unexpected exception raised CONSTRAINT_ERROR
How can I solve it?
PS: Header of the Get procedure and private part are mandatory...
Thank you!
if you eliminate the unnecessary use of access types, your problem will go away:
type Map is record
List : Cell_Array;
...
end record;
Access types are needed so rarely in well designed Ada that I'm tempted to say "never".

How to correctly declare an array property in Delphi?

I'm trying to create an array to store every item of a TStringList into an array which size may vary depending on the quantity of items in said TStringList.
I know my syntax is wrong and what I want is probably a dynamic array, so the [0..100] is probably wrong aswell but I could not find any alternative syntax online.
ProductAvailabilityResult = Class(TRemotable)
private
FResultArray : array[1..100] of string;
published
property ResultArray[Index: Integer]: array of string read FResultArray write FResultArray;
End;
And this is how I would invoke it and populate it. conditionList being my TStringList which I would populate into my array.
for I := 0 to conditionList.Count - 1 do
begin
aProductAvailabilityResult.ResultArray[I] := conditionList[I];
end;
In case you may or may not have alternative suggestions to what i'm doing, the reason for this setup is because it's a web service app sending results over a SOAP server, and I don't think my PHP/Soap client can read TStringLists, so I need to pass it to an array first.
Let me know, Thanks!
Your syntax for declaring an array property is close, but you need to use getter/setter methods instead of direct field access, and array properties cannot be declared as published:
type
ProductAvailabilityResult = class(TRemotable)
private
FResultArray : array of string;
function GetResultArray(Index: Integer): string;
function GetResultArrayCount: Integer;
procedure SetResultArray(Index: Integer; const Value: string);
procedure SetResultArrayCount(Value: Integer);
public
property ResultArray[Index: Integer]: string read GetResultArray write SetResultArray default;
property ResultArrayCount: Integer read GetResultArrayCount write SetResultArrayCount;
end;
function ProductAvailabilityResult.GetResultArray(Index: Integer): string;
begin
Result := FResultArray[Index];
end;
function ProductAvailabilityResult.GetResultArrayCount: Integer;
begin
Result := Length(FResultArray);
end;
procedure ProductAvailabilityResult.SetResultArray(Index: Integer; const Value: string);
begin
FResultArray[Index] := Value;
end;
procedure ProductAvailabilityResult.SetResultArrayCount(Value: Integer);
begin
SetLength(FResultArray, Value);
end;
Then you can do this:
aProductAvailabilityResult.ResultArrayCount := conditionList.Count;
for I := 0 to conditionList.Count - 1 do
begin
aProductAvailabilityResult[I] := conditionList[I];
end;
You might want to consider adding a method to copy strings from a source TStrings:
type
ProductAvailabilityResult = class(TRemotable)
private
...
public
procedure AssignStrings(AStrings: TStrings);
...
end;
procedure ProductAvailabilityResult.AssignStrings(AStrings: TStrings);
var
I: Integer;
begin
SetLength(FResultArray, AStrings.Count);
for I := 0 to AStrings.Count - 1 do
FResultArray[I] := AStrings[I];
end;
aProductAvailabilityResult.AssignStrings(conditionList);
You've declared an array property, albeit with some syntax errors. However, you state in the question and comments that you want a property that is a dynamic array. That's different from an array property.
Declare a dynamic array property like so:
type
ProductAvailabilityResult = class(TRemotable)
private
FResultArray: TArray<string>;
published
property ResultArray: TArray<string> read FResultArray write FResultArray;
end;
Populate it like this:
var
i: Integer;
List: TStringList;
par: ProductAvailabilityResult;
arr: TArray<string>;
....
List := ...;
par := ...;
SetLength(arr, List.Count);
for i := 0 to List.Count-1 do
arr[i] := List[i];
par.ResultArray := arr;

Delphi 2007 and Dynamic Variant Array as Var Parameter

I have a form which allows a use to select a record and this form then returns the ID of the record and an arbitrary number of fields values that the calling form may need. To do this, I have a function which handles creating the select form and passes all the values to and from the calling form:
Function Execute(AOwner: TComponent; AConnection: TADOConnection;
AEditor: String; AButtons: TViewButtons; Var AID: Integer;
Var ARtnVals: Array of Variant): TModalResult;
Var
I: Integer;
Begin
frmSelectGrid := TfrmSelectGrid.Create(AOwner);
Try
With frmSelectGrid Do
Begin
Connection := AConnection;
Editor := AEditor;
Buttons := AButtons;
ID := AID;
Result := ShowModal;
If Result = mrOK Then
Begin
AID := ID;
//VarArrayRedim(ARtnVals, Length(RtnVals)); !! Won't compile
//SetLength(ARtnVals, Length(RtnVals)); !! Won't compile either
For I := 0 To High(RtnVals) Do
ARtnVals[I] := RtnVals[I]; // Causes runtime exception
End;
End;
Finally
FreeAndNil(frmSelectGrid);
End;
End;
The selector form has the following public properties:
public
Connection: TADOConnection;
Editor: String;
Buttons: TViewButtons;
ID: Integer;
RtnVals: Array of Variant;
end;
And in the OK click, I have the following code:
Var
I, Idx, C: Integer;
// Count how many fields are being returned
C := 0;
For I := 0 To Config.Fields.Count - 1 Do
If Config.Fields[I].Returned Then
Inc(C);
// If no fields to be returned, then just exit.
If C = 0 Then
Exit;
// Set the size of the RtnVals and assign the field values to the array.
SetLength(RtnVals, C);
Idx := 0;
For I := 0 To Config.Fields.Count - 1 Do
If Config.Fields[I].Returned Then
Begin
RtnVals[Idx] := aqItems.FieldByName(Config.Fields[I].FieldName).Value;
Inc(Idx);
End;
So, once the user clicks OK to select a record, the RtnVals array is populated with the field values of the fields to be returned. I now need to copy these values to ARtnVals in the Execute function so that they are returned to the calling form.
My question is how do I set the size of the ARtnVals array so that I can copy the fields? SetLength doesn't work like it does in the OK click function above. VarArrayRedim doesn't work either.
When written in a procedure parameter list, this code
Var ARtnVals: Array of Variant
is an open array, and not a dynamic array. An open array cannot be resized. An open array is no use to you here.
Instead define a type for the array:
type
TDynamicArrayOfVariant = array of Variant;
Use that type for your parameter, which is actually best as an out parameter:
function Execute(..., out RtnVals: TDynamicArrayOfVariant): TModalResult;
And then pass the function a TDynamicArrayOfVariant to be populated.
Now you have a dynamic array rather than an open array in Execute, and you can use SetLength to size it.

Loading images into TImage, via array

I'm very new to delphi, doing a project for my A level. When I run my code the images just don't show, I've looked everywhere and my teacher can't help me. Can anyone tell me what I'm missing?
const
Animal : array[0..6] of string = ('Bears','Dogs','Cats','Chickens','Horses','Cows','Monkeys');
ImagePaths : array [0..6] of string
= ('img0.JPG', 'img1.JPG', 'img2.JPG', 'img3.JPG', 'img4.JPG', 'img5.JPG',
'img6.JPG');
var i:integer;
Images : array [0..11] of TImage;
procedure LoadImages;
var
k,l:integer;
begin
Randomize;
k:=Random(11);
for l:= 0 to k do
begin
Images[l] := TImage.Create(nil);
Images[l].Picture.LoadFromFile(ImagePaths[i])
end
end;
procedure TForm4.FormCreate(Sender: TObject);
begin
randomize;
i:=random(6);
QuestionLbl.Caption:=Format('How many %s are there?',[Animal[i]]);
LoadImages;
end;
The idea is that a random number of images of the same randomly selected animal is displayed for a child to then count and input, if that helps. Much appreciate any help.
edit.
as this is only a prototype I have copied it all to a new application and this is all the code I didn't include:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,jpeg, ExtCtrls;
type
TForm1 = class(TForm)
QuestionLbl: TLabel;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
The same error is occurring and I'm afraid I'm too ignorant to follow what I'm sure were very clear instructions.
What appears to be missing is that you need to tell the image which control is its parent so that it can appear on screen. Do that like this:
Images[l].Parent := TheForm;
Obviously your form variable will have a different name, but I'm sure you know what it's called.
When you do this you will find that they all end up on top of each other. Assign to the Top and Left properties to position then. Finally you will likely want to set the Height and Width properties of the images to match the dimensions of the images, Images[l].Picture.Height and Images[l].Picture.Width.
I can't imagine why your code produces an access violation but it's presumably unrelated to the question you asked. The following code proves that what I say above is correct:
procedure TMyForm.FormCreate(Sender: TObject);
var
Image: TImage;
begin
Image := TImage.Create(Self);
Image.Parent := Self;
Image.Picture.LoadFromFile('C:\desktop\image.jpg');
Image.Top := 0;
Image.Left := 0;
Image.Height := Image.Picture.Height;
Image.Width := Image.Picture.Width;
end;
Without your full code I cannot debug your AV.
Why you just don't put your TImages on the form, and just LoadFromFile the ones you want to show ?
Appear to me that would be easier.
But: what you trying to accomplish? From the code, I can imagine you were trying to show a number of images to people count them and answer the question...
So, if you add (and position) the 11 empty(no image) TImages in the form, you can do:
// Any trouble in copying your FormCreate header, David? ;-)
procedure TMyForm.FormCreate(Sender: TObject);
begin
Images[0] := Image_N1; // First TImage
Images[1] := Image_N2;
Images[2] := Image_N3;
// Do that until the 12 slots are filled
// As a exercise for Danny Robinson( the OP ), you can do that in a for..do using
// the Form.Components array property to automate it instead of
// doing one-at-a-line
end;
procedure ClearImages;
var I: Integer;
begin
for I = Low(Images) to High(Images) do
begin
Images.Picture.Graphic := Nil;
end;
end;
procedure LoadImages;
var
k,l:integer;
begin
ClearImages;
Randomize;
k:=Random(11);
for l:= 0 to k do
begin
Images[l].Picture.LoadFromFile(ImagePaths[i])
end;
end;
If you still need to create the TImages on the fly, just create the 12 TImages
once on FormCreate (as in David's answer) and keep calling the LoadImages.
EDIT:
Some ideas, since you are learning.
Creating visual controls on-the-fly is a very boring(in my opinion, of course) task that involves:
Creating the object, obviously
Assigning it to a parent control (forms doesn't need this pass)
Sizing it accordingly to your visual planning
Positioning it in the place of the parent control you want it to be
Set it's anchors, for it to reposition and/or resize when the parent control is resized (if needed)
Only after all this, make it do what you want it to do (in this case, showing images).
Almost all those steps David Heffernan's answer show the code for it. But, unless you really need a dynamic layout, doing all those on design-time is more practical ;-)
You need to set the Parent property of each TImage in order to see them onscreen. You can't use the global Form pointer variable, though, because it has not been assigned yet when the OnCreate event is triggered. So pass in the form's Self pointer as a parameter of LoadImages() instead.
You have another bug - you declared a 12-element TImage array but declared a 7-element String array for the image paths. The way you are using Random(), if it generates a value above 6, you will go out of bounds of the String array.
Try this instead:
const
...
ImagePaths : array [0..6] of string = ('img0.JPG', 'img1.JPG', 'img2.JPG', 'img3.JPG', 'img4.JPG', 'img5.JPG', 'img6.JPG');
var
i: integer;
Images : array [0..6] of TImage;
procedure LoadImages(AParent: TWinControl);
var
i, k: integer;
begin
Randomize;
k := Random(7);
for i := 0 to k do
begin
Images[i] := TImage.Create(nil);
Images[I].Parent := AParent;
// set other properties, like Left/Top...
Images[l].Picture.LoadFromFile(ImagePaths[i]);
end;
end;
procedure TForm4.FormCreate(Sender: TObject);
begin
...
LoadImages(Self);
end;
TImage component must to be painted on the screen,
for do so make a 1pixel panel as the parent to load the graphics.
like in a loading screen so the images can be used as default TImage procedures.

Resources