Changeset: eacb72db0f0a for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=eacb72db0f0a
Branch: Jun2020
Log Message:

Merge with Jun2020-decimals.


diffs (truncated from 539 to 300 lines):

diff --git a/sql/backends/monet5/sql_result.c b/sql/backends/monet5/sql_result.c
--- a/sql/backends/monet5/sql_result.c
+++ b/sql/backends/monet5/sql_result.c
@@ -2031,6 +2031,8 @@ get_print_width(int mtype, sql_class ecl
                count = 1 + digits;
                if (scale > 0)
                        count += 1;
+               if (scale == digits) // for preceding 0, e.g. 0.
+                       count += 1;
                return count;
        } else if (eclass == EC_DATE) {
                return 10;
diff --git a/sql/backends/monet5/sql_round_impl.h 
b/sql/backends/monet5/sql_round_impl.h
--- a/sql/backends/monet5/sql_round_impl.h
+++ b/sql/backends/monet5/sql_round_impl.h
@@ -263,36 +263,25 @@ str
 str_2dec(TYPE *res, const str *val, const int *d, const int *sc)
 {
        char *s;
-       char *dot, *end;
        int digits;
        int scale;
        BIG value;
 
-       s = *val;
-       if (strNil(s)) {
-               *res = NIL(TYPE);
-               return MAL_SUCCEED;
-       }
-       dot = strchr(s, '.');
-       if (dot != NULL) {
-               s = strip_extra_zeros(s);
-               digits = _strlen(s) - 1;
-               scale = _strlen(dot + 1);
-       } else {
-               digits = _strlen(s);
-               scale = 0;
-       }
-       end = NULL;
-       value = 0;
-
-       if (digits < 0)
-               throw(SQL, STRING(TYPE), SQLSTATE(42000) "Decimal (%s) doesn't 
have format (%d.%d)", *val, *d, *sc);
        if (*d < 0 || *d >= (int) (sizeof(scales) / sizeof(scales[0])))
                throw(SQL, STRING(TYPE), SQLSTATE(42000) "Decimal (%s) doesn't 
have format (%d.%d)", *val, *d, *sc);
 
-       value = decimal_from_str(s, &end);
-       if (*s == '+' || *s == '-')
-               digits--;
+       s = *val;
+
+       int has_errors;
+       value = 0;
+
+       // s = strip_extra_zeros(s);
+
+       value = decimal_from_str(s, &digits, &scale, &has_errors);
+       if (has_errors)
+               throw(SQL, STRING(TYPE), SQLSTATE(42000) "Decimal (%s) doesn't 
have format (%d.%d)", *val, *d, *sc);
+
+       // handle situations where the de facto scale is different from the 
formal scale.
        if (scale < *sc) {
                /* the current scale is too small, increase it by adding 0's */
                int dff = *sc - scale;  /* CANNOT be 0! */
@@ -323,7 +312,7 @@ str_2dec(TYPE *res, const str *val, cons
                        throw(SQL, STRING(TYPE), SQLSTATE(42000) "Rounding of 
decimal (%s) doesn't fit format (%d.%d)", *val, *d, *sc);
                }
        }
-       if (value <= -scales[*d] || value >= scales[*d]  || *end) {
+       if (value <= -scales[*d] || value >= scales[*d]) {
                throw(SQL, STRING(TYPE), SQLSTATE(42000) "Decimal (%s) doesn't 
have format (%d.%d)", *val, *d, *sc);
        }
        *res = (TYPE) value;
diff --git a/sql/backends/monet5/vaults/shp/shp.c 
b/sql/backends/monet5/vaults/shp/shp.c
--- a/sql/backends/monet5/vaults/shp/shp.c
+++ b/sql/backends/monet5/vaults/shp/shp.c
@@ -16,7 +16,7 @@
 #include <string.h>
 #include "sql_mvc.h"
 #include "sql.h"
-#define HAVE_CXX11 0           /* stupid include file gdal/cpl_port.h */
+#define HAVE_CXX11 1           /* stupid include file gdal/cpl_port.h */
 #ifndef __clang_major__                /* stupid include file gdal/cpl_port.h 
*/
 #define __clang_major__ 0
 #endif
diff --git a/sql/server/sql_decimal.c b/sql/server/sql_decimal.c
--- a/sql/server/sql_decimal.c
+++ b/sql/server/sql_decimal.c
@@ -10,42 +10,121 @@
 
 #include "sql_decimal.h"
 
-#ifdef HAVE_HGE
-hge
-#else
-lng
-#endif
-decimal_from_str(char *dec, char **end)
+static inline
+void parse_digits(DEC_TPE* res, char **dec, int* digits) {
+
+       char*   _dec    = *dec;
+       DEC_TPE _res    = *res;
+       int _digits             = *digits;
+
+       
+
+       *res    = _res;
+       *dec    = _dec;
+       *digits = _digits;
+}
+
+DEC_TPE
+decimal_from_str(char *dec, int* digits, int* scale, int* has_errors)
 {
+
 #ifdef HAVE_HGE
-       hge res = 0;
-       const hge max0 = GDK_hge_max / 10, max1 = GDK_hge_max % 10;
+    const hge max0 = GDK_hge_max / 10, max1 = GDK_hge_max % 10;
 #else
-       lng res = 0;
-       const lng max0 = GDK_lng_max / 10, max1 = GDK_lng_max % 10;
+    const lng max0 = GDK_lng_max / 10, max1 = GDK_lng_max % 10;
 #endif
+
+       assert(digits);
+       assert(scale);
+       assert(has_errors);
+
+       DEC_TPE res = 0;
+       *has_errors = 0;
+
+       int _digits     = 0;
+       int _scale      = 0;
+
+// preceding whitespace:
        int neg = 0;
-
        while(isspace((unsigned char) *dec))
                dec++;
+
+// optional sign:
        if (*dec == '-') {
                neg = 1;
                dec++;
        } else if (*dec == '+') {
                dec++;
        }
-       for (; *dec && (isdigit((unsigned char) *dec) || *dec == '.'); dec++) {
-               if (*dec != '.') {
-                       if (res > max0 || (res == max0 && *dec - '0' > max1))
-                               break;
-                       res *= 10;
-                       res += *dec - '0';
+
+// optional fractional separator first opportunity
+       if (*dec == '.') {  // case: (+|-).456
+fractional_sep_first_opp:
+               dec++;
+               goto trailing_digits;
+       }
+
+// preceding_digits:
+       if (!isdigit((unsigned char) *dec)) {
+               *has_errors = 1;
+               goto end_state;
+       }
+       while (*dec == '0'){
+               // skip leading zeros in preceding digits, e.g. '0004563.1234' 
=> '4563.1234'
+               dec++;
+               if (*dec == '.') {
+                       if (dec[1] == 0) { // special case: '(0...0)0.'. We 
give this expression precision (1,0).
+                               _digits = 1;
+                               dec++;
+                               goto end_state;
+                       }
+
+                       goto fractional_sep_first_opp;
                }
        }
+       for (; *dec && (isdigit((unsigned char) *dec)); dec++) {
+               if (res > max0 || (res == max0 && *dec - '0' > max1)) {
+                       *has_errors = 1;
+                       return 0;
+               }
+               res *= 10;
+               res += *dec - '0';
+               _digits++;
+       }
+
+// optional fractional separator second opportunity
+       if (*dec == '.')        // case: (+|-)123.(456)
+               dec++;
+       else                                    // case:  (+|-)123
+               goto trailing_whitespace;
+
+trailing_digits:
+       if (!isdigit((unsigned char) *dec))
+               goto trailing_whitespace;
+       for (; *dec && (isdigit((unsigned char) *dec)); dec++) {
+               if (res > max0 || (res == max0 && *dec - '0' > max1)) {
+                       *has_errors = 1;
+                       return 0;
+               }
+               res *= 10;
+               res += *dec - '0';
+               _scale++;
+       }
+       _digits += _scale;
+
+trailing_whitespace:
        while(isspace((unsigned char) *dec))
                dec++;
-       if (end)
-               *end = dec;
+
+end_state:
+       /* When the string cannot be parsed up to and including the null 
terminator,
+        * the string is an invalid decimal representation. */
+       if (*dec != 0)
+               *has_errors = 1;
+
+       *digits = _digits;
+       *scale = _scale;
+
        if (neg)
                return -res;
        else
diff --git a/sql/server/sql_decimal.h b/sql/server/sql_decimal.h
--- a/sql/server/sql_decimal.h
+++ b/sql/server/sql_decimal.h
@@ -14,12 +14,13 @@
 #include "gdk.h"
 
 #ifdef HAVE_HGE
-extern hge decimal_from_str(char *dec, char **end);
-extern char * decimal_to_str(hge v, sql_subtype *t);
+#define DEC_TPE hge
 #else
-extern lng decimal_from_str(char *dec, char **end);
-extern char * decimal_to_str(lng v, sql_subtype *t);
+#define DEC_TPE lng
 #endif
 
+extern DEC_TPE decimal_from_str(char *dec, int* digits, int* scale, int* 
has_errors);
+extern char * decimal_to_str(DEC_TPE v, sql_subtype *t);
+
 #endif /* _SQL_DECIMAL_H */
 
diff --git a/sql/server/sql_parser.y b/sql/server/sql_parser.y
--- a/sql/server/sql_parser.y
+++ b/sql/server/sql_parser.y
@@ -4740,41 +4740,39 @@ literal:
                }
  |  INTNUM
                { char *s = sa_strdup(SA, $1);
-                 char *dot = strchr(s, '.');
-                 int digits = _strlen(s) - 1;
-                 int scale = digits - (int) (dot-s);
-                 sql_subtype t;
-
-                 if (digits <= 0)
-                       digits = 1;
-                 if (digits <= MAX_DEC_DIGITS) {
-                       double val = strtod($1,NULL);
-#ifdef HAVE_HGE
-                       hge value = decimal_from_str(s, NULL);
-#else
-                       lng value = decimal_from_str(s, NULL);
-#endif
-
-                       if (*s == '+' || *s == '-')
-                               digits --;
-                       sql_find_subtype(&t, "decimal", digits, scale );
-                       $$ = _newAtomNode( atom_dec(SA, &t, value, val));
-                  } else {
-                       char *p = $1;
-                       double val;
-
-                       errno = 0;
-                       val = strtod($1,&p);
-                       if (p == $1 || is_dbl_nil(val) || (errno == ERANGE && 
(val < -1 || val > 1))) {
-                               char *msg = sql_message(SQLSTATE(22003) "Double 
value too large or not a number (%s)", $1);
-
-                               yyerror(m, msg);
-                               _DELETE(msg);
-                               $$ = NULL;
-                               YYABORT;
+                       int digits;
+                       int scale;
+                       int has_errors;
+                       sql_subtype t;
+
+                       DEC_TPE value = decimal_from_str(s, &digits, &scale, 
&has_errors);
+
+                       if (!has_errors) {
+                               // The float-like value seems to fit in decimal 
storage
+                               double val = strtod($1,NULL);
+                               sql_find_subtype(&t, "decimal", digits, scale );
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to