This question is a follow-up to How to get access to a record field .
The more complex (now) code involves binding a whole vector of records. Something along the lines below:
type Tag is record
Field : String := "value";
end record;
type Tag_Access is access all Tag;
package Tags_Vectors is new Indefinite_Vectors
(Index_Type => Positive,
Element_Type => Wheel_Tag);
procedure Bind_Tag (T : in out Tag_Access; Stmt : Gnade.Statement) is
begin
Gnade.Bind_Text (Stmt, T.Field'Address, T.Field'Length);
end Bind_Tag;
procedure Insert_Tags is
Stmt : Gnade.Statement;
Tags : Tags_Vectors.Vector;
-- Make necessary arrangements to populate the Stmt and Tags
C : Tags_Vectors.Cursor := Tags.First;
begin
while Tags_Vectors.Has_Element (C) loop
Bind_Tag (Stmt, Tags_Vectors.Element (C)'Access);
Tags_Vectors.Next (C);
end loop;
Gnade.Step (Db, Stmt);
end Insert_Tag;
I'm not sure what kind of thing Tags_Vector.Element (C)
returns. Syntactically, at least, it seems Ada doesn't object to this having an access attribute. But, I don't understand the error (which side does it think is the variable and which side is the constant?) Why is it bad that access to variable designates a constant? (Is it trying to say that I might be changing the value of a constant? -- but I never wanted any of those things to be constants...)
The main issue is that Tag_Vectors.Element returns a temporary element and not one that can be modified on the fly. It appears as constant to the compiler and the function needs an "in out" which denotes "variable" modification. That means you need a more permanent variable to hold it. Additionally it needs to be a access variable, not an element. So you need to change a couple of things.
You can either make a variable for the element and one for its access as well and use those:
procedure Insert_Tags is
Stmt : Gnade.Statement;
Tags : Tags_Vectors.Vector;
-- Make necessary arrangements to populate the Stmt and Tags
C : Tags_Vectors.Cursor := Tags.First;
Temp : aliased Wheel_Tag;
Temp_Access : Tag_Access;
begin
while Tags_Vectors.Has_Element (C) loop
Temp := Tags_Vectors.Element(C);
Temp_Access := Temp'Unchecked_Access;
Bind_Tag (Temp_Access, Stmt);
Tags_Vectors.Next (C);
end loop;
Gnade.Step (Db, Stmt);
end Insert_Tags;
Or you can also just use an access variable and the Reference function of the vector:
procedure Insert_Tags is
Stmt : Gnade.Statement;
Tags : Tags_Vectors.Vector;
-- Make necessary arrangements to populate the Stmt and Tags
C : Tags_Vectors.Cursor := Tags.First;
Temp_Access : Tag_Access;
begin
while Tags_Vectors.Has_Element (C) loop
Temp_Access := Tags.Reference(C).Element;
Bind_Tag (Temp_Access, Stmt);
Tags_Vectors.Next (C);
end loop;
Gnade.Step (Db, Stmt);
end Insert_Tags;
Note that these access variable assignments are only ok if Bind_Tag doesn't save the access internally. If it does, then you have to ensure that those vector elements are never moved or deleted while the internal workings hold those access values.