location)));
}
- if (InRecovery)
- {
- /*
- * Our theory for replaying a CREATE is to forcibly drop the target
- * subdirectory if present, and then recreate it. This may be more
- * work than needed, but it is simple to implement.
- */
- if (stat(location_with_version_dir, &st) == 0 && S_ISDIR(st.st_mode))
- {
- if (!rmtree(location_with_version_dir, true))
- /* If this failed, MakePGDirectory() below is going to error. */
- ereport(WARNING,
- (errmsg("some useless files may be left behind in old database directory \"%s\"",
- location_with_version_dir)));
- }
- }
-
/*
* The creation of the version directory prevents more than one tablespace
- * in a single location.
+ * in a single location. This imitates TablespaceCreateDbspace(), but it
+ * ignores concurrency and missing parent directories. The chmod() would
+ * have failed in the absence of a parent. pg_tablespace_spcname_index
+ * prevents concurrency.
*/
- if (MakePGDirectory(location_with_version_dir) < 0)
+ if (stat(location_with_version_dir, &st) < 0)
{
- if (errno == EEXIST)
+ if (errno != ENOENT)
ereport(ERROR,
- (errcode(ERRCODE_OBJECT_IN_USE),
- errmsg("directory \"%s\" already in use as a tablespace",
+ (errcode_for_file_access(),
+ errmsg("could not stat directory \"%s\": %m",
location_with_version_dir)));
- else
+ else if (MakePGDirectory(location_with_version_dir) < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not create directory \"%s\": %m",
location_with_version_dir)));
}
+ else if (!S_ISDIR(st.st_mode))
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("\"%s\" exists but is not a directory",
+ location_with_version_dir)));
+ else if (!InRecovery)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_IN_USE),
+ errmsg("directory \"%s\" already in use as a tablespace",
+ location_with_version_dir)));
/*
* In recovery, remove old symlink, in case it points to the wrong place.
use PostgresNode;
use TestLib;
-use Test::More tests => 34;
+use Test::More tests => 38;
sub check_orphan_relfilenodes
{
my $tablespace_dir = $node->basedir . '/tablespace_other';
mkdir($tablespace_dir);
$tablespace_dir = TestLib::perl2host($tablespace_dir);
- $node->safe_psql('postgres',
- "CREATE TABLESPACE other LOCATION '$tablespace_dir';");
+ my $result;
+
+ # Test redo of CREATE TABLESPACE.
+ $node->safe_psql(
+ 'postgres', "
+ CREATE TABLE moved (id int);
+ INSERT INTO moved VALUES (1);
+ CREATE TABLESPACE other LOCATION '$tablespace_dir';
+ BEGIN;
+ ALTER TABLE moved SET TABLESPACE other;
+ CREATE TABLE originated (id int);
+ INSERT INTO originated VALUES (1);
+ CREATE UNIQUE INDEX ON originated(id) TABLESPACE other;
+ COMMIT;");
+ $node->stop('immediate');
+ $node->start;
+ $result = $node->safe_psql('postgres', "SELECT count(*) FROM moved;");
+ is($result, qq(1), "wal_level = $wal_level, CREATE+SET TABLESPACE");
+ $result = $node->safe_psql(
+ 'postgres', "
+ INSERT INTO originated VALUES (1) ON CONFLICT (id)
+ DO UPDATE set id = originated.id + 1
+ RETURNING id;");
+ is($result, qq(2),
+ "wal_level = $wal_level, CREATE TABLESPACE, CREATE INDEX");
# Test direct truncation optimization. No tuples.
$node->safe_psql(
COMMIT;");
$node->stop('immediate');
$node->start;
- my $result = $node->safe_psql('postgres', "SELECT count(*) FROM trunc;");
+ $result = $node->safe_psql('postgres', "SELECT count(*) FROM trunc;");
is($result, qq(0), "wal_level = $wal_level, TRUNCATE with empty table");
# Test truncation with inserted tuples within the same transaction.