The documentation is a little gnostic, but it includes this:
The argument values supplied to a PL/Tcl function's code are simply the input arguments converted to text form (just as if they had been displayed by a SELECT
statement). Conversely, the return
command will accept any string that is acceptable input format for the function's declared return type. So, within the PL/Tcl function, all values are just text strings.
So the array value from Tcl's PoV is going to be {1,2,3}
or something like that. Everything else is converting between that serialization and Tcl's lists. (All this will also work just fine for other types of numeric array, but will be dangerous if you do arrays of characters or strings, as the delimiter characters can appear within. Of course, in that case I'd also think you were doing something a bit wrong in the first place…)
Handling PostgreSQL int[]
arrays
To extract the integers from such a thing, we'd do:
set tclListOfValues [split [string trim $1 "{}"] ","]
After that, you can use llength
and lindex
and foreach
and so on. The reverse operation, converting a Tcl list (assumed to be of integers) to an int[]
for returning:
return \{[join $tclListOfValues ","]\}
Handling nested PostgreSQL arrays
Things will get a lot more awkward if you need to access nested arrays. The issue is that it's a two-level split, and that's best done by applying some clever magic with string map
before the outer split
:
set listOfLists {}
foreach innerArray [split [string map {"\},\{" "\u0000"} [string trim $1 "{}"]] "\u0000"] {
lappend listOfLists [split $innerArray ","]
}
In Tcl 8.6, you can do this slightly more neatly with lmap
like this (conceptually a one-liner, but broken up for clarity):
set listOfLists [lmap innerArray \
[split [string map {"\},\{" "\u0000"} [string trim $1 "{}"]] "\u0000"] {
split $innerArray ","
}]
In the reverse direction:
set resultAccumulator {}
foreach innerList $listOfLists {
lappend resultAccumulator [join $innerList ","]
}
return \{[join $resultAccumulator "\},\{"]\}
Or in Tcl 8.6 style with lmap
again:
return \{[join [lmap innerList $listOfLists {join $innerList ","}] "\},\{"]\}