-- -- 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 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)