-- -- num_nulls() -- SELECT num_nonnulls(NULL); num_nonnulls -------------- 0 (1 row) SELECT num_nonnulls('1'); num_nonnulls -------------- 1 (1 row) SELECT num_nonnulls(NULL::text); num_nonnulls -------------- 0 (1 row) SELECT num_nonnulls(NULL::text, NULL::int); num_nonnulls -------------- 0 (1 row) SELECT num_nonnulls(1, 2, NULL::text, NULL::point, '', int8 '9', 1.0 / NULL); num_nonnulls -------------- 4 (1 row) SELECT num_nonnulls(VARIADIC '{1,2,NULL,3}'::int[]); num_nonnulls -------------- 3 (1 row) SELECT num_nonnulls(VARIADIC '{"1","2","3","4"}'::text[]); num_nonnulls -------------- 4 (1 row) SELECT num_nonnulls(VARIADIC ARRAY(SELECT CASE WHEN i <> 40 THEN i END FROM generate_series(1, 100) i)); num_nonnulls -------------- 99 (1 row) SELECT num_nulls(NULL); num_nulls ----------- 1 (1 row) SELECT num_nulls('1'); num_nulls ----------- 0 (1 row) SELECT num_nulls(NULL::text); num_nulls ----------- 1 (1 row) SELECT num_nulls(NULL::text, NULL::int); num_nulls ----------- 2 (1 row) SELECT num_nulls(1, 2, NULL::text, NULL::point, '', int8 '9', 1.0 / NULL); num_nulls ----------- 3 (1 row) SELECT num_nulls(VARIADIC '{1,2,NULL,3}'::int[]); num_nulls ----------- 1 (1 row) SELECT num_nulls(VARIADIC '{"1","2","3","4"}'::text[]); num_nulls ----------- 0 (1 row) SELECT num_nulls(VARIADIC ARRAY(SELECT CASE WHEN i <> 40 THEN i END FROM generate_series(1, 100) i)); num_nulls ----------- 1 (1 row) -- special cases SELECT num_nonnulls(VARIADIC NULL::text[]); num_nonnulls -------------- (1 row) SELECT num_nonnulls(VARIADIC '{}'::int[]); num_nonnulls -------------- 0 (1 row) SELECT num_nulls(VARIADIC NULL::text[]); num_nulls ----------- (1 row) SELECT num_nulls(VARIADIC '{}'::int[]); num_nulls ----------- 0 (1 row) -- should fail, one or more arguments is required SELECT num_nonnulls(); ERROR: function num_nonnulls() does not exist LINE 1: SELECT num_nonnulls(); ^ HINT: No function matches the given name and argument types. You might need to add explicit type casts. SELECT num_nulls(); ERROR: function num_nulls() does not exist LINE 1: SELECT num_nulls(); ^ HINT: No function matches the given name and argument types. You might need to add explicit type casts. -- -- Test some built-in SRFs -- -- The outputs of these are variable, so we can't just print their results -- directly, but we can at least verify that the code doesn't fail. -- select setting as segsize from pg_settings where name = 'wal_segment_size' \gset select count(*) > 0 as ok from pg_ls_waldir(); ok ---- t (1 row) -- Test ProjectSet as well as FunctionScan select count(*) > 0 as ok from (select pg_ls_waldir()) ss; ok ---- t (1 row) -- Test not-run-to-completion cases. select * from pg_ls_waldir() limit 0; name | size | modification ------+------+-------------- (0 rows) select count(*) > 0 as ok from (select * from pg_ls_waldir() limit 1) ss; ok ---- t (1 row) select (w).size = :segsize as ok from (select pg_ls_waldir() w) ss where length((w).name) = 24 limit 1; ok ---- t (1 row) select count(*) >= 0 as ok from pg_ls_archive_statusdir(); ok ---- t (1 row) select * from (select pg_ls_dir('.') a) a where a = 'base' limit 1; a ------ base (1 row) select * from (select (pg_timezone_names()).name) ptn where name='UTC' limit 1; name ------ UTC (1 row) select count(*) > 0 from (select pg_tablespace_databases(oid) as pts from pg_tablespace where spcname = 'pg_default') pts join pg_database db on pts.pts = db.oid; ?column? ---------- t (1 row) -- -- Test adding a support function to a subject function -- CREATE FUNCTION my_int_eq(int, int) RETURNS bool LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE AS $$int4eq$$; -- By default, planner does not think that's selective EXPLAIN (COSTS OFF) SELECT * FROM tenk1 a JOIN tenk1 b ON a.unique1 = b.unique1 WHERE my_int_eq(a.unique2, 42); QUERY PLAN ---------------------------------------------- Hash Join Hash Cond: (b.unique1 = a.unique1) -> Seq Scan on tenk1 b -> Hash -> Seq Scan on tenk1 a Filter: my_int_eq(unique2, 42) (6 rows) -- With support function that knows it's int4eq, we get a different plan ALTER FUNCTION my_int_eq(int, int) SUPPORT test_support_func; EXPLAIN (COSTS OFF) SELECT * FROM tenk1 a JOIN tenk1 b ON a.unique1 = b.unique1 WHERE my_int_eq(a.unique2, 42); QUERY PLAN ------------------------------------------------- Nested Loop -> Seq Scan on tenk1 a Filter: my_int_eq(unique2, 42) -> Index Scan using tenk1_unique1 on tenk1 b Index Cond: (unique1 = a.unique1) (5 rows) -- Also test non-default rowcount estimate CREATE FUNCTION my_gen_series(int, int) RETURNS SETOF integer LANGUAGE internal STRICT IMMUTABLE PARALLEL SAFE AS $$generate_series_int4$$ SUPPORT test_support_func; EXPLAIN (COSTS OFF) SELECT * FROM tenk1 a JOIN my_gen_series(1,1000) g ON a.unique1 = g; QUERY PLAN ---------------------------------------- Hash Join Hash Cond: (g.g = a.unique1) -> Function Scan on my_gen_series g -> Hash -> Seq Scan on tenk1 a (5 rows) EXPLAIN (COSTS OFF) SELECT * FROM tenk1 a JOIN my_gen_series(1,10) g ON a.unique1 = g; QUERY PLAN ------------------------------------------------- Nested Loop -> Function Scan on my_gen_series g -> Index Scan using tenk1_unique1 on tenk1 a Index Cond: (unique1 = g.g) (4 rows)