1 /*
2 * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2.0,
6 * as published by the Free Software Foundation.
7 *
8 * This program is also distributed with certain software (including
9 * but not limited to OpenSSL) that is licensed under separate terms,
10 * as designated in a particular file or component or in included license
11 * documentation. The authors of MySQL hereby grant you an additional
12 * permission to link the program and your derivative works with the
13 * separately licensed software that they have included with MySQL.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License, version 2.0, for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301 USA
24 */
25
26
27 #include "query_string_builder.h"
28 #include "mysql/plugin.h"
29 #include "my_sys.h" // escape_string_for_mysql
30
31 using namespace xpl;
32
33 charset_info_st* Query_string_builder::m_charset = NULL;
34 my_thread_once_t Query_string_builder::m_charset_initialized = MY_THREAD_ONCE_INIT;
35
init_charset()36 void Query_string_builder::init_charset()
37 {
38 m_charset = get_charset_by_csname("utf8mb4", MY_CS_PRIMARY, MYF(MY_WME));
39 }
40
41
Query_string_builder(size_t reserve)42 Query_string_builder::Query_string_builder(size_t reserve)
43 : m_in_quoted(false), m_in_identifier(false)
44 {
45 my_thread_once(&m_charset_initialized, init_charset);
46 assert(m_charset != NULL);
47
48 m_str.reserve(reserve);
49 }
50
51
~Query_string_builder()52 Query_string_builder::~Query_string_builder()
53 {
54 }
55
56
quote_identifier(const char * s,size_t length)57 Query_string_builder &Query_string_builder::quote_identifier(const char *s, size_t length)
58 {
59 m_str.append("`");
60 escape_identifier(s, length);
61 m_str.append("`");
62 return *this;
63 }
64
65
quote_identifier_if_needed(const char * s,size_t length)66 Query_string_builder &Query_string_builder::quote_identifier_if_needed(const char *s, size_t length)
67 {
68 bool need_quote = false;
69 if (length > 0 && isalpha(s[0]))
70 {
71 for (size_t i = 1; i < length; i++)
72 if (!isalnum(s[i]) && s[i] != '_')
73 {
74 need_quote = true;
75 break;
76 }
77 }
78 else
79 need_quote = true;
80
81 if (need_quote)
82 return quote_identifier(s, length);
83 else
84 return put(s, length);
85 }
86
87
escape_identifier(const char * s,size_t length)88 Query_string_builder &Query_string_builder::escape_identifier(const char *s, size_t length)
89 {
90 size_t str_pos = m_str.size();
91 // resize the buffer to fit the original size + worst case length of s
92 m_str.resize(str_pos + length*2);
93
94 char* cursor_out = &m_str[str_pos];
95 const char* cursor_in = s;
96
97 for (size_t idx = 0; idx < length; ++idx)
98 {
99 if (*cursor_in == '`')
100 *cursor_out++ = '`';
101 *cursor_out++ = *cursor_in++;
102 }
103 m_str.resize(str_pos + (cursor_out - &m_str[str_pos]));
104 return *this;
105 }
106
107
escape_string(const char * s,size_t length)108 Query_string_builder &Query_string_builder::escape_string(const char *s, size_t length)
109 {
110 size_t str_pos = m_str.size();
111 // resize the buffer to fit the original size + worst case length of s
112 m_str.resize(str_pos + 2*length+1);
113
114 size_t r = escape_string_for_mysql(m_charset, &m_str[str_pos], 2*length+1, s, length);
115 m_str.resize(str_pos + r);
116
117 return *this;
118 }
119
120
quote_string(const char * s,size_t length)121 Query_string_builder &Query_string_builder::quote_string(const char *s, size_t length)
122 {
123 m_str.append("'");
124 escape_string(s, length);
125 m_str.append("'");
126
127 return *this;
128 }
129
130
put(const char * s,size_t length)131 Query_string_builder &Query_string_builder::put(const char *s, size_t length)
132 {
133 if (m_in_quoted)
134 escape_string(s, length);
135 else if (m_in_identifier)
136 escape_identifier(s, length);
137 else
138 m_str.append(s, length);
139
140 return *this;
141 }
142
143
format()144 Query_formatter Query_string_builder::format()
145 {
146 return Query_formatter(m_str, *m_charset);
147 }
148