1
1
/* -----------------------------------------------------------------------
2
2
* formatting.c
3
3
*
4
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.23 2000/10/29 13:17:34 petere Exp $
4
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.24 2000/11/25 05:00:29 momjian Exp $
5
5
*
6
6
*
7
7
* Portions Copyright (c) 1999-2000, PostgreSQL, Inc
@@ -127,6 +127,7 @@ typedef struct
127
127
int len ,/* keyword length*/
128
128
(* action ) (),
129
129
id ;/* keyword id*/
130
+ bool isdigit ;/* is expected output/input digit */
130
131
}KeyWord ;
131
132
132
133
typedef struct
@@ -344,14 +345,16 @@ static intNUMCounter = 0;
344
345
* ----------
345
346
*/
346
347
typedef struct {
347
- int hh ,am ,pm ,mi ,ss ,ssss ,d ,dd ,ddd ,mm ,yyyy ,bc ,iw ,ww ,w ,cc ,q ,j ;
348
+ int hh ,am ,pm ,mi ,ss ,ssss ,d ,dd ,ddd ,mm ,yyyy ,yyy ,yy ,y ,
349
+ bc ,iw ,ww ,w ,cc ,q ,j ;
348
350
}TmFromChar ;
349
351
350
352
#define ZERO_tmfc (_X )\
351
353
do { \
352
354
(_X)->hh= (_X)->am= (_X)->pm= (_X)->mi= (_X)->ss= (_X)->ssss= \
353
- (_X)->d= (_X)->dd= (_X)->ddd= (_X)->mm= (_X)->yyyy= (_X)->bc= \
354
- (_X)->iw= (_X)->ww= (_X)->w= (_X)->cc= (_X)->q= (_X)->j= 0; \
355
+ (_X)->d= (_X)->dd= (_X)->ddd= (_X)->mm= (_X)->yyyy= (_X)->yyy= \
356
+ (_X)->yy= (_X)->y= (_X)->bc= (_X)->iw= (_X)->ww= (_X)->w= \
357
+ (_X)->cc= (_X)->q= (_X)->j= 0; \
355
358
} while(0)
356
359
357
360
#ifdef DEBUG_TO_FROM_CHAR
@@ -453,7 +456,7 @@ static KeySuffix DCH_suff[] = {
453
456
* it is not good.
454
457
*
455
458
* (!)
456
- * Position for the keyword is simular as position in the enum DCH/NUM_poz
459
+ *- Position for the keyword is simular as position in the enum DCH/NUM_poz.
457
460
* (!)
458
461
*
459
462
* For fast search is used the 'int index[]', index is ascii table from position
@@ -598,88 +601,88 @@ typedef enum
598
601
* ----------
599
602
*/
600
603
static KeyWord DCH_keywords []= {
601
- /*keyword,len,func. type is in Index */
602
- {"A.D." ,4 ,dch_date ,DCH_A_D },/* A */
603
- {"A.M." ,4 ,dch_time ,DCH_A_M },
604
- {"AD" ,2 ,dch_date ,DCH_AD },
605
- {"AM" ,2 ,dch_time ,DCH_AM },
606
- {"B.C." ,4 ,dch_date ,DCH_B_C },/* B */
607
- {"BC" ,2 ,dch_date ,DCH_BC },
608
- {"CC" ,2 ,dch_date ,DCH_CC },/* C */
609
- {"DAY" ,3 ,dch_date ,DCH_DAY },/* D */
610
- {"DDD" ,3 ,dch_date ,DCH_DDD },
611
- {"DD" ,2 ,dch_date ,DCH_DD },
612
- {"DY" ,2 ,dch_date ,DCH_DY },
613
- {"Day" ,3 ,dch_date ,DCH_Day },
614
- {"Dy" ,2 ,dch_date ,DCH_Dy },
615
- {"D" ,1 ,dch_date ,DCH_D },
616
- {"FX" ,2 ,dch_global ,DCH_FX },/* F */
617
- {"HH24" ,4 ,dch_time ,DCH_HH24 }, /* H */
618
- {"HH12" ,4 ,dch_time ,DCH_HH12 },
619
- {"HH" ,2 ,dch_time ,DCH_HH },
620
- {"IW" ,2 ,dch_date ,DCH_IW },/* I */
621
- {"J" ,1 ,dch_date ,DCH_J },/* J */
622
- {"MI" ,2 ,dch_time ,DCH_MI },
623
- {"MM" ,2 ,dch_date ,DCH_MM },
624
- {"MONTH" ,5 ,dch_date ,DCH_MONTH },
625
- {"MON" ,3 ,dch_date ,DCH_MON },
626
- {"Month" ,5 ,dch_date ,DCH_Month },
627
- {"Mon" ,3 ,dch_date ,DCH_Mon },
628
- {"P.M." ,4 ,dch_time ,DCH_P_M },/* P */
629
- {"PM" ,2 ,dch_time ,DCH_PM },
630
- {"Q" ,1 ,dch_date ,DCH_Q },/* Q */
631
- {"RM" ,2 ,dch_date ,DCH_RM },/* R */
632
- {"SSSS" ,4 ,dch_time ,DCH_SSSS },/* S */
633
- {"SS" ,2 ,dch_time ,DCH_SS },
634
- {"TZ" ,2 ,dch_time ,DCH_TZ },/* T */
635
- {"WW" ,2 ,dch_date ,DCH_WW },/* W */
636
- {"W" ,1 ,dch_date ,DCH_W },
637
- {"Y,YYY" ,5 ,dch_date ,DCH_Y_YYY },/* Y */
638
- {"YYYY" ,4 ,dch_date ,DCH_YYYY },
639
- {"YYY" ,3 ,dch_date ,DCH_YYY },
640
- {"YY" ,2 ,dch_date ,DCH_YY },
641
- {"Y" ,1 ,dch_date ,DCH_Y },
642
- {"a.d." ,4 ,dch_date ,DCH_a_d },/* a */
643
- {"a.m." ,4 ,dch_time ,DCH_a_m },
644
- {"ad" ,2 ,dch_date ,DCH_ad },
645
- {"am" ,2 ,dch_time ,DCH_am },
646
- {"b.c." ,4 ,dch_date ,DCH_b_c },/* b */
647
- {"bc" ,2 ,dch_date ,DCH_bc },
648
- {"cc" ,2 ,dch_date ,DCH_CC },/* c */
649
- {"day" ,3 ,dch_date ,DCH_day },/* d */
650
- {"ddd" ,3 ,dch_date ,DCH_DDD },
651
- {"dd" ,2 ,dch_date ,DCH_DD },
652
- {"dy" ,2 ,dch_date ,DCH_dy },
653
- {"d" ,1 ,dch_date ,DCH_D },
654
- {"fx" ,2 ,dch_global ,DCH_FX },/* f */
655
- {"hh24" ,4 ,dch_time ,DCH_HH24 }, /* h */
656
- {"hh12" ,4 ,dch_time ,DCH_HH12 },
657
- {"hh" ,2 ,dch_time ,DCH_HH },
658
- {"iw" ,2 ,dch_date ,DCH_IW },/* i */
659
- {"j" ,1 ,dch_time ,DCH_J },/* j */
660
- {"mi" ,2 ,dch_time ,DCH_MI },/* m */
661
- {"mm" ,2 ,dch_date ,DCH_MM },
662
- {"month" ,5 ,dch_date ,DCH_month },
663
- {"mon" ,3 ,dch_date ,DCH_mon },
664
- {"p.m." ,4 ,dch_time ,DCH_p_m },/* p */
665
- {"pm" ,2 ,dch_time ,DCH_pm },
666
- {"q" ,1 ,dch_date ,DCH_Q },/* q */
667
- {"rm" ,2 ,dch_date ,DCH_rm },/* r */
668
- {"ssss" ,4 ,dch_time ,DCH_SSSS },/* s */
669
- {"ss" ,2 ,dch_time ,DCH_SS },
670
- {"tz" ,2 ,dch_time ,DCH_tz },/* t */
671
- {"ww" ,2 ,dch_date ,DCH_WW },/* w */
672
- {"w" ,1 ,dch_date ,DCH_W },
673
- {"y,yyy" ,5 ,dch_date ,DCH_Y_YYY },/* y */
674
- {"yyyy" ,4 ,dch_date ,DCH_YYYY },
675
- {"yyy" ,3 ,dch_date ,DCH_YYY },
676
- {"yy" ,2 ,dch_date ,DCH_YY },
677
- {"y" ,1 ,dch_date ,DCH_Y },
604
+ /*keyword, len, func, type, isdigit is in Index */
605
+ {"A.D." ,4 ,dch_date ,DCH_A_D , FALSE },/* A */
606
+ {"A.M." ,4 ,dch_time ,DCH_A_M , FALSE },
607
+ {"AD" ,2 ,dch_date ,DCH_AD , FALSE },
608
+ {"AM" ,2 ,dch_time ,DCH_AM , FALSE },
609
+ {"B.C." ,4 ,dch_date ,DCH_B_C , FALSE },/* B */
610
+ {"BC" ,2 ,dch_date ,DCH_BC , FALSE },
611
+ {"CC" ,2 ,dch_date ,DCH_CC , TRUE },/* C */
612
+ {"DAY" ,3 ,dch_date ,DCH_DAY , FALSE },/* D */
613
+ {"DDD" ,3 ,dch_date ,DCH_DDD , TRUE },
614
+ {"DD" ,2 ,dch_date ,DCH_DD , TRUE },
615
+ {"DY" ,2 ,dch_date ,DCH_DY , FALSE },
616
+ {"Day" ,3 ,dch_date ,DCH_Day , FALSE },
617
+ {"Dy" ,2 ,dch_date ,DCH_Dy , FALSE },
618
+ {"D" ,1 ,dch_date ,DCH_D , TRUE },
619
+ {"FX" ,2 ,dch_global ,DCH_FX , FALSE },/* F */
620
+ {"HH24" ,4 ,dch_time ,DCH_HH24 , TRUE}, /* H */
621
+ {"HH12" ,4 ,dch_time ,DCH_HH12 , TRUE },
622
+ {"HH" ,2 ,dch_time ,DCH_HH , TRUE },
623
+ {"IW" ,2 ,dch_date ,DCH_IW , TRUE },/* I */
624
+ {"J" ,1 ,dch_date ,DCH_J , TRUE },/* J */
625
+ {"MI" ,2 ,dch_time ,DCH_MI , TRUE },
626
+ {"MM" ,2 ,dch_date ,DCH_MM , TRUE },
627
+ {"MONTH" ,5 ,dch_date ,DCH_MONTH , FALSE },
628
+ {"MON" ,3 ,dch_date ,DCH_MON , FALSE },
629
+ {"Month" ,5 ,dch_date ,DCH_Month , FALSE },
630
+ {"Mon" ,3 ,dch_date ,DCH_Mon , FALSE },
631
+ {"P.M." ,4 ,dch_time ,DCH_P_M , FALSE },/* P */
632
+ {"PM" ,2 ,dch_time ,DCH_PM , FALSE },
633
+ {"Q" ,1 ,dch_date ,DCH_Q , TRUE },/* Q */
634
+ {"RM" ,2 ,dch_date ,DCH_RM , FALSE },/* R */
635
+ {"SSSS" ,4 ,dch_time ,DCH_SSSS , TRUE },/* S */
636
+ {"SS" ,2 ,dch_time ,DCH_SS , TRUE },
637
+ {"TZ" ,2 ,dch_time ,DCH_TZ , FALSE },/* T */
638
+ {"WW" ,2 ,dch_date ,DCH_WW , TRUE },/* W */
639
+ {"W" ,1 ,dch_date ,DCH_W , TRUE },
640
+ {"Y,YYY" ,5 ,dch_date ,DCH_Y_YYY , TRUE },/* Y */
641
+ {"YYYY" ,4 ,dch_date ,DCH_YYYY , TRUE },
642
+ {"YYY" ,3 ,dch_date ,DCH_YYY , TRUE },
643
+ {"YY" ,2 ,dch_date ,DCH_YY , TRUE },
644
+ {"Y" ,1 ,dch_date ,DCH_Y , TRUE },
645
+ {"a.d." ,4 ,dch_date ,DCH_a_d , FALSE },/* a */
646
+ {"a.m." ,4 ,dch_time ,DCH_a_m , FALSE },
647
+ {"ad" ,2 ,dch_date ,DCH_ad , FALSE },
648
+ {"am" ,2 ,dch_time ,DCH_am , FALSE },
649
+ {"b.c." ,4 ,dch_date ,DCH_b_c , FALSE },/* b */
650
+ {"bc" ,2 ,dch_date ,DCH_bc , FALSE },
651
+ {"cc" ,2 ,dch_date ,DCH_CC , TRUE },/* c */
652
+ {"day" ,3 ,dch_date ,DCH_day , FALSE },/* d */
653
+ {"ddd" ,3 ,dch_date ,DCH_DDD , TRUE },
654
+ {"dd" ,2 ,dch_date ,DCH_DD , TRUE },
655
+ {"dy" ,2 ,dch_date ,DCH_dy , FALSE },
656
+ {"d" ,1 ,dch_date ,DCH_D , TRUE },
657
+ {"fx" ,2 ,dch_global ,DCH_FX , FALSE },/* f */
658
+ {"hh24" ,4 ,dch_time ,DCH_HH24 , TRUE}, /* h */
659
+ {"hh12" ,4 ,dch_time ,DCH_HH12 , TRUE },
660
+ {"hh" ,2 ,dch_time ,DCH_HH , TRUE },
661
+ {"iw" ,2 ,dch_date ,DCH_IW , TRUE },/* i */
662
+ {"j" ,1 ,dch_time ,DCH_J , TRUE },/* j */
663
+ {"mi" ,2 ,dch_time ,DCH_MI , TRUE },/* m */
664
+ {"mm" ,2 ,dch_date ,DCH_MM , TRUE },
665
+ {"month" ,5 ,dch_date ,DCH_month , FALSE },
666
+ {"mon" ,3 ,dch_date ,DCH_mon , FALSE },
667
+ {"p.m." ,4 ,dch_time ,DCH_p_m , FALSE },/* p */
668
+ {"pm" ,2 ,dch_time ,DCH_pm , FALSE },
669
+ {"q" ,1 ,dch_date ,DCH_Q , TRUE },/* q */
670
+ {"rm" ,2 ,dch_date ,DCH_rm , FALSE },/* r */
671
+ {"ssss" ,4 ,dch_time ,DCH_SSSS , TRUE },/* s */
672
+ {"ss" ,2 ,dch_time ,DCH_SS , TRUE },
673
+ {"tz" ,2 ,dch_time ,DCH_tz , FALSE },/* t */
674
+ {"ww" ,2 ,dch_date ,DCH_WW , TRUE },/* w */
675
+ {"w" ,1 ,dch_date ,DCH_W , TRUE },
676
+ {"y,yyy" ,5 ,dch_date ,DCH_Y_YYY , TRUE },/* y */
677
+ {"yyyy" ,4 ,dch_date ,DCH_YYYY , TRUE },
678
+ {"yyy" ,3 ,dch_date ,DCH_YYY , TRUE },
679
+ {"yy" ,2 ,dch_date ,DCH_YY , TRUE },
680
+ {"y" ,1 ,dch_date ,DCH_Y , TRUE },
678
681
/* last */
679
682
{NULL ,0 ,NULL ,0 }};
680
683
681
684
/* ----------
682
- * KeyWords for NUMBER version
685
+ * KeyWords for NUMBER version (now, isdigit info is not needful here..)
683
686
* ----------
684
687
*/
685
688
static KeyWord NUM_keywords []= {
@@ -1230,7 +1233,7 @@ DCH_processor(FormatNode *node, char *inout, int flag)
1230
1233
* Skip blank space in FROM_CHAR's input
1231
1234
* ----------
1232
1235
*/
1233
- if (isspace (n -> character )&& IS_FX == 0 )
1236
+ if (isspace (n -> character )&& IS_FX == 0 )
1234
1237
{
1235
1238
while (* s != '\0' && isspace ((int )* (s + 1 )))
1236
1239
++ s ;
@@ -1526,6 +1529,40 @@ dch_global(int arg, char *inout, int suf, int flag, FormatNode *node)
1526
1529
return -1 ;
1527
1530
}
1528
1531
1532
+ /* ----------
1533
+ * Return TRUE if next format picture is not digit value
1534
+ * ----------
1535
+ */
1536
+ static bool
1537
+ is_next_separator (FormatNode * n )
1538
+ {
1539
+ if (n -> type == NODE_TYPE_END )
1540
+ return FALSE;
1541
+
1542
+ if (n -> type == NODE_TYPE_ACTION && S_THth (n -> suffix ))
1543
+ return TRUE;
1544
+
1545
+ /*
1546
+ * Next node
1547
+ */
1548
+ n ++ ;
1549
+
1550
+ if (n -> type == NODE_TYPE_END )
1551
+ return FALSE;
1552
+
1553
+ if (n -> type == NODE_TYPE_ACTION )
1554
+ {
1555
+ if (n -> key -> isdigit )
1556
+ return FALSE;
1557
+
1558
+ return TRUE;
1559
+ }
1560
+ else if (isdigit (n -> character ))
1561
+ return FALSE;
1562
+
1563
+ return TRUE;/* some non-digit input (separator) */
1564
+ }
1565
+
1529
1566
#define AMPM_ERROR elog(ERROR, "to_timestamp(): bad AM/PM string")
1530
1567
1531
1568
/* ----------
@@ -1736,7 +1773,10 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node)
1736
1773
}
1737
1774
else if (flag == FROM_CHAR )
1738
1775
{
1739
- sscanf (inout ,"%d" ,& tmfc -> ssss );
1776
+ if (is_next_separator (node ))
1777
+ sscanf (inout ,"%d" ,& tmfc -> ssss );
1778
+ else
1779
+ sscanf (inout ,"%05d" ,& tmfc -> ssss );
1740
1780
return int4len ((int4 )tmfc -> ssss )- 1 + SKIP_THth (suf );
1741
1781
}
1742
1782
break ;
@@ -2192,7 +2232,11 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
2192
2232
}
2193
2233
else if (flag == FROM_CHAR )
2194
2234
{
2195
- sscanf (inout ,"%d" ,& tmfc -> yyyy );
2235
+ if (is_next_separator (node ))
2236
+ sscanf (inout ,"%d" ,& tmfc -> yyyy );
2237
+ else
2238
+ sscanf (inout ,"%04d" ,& tmfc -> yyyy );
2239
+
2196
2240
if (!S_FM (suf )&& tmfc -> yyyy <=9999 && tmfc -> yyyy >=-9999 )
2197
2241
len = 4 ;
2198
2242
else
@@ -2217,7 +2261,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
2217
2261
}
2218
2262
else if (flag == FROM_CHAR )
2219
2263
{
2220
- sscanf (inout ,"%03d" ,& tmfc -> yyyy );
2264
+ sscanf (inout ,"%03d" ,& tmfc -> yyy );
2221
2265
return 2 + SKIP_THth (suf );
2222
2266
}
2223
2267
break ;
@@ -2237,7 +2281,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
2237
2281
}
2238
2282
else if (flag == FROM_CHAR )
2239
2283
{
2240
- sscanf (inout ,"%02d" ,& tmfc -> yyyy );
2284
+ sscanf (inout ,"%02d" ,& tmfc -> yy );
2241
2285
return 1 + SKIP_THth (suf );
2242
2286
}
2243
2287
break ;
@@ -2257,7 +2301,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
2257
2301
}
2258
2302
else if (flag == FROM_CHAR )
2259
2303
{
2260
- sscanf (inout ,"%1d" ,& tmfc -> yyyy );
2304
+ sscanf (inout ,"%1d" ,& tmfc -> y );
2261
2305
return 0 + SKIP_THth (suf );
2262
2306
}
2263
2307
break ;
@@ -2725,15 +2769,55 @@ to_timestamp(PG_FUNCTION_ARGS)
2725
2769
2726
2770
if (tmfc -> yyyy )
2727
2771
tm -> tm_year = tmfc -> yyyy ;
2772
+
2773
+ else if (tmfc -> y )
2774
+ {
2775
+ /*
2776
+ * 1-digit year:
2777
+ *always +2000
2778
+ */
2779
+ tm -> tm_year = tmfc -> y + 2000 ;
2780
+ }
2781
+ else if (tmfc -> yy )
2782
+ {
2783
+ /*
2784
+ * 2-digit year:
2785
+ *'00' ... '69' = 2000 ... 2069
2786
+ *'70' ... '99' = 1970 ... 1999
2787
+ */
2788
+ tm -> tm_year = tmfc -> yy ;
2728
2789
2729
- if (tmfc -> j )
2730
- j2date (tmfc -> j ,& tm -> tm_year ,& tm -> tm_mon ,& tm -> tm_mday );
2790
+ if (tm -> tm_year < 70 )
2791
+ tm -> tm_year += 2000 ;
2792
+ else
2793
+ tm -> tm_year += 1900 ;
2794
+ }
2795
+ else if (tmfc -> yyy )
2796
+ {
2797
+ /*
2798
+ * 3-digit year:
2799
+ *'100' ... '999' = 1100 ... 1999
2800
+ *'000' ... '099' = 2000 ... 2099
2801
+ */
2802
+ tm -> tm_year = tmfc -> yyy ;
2731
2803
2732
- if (tmfc -> bc && tm -> tm_year > 0 )
2733
- tm -> tm_year = - (tm -> tm_year );
2804
+ if (tm -> tm_year >=100 )
2805
+ tm -> tm_year += 1000 ;
2806
+ else
2807
+ tm -> tm_year += 2000 ;
2808
+ }
2809
+
2810
+
2811
+ if (tmfc -> bc )
2812
+ {
2813
+ if (tm -> tm_year > 0 )
2814
+ tm -> tm_year = - (tm -> tm_year - 1 );
2815
+ else
2816
+ elog (ERROR ,"Inconsistant use of year %04d and 'BC'" ,tm -> tm_year );
2817
+ }
2734
2818
2735
- if (tm -> tm_year < 0 )
2736
- tm -> tm_year = tm -> tm_year + 1 ;
2819
+ if (tmfc -> j )
2820
+ j2date ( tmfc -> j , & tm -> tm_year , & tm -> tm_mon , & tm -> tm_mday ) ;
2737
2821
2738
2822
if (tmfc -> iw )
2739
2823
isoweek2date (tmfc -> iw ,& tm -> tm_year ,& tm -> tm_mon ,& tm -> tm_mday );