Merge lp:~akopytov/percona-server/bug915814-5.5 into lp:percona-server/5.5

Proposed by Alexey Kopytov
Status: Merged
Approved by: Laurynas Biveinis
Approved revision: no longer in the source branch.
Merged at revision: 230
Proposed branch: lp:~akopytov/percona-server/bug915814-5.5
Merge into: lp:percona-server/5.5
Diff against target: 1805 lines (+448/-1188)
1 file modified
patches/query_cache_enhance.patch (+448/-1188)
To merge this branch: bzr merge lp:~akopytov/percona-server/bug915814-5.5
Reviewer Review Type Date Requested Status
Laurynas Biveinis (community) Approve
Review via email: mp+98997@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Alexey Kopytov (akopytov) wrote :
Revision history for this message
Alexey Kopytov (akopytov) wrote :

There was another problem with the old patch that was caught by Jenkins. Link for the fixed version: http://jenkins.percona.com/view/Percona%20Server%205.5/job/percona-server-5.5-param/305/

Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote :

I'd prefer to have a #define or enum constant for the query buffer length, together with the layout-explaining comment, instead of two separate copies at around diff lines 348 and 942.

review: Needs Fixing
Revision history for this message
Alexey Kopytov (akopytov) wrote :

On 25.03.12 14:16, Laurynas Biveinis wrote:
> I'd prefer to have a #define or enum constant for the query buffer length

Done.
http://jenkins.percona.com/view/Percona%20Server%205.5/job/percona-server-5.5-param/306/

Revision history for this message
Laurynas Biveinis (laurynas-biveinis) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'patches/query_cache_enhance.patch'
--- patches/query_cache_enhance.patch 2012-02-02 07:11:59 +0000
+++ patches/query_cache_enhance.patch 2012-03-25 11:37:19 +0000
@@ -1,4 +1,4 @@
1# name : query_cache_enhance.patch1# name : query_cache_with_comments.patch
2# introduced : 11 or before2# introduced : 11 or before
3# maintainer : Oleg3# maintainer : Oleg
4#4#
@@ -25,7 +25,7 @@
25+2010-11 - Ported to 5.525+2010-11 - Ported to 5.5
26--- a/sql/mysqld.cc26--- a/sql/mysqld.cc
27+++ b/sql/mysqld.cc27+++ b/sql/mysqld.cc
28@@ -909,6 +909,7 @@28@@ -915,6 +915,7 @@
29 #endif29 #endif
30 #ifdef HAVE_QUERY_CACHE30 #ifdef HAVE_QUERY_CACHE
31 ulong query_cache_min_res_unit= QUERY_CACHE_MIN_RESULT_DATA_SIZE;31 ulong query_cache_min_res_unit= QUERY_CACHE_MIN_RESULT_DATA_SIZE;
@@ -43,510 +43,252 @@
43 extern ulonglong log_output_options;43 extern ulonglong log_output_options;
44 extern ulong log_backup_output_options;44 extern ulong log_backup_output_options;
45 extern my_bool opt_log_queries_not_using_indexes;45 extern my_bool opt_log_queries_not_using_indexes;
46--- /dev/null
47+++ b/sql/query_strip_comments.h
48@@ -0,0 +1,37 @@
49+#ifndef _SQL_QUERY_STRIPC_COMMENTS_H_
50+#define _SQL_QUERY_STRIPC_COMMENTS_H_
51+#ifdef HAVE_QUERY_CACHE
52+
53+// implemented in sql_cache.cc
54+class QueryStripComments
55+{
56+private:
57+ QueryStripComments(const QueryStripComments&);
58+ QueryStripComments& operator=(const QueryStripComments&);
59+public:
60+ QueryStripComments();
61+ ~QueryStripComments();
62+ void set(const char* a_query, uint a_query_length, uint a_additional_length);
63+
64+ char* query() { return buffer; }
65+ uint query_length() { return length; }
66+private:
67+ void cleanup();
68+private:
69+ char* buffer;
70+ uint length /*query length, not buffer length*/;
71+ uint buffer_length;
72+};
73+class QueryStripComments_Backup
74+{
75+public:
76+ QueryStripComments_Backup(THD* a_thd,QueryStripComments* qsc);
77+ ~QueryStripComments_Backup();
78+private:
79+ THD* thd;
80+ char* query;
81+ uint length;
82+};
83+
84+#endif // HAVE_QUERY_CACHE
85+#endif // _SQL_QUERY_STRIPC_COMMENTS_H_
46--- a/sql/sql_cache.cc86--- a/sql/sql_cache.cc
47+++ b/sql/sql_cache.cc87+++ b/sql/sql_cache.cc
48@@ -344,6 +344,496 @@88@@ -344,6 +344,198 @@
49 #include "probes_mysql.h"89 #include "probes_mysql.h"
50 #include "transaction.h"90 #include "transaction.h"
51 91
52+92+#include "query_strip_comments.h"
53+namespace query_comments_parser93+
54+{94+/*
55+95+ Number of bytes to be allocated in a query cache buffer in addition to the
56+96+ query string length.
57+enum Kind97+
58+{98+ The query buffer layout is:
59+ /* 'Empty' symbol - epsilon in classic parsers */99+
60+ Empty,100+ buffer :==
61+ /*101+ <statement> The input statement(s)
62+ Special symbols:102+ '\0' Terminating null char
63+ * exclamation comment: slash-star-exclamation comment-body star-slash103+ <db_length> Length of following current database name (size_t)
64+ * single-line and multi-line comments104+ <db_name> Name of current database
65+ */105+ <flags> Flags struct
66+ Special,
67+ /* Whitespaces: ' ' \t \r \n */
68+ WhiteSpace,
69+ /*
70+ 1) C-style comment (slash-star comment-body star-slash)
71+ 2) signle-line comment:
72+ * sharp comment (sharp comment-body new-line)
73+ * minus-minus comment (minus-minus comment-body new-line)
74+ */
75+ Comment,
76+ /* Not a special symbols (this symbols can't be before SELECT ). */
77+ Another,
78+ /* Error: not-closed quotes, not-closed C-style comment, end-of-query */
79+ Error
80+};
81+
82+
83+/**
84+ Analyze kind of prefix of input string.
85+
86+ @param where pointer to pointer to begin of string. After analyzing input
87+ string function skip analyzed prefix and return pointer to the next part
88+ of string in the @param where.
89+
90+ @return kind of analyzed prefix.
91+*/106+*/
92+static Kind analyze(const char **where, const char *const end)107+#define QUERY_BUFFER_ADDITIONAL_LENGTH(db_length) \
93+{108+ (1 + sizeof(size_t) + db_length + QUERY_CACHE_FLAGS_SIZE)
94+ DBUG_ASSERT(where != NULL);109+
95+ DBUG_ASSERT(*where != NULL);110+QueryStripComments::QueryStripComments()
96+ const char*&to= *where;111+{
97+ /* if empty */112+ buffer = 0;
98+ if (*to == '\0')113+ length = 0;
99+ {114+ buffer_length = 0;
100+ return Empty;115+}
101+ }116+QueryStripComments::~QueryStripComments()
102+117+{
103+ /* current symbol */118+ cleanup();
104+ char current= *to;119+}
105+120+
106+ switch (current)121+inline bool query_strip_comments_is_white_space(char c)
107+ {122+{
108+ case '\'':123+ return ((' ' == c) || ('\t' == c) || ('\r' == c) || ('\n' ==c ));
109+ case '"':124+}
110+ /* skip quote */125+void QueryStripComments::set(const char* query, uint query_length, uint additional_length)
111+ to++;126+{
112+ /* search pair */127+ uint new_buffer_length = query_length + additional_length;
113+ while (true)128+ if(new_buffer_length > buffer_length)
129+ {
130+ cleanup();
131+ buffer = (char*)my_malloc(new_buffer_length,MYF(0));
132+ }
133+ uint query_position = 0;
134+ uint position = 0;
135+ // Skip whitespaces from begin
136+ while((query_position < query_length) && query_strip_comments_is_white_space(query[query_position]))
137+ {
138+ ++query_position;
139+ }
140+ long int last_space = -1;
141+ while(query_position < query_length)
142+ {
143+ char current = query[query_position];
144+ bool insert_space = false; // insert space to buffer, (IMPORTANT) don't update query_position
145+ switch(current)
114+ {146+ {
115+ /* check for pair of quote */147+ case '\'':
116+ if (*to == current)148+ case '"':
117+ {149+ {
118+ /* skip second quote */150+ buffer[position++] = query[query_position++]; // copy current symbol
119+ to++;151+ while(query_position < query_length)
120+ /* check for same symbol after second quote */152+ {
121+ if (to < end && *to == current)153+ if(current == query[query_position]) // found pair quote
122+ {154+ {
123+ /* same symbol, skip it */155+ break;
124+ to++;156+ }
125+ /* check for end-of-line */157+ buffer[position++] = query[query_position++]; // copy current symbol
126+ if (to == end)158+ }
127+ {159+ break;
128+ /* not found - not closed quote */160+ }
129+ return Error;161+ case '/':
130+ }162+ {
131+ else163+ if(((query_position + 2) < query_length) && ('*' == query[query_position+1]) && ('!' != query[query_position+2]))
132+ {164+ {
133+ /* continue search of pair */165+ query_position += 2; // skip "/*"
166+ do
167+ {
168+ if('*' == query[query_position] && '/' == query[query_position+1]) // check for "*/"
169+ {
170+ query_position += 2; // skip "*/"
171+ insert_space = true;
172+ break;
173+ }
174+ else
175+ {
176+ ++query_position;
177+ }
178+ }
179+ while(query_position < query_length);
180+ if(!insert_space)
181+ {
134+ continue;182+ continue;
135+ }183+ }
136+ }184+ }
137+ else185+ break;
138+ {186+ }
139+ return Another;187+ case '-':
140+ }188+ {
141+ }189+ if(query[query_position+1] == '-')
142+ /* check for escaped symbols */190+ {
143+ if (*to == '\\')191+ ++query_position; // skip "-", and go to search of "\n"
144+ {192+ }
145+ /* backslash, skip it */193+ else
146+ to++;194+ {
147+ }195+ break;
148+ /* check for end-of-line */196+ }
149+ if (to == end)197+ }
150+ {198+ case '#':
151+ /* not found - not closed quote */199+ {
152+ return Error;200+ do
153+ }201+ {
154+ /* skip current symbol */202+ ++query_position; // skip current symbol (# or -)
155+ to++;203+ if('\n' == query[query_position]) // check for '\n'
156+ }204+ {
157+ case '-':205+ ++query_position; // skip '\n'
158+ /* Skip minus */206+ insert_space = true;
159+ to++;207+ break;
160+ /* Check for second minus */208+ }
161+ if (*to != '-')209+ }
162+ {210+ while(query_position < query_length);
163+ /* Just minus */211+ if(insert_space)
164+ return Another;212+ {
165+ }213+ break;
166+ else214+ }
167+ {215+ else
168+ /*216+ {
169+ Prefix is minus-minus, next case-branch is processing217+ continue;
170+ single line comments.218+ }
171+ */219+ }
172+ }220+ default:
173+ case '#':221+ if(query_strip_comments_is_white_space(current))
174+ /*222+ {
175+ This is single-line comment, it started by "#" or "--".223+ insert_space = true;
176+ Skip first symbol.224+ ++query_position;
177+ */225+ }
178+ to++;226+ break; // make gcc happy
179+ /* search new-line */227+ }
180+ to= strchr(to, '\n');228+ if(insert_space)
181+ if (NULL == to)229+ {
182+ {230+ if((uint) (last_space + 1) != position)
183+ /* not found, end of the comment is the end of the query */231+ {
184+ to= end;232+ last_space = position;
185+ }233+ buffer[position++] = ' ';
186+ else234+ }
187+ {235+ }
188+ /* skip end-of-line */236+ else if (query_position < query_length)
189+ to++;237+ {
190+ }238+ buffer[position++] = query[query_position++];
191+ return Comment;239+ }
192+ case '/':240+ }
193+ /* skip slash */241+ while((0 < position) && query_strip_comments_is_white_space(buffer[position - 1]))
194+ to++;242+ {
195+ /* check for star */243+ --position;
196+ if (*to == '*')244+ }
197+ {245+ buffer[position] = 0;
198+ /* skip star */246+ length = position;
199+ to++;247+}
200+ /* check for exclamation */248+void QueryStripComments::cleanup()
201+ bool exclamation= (*to == '!');249+{
202+ /* search star-slash */250+ if(buffer)
203+ to= strstr(to, "*/");251+ {
204+ if (NULL == to)252+ my_free(buffer);
205+ {253+ }
206+ /* not found - not closed comment */254+ buffer = 0;
207+ return Error;255+ length = 0;
208+ }256+ buffer_length = 0;
209+ else257+}
210+ {258+QueryStripComments_Backup::QueryStripComments_Backup(THD* a_thd,QueryStripComments* qsc)
211+ /* found */259+{
212+ DBUG_ASSERT(to + 1 < end);260+ if(opt_query_cache_strip_comments)
213+ DBUG_ASSERT(0 == strncmp(to, "*/", 2));261+ {
214+ /* skip star-slash */262+ thd = a_thd;
215+ to++;263+ query = thd->query();
216+ to++;264+ length = thd->query_length();
217+ return (exclamation ? Special : Comment);265+ qsc->set(query, length, QUERY_BUFFER_ADDITIONAL_LENGTH(thd->db_length));
218+ }266+ *(size_t *) (qsc->query() + qsc->query_length() + 1)= thd->db_length;
219+ }267+ thd->set_query(qsc->query(),qsc->query_length());
220+ else268+ }
221+ {269+ else
222+ /* just slash */270+ {
223+ return Another;271+ thd = 0;
224+ }272+ query = 0;
225+ case ' ':273+ length = 0;
226+ case '\t':274+ }
227+ case '\r':275+}
228+ case '\n':276+QueryStripComments_Backup::~QueryStripComments_Backup()
229+ {277+{
230+ /* skip space */278+ if(thd)
231+ to++;279+ {
232+ return WhiteSpace;280+ thd->set_query(query,length);
233+ }281+ }
234+ case '\\':282+}
235+ {
236+ /* skip backslash */
237+ to++;
238+ if (to == end)
239+ {
240+ /*
241+ query complete by backslash
242+ probable error?
243+ */
244+ return Another;
245+ }
246+ else
247+ {
248+ /* skip after backslash symbol */
249+ to++;
250+ return Another;
251+ }
252+ }
253+ case '(':
254+ case ')':
255+ {
256+ /* skip parenthese */
257+ to++;
258+ return Special;
259+ }
260+ default:
261+ {
262+ /* skip symbol */
263+ to++;
264+ return Another;
265+ }
266+ };
267+}
268+
269+
270+static bool remove_comments_from_query(const char *const query,
271+ const size_t query_length,
272+ char *const result,
273+ size_t *result_length)
274+{
275+ /* pointer to begin of parsed block */
276+ const char *from= query;
277+ const char *to= query;
278+ /* pointer to end of the query */
279+ const char *const end= query + query_length;
280+ /* pointer to last space */
281+ const char *space= NULL;
282+ /* current position in result buffer */
283+ char *current= result;
284+ while (true)
285+ {
286+ from= to;
287+ switch (analyze(&to, end))
288+ {
289+ case Empty:
290+ {
291+ /*
292+ parse completed
293+ check for whitespace in the end
294+ */
295+ if (current == space)
296+ {
297+ /* drop whitespace in the end of query */
298+ --current;
299+ }
300+ /* result is null-terminated string */
301+ *current= 0;
302+ /* set result length */
303+ *result_length= current - result;
304+ /* all right */
305+ return true;
306+ }
307+ case Comment:
308+ /* should just insert space instead of comment */
309+ case WhiteSpace:
310+ if (space == current || from == query)
311+ {
312+ /* previous symbol was space */
313+ }
314+ else
315+ {
316+ /* insert space to result buffer */
317+ *current= ' ';
318+ /* switch after inserted space */
319+ current++;
320+ }
321+ /* remember last-after-space position */
322+ space= current;
323+ /* parse again */
324+ continue;
325+ case Special:
326+ case Another:
327+ {
328+ /* calculate parsed block size */
329+ size_t block_size= to - from;
330+ /* copy parsed block to result */
331+ memcpy(current, from, block_size);
332+ /* switch result after copied block */
333+ current+= block_size;
334+ /* switch after parsed block */
335+ from= to;
336+ /* parse again */
337+ continue;
338+ }
339+ case Error:
340+ default:
341+ {
342+ /* bad source query */
343+ return false;
344+ }
345+ }
346+ }
347+}
348+
349+
350+static size_t skip_not_another(const char *const query, size_t query_length)
351+{
352+ const char *from= query;
353+ const char *to= query;
354+ const char *const end= query + query_length;
355+ while (true)
356+ {
357+ switch (analyze(&to, end))
358+ {
359+ case Error:
360+ return 0;
361+ case Empty:
362+ case Another:
363+ return (from - query);
364+ default:
365+ from= to;
366+ continue;
367+ };
368+ }
369+}
370+
371+
372+static size_t skip_default(const char *const query, size_t /* query_length */)
373+{
374+ size_t query_position= 0;
375+ /*
376+ Skip '(' characters in queries like following:
377+ (select a from t1) union (select a from t1);
378+ */
379+ while (query[query_position]=='(')
380+ query_position++;
381+ return query_position;
382+}
383+
384+
385+} /* namespace query_comments_parser */
386+
387+class Query_Switcher
388+{
389+private:
390+ Query_Switcher(const Query_Switcher&);
391+ Query_Switcher& operator=(const Query_Switcher&);
392+
393+
394+public:
395+ Query_Switcher(THD *thd) :
396+ target_query(&(thd_query_string(thd)->str)),
397+ target_length(&(thd_query_string(thd)->length)),
398+ backup_query(thd->query()),
399+ backup_length(thd->query_length())
400+ {
401+ }
402+
403+ Query_Switcher(char **query,
404+ size_t *length) :
405+ target_query(query),
406+ target_length(length),
407+ backup_query(*query),
408+ backup_length(*length)
409+ {
410+ }
411+public:
412+ void replace(Query_Without_Comments *query_without_comments)
413+ {
414+ *target_query= query_without_comments->query();
415+ *target_length= query_without_comments->length();
416+ }
417+ void restore()
418+ {
419+ *target_query= backup_query;
420+ *target_length= backup_length;
421+ }
422+private:
423+ char* *target_query;
424+ size_t *target_length;
425+public:
426+ char *const backup_query;
427+ size_t const backup_length;
428+};
429+
430+class Comments_Processor
431+{
432+private:
433+ Comments_Processor(const Comments_Processor&);
434+ Comments_Processor& operator=(const Comments_Processor&);
435+
436+
437+public:
438+ Comments_Processor(THD *thd) :
439+ query_switcher (thd),
440+ db_length (thd->db_length),
441+ query_without_comments(&(thd->query_without_comments)),
442+ enabled (opt_query_cache_strip_comments),
443+ restore (false)
444+ {
445+ }
446+
447+
448+ Comments_Processor(Query_Without_Comments *current_query_without_comments,
449+ char **query,
450+ size_t *length,
451+ const size_t current_db_length) :
452+ query_switcher (query, length),
453+ db_length (current_db_length),
454+ query_without_comments(current_query_without_comments),
455+ enabled (opt_query_cache_strip_comments),
456+ restore (false)
457+ {
458+ }
459+
460+
461+ ~Comments_Processor()
462+ {
463+ restore_comments();
464+ }
465+
466+
467+ size_t prefix_length()
468+ {
469+ using query_comments_parser::skip_not_another;
470+ using query_comments_parser::skip_default;
471+ if (enabled)
472+ {
473+ return skip_not_another(query_switcher.backup_query,
474+ query_switcher.backup_length);
475+ }
476+ else
477+ {
478+ return skip_default(query_switcher.backup_query,
479+ query_switcher.backup_length);
480+ }
481+ }
482+
483+
484+ bool remove_comments()
485+ {
486+ if (!enabled || restore)
487+ {
488+ return true;
489+ }
490+ /* Allocate memory for query rewrite */
491+ if (!query_without_comments->allocate(query_switcher.backup_length,
492+ db_length))
493+ {
494+ return false;
495+ }
496+ /* Remove comment from query */
497+ size_t result_length;
498+ using query_comments_parser::remove_comments_from_query;
499+ if (!(restore= remove_comments_from_query(query_switcher.backup_query,
500+ query_switcher.backup_length,
501+ query_without_comments->query(),
502+ &result_length)))
503+ {
504+ return false;
505+ }
506+ query_without_comments->set_length(result_length);
507+ size_t db_length_from_query=
508+ *((size_t*)(query_switcher.backup_query +
509+ query_switcher.backup_length + 1));
510+ *((size_t*)(query_without_comments->query() +
511+ result_length + 1))= db_length_from_query;
512+ /* Replace original query by striped */
513+ query_switcher.replace(query_without_comments);
514+ return restore;
515+ }
516+
517+
518+ void restore_comments()
519+ {
520+ if (enabled && restore)
521+ {
522+ /* Replace striped query by original */
523+ query_switcher.restore();
524+
525+ /* Clean query_without_comments */
526+ query_without_comments->set_length(0);
527+
528+ /* Mark as restored */
529+ restore= false;
530+ }
531+ }
532+private:
533+ Query_Switcher query_switcher;
534+private:
535+ const size_t db_length;
536+private:
537+ Query_Without_Comments *query_without_comments;
538+ bool enabled;
539+ bool restore;
540+};
541+283+
542 #ifdef EMBEDDED_LIBRARY284 #ifdef EMBEDDED_LIBRARY
543 #include "emb_qcache.h"285 #include "emb_qcache.h"
544 #endif286 #endif
545@@ -454,7 +944,12 @@287@@ -454,7 +646,12 @@
546 Query_cache_wait_state wait_state(thd, __func__, __FILE__, __LINE__);288 Query_cache_wait_state wait_state(thd, __func__, __FILE__, __LINE__);
547 DBUG_ENTER("Query_cache::try_lock");289 DBUG_ENTER("Query_cache::try_lock");
548 290
549+ const char *old_proc_info= thd->proc_info;291+ const char* old_proc_info= thd->proc_info;
550+ thd_proc_info(thd,"Waiting on query cache mutex");292+ thd_proc_info(thd,"Waiting on query cache mutex");
551+ DEBUG_SYNC(thd, "before_query_cache_mutex");293+ DEBUG_SYNC(thd, "before_query_cache_mutex");
552 mysql_mutex_lock(&structure_guard_mutex);294 mysql_mutex_lock(&structure_guard_mutex);
@@ -555,171 +297,191 @@
555 while (1)297 while (1)
556 {298 {
557 if (m_cache_lock_status == Query_cache::UNLOCKED)299 if (m_cache_lock_status == Query_cache::UNLOCKED)
558@@ -1274,6 +1769,8 @@300@@ -1274,6 +1471,8 @@
559 unlock();301 unlock();
560 DBUG_VOID_RETURN;302 DBUG_VOID_RETURN;
561 }303 }
562+ Comments_Processor comments_processor(thd);304+ QueryStripComments *query_strip_comments = &(thd->query_strip_comments);
563+ comments_processor.remove_comments();305+ QueryStripComments_Backup backup(thd,query_strip_comments);
564 306
565 /* Key is query + database + flag */307 /* Key is query + database + flag */
566 if (thd->db_length)308 if (thd->db_length)
567@@ -1440,7 +1937,7 @@309@@ -1451,6 +1650,9 @@
568 */310 Query_cache_block_table *block_table, *block_table_end;
569
570 int
571-Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
572+Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length_uint)
573 {
574 ulonglong engine_data;
575 Query_cache_query *query;
576@@ -1452,6 +1949,11 @@
577 ulong tot_length;311 ulong tot_length;
578 Query_cache_query_flags flags;312 Query_cache_query_flags flags;
313+ QueryStripComments *query_strip_comments = &(thd->query_strip_comments);
314+ char *sql_backup = sql;
315+ uint query_length_backup = query_length;
579 DBUG_ENTER("Query_cache::send_result_to_client");316 DBUG_ENTER("Query_cache::send_result_to_client");
580+ size_t query_length= query_length_uint;
581+ Comments_Processor comments_processor(&(thd->query_without_comments),
582+ &sql,
583+ &query_length,
584+ thd->db_length);
585 317
586 /*318 /*
587 Testing 'query_cache_size' without a lock here is safe: the thing319@@ -1472,21 +1674,103 @@
588@@ -1471,13 +1973,7 @@
589 }
590 320
591 {321 {
592- uint i= 0;322 uint i= 0;
593- /*323- /*
594- Skip '(' characters in queries like following:324- Skip '(' characters in queries like following:
595- (select a from t1) union (select a from t1);325- (select a from t1) union (select a from t1);
596- */326- */
597- while (sql[i]=='(')327- while (sql[i]=='(')
598- i++;328- i++;
599+ size_t i= comments_processor.prefix_length();329+ if(opt_query_cache_strip_comments)
600 330+ {
601 /*331+ /* Skip all comments and non-letter symbols */
602 Test if the query is a SELECT332+ uint& query_position = i;
603@@ -1487,10 +1983,11 @@333+ char* query = sql;
604 frequently appeared in real life, consequently we can334+ while(query_position < query_length)
605 check all such queries, too.335+ {
606 */336+ bool check = false;
607- if ((my_toupper(system_charset_info, sql[i]) != 'S' ||337+ char current = query[query_position];
608- my_toupper(system_charset_info, sql[i + 1]) != 'E' ||338+ switch(current)
609- my_toupper(system_charset_info, sql[i + 2]) != 'L') &&339+ {
610- sql[i] != '/')340+ case '/':
611+ if (!((i + 2 < query_length) &&341+ if(((query_position + 2) < query_length) && ('*' == query[query_position+1]) && ('!' != query[query_position+2]))
612+ ((my_toupper(system_charset_info, sql[i]) == 'S' &&342+ {
613+ my_toupper(system_charset_info, sql[i + 1]) == 'E' &&343+ query_position += 2; // skip "/*"
614+ my_toupper(system_charset_info, sql[i + 2]) == 'L') ||344+ do
615+ sql[i] == '/')))345+ {
616 {346+ if('*' == query[query_position] && '/' == query[query_position+1]) // check for "*/" (without space)
617 DBUG_PRINT("qcache", ("The statement is not a SELECT; Not cached"));347+ {
618 goto err;348+ query_position += 2; // skip "*/" (without space)
619@@ -1543,6 +2040,7 @@349+ break;
350+ }
351+ else
352+ {
353+ ++query_position;
354+ }
355+ }
356+ while(query_position < query_length);
357+ continue; // analyze current symbol
358+ }
359+ break;
360+ case '-':
361+ if(query[query_position+1] == '-')
362+ {
363+ ++query_position; // skip "-"
364+ }
365+ else
366+ {
367+ break;
368+ }
369+ case '#':
370+ do
371+ {
372+ ++query_position; // skip current symbol
373+ if('\n' == query[query_position]) // check for '\n'
374+ {
375+ ++query_position; // skip '\n'
376+ break;
377+ }
378+ }
379+ while(query_position < query_length);
380+ continue; // analyze current symbol
381+ case '\r':
382+ case '\n':
383+ case '\t':
384+ case ' ':
385+ case '(':
386+ case ')':
387+ break;
388+ default:
389+ check = true;
390+ break; // make gcc happy
391+ } // switch(current)
392+ if(check)
393+ {
394+ if(query_position + 2 < query_length)
395+ {
396+ // cacheable
397+ break;
398+ }
399+ else
400+ {
401+ DBUG_PRINT("qcache", ("The statement is not a SELECT; Not cached"));
402+ goto err;
403+ }
404+ } // if(check)
405+ ++query_position;
406+ } // while(query_position < query_length)
407+ }
408+ else // if(opt_query_cache_strip_comments)
409+ {
410+ /*
411+ Skip '(' characters in queries like following:
412+ (select a from t1) union (select a from t1);
413+ */
414+ while (sql[i]=='(')
415+ i++;
416
417- /*
418- Test if the query is a SELECT
419- (pre-space is removed in dispatch_command).
420+ } // if(opt_query_cache_strip_comments)
421+ /*
422+ Test if the query is a SELECT
423+ (pre-space is removed in dispatch_command).
424
425- First '/' looks like comment before command it is not
426- frequently appeared in real life, consequently we can
427- check all such queries, too.
428- */
429+ First '/' looks like comment before command it is not
430+ frequently appeared in real life, consequently we can
431+ check all such queries, too.
432+ */
433 if ((my_toupper(system_charset_info, sql[i]) != 'S' ||
434 my_toupper(system_charset_info, sql[i + 1]) != 'E' ||
435 my_toupper(system_charset_info, sql[i + 2]) != 'L') &&
436@@ -1543,6 +1827,14 @@
620 goto err_unlock;437 goto err_unlock;
621 438
622 Query_cache_block *query_block;439 Query_cache_block *query_block;
623+ comments_processor.remove_comments();440+ if(opt_query_cache_strip_comments)
441+ {
442+ query_strip_comments->set(sql, query_length,
443+ QUERY_BUFFER_ADDITIONAL_LENGTH(thd->db_length));
444+ sql = query_strip_comments->query();
445+ query_length = query_strip_comments->query_length();
446+ *(size_t *) (sql + query_length + 1)= thd->db_length;
447+ }
624 448
625 tot_length= query_length + 1 + sizeof(size_t) + 449 tot_length= query_length + 1 + sizeof(size_t) +
626 thd->db_length + QUERY_CACHE_FLAGS_SIZE;450 thd->db_length + QUERY_CACHE_FLAGS_SIZE;
627@@ -1611,6 +2109,7 @@451@@ -1611,6 +1903,8 @@
628 (uchar*) &flags, QUERY_CACHE_FLAGS_SIZE);452 (uchar*) &flags, QUERY_CACHE_FLAGS_SIZE);
629 query_block = (Query_cache_block *) my_hash_search(&queries, (uchar*) sql,453 query_block = (Query_cache_block *) my_hash_search(&queries, (uchar*) sql,
630 tot_length);454 tot_length);
631+ comments_processor.restore_comments();455+ sql = sql_backup;
456+ query_length = query_length_backup;
632 /* Quick abort on unlocked data */457 /* Quick abort on unlocked data */
633 if (query_block == 0 ||458 if (query_block == 0 ||
634 query_block->query()->result() == 0 ||459 query_block->query()->result() == 0 ||
635--- a/sql/sql_class.h460--- a/sql/sql_class.h
636+++ b/sql/sql_class.h461+++ b/sql/sql_class.h
637@@ -1485,6 +1485,74 @@462@@ -40,6 +40,9 @@
638 463 #include "thr_lock.h" /* thr_lock_type, THR_LOCK_DATA,
639 extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);464 THR_LOCK_INFO */
640 465
641+466+#ifdef HAVE_QUERY_CACHE
642+#ifdef HAVE_QUERY_CACHE467+#include "query_strip_comments.h"
643+468+#endif // HAVE_QUERY_CACHE
644+469
645+/*470 class Reprepare_observer;
646+ @class Query_Without_Comments471 class Relay_log_info;
647+ This class provides way for safety (re)allocation472@@ -766,6 +769,9 @@
648+ a memory for a query without comments.473 statement lifetime. FIXME: must be const
649+*/474 */
650+class Query_Without_Comments475 ulong id;
651+{476+#ifdef HAVE_QUERY_CACHE
652+private:477+ QueryStripComments query_strip_comments; // see sql_cache.cc
653+ /*478+#endif //HAVE_QUERY_CACHE
654+ Denied copy and assigment for object of this class.479
655+ */480 /*
656+ Query_Without_Comments(const Query_Without_Comments&);481 MARK_COLUMNS_NONE: Means mark_used_colums is not set and no indicator to
657+ Query_Without_Comments& operator=(const Query_Without_Comments&);
658+
659+
660+public:
661+ /*
662+ Constructor is filling fields by zero (no allocation).
663+ */
664+ Query_Without_Comments();
665+
666+
667+ /*
668+ Destructor clean allocated memory
669+ */
670+ ~Query_Without_Comments();
671+public:
672+
673+
674+/*
675+ (Re)allocate memory for query. Query length after that is 0.
676+ */
677+ bool allocate(size_t query_length, size_t db_length);
678+
679+
680+ /*
681+ Set result query length, when query
682+ without comments is copied to buffer.
683+ */
684+ void set_length(size_t query_length);
685+
686+
687+public:
688+ /*
689+ Result query.
690+ */
691+ char* query();
692+
693+
694+ /*
695+ Result query length
696+ */
697+ size_t length();
698+
699+
700+private:
701+ char* buffer;
702+ size_t q_length;
703+ size_t b_length;
704+};
705+
706+
707+#endif /* HAVE_QUERY_CACHE */
708+
709 /**
710 @class THD
711 For each client connection we create a separate thread with THD serving as
712@@ -1542,6 +1610,7 @@
713 struct st_mysql_stmt *current_stmt;
714 #endif
715 #ifdef HAVE_QUERY_CACHE
716+ Query_Without_Comments query_without_comments;
717 Query_cache_tls query_cache_tls;
718 #endif
719 NET net; // client connection descriptor
720--- a/sql/sys_vars.cc482--- a/sql/sys_vars.cc
721+++ b/sql/sys_vars.cc483+++ b/sql/sys_vars.cc
722@@ -1888,6 +1888,11 @@484@@ -1895,6 +1895,11 @@
723 NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),485 NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
724 ON_UPDATE(fix_query_cache_size));486 ON_UPDATE(fix_query_cache_size));
725 487
@@ -733,7 +495,7 @@
733 "Don't cache results that are bigger than this",495 "Don't cache results that are bigger than this",
734--- /dev/null496--- /dev/null
735+++ b/mysql-test/include/percona_query_cache_with_comments.inc497+++ b/mysql-test/include/percona_query_cache_with_comments.inc
736@@ -0,0 +1,117 @@498@@ -0,0 +1,95 @@
737+--source include/percona_query_cache_with_comments_clear.inc499+--source include/percona_query_cache_with_comments_clear.inc
738+let $query=/* with comment first */select * from t1;500+let $query=/* with comment first */select * from t1;
739+eval $query;501+eval $query;
@@ -827,30 +589,8 @@
827+;589+;
828+--source include/percona_query_cache_with_comments_eval.inc590+--source include/percona_query_cache_with_comments_eval.inc
829+591+
830+let $query=select */* a comment \*/from t1;
831+--source include/percona_query_cache_with_comments_eval.inc
832+
833+let $query=select *# a comment \\
834+from t1;
835+--source include/percona_query_cache_with_comments_eval.inc
836+
837+let $query=select *-- a comment \\
838+from t1;
839+--source include/percona_query_cache_with_comments_eval.inc
840+
841+let $query=select "\\\\"" /* not a comment */" from t1;
842+--source include/percona_query_cache_with_comments_eval.inc
843+
844+let $query=select "\\\\"" /*! not a comment */" from t1;
845+--source include/percona_query_cache_with_comments_eval.inc
846+
847+# following two queries related to bug #856404.
848+# There are different queries, but opt_query_cache_strip_comments thinks that they are equal.
849+let $query=select ' \' ' from t1;592+let $query=select ' \' ' from t1;
850+--source include/percona_query_cache_with_comments_eval.inc593+--source include/percona_query_cache_with_comments_eval.inc
851+
852+let $query=select ' \' /* comment inside quotes with internal backslash quote */' from t1;
853+--source include/percona_query_cache_with_comments_eval.inc
854--- /dev/null594--- /dev/null
855+++ b/mysql-test/include/percona_query_cache_with_comments_begin.inc595+++ b/mysql-test/include/percona_query_cache_with_comments_begin.inc
856@@ -0,0 +1,12 @@596@@ -0,0 +1,12 @@
@@ -903,7 +643,7 @@
903+643+
904--- /dev/null644--- /dev/null
905+++ b/mysql-test/r/percona_query_cache_with_comments.result645+++ b/mysql-test/r/percona_query_cache_with_comments.result
906@@ -0,0 +1,1058 @@646@@ -0,0 +1,866 @@
907+set global query_cache_strip_comments=ON;647+set global query_cache_strip_comments=ON;
908+set GLOBAL query_cache_size=1355776;648+set GLOBAL query_cache_size=1355776;
909+drop table if exists t1;649+drop table if exists t1;
@@ -1737,228 +1477,36 @@
1737+Variable_name Value1477+Variable_name Value
1738+Qcache_hits 501478+Qcache_hits 50
1739+-----------------------------------------------------1479+-----------------------------------------------------
1740+select */* a comment \*/from t1
1741+-----------------------------------------------------
1742+show status like "Qcache_queries_in_cache";
1743+Variable_name Value
1744+Qcache_queries_in_cache 1
1745+show status like "Qcache_inserts";
1746+Variable_name Value
1747+Qcache_inserts 1
1748+show status like "Qcache_hits";
1749+Variable_name Value
1750+Qcache_hits 50
1751+select */* a comment \*/from t1;
1752+a
1753+1
1754+2
1755+3
1756+select */* a comment \*/from t1;
1757+a
1758+1
1759+2
1760+3
1761+show status like "Qcache_queries_in_cache";
1762+Variable_name Value
1763+Qcache_queries_in_cache 1
1764+show status like "Qcache_inserts";
1765+Variable_name Value
1766+Qcache_inserts 1
1767+show status like "Qcache_hits";
1768+Variable_name Value
1769+Qcache_hits 52
1770+-----------------------------------------------------
1771+select *# a comment \
1772+from t1
1773+-----------------------------------------------------
1774+show status like "Qcache_queries_in_cache";
1775+Variable_name Value
1776+Qcache_queries_in_cache 1
1777+show status like "Qcache_inserts";
1778+Variable_name Value
1779+Qcache_inserts 1
1780+show status like "Qcache_hits";
1781+Variable_name Value
1782+Qcache_hits 52
1783+select *# a comment \
1784+from t1;
1785+a
1786+1
1787+2
1788+3
1789+select *# a comment \
1790+from t1;
1791+a
1792+1
1793+2
1794+3
1795+show status like "Qcache_queries_in_cache";
1796+Variable_name Value
1797+Qcache_queries_in_cache 1
1798+show status like "Qcache_inserts";
1799+Variable_name Value
1800+Qcache_inserts 1
1801+show status like "Qcache_hits";
1802+Variable_name Value
1803+Qcache_hits 54
1804+-----------------------------------------------------
1805+select *-- a comment \
1806+from t1
1807+-----------------------------------------------------
1808+show status like "Qcache_queries_in_cache";
1809+Variable_name Value
1810+Qcache_queries_in_cache 1
1811+show status like "Qcache_inserts";
1812+Variable_name Value
1813+Qcache_inserts 1
1814+show status like "Qcache_hits";
1815+Variable_name Value
1816+Qcache_hits 54
1817+select *-- a comment \
1818+from t1;
1819+a
1820+1
1821+2
1822+3
1823+select *-- a comment \
1824+from t1;
1825+a
1826+1
1827+2
1828+3
1829+show status like "Qcache_queries_in_cache";
1830+Variable_name Value
1831+Qcache_queries_in_cache 1
1832+show status like "Qcache_inserts";
1833+Variable_name Value
1834+Qcache_inserts 1
1835+show status like "Qcache_hits";
1836+Variable_name Value
1837+Qcache_hits 56
1838+-----------------------------------------------------
1839+select "\\"" /* not a comment */" from t1
1840+-----------------------------------------------------
1841+show status like "Qcache_queries_in_cache";
1842+Variable_name Value
1843+Qcache_queries_in_cache 1
1844+show status like "Qcache_inserts";
1845+Variable_name Value
1846+Qcache_inserts 1
1847+show status like "Qcache_hits";
1848+Variable_name Value
1849+Qcache_hits 56
1850+select "\\"" /* not a comment */" from t1;
1851+\" /* not a comment */
1852+\" /* not a comment */
1853+\" /* not a comment */
1854+\" /* not a comment */
1855+select "\\"" /* not a comment */" from t1;
1856+\" /* not a comment */
1857+\" /* not a comment */
1858+\" /* not a comment */
1859+\" /* not a comment */
1860+show status like "Qcache_queries_in_cache";
1861+Variable_name Value
1862+Qcache_queries_in_cache 2
1863+show status like "Qcache_inserts";
1864+Variable_name Value
1865+Qcache_inserts 2
1866+show status like "Qcache_hits";
1867+Variable_name Value
1868+Qcache_hits 57
1869+-----------------------------------------------------
1870+select "\\"" /*! not a comment */" from t1
1871+-----------------------------------------------------
1872+show status like "Qcache_queries_in_cache";
1873+Variable_name Value
1874+Qcache_queries_in_cache 2
1875+show status like "Qcache_inserts";
1876+Variable_name Value
1877+Qcache_inserts 2
1878+show status like "Qcache_hits";
1879+Variable_name Value
1880+Qcache_hits 57
1881+select "\\"" /*! not a comment */" from t1;
1882+\" /*! not a comment */
1883+\" /*! not a comment */
1884+\" /*! not a comment */
1885+\" /*! not a comment */
1886+select "\\"" /*! not a comment */" from t1;
1887+\" /*! not a comment */
1888+\" /*! not a comment */
1889+\" /*! not a comment */
1890+\" /*! not a comment */
1891+show status like "Qcache_queries_in_cache";
1892+Variable_name Value
1893+Qcache_queries_in_cache 3
1894+show status like "Qcache_inserts";
1895+Variable_name Value
1896+Qcache_inserts 3
1897+show status like "Qcache_hits";
1898+Variable_name Value
1899+Qcache_hits 58
1900+-----------------------------------------------------
1901+select ' \' ' from t11480+select ' \' ' from t1
1902+-----------------------------------------------------1481+-----------------------------------------------------
1903+show status like "Qcache_queries_in_cache";1482+show status like "Qcache_queries_in_cache";
1904+Variable_name Value1483+Variable_name Value
1905+Qcache_queries_in_cache 31484+Qcache_queries_in_cache 1
1906+show status like "Qcache_inserts";1485+show status like "Qcache_inserts";
1907+Variable_name Value1486+Variable_name Value
1908+Qcache_inserts 31487+Qcache_inserts 1
1909+show status like "Qcache_hits";1488+show status like "Qcache_hits";
1910+Variable_name Value1489+Variable_name Value
1911+Qcache_hits 581490+Qcache_hits 50
1912+select ' \' ' from t1;1491+select ' \' ' from t1;
1913+' 1492+'
1914+ ' 1493+ '
1915+ ' 1494+ '
1916+ ' 1495+ '
1917+select ' \' ' from t1;1496+select ' \' ' from t1;
1918+' 1497+'
1919+ ' 1498+ '
1920+ ' 1499+ '
1921+ ' 1500+ '
1922+show status like "Qcache_queries_in_cache";1501+show status like "Qcache_queries_in_cache";
1923+Variable_name Value1502+Variable_name Value
1924+Qcache_queries_in_cache 41503+Qcache_queries_in_cache 2
1925+show status like "Qcache_inserts";1504+show status like "Qcache_inserts";
1926+Variable_name Value1505+Variable_name Value
1927+Qcache_inserts 41506+Qcache_inserts 2
1928+show status like "Qcache_hits";1507+show status like "Qcache_hits";
1929+Variable_name Value1508+Variable_name Value
1930+Qcache_hits 591509+Qcache_hits 51
1931+-----------------------------------------------------
1932+select ' \' /* comment inside quotes with internal backslash quote */' from t1
1933+-----------------------------------------------------
1934+show status like "Qcache_queries_in_cache";
1935+Variable_name Value
1936+Qcache_queries_in_cache 4
1937+show status like "Qcache_inserts";
1938+Variable_name Value
1939+Qcache_inserts 4
1940+show status like "Qcache_hits";
1941+Variable_name Value
1942+Qcache_hits 59
1943+select ' \' /* comment inside quotes with internal backslash quote */' from t1;
1944+' /* comment inside quotes with internal backslash quote */
1945+ ' /* comment inside quotes with internal backslash quote */
1946+ ' /* comment inside quotes with internal backslash quote */
1947+ ' /* comment inside quotes with internal backslash quote */
1948+select ' \' /* comment inside quotes with internal backslash quote */' from t1;
1949+' /* comment inside quotes with internal backslash quote */
1950+ ' /* comment inside quotes with internal backslash quote */
1951+ ' /* comment inside quotes with internal backslash quote */
1952+ ' /* comment inside quotes with internal backslash quote */
1953+show status like "Qcache_queries_in_cache";
1954+Variable_name Value
1955+Qcache_queries_in_cache 5
1956+show status like "Qcache_inserts";
1957+Variable_name Value
1958+Qcache_inserts 5
1959+show status like "Qcache_hits";
1960+Variable_name Value
1961+Qcache_hits 60
1962+DROP TABLE t1;1510+DROP TABLE t1;
1963+SET GLOBAL query_cache_size=default;1511+SET GLOBAL query_cache_size=default;
1964+set global query_cache_strip_comments=OFF;1512+set global query_cache_strip_comments=OFF;
@@ -1988,7 +1536,7 @@
1988+SET GLOBAL query_cache_size= default;1536+SET GLOBAL query_cache_size= default;
1989--- /dev/null1537--- /dev/null
1990+++ b/mysql-test/r/percona_query_cache_with_comments_disable.result1538+++ b/mysql-test/r/percona_query_cache_with_comments_disable.result
1991@@ -0,0 +1,1057 @@1539@@ -0,0 +1,865 @@
1992+set GLOBAL query_cache_size=1355776;1540+set GLOBAL query_cache_size=1355776;
1993+drop table if exists t1;1541+drop table if exists t1;
1994+create table t1 (a int not null);1542+create table t1 (a int not null);
@@ -2821,228 +2369,36 @@
2821+Variable_name Value2369+Variable_name Value
2822+Qcache_hits 252370+Qcache_hits 25
2823+-----------------------------------------------------2371+-----------------------------------------------------
2824+select */* a comment \*/from t1
2825+-----------------------------------------------------
2826+show status like "Qcache_queries_in_cache";
2827+Variable_name Value
2828+Qcache_queries_in_cache 20
2829+show status like "Qcache_inserts";
2830+Variable_name Value
2831+Qcache_inserts 20
2832+show status like "Qcache_hits";
2833+Variable_name Value
2834+Qcache_hits 25
2835+select */* a comment \*/from t1;
2836+a
2837+1
2838+2
2839+3
2840+select */* a comment \*/from t1;
2841+a
2842+1
2843+2
2844+3
2845+show status like "Qcache_queries_in_cache";
2846+Variable_name Value
2847+Qcache_queries_in_cache 21
2848+show status like "Qcache_inserts";
2849+Variable_name Value
2850+Qcache_inserts 21
2851+show status like "Qcache_hits";
2852+Variable_name Value
2853+Qcache_hits 26
2854+-----------------------------------------------------
2855+select *# a comment \
2856+from t1
2857+-----------------------------------------------------
2858+show status like "Qcache_queries_in_cache";
2859+Variable_name Value
2860+Qcache_queries_in_cache 21
2861+show status like "Qcache_inserts";
2862+Variable_name Value
2863+Qcache_inserts 21
2864+show status like "Qcache_hits";
2865+Variable_name Value
2866+Qcache_hits 26
2867+select *# a comment \
2868+from t1;
2869+a
2870+1
2871+2
2872+3
2873+select *# a comment \
2874+from t1;
2875+a
2876+1
2877+2
2878+3
2879+show status like "Qcache_queries_in_cache";
2880+Variable_name Value
2881+Qcache_queries_in_cache 22
2882+show status like "Qcache_inserts";
2883+Variable_name Value
2884+Qcache_inserts 22
2885+show status like "Qcache_hits";
2886+Variable_name Value
2887+Qcache_hits 27
2888+-----------------------------------------------------
2889+select *-- a comment \
2890+from t1
2891+-----------------------------------------------------
2892+show status like "Qcache_queries_in_cache";
2893+Variable_name Value
2894+Qcache_queries_in_cache 22
2895+show status like "Qcache_inserts";
2896+Variable_name Value
2897+Qcache_inserts 22
2898+show status like "Qcache_hits";
2899+Variable_name Value
2900+Qcache_hits 27
2901+select *-- a comment \
2902+from t1;
2903+a
2904+1
2905+2
2906+3
2907+select *-- a comment \
2908+from t1;
2909+a
2910+1
2911+2
2912+3
2913+show status like "Qcache_queries_in_cache";
2914+Variable_name Value
2915+Qcache_queries_in_cache 23
2916+show status like "Qcache_inserts";
2917+Variable_name Value
2918+Qcache_inserts 23
2919+show status like "Qcache_hits";
2920+Variable_name Value
2921+Qcache_hits 28
2922+-----------------------------------------------------
2923+select "\\"" /* not a comment */" from t1
2924+-----------------------------------------------------
2925+show status like "Qcache_queries_in_cache";
2926+Variable_name Value
2927+Qcache_queries_in_cache 23
2928+show status like "Qcache_inserts";
2929+Variable_name Value
2930+Qcache_inserts 23
2931+show status like "Qcache_hits";
2932+Variable_name Value
2933+Qcache_hits 28
2934+select "\\"" /* not a comment */" from t1;
2935+\" /* not a comment */
2936+\" /* not a comment */
2937+\" /* not a comment */
2938+\" /* not a comment */
2939+select "\\"" /* not a comment */" from t1;
2940+\" /* not a comment */
2941+\" /* not a comment */
2942+\" /* not a comment */
2943+\" /* not a comment */
2944+show status like "Qcache_queries_in_cache";
2945+Variable_name Value
2946+Qcache_queries_in_cache 24
2947+show status like "Qcache_inserts";
2948+Variable_name Value
2949+Qcache_inserts 24
2950+show status like "Qcache_hits";
2951+Variable_name Value
2952+Qcache_hits 29
2953+-----------------------------------------------------
2954+select "\\"" /*! not a comment */" from t1
2955+-----------------------------------------------------
2956+show status like "Qcache_queries_in_cache";
2957+Variable_name Value
2958+Qcache_queries_in_cache 24
2959+show status like "Qcache_inserts";
2960+Variable_name Value
2961+Qcache_inserts 24
2962+show status like "Qcache_hits";
2963+Variable_name Value
2964+Qcache_hits 29
2965+select "\\"" /*! not a comment */" from t1;
2966+\" /*! not a comment */
2967+\" /*! not a comment */
2968+\" /*! not a comment */
2969+\" /*! not a comment */
2970+select "\\"" /*! not a comment */" from t1;
2971+\" /*! not a comment */
2972+\" /*! not a comment */
2973+\" /*! not a comment */
2974+\" /*! not a comment */
2975+show status like "Qcache_queries_in_cache";
2976+Variable_name Value
2977+Qcache_queries_in_cache 25
2978+show status like "Qcache_inserts";
2979+Variable_name Value
2980+Qcache_inserts 25
2981+show status like "Qcache_hits";
2982+Variable_name Value
2983+Qcache_hits 30
2984+-----------------------------------------------------
2985+select ' \' ' from t12372+select ' \' ' from t1
2986+-----------------------------------------------------2373+-----------------------------------------------------
2987+show status like "Qcache_queries_in_cache";2374+show status like "Qcache_queries_in_cache";
2988+Variable_name Value2375+Variable_name Value
2989+Qcache_queries_in_cache 252376+Qcache_queries_in_cache 20
2990+show status like "Qcache_inserts";2377+show status like "Qcache_inserts";
2991+Variable_name Value2378+Variable_name Value
2992+Qcache_inserts 252379+Qcache_inserts 20
2993+show status like "Qcache_hits";2380+show status like "Qcache_hits";
2994+Variable_name Value2381+Variable_name Value
2995+Qcache_hits 302382+Qcache_hits 25
2996+select ' \' ' from t1;2383+select ' \' ' from t1;
2997+' 2384+'
2998+ ' 2385+ '
2999+ ' 2386+ '
3000+ ' 2387+ '
3001+select ' \' ' from t1;2388+select ' \' ' from t1;
3002+' 2389+'
3003+ ' 2390+ '
3004+ ' 2391+ '
3005+ ' 2392+ '
3006+show status like "Qcache_queries_in_cache";2393+show status like "Qcache_queries_in_cache";
3007+Variable_name Value2394+Variable_name Value
3008+Qcache_queries_in_cache 262395+Qcache_queries_in_cache 21
3009+show status like "Qcache_inserts";2396+show status like "Qcache_inserts";
3010+Variable_name Value2397+Variable_name Value
3011+Qcache_inserts 262398+Qcache_inserts 21
3012+show status like "Qcache_hits";2399+show status like "Qcache_hits";
3013+Variable_name Value2400+Variable_name Value
3014+Qcache_hits 312401+Qcache_hits 26
3015+-----------------------------------------------------
3016+select ' \' /* comment inside quotes with internal backslash quote */' from t1
3017+-----------------------------------------------------
3018+show status like "Qcache_queries_in_cache";
3019+Variable_name Value
3020+Qcache_queries_in_cache 26
3021+show status like "Qcache_inserts";
3022+Variable_name Value
3023+Qcache_inserts 26
3024+show status like "Qcache_hits";
3025+Variable_name Value
3026+Qcache_hits 31
3027+select ' \' /* comment inside quotes with internal backslash quote */' from t1;
3028+' /* comment inside quotes with internal backslash quote */
3029+ ' /* comment inside quotes with internal backslash quote */
3030+ ' /* comment inside quotes with internal backslash quote */
3031+ ' /* comment inside quotes with internal backslash quote */
3032+select ' \' /* comment inside quotes with internal backslash quote */' from t1;
3033+' /* comment inside quotes with internal backslash quote */
3034+ ' /* comment inside quotes with internal backslash quote */
3035+ ' /* comment inside quotes with internal backslash quote */
3036+ ' /* comment inside quotes with internal backslash quote */
3037+show status like "Qcache_queries_in_cache";
3038+Variable_name Value
3039+Qcache_queries_in_cache 27
3040+show status like "Qcache_inserts";
3041+Variable_name Value
3042+Qcache_inserts 27
3043+show status like "Qcache_hits";
3044+Variable_name Value
3045+Qcache_hits 32
3046+DROP TABLE t1;2402+DROP TABLE t1;
3047+SET GLOBAL query_cache_size=default;2403+SET GLOBAL query_cache_size=default;
3048+set global query_cache_strip_comments=OFF;2404+set global query_cache_strip_comments=OFF;
@@ -3735,7 +3091,7 @@
3735+SET GLOBAL query_cache_size=0;3091+SET GLOBAL query_cache_size=0;
3736--- a/mysql-test/r/mysqld--help-notwin.result3092--- a/mysql-test/r/mysqld--help-notwin.result
3737+++ b/mysql-test/r/mysqld--help-notwin.result3093+++ b/mysql-test/r/mysqld--help-notwin.result
3738@@ -493,6 +493,10 @@3094@@ -500,6 +500,10 @@
3739 The minimum size for blocks allocated by the query cache3095 The minimum size for blocks allocated by the query cache
3740 --query-cache-size=# 3096 --query-cache-size=#
3741 The memory allocated to store results from old queries3097 The memory allocated to store results from old queries
@@ -3746,7 +3102,7 @@
3746 --query-cache-type=name 3102 --query-cache-type=name
3747 OFF = Don't cache or retrieve results. ON = Cache all3103 OFF = Don't cache or retrieve results. ON = Cache all
3748 results except SELECT SQL_NO_CACHE ... queries. DEMAND =3104 results except SELECT SQL_NO_CACHE ... queries. DEMAND =
3749@@ -931,6 +935,7 @@3105@@ -942,6 +946,7 @@
3750 query-cache-limit 10485763106 query-cache-limit 1048576
3751 query-cache-min-res-unit 40963107 query-cache-min-res-unit 4096
3752 query-cache-size 03108 query-cache-size 0
@@ -3778,7 +3134,7 @@
3778+try_lock_mutex_query3134+try_lock_mutex_query
3779+SET GLOBAL query_cache_size=0;3135+SET GLOBAL query_cache_size=0;
3780--- /dev/null3136--- /dev/null
3781+++ b/mysql-test/r/percona_query_cache_with_comments_crash_2.result3137+++ b/mysql-test/r/percona_bug856404.result
3782@@ -0,0 +1,8 @@3138@@ -0,0 +1,8 @@
3783+DROP TABLE IF EXISTS table17_int;3139+DROP TABLE IF EXISTS table17_int;
3784+DROP TABLE IF EXISTS table30_int;3140+DROP TABLE IF EXISTS table30_int;
@@ -3789,120 +3145,24 @@
3789+DROP TABLE table17_int;3145+DROP TABLE table17_int;
3790+DROP TABLE table30_int;3146+DROP TABLE table30_int;
3791--- /dev/null3147--- /dev/null
3792+++ b/mysql-test/t/percona_query_cache_with_comments_crash_2-master.opt3148+++ b/mysql-test/t/percona_bug856404-master.opt
3793@@ -0,0 +1 @@3149@@ -0,0 +1 @@
3794+--query-cache-size=10M --query-cache-strip-comments3150+--query-cache-size=10M --query-cache-strip-comments
3795--- /dev/null3151--- /dev/null
3796+++ b/mysql-test/t/percona_query_cache_with_comments_crash_2.test3152+++ b/mysql-test/t/percona_bug856404.test
3797@@ -0,0 +1,9 @@3153@@ -0,0 +1,15 @@
3154+########################################################################
3155+# Bug #856404: Crash when query_cache_strip_comments enabled
3156+########################################################################
3157+
3798+--disable_warnings3158+--disable_warnings
3799+DROP TABLE IF EXISTS table17_int;3159+DROP TABLE IF EXISTS table17_int;
3800+DROP TABLE IF EXISTS table30_int;3160+DROP TABLE IF EXISTS table30_int;
3801+--enable_warnings3161+--enable_warnings
3162+
3802+CREATE TABLE `table17_int` (pk integer auto_increment primary key, `col_char_10_not_null_key` char(10), `col_enum_not_null_key` int);3163+CREATE TABLE `table17_int` (pk integer auto_increment primary key, `col_char_10_not_null_key` char(10), `col_enum_not_null_key` int);
3803+CREATE TABLE `table30_int` (pk integer auto_increment primary key, `col_enum_not_null_key` int);3164+CREATE TABLE `table30_int` (pk integer auto_increment primary key, `col_enum_not_null_key` int);
3804+SELECT X . `pk` FROM `table17_int` AS X LEFT JOIN `table30_int` AS Y USING ( `col_enum_not_null_key` ) WHERE X . `col_char_10_not_null_key` != ' you need to translate Views labels into other languages, consider installing the <a href=\" !path\">Internationalization</a> package\'s Views translation module.' LIMIT 7 /*Generated by THREAD_ID 1*/;3165+SELECT X . `pk` FROM `table17_int` AS X LEFT JOIN `table30_int` AS Y USING ( `col_enum_not_null_key` ) WHERE X . `col_char_10_not_null_key` != ' you need to translate Views labels into other languages, consider installing the <a href=\" !path\">Internationalization</a> package\'s Views translation module.' LIMIT 7 /*Generated by THREAD_ID 1*/;
3166+
3805+DROP TABLE table17_int;3167+DROP TABLE table17_int;
3806+DROP TABLE table30_int;3168+DROP TABLE table30_int;
3807--- a/sql/sql_class.cc
3808+++ b/sql/sql_class.cc
3809@@ -807,6 +807,99 @@
3810 sql_errno == ER_TRG_NO_DEFINER);
3811 }
3812
3813+#ifdef HAVE_QUERY_CACHE
3814+
3815+
3816+Query_Without_Comments::Query_Without_Comments() :
3817+ buffer(0),
3818+ q_length(0),
3819+ b_length(0)
3820+{
3821+}
3822+
3823+
3824+Query_Without_Comments::~Query_Without_Comments()
3825+{
3826+ if(buffer)
3827+ {
3828+ my_free(buffer);
3829+ }
3830+}
3831+
3832+
3833+bool Query_Without_Comments::allocate(size_t query_length, size_t db_length)
3834+{
3835+ DBUG_ENTER("Query_Without_Comments::allocate");
3836+ DBUG_PRINT("info", ("old buffer: %p "
3837+ "old query: '%-.4096s' "
3838+ "old buffer length: %u "
3839+ "old query length: %u",
3840+ buffer,
3841+ buffer,
3842+ (uint) b_length,
3843+ (uint) q_length));
3844+ /* save maximum query length for check in the set_length */
3845+ q_length= query_length;
3846+ /* according to sql_parse.cc memory allocation */
3847+ size_t new_b_length= (query_length + 1) + sizeof(size_t) + db_length +
3848+ QUERY_CACHE_FLAGS_SIZE;
3849+ if (b_length < new_b_length)
3850+ {
3851+ b_length= new_b_length;
3852+ if (buffer)
3853+ {
3854+ buffer= (char*) my_realloc(buffer, b_length, MYF(0));
3855+ }
3856+ else
3857+ {
3858+ buffer= (char *) my_malloc(b_length, MYF(0));
3859+ }
3860+ }
3861+ buffer[0]= 0;
3862+ DBUG_PRINT("info", ("buffer: %p "
3863+ "buffer length: %u "
3864+ "query maximum length: %u",
3865+ buffer,
3866+ (uint) b_length,
3867+ (uint) q_length));
3868+ DBUG_RETURN(buffer);
3869+}
3870+
3871+
3872+void Query_Without_Comments::set_length(size_t query_length)
3873+{
3874+ DBUG_ENTER("Query_Without_Comments::set_length");
3875+ DBUG_ASSERT(query_length <= q_length);
3876+ buffer[query_length]= 0;
3877+ DBUG_PRINT("info", ("buffer: %p "
3878+ "query: '%-.4096s' "
3879+ "buffer length: %u "
3880+ "query maximum length: %u "
3881+ "query length: %u",
3882+ buffer,
3883+ buffer,
3884+ (uint) b_length,
3885+ (uint) q_length,
3886+ (uint) query_length));
3887+ q_length= query_length;
3888+ DBUG_VOID_RETURN;
3889+}
3890+
3891+
3892+char* Query_Without_Comments::query()
3893+{
3894+ return buffer;
3895+}
3896+
3897+
3898+size_t Query_Without_Comments::length()
3899+{
3900+ return q_length;
3901+}
3902+
3903+
3904+#endif // HAVE_QUERY_CACHE
3905+
3906
3907 THD::THD()
3908 :Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION,

Subscribers

People subscribed via source and target branches