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

Commit70530c8

Browse files
committed
Adjust the parser to accept the typename syntax INTERVAL ... SECOND(n)
and the literal syntax INTERVAL 'string' ... SECOND(n), as required by theSQL standard. Our old syntax put (n) directly after INTERVAL, which wasa mistake, but will still be accepted for backward compatibility as wellas symmetry with the TIMESTAMP cases.Change intervaltypmodout to show it in the spec's way, too. (This couldpotentially affect clients, if there are any that analyze the typmod of anINTERVAL in any detail.)Also fix interval input to handle 'min:sec.frac' properly; I had overlookedthis case in my previous patch.Document the use of the interval fields qualifier, which up to now we hadnever mentioned in the docs. (I think the omission was intentional becauseit didn't work per spec; but it does now, or at least close enough to becredible.)
1 parentd53a566 commit70530c8

File tree

6 files changed

+294
-56
lines changed

6 files changed

+294
-56
lines changed

‎doc/src/sgml/datatype.sgml

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.227 2008/05/16 16:31:01 tgl Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.228 2008/09/11 15:27:30 tgl Exp $ -->
22

33
<chapter id="datatype">
44
<title id="datatype-title">Data Types</title>
@@ -131,7 +131,7 @@
131131
</row>
132132

133133
<row>
134-
<entry><type>interval [ (<replaceable>p</replaceable>) ]</type></entry>
134+
<entry><type>interval [<replaceable>fields</replaceable> ] [(<replaceable>p</replaceable>) ]</type></entry>
135135
<entry></entry>
136136
<entry>time span</entry>
137137
</row>
@@ -1420,7 +1420,7 @@ SELECT b, char_length(b) FROM test2;
14201420
<entry>1 microsecond / 14 digits</entry>
14211421
</row>
14221422
<row>
1423-
<entry><type>interval [ (<replaceable>p</replaceable>) ]</type></entry>
1423+
<entry><type>interval [<replaceable>fields</replaceable> ] [(<replaceable>p</replaceable>) ]</type></entry>
14241424
<entry>12 bytes</entry>
14251425
<entry>time intervals</entry>
14261426
<entry>-178000000 years</entry>
@@ -1505,6 +1505,30 @@ SELECT b, char_length(b) FROM test2;
15051505
storage is used, or from 0 to 10 when floating-point storage is used.
15061506
</para>
15071507

1508+
<para>
1509+
The <type>interval</type> type has an additional option, which is
1510+
to restrict the set of stored fields by writing one of these phrases:
1511+
<programlisting>
1512+
YEAR
1513+
MONTH
1514+
DAY
1515+
HOUR
1516+
MINUTE
1517+
SECOND
1518+
YEAR TO MONTH
1519+
DAY TO HOUR
1520+
DAY TO MINUTE
1521+
DAY TO SECOND
1522+
HOUR TO MINUTE
1523+
MINUTE TO SECOND
1524+
</programlisting>
1525+
Input falling outside the specified set of fields is silently discarded.
1526+
Note that if both <replaceable>fields</replaceable> and
1527+
<replaceable>precision</replaceable> are specified, the
1528+
<replaceable>fields</replaceable> must include <literal>SECOND</>,
1529+
since the precision applies only to the seconds.
1530+
</para>
1531+
15081532
<para>
15091533
The type <type>time with time zone</type> is defined by the SQL
15101534
standard, but the definition exhibits properties which lead to
@@ -1928,18 +1952,26 @@ January 8 04:05:06 1999 PST
19281952
<replaceable>direction</> can be <literal>ago</literal> or
19291953
empty. The at sign (<literal>@</>) is optional noise. The amounts
19301954
of different units are implicitly added up with appropriate
1931-
sign accounting.
1955+
sign accounting. <literal>ago</literal> negates all the fields.
19321956
</para>
19331957

19341958
<para>
19351959
Quantities of days, hours, minutes, and seconds can be specified without
19361960
explicit unit markings. For example, <literal>'1 12:59:10'</> is read
1937-
the same as <literal>'1 day 12 hours 59 min 10 sec'</>.
1961+
the same as <literal>'1 day 12 hours 59 min 10 sec'</>. Also,
1962+
a combination of years and months can be specified with a dash;
1963+
for example <literal>'200-10'</> is read the same as <literal>'200 years
1964+
10 months'</>. (These shorter forms are in fact the only ones allowed
1965+
by the SQL standard.)
19381966
</para>
19391967

19401968
<para>
1941-
The optional subsecond precision <replaceable>p</replaceable> should
1942-
be between 0 and 6, and defaults to the precision of the input literal.
1969+
When writing an interval constant with a <replaceable>fields</>
1970+
specification, or when assigning to an interval column that was defined
1971+
with a <replaceable>fields</> specification, the interpretation of
1972+
unmarked quantities depends on the <replaceable>fields</>. For
1973+
example <literal>INTERVAL '1' YEAR</> is read as 1 year, whereas
1974+
<literal>INTERVAL '1'</> means 1 second.
19431975
</para>
19441976

19451977
<para>

‎src/backend/parser/gram.y

Lines changed: 114 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.622 2008/09/02 20:37:54 tgl Exp $
14+
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.623 2008/09/11 15:27:30 tgl Exp $
1515
*
1616
* HISTORY
1717
* AUTHORDATEMAJOR EVENT
@@ -292,7 +292,7 @@ static TypeName *TableFuncTypeName(List *columns);
292292

293293
%type<list>extract_listoverlay_listposition_list
294294
%type<list>substr_listtrim_list
295-
%type<ival>opt_interval
295+
%type<list>opt_intervalinterval_second
296296
%type<node>overlay_placingsubstr_fromsubstr_for
297297

298298
%type<boolean>opt_insteadopt_analyze
@@ -1222,28 +1222,39 @@ zone_value:
12221222
|ConstIntervalSconstopt_interval
12231223
{
12241224
TypeName *t =$1;
1225-
if ($3 !=INTERVAL_FULL_RANGE)
1225+
if ($3 !=NIL)
12261226
{
1227-
if (($3 & ~(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE))) !=0)
1227+
A_Const *n = (A_Const *) linitial($3);
1228+
if ((n->val.val.ival & ~(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE))) !=0)
12281229
ereport(ERROR,
12291230
(errcode(ERRCODE_SYNTAX_ERROR),
12301231
errmsg("time zone interval must be HOUR or HOUR TO MINUTE"),
12311232
scanner_errposition(@3)));
1232-
t->typmods = list_make1(makeIntConst($3,@3));
12331233
}
1234+
t->typmods =$3;
12341235
$$ = makeStringConstCast($2,@2, t);
12351236
}
12361237
|ConstInterval'('Iconst')'Sconstopt_interval
12371238
{
12381239
TypeName *t =$1;
1239-
if (($6 != INTERVAL_FULL_RANGE)
1240-
&& (($6 & ~(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE))) !=0))
1241-
ereport(ERROR,
1242-
(errcode(ERRCODE_SYNTAX_ERROR),
1243-
errmsg("time zone interval must be HOUR or HOUR TO MINUTE"),
1244-
scanner_errposition(@6)));
1245-
t->typmods = list_make2(makeIntConst($6,@6),
1246-
makeIntConst($3, @3));
1240+
if ($6 != NIL)
1241+
{
1242+
A_Const *n = (A_Const *) linitial($6);
1243+
if ((n->val.val.ival & ~(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE))) !=0)
1244+
ereport(ERROR,
1245+
(errcode(ERRCODE_SYNTAX_ERROR),
1246+
errmsg("time zone interval must be HOUR or HOUR TO MINUTE"),
1247+
scanner_errposition(@6)));
1248+
if (list_length($6) !=1)
1249+
ereport(ERROR,
1250+
(errcode(ERRCODE_SYNTAX_ERROR),
1251+
errmsg("interval precision specified twice"),
1252+
scanner_errposition(@1)));
1253+
t->typmods = lappend($6, makeIntConst($3,@3));
1254+
}
1255+
else
1256+
t->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1),
1257+
makeIntConst($3, @3));
12471258
$$ = makeStringConstCast($5,@5, t);
12481259
}
12491260
|NumericOnly{$$ = makeAConst($1,@1); }
@@ -6983,14 +6994,23 @@ SimpleTypename:
69836994
| ConstInterval opt_interval
69846995
{
69856996
$$ =$1;
6986-
if ($2 != INTERVAL_FULL_RANGE)
6987-
$$->typmods = list_make1(makeIntConst($2,@2));
6997+
$$->typmods =$2;
69886998
}
69896999
| ConstInterval'(' Iconst')' opt_interval
69907000
{
69917001
$$ =$1;
6992-
$$->typmods = list_make2(makeIntConst($5,@5),
6993-
makeIntConst($3, @3));
7002+
if ($5 != NIL)
7003+
{
7004+
if (list_length($5) !=1)
7005+
ereport(ERROR,
7006+
(errcode(ERRCODE_SYNTAX_ERROR),
7007+
errmsg("interval precision specified twice"),
7008+
scanner_errposition(@1)));
7009+
$$->typmods = lappend($5, makeIntConst($3,@3));
7010+
}
7011+
else
7012+
$$->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1),
7013+
makeIntConst($3, @3));
69947014
}
69957015
;
69967016

@@ -7337,30 +7357,74 @@ opt_timezone:
73377357
;
73387358

73397359
opt_interval:
7340-
YEAR_P{$$ = INTERVAL_MASK(YEAR); }
7341-
| MONTH_P{$$ = INTERVAL_MASK(MONTH); }
7342-
| DAY_P{$$ = INTERVAL_MASK(DAY); }
7343-
| HOUR_P{$$ = INTERVAL_MASK(HOUR); }
7344-
| MINUTE_P{$$ = INTERVAL_MASK(MINUTE); }
7345-
| SECOND_P{$$ = INTERVAL_MASK(SECOND); }
7360+
YEAR_P
7361+
{$$ = list_make1(makeIntConst(INTERVAL_MASK(YEAR),@1)); }
7362+
| MONTH_P
7363+
{$$ = list_make1(makeIntConst(INTERVAL_MASK(MONTH),@1)); }
7364+
| DAY_P
7365+
{$$ = list_make1(makeIntConst(INTERVAL_MASK(DAY),@1)); }
7366+
| HOUR_P
7367+
{$$ = list_make1(makeIntConst(INTERVAL_MASK(HOUR),@1)); }
7368+
| MINUTE_P
7369+
{$$ = list_make1(makeIntConst(INTERVAL_MASK(MINUTE),@1)); }
7370+
| interval_second
7371+
{$$ =$1; }
73467372
| YEAR_P TO MONTH_P
7347-
{$$ = INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH); }
7373+
{
7374+
$$ = list_make1(makeIntConst(INTERVAL_MASK(YEAR) |
7375+
INTERVAL_MASK(MONTH), @1));
7376+
}
73487377
| DAY_P TO HOUR_P
7349-
{$$ = INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR); }
7378+
{
7379+
$$ = list_make1(makeIntConst(INTERVAL_MASK(DAY) |
7380+
INTERVAL_MASK(HOUR), @1));
7381+
}
73507382
| DAY_P TO MINUTE_P
7351-
{$$ = INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR)
7352-
| INTERVAL_MASK(MINUTE); }
7353-
| DAY_P TO SECOND_P
7354-
{$$ = INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR)
7355-
| INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND); }
7383+
{
7384+
$$ = list_make1(makeIntConst(INTERVAL_MASK(DAY) |
7385+
INTERVAL_MASK(HOUR) |
7386+
INTERVAL_MASK(MINUTE), @1));
7387+
}
7388+
| DAY_P TO interval_second
7389+
{
7390+
$$ =$3;
7391+
linitial($$) = makeIntConst(INTERVAL_MASK(DAY) |
7392+
INTERVAL_MASK(HOUR) |
7393+
INTERVAL_MASK(MINUTE) |
7394+
INTERVAL_MASK(SECOND), @1);
7395+
}
73567396
| HOUR_P TO MINUTE_P
7357-
{$$ = INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE); }
7358-
| HOUR_P TO SECOND_P
7359-
{$$ = INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE)
7360-
| INTERVAL_MASK(SECOND); }
7361-
| MINUTE_P TO SECOND_P
7362-
{$$ = INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND); }
7363-
|/*EMPTY*/{$$ = INTERVAL_FULL_RANGE; }
7397+
{
7398+
$$ = list_make1(makeIntConst(INTERVAL_MASK(HOUR) |
7399+
INTERVAL_MASK(MINUTE), @1));
7400+
}
7401+
| HOUR_P TO interval_second
7402+
{
7403+
$$ =$3;
7404+
linitial($$) = makeIntConst(INTERVAL_MASK(HOUR) |
7405+
INTERVAL_MASK(MINUTE) |
7406+
INTERVAL_MASK(SECOND), @1);
7407+
}
7408+
| MINUTE_P TO interval_second
7409+
{
7410+
$$ =$3;
7411+
linitial($$) = makeIntConst(INTERVAL_MASK(MINUTE) |
7412+
INTERVAL_MASK(SECOND), @1);
7413+
}
7414+
|/*EMPTY*/
7415+
{$$ = NIL; }
7416+
;
7417+
7418+
interval_second:
7419+
SECOND_P
7420+
{
7421+
$$ = list_make1(makeIntConst(INTERVAL_MASK(SECOND),@1));
7422+
}
7423+
| SECOND_P'(' Iconst')'
7424+
{
7425+
$$ = list_make2(makeIntConst(INTERVAL_MASK(SECOND),@1),
7426+
makeIntConst($3, @3));
7427+
}
73647428
;
73657429

73667430

@@ -9014,16 +9078,24 @@ AexprConst: Iconst
90149078
| ConstInterval Sconst opt_interval
90159079
{
90169080
TypeName *t = $1;
9017-
/* precision is not specified, but fields may be...*/
9018-
if ($3 != INTERVAL_FULL_RANGE)
9019-
t->typmods =list_make1(makeIntConst($3, @3));
9081+
t->typmods = $3;
90209082
$$ =makeStringConstCast($2, @2, t);
90219083
}
90229084
| ConstInterval'(' Iconst')' Sconst opt_interval
90239085
{
90249086
TypeName *t = $1;
9025-
t->typmods =list_make2(makeIntConst($6, @6),
9026-
makeIntConst($3, @3));
9087+
if ($6 != NIL)
9088+
{
9089+
if (list_length($6) !=1)
9090+
ereport(ERROR,
9091+
(errcode(ERRCODE_SYNTAX_ERROR),
9092+
errmsg("interval precision specified twice"),
9093+
scanner_errposition(@1)));
9094+
t->typmods =lappend($6,makeIntConst($3, @3));
9095+
}
9096+
else
9097+
t->typmods =list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1),
9098+
makeIntConst($3, @3));
90279099
$$ =makeStringConstCast($5, @5, t);
90289100
}
90299101
| TRUE_P

‎src/backend/utils/adt/datetime.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.191 2008/09/10 18:29:41 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.192 2008/09/11 15:27:30 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -2256,9 +2256,25 @@ DecodeTime(char *str, int fmask, int range,
22562256
tm->tm_hour=0;
22572257
}
22582258
}
2259-
elseif (*cp!=':')
2260-
returnDTERR_BAD_FORMAT;
2261-
else
2259+
elseif (*cp=='.')
2260+
{
2261+
/* always assume mm:ss.sss is MINUTE TO SECOND */
2262+
doublefrac;
2263+
2264+
str=cp;
2265+
frac=strtod(str,&cp);
2266+
if (*cp!='\0')
2267+
returnDTERR_BAD_FORMAT;
2268+
#ifdefHAVE_INT64_TIMESTAMP
2269+
*fsec=rint(frac*1000000);
2270+
#else
2271+
*fsec=frac;
2272+
#endif
2273+
tm->tm_sec=tm->tm_min;
2274+
tm->tm_min=tm->tm_hour;
2275+
tm->tm_hour=0;
2276+
}
2277+
elseif (*cp==':')
22622278
{
22632279
str=cp+1;
22642280
errno=0;
@@ -2284,6 +2300,8 @@ DecodeTime(char *str, int fmask, int range,
22842300
else
22852301
returnDTERR_BAD_FORMAT;
22862302
}
2303+
else
2304+
returnDTERR_BAD_FORMAT;
22872305

22882306
/* do a sanity check */
22892307
#ifdefHAVE_INT64_TIMESTAMP

‎src/backend/utils/adt/timestamp.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.191 2008/09/10 18:29:41 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.192 2008/09/11 15:27:30 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -744,7 +744,7 @@ intervaltypmodin(PG_FUNCTION_ARGS)
744744
tl=ArrayGetIntegerTypmods(ta,&n);
745745

746746
/*
747-
* tl[0] -opt_intervaltl[1] -Iconst (optional)
747+
* tl[0] -interval range (fields bitmask)tl[1] -precision (optional)
748748
*
749749
* Note we must validate tl[0] even though it's normally guaranteed
750750
* correct by the grammar --- consider SELECT 'foo'::"interval"(1000).
@@ -881,7 +881,7 @@ intervaltypmodout(PG_FUNCTION_ARGS)
881881
}
882882

883883
if (precision!=INTERVAL_FULL_PRECISION)
884-
snprintf(res,64,"(%d)%s",precision,fieldstr);
884+
snprintf(res,64,"%s(%d)",fieldstr,precision);
885885
else
886886
snprintf(res,64,"%s",fieldstr);
887887

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp