void InitPostgres(char *name) /* database name */ { bool bootstrap; /* true if BootstrapProcessing */ /* ---------------- * see if we're running in BootstrapProcessing mode * ---------------- */ bootstrap = IsBootstrapProcessingMode(); /* ---------------- * turn on the exception handler. Note: we cannot use elog, Assert, * AssertState, etc. until after exception handling is on. * ---------------- */ EnableExceptionHandling(true); /* ---------------- * A stupid check to make sure we don't call this more than once. * But things like ReinitPostgres() get around this by just diddling * the PostgresIsInitialized flag. * ---------------- */ AssertState(!PostgresIsInitialized); /* ---------------- * Memory system initialization. * (we may call palloc after EnableMemoryContext()) * * Note EnableMemoryContext() must happen before EnablePortalManager(). * ---------------- */ EnableMemoryContext(true); /* initializes the "top context" */ EnablePortalManager(true); /* memory for portal/transaction stuff */ /* ---------------- * initialize the backend local portal stack used by * internal PQ function calls. see src/lib/libpq/be-dumpdata.c * This is different from the "portal manager" so this goes here. * -cim 2/12/91 * ---------------- */ be_portalinit(); /* ---------------- * attach to shared memory and semaphores, and initialize our * input/output/debugging file descriptors. * ---------------- */ InitCommunication(); InitStdio(); /* * initialize the local buffer manager */ InitLocalBuffer(); if (!TransactionFlushEnabled()) on_exitpg(FlushBufferPool, (caddr_t) NULL); /* ---------------- * check for valid "meta gunk" (??? -cim 10/5/90) and change to * database directory. * * Note: DatabaseName, MyDatabaseName, and DatabasePath are all * initialized with DatabaseMetaGunkIsConsistent(), strncpy() and * DoChdirAndInitDatabase() below! XXX clean this crap up! * -cim 10/5/90 * ---------------- */ { char myPath[MAXPGPATH] = "."; /* DatabasePath points here! */ /* ---------------- * DatabaseMetaGunkIsConsistent fills in myPath, but what about * when bootstrap or Noversion is true?? -cim 10/5/90 * ---------------- */ if (! bootstrap && ! DatabaseMetaGunkIsConsistent(name, myPath) && ! Noversion) { elog(NOTICE, "InitPostgres: could not locate valid PG_VERSION\n"); elog(NOTICE, "files for %s and %s.", DataDir, name); elog(FATAL, "Have you run initdb/createdb and set PGDATA properly?"); } /* ---------------- * ok, we've figured out myName and myPath, now save these * and chdir to myPath. * ---------------- */ DoChdirAndInitDatabaseNameAndPath(name, myPath); } /* ******************************** * code after this point assumes we are in the proper directory! * ******************************** */ /* ---------------- * initialize the database id used for system caches and lock tables * ---------------- */ InitMyDatabaseId(); smgrinit(); /* ---------------- * initialize the transaction system and the relation descriptor * cache. Note we have to make certain the lock manager is off while * we do this. * ---------------- */ AmiTransactionOverride(IsBootstrapProcessingMode()); LockDisable(true); /* * Part of the initialization processing done here sets a read * lock on pg_log. Since locking is disabled the set doesn't have * intended effect of locking out writers, but this is ok, since * we only lock it to examine AMI transaction status, and this is * never written after initdb is done. -mer 15 June 1992 */ RelationInitialize(); /* pre-allocated reldescs created here */ InitializeTransactionSystem(); /* pg_log,etc init/crash recovery here */ LockDisable(false); /* ---------------- * anyone knows what this does? something having to do with * system catalog cache invalidation in the case of multiple * backends, I think -cim 10/3/90 * Sets up MyBackendId a unique backend identifier. * ---------------- */ InitSharedInvalidationState(); /* ---------------- * Set up a per backend process in shared memory. Must be done after * InitSharedInvalidationState() as it relies on MyBackendId being * initialized already. XXX -mer 11 Aug 1991 * ---------------- */ InitProcess(PostgresIpcKey); if (MyBackendId > MaxBackendId || MyBackendId <= 0) { elog(FATAL, "cinit2: bad backend id %d (%d)", MyBackendTag, MyBackendId); } /* ---------------- * initialize the access methods. * ---------------- */ initam(); /* ---------------- * initialize all the system catalog caches. * ---------------- */ zerocaches(); InitCatalogCache(); /* ---------------- * set ourselves to the proper user id and figure out our postgres * user id. If we ever add security so that we check for valid * postgres users, we might do it here. * ---------------- */ InitUserid(); /* ---------------- * ok, all done, now let's make sure we don't do it again. * ---------------- */ PostgresIsInitialized = true; /* on_exitpg(DestroyLocalRelList, (caddr_t) NULL); */ /* ---------------- * Done with "InitPostgres", now change to NormalProcessing unless * we're in BootstrapProcessing mode. * ---------------- */ if (!bootstrap) SetProcessingMode(NormalProcessing); /* if (testFlag || lockingOff) */ if (lockingOff) LockDisable(true); }
/* -------------------------------- * InitPostgres * Initialize POSTGRES. * * Note: * Be very careful with the order of calls in the InitPostgres function. * -------------------------------- */ void InitPostgres(const char *dbname, const char *username) { bool bootstrap = IsBootstrapProcessingMode(); /* * Set up the global variables holding database id and path. * * We take a shortcut in the bootstrap case, otherwise we have to look up * the db name in pg_database. */ if (bootstrap) { MyDatabaseId = TemplateDbOid; SetDatabasePath(GetDatabasePath(MyDatabaseId)); } else { char *fullpath, datpath[MAXPGPATH]; /* * Formerly we validated DataDir here, but now that's done * earlier. */ /* * Find oid and path of the database we're about to open. Since * we're not yet up and running we have to use the hackish * GetRawDatabaseInfo. */ GetRawDatabaseInfo(dbname, &MyDatabaseId, datpath); if (!OidIsValid(MyDatabaseId)) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname))); fullpath = GetDatabasePath(MyDatabaseId); /* Verify the database path */ if (access(fullpath, F_OK) == -1) { if (errno == ENOENT) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname), errdetail("The database subdirectory \"%s\" is missing.", fullpath))); else ereport(FATAL, (errcode_for_file_access(), errmsg("could not access directory \"%s\": %m", fullpath))); } ValidatePgVersion(fullpath); if (chdir(fullpath) == -1) ereport(FATAL, (errcode_for_file_access(), errmsg("could not change directory to \"%s\": %m", fullpath))); SetDatabasePath(fullpath); } /* * Code after this point assumes we are in the proper directory! */ /* * Set up my per-backend PGPROC struct in shared memory. (We need * to know MyDatabaseId before we can do this, since it's entered into * the PGPROC struct.) */ InitProcess(); /* * Initialize my entry in the shared-invalidation manager's array of * per-backend data. (Formerly this came before InitProcess, but now * it must happen after, because it uses MyProc.) Once I have done * this, I am visible to other backends! * * Sets up MyBackendId, a unique backend identifier. */ MyBackendId = InvalidBackendId; InitBackendSharedInvalidationState(); if (MyBackendId > MaxBackends || MyBackendId <= 0) elog(FATAL, "bad backend id: %d", MyBackendId); /* * Initialize the transaction system override state. */ AmiTransactionOverride(bootstrap); /* * Initialize the relation descriptor cache. This must create at * least the minimum set of "nailed-in" cache entries. No catalog * access happens here. */ RelationCacheInitialize(); /* * Initialize all the system catalog caches. Note that no catalog * access happens here; we only set up the cache structure. */ InitCatalogCache(); /* Initialize portal manager */ EnablePortalManager(); /* * Initialize the deferred trigger manager --- must happen before * first transaction start. */ DeferredTriggerInit(); /* start a new transaction here before access to db */ if (!bootstrap) StartTransactionCommand(); /* * It's now possible to do real access to the system catalogs. * * Replace faked-up relcache entries with correct info. */ RelationCacheInitializePhase2(); /* * Figure out our postgres user id. In standalone mode we use a fixed * id, otherwise we figure it out from the authenticated user name. */ if (bootstrap) InitializeSessionUserIdStandalone(); else if (!IsUnderPostmaster) { InitializeSessionUserIdStandalone(); if (!ThereIsAtLeastOneUser()) ereport(WARNING, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("no users are defined in this database system"), errhint("You should immediately run CREATE USER \"%s\" WITH SYSID %d CREATEUSER;.", username, BOOTSTRAP_USESYSID))); } else { /* normal multiuser case */ InitializeSessionUserId(username); } /* * Unless we are bootstrapping, double-check that InitMyDatabaseInfo() * got a correct result. We can't do this until all the * database-access infrastructure is up. */ if (!bootstrap) ReverifyMyDatabase(dbname); /* * Final phase of relation cache startup: write a new cache file if * necessary. This is done after ReverifyMyDatabase to avoid writing * a cache file into a dead database. */ RelationCacheInitializePhase3(); /* * Check a normal user hasn't connected to a superuser reserved slot. * We can't do this till after we've read the user information, and we * must do it inside a transaction since checking superuserness may * require database access. The superuser check is probably the most * expensive part; don't do it until necessary. */ if (ReservedBackends > 0 && CountEmptyBackendSlots() < ReservedBackends && !superuser()) ereport(FATAL, (errcode(ERRCODE_TOO_MANY_CONNECTIONS), errmsg("connection limit exceeded for non-superusers"))); /* * Initialize various default states that can't be set up until we've * selected the active user and done ReverifyMyDatabase. */ /* set default namespace search path */ InitializeSearchPath(); /* initialize client encoding */ InitializeClientEncoding(); /* * Now all default states are fully set up. Report them to client if * appropriate. */ BeginReportingGUCOptions(); /* * Set up process-exit callback to do pre-shutdown cleanup. This * should be last because we want shmem_exit to call this routine * before the exit callbacks that are registered by buffer manager, * lock manager, etc. We need to run this code before we close down * database access! */ on_shmem_exit(ShutdownPostgres, 0); /* close the transaction we started above */ if (!bootstrap) CommitTransactionCommand(); }