Array parameters to and from postgresql stored procedures using Npgsql from F# - arrays

I have two SQL functions (procedures) in postgresql. They take and return array; their signatures are
create function arr_ret( x int) returns int[] as
and
create function arr_param( x int[] ) returns int as
The first function when executed returns
> ctx.Functions.ArrRet.Invoke(6);;
Executing SQL : EXEC arr_ret(6) - params
val it : Unit = ()
>
As can be seen, the signature of the invoke operation is Unit() = (); doesn't return anything. I would have expected Unit() = int list because the procedure is expected to return an array of integers.
The second function when executed
> ctx.Functions.ArrParam.Invoke( [1;2;3;4;5;6] );;
ctx.Functions.ArrParam.Invoke( [1;2;3;4;5;6] );;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stdin(22,1): error FS0501: The member or object constructor 'Invoke' takes 0 argument(s) but is here given 1. The requir
ed signature is 'SqlDataProvider<...>.dataContext.Functions.ArrParam.Result.Invoke() : SqlDataProvider<...>.dataContext.
Functions.ArrParam.Result.SprocResult'.
Npgsql is not seeing the parameter (either input or output) that is of array type. The documentation says postgresql array and composite types are supported from 3.0+ version and I am using the latest 3.2.3

You are sending a single argument of type FSharpList into a method that expects params. The way you are using it will send the entire list as a single parameter.
ctx.Functions.ArrParam.Invoke(1, 2, 3, 4, 5, 6);;
The above will send them individually as you want, but not if you pass the entire collection. The reason for this is the type provider is trying to resolve the type of object instead treating the entire array as multiple arguments.
In C#, this would work fine, but not in F#.
Here's a good way to test.
In C# define this method:
public static void PrintArgs(params object[] args)
{
foreach (var arg in args)
{
Console.WriteLine($"Type: {arg.GetType().Name}");
}
}
In F# call it as:
PrintArgs(1, 2.0, true, "4")
PrintArgs([1; 2; 3; 4])
They result in:
>
Type: Int32
Type: Double
Type: Boolean
Type: String
val it : unit = ()
>
Type: FSharpList`1
val it : unit = ()
>
Your problem is what happens in the second call, it's actually a List that's being sent and not multiple arguments.

Related

Call C functions from Swift 4

I've generated C code from MATLAB by using the codegen tool. The function can be described as follows:
function [result] = calculate_data(my_matrix)
for idx = 1:length(my_matrix)
result = result + sum(my_matrix(idx,1:3));
end
end
When using the codegen tool, I explicitly stated that my_matrix is a type of double(:inf, 3). In other words, the number of rows is unbounded, but it will have 3 columns. When the code is generated, this is the function that is generated that I am to execute:
calculate_data(my_matrix : UnsafePointer<emxArray_real_T>!, result : UnsafeMutablePointer<emxArray_real_T>!)
emxArray_real_T is defined as follows in a different c file:
struct emxArray_real_T
{
double *data;
int *size;
int allocatedSize;
int numDimensions;
boolean_T canFreeData;
};
When I see my initialization options for the above class, this one in particular makes sense:
emxArray_real_T.init(data: UnsafeMutablePointer<Double>!, size: UnsafeMutablePointer<Int32>!, allocatedSize: Int32, numDimensions: Int32, canFreeData: boolean_T)
I've tried to follow this document as a means to wrap my head around how to call the generated C code, but I think I might be missing a basic step. Here is what I am doing:
// create an 2d array with some fake data
var mySampleData = [[Double]]();
for i in 0 ..< 3 {
mySampleData.append([1.1, 2.2, 3.3]);
}
// begin fulfilling requirements for emxArray_real_T
var data_pointer = UnsafeMutablePointer<Double>.allocate(capacity: 3);
data_pointer.initialize(from: mySampleData)
However, the above code throws an error stating that:
Generic parameter 'C' could not be inferred
I take it that I am then doing something completely wrong, and am probably on an incorrect path. There is a similar post that relates to my question, How to convert float[][] type array to "emxArray_real_T *x" , however the provided solution seems to be for C, as opposed to for Swift 4. How can I effectively call a C function using Swift 4, and meet the requirements of the emxArray_real_T.init method? Using fake data is ok to demonstrate the basic principle.
In a simple Xcode project with mocked C constructs for the struct emxArray_real_T and the function calculate_data I can run the following code successfully. To create an object of type emxArray_real_T I do
var data: [Double] = (0 ..< 12).map(Double.init)
var size: [Int32] = [4, 3]
var array = emxArray_real_T(
data: &data,
size: &size,
allocatedSize: 12,
numDimensions: 2,
canFreeData: false
)
This object can be passed to the function calculate_data like calculate_data(&array, nil). In a real application nil would be another array object. For the sake of simplicity it is just used as a placeholder here.
Your second issue can be solved by using the right types ([Double] instead of Double in line 6):
var mySampleData = [[Double]]();
for i in 0 ..< 3 {
mySampleData.append([i*1, i*2, i*3].map(Double.init));
}
let pointer = UnsafeMutablePointer<[Double]>.allocate(capacity: 3)
pointer.initialize(from: mySampleData, count: 3)
print((pointer + 0).pointee)
print((pointer + 1).pointee)
print((pointer + 2).pointee)
pointer.deallocate()
The output will be
[0.0, 0.0, 0.0]
[1.0, 2.0, 3.0]
[2.0, 4.0, 6.0]
as expected.
I have to admit that I used Swift 5.0.1. This should not make significant differences, though.

'withUnsafeBytes' is deprecated warning when passing void* argument to c function in swift 5

I have a library parsing FIT file in swift using an externally provided c library. The parsing function takes as argument a void * data.
To call the function, I was converting the data using data.withUnsafeBytes( { (ptr: UnsafePointer<UInt8>) in ...} to build the argument to the c function and it was working fine.
After the upgrade of Xcode to swift 5, I now get a deprecated warning
'withUnsafeBytes' is deprecated: use withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R instead
I couldn't work out how to fix the code to remove the deprecated warning. The code has been working fine and without warning in swift 4
I tried to change the argument in the closure to take UnsafeRawBufferPointer instead of the UnsafePointer but this resulted in an error in calling the function: Cannot convert 'UnsafeRawBufferPointer' to expected argument type 'UnsafeRawPointer?'
This is a small swift file to show the problem:
import Foundation
// Create sample data (Typically would be read from a file
let data = Data(repeating: 1, count: 10)
data.withUnsafeBytes( { (ptr : UnsafePointer<UInt8>) in
// call the c function with the void* argument
let value = readFITfile(ptr)
print( value )
})
And an example c function
unsigned readFITfile(const void * data){
//Silly example to show it works, just returning the value of pointer as int
//Typically would parse the data and return a structure
return (unsigned)data;
}
I saved a small repo with the above code here https://github.com/roznet/swift2c and the full scale project with the parsing of the file is here https://github.com/roznet/fit-sdk-swift
You have to change the closure argument to UnsafeRawBufferPointer and then take its baseAdress (which is a UnsafeRawPointer?, the Swift equivalent of void * in C):
data.withUnsafeBytes( { (ptr : UnsafeRawBufferPointer) in
let value = readFITfile(ptr.baseAddress)
// ...
})
The Swift compiler can also infer the closure argument type automatically:
data.withUnsafeBytes( { ptr in
let value = readFITfile(ptr.baseAddress)
// ...
})
For more information about this problem, see withUnsafeBytes Data API confusion in the Swift forum.
To get UnsafePointer now you should do something like that
data.withUnsafeBytes { (ptr: UnsafeRawBufferPointer) in
if let ptrAddress = ptr.baseAddress, ptr.count > 0 {
let pointer = ptrAddress.assumingMemoryBound(to: UInt8.self) // here you got UnsafePointer<UInt8>
let value = readFITfile(ptr)
print( value )
} else {
// Here you should provide some error handling if you want ofc
}
}

Postgres C extension aggregate: How to detect first time aggregate function is called

I'm writing a C extension aggregate function for PostgreSQL , and in C code I would like to know if it is the first time that transition function of the aggregate be called.
For example, I define a aggregate function such as:
CREATE AGGREGATE my_aggregate (text) (
sfunc = my_transfunc,
stype = text,
finalfunc = my_finalfn,
initcond = '');
Then in C code of my_transfunc, how can I know if it is the first time my_transfunc be called ( but not the second, third ... time).
Datum my_transfunc(PG_FUNCTION_ARGS) {
// How to check if the first time function called
if (first_time) { then do something }
else { do some other things }
}
I don't want to use global or static variable here as this made my function is not threaded-safe which violent the requirement for my function.
Generally this is a matter of a proper setting of initcond. Typically you do not need to know whether the function is executed for the first time if only the algorithm is designed properly.
In your case, assuming that the function returns non-empty string, you can check whether the argument is empty (i.e. is equal to initcond). Of course, you can set initcond to a special value instead of an empty string.
Datum my_transfunc(PG_FUNCTION_ARGS) {
text *arg = PG_GETARG_TEXT_PP(0);
int32 arg_size = VARSIZE_ANY_EXHDR(arg);
if (arg_size == 0) { // arg == initcond }
else { // do some other things }
}

what is magic of Scala Array.apply

From array.scala of scala-2.10.4, The Array is defined as
final class Array[T](_length: Int) extends java.io.Serializable with java.lang.Cloneable {
/** The length of the array */
def length: Int = throw new Error()
def apply(i: Int): T = throw new Error()
def update(i: Int, x: T) { throw new Error() }
override def clone(): Array[T] = throw new Error()
}
Please note, the apply method will throw an exception! And for the accompany object Arrry, I find the following codes:
def apply[T: ClassTag](xs: T*): Array[T] = {
val array = new Array[T](xs.length)
var i = 0
for (x <- xs.iterator) { array(i) = x; i += 1 }
array
}
I know there is an implicit parameter which is ClassTag[T], what make me surprised is how
new Array[T] (xs.length)
is compiled. By decompiling the Array.class, I find that line is translated to :
public <T> Object apply(Seq<T> xs, ClassTag<T> evidence$2)
{
// evidence$2 is implicit parameter
Object array = evidence$2.newArray(xs.length());
...
}
I am really confused by this kind of translation, what is the rule under the hood?
Thanks
Chang
The Scala Array Class is just a fake wrapper for the runtime so you can use arrays in Scala. You're probably confused because those methods on the Array class throw exceptions. The reason they did this is so that if you actually end up using the fake class it blows up since really it should be using the java runtime array, which does not have a proper container class like Scala. You can see how the compiler handles it here. When your using arrays in Scala you're probably also using some implicits from predef like ArrayOps and WrappedArray for extra helper methods.
TLDR: Scala compiler magic makes arrays work with the java runtime under the hood.
On the JVM arrays are exempt from type-erasure, e.g. at runtime instead of Array[_] there is a difference between Array[Int], Array[String] and Array[AnyRef] for example. Unlike Java, Scala can handle this mostly transparently, so
class Foo {
val foo = new Array[Int](123)
}
has a direct byte-code invocation for creating the integer array, whereas
class Bar[A](implicit ev: reflect.ClassTag[A]) {
val bar = new Array[A](123)
}
is solved by using the implicit type evidence parameter of type ClassTag[A] so that at runtime the JVM can still create the correct array. This is translated into the call you saw, ev.newArray(123).

HOw to get hold of return value when using dapper to execute

HOw would I make the above code return bool based on the execution. So i can return to the calling method.
public void UpdateSpanStartDate(SpanRecord spanRecord)
{
Run(conn => conn.Execute("[dbo].[SpecailSpanStartUpdate]",
new DynamicParameters(new Dictionary<string, object>
{
{"SpanId", spanRecord.SpanId},
}), null,Config.CommandTimeout, CommandType.StoredProcedure));
}
That depends entirely on where the bool is meant to be coming from. The most common setup would be for the sproc to select some kind out output; if this is the case, the most appropriate thing to do is to use Query<T> along with a LINQ operation such as Single. For example (also tidying up the parameters):
Run(conn => conn.Query<int>("[dbo].[SpecailSpanStartUpdate]",
new {spanRecord.SpanId}, null,
Config.CommandTimeout, CommandType.StoredProcedure).Single() != 0);
Here I'm expecting a single row that has an int in the first column, returning true if the int is non-zero.

Resources