Advertisement
Guest User

Revert PostgreSQL 9.1 Timezone changes

a guest
Dec 15th, 2012
879
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 69.24 KB | None | 0 0
  1. diff -u -r -b -B postgresql-9.2.1a/doc/src/sgml/config.sgml postgresql-9.2.1/doc/src/sgml/config.sgml
  2. --- postgresql-9.2.1a/doc/src/sgml/config.sgml Wed Sep 19 17:47:58 2012
  3. +++ postgresql-9.2.1/doc/src/sgml/config.sgml Sat Dec 15 03:45:00 2012
  4. @@ -4119,10 +4119,9 @@
  5. Sets the time zone used for timestamps written in the server log.
  6. Unlike <xref linkend="guc-timezone">, this value is cluster-wide,
  7. so that all sessions will report timestamps consistently.
  8. - The built-in default is <literal>GMT</>, but that is typically
  9. - overridden in <filename>postgresql.conf</>; <application>initdb</>
  10. - will install a setting there corresponding to its system environment.
  11. - See <xref linkend="datatype-timezones"> for more information.
  12. + If not explicitly set, the server initializes this variable to the
  13. + time zone specified by its system environment. See <xref
  14. + linkend="datatype-timezones"> for more information.
  15. This parameter can only be set in the <filename>postgresql.conf</>
  16. file or on the server command line.
  17. </para>
  18. @@ -5195,10 +5194,9 @@
  19. <listitem>
  20. <para>
  21. Sets the time zone for displaying and interpreting time stamps.
  22. - The built-in default is <literal>GMT</>, but that is typically
  23. - overridden in <filename>postgresql.conf</>; <application>initdb</>
  24. - will install a setting there corresponding to its system environment.
  25. - See <xref linkend="datatype-timezones"> for more information.
  26. + If not explicitly set, the server initializes this variable to the
  27. + time zone specified by its system environment. See <xref
  28. + linkend="datatype-timezones"> for more information.
  29. </para>
  30. </listitem>
  31. </varlistentry>
  32. diff -u -r -b -B postgresql-9.2.1a/doc/src/sgml/datatype.sgml postgresql-9.2.1/doc/src/sgml/datatype.sgml
  33. --- postgresql-9.2.1a/doc/src/sgml/datatype.sgml Wed Sep 19 17:47:58 2012
  34. +++ postgresql-9.2.1/doc/src/sgml/datatype.sgml Sat Dec 15 03:45:00 2012
  35. @@ -2322,7 +2322,7 @@
  36. but continue to be prone to arbitrary changes, particularly with
  37. respect to daylight-savings rules.
  38. <productname>PostgreSQL</productname> uses the widely-used
  39. - <literal>zoneinfo</> (Olson) time zone database for information about
  40. + <literal>zoneinfo</> time zone database for information about
  41. historical time zone rules. For times in the future, the assumption
  42. is that the latest known rules for a given time zone will
  43. continue to be observed indefinitely far into the future.
  44. @@ -2468,11 +2468,28 @@
  45. The <xref linkend="guc-timezone"> configuration parameter can
  46. be set in the file <filename>postgresql.conf</>, or in any of the
  47. other standard ways described in <xref linkend="runtime-config">.
  48. - There are also some special ways to set it:
  49. + There are also several special ways to set it:
  50.  
  51. <itemizedlist>
  52. <listitem>
  53. <para>
  54. + If <varname>timezone</> is not specified in
  55. + <filename>postgresql.conf</> or as a server command-line option,
  56. + the server attempts to use the value of the <envar>TZ</envar>
  57. + environment variable as the default time zone. If <envar>TZ</envar>
  58. + is not defined or is not any of the time zone names known to
  59. + <productname>PostgreSQL</productname>, the server attempts to
  60. + determine the operating system's default time zone by checking the
  61. + behavior of the C library function <literal>localtime()</>. The
  62. + default time zone is selected as the closest match among
  63. + <productname>PostgreSQL</productname>'s known time zones.
  64. + (These rules are also used to choose the default value of
  65. + <xref linkend="guc-log-timezone">, if not specified.)
  66. + </para>
  67. + </listitem>
  68. +
  69. + <listitem>
  70. + <para>
  71. The <acronym>SQL</acronym> command <command>SET TIME ZONE</command>
  72. sets the time zone for the session. This is an alternative spelling
  73. of <command>SET TIMEZONE TO</> with a more SQL-spec-compatible syntax.
  74. diff -u -r -b -B postgresql-9.2.1a/doc/src/sgml/ref/set.sgml postgresql-9.2.1/doc/src/sgml/ref/set.sgml
  75. --- postgresql-9.2.1a/doc/src/sgml/ref/set.sgml Wed Sep 19 17:47:58 2012
  76. +++ postgresql-9.2.1/doc/src/sgml/ref/set.sgml Sat Dec 15 03:45:00 2012
  77. @@ -239,7 +239,9 @@
  78. <listitem>
  79. <para>
  80. Set the time zone to your local time zone (that is, the
  81. - server's default value of <varname>timezone</>).
  82. + server's default value of <varname>timezone</>; if this
  83. + has not been explicitly set anywhere, it will be the zone that
  84. + the server's operating system defaults to).
  85. </para>
  86. </listitem>
  87. </varlistentry>
  88. diff -u -r -b -B postgresql-9.2.1a/src/backend/bootstrap/bootstrap.c postgresql-9.2.1/src/backend/bootstrap/bootstrap.c
  89. --- postgresql-9.2.1a/src/backend/bootstrap/bootstrap.c Wed Sep 19 17:47:58 2012
  90. +++ postgresql-9.2.1/src/backend/bootstrap/bootstrap.c Sat Dec 15 03:45:00 2012
  91. @@ -341,6 +341,10 @@
  92. {
  93. if (!SelectConfigFiles(userDoption, progname))
  94. proc_exit(1);
  95. + /* If timezone is not set, determine what the OS uses */
  96. + pg_timezone_initialize();
  97. + /* If timezone_abbreviations is not set, select default */
  98. + pg_timezone_abbrev_initialize();
  99. }
  100.  
  101. /* Validate we have been given a reasonable-looking DataDir */
  102. diff -u -r -b -B postgresql-9.2.1a/src/backend/commands/variable.c postgresql-9.2.1/src/backend/commands/variable.c
  103. --- postgresql-9.2.1a/src/backend/commands/variable.c Wed Sep 19 17:47:58 2012
  104. +++ postgresql-9.2.1/src/backend/commands/variable.c Sat Dec 15 03:45:00 2012
  105. @@ -259,6 +259,23 @@
  106. char *endptr;
  107. double hours;
  108.  
  109. + if (*newval == NULL)
  110. + {
  111. + /*
  112. + * The boot_val given for TimeZone in guc.c is NULL. When we see this
  113. + * we just do nothing. If this isn't overridden from the config file
  114. + * then pg_timezone_initialize() will eventually select a default
  115. + * value from the environment. This hack has two purposes: to avoid
  116. + * wasting cycles loading values that might soon be overridden from
  117. + * the config file, and to avoid trying to read the timezone files
  118. + * during InitializeGUCOptions(). The latter doesn't work in an
  119. + * EXEC_BACKEND subprocess because my_exec_path hasn't been set yet
  120. + * and so we can't locate PGSHAREDIR.
  121. + */
  122. + Assert(source == PGC_S_DEFAULT);
  123. + return true;
  124. + }
  125. +
  126. /*
  127. * Initialize the "extra" struct that will be passed to assign_timezone.
  128. * We don't want to change any of the three global variables except as
  129. @@ -357,7 +374,7 @@
  130. return false;
  131. }
  132.  
  133. - if (!pg_tz_acceptable(new_tz))
  134. + if (!tz_acceptable(new_tz))
  135. {
  136. GUC_check_errmsg("time zone \"%s\" appears to use leap seconds",
  137. *newval);
  138. @@ -410,6 +427,10 @@
  139. {
  140. timezone_extra *myextra = (timezone_extra *) extra;
  141.  
  142. + /* Do nothing for the boot_val default of NULL */
  143. + if (!myextra)
  144. + return;
  145. +
  146. session_timezone = myextra->session_timezone;
  147. CTimeZone = myextra->CTimeZone;
  148. HasCTZSet = myextra->HasCTZSet;
  149. @@ -469,8 +490,20 @@
  150. {
  151. pg_tz *new_tz;
  152.  
  153. + if (*newval == NULL)
  154. + {
  155. /*
  156. - * Assume it is a timezone name, and try to load it.
  157. + * The boot_val given for log_timezone in guc.c is NULL. When we see
  158. + * this we just do nothing. If this isn't overridden from the config
  159. + * file then pg_timezone_initialize() will eventually select a default
  160. + * value from the environment.
  161. + */
  162. + Assert(source == PGC_S_DEFAULT);
  163. + return true;
  164. + }
  165. +
  166. + /*
  167. + * Otherwise assume it is a timezone name, and try to load it.
  168. */
  169. new_tz = pg_tzset(*newval);
  170.  
  171. @@ -480,7 +513,7 @@
  172. return false;
  173. }
  174.  
  175. - if (!pg_tz_acceptable(new_tz))
  176. + if (!tz_acceptable(new_tz))
  177. {
  178. GUC_check_errmsg("time zone \"%s\" appears to use leap seconds",
  179. *newval);
  180. @@ -505,6 +538,10 @@
  181. void
  182. assign_log_timezone(const char *newval, void *extra)
  183. {
  184. + /* Do nothing for the boot_val default of NULL */
  185. + if (!extra)
  186. + return;
  187. +
  188. log_timezone = *((pg_tz **) extra);
  189. }
  190.  
  191. diff -u -r -b -B postgresql-9.2.1a/src/backend/postmaster/postmaster.c postgresql-9.2.1/src/backend/postmaster/postmaster.c
  192. --- postgresql-9.2.1a/src/backend/postmaster/postmaster.c Wed Sep 19 17:47:58 2012
  193. +++ postgresql-9.2.1/src/backend/postmaster/postmaster.c Sat Dec 15 03:45:00 2012
  194. @@ -824,6 +824,21 @@
  195. CreateDataDirLockFile(true);
  196.  
  197. /*
  198. + * If timezone is not set, determine what the OS uses. (In theory this
  199. + * should be done during GUC initialization, but because it can take as
  200. + * much as several seconds, we delay it until after we've created the
  201. + * postmaster.pid file. This prevents problems with boot scripts that
  202. + * expect the pidfile to appear quickly. Also, we avoid problems with
  203. + * trying to locate the timezone files too early in initialization.)
  204. + */
  205. + pg_timezone_initialize();
  206. +
  207. + /*
  208. + * Likewise, init timezone_abbreviations if not already set.
  209. + */
  210. + pg_timezone_abbrev_initialize();
  211. +
  212. + /*
  213. * Initialize SSL library, if specified.
  214. */
  215. #ifdef USE_SSL
  216. diff -u -r -b -B postgresql-9.2.1a/src/backend/tcop/postgres.c postgresql-9.2.1/src/backend/tcop/postgres.c
  217. --- postgresql-9.2.1a/src/backend/tcop/postgres.c Wed Sep 19 17:47:58 2012
  218. +++ postgresql-9.2.1/src/backend/tcop/postgres.c Sat Dec 15 03:45:00 2012
  219. @@ -3575,6 +3575,10 @@
  220. {
  221. if (!SelectConfigFiles(userDoption, progname))
  222. proc_exit(1);
  223. + /* If timezone is not set, determine what the OS uses */
  224. + pg_timezone_initialize();
  225. + /* If timezone_abbreviations is not set, select default */
  226. + pg_timezone_abbrev_initialize();
  227. }
  228.  
  229. /*
  230. diff -u -r -b -B postgresql-9.2.1a/src/backend/utils/error/elog.c postgresql-9.2.1/src/backend/utils/error/elog.c
  231. --- postgresql-9.2.1a/src/backend/utils/error/elog.c Wed Sep 19 17:47:58 2012
  232. +++ postgresql-9.2.1/src/backend/utils/error/elog.c Sat Dec 15 15:05:08 2012
  233. @@ -1851,20 +1851,24 @@
  234. {
  235. struct timeval tv;
  236. pg_time_t stamp_time;
  237. + pg_tz *tz;
  238. char msbuf[8];
  239.  
  240. gettimeofday(&tv, NULL);
  241. stamp_time = (pg_time_t) tv.tv_sec;
  242.  
  243. /*
  244. - * Note: we expect that guc.c will ensure that log_timezone is set up (at
  245. - * least with a minimal GMT value) before Log_line_prefix can become
  246. - * nonempty or CSV mode can be selected.
  247. + * Normally we print log timestamps in log_timezone, but during startup we
  248. + * could get here before that's set. If so, fall back to gmt_timezone
  249. + * (which guc.c ensures is set up before Log_line_prefix can become
  250. + * nonempty).
  251. */
  252. + tz = log_timezone ? log_timezone : gmt_timezone;
  253. +
  254. pg_strftime(formatted_log_time, FORMATTED_TS_LEN,
  255. /* leave room for milliseconds... */
  256. "%Y-%m-%d %H:%M:%S %Z",
  257. - pg_localtime(&stamp_time, log_timezone));
  258. + pg_localtime(&stamp_time, tz));
  259.  
  260. /* 'paste' milliseconds into place... */
  261. sprintf(msbuf, ".%03d", (int) (tv.tv_usec / 1000));
  262. @@ -1878,15 +1882,19 @@
  263. setup_formatted_start_time(void)
  264. {
  265. pg_time_t stamp_time = (pg_time_t) MyStartTime;
  266. + pg_tz *tz;
  267.  
  268. /*
  269. - * Note: we expect that guc.c will ensure that log_timezone is set up (at
  270. - * least with a minimal GMT value) before Log_line_prefix can become
  271. - * nonempty or CSV mode can be selected.
  272. + * Normally we print log timestamps in log_timezone, but during startup we
  273. + * could get here before that's set. If so, fall back to gmt_timezone
  274. + * (which guc.c ensures is set up before Log_line_prefix can become
  275. + * nonempty).
  276. */
  277. + tz = log_timezone ? log_timezone : gmt_timezone;
  278. +
  279. pg_strftime(formatted_start_time, FORMATTED_TS_LEN,
  280. "%Y-%m-%d %H:%M:%S %Z",
  281. - pg_localtime(&stamp_time, log_timezone));
  282. + pg_localtime(&stamp_time, tz));
  283. }
  284.  
  285. /*
  286. @@ -1985,11 +1993,14 @@
  287. case 't':
  288. {
  289. pg_time_t stamp_time = (pg_time_t) time(NULL);
  290. + pg_tz *tz;
  291. char strfbuf[128];
  292.  
  293. + tz = log_timezone ? log_timezone : gmt_timezone;
  294. +
  295. pg_strftime(strfbuf, sizeof(strfbuf),
  296. "%Y-%m-%d %H:%M:%S %Z",
  297. - pg_localtime(&stamp_time, log_timezone));
  298. + pg_localtime(&stamp_time, tz));
  299. appendStringInfoString(buf, strfbuf);
  300. }
  301. break;
  302. diff -u -r -b -B postgresql-9.2.1a/src/backend/utils/misc/guc-file.c postgresql-9.2.1/src/backend/utils/misc/guc-file.c
  303. --- postgresql-9.2.1a/src/backend/utils/misc/guc-file.c Wed Sep 19 18:03:44 2012
  304. +++ postgresql-9.2.1/src/backend/utils/misc/guc-file.c Sat Dec 15 03:54:30 2012
  305. @@ -1,6 +1,6 @@
  306. -#line 2 "guc-file.c"
  307. +#line 2 "src\\backend\\utils\\misc\\guc-file.c"
  308.  
  309. -#line 4 "guc-file.c"
  310. +#line 4 "src\\backend\\utils\\misc\\guc-file.c"
  311.  
  312. #define YY_INT_ALIGNED short int
  313.  
  314. @@ -360,7 +360,7 @@
  315.  
  316. /* Begin user sect3 */
  317.  
  318. -#define GUC_yywrap(n) 1
  319. +#define GUC_yywrap() 1
  320. #define YY_SKIP_YYWRAP
  321.  
  322. typedef unsigned char YY_CHAR;
  323. @@ -522,7 +522,7 @@
  324. #define YY_MORE_ADJ 0
  325. #define YY_RESTORE_YY_MORE_OFFSET
  326. char *GUC_yytext;
  327. -#line 1 "guc-file.l"
  328. +#line 1 "src\\backend\\utils\\misc\\guc-file.l"
  329. /* -*-pgsql-c-*- */
  330. /*
  331. * Scanner for the configuration file
  332. @@ -531,7 +531,7 @@
  333. *
  334. * src/backend/utils/misc/guc-file.l
  335. */
  336. -#line 11 "guc-file.l"
  337. +#line 11 "src\\backend\\utils\\misc\\guc-file.l"
  338.  
  339. #include "postgres.h"
  340.  
  341. @@ -576,7 +576,7 @@
  342. static char *GUC_scanstr(const char *s);
  343.  
  344. #define YY_NO_INPUT 1
  345. -#line 580 "guc-file.c"
  346. +#line 580 "src\\backend\\utils\\misc\\guc-file.c"
  347.  
  348. #define INITIAL 0
  349.  
  350. @@ -761,10 +761,10 @@
  351. register char *yy_cp, *yy_bp;
  352. register int yy_act;
  353.  
  354. -#line 86 "guc-file.l"
  355. +#line 86 "src\\backend\\utils\\misc\\guc-file.l"
  356.  
  357.  
  358. -#line 768 "guc-file.c"
  359. +#line 768 "src\\backend\\utils\\misc\\guc-file.c"
  360.  
  361. if ( !(yy_init) )
  362. {
  363. @@ -846,65 +846,65 @@
  364. case 1:
  365. /* rule 1 can match eol */
  366. YY_RULE_SETUP
  367. -#line 88 "guc-file.l"
  368. +#line 88 "src\\backend\\utils\\misc\\guc-file.l"
  369. ConfigFileLineno++; return GUC_EOL;
  370. YY_BREAK
  371. case 2:
  372. YY_RULE_SETUP
  373. -#line 89 "guc-file.l"
  374. +#line 89 "src\\backend\\utils\\misc\\guc-file.l"
  375. /* eat whitespace */
  376. YY_BREAK
  377. case 3:
  378. YY_RULE_SETUP
  379. -#line 90 "guc-file.l"
  380. +#line 90 "src\\backend\\utils\\misc\\guc-file.l"
  381. /* eat comment (.* matches anything until newline) */
  382. YY_BREAK
  383. case 4:
  384. YY_RULE_SETUP
  385. -#line 92 "guc-file.l"
  386. +#line 92 "src\\backend\\utils\\misc\\guc-file.l"
  387. return GUC_ID;
  388. YY_BREAK
  389. case 5:
  390. YY_RULE_SETUP
  391. -#line 93 "guc-file.l"
  392. +#line 93 "src\\backend\\utils\\misc\\guc-file.l"
  393. return GUC_QUALIFIED_ID;
  394. YY_BREAK
  395. case 6:
  396. YY_RULE_SETUP
  397. -#line 94 "guc-file.l"
  398. +#line 94 "src\\backend\\utils\\misc\\guc-file.l"
  399. return GUC_STRING;
  400. YY_BREAK
  401. case 7:
  402. YY_RULE_SETUP
  403. -#line 95 "guc-file.l"
  404. +#line 95 "src\\backend\\utils\\misc\\guc-file.l"
  405. return GUC_UNQUOTED_STRING;
  406. YY_BREAK
  407. case 8:
  408. YY_RULE_SETUP
  409. -#line 96 "guc-file.l"
  410. +#line 96 "src\\backend\\utils\\misc\\guc-file.l"
  411. return GUC_INTEGER;
  412. YY_BREAK
  413. case 9:
  414. YY_RULE_SETUP
  415. -#line 97 "guc-file.l"
  416. +#line 97 "src\\backend\\utils\\misc\\guc-file.l"
  417. return GUC_REAL;
  418. YY_BREAK
  419. case 10:
  420. YY_RULE_SETUP
  421. -#line 98 "guc-file.l"
  422. +#line 98 "src\\backend\\utils\\misc\\guc-file.l"
  423. return GUC_EQUALS;
  424. YY_BREAK
  425. case 11:
  426. YY_RULE_SETUP
  427. -#line 100 "guc-file.l"
  428. +#line 100 "src\\backend\\utils\\misc\\guc-file.l"
  429. return GUC_ERROR;
  430. YY_BREAK
  431. case 12:
  432. YY_RULE_SETUP
  433. -#line 102 "guc-file.l"
  434. +#line 102 "src\\backend\\utils\\misc\\guc-file.l"
  435. YY_FATAL_ERROR( "flex scanner jammed" );
  436. YY_BREAK
  437. -#line 908 "guc-file.c"
  438. +#line 908 "src\\backend\\utils\\misc\\guc-file.c"
  439. case YY_STATE_EOF(INITIAL):
  440. yyterminate();
  441.  
  442. @@ -1862,7 +1862,7 @@
  443.  
  444. #define YYTABLES_NAME "yytables"
  445.  
  446. -#line 102 "guc-file.l"
  447. +#line 102 "src\\backend\\utils\\misc\\guc-file.l"
  448.  
  449.  
  450.  
  451. @@ -2038,6 +2038,7 @@
  452. if (context == PGC_SIGHUP)
  453. {
  454. InitializeGUCOptionsFromEnvironment();
  455. + pg_timezone_initialize();
  456. pg_timezone_abbrev_initialize();
  457. /* this selects SQL_ASCII in processes not connected to a database */
  458. SetConfigOption("client_encoding", GetDatabaseEncodingName(),
  459. diff -u -r -b -B postgresql-9.2.1a/src/backend/utils/misc/guc-file.l postgresql-9.2.1/src/backend/utils/misc/guc-file.l
  460. --- postgresql-9.2.1a/src/backend/utils/misc/guc-file.l Wed Sep 19 17:47:58 2012
  461. +++ postgresql-9.2.1/src/backend/utils/misc/guc-file.l Sat Dec 15 03:45:00 2012
  462. @@ -273,6 +273,7 @@
  463. if (context == PGC_SIGHUP)
  464. {
  465. InitializeGUCOptionsFromEnvironment();
  466. + pg_timezone_initialize();
  467. pg_timezone_abbrev_initialize();
  468. /* this selects SQL_ASCII in processes not connected to a database */
  469. SetConfigOption("client_encoding", GetDatabaseEncodingName(),
  470. diff -u -r -b -B postgresql-9.2.1a/src/backend/utils/misc/guc.c postgresql-9.2.1/src/backend/utils/misc/guc.c
  471. --- postgresql-9.2.1a/src/backend/utils/misc/guc.c Wed Sep 19 17:47:58 2012
  472. +++ postgresql-9.2.1/src/backend/utils/misc/guc.c Sat Dec 15 15:07:29 2012
  473. @@ -187,7 +187,6 @@
  474. static bool check_canonical_path(char **newval, void **extra, GucSource source);
  475. static bool check_timezone_abbreviations(char **newval, void **extra, GucSource source);
  476. static void assign_timezone_abbreviations(const char *newval, void *extra);
  477. -static void pg_timezone_abbrev_initialize(void);
  478. static const char *show_archive_command(void);
  479. static void assign_tcp_keepalives_idle(int newval, void *extra);
  480. static void assign_tcp_keepalives_interval(int newval, void *extra);
  481. @@ -2567,7 +2566,7 @@
  482. NULL
  483. },
  484. &log_timezone_string,
  485. - "GMT",
  486. + NULL,
  487. check_log_timezone, assign_log_timezone, show_log_timezone
  488. },
  489.  
  490. @@ -2858,7 +2857,7 @@
  491. GUC_REPORT
  492. },
  493. &timezone_string,
  494. - "GMT",
  495. + NULL,
  496. check_timezone, assign_timezone, show_timezone
  497. },
  498. {
  499. @@ -3841,7 +3840,7 @@
  500. * Before log_line_prefix could possibly receive a nonempty setting, make
  501. * sure that timezone processing is minimally alive (see elog.c).
  502. */
  503. - pg_timezone_initialize();
  504. + pg_timezone_pre_initialize();
  505.  
  506. /*
  507. * Build sorted array of all GUC variables.
  508. @@ -4142,15 +4141,6 @@
  509. SetConfigOption("data_directory", DataDir, PGC_POSTMASTER, PGC_S_OVERRIDE);
  510.  
  511. /*
  512. - * If timezone_abbreviations wasn't set in the configuration file, install
  513. - * the default value. We do it this way because we can't safely install a
  514. - * "real" value until my_exec_path is set, which may not have happened
  515. - * when InitializeGUCOptions runs, so the bootstrap default value cannot
  516. - * be the real desired default.
  517. - */
  518. - pg_timezone_abbrev_initialize();
  519. -
  520. - /*
  521. * Figure out where pg_hba.conf is, and make sure the path is absolute.
  522. */
  523. if (HbaFileName)
  524. @@ -8521,11 +8511,8 @@
  525. * This is called after initial loading of postgresql.conf. If no
  526. * timezone_abbreviations setting was found therein, select default.
  527. * If a non-default value is already installed, nothing will happen.
  528. - *
  529. - * This can also be called from ProcessConfigFile to establish the default
  530. - * value after a postgresql.conf entry for it is removed.
  531. */
  532. -static void
  533. +void
  534. pg_timezone_abbrev_initialize(void)
  535. {
  536. SetConfigOption("timezone_abbreviations", "Default",
  537. diff -u -r -b -B postgresql-9.2.1a/src/backend/utils/misc/postgresql.conf.sample postgresql-9.2.1/src/backend/utils/misc/postgresql.conf.sample
  538. --- postgresql-9.2.1a/src/backend/utils/misc/postgresql.conf.sample Wed Sep 19 17:47:58 2012
  539. +++ postgresql-9.2.1/src/backend/utils/misc/postgresql.conf.sample Sat Dec 15 03:45:00 2012
  540. @@ -414,7 +414,7 @@
  541. #log_temp_files = -1 # log temporary files equal or larger
  542. # than the specified size in kilobytes;
  543. # -1 disables, 0 logs all temp files
  544. -#log_timezone = 'GMT'
  545. +#log_timezone = '(defaults to server environment setting)'
  546.  
  547.  
  548. #------------------------------------------------------------------------------
  549. @@ -495,7 +495,7 @@
  550.  
  551. #datestyle = 'iso, mdy'
  552. #intervalstyle = 'postgres'
  553. -#timezone = 'GMT'
  554. +#timezone = '(defaults to server environment setting)'
  555. #timezone_abbreviations = 'Default' # Select the set of available time zone
  556. # abbreviations. Currently, there are
  557. # Default
  558. diff -u -r -b -B postgresql-9.2.1a/src/bin/initdb/.gitignore postgresql-9.2.1/src/bin/initdb/.gitignore
  559. --- postgresql-9.2.1a/src/bin/initdb/.gitignore Wed Sep 19 17:47:58 2012
  560. +++ postgresql-9.2.1/src/bin/initdb/.gitignore Sat Dec 15 03:45:01 2012
  561. @@ -1,5 +1,4 @@
  562. /encnames.c
  563. /pqsignal.c
  564. -/localtime.c
  565.  
  566. /initdb
  567. diff -u -r -b -B postgresql-9.2.1a/src/bin/initdb/Makefile postgresql-9.2.1/src/bin/initdb/Makefile
  568. --- postgresql-9.2.1a/src/bin/initdb/Makefile Wed Sep 19 17:47:58 2012
  569. +++ postgresql-9.2.1/src/bin/initdb/Makefile Sat Dec 15 15:09:42 2012
  570. @@ -16,14 +16,14 @@
  571. top_builddir = ../../..
  572. include $(top_builddir)/src/Makefile.global
  573.  
  574. -override CPPFLAGS := -DFRONTEND -I$(libpq_srcdir) -I$(top_srcdir)/src/timezone $(CPPFLAGS)
  575. +override CPPFLAGS := -DFRONTEND -I$(libpq_srcdir) $(CPPFLAGS)
  576.  
  577. # use system timezone data?
  578. ifneq (,$(with_system_tzdata))
  579. override CPPFLAGS += '-DSYSTEMTZDIR="$(with_system_tzdata)"'
  580. endif
  581.  
  582. -OBJS= initdb.o findtimezone.o localtime.o encnames.o pqsignal.o $(WIN32RES)
  583. +OBJS= initdb.o encnames.o pqsignal.o $(WIN32RES)
  584.  
  585. all: initdb
  586.  
  587. @@ -40,11 +40,6 @@
  588. pqsignal.c: % : $(top_srcdir)/src/interfaces/libpq/%
  589. rm -f $@ && $(LN_S) $< .
  590.  
  591. -# Likewise, pull in localtime.c from src/timezones
  592. -
  593. -localtime.c: % : $(top_srcdir)/src/timezone/%
  594. - rm -f $@ && $(LN_S) $< .
  595. -
  596. install: all installdirs
  597. $(INSTALL_PROGRAM) initdb$(X) '$(DESTDIR)$(bindir)/initdb$(X)'
  598.  
  599. @@ -55,7 +50,7 @@
  600. rm -f '$(DESTDIR)$(bindir)/initdb$(X)'
  601.  
  602. clean distclean maintainer-clean:
  603. - rm -f initdb$(X) $(OBJS) encnames.c pqsignal.c localtime.c
  604. + rm -f initdb$(X) $(OBJS) encnames.c pqsignal.c
  605.  
  606.  
  607. # ensure that changes in datadir propagate into object file
  608. Only in postgresql-9.2.1a/src/bin/initdb: findtimezone.c
  609. diff -u -r -b -B postgresql-9.2.1a/src/bin/initdb/initdb.c postgresql-9.2.1/src/bin/initdb/initdb.c
  610. --- postgresql-9.2.1a/src/bin/initdb/initdb.c Wed Sep 19 17:47:58 2012
  611. +++ postgresql-9.2.1/src/bin/initdb/initdb.c Sat Dec 15 15:16:01 2012
  612. @@ -61,9 +61,6 @@
  613. #include "getopt_long.h"
  614. #include "miscadmin.h"
  615.  
  616. -/* Ideally this would be in a .h file, but it hardly seems worth the trouble */
  617. -extern const char *select_default_timezone(const char *share_path);
  618. -
  619. static const char *auth_methods_host[] = {"trust", "reject", "md5", "password", "ident", "radius",
  620. #ifdef ENABLE_GSS
  621. "gss",
  622. @@ -979,9 +976,8 @@
  623. setup_config(void)
  624. {
  625. char **conflines;
  626. - char repltok[TZ_STRLEN_MAX + 100];
  627. + char repltok[100];
  628. char path[MAXPGPATH];
  629. - const char *default_timezone;
  630.  
  631. fputs(_("creating configuration files ... "), stdout);
  632. fflush(stdout);
  633. @@ -1044,17 +1040,6 @@
  634. "#default_text_search_config = 'pg_catalog.simple'",
  635. repltok);
  636.  
  637. - default_timezone = select_default_timezone(share_path);
  638. - if (default_timezone)
  639. - {
  640. - snprintf(repltok, sizeof(repltok), "timezone = '%s'",
  641. - escape_quotes(default_timezone));
  642. - conflines = replace_token(conflines, "#timezone = 'GMT'", repltok);
  643. - snprintf(repltok, sizeof(repltok), "log_timezone = '%s'",
  644. - escape_quotes(default_timezone));
  645. - conflines = replace_token(conflines, "#log_timezone = 'GMT'", repltok);
  646. - }
  647. -
  648. snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data);
  649.  
  650. writefile(path, conflines);
  651. @@ -2877,6 +2862,16 @@
  652. sprintf(pgdenv, "PGDATA=%s", pg_data);
  653. putenv(pgdenv);
  654.  
  655. + /*
  656. + * Also ensure that TZ is set, so that we don't waste time identifying the
  657. + * system timezone each of the many times we start a standalone backend.
  658. + * It's okay to use a hard-wired value here because nothing done during
  659. + * initdb cares about the timezone setting.
  660. + */
  661. + putenv("TZ=GMT");
  662. +
  663.  
  664. +
  665. +
  666. if ((ret = find_other_exec(argv[0], "postgres", PG_BACKEND_VERSIONSTR,
  667. backend_exec)) < 0)
  668. {
  669. diff -u -r -b -B postgresql-9.2.1a/src/include/pgtime.h postgresql-9.2.1/src/include/pgtime.h
  670. --- postgresql-9.2.1a/src/include/pgtime.h Wed Sep 19 17:47:58 2012
  671. +++ postgresql-9.2.1/src/include/pgtime.h Sat Dec 15 03:45:28 2012
  672. @@ -40,11 +40,6 @@
  673. typedef struct pg_tz pg_tz;
  674. typedef struct pg_tzenum pg_tzenum;
  675.  
  676. -/* Maximum length of a timezone name (not including trailing null) */
  677. -#define TZ_STRLEN_MAX 255
  678. -
  679. -/* these functions are in localtime.c */
  680. -
  681. extern struct pg_tm *pg_localtime(const pg_time_t *timep, const pg_tz *tz);
  682. extern struct pg_tm *pg_gmtime(const pg_time_t *timep);
  683. extern int pg_next_dst_boundary(const pg_time_t *timep,
  684. @@ -57,20 +52,22 @@
  685. extern size_t pg_strftime(char *s, size_t max, const char *format,
  686. const struct pg_tm * tm);
  687.  
  688. +extern void pg_timezone_pre_initialize(void);
  689. +extern void pg_timezone_initialize(void);
  690. +extern pg_tz *pg_tzset(const char *tzname);
  691. +extern bool tz_acceptable(pg_tz *tz);
  692. extern bool pg_get_timezone_offset(const pg_tz *tz, long int *gmtoff);
  693. extern const char *pg_get_timezone_name(pg_tz *tz);
  694. -extern bool pg_tz_acceptable(pg_tz *tz);
  695.  
  696. -/* these functions and variables are in pgtz.c */
  697. +extern pg_tzenum *pg_tzenumerate_start(void);
  698. +extern pg_tz *pg_tzenumerate_next(pg_tzenum *dir);
  699. +extern void pg_tzenumerate_end(pg_tzenum *dir);
  700.  
  701. extern pg_tz *session_timezone;
  702. extern pg_tz *log_timezone;
  703. +extern pg_tz *gmt_timezone;
  704.  
  705. -extern void pg_timezone_initialize(void);
  706. -extern pg_tz *pg_tzset(const char *tzname);
  707. -
  708. -extern pg_tzenum *pg_tzenumerate_start(void);
  709. -extern pg_tz *pg_tzenumerate_next(pg_tzenum *dir);
  710. -extern void pg_tzenumerate_end(pg_tzenum *dir);
  711. +/* Maximum length of a timezone name (not including trailing null) */
  712. +#define TZ_STRLEN_MAX 255
  713.  
  714. #endif /* _PGTIME_H */
  715. diff -u -r -b -B postgresql-9.2.1a/src/include/utils/guc.h postgresql-9.2.1/src/include/utils/guc.h
  716. --- postgresql-9.2.1a/src/include/utils/guc.h Wed Sep 19 17:47:58 2012
  717. +++ postgresql-9.2.1/src/include/utils/guc.h Sat Dec 15 03:45:28 2012
  718. @@ -333,6 +333,8 @@
  719. extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name);
  720. extern ArrayType *GUCArrayReset(ArrayType *array);
  721.  
  722. +extern void pg_timezone_abbrev_initialize(void);
  723. +
  724. #ifdef EXEC_BACKEND
  725. extern void write_nondefault_variables(GucContext context);
  726. extern void read_nondefault_variables(void);
  727. diff -u -r -b -B postgresql-9.2.1a/src/timezone/localtime.c postgresql-9.2.1/src/timezone/localtime.c
  728. --- postgresql-9.2.1a/src/timezone/localtime.c Wed Sep 19 17:47:58 2012
  729. +++ postgresql-9.2.1/src/timezone/localtime.c Sat Dec 15 03:45:28 2012
  730. @@ -16,7 +16,6 @@
  731.  
  732. #include <fcntl.h>
  733.  
  734. -#include "datatype/timestamp.h"
  735. #include "private.h"
  736. #include "pgtz.h"
  737. #include "tzfile.h"
  738. @@ -735,7 +734,6 @@
  739. * can't assume pg_open_tzfile() is sane yet, and we don't care about
  740. * leap seconds anyway.
  741. */
  742. - sp->goback = sp->goahead = FALSE;
  743. load_result = -1;
  744. }
  745. else
  746. @@ -1479,29 +1477,3 @@
  747. return tz->TZname;
  748. return NULL;
  749. }
  750. -
  751. -/*
  752. - * Check whether timezone is acceptable.
  753. - *
  754. - * What we are doing here is checking for leap-second-aware timekeeping.
  755. - * We need to reject such TZ settings because they'll wreak havoc with our
  756. - * date/time arithmetic.
  757. - */
  758. -bool
  759. -pg_tz_acceptable(pg_tz *tz)
  760. -{
  761. - struct pg_tm *tt;
  762. - pg_time_t time2000;
  763. -
  764. - /*
  765. - * To detect leap-second timekeeping, run pg_localtime for what should be
  766. - * GMT midnight, 2000-01-01. Insist that the tm_sec value be zero; any
  767. - * other result has to be due to leap seconds.
  768. - */
  769. - time2000 = (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY;
  770. - tt = pg_localtime(&time2000, tz);
  771. - if (!tt || tt->tm_sec != 0)
  772. - return false;
  773. -
  774. - return true;
  775. -}
  776. diff -u -r -b -B postgresql-9.2.1a/src/timezone/pgtz.c postgresql-9.2.1/src/timezone/pgtz.c
  777. --- postgresql-9.2.1a/src/timezone/pgtz.c Wed Sep 19 17:47:58 2012
  778. +++ postgresql-9.2.1/src/timezone/pgtz.c Sat Dec 15 04:16:13 2012
  779. @@ -10,6 +10,8 @@
  780. *
  781. *-------------------------------------------------------------------------
  782. */
  783. +#define NO_REDEFINE_TIMEFUNCS
  784. +
  785. #include "postgres.h"
  786.  
  787. #include <ctype.h>
  788. @@ -20,9 +22,11 @@
  789. #include "miscadmin.h"
  790. #include "pgtz.h"
  791. #include "storage/fd.h"
  792. +#include "tzfile.h"
  793. +#include "utils/datetime.h"
  794. +#include "utils/guc.h"
  795. #include "utils/hsearch.h"
  796.  
  797. -
  798. /* Current session timezone (controlled by TimeZone GUC) */
  799. pg_tz *session_timezone = NULL;
  800.  
  801. @@ -29,10 +33,17 @@
  802. /* Current log timezone (controlled by log_timezone GUC) */
  803. pg_tz *log_timezone = NULL;
  804.  
  805. +/* Fallback GMT timezone for last-ditch error message formatting */
  806. +pg_tz *gmt_timezone = NULL;
  807. +static pg_tz gmt_timezone_data;
  808. +
  809.  
  810. static bool scan_directory_ci(const char *dirname,
  811. const char *fname, int fnamelen,
  812. char *canonname, int canonnamelen);
  813. +static const char *identify_system_timezone(void);
  814. +static pg_tz *get_pg_tz_for_zone(const char *tzname);
  815. +static pg_tz *select_default_timezone(void);
  816.  
  817.  
  818. /*
  819. @@ -69,7 +80,7 @@
  820. * timezone database does not contain case-equivalent names).
  821. *
  822. * If "canonname" is not NULL, then on success the canonical spelling of the
  823. - * given name is stored there (the buffer must be > TZ_STRLEN_MAX bytes!).
  824. + * given name is stored there (it is assumed to be > TZ_STRLEN_MAX bytes!).
  825. */
  826. int
  827. pg_open_tzfile(const char *name, char *canonname)
  828. @@ -165,6 +176,1054 @@
  829.  
  830.  
  831. /*
  832. + * The following block of code attempts to determine which timezone in our
  833. + * timezone database is the best match for the active system timezone.
  834. + *
  835. + * On most systems, we rely on trying to match the observable behavior of
  836. + * the C library's localtime() function. The database zone that matches
  837. + * furthest into the past is the one to use. Often there will be several
  838. + * zones with identical rankings (since the zic database assigns multiple
  839. + * names to many zones). We break ties arbitrarily by preferring shorter,
  840. + * then alphabetically earlier zone names.
  841. + *
  842. + * Win32's native knowledge about timezones appears to be too incomplete
  843. + * and too different from the zic database for the above matching strategy
  844. + * to be of any use. But there is just a limited number of timezones
  845. + * available, so we can rely on a handmade mapping table instead.
  846. + */
  847. +
  848. +#ifndef WIN32
  849. +
  850. +#define T_DAY ((time_t) (60*60*24))
  851. +#define T_WEEK ((time_t) (60*60*24*7))
  852. +#define T_MONTH ((time_t) (60*60*24*31))
  853. +
  854. +#define MAX_TEST_TIMES (52*100) /* 100 years */
  855. +
  856. +struct tztry
  857. +{
  858. + int n_test_times;
  859. + time_t test_times[MAX_TEST_TIMES];
  860. +};
  861. +
  862. +static void scan_available_timezones(char *tzdir, char *tzdirsub,
  863. + struct tztry * tt,
  864. + int *bestscore, char *bestzonename);
  865. +
  866. +
  867. +/*
  868. + * Get GMT offset from a system struct tm
  869. + */
  870. +static int
  871. +get_timezone_offset(struct tm * tm)
  872. +{
  873. +#if defined(HAVE_STRUCT_TM_TM_ZONE)
  874. + return tm->tm_gmtoff;
  875. +#elif defined(HAVE_INT_TIMEZONE)
  876. + return -TIMEZONE_GLOBAL;
  877. +#else
  878. +#error No way to determine TZ? Can this happen?
  879. +#endif
  880. +}
  881. +
  882. +/*
  883. + * Convenience subroutine to convert y/m/d to time_t (NOT pg_time_t)
  884. + */
  885. +static time_t
  886. +build_time_t(int year, int month, int day)
  887. +{
  888. + struct tm tm;
  889. +
  890. + memset(&tm, 0, sizeof(tm));
  891. + tm.tm_mday = day;
  892. + tm.tm_mon = month - 1;
  893. + tm.tm_year = year - 1900;
  894. +
  895. + return mktime(&tm);
  896. +}
  897. +
  898. +/*
  899. + * Does a system tm value match one we computed ourselves?
  900. + */
  901. +static bool
  902. +compare_tm(struct tm * s, struct pg_tm * p)
  903. +{
  904. + if (s->tm_sec != p->tm_sec ||
  905. + s->tm_min != p->tm_min ||
  906. + s->tm_hour != p->tm_hour ||
  907. + s->tm_mday != p->tm_mday ||
  908. + s->tm_mon != p->tm_mon ||
  909. + s->tm_year != p->tm_year ||
  910. + s->tm_wday != p->tm_wday ||
  911. + s->tm_yday != p->tm_yday ||
  912. + s->tm_isdst != p->tm_isdst)
  913. + return false;
  914. + return true;
  915. +}
  916. +
  917. +/*
  918. + * See how well a specific timezone setting matches the system behavior
  919. + *
  920. + * We score a timezone setting according to the number of test times it
  921. + * matches. (The test times are ordered later-to-earlier, but this routine
  922. + * doesn't actually know that; it just scans until the first non-match.)
  923. + *
  924. + * We return -1 for a completely unusable setting; this is worse than the
  925. + * score of zero for a setting that works but matches not even the first
  926. + * test time.
  927. + */
  928. +static int
  929. +score_timezone(const char *tzname, struct tztry * tt)
  930. +{
  931. + int i;
  932. + pg_time_t pgtt;
  933. + struct tm *systm;
  934. + struct pg_tm *pgtm;
  935. + char cbuf[TZ_STRLEN_MAX + 1];
  936. + pg_tz tz;
  937. +
  938. +
  939. + /*
  940. + * Load timezone directly. Don't use pg_tzset, because we don't want all
  941. + * timezones loaded in the cache at startup.
  942. + */
  943. + if (tzload(tzname, NULL, &tz.state, TRUE) != 0)
  944. + {
  945. + if (tzname[0] == ':' || tzparse(tzname, &tz.state, FALSE) != 0)
  946. + {
  947. + return -1; /* can't handle the TZ name at all */
  948. + }
  949. + }
  950. +
  951. + /* Reject if leap seconds involved */
  952. + if (!tz_acceptable(&tz))
  953. + {
  954. + elog(DEBUG4, "Reject TZ \"%s\": uses leap seconds", tzname);
  955. + return -1;
  956. + }
  957. +
  958. + /* Check for match at all the test times */
  959. + for (i = 0; i < tt->n_test_times; i++)
  960. + {
  961. + pgtt = (pg_time_t) (tt->test_times[i]);
  962. + pgtm = pg_localtime(&pgtt, &tz);
  963. + if (!pgtm)
  964. + return -1; /* probably shouldn't happen */
  965. + systm = localtime(&(tt->test_times[i]));
  966. + if (!systm)
  967. + {
  968. + elog(DEBUG4, "TZ \"%s\" scores %d: at %ld %04d-%02d-%02d %02d:%02d:%02d %s, system had no data",
  969. + tzname, i, (long) pgtt,
  970. + pgtm->tm_year + 1900, pgtm->tm_mon + 1, pgtm->tm_mday,
  971. + pgtm->tm_hour, pgtm->tm_min, pgtm->tm_sec,
  972. + pgtm->tm_isdst ? "dst" : "std");
  973. + return i;
  974. + }
  975. + if (!compare_tm(systm, pgtm))
  976. + {
  977. + elog(DEBUG4, "TZ \"%s\" scores %d: at %ld %04d-%02d-%02d %02d:%02d:%02d %s versus %04d-%02d-%02d %02d:%02d:%02d %s",
  978. + tzname, i, (long) pgtt,
  979. + pgtm->tm_year + 1900, pgtm->tm_mon + 1, pgtm->tm_mday,
  980. + pgtm->tm_hour, pgtm->tm_min, pgtm->tm_sec,
  981. + pgtm->tm_isdst ? "dst" : "std",
  982. + systm->tm_year + 1900, systm->tm_mon + 1, systm->tm_mday,
  983. + systm->tm_hour, systm->tm_min, systm->tm_sec,
  984. + systm->tm_isdst ? "dst" : "std");
  985. + return i;
  986. + }
  987. + if (systm->tm_isdst >= 0)
  988. + {
  989. + /* Check match of zone names, too */
  990. + if (pgtm->tm_zone == NULL)
  991. + return -1; /* probably shouldn't happen */
  992. + memset(cbuf, 0, sizeof(cbuf));
  993. + strftime(cbuf, sizeof(cbuf) - 1, "%Z", systm); /* zone abbr */
  994. + if (strcmp(cbuf, pgtm->tm_zone) != 0)
  995. + {
  996. + elog(DEBUG4, "TZ \"%s\" scores %d: at %ld \"%s\" versus \"%s\"",
  997. + tzname, i, (long) pgtt,
  998. + pgtm->tm_zone, cbuf);
  999. + return i;
  1000. + }
  1001. + }
  1002. + }
  1003. +
  1004. + elog(DEBUG4, "TZ \"%s\" gets max score %d", tzname, i);
  1005. + return i;
  1006. +}
  1007. +
  1008. +
  1009. +/*
  1010. + * Try to identify a timezone name (in our terminology) that best matches the
  1011. + * observed behavior of the system timezone library. We cannot assume that
  1012. + * the system TZ environment setting (if indeed there is one) matches our
  1013. + * terminology, so we ignore it and just look at what localtime() returns.
  1014. + */
  1015. +static const char *
  1016. +identify_system_timezone(void)
  1017. +{
  1018. + static char resultbuf[TZ_STRLEN_MAX + 1];
  1019. + time_t tnow;
  1020. + time_t t;
  1021. + struct tztry tt;
  1022. + struct tm *tm;
  1023. + int thisyear;
  1024. + int bestscore;
  1025. + char tmptzdir[MAXPGPATH];
  1026. + int std_ofs;
  1027. + char std_zone_name[TZ_STRLEN_MAX + 1],
  1028. + dst_zone_name[TZ_STRLEN_MAX + 1];
  1029. + char cbuf[TZ_STRLEN_MAX + 1];
  1030. +
  1031. + /* Initialize OS timezone library */
  1032. + tzset();
  1033. +
  1034. + /*
  1035. + * Set up the list of dates to be probed to see how well our timezone
  1036. + * matches the system zone. We first probe January and July of the
  1037. + * current year; this serves to quickly eliminate the vast majority of the
  1038. + * TZ database entries. If those dates match, we probe every week for 100
  1039. + * years backwards from the current July. (Weekly resolution is good
  1040. + * enough to identify DST transition rules, since everybody switches on
  1041. + * Sundays.) This is sufficient to cover most of the Unix time_t range,
  1042. + * and we don't want to look further than that since many systems won't
  1043. + * have sane TZ behavior further back anyway. The further back the zone
  1044. + * matches, the better we score it. This may seem like a rather random
  1045. + * way of doing things, but experience has shown that system-supplied
  1046. + * timezone definitions are likely to have DST behavior that is right for
  1047. + * the recent past and not so accurate further back. Scoring in this way
  1048. + * allows us to recognize zones that have some commonality with the zic
  1049. + * database, without insisting on exact match. (Note: we probe Thursdays,
  1050. + * not Sundays, to avoid triggering DST-transition bugs in localtime
  1051. + * itself.)
  1052. + */
  1053. + tnow = time(NULL);
  1054. + tm = localtime(&tnow);
  1055. + if (!tm)
  1056. + return NULL; /* give up if localtime is broken... */
  1057. + thisyear = tm->tm_year + 1900;
  1058. +
  1059. + t = build_time_t(thisyear, 1, 15);
  1060. +
  1061. + /*
  1062. + * Round back to GMT midnight Thursday. This depends on the knowledge
  1063. + * that the time_t origin is Thu Jan 01 1970. (With a different origin
  1064. + * we'd be probing some other day of the week, but it wouldn't matter
  1065. + * anyway unless localtime() had DST-transition bugs.)
  1066. + */
  1067. + t -= (t % T_WEEK);
  1068. +
  1069. + tt.n_test_times = 0;
  1070. + tt.test_times[tt.n_test_times++] = t;
  1071. +
  1072. + t = build_time_t(thisyear, 7, 15);
  1073. + t -= (t % T_WEEK);
  1074. +
  1075. + tt.test_times[tt.n_test_times++] = t;
  1076. +
  1077. + while (tt.n_test_times < MAX_TEST_TIMES)
  1078. + {
  1079. + t -= T_WEEK;
  1080. + tt.test_times[tt.n_test_times++] = t;
  1081. + }
  1082. +
  1083. + /* Search for the best-matching timezone file */
  1084. + strcpy(tmptzdir, pg_TZDIR());
  1085. + bestscore = -1;
  1086. + resultbuf[0] = '\0';
  1087. + scan_available_timezones(tmptzdir, tmptzdir + strlen(tmptzdir) + 1,
  1088. + &tt,
  1089. + &bestscore, resultbuf);
  1090. + if (bestscore > 0)
  1091. + {
  1092. + /* Ignore zic's rather silly "Factory" time zone; use GMT instead */
  1093. + if (strcmp(resultbuf, "Factory") == 0)
  1094. + return NULL;
  1095. + return resultbuf;
  1096.  
  1097. + }
  1098. +
  1099. + /*
  1100. + * Couldn't find a match in the database, so next we try constructed zone
  1101. + * names (like "PST8PDT").
  1102. + *
  1103. + * First we need to determine the names of the local standard and daylight
  1104. + * zones. The idea here is to scan forward from today until we have seen
  1105. + * both zones, if both are in use.
  1106. + */
  1107. + memset(std_zone_name, 0, sizeof(std_zone_name));
  1108. + memset(dst_zone_name, 0, sizeof(dst_zone_name));
  1109. + std_ofs = 0;
  1110. +
  1111. + tnow = time(NULL);
  1112. +
  1113. + /*
  1114. + * Round back to a GMT midnight so results don't depend on local time of
  1115. + * day
  1116. + */
  1117. + tnow -= (tnow % T_DAY);
  1118. +
  1119. + /*
  1120. + * We have to look a little further ahead than one year, in case today is
  1121. + * just past a DST boundary that falls earlier in the year than the next
  1122. + * similar boundary. Arbitrarily scan up to 14 months.
  1123. + */
  1124. + for (t = tnow; t <= tnow + T_MONTH * 14; t += T_MONTH)
  1125. + {
  1126. + tm = localtime(&t);
  1127. + if (!tm)
  1128. + continue;
  1129. + if (tm->tm_isdst < 0)
  1130. + continue;
  1131. + if (tm->tm_isdst == 0 && std_zone_name[0] == '\0')
  1132. + {
  1133. + /* found STD zone */
  1134. + memset(cbuf, 0, sizeof(cbuf));
  1135. + strftime(cbuf, sizeof(cbuf) - 1, "%Z", tm); /* zone abbr */
  1136. + strcpy(std_zone_name, cbuf);
  1137. + std_ofs = get_timezone_offset(tm);
  1138. + }
  1139. + if (tm->tm_isdst > 0 && dst_zone_name[0] == '\0')
  1140. + {
  1141. + /* found DST zone */
  1142. + memset(cbuf, 0, sizeof(cbuf));
  1143. + strftime(cbuf, sizeof(cbuf) - 1, "%Z", tm); /* zone abbr */
  1144. + strcpy(dst_zone_name, cbuf);
  1145. + }
  1146. + /* Done if found both */
  1147. + if (std_zone_name[0] && dst_zone_name[0])
  1148. + break;
  1149. + }
  1150. +
  1151. + /* We should have found a STD zone name by now... */
  1152. + if (std_zone_name[0] == '\0')
  1153. + {
  1154. + ereport(LOG,
  1155. + (errmsg("could not determine system time zone"),
  1156. + errdetail("The PostgreSQL time zone will be set to \"%s\".",
  1157. + "GMT"),
  1158. + errhint("You can specify the correct timezone in postgresql.conf.")));
  1159. + return NULL; /* go to GMT */
  1160. + }
  1161. +
  1162. + /* If we found DST then try STD<ofs>DST */
  1163. + if (dst_zone_name[0] != '\0')
  1164. + {
  1165. + snprintf(resultbuf, sizeof(resultbuf), "%s%d%s",
  1166. + std_zone_name, -std_ofs / 3600, dst_zone_name);
  1167. + if (score_timezone(resultbuf, &tt) > 0)
  1168. + return resultbuf;
  1169. + }
  1170. +
  1171. + /* Try just the STD timezone (works for GMT at least) */
  1172. + strcpy(resultbuf, std_zone_name);
  1173. + if (score_timezone(resultbuf, &tt) > 0)
  1174. + return resultbuf;
  1175. +
  1176. + /* Try STD<ofs> */
  1177. + snprintf(resultbuf, sizeof(resultbuf), "%s%d",
  1178. + std_zone_name, -std_ofs / 3600);
  1179. + if (score_timezone(resultbuf, &tt) > 0)
  1180. + return resultbuf;
  1181. +
  1182. + /*
  1183. + * Did not find the timezone. Fallback to use a GMT zone. Note that the
  1184. + * zic timezone database names the GMT-offset zones in POSIX style: plus
  1185. + * is west of Greenwich. It's unfortunate that this is opposite of SQL
  1186. + * conventions. Should we therefore change the names? Probably not...
  1187. + */
  1188. + snprintf(resultbuf, sizeof(resultbuf), "Etc/GMT%s%d",
  1189. + (-std_ofs > 0) ? "+" : "", -std_ofs / 3600);
  1190. +
  1191. + ereport(LOG,
  1192. + (errmsg("could not recognize system time zone"),
  1193. + errdetail("The PostgreSQL time zone will be set to \"%s\".",
  1194. + resultbuf),
  1195. + errhint("You can specify the correct timezone in postgresql.conf.")));
  1196. + return resultbuf;
  1197. +}
  1198. +
  1199. +/*
  1200. + * Recursively scan the timezone database looking for the best match to
  1201. + * the system timezone behavior.
  1202. + *
  1203. + * tzdir points to a buffer of size MAXPGPATH. On entry, it holds the
  1204. + * pathname of a directory containing TZ files. We internally modify it
  1205. + * to hold pathnames of sub-directories and files, but must restore it
  1206. + * to its original contents before exit.
  1207. + *
  1208. + * tzdirsub points to the part of tzdir that represents the subfile name
  1209. + * (ie, tzdir + the original directory name length, plus one for the
  1210. + * first added '/').
  1211. + *
  1212. + * tt tells about the system timezone behavior we need to match.
  1213. + *
  1214. + * *bestscore and *bestzonename on entry hold the best score found so far
  1215. + * and the name of the best zone. We overwrite them if we find a better
  1216. + * score. bestzonename must be a buffer of length TZ_STRLEN_MAX + 1.
  1217. + */
  1218. +static void
  1219. +scan_available_timezones(char *tzdir, char *tzdirsub, struct tztry * tt,
  1220. + int *bestscore, char *bestzonename)
  1221. +{
  1222. + int tzdir_orig_len = strlen(tzdir);
  1223. + DIR *dirdesc;
  1224. + struct dirent *direntry;
  1225. +
  1226. + dirdesc = AllocateDir(tzdir);
  1227. + if (!dirdesc)
  1228. + {
  1229. + ereport(LOG,
  1230. + (errcode_for_file_access(),
  1231. + errmsg("could not open directory \"%s\": %m", tzdir)));
  1232. + return;
  1233. + }
  1234. +
  1235. + while ((direntry = ReadDir(dirdesc, tzdir)) != NULL)
  1236. + {
  1237. + struct stat statbuf;
  1238. +
  1239. + /* Ignore . and .., plus any other "hidden" files */
  1240. + if (direntry->d_name[0] == '.')
  1241. + continue;
  1242. +
  1243. + snprintf(tzdir + tzdir_orig_len, MAXPGPATH - tzdir_orig_len,
  1244. + "/%s", direntry->d_name);
  1245. +
  1246. + if (stat(tzdir, &statbuf) != 0)
  1247. + {
  1248. + ereport(LOG,
  1249. + (errcode_for_file_access(),
  1250. + errmsg("could not stat \"%s\": %m", tzdir)));
  1251. + tzdir[tzdir_orig_len] = '\0';
  1252. + continue;
  1253. + }
  1254. +
  1255. + if (S_ISDIR(statbuf.st_mode))
  1256. + {
  1257. + /* Recurse into subdirectory */
  1258. + scan_available_timezones(tzdir, tzdirsub, tt,
  1259. + bestscore, bestzonename);
  1260. + }
  1261. + else
  1262. + {
  1263. + /* Load and test this file */
  1264. + int score = score_timezone(tzdirsub, tt);
  1265. +
  1266. + if (score > *bestscore)
  1267. + {
  1268. + *bestscore = score;
  1269. + strlcpy(bestzonename, tzdirsub, TZ_STRLEN_MAX + 1);
  1270. + }
  1271. + else if (score == *bestscore)
  1272. + {
  1273. + /* Consider how to break a tie */
  1274. + if (strlen(tzdirsub) < strlen(bestzonename) ||
  1275. + (strlen(tzdirsub) == strlen(bestzonename) &&
  1276. + strcmp(tzdirsub, bestzonename) < 0))
  1277. + strlcpy(bestzonename, tzdirsub, TZ_STRLEN_MAX + 1);
  1278. + }
  1279. + }
  1280. +
  1281. + /* Restore tzdir */
  1282. + tzdir[tzdir_orig_len] = '\0';
  1283. + }
  1284. +
  1285. + FreeDir(dirdesc);
  1286. +}
  1287. +#else /* WIN32 */
  1288. +
  1289. +static const struct
  1290. +{
  1291. + const char *stdname; /* Windows name of standard timezone */
  1292. + const char *dstname; /* Windows name of daylight timezone */
  1293. + const char *pgtzname; /* Name of pgsql timezone to map to */
  1294. +} win32_tzmap[] =
  1295. +
  1296. +{
  1297. + /*
  1298. + * This list was built from the contents of the registry at
  1299. + * HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time
  1300. + * Zones on Windows 2003 R2.
  1301. + *
  1302. + * The zones have been matched to zic timezones by looking at the cities
  1303. + * listed in the win32 display name (in the comment here) in most cases.
  1304. + */
  1305. + {
  1306. + "Afghanistan Standard Time", "Afghanistan Daylight Time",
  1307. + "Asia/Kabul"
  1308. + }, /* (GMT+04:30) Kabul */
  1309. + {
  1310. + "Alaskan Standard Time", "Alaskan Daylight Time",
  1311. + "US/Alaska"
  1312. + }, /* (GMT-09:00) Alaska */
  1313. + {
  1314. + "Arab Standard Time", "Arab Daylight Time",
  1315. + "Asia/Kuwait"
  1316. + }, /* (GMT+03:00) Kuwait, Riyadh */
  1317. + {
  1318. + "Arabian Standard Time", "Arabian Daylight Time",
  1319. + "Asia/Muscat"
  1320. + }, /* (GMT+04:00) Abu Dhabi, Muscat */
  1321. + {
  1322. + "Arabic Standard Time", "Arabic Daylight Time",
  1323. + "Asia/Baghdad"
  1324. + }, /* (GMT+03:00) Baghdad */
  1325. + {
  1326. + "Argentina Standard Time", "Argentina Daylight Time",
  1327. + "America/Buenos_Aires"
  1328. + }, /* (GMT-03:00) Buenos Aires */
  1329. + {
  1330. + "Armenian Standard Time", "Armenian Daylight Time",
  1331. + "Asia/Yerevan"
  1332. + }, /* (GMT+04:00) Yerevan */
  1333. + {
  1334. + "Atlantic Standard Time", "Atlantic Daylight Time",
  1335. + "Canada/Atlantic"
  1336. + }, /* (GMT-04:00) Atlantic Time (Canada) */
  1337. + {
  1338. + "AUS Central Standard Time", "AUS Central Daylight Time",
  1339. + "Australia/Darwin"
  1340. + }, /* (GMT+09:30) Darwin */
  1341. + {
  1342. + "AUS Eastern Standard Time", "AUS Eastern Daylight Time",
  1343. + "Australia/Canberra"
  1344. + }, /* (GMT+10:00) Canberra, Melbourne, Sydney */
  1345. + {
  1346. + "Azerbaijan Standard Time", "Azerbaijan Daylight Time",
  1347. + "Asia/Baku"
  1348. + }, /* (GMT+04:00) Baku */
  1349. + {
  1350. + "Azores Standard Time", "Azores Daylight Time",
  1351. + "Atlantic/Azores"
  1352. + }, /* (GMT-01:00) Azores */
  1353. + {
  1354. + "Bangladesh Standard Time", "Bangladesh Daylight Time",
  1355. + "Asia/Dhaka"
  1356. + }, /* (GMT+06:00) Dhaka */
  1357. + {
  1358. + "Canada Central Standard Time", "Canada Central Daylight Time",
  1359. + "Canada/Saskatchewan"
  1360. + }, /* (GMT-06:00) Saskatchewan */
  1361. + {
  1362. + "Cape Verde Standard Time", "Cape Verde Daylight Time",
  1363. + "Atlantic/Cape_Verde"
  1364. + }, /* (GMT-01:00) Cape Verde Is. */
  1365. + {
  1366. + "Caucasus Standard Time", "Caucasus Daylight Time",
  1367. + "Asia/Baku"
  1368. + }, /* (GMT+04:00) Baku, Tbilisi, Yerevan */
  1369. + {
  1370. + "Cen. Australia Standard Time", "Cen. Australia Daylight Time",
  1371. + "Australia/Adelaide"
  1372. + }, /* (GMT+09:30) Adelaide */
  1373. + {
  1374. + "Central America Standard Time", "Central America Daylight Time",
  1375. + "CST6CDT"
  1376. + }, /* (GMT-06:00) Central America */
  1377. + {
  1378. + "Central Asia Standard Time", "Central Asia Daylight Time",
  1379. + "Asia/Dhaka"
  1380. + }, /* (GMT+06:00) Astana, Dhaka */
  1381. + {
  1382. + "Central Brazilian Standard Time", "Central Brazilian Daylight Time",
  1383. + "America/Cuiaba"
  1384. + }, /* (GMT-04:00) Cuiaba */
  1385. + {
  1386. + "Central Europe Standard Time", "Central Europe Daylight Time",
  1387. + "Europe/Belgrade"
  1388. + }, /* (GMT+01:00) Belgrade, Bratislava, Budapest,
  1389. + * Ljubljana, Prague */
  1390. + {
  1391. + "Central European Standard Time", "Central European Daylight Time",
  1392. + "Europe/Sarajevo"
  1393. + }, /* (GMT+01:00) Sarajevo, Skopje, Warsaw,
  1394. + * Zagreb */
  1395. + {
  1396. + "Central Pacific Standard Time", "Central Pacific Daylight Time",
  1397. + "Pacific/Noumea"
  1398. + }, /* (GMT+11:00) Magadan, Solomon Is., New
  1399. + * Caledonia */
  1400. + {
  1401. + "Central Standard Time", "Central Daylight Time",
  1402. + "US/Central"
  1403. + }, /* (GMT-06:00) Central Time (US & Canada) */
  1404. + {
  1405. + "Central Standard Time (Mexico)", "Central Daylight Time (Mexico)",
  1406. + "America/Mexico_City"
  1407. + }, /* (GMT-06:00) Guadalajara, Mexico City,
  1408. + * Monterrey - New */
  1409. + {
  1410. + "China Standard Time", "China Daylight Time",
  1411. + "Asia/Hong_Kong"
  1412. + }, /* (GMT+08:00) Beijing, Chongqing, Hong Kong,
  1413. + * Urumqi */
  1414. + {
  1415. + "Dateline Standard Time", "Dateline Daylight Time",
  1416. + "Etc/GMT+12"
  1417. + }, /* (GMT-12:00) International Date Line West */
  1418. + {
  1419. + "E. Africa Standard Time", "E. Africa Daylight Time",
  1420. + "Africa/Nairobi"
  1421. + }, /* (GMT+03:00) Nairobi */
  1422. + {
  1423. + "E. Australia Standard Time", "E. Australia Daylight Time",
  1424. + "Australia/Brisbane"
  1425. + }, /* (GMT+10:00) Brisbane */
  1426. + {
  1427. + "E. Europe Standard Time", "E. Europe Daylight Time",
  1428. + "Europe/Bucharest"
  1429. + }, /* (GMT+02:00) Bucharest */
  1430. + {
  1431. + "E. South America Standard Time", "E. South America Daylight Time",
  1432. + "America/Araguaina"
  1433. + }, /* (GMT-03:00) Brasilia */
  1434. + {
  1435. + "Eastern Standard Time", "Eastern Daylight Time",
  1436. + "US/Eastern"
  1437. + }, /* (GMT-05:00) Eastern Time (US & Canada) */
  1438. + {
  1439. + "Egypt Standard Time", "Egypt Daylight Time",
  1440. + "Africa/Cairo"
  1441. + }, /* (GMT+02:00) Cairo */
  1442. + {
  1443. + "Ekaterinburg Standard Time", "Ekaterinburg Daylight Time",
  1444. + "Asia/Yekaterinburg"
  1445. + }, /* (GMT+05:00) Ekaterinburg */
  1446. + {
  1447. + "Fiji Standard Time", "Fiji Daylight Time",
  1448. + "Pacific/Fiji"
  1449. + }, /* (GMT+12:00) Fiji, Kamchatka, Marshall Is. */
  1450. + {
  1451. + "FLE Standard Time", "FLE Daylight Time",
  1452. + "Europe/Helsinki"
  1453. + }, /* (GMT+02:00) Helsinki, Kyiv, Riga, Sofia,
  1454. + * Tallinn, Vilnius */
  1455. + {
  1456. + "Georgian Standard Time", "Georgian Daylight Time",
  1457. + "Asia/Tbilisi"
  1458. + }, /* (GMT+03:00) Tbilisi */
  1459. + {
  1460. + "GMT Standard Time", "GMT Daylight Time",
  1461. + "Europe/London"
  1462. + }, /* (GMT) Greenwich Mean Time : Dublin,
  1463. + * Edinburgh, Lisbon, London */
  1464. + {
  1465. + "Greenland Standard Time", "Greenland Daylight Time",
  1466. + "America/Godthab"
  1467. + }, /* (GMT-03:00) Greenland */
  1468. + {
  1469. + "Greenwich Standard Time", "Greenwich Daylight Time",
  1470. + "Africa/Casablanca"
  1471. + }, /* (GMT) Casablanca, Monrovia */
  1472. + {
  1473. + "GTB Standard Time", "GTB Daylight Time",
  1474. + "Europe/Athens"
  1475. + }, /* (GMT+02:00) Athens, Istanbul, Minsk */
  1476. + {
  1477. + "Hawaiian Standard Time", "Hawaiian Daylight Time",
  1478. + "US/Hawaii"
  1479. + }, /* (GMT-10:00) Hawaii */
  1480. + {
  1481. + "India Standard Time", "India Daylight Time",
  1482. + "Asia/Calcutta"
  1483. + }, /* (GMT+05:30) Chennai, Kolkata, Mumbai, New
  1484. + * Delhi */
  1485. + {
  1486. + "Iran Standard Time", "Iran Daylight Time",
  1487. + "Asia/Tehran"
  1488. + }, /* (GMT+03:30) Tehran */
  1489. + {
  1490. + "Jerusalem Standard Time", "Jerusalem Daylight Time",
  1491. + "Asia/Jerusalem"
  1492. + }, /* (GMT+02:00) Jerusalem */
  1493. + {
  1494. + "Jordan Standard Time", "Jordan Daylight Time",
  1495. + "Asia/Amman"
  1496. + }, /* (GMT+02:00) Amman */
  1497. + {
  1498. + "Kamchatka Standard Time", "Kamchatka Daylight Time",
  1499. + "Asia/Kamchatka"
  1500. + }, /* (GMT+12:00) Petropavlovsk-Kamchatsky */
  1501. + {
  1502. + "Korea Standard Time", "Korea Daylight Time",
  1503. + "Asia/Seoul"
  1504. + }, /* (GMT+09:00) Seoul */
  1505. + {
  1506. + "Mauritius Standard Time", "Mauritius Daylight Time",
  1507. + "Indian/Mauritius"
  1508. + }, /* (GMT+04:00) Port Louis */
  1509. + {
  1510. + "Mexico Standard Time", "Mexico Daylight Time",
  1511. + "America/Mexico_City"
  1512. + }, /* (GMT-06:00) Guadalajara, Mexico City,
  1513. + * Monterrey */
  1514. + {
  1515. + "Mexico Standard Time 2", "Mexico Daylight Time 2",
  1516. + "America/Chihuahua"
  1517. + }, /* (GMT-07:00) Chihuahua, La Paz, Mazatlan */
  1518. + {
  1519. + "Mid-Atlantic Standard Time", "Mid-Atlantic Daylight Time",
  1520. + "Atlantic/South_Georgia"
  1521. + }, /* (GMT-02:00) Mid-Atlantic */
  1522. + {
  1523. + "Middle East Standard Time", "Middle East Daylight Time",
  1524. + "Asia/Beirut"
  1525. + }, /* (GMT+02:00) Beirut */
  1526. + {
  1527. + "Montevideo Standard Time", "Montevideo Daylight Time",
  1528. + "America/Montevideo"
  1529. + }, /* (GMT-03:00) Montevideo */
  1530. + {
  1531. + "Morocco Standard Time", "Morocco Daylight Time",
  1532. + "Africa/Casablanca"
  1533. + }, /* (GMT) Casablanca */
  1534. + {
  1535. + "Mountain Standard Time", "Mountain Daylight Time",
  1536. + "US/Mountain"
  1537. + }, /* (GMT-07:00) Mountain Time (US & Canada) */
  1538. + {
  1539. + "Mountain Standard Time (Mexico)", "Mountain Daylight Time (Mexico)",
  1540. + "America/Chihuahua"
  1541. + }, /* (GMT-07:00) Chihuahua, La Paz, Mazatlan -
  1542. + * New */
  1543. + {
  1544. + "Myanmar Standard Time", "Myanmar Daylight Time",
  1545. + "Asia/Rangoon"
  1546. + }, /* (GMT+06:30) Rangoon */
  1547. + {
  1548. + "N. Central Asia Standard Time", "N. Central Asia Daylight Time",
  1549. + "Asia/Novosibirsk"
  1550. + }, /* (GMT+06:00) Novosibirsk */
  1551. + {
  1552. + "Namibia Standard Time", "Namibia Daylight Time",
  1553. + "Africa/Windhoek"
  1554. + }, /* (GMT+02:00) Windhoek */
  1555. + {
  1556. + "Nepal Standard Time", "Nepal Daylight Time",
  1557. + "Asia/Katmandu"
  1558. + }, /* (GMT+05:45) Kathmandu */
  1559. + {
  1560. + "New Zealand Standard Time", "New Zealand Daylight Time",
  1561. + "Pacific/Auckland"
  1562. + }, /* (GMT+12:00) Auckland, Wellington */
  1563. + {
  1564. + "Newfoundland Standard Time", "Newfoundland Daylight Time",
  1565. + "Canada/Newfoundland"
  1566. + }, /* (GMT-03:30) Newfoundland */
  1567. + {
  1568. + "North Asia East Standard Time", "North Asia East Daylight Time",
  1569. + "Asia/Irkutsk"
  1570. + }, /* (GMT+08:00) Irkutsk, Ulaan Bataar */
  1571. + {
  1572. + "North Asia Standard Time", "North Asia Daylight Time",
  1573. + "Asia/Krasnoyarsk"
  1574. + }, /* (GMT+07:00) Krasnoyarsk */
  1575. + {
  1576. + "Pacific SA Standard Time", "Pacific SA Daylight Time",
  1577. + "America/Santiago"
  1578. + }, /* (GMT-04:00) Santiago */
  1579. + {
  1580. + "Pacific Standard Time", "Pacific Daylight Time",
  1581. + "US/Pacific"
  1582. + }, /* (GMT-08:00) Pacific Time (US & Canada);
  1583. + * Tijuana */
  1584. + {
  1585. + "Pacific Standard Time (Mexico)", "Pacific Daylight Time (Mexico)",
  1586. + "America/Tijuana"
  1587. + }, /* (GMT-08:00) Tijuana, Baja California */
  1588. + {
  1589. + "Pakistan Standard Time", "Pakistan Daylight Time",
  1590. + "Asia/Karachi"
  1591. + }, /* (GMT+05:00) Islamabad, Karachi */
  1592. + {
  1593. + "Paraguay Standard Time", "Paraguay Daylight Time",
  1594. + "America/Asuncion"
  1595. + }, /* (GMT-04:00) Asuncion */
  1596. + {
  1597. + "Romance Standard Time", "Romance Daylight Time",
  1598. + "Europe/Brussels"
  1599. + }, /* (GMT+01:00) Brussels, Copenhagen, Madrid,
  1600. + * Paris */
  1601. + {
  1602. + "Russian Standard Time", "Russian Daylight Time",
  1603. + "Europe/Moscow"
  1604. + }, /* (GMT+03:00) Moscow, St. Petersburg,
  1605. + * Volgograd */
  1606. + {
  1607. + "SA Eastern Standard Time", "SA Eastern Daylight Time",
  1608. + "America/Buenos_Aires"
  1609. + }, /* (GMT-03:00) Buenos Aires, Georgetown */
  1610. + {
  1611. + "SA Pacific Standard Time", "SA Pacific Daylight Time",
  1612. + "America/Bogota"
  1613. + }, /* (GMT-05:00) Bogota, Lima, Quito */
  1614. + {
  1615. + "SA Western Standard Time", "SA Western Daylight Time",
  1616. + "America/Caracas"
  1617. + }, /* (GMT-04:00) Caracas, La Paz */
  1618. + {
  1619. + "Samoa Standard Time", "Samoa Daylight Time",
  1620. + "Pacific/Midway"
  1621. + }, /* (GMT-11:00) Midway Island, Samoa */
  1622. + {
  1623. + "SE Asia Standard Time", "SE Asia Daylight Time",
  1624. + "Asia/Bangkok"
  1625. + }, /* (GMT+07:00) Bangkok, Hanoi, Jakarta */
  1626. + {
  1627. + "Malay Peninsula Standard Time", "Malay Peninsula Daylight Time",
  1628. + "Asia/Kuala_Lumpur"
  1629. + }, /* (GMT+08:00) Kuala Lumpur, Singapore */
  1630. + {
  1631. + "South Africa Standard Time", "South Africa Daylight Time",
  1632. + "Africa/Harare"
  1633. + }, /* (GMT+02:00) Harare, Pretoria */
  1634. + {
  1635. + "Sri Lanka Standard Time", "Sri Lanka Daylight Time",
  1636. + "Asia/Colombo"
  1637. + }, /* (GMT+06:00) Sri Jayawardenepura */
  1638. + {
  1639. + "Taipei Standard Time", "Taipei Daylight Time",
  1640. + "Asia/Taipei"
  1641. + }, /* (GMT+08:00) Taipei */
  1642. + {
  1643. + "Tasmania Standard Time", "Tasmania Daylight Time",
  1644. + "Australia/Hobart"
  1645. + }, /* (GMT+10:00) Hobart */
  1646. + {
  1647. + "Tokyo Standard Time", "Tokyo Daylight Time",
  1648. + "Asia/Tokyo"
  1649. + }, /* (GMT+09:00) Osaka, Sapporo, Tokyo */
  1650. + {
  1651. + "Tonga Standard Time", "Tonga Daylight Time",
  1652. + "Pacific/Tongatapu"
  1653. + }, /* (GMT+13:00) Nuku'alofa */
  1654. + {
  1655. + "Ulaanbaatar Standard Time", "Ulaanbaatar Daylight Time",
  1656. + "Asia/Ulaanbaatar",
  1657. + }, /* (GMT+08:00) Ulaanbaatar */
  1658. + {
  1659. + "US Eastern Standard Time", "US Eastern Daylight Time",
  1660. + "US/Eastern"
  1661. + }, /* (GMT-05:00) Indiana (East) */
  1662. + {
  1663. + "US Mountain Standard Time", "US Mountain Daylight Time",
  1664. + "US/Arizona"
  1665. + }, /* (GMT-07:00) Arizona */
  1666. + {
  1667. + "Coordinated Universal Time", "Coordinated Universal Time",
  1668. + "UTC"
  1669. + }, /* (GMT) Coordinated Universal Time */
  1670. + {
  1671. + "UTC+12", "UTC+12",
  1672. + "Etc/GMT+12"
  1673. + }, /* (GMT+12:00) Coordinated Universal Time+12 */
  1674. + {
  1675. + "UTC-02", "UTC-02",
  1676. + "Etc/GMT-02"
  1677. + }, /* (GMT-02:00) Coordinated Universal Time-02 */
  1678. + {
  1679. + "UTC-11", "UTC-11",
  1680. + "Etc/GMT-11"
  1681. + }, /* (GMT-11:00) Coordinated Universal Time-11 */
  1682. + {
  1683. + "Venezuela Standard Time", "Venezuela Daylight Time",
  1684. + "America/Caracas",
  1685. + }, /* (GMT-04:30) Caracas */
  1686. + {
  1687. + "Vladivostok Standard Time", "Vladivostok Daylight Time",
  1688. + "Asia/Vladivostok"
  1689. + }, /* (GMT+10:00) Vladivostok */
  1690. + {
  1691. + "W. Australia Standard Time", "W. Australia Daylight Time",
  1692. + "Australia/Perth"
  1693. + }, /* (GMT+08:00) Perth */
  1694. +#ifdef NOT_USED
  1695. + /* Could not find a match for this one (just a guess). Excluded for now. */
  1696. + {
  1697. + "W. Central Africa Standard Time", "W. Central Africa Daylight Time",
  1698. + "WAT"
  1699. + }, /* (GMT+01:00) West Central Africa */
  1700. +#endif
  1701. + {
  1702. + "W. Europe Standard Time", "W. Europe Daylight Time",
  1703. + "CET"
  1704. + }, /* (GMT+01:00) Amsterdam, Berlin, Bern, Rome,
  1705. + * Stockholm, Vienna */
  1706. + {
  1707. + "West Asia Standard Time", "West Asia Daylight Time",
  1708. + "Asia/Karachi"
  1709. + }, /* (GMT+05:00) Islamabad, Karachi, Tashkent */
  1710. + {
  1711. + "West Pacific Standard Time", "West Pacific Daylight Time",
  1712. + "Pacific/Guam"
  1713. + }, /* (GMT+10:00) Guam, Port Moresby */
  1714. + {
  1715. + "Yakutsk Standard Time", "Yakutsk Daylight Time",
  1716. + "Asia/Yakutsk"
  1717. + }, /* (GMT+09:00) Yakutsk */
  1718. + {
  1719. + NULL, NULL, NULL
  1720. + }
  1721. +};
  1722. +
  1723. +static const char *
  1724. +identify_system_timezone(void)
  1725. +{
  1726. + int i;
  1727. + char tzname[128];
  1728. + char localtzname[256];
  1729. + time_t t = time(NULL);
  1730. + struct tm *tm = localtime(&t);
  1731. + HKEY rootKey;
  1732. + int idx;
  1733. +
  1734. + if (!tm)
  1735. + {
  1736. + ereport(LOG,
  1737. + (errmsg("could not identify system time zone: localtime() failed"),
  1738. + errdetail("The PostgreSQL time zone will be set to \"%s\".",
  1739. + "GMT"),
  1740. + errhint("You can specify the correct timezone in postgresql.conf.")));
  1741. + return NULL; /* go to GMT */
  1742. + }
  1743. +
  1744. + memset(tzname, 0, sizeof(tzname));
  1745. + strftime(tzname, sizeof(tzname) - 1, "%Z", tm);
  1746. +
  1747. + for (i = 0; win32_tzmap[i].stdname != NULL; i++)
  1748. + {
  1749. + if (strcmp(tzname, win32_tzmap[i].stdname) == 0 ||
  1750. + strcmp(tzname, win32_tzmap[i].dstname) == 0)
  1751. + {
  1752. + elog(DEBUG4, "TZ \"%s\" matches system time zone \"%s\"",
  1753. + win32_tzmap[i].pgtzname, tzname);
  1754. + return win32_tzmap[i].pgtzname;
  1755. + }
  1756. + }
  1757. +
  1758. + /*
  1759. + * Localized Windows versions return localized names for the timezone.
  1760. + * Scan the registry to find the English name, and then try matching
  1761. + * against our table again.
  1762. + */
  1763. + memset(localtzname, 0, sizeof(localtzname));
  1764. + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1765. + "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
  1766. + 0,
  1767. + KEY_READ,
  1768. + &rootKey) != ERROR_SUCCESS)
  1769. + {
  1770. + ereport(LOG,
  1771. + (errmsg("could not open registry key to identify system time zone: error code %lu",
  1772. + GetLastError()),
  1773. + errdetail("The PostgreSQL time zone will be set to \"%s\".",
  1774. + "GMT"),
  1775. + errhint("You can specify the correct timezone in postgresql.conf.")));
  1776. + return NULL; /* go to GMT */
  1777. + }
  1778. +
  1779. + for (idx = 0;; idx++)
  1780. + {
  1781. + char keyname[256];
  1782. + char zonename[256];
  1783. + DWORD namesize;
  1784. + FILETIME lastwrite;
  1785. + HKEY key;
  1786. + LONG r;
  1787. +
  1788. + memset(keyname, 0, sizeof(keyname));
  1789. + namesize = sizeof(keyname);
  1790. + if ((r = RegEnumKeyEx(rootKey,
  1791. + idx,
  1792. + keyname,
  1793. + &namesize,
  1794. + NULL,
  1795. + NULL,
  1796. + NULL,
  1797. + &lastwrite)) != ERROR_SUCCESS)
  1798. + {
  1799. + if (r == ERROR_NO_MORE_ITEMS)
  1800. + break;
  1801. + ereport(LOG,
  1802. + (errmsg_internal("could not enumerate registry subkeys to identify system time zone: %d", (int) r)));
  1803. + break;
  1804. + }
  1805. +
  1806. + if ((r = RegOpenKeyEx(rootKey, keyname, 0, KEY_READ, &key)) != ERROR_SUCCESS)
  1807. + {
  1808. + ereport(LOG,
  1809. + (errmsg_internal("could not open registry subkey to identify system time zone: %d", (int) r)));
  1810. + break;
  1811. + }
  1812. +
  1813. + memset(zonename, 0, sizeof(zonename));
  1814. + namesize = sizeof(zonename);
  1815. + if ((r = RegQueryValueEx(key, "Std", NULL, NULL, (unsigned char *) zonename, &namesize)) != ERROR_SUCCESS)
  1816. + {
  1817. + ereport(LOG,
  1818. + (errmsg_internal("could not query value for key \"std\" to identify system time zone \"%s\": %d",
  1819. + keyname, (int) r)));
  1820. + RegCloseKey(key);
  1821. + continue; /* Proceed to look at the next timezone */
  1822. + }
  1823. + if (strcmp(tzname, zonename) == 0)
  1824. + {
  1825. + /* Matched zone */
  1826. + strcpy(localtzname, keyname);
  1827. + RegCloseKey(key);
  1828. + break;
  1829. + }
  1830. + memset(zonename, 0, sizeof(zonename));
  1831. + namesize = sizeof(zonename);
  1832. + if ((r = RegQueryValueEx(key, "Dlt", NULL, NULL, (unsigned char *) zonename, &namesize)) != ERROR_SUCCESS)
  1833. + {
  1834. + ereport(LOG,
  1835. + (errmsg_internal("could not query value for key \"dlt\" to identify system time zone \"%s\": %d",
  1836. + keyname, (int) r)));
  1837. + RegCloseKey(key);
  1838. + continue; /* Proceed to look at the next timezone */
  1839. + }
  1840. + if (strcmp(tzname, zonename) == 0)
  1841. + {
  1842. + /* Matched DST zone */
  1843. + strcpy(localtzname, keyname);
  1844. + RegCloseKey(key);
  1845. + break;
  1846. + }
  1847. +
  1848. + RegCloseKey(key);
  1849. + }
  1850. +
  1851. + RegCloseKey(rootKey);
  1852. +
  1853. + if (localtzname[0])
  1854. + {
  1855. + /* Found a localized name, so scan for that one too */
  1856. + for (i = 0; win32_tzmap[i].stdname != NULL; i++)
  1857. + {
  1858. + if (strcmp(localtzname, win32_tzmap[i].stdname) == 0 ||
  1859. + strcmp(localtzname, win32_tzmap[i].dstname) == 0)
  1860. + {
  1861. + elog(DEBUG4, "TZ \"%s\" matches localized system time zone \"%s\" (\"%s\")",
  1862. + win32_tzmap[i].pgtzname, tzname, localtzname);
  1863. + return win32_tzmap[i].pgtzname;
  1864. + }
  1865. + }
  1866. + }
  1867. +
  1868. + ereport(LOG,
  1869. + (errmsg("could not find a match for system time zone \"%s\"",
  1870. + tzname),
  1871. + errdetail("The PostgreSQL time zone will be set to \"%s\".",
  1872. + "GMT"),
  1873. + errhint("You can specify the correct timezone in postgresql.conf.")));
  1874. + return NULL; /* go to GMT */
  1875. +}
  1876. +#endif /* WIN32 */
  1877. +
  1878. +
  1879. +
  1880. +/*
  1881. * We keep loaded timezones in a hashtable so we don't have to
  1882. * load and parse the TZ definition file every time one is selected.
  1883. * Because we want timezone names to be found case-insensitively,
  1884. @@ -203,18 +1262,8 @@
  1885. /*
  1886. * Load a timezone from file or from cache.
  1887. * Does not verify that the timezone is acceptable!
  1888. - *
  1889. - * "GMT" is always interpreted as the tzparse() definition, without attempting
  1890. - * to load a definition from the filesystem. This has a number of benefits:
  1891. - * 1. It's guaranteed to succeed, so we don't have the failure mode wherein
  1892. - * the bootstrap default timezone setting doesn't work (as could happen if
  1893. - * the OS attempts to supply a leap-second-aware version of "GMT").
  1894. - * 2. Because we aren't accessing the filesystem, we can safely initialize
  1895. - * the "GMT" zone definition before my_exec_path is known.
  1896. - * 3. It's quick enough that we don't waste much time when the bootstrap
  1897. - * default timezone setting is later overridden from postgresql.conf.
  1898. */
  1899. -pg_tz *
  1900. +struct pg_tz *
  1901. pg_tzset(const char *name)
  1902. {
  1903. pg_tz_cache *tzp;
  1904. @@ -251,20 +1300,7 @@
  1905. return &tzp->tz;
  1906. }
  1907.  
  1908. - /*
  1909. - * "GMT" is always sent to tzparse(), as per discussion above.
  1910. - */
  1911. - if (strcmp(uppername, "GMT") == 0)
  1912. - {
  1913. - if (tzparse(uppername, &tzstate, TRUE) != 0)
  1914. - {
  1915. - /* This really, really should not happen ... */
  1916. - elog(ERROR, "could not initialize GMT time zone");
  1917. - }
  1918. - /* Use uppercase name as canonical */
  1919. - strcpy(canonname, uppername);
  1920. - }
  1921. - else if (tzload(uppername, canonname, &tzstate, TRUE) != 0)
  1922. + if (tzload(uppername, canonname, &tzstate, TRUE) != 0)
  1923. {
  1924. if (uppername[0] == ':' || tzparse(uppername, &tzstate, FALSE) != 0)
  1925. {
  1926. @@ -290,26 +1326,175 @@
  1927.  
  1928.  
  1929. /*
  1930. - * Initialize timezone library
  1931. - *
  1932. - * This is called before GUC variable initialization begins. Its purpose
  1933. - * is to ensure that log_timezone has a valid value before any logging GUC
  1934. - * variables could become set to values that require elog.c to provide
  1935. - * timestamps (e.g., log_line_prefix). We may as well initialize
  1936. - * session_timestamp to something valid, too.
  1937. +* Check whether timezone is acceptable.
  1938. +*
  1939. +* What we are doing here is checking for leap-second-aware timekeeping.
  1940. +* We need to reject such TZ settings because they'll wreak havoc with our
  1941. +* date/time arithmetic.
  1942. +*
  1943. +* NB: this must NOT ereport(ERROR). The caller must get control back so that
  1944. +* it can restore the old value of TZ if we don't like the new one.
  1945. +*/
  1946. +bool
  1947. +tz_acceptable(pg_tz *tz)
  1948. +{
  1949. + struct pg_tm *tt;
  1950. + pg_time_t time2000;
  1951. +
  1952. + /*
  1953. + * To detect leap-second timekeeping, run pg_localtime for what should be
  1954. + * GMT midnight, 2000-01-01. Insist that the tm_sec value be zero; any
  1955. + * other result has to be due to leap seconds.
  1956. */
  1957. + time2000 = (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY;
  1958. + tt = pg_localtime(&time2000, tz);
  1959. + if (!tt || tt->tm_sec != 0)
  1960. + return false;
  1961. +
  1962. + return true;
  1963. +}
  1964. +
  1965. +
  1966. +/*
  1967. +* Get a pg_tz struct for the given timezone name. Returns NULL if name
  1968. +* is invalid or not an "acceptable" zone.
  1969. +*/
  1970. +static pg_tz *
  1971. +get_pg_tz_for_zone(const char *tzname)
  1972. +{
  1973. + pg_tz *tz;
  1974. +
  1975. + if (!tzname || !tzname[0])
  1976. + return NULL;
  1977. +
  1978. + tz = pg_tzset(tzname);
  1979. + if (!tz)
  1980. + return NULL;
  1981. +
  1982. + if (!tz_acceptable(tz))
  1983. + return NULL;
  1984. +
  1985. + return tz;
  1986. +}
  1987. +
  1988. +/*
  1989. +* Identify a suitable default timezone setting based on the environment.
  1990. +*
  1991. +* We first look to the TZ environment variable. If not found or not
  1992. +* recognized by our own code, we see if we can identify the timezone
  1993. +* from the behavior of the system timezone library. When all else fails,
  1994. +* fall back to GMT.
  1995. +*/
  1996. +static pg_tz *
  1997. +select_default_timezone(void)
  1998. +{
  1999. + pg_tz *def_tz;
  2000. +
  2001. + def_tz = get_pg_tz_for_zone(getenv("TZ"));
  2002. + if (def_tz)
  2003. + return def_tz;
  2004. +
  2005. + def_tz = get_pg_tz_for_zone(identify_system_timezone());
  2006. + if (def_tz)
  2007. + return def_tz;
  2008. +
  2009. + def_tz = get_pg_tz_for_zone("GMT");
  2010. + if (def_tz)
  2011. + return def_tz;
  2012. +
  2013. + ereport(FATAL,
  2014. + (errmsg("could not select a suitable default time zone"),
  2015. + errdetail("It appears that your GMT time zone uses leap seconds. PostgreSQL does not support leap seconds.")));
  2016. + return NULL; /* keep compiler quiet */
  2017. +}
  2018. +
  2019. +
  2020. +/*
  2021. +* Pre-initialize timezone library
  2022. +*
  2023. +* This is called before GUC variable initialization begins. Its purpose
  2024. +* is to ensure that elog.c has a pgtz variable available to format timestamps
  2025. +* with, in case log_line_prefix is set to a value requiring that. We cannot
  2026. +* set log_timezone yet.
  2027. +*/
  2028. +void
  2029. +pg_timezone_pre_initialize(void)
  2030. +{
  2031. + /*
  2032. + * We can't use tzload() because we may not know where PGSHAREDIR is (in
  2033. + * particular this is true in an EXEC_BACKEND subprocess). Since this
  2034. + * timezone variable will only be used for emergency fallback purposes, it
  2035. + * seems OK to just use the "lastditch" case provided by tzparse().
  2036. + */
  2037. + if (tzparse("GMT", &gmt_timezone_data.state, TRUE) != 0)
  2038. + elog(FATAL, "could not initialize GMT time zone");
  2039. + strcpy(gmt_timezone_data.TZname, "GMT");
  2040. + gmt_timezone = &gmt_timezone_data;
  2041. +}
  2042. +
  2043. +/*
  2044. +* Initialize timezone library
  2045. +*
  2046. +* This is called after initial loading of postgresql.conf. If no TimeZone
  2047. +* setting was found therein, we try to derive one from the environment.
  2048. +* Likewise for log_timezone.
  2049. +*
  2050. +* Note: this is also called from ProcessConfigFile, to re-establish valid
  2051. +* GUC settings if the GUCs have been reset to default following their
  2052. +* removal from postgresql.conf.
  2053. +*/
  2054. void
  2055. pg_timezone_initialize(void)
  2056. {
  2057. + pg_tz *def_tz = NULL;
  2058. +
  2059. + /*
  2060. + * Make sure that session_timezone and log_timezone are set.
  2061. + * (session_timezone could still be NULL even if a timezone value was set
  2062. + * in postgresql.conf, if that setting was interval-based rather than
  2063. + * timezone-based.)
  2064. + */
  2065. + if (!session_timezone)
  2066. + {
  2067. + def_tz = select_default_timezone();
  2068. + session_timezone = def_tz;
  2069. + }
  2070. + if (!log_timezone)
  2071. + {
  2072. + /* Don't duplicate work */
  2073. + if (!def_tz)
  2074. + def_tz = select_default_timezone();
  2075. + log_timezone = def_tz;
  2076. + }
  2077. +
  2078. /*
  2079. - * We may not yet know where PGSHAREDIR is (in particular this is true in
  2080. - * an EXEC_BACKEND subprocess). So use "GMT", which pg_tzset forces to be
  2081. - * interpreted without reference to the filesystem. This corresponds to
  2082. - * the bootstrap default for these variables in guc.c, although in
  2083. - * principle it could be different.
  2084. + * Now, set the timezone and log_timezone GUCs if they're still default.
  2085. + * (This will redundantly call pg_tzset().)
  2086. + *
  2087. + * We choose to label these values PGC_S_ENV_VAR, rather than
  2088. + * PGC_S_DYNAMIC_DEFAULT which would be functionally equivalent, because
  2089. + * they came either from getenv("TZ") or from libc behavior that's
  2090. + * determined by process environment of some kind.
  2091. + *
  2092. + * Note: in the case where a setting has just been removed from
  2093. + * postgresql.conf, this code will not do what you might expect, namely
  2094. + * call select_default_timezone() and install that value as the setting.
  2095. + * Rather, the previously active setting --- typically the one from
  2096. + * postgresql.conf --- will be reinstalled, relabeled as PGC_S_ENV_VAR. If
  2097. + * we did try to install the "correct" default value, the effect would be
  2098. + * that each postmaster child would independently run an extremely
  2099. + * expensive search of the timezone database, bringing the database to its
  2100. + * knees for possibly multiple seconds. This is so unpleasant, and could
  2101. + * so easily be triggered quite unintentionally, that it seems better to
  2102. + * violate the principle of least astonishment.
  2103. */
  2104. - session_timezone = pg_tzset("GMT");
  2105. - log_timezone = session_timezone;
  2106. + if (GetConfigOptionResetString("timezone") == NULL)
  2107. + SetConfigOption("timezone", pg_get_timezone_name(session_timezone),
  2108. + PGC_POSTMASTER, PGC_S_ENV_VAR);
  2109. +
  2110. + if (GetConfigOptionResetString("log_timezone") == NULL)
  2111. + SetConfigOption("log_timezone", pg_get_timezone_name(log_timezone),
  2112. + PGC_POSTMASTER, PGC_S_ENV_VAR);
  2113. }
  2114.  
  2115.  
  2116. @@ -423,7 +1608,7 @@
  2117. continue;
  2118. }
  2119.  
  2120. - if (!pg_tz_acceptable(&dir->tz))
  2121. + if (!tz_acceptable(&dir->tz))
  2122. {
  2123. /* Ignore leap-second zones */
  2124. continue;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement