Sorry for the late reply on this thread.

On 14/8/2024 23:05, Imseih (AWS), Sami wrote:
> There are no tests as this requires more discussion in a separate thread(?)
> Unfortunately, TAP tests don't allow us to keep a connection and 
> manually permutate the order of queries sent to different connections. 
> But isolation tests are designed to do so. Of course, they aren't the 
> best if you need to compare values produced by various queries but see a 
> clumsy sketch doing that in the attachment.

It would be nice to use isolation tests as you have,  those type of tests 
don't support psql meta-commands. We need \parse, \bind, \bind_named 
to test queryId for queries issued through extended query protocol.

With TAP tests we can use query_until in BackgroundPsql to have one
connection issue a command and another connection track the # of distinct
queryIds expected.  See the 007_query_id.pl of an example TAP test that
could be added under test_misc.

An INJECTION_POINT can also be added right before we call pgstat_report_query_id
in plancache.c. This will allow us to test when we expect the queryId to
change after a cache revalidation. Thoughts?

> Also, while writing the test, I found out that now, JumbleQuery takes 
> into account constants of the A_Const node, and calls of the same 
> prepared statement with different parameters generate different 
> query_id. Is it a reason to introduce JumbleQuery options and allow 
> different logic of queryid generation?

Can you start a new thread for this prepared statement scenario?

--
Sami

# Copyright (c) 2021-2024, PostgreSQL Global Development Group

# Check that query_id is advertised as expected. This requires a concurrent
# session to check for the last query_id advertised by another session.
use strict;
use warnings FATAL => 'all';
use PostgreSQL::Test::Cluster;
use PostgreSQL::Test::Utils;
use Test::More;

# declare global variables
my $ret;
my $node;
my $psql_session1;
my $psql_session2;

# declare the helper functions
sub test_num_unique_qids
{
    my ($command, $expected_qids, $wait_for) = @_;

    $psql_session1->query_safe($command);

    $psql_session2->query_safe(q(INSERT INTO track_query_id 
                                 SELECT query_id FROM pg_stat_activity 
                                 WHERE application_name = 'query_id_test'
                                 AND rtrim(query) = 'SELECT * FROM test_query_id'
                                 AND query_id is NOT NULL and query_id <> 0;));

    $ret = $psql_session2->query_safe(
	    qq[
            SELECT COUNT(DISTINCT query_id) FROM track_query_id;
    ]);
    
    is($ret, $expected_qids, "# of distinct queryIds");
}

sub create_track_qid_table
{
    $node->safe_psql("postgres", qq[CREATE TABLE track_query_id (query_id BIGINT);]);
}

sub create_test_qid_table
{
    $node->safe_psql("postgres", qq[DROP TABLE IF EXISTS test_query_id;]);
    $node->safe_psql("postgres", qq[CREATE TABLE test_query_id (id INT);]);
}

# Setup the test
## create the node
$node = PostgreSQL::Test::Cluster->new('main');
$node->init;
$node->append_conf('postgresql.conf', 'compute_query_id = on');
$node->start;

## create the sessions
## session1 will run the queries and session2 will query pg_stat_activity 
## for the last query_id of session1 and write it to track_query_id
$psql_session1 = $node->background_psql('postgres');
$psql_session1->query_until(qr//, q(SET application_name = query_id_test;));
$psql_session2 = $node->background_psql('postgres');

create_track_qid_table();

# test 1 - check post-parse queryId is reported with extended query protocol
# We expected 1 queryId to be reported so far.
create_test_qid_table();
test_num_unique_qids("SELECT * FROM test_query_id \\parse n1\n", 1, qr//);

# test 2 - check bind-execute queryId is reported in extended query protocol
# Since we recreate the table of the underlysing named portal, we now expect
# 2 queryIds to be reported.
create_test_qid_table();
test_num_unique_qids("\\bind_named n1 \\g\n", 2, qr//);

# Destroy the sessions and the node
$psql_session1->quit;
$psql_session2->quit;
$node->stop;

done_testing();

Reply via email to