From 2766627b3ff86c4b31cc47f57eeed8a35d32ac7d Mon Sep 17 00:00:00 2001 From: Rahim Kanji Date: Tue, 9 Jul 2024 13:23:20 +0500 Subject: [PATCH] TAP test now checks multi-statement --- test/tap/tests/pgsql-basic_tests-t.cpp | 351 ++++++++++++++++++++++++- 1 file changed, 342 insertions(+), 9 deletions(-) diff --git a/test/tap/tests/pgsql-basic_tests-t.cpp b/test/tap/tests/pgsql-basic_tests-t.cpp index 955fdb5f1..fa94f1044 100644 --- a/test/tap/tests/pgsql-basic_tests-t.cpp +++ b/test/tap/tests/pgsql-basic_tests-t.cpp @@ -25,6 +25,15 @@ res; \ }) +#define PQSENDQUERY(conn,query) ({int send_status = PQsendQuery(conn,query); \ + if (send_status != 1) { \ + fprintf(stderr, "File %s, line %d, status %d, %s\n", \ + __FILE__, __LINE__, status, PQerrorMessage(conn)); \ + } \ + send_status; \ + }) + + CommandLine cl; PGconn* create_new_connection(bool with_ssl) { @@ -35,18 +44,18 @@ PGconn* create_new_connection(bool with_ssl) { if (with_ssl) { ss << " sslmode=require"; - } else { + } else { ss << " sslmode=disable"; - } - - PGconn* conn = PQconnectdb(ss.str().c_str()); + } + + PGconn* conn = PQconnectdb(ss.str().c_str()); const bool res = (conn && PQstatus(conn) == CONNECTION_OK); ok(res, "Connection created successfully. %s", PQerrorMessage(conn)); if (res) return conn; - PQfinish(conn); - return nullptr; + PQfinish(conn); + return nullptr; } // Function to set up the test environment @@ -259,6 +268,324 @@ void test_constraint_violation(PGconn* conn) { PQclear(res); } +void test_multi_statement_transaction(PGconn* conn) { + PGresult* res; + int status; + + // Execute multi-statement transaction + status = PQsendQuery(conn, "BEGIN; " + "INSERT INTO test_table (value) VALUES ('multi statement'); " + "UPDATE test_table SET value = 'multi statement updated' WHERE value = 'multi statement'; " + "COMMIT;"); + ok(status == 1, "Multi-statement transaction sent"); + PQconsumeInput(conn); + while (PQisBusy(conn)) { + PQconsumeInput(conn); + } + + // Check result of BEGIN + res = PQgetResult(conn); + ok(PQresultStatus(res) == PGRES_COMMAND_OK, "BEGIN executed successfully"); + PQclear(res); + + // Check result of INSERT + res = PQgetResult(conn); + ok(PQresultStatus(res) == PGRES_COMMAND_OK, "INSERT executed successfully"); + PQclear(res); + + // Check result of UPDATE + res = PQgetResult(conn); + ok(PQresultStatus(res) == PGRES_COMMAND_OK, "UPDATE executed successfully"); + PQclear(res); + + // Check result of COMMIT + res = PQgetResult(conn); + ok(PQresultStatus(res) == PGRES_COMMAND_OK, "COMMIT executed successfully"); + PQclear(res); + + res = PQgetResult(conn); + ok(PQtransactionStatus(conn) == PQTRANS_IDLE, "Connection in Idle state"); + + // Verify the results + status = PQsendQuery(conn, "SELECT value FROM test_table WHERE value = 'multi statement updated'"); + ok(status == 1, "Verification query sent"); + PQconsumeInput(conn); + while (PQisBusy(conn)) { + PQconsumeInput(conn); + } + res = PQgetResult(conn); + if (PQresultStatus(res) == PGRES_TUPLES_OK) { + int nRows = PQntuples(res); + ok(nRows == 1, "Multi-statement transaction committed correctly"); + char* result = PQgetvalue(res, 0, 0); + ok(strcmp(result, "multi statement updated") == 0, "Multi-statement transaction result is correct"); + } else { + ok(0, "Failed to verify multi-statement transaction"); + } + PQclear(res); + PQgetResult(conn); +} + +void test_multi_statement_transaction_with_error(PGconn* conn) { + PGresult* res; + int status; + + // Execute multi-statement transaction with an error + status = PQSENDQUERY(conn, "BEGIN; " + "INSERT INTO test_table (value) VALUES ('multi statement error'); " + "UPDATE test_table SET value = 'multi statement error updated' WHERE value = 'multi statement error'; " + "INSERT INTO test_table (non_existent_column) VALUES ('error'); " + "COMMIT;"); + ok(status == 1, "Multi-statement transaction with error sent"); + PQconsumeInput(conn); + while (PQisBusy(conn)) { + PQconsumeInput(conn); + } + + // Check result of BEGIN + res = PQgetResult(conn); + ok(PQresultStatus(res) == PGRES_COMMAND_OK, "BEGIN executed successfully"); + PQclear(res); + + // Check result of INSERT + res = PQgetResult(conn); + ok(PQresultStatus(res) == PGRES_COMMAND_OK, "INSERT executed successfully"); + PQclear(res); + + // Check result of UPDATE + res = PQgetResult(conn); + ok(PQresultStatus(res) == PGRES_COMMAND_OK, "UPDATE executed successfully"); + PQclear(res); + + // Check result of erroneous INSERT + res = PQgetResult(conn); + ok(PQresultStatus(res) == PGRES_FATAL_ERROR, "Erroneous INSERT failed as expected"); + PQclear(res); + + PQgetResult(conn); + // Ensure the transaction is in error state + ok(PQtransactionStatus(conn) == PQTRANS_INERROR, "Connection in Error Transaction state"); + + // Rollback the transaction + status = PQsendQuery(conn, "ROLLBACK"); + ok(status == 1, "ROLLBACK sent"); + PQconsumeInput(conn); + while (PQisBusy(conn)) { + PQconsumeInput(conn); + } + res = PQgetResult(conn); + ok(PQresultStatus(res) == PGRES_COMMAND_OK, "ROLLBACK executed successfully"); + PQclear(res); + + PQgetResult(conn); + + ok(PQtransactionStatus(conn) == PQTRANS_IDLE, "Connection in Idle state"); + + // Verify the results + status = PQsendQuery(conn, "SELECT value FROM test_table WHERE value = 'multi statement error' OR value = 'multi statement error updated'"); + ok(status == 1, "Verification query sent"); + PQconsumeInput(conn); + while (PQisBusy(conn)) { + PQconsumeInput(conn); + } + res = PQgetResult(conn); + if (PQresultStatus(res) == PGRES_TUPLES_OK) { + int nRows = PQntuples(res); + ok(nRows == 0, "Multi-statement transaction with error rolled back correctly"); + } else { + ok(0, "Failed to verify rollback of multi-statement transaction with error"); + } + PQclear(res); + PQgetResult(conn); +} + +void test_multi_statement_select_insert(PGconn* conn) { + PGresult* res; + int status; + + // Execute multi-statement SELECT and INSERT + status = PQsendQuery(conn, "SELECT value FROM test_table WHERE id = 1; " + "INSERT INTO test_table (value) VALUES ('multi statement select insert');"); + ok(status == 1, "Multi-statement SELECT and INSERT sent"); + PQconsumeInput(conn); + while (PQisBusy(conn)) { + PQconsumeInput(conn); + } + + // Check result of SELECT + res = PQgetResult(conn); + ok(PQresultStatus(res) == PGRES_TUPLES_OK, "SELECT executed successfully"); + PQclear(res); + + // Check result of INSERT + res = PQgetResult(conn); + ok(PQresultStatus(res) == PGRES_COMMAND_OK, "INSERT executed successfully"); + PQclear(res); + + PQgetResult(conn); + + // Verify the results + status = PQsendQuery(conn, "SELECT value FROM test_table WHERE value = 'multi statement select insert'"); + ok(status == 1, "Verification query sent"); + PQconsumeInput(conn); + while (PQisBusy(conn)) { + PQconsumeInput(conn); + } + res = PQgetResult(conn); + if (PQresultStatus(res) == PGRES_TUPLES_OK) { + int nRows = PQntuples(res); + ok(nRows == 1, "Multi-statement SELECT and INSERT committed correctly"); + char* result = PQgetvalue(res, 0, 0); + ok(strcmp(result, "multi statement select insert") == 0, "Multi-statement SELECT and INSERT result is correct"); + } else { + ok(0, "Failed to verify multi-statement SELECT and INSERT"); + } + PQclear(res); + PQgetResult(conn); +} + +void test_multi_statement_delete_update(PGconn* conn) { + PGresult* res; + int status; + + // Execute multi-statement DELETE and UPDATE + status = PQsendQuery(conn, "DELETE FROM test_table WHERE value = 'test1'; " + "UPDATE test_table SET value = 'multi statement delete update' WHERE value = 'test4';"); + ok(status == 1, "Multi-statement DELETE and UPDATE sent"); + PQconsumeInput(conn); + while (PQisBusy(conn)) { + PQconsumeInput(conn); + } + + // Check result of DELETE + res = PQgetResult(conn); + ok(PQresultStatus(res) == PGRES_COMMAND_OK, "DELETE executed successfully"); + PQclear(res); + + // Check result of UPDATE + res = PQgetResult(conn); + ok(PQresultStatus(res) == PGRES_COMMAND_OK, "UPDATE executed successfully"); + PQclear(res); + + PQgetResult(conn); + + // Verify the results + status = PQsendQuery(conn, "SELECT value FROM test_table WHERE value = 'multi statement delete update'"); + ok(status == 1, "Verification query sent"); + PQconsumeInput(conn); + while (PQisBusy(conn)) { + PQconsumeInput(conn); + } + res = PQgetResult(conn); + if (PQresultStatus(res) == PGRES_TUPLES_OK) { + int nRows = PQntuples(res); + ok(nRows == 1, "Multi-statement DELETE and UPDATE committed correctly"); + char* result = PQgetvalue(res, 0, 0); + ok(strcmp(result, "multi statement delete update") == 0, "Multi-statement DELETE and UPDATE result is correct"); + } else { + ok(0, "Failed to verify multi-statement DELETE and UPDATE"); + } + PQclear(res); + PQgetResult(conn); +} + +void test_multi_statement_with_error(PGconn* conn) { + PGresult* res; + int status; + + // Execute multi-statement with an error + status = PQsendQuery(conn, "INSERT INTO test_table (value) VALUES ('multi statement error'); " + "UPDATE test_table SET value = 'multi statement error updated' WHERE value = 'multi statement error'; " + "INSERT INTO test_table (non_existent_column) VALUES ('error');"); + ok(status == 1, "Multi-statement with error sent"); + PQconsumeInput(conn); + while (PQisBusy(conn)) { + PQconsumeInput(conn); + } + + // Check result of INSERT + res = PQgetResult(conn); + ok(PQresultStatus(res) == PGRES_COMMAND_OK, "INSERT executed successfully"); + PQclear(res); + + // Check result of UPDATE + res = PQgetResult(conn); + ok(PQresultStatus(res) == PGRES_COMMAND_OK, "UPDATE executed successfully"); + PQclear(res); + + // Check result of erroneous INSERT + res = PQgetResult(conn); + ok(PQresultStatus(res) == PGRES_FATAL_ERROR, "Erroneous INSERT failed as expected"); + PQclear(res); + + PQgetResult(conn); + // Verify the results + status = PQsendQuery(conn, "SELECT value FROM test_table WHERE value = 'multi statement error' OR value = 'multi statement error updated'"); + ok(status == 1, "Verification query sent"); + PQconsumeInput(conn); + while (PQisBusy(conn)) { + PQconsumeInput(conn); + } + res = PQgetResult(conn); + if (PQresultStatus(res) == PGRES_TUPLES_OK) { + int nRows = PQntuples(res); + ok(nRows == 0, "No rows are inserted or updated"); + } else { + ok(0, "Failed to verify rows from multi-statement with error"); + } + PQclear(res); + PQgetResult(conn); +} + +void test_multi_statement_insert_select_select(PGconn* conn) { + PGresult* res; + int status; + + // Execute multi-statement INSERT, SELECT, and SELECT + status = PQsendQuery(conn, "INSERT INTO test_table (value) VALUES ('multi statement select1'), ('multi statement select2'); " + "SELECT value FROM test_table WHERE value = 'multi statement select1'; " + "SELECT value FROM test_table WHERE value = 'multi statement select2';"); + ok(status == 1, "Multi-statement INSERT and SELECTs sent"); + PQconsumeInput(conn); + while (PQisBusy(conn)) { + PQconsumeInput(conn); + } + + // Check result of the INSERT + res = PQgetResult(conn); + ok(PQresultStatus(res) == PGRES_COMMAND_OK, "INSERT executed successfully"); + PQclear(res); + + // Check result of the first SELECT + res = PQgetResult(conn); + if (PQresultStatus(res) == PGRES_TUPLES_OK) { + int nRows = PQntuples(res); + ok(nRows == 1, "First SELECT executed successfully"); + if (nRows > 0) { + char* result = PQgetvalue(res, 0, 0); + ok(strcmp(result, "multi statement select1") == 0, "First SELECT result is correct"); + } + } else { + ok(0, "First SELECT failed"); + } + PQclear(res); + + // Check result of the second SELECT + res = PQgetResult(conn); + if (PQresultStatus(res) == PGRES_TUPLES_OK) { + int nRows = PQntuples(res); + ok(nRows == 1, "Second SELECT executed successfully"); + if (nRows > 0) { + char* result = PQgetvalue(res, 0, 0); + ok(strcmp(result, "multi statement select2") == 0, "Second SELECT result is correct"); + } + } else { + ok(0, "Second SELECT failed"); + } + PQclear(res); + PQgetResult(conn); +} + void teardown_database(PGconn* conn) { PGresult* res; @@ -271,7 +598,7 @@ void test_invalid_connection(bool with_ssl) { std::stringstream ss; ss << "host=invalid_host port=invalid_port dbname=invalid_db user=invalid_user password=invalid_password"; - + if (with_ssl) { ss << " sslmode=require"; } else { @@ -300,6 +627,12 @@ void execute_tests(bool with_ssl) { test_transaction_error(conn); test_null_value(conn); test_constraint_violation(conn); + test_multi_statement_transaction(conn); + test_multi_statement_transaction_with_error(conn); + test_multi_statement_select_insert(conn); + test_multi_statement_delete_update(conn); + test_multi_statement_with_error(conn); + test_multi_statement_insert_select_select(conn); teardown_database(conn); test_invalid_connection(with_ssl); @@ -307,8 +640,8 @@ void execute_tests(bool with_ssl) { } int main(int argc, char** argv) { - - plan(88); // Total number of tests planned + + plan(176); // Total number of tests planned if (cl.getEnv()) return exit_status();