Differences in results caused by different writing methods of GaussDB (DWS) functions

This article is shared from Huawei Cloud Community " GaussDB (DWS) Function Result Difference Case: Greatest ", author: Are you a rescuer invited by a monkey.

GaussDB (DWS) supports multiple compatibility modes. In order to be compatible with the target database, there are more or less behavioral differences between the modes. Here is a case of difference in results caused by different writing methods of expression functions in mysql compatibility mode.

problem background

Problem Version  GaussDB 8.1.1

Problem Description

Users reported that in mysql compatibility mode, there are differences in the execution results of the following two SQL: 

select greatest(1,2,100,-1,0,nvl(null,0)) The result is 2 

select greatest(1,2,100,-1 ,0) The result is 100

Scene reproduction

mysql=# select greatest(1,2,100,-1,nvl(null,0));

greatest

----------

2

(1 row)

mysql=# select greatest(1,2,100,-1,0,0);

greatest

----------

100

(1 row)

root cause analysis

1. I don’t know if my friends have noticed that one of the two result sets is displayed on the left and the other is on the right; ok, let’s first confirm the data types of these two results:

mysql=# select pg_typeof(greatest(1,2,100,-1,nvl(null,0)));

pg_typeof

-----------

text

(1 row)

mysql=# select pg_typeof(greatest(1,2,100,-1,0));

pg_typeof

-----------

integer

(1 row)

2. Relying on pg_typeof, we get the data type of the returned result; this means that the first statement is sorted by text type to select the maximum value, in order ('0', '1', '-1', '100' ,'2'), so we get that the maximum value is '2' of type string.

0

1

-1

100

2

3. By analogy, the second statement sorts and selects the maximum value by int type, which is (-1, 0, 1, 2, 100), so we get that the maximum value is 100 of the numeric type.

-1

0

1

2

100

4. The return type of the expression function greatest is determined based on the input parameter type, and the difference here is the result difference caused by the fifth input parameter type.

mysql=# select pg_typeof(nvl(null,0));

pg_typeof

-----------

text

(1 row)

mysql=# select pg_typeof(0);

pg_typeof

-----------

integer

(1 row)

5. The reason why nvl/greatest has different return types is determined by the type matching rules in mysql compatibility mode.

For specific rules, please refer to: UNION, CASE and related structures .

Proposed changes

For this difference scenario, it is recommended to explicitly specify the input parameter type when the return type is uncertain, and change nvl(null,0) to nvl(null,0)::int, so that the result is sorted by int, which is different from another The table statement is as expected.

mysql=# select greatest(1,2,100,-1,nvl(null,0)::int);

greatest

----------

100

(1 row)

knowledge analysis

The SQL UNION structure matches different data types and outputs a unified data type result set. Because all query results in a SELECT UNION statement must be displayed in one column, the element types in each SELECT clause must match each other and be converted into a unified data type. The same requirement exists widely in expressions and functions such as UNION, ARRAY and CASE, COALESCE, IF, IFNULL and GREATEST, LEAST and NVL .        

GaussDB (DWS) supports multiple compatibility modes, and the type matching rules in different compatibility modes are also different. For ease of understanding, here is an example of the IFNULL type matching rule in mysql compatibility mode , which is consistent with the rule of GREATEST in mysql compatibility mode.    

Rule 1:  If all inputs are of the same type, excluding the unknown type, then resolve to the same data type as the input.

mysql=# select pg_typeof(1),pg_typeof(2);

pg_typeof | pg_typeof

-----------+-----------

integer | integer

(1 row)

mysql=# select ifnull(1,2),pg_typeof(ifnull(1,2));

ifnull | pg_typeof

--------+-----------

1 | integer

(1 row)

Rule 2:  If all input is unknown type, it will be parsed into text type. (The constant string is the unknown type)

mysql=# select pg_typeof('1'),pg_typeof('2');

pg_typeof | pg_typeof

-----------+-----------

unknown | unknown

(1 row)

mysql=# select ifnull('1','2'),pg_typeof(ifnull('1','2'));

ifnull | pg_typeof

--------+-----------

1 | text

(1 row)

Rule 3:  If the input is an unknown type and a certain non-unknown type, it is parsed into the non-unknown type.

mysql=# select pg_typeof(current_date),pg_typeof('20230801');

pg_typeof | pg_typeof

-----------+-----------

date | unknown

(1 row)

mysql=# select ifnull(current_date,'20230801'),pg_typeof(ifnull(current_date,'20230801'));

ifnull | pg_typeof

------------+-----------

2023-08-10 | date

(1 row)

Rule 4:  If there are multiple non-unknown types, treat the enum type as the text type, and then compare.

mysql=# create type gender as enum('boy','girl');

CREATE TYPE

mysql=# select pg_typeof('boy'::gender),pg_typeof('girl'::varchar);

pg_typeof | pg_typeof

-----------+-------------------

gender | character varying

(1 row)

mysql=# select ifnull('boy'::gender,'girl'::varchar),pg_typeof(ifnull('boy'::gender,'girl'::varchar));

ifnull | pg_typeof

--------+-----------

boy | text

(1 row)

Rule 5:  If the input types are of the same type category, the type with higher priority of that type is chosen. If it is a different type category, it will be parsed into text type.

--相同类型范畴

mysql=# select pg_typeof(1),pg_typeof(2.0);

pg_typeof | pg_typeof

-----------+-----------

integer | numeric

(1 row)

mysql=# select ifnull(1,2.0),pg_typeof(ifnull(1,2.0));

ifnull | pg_typeof

--------+-----------

1 | numeric

(1 row)

--不同类型范畴

mysql=# select pg_typeof(1),pg_typeof(current_date);

pg_typeof | pg_typeof

-----------+-----------

integer | date

(1 row)

mysql=# select ifnull(1,current_date),pg_typeof(ifnull(1,current_date));

ifnull | pg_typeof

--------+-----------

1 | text

(1 row)

Rule 6:  Convert all input to the selected type. Fails if there is no implicit conversion from the given input to the selected type.

--json does not exist implicit conversion to text 

mysql=# select pg_typeof(1),pg_typeof('{"a":1}'::json); 

pg_typeof | pg_typeof 

----------- +----------- 

integer | json 

(1 row) 

mysql=# select ifnull(1,'{"a":1}'::json),pg_typeof(ifnull(1,'{" a":1}'::json)); 

ERROR: IFNULL could not convert type json to text 

LINE 1: select ifnull(1,'{"a":1}'::json),pg_typeof(ifnull(1, '{"a":1}... 

^ 

CONTEXT: referenced column: ifnull 

--You can try to explicitly specify the type conversion 

mysql=# select ifnull(1,'{"a":1}'::json::text ); 

ifnull 

-------- 

1 

(1 row)

Click to follow and learn about Huawei Cloud's fresh technologies for the first time~

Ministry of Industry and Information Technology: Do not provide network access services for unregistered apps Go 1.21 officially released Ruan Yifeng released " TypeScript Tutorial" Bram Moolenaar, the father of Vim, passed away due to illness The self-developed kernel Linus personally reviewed the code, hoping to calm down the "infighting" driven by the Bcachefs file system. ByteDance launched a public DNS service . Excellent, committed to the Linux kernel mainline this month
{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/u/4526289/blog/10094699