diff --git a/src/backend/distributed/transaction/relation_access_tracking.c b/src/backend/distributed/transaction/relation_access_tracking.c index c4335c250..b8ef8ba7b 100644 --- a/src/backend/distributed/transaction/relation_access_tracking.c +++ b/src/backend/distributed/transaction/relation_access_tracking.c @@ -713,14 +713,37 @@ CheckConflictingRelationAccesses(Oid relationId, ShardPlacementAccessType access char *conflictingAccessTypeText = PlacementAccessTypeToText(conflictingAccessType); - ereport(ERROR, (errmsg("cannot execute %s on reference relation \"%s\" because " - "there was a parallel %s access to distributed relation " - "\"%s\" in the same transaction", - accessTypeText, relationName, conflictingAccessTypeText, - conflictingRelationName), - errhint("Try re-running the transaction with " - "\"SET LOCAL citus.multi_shard_modify_mode TO " - "\'sequential\';\""))); + /* + * Relation could already be dropped if the accessType is DDL and the + * command that we were executing were a DROP command. In that case, + * as this function is executed via DROP trigger, standard_ProcessUtility + * had already dropped the table from PostgreSQL's perspective. Hence, it + * returns NULL pointer for the name of the relation. + */ + if (relationName == NULL) + { + ereport(ERROR, (errmsg("cannot execute %s on reference relation because " + "there was a parallel %s access to distributed relation " + "\"%s\" in the same transaction", + accessTypeText, conflictingAccessTypeText, + conflictingRelationName), + errhint("Try re-running the transaction with " + "\"SET LOCAL citus.multi_shard_modify_mode TO " + "\'sequential\';\""))); + } + else + { + ereport(ERROR, (errmsg( + "cannot execute %s on reference relation \"%s\" because " + "there was a parallel %s access to distributed relation " + "\"%s\" in the same transaction", + accessTypeText, relationName, + conflictingAccessTypeText, + conflictingRelationName), + errhint("Try re-running the transaction with " + "\"SET LOCAL citus.multi_shard_modify_mode TO " + "\'sequential\';\""))); + } } else if (cacheEntry->referencingRelationsViaForeignKey != NIL && accessType > PLACEMENT_ACCESS_SELECT) diff --git a/src/test/regress/expected/foreign_key_restriction_enforcement.out b/src/test/regress/expected/foreign_key_restriction_enforcement.out index 0fcade1c5..04209af5c 100644 --- a/src/test/regress/expected/foreign_key_restriction_enforcement.out +++ b/src/test/regress/expected/foreign_key_restriction_enforcement.out @@ -857,6 +857,35 @@ BEGIN; NOTICE: truncate cascades to table "reference_table" NOTICE: truncate cascades to table "on_update_fkey_table" ROLLBACK; +-- case 4.7: SELECT to a dist table is followed by a DROP +-- DROP following SELECT is important as we error out after +-- the standart process utility hook drops the table. +-- That could cause SIGSEGV before the patch. +-- Below block should "successfully" error out +BEGIN; + SELECT count(*) FROM on_update_fkey_table; + count +--------------------------------------------------------------------- + 1001 +(1 row) + + DROP TABLE reference_table CASCADE; +NOTICE: drop cascades to constraint fkey on table on_update_fkey_table +ERROR: cannot execute DDL on reference relation because there was a parallel SELECT access to distributed relation "on_update_fkey_table" in the same transaction +ROLLBACK; +-- case 4.8: Router SELECT to a dist table is followed by a TRUNCATE +-- No errors expected from below block as SELECT there is a router +-- query +BEGIN; + SELECT count(*) FROM on_update_fkey_table WHERE id = 9; + count +--------------------------------------------------------------------- + 1 +(1 row) + + DROP TABLE reference_table CASCADE; +NOTICE: drop cascades to constraint fkey on table on_update_fkey_table +ROLLBACK; RESET client_min_messages; \set VERBOSITY default -- case 5.1: Parallel UPDATE on distributed table follow by a SELECT diff --git a/src/test/regress/sql/foreign_key_restriction_enforcement.sql b/src/test/regress/sql/foreign_key_restriction_enforcement.sql index 8e482c857..3c2f42ba5 100644 --- a/src/test/regress/sql/foreign_key_restriction_enforcement.sql +++ b/src/test/regress/sql/foreign_key_restriction_enforcement.sql @@ -489,6 +489,24 @@ BEGIN; TRUNCATE transitive_reference_table CASCADE; ROLLBACK; +-- case 4.7: SELECT to a dist table is followed by a DROP +-- DROP following SELECT is important as we error out after +-- the standart process utility hook drops the table. +-- That could cause SIGSEGV before the patch. +-- Below block should "successfully" error out +BEGIN; + SELECT count(*) FROM on_update_fkey_table; + DROP TABLE reference_table CASCADE; +ROLLBACK; + +-- case 4.8: Router SELECT to a dist table is followed by a TRUNCATE +-- No errors expected from below block as SELECT there is a router +-- query +BEGIN; + SELECT count(*) FROM on_update_fkey_table WHERE id = 9; + DROP TABLE reference_table CASCADE; +ROLLBACK; + RESET client_min_messages; \set VERBOSITY default