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