1
1
/* -----------------------------------------------------------------------
2
2
* formatting.c
3
3
*
4
- * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.79 2004/10/13 01:25:11 neilc Exp $
4
+ * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.80 2004/10/28 18:55:06 tgl Exp $
5
5
*
6
6
*
7
7
* Portions Copyright (c) 1999-2004, PostgreSQL Global Development Group
@@ -853,7 +853,8 @@ typedef struct NUMProc
853
853
num_pre , /* space before first number */
854
854
855
855
read_dec , /* to_number - was read dec. point */
856
- read_post ; /* to_number - number of dec. digit */
856
+ read_post , /* to_number - number of dec. digit */
857
+ read_pre ; /* to_number - number non-dec. digit */
857
858
858
859
char * number , /* string with number */
859
860
* number_p , /* pointer to current number position */
@@ -3623,15 +3624,18 @@ get_last_relevant_decnum(char *num)
3623
3624
static void
3624
3625
NUM_numpart_from_char (NUMProc * Np , int id , int plen )
3625
3626
{
3626
-
3627
+ bool isread = FALSE;
3628
+
3627
3629
#ifdef DEBUG_TO_FROM_CHAR
3628
- elog (DEBUG_elog_output , " --- scan start --- " );
3630
+ elog (DEBUG_elog_output , " --- scan start --- id=%s" ,
3631
+ (id == NUM_0 || id == NUM_9 ) ? "NUM_0/9" : id == NUM_DEC ? "NUM_DEC" : "???" );
3629
3632
#endif
3630
3633
3631
3634
if (* Np -> inout_p == ' ' )
3632
3635
Np -> inout_p ++ ;
3633
3636
3634
3637
#define OVERLOAD_TEST (Np->inout_p >= Np->inout + plen)
3638
+ #define AMOUNT_TEST (_s ) (plen-(Np->inout_p-Np->inout) >= _s)
3635
3639
3636
3640
if (* Np -> inout_p == ' ' )
3637
3641
Np -> inout_p ++ ;
@@ -3640,68 +3644,73 @@ NUM_numpart_from_char(NUMProc *Np, int id, int plen)
3640
3644
return ;
3641
3645
3642
3646
/*
3643
- * read sign
3647
+ * read sign before number
3644
3648
*/
3645
- if (* Np -> number == ' ' && (id == NUM_0 || id == NUM_9 || NUM_S ))
3649
+ if (* Np -> number == ' ' && (id == NUM_0 || id == NUM_9 ) &&
3650
+ (Np -> read_pre + Np -> read_post )== 0 )
3646
3651
{
3647
3652
3648
3653
#ifdef DEBUG_TO_FROM_CHAR
3649
- elog (DEBUG_elog_output , "Try read sign (%c)" , * Np -> inout_p );
3654
+ elog (DEBUG_elog_output , "Try read sign (%c), locale positive: %s, negative: %s" ,
3655
+ * Np -> inout_p , Np -> L_positive_sign , Np -> L_negative_sign );
3650
3656
#endif
3651
3657
3652
3658
/*
3653
3659
* locale sign
3654
3660
*/
3655
- if (IS_LSIGN (Np -> Num ))
3661
+ if (IS_LSIGN (Np -> Num ) && Np -> Num -> lsign == NUM_LSIGN_PRE )
3656
3662
{
3657
-
3658
- int x = strlen (Np -> L_negative_sign );
3659
-
3663
+ int x = 0 ;
3660
3664
#ifdef DEBUG_TO_FROM_CHAR
3661
- elog (DEBUG_elog_output , "Try read locale sign (%c)" , * Np -> inout_p );
3665
+ elog (DEBUG_elog_output , "Try read locale pre- sign (%c)" , * Np -> inout_p );
3662
3666
#endif
3663
- if (!strncmp (Np -> inout_p , Np -> L_negative_sign , x ))
3667
+ if ((x = strlen (Np -> L_negative_sign )) &&
3668
+ AMOUNT_TEST (x ) &&
3669
+ strncmp (Np -> inout_p , Np -> L_negative_sign , x )== 0 )
3664
3670
{
3665
- Np -> inout_p += x - 1 ;
3671
+ Np -> inout_p += x ;
3666
3672
* Np -> number = '-' ;
3667
- return ;
3668
3673
}
3669
-
3670
- x = strlen ( Np -> L_positive_sign );
3671
- if (! strncmp (Np -> inout_p , Np -> L_positive_sign , x ))
3674
+ else if (( x = strlen ( Np -> L_positive_sign )) &&
3675
+ AMOUNT_TEST ( x ) &&
3676
+ strncmp (Np -> inout_p , Np -> L_positive_sign , x )== 0 )
3672
3677
{
3673
- Np -> inout_p += x - 1 ;
3678
+ Np -> inout_p += x ;
3674
3679
* Np -> number = '+' ;
3675
- return ;
3676
3680
}
3677
3681
}
3678
-
3682
+ else
3683
+ {
3679
3684
#ifdef DEBUG_TO_FROM_CHAR
3680
- elog (DEBUG_elog_output , "Try read simple sign (%c)" , * Np -> inout_p );
3685
+ elog (DEBUG_elog_output , "Try read simple sign (%c)" , * Np -> inout_p );
3681
3686
#endif
3687
+ /*
3688
+ * simple + - < >
3689
+ */
3690
+ if (* Np -> inout_p == '-' || (IS_BRACKET (Np -> Num ) &&
3691
+ * Np -> inout_p == '<' ))
3692
+ {
3682
3693
3683
- /*
3684
- * simple + - < >
3685
- */
3686
- if (* Np -> inout_p == '-' || (IS_BRACKET (Np -> Num ) &&
3687
- * Np -> inout_p == '<' ))
3688
- {
3689
-
3690
- * Np -> number = '-' ; /* set - */
3691
- Np -> inout_p ++ ;
3694
+ * Np -> number = '-' ; /* set - */
3695
+ Np -> inout_p ++ ;
3692
3696
3693
- }
3694
- else if (* Np -> inout_p == '+' )
3695
- {
3697
+ }
3698
+ else if (* Np -> inout_p == '+' )
3699
+ {
3696
3700
3697
- * Np -> number = '+' ; /* set + */
3698
- Np -> inout_p ++ ;
3701
+ * Np -> number = '+' ; /* set + */
3702
+ Np -> inout_p ++ ;
3703
+ }
3699
3704
}
3700
3705
}
3701
3706
3702
3707
if (OVERLOAD_TEST )
3703
3708
return ;
3704
-
3709
+
3710
+ #ifdef DEBUG_TO_FROM_CHAR
3711
+ elog (DEBUG_elog_output , "Scan for numbers (%c), current number: '%s'" , * Np -> inout_p , Np -> number );
3712
+ #endif
3713
+
3705
3714
/*
3706
3715
* read digit
3707
3716
*/
@@ -3716,16 +3725,19 @@ NUM_numpart_from_char(NUMProc *Np, int id, int plen)
3716
3725
3717
3726
if (Np -> read_dec )
3718
3727
Np -> read_post ++ ;
3728
+ else
3729
+ Np -> read_pre ++ ;
3719
3730
3731
+ isread = TRUE;
3732
+
3720
3733
#ifdef DEBUG_TO_FROM_CHAR
3721
3734
elog (DEBUG_elog_output , "Read digit (%c)" , * Np -> inout_p );
3722
3735
#endif
3723
-
3724
- /*
3725
- * read decimal point
3726
- */
3736
+ /*
3737
+ * read decimal point
3738
+ */
3727
3739
}
3728
- else if (IS_DECIMAL (Np -> Num ))
3740
+ else if (IS_DECIMAL (Np -> Num ) && Np -> read_dec == FALSE )
3729
3741
{
3730
3742
3731
3743
#ifdef DEBUG_TO_FROM_CHAR
@@ -3737,7 +3749,7 @@ NUM_numpart_from_char(NUMProc *Np, int id, int plen)
3737
3749
* Np -> number_p = '.' ;
3738
3750
Np -> number_p ++ ;
3739
3751
Np -> read_dec = TRUE;
3740
-
3752
+ isread = TRUE;
3741
3753
}
3742
3754
else
3743
3755
{
@@ -3747,15 +3759,90 @@ NUM_numpart_from_char(NUMProc *Np, int id, int plen)
3747
3759
elog (DEBUG_elog_output , "Try read locale point (%c)" ,
3748
3760
* Np -> inout_p );
3749
3761
#endif
3750
- if (! strncmp (Np -> inout_p , Np -> decimal , x ))
3762
+ if (x && AMOUNT_TEST ( x ) && strncmp (Np -> inout_p , Np -> decimal , x )== 0 )
3751
3763
{
3752
3764
Np -> inout_p += x - 1 ;
3753
3765
* Np -> number_p = '.' ;
3754
3766
Np -> number_p ++ ;
3755
3767
Np -> read_dec = TRUE;
3768
+ isread = TRUE;
3756
3769
}
3757
3770
}
3758
3771
}
3772
+
3773
+ if (OVERLOAD_TEST )
3774
+ return ;
3775
+
3776
+ /*
3777
+ * Read sign behind "last" number
3778
+ *
3779
+ * We need sign detection because determine exact position of
3780
+ * post-sign is difficult:
3781
+ *
3782
+ * FM9999.9999999S -> 123.001-
3783
+ * 9.9S -> .5-
3784
+ * FM9.999999MI -> 5.01-
3785
+ */
3786
+ if (* Np -> number == ' ' && Np -> read_pre + Np -> read_post > 0 )
3787
+ {
3788
+ /*
3789
+ * locale sign (NUM_S) is always anchored behind a last number, if:
3790
+ * - locale sign expected
3791
+ * - last read char was NUM_0/9 or NUM_DEC
3792
+ * - and next char is not digit
3793
+ */
3794
+ if (IS_LSIGN (Np -> Num ) && isread &&
3795
+ (Np -> inout_p + 1 ) <= Np -> inout + plen &&
3796
+ isdigit (* (Np -> inout_p + 1 ))== 0 )
3797
+ {
3798
+ int x ;
3799
+ char * tmp = Np -> inout_p ++ ;
3800
+
3801
+ #ifdef DEBUG_TO_FROM_CHAR
3802
+ elog (DEBUG_elog_output , "Try read locale post-sign (%c)" , * Np -> inout_p );
3803
+ #endif
3804
+ if ((x = strlen (Np -> L_negative_sign )) &&
3805
+ AMOUNT_TEST (x ) &&
3806
+ strncmp (Np -> inout_p , Np -> L_negative_sign , x )== 0 )
3807
+ {
3808
+ Np -> inout_p += x - 1 ; /* -1 .. NUM_processor() do inout_p++ */
3809
+ * Np -> number = '-' ;
3810
+ }
3811
+ else if ((x = strlen (Np -> L_positive_sign )) &&
3812
+ AMOUNT_TEST (x ) &&
3813
+ strncmp (Np -> inout_p , Np -> L_positive_sign , x )== 0 )
3814
+ {
3815
+ Np -> inout_p += x - 1 ; /* -1 .. NUM_processor() do inout_p++ */
3816
+ * Np -> number = '+' ;
3817
+ }
3818
+ if (* Np -> number == ' ' )
3819
+ /* no sign read */
3820
+ Np -> inout_p = tmp ;
3821
+ }
3822
+
3823
+ /*
3824
+ * try read non-locale sign, it's happen only if format is not exact
3825
+ * and we cannot determine sign position of MI/PL/SG, an example:
3826
+ *
3827
+ * FM9.999999MI -> 5.01-
3828
+ *
3829
+ * if (.... && IS_LSIGN(Np->Num)==FALSE) prevents read wrong formats
3830
+ * like to_number('1 -', '9S') where sign is not anchored to last number.
3831
+ */
3832
+ else if (isread == FALSE && IS_LSIGN (Np -> Num )== FALSE &&
3833
+ (IS_PLUS (Np -> Num ) || IS_MINUS (Np -> Num )))
3834
+ {
3835
+ #ifdef DEBUG_TO_FROM_CHAR
3836
+ elog (DEBUG_elog_output , "Try read simple post-sign (%c)" , * Np -> inout_p );
3837
+ #endif
3838
+ /*
3839
+ * simple + -
3840
+ */
3841
+ if (* Np -> inout_p == '-' || * Np -> inout_p == '+' )
3842
+ /* NUM_processor() do inout_p++ */
3843
+ * Np -> number = * Np -> inout_p ;
3844
+ }
3845
+ }
3759
3846
}
3760
3847
3761
3848
#define IS_PREDEC_SPACE (_n ) \
@@ -3978,6 +4065,7 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
3978
4065
Np -> inout = inout ;
3979
4066
Np -> last_relevant = NULL ;
3980
4067
Np -> read_post = 0 ;
4068
+ Np -> read_pre = 0 ;
3981
4069
Np -> read_dec = FALSE;
3982
4070
3983
4071
if (Np -> Num -> zero_start )
@@ -4130,6 +4218,11 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
4130
4218
{
4131
4219
/*
4132
4220
* Create/reading digit/zero/blank/sing
4221
+ *
4222
+ * 'NUM_S' note:
4223
+ * The locale sign is anchored to number and we read/write it
4224
+ * when we work with first or last number (NUM_0/NUM_9). This
4225
+ * is reason why NUM_S missing in follow switch().
4133
4226
*/
4134
4227
switch (n -> key -> id )
4135
4228
{
0 commit comments