1 | /*------------------------------------------------------------------------- |
2 | * |
3 | * postinit.c |
4 | * postgres initialization utilities |
5 | * |
6 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
7 | * Portions Copyright (c) 1994, Regents of the University of California |
8 | * |
9 | * |
10 | * IDENTIFICATION |
11 | * src/backend/utils/init/postinit.c |
12 | * |
13 | * |
14 | *------------------------------------------------------------------------- |
15 | */ |
16 | #include "postgres.h" |
17 | |
18 | #include <ctype.h> |
19 | #include <fcntl.h> |
20 | #include <unistd.h> |
21 | |
22 | #include "access/genam.h" |
23 | #include "access/heapam.h" |
24 | #include "access/htup_details.h" |
25 | #include "access/session.h" |
26 | #include "access/sysattr.h" |
27 | #include "access/tableam.h" |
28 | #include "access/xact.h" |
29 | #include "access/xlog.h" |
30 | #include "catalog/catalog.h" |
31 | #include "catalog/indexing.h" |
32 | #include "catalog/namespace.h" |
33 | #include "catalog/pg_authid.h" |
34 | #include "catalog/pg_database.h" |
35 | #include "catalog/pg_db_role_setting.h" |
36 | #include "catalog/pg_tablespace.h" |
37 | #include "libpq/auth.h" |
38 | #include "libpq/libpq-be.h" |
39 | #include "mb/pg_wchar.h" |
40 | #include "miscadmin.h" |
41 | #include "pgstat.h" |
42 | #include "postmaster/autovacuum.h" |
43 | #include "postmaster/postmaster.h" |
44 | #include "replication/walsender.h" |
45 | #include "storage/bufmgr.h" |
46 | #include "storage/fd.h" |
47 | #include "storage/ipc.h" |
48 | #include "storage/lmgr.h" |
49 | #include "storage/procarray.h" |
50 | #include "storage/procsignal.h" |
51 | #include "storage/proc.h" |
52 | #include "storage/sinvaladt.h" |
53 | #include "storage/smgr.h" |
54 | #include "storage/sync.h" |
55 | #include "tcop/tcopprot.h" |
56 | #include "utils/acl.h" |
57 | #include "utils/fmgroids.h" |
58 | #include "utils/guc.h" |
59 | #include "utils/memutils.h" |
60 | #include "utils/pg_locale.h" |
61 | #include "utils/portal.h" |
62 | #include "utils/ps_status.h" |
63 | #include "utils/snapmgr.h" |
64 | #include "utils/syscache.h" |
65 | #include "utils/timeout.h" |
66 | |
67 | |
68 | static HeapTuple GetDatabaseTuple(const char *dbname); |
69 | static HeapTuple GetDatabaseTupleByOid(Oid dboid); |
70 | static void PerformAuthentication(Port *port); |
71 | static void CheckMyDatabase(const char *name, bool am_superuser, bool override_allow_connections); |
72 | static void InitCommunication(void); |
73 | static void ShutdownPostgres(int code, Datum arg); |
74 | static void StatementTimeoutHandler(void); |
75 | static void LockTimeoutHandler(void); |
76 | static void IdleInTransactionSessionTimeoutHandler(void); |
77 | static bool ThereIsAtLeastOneRole(void); |
78 | static void process_startup_options(Port *port, bool am_superuser); |
79 | static void process_settings(Oid databaseid, Oid roleid); |
80 | |
81 | |
82 | /*** InitPostgres support ***/ |
83 | |
84 | |
85 | /* |
86 | * GetDatabaseTuple -- fetch the pg_database row for a database |
87 | * |
88 | * This is used during backend startup when we don't yet have any access to |
89 | * system catalogs in general. In the worst case, we can seqscan pg_database |
90 | * using nothing but the hard-wired descriptor that relcache.c creates for |
91 | * pg_database. In more typical cases, relcache.c was able to load |
92 | * descriptors for both pg_database and its indexes from the shared relcache |
93 | * cache file, and so we can do an indexscan. criticalSharedRelcachesBuilt |
94 | * tells whether we got the cached descriptors. |
95 | */ |
96 | static HeapTuple |
97 | GetDatabaseTuple(const char *dbname) |
98 | { |
99 | HeapTuple tuple; |
100 | Relation relation; |
101 | SysScanDesc scan; |
102 | ScanKeyData key[1]; |
103 | |
104 | /* |
105 | * form a scan key |
106 | */ |
107 | ScanKeyInit(&key[0], |
108 | Anum_pg_database_datname, |
109 | BTEqualStrategyNumber, F_NAMEEQ, |
110 | CStringGetDatum(dbname)); |
111 | |
112 | /* |
113 | * Open pg_database and fetch a tuple. Force heap scan if we haven't yet |
114 | * built the critical shared relcache entries (i.e., we're starting up |
115 | * without a shared relcache cache file). |
116 | */ |
117 | relation = table_open(DatabaseRelationId, AccessShareLock); |
118 | scan = systable_beginscan(relation, DatabaseNameIndexId, |
119 | criticalSharedRelcachesBuilt, |
120 | NULL, |
121 | 1, key); |
122 | |
123 | tuple = systable_getnext(scan); |
124 | |
125 | /* Must copy tuple before releasing buffer */ |
126 | if (HeapTupleIsValid(tuple)) |
127 | tuple = heap_copytuple(tuple); |
128 | |
129 | /* all done */ |
130 | systable_endscan(scan); |
131 | table_close(relation, AccessShareLock); |
132 | |
133 | return tuple; |
134 | } |
135 | |
136 | /* |
137 | * GetDatabaseTupleByOid -- as above, but search by database OID |
138 | */ |
139 | static HeapTuple |
140 | GetDatabaseTupleByOid(Oid dboid) |
141 | { |
142 | HeapTuple tuple; |
143 | Relation relation; |
144 | SysScanDesc scan; |
145 | ScanKeyData key[1]; |
146 | |
147 | /* |
148 | * form a scan key |
149 | */ |
150 | ScanKeyInit(&key[0], |
151 | Anum_pg_database_oid, |
152 | BTEqualStrategyNumber, F_OIDEQ, |
153 | ObjectIdGetDatum(dboid)); |
154 | |
155 | /* |
156 | * Open pg_database and fetch a tuple. Force heap scan if we haven't yet |
157 | * built the critical shared relcache entries (i.e., we're starting up |
158 | * without a shared relcache cache file). |
159 | */ |
160 | relation = table_open(DatabaseRelationId, AccessShareLock); |
161 | scan = systable_beginscan(relation, DatabaseOidIndexId, |
162 | criticalSharedRelcachesBuilt, |
163 | NULL, |
164 | 1, key); |
165 | |
166 | tuple = systable_getnext(scan); |
167 | |
168 | /* Must copy tuple before releasing buffer */ |
169 | if (HeapTupleIsValid(tuple)) |
170 | tuple = heap_copytuple(tuple); |
171 | |
172 | /* all done */ |
173 | systable_endscan(scan); |
174 | table_close(relation, AccessShareLock); |
175 | |
176 | return tuple; |
177 | } |
178 | |
179 | |
180 | /* |
181 | * PerformAuthentication -- authenticate a remote client |
182 | * |
183 | * returns: nothing. Will not return at all if there's any failure. |
184 | */ |
185 | static void |
186 | PerformAuthentication(Port *port) |
187 | { |
188 | /* This should be set already, but let's make sure */ |
189 | ClientAuthInProgress = true; /* limit visibility of log messages */ |
190 | |
191 | /* |
192 | * In EXEC_BACKEND case, we didn't inherit the contents of pg_hba.conf |
193 | * etcetera from the postmaster, and have to load them ourselves. |
194 | * |
195 | * FIXME: [fork/exec] Ugh. Is there a way around this overhead? |
196 | */ |
197 | #ifdef EXEC_BACKEND |
198 | |
199 | /* |
200 | * load_hba() and load_ident() want to work within the PostmasterContext, |
201 | * so create that if it doesn't exist (which it won't). We'll delete it |
202 | * again later, in PostgresMain. |
203 | */ |
204 | if (PostmasterContext == NULL) |
205 | PostmasterContext = AllocSetContextCreate(TopMemoryContext, |
206 | "Postmaster" , |
207 | ALLOCSET_DEFAULT_SIZES); |
208 | |
209 | if (!load_hba()) |
210 | { |
211 | /* |
212 | * It makes no sense to continue if we fail to load the HBA file, |
213 | * since there is no way to connect to the database in this case. |
214 | */ |
215 | ereport(FATAL, |
216 | (errmsg("could not load pg_hba.conf" ))); |
217 | } |
218 | |
219 | if (!load_ident()) |
220 | { |
221 | /* |
222 | * It is ok to continue if we fail to load the IDENT file, although it |
223 | * means that you cannot log in using any of the authentication |
224 | * methods that need a user name mapping. load_ident() already logged |
225 | * the details of error to the log. |
226 | */ |
227 | } |
228 | #endif |
229 | |
230 | /* |
231 | * Set up a timeout in case a buggy or malicious client fails to respond |
232 | * during authentication. Since we're inside a transaction and might do |
233 | * database access, we have to use the statement_timeout infrastructure. |
234 | */ |
235 | enable_timeout_after(STATEMENT_TIMEOUT, AuthenticationTimeout * 1000); |
236 | |
237 | /* |
238 | * Now perform authentication exchange. |
239 | */ |
240 | ClientAuthentication(port); /* might not return, if failure */ |
241 | |
242 | /* |
243 | * Done with authentication. Disable the timeout, and log if needed. |
244 | */ |
245 | disable_timeout(STATEMENT_TIMEOUT, false); |
246 | |
247 | if (Log_connections) |
248 | { |
249 | if (am_walsender) |
250 | { |
251 | #ifdef USE_SSL |
252 | if (port->ssl_in_use) |
253 | ereport(LOG, |
254 | (port->application_name != NULL |
255 | ? errmsg("replication connection authorized: user=%s application_name=%s SSL enabled (protocol=%s, cipher=%s, bits=%d, compression=%s)" , |
256 | port->user_name, |
257 | port->application_name, |
258 | be_tls_get_version(port), |
259 | be_tls_get_cipher(port), |
260 | be_tls_get_cipher_bits(port), |
261 | be_tls_get_compression(port) ? _("on" ) : _("off" )) |
262 | : errmsg("replication connection authorized: user=%s SSL enabled (protocol=%s, cipher=%s, bits=%d, compression=%s)" , |
263 | port->user_name, |
264 | be_tls_get_version(port), |
265 | be_tls_get_cipher(port), |
266 | be_tls_get_cipher_bits(port), |
267 | be_tls_get_compression(port) ? _("on" ) : _("off" )))); |
268 | else |
269 | #endif |
270 | ereport(LOG, |
271 | (port->application_name != NULL |
272 | ? errmsg("replication connection authorized: user=%s application_name=%s" , |
273 | port->user_name, |
274 | port->application_name) |
275 | : errmsg("replication connection authorized: user=%s" , |
276 | port->user_name))); |
277 | } |
278 | else |
279 | { |
280 | #ifdef USE_SSL |
281 | if (port->ssl_in_use) |
282 | ereport(LOG, |
283 | (port->application_name != NULL |
284 | ? errmsg("connection authorized: user=%s database=%s application_name=%s SSL enabled (protocol=%s, cipher=%s, bits=%d, compression=%s)" , |
285 | port->user_name, port->database_name, port->application_name, |
286 | be_tls_get_version(port), |
287 | be_tls_get_cipher(port), |
288 | be_tls_get_cipher_bits(port), |
289 | be_tls_get_compression(port) ? _("on" ) : _("off" )) |
290 | : errmsg("connection authorized: user=%s database=%s SSL enabled (protocol=%s, cipher=%s, bits=%d, compression=%s)" , |
291 | port->user_name, port->database_name, |
292 | be_tls_get_version(port), |
293 | be_tls_get_cipher(port), |
294 | be_tls_get_cipher_bits(port), |
295 | be_tls_get_compression(port) ? _("on" ) : _("off" )))); |
296 | else |
297 | #endif |
298 | ereport(LOG, |
299 | (port->application_name != NULL |
300 | ? errmsg("connection authorized: user=%s database=%s application_name=%s" , |
301 | port->user_name, port->database_name, port->application_name) |
302 | : errmsg("connection authorized: user=%s database=%s" , |
303 | port->user_name, port->database_name))); |
304 | } |
305 | } |
306 | |
307 | set_ps_display("startup" , false); |
308 | |
309 | ClientAuthInProgress = false; /* client_min_messages is active now */ |
310 | } |
311 | |
312 | |
313 | /* |
314 | * CheckMyDatabase -- fetch information from the pg_database entry for our DB |
315 | */ |
316 | static void |
317 | CheckMyDatabase(const char *name, bool am_superuser, bool override_allow_connections) |
318 | { |
319 | HeapTuple tup; |
320 | Form_pg_database dbform; |
321 | char *collate; |
322 | char *ctype; |
323 | |
324 | /* Fetch our pg_database row normally, via syscache */ |
325 | tup = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId)); |
326 | if (!HeapTupleIsValid(tup)) |
327 | elog(ERROR, "cache lookup failed for database %u" , MyDatabaseId); |
328 | dbform = (Form_pg_database) GETSTRUCT(tup); |
329 | |
330 | /* This recheck is strictly paranoia */ |
331 | if (strcmp(name, NameStr(dbform->datname)) != 0) |
332 | ereport(FATAL, |
333 | (errcode(ERRCODE_UNDEFINED_DATABASE), |
334 | errmsg("database \"%s\" has disappeared from pg_database" , |
335 | name), |
336 | errdetail("Database OID %u now seems to belong to \"%s\"." , |
337 | MyDatabaseId, NameStr(dbform->datname)))); |
338 | |
339 | /* |
340 | * Check permissions to connect to the database. |
341 | * |
342 | * These checks are not enforced when in standalone mode, so that there is |
343 | * a way to recover from disabling all access to all databases, for |
344 | * example "UPDATE pg_database SET datallowconn = false;". |
345 | * |
346 | * We do not enforce them for autovacuum worker processes either. |
347 | */ |
348 | if (IsUnderPostmaster && !IsAutoVacuumWorkerProcess()) |
349 | { |
350 | /* |
351 | * Check that the database is currently allowing connections. |
352 | */ |
353 | if (!dbform->datallowconn && !override_allow_connections) |
354 | ereport(FATAL, |
355 | (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), |
356 | errmsg("database \"%s\" is not currently accepting connections" , |
357 | name))); |
358 | |
359 | /* |
360 | * Check privilege to connect to the database. (The am_superuser test |
361 | * is redundant, but since we have the flag, might as well check it |
362 | * and save a few cycles.) |
363 | */ |
364 | if (!am_superuser && |
365 | pg_database_aclcheck(MyDatabaseId, GetUserId(), |
366 | ACL_CONNECT) != ACLCHECK_OK) |
367 | ereport(FATAL, |
368 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
369 | errmsg("permission denied for database \"%s\"" , name), |
370 | errdetail("User does not have CONNECT privilege." ))); |
371 | |
372 | /* |
373 | * Check connection limit for this database. |
374 | * |
375 | * There is a race condition here --- we create our PGPROC before |
376 | * checking for other PGPROCs. If two backends did this at about the |
377 | * same time, they might both think they were over the limit, while |
378 | * ideally one should succeed and one fail. Getting that to work |
379 | * exactly seems more trouble than it is worth, however; instead we |
380 | * just document that the connection limit is approximate. |
381 | */ |
382 | if (dbform->datconnlimit >= 0 && |
383 | !am_superuser && |
384 | CountDBConnections(MyDatabaseId) > dbform->datconnlimit) |
385 | ereport(FATAL, |
386 | (errcode(ERRCODE_TOO_MANY_CONNECTIONS), |
387 | errmsg("too many connections for database \"%s\"" , |
388 | name))); |
389 | } |
390 | |
391 | /* |
392 | * OK, we're golden. Next to-do item is to save the encoding info out of |
393 | * the pg_database tuple. |
394 | */ |
395 | SetDatabaseEncoding(dbform->encoding); |
396 | /* Record it as a GUC internal option, too */ |
397 | SetConfigOption("server_encoding" , GetDatabaseEncodingName(), |
398 | PGC_INTERNAL, PGC_S_OVERRIDE); |
399 | /* If we have no other source of client_encoding, use server encoding */ |
400 | SetConfigOption("client_encoding" , GetDatabaseEncodingName(), |
401 | PGC_BACKEND, PGC_S_DYNAMIC_DEFAULT); |
402 | |
403 | /* assign locale variables */ |
404 | collate = NameStr(dbform->datcollate); |
405 | ctype = NameStr(dbform->datctype); |
406 | |
407 | if (pg_perm_setlocale(LC_COLLATE, collate) == NULL) |
408 | ereport(FATAL, |
409 | (errmsg("database locale is incompatible with operating system" ), |
410 | errdetail("The database was initialized with LC_COLLATE \"%s\", " |
411 | " which is not recognized by setlocale()." , collate), |
412 | errhint("Recreate the database with another locale or install the missing locale." ))); |
413 | |
414 | if (pg_perm_setlocale(LC_CTYPE, ctype) == NULL) |
415 | ereport(FATAL, |
416 | (errmsg("database locale is incompatible with operating system" ), |
417 | errdetail("The database was initialized with LC_CTYPE \"%s\", " |
418 | " which is not recognized by setlocale()." , ctype), |
419 | errhint("Recreate the database with another locale or install the missing locale." ))); |
420 | |
421 | /* Make the locale settings visible as GUC variables, too */ |
422 | SetConfigOption("lc_collate" , collate, PGC_INTERNAL, PGC_S_OVERRIDE); |
423 | SetConfigOption("lc_ctype" , ctype, PGC_INTERNAL, PGC_S_OVERRIDE); |
424 | |
425 | check_strxfrm_bug(); |
426 | |
427 | ReleaseSysCache(tup); |
428 | } |
429 | |
430 | |
431 | |
432 | /* -------------------------------- |
433 | * InitCommunication |
434 | * |
435 | * This routine initializes stuff needed for ipc, locking, etc. |
436 | * it should be called something more informative. |
437 | * -------------------------------- |
438 | */ |
439 | static void |
440 | InitCommunication(void) |
441 | { |
442 | /* |
443 | * initialize shared memory and semaphores appropriately. |
444 | */ |
445 | if (!IsUnderPostmaster) /* postmaster already did this */ |
446 | { |
447 | /* |
448 | * We're running a postgres bootstrap process or a standalone backend. |
449 | * Though we won't listen on PostPortNumber, use it to select a shmem |
450 | * key. This increases the chance of detecting a leftover live |
451 | * backend of this DataDir. |
452 | */ |
453 | CreateSharedMemoryAndSemaphores(PostPortNumber); |
454 | } |
455 | } |
456 | |
457 | |
458 | /* |
459 | * pg_split_opts -- split a string of options and append it to an argv array |
460 | * |
461 | * The caller is responsible for ensuring the argv array is large enough. The |
462 | * maximum possible number of arguments added by this routine is |
463 | * (strlen(optstr) + 1) / 2. |
464 | * |
465 | * Because some option values can contain spaces we allow escaping using |
466 | * backslashes, with \\ representing a literal backslash. |
467 | */ |
468 | void |
469 | pg_split_opts(char **argv, int *argcp, const char *optstr) |
470 | { |
471 | StringInfoData s; |
472 | |
473 | initStringInfo(&s); |
474 | |
475 | while (*optstr) |
476 | { |
477 | bool last_was_escape = false; |
478 | |
479 | resetStringInfo(&s); |
480 | |
481 | /* skip over leading space */ |
482 | while (isspace((unsigned char) *optstr)) |
483 | optstr++; |
484 | |
485 | if (*optstr == '\0') |
486 | break; |
487 | |
488 | /* |
489 | * Parse a single option, stopping at the first space, unless it's |
490 | * escaped. |
491 | */ |
492 | while (*optstr) |
493 | { |
494 | if (isspace((unsigned char) *optstr) && !last_was_escape) |
495 | break; |
496 | |
497 | if (!last_was_escape && *optstr == '\\') |
498 | last_was_escape = true; |
499 | else |
500 | { |
501 | last_was_escape = false; |
502 | appendStringInfoChar(&s, *optstr); |
503 | } |
504 | |
505 | optstr++; |
506 | } |
507 | |
508 | /* now store the option in the next argv[] position */ |
509 | argv[(*argcp)++] = pstrdup(s.data); |
510 | } |
511 | |
512 | pfree(s.data); |
513 | } |
514 | |
515 | /* |
516 | * Initialize MaxBackends value from config options. |
517 | * |
518 | * This must be called after modules have had the chance to register background |
519 | * workers in shared_preload_libraries, and before shared memory size is |
520 | * determined. |
521 | * |
522 | * Note that in EXEC_BACKEND environment, the value is passed down from |
523 | * postmaster to subprocesses via BackendParameters in SubPostmasterMain; only |
524 | * postmaster itself and processes not under postmaster control should call |
525 | * this. |
526 | */ |
527 | void |
528 | InitializeMaxBackends(void) |
529 | { |
530 | Assert(MaxBackends == 0); |
531 | |
532 | /* the extra unit accounts for the autovacuum launcher */ |
533 | MaxBackends = MaxConnections + autovacuum_max_workers + 1 + |
534 | max_worker_processes + max_wal_senders; |
535 | |
536 | /* internal error because the values were all checked previously */ |
537 | if (MaxBackends > MAX_BACKENDS) |
538 | elog(ERROR, "too many backends configured" ); |
539 | } |
540 | |
541 | /* |
542 | * Early initialization of a backend (either standalone or under postmaster). |
543 | * This happens even before InitPostgres. |
544 | * |
545 | * This is separate from InitPostgres because it is also called by auxiliary |
546 | * processes, such as the background writer process, which may not call |
547 | * InitPostgres at all. |
548 | */ |
549 | void |
550 | BaseInit(void) |
551 | { |
552 | /* |
553 | * Attach to shared memory and semaphores, and initialize our |
554 | * input/output/debugging file descriptors. |
555 | */ |
556 | InitCommunication(); |
557 | DebugFileOpen(); |
558 | |
559 | /* Do local initialization of file, storage and buffer managers */ |
560 | InitFileAccess(); |
561 | InitSync(); |
562 | smgrinit(); |
563 | InitBufferPoolAccess(); |
564 | } |
565 | |
566 | |
567 | /* -------------------------------- |
568 | * InitPostgres |
569 | * Initialize POSTGRES. |
570 | * |
571 | * The database can be specified by name, using the in_dbname parameter, or by |
572 | * OID, using the dboid parameter. In the latter case, the actual database |
573 | * name can be returned to the caller in out_dbname. If out_dbname isn't |
574 | * NULL, it must point to a buffer of size NAMEDATALEN. |
575 | * |
576 | * Similarly, the username can be passed by name, using the username parameter, |
577 | * or by OID using the useroid parameter. |
578 | * |
579 | * In bootstrap mode no parameters are used. The autovacuum launcher process |
580 | * doesn't use any parameters either, because it only goes far enough to be |
581 | * able to read pg_database; it doesn't connect to any particular database. |
582 | * In walsender mode only username is used. |
583 | * |
584 | * As of PostgreSQL 8.2, we expect InitProcess() was already called, so we |
585 | * already have a PGPROC struct ... but it's not completely filled in yet. |
586 | * |
587 | * Note: |
588 | * Be very careful with the order of calls in the InitPostgres function. |
589 | * -------------------------------- |
590 | */ |
591 | void |
592 | InitPostgres(const char *in_dbname, Oid dboid, const char *username, |
593 | Oid useroid, char *out_dbname, bool override_allow_connections) |
594 | { |
595 | bool bootstrap = IsBootstrapProcessingMode(); |
596 | bool am_superuser; |
597 | char *fullpath; |
598 | char dbname[NAMEDATALEN]; |
599 | |
600 | elog(DEBUG3, "InitPostgres" ); |
601 | |
602 | /* |
603 | * Add my PGPROC struct to the ProcArray. |
604 | * |
605 | * Once I have done this, I am visible to other backends! |
606 | */ |
607 | InitProcessPhase2(); |
608 | |
609 | /* |
610 | * Initialize my entry in the shared-invalidation manager's array of |
611 | * per-backend data. |
612 | * |
613 | * Sets up MyBackendId, a unique backend identifier. |
614 | */ |
615 | MyBackendId = InvalidBackendId; |
616 | |
617 | SharedInvalBackendInit(false); |
618 | |
619 | if (MyBackendId > MaxBackends || MyBackendId <= 0) |
620 | elog(FATAL, "bad backend ID: %d" , MyBackendId); |
621 | |
622 | /* Now that we have a BackendId, we can participate in ProcSignal */ |
623 | ProcSignalInit(MyBackendId); |
624 | |
625 | /* |
626 | * Also set up timeout handlers needed for backend operation. We need |
627 | * these in every case except bootstrap. |
628 | */ |
629 | if (!bootstrap) |
630 | { |
631 | RegisterTimeout(DEADLOCK_TIMEOUT, CheckDeadLockAlert); |
632 | RegisterTimeout(STATEMENT_TIMEOUT, StatementTimeoutHandler); |
633 | RegisterTimeout(LOCK_TIMEOUT, LockTimeoutHandler); |
634 | RegisterTimeout(IDLE_IN_TRANSACTION_SESSION_TIMEOUT, |
635 | IdleInTransactionSessionTimeoutHandler); |
636 | } |
637 | |
638 | /* |
639 | * bufmgr needs another initialization call too |
640 | */ |
641 | InitBufferPoolBackend(); |
642 | |
643 | /* |
644 | * Initialize local process's access to XLOG. |
645 | */ |
646 | if (IsUnderPostmaster) |
647 | { |
648 | /* |
649 | * The postmaster already started the XLOG machinery, but we need to |
650 | * call InitXLOGAccess(), if the system isn't in hot-standby mode. |
651 | * This is handled by calling RecoveryInProgress and ignoring the |
652 | * result. |
653 | */ |
654 | (void) RecoveryInProgress(); |
655 | } |
656 | else |
657 | { |
658 | /* |
659 | * We are either a bootstrap process or a standalone backend. Either |
660 | * way, start up the XLOG machinery, and register to have it closed |
661 | * down at exit. |
662 | * |
663 | * We don't yet have an aux-process resource owner, but StartupXLOG |
664 | * and ShutdownXLOG will need one. Hence, create said resource owner |
665 | * (and register a callback to clean it up after ShutdownXLOG runs). |
666 | */ |
667 | CreateAuxProcessResourceOwner(); |
668 | |
669 | StartupXLOG(); |
670 | /* Release (and warn about) any buffer pins leaked in StartupXLOG */ |
671 | ReleaseAuxProcessResources(true); |
672 | /* Reset CurrentResourceOwner to nothing for the moment */ |
673 | CurrentResourceOwner = NULL; |
674 | |
675 | on_shmem_exit(ShutdownXLOG, 0); |
676 | } |
677 | |
678 | /* |
679 | * Initialize the relation cache and the system catalog caches. Note that |
680 | * no catalog access happens here; we only set up the hashtable structure. |
681 | * We must do this before starting a transaction because transaction abort |
682 | * would try to touch these hashtables. |
683 | */ |
684 | RelationCacheInitialize(); |
685 | InitCatalogCache(); |
686 | InitPlanCache(); |
687 | |
688 | /* Initialize portal manager */ |
689 | EnablePortalManager(); |
690 | |
691 | /* Initialize stats collection --- must happen before first xact */ |
692 | if (!bootstrap) |
693 | pgstat_initialize(); |
694 | |
695 | /* |
696 | * Load relcache entries for the shared system catalogs. This must create |
697 | * at least entries for pg_database and catalogs used for authentication. |
698 | */ |
699 | RelationCacheInitializePhase2(); |
700 | |
701 | /* |
702 | * Set up process-exit callback to do pre-shutdown cleanup. This is the |
703 | * first before_shmem_exit callback we register; thus, this will be the |
704 | * last thing we do before low-level modules like the buffer manager begin |
705 | * to close down. We need to have this in place before we begin our first |
706 | * transaction --- if we fail during the initialization transaction, as is |
707 | * entirely possible, we need the AbortTransaction call to clean up. |
708 | */ |
709 | before_shmem_exit(ShutdownPostgres, 0); |
710 | |
711 | /* The autovacuum launcher is done here */ |
712 | if (IsAutoVacuumLauncherProcess()) |
713 | { |
714 | /* report this backend in the PgBackendStatus array */ |
715 | pgstat_bestart(); |
716 | |
717 | return; |
718 | } |
719 | |
720 | /* |
721 | * Start a new transaction here before first access to db, and get a |
722 | * snapshot. We don't have a use for the snapshot itself, but we're |
723 | * interested in the secondary effect that it sets RecentGlobalXmin. (This |
724 | * is critical for anything that reads heap pages, because HOT may decide |
725 | * to prune them even if the process doesn't attempt to modify any |
726 | * tuples.) |
727 | */ |
728 | if (!bootstrap) |
729 | { |
730 | /* statement_timestamp must be set for timeouts to work correctly */ |
731 | SetCurrentStatementStartTimestamp(); |
732 | StartTransactionCommand(); |
733 | |
734 | /* |
735 | * transaction_isolation will have been set to the default by the |
736 | * above. If the default is "serializable", and we are in hot |
737 | * standby, we will fail if we don't change it to something lower. |
738 | * Fortunately, "read committed" is plenty good enough. |
739 | */ |
740 | XactIsoLevel = XACT_READ_COMMITTED; |
741 | |
742 | (void) GetTransactionSnapshot(); |
743 | } |
744 | |
745 | /* |
746 | * Perform client authentication if necessary, then figure out our |
747 | * postgres user ID, and see if we are a superuser. |
748 | * |
749 | * In standalone mode and in autovacuum worker processes, we use a fixed |
750 | * ID, otherwise we figure it out from the authenticated user name. |
751 | */ |
752 | if (bootstrap || IsAutoVacuumWorkerProcess()) |
753 | { |
754 | InitializeSessionUserIdStandalone(); |
755 | am_superuser = true; |
756 | } |
757 | else if (!IsUnderPostmaster) |
758 | { |
759 | InitializeSessionUserIdStandalone(); |
760 | am_superuser = true; |
761 | if (!ThereIsAtLeastOneRole()) |
762 | ereport(WARNING, |
763 | (errcode(ERRCODE_UNDEFINED_OBJECT), |
764 | errmsg("no roles are defined in this database system" ), |
765 | errhint("You should immediately run CREATE USER \"%s\" SUPERUSER;." , |
766 | username != NULL ? username : "postgres" ))); |
767 | } |
768 | else if (IsBackgroundWorker) |
769 | { |
770 | if (username == NULL && !OidIsValid(useroid)) |
771 | { |
772 | InitializeSessionUserIdStandalone(); |
773 | am_superuser = true; |
774 | } |
775 | else |
776 | { |
777 | InitializeSessionUserId(username, useroid); |
778 | am_superuser = superuser(); |
779 | } |
780 | } |
781 | else |
782 | { |
783 | /* normal multiuser case */ |
784 | Assert(MyProcPort != NULL); |
785 | PerformAuthentication(MyProcPort); |
786 | InitializeSessionUserId(username, useroid); |
787 | am_superuser = superuser(); |
788 | } |
789 | |
790 | /* |
791 | * If we're trying to shut down, only superusers can connect, and new |
792 | * replication connections are not allowed. |
793 | */ |
794 | if ((!am_superuser || am_walsender) && |
795 | MyProcPort != NULL && |
796 | MyProcPort->canAcceptConnections == CAC_WAITBACKUP) |
797 | { |
798 | if (am_walsender) |
799 | ereport(FATAL, |
800 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
801 | errmsg("new replication connections are not allowed during database shutdown" ))); |
802 | else |
803 | ereport(FATAL, |
804 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
805 | errmsg("must be superuser to connect during database shutdown" ))); |
806 | } |
807 | |
808 | /* |
809 | * Binary upgrades only allowed super-user connections |
810 | */ |
811 | if (IsBinaryUpgrade && !am_superuser) |
812 | { |
813 | ereport(FATAL, |
814 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
815 | errmsg("must be superuser to connect in binary upgrade mode" ))); |
816 | } |
817 | |
818 | /* |
819 | * The last few connection slots are reserved for superusers. Replication |
820 | * connections are drawn from slots reserved with max_wal_senders and not |
821 | * limited by max_connections or superuser_reserved_connections. |
822 | */ |
823 | if (!am_superuser && !am_walsender && |
824 | ReservedBackends > 0 && |
825 | !HaveNFreeProcs(ReservedBackends)) |
826 | ereport(FATAL, |
827 | (errcode(ERRCODE_TOO_MANY_CONNECTIONS), |
828 | errmsg("remaining connection slots are reserved for non-replication superuser connections" ))); |
829 | |
830 | /* Check replication permissions needed for walsender processes. */ |
831 | if (am_walsender) |
832 | { |
833 | Assert(!bootstrap); |
834 | |
835 | if (!superuser() && !has_rolreplication(GetUserId())) |
836 | ereport(FATAL, |
837 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
838 | errmsg("must be superuser or replication role to start walsender" ))); |
839 | } |
840 | |
841 | /* |
842 | * If this is a plain walsender only supporting physical replication, we |
843 | * don't want to connect to any particular database. Just finish the |
844 | * backend startup by processing any options from the startup packet, and |
845 | * we're done. |
846 | */ |
847 | if (am_walsender && !am_db_walsender) |
848 | { |
849 | /* process any options passed in the startup packet */ |
850 | if (MyProcPort != NULL) |
851 | process_startup_options(MyProcPort, am_superuser); |
852 | |
853 | /* Apply PostAuthDelay as soon as we've read all options */ |
854 | if (PostAuthDelay > 0) |
855 | pg_usleep(PostAuthDelay * 1000000L); |
856 | |
857 | /* initialize client encoding */ |
858 | InitializeClientEncoding(); |
859 | |
860 | /* report this backend in the PgBackendStatus array */ |
861 | pgstat_bestart(); |
862 | |
863 | /* close the transaction we started above */ |
864 | CommitTransactionCommand(); |
865 | |
866 | return; |
867 | } |
868 | |
869 | /* |
870 | * Set up the global variables holding database id and default tablespace. |
871 | * But note we won't actually try to touch the database just yet. |
872 | * |
873 | * We take a shortcut in the bootstrap case, otherwise we have to look up |
874 | * the db's entry in pg_database. |
875 | */ |
876 | if (bootstrap) |
877 | { |
878 | MyDatabaseId = TemplateDbOid; |
879 | MyDatabaseTableSpace = DEFAULTTABLESPACE_OID; |
880 | } |
881 | else if (in_dbname != NULL) |
882 | { |
883 | HeapTuple tuple; |
884 | Form_pg_database dbform; |
885 | |
886 | tuple = GetDatabaseTuple(in_dbname); |
887 | if (!HeapTupleIsValid(tuple)) |
888 | ereport(FATAL, |
889 | (errcode(ERRCODE_UNDEFINED_DATABASE), |
890 | errmsg("database \"%s\" does not exist" , in_dbname))); |
891 | dbform = (Form_pg_database) GETSTRUCT(tuple); |
892 | MyDatabaseId = dbform->oid; |
893 | MyDatabaseTableSpace = dbform->dattablespace; |
894 | /* take database name from the caller, just for paranoia */ |
895 | strlcpy(dbname, in_dbname, sizeof(dbname)); |
896 | } |
897 | else if (OidIsValid(dboid)) |
898 | { |
899 | /* caller specified database by OID */ |
900 | HeapTuple tuple; |
901 | Form_pg_database dbform; |
902 | |
903 | tuple = GetDatabaseTupleByOid(dboid); |
904 | if (!HeapTupleIsValid(tuple)) |
905 | ereport(FATAL, |
906 | (errcode(ERRCODE_UNDEFINED_DATABASE), |
907 | errmsg("database %u does not exist" , dboid))); |
908 | dbform = (Form_pg_database) GETSTRUCT(tuple); |
909 | MyDatabaseId = dbform->oid; |
910 | MyDatabaseTableSpace = dbform->dattablespace; |
911 | Assert(MyDatabaseId == dboid); |
912 | strlcpy(dbname, NameStr(dbform->datname), sizeof(dbname)); |
913 | /* pass the database name back to the caller */ |
914 | if (out_dbname) |
915 | strcpy(out_dbname, dbname); |
916 | } |
917 | else |
918 | { |
919 | /* |
920 | * If this is a background worker not bound to any particular |
921 | * database, we're done now. Everything that follows only makes sense |
922 | * if we are bound to a specific database. We do need to close the |
923 | * transaction we started before returning. |
924 | */ |
925 | if (!bootstrap) |
926 | { |
927 | pgstat_bestart(); |
928 | CommitTransactionCommand(); |
929 | } |
930 | return; |
931 | } |
932 | |
933 | /* |
934 | * Now, take a writer's lock on the database we are trying to connect to. |
935 | * If there is a concurrently running DROP DATABASE on that database, this |
936 | * will block us until it finishes (and has committed its update of |
937 | * pg_database). |
938 | * |
939 | * Note that the lock is not held long, only until the end of this startup |
940 | * transaction. This is OK since we will advertise our use of the |
941 | * database in the ProcArray before dropping the lock (in fact, that's the |
942 | * next thing to do). Anyone trying a DROP DATABASE after this point will |
943 | * see us in the array once they have the lock. Ordering is important for |
944 | * this because we don't want to advertise ourselves as being in this |
945 | * database until we have the lock; otherwise we create what amounts to a |
946 | * deadlock with CountOtherDBBackends(). |
947 | * |
948 | * Note: use of RowExclusiveLock here is reasonable because we envision |
949 | * our session as being a concurrent writer of the database. If we had a |
950 | * way of declaring a session as being guaranteed-read-only, we could use |
951 | * AccessShareLock for such sessions and thereby not conflict against |
952 | * CREATE DATABASE. |
953 | */ |
954 | if (!bootstrap) |
955 | LockSharedObject(DatabaseRelationId, MyDatabaseId, 0, |
956 | RowExclusiveLock); |
957 | |
958 | /* |
959 | * Now we can mark our PGPROC entry with the database ID. |
960 | * |
961 | * We assume this is an atomic store so no lock is needed; though actually |
962 | * things would work fine even if it weren't atomic. Anyone searching the |
963 | * ProcArray for this database's ID should hold the database lock, so they |
964 | * would not be executing concurrently with this store. A process looking |
965 | * for another database's ID could in theory see a chance match if it read |
966 | * a partially-updated databaseId value; but as long as all such searches |
967 | * wait and retry, as in CountOtherDBBackends(), they will certainly see |
968 | * the correct value on their next try. |
969 | */ |
970 | MyProc->databaseId = MyDatabaseId; |
971 | |
972 | /* |
973 | * We established a catalog snapshot while reading pg_authid and/or |
974 | * pg_database; but until we have set up MyDatabaseId, we won't react to |
975 | * incoming sinval messages for unshared catalogs, so we won't realize it |
976 | * if the snapshot has been invalidated. Assume it's no good anymore. |
977 | */ |
978 | InvalidateCatalogSnapshot(); |
979 | |
980 | /* |
981 | * Recheck pg_database to make sure the target database hasn't gone away. |
982 | * If there was a concurrent DROP DATABASE, this ensures we will die |
983 | * cleanly without creating a mess. |
984 | */ |
985 | if (!bootstrap) |
986 | { |
987 | HeapTuple tuple; |
988 | |
989 | tuple = GetDatabaseTuple(dbname); |
990 | if (!HeapTupleIsValid(tuple) || |
991 | MyDatabaseId != ((Form_pg_database) GETSTRUCT(tuple))->oid || |
992 | MyDatabaseTableSpace != ((Form_pg_database) GETSTRUCT(tuple))->dattablespace) |
993 | ereport(FATAL, |
994 | (errcode(ERRCODE_UNDEFINED_DATABASE), |
995 | errmsg("database \"%s\" does not exist" , dbname), |
996 | errdetail("It seems to have just been dropped or renamed." ))); |
997 | } |
998 | |
999 | /* |
1000 | * Now we should be able to access the database directory safely. Verify |
1001 | * it's there and looks reasonable. |
1002 | */ |
1003 | fullpath = GetDatabasePath(MyDatabaseId, MyDatabaseTableSpace); |
1004 | |
1005 | if (!bootstrap) |
1006 | { |
1007 | if (access(fullpath, F_OK) == -1) |
1008 | { |
1009 | if (errno == ENOENT) |
1010 | ereport(FATAL, |
1011 | (errcode(ERRCODE_UNDEFINED_DATABASE), |
1012 | errmsg("database \"%s\" does not exist" , |
1013 | dbname), |
1014 | errdetail("The database subdirectory \"%s\" is missing." , |
1015 | fullpath))); |
1016 | else |
1017 | ereport(FATAL, |
1018 | (errcode_for_file_access(), |
1019 | errmsg("could not access directory \"%s\": %m" , |
1020 | fullpath))); |
1021 | } |
1022 | |
1023 | ValidatePgVersion(fullpath); |
1024 | } |
1025 | |
1026 | SetDatabasePath(fullpath); |
1027 | |
1028 | /* |
1029 | * It's now possible to do real access to the system catalogs. |
1030 | * |
1031 | * Load relcache entries for the system catalogs. This must create at |
1032 | * least the minimum set of "nailed-in" cache entries. |
1033 | */ |
1034 | RelationCacheInitializePhase3(); |
1035 | |
1036 | /* set up ACL framework (so CheckMyDatabase can check permissions) */ |
1037 | initialize_acl(); |
1038 | |
1039 | /* |
1040 | * Re-read the pg_database row for our database, check permissions and set |
1041 | * up database-specific GUC settings. We can't do this until all the |
1042 | * database-access infrastructure is up. (Also, it wants to know if the |
1043 | * user is a superuser, so the above stuff has to happen first.) |
1044 | */ |
1045 | if (!bootstrap) |
1046 | CheckMyDatabase(dbname, am_superuser, override_allow_connections); |
1047 | |
1048 | /* |
1049 | * Now process any command-line switches and any additional GUC variable |
1050 | * settings passed in the startup packet. We couldn't do this before |
1051 | * because we didn't know if client is a superuser. |
1052 | */ |
1053 | if (MyProcPort != NULL) |
1054 | process_startup_options(MyProcPort, am_superuser); |
1055 | |
1056 | /* Process pg_db_role_setting options */ |
1057 | process_settings(MyDatabaseId, GetSessionUserId()); |
1058 | |
1059 | /* Apply PostAuthDelay as soon as we've read all options */ |
1060 | if (PostAuthDelay > 0) |
1061 | pg_usleep(PostAuthDelay * 1000000L); |
1062 | |
1063 | /* |
1064 | * Initialize various default states that can't be set up until we've |
1065 | * selected the active user and gotten the right GUC settings. |
1066 | */ |
1067 | |
1068 | /* set default namespace search path */ |
1069 | InitializeSearchPath(); |
1070 | |
1071 | /* initialize client encoding */ |
1072 | InitializeClientEncoding(); |
1073 | |
1074 | /* Initialize this backend's session state. */ |
1075 | InitializeSession(); |
1076 | |
1077 | /* report this backend in the PgBackendStatus array */ |
1078 | if (!bootstrap) |
1079 | pgstat_bestart(); |
1080 | |
1081 | /* close the transaction we started above */ |
1082 | if (!bootstrap) |
1083 | CommitTransactionCommand(); |
1084 | } |
1085 | |
1086 | /* |
1087 | * Process any command-line switches and any additional GUC variable |
1088 | * settings passed in the startup packet. |
1089 | */ |
1090 | static void |
1091 | process_startup_options(Port *port, bool am_superuser) |
1092 | { |
1093 | GucContext gucctx; |
1094 | ListCell *gucopts; |
1095 | |
1096 | gucctx = am_superuser ? PGC_SU_BACKEND : PGC_BACKEND; |
1097 | |
1098 | /* |
1099 | * First process any command-line switches that were included in the |
1100 | * startup packet, if we are in a regular backend. |
1101 | */ |
1102 | if (port->cmdline_options != NULL) |
1103 | { |
1104 | /* |
1105 | * The maximum possible number of commandline arguments that could |
1106 | * come from port->cmdline_options is (strlen + 1) / 2; see |
1107 | * pg_split_opts(). |
1108 | */ |
1109 | char **av; |
1110 | int maxac; |
1111 | int ac; |
1112 | |
1113 | maxac = 2 + (strlen(port->cmdline_options) + 1) / 2; |
1114 | |
1115 | av = (char **) palloc(maxac * sizeof(char *)); |
1116 | ac = 0; |
1117 | |
1118 | av[ac++] = "postgres" ; |
1119 | |
1120 | pg_split_opts(av, &ac, port->cmdline_options); |
1121 | |
1122 | av[ac] = NULL; |
1123 | |
1124 | Assert(ac < maxac); |
1125 | |
1126 | (void) process_postgres_switches(ac, av, gucctx, NULL); |
1127 | } |
1128 | |
1129 | /* |
1130 | * Process any additional GUC variable settings passed in startup packet. |
1131 | * These are handled exactly like command-line variables. |
1132 | */ |
1133 | gucopts = list_head(port->guc_options); |
1134 | while (gucopts) |
1135 | { |
1136 | char *name; |
1137 | char *value; |
1138 | |
1139 | name = lfirst(gucopts); |
1140 | gucopts = lnext(gucopts); |
1141 | |
1142 | value = lfirst(gucopts); |
1143 | gucopts = lnext(gucopts); |
1144 | |
1145 | SetConfigOption(name, value, gucctx, PGC_S_CLIENT); |
1146 | } |
1147 | } |
1148 | |
1149 | /* |
1150 | * Load GUC settings from pg_db_role_setting. |
1151 | * |
1152 | * We try specific settings for the database/role combination, as well as |
1153 | * general for this database and for this user. |
1154 | */ |
1155 | static void |
1156 | process_settings(Oid databaseid, Oid roleid) |
1157 | { |
1158 | Relation relsetting; |
1159 | Snapshot snapshot; |
1160 | |
1161 | if (!IsUnderPostmaster) |
1162 | return; |
1163 | |
1164 | relsetting = table_open(DbRoleSettingRelationId, AccessShareLock); |
1165 | |
1166 | /* read all the settings under the same snapshot for efficiency */ |
1167 | snapshot = RegisterSnapshot(GetCatalogSnapshot(DbRoleSettingRelationId)); |
1168 | |
1169 | /* Later settings are ignored if set earlier. */ |
1170 | ApplySetting(snapshot, databaseid, roleid, relsetting, PGC_S_DATABASE_USER); |
1171 | ApplySetting(snapshot, InvalidOid, roleid, relsetting, PGC_S_USER); |
1172 | ApplySetting(snapshot, databaseid, InvalidOid, relsetting, PGC_S_DATABASE); |
1173 | ApplySetting(snapshot, InvalidOid, InvalidOid, relsetting, PGC_S_GLOBAL); |
1174 | |
1175 | UnregisterSnapshot(snapshot); |
1176 | table_close(relsetting, AccessShareLock); |
1177 | } |
1178 | |
1179 | /* |
1180 | * Backend-shutdown callback. Do cleanup that we want to be sure happens |
1181 | * before all the supporting modules begin to nail their doors shut via |
1182 | * their own callbacks. |
1183 | * |
1184 | * User-level cleanup, such as temp-relation removal and UNLISTEN, happens |
1185 | * via separate callbacks that execute before this one. We don't combine the |
1186 | * callbacks because we still want this one to happen if the user-level |
1187 | * cleanup fails. |
1188 | */ |
1189 | static void |
1190 | ShutdownPostgres(int code, Datum arg) |
1191 | { |
1192 | /* Make sure we've killed any active transaction */ |
1193 | AbortOutOfAnyTransaction(); |
1194 | |
1195 | /* |
1196 | * User locks are not released by transaction end, so be sure to release |
1197 | * them explicitly. |
1198 | */ |
1199 | LockReleaseAll(USER_LOCKMETHOD, true); |
1200 | } |
1201 | |
1202 | |
1203 | /* |
1204 | * STATEMENT_TIMEOUT handler: trigger a query-cancel interrupt. |
1205 | */ |
1206 | static void |
1207 | StatementTimeoutHandler(void) |
1208 | { |
1209 | int sig = SIGINT; |
1210 | |
1211 | /* |
1212 | * During authentication the timeout is used to deal with |
1213 | * authentication_timeout - we want to quit in response to such timeouts. |
1214 | */ |
1215 | if (ClientAuthInProgress) |
1216 | sig = SIGTERM; |
1217 | |
1218 | #ifdef HAVE_SETSID |
1219 | /* try to signal whole process group */ |
1220 | kill(-MyProcPid, sig); |
1221 | #endif |
1222 | kill(MyProcPid, sig); |
1223 | } |
1224 | |
1225 | /* |
1226 | * LOCK_TIMEOUT handler: trigger a query-cancel interrupt. |
1227 | */ |
1228 | static void |
1229 | LockTimeoutHandler(void) |
1230 | { |
1231 | #ifdef HAVE_SETSID |
1232 | /* try to signal whole process group */ |
1233 | kill(-MyProcPid, SIGINT); |
1234 | #endif |
1235 | kill(MyProcPid, SIGINT); |
1236 | } |
1237 | |
1238 | static void |
1239 | IdleInTransactionSessionTimeoutHandler(void) |
1240 | { |
1241 | IdleInTransactionSessionTimeoutPending = true; |
1242 | InterruptPending = true; |
1243 | SetLatch(MyLatch); |
1244 | } |
1245 | |
1246 | /* |
1247 | * Returns true if at least one role is defined in this database cluster. |
1248 | */ |
1249 | static bool |
1250 | ThereIsAtLeastOneRole(void) |
1251 | { |
1252 | Relation pg_authid_rel; |
1253 | TableScanDesc scan; |
1254 | bool result; |
1255 | |
1256 | pg_authid_rel = table_open(AuthIdRelationId, AccessShareLock); |
1257 | |
1258 | scan = table_beginscan_catalog(pg_authid_rel, 0, NULL); |
1259 | result = (heap_getnext(scan, ForwardScanDirection) != NULL); |
1260 | |
1261 | table_endscan(scan); |
1262 | table_close(pg_authid_rel, AccessShareLock); |
1263 | |
1264 | return result; |
1265 | } |
1266 | |