Skip to content

Commit ded2d88

Browse files
committed
Bug#25530204: THE RESULT OF SUM ON JSON_EXTRACT LOST THE DECIMAL PART
When using the SUM aggregate function on an expression that returns a JSON value, the result does not have a fractional part. The reason is that the Item_json_func class does not change Item::decimals from its initial zero value. This is used to determine how the result is presented, and when it is zero, the fractional part is lost. Fix: Set Item::decimals to NOT_FIXED_DEC (31) in Item_json_func::resolve_type(). This is the same value that is used for other string types. For consistency, setting this member, and other members common to expressions that return JSON values, is moved into a separate helper function, Item::set_data_type_json(). Item_json and Item_sum_json are also updated to using the helper function. Item_sum_json redundantly set the data type to JSON both in its constructors and in fix_fields(). The patch removes the code from fix_fields() so that it is only set once. Similarly, make Item_json_func set the data type in its constructors instead of in resolve_type(). Changed test result: Two test cases in json.json_agg get slightly different output because the type of 1.0 * JSON_ARRAYAGG(a) changed from DOUBLE(18, 1) to DOUBLE, and the type of SEC_TO_TIME(JSON_ARRAYAGG(a)) changed from TIME(6) to TIME. x.find_doc_proj shows metadata for some results where "fractional_parts" is changed from 0 to 31 as expected. Change-Id: I37a24afa463201059b7232583d60a5d2e6774fe0
1 parent d639791 commit ded2d88

File tree

9 files changed

+54
-48
lines changed

9 files changed

+54
-48
lines changed

mysql-test/suite/json/r/json_agg.result

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,8 +1112,8 @@ CREATE TABLE t2(gid int, a int);
11121112
INSERT INTO t2(gid, a) VALUES (1, 1), (1, 2), (2, 4), (2, 8);
11131113
SELECT gid, 1.0 * JSON_ARRAYAGG(a) FROM t2 GROUP BY gid;
11141114
gid 1.0 * JSON_ARRAYAGG(a)
1115-
1 0.0
1116-
2 0.0
1115+
1 0
1116+
2 0
11171117
Warnings:
11181118
Warning 3156 Invalid JSON value for CAST to DOUBLE from column json_arrayagg( at row 3
11191119
Warning 3156 Invalid JSON value for CAST to DOUBLE from column json_arrayagg( at row 5
@@ -1142,8 +1142,8 @@ Warning 3156 Invalid JSON value for CAST to DATE/TIME/DATETIME/TIMESTAMP from co
11421142
Warning 3156 Invalid JSON value for CAST to DATE/TIME/DATETIME/TIMESTAMP from column json_arrayagg( at row 5
11431143
SELECT gid, SEC_TO_TIME(JSON_ARRAYAGG(a)) FROM t2 GROUP BY gid;
11441144
gid SEC_TO_TIME(JSON_ARRAYAGG(a))
1145-
1 00:00:00
1146-
2 00:00:00
1145+
1 00:00:00.000000
1146+
2 00:00:00.000000
11471147
Warnings:
11481148
Warning 3156 Invalid JSON value for CAST to DECIMAL from column json_arrayagg( at row 3
11491149
Warning 3156 Invalid JSON value for CAST to DECIMAL from column json_arrayagg( at row 5

mysql-test/suite/json/r/json_no_table.result

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3332,3 +3332,9 @@ JSON_CONTAINS_PATH('{"a":"x"}', CAST('all' AS CHAR CHARSET utf16),
33323332
'$.a', '$.b') AS c4;
33333333
c1 c2 c3 c4
33343334
"$[0]" ["$[0]", "$[1]"] 1 0
3335+
#
3336+
# Bug#25530204: THE RESULT OF SUM ON JSON_EXTRACT LOST THE DECIMAL PART
3337+
#
3338+
SELECT SUM(CAST('5.45' AS JSON));
3339+
SUM(CAST('5.45' AS JSON))
3340+
5.45

mysql-test/suite/json/t/json_no_table.test

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2329,3 +2329,8 @@ SELECT JSON_SEARCH('["a", "a"]', CAST('one' AS CHAR CHARSET utf16), 'a') AS c1,
23292329
'$.a', '$.b') AS c3,
23302330
JSON_CONTAINS_PATH('{"a":"x"}', CAST('all' AS CHAR CHARSET utf16),
23312331
'$.a', '$.b') AS c4;
2332+
2333+
--echo #
2334+
--echo # Bug#25530204: THE RESULT OF SUM ON JSON_EXTRACT LOST THE DECIMAL PART
2335+
--echo #
2336+
SELECT SUM(CAST('5.45' AS JSON));

rapid/plugin/x/tests/mtr/r/find_doc_proj.result

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ Mysqlx.Resultset.ColumnMetaData {
152152
schema: ""
153153
catalog: "def"
154154
collation: 46
155-
fractional_digits: 0
155+
fractional_digits: 31
156156
length: 16777216
157157
flags: 0
158158
content_type: 2
@@ -221,7 +221,7 @@ Mysqlx.Resultset.ColumnMetaData {
221221
schema: ""
222222
catalog: "def"
223223
collation: 46
224-
fractional_digits: 0
224+
fractional_digits: 31
225225
length: 16777216
226226
flags: 0
227227
content_type: 2
@@ -294,7 +294,7 @@ Mysqlx.Resultset.ColumnMetaData {
294294
schema: ""
295295
catalog: "def"
296296
collation: 46
297-
fractional_digits: 0
297+
fractional_digits: 31
298298
length: 16777216
299299
flags: 0
300300
content_type: 2
@@ -351,7 +351,7 @@ Mysqlx.Resultset.ColumnMetaData {
351351
schema: ""
352352
catalog: "def"
353353
collation: 46
354-
fractional_digits: 0
354+
fractional_digits: 31
355355
length: 16777216
356356
flags: 0
357357
content_type: 2

sql/item.cc

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7368,13 +7368,11 @@ class Item_json final : public Item_basic_constant
73687368
{
73697369
Json_wrapper m_value;
73707370
public:
7371-
Item_json(Json_wrapper &&value, const Item_name_string &name,
7372-
const DTCollation &coll)
7371+
Item_json(Json_wrapper &&value, const Item_name_string &name)
73737372
: m_value(std::move(value))
73747373
{
7375-
set_data_type(MYSQL_TYPE_JSON);
7374+
set_data_type_json();
73767375
item_name= name;
7377-
collation.set(coll);
73787376
}
73797377
enum Type type() const override { return STRING_ITEM; }
73807378

@@ -7426,7 +7424,7 @@ class Item_json final : public Item_basic_constant
74267424
Item *clone_item() const override
74277425
{
74287426
Json_wrapper wr(m_value.clone_dom(current_thd));
7429-
return new Item_json(std::move(wr), item_name, collation);
7427+
return new Item_json(std::move(wr), item_name);
74307428
}
74317429
/* purecov: end */
74327430
};
@@ -9271,8 +9269,7 @@ bool resolve_const_item(THD *thd, Item **ref, Item *comp_item)
92719269
if (item->null_value)
92729270
new_item= new Item_null(item->item_name);
92739271
else
9274-
new_item= new Item_json(std::move(wr), item->item_name,
9275-
item->collation);
9272+
new_item= new Item_json(std::move(wr), item->item_name);
92769273
break;
92779274
}
92789275
char buff[MAX_FIELD_WIDTH];

sql/item.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,17 @@ class Item : public Parse_tree_node
11861186
max_length= MAX_DATE_WIDTH + fsp + (fsp > 0 ? 1 : 0);
11871187
}
11881188

1189+
/**
1190+
Set the data type of the Item to be JSON.
1191+
*/
1192+
void set_data_type_json()
1193+
{
1194+
set_data_type(MYSQL_TYPE_JSON);
1195+
collation.set(&my_charset_utf8mb4_bin, DERIVATION_IMPLICIT);
1196+
decimals= NOT_FIXED_DEC;
1197+
max_length= MAX_BLOB_WIDTH;
1198+
}
1199+
11891200
/**
11901201
Set type information of Item from "result" information.
11911202
For String types, type is set based on maximum string size.

sql/item_json_func.h

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include <stddef.h>
2020
#include <sys/types.h>
21+
#include <utility> // std::forward
2122

2223
#include "binary_log_types.h"
2324
#include "enum_query_type.h"
@@ -142,25 +143,21 @@ class Item_json_func : public Item_func
142143
override;
143144

144145
public:
145-
Item_json_func(THD *thd, const POS &pos, Item *a) : Item_func(pos, a),
146-
m_path_cache(thd, 1)
147-
{}
148-
Item_json_func(THD *thd, const POS &pos, Item *a, Item *b) : Item_func(pos, a, b),
149-
m_path_cache(thd, 2)
150-
{}
151-
Item_json_func(THD *thd, const POS &pos, Item *a, Item *b, Item *c)
152-
: Item_func(pos, a, b, c), m_path_cache(thd, 3)
153-
{}
154-
Item_json_func(THD *thd, const POS &pos, PT_item_list *a) : Item_func(pos, a),
155-
m_path_cache(thd, arg_count)
156-
{}
146+
/**
147+
Construct an Item_json_func instance.
148+
@param thd THD handle
149+
@param args arguments to forward to Item_func's constructor
150+
*/
151+
template <typename... Args>
152+
Item_json_func(THD *thd, Args&&... args)
153+
: Item_func(std::forward<Args>(args)...), m_path_cache(thd, arg_count)
154+
{
155+
set_data_type_json();
156+
}
157157

158158
bool resolve_type(THD *) override
159159
{
160-
set_data_type(MYSQL_TYPE_JSON);
161-
max_length= MAX_BLOB_WIDTH;
162160
maybe_null= true;
163-
collation.set(&my_charset_utf8mb4_bin, DERIVATION_IMPLICIT);
164161
return false;
165162
}
166163
enum Item_result result_type() const override { return STRING_RESULT; }

sql/item_sum.cc

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4230,12 +4230,9 @@ bool Item_sum_json::fix_fields(THD *thd, Item **ref)
42304230
if (resolve_type(thd))
42314231
return true;
42324232

4233-
set_data_type(MYSQL_TYPE_JSON);
4234-
42354233
if (check_sum_func(thd, ref))
42364234
return true;
42374235

4238-
max_length= MAX_BLOB_WIDTH;
42394236
maybe_null= true;
42404237
null_value= true;
42414238
fixed= true;

sql/item_sum.h

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <math.h>
2424
#include <stddef.h>
2525
#include <sys/types.h>
26+
#include <utility> // std::forward
2627

2728
#include "binary_log_types.h"
2829
#include "enum_query_type.h"
@@ -1026,22 +1027,14 @@ class Item_sum_json : public Item_sum
10261027
Json_wrapper m_wrapper;
10271028

10281029
public:
1029-
Item_sum_json(THD *thd, Item_sum *item)
1030-
: Item_sum(thd, item)
1031-
{
1032-
set_data_type(MYSQL_TYPE_JSON);
1033-
}
1034-
1035-
Item_sum_json(const POS &pos, Item *a)
1036-
: Item_sum(pos, a)
1037-
{
1038-
set_data_type(MYSQL_TYPE_JSON);
1039-
}
1040-
1041-
Item_sum_json(const POS &pos, Item *a, Item *b)
1042-
: Item_sum(pos, a, b)
1030+
/**
1031+
Construct an Item_sum_json instance.
1032+
@param args arguments to forward to Item_sum's constructor
1033+
*/
1034+
template <typename... Args>
1035+
Item_sum_json(Args&&... args) : Item_sum(std::forward<Args>(args)...)
10431036
{
1044-
set_data_type(MYSQL_TYPE_JSON);
1037+
set_data_type_json();
10451038
}
10461039

10471040
bool fix_fields(THD *thd, Item **pItem) override;

0 commit comments

Comments
 (0)