Changeset: d54e331f8b06 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/d54e331f8b06
Modified Files:
        sql/server/rel_select.c
        sql/test/SQLancer/Tests/sqlancer08.test
Branch: Aug2024
Log Message:

Optimize precision and scale when casting to decimal.


diffs (71 lines):

diff --git a/sql/server/rel_select.c b/sql/server/rel_select.c
--- a/sql/server/rel_select.c
+++ b/sql/server/rel_select.c
@@ -4043,6 +4043,8 @@ rel_case_exp(sql_query *query, sql_rel *
        }
 }
 
+#define E_ATOM_STRING(e) ((atom*)(e)->l)->data.val.sval
+
 static sql_exp *
 rel_cast(sql_query *query, sql_rel **rel, symbol *se, int f)
 {
@@ -4055,6 +4057,7 @@ rel_cast(sql_query *query, sql_rel **rel
 
        if (!e)
                return NULL;
+
        /* strings may need to be truncated */
        if (EC_VARCHAR(tpe->type->eclass) && tpe->digits > 0) {
                sql_subtype *et = exp_subtype(e);
@@ -4065,10 +4068,34 @@ rel_cast(sql_query *query, sql_rel **rel
                                e = exp_binop(sql->sa, e, exp_atom_int(sql->sa, 
tpe->digits), c);
                }
        }
+
+       if (e->type == e_atom && tpe->type->eclass == EC_DEC) {
+               sql_subtype *et = exp_subtype(e);
+               if (et->type->eclass == EC_CHAR || et->type->eclass == EC_DEC)
+                       tpe = sql_bind_subtype(sql->sa, "decimal", et->digits, 
et->scale);
+               else if (et->type->eclass == EC_STRING) {
+                       char *s = E_ATOM_STRING(e);
+                       unsigned int min_precision = 0, min_scale = 0;
+                       bool dot_seen = false;
+                       for (size_t i = 0; i < strlen(s); i++) {
+                               if (isdigit(s[i])) {
+                                       min_precision++;
+                                       if (dot_seen)
+                                               min_scale++;
+                               } else if (s[i] == '.') {
+                                       dot_seen = true;
+                               }
+                       }
+                       tpe = sql_bind_subtype(sql->sa, "decimal", 
min_precision, min_scale);
+               }
+       }
+
        if (e)
                e = exp_check_type(sql, tpe, rel ? *rel : NULL, e, type_cast);
+
        if (e && e->type == e_convert)
                exp_label(sql->sa, e, ++sql->label);
+
        return e;
 }
 
diff --git a/sql/test/SQLancer/Tests/sqlancer08.test 
b/sql/test/SQLancer/Tests/sqlancer08.test
--- a/sql/test/SQLancer/Tests/sqlancer08.test
+++ b/sql/test/SQLancer/Tests/sqlancer08.test
@@ -170,10 +170,10 @@ 0
 statement ok
 ROLLBACK
 
-statement error 42000!Decimal (0.2.3) doesn't have format (10.2)
+statement error 42000!Decimal (0.2.3) doesn't have format (3.2)
 select cast('0.2.3' as decimal(10,2))
 
-statement error 42000!Decimal (+0..2) doesn't have format (10.2)
+statement error 42000!Decimal (+0..2) doesn't have format (2.1)
 select cast('+0..2' as decimal(10,2))
 
 statement ok
_______________________________________________
checkin-list mailing list -- checkin-list@monetdb.org
To unsubscribe send an email to checkin-list-le...@monetdb.org

Reply via email to