PageRenderTime 56ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/src/backend/commands/variable.c

https://github.com/bbt123/postgres
C | 917 lines | 592 code | 108 blank | 217 comment | 141 complexity | 4b0bb4efddcf83632de823bbabf71c43 MD5 | raw file
Possible License(s): AGPL-3.0
  1. /*-------------------------------------------------------------------------
  2. *
  3. * variable.c
  4. * Routines for handling specialized SET variables.
  5. *
  6. *
  7. * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
  8. * Portions Copyright (c) 1994, Regents of the University of California
  9. *
  10. *
  11. * IDENTIFICATION
  12. * src/backend/commands/variable.c
  13. *
  14. *-------------------------------------------------------------------------
  15. */
  16. #include "postgres.h"
  17. #include <ctype.h>
  18. #include "access/htup_details.h"
  19. #include "access/xact.h"
  20. #include "catalog/pg_authid.h"
  21. #include "commands/variable.h"
  22. #include "miscadmin.h"
  23. #include "utils/acl.h"
  24. #include "utils/builtins.h"
  25. #include "utils/syscache.h"
  26. #include "utils/snapmgr.h"
  27. #include "utils/timestamp.h"
  28. #include "mb/pg_wchar.h"
  29. /*
  30. * DATESTYLE
  31. */
  32. /*
  33. * check_datestyle: GUC check_hook for datestyle
  34. */
  35. bool
  36. check_datestyle(char **newval, void **extra, GucSource source)
  37. {
  38. int newDateStyle = DateStyle;
  39. int newDateOrder = DateOrder;
  40. bool have_style = false;
  41. bool have_order = false;
  42. bool ok = true;
  43. char *rawstring;
  44. int *myextra;
  45. char *result;
  46. List *elemlist;
  47. ListCell *l;
  48. /* Need a modifiable copy of string */
  49. rawstring = pstrdup(*newval);
  50. /* Parse string into list of identifiers */
  51. if (!SplitIdentifierString(rawstring, ',', &elemlist))
  52. {
  53. /* syntax error in list */
  54. GUC_check_errdetail("List syntax is invalid.");
  55. pfree(rawstring);
  56. list_free(elemlist);
  57. return false;
  58. }
  59. foreach(l, elemlist)
  60. {
  61. char *tok = (char *) lfirst(l);
  62. /* Ugh. Somebody ought to write a table driven version -- mjl */
  63. if (pg_strcasecmp(tok, "ISO") == 0)
  64. {
  65. if (have_style && newDateStyle != USE_ISO_DATES)
  66. ok = false; /* conflicting styles */
  67. newDateStyle = USE_ISO_DATES;
  68. have_style = true;
  69. }
  70. else if (pg_strcasecmp(tok, "SQL") == 0)
  71. {
  72. if (have_style && newDateStyle != USE_SQL_DATES)
  73. ok = false; /* conflicting styles */
  74. newDateStyle = USE_SQL_DATES;
  75. have_style = true;
  76. }
  77. else if (pg_strncasecmp(tok, "POSTGRES", 8) == 0)
  78. {
  79. if (have_style && newDateStyle != USE_POSTGRES_DATES)
  80. ok = false; /* conflicting styles */
  81. newDateStyle = USE_POSTGRES_DATES;
  82. have_style = true;
  83. }
  84. else if (pg_strcasecmp(tok, "GERMAN") == 0)
  85. {
  86. if (have_style && newDateStyle != USE_GERMAN_DATES)
  87. ok = false; /* conflicting styles */
  88. newDateStyle = USE_GERMAN_DATES;
  89. have_style = true;
  90. /* GERMAN also sets DMY, unless explicitly overridden */
  91. if (!have_order)
  92. newDateOrder = DATEORDER_DMY;
  93. }
  94. else if (pg_strcasecmp(tok, "YMD") == 0)
  95. {
  96. if (have_order && newDateOrder != DATEORDER_YMD)
  97. ok = false; /* conflicting orders */
  98. newDateOrder = DATEORDER_YMD;
  99. have_order = true;
  100. }
  101. else if (pg_strcasecmp(tok, "DMY") == 0 ||
  102. pg_strncasecmp(tok, "EURO", 4) == 0)
  103. {
  104. if (have_order && newDateOrder != DATEORDER_DMY)
  105. ok = false; /* conflicting orders */
  106. newDateOrder = DATEORDER_DMY;
  107. have_order = true;
  108. }
  109. else if (pg_strcasecmp(tok, "MDY") == 0 ||
  110. pg_strcasecmp(tok, "US") == 0 ||
  111. pg_strncasecmp(tok, "NONEURO", 7) == 0)
  112. {
  113. if (have_order && newDateOrder != DATEORDER_MDY)
  114. ok = false; /* conflicting orders */
  115. newDateOrder = DATEORDER_MDY;
  116. have_order = true;
  117. }
  118. else if (pg_strcasecmp(tok, "DEFAULT") == 0)
  119. {
  120. /*
  121. * Easiest way to get the current DEFAULT state is to fetch the
  122. * DEFAULT string from guc.c and recursively parse it.
  123. *
  124. * We can't simply "return check_datestyle(...)" because we need
  125. * to handle constructs like "DEFAULT, ISO".
  126. */
  127. char *subval;
  128. void *subextra = NULL;
  129. subval = strdup(GetConfigOptionResetString("datestyle"));
  130. if (!subval)
  131. {
  132. ok = false;
  133. break;
  134. }
  135. if (!check_datestyle(&subval, &subextra, source))
  136. {
  137. free(subval);
  138. ok = false;
  139. break;
  140. }
  141. myextra = (int *) subextra;
  142. if (!have_style)
  143. newDateStyle = myextra[0];
  144. if (!have_order)
  145. newDateOrder = myextra[1];
  146. free(subval);
  147. free(subextra);
  148. }
  149. else
  150. {
  151. GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
  152. pfree(rawstring);
  153. list_free(elemlist);
  154. return false;
  155. }
  156. }
  157. pfree(rawstring);
  158. list_free(elemlist);
  159. if (!ok)
  160. {
  161. GUC_check_errdetail("Conflicting \"datestyle\" specifications.");
  162. return false;
  163. }
  164. /*
  165. * Prepare the canonical string to return. GUC wants it malloc'd.
  166. */
  167. result = (char *) malloc(32);
  168. if (!result)
  169. return false;
  170. switch (newDateStyle)
  171. {
  172. case USE_ISO_DATES:
  173. strcpy(result, "ISO");
  174. break;
  175. case USE_SQL_DATES:
  176. strcpy(result, "SQL");
  177. break;
  178. case USE_GERMAN_DATES:
  179. strcpy(result, "German");
  180. break;
  181. default:
  182. strcpy(result, "Postgres");
  183. break;
  184. }
  185. switch (newDateOrder)
  186. {
  187. case DATEORDER_YMD:
  188. strcat(result, ", YMD");
  189. break;
  190. case DATEORDER_DMY:
  191. strcat(result, ", DMY");
  192. break;
  193. default:
  194. strcat(result, ", MDY");
  195. break;
  196. }
  197. free(*newval);
  198. *newval = result;
  199. /*
  200. * Set up the "extra" struct actually used by assign_datestyle.
  201. */
  202. myextra = (int *) malloc(2 * sizeof(int));
  203. if (!myextra)
  204. return false;
  205. myextra[0] = newDateStyle;
  206. myextra[1] = newDateOrder;
  207. *extra = (void *) myextra;
  208. return true;
  209. }
  210. /*
  211. * assign_datestyle: GUC assign_hook for datestyle
  212. */
  213. void
  214. assign_datestyle(const char *newval, void *extra)
  215. {
  216. int *myextra = (int *) extra;
  217. DateStyle = myextra[0];
  218. DateOrder = myextra[1];
  219. }
  220. /*
  221. * TIMEZONE
  222. */
  223. /*
  224. * check_timezone: GUC check_hook for timezone
  225. */
  226. bool
  227. check_timezone(char **newval, void **extra, GucSource source)
  228. {
  229. pg_tz *new_tz;
  230. long gmtoffset;
  231. char *endptr;
  232. double hours;
  233. if (pg_strncasecmp(*newval, "interval", 8) == 0)
  234. {
  235. /*
  236. * Support INTERVAL 'foo'. This is for SQL spec compliance, not
  237. * because it has any actual real-world usefulness.
  238. */
  239. const char *valueptr = *newval;
  240. char *val;
  241. Interval *interval;
  242. valueptr += 8;
  243. while (isspace((unsigned char) *valueptr))
  244. valueptr++;
  245. if (*valueptr++ != '\'')
  246. return false;
  247. val = pstrdup(valueptr);
  248. /* Check and remove trailing quote */
  249. endptr = strchr(val, '\'');
  250. if (!endptr || endptr[1] != '\0')
  251. {
  252. pfree(val);
  253. return false;
  254. }
  255. *endptr = '\0';
  256. /*
  257. * Try to parse it. XXX an invalid interval format will result in
  258. * ereport(ERROR), which is not desirable for GUC. We did what we
  259. * could to guard against this in flatten_set_variable_args, but a
  260. * string coming in from postgresql.conf might contain anything.
  261. */
  262. interval = DatumGetIntervalP(DirectFunctionCall3(interval_in,
  263. CStringGetDatum(val),
  264. ObjectIdGetDatum(InvalidOid),
  265. Int32GetDatum(-1)));
  266. pfree(val);
  267. if (interval->month != 0)
  268. {
  269. GUC_check_errdetail("Cannot specify months in time zone interval.");
  270. pfree(interval);
  271. return false;
  272. }
  273. if (interval->day != 0)
  274. {
  275. GUC_check_errdetail("Cannot specify days in time zone interval.");
  276. pfree(interval);
  277. return false;
  278. }
  279. /* Here we change from SQL to Unix sign convention */
  280. #ifdef HAVE_INT64_TIMESTAMP
  281. gmtoffset = -(interval->time / USECS_PER_SEC);
  282. #else
  283. gmtoffset = -interval->time;
  284. #endif
  285. new_tz = pg_tzset_offset(gmtoffset);
  286. pfree(interval);
  287. }
  288. else
  289. {
  290. /*
  291. * Try it as a numeric number of hours (possibly fractional).
  292. */
  293. hours = strtod(*newval, &endptr);
  294. if (endptr != *newval && *endptr == '\0')
  295. {
  296. /* Here we change from SQL to Unix sign convention */
  297. gmtoffset = -hours * SECS_PER_HOUR;
  298. new_tz = pg_tzset_offset(gmtoffset);
  299. }
  300. else
  301. {
  302. /*
  303. * Otherwise assume it is a timezone name, and try to load it.
  304. */
  305. new_tz = pg_tzset(*newval);
  306. if (!new_tz)
  307. {
  308. /* Doesn't seem to be any great value in errdetail here */
  309. return false;
  310. }
  311. if (!pg_tz_acceptable(new_tz))
  312. {
  313. GUC_check_errmsg("time zone \"%s\" appears to use leap seconds",
  314. *newval);
  315. GUC_check_errdetail("PostgreSQL does not support leap seconds.");
  316. return false;
  317. }
  318. }
  319. }
  320. /*
  321. * Pass back data for assign_timezone to use
  322. */
  323. *extra = malloc(sizeof(pg_tz *));
  324. if (!*extra)
  325. return false;
  326. *((pg_tz **) *extra) = new_tz;
  327. return true;
  328. }
  329. /*
  330. * assign_timezone: GUC assign_hook for timezone
  331. */
  332. void
  333. assign_timezone(const char *newval, void *extra)
  334. {
  335. session_timezone = *((pg_tz **) extra);
  336. }
  337. /*
  338. * show_timezone: GUC show_hook for timezone
  339. */
  340. const char *
  341. show_timezone(void)
  342. {
  343. const char *tzn;
  344. /* Always show the zone's canonical name */
  345. tzn = pg_get_timezone_name(session_timezone);
  346. if (tzn != NULL)
  347. return tzn;
  348. return "unknown";
  349. }
  350. /*
  351. * LOG_TIMEZONE
  352. *
  353. * For log_timezone, we don't support the interval-based methods of setting a
  354. * zone, which are only there for SQL spec compliance not because they're
  355. * actually useful.
  356. */
  357. /*
  358. * check_log_timezone: GUC check_hook for log_timezone
  359. */
  360. bool
  361. check_log_timezone(char **newval, void **extra, GucSource source)
  362. {
  363. pg_tz *new_tz;
  364. /*
  365. * Assume it is a timezone name, and try to load it.
  366. */
  367. new_tz = pg_tzset(*newval);
  368. if (!new_tz)
  369. {
  370. /* Doesn't seem to be any great value in errdetail here */
  371. return false;
  372. }
  373. if (!pg_tz_acceptable(new_tz))
  374. {
  375. GUC_check_errmsg("time zone \"%s\" appears to use leap seconds",
  376. *newval);
  377. GUC_check_errdetail("PostgreSQL does not support leap seconds.");
  378. return false;
  379. }
  380. /*
  381. * Pass back data for assign_log_timezone to use
  382. */
  383. *extra = malloc(sizeof(pg_tz *));
  384. if (!*extra)
  385. return false;
  386. *((pg_tz **) *extra) = new_tz;
  387. return true;
  388. }
  389. /*
  390. * assign_log_timezone: GUC assign_hook for log_timezone
  391. */
  392. void
  393. assign_log_timezone(const char *newval, void *extra)
  394. {
  395. log_timezone = *((pg_tz **) extra);
  396. }
  397. /*
  398. * show_log_timezone: GUC show_hook for log_timezone
  399. */
  400. const char *
  401. show_log_timezone(void)
  402. {
  403. const char *tzn;
  404. /* Always show the zone's canonical name */
  405. tzn = pg_get_timezone_name(log_timezone);
  406. if (tzn != NULL)
  407. return tzn;
  408. return "unknown";
  409. }
  410. /*
  411. * SET TRANSACTION READ ONLY and SET TRANSACTION READ WRITE
  412. *
  413. * We allow idempotent changes (r/w -> r/w and r/o -> r/o) at any time, and
  414. * we also always allow changes from read-write to read-only. However,
  415. * read-only may be changed to read-write only when in a top-level transaction
  416. * that has not yet taken an initial snapshot. Can't do it in a hot standby
  417. * slave, either.
  418. *
  419. * If we are not in a transaction at all, just allow the change; it means
  420. * nothing since XactReadOnly will be reset by the next StartTransaction().
  421. * The IsTransactionState() test protects us against trying to check
  422. * RecoveryInProgress() in contexts where shared memory is not accessible.
  423. */
  424. bool
  425. check_transaction_read_only(bool *newval, void **extra, GucSource source)
  426. {
  427. if (*newval == false && XactReadOnly && IsTransactionState())
  428. {
  429. /* Can't go to r/w mode inside a r/o transaction */
  430. if (IsSubTransaction())
  431. {
  432. GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
  433. GUC_check_errmsg("cannot set transaction read-write mode inside a read-only transaction");
  434. return false;
  435. }
  436. /* Top level transaction can't change to r/w after first snapshot. */
  437. if (FirstSnapshotSet)
  438. {
  439. GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
  440. GUC_check_errmsg("transaction read-write mode must be set before any query");
  441. return false;
  442. }
  443. /* Can't go to r/w mode while recovery is still active */
  444. if (RecoveryInProgress())
  445. {
  446. GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
  447. GUC_check_errmsg("cannot set transaction read-write mode during recovery");
  448. return false;
  449. }
  450. }
  451. return true;
  452. }
  453. /*
  454. * SET TRANSACTION ISOLATION LEVEL
  455. *
  456. * We allow idempotent changes at any time, but otherwise this can only be
  457. * changed in a toplevel transaction that has not yet taken a snapshot.
  458. *
  459. * As in check_transaction_read_only, allow it if not inside a transaction.
  460. */
  461. bool
  462. check_XactIsoLevel(char **newval, void **extra, GucSource source)
  463. {
  464. int newXactIsoLevel;
  465. if (strcmp(*newval, "serializable") == 0)
  466. {
  467. newXactIsoLevel = XACT_SERIALIZABLE;
  468. }
  469. else if (strcmp(*newval, "repeatable read") == 0)
  470. {
  471. newXactIsoLevel = XACT_REPEATABLE_READ;
  472. }
  473. else if (strcmp(*newval, "read committed") == 0)
  474. {
  475. newXactIsoLevel = XACT_READ_COMMITTED;
  476. }
  477. else if (strcmp(*newval, "read uncommitted") == 0)
  478. {
  479. newXactIsoLevel = XACT_READ_UNCOMMITTED;
  480. }
  481. else if (strcmp(*newval, "default") == 0)
  482. {
  483. newXactIsoLevel = DefaultXactIsoLevel;
  484. }
  485. else
  486. return false;
  487. if (newXactIsoLevel != XactIsoLevel && IsTransactionState())
  488. {
  489. if (FirstSnapshotSet)
  490. {
  491. GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
  492. GUC_check_errmsg("SET TRANSACTION ISOLATION LEVEL must be called before any query");
  493. return false;
  494. }
  495. /* We ignore a subtransaction setting it to the existing value. */
  496. if (IsSubTransaction())
  497. {
  498. GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
  499. GUC_check_errmsg("SET TRANSACTION ISOLATION LEVEL must not be called in a subtransaction");
  500. return false;
  501. }
  502. /* Can't go to serializable mode while recovery is still active */
  503. if (newXactIsoLevel == XACT_SERIALIZABLE && RecoveryInProgress())
  504. {
  505. GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
  506. GUC_check_errmsg("cannot use serializable mode in a hot standby");
  507. GUC_check_errhint("You can use REPEATABLE READ instead.");
  508. return false;
  509. }
  510. }
  511. *extra = malloc(sizeof(int));
  512. if (!*extra)
  513. return false;
  514. *((int *) *extra) = newXactIsoLevel;
  515. return true;
  516. }
  517. void
  518. assign_XactIsoLevel(const char *newval, void *extra)
  519. {
  520. XactIsoLevel = *((int *) extra);
  521. }
  522. const char *
  523. show_XactIsoLevel(void)
  524. {
  525. /* We need this because we don't want to show "default". */
  526. switch (XactIsoLevel)
  527. {
  528. case XACT_READ_UNCOMMITTED:
  529. return "read uncommitted";
  530. case XACT_READ_COMMITTED:
  531. return "read committed";
  532. case XACT_REPEATABLE_READ:
  533. return "repeatable read";
  534. case XACT_SERIALIZABLE:
  535. return "serializable";
  536. default:
  537. return "bogus";
  538. }
  539. }
  540. /*
  541. * SET TRANSACTION [NOT] DEFERRABLE
  542. */
  543. bool
  544. check_transaction_deferrable(bool *newval, void **extra, GucSource source)
  545. {
  546. if (IsSubTransaction())
  547. {
  548. GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
  549. GUC_check_errmsg("SET TRANSACTION [NOT] DEFERRABLE cannot be called within a subtransaction");
  550. return false;
  551. }
  552. if (FirstSnapshotSet)
  553. {
  554. GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
  555. GUC_check_errmsg("SET TRANSACTION [NOT] DEFERRABLE must be called before any query");
  556. return false;
  557. }
  558. return true;
  559. }
  560. /*
  561. * Random number seed
  562. *
  563. * We can't roll back the random sequence on error, and we don't want
  564. * config file reloads to affect it, so we only want interactive SET SEED
  565. * commands to set it. We use the "extra" storage to ensure that rollbacks
  566. * don't try to do the operation again.
  567. */
  568. bool
  569. check_random_seed(double *newval, void **extra, GucSource source)
  570. {
  571. *extra = malloc(sizeof(int));
  572. if (!*extra)
  573. return false;
  574. /* Arm the assign only if source of value is an interactive SET */
  575. *((int *) *extra) = (source >= PGC_S_INTERACTIVE);
  576. return true;
  577. }
  578. void
  579. assign_random_seed(double newval, void *extra)
  580. {
  581. /* We'll do this at most once for any setting of the GUC variable */
  582. if (*((int *) extra))
  583. DirectFunctionCall1(setseed, Float8GetDatum(newval));
  584. *((int *) extra) = 0;
  585. }
  586. const char *
  587. show_random_seed(void)
  588. {
  589. return "unavailable";
  590. }
  591. /*
  592. * SET CLIENT_ENCODING
  593. */
  594. bool
  595. check_client_encoding(char **newval, void **extra, GucSource source)
  596. {
  597. int encoding;
  598. const char *canonical_name;
  599. /* Look up the encoding by name */
  600. encoding = pg_valid_client_encoding(*newval);
  601. if (encoding < 0)
  602. return false;
  603. /* Get the canonical name (no aliases, uniform case) */
  604. canonical_name = pg_encoding_to_char(encoding);
  605. /*
  606. * If we are not within a transaction then PrepareClientEncoding will not
  607. * be able to look up the necessary conversion procs. If we are still
  608. * starting up, it will return "OK" anyway, and InitializeClientEncoding
  609. * will fix things once initialization is far enough along. After
  610. * startup, we'll fail. This would only happen if someone tries to change
  611. * client_encoding in postgresql.conf and then SIGHUP existing sessions.
  612. * It seems like a bad idea for client_encoding to change that way anyhow,
  613. * so we don't go out of our way to support it.
  614. *
  615. * Note: in the postmaster, or any other process that never calls
  616. * InitializeClientEncoding, PrepareClientEncoding will always succeed,
  617. * and so will SetClientEncoding; but they won't do anything, which is OK.
  618. */
  619. if (PrepareClientEncoding(encoding) < 0)
  620. {
  621. if (IsTransactionState())
  622. {
  623. /* Must be a genuine no-such-conversion problem */
  624. GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
  625. GUC_check_errdetail("Conversion between %s and %s is not supported.",
  626. canonical_name,
  627. GetDatabaseEncodingName());
  628. }
  629. else
  630. {
  631. /* Provide a useful complaint */
  632. GUC_check_errdetail("Cannot change \"client_encoding\" now.");
  633. }
  634. return false;
  635. }
  636. /*
  637. * Replace the user-supplied string with the encoding's canonical name.
  638. * This gets rid of aliases and case-folding variations.
  639. *
  640. * XXX Although canonicalizing seems like a good idea in the abstract, it
  641. * breaks pre-9.1 JDBC drivers, which expect that if they send "UNICODE"
  642. * as the client_encoding setting then it will read back the same way. As
  643. * a workaround, don't replace the string if it's "UNICODE". Remove that
  644. * hack when pre-9.1 JDBC drivers are no longer in use.
  645. */
  646. if (strcmp(*newval, canonical_name) != 0 &&
  647. strcmp(*newval, "UNICODE") != 0)
  648. {
  649. free(*newval);
  650. *newval = strdup(canonical_name);
  651. if (!*newval)
  652. return false;
  653. }
  654. /*
  655. * Save the encoding's ID in *extra, for use by assign_client_encoding.
  656. */
  657. *extra = malloc(sizeof(int));
  658. if (!*extra)
  659. return false;
  660. *((int *) *extra) = encoding;
  661. return true;
  662. }
  663. void
  664. assign_client_encoding(const char *newval, void *extra)
  665. {
  666. int encoding = *((int *) extra);
  667. /* We do not expect an error if PrepareClientEncoding succeeded */
  668. if (SetClientEncoding(encoding) < 0)
  669. elog(LOG, "SetClientEncoding(%d) failed", encoding);
  670. }
  671. /*
  672. * SET SESSION AUTHORIZATION
  673. */
  674. typedef struct
  675. {
  676. /* This is the "extra" state for both SESSION AUTHORIZATION and ROLE */
  677. Oid roleid;
  678. bool is_superuser;
  679. } role_auth_extra;
  680. bool
  681. check_session_authorization(char **newval, void **extra, GucSource source)
  682. {
  683. HeapTuple roleTup;
  684. Oid roleid;
  685. bool is_superuser;
  686. role_auth_extra *myextra;
  687. /* Do nothing for the boot_val default of NULL */
  688. if (*newval == NULL)
  689. return true;
  690. if (!IsTransactionState())
  691. {
  692. /*
  693. * Can't do catalog lookups, so fail. The result of this is that
  694. * session_authorization cannot be set in postgresql.conf, which seems
  695. * like a good thing anyway, so we don't work hard to avoid it.
  696. */
  697. return false;
  698. }
  699. /* Look up the username */
  700. roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
  701. if (!HeapTupleIsValid(roleTup))
  702. {
  703. GUC_check_errmsg("role \"%s\" does not exist", *newval);
  704. return false;
  705. }
  706. roleid = HeapTupleGetOid(roleTup);
  707. is_superuser = ((Form_pg_authid) GETSTRUCT(roleTup))->rolsuper;
  708. ReleaseSysCache(roleTup);
  709. /* Set up "extra" struct for assign_session_authorization to use */
  710. myextra = (role_auth_extra *) malloc(sizeof(role_auth_extra));
  711. if (!myextra)
  712. return false;
  713. myextra->roleid = roleid;
  714. myextra->is_superuser = is_superuser;
  715. *extra = (void *) myextra;
  716. return true;
  717. }
  718. void
  719. assign_session_authorization(const char *newval, void *extra)
  720. {
  721. role_auth_extra *myextra = (role_auth_extra *) extra;
  722. /* Do nothing for the boot_val default of NULL */
  723. if (!myextra)
  724. return;
  725. SetSessionAuthorization(myextra->roleid, myextra->is_superuser);
  726. }
  727. /*
  728. * SET ROLE
  729. *
  730. * The SQL spec requires "SET ROLE NONE" to unset the role, so we hardwire
  731. * a translation of "none" to InvalidOid. Otherwise this is much like
  732. * SET SESSION AUTHORIZATION.
  733. */
  734. extern char *role_string; /* in guc.c */
  735. bool
  736. check_role(char **newval, void **extra, GucSource source)
  737. {
  738. HeapTuple roleTup;
  739. Oid roleid;
  740. bool is_superuser;
  741. role_auth_extra *myextra;
  742. if (strcmp(*newval, "none") == 0)
  743. {
  744. /* hardwired translation */
  745. roleid = InvalidOid;
  746. is_superuser = false;
  747. }
  748. else
  749. {
  750. if (!IsTransactionState())
  751. {
  752. /*
  753. * Can't do catalog lookups, so fail. The result of this is that
  754. * role cannot be set in postgresql.conf, which seems like a good
  755. * thing anyway, so we don't work hard to avoid it.
  756. */
  757. return false;
  758. }
  759. /* Look up the username */
  760. roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
  761. if (!HeapTupleIsValid(roleTup))
  762. {
  763. GUC_check_errmsg("role \"%s\" does not exist", *newval);
  764. return false;
  765. }
  766. roleid = HeapTupleGetOid(roleTup);
  767. is_superuser = ((Form_pg_authid) GETSTRUCT(roleTup))->rolsuper;
  768. ReleaseSysCache(roleTup);
  769. /*
  770. * Verify that session user is allowed to become this role
  771. */
  772. if (!is_member_of_role(GetSessionUserId(), roleid))
  773. {
  774. GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
  775. GUC_check_errmsg("permission denied to set role \"%s\"",
  776. *newval);
  777. return false;
  778. }
  779. }
  780. /* Set up "extra" struct for assign_role to use */
  781. myextra = (role_auth_extra *) malloc(sizeof(role_auth_extra));
  782. if (!myextra)
  783. return false;
  784. myextra->roleid = roleid;
  785. myextra->is_superuser = is_superuser;
  786. *extra = (void *) myextra;
  787. return true;
  788. }
  789. void
  790. assign_role(const char *newval, void *extra)
  791. {
  792. role_auth_extra *myextra = (role_auth_extra *) extra;
  793. SetCurrentRoleId(myextra->roleid, myextra->is_superuser);
  794. }
  795. const char *
  796. show_role(void)
  797. {
  798. /*
  799. * Check whether SET ROLE is active; if not return "none". This is a
  800. * kluge to deal with the fact that SET SESSION AUTHORIZATION logically
  801. * resets SET ROLE to NONE, but we cannot set the GUC role variable from
  802. * assign_session_authorization (because we haven't got enough info to
  803. * call set_config_option).
  804. */
  805. if (!OidIsValid(GetCurrentRoleId()))
  806. return "none";
  807. /* Otherwise we can just use the GUC string */
  808. return role_string ? role_string : "none";
  809. }