I'm trying to maintain a Php application with a PostgreSQL database. At one point, a stored procedure is called, lets say function_x and inside function_x, function_y is called; function_y is passed a variable named parameter_1, and the definition of parameter_1 is:
parameter_1 numeric[][3] := {};
I'm trying to do a select function_y directly on the command line (or pgadmin) but I'm having problems passing an empty array into the function. according to the docs you have to use variadic but so I tried:
select function_y(581, 'CPN-00000000001-0000', 'TPN-00000000001-0001', 100, 2013, variadic arr := array[]);
But I got this error:
ERROR: cannot determine type of empty array
I tried different approaches but nothing works. How can I pass a multidimensional array as a parameter at a query?
1) You can, but you do not have to use VARIADIC parameters for array variables. You'd have to use it in the declaration of the function, not in the call, though.
2) Postgres array variables ignore dimensions in the definition. I quote the manual here:
The current implementation does not enforce the declared number of
dimensions either. Arrays of a particular element type are all
considered to be of the same type, regardless of size or number of
dimensions. So, declaring the array size or number of dimensions in
CREATE TABLE is simply documentation; it does not affect run-time behavior.
3) This is invalid syntax:
parameter_1 numeric[][3] := {};
Single quotes are required:
parameter_1 numeric[][3] := '{}';
Which is effectively the same as
parameter_1 numeric[] := '{}';
More details, code examples and links in this closely related answer:
Return rows matching elements of input array in plpgsql function
Related
I'm trying to do something with array passing and access types. I've run into a situation where the stack size on an embedded system makes it difficult to pass around a large array through the typical parameter passing mechanism.
To save stack size, I've started using access types but I don't want to do dynamic allocation.
What I have is something like this:
type My_Array_Type is array (Natural range<>) of Integer;
type My_Array_Type_Ptr is access all My_Array_Type;
procedure Do_Stuff(Things : My_Array_Type_Ptr) is
begin
-- things
end Do_Stuff;
procedure Do_Stuff(Num_Things : Integer) is
Things : My_Array_Type_Ptr := new My_Array_Type(1..Num_Things);
begin
Do_Stuff(Things);
-- more things
end Do_Stuff;
HOWEVER, what I'd like to do is something like this:
type My_Array_Type is array (Natural range<>) of Integer;
procedure Do_Stuff(Things : access all My_Array_Type) is
begin
-- things
end Do_Stuff;
procedure Do_Stuff(Num_Things : Integer) is
Things : aliased My_Array_Type(1..Num_Things);
begin
Do_Stuff(Things'Access);
-- more things
end Do_Stuff;
But obviously it doesn't work.
Essentially, I want to pass a reference to the stack allocated array and change it in the other subprogram, but I don't want dynamically allocated memory. How can I do this?
Also, as a side note: I keep seeing conflicting information about if something is dynamically allocated if it has to be released or not -- I read most implementations don't have garbage collectors but don't need them. Can anyone clarify -- In the example I showed first, do I need to explicitly deallocate?
EDIT:
After trying the solutions mentioned below, I settled on a combination of two things:
Using the in out parameter passing mechanism.
Reducing the storage requirements of my data type.
So rather than Integer I'm using:
type UInt8 is new Interfaces.Unsigned_8;
Which is:
type UInt8 is mod 2**8
with Size => 8;
This works perfectly, since my values aren't actually integers, they are in fact unsigned bytes.
In Ada, you really don’t need to use access types for this situation.
Remarks below for native Ada code; for imported (& I suppose exported) subprograms the generated code obviously needs to obey the foreign language conventions.
The mode of a parameter (whether you’re allowed to write to it, whether (if you’re allowed to write to it) it has some initial value) is distinct from the parameter passing mechanism.
If you have a parameter of size larger than a register and the parameter passing mechanism is not by-reference (i.e. by passing the address of the actual object), complain to your compiler vendor!
The Ada way would be like this:
with Ada.Text_IO; use Ada.Text_IO;
with System.Storage_Elements;
procedure Jsinglet is
type My_Array_Type is array (Natural range<>) of Integer;
procedure Do_Stuff_1 (Things : in out My_Array_Type) is
begin
Put_Line (System.Storage_Elements.To_Integer (Things'Address)'Img);
end Do_Stuff_1;
procedure Do_Stuff (Num_Things : Integer) is
Things : My_Array_Type (1 .. Num_Things);
begin
Put_Line (System.Storage_Elements.To_Integer (Things'Address)'Img);
Do_Stuff_1 (Things);
end Do_Stuff;
begin
Do_Stuff (42);
end Jsinglet;
Running the program results here in
$ ./jsinglet
140732831549024
140732831549024
showing that the address has been passed, not the value.
The in out mode on Do_Stuff_1’s parameter means that Do_Stuff_1 can read the contents of the array passed to it before writing to it.
out would mean that Do_Stuff_1 shouldn’t read the contents until it has itself written them (it can, but - depending on the parameter’s type - it may read uninitialized or default-initialized data)
in would mean that the contents couldn’t be written to.
As of Ada2012 you can mark parameters as aliased and they will be passed by reference, but your source object must also be either tagged or aliased.
EDIT: It cannot be an array either it appears, so look below. Aliased parameters do work for types like integers, enumerations, records, etc. though.
You can also wrap the array in a tagged or limited record to force the compiler to use by reference passing as those are "by reference" types
type My_Array_Type is array (Natural range<>) of Integer;
type By_Reference(Length : Natural) is tagged record -- or limited
Elements : My_Array_Type(1..Length);
end record;
procedure Do_Stuff(Things : in out By_Reference) is
begin
-- things
end Do_Stuff;
procedure Do_Stuff(Num_Things : Integer) is
Things : By_Reference(Num_Things);
begin
Do_Stuff(Things);
-- more things
end Do_Stuff;
For your deallocation question, your example must explicitly deallocate the memory. There are ways to get automatic deallocation:
Compiler with Garbage Collection (I know of none)
Custom 3rd party library that provides it
Use a holder or container from Ada.Containers
Use a local (non library level) named access type with a specified storage size (your access type is library level and has not storage size specified). When the access type goes out of scope it will deallocate.
I Am having two arrays named atest and NEWARRAY,I have tried to compare the elements of two arrays with simple if()and this is comparing only the first element of an array , how to compare all the array values at once,here's my code
IF (Alltrim(atest)== Alltrim(NEWARRAY))
Messagebox('Success',64,'Status')
Else
Messagebox('MisMatch',16,'Status')
ENDIF
Fox has a few functions that operate on whole arrays - like acopy, ascan and asort - but there is no built-in function that compares whole arrays. So you'll have to do the comparison element per element, for example with a for loop.
And yes, if you use an array name as an expression - including passing it by value - then you'll get the value of the first array element instead. There is one exception, though: when you pass an array to a built-in function in a place where an array parameter is expected then the compiler will automatically emit a reference token under the hood in order to arrange pass-by-reference instead of pass-by-value.
So, if you have a user-defined function f() to which you want to pass an array a then you need to call it like this: f(#m.a) but you can call built-in functions taking arrays like this: alen(a) (since the m. can be left off in this situation as well). In fact, Fox would complain if you coded something like alen(#m.a) or alen(#a), and older Foxen could even crash in such situations.
Conversely, if an array is the target of an assignment like a = 42 or store 42 to a then the value will be assigned to all array elements. This is convenient for initialising arrays to something like 0, '' or .null..
Hence, if you have two arrays a and b then a = b will assign the first value of b to all elements of a, and if a == b will compare the respective first cells only.
Sidenote: should you ever have to compare records from tables with equal or equivalent structure then you should remember to look up compobj(). It does for objects and scatter records what Fox won't do for arrays: it compares them whole-sale. That is, it compares the values of properties with matching names and tells you if there's a mismatch, and it does so much faster than hand-crafted code could do it.
Theoretically you could gather an array into a table/cursor record and then use scatter name Walther to produce a scatter record, which could then be compared to a scatter record named Herbert that was produced in a similar fashion from the contents of the other array: compobj(m.Walther, m.Herbert) would tell you whether the original arrays were equal or not. However, I'd be hard pressed to imagine circumstances where one might use something like that in production code...
You could create a simple procedure like this for comparison:
Procedure CompareArrays(ta1, ta2)
If Alen(ta1) != Alen(ta2)
Return .F.
EndIf
Local ix
For ix=1 to Alen(ta1)
If (Type('ta1[m.ix]') != Type('ta2[m.ix]') or ta1[m.ix] != ta2[m.ix])
Return .F.
endif
endfor
endproc
And pass your arrays by reference. ie:
isIdentical = CompareArrays(#laArr1, #laArr2)
If array members could hold objects, you should use compobj for comparison of array elements.
I have a very simple code snippet which you can check here:
type
TMatrix = array of array of Byte;
PMatrix = ^TMatrix;
const
testarray:array [0..2,0..2] of Byte=(
(1,2,3), (4,5,6), (7,8,9));
function PickValue(input:PMatrix):Byte;
begin
Result:=input^[1,3];
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Showmessage(inttostr(PickValue(#testarray)));
end;
end.
How can I cast testarray properly to pass it to the PickValue function? Above code crashes in its current form. I'm using delphi 2007.
Thanks in advance!
You cannot cast that static array to be a dynamic array. These types are simply not compatible. The static array is laid out in one contiguous block of memory. The dynamic array has indirection to variable sized arrays at each dimension. In effect think of it as ^^Byte with extra compiler management and meta data. No amount of casting can help you.
You have, at least, the following options:
Copy the contents of the static array to a dynamic array. Then pass that dynamic array to your function.
Switch your static array to be a dynamic array so that no conversion is needed.
Arrange that your function accepts static arrays rather than dynamic arrays, again to avoid requiring a conversion.
Have the function accept a pointer to the first element and the inner dimension. Then perform the indexing manually. The i,j element is at linear offset i*innerDim + j.
Your pointer type PMatrix is probably not needed. Dynamic arrays are already implemented as pointers. This seems to be a level of indirection too far.
Of course, asking for element 3 when the array indices only go up to 2 isn't right, but that is presently the lesser of your concerns. Remember that dynamic arrays are zero based and you have specified zero based for your static array.
I am struggling to be able to recommend which solution is best since I don't understand your real goals and usage based on the simplified example presented here.
How does one access an element of an array that is returned from a function? For example, shape() returns an array of integers. How does one compare an element of that array to an integer? The following does not compile:
integer :: a
integer, dimension(5) :: b
a = 5
if (a .eq. shape(b)) then
print *, 'equal'
end if
The error is:
if (a .eq. shape(c)) then
1
Error: IF clause at (1) requires a scalar LOGICAL expression
I understand that this is because shape(c) returns an array. However, accessing an element of the array does not appear to be possible like so: shape(c)(1)
Now if I add these two lines:
integer, dimension(1) :: c
c = shape(b)
...and change the if clause to this:
if (a .eq. c(1)) then
... then it works. But do I really have to declare an extra array variable to hold the return value of shape(), or is there some other way to do it?
Further to the answers that deal with SHAPE and logical expressions etc, the general answer to your question "How does one access an element of an array that is returned from a function?" is
you assign the expression that has the function reference to an array variable, and then index that array variable.
you use the expression that has the function reference as an actual argument to a procedure that takes a dummy array argument, and does the indexing for you.
Consequently, the general answer to your last questions "But do I really have to declare an extra array variable to hold the return value of shape(), or is there some other way to do it?" is "Yes, you do need to declare another array variable" and hence "No, there is no other way".
(Note that reasonable optimising compilers will avoid the need for any additional memory operations/allocations etc once they have the result of the array function, it's really just a syntax issue.)
The rationale for this particular aspect of language design is sometimes ascribed to a need to avoid syntax ambiguity and confusion for array function results that are of character type (they could potentially be indexed and/or substringed - how do you tell what was intended?). Others think it was done this way just to annoy C programmers.
Instead of using shape(array), I would use size(array).
Note that this will return an integer indicating how many elements there are in ALL dimensions, unless you specify the DIM attribute, in which case it will return only the number of elements in the specified dimension.
Take a look at the gfortran documentation:
http://gcc.gnu.org/onlinedocs/gfortran/SIZE.html.
Also, look up lbound and ubound.
Note that the expression
a == shape(b)
returns a rank-1 array of logicals and the if statement requires that the condition reduce to a scalar logical expression. You could reduce the rank-1 array to a scalar like this:
if (all(a == shape(b)))
This is certainly not a general replacement for the syntactically-invalid application of array indexing to an array-returning function such as shape(b)(1).
It is possible even without the intermediate variable using ASSOCIATE:
real c(3,3)
associate (x=>shape(c))
print *,x(1),x(2)
end associate
end
I have quite a few variables declared as
var
Something: array of XXX;
begin
SetLength(Something, 10);
try
...
finally
SetLength(Something, 0);
end;
end;
To what extend is safe to have them replaced:
var
Something: TArray<XXX>;
begin
SetLength(Something, 10);
try
...
finally
SetLength(Something, 0);
end;
end;
As already answered, TArray<XXX> is exactly like any other custom type defined as array of XXX. In fact, TArray<XXX> is a custom type defined as array of XXX.
That said, a custom type defined as array of XXX is not equivalent to array of XXX in the context of a procedure or function parameter. In procedure Foo(x: array of Integer), x is an open array parameter, which can accept any type of integer array. In contrast, procedure Foo(x: TArray<Integer>) takes an actual TArray<Integer> type only. You can see the difference when attempting to pass a fixed-size array, but also when attempting to pass a TDynIntegerArray (a different type, also defined as array of Integer).
So, for variables, sure, if you have array of XXX, change it to TArray<XXX> all you want. Just make sure you don't do a global search and replace.
It is perfectly safe to do this. The compiler will produce identical output.
I personally would, all other things being equal, recommend doing so. The use of the generic array TArray<T> gives you much more flexibility and better type compatibility.
Of course those benefits can only be seen with more realistic code that does some work. You most typically see benefits when using generic containers. But you might also see benefits when trying to build code using multiple different libraries.
The use of generic arrays allows easy type compatibility. Before generic arrays you would define an array type like this:
TIntArray = array of Integer;
If two libraries do this then you have incompatible types. If the libraries agree to use generic arrays then there will be compatibility.
To see this more clearly, consider this fragment:
type
TIntArray1 = array of Integer;
TIntArray2 = array of Integer;
....
var
arr1: TIntArray1;
arr2: TIntArray2;
....
arr1 := arr2;
This assignment is not valid and fails with a type mis-match compiler error. This is entirely to be expected within the Pascal language. It is after all strongly typed and these are distinct types. Even if they are implemented identically.
On the other hand:
var
arr1: TArray<Integer>;
arr2: TArray<Integer>;
....
arr1 := arr2;
is valid and does compile. The documentation for generic type compatibility says:
Two instantiated generics are considered assignment compatible if the base types are identical (or are aliases to a common type) and the type arguments are identical.