|
|
|
|
@ -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();
|
|
|
|
|
|