Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit6d7ff84

Browse files
committed
Add code to test for unknown timezone names (following some ideas from
Ross Reedstrom, a couple months back) and to detect timezones that areusing leap-second timekeeping. The unknown-zone-name test is prettyheuristic and ugly, but it seems better than the old behavior of justswitching to GMT given a bad name. Also make DecodePosixTimezone() atad more robust.
1 parent6d8c774 commit6d7ff84

File tree

3 files changed

+265
-39
lines changed

3 files changed

+265
-39
lines changed

‎src/backend/commands/variable.c

Lines changed: 231 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.75 2003/04/27 17:31:25 tgl Exp $
12+
* $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.76 2003/05/18 01:06:25 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -235,7 +235,147 @@ show_datestyle(void)
235235
/*
236236
* Storage for TZ env var is allocated with an arbitrary size of 64 bytes.
237237
*/
238-
staticchartzbuf[64];
238+
#defineTZBUF_LEN64
239+
240+
staticchartzbuf[TZBUF_LEN];
241+
242+
/*
243+
* First time through, we remember the original environment TZ value, if any.
244+
*/
245+
staticboolhave_saved_tz= false;
246+
staticcharorig_tzbuf[TZBUF_LEN];
247+
248+
/*
249+
* Convenience subroutine for assigning the value of TZ
250+
*/
251+
staticvoid
252+
set_tz(constchar*tz)
253+
{
254+
strcpy(tzbuf,"TZ=");
255+
strncpy(tzbuf+3,tz,sizeof(tzbuf)-4);
256+
if (putenv(tzbuf)!=0)/* shouldn't happen? */
257+
elog(LOG,"Unable to set TZ environment variable");
258+
tzset();
259+
}
260+
261+
/*
262+
* Remove any value of TZ we have established
263+
*
264+
* Note: this leaves us with *no* value of TZ in the environment, and
265+
* is therefore only appropriate for reverting to that state, not for
266+
* reverting to a state where TZ was set to something else.
267+
*/
268+
staticvoid
269+
clear_tz(void)
270+
{
271+
/*
272+
* unsetenv() works fine, but is BSD, not POSIX, and is not
273+
* available under Solaris, among others. Apparently putenv()
274+
* called as below clears the process-specific environment
275+
* variables. Other reasonable arguments to putenv() (e.g.
276+
* "TZ=", "TZ", "") result in a core dump (under Linux
277+
* anyway). - thomas 1998-01-26
278+
*/
279+
if (tzbuf[0]=='T')
280+
{
281+
strcpy(tzbuf,"=");
282+
if (putenv(tzbuf)!=0)
283+
elog(LOG,"Unable to clear TZ environment variable");
284+
tzset();
285+
}
286+
}
287+
288+
/*
289+
* Check whether tzset() succeeded
290+
*
291+
* Unfortunately, tzset doesn't offer any well-defined way to detect that the
292+
* value of TZ was bad. Often it will just select UTC (GMT) as the effective
293+
* timezone. We use the following heuristics:
294+
*
295+
* If tzname[1] is a nonempty string, *or* the global timezone variable is
296+
* not zero, then tzset must have recognized the TZ value as something
297+
* different from UTC. Return true.
298+
*
299+
* Otherwise, check to see if the TZ name is a known spelling of "UTC"
300+
* (ie, appears in our internal tables as a timezone equivalent to UTC).
301+
* If so, accept it.
302+
*
303+
* This will reject nonstandard spellings of UTC unless tzset() chose to
304+
* set tzname[1] as well as tzname[0]. The glibc version of tzset() will
305+
* do so, but on other systems we may be tightening the spec a little.
306+
*
307+
* Another problem is that on some platforms (eg HPUX), if tzset thinks the
308+
* input is bogus then it will adopt the system default timezone, which we
309+
* really can't tell is not the intended translation of the input.
310+
*
311+
* Still, it beats failing to detect bad TZ names at all, and a silent
312+
* failure mode of adopting the system-wide default is much better than
313+
* a silent failure mode of adopting UTC.
314+
*
315+
* NB: this must NOT elog(ERROR). The caller must get control back so that
316+
* it can restore the old value of TZ if we don't like the new one.
317+
*/
318+
staticbool
319+
tzset_succeeded(constchar*tz)
320+
{
321+
chartztmp[TZBUF_LEN];
322+
char*cp;
323+
inttzval;
324+
325+
/*
326+
* Check first set of heuristics to say that tzset definitely worked.
327+
*/
328+
if (tzname[1]&&tzname[1][0]!='\0')
329+
return true;
330+
if (TIMEZONE_GLOBAL!=0)
331+
return true;
332+
333+
/*
334+
* Check for known spellings of "UTC". Note we must downcase the input
335+
* before passing it to DecodePosixTimezone().
336+
*/
337+
StrNCpy(tztmp,tz,sizeof(tztmp));
338+
for (cp=tztmp;*cp;cp++)
339+
*cp=tolower((unsignedchar)*cp);
340+
if (DecodePosixTimezone(tztmp,&tzval)==0)
341+
if (tzval==0)
342+
return true;
343+
344+
return false;
345+
}
346+
347+
/*
348+
* Check whether timezone is acceptable.
349+
*
350+
* What we are doing here is checking for leap-second-aware timekeeping.
351+
* We need to reject such TZ settings because they'll wreak havoc with our
352+
* date/time arithmetic.
353+
*
354+
* NB: this must NOT elog(ERROR). The caller must get control back so that
355+
* it can restore the old value of TZ if we don't like the new one.
356+
*/
357+
staticbool
358+
tz_acceptable(void)
359+
{
360+
structtmtt;
361+
time_ttime2000;
362+
363+
/*
364+
* To detect leap-second timekeeping, compute the time_t value for
365+
* local midnight, 2000-01-01. Insist that this be a multiple of 60;
366+
* any partial-minute offset has to be due to leap seconds.
367+
*/
368+
MemSet(&tt,0,sizeof(tt));
369+
tt.tm_year=100;
370+
tt.tm_mon=0;
371+
tt.tm_mday=1;
372+
tt.tm_isdst=-1;
373+
time2000=mktime(&tt);
374+
if ((time2000 %60)!=0)
375+
return false;
376+
377+
return true;
378+
}
239379

240380
/*
241381
* assign_timezone: GUC assign_hook for timezone
@@ -247,6 +387,21 @@ assign_timezone(const char *value, bool doit, bool interactive)
247387
char*endptr;
248388
doublehours;
249389

390+
/*
391+
* On first call, see if there is a TZ in the original environment.
392+
* Save that value permanently.
393+
*/
394+
if (!have_saved_tz)
395+
{
396+
char*orig_tz=getenv("TZ");
397+
398+
if (orig_tz)
399+
StrNCpy(orig_tzbuf,orig_tz,sizeof(orig_tzbuf));
400+
else
401+
orig_tzbuf[0]='\0';
402+
have_saved_tz= true;
403+
}
404+
250405
/*
251406
* Check for INTERVAL 'foo'
252407
*/
@@ -313,45 +468,95 @@ assign_timezone(const char *value, bool doit, bool interactive)
313468
elseif (strcasecmp(value,"UNKNOWN")==0)
314469
{
315470
/*
316-
* Clear any TZ value we may have established.
317-
*
318-
* unsetenv() works fine, but is BSD, not POSIX, and is not
319-
* available under Solaris, among others. Apparently putenv()
320-
* called as below clears the process-specific environment
321-
* variables. Other reasonable arguments to putenv() (e.g.
322-
* "TZ=", "TZ", "") result in a core dump (under Linux
323-
* anyway). - thomas 1998-01-26
471+
* UNKNOWN is the value shown as the "default" for TimeZone
472+
* in guc.c. We interpret it as meaning the original TZ
473+
* inherited from the environment. Note that if there is an
474+
* original TZ setting, we will return that rather than UNKNOWN
475+
* as the canonical spelling.
324476
*/
325477
if (doit)
326478
{
327-
if (tzbuf[0]=='T')
479+
boolok;
480+
481+
/* Revert to original setting of TZ, whatever it was */
482+
if (orig_tzbuf[0])
328483
{
329-
strcpy(tzbuf,"=");
330-
if (putenv(tzbuf)!=0)
331-
elog(ERROR,"Unable to clear TZ environment variable");
332-
tzset();
484+
set_tz(orig_tzbuf);
485+
ok=tzset_succeeded(orig_tzbuf)&&tz_acceptable();
486+
}
487+
else
488+
{
489+
clear_tz();
490+
ok=tz_acceptable();
491+
}
492+
493+
if (ok)
494+
HasCTZSet= false;
495+
else
496+
{
497+
/* Bogus, so force UTC (equivalent to INTERVAL 0) */
498+
CTimeZone=0;
499+
HasCTZSet= true;
333500
}
334-
HasCTZSet= false;
335501
}
336502
}
337503
else
338504
{
339505
/*
340506
* Otherwise assume it is a timezone name.
341507
*
342-
* XXX unfortunately we have no reasonable way to check whether a
343-
* timezone name is good, so we have to just assume that it
344-
* is.
508+
* We have to actually apply the change before we can have any
509+
* hope of checking it. So, save the old value in case we have
510+
* to back out. Note that it's possible the old setting is in
511+
* tzbuf, so we'd better copy it.
345512
*/
346-
if (doit)
513+
charsave_tzbuf[TZBUF_LEN];
514+
char*save_tz;
515+
boolknown,
516+
acceptable;
517+
518+
save_tz=getenv("TZ");
519+
if (save_tz)
520+
StrNCpy(save_tzbuf,save_tz,sizeof(save_tzbuf));
521+
522+
set_tz(value);
523+
524+
known=tzset_succeeded(value);
525+
acceptable=tz_acceptable();
526+
527+
if (doit&&known&&acceptable)
347528
{
348-
strcpy(tzbuf,"TZ=");
349-
strncat(tzbuf,value,sizeof(tzbuf)-4);
350-
if (putenv(tzbuf)!=0)/* shouldn't happen? */
351-
elog(LOG,"assign_timezone: putenv failed");
352-
tzset();
529+
/* Keep the changed TZ */
353530
HasCTZSet= false;
354531
}
532+
else
533+
{
534+
/*
535+
* Revert to prior TZ setting; note we haven't changed
536+
* HasCTZSet in this path, so if we were previously using
537+
* a fixed offset, we still are.
538+
*/
539+
if (save_tz)
540+
set_tz(save_tzbuf);
541+
else
542+
clear_tz();
543+
/* Complain if it was bad */
544+
if (!known)
545+
{
546+
elog(interactive ?ERROR :LOG,
547+
"unrecognized timezone name \"%s\"",
548+
value);
549+
returnNULL;
550+
}
551+
if (!acceptable)
552+
{
553+
elog(interactive ?ERROR :LOG,
554+
"timezone \"%s\" appears to use leap seconds"
555+
"\n\tPostgreSQL does not support leap seconds",
556+
value);
557+
returnNULL;
558+
}
559+
}
355560
}
356561
}
357562

@@ -369,10 +574,7 @@ assign_timezone(const char *value, bool doit, bool interactive)
369574
returnNULL;
370575

371576
if (HasCTZSet)
372-
{
373-
snprintf(result,sizeof(tzbuf),"%.5f",
374-
(double)CTimeZone /3600.0);
375-
}
577+
snprintf(result,sizeof(tzbuf),"%.5f", (double)CTimeZone /3600.0);
376578
elseif (tzbuf[0]=='T')
377579
strcpy(result,tzbuf+3);
378580
else

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp