From 3b47a295d67ae4c7de857e98ca638ea17c88f2be Mon Sep 17 00:00:00 2001 From: Rahim Kanji Date: Mon, 21 Jul 2025 19:40:38 +0500 Subject: [PATCH] Updated TAP test --- .../pgsql-extended_query_protocol_test-t.cpp | 184 +++++++++++++++++- 1 file changed, 183 insertions(+), 1 deletion(-) diff --git a/test/tap/tests/pgsql-extended_query_protocol_test-t.cpp b/test/tap/tests/pgsql-extended_query_protocol_test-t.cpp index eb7797ed0..c925d29a7 100644 --- a/test/tap/tests/pgsql-extended_query_protocol_test-t.cpp +++ b/test/tap/tests/pgsql-extended_query_protocol_test-t.cpp @@ -209,6 +209,186 @@ void test_parse_with_sync() { } } +void test_parse_use_same_stmt_name() { + diag("Test %d: Parse using same statement name", test_count++); + auto conn = create_connection(); + if (!conn) return; + + try { + + char type; + std::vector buffer; + + { + conn->prepareStatement("test_stmt_multi", "SELECT $1::int", false); + conn->describeStatement("test_stmt_multi", false); + conn->sendSync(); + + // Read the parse complete for the first statement + conn->readMessage(type, buffer); + ok(type == PgConnection::PARSE_COMPLETE, "Received parse complete for first parse"); + + // Read the describe complete for the first statement + conn->readMessage(type, buffer); + ok(type == PgConnection::PARAMETER_DESCRIPTION, "Received parameter description for first parse"); + + // Read parameter description + BufferReader reader(buffer); + int num_params = reader.readInt16(); + ok(num_params == 1, "Received 1 parameter description for first parse"); + // Read parameter type OID + unsigned int typeOid = reader.readInt32(); + ok(typeOid == 23, "Parameter type OID is 23 (int)"); + + conn->waitForReady(); + } + + { + conn->prepareStatement("test_stmt_multi", "SELECT $1::text", false); + conn->sendSync(); + + conn->readMessage(type, buffer); + ok(type == PgConnection::ERROR_RESPONSE, + "Received error response for second parse with same name"); + + std::string errormsg; + std::string errorcode; + + if (type == PgConnection::ERROR_RESPONSE) { + BufferReader reader(buffer); + char field; + while (reader.remaining() > 0 && (field = reader.readByte()) != 0) { + if (field == 'M') errormsg = reader.readString(); + else if (field == 'C') errorcode = reader.readString(); + else reader.readString(); + } + } + + ok(errorcode == "42P05", "Received ERRCODE_DUPLICATE_PSTATEMENT Error:%s", errormsg.c_str()); + // Now read the ready for query + conn->readMessage(type, buffer); + ok(type == PgConnection::READY_FOR_QUERY, "Received ready for query after multiple parse"); + } + + { + conn->describeStatement("test_stmt_multi", false); + conn->sendSync(); + + // Read the describe complete for the second statement + conn->readMessage(type, buffer); + ok(type == PgConnection::PARAMETER_DESCRIPTION, "Received parameter description for second parse"); + // Read parameter description + BufferReader reader(buffer); + int num_params = reader.readInt16(); + ok(num_params == 1, "Received 1 parameter description for second parse"); + // Read parameter type OID + unsigned int typeOid = reader.readInt32(); + ok(typeOid == 23, "Parameter type OID is 23 (int)"); + + conn->waitForReady(); + } + + { + conn->closeStatement("test_stmt_multi", false); + conn->sendSync(); + + // Read the close complete for the statement + conn->readMessage(type, buffer); + ok(type == PgConnection::CLOSE_COMPLETE, "Received close complete for statement"); + // Now read the ready for query + conn->readMessage(type, buffer); + ok(type == PgConnection::READY_FOR_QUERY, "Received ready for query after close statement"); + } + + { + conn->prepareStatement("test_stmt_multi", "SELECT $1::text", false); + conn->describeStatement("test_stmt_multi", false); + conn->sendSync(); + + conn->readMessage(type, buffer); + ok(type == PgConnection::PARSE_COMPLETE, "Received parse complete for second parse with same name"); + + // Read the describe complete for the second statement + conn->readMessage(type, buffer); + ok(type == PgConnection::PARAMETER_DESCRIPTION, "Received parameter description for second parse with same name"); + // Read parameter description + BufferReader reader(buffer); + int num_params = reader.readInt16(); + ok(num_params == 1, "Received 1 parameter description for second parse with same name"); + // Read parameter type OID + unsigned int typeOid = reader.readInt32(); + ok(typeOid == 25, "Parameter type OID is 25 (text)"); + conn->waitForReady(); + } + } + catch (const PgException& e) { + ok(false, "Parse using same statement name failed with error: %s", e.what()); + } +} + +void test_parse_use_unnamed_stmt() { + diag("Test %d: Parse using unnamed statement", test_count++); + auto conn = create_connection(); + if (!conn) return; + + try { + + char type; + std::vector buffer; + + { + conn->prepareStatement("", "SELECT $1::int", false); + conn->describeStatement("", false); + conn->sendSync(); + + // Read the parse complete for the first statement + conn->readMessage(type, buffer); + ok(type == PgConnection::PARSE_COMPLETE, "Received parse complete for first parse"); + + // Read the describe complete for the first statement + conn->readMessage(type, buffer); + ok(type == PgConnection::PARAMETER_DESCRIPTION, "Received parameter description for first parse"); + + // Read parameter description + BufferReader reader(buffer); + int num_params = reader.readInt16(); + ok(num_params == 1, "Received 1 parameter description for first parse"); + // Read parameter type OID + unsigned int typeOid = reader.readInt32(); + ok(typeOid == 23, "Parameter type OID is 23 (int)"); + + conn->waitForReady(); + } + + { + conn->prepareStatement("", "SELECT $1::text", false); + conn->describeStatement("", false); + conn->sendSync(); + + // Read the parse complete for the first statement + conn->readMessage(type, buffer); + ok(type == PgConnection::PARSE_COMPLETE, "Received parse complete for second parse"); + + // Read the describe complete for the first statement + conn->readMessage(type, buffer); + ok(type == PgConnection::PARAMETER_DESCRIPTION, "Received parameter description for second parse"); + + // Read parameter description + BufferReader reader(buffer); + int num_params = reader.readInt16(); + ok(num_params == 1, "Received 1 parameter description for first parse"); + // Read parameter type OID + unsigned int typeOid = reader.readInt32(); + ok(typeOid == 25, "Parameter type OID is 25 (text)"); + + conn->waitForReady(); + } + } + catch (const PgException& e) { + ok(false, "Parse using unnamed statement with error: %s", e.what()); + } +} + void test_malformed_packet() { diag("Test %d: Malformed parse packet", test_count++); auto conn = create_connection(); @@ -3261,7 +3441,7 @@ int main(int argc, char** argv) { if (cl.getEnv()) return exit_status(); - plan(332); // Adjust based on number of tests + plan(356); // Adjust based on number of tests auto admin_conn = createNewConnection(ConnType::ADMIN, "", false); @@ -3287,6 +3467,8 @@ int main(int argc, char** argv) { test_empty_stmt(); //test_prepare_statment_mix(); test_invalid_query_parse_packet(); + test_parse_use_same_stmt_name(); + test_parse_use_unnamed_stmt(); // Describe Prepared Statement test_describe_existing_statement();