|
13 | 13 | *
|
14 | 14 | *
|
15 | 15 | * IDENTIFICATION
|
16 |
| - * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.185 2006/10/04 00:29:51 momjian Exp $ |
| 16 | + * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.186 2006/10/18 22:44:12 tgl Exp $ |
17 | 17 | *
|
18 | 18 | *-------------------------------------------------------------------------
|
19 | 19 | */
|
@@ -58,6 +58,7 @@ static bool get_db_info(const char *name, LOCKMODE lockmode,
|
58 | 58 | Oid *dbTablespace);
|
59 | 59 | static bool have_createdb_privilege(void);
|
60 | 60 | static void remove_dbtablespaces(Oid db_id);
|
| 61 | +static bool check_db_file_conflict(Oid db_id); |
61 | 62 |
|
62 | 63 |
|
63 | 64 | /*
|
@@ -335,13 +336,23 @@ createdb(const CreatedbStmt *stmt)
|
335 | 336 | (errcode(ERRCODE_DUPLICATE_DATABASE),
|
336 | 337 | errmsg("database \"%s\" already exists", dbname)));
|
337 | 338 |
|
| 339 | + /* |
| 340 | + * Select an OID for the new database, checking that it doesn't have |
| 341 | + * a filename conflict with anything already existing in the tablespace |
| 342 | + * directories. |
| 343 | + */ |
| 344 | + pg_database_rel = heap_open(DatabaseRelationId, RowExclusiveLock); |
| 345 | + |
| 346 | + do |
| 347 | + { |
| 348 | + dboid = GetNewOid(pg_database_rel); |
| 349 | + } while (check_db_file_conflict(dboid)); |
| 350 | + |
338 | 351 | /*
|
339 | 352 | * Insert a new tuple into pg_database. This establishes our ownership of
|
340 | 353 | * the new database name (anyone else trying to insert the same name will
|
341 |
| - * block on the unique index, and fail after we commit). It also assigns |
342 |
| - * the OID that the new database will have. |
| 354 | + * block on the unique index, and fail after we commit). |
343 | 355 | */
|
344 |
| - pg_database_rel = heap_open(DatabaseRelationId, RowExclusiveLock); |
345 | 356 |
|
346 | 357 | /* Form tuple */
|
347 | 358 | MemSet(new_record, 0, sizeof(new_record));
|
@@ -371,7 +382,9 @@ createdb(const CreatedbStmt *stmt)
|
371 | 382 | tuple = heap_formtuple(RelationGetDescr(pg_database_rel),
|
372 | 383 | new_record, new_record_nulls);
|
373 | 384 |
|
374 |
| - dboid = simple_heap_insert(pg_database_rel, tuple); |
| 385 | + HeapTupleSetOid(tuple, dboid); |
| 386 | + |
| 387 | + simple_heap_insert(pg_database_rel, tuple); |
375 | 388 |
|
376 | 389 | /* Update indexes */
|
377 | 390 | CatalogUpdateIndexes(pg_database_rel, tuple);
|
@@ -1216,7 +1229,7 @@ remove_dbtablespaces(Oid db_id)
|
1216 | 1229 |
|
1217 | 1230 | dstpath = GetDatabasePath(db_id, dsttablespace);
|
1218 | 1231 |
|
1219 |
| - if (stat(dstpath, &st) < 0 || !S_ISDIR(st.st_mode)) |
| 1232 | + if (lstat(dstpath, &st) < 0 || !S_ISDIR(st.st_mode)) |
1220 | 1233 | {
|
1221 | 1234 | /* Assume we can ignore it */
|
1222 | 1235 | pfree(dstpath);
|
@@ -1251,6 +1264,55 @@ remove_dbtablespaces(Oid db_id)
|
1251 | 1264 | heap_close(rel, AccessShareLock);
|
1252 | 1265 | }
|
1253 | 1266 |
|
| 1267 | +/* |
| 1268 | + * Check for existing files that conflict with a proposed new DB OID; |
| 1269 | + * return TRUE if there are any |
| 1270 | + * |
| 1271 | + * If there were a subdirectory in any tablespace matching the proposed new |
| 1272 | + * OID, we'd get a create failure due to the duplicate name ... and then we'd |
| 1273 | + * try to remove that already-existing subdirectory during the cleanup in |
| 1274 | + * remove_dbtablespaces. Nuking existing files seems like a bad idea, so |
| 1275 | + * instead we make this extra check before settling on the OID of the new |
| 1276 | + * database. This exactly parallels what GetNewRelFileNode() does for table |
| 1277 | + * relfilenode values. |
| 1278 | + */ |
| 1279 | +static bool |
| 1280 | +check_db_file_conflict(Oid db_id) |
| 1281 | +{ |
| 1282 | + bool result = false; |
| 1283 | + Relation rel; |
| 1284 | + HeapScanDesc scan; |
| 1285 | + HeapTuple tuple; |
| 1286 | + |
| 1287 | + rel = heap_open(TableSpaceRelationId, AccessShareLock); |
| 1288 | + scan = heap_beginscan(rel, SnapshotNow, 0, NULL); |
| 1289 | + while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) |
| 1290 | + { |
| 1291 | + Oid dsttablespace = HeapTupleGetOid(tuple); |
| 1292 | + char *dstpath; |
| 1293 | + struct stat st; |
| 1294 | + |
| 1295 | + /* Don't mess with the global tablespace */ |
| 1296 | + if (dsttablespace == GLOBALTABLESPACE_OID) |
| 1297 | + continue; |
| 1298 | + |
| 1299 | + dstpath = GetDatabasePath(db_id, dsttablespace); |
| 1300 | + |
| 1301 | + if (lstat(dstpath, &st) == 0) |
| 1302 | + { |
| 1303 | + /* Found a conflicting file (or directory, whatever) */ |
| 1304 | + pfree(dstpath); |
| 1305 | + result = true; |
| 1306 | + break; |
| 1307 | + } |
| 1308 | + |
| 1309 | + pfree(dstpath); |
| 1310 | + } |
| 1311 | + |
| 1312 | + heap_endscan(scan); |
| 1313 | + heap_close(rel, AccessShareLock); |
| 1314 | + return result; |
| 1315 | +} |
1254 | 1316 |
|
1255 | 1317 | /*
|
1256 | 1318 | * get_database_oid - given a database name, look up the OID
|
|
0 commit comments