@@ -185,12 +185,23 @@ select * from T_pkey2 order by key1 using @<, key2 collate "C";
185185
186186-- show dump of trigger data
187187insert into trigger_test values(1,'insert');
188- NOTICE: NEW: {i: 1, v: insert}
188+ NOTICE: NEW: {}
189+ NOTICE: OLD: {}
190+ NOTICE: TG_level: STATEMENT
191+ NOTICE: TG_name: statement_trigger
192+ NOTICE: TG_op: INSERT
193+ NOTICE: TG_relatts: {{} i v {} test_skip test_return_null test_argisnull}
194+ NOTICE: TG_relid: bogus:12345
195+ NOTICE: TG_table_name: trigger_test
196+ NOTICE: TG_table_schema: public
197+ NOTICE: TG_when: BEFORE
198+ NOTICE: args: {42 {statement trigger}}
199+ NOTICE: NEW: {i: 1, test_argisnull: f, test_return_null: f, test_skip: f, v: insert}
189200NOTICE: OLD: {}
190201NOTICE: TG_level: ROW
191202NOTICE: TG_name: show_trigger_data_trig
192203NOTICE: TG_op: INSERT
193- NOTICE: TG_relatts: {{} i v}
204+ NOTICE: TG_relatts: {{} i v {} test_skip test_return_null test_argisnull }
194205NOTICE: TG_relid: bogus:12345
195206NOTICE: TG_table_name: trigger_test
196207NOTICE: TG_table_schema: public
@@ -232,30 +243,77 @@ NOTICE: TG_table_name: trigger_test_view
232243NOTICE: TG_table_schema: public
233244NOTICE: TG_when: {INSTEAD OF}
234245NOTICE: args: {24 {skidoo view}}
246+ update trigger_test set v = 'update', test_skip=true where i = 1;
247+ NOTICE: NEW: {}
248+ NOTICE: OLD: {}
249+ NOTICE: TG_level: STATEMENT
250+ NOTICE: TG_name: statement_trigger
251+ NOTICE: TG_op: UPDATE
252+ NOTICE: TG_relatts: {{} i v {} test_skip test_return_null test_argisnull}
253+ NOTICE: TG_relid: bogus:12345
254+ NOTICE: TG_table_name: trigger_test
255+ NOTICE: TG_table_schema: public
256+ NOTICE: TG_when: BEFORE
257+ NOTICE: args: {42 {statement trigger}}
258+ NOTICE: SKIPPING OPERATION UPDATE
235259update trigger_test set v = 'update' where i = 1;
236- NOTICE: NEW: {i: 1, v: update}
237- NOTICE: OLD: {i: 1, v: insert}
260+ NOTICE: NEW: {}
261+ NOTICE: OLD: {}
262+ NOTICE: TG_level: STATEMENT
263+ NOTICE: TG_name: statement_trigger
264+ NOTICE: TG_op: UPDATE
265+ NOTICE: TG_relatts: {{} i v {} test_skip test_return_null test_argisnull}
266+ NOTICE: TG_relid: bogus:12345
267+ NOTICE: TG_table_name: trigger_test
268+ NOTICE: TG_table_schema: public
269+ NOTICE: TG_when: BEFORE
270+ NOTICE: args: {42 {statement trigger}}
271+ NOTICE: NEW: {i: 1, test_argisnull: f, test_return_null: f, test_skip: f, v: update}
272+ NOTICE: OLD: {i: 1, test_argisnull: f, test_return_null: f, test_skip: f, v: insert}
238273NOTICE: TG_level: ROW
239274NOTICE: TG_name: show_trigger_data_trig
240275NOTICE: TG_op: UPDATE
241- NOTICE: TG_relatts: {{} i v}
276+ NOTICE: TG_relatts: {{} i v {} test_skip test_return_null test_argisnull }
242277NOTICE: TG_relid: bogus:12345
243278NOTICE: TG_table_name: trigger_test
244279NOTICE: TG_table_schema: public
245280NOTICE: TG_when: BEFORE
246281NOTICE: args: {23 skidoo}
247282delete from trigger_test;
248283NOTICE: NEW: {}
249- NOTICE: OLD: {i: 1, v: update}
284+ NOTICE: OLD: {}
285+ NOTICE: TG_level: STATEMENT
286+ NOTICE: TG_name: statement_trigger
287+ NOTICE: TG_op: DELETE
288+ NOTICE: TG_relatts: {{} i v {} test_skip test_return_null test_argisnull}
289+ NOTICE: TG_relid: bogus:12345
290+ NOTICE: TG_table_name: trigger_test
291+ NOTICE: TG_table_schema: public
292+ NOTICE: TG_when: BEFORE
293+ NOTICE: args: {42 {statement trigger}}
294+ NOTICE: NEW: {}
295+ NOTICE: OLD: {i: 1, test_argisnull: f, test_return_null: f, test_skip: f, v: update}
250296NOTICE: TG_level: ROW
251297NOTICE: TG_name: show_trigger_data_trig
252298NOTICE: TG_op: DELETE
253- NOTICE: TG_relatts: {{} i v}
299+ NOTICE: TG_relatts: {{} i v {} test_skip test_return_null test_argisnull }
254300NOTICE: TG_relid: bogus:12345
255301NOTICE: TG_table_name: trigger_test
256302NOTICE: TG_table_schema: public
257303NOTICE: TG_when: BEFORE
258304NOTICE: args: {23 skidoo}
305+ truncate trigger_test;
306+ NOTICE: NEW: {}
307+ NOTICE: OLD: {}
308+ NOTICE: TG_level: STATEMENT
309+ NOTICE: TG_name: statement_trigger
310+ NOTICE: TG_op: TRUNCATE
311+ NOTICE: TG_relatts: {{} i v {} test_skip test_return_null test_argisnull}
312+ NOTICE: TG_relid: bogus:12345
313+ NOTICE: TG_table_name: trigger_test
314+ NOTICE: TG_table_schema: public
315+ NOTICE: TG_when: BEFORE
316+ NOTICE: args: {42 {statement trigger}}
259317-- Test composite-type arguments
260318select tcl_composite_arg_ref1(row('tkey', 42, 'ref2'));
261319 tcl_composite_arg_ref1
@@ -288,6 +346,22 @@ select tcl_argisnull(null);
288346 t
289347(1 row)
290348
349+ -- should error
350+ insert into trigger_test(test_argisnull) values(true);
351+ NOTICE: NEW: {}
352+ NOTICE: OLD: {}
353+ NOTICE: TG_level: STATEMENT
354+ NOTICE: TG_name: statement_trigger
355+ NOTICE: TG_op: INSERT
356+ NOTICE: TG_relatts: {{} i v {} test_skip test_return_null test_argisnull}
357+ NOTICE: TG_relid: bogus:12345
358+ NOTICE: TG_table_name: trigger_test
359+ NOTICE: TG_table_schema: public
360+ NOTICE: TG_when: BEFORE
361+ NOTICE: args: {42 {statement trigger}}
362+ ERROR: argisnull cannot be used in triggers
363+ select trigger_data();
364+ ERROR: trigger functions can only be called as triggers
291365-- Test spi_lastoid primitive
292366create temp table t1 (f1 int);
293367select tcl_lastoid('t1');
@@ -304,14 +378,14 @@ select tcl_lastoid('t2') > 0;
304378(1 row)
305379
306380-- test some error cases
307- CREATE FUNCTION tcl_error(OUT a int, OUT b int) AS $$return {$$ LANGUAGE pltcl;
308- SELECT tcl_error();
381+ create function tcl_error(out a int, out b int) as $$return {$$ language pltcl;
382+ select tcl_error();
309383ERROR: missing close-brace
310- CREATE FUNCTION bad_record(OUT a text, OUT b text) AS $$return [list a]$$ LANGUAGE pltcl;
311- SELECT bad_record();
384+ create function bad_record(out a text, out b text) as $$return [list a]$$ language pltcl;
385+ select bad_record();
312386ERROR: column name/value list must have even number of elements
313- CREATE FUNCTION bad_field(OUT a text, OUT b text) AS $$return [list a 1 b 2 cow 3]$$ LANGUAGE pltcl;
314- SELECT bad_field();
387+ create function bad_field(out a text, out b text) as $$return [list a 1 b 2 cow 3]$$ language pltcl;
388+ select bad_field();
315389ERROR: column name/value list contains nonexistent column name "cow"
316390-- test compound return
317391select * from tcl_test_cube_squared(5);
@@ -351,16 +425,238 @@ select 1, tcl_test_sequence(0,5);
351425 1 | 4
352426(5 rows)
353427
354- CREATE FUNCTION non_srf() RETURNS int AS $$return_next 1$$ LANGUAGE pltcl;
428+ create function non_srf() returns int as $$return_next 1$$ language pltcl;
355429select non_srf();
356430ERROR: return_next cannot be used in non-set-returning functions
357- CREATE FUNCTION bad_record_srf(OUT a text, OUT b text) RETURNS SETOF record AS $$
431+ create function bad_record_srf(out a text, out b text) returns setof record as $$
358432return_next [list a]
359- $$ LANGUAGE pltcl;
360- SELECT bad_record_srf();
433+ $$ language pltcl;
434+ select bad_record_srf();
361435ERROR: column name/value list must have even number of elements
362- CREATE FUNCTION bad_field_srf(OUT a text, OUT b text) RETURNS SETOF record AS $$
436+ create function bad_field_srf(out a text, out b text) returns setof record as $$
363437return_next [list a 1 b 2 cow 3]
364- $$ LANGUAGE pltcl;
365- SELECT bad_field_srf();
438+ $$ language pltcl;
439+ select bad_field_srf();
366440ERROR: column name/value list contains nonexistent column name "cow"
441+ -- test quote
442+ select tcl_eval('quote foo bar');
443+ ERROR: wrong # args: should be "quote string"
444+ select tcl_eval('quote [format %c 39]');
445+ tcl_eval
446+ ----------
447+ ''
448+ (1 row)
449+
450+ select tcl_eval('quote [format %c 92]');
451+ tcl_eval
452+ ----------
453+ \\
454+ (1 row)
455+
456+ -- Test argisnull
457+ select tcl_eval('argisnull');
458+ ERROR: wrong # args: should be "argisnull argno"
459+ select tcl_eval('argisnull 14');
460+ ERROR: argno out of range
461+ select tcl_eval('argisnull abc');
462+ ERROR: expected integer but got "abc"
463+ -- Test return_null
464+ select tcl_eval('return_null 14');
465+ ERROR: wrong # args: should be "return_null "
466+ -- should error
467+ insert into trigger_test(test_return_null) values(true);
468+ NOTICE: NEW: {}
469+ NOTICE: OLD: {}
470+ NOTICE: TG_level: STATEMENT
471+ NOTICE: TG_name: statement_trigger
472+ NOTICE: TG_op: INSERT
473+ NOTICE: TG_relatts: {{} i v {} test_skip test_return_null test_argisnull}
474+ NOTICE: TG_relid: bogus:12345
475+ NOTICE: TG_table_name: trigger_test
476+ NOTICE: TG_table_schema: public
477+ NOTICE: TG_when: BEFORE
478+ NOTICE: args: {42 {statement trigger}}
479+ ERROR: return_null cannot be used in triggers
480+ -- Test spi_exec
481+ select tcl_eval('spi_exec');
482+ ERROR: wrong # args: should be "spi_exec ?-count n? ?-array name? query ?loop body?"
483+ select tcl_eval('spi_exec -count');
484+ ERROR: missing argument to -count or -array
485+ select tcl_eval('spi_exec -array');
486+ ERROR: missing argument to -count or -array
487+ select tcl_eval('spi_exec -count abc');
488+ ERROR: expected integer but got "abc"
489+ select tcl_eval('spi_exec query loop body toomuch');
490+ ERROR: wrong # args: should be "query ?loop body?"
491+ select tcl_eval('spi_exec "begin; rollback;"');
492+ ERROR: pltcl: SPI_execute failed: SPI_ERROR_TRANSACTION
493+ -- Test spi_execp
494+ select tcl_eval('spi_execp');
495+ ERROR: missing argument to -count or -array
496+ select tcl_eval('spi_execp -count');
497+ ERROR: missing argument to -array, -count or -nulls
498+ select tcl_eval('spi_execp -array');
499+ ERROR: missing argument to -array, -count or -nulls
500+ select tcl_eval('spi_execp -count abc');
501+ ERROR: expected integer but got "abc"
502+ select tcl_eval('spi_execp -nulls');
503+ ERROR: missing argument to -array, -count or -nulls
504+ select tcl_eval('spi_execp ""');
505+ ERROR: invalid queryid ''
506+ -- test spi_prepare
507+ select tcl_eval('spi_prepare');
508+ ERROR: wrong # args: should be "spi_prepare query argtypes"
509+ select tcl_eval('spi_prepare a b');
510+ ERROR: type "b" does not exist
511+ select tcl_eval('spi_prepare a "b {"');
512+ ERROR: unmatched open brace in list
513+ select tcl_error_handling_test($tcl$spi_prepare "select moo" []$tcl$);
514+ tcl_error_handling_test
515+ --------------------------------------
516+ SQLSTATE: 42703 +
517+ condition: undefined_column +
518+ cursor_position: 8 +
519+ message: column "moo" does not exist+
520+ statement: select moo
521+ (1 row)
522+
523+ -- test full error text
524+ select tcl_error_handling_test($tcl$
525+ spi_exec "DO $$
526+ BEGIN
527+ RAISE 'my message'
528+ USING HINT = 'my hint'
529+ , DETAIL = 'my detail'
530+ , SCHEMA = 'my schema'
531+ , TABLE = 'my table'
532+ , COLUMN = 'my column'
533+ , CONSTRAINT = 'my constraint'
534+ , DATATYPE = 'my datatype'
535+ ;
536+ END$$;"
537+ $tcl$);
538+ tcl_error_handling_test
539+ --------------------------------------------------------------
540+ SQLSTATE: P0001 +
541+ column: my column +
542+ condition: raise_exception +
543+ constraint: my constraint +
544+ context: PL/pgSQL function inline_code_block line 3 at RAISE+
545+ SQL statement "DO $$ +
546+ BEGIN +
547+ RAISE 'my message' +
548+ USING HINT = 'my hint' +
549+ , DETAIL = 'my detail' +
550+ , SCHEMA = 'my schema' +
551+ , TABLE = 'my table' +
552+ , COLUMN = 'my column' +
553+ , CONSTRAINT = 'my constraint' +
554+ , DATATYPE = 'my datatype' +
555+ ; +
556+ END$$;" +
557+ datatype: my datatype +
558+ detail: my detail +
559+ hint: my hint +
560+ message: my message +
561+ schema: my schema +
562+ table: my table
563+ (1 row)
564+
565+ -- verify tcl_error_handling_test() properly reports non-postgres errors
566+ select tcl_error_handling_test('moo');
567+ tcl_error_handling_test
568+ ----------------------------
569+ invalid command name "moo"
570+ (1 row)
571+
572+ -- test elog
573+ select tcl_eval('elog');
574+ ERROR: wrong # args: should be "elog level msg"
575+ select tcl_eval('elog foo bar');
576+ ERROR: bad priority "foo": must be DEBUG, LOG, INFO, NOTICE, WARNING, ERROR, or FATAL
577+ -- test forced error
578+ select tcl_eval('error "forced error"');
579+ ERROR: forced error
580+ -- test loop control in spi_exec[p]
581+ select tcl_spi_exec(true, 'break');
582+ NOTICE: col1 1, col2 foo
583+ NOTICE: col1 2, col2 bar
584+ NOTICE: action: break
585+ NOTICE: end of function
586+ tcl_spi_exec
587+ --------------
588+
589+ (1 row)
590+
591+ select tcl_spi_exec(true, 'continue');
592+ NOTICE: col1 1, col2 foo
593+ NOTICE: col1 2, col2 bar
594+ NOTICE: action: continue
595+ NOTICE: col1 3, col2 baz
596+ NOTICE: end of function
597+ tcl_spi_exec
598+ --------------
599+
600+ (1 row)
601+
602+ select tcl_spi_exec(true, 'error');
603+ NOTICE: col1 1, col2 foo
604+ NOTICE: col1 2, col2 bar
605+ NOTICE: action: error
606+ ERROR: error message
607+ select tcl_spi_exec(true, 'return');
608+ NOTICE: col1 1, col2 foo
609+ NOTICE: col1 2, col2 bar
610+ NOTICE: action: return
611+ tcl_spi_exec
612+ --------------
613+
614+ (1 row)
615+
616+ select tcl_spi_exec(false, 'break');
617+ NOTICE: col1 1, col2 foo
618+ NOTICE: col1 2, col2 bar
619+ NOTICE: action: break
620+ NOTICE: end of function
621+ tcl_spi_exec
622+ --------------
623+
624+ (1 row)
625+
626+ select tcl_spi_exec(false, 'continue');
627+ NOTICE: col1 1, col2 foo
628+ NOTICE: col1 2, col2 bar
629+ NOTICE: action: continue
630+ NOTICE: col1 3, col2 baz
631+ NOTICE: end of function
632+ tcl_spi_exec
633+ --------------
634+
635+ (1 row)
636+
637+ select tcl_spi_exec(false, 'error');
638+ NOTICE: col1 1, col2 foo
639+ NOTICE: col1 2, col2 bar
640+ NOTICE: action: error
641+ ERROR: error message
642+ select tcl_spi_exec(false, 'return');
643+ NOTICE: col1 1, col2 foo
644+ NOTICE: col1 2, col2 bar
645+ NOTICE: action: return
646+ tcl_spi_exec
647+ --------------
648+
649+ (1 row)
650+
651+ -- forcibly run the Tcl event loop for awhile, to check that we have not
652+ -- messed things up too badly by disabling the Tcl notifier subsystem
653+ select tcl_eval($$
654+ unset -nocomplain ::tcl_vwait
655+ after 100 {set ::tcl_vwait 1}
656+ vwait ::tcl_vwait
657+ unset -nocomplain ::tcl_vwait$$);
658+ tcl_eval
659+ ----------
660+
661+ (1 row)
662+
0 commit comments