mirror of
https://git.postgresql.org/git/postgresql.git
synced 2026-02-11 19:17:33 +08:00
Add "-gmt 1" to our test invocations of the Tcl "clock" command, so that they do not consult the timezone environment. While it doesn't really matter which timezone is used here, it does matter that the command not fall over entirely. We've now discovered that at least on FreeBSD, "clock scan" will fail if /etc/localtime is missing. It seems worth making the test insensitive to that. Per Tomas Vondras' buildfarm animal dikkop. Thanks to Thomas Munro for the diagnosis. Discussion: https://postgr.es/m/316d304a-1dcd-cea1-3d6c-27f794727a06@enterprisedb.com
279 lines
6.7 KiB
PL/PgSQL
279 lines
6.7 KiB
PL/PgSQL
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" -gmt 1] -format "%U" -gmt 1]
|
|
$$ 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$;
|