1 #ifndef SQL_MODE_H_INCLUDED
2 #define SQL_MODE_H_INCLUDED
3 /*
4    Copyright (c) 2019, MariaDB.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; version 2 of the License.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */
18 
19 #ifdef USE_PRAGMA_INTERFACE
20 #pragma interface			/* gcc class implementation */
21 #endif
22 
23 #include "sql_basic_types.h"
24 
25 /*
26   class Sql_mode_dependency
27 
28   A combination of hard and soft dependency on sql_mode.
29   Used to watch if a GENERATED ALWAYS AS expression guarantees consitent
30   data written to its virtual column.
31 
32   A virtual column can appear in an index if:
33   - the generation expression does not depend on any sql_mode flags, or
34   - the generation expression has a soft dependency on an sql_mode flag,
35     and the column knows how to handle this dependeny.
36 
37   A virtual column cannot appear in an index if:
38   - its generation expression has a hard dependency
39   - its generation expression has a soft dependency, but the column
40     cannot handle it on store.
41   An error is reported in such cases.
42 
43   How dependencies appear:
44   - When a column return value depends on some sql_mode flag,
45     its Item_field adds a corresponding bit to m_soft. For example,
46     Item_field for a CHAR(N) column adds the PAD_CHAR_TO_FULL_LENGTH flag.
47   - When an SQL function/operator return value depends on some sql_mode flag,
48     it adds a corresponding bit to m_soft. For example, Item_func_minus
49     adds the MODE_NO_UNSIGNED_SUBTRACTION in case of unsigned arguments.
50 
51   How dependency are processed (see examples below):
52   - All SQL functions/operators bit-OR all hard dependencies from all arguments.
53   - Some soft dependencies can be handled by the underlying Field on store,
54     e.g. CHAR(N) can handle PAD_CHAR_TO_FULL_LENGTH.
55   - Some soft dependencies can be handled by SQL functions and operators,
56     e.g. RTRIM(expr) removes expr's soft dependency on PAD_CHAR_TO_FULL_LENGTH.
57     If a function or operator handles a soft dependency on a certain sql_mode
58     flag, it removes the corresponding bit from m_soft (see below).
59     Note, m_hard is not touched in such cases.
60   - When an expression with a soft dependency on a certain sql_mode flag
61     goes as an argument to an SQL function/operator which cannot handle
62     this flag, the dependency escalates from soft to hard
63     (by moving the corresponding bit from m_soft to m_hard) and cannot be
64     handled any more on the upper level, neither by a Field on store,
65     nor by another SQL function/operator.
66 
67   There are four kinds of Items:
68   1. Items that generate a soft or hard dependency, e.g.
69      - Item_field for CHAR(N) - generates soft/PAD_CHAR_TO_FULL_LENGTH
70      - Item_func_minus        - generates soft/NO_UNSIGNED_SUBTRACTION
71   2. Items that convert a soft dependency to a hard dependency.
72      This happens e.g. when an Item_func instance gets a soft dependency
73      from its arguments, and it does not know how to handle this dependency.
74      Most Item_func descendants do this.
75   3. Items that remove soft dependencies, e.g.:
76      - Item_func_rtrim - removes soft/PAD_CHAR_TO_FULL_LENGTH
77                          that came from args[0] (under certain conditions)
78      - Item_func_rpad  - removes soft/PAD_CJAR_TO_FULL_LENGTH
79                          that came from args[0] (under certain conditions)
80   4. Items that repeat soft dependency from its arguments to the caller.
81      They are not implemented yet. But functions like Item_func_coalesce,
82      Item_func_case, Item_func_case_abbreviation2 could do this.
83 
84   Examples:
85 
86   1. CREATE OR REPLACE TABLE t1 (a CHAR(5), v CHAR(20) AS(a), KEY(v));
87 
88      Here `v` has a soft dependency on `a`.
89      The value of `a` depends on PAD_CHAR_TO_FULL_LENGTH, it can return:
90      - 'a'                         - if PAD_CHAR_TO_FULL_LENGTH is disabled
91      - 'a' followed by four spaces - if PAD_CHAR_TO_FULL_LENGTH is enabled
92      But `v` will pad trailing spaces to the full length on store anyway.
93      So Field_string handles this soft dependency on store.
94      This combination of the virtial column data type and its generation
95      expression is safe and provides consistent data in `v`, which is
96      'a' followed by four spaces, no matter what PAD_CHAR_TO_FULL_LENGTH is.
97 
98   2. CREATE OR REPLACE TABLE t1 (a CHAR(5), v VARCHAR(20) AS(a), KEY(v));
99 
100      Here `v` has a soft dependency on `a`. But Field_varstring does
101      not pad spaces on store, so it cannot handle this dependency.
102      This combination of the virtual column data type and its generation
103      expression is not safe. An error is returned.
104 
105   3. CREATE OR REPLACE TABLE t1 (a CHAR(5), v INT AS(LENGTH(a)), KEY(v));
106 
107      Here `v` has a hard dependency on `a`, because the value of `a`
108      is wrapped to the function LENGTH().
109      The value of `LENGTH(a)` depends on PAD_CHAR_TO_FULL_LENGTH, it can return:
110      - 1  - if PAD_CHAR_TO_FULL_LENGTH is disabled
111      - 4  - if PAD_CHAR_TO_FULL_LENGTH is enabled
112      This combination cannot provide consistent data stored to `v`,
113      therefore it's disallowed.
114 */
115 class Sql_mode_dependency
116 {
117   sql_mode_t m_hard;
118   sql_mode_t m_soft;
119 public:
Sql_mode_dependency()120   Sql_mode_dependency()
121    :m_hard(0), m_soft(0)
122   { }
Sql_mode_dependency(sql_mode_t hard,sql_mode_t soft)123   Sql_mode_dependency(sql_mode_t hard, sql_mode_t soft)
124    :m_hard(hard), m_soft(soft)
125   { }
hard()126   sql_mode_t hard() const { return m_hard; }
soft()127   sql_mode_t soft() const { return m_soft; }
128   operator bool () const
129   {
130     return m_hard > 0 || m_soft > 0;
131   }
132   Sql_mode_dependency operator|(const Sql_mode_dependency &other) const
133   {
134     return Sql_mode_dependency(m_hard | other.m_hard, m_soft | other.m_soft);
135   }
136   Sql_mode_dependency operator&(const Sql_mode_dependency &other) const
137   {
138     return Sql_mode_dependency(m_hard & other.m_hard, m_soft & other.m_soft);
139   }
140   Sql_mode_dependency &operator|=(const Sql_mode_dependency &other)
141   {
142     m_hard|= other.m_hard;
143     m_soft|= other.m_soft;
144     return *this;
145   }
146   Sql_mode_dependency &operator&=(const Sql_mode_dependency &other)
147   {
148     m_hard&= other.m_hard;
149     m_soft&= other.m_soft;
150     return *this;
151   }
soft_to_hard()152   Sql_mode_dependency &soft_to_hard()
153   {
154     m_hard|= m_soft;
155     m_soft= 0;
156     return *this;
157   }
158   void push_dependency_warnings(THD *thd) const;
159 };
160 
161 
162 #endif // SQL_MODE_H_INCLUDED
163