From 11352a322daed882fd5c0bdad60c6f9309b23959 Mon Sep 17 00:00:00 2001 From: Mergen Imeev <imeevma@gmail.com> Date: Mon, 16 Mar 2020 15:12:37 +0300 Subject: [PATCH] sql: fix CAST() from STRING to INTEGER Prior to this patch, STRING, which contains the DOUBLE value, could be cast to INTEGER. This was done by converting STRING to DOUBLE and then converting this DOUBLE value to INTEGER. This may affect the accuracy of CAST(), so it was forbidden. Before patch: box.execute("SELECT CAST('111.1' as INTEGER);") Result: 111 After patch: box.execute("SELECT CAST('1.1' as INTEGER);") Result: 'Type mismatch: can not convert 1.1 to integer' box.execute("SELECT CAST('1.0' as INTEGER);") Result: 'Type mismatch: can not convert 1.0 to integer' box.execute("SELECT CAST('1.' as INTEGER);") Result: 'Type mismatch: can not convert 1. to integer' --- src/box/sql/vdbemem.c | 16 ++++++++++++++-- test/sql/types.result | 23 +++++++++-------------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c index 18fe958a26..7490f5ddaf 100644 --- a/src/box/sql/vdbemem.c +++ b/src/box/sql/vdbemem.c @@ -696,7 +696,7 @@ sqlVdbeMemCast(Mem * pMem, enum field_type type) return -1; case FIELD_TYPE_INTEGER: case FIELD_TYPE_UNSIGNED: - if ((pMem->flags & MEM_Blob) != 0) { + if ((pMem->flags & (MEM_Blob | MEM_Str)) != 0) { bool is_neg; int64_t val; if (sql_atoi64(pMem->z, &val, &is_neg, pMem->n) != 0) @@ -711,8 +711,20 @@ sqlVdbeMemCast(Mem * pMem, enum field_type type) MemSetTypeFlag(pMem, MEM_UInt); return 0; } - if (sqlVdbeMemIntegerify(pMem) != 0) + if ((pMem->flags & MEM_Real) != 0) { + double d; + if (sqlVdbeRealValue(pMem, &d) != 0) + return -1; + if (d < INT64_MAX && d >= INT64_MIN) { + mem_set_int(pMem, d, d <= -1); + return 0; + } + if (d >= INT64_MAX && d < UINT64_MAX) { + mem_set_u64(pMem, d); + return 0; + } return -1; + } if (type == FIELD_TYPE_UNSIGNED && (pMem->flags & MEM_UInt) == 0) return -1; diff --git a/test/sql/types.result b/test/sql/types.result index 38e4385adb..54aff460e9 100644 --- a/test/sql/types.result +++ b/test/sql/types.result @@ -269,11 +269,8 @@ box.space.T1:drop() -- box.execute("SELECT CAST('1.123' AS INTEGER);") --- -- metadata: - - name: CAST('1.123' AS INTEGER) - type: integer - rows: - - [1] +- null +- 'Type mismatch: can not convert 1.123 to integer' ... box.execute("CREATE TABLE t1 (f TEXT PRIMARY KEY);") --- @@ -285,13 +282,8 @@ box.execute("INSERT INTO t1 VALUES('0.0'), ('1.5'), ('3.9312453');") ... box.execute("SELECT CAST(f AS INTEGER) FROM t1;") --- -- metadata: - - name: CAST(f AS INTEGER) - type: integer - rows: - - [0] - - [1] - - [3] +- null +- 'Type mismatch: can not convert 0.0 to integer' ... box.space.T1:drop() --- @@ -1105,8 +1097,11 @@ box.execute("SELECT CAST(1.5 AS UNSIGNED);") ... box.execute("SELECT CAST(-1.5 AS UNSIGNED);") --- -- null -- 'Type mismatch: can not convert -1 to unsigned' +- metadata: + - name: CAST(-1.5 AS UNSIGNED) + type: unsigned + rows: + - [-1] ... box.execute("SELECT CAST(true AS UNSIGNED);") --- -- GitLab