|
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 | staticboolhave_createdb_privilege(void);
|
60 | 60 | staticvoidremove_dbtablespaces(Oiddb_id);
|
| 61 | +staticboolcheck_db_file_conflict(Oiddb_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 | +staticbool |
| 1280 | +check_db_file_conflict(Oiddb_id) |
| 1281 | +{ |
| 1282 | +boolresult= false; |
| 1283 | +Relationrel; |
| 1284 | +HeapScanDescscan; |
| 1285 | +HeapTupletuple; |
| 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 | +Oiddsttablespace=HeapTupleGetOid(tuple); |
| 1292 | +char*dstpath; |
| 1293 | +structstatst; |
| 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 | +returnresult; |
| 1315 | +} |
1254 | 1316 |
|
1255 | 1317 | /*
|
1256 | 1318 | * get_database_oid - given a database name, look up the OID
|
|