CREATE SCHEMA citus_stat_tenants;
SET search_path TO citus_stat_tenants;
SET citus.next_shard_id TO 5797500;
SET citus.shard_replication_factor TO 1;
-- make sure that we are tracking the tenant stats
SELECT result FROM run_command_on_all_nodes('SHOW citus.stat_tenants_track');
 result
---------------------------------------------------------------------
 all
 all
 all
(3 rows)

CREATE OR REPLACE FUNCTION pg_catalog.sleep_until_next_period()
RETURNS VOID
LANGUAGE C
AS 'citus', $$sleep_until_next_period$$;
SELECT citus_stat_tenants_reset();
 citus_stat_tenants_reset
---------------------------------------------------------------------

(1 row)

-- set period to upper limit to prevent stats from being reset
SELECT result FROM run_command_on_all_nodes('ALTER SYSTEM SET citus.stat_tenants_period TO 86400');
    result
---------------------------------------------------------------------
 ALTER SYSTEM
 ALTER SYSTEM
 ALTER SYSTEM
(3 rows)

SELECT result FROM run_command_on_all_nodes('SELECT pg_reload_conf()');
 result
---------------------------------------------------------------------
 t
 t
 t
(3 rows)

CREATE TABLE dist_tbl (a INT, b TEXT);
SELECT create_distributed_table('dist_tbl', 'a', shard_count:=4, colocate_with:='none');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE dist_tbl_2 (a INT, b INT);
SELECT create_distributed_table('dist_tbl_2', 'a', colocate_with:='dist_tbl');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE dist_tbl_text (a TEXT, b INT);
SELECT create_distributed_table('dist_tbl_text', 'a', shard_count:=4, colocate_with:='none');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE ref_tbl (a INT, b INT);
SELECT create_reference_table('ref_tbl');
 create_reference_table
---------------------------------------------------------------------

(1 row)

INSERT INTO dist_tbl VALUES (1, 'abcd');
INSERT INTO dist_tbl VALUES (2, 'abcd');
UPDATE dist_tbl SET b = a + 1 WHERE a = 3;
UPDATE dist_tbl SET b = a + 1 WHERE a = 4;
DELETE FROM dist_tbl WHERE a = 5;
SELECT tenant_attribute, read_count_in_this_period, read_count_in_last_period, query_count_in_this_period, query_count_in_last_period,
    (cpu_usage_in_this_period>0) AS cpu_is_used_in_this_period, (cpu_usage_in_last_period>0) AS cpu_is_used_in_last_period
FROM citus_stat_tenants(true)
ORDER BY tenant_attribute;
 tenant_attribute | read_count_in_this_period | read_count_in_last_period | query_count_in_this_period | query_count_in_last_period | cpu_is_used_in_this_period | cpu_is_used_in_last_period
---------------------------------------------------------------------
 1                |                         0 |                         0 |                          1 |                          0 | t                          | f
 2                |                         0 |                         0 |                          1 |                          0 | t                          | f
 3                |                         0 |                         0 |                          1 |                          0 | t                          | f
 4                |                         0 |                         0 |                          1 |                          0 | t                          | f
 5                |                         0 |                         0 |                          1 |                          0 | t                          | f
(5 rows)

SELECT citus_stat_tenants_reset();
 citus_stat_tenants_reset
---------------------------------------------------------------------

(1 row)

-- queries with multiple tenants should not be counted
SELECT count(*)>=0 FROM dist_tbl WHERE a IN (1, 5);
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- queries with reference tables should not be counted
SELECT count(*)>=0 FROM ref_tbl WHERE a = 1;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants(true) ORDER BY tenant_attribute;
 tenant_attribute | query_count_in_this_period
---------------------------------------------------------------------
(0 rows)

-- queries with multiple tables but one tenant should be counted
SELECT count(*)>=0 FROM dist_tbl, dist_tbl_2 WHERE dist_tbl.a = 1 AND dist_tbl_2.a = 1;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl JOIN dist_tbl_2 ON dist_tbl.a = dist_tbl_2.a WHERE dist_tbl.a = 1;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants(true) WHERE tenant_attribute = '1';
 tenant_attribute | query_count_in_this_period
---------------------------------------------------------------------
 1                |                          2
(1 row)

-- test scoring
-- all of these distribution column values are from second worker
SELECT nodeid AS worker_2_nodeid FROM pg_dist_node WHERE nodeport = :worker_2_port \gset
SELECT count(*)>=0 FROM dist_tbl WHERE a = 2;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl WHERE a = 2;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl WHERE a = 3;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl WHERE a = 3;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl WHERE a = 4;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = 'abcd';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT tenant_attribute, query_count_in_this_period, score FROM citus_stat_tenants(true) WHERE nodeid = :worker_2_nodeid ORDER BY score DESC, tenant_attribute;
 tenant_attribute | query_count_in_this_period |   score
---------------------------------------------------------------------
 2                |                          2 | 2000000000
 3                |                          2 | 2000000000
 4                |                          1 | 1000000000
 abcd             |                          1 | 1000000000
(4 rows)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = 'abcd';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = 'abcd';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = 'bcde';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = 'cdef';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT tenant_attribute, query_count_in_this_period, score FROM citus_stat_tenants(true) WHERE nodeid = :worker_2_nodeid ORDER BY score DESC, tenant_attribute;
 tenant_attribute | query_count_in_this_period |   score
---------------------------------------------------------------------
 abcd             |                          3 | 3000000000
 2                |                          2 | 2000000000
 3                |                          2 | 2000000000
 4                |                          1 | 1000000000
 bcde             |                          1 | 1000000000
 cdef             |                          1 | 1000000000
(6 rows)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = 'bcde';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = 'bcde';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = 'defg';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT tenant_attribute, query_count_in_this_period, score FROM citus_stat_tenants(true) WHERE nodeid = :worker_2_nodeid ORDER BY score DESC, tenant_attribute;
 tenant_attribute | query_count_in_this_period |   score
---------------------------------------------------------------------
 abcd             |                          3 | 3000000000
 bcde             |                          3 | 3000000000
 2                |                          2 | 2000000000
 3                |                          2 | 2000000000
 defg             |                          1 | 1000000000
(5 rows)

-- test period passing
\c - - - :worker_1_port
SET search_path TO citus_stat_tenants;
SET citus.stat_tenants_period TO 2;
SELECT citus_stat_tenants_reset();
 citus_stat_tenants_reset
---------------------------------------------------------------------

(1 row)

SELECT sleep_until_next_period();
 sleep_until_next_period
---------------------------------------------------------------------

(1 row)

SELECT count(*)>=0 FROM dist_tbl WHERE a = 1;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

INSERT INTO dist_tbl VALUES (5, 'abcd');
SELECT tenant_attribute, read_count_in_this_period, read_count_in_last_period, query_count_in_this_period, query_count_in_last_period,
    (cpu_usage_in_this_period>0) AS cpu_is_used_in_this_period, (cpu_usage_in_last_period>0) AS cpu_is_used_in_last_period
FROM citus_stat_tenants_local
ORDER BY tenant_attribute;
 tenant_attribute | read_count_in_this_period | read_count_in_last_period | query_count_in_this_period | query_count_in_last_period | cpu_is_used_in_this_period | cpu_is_used_in_last_period
---------------------------------------------------------------------
 1                |                         1 |                         0 |                          1 |                          0 | t                          | f
 5                |                         0 |                         0 |                          1 |                          0 | t                          | f
(2 rows)

-- simulate passing the period
SELECT sleep_until_next_period();
 sleep_until_next_period
---------------------------------------------------------------------

(1 row)

SELECT pg_sleep(1);
 pg_sleep
---------------------------------------------------------------------

(1 row)

SELECT tenant_attribute, read_count_in_this_period, read_count_in_last_period, query_count_in_this_period, query_count_in_last_period,
    (cpu_usage_in_this_period>0) AS cpu_is_used_in_this_period, (cpu_usage_in_last_period>0) AS cpu_is_used_in_last_period
FROM citus_stat_tenants_local
ORDER BY tenant_attribute;
 tenant_attribute | read_count_in_this_period | read_count_in_last_period | query_count_in_this_period | query_count_in_last_period | cpu_is_used_in_this_period | cpu_is_used_in_last_period
---------------------------------------------------------------------
 1                |                         0 |                         1 |                          0 |                          1 | f                          | t
 5                |                         0 |                         0 |                          0 |                          1 | f                          | t
(2 rows)

SELECT sleep_until_next_period();
 sleep_until_next_period
---------------------------------------------------------------------

(1 row)

SELECT pg_sleep(1);
 pg_sleep
---------------------------------------------------------------------

(1 row)

SELECT tenant_attribute, read_count_in_this_period, read_count_in_last_period, query_count_in_this_period, query_count_in_last_period,
    (cpu_usage_in_this_period>0) AS cpu_is_used_in_this_period, (cpu_usage_in_last_period>0) AS cpu_is_used_in_last_period
FROM citus_stat_tenants_local
ORDER BY tenant_attribute;
 tenant_attribute | read_count_in_this_period | read_count_in_last_period | query_count_in_this_period | query_count_in_last_period | cpu_is_used_in_this_period | cpu_is_used_in_last_period
---------------------------------------------------------------------
 1                |                         0 |                         0 |                          0 |                          0 | f                          | f
 5                |                         0 |                         0 |                          0 |                          0 | f                          | f
(2 rows)

\c - - - :master_port
SET search_path TO citus_stat_tenants;
-- test logs
SET client_min_messages TO LOG;
SELECT count(*)>=0 FROM citus_stat_tenants;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SET citus.stat_tenants_log_level TO ERROR;
SELECT count(*)>=0 FROM citus_stat_tenants;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SET citus.stat_tenants_log_level TO OFF;
SELECT count(*)>=0 FROM citus_stat_tenants;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SET citus.stat_tenants_log_level TO LOG;
SELECT count(*)>=0 FROM citus_stat_tenants;
LOG:  Generating citus_stat_tenants
CONTEXT:  PL/pgSQL function citus_stat_tenants(boolean) line XX at RAISE
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SET citus.stat_tenants_log_level TO DEBUG;
SELECT count(*)>=0 FROM citus_stat_tenants;
LOG:  Generating citus_stat_tenants
CONTEXT:  PL/pgSQL function citus_stat_tenants(boolean) line XX at RAISE
 ?column?
---------------------------------------------------------------------
 t
(1 row)

RESET client_min_messages;
SELECT citus_stat_tenants_reset();
 citus_stat_tenants_reset
---------------------------------------------------------------------

(1 row)

-- test turning monitoring on/off
SET citus.stat_tenants_track TO "NONE";
SELECT count(*)>=0 FROM dist_tbl WHERE a = 1;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

INSERT INTO dist_tbl VALUES (1, 1);
SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants;
 tenant_attribute | query_count_in_this_period
---------------------------------------------------------------------
(0 rows)

SET citus.stat_tenants_track TO "ALL";
SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants;
 tenant_attribute | query_count_in_this_period
---------------------------------------------------------------------
(0 rows)

SELECT count(*)>=0 FROM dist_tbl WHERE a = 1;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

INSERT INTO dist_tbl VALUES (1, 1);
SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants;
 tenant_attribute | query_count_in_this_period
---------------------------------------------------------------------
 1                |                          2
(1 row)

-- test special and multibyte characters in tenant attribute
SELECT citus_stat_tenants_reset();
 citus_stat_tenants_reset
---------------------------------------------------------------------

(1 row)

TRUNCATE TABLE dist_tbl_text;
SELECT count(*)>=0 FROM dist_tbl_text WHERE a = '/bcde';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = '/*bcde';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = '/b*cde';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = '/b*c/de';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = 'b/*//cde';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = '/b/*/cde';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = '/b/**/cde';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = 'bcde*';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = 'bcde*/';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = U&'\0061\0308bc';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

\c - - - :worker_1_port
SELECT tenant_attribute, read_count_in_this_period, read_count_in_last_period, query_count_in_this_period, query_count_in_last_period FROM citus_stat_tenants(true) ORDER BY tenant_attribute;
 tenant_attribute | read_count_in_this_period | read_count_in_last_period | query_count_in_this_period | query_count_in_last_period
---------------------------------------------------------------------
 /*bcde           |                         1 |                         0 |                          1 |                          0
 /b*c/de          |                         1 |                         0 |                          1 |                          0
 /b*cde           |                         1 |                         0 |                          1 |                          0
 /b/**/cde        |                         1 |                         0 |                          1 |                          0
 /b/*/cde         |                         1 |                         0 |                          1 |                          0
 /bcde            |                         1 |                         0 |                          1 |                          0
 äbc              |                         1 |                         0 |                          1 |                          0
 b/*//cde         |                         1 |                         0 |                          1 |                          0
 bcde*            |                         1 |                         0 |                          1 |                          0
 bcde*/           |                         1 |                         0 |                          1 |                          0
(10 rows)

\c - - - :worker_2_port
SET search_path TO citus_stat_tenants;
SELECT tenant_attribute, read_count_in_this_period, read_count_in_last_period, query_count_in_this_period, query_count_in_last_period FROM citus_stat_tenants(true) ORDER BY tenant_attribute;
 tenant_attribute | read_count_in_this_period | read_count_in_last_period | query_count_in_this_period | query_count_in_last_period
---------------------------------------------------------------------
 /*bcde           |                         1 |                         0 |                          1 |                          0
 /b*c/de          |                         1 |                         0 |                          1 |                          0
 /b*cde           |                         1 |                         0 |                          1 |                          0
 /b/**/cde        |                         1 |                         0 |                          1 |                          0
 /b/*/cde         |                         1 |                         0 |                          1 |                          0
 /bcde            |                         1 |                         0 |                          1 |                          0
 äbc              |                         1 |                         0 |                          1 |                          0
 b/*//cde         |                         1 |                         0 |                          1 |                          0
 bcde*            |                         1 |                         0 |                          1 |                          0
 bcde*/           |                         1 |                         0 |                          1 |                          0
(10 rows)

SELECT citus_stat_tenants_reset();
 citus_stat_tenants_reset
---------------------------------------------------------------------

(1 row)

-- test local queries
-- all of these distribution column values are from second worker
SELECT count(*)>=0 FROM dist_tbl_text WHERE a = '/b*c/de';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = '/bcde';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = U&'\0061\0308bc';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = 'bcde*';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

DELETE FROM dist_tbl_text WHERE a = '/b*c/de';
DELETE FROM dist_tbl_text WHERE a = '/bcde';
DELETE FROM dist_tbl_text WHERE a = U&'\0061\0308bc';
DELETE FROM dist_tbl_text WHERE a = 'bcde*';
SELECT tenant_attribute, read_count_in_this_period, read_count_in_last_period, query_count_in_this_period, query_count_in_last_period FROM citus_stat_tenants_local(true) ORDER BY tenant_attribute;
 tenant_attribute | read_count_in_this_period | read_count_in_last_period | query_count_in_this_period | query_count_in_last_period
---------------------------------------------------------------------
 /b*c/de          |                         1 |                         0 |                          2 |                          0
 /bcde            |                         1 |                         0 |                          2 |                          0
 äbc              |                         1 |                         0 |                          2 |                          0
 bcde*            |                         1 |                         0 |                          2 |                          0
(4 rows)

-- test local cached queries & prepared statements
PREPARE dist_tbl_text_select_plan (text) AS SELECT count(*)>=0 FROM dist_tbl_text WHERE a = $1;
EXECUTE dist_tbl_text_select_plan('/b*c/de');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan('/bcde');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan(U&'\0061\0308bc');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan('bcde*');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan('/b*c/de');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan('/bcde');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan(U&'\0061\0308bc');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan('bcde*');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan('/b*c/de');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan('/bcde');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan(U&'\0061\0308bc');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan('bcde*');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT tenant_attribute, read_count_in_this_period, read_count_in_last_period, query_count_in_this_period, query_count_in_last_period FROM citus_stat_tenants_local(true) ORDER BY tenant_attribute;
 tenant_attribute | read_count_in_this_period | read_count_in_last_period | query_count_in_this_period | query_count_in_last_period
---------------------------------------------------------------------
 /b*c/de          |                         4 |                         0 |                          5 |                          0
 /bcde            |                         4 |                         0 |                          5 |                          0
 äbc              |                         4 |                         0 |                          5 |                          0
 bcde*            |                         4 |                         0 |                          5 |                          0
(4 rows)

\c - - - :master_port
SET search_path TO citus_stat_tenants;
PREPARE dist_tbl_text_select_plan (text) AS SELECT count(*)>=0 FROM dist_tbl_text WHERE a = $1;
EXECUTE dist_tbl_text_select_plan('/b*c/de');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan('/bcde');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan(U&'\0061\0308bc');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan('bcde*');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan('/b*c/de');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan('/bcde');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan(U&'\0061\0308bc');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan('bcde*');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan('/b*c/de');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan('/bcde');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan(U&'\0061\0308bc');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE dist_tbl_text_select_plan('bcde*');
 ?column?
---------------------------------------------------------------------
 t
(1 row)

\c - - - :worker_2_port
SET search_path TO citus_stat_tenants;
SELECT tenant_attribute, read_count_in_this_period, read_count_in_last_period, query_count_in_this_period, query_count_in_last_period FROM citus_stat_tenants(true) ORDER BY tenant_attribute;
 tenant_attribute | read_count_in_this_period | read_count_in_last_period | query_count_in_this_period | query_count_in_last_period
---------------------------------------------------------------------
 /b*c/de          |                         7 |                         0 |                          8 |                          0
 /bcde            |                         7 |                         0 |                          8 |                          0
 äbc              |                         7 |                         0 |                          8 |                          0
 bcde*            |                         7 |                         0 |                          8 |                          0
(4 rows)

\c - - - :master_port
SET search_path TO citus_stat_tenants;
SELECT citus_stat_tenants_reset();
 citus_stat_tenants_reset
---------------------------------------------------------------------

(1 row)

SELECT count(*)>=0 FROM dist_tbl_text WHERE a = 'thisisaveryloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongname';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT tenant_attribute, read_count_in_this_period, read_count_in_last_period, query_count_in_this_period, query_count_in_last_period FROM citus_stat_tenants ORDER BY tenant_attribute;
                                          tenant_attribute                                           | read_count_in_this_period | read_count_in_last_period | query_count_in_this_period | query_count_in_last_period
---------------------------------------------------------------------
 thisisaverylooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo |                         1 |                         0 |                          1 |                          0
(1 row)

-- test role permissions
CREATE ROLE stats_non_superuser WITH LOGIN;
SET ROLE stats_non_superuser;
SELECT count(*)>=0 FROM citus_stat_tenants;
ERROR:  permission denied for view citus_stat_tenants
SELECT count(*)>=0 FROM citus_stat_tenants_local;
ERROR:  permission denied for view citus_stat_tenants_local
SELECT count(*)>=0 FROM citus_stat_tenants();
ERROR:  permission denied for function citus_stat_tenants
SELECT count(*)>=0 FROM citus_stat_tenants_local();
ERROR:  permission denied for function citus_stat_tenants_local
RESET ROLE;
GRANT pg_monitor TO stats_non_superuser;
SET ROLE stats_non_superuser;
SELECT count(*)>=0 FROM citus_stat_tenants;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM citus_stat_tenants_local;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM citus_stat_tenants();
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM citus_stat_tenants_local();
 ?column?
---------------------------------------------------------------------
 t
(1 row)

RESET ROLE;
DROP ROLE stats_non_superuser;
-- test function push down
CREATE OR REPLACE FUNCTION
  select_from_dist_tbl_text(p_keyword text)
RETURNS boolean LANGUAGE plpgsql AS $fn$
BEGIN
  RETURN(SELECT count(*)>=0 FROM citus_stat_tenants.dist_tbl_text WHERE a = $1);
END;
$fn$;
SELECT create_distributed_function(
  'select_from_dist_tbl_text(text)', 'p_keyword', colocate_with => 'dist_tbl_text'
);
 create_distributed_function
---------------------------------------------------------------------

(1 row)

SELECT citus_stat_tenants_reset();
 citus_stat_tenants_reset
---------------------------------------------------------------------

(1 row)

SELECT select_from_dist_tbl_text('/b*c/de');
 select_from_dist_tbl_text
---------------------------------------------------------------------
 t
(1 row)

SELECT select_from_dist_tbl_text('/b*c/de');
 select_from_dist_tbl_text
---------------------------------------------------------------------
 t
(1 row)

SELECT select_from_dist_tbl_text(U&'\0061\0308bc');
 select_from_dist_tbl_text
---------------------------------------------------------------------
 t
(1 row)

SELECT select_from_dist_tbl_text(U&'\0061\0308bc');
 select_from_dist_tbl_text
---------------------------------------------------------------------
 t
(1 row)

SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants ORDER BY tenant_attribute;
 tenant_attribute | query_count_in_this_period
---------------------------------------------------------------------
 /b*c/de          |                          2
 äbc              |                          2
(2 rows)

CREATE OR REPLACE PROCEDURE select_from_dist_tbl_text_proc(
   p_keyword text
)
LANGUAGE plpgsql
AS $$
BEGIN
    PERFORM select_from_dist_tbl_text(p_keyword);
    PERFORM count(*)>=0 FROM citus_stat_tenants.dist_tbl_text WHERE b < 0;
    PERFORM count(*)>=0 FROM citus_stat_tenants.dist_tbl_text;
    PERFORM count(*)>=0 FROM citus_stat_tenants.dist_tbl_text WHERE a = p_keyword;
    COMMIT;
END;$$;
CALL citus_stat_tenants.select_from_dist_tbl_text_proc('/b*c/de');
CALL citus_stat_tenants.select_from_dist_tbl_text_proc('/b*c/de');
CALL citus_stat_tenants.select_from_dist_tbl_text_proc('/b*c/de');
CALL citus_stat_tenants.select_from_dist_tbl_text_proc(U&'\0061\0308bc');
CALL citus_stat_tenants.select_from_dist_tbl_text_proc(U&'\0061\0308bc');
CALL citus_stat_tenants.select_from_dist_tbl_text_proc(U&'\0061\0308bc');
CALL citus_stat_tenants.select_from_dist_tbl_text_proc(NULL);
SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants ORDER BY tenant_attribute;
 tenant_attribute | query_count_in_this_period
---------------------------------------------------------------------
 /b*c/de          |                          8
 äbc              |                          8
(2 rows)

CREATE OR REPLACE VIEW
  select_from_dist_tbl_text_view
AS
  SELECT * FROM citus_stat_tenants.dist_tbl_text;
SELECT count(*)>=0 FROM select_from_dist_tbl_text_view WHERE a = '/b*c/de';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM select_from_dist_tbl_text_view WHERE a = '/b*c/de';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM select_from_dist_tbl_text_view WHERE a = '/b*c/de';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM select_from_dist_tbl_text_view WHERE a = U&'\0061\0308bc';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM select_from_dist_tbl_text_view WHERE a = U&'\0061\0308bc';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT count(*)>=0 FROM select_from_dist_tbl_text_view WHERE a = U&'\0061\0308bc';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants ORDER BY tenant_attribute;
 tenant_attribute | query_count_in_this_period
---------------------------------------------------------------------
 /b*c/de          |                         11
 äbc              |                         11
(2 rows)

-- single shard distributed table, which is not part of a tenant schema
SELECT citus_stat_tenants_reset();
 citus_stat_tenants_reset
---------------------------------------------------------------------

(1 row)

SET citus.shard_replication_factor TO 1;
CREATE TABLE dist_tbl_text_single_shard(a text, b int);
select create_distributed_table('dist_tbl_text_single_shard', NULL);
 create_distributed_table
---------------------------------------------------------------------

(1 row)

INSERT INTO dist_tbl_text_single_shard VALUES ('/b*c/de', 1);
SELECT count(*)>=0 FROM dist_tbl_text_single_shard WHERE a = '/b*c/de';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

DELETE FROM dist_tbl_text_single_shard WHERE a = '/b*c/de';
UPDATE dist_tbl_text_single_shard SET b = 1 WHERE a = '/b*c/de';
SELECT tenant_attribute, query_count_in_this_period FROM citus_stat_tenants;
 tenant_attribute | query_count_in_this_period
---------------------------------------------------------------------
(0 rows)

-- schema based tenants
SELECT citus_stat_tenants_reset();
 citus_stat_tenants_reset
---------------------------------------------------------------------

(1 row)

SET citus.enable_schema_based_sharding TO ON;
CREATE SCHEMA citus_stat_tenants_t1;
CREATE TABLE citus_stat_tenants_t1.users(id int);
SELECT id FROM citus_stat_tenants_t1.users WHERE id = 2;
 id
---------------------------------------------------------------------
(0 rows)

INSERT INTO citus_stat_tenants_t1.users VALUES (1);
UPDATE citus_stat_tenants_t1.users SET id = 2 WHERE id = 1;
DELETE FROM citus_stat_tenants_t1.users WHERE id = 2;
SELECT tenant_attribute, read_count_in_this_period, read_count_in_last_period, query_count_in_this_period, query_count_in_last_period FROM citus_stat_tenants ORDER BY tenant_attribute;
   tenant_attribute    | read_count_in_this_period | read_count_in_last_period | query_count_in_this_period | query_count_in_last_period
---------------------------------------------------------------------
 citus_stat_tenants_t1 |                         1 |                         0 |                          4 |                          0
(1 row)

SELECT citus_stat_tenants_reset();
 citus_stat_tenants_reset
---------------------------------------------------------------------

(1 row)

PREPARE schema_tenant_insert_plan (int) AS insert into citus_stat_tenants_t1.users values ($1);
EXECUTE schema_tenant_insert_plan(1);
PREPARE schema_tenant_select_plan (int) AS SELECT count(*) > 1 FROM citus_stat_tenants_t1.users where Id = $1;
EXECUTE schema_tenant_select_plan(1);
 ?column?
---------------------------------------------------------------------
 f
(1 row)

SELECT tenant_attribute, read_count_in_this_period, read_count_in_last_period, query_count_in_this_period, query_count_in_last_period FROM citus_stat_tenants ORDER BY tenant_attribute;
   tenant_attribute    | read_count_in_this_period | read_count_in_last_period | query_count_in_this_period | query_count_in_last_period
---------------------------------------------------------------------
 citus_stat_tenants_t1 |                         1 |                         0 |                          2 |                          0
(1 row)

SELECT citus_stat_tenants_reset();
 citus_stat_tenants_reset
---------------------------------------------------------------------

(1 row)

-- local execution & prepared statements
\c - - - :worker_2_port
SET search_path TO citus_stat_tenants;
PREPARE schema_tenant_insert_plan (int) AS insert into citus_stat_tenants_t1.users values ($1);
EXECUTE schema_tenant_insert_plan(1);
EXECUTE schema_tenant_insert_plan(1);
EXECUTE schema_tenant_insert_plan(1);
EXECUTE schema_tenant_insert_plan(1);
EXECUTE schema_tenant_insert_plan(1);
PREPARE schema_tenant_select_plan (int) AS SELECT count(*) > 1 FROM citus_stat_tenants_t1.users where Id = $1;
EXECUTE schema_tenant_select_plan(1);
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE schema_tenant_select_plan(1);
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE schema_tenant_select_plan(1);
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE schema_tenant_select_plan(1);
 ?column?
---------------------------------------------------------------------
 t
(1 row)

EXECUTE schema_tenant_select_plan(1);
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT tenant_attribute, read_count_in_this_period, read_count_in_last_period, query_count_in_this_period, query_count_in_last_period FROM citus_stat_tenants ORDER BY tenant_attribute;
   tenant_attribute    | read_count_in_this_period | read_count_in_last_period | query_count_in_this_period | query_count_in_last_period
---------------------------------------------------------------------
 citus_stat_tenants_t1 |                         5 |                         0 |                         10 |                          0
(1 row)

\c - - - :master_port
SET search_path TO citus_stat_tenants;
SET citus.enable_schema_based_sharding TO OFF;
SELECT citus_stat_tenants_reset();
 citus_stat_tenants_reset
---------------------------------------------------------------------

(1 row)

-- test sampling
-- set rate to 0 to disable sampling
SELECT result FROM run_command_on_all_nodes('ALTER SYSTEM set citus.stat_tenants_untracked_sample_rate to 0;');
    result
---------------------------------------------------------------------
 ALTER SYSTEM
 ALTER SYSTEM
 ALTER SYSTEM
(3 rows)

SELECT result FROM run_command_on_all_nodes('SELECT pg_reload_conf()');
 result
---------------------------------------------------------------------
 t
 t
 t
(3 rows)

INSERT INTO dist_tbl VALUES (1, 'abcd');
INSERT INTO dist_tbl VALUES (2, 'abcd');
UPDATE dist_tbl SET b = a + 1 WHERE a = 3;
UPDATE dist_tbl SET b = a + 1 WHERE a = 4;
DELETE FROM dist_tbl WHERE a = 5;
SELECT tenant_attribute, read_count_in_this_period, read_count_in_last_period, query_count_in_this_period, query_count_in_last_period FROM citus_stat_tenants ORDER BY tenant_attribute;
 tenant_attribute | read_count_in_this_period | read_count_in_last_period | query_count_in_this_period | query_count_in_last_period
---------------------------------------------------------------------
(0 rows)

-- test sampling
-- set rate to 1 to track all tenants
SELECT result FROM run_command_on_all_nodes('ALTER SYSTEM set citus.stat_tenants_untracked_sample_rate to 1;');
    result
---------------------------------------------------------------------
 ALTER SYSTEM
 ALTER SYSTEM
 ALTER SYSTEM
(3 rows)

SELECT result FROM run_command_on_all_nodes('SELECT pg_reload_conf()');
 result
---------------------------------------------------------------------
 t
 t
 t
(3 rows)

SELECT sleep_until_next_period();
 sleep_until_next_period
---------------------------------------------------------------------

(1 row)

SELECT pg_sleep(0.1);
 pg_sleep
---------------------------------------------------------------------

(1 row)

INSERT INTO dist_tbl VALUES (1, 'abcd');
INSERT INTO dist_tbl VALUES (2, 'abcd');
UPDATE dist_tbl SET b = a + 1 WHERE a = 3;
UPDATE dist_tbl SET b = a + 1 WHERE a = 4;
DELETE FROM dist_tbl WHERE a = 5;
SELECT tenant_attribute, read_count_in_this_period, read_count_in_last_period, query_count_in_this_period, query_count_in_last_period,
    (cpu_usage_in_this_period>0) AS cpu_is_used_in_this_period, (cpu_usage_in_last_period>0) AS cpu_is_used_in_last_period
FROM citus_stat_tenants(true)
ORDER BY tenant_attribute;
 tenant_attribute | read_count_in_this_period | read_count_in_last_period | query_count_in_this_period | query_count_in_last_period | cpu_is_used_in_this_period | cpu_is_used_in_last_period
---------------------------------------------------------------------
 1                |                         0 |                         0 |                          1 |                          0 | t                          | f
 2                |                         0 |                         0 |                          1 |                          0 | t                          | f
 3                |                         0 |                         0 |                          1 |                          0 | t                          | f
 4                |                         0 |                         0 |                          1 |                          0 | t                          | f
 5                |                         0 |                         0 |                          1 |                          0 | t                          | f
(5 rows)

SET client_min_messages TO ERROR;
DROP SCHEMA citus_stat_tenants CASCADE;
DROP SCHEMA citus_stat_tenants_t1 CASCADE;
