blob: e9f59989b5b8261b8577169103af6ee29db9aef0 [file] [log] [blame]
create table T_comp1 (
tkey char(10),
ref1 int4,
ref2 char(20)
);
create function tcl_composite_arg_ref1(T_comp1) returns int as '
return $1(ref1)
' language pltcl;
create function tcl_composite_arg_ref2(T_comp1) returns text as '
return $1(ref2)
' language pltcl;
create function tcl_argisnull(text) returns bool as '
argisnull 1
' language pltcl;
create function tcl_int4add(int4,int4) returns int4 as '
return [expr $1 + $2]
' language pltcl;
-- We use split(n) as a quick-and-dirty way of parsing the input array
-- value, which comes in as a string like '{1,2}'. There are better ways...
create function tcl_int4_accum(int4[], int4) returns int4[] as '
set state [split $1 "{,}"]
set newsum [expr {[lindex $state 1] + $2}]
set newcnt [expr {[lindex $state 2] + 1}]
return "{$newsum,$newcnt}"
' language pltcl;
create function tcl_int4_avg(int4[]) returns int4 as '
set state [split $1 "{,}"]
if {[lindex $state 2] == 0} { return_null }
return [expr {[lindex $state 1] / [lindex $state 2]}]
' language pltcl;
create aggregate tcl_avg (
sfunc = tcl_int4_accum,
basetype = int4,
stype = int4[],
finalfunc = tcl_int4_avg,
initcond = '{0,0}'
);
create aggregate tcl_sum (
sfunc = tcl_int4add,
basetype = int4,
stype = int4,
initcond1 = 0
);
create function tcl_int4lt(int4,int4) returns bool as '
if {$1 < $2} {
return t
}
return f
' language pltcl;
create function tcl_int4le(int4,int4) returns bool as '
if {$1 <= $2} {
return t
}
return f
' language pltcl;
create function tcl_int4eq(int4,int4) returns bool as '
if {$1 == $2} {
return t
}
return f
' language pltcl;
create function tcl_int4ge(int4,int4) returns bool as '
if {$1 >= $2} {
return t
}
return f
' language pltcl;
create function tcl_int4gt(int4,int4) returns bool as '
if {$1 > $2} {
return t
}
return f
' language pltcl;
create operator @< (
leftarg = int4,
rightarg = int4,
procedure = tcl_int4lt
);
create operator @<= (
leftarg = int4,
rightarg = int4,
procedure = tcl_int4le
);
create operator @= (
leftarg = int4,
rightarg = int4,
procedure = tcl_int4eq
);
create operator @>= (
leftarg = int4,
rightarg = int4,
procedure = tcl_int4ge
);
create operator @> (
leftarg = int4,
rightarg = int4,
procedure = tcl_int4gt
);
create function tcl_int4cmp(int4,int4) returns int4 as '
if {$1 < $2} {
return -1
}
if {$1 > $2} {
return 1
}
return 0
' language pltcl;
CREATE OPERATOR CLASS tcl_int4_ops
FOR TYPE int4 USING btree AS
OPERATOR 1 @<,
OPERATOR 2 @<=,
OPERATOR 3 @=,
OPERATOR 4 @>=,
OPERATOR 5 @>,
FUNCTION 1 tcl_int4cmp(int4,int4) ;
--
-- Test usage of Tcl's "clock" command. In recent Tcl versions this
-- command fails without working "unknown" support, so it's a good canary
-- for initialization problems.
--
create function tcl_date_week(int4,int4,int4) returns text as $$
return [clock format [clock scan "$2/$3/$1"] -format "%U"]
$$ language pltcl immutable;
select tcl_date_week(2010,1,26);
select tcl_date_week(2001,10,24);
-- test pltcl event triggers
create function tclsnitch() returns event_trigger language pltcl as $$
elog NOTICE "tclsnitch: $TG_event $TG_tag"
$$;
create event trigger tcl_a_snitch on ddl_command_start execute procedure tclsnitch();
create event trigger tcl_b_snitch on ddl_command_end execute procedure tclsnitch();
create function foobar() returns int language sql as $$select 1;$$;
alter function foobar() cost 77;
drop function foobar();
create table foo();
drop table foo;
drop event trigger tcl_a_snitch;
drop event trigger tcl_b_snitch;
create function tcl_test_cube_squared(in int, out squared int, out cubed int) as $$
return [list squared [expr {$1 * $1}] cubed [expr {$1 * $1 * $1}]]
$$ language pltcl;
create function tcl_test_squared_rows(int,int) returns table (x int, y int) as $$
for {set i $1} {$i < $2} {incr i} {
return_next [list y [expr {$i * $i}] x $i]
}
$$ language pltcl;
create function tcl_test_sequence(int,int) returns setof int as $$
for {set i $1} {$i < $2} {incr i} {
return_next $i
}
$$ language pltcl;
create function tcl_eval(string text) returns text as $$
eval $1
$$ language pltcl;
-- test use of errorCode in error handling
create function tcl_error_handling_test(text) returns text
language pltcl
as $function$
if {[catch $1 err]} {
# If not a Postgres error, just return the basic error message
if {[lindex $::errorCode 0] != "POSTGRES"} {
return $err
}
# Get rid of keys that can't be expected to remain constant
array set myArray $::errorCode
unset myArray(POSTGRES)
unset -nocomplain myArray(funcname)
unset -nocomplain myArray(filename)
unset -nocomplain myArray(lineno)
# Format into something nicer
set vals []
foreach {key} [lsort [array names myArray]] {
set value [string map {"\n" "\n\t"} $myArray($key)]
lappend vals "$key: $value"
}
return [join $vals "\n"]
} else {
return "no error"
}
$function$;
-- test spi_exec and spi_execp with -array
create function tcl_spi_exec(
prepare boolean,
action text
)
returns void language pltcl AS $function$
set query "select * from (values (1,'foo'),(2,'bar'),(3,'baz')) v(col1,col2)"
if {$1 == "t"} {
set prep [spi_prepare $query {}]
spi_execp -array A $prep {
elog NOTICE "col1 $A(col1), col2 $A(col2)"
switch $A(col1) {
2 {
elog NOTICE "action: $2"
switch $2 {
break {
break
}
continue {
continue
}
return {
return
}
error {
error "error message"
}
}
error "should not get here"
}
}
}
} else {
spi_exec -array A $query {
elog NOTICE "col1 $A(col1), col2 $A(col2)"
switch $A(col1) {
2 {
elog NOTICE "action: $2"
switch $2 {
break {
break
}
continue {
continue
}
return {
return
}
error {
error "error message"
}
}
error "should not get here"
}
}
}
}
elog NOTICE "end of function"
$function$;