1create table T_comp1 ( 2 tkey char(10), 3 ref1 int4, 4 ref2 char(20) 5); 6 7create function tcl_composite_arg_ref1(T_comp1) returns int as ' 8 return $1(ref1) 9' language pltcl; 10 11create function tcl_composite_arg_ref2(T_comp1) returns text as ' 12 return $1(ref2) 13' language pltcl; 14 15create function tcl_argisnull(text) returns bool as ' 16 argisnull 1 17' language pltcl; 18 19 20create function tcl_int4add(int4,int4) returns int4 as ' 21 return [expr $1 + $2] 22' language pltcl; 23 24-- We use split(n) as a quick-and-dirty way of parsing the input array 25-- value, which comes in as a string like '{1,2}'. There are better ways... 26 27create function tcl_int4_accum(int4[], int4) returns int4[] as ' 28 set state [split $1 "{,}"] 29 set newsum [expr {[lindex $state 1] + $2}] 30 set newcnt [expr {[lindex $state 2] + 1}] 31 return "{$newsum,$newcnt}" 32' language pltcl; 33 34create function tcl_int4_avg(int4[]) returns int4 as ' 35 set state [split $1 "{,}"] 36 if {[lindex $state 2] == 0} { return_null } 37 return [expr {[lindex $state 1] / [lindex $state 2]}] 38' language pltcl; 39 40create aggregate tcl_avg ( 41 sfunc = tcl_int4_accum, 42 basetype = int4, 43 stype = int4[], 44 finalfunc = tcl_int4_avg, 45 initcond = '{0,0}' 46 ); 47 48create aggregate tcl_sum ( 49 sfunc = tcl_int4add, 50 basetype = int4, 51 stype = int4, 52 initcond1 = 0 53 ); 54 55create function tcl_int4lt(int4,int4) returns bool as ' 56 if {$1 < $2} { 57 return t 58 } 59 return f 60' language pltcl; 61 62create function tcl_int4le(int4,int4) returns bool as ' 63 if {$1 <= $2} { 64 return t 65 } 66 return f 67' language pltcl; 68 69create function tcl_int4eq(int4,int4) returns bool as ' 70 if {$1 == $2} { 71 return t 72 } 73 return f 74' language pltcl; 75 76create function tcl_int4ge(int4,int4) returns bool as ' 77 if {$1 >= $2} { 78 return t 79 } 80 return f 81' language pltcl; 82 83create function tcl_int4gt(int4,int4) returns bool as ' 84 if {$1 > $2} { 85 return t 86 } 87 return f 88' language pltcl; 89 90create operator @< ( 91 leftarg = int4, 92 rightarg = int4, 93 procedure = tcl_int4lt 94 ); 95 96create operator @<= ( 97 leftarg = int4, 98 rightarg = int4, 99 procedure = tcl_int4le 100 ); 101 102create operator @= ( 103 leftarg = int4, 104 rightarg = int4, 105 procedure = tcl_int4eq 106 ); 107 108create operator @>= ( 109 leftarg = int4, 110 rightarg = int4, 111 procedure = tcl_int4ge 112 ); 113 114create operator @> ( 115 leftarg = int4, 116 rightarg = int4, 117 procedure = tcl_int4gt 118 ); 119 120create function tcl_int4cmp(int4,int4) returns int4 as ' 121 if {$1 < $2} { 122 return -1 123 } 124 if {$1 > $2} { 125 return 1 126 } 127 return 0 128' language pltcl; 129 130CREATE OPERATOR CLASS tcl_int4_ops 131 FOR TYPE int4 USING btree AS 132 OPERATOR 1 @<, 133 OPERATOR 2 @<=, 134 OPERATOR 3 @=, 135 OPERATOR 4 @>=, 136 OPERATOR 5 @>, 137 FUNCTION 1 tcl_int4cmp(int4,int4) ; 138 139-- 140-- Test usage of Tcl's "clock" command. In recent Tcl versions this 141-- command fails without working "unknown" support, so it's a good canary 142-- for initialization problems. 143-- 144create function tcl_date_week(int4,int4,int4) returns text as $$ 145 return [clock format [clock scan "$2/$3/$1"] -format "%U"] 146$$ language pltcl immutable; 147 148select tcl_date_week(2010,1,26); 149select tcl_date_week(2001,10,24); 150 151-- test pltcl event triggers 152create function tclsnitch() returns event_trigger language pltcl as $$ 153 elog NOTICE "tclsnitch: $TG_event $TG_tag" 154$$; 155 156create event trigger tcl_a_snitch on ddl_command_start execute procedure tclsnitch(); 157create event trigger tcl_b_snitch on ddl_command_end execute procedure tclsnitch(); 158 159create function foobar() returns int language sql as $$select 1;$$; 160alter function foobar() cost 77; 161drop function foobar(); 162 163create table foo(); 164drop table foo; 165 166drop event trigger tcl_a_snitch; 167drop event trigger tcl_b_snitch; 168 169create function tcl_test_cube_squared(in int, out squared int, out cubed int) as $$ 170 return [list squared [expr {$1 * $1}] cubed [expr {$1 * $1 * $1}]] 171$$ language pltcl; 172 173create function tcl_test_squared_rows(int,int) returns table (x int, y int) as $$ 174 for {set i $1} {$i < $2} {incr i} { 175 return_next [list y [expr {$i * $i}] x $i] 176 } 177$$ language pltcl; 178 179create function tcl_test_sequence(int,int) returns setof int as $$ 180 for {set i $1} {$i < $2} {incr i} { 181 return_next $i 182 } 183$$ language pltcl; 184 185create function tcl_eval(string text) returns text as $$ 186 eval $1 187$$ language pltcl; 188 189-- test use of errorCode in error handling 190create function tcl_error_handling_test(text) returns text 191language pltcl 192as $function$ 193 if {[catch $1 err]} { 194 # If not a Postgres error, just return the basic error message 195 if {[lindex $::errorCode 0] != "POSTGRES"} { 196 return $err 197 } 198 199 # Get rid of keys that can't be expected to remain constant 200 array set myArray $::errorCode 201 unset myArray(POSTGRES) 202 unset -nocomplain myArray(funcname) 203 unset -nocomplain myArray(filename) 204 unset -nocomplain myArray(lineno) 205 206 # Format into something nicer 207 set vals [] 208 foreach {key} [lsort [array names myArray]] { 209 set value [string map {"\n" "\n\t"} $myArray($key)] 210 lappend vals "$key: $value" 211 } 212 return [join $vals "\n"] 213 } else { 214 return "no error" 215 } 216$function$; 217 218-- test spi_exec and spi_execp with -array 219create function tcl_spi_exec( 220 prepare boolean, 221 action text 222) 223returns void language pltcl AS $function$ 224set query "select * from (values (1,'foo'),(2,'bar'),(3,'baz')) v(col1,col2)" 225if {$1 == "t"} { 226 set prep [spi_prepare $query {}] 227 spi_execp -array A $prep { 228 elog NOTICE "col1 $A(col1), col2 $A(col2)" 229 230 switch $A(col1) { 231 2 { 232 elog NOTICE "action: $2" 233 switch $2 { 234 break { 235 break 236 } 237 continue { 238 continue 239 } 240 return { 241 return 242 } 243 error { 244 error "error message" 245 } 246 } 247 error "should not get here" 248 } 249 } 250 } 251} else { 252 spi_exec -array A $query { 253 elog NOTICE "col1 $A(col1), col2 $A(col2)" 254 255 switch $A(col1) { 256 2 { 257 elog NOTICE "action: $2" 258 switch $2 { 259 break { 260 break 261 } 262 continue { 263 continue 264 } 265 return { 266 return 267 } 268 error { 269 error "error message" 270 } 271 } 272 error "should not get here" 273 } 274 } 275 } 276} 277elog NOTICE "end of function" 278$function$; 279