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

Commitf867339

Browse files
committed
Make our parsing of INTERVAL literals spec-compliant (or at least a heck of
a lot closer than it was before). To do this, tweak coerce_type() to passthrough the typmod information when invoking interval_in() on an UNKNOWNconstant; then fix DecodeInterval to pay attention to the typmod when decidinghow to interpret a units-less integer value. I changed one or two otherdetails as well. I believe the code now reacts as expected by spec for allthe literal syntaxes that are specifically enumerated in the spec. Thereare corner cases involving strings that don't exactly match the set of fieldscalled out by the typmod, for which we might want to tweak the behavior somemore; but I think this is an area of user friendliness rather than speccompliance. There remain some non-compliant details about the SQL syntax(as opposed to what's inside the literal string); but at least we'll throwerror rather than silently doing the wrong thing in those cases.
1 parent3b9ec46 commitf867339

File tree

7 files changed

+296
-30
lines changed

7 files changed

+296
-30
lines changed

‎src/backend/parser/parse_coerce.c

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.166 2008/09/01 20:42:44 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.167 2008/09/10 18:29:40 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -179,6 +179,7 @@ coerce_type(ParseState *pstate, Node *node,
179179
Const*newcon=makeNode(Const);
180180
OidbaseTypeId;
181181
int32baseTypeMod;
182+
int32inputTypeMod;
182183
TypetargetType;
183184
ParseCallbackStatepcbstate;
184185

@@ -190,13 +191,27 @@ coerce_type(ParseState *pstate, Node *node,
190191
* what we want here. The needed check will be applied properly
191192
* inside coerce_to_domain().
192193
*/
193-
baseTypeMod=-1;
194+
baseTypeMod=targetTypeMod;
194195
baseTypeId=getBaseTypeAndTypmod(targetTypeId,&baseTypeMod);
195196

197+
/*
198+
* For most types we pass typmod -1 to the input routine, because
199+
* existing input routines follow implicit-coercion semantics for
200+
* length checks, which is not always what we want here. Any length
201+
* constraint will be applied later by our caller. An exception
202+
* however is the INTERVAL type, for which we *must* pass the typmod
203+
* or it won't be able to obey the bizarre SQL-spec input rules.
204+
* (Ugly as sin, but so is this part of the spec...)
205+
*/
206+
if (baseTypeId==INTERVALOID)
207+
inputTypeMod=baseTypeMod;
208+
else
209+
inputTypeMod=-1;
210+
196211
targetType=typeidType(baseTypeId);
197212

198213
newcon->consttype=baseTypeId;
199-
newcon->consttypmod=-1;
214+
newcon->consttypmod=inputTypeMod;
200215
newcon->constlen=typeLen(targetType);
201216
newcon->constbyval=typeByVal(targetType);
202217
newcon->constisnull=con->constisnull;
@@ -215,20 +230,17 @@ coerce_type(ParseState *pstate, Node *node,
215230
setup_parser_errposition_callback(&pcbstate,pstate,con->location);
216231

217232
/*
218-
* We pass typmod -1 to the input routine, primarily because existing
219-
* input routines follow implicit-coercion semantics for length
220-
* checks, which is not always what we want here. Any length
221-
* constraint will be applied later by our caller.
222-
*
223233
* We assume here that UNKNOWN's internal representation is the same
224234
* as CSTRING.
225235
*/
226236
if (!con->constisnull)
227237
newcon->constvalue=stringTypeDatum(targetType,
228238
DatumGetCString(con->constvalue),
229-
-1);
239+
inputTypeMod);
230240
else
231-
newcon->constvalue=stringTypeDatum(targetType,NULL,-1);
241+
newcon->constvalue=stringTypeDatum(targetType,
242+
NULL,
243+
inputTypeMod);
232244

233245
cancel_parser_errposition_callback(&pcbstate);
234246

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

Lines changed: 73 additions & 12 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.190 2008/06/09 19:34:02 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.191 2008/09/10 18:29:41 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -35,8 +35,8 @@ static int DecodeNumber(int flen, char *field, bool haveTextMonth,
3535
staticintDecodeNumberField(intlen,char*str,
3636
intfmask,int*tmask,
3737
structpg_tm*tm,fsec_t*fsec,bool*is2digits);
38-
staticintDecodeTime(char*str,intfmask,int*tmask,
39-
structpg_tm*tm,fsec_t*fsec);
38+
staticintDecodeTime(char*str,intfmask,intrange,
39+
int*tmask,structpg_tm*tm,fsec_t*fsec);
4040
staticintDecodeTimezone(char*str,int*tzp);
4141
staticconstdatetkn*datebsearch(constchar*key,constdatetkn*base,intnel);
4242
staticintDecodeDate(char*str,intfmask,int*tmask,bool*is2digits,
@@ -832,7 +832,8 @@ DecodeDateTime(char **field, int *ftype, int nf,
832832
break;
833833

834834
caseDTK_TIME:
835-
dterr=DecodeTime(field[i],fmask,&tmask,tm,fsec);
835+
dterr=DecodeTime(field[i],fmask,INTERVAL_FULL_RANGE,
836+
&tmask,tm,fsec);
836837
if (dterr)
837838
returndterr;
838839

@@ -1563,6 +1564,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
15631564

15641565
caseDTK_TIME:
15651566
dterr=DecodeTime(field[i], (fmask |DTK_DATE_M),
1567+
INTERVAL_FULL_RANGE,
15661568
&tmask,tm,fsec);
15671569
if (dterr)
15681570
returndterr;
@@ -2224,7 +2226,8 @@ ValidateDate(int fmask, bool is2digits, bool bc, struct pg_tm * tm)
22242226
* used to represent time spans.
22252227
*/
22262228
staticint
2227-
DecodeTime(char*str,intfmask,int*tmask,structpg_tm*tm,fsec_t*fsec)
2229+
DecodeTime(char*str,intfmask,intrange,
2230+
int*tmask,structpg_tm*tm,fsec_t*fsec)
22282231
{
22292232
char*cp;
22302233

@@ -2245,6 +2248,13 @@ DecodeTime(char *str, int fmask, int *tmask, struct pg_tm * tm, fsec_t *fsec)
22452248
{
22462249
tm->tm_sec=0;
22472250
*fsec=0;
2251+
/* If it's a MINUTE TO SECOND interval, take 2 fields as being mm:ss */
2252+
if (range== (INTERVAL_MASK(MINUTE) |INTERVAL_MASK(SECOND)))
2253+
{
2254+
tm->tm_sec=tm->tm_min;
2255+
tm->tm_min=tm->tm_hour;
2256+
tm->tm_hour=0;
2257+
}
22482258
}
22492259
elseif (*cp!=':')
22502260
returnDTERR_BAD_FORMAT;
@@ -2705,7 +2715,8 @@ DecodeSpecial(int field, char *lowtoken, int *val)
27052715
*preceding an hh:mm:ss field. - thomas 1998-04-30
27062716
*/
27072717
int
2708-
DecodeInterval(char**field,int*ftype,intnf,int*dtype,structpg_tm*tm,fsec_t*fsec)
2718+
DecodeInterval(char**field,int*ftype,intnf,intrange,
2719+
int*dtype,structpg_tm*tm,fsec_t*fsec)
27092720
{
27102721
boolis_before= FALSE;
27112722
char*cp;
@@ -2734,7 +2745,8 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm,
27342745
switch (ftype[i])
27352746
{
27362747
caseDTK_TIME:
2737-
dterr=DecodeTime(field[i],fmask,&tmask,tm,fsec);
2748+
dterr=DecodeTime(field[i],fmask,range,
2749+
&tmask,tm,fsec);
27382750
if (dterr)
27392751
returndterr;
27402752
type=DTK_DAY;
@@ -2757,7 +2769,8 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm,
27572769
while (*cp!='\0'&&*cp!=':'&&*cp!='.')
27582770
cp++;
27592771
if (*cp==':'&&
2760-
DecodeTime(field[i]+1,fmask,&tmask,tm,fsec)==0)
2772+
DecodeTime(field[i]+1,fmask,INTERVAL_FULL_RANGE,
2773+
&tmask,tm,fsec)==0)
27612774
{
27622775
if (*field[i]=='-')
27632776
{
@@ -2796,19 +2809,66 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm,
27962809
type=DTK_HOUR;
27972810
}
27982811
}
2799-
/*DROP THROUGH */
2812+
/*FALL THROUGH */
28002813

28012814
caseDTK_DATE:
28022815
caseDTK_NUMBER:
2816+
if (type==IGNORE_DTF)
2817+
{
2818+
/* use typmod to decide what rightmost integer field is */
2819+
switch (range)
2820+
{
2821+
caseINTERVAL_MASK(YEAR):
2822+
type=DTK_YEAR;
2823+
break;
2824+
caseINTERVAL_MASK(MONTH):
2825+
caseINTERVAL_MASK(YEAR) |INTERVAL_MASK(MONTH):
2826+
type=DTK_MONTH;
2827+
break;
2828+
caseINTERVAL_MASK(DAY):
2829+
type=DTK_DAY;
2830+
break;
2831+
caseINTERVAL_MASK(HOUR):
2832+
caseINTERVAL_MASK(DAY) |INTERVAL_MASK(HOUR):
2833+
caseINTERVAL_MASK(DAY) |INTERVAL_MASK(HOUR) |INTERVAL_MASK(MINUTE):
2834+
caseINTERVAL_MASK(DAY) |INTERVAL_MASK(HOUR) |INTERVAL_MASK(MINUTE) |INTERVAL_MASK(SECOND):
2835+
type=DTK_HOUR;
2836+
break;
2837+
caseINTERVAL_MASK(MINUTE):
2838+
caseINTERVAL_MASK(HOUR) |INTERVAL_MASK(MINUTE):
2839+
type=DTK_MINUTE;
2840+
break;
2841+
caseINTERVAL_MASK(SECOND):
2842+
caseINTERVAL_MASK(HOUR) |INTERVAL_MASK(MINUTE) |INTERVAL_MASK(SECOND):
2843+
caseINTERVAL_MASK(MINUTE) |INTERVAL_MASK(SECOND):
2844+
type=DTK_SECOND;
2845+
break;
2846+
default:
2847+
type=DTK_SECOND;
2848+
break;
2849+
}
2850+
}
2851+
28032852
errno=0;
28042853
val=strtoi(field[i],&cp,10);
28052854
if (errno==ERANGE)
28062855
returnDTERR_FIELD_OVERFLOW;
28072856

2808-
if (type==IGNORE_DTF)
2809-
type=DTK_SECOND;
2857+
if (*cp=='-')
2858+
{
2859+
/* SQL "years-months" syntax */
2860+
intval2;
28102861

2811-
if (*cp=='.')
2862+
val2=strtoi(cp+1,&cp,10);
2863+
if (errno==ERANGE||val2<0||val2 >=MONTHS_PER_YEAR)
2864+
returnDTERR_FIELD_OVERFLOW;
2865+
if (*cp!='\0')
2866+
returnDTERR_BAD_FORMAT;
2867+
type=DTK_MONTH;
2868+
val=val*MONTHS_PER_YEAR+val2;
2869+
fval=0;
2870+
}
2871+
elseif (*cp=='.')
28122872
{
28132873
fval=strtod(cp,&cp);
28142874
if (*cp!='\0')
@@ -2896,6 +2956,7 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm,
28962956
#endif
28972957
}
28982958
tmask=DTK_M(HOUR);
2959+
type=DTK_DAY;
28992960
break;
29002961

29012962
caseDTK_DAY:

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.155 2008/03/25 22:42:44 tgl Exp $
13+
* $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.156 2008/09/10 18:29:41 tgl Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -632,7 +632,8 @@ reltimein(PG_FUNCTION_ARGS)
632632
dterr=ParseDateTime(str,workbuf,sizeof(workbuf),
633633
field,ftype,MAXDATEFIELDS,&nf);
634634
if (dterr==0)
635-
dterr=DecodeInterval(field,ftype,nf,&dtype,tm,&fsec);
635+
dterr=DecodeInterval(field,ftype,nf,INTERVAL_FULL_RANGE,
636+
&dtype,tm,&fsec);
636637
if (dterr!=0)
637638
{
638639
if (dterr==DTERR_FIELD_OVERFLOW)

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

Lines changed: 9 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.190 2008/07/07 18:09:46 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.191 2008/09/10 18:29:41 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -604,6 +604,7 @@ interval_in(PG_FUNCTION_ARGS)
604604
*tm=&tt;
605605
intdtype;
606606
intnf;
607+
intrange;
607608
intdterr;
608609
char*field[MAXDATEFIELDS];
609610
intftype[MAXDATEFIELDS];
@@ -617,10 +618,15 @@ interval_in(PG_FUNCTION_ARGS)
617618
tm->tm_sec=0;
618619
fsec=0;
619620

621+
if (typmod >=0)
622+
range=INTERVAL_RANGE(typmod);
623+
else
624+
range=INTERVAL_FULL_RANGE;
625+
620626
dterr=ParseDateTime(str,workbuf,sizeof(workbuf),field,
621627
ftype,MAXDATEFIELDS,&nf);
622628
if (dterr==0)
623-
dterr=DecodeInterval(field,ftype,nf,&dtype,tm,&fsec);
629+
dterr=DecodeInterval(field,ftype,nf,range,&dtype,tm,&fsec);
624630
if (dterr!=0)
625631
{
626632
if (dterr==DTERR_FIELD_OVERFLOW)
@@ -945,7 +951,7 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
945951
* Unspecified range and precision? Then not necessary to adjust. Setting
946952
* typmod to -1 is the convention for all types.
947953
*/
948-
if (typmod!=-1)
954+
if (typmod>=0)
949955
{
950956
intrange=INTERVAL_RANGE(typmod);
951957
intprecision=INTERVAL_PRECISION(typmod);

‎src/include/utils/datetime.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
1010
* Portions Copyright (c) 1994, Regents of the University of California
1111
*
12-
* $PostgreSQL: pgsql/src/include/utils/datetime.h,v 1.69 2008/01/01 19:45:59 momjian Exp $
12+
* $PostgreSQL: pgsql/src/include/utils/datetime.h,v 1.70 2008/09/10 18:29:41 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -290,7 +290,7 @@ extern int DecodeTimeOnly(char **field, int *ftype,
290290
intnf,int*dtype,
291291
structpg_tm*tm,fsec_t*fsec,int*tzp);
292292
externintDecodeInterval(char**field,int*ftype,
293-
intnf,int*dtype,
293+
intnf,intrange,int*dtype,
294294
structpg_tm*tm,fsec_t*fsec);
295295
externvoidDateTimeParseError(intdterr,constchar*str,
296296
constchar*datatype);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp