00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "postgres.h"
00021
00022 #include <fcntl.h>
00023 #include <locale.h>
00024 #include <unistd.h>
00025 #include <sys/stat.h>
00026
00027 #include "access/genam.h"
00028 #include "access/heapam.h"
00029 #include "access/htup_details.h"
00030 #include "access/xact.h"
00031 #include "access/xlogutils.h"
00032 #include "catalog/catalog.h"
00033 #include "catalog/dependency.h"
00034 #include "catalog/indexing.h"
00035 #include "catalog/objectaccess.h"
00036 #include "catalog/pg_authid.h"
00037 #include "catalog/pg_database.h"
00038 #include "catalog/pg_db_role_setting.h"
00039 #include "catalog/pg_tablespace.h"
00040 #include "commands/comment.h"
00041 #include "commands/dbcommands.h"
00042 #include "commands/seclabel.h"
00043 #include "commands/tablespace.h"
00044 #include "mb/pg_wchar.h"
00045 #include "miscadmin.h"
00046 #include "pgstat.h"
00047 #include "postmaster/bgwriter.h"
00048 #include "storage/copydir.h"
00049 #include "storage/fd.h"
00050 #include "storage/lmgr.h"
00051 #include "storage/ipc.h"
00052 #include "storage/procarray.h"
00053 #include "storage/smgr.h"
00054 #include "utils/acl.h"
00055 #include "utils/builtins.h"
00056 #include "utils/fmgroids.h"
00057 #include "utils/pg_locale.h"
00058 #include "utils/snapmgr.h"
00059 #include "utils/syscache.h"
00060 #include "utils/tqual.h"
00061
00062
00063 typedef struct
00064 {
00065 Oid src_dboid;
00066 Oid dest_dboid;
00067 } createdb_failure_params;
00068
00069 typedef struct
00070 {
00071 Oid dest_dboid;
00072 Oid dest_tsoid;
00073 } movedb_failure_params;
00074
00075
00076 static void createdb_failure_callback(int code, Datum arg);
00077 static void movedb(const char *dbname, const char *tblspcname);
00078 static void movedb_failure_callback(int code, Datum arg);
00079 static bool get_db_info(const char *name, LOCKMODE lockmode,
00080 Oid *dbIdP, Oid *ownerIdP,
00081 int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
00082 Oid *dbLastSysOidP, TransactionId *dbFrozenXidP,
00083 MultiXactId *dbMinMultiP,
00084 Oid *dbTablespace, char **dbCollate, char **dbCtype);
00085 static bool have_createdb_privilege(void);
00086 static void remove_dbtablespaces(Oid db_id);
00087 static bool check_db_file_conflict(Oid db_id);
00088 static int errdetail_busy_db(int notherbackends, int npreparedxacts);
00089
00090
00091
00092
00093
00094 Oid
00095 createdb(const CreatedbStmt *stmt)
00096 {
00097 HeapScanDesc scan;
00098 Relation rel;
00099 Oid src_dboid;
00100 Oid src_owner;
00101 int src_encoding;
00102 char *src_collate;
00103 char *src_ctype;
00104 bool src_istemplate;
00105 bool src_allowconn;
00106 Oid src_lastsysoid;
00107 TransactionId src_frozenxid;
00108 MultiXactId src_minmxid;
00109 Oid src_deftablespace;
00110 volatile Oid dst_deftablespace;
00111 Relation pg_database_rel;
00112 HeapTuple tuple;
00113 Datum new_record[Natts_pg_database];
00114 bool new_record_nulls[Natts_pg_database];
00115 Oid dboid;
00116 Oid datdba;
00117 ListCell *option;
00118 DefElem *dtablespacename = NULL;
00119 DefElem *downer = NULL;
00120 DefElem *dtemplate = NULL;
00121 DefElem *dencoding = NULL;
00122 DefElem *dcollate = NULL;
00123 DefElem *dctype = NULL;
00124 DefElem *dconnlimit = NULL;
00125 char *dbname = stmt->dbname;
00126 char *dbowner = NULL;
00127 const char *dbtemplate = NULL;
00128 char *dbcollate = NULL;
00129 char *dbctype = NULL;
00130 char *canonname;
00131 int encoding = -1;
00132 int dbconnlimit = -1;
00133 int notherbackends;
00134 int npreparedxacts;
00135 createdb_failure_params fparms;
00136 Snapshot snapshot;
00137
00138
00139 foreach(option, stmt->options)
00140 {
00141 DefElem *defel = (DefElem *) lfirst(option);
00142
00143 if (strcmp(defel->defname, "tablespace") == 0)
00144 {
00145 if (dtablespacename)
00146 ereport(ERROR,
00147 (errcode(ERRCODE_SYNTAX_ERROR),
00148 errmsg("conflicting or redundant options")));
00149 dtablespacename = defel;
00150 }
00151 else if (strcmp(defel->defname, "owner") == 0)
00152 {
00153 if (downer)
00154 ereport(ERROR,
00155 (errcode(ERRCODE_SYNTAX_ERROR),
00156 errmsg("conflicting or redundant options")));
00157 downer = defel;
00158 }
00159 else if (strcmp(defel->defname, "template") == 0)
00160 {
00161 if (dtemplate)
00162 ereport(ERROR,
00163 (errcode(ERRCODE_SYNTAX_ERROR),
00164 errmsg("conflicting or redundant options")));
00165 dtemplate = defel;
00166 }
00167 else if (strcmp(defel->defname, "encoding") == 0)
00168 {
00169 if (dencoding)
00170 ereport(ERROR,
00171 (errcode(ERRCODE_SYNTAX_ERROR),
00172 errmsg("conflicting or redundant options")));
00173 dencoding = defel;
00174 }
00175 else if (strcmp(defel->defname, "lc_collate") == 0)
00176 {
00177 if (dcollate)
00178 ereport(ERROR,
00179 (errcode(ERRCODE_SYNTAX_ERROR),
00180 errmsg("conflicting or redundant options")));
00181 dcollate = defel;
00182 }
00183 else if (strcmp(defel->defname, "lc_ctype") == 0)
00184 {
00185 if (dctype)
00186 ereport(ERROR,
00187 (errcode(ERRCODE_SYNTAX_ERROR),
00188 errmsg("conflicting or redundant options")));
00189 dctype = defel;
00190 }
00191 else if (strcmp(defel->defname, "connectionlimit") == 0)
00192 {
00193 if (dconnlimit)
00194 ereport(ERROR,
00195 (errcode(ERRCODE_SYNTAX_ERROR),
00196 errmsg("conflicting or redundant options")));
00197 dconnlimit = defel;
00198 }
00199 else if (strcmp(defel->defname, "location") == 0)
00200 {
00201 ereport(WARNING,
00202 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00203 errmsg("LOCATION is not supported anymore"),
00204 errhint("Consider using tablespaces instead.")));
00205 }
00206 else
00207 elog(ERROR, "option \"%s\" not recognized",
00208 defel->defname);
00209 }
00210
00211 if (downer && downer->arg)
00212 dbowner = strVal(downer->arg);
00213 if (dtemplate && dtemplate->arg)
00214 dbtemplate = strVal(dtemplate->arg);
00215 if (dencoding && dencoding->arg)
00216 {
00217 const char *encoding_name;
00218
00219 if (IsA(dencoding->arg, Integer))
00220 {
00221 encoding = intVal(dencoding->arg);
00222 encoding_name = pg_encoding_to_char(encoding);
00223 if (strcmp(encoding_name, "") == 0 ||
00224 pg_valid_server_encoding(encoding_name) < 0)
00225 ereport(ERROR,
00226 (errcode(ERRCODE_UNDEFINED_OBJECT),
00227 errmsg("%d is not a valid encoding code",
00228 encoding)));
00229 }
00230 else if (IsA(dencoding->arg, String))
00231 {
00232 encoding_name = strVal(dencoding->arg);
00233 encoding = pg_valid_server_encoding(encoding_name);
00234 if (encoding < 0)
00235 ereport(ERROR,
00236 (errcode(ERRCODE_UNDEFINED_OBJECT),
00237 errmsg("%s is not a valid encoding name",
00238 encoding_name)));
00239 }
00240 else
00241 elog(ERROR, "unrecognized node type: %d",
00242 nodeTag(dencoding->arg));
00243 }
00244 if (dcollate && dcollate->arg)
00245 dbcollate = strVal(dcollate->arg);
00246 if (dctype && dctype->arg)
00247 dbctype = strVal(dctype->arg);
00248
00249 if (dconnlimit && dconnlimit->arg)
00250 {
00251 dbconnlimit = intVal(dconnlimit->arg);
00252 if (dbconnlimit < -1)
00253 ereport(ERROR,
00254 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00255 errmsg("invalid connection limit: %d", dbconnlimit)));
00256 }
00257
00258
00259 if (dbowner)
00260 datdba = get_role_oid(dbowner, false);
00261 else
00262 datdba = GetUserId();
00263
00264
00265
00266
00267
00268
00269
00270
00271 if (!have_createdb_privilege())
00272 ereport(ERROR,
00273 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00274 errmsg("permission denied to create database")));
00275
00276 check_is_member_of_role(GetUserId(), datdba);
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287 if (!dbtemplate)
00288 dbtemplate = "template1";
00289
00290 if (!get_db_info(dbtemplate, ShareLock,
00291 &src_dboid, &src_owner, &src_encoding,
00292 &src_istemplate, &src_allowconn, &src_lastsysoid,
00293 &src_frozenxid, &src_minmxid, &src_deftablespace,
00294 &src_collate, &src_ctype))
00295 ereport(ERROR,
00296 (errcode(ERRCODE_UNDEFINED_DATABASE),
00297 errmsg("template database \"%s\" does not exist",
00298 dbtemplate)));
00299
00300
00301
00302
00303
00304 if (!src_istemplate)
00305 {
00306 if (!pg_database_ownercheck(src_dboid, GetUserId()))
00307 ereport(ERROR,
00308 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00309 errmsg("permission denied to copy database \"%s\"",
00310 dbtemplate)));
00311 }
00312
00313
00314 if (encoding < 0)
00315 encoding = src_encoding;
00316 if (dbcollate == NULL)
00317 dbcollate = src_collate;
00318 if (dbctype == NULL)
00319 dbctype = src_ctype;
00320
00321
00322 if (!PG_VALID_BE_ENCODING(encoding))
00323 ereport(ERROR,
00324 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00325 errmsg("invalid server encoding %d", encoding)));
00326
00327
00328 if (!check_locale(LC_COLLATE, dbcollate, &canonname))
00329 ereport(ERROR,
00330 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00331 errmsg("invalid locale name: \"%s\"", dbcollate)));
00332 dbcollate = canonname;
00333 if (!check_locale(LC_CTYPE, dbctype, &canonname))
00334 ereport(ERROR,
00335 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00336 errmsg("invalid locale name: \"%s\"", dbctype)));
00337 dbctype = canonname;
00338
00339 check_encoding_locale_matches(encoding, dbcollate, dbctype);
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351 if (strcmp(dbtemplate, "template0") != 0)
00352 {
00353 if (encoding != src_encoding)
00354 ereport(ERROR,
00355 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00356 errmsg("new encoding (%s) is incompatible with the encoding of the template database (%s)",
00357 pg_encoding_to_char(encoding),
00358 pg_encoding_to_char(src_encoding)),
00359 errhint("Use the same encoding as in the template database, or use template0 as template.")));
00360
00361 if (strcmp(dbcollate, src_collate) != 0)
00362 ereport(ERROR,
00363 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00364 errmsg("new collation (%s) is incompatible with the collation of the template database (%s)",
00365 dbcollate, src_collate),
00366 errhint("Use the same collation as in the template database, or use template0 as template.")));
00367
00368 if (strcmp(dbctype, src_ctype) != 0)
00369 ereport(ERROR,
00370 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00371 errmsg("new LC_CTYPE (%s) is incompatible with the LC_CTYPE of the template database (%s)",
00372 dbctype, src_ctype),
00373 errhint("Use the same LC_CTYPE as in the template database, or use template0 as template.")));
00374 }
00375
00376
00377 if (dtablespacename && dtablespacename->arg)
00378 {
00379 char *tablespacename;
00380 AclResult aclresult;
00381
00382 tablespacename = strVal(dtablespacename->arg);
00383 dst_deftablespace = get_tablespace_oid(tablespacename, false);
00384
00385 aclresult = pg_tablespace_aclcheck(dst_deftablespace, GetUserId(),
00386 ACL_CREATE);
00387 if (aclresult != ACLCHECK_OK)
00388 aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
00389 tablespacename);
00390
00391
00392 if (dst_deftablespace == GLOBALTABLESPACE_OID)
00393 ereport(ERROR,
00394 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00395 errmsg("pg_global cannot be used as default tablespace")));
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409 if (dst_deftablespace != src_deftablespace)
00410 {
00411 char *srcpath;
00412 struct stat st;
00413
00414 srcpath = GetDatabasePath(src_dboid, dst_deftablespace);
00415
00416 if (stat(srcpath, &st) == 0 &&
00417 S_ISDIR(st.st_mode) &&
00418 !directory_is_empty(srcpath))
00419 ereport(ERROR,
00420 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00421 errmsg("cannot assign new default tablespace \"%s\"",
00422 tablespacename),
00423 errdetail("There is a conflict because database \"%s\" already has some tables in this tablespace.",
00424 dbtemplate)));
00425 pfree(srcpath);
00426 }
00427 }
00428 else
00429 {
00430
00431 dst_deftablespace = src_deftablespace;
00432
00433 }
00434
00435
00436
00437
00438
00439
00440 if (OidIsValid(get_database_oid(dbname, true)))
00441 ereport(ERROR,
00442 (errcode(ERRCODE_DUPLICATE_DATABASE),
00443 errmsg("database \"%s\" already exists", dbname)));
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454 if (CountOtherDBBackends(src_dboid, ¬herbackends, &npreparedxacts))
00455 ereport(ERROR,
00456 (errcode(ERRCODE_OBJECT_IN_USE),
00457 errmsg("source database \"%s\" is being accessed by other users",
00458 dbtemplate),
00459 errdetail_busy_db(notherbackends, npreparedxacts)));
00460
00461
00462
00463
00464
00465
00466 pg_database_rel = heap_open(DatabaseRelationId, RowExclusiveLock);
00467
00468 do
00469 {
00470 dboid = GetNewOid(pg_database_rel);
00471 } while (check_db_file_conflict(dboid));
00472
00473
00474
00475
00476
00477
00478
00479
00480 MemSet(new_record, 0, sizeof(new_record));
00481 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
00482
00483 new_record[Anum_pg_database_datname - 1] =
00484 DirectFunctionCall1(namein, CStringGetDatum(dbname));
00485 new_record[Anum_pg_database_datdba - 1] = ObjectIdGetDatum(datdba);
00486 new_record[Anum_pg_database_encoding - 1] = Int32GetDatum(encoding);
00487 new_record[Anum_pg_database_datcollate - 1] =
00488 DirectFunctionCall1(namein, CStringGetDatum(dbcollate));
00489 new_record[Anum_pg_database_datctype - 1] =
00490 DirectFunctionCall1(namein, CStringGetDatum(dbctype));
00491 new_record[Anum_pg_database_datistemplate - 1] = BoolGetDatum(false);
00492 new_record[Anum_pg_database_datallowconn - 1] = BoolGetDatum(true);
00493 new_record[Anum_pg_database_datconnlimit - 1] = Int32GetDatum(dbconnlimit);
00494 new_record[Anum_pg_database_datlastsysoid - 1] = ObjectIdGetDatum(src_lastsysoid);
00495 new_record[Anum_pg_database_datfrozenxid - 1] = TransactionIdGetDatum(src_frozenxid);
00496 new_record[Anum_pg_database_datminmxid - 1] = TransactionIdGetDatum(src_minmxid);
00497 new_record[Anum_pg_database_dattablespace - 1] = ObjectIdGetDatum(dst_deftablespace);
00498
00499
00500
00501
00502
00503
00504 new_record_nulls[Anum_pg_database_datacl - 1] = true;
00505
00506 tuple = heap_form_tuple(RelationGetDescr(pg_database_rel),
00507 new_record, new_record_nulls);
00508
00509 HeapTupleSetOid(tuple, dboid);
00510
00511 simple_heap_insert(pg_database_rel, tuple);
00512
00513
00514 CatalogUpdateIndexes(pg_database_rel, tuple);
00515
00516
00517
00518
00519
00520
00521 recordDependencyOnOwner(DatabaseRelationId, dboid, datdba);
00522
00523
00524 copyTemplateDependencies(src_dboid, dboid);
00525
00526
00527 InvokeObjectPostCreateHook(DatabaseRelationId, dboid, 0);
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538 RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT);
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561 snapshot = RegisterSnapshot(GetLatestSnapshot());
00562
00563
00564
00565
00566
00567
00568
00569
00570 fparms.src_dboid = src_dboid;
00571 fparms.dest_dboid = dboid;
00572 PG_ENSURE_ERROR_CLEANUP(createdb_failure_callback,
00573 PointerGetDatum(&fparms));
00574 {
00575
00576
00577
00578
00579 rel = heap_open(TableSpaceRelationId, AccessShareLock);
00580 scan = heap_beginscan(rel, snapshot, 0, NULL);
00581 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
00582 {
00583 Oid srctablespace = HeapTupleGetOid(tuple);
00584 Oid dsttablespace;
00585 char *srcpath;
00586 char *dstpath;
00587 struct stat st;
00588
00589
00590 if (srctablespace == GLOBALTABLESPACE_OID)
00591 continue;
00592
00593 srcpath = GetDatabasePath(src_dboid, srctablespace);
00594
00595 if (stat(srcpath, &st) < 0 || !S_ISDIR(st.st_mode) ||
00596 directory_is_empty(srcpath))
00597 {
00598
00599 pfree(srcpath);
00600 continue;
00601 }
00602
00603 if (srctablespace == src_deftablespace)
00604 dsttablespace = dst_deftablespace;
00605 else
00606 dsttablespace = srctablespace;
00607
00608 dstpath = GetDatabasePath(dboid, dsttablespace);
00609
00610
00611
00612
00613
00614
00615 copydir(srcpath, dstpath, false);
00616
00617
00618 {
00619 xl_dbase_create_rec xlrec;
00620 XLogRecData rdata[1];
00621
00622 xlrec.db_id = dboid;
00623 xlrec.tablespace_id = dsttablespace;
00624 xlrec.src_db_id = src_dboid;
00625 xlrec.src_tablespace_id = srctablespace;
00626
00627 rdata[0].data = (char *) &xlrec;
00628 rdata[0].len = sizeof(xl_dbase_create_rec);
00629 rdata[0].buffer = InvalidBuffer;
00630 rdata[0].next = NULL;
00631
00632 (void) XLogInsert(RM_DBASE_ID, XLOG_DBASE_CREATE, rdata);
00633 }
00634 }
00635 heap_endscan(scan);
00636 heap_close(rel, AccessShareLock);
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667 RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT);
00668
00669
00670
00671
00672 heap_close(pg_database_rel, NoLock);
00673
00674
00675
00676
00677
00678
00679
00680 ForceSyncCommit();
00681 }
00682 PG_END_ENSURE_ERROR_CLEANUP(createdb_failure_callback,
00683 PointerGetDatum(&fparms));
00684
00685
00686 UnregisterSnapshot(snapshot);
00687
00688 return dboid;
00689 }
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713 void
00714 check_encoding_locale_matches(int encoding, const char *collate, const char *ctype)
00715 {
00716 int ctype_encoding = pg_get_encoding_from_locale(ctype, true);
00717 int collate_encoding = pg_get_encoding_from_locale(collate, true);
00718
00719 if (!(ctype_encoding == encoding ||
00720 ctype_encoding == PG_SQL_ASCII ||
00721 ctype_encoding == -1 ||
00722 #ifdef WIN32
00723 encoding == PG_UTF8 ||
00724 #endif
00725 (encoding == PG_SQL_ASCII && superuser())))
00726 ereport(ERROR,
00727 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00728 errmsg("encoding \"%s\" does not match locale \"%s\"",
00729 pg_encoding_to_char(encoding),
00730 ctype),
00731 errdetail("The chosen LC_CTYPE setting requires encoding \"%s\".",
00732 pg_encoding_to_char(ctype_encoding))));
00733
00734 if (!(collate_encoding == encoding ||
00735 collate_encoding == PG_SQL_ASCII ||
00736 collate_encoding == -1 ||
00737 #ifdef WIN32
00738 encoding == PG_UTF8 ||
00739 #endif
00740 (encoding == PG_SQL_ASCII && superuser())))
00741 ereport(ERROR,
00742 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00743 errmsg("encoding \"%s\" does not match locale \"%s\"",
00744 pg_encoding_to_char(encoding),
00745 collate),
00746 errdetail("The chosen LC_COLLATE setting requires encoding \"%s\".",
00747 pg_encoding_to_char(collate_encoding))));
00748 }
00749
00750
00751 static void
00752 createdb_failure_callback(int code, Datum arg)
00753 {
00754 createdb_failure_params *fparms = (createdb_failure_params *) DatumGetPointer(arg);
00755
00756
00757
00758
00759
00760
00761 UnlockSharedObject(DatabaseRelationId, fparms->src_dboid, 0, ShareLock);
00762
00763
00764 remove_dbtablespaces(fparms->dest_dboid);
00765 }
00766
00767
00768
00769
00770
00771 void
00772 dropdb(const char *dbname, bool missing_ok)
00773 {
00774 Oid db_id;
00775 bool db_istemplate;
00776 Relation pgdbrel;
00777 HeapTuple tup;
00778 int notherbackends;
00779 int npreparedxacts;
00780
00781
00782
00783
00784
00785
00786
00787
00788 pgdbrel = heap_open(DatabaseRelationId, RowExclusiveLock);
00789
00790 if (!get_db_info(dbname, AccessExclusiveLock, &db_id, NULL, NULL,
00791 &db_istemplate, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
00792 {
00793 if (!missing_ok)
00794 {
00795 ereport(ERROR,
00796 (errcode(ERRCODE_UNDEFINED_DATABASE),
00797 errmsg("database \"%s\" does not exist", dbname)));
00798 }
00799 else
00800 {
00801
00802 heap_close(pgdbrel, RowExclusiveLock);
00803 ereport(NOTICE,
00804 (errmsg("database \"%s\" does not exist, skipping",
00805 dbname)));
00806 return;
00807 }
00808 }
00809
00810
00811
00812
00813 if (!pg_database_ownercheck(db_id, GetUserId()))
00814 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
00815 dbname);
00816
00817
00818 InvokeObjectDropHook(DatabaseRelationId, db_id, 0);
00819
00820
00821
00822
00823
00824
00825 if (db_istemplate)
00826 ereport(ERROR,
00827 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00828 errmsg("cannot drop a template database")));
00829
00830
00831 if (db_id == MyDatabaseId)
00832 ereport(ERROR,
00833 (errcode(ERRCODE_OBJECT_IN_USE),
00834 errmsg("cannot drop the currently open database")));
00835
00836
00837
00838
00839
00840
00841
00842 if (CountOtherDBBackends(db_id, ¬herbackends, &npreparedxacts))
00843 ereport(ERROR,
00844 (errcode(ERRCODE_OBJECT_IN_USE),
00845 errmsg("database \"%s\" is being accessed by other users",
00846 dbname),
00847 errdetail_busy_db(notherbackends, npreparedxacts)));
00848
00849
00850
00851
00852 tup = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(db_id));
00853 if (!HeapTupleIsValid(tup))
00854 elog(ERROR, "cache lookup failed for database %u", db_id);
00855
00856 simple_heap_delete(pgdbrel, &tup->t_self);
00857
00858 ReleaseSysCache(tup);
00859
00860
00861
00862
00863 DeleteSharedComments(db_id, DatabaseRelationId);
00864 DeleteSharedSecurityLabel(db_id, DatabaseRelationId);
00865
00866
00867
00868
00869 DropSetting(db_id, InvalidOid);
00870
00871
00872
00873
00874 dropDatabaseDependencies(db_id);
00875
00876
00877
00878
00879
00880
00881 DropDatabaseBuffers(db_id);
00882
00883
00884
00885
00886 pgstat_drop_database(db_id);
00887
00888
00889
00890
00891
00892
00893
00894 ForgetDatabaseFsyncRequests(db_id);
00895
00896
00897
00898
00899
00900
00901
00902 RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT);
00903
00904
00905
00906
00907 remove_dbtablespaces(db_id);
00908
00909
00910
00911
00912 heap_close(pgdbrel, NoLock);
00913
00914
00915
00916
00917
00918
00919
00920 ForceSyncCommit();
00921 }
00922
00923
00924
00925
00926
00927 Oid
00928 RenameDatabase(const char *oldname, const char *newname)
00929 {
00930 Oid db_id;
00931 HeapTuple newtup;
00932 Relation rel;
00933 int notherbackends;
00934 int npreparedxacts;
00935
00936
00937
00938
00939
00940 rel = heap_open(DatabaseRelationId, RowExclusiveLock);
00941
00942 if (!get_db_info(oldname, AccessExclusiveLock, &db_id, NULL, NULL,
00943 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
00944 ereport(ERROR,
00945 (errcode(ERRCODE_UNDEFINED_DATABASE),
00946 errmsg("database \"%s\" does not exist", oldname)));
00947
00948
00949 if (!pg_database_ownercheck(db_id, GetUserId()))
00950 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
00951 oldname);
00952
00953
00954 if (!have_createdb_privilege())
00955 ereport(ERROR,
00956 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00957 errmsg("permission denied to rename database")));
00958
00959
00960
00961
00962
00963 if (OidIsValid(get_database_oid(newname, true)))
00964 ereport(ERROR,
00965 (errcode(ERRCODE_DUPLICATE_DATABASE),
00966 errmsg("database \"%s\" already exists", newname)));
00967
00968
00969
00970
00971
00972
00973
00974 if (db_id == MyDatabaseId)
00975 ereport(ERROR,
00976 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00977 errmsg("current database cannot be renamed")));
00978
00979
00980
00981
00982
00983
00984
00985 if (CountOtherDBBackends(db_id, ¬herbackends, &npreparedxacts))
00986 ereport(ERROR,
00987 (errcode(ERRCODE_OBJECT_IN_USE),
00988 errmsg("database \"%s\" is being accessed by other users",
00989 oldname),
00990 errdetail_busy_db(notherbackends, npreparedxacts)));
00991
00992
00993 newtup = SearchSysCacheCopy1(DATABASEOID, ObjectIdGetDatum(db_id));
00994 if (!HeapTupleIsValid(newtup))
00995 elog(ERROR, "cache lookup failed for database %u", db_id);
00996 namestrcpy(&(((Form_pg_database) GETSTRUCT(newtup))->datname), newname);
00997 simple_heap_update(rel, &newtup->t_self, newtup);
00998 CatalogUpdateIndexes(rel, newtup);
00999
01000 InvokeObjectPostAlterHook(DatabaseRelationId, db_id, 0);
01001
01002
01003
01004
01005 heap_close(rel, NoLock);
01006
01007 return db_id;
01008 }
01009
01010
01011
01012
01013
01014 static void
01015 movedb(const char *dbname, const char *tblspcname)
01016 {
01017 Oid db_id;
01018 Relation pgdbrel;
01019 int notherbackends;
01020 int npreparedxacts;
01021 HeapTuple oldtuple,
01022 newtuple;
01023 Oid src_tblspcoid,
01024 dst_tblspcoid;
01025 Datum new_record[Natts_pg_database];
01026 bool new_record_nulls[Natts_pg_database];
01027 bool new_record_repl[Natts_pg_database];
01028 ScanKeyData scankey;
01029 SysScanDesc sysscan;
01030 AclResult aclresult;
01031 char *src_dbpath;
01032 char *dst_dbpath;
01033 DIR *dstdir;
01034 struct dirent *xlde;
01035 movedb_failure_params fparms;
01036
01037
01038
01039
01040
01041
01042
01043 pgdbrel = heap_open(DatabaseRelationId, RowExclusiveLock);
01044
01045 if (!get_db_info(dbname, AccessExclusiveLock, &db_id, NULL, NULL,
01046 NULL, NULL, NULL, NULL, NULL, &src_tblspcoid, NULL, NULL))
01047 ereport(ERROR,
01048 (errcode(ERRCODE_UNDEFINED_DATABASE),
01049 errmsg("database \"%s\" does not exist", dbname)));
01050
01051
01052
01053
01054
01055
01056
01057 LockSharedObjectForSession(DatabaseRelationId, db_id, 0,
01058 AccessExclusiveLock);
01059
01060
01061
01062
01063 if (!pg_database_ownercheck(db_id, GetUserId()))
01064 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
01065 dbname);
01066
01067
01068
01069
01070 if (db_id == MyDatabaseId)
01071 ereport(ERROR,
01072 (errcode(ERRCODE_OBJECT_IN_USE),
01073 errmsg("cannot change the tablespace of the currently open database")));
01074
01075
01076
01077
01078 dst_tblspcoid = get_tablespace_oid(tblspcname, false);
01079
01080
01081
01082
01083 aclresult = pg_tablespace_aclcheck(dst_tblspcoid, GetUserId(),
01084 ACL_CREATE);
01085 if (aclresult != ACLCHECK_OK)
01086 aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
01087 tblspcname);
01088
01089
01090
01091
01092 if (dst_tblspcoid == GLOBALTABLESPACE_OID)
01093 ereport(ERROR,
01094 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
01095 errmsg("pg_global cannot be used as default tablespace")));
01096
01097
01098
01099
01100 if (src_tblspcoid == dst_tblspcoid)
01101 {
01102 heap_close(pgdbrel, NoLock);
01103 UnlockSharedObjectForSession(DatabaseRelationId, db_id, 0,
01104 AccessExclusiveLock);
01105 return;
01106 }
01107
01108
01109
01110
01111
01112
01113
01114 if (CountOtherDBBackends(db_id, ¬herbackends, &npreparedxacts))
01115 ereport(ERROR,
01116 (errcode(ERRCODE_OBJECT_IN_USE),
01117 errmsg("database \"%s\" is being accessed by other users",
01118 dbname),
01119 errdetail_busy_db(notherbackends, npreparedxacts)));
01120
01121
01122
01123
01124 src_dbpath = GetDatabasePath(db_id, src_tblspcoid);
01125 dst_dbpath = GetDatabasePath(db_id, dst_tblspcoid);
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137 RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT);
01138
01139
01140
01141
01142
01143
01144
01145
01146 dstdir = AllocateDir(dst_dbpath);
01147 if (dstdir != NULL)
01148 {
01149 while ((xlde = ReadDir(dstdir, dst_dbpath)) != NULL)
01150 {
01151 if (strcmp(xlde->d_name, ".") == 0 ||
01152 strcmp(xlde->d_name, "..") == 0)
01153 continue;
01154
01155 ereport(ERROR,
01156 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
01157 errmsg("some relations of database \"%s\" are already in tablespace \"%s\"",
01158 dbname, tblspcname),
01159 errhint("You must move them back to the database's default tablespace before using this command.")));
01160 }
01161
01162 FreeDir(dstdir);
01163
01164
01165
01166
01167
01168 if (rmdir(dst_dbpath) != 0)
01169 elog(ERROR, "could not remove directory \"%s\": %m",
01170 dst_dbpath);
01171 }
01172
01173
01174
01175
01176
01177
01178
01179 fparms.dest_dboid = db_id;
01180 fparms.dest_tsoid = dst_tblspcoid;
01181 PG_ENSURE_ERROR_CLEANUP(movedb_failure_callback,
01182 PointerGetDatum(&fparms));
01183 {
01184
01185
01186
01187 copydir(src_dbpath, dst_dbpath, false);
01188
01189
01190
01191
01192 {
01193 xl_dbase_create_rec xlrec;
01194 XLogRecData rdata[1];
01195
01196 xlrec.db_id = db_id;
01197 xlrec.tablespace_id = dst_tblspcoid;
01198 xlrec.src_db_id = db_id;
01199 xlrec.src_tablespace_id = src_tblspcoid;
01200
01201 rdata[0].data = (char *) &xlrec;
01202 rdata[0].len = sizeof(xl_dbase_create_rec);
01203 rdata[0].buffer = InvalidBuffer;
01204 rdata[0].next = NULL;
01205
01206 (void) XLogInsert(RM_DBASE_ID, XLOG_DBASE_CREATE, rdata);
01207 }
01208
01209
01210
01211
01212 ScanKeyInit(&scankey,
01213 Anum_pg_database_datname,
01214 BTEqualStrategyNumber, F_NAMEEQ,
01215 NameGetDatum(dbname));
01216 sysscan = systable_beginscan(pgdbrel, DatabaseNameIndexId, true,
01217 SnapshotNow, 1, &scankey);
01218 oldtuple = systable_getnext(sysscan);
01219 if (!HeapTupleIsValid(oldtuple))
01220 ereport(ERROR,
01221 (errcode(ERRCODE_UNDEFINED_DATABASE),
01222 errmsg("database \"%s\" does not exist", dbname)));
01223
01224 MemSet(new_record, 0, sizeof(new_record));
01225 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
01226 MemSet(new_record_repl, false, sizeof(new_record_repl));
01227
01228 new_record[Anum_pg_database_dattablespace - 1] = ObjectIdGetDatum(dst_tblspcoid);
01229 new_record_repl[Anum_pg_database_dattablespace - 1] = true;
01230
01231 newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(pgdbrel),
01232 new_record,
01233 new_record_nulls, new_record_repl);
01234 simple_heap_update(pgdbrel, &oldtuple->t_self, newtuple);
01235
01236
01237 CatalogUpdateIndexes(pgdbrel, newtuple);
01238
01239 InvokeObjectPostAlterHook(DatabaseRelationId,
01240 HeapTupleGetOid(newtuple), 0);
01241
01242 systable_endscan(sysscan);
01243
01244
01245
01246
01247
01248
01249
01250 RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT);
01251
01252
01253
01254
01255
01256
01257
01258 ForceSyncCommit();
01259
01260
01261
01262
01263 heap_close(pgdbrel, NoLock);
01264 }
01265 PG_END_ENSURE_ERROR_CLEANUP(movedb_failure_callback,
01266 PointerGetDatum(&fparms));
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279 PopActiveSnapshot();
01280 CommitTransactionCommand();
01281
01282
01283 StartTransactionCommand();
01284
01285
01286
01287
01288 if (!rmtree(src_dbpath, true))
01289 ereport(WARNING,
01290 (errmsg("some useless files may be left behind in old database directory \"%s\"",
01291 src_dbpath)));
01292
01293
01294
01295
01296 {
01297 xl_dbase_drop_rec xlrec;
01298 XLogRecData rdata[1];
01299
01300 xlrec.db_id = db_id;
01301 xlrec.tablespace_id = src_tblspcoid;
01302
01303 rdata[0].data = (char *) &xlrec;
01304 rdata[0].len = sizeof(xl_dbase_drop_rec);
01305 rdata[0].buffer = InvalidBuffer;
01306 rdata[0].next = NULL;
01307
01308 (void) XLogInsert(RM_DBASE_ID, XLOG_DBASE_DROP, rdata);
01309 }
01310
01311
01312 UnlockSharedObjectForSession(DatabaseRelationId, db_id, 0,
01313 AccessExclusiveLock);
01314 }
01315
01316
01317 static void
01318 movedb_failure_callback(int code, Datum arg)
01319 {
01320 movedb_failure_params *fparms = (movedb_failure_params *) DatumGetPointer(arg);
01321 char *dstpath;
01322
01323
01324 dstpath = GetDatabasePath(fparms->dest_dboid, fparms->dest_tsoid);
01325
01326 (void) rmtree(dstpath, true);
01327 }
01328
01329
01330
01331
01332
01333 Oid
01334 AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel)
01335 {
01336 Relation rel;
01337 Oid dboid;
01338 HeapTuple tuple,
01339 newtuple;
01340 ScanKeyData scankey;
01341 SysScanDesc scan;
01342 ListCell *option;
01343 int connlimit = -1;
01344 DefElem *dconnlimit = NULL;
01345 DefElem *dtablespace = NULL;
01346 Datum new_record[Natts_pg_database];
01347 bool new_record_nulls[Natts_pg_database];
01348 bool new_record_repl[Natts_pg_database];
01349
01350
01351 foreach(option, stmt->options)
01352 {
01353 DefElem *defel = (DefElem *) lfirst(option);
01354
01355 if (strcmp(defel->defname, "connectionlimit") == 0)
01356 {
01357 if (dconnlimit)
01358 ereport(ERROR,
01359 (errcode(ERRCODE_SYNTAX_ERROR),
01360 errmsg("conflicting or redundant options")));
01361 dconnlimit = defel;
01362 }
01363 else if (strcmp(defel->defname, "tablespace") == 0)
01364 {
01365 if (dtablespace)
01366 ereport(ERROR,
01367 (errcode(ERRCODE_SYNTAX_ERROR),
01368 errmsg("conflicting or redundant options")));
01369 dtablespace = defel;
01370 }
01371 else
01372 elog(ERROR, "option \"%s\" not recognized",
01373 defel->defname);
01374 }
01375
01376 if (dtablespace)
01377 {
01378
01379 Assert(!dconnlimit);
01380
01381 PreventTransactionChain(isTopLevel, "ALTER DATABASE SET TABLESPACE");
01382 movedb(stmt->dbname, strVal(dtablespace->arg));
01383 return InvalidOid;
01384 }
01385
01386 if (dconnlimit)
01387 {
01388 connlimit = intVal(dconnlimit->arg);
01389 if (connlimit < -1)
01390 ereport(ERROR,
01391 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
01392 errmsg("invalid connection limit: %d", connlimit)));
01393 }
01394
01395
01396
01397
01398
01399
01400 rel = heap_open(DatabaseRelationId, RowExclusiveLock);
01401 ScanKeyInit(&scankey,
01402 Anum_pg_database_datname,
01403 BTEqualStrategyNumber, F_NAMEEQ,
01404 NameGetDatum(stmt->dbname));
01405 scan = systable_beginscan(rel, DatabaseNameIndexId, true,
01406 SnapshotNow, 1, &scankey);
01407 tuple = systable_getnext(scan);
01408 if (!HeapTupleIsValid(tuple))
01409 ereport(ERROR,
01410 (errcode(ERRCODE_UNDEFINED_DATABASE),
01411 errmsg("database \"%s\" does not exist", stmt->dbname)));
01412
01413 dboid = HeapTupleGetOid(tuple);
01414
01415 if (!pg_database_ownercheck(HeapTupleGetOid(tuple), GetUserId()))
01416 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
01417 stmt->dbname);
01418
01419
01420
01421
01422 MemSet(new_record, 0, sizeof(new_record));
01423 MemSet(new_record_nulls, false, sizeof(new_record_nulls));
01424 MemSet(new_record_repl, false, sizeof(new_record_repl));
01425
01426 if (dconnlimit)
01427 {
01428 new_record[Anum_pg_database_datconnlimit - 1] = Int32GetDatum(connlimit);
01429 new_record_repl[Anum_pg_database_datconnlimit - 1] = true;
01430 }
01431
01432 newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel), new_record,
01433 new_record_nulls, new_record_repl);
01434 simple_heap_update(rel, &tuple->t_self, newtuple);
01435
01436
01437 CatalogUpdateIndexes(rel, newtuple);
01438
01439 InvokeObjectPostAlterHook(DatabaseRelationId,
01440 HeapTupleGetOid(newtuple), 0);
01441
01442 systable_endscan(scan);
01443
01444
01445 heap_close(rel, NoLock);
01446
01447 return dboid;
01448 }
01449
01450
01451
01452
01453
01454 Oid
01455 AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
01456 {
01457 Oid datid = get_database_oid(stmt->dbname, false);
01458
01459
01460
01461
01462
01463 shdepLockAndCheckObject(DatabaseRelationId, datid);
01464
01465 if (!pg_database_ownercheck(datid, GetUserId()))
01466 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
01467 stmt->dbname);
01468
01469 AlterSetting(datid, InvalidOid, stmt->setstmt);
01470
01471 UnlockSharedObject(DatabaseRelationId, datid, 0, AccessShareLock);
01472
01473 return datid;
01474 }
01475
01476
01477
01478
01479
01480 Oid
01481 AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
01482 {
01483 Oid db_id;
01484 HeapTuple tuple;
01485 Relation rel;
01486 ScanKeyData scankey;
01487 SysScanDesc scan;
01488 Form_pg_database datForm;
01489
01490
01491
01492
01493
01494
01495 rel = heap_open(DatabaseRelationId, RowExclusiveLock);
01496 ScanKeyInit(&scankey,
01497 Anum_pg_database_datname,
01498 BTEqualStrategyNumber, F_NAMEEQ,
01499 NameGetDatum(dbname));
01500 scan = systable_beginscan(rel, DatabaseNameIndexId, true,
01501 SnapshotNow, 1, &scankey);
01502 tuple = systable_getnext(scan);
01503 if (!HeapTupleIsValid(tuple))
01504 ereport(ERROR,
01505 (errcode(ERRCODE_UNDEFINED_DATABASE),
01506 errmsg("database \"%s\" does not exist", dbname)));
01507
01508 db_id = HeapTupleGetOid(tuple);
01509 datForm = (Form_pg_database) GETSTRUCT(tuple);
01510
01511
01512
01513
01514
01515
01516 if (datForm->datdba != newOwnerId)
01517 {
01518 Datum repl_val[Natts_pg_database];
01519 bool repl_null[Natts_pg_database];
01520 bool repl_repl[Natts_pg_database];
01521 Acl *newAcl;
01522 Datum aclDatum;
01523 bool isNull;
01524 HeapTuple newtuple;
01525
01526
01527 if (!pg_database_ownercheck(HeapTupleGetOid(tuple), GetUserId()))
01528 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
01529 dbname);
01530
01531
01532 check_is_member_of_role(GetUserId(), newOwnerId);
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543 if (!have_createdb_privilege())
01544 ereport(ERROR,
01545 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
01546 errmsg("permission denied to change owner of database")));
01547
01548 memset(repl_null, false, sizeof(repl_null));
01549 memset(repl_repl, false, sizeof(repl_repl));
01550
01551 repl_repl[Anum_pg_database_datdba - 1] = true;
01552 repl_val[Anum_pg_database_datdba - 1] = ObjectIdGetDatum(newOwnerId);
01553
01554
01555
01556
01557
01558 aclDatum = heap_getattr(tuple,
01559 Anum_pg_database_datacl,
01560 RelationGetDescr(rel),
01561 &isNull);
01562 if (!isNull)
01563 {
01564 newAcl = aclnewowner(DatumGetAclP(aclDatum),
01565 datForm->datdba, newOwnerId);
01566 repl_repl[Anum_pg_database_datacl - 1] = true;
01567 repl_val[Anum_pg_database_datacl - 1] = PointerGetDatum(newAcl);
01568 }
01569
01570 newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel), repl_val, repl_null, repl_repl);
01571 simple_heap_update(rel, &newtuple->t_self, newtuple);
01572 CatalogUpdateIndexes(rel, newtuple);
01573
01574 heap_freetuple(newtuple);
01575
01576
01577 changeDependencyOnOwner(DatabaseRelationId, HeapTupleGetOid(tuple),
01578 newOwnerId);
01579 }
01580
01581 InvokeObjectPostAlterHook(DatabaseRelationId, HeapTupleGetOid(tuple), 0);
01582
01583 systable_endscan(scan);
01584
01585
01586 heap_close(rel, NoLock);
01587
01588 return db_id;
01589 }
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602 static bool
01603 get_db_info(const char *name, LOCKMODE lockmode,
01604 Oid *dbIdP, Oid *ownerIdP,
01605 int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
01606 Oid *dbLastSysOidP, TransactionId *dbFrozenXidP,
01607 MultiXactId *dbMinMultiP,
01608 Oid *dbTablespace, char **dbCollate, char **dbCtype)
01609 {
01610 bool result = false;
01611 Relation relation;
01612
01613 AssertArg(name);
01614
01615
01616 relation = heap_open(DatabaseRelationId, AccessShareLock);
01617
01618
01619
01620
01621
01622
01623 for (;;)
01624 {
01625 ScanKeyData scanKey;
01626 SysScanDesc scan;
01627 HeapTuple tuple;
01628 Oid dbOid;
01629
01630
01631
01632
01633
01634 ScanKeyInit(&scanKey,
01635 Anum_pg_database_datname,
01636 BTEqualStrategyNumber, F_NAMEEQ,
01637 NameGetDatum(name));
01638
01639 scan = systable_beginscan(relation, DatabaseNameIndexId, true,
01640 SnapshotNow, 1, &scanKey);
01641
01642 tuple = systable_getnext(scan);
01643
01644 if (!HeapTupleIsValid(tuple))
01645 {
01646
01647 systable_endscan(scan);
01648 break;
01649 }
01650
01651 dbOid = HeapTupleGetOid(tuple);
01652
01653 systable_endscan(scan);
01654
01655
01656
01657
01658 if (lockmode != NoLock)
01659 LockSharedObject(DatabaseRelationId, dbOid, 0, lockmode);
01660
01661
01662
01663
01664
01665
01666 tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(dbOid));
01667 if (HeapTupleIsValid(tuple))
01668 {
01669 Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple);
01670
01671 if (strcmp(name, NameStr(dbform->datname)) == 0)
01672 {
01673
01674 if (dbIdP)
01675 *dbIdP = dbOid;
01676
01677 if (ownerIdP)
01678 *ownerIdP = dbform->datdba;
01679
01680 if (encodingP)
01681 *encodingP = dbform->encoding;
01682
01683 if (dbIsTemplateP)
01684 *dbIsTemplateP = dbform->datistemplate;
01685
01686 if (dbAllowConnP)
01687 *dbAllowConnP = dbform->datallowconn;
01688
01689 if (dbLastSysOidP)
01690 *dbLastSysOidP = dbform->datlastsysoid;
01691
01692 if (dbFrozenXidP)
01693 *dbFrozenXidP = dbform->datfrozenxid;
01694
01695 if (dbMinMultiP)
01696 *dbMinMultiP = dbform->datminmxid;
01697
01698 if (dbTablespace)
01699 *dbTablespace = dbform->dattablespace;
01700
01701 if (dbCollate)
01702 *dbCollate = pstrdup(NameStr(dbform->datcollate));
01703 if (dbCtype)
01704 *dbCtype = pstrdup(NameStr(dbform->datctype));
01705 ReleaseSysCache(tuple);
01706 result = true;
01707 break;
01708 }
01709
01710 ReleaseSysCache(tuple);
01711 }
01712
01713 if (lockmode != NoLock)
01714 UnlockSharedObject(DatabaseRelationId, dbOid, 0, lockmode);
01715 }
01716
01717 heap_close(relation, AccessShareLock);
01718
01719 return result;
01720 }
01721
01722
01723 static bool
01724 have_createdb_privilege(void)
01725 {
01726 bool result = false;
01727 HeapTuple utup;
01728
01729
01730 if (superuser())
01731 return true;
01732
01733 utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(GetUserId()));
01734 if (HeapTupleIsValid(utup))
01735 {
01736 result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreatedb;
01737 ReleaseSysCache(utup);
01738 }
01739 return result;
01740 }
01741
01742
01743
01744
01745
01746
01747
01748 static void
01749 remove_dbtablespaces(Oid db_id)
01750 {
01751 Relation rel;
01752 HeapScanDesc scan;
01753 HeapTuple tuple;
01754 Snapshot snapshot;
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764 snapshot = RegisterSnapshot(GetLatestSnapshot());
01765
01766 rel = heap_open(TableSpaceRelationId, AccessShareLock);
01767 scan = heap_beginscan(rel, snapshot, 0, NULL);
01768 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
01769 {
01770 Oid dsttablespace = HeapTupleGetOid(tuple);
01771 char *dstpath;
01772 struct stat st;
01773
01774
01775 if (dsttablespace == GLOBALTABLESPACE_OID)
01776 continue;
01777
01778 dstpath = GetDatabasePath(db_id, dsttablespace);
01779
01780 if (lstat(dstpath, &st) < 0 || !S_ISDIR(st.st_mode))
01781 {
01782
01783 pfree(dstpath);
01784 continue;
01785 }
01786
01787 if (!rmtree(dstpath, true))
01788 ereport(WARNING,
01789 (errmsg("some useless files may be left behind in old database directory \"%s\"",
01790 dstpath)));
01791
01792
01793 {
01794 xl_dbase_drop_rec xlrec;
01795 XLogRecData rdata[1];
01796
01797 xlrec.db_id = db_id;
01798 xlrec.tablespace_id = dsttablespace;
01799
01800 rdata[0].data = (char *) &xlrec;
01801 rdata[0].len = sizeof(xl_dbase_drop_rec);
01802 rdata[0].buffer = InvalidBuffer;
01803 rdata[0].next = NULL;
01804
01805 (void) XLogInsert(RM_DBASE_ID, XLOG_DBASE_DROP, rdata);
01806 }
01807
01808 pfree(dstpath);
01809 }
01810
01811 heap_endscan(scan);
01812 heap_close(rel, AccessShareLock);
01813 UnregisterSnapshot(snapshot);
01814 }
01815
01816
01817
01818
01819
01820
01821
01822
01823
01824
01825
01826
01827
01828 static bool
01829 check_db_file_conflict(Oid db_id)
01830 {
01831 bool result = false;
01832 Relation rel;
01833 HeapScanDesc scan;
01834 HeapTuple tuple;
01835 Snapshot snapshot;
01836
01837
01838
01839
01840
01841
01842
01843
01844 snapshot = RegisterSnapshot(GetLatestSnapshot());
01845
01846 rel = heap_open(TableSpaceRelationId, AccessShareLock);
01847 scan = heap_beginscan(rel, snapshot, 0, NULL);
01848 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
01849 {
01850 Oid dsttablespace = HeapTupleGetOid(tuple);
01851 char *dstpath;
01852 struct stat st;
01853
01854
01855 if (dsttablespace == GLOBALTABLESPACE_OID)
01856 continue;
01857
01858 dstpath = GetDatabasePath(db_id, dsttablespace);
01859
01860 if (lstat(dstpath, &st) == 0)
01861 {
01862
01863 pfree(dstpath);
01864 result = true;
01865 break;
01866 }
01867
01868 pfree(dstpath);
01869 }
01870
01871 heap_endscan(scan);
01872 heap_close(rel, AccessShareLock);
01873 UnregisterSnapshot(snapshot);
01874
01875 return result;
01876 }
01877
01878
01879
01880
01881 static int
01882 errdetail_busy_db(int notherbackends, int npreparedxacts)
01883 {
01884 if (notherbackends > 0 && npreparedxacts > 0)
01885
01886
01887 errdetail("There are %d other session(s) and %d prepared transaction(s) using the database.",
01888 notherbackends, npreparedxacts);
01889 else if (notherbackends > 0)
01890 errdetail_plural("There is %d other session using the database.",
01891 "There are %d other sessions using the database.",
01892 notherbackends,
01893 notherbackends);
01894 else
01895 errdetail_plural("There is %d prepared transaction using the database.",
01896 "There are %d prepared transactions using the database.",
01897 npreparedxacts,
01898 npreparedxacts);
01899 return 0;
01900 }
01901
01902
01903
01904
01905
01906
01907
01908 Oid
01909 get_database_oid(const char *dbname, bool missing_ok)
01910 {
01911 Relation pg_database;
01912 ScanKeyData entry[1];
01913 SysScanDesc scan;
01914 HeapTuple dbtuple;
01915 Oid oid;
01916
01917
01918
01919
01920
01921 pg_database = heap_open(DatabaseRelationId, AccessShareLock);
01922 ScanKeyInit(&entry[0],
01923 Anum_pg_database_datname,
01924 BTEqualStrategyNumber, F_NAMEEQ,
01925 CStringGetDatum(dbname));
01926 scan = systable_beginscan(pg_database, DatabaseNameIndexId, true,
01927 SnapshotNow, 1, entry);
01928
01929 dbtuple = systable_getnext(scan);
01930
01931
01932 if (HeapTupleIsValid(dbtuple))
01933 oid = HeapTupleGetOid(dbtuple);
01934 else
01935 oid = InvalidOid;
01936
01937 systable_endscan(scan);
01938 heap_close(pg_database, AccessShareLock);
01939
01940 if (!OidIsValid(oid) && !missing_ok)
01941 ereport(ERROR,
01942 (errcode(ERRCODE_UNDEFINED_DATABASE),
01943 errmsg("database \"%s\" does not exist",
01944 dbname)));
01945
01946 return oid;
01947 }
01948
01949
01950
01951
01952
01953
01954
01955 char *
01956 get_database_name(Oid dbid)
01957 {
01958 HeapTuple dbtuple;
01959 char *result;
01960
01961 dbtuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(dbid));
01962 if (HeapTupleIsValid(dbtuple))
01963 {
01964 result = pstrdup(NameStr(((Form_pg_database) GETSTRUCT(dbtuple))->datname));
01965 ReleaseSysCache(dbtuple);
01966 }
01967 else
01968 result = NULL;
01969
01970 return result;
01971 }
01972
01973
01974
01975
01976 void
01977 dbase_redo(XLogRecPtr lsn, XLogRecord *record)
01978 {
01979 uint8 info = record->xl_info & ~XLR_INFO_MASK;
01980
01981
01982 Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
01983
01984 if (info == XLOG_DBASE_CREATE)
01985 {
01986 xl_dbase_create_rec *xlrec = (xl_dbase_create_rec *) XLogRecGetData(record);
01987 char *src_path;
01988 char *dst_path;
01989 struct stat st;
01990
01991 src_path = GetDatabasePath(xlrec->src_db_id, xlrec->src_tablespace_id);
01992 dst_path = GetDatabasePath(xlrec->db_id, xlrec->tablespace_id);
01993
01994
01995
01996
01997
01998
01999 if (stat(dst_path, &st) == 0 && S_ISDIR(st.st_mode))
02000 {
02001 if (!rmtree(dst_path, true))
02002
02003 ereport(WARNING,
02004 (errmsg("some useless files may be left behind in old database directory \"%s\"",
02005 dst_path)));
02006 }
02007
02008
02009
02010
02011
02012 FlushDatabaseBuffers(xlrec->src_db_id);
02013
02014
02015
02016
02017
02018
02019 copydir(src_path, dst_path, false);
02020 }
02021 else if (info == XLOG_DBASE_DROP)
02022 {
02023 xl_dbase_drop_rec *xlrec = (xl_dbase_drop_rec *) XLogRecGetData(record);
02024 char *dst_path;
02025
02026 dst_path = GetDatabasePath(xlrec->db_id, xlrec->tablespace_id);
02027
02028 if (InHotStandby)
02029 {
02030
02031
02032
02033
02034
02035
02036 LockSharedObjectForSession(DatabaseRelationId, xlrec->db_id, 0, AccessExclusiveLock);
02037 ResolveRecoveryConflictWithDatabase(xlrec->db_id);
02038 }
02039
02040
02041 DropDatabaseBuffers(xlrec->db_id);
02042
02043
02044 ForgetDatabaseFsyncRequests(xlrec->db_id);
02045
02046
02047 XLogDropDatabase(xlrec->db_id);
02048
02049
02050 if (!rmtree(dst_path, true))
02051 ereport(WARNING,
02052 (errmsg("some useless files may be left behind in old database directory \"%s\"",
02053 dst_path)));
02054
02055 if (InHotStandby)
02056 {
02057
02058
02059
02060
02061
02062
02063
02064 UnlockSharedObjectForSession(DatabaseRelationId, xlrec->db_id, 0, AccessExclusiveLock);
02065 }
02066 }
02067 else
02068 elog(PANIC, "dbase_redo: unknown op code %u", info);
02069 }