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
1=== modified file 'patches/query_cache_enhance.patch'
2--- patches/query_cache_enhance.patch 2012-02-02 07:11:59 +0000
3+++ patches/query_cache_enhance.patch 2012-03-25 11:37:19 +0000
4@@ -1,4 +1,4 @@
5-# name : query_cache_enhance.patch
6+# name : query_cache_with_comments.patch
7 # introduced : 11 or before
8 # maintainer : Oleg
9 #
10@@ -25,7 +25,7 @@
11 +2010-11 - Ported to 5.5
12 --- a/sql/mysqld.cc
13 +++ b/sql/mysqld.cc
14-@@ -909,6 +909,7 @@
15+@@ -915,6 +915,7 @@
16 #endif
17 #ifdef HAVE_QUERY_CACHE
18 ulong query_cache_min_res_unit= QUERY_CACHE_MIN_RESULT_DATA_SIZE;
19@@ -43,510 +43,252 @@
20 extern ulonglong log_output_options;
21 extern ulong log_backup_output_options;
22 extern my_bool opt_log_queries_not_using_indexes;
23+--- /dev/null
24++++ b/sql/query_strip_comments.h
25+@@ -0,0 +1,37 @@
26++#ifndef _SQL_QUERY_STRIPC_COMMENTS_H_
27++#define _SQL_QUERY_STRIPC_COMMENTS_H_
28++#ifdef HAVE_QUERY_CACHE
29++
30++// implemented in sql_cache.cc
31++class QueryStripComments
32++{
33++private:
34++ QueryStripComments(const QueryStripComments&);
35++ QueryStripComments& operator=(const QueryStripComments&);
36++public:
37++ QueryStripComments();
38++ ~QueryStripComments();
39++ void set(const char* a_query, uint a_query_length, uint a_additional_length);
40++
41++ char* query() { return buffer; }
42++ uint query_length() { return length; }
43++private:
44++ void cleanup();
45++private:
46++ char* buffer;
47++ uint length /*query length, not buffer length*/;
48++ uint buffer_length;
49++};
50++class QueryStripComments_Backup
51++{
52++public:
53++ QueryStripComments_Backup(THD* a_thd,QueryStripComments* qsc);
54++ ~QueryStripComments_Backup();
55++private:
56++ THD* thd;
57++ char* query;
58++ uint length;
59++};
60++
61++#endif // HAVE_QUERY_CACHE
62++#endif // _SQL_QUERY_STRIPC_COMMENTS_H_
63 --- a/sql/sql_cache.cc
64 +++ b/sql/sql_cache.cc
65-@@ -344,6 +344,496 @@
66+@@ -344,6 +344,198 @@
67 #include "probes_mysql.h"
68 #include "transaction.h"
69
70-+
71-+namespace query_comments_parser
72-+{
73-+
74-+
75-+enum Kind
76-+{
77-+ /* 'Empty' symbol - epsilon in classic parsers */
78-+ Empty,
79-+ /*
80-+ Special symbols:
81-+ * exclamation comment: slash-star-exclamation comment-body star-slash
82-+ * single-line and multi-line comments
83-+ */
84-+ Special,
85-+ /* Whitespaces: ' ' \t \r \n */
86-+ WhiteSpace,
87-+ /*
88-+ 1) C-style comment (slash-star comment-body star-slash)
89-+ 2) signle-line comment:
90-+ * sharp comment (sharp comment-body new-line)
91-+ * minus-minus comment (minus-minus comment-body new-line)
92-+ */
93-+ Comment,
94-+ /* Not a special symbols (this symbols can't be before SELECT ). */
95-+ Another,
96-+ /* Error: not-closed quotes, not-closed C-style comment, end-of-query */
97-+ Error
98-+};
99-+
100-+
101-+/**
102-+ Analyze kind of prefix of input string.
103-+
104-+ @param where pointer to pointer to begin of string. After analyzing input
105-+ string function skip analyzed prefix and return pointer to the next part
106-+ of string in the @param where.
107-+
108-+ @return kind of analyzed prefix.
109++#include "query_strip_comments.h"
110++
111++/*
112++ Number of bytes to be allocated in a query cache buffer in addition to the
113++ query string length.
114++
115++ The query buffer layout is:
116++
117++ buffer :==
118++ <statement> The input statement(s)
119++ '\0' Terminating null char
120++ <db_length> Length of following current database name (size_t)
121++ <db_name> Name of current database
122++ <flags> Flags struct
123 +*/
124-+static Kind analyze(const char **where, const char *const end)
125-+{
126-+ DBUG_ASSERT(where != NULL);
127-+ DBUG_ASSERT(*where != NULL);
128-+ const char*&to= *where;
129-+ /* if empty */
130-+ if (*to == '\0')
131-+ {
132-+ return Empty;
133-+ }
134-+
135-+ /* current symbol */
136-+ char current= *to;
137-+
138-+ switch (current)
139-+ {
140-+ case '\'':
141-+ case '"':
142-+ /* skip quote */
143-+ to++;
144-+ /* search pair */
145-+ while (true)
146++#define QUERY_BUFFER_ADDITIONAL_LENGTH(db_length) \
147++ (1 + sizeof(size_t) + db_length + QUERY_CACHE_FLAGS_SIZE)
148++
149++QueryStripComments::QueryStripComments()
150++{
151++ buffer = 0;
152++ length = 0;
153++ buffer_length = 0;
154++}
155++QueryStripComments::~QueryStripComments()
156++{
157++ cleanup();
158++}
159++
160++inline bool query_strip_comments_is_white_space(char c)
161++{
162++ return ((' ' == c) || ('\t' == c) || ('\r' == c) || ('\n' ==c ));
163++}
164++void QueryStripComments::set(const char* query, uint query_length, uint additional_length)
165++{
166++ uint new_buffer_length = query_length + additional_length;
167++ if(new_buffer_length > buffer_length)
168++ {
169++ cleanup();
170++ buffer = (char*)my_malloc(new_buffer_length,MYF(0));
171++ }
172++ uint query_position = 0;
173++ uint position = 0;
174++ // Skip whitespaces from begin
175++ while((query_position < query_length) && query_strip_comments_is_white_space(query[query_position]))
176++ {
177++ ++query_position;
178++ }
179++ long int last_space = -1;
180++ while(query_position < query_length)
181++ {
182++ char current = query[query_position];
183++ bool insert_space = false; // insert space to buffer, (IMPORTANT) don't update query_position
184++ switch(current)
185 + {
186-+ /* check for pair of quote */
187-+ if (*to == current)
188-+ {
189-+ /* skip second quote */
190-+ to++;
191-+ /* check for same symbol after second quote */
192-+ if (to < end && *to == current)
193-+ {
194-+ /* same symbol, skip it */
195-+ to++;
196-+ /* check for end-of-line */
197-+ if (to == end)
198-+ {
199-+ /* not found - not closed quote */
200-+ return Error;
201-+ }
202-+ else
203-+ {
204-+ /* continue search of pair */
205++ case '\'':
206++ case '"':
207++ {
208++ buffer[position++] = query[query_position++]; // copy current symbol
209++ while(query_position < query_length)
210++ {
211++ if(current == query[query_position]) // found pair quote
212++ {
213++ break;
214++ }
215++ buffer[position++] = query[query_position++]; // copy current symbol
216++ }
217++ break;
218++ }
219++ case '/':
220++ {
221++ if(((query_position + 2) < query_length) && ('*' == query[query_position+1]) && ('!' != query[query_position+2]))
222++ {
223++ query_position += 2; // skip "/*"
224++ do
225++ {
226++ if('*' == query[query_position] && '/' == query[query_position+1]) // check for "*/"
227++ {
228++ query_position += 2; // skip "*/"
229++ insert_space = true;
230++ break;
231++ }
232++ else
233++ {
234++ ++query_position;
235++ }
236++ }
237++ while(query_position < query_length);
238++ if(!insert_space)
239++ {
240 + continue;
241 + }
242 + }
243-+ else
244-+ {
245-+ return Another;
246-+ }
247-+ }
248-+ /* check for escaped symbols */
249-+ if (*to == '\\')
250-+ {
251-+ /* backslash, skip it */
252-+ to++;
253-+ }
254-+ /* check for end-of-line */
255-+ if (to == end)
256-+ {
257-+ /* not found - not closed quote */
258-+ return Error;
259-+ }
260-+ /* skip current symbol */
261-+ to++;
262-+ }
263-+ case '-':
264-+ /* Skip minus */
265-+ to++;
266-+ /* Check for second minus */
267-+ if (*to != '-')
268-+ {
269-+ /* Just minus */
270-+ return Another;
271-+ }
272-+ else
273-+ {
274-+ /*
275-+ Prefix is minus-minus, next case-branch is processing
276-+ single line comments.
277-+ */
278-+ }
279-+ case '#':
280-+ /*
281-+ This is single-line comment, it started by "#" or "--".
282-+ Skip first symbol.
283-+ */
284-+ to++;
285-+ /* search new-line */
286-+ to= strchr(to, '\n');
287-+ if (NULL == to)
288-+ {
289-+ /* not found, end of the comment is the end of the query */
290-+ to= end;
291-+ }
292-+ else
293-+ {
294-+ /* skip end-of-line */
295-+ to++;
296-+ }
297-+ return Comment;
298-+ case '/':
299-+ /* skip slash */
300-+ to++;
301-+ /* check for star */
302-+ if (*to == '*')
303-+ {
304-+ /* skip star */
305-+ to++;
306-+ /* check for exclamation */
307-+ bool exclamation= (*to == '!');
308-+ /* search star-slash */
309-+ to= strstr(to, "*/");
310-+ if (NULL == to)
311-+ {
312-+ /* not found - not closed comment */
313-+ return Error;
314-+ }
315-+ else
316-+ {
317-+ /* found */
318-+ DBUG_ASSERT(to + 1 < end);
319-+ DBUG_ASSERT(0 == strncmp(to, "*/", 2));
320-+ /* skip star-slash */
321-+ to++;
322-+ to++;
323-+ return (exclamation ? Special : Comment);
324-+ }
325-+ }
326-+ else
327-+ {
328-+ /* just slash */
329-+ return Another;
330-+ }
331-+ case ' ':
332-+ case '\t':
333-+ case '\r':
334-+ case '\n':
335-+ {
336-+ /* skip space */
337-+ to++;
338-+ return WhiteSpace;
339-+ }
340-+ case '\\':
341-+ {
342-+ /* skip backslash */
343-+ to++;
344-+ if (to == end)
345-+ {
346-+ /*
347-+ query complete by backslash
348-+ probable error?
349-+ */
350-+ return Another;
351-+ }
352-+ else
353-+ {
354-+ /* skip after backslash symbol */
355-+ to++;
356-+ return Another;
357-+ }
358-+ }
359-+ case '(':
360-+ case ')':
361-+ {
362-+ /* skip parenthese */
363-+ to++;
364-+ return Special;
365-+ }
366-+ default:
367-+ {
368-+ /* skip symbol */
369-+ to++;
370-+ return Another;
371-+ }
372-+ };
373-+}
374-+
375-+
376-+static bool remove_comments_from_query(const char *const query,
377-+ const size_t query_length,
378-+ char *const result,
379-+ size_t *result_length)
380-+{
381-+ /* pointer to begin of parsed block */
382-+ const char *from= query;
383-+ const char *to= query;
384-+ /* pointer to end of the query */
385-+ const char *const end= query + query_length;
386-+ /* pointer to last space */
387-+ const char *space= NULL;
388-+ /* current position in result buffer */
389-+ char *current= result;
390-+ while (true)
391-+ {
392-+ from= to;
393-+ switch (analyze(&to, end))
394-+ {
395-+ case Empty:
396-+ {
397-+ /*
398-+ parse completed
399-+ check for whitespace in the end
400-+ */
401-+ if (current == space)
402-+ {
403-+ /* drop whitespace in the end of query */
404-+ --current;
405-+ }
406-+ /* result is null-terminated string */
407-+ *current= 0;
408-+ /* set result length */
409-+ *result_length= current - result;
410-+ /* all right */
411-+ return true;
412-+ }
413-+ case Comment:
414-+ /* should just insert space instead of comment */
415-+ case WhiteSpace:
416-+ if (space == current || from == query)
417-+ {
418-+ /* previous symbol was space */
419-+ }
420-+ else
421-+ {
422-+ /* insert space to result buffer */
423-+ *current= ' ';
424-+ /* switch after inserted space */
425-+ current++;
426-+ }
427-+ /* remember last-after-space position */
428-+ space= current;
429-+ /* parse again */
430-+ continue;
431-+ case Special:
432-+ case Another:
433-+ {
434-+ /* calculate parsed block size */
435-+ size_t block_size= to - from;
436-+ /* copy parsed block to result */
437-+ memcpy(current, from, block_size);
438-+ /* switch result after copied block */
439-+ current+= block_size;
440-+ /* switch after parsed block */
441-+ from= to;
442-+ /* parse again */
443-+ continue;
444-+ }
445-+ case Error:
446-+ default:
447-+ {
448-+ /* bad source query */
449-+ return false;
450-+ }
451-+ }
452-+ }
453-+}
454-+
455-+
456-+static size_t skip_not_another(const char *const query, size_t query_length)
457-+{
458-+ const char *from= query;
459-+ const char *to= query;
460-+ const char *const end= query + query_length;
461-+ while (true)
462-+ {
463-+ switch (analyze(&to, end))
464-+ {
465-+ case Error:
466-+ return 0;
467-+ case Empty:
468-+ case Another:
469-+ return (from - query);
470-+ default:
471-+ from= to;
472-+ continue;
473-+ };
474-+ }
475-+}
476-+
477-+
478-+static size_t skip_default(const char *const query, size_t /* query_length */)
479-+{
480-+ size_t query_position= 0;
481-+ /*
482-+ Skip '(' characters in queries like following:
483-+ (select a from t1) union (select a from t1);
484-+ */
485-+ while (query[query_position]=='(')
486-+ query_position++;
487-+ return query_position;
488-+}
489-+
490-+
491-+} /* namespace query_comments_parser */
492-+
493-+class Query_Switcher
494-+{
495-+private:
496-+ Query_Switcher(const Query_Switcher&);
497-+ Query_Switcher& operator=(const Query_Switcher&);
498-+
499-+
500-+public:
501-+ Query_Switcher(THD *thd) :
502-+ target_query(&(thd_query_string(thd)->str)),
503-+ target_length(&(thd_query_string(thd)->length)),
504-+ backup_query(thd->query()),
505-+ backup_length(thd->query_length())
506-+ {
507-+ }
508-+
509-+ Query_Switcher(char **query,
510-+ size_t *length) :
511-+ target_query(query),
512-+ target_length(length),
513-+ backup_query(*query),
514-+ backup_length(*length)
515-+ {
516-+ }
517-+public:
518-+ void replace(Query_Without_Comments *query_without_comments)
519-+ {
520-+ *target_query= query_without_comments->query();
521-+ *target_length= query_without_comments->length();
522-+ }
523-+ void restore()
524-+ {
525-+ *target_query= backup_query;
526-+ *target_length= backup_length;
527-+ }
528-+private:
529-+ char* *target_query;
530-+ size_t *target_length;
531-+public:
532-+ char *const backup_query;
533-+ size_t const backup_length;
534-+};
535-+
536-+class Comments_Processor
537-+{
538-+private:
539-+ Comments_Processor(const Comments_Processor&);
540-+ Comments_Processor& operator=(const Comments_Processor&);
541-+
542-+
543-+public:
544-+ Comments_Processor(THD *thd) :
545-+ query_switcher (thd),
546-+ db_length (thd->db_length),
547-+ query_without_comments(&(thd->query_without_comments)),
548-+ enabled (opt_query_cache_strip_comments),
549-+ restore (false)
550-+ {
551-+ }
552-+
553-+
554-+ Comments_Processor(Query_Without_Comments *current_query_without_comments,
555-+ char **query,
556-+ size_t *length,
557-+ const size_t current_db_length) :
558-+ query_switcher (query, length),
559-+ db_length (current_db_length),
560-+ query_without_comments(current_query_without_comments),
561-+ enabled (opt_query_cache_strip_comments),
562-+ restore (false)
563-+ {
564-+ }
565-+
566-+
567-+ ~Comments_Processor()
568-+ {
569-+ restore_comments();
570-+ }
571-+
572-+
573-+ size_t prefix_length()
574-+ {
575-+ using query_comments_parser::skip_not_another;
576-+ using query_comments_parser::skip_default;
577-+ if (enabled)
578-+ {
579-+ return skip_not_another(query_switcher.backup_query,
580-+ query_switcher.backup_length);
581-+ }
582-+ else
583-+ {
584-+ return skip_default(query_switcher.backup_query,
585-+ query_switcher.backup_length);
586-+ }
587-+ }
588-+
589-+
590-+ bool remove_comments()
591-+ {
592-+ if (!enabled || restore)
593-+ {
594-+ return true;
595-+ }
596-+ /* Allocate memory for query rewrite */
597-+ if (!query_without_comments->allocate(query_switcher.backup_length,
598-+ db_length))
599-+ {
600-+ return false;
601-+ }
602-+ /* Remove comment from query */
603-+ size_t result_length;
604-+ using query_comments_parser::remove_comments_from_query;
605-+ if (!(restore= remove_comments_from_query(query_switcher.backup_query,
606-+ query_switcher.backup_length,
607-+ query_without_comments->query(),
608-+ &result_length)))
609-+ {
610-+ return false;
611-+ }
612-+ query_without_comments->set_length(result_length);
613-+ size_t db_length_from_query=
614-+ *((size_t*)(query_switcher.backup_query +
615-+ query_switcher.backup_length + 1));
616-+ *((size_t*)(query_without_comments->query() +
617-+ result_length + 1))= db_length_from_query;
618-+ /* Replace original query by striped */
619-+ query_switcher.replace(query_without_comments);
620-+ return restore;
621-+ }
622-+
623-+
624-+ void restore_comments()
625-+ {
626-+ if (enabled && restore)
627-+ {
628-+ /* Replace striped query by original */
629-+ query_switcher.restore();
630-+
631-+ /* Clean query_without_comments */
632-+ query_without_comments->set_length(0);
633-+
634-+ /* Mark as restored */
635-+ restore= false;
636-+ }
637-+ }
638-+private:
639-+ Query_Switcher query_switcher;
640-+private:
641-+ const size_t db_length;
642-+private:
643-+ Query_Without_Comments *query_without_comments;
644-+ bool enabled;
645-+ bool restore;
646-+};
647++ break;
648++ }
649++ case '-':
650++ {
651++ if(query[query_position+1] == '-')
652++ {
653++ ++query_position; // skip "-", and go to search of "\n"
654++ }
655++ else
656++ {
657++ break;
658++ }
659++ }
660++ case '#':
661++ {
662++ do
663++ {
664++ ++query_position; // skip current symbol (# or -)
665++ if('\n' == query[query_position]) // check for '\n'
666++ {
667++ ++query_position; // skip '\n'
668++ insert_space = true;
669++ break;
670++ }
671++ }
672++ while(query_position < query_length);
673++ if(insert_space)
674++ {
675++ break;
676++ }
677++ else
678++ {
679++ continue;
680++ }
681++ }
682++ default:
683++ if(query_strip_comments_is_white_space(current))
684++ {
685++ insert_space = true;
686++ ++query_position;
687++ }
688++ break; // make gcc happy
689++ }
690++ if(insert_space)
691++ {
692++ if((uint) (last_space + 1) != position)
693++ {
694++ last_space = position;
695++ buffer[position++] = ' ';
696++ }
697++ }
698++ else if (query_position < query_length)
699++ {
700++ buffer[position++] = query[query_position++];
701++ }
702++ }
703++ while((0 < position) && query_strip_comments_is_white_space(buffer[position - 1]))
704++ {
705++ --position;
706++ }
707++ buffer[position] = 0;
708++ length = position;
709++}
710++void QueryStripComments::cleanup()
711++{
712++ if(buffer)
713++ {
714++ my_free(buffer);
715++ }
716++ buffer = 0;
717++ length = 0;
718++ buffer_length = 0;
719++}
720++QueryStripComments_Backup::QueryStripComments_Backup(THD* a_thd,QueryStripComments* qsc)
721++{
722++ if(opt_query_cache_strip_comments)
723++ {
724++ thd = a_thd;
725++ query = thd->query();
726++ length = thd->query_length();
727++ qsc->set(query, length, QUERY_BUFFER_ADDITIONAL_LENGTH(thd->db_length));
728++ *(size_t *) (qsc->query() + qsc->query_length() + 1)= thd->db_length;
729++ thd->set_query(qsc->query(),qsc->query_length());
730++ }
731++ else
732++ {
733++ thd = 0;
734++ query = 0;
735++ length = 0;
736++ }
737++}
738++QueryStripComments_Backup::~QueryStripComments_Backup()
739++{
740++ if(thd)
741++ {
742++ thd->set_query(query,length);
743++ }
744++}
745 +
746 #ifdef EMBEDDED_LIBRARY
747 #include "emb_qcache.h"
748 #endif
749-@@ -454,7 +944,12 @@
750+@@ -454,7 +646,12 @@
751 Query_cache_wait_state wait_state(thd, __func__, __FILE__, __LINE__);
752 DBUG_ENTER("Query_cache::try_lock");
753
754-+ const char *old_proc_info= thd->proc_info;
755++ const char* old_proc_info= thd->proc_info;
756 + thd_proc_info(thd,"Waiting on query cache mutex");
757 + DEBUG_SYNC(thd, "before_query_cache_mutex");
758 mysql_mutex_lock(&structure_guard_mutex);
759@@ -555,171 +297,191 @@
760 while (1)
761 {
762 if (m_cache_lock_status == Query_cache::UNLOCKED)
763-@@ -1274,6 +1769,8 @@
764+@@ -1274,6 +1471,8 @@
765 unlock();
766 DBUG_VOID_RETURN;
767 }
768-+ Comments_Processor comments_processor(thd);
769-+ comments_processor.remove_comments();
770++ QueryStripComments *query_strip_comments = &(thd->query_strip_comments);
771++ QueryStripComments_Backup backup(thd,query_strip_comments);
772
773 /* Key is query + database + flag */
774 if (thd->db_length)
775-@@ -1440,7 +1937,7 @@
776- */
777-
778- int
779--Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
780-+Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length_uint)
781- {
782- ulonglong engine_data;
783- Query_cache_query *query;
784-@@ -1452,6 +1949,11 @@
785+@@ -1451,6 +1650,9 @@
786+ Query_cache_block_table *block_table, *block_table_end;
787 ulong tot_length;
788 Query_cache_query_flags flags;
789++ QueryStripComments *query_strip_comments = &(thd->query_strip_comments);
790++ char *sql_backup = sql;
791++ uint query_length_backup = query_length;
792 DBUG_ENTER("Query_cache::send_result_to_client");
793-+ size_t query_length= query_length_uint;
794-+ Comments_Processor comments_processor(&(thd->query_without_comments),
795-+ &sql,
796-+ &query_length,
797-+ thd->db_length);
798
799 /*
800- Testing 'query_cache_size' without a lock here is safe: the thing
801-@@ -1471,13 +1973,7 @@
802- }
803+@@ -1472,21 +1674,103 @@
804
805 {
806-- uint i= 0;
807+ uint i= 0;
808 - /*
809 - Skip '(' characters in queries like following:
810 - (select a from t1) union (select a from t1);
811 - */
812 - while (sql[i]=='(')
813 - i++;
814-+ size_t i= comments_processor.prefix_length();
815-
816- /*
817- Test if the query is a SELECT
818-@@ -1487,10 +1983,11 @@
819- frequently appeared in real life, consequently we can
820- check all such queries, too.
821- */
822-- if ((my_toupper(system_charset_info, sql[i]) != 'S' ||
823-- my_toupper(system_charset_info, sql[i + 1]) != 'E' ||
824-- my_toupper(system_charset_info, sql[i + 2]) != 'L') &&
825-- sql[i] != '/')
826-+ if (!((i + 2 < query_length) &&
827-+ ((my_toupper(system_charset_info, sql[i]) == 'S' &&
828-+ my_toupper(system_charset_info, sql[i + 1]) == 'E' &&
829-+ my_toupper(system_charset_info, sql[i + 2]) == 'L') ||
830-+ sql[i] == '/')))
831- {
832- DBUG_PRINT("qcache", ("The statement is not a SELECT; Not cached"));
833- goto err;
834-@@ -1543,6 +2040,7 @@
835++ if(opt_query_cache_strip_comments)
836++ {
837++ /* Skip all comments and non-letter symbols */
838++ uint& query_position = i;
839++ char* query = sql;
840++ while(query_position < query_length)
841++ {
842++ bool check = false;
843++ char current = query[query_position];
844++ switch(current)
845++ {
846++ case '/':
847++ if(((query_position + 2) < query_length) && ('*' == query[query_position+1]) && ('!' != query[query_position+2]))
848++ {
849++ query_position += 2; // skip "/*"
850++ do
851++ {
852++ if('*' == query[query_position] && '/' == query[query_position+1]) // check for "*/" (without space)
853++ {
854++ query_position += 2; // skip "*/" (without space)
855++ break;
856++ }
857++ else
858++ {
859++ ++query_position;
860++ }
861++ }
862++ while(query_position < query_length);
863++ continue; // analyze current symbol
864++ }
865++ break;
866++ case '-':
867++ if(query[query_position+1] == '-')
868++ {
869++ ++query_position; // skip "-"
870++ }
871++ else
872++ {
873++ break;
874++ }
875++ case '#':
876++ do
877++ {
878++ ++query_position; // skip current symbol
879++ if('\n' == query[query_position]) // check for '\n'
880++ {
881++ ++query_position; // skip '\n'
882++ break;
883++ }
884++ }
885++ while(query_position < query_length);
886++ continue; // analyze current symbol
887++ case '\r':
888++ case '\n':
889++ case '\t':
890++ case ' ':
891++ case '(':
892++ case ')':
893++ break;
894++ default:
895++ check = true;
896++ break; // make gcc happy
897++ } // switch(current)
898++ if(check)
899++ {
900++ if(query_position + 2 < query_length)
901++ {
902++ // cacheable
903++ break;
904++ }
905++ else
906++ {
907++ DBUG_PRINT("qcache", ("The statement is not a SELECT; Not cached"));
908++ goto err;
909++ }
910++ } // if(check)
911++ ++query_position;
912++ } // while(query_position < query_length)
913++ }
914++ else // if(opt_query_cache_strip_comments)
915++ {
916++ /*
917++ Skip '(' characters in queries like following:
918++ (select a from t1) union (select a from t1);
919++ */
920++ while (sql[i]=='(')
921++ i++;
922+
923+- /*
924+- Test if the query is a SELECT
925+- (pre-space is removed in dispatch_command).
926++ } // if(opt_query_cache_strip_comments)
927++ /*
928++ Test if the query is a SELECT
929++ (pre-space is removed in dispatch_command).
930+
931+- First '/' looks like comment before command it is not
932+- frequently appeared in real life, consequently we can
933+- check all such queries, too.
934+- */
935++ First '/' looks like comment before command it is not
936++ frequently appeared in real life, consequently we can
937++ check all such queries, too.
938++ */
939+ if ((my_toupper(system_charset_info, sql[i]) != 'S' ||
940+ my_toupper(system_charset_info, sql[i + 1]) != 'E' ||
941+ my_toupper(system_charset_info, sql[i + 2]) != 'L') &&
942+@@ -1543,6 +1827,14 @@
943 goto err_unlock;
944
945 Query_cache_block *query_block;
946-+ comments_processor.remove_comments();
947++ if(opt_query_cache_strip_comments)
948++ {
949++ query_strip_comments->set(sql, query_length,
950++ QUERY_BUFFER_ADDITIONAL_LENGTH(thd->db_length));
951++ sql = query_strip_comments->query();
952++ query_length = query_strip_comments->query_length();
953++ *(size_t *) (sql + query_length + 1)= thd->db_length;
954++ }
955
956 tot_length= query_length + 1 + sizeof(size_t) +
957 thd->db_length + QUERY_CACHE_FLAGS_SIZE;
958-@@ -1611,6 +2109,7 @@
959+@@ -1611,6 +1903,8 @@
960 (uchar*) &flags, QUERY_CACHE_FLAGS_SIZE);
961 query_block = (Query_cache_block *) my_hash_search(&queries, (uchar*) sql,
962 tot_length);
963-+ comments_processor.restore_comments();
964++ sql = sql_backup;
965++ query_length = query_length_backup;
966 /* Quick abort on unlocked data */
967 if (query_block == 0 ||
968 query_block->query()->result() == 0 ||
969 --- a/sql/sql_class.h
970 +++ b/sql/sql_class.h
971-@@ -1485,6 +1485,74 @@
972-
973- extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
974-
975-+
976-+#ifdef HAVE_QUERY_CACHE
977-+
978-+
979-+/*
980-+ @class Query_Without_Comments
981-+ This class provides way for safety (re)allocation
982-+ a memory for a query without comments.
983-+*/
984-+class Query_Without_Comments
985-+{
986-+private:
987-+ /*
988-+ Denied copy and assigment for object of this class.
989-+ */
990-+ Query_Without_Comments(const Query_Without_Comments&);
991-+ Query_Without_Comments& operator=(const Query_Without_Comments&);
992-+
993-+
994-+public:
995-+ /*
996-+ Constructor is filling fields by zero (no allocation).
997-+ */
998-+ Query_Without_Comments();
999-+
1000-+
1001-+ /*
1002-+ Destructor clean allocated memory
1003-+ */
1004-+ ~Query_Without_Comments();
1005-+public:
1006-+
1007-+
1008-+/*
1009-+ (Re)allocate memory for query. Query length after that is 0.
1010-+ */
1011-+ bool allocate(size_t query_length, size_t db_length);
1012-+
1013-+
1014-+ /*
1015-+ Set result query length, when query
1016-+ without comments is copied to buffer.
1017-+ */
1018-+ void set_length(size_t query_length);
1019-+
1020-+
1021-+public:
1022-+ /*
1023-+ Result query.
1024-+ */
1025-+ char* query();
1026-+
1027-+
1028-+ /*
1029-+ Result query length
1030-+ */
1031-+ size_t length();
1032-+
1033-+
1034-+private:
1035-+ char* buffer;
1036-+ size_t q_length;
1037-+ size_t b_length;
1038-+};
1039-+
1040-+
1041-+#endif /* HAVE_QUERY_CACHE */
1042-+
1043- /**
1044- @class THD
1045- For each client connection we create a separate thread with THD serving as
1046-@@ -1542,6 +1610,7 @@
1047- struct st_mysql_stmt *current_stmt;
1048- #endif
1049- #ifdef HAVE_QUERY_CACHE
1050-+ Query_Without_Comments query_without_comments;
1051- Query_cache_tls query_cache_tls;
1052- #endif
1053- NET net; // client connection descriptor
1054+@@ -40,6 +40,9 @@
1055+ #include "thr_lock.h" /* thr_lock_type, THR_LOCK_DATA,
1056+ THR_LOCK_INFO */
1057+
1058++#ifdef HAVE_QUERY_CACHE
1059++#include "query_strip_comments.h"
1060++#endif // HAVE_QUERY_CACHE
1061+
1062+ class Reprepare_observer;
1063+ class Relay_log_info;
1064+@@ -766,6 +769,9 @@
1065+ statement lifetime. FIXME: must be const
1066+ */
1067+ ulong id;
1068++#ifdef HAVE_QUERY_CACHE
1069++ QueryStripComments query_strip_comments; // see sql_cache.cc
1070++#endif //HAVE_QUERY_CACHE
1071+
1072+ /*
1073+ MARK_COLUMNS_NONE: Means mark_used_colums is not set and no indicator to
1074 --- a/sql/sys_vars.cc
1075 +++ b/sql/sys_vars.cc
1076-@@ -1888,6 +1888,11 @@
1077+@@ -1895,6 +1895,11 @@
1078 NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
1079 ON_UPDATE(fix_query_cache_size));
1080
1081@@ -733,7 +495,7 @@
1082 "Don't cache results that are bigger than this",
1083 --- /dev/null
1084 +++ b/mysql-test/include/percona_query_cache_with_comments.inc
1085-@@ -0,0 +1,117 @@
1086+@@ -0,0 +1,95 @@
1087 +--source include/percona_query_cache_with_comments_clear.inc
1088 +let $query=/* with comment first */select * from t1;
1089 +eval $query;
1090@@ -827,30 +589,8 @@
1091 +;
1092 +--source include/percona_query_cache_with_comments_eval.inc
1093 +
1094-+let $query=select */* a comment \*/from t1;
1095-+--source include/percona_query_cache_with_comments_eval.inc
1096-+
1097-+let $query=select *# a comment \\
1098-+from t1;
1099-+--source include/percona_query_cache_with_comments_eval.inc
1100-+
1101-+let $query=select *-- a comment \\
1102-+from t1;
1103-+--source include/percona_query_cache_with_comments_eval.inc
1104-+
1105-+let $query=select "\\\\"" /* not a comment */" from t1;
1106-+--source include/percona_query_cache_with_comments_eval.inc
1107-+
1108-+let $query=select "\\\\"" /*! not a comment */" from t1;
1109-+--source include/percona_query_cache_with_comments_eval.inc
1110-+
1111-+# following two queries related to bug #856404.
1112-+# There are different queries, but opt_query_cache_strip_comments thinks that they are equal.
1113 +let $query=select ' \' ' from t1;
1114 +--source include/percona_query_cache_with_comments_eval.inc
1115-+
1116-+let $query=select ' \' /* comment inside quotes with internal backslash quote */' from t1;
1117-+--source include/percona_query_cache_with_comments_eval.inc
1118 --- /dev/null
1119 +++ b/mysql-test/include/percona_query_cache_with_comments_begin.inc
1120 @@ -0,0 +1,12 @@
1121@@ -903,7 +643,7 @@
1122 +
1123 --- /dev/null
1124 +++ b/mysql-test/r/percona_query_cache_with_comments.result
1125-@@ -0,0 +1,1058 @@
1126+@@ -0,0 +1,866 @@
1127 +set global query_cache_strip_comments=ON;
1128 +set GLOBAL query_cache_size=1355776;
1129 +drop table if exists t1;
1130@@ -1737,228 +1477,36 @@
1131 +Variable_name Value
1132 +Qcache_hits 50
1133 +-----------------------------------------------------
1134-+select */* a comment \*/from t1
1135-+-----------------------------------------------------
1136-+show status like "Qcache_queries_in_cache";
1137-+Variable_name Value
1138-+Qcache_queries_in_cache 1
1139-+show status like "Qcache_inserts";
1140-+Variable_name Value
1141-+Qcache_inserts 1
1142-+show status like "Qcache_hits";
1143-+Variable_name Value
1144-+Qcache_hits 50
1145-+select */* a comment \*/from t1;
1146-+a
1147-+1
1148-+2
1149-+3
1150-+select */* a comment \*/from t1;
1151-+a
1152-+1
1153-+2
1154-+3
1155-+show status like "Qcache_queries_in_cache";
1156-+Variable_name Value
1157-+Qcache_queries_in_cache 1
1158-+show status like "Qcache_inserts";
1159-+Variable_name Value
1160-+Qcache_inserts 1
1161-+show status like "Qcache_hits";
1162-+Variable_name Value
1163-+Qcache_hits 52
1164-+-----------------------------------------------------
1165-+select *# a comment \
1166-+from t1
1167-+-----------------------------------------------------
1168-+show status like "Qcache_queries_in_cache";
1169-+Variable_name Value
1170-+Qcache_queries_in_cache 1
1171-+show status like "Qcache_inserts";
1172-+Variable_name Value
1173-+Qcache_inserts 1
1174-+show status like "Qcache_hits";
1175-+Variable_name Value
1176-+Qcache_hits 52
1177-+select *# a comment \
1178-+from t1;
1179-+a
1180-+1
1181-+2
1182-+3
1183-+select *# a comment \
1184-+from t1;
1185-+a
1186-+1
1187-+2
1188-+3
1189-+show status like "Qcache_queries_in_cache";
1190-+Variable_name Value
1191-+Qcache_queries_in_cache 1
1192-+show status like "Qcache_inserts";
1193-+Variable_name Value
1194-+Qcache_inserts 1
1195-+show status like "Qcache_hits";
1196-+Variable_name Value
1197-+Qcache_hits 54
1198-+-----------------------------------------------------
1199-+select *-- a comment \
1200-+from t1
1201-+-----------------------------------------------------
1202-+show status like "Qcache_queries_in_cache";
1203-+Variable_name Value
1204-+Qcache_queries_in_cache 1
1205-+show status like "Qcache_inserts";
1206-+Variable_name Value
1207-+Qcache_inserts 1
1208-+show status like "Qcache_hits";
1209-+Variable_name Value
1210-+Qcache_hits 54
1211-+select *-- a comment \
1212-+from t1;
1213-+a
1214-+1
1215-+2
1216-+3
1217-+select *-- a comment \
1218-+from t1;
1219-+a
1220-+1
1221-+2
1222-+3
1223-+show status like "Qcache_queries_in_cache";
1224-+Variable_name Value
1225-+Qcache_queries_in_cache 1
1226-+show status like "Qcache_inserts";
1227-+Variable_name Value
1228-+Qcache_inserts 1
1229-+show status like "Qcache_hits";
1230-+Variable_name Value
1231-+Qcache_hits 56
1232-+-----------------------------------------------------
1233-+select "\\"" /* not a comment */" from t1
1234-+-----------------------------------------------------
1235-+show status like "Qcache_queries_in_cache";
1236-+Variable_name Value
1237-+Qcache_queries_in_cache 1
1238-+show status like "Qcache_inserts";
1239-+Variable_name Value
1240-+Qcache_inserts 1
1241-+show status like "Qcache_hits";
1242-+Variable_name Value
1243-+Qcache_hits 56
1244-+select "\\"" /* not a comment */" from t1;
1245-+\" /* not a comment */
1246-+\" /* not a comment */
1247-+\" /* not a comment */
1248-+\" /* not a comment */
1249-+select "\\"" /* not a comment */" from t1;
1250-+\" /* not a comment */
1251-+\" /* not a comment */
1252-+\" /* not a comment */
1253-+\" /* not a comment */
1254-+show status like "Qcache_queries_in_cache";
1255-+Variable_name Value
1256-+Qcache_queries_in_cache 2
1257-+show status like "Qcache_inserts";
1258-+Variable_name Value
1259-+Qcache_inserts 2
1260-+show status like "Qcache_hits";
1261-+Variable_name Value
1262-+Qcache_hits 57
1263-+-----------------------------------------------------
1264-+select "\\"" /*! not a comment */" from t1
1265-+-----------------------------------------------------
1266-+show status like "Qcache_queries_in_cache";
1267-+Variable_name Value
1268-+Qcache_queries_in_cache 2
1269-+show status like "Qcache_inserts";
1270-+Variable_name Value
1271-+Qcache_inserts 2
1272-+show status like "Qcache_hits";
1273-+Variable_name Value
1274-+Qcache_hits 57
1275-+select "\\"" /*! not a comment */" from t1;
1276-+\" /*! not a comment */
1277-+\" /*! not a comment */
1278-+\" /*! not a comment */
1279-+\" /*! not a comment */
1280-+select "\\"" /*! not a comment */" from t1;
1281-+\" /*! not a comment */
1282-+\" /*! not a comment */
1283-+\" /*! not a comment */
1284-+\" /*! not a comment */
1285-+show status like "Qcache_queries_in_cache";
1286-+Variable_name Value
1287-+Qcache_queries_in_cache 3
1288-+show status like "Qcache_inserts";
1289-+Variable_name Value
1290-+Qcache_inserts 3
1291-+show status like "Qcache_hits";
1292-+Variable_name Value
1293-+Qcache_hits 58
1294-+-----------------------------------------------------
1295 +select ' \' ' from t1
1296 +-----------------------------------------------------
1297 +show status like "Qcache_queries_in_cache";
1298 +Variable_name Value
1299-+Qcache_queries_in_cache 3
1300-+show status like "Qcache_inserts";
1301-+Variable_name Value
1302-+Qcache_inserts 3
1303-+show status like "Qcache_hits";
1304-+Variable_name Value
1305-+Qcache_hits 58
1306-+select ' \' ' from t1;
1307-+'
1308-+ '
1309-+ '
1310-+ '
1311-+select ' \' ' from t1;
1312-+'
1313-+ '
1314-+ '
1315-+ '
1316-+show status like "Qcache_queries_in_cache";
1317-+Variable_name Value
1318-+Qcache_queries_in_cache 4
1319-+show status like "Qcache_inserts";
1320-+Variable_name Value
1321-+Qcache_inserts 4
1322-+show status like "Qcache_hits";
1323-+Variable_name Value
1324-+Qcache_hits 59
1325-+-----------------------------------------------------
1326-+select ' \' /* comment inside quotes with internal backslash quote */' from t1
1327-+-----------------------------------------------------
1328-+show status like "Qcache_queries_in_cache";
1329-+Variable_name Value
1330-+Qcache_queries_in_cache 4
1331-+show status like "Qcache_inserts";
1332-+Variable_name Value
1333-+Qcache_inserts 4
1334-+show status like "Qcache_hits";
1335-+Variable_name Value
1336-+Qcache_hits 59
1337-+select ' \' /* comment inside quotes with internal backslash quote */' from t1;
1338-+' /* comment inside quotes with internal backslash quote */
1339-+ ' /* comment inside quotes with internal backslash quote */
1340-+ ' /* comment inside quotes with internal backslash quote */
1341-+ ' /* comment inside quotes with internal backslash quote */
1342-+select ' \' /* comment inside quotes with internal backslash quote */' from t1;
1343-+' /* comment inside quotes with internal backslash quote */
1344-+ ' /* comment inside quotes with internal backslash quote */
1345-+ ' /* comment inside quotes with internal backslash quote */
1346-+ ' /* comment inside quotes with internal backslash quote */
1347-+show status like "Qcache_queries_in_cache";
1348-+Variable_name Value
1349-+Qcache_queries_in_cache 5
1350-+show status like "Qcache_inserts";
1351-+Variable_name Value
1352-+Qcache_inserts 5
1353-+show status like "Qcache_hits";
1354-+Variable_name Value
1355-+Qcache_hits 60
1356++Qcache_queries_in_cache 1
1357++show status like "Qcache_inserts";
1358++Variable_name Value
1359++Qcache_inserts 1
1360++show status like "Qcache_hits";
1361++Variable_name Value
1362++Qcache_hits 50
1363++select ' \' ' from t1;
1364++'
1365++ '
1366++ '
1367++ '
1368++select ' \' ' from t1;
1369++'
1370++ '
1371++ '
1372++ '
1373++show status like "Qcache_queries_in_cache";
1374++Variable_name Value
1375++Qcache_queries_in_cache 2
1376++show status like "Qcache_inserts";
1377++Variable_name Value
1378++Qcache_inserts 2
1379++show status like "Qcache_hits";
1380++Variable_name Value
1381++Qcache_hits 51
1382 +DROP TABLE t1;
1383 +SET GLOBAL query_cache_size=default;
1384 +set global query_cache_strip_comments=OFF;
1385@@ -1988,7 +1536,7 @@
1386 +SET GLOBAL query_cache_size= default;
1387 --- /dev/null
1388 +++ b/mysql-test/r/percona_query_cache_with_comments_disable.result
1389-@@ -0,0 +1,1057 @@
1390+@@ -0,0 +1,865 @@
1391 +set GLOBAL query_cache_size=1355776;
1392 +drop table if exists t1;
1393 +create table t1 (a int not null);
1394@@ -2821,228 +2369,36 @@
1395 +Variable_name Value
1396 +Qcache_hits 25
1397 +-----------------------------------------------------
1398-+select */* a comment \*/from t1
1399-+-----------------------------------------------------
1400-+show status like "Qcache_queries_in_cache";
1401-+Variable_name Value
1402-+Qcache_queries_in_cache 20
1403-+show status like "Qcache_inserts";
1404-+Variable_name Value
1405-+Qcache_inserts 20
1406-+show status like "Qcache_hits";
1407-+Variable_name Value
1408-+Qcache_hits 25
1409-+select */* a comment \*/from t1;
1410-+a
1411-+1
1412-+2
1413-+3
1414-+select */* a comment \*/from t1;
1415-+a
1416-+1
1417-+2
1418-+3
1419-+show status like "Qcache_queries_in_cache";
1420-+Variable_name Value
1421-+Qcache_queries_in_cache 21
1422-+show status like "Qcache_inserts";
1423-+Variable_name Value
1424-+Qcache_inserts 21
1425-+show status like "Qcache_hits";
1426-+Variable_name Value
1427-+Qcache_hits 26
1428-+-----------------------------------------------------
1429-+select *# a comment \
1430-+from t1
1431-+-----------------------------------------------------
1432-+show status like "Qcache_queries_in_cache";
1433-+Variable_name Value
1434-+Qcache_queries_in_cache 21
1435-+show status like "Qcache_inserts";
1436-+Variable_name Value
1437-+Qcache_inserts 21
1438-+show status like "Qcache_hits";
1439-+Variable_name Value
1440-+Qcache_hits 26
1441-+select *# a comment \
1442-+from t1;
1443-+a
1444-+1
1445-+2
1446-+3
1447-+select *# a comment \
1448-+from t1;
1449-+a
1450-+1
1451-+2
1452-+3
1453-+show status like "Qcache_queries_in_cache";
1454-+Variable_name Value
1455-+Qcache_queries_in_cache 22
1456-+show status like "Qcache_inserts";
1457-+Variable_name Value
1458-+Qcache_inserts 22
1459-+show status like "Qcache_hits";
1460-+Variable_name Value
1461-+Qcache_hits 27
1462-+-----------------------------------------------------
1463-+select *-- a comment \
1464-+from t1
1465-+-----------------------------------------------------
1466-+show status like "Qcache_queries_in_cache";
1467-+Variable_name Value
1468-+Qcache_queries_in_cache 22
1469-+show status like "Qcache_inserts";
1470-+Variable_name Value
1471-+Qcache_inserts 22
1472-+show status like "Qcache_hits";
1473-+Variable_name Value
1474-+Qcache_hits 27
1475-+select *-- a comment \
1476-+from t1;
1477-+a
1478-+1
1479-+2
1480-+3
1481-+select *-- a comment \
1482-+from t1;
1483-+a
1484-+1
1485-+2
1486-+3
1487-+show status like "Qcache_queries_in_cache";
1488-+Variable_name Value
1489-+Qcache_queries_in_cache 23
1490-+show status like "Qcache_inserts";
1491-+Variable_name Value
1492-+Qcache_inserts 23
1493-+show status like "Qcache_hits";
1494-+Variable_name Value
1495-+Qcache_hits 28
1496-+-----------------------------------------------------
1497-+select "\\"" /* not a comment */" from t1
1498-+-----------------------------------------------------
1499-+show status like "Qcache_queries_in_cache";
1500-+Variable_name Value
1501-+Qcache_queries_in_cache 23
1502-+show status like "Qcache_inserts";
1503-+Variable_name Value
1504-+Qcache_inserts 23
1505-+show status like "Qcache_hits";
1506-+Variable_name Value
1507-+Qcache_hits 28
1508-+select "\\"" /* not a comment */" from t1;
1509-+\" /* not a comment */
1510-+\" /* not a comment */
1511-+\" /* not a comment */
1512-+\" /* not a comment */
1513-+select "\\"" /* not a comment */" from t1;
1514-+\" /* not a comment */
1515-+\" /* not a comment */
1516-+\" /* not a comment */
1517-+\" /* not a comment */
1518-+show status like "Qcache_queries_in_cache";
1519-+Variable_name Value
1520-+Qcache_queries_in_cache 24
1521-+show status like "Qcache_inserts";
1522-+Variable_name Value
1523-+Qcache_inserts 24
1524-+show status like "Qcache_hits";
1525-+Variable_name Value
1526-+Qcache_hits 29
1527-+-----------------------------------------------------
1528-+select "\\"" /*! not a comment */" from t1
1529-+-----------------------------------------------------
1530-+show status like "Qcache_queries_in_cache";
1531-+Variable_name Value
1532-+Qcache_queries_in_cache 24
1533-+show status like "Qcache_inserts";
1534-+Variable_name Value
1535-+Qcache_inserts 24
1536-+show status like "Qcache_hits";
1537-+Variable_name Value
1538-+Qcache_hits 29
1539-+select "\\"" /*! not a comment */" from t1;
1540-+\" /*! not a comment */
1541-+\" /*! not a comment */
1542-+\" /*! not a comment */
1543-+\" /*! not a comment */
1544-+select "\\"" /*! not a comment */" from t1;
1545-+\" /*! not a comment */
1546-+\" /*! not a comment */
1547-+\" /*! not a comment */
1548-+\" /*! not a comment */
1549-+show status like "Qcache_queries_in_cache";
1550-+Variable_name Value
1551-+Qcache_queries_in_cache 25
1552-+show status like "Qcache_inserts";
1553-+Variable_name Value
1554-+Qcache_inserts 25
1555-+show status like "Qcache_hits";
1556-+Variable_name Value
1557-+Qcache_hits 30
1558-+-----------------------------------------------------
1559 +select ' \' ' from t1
1560 +-----------------------------------------------------
1561 +show status like "Qcache_queries_in_cache";
1562 +Variable_name Value
1563-+Qcache_queries_in_cache 25
1564-+show status like "Qcache_inserts";
1565-+Variable_name Value
1566-+Qcache_inserts 25
1567-+show status like "Qcache_hits";
1568-+Variable_name Value
1569-+Qcache_hits 30
1570-+select ' \' ' from t1;
1571-+'
1572-+ '
1573-+ '
1574-+ '
1575-+select ' \' ' from t1;
1576-+'
1577-+ '
1578-+ '
1579-+ '
1580-+show status like "Qcache_queries_in_cache";
1581-+Variable_name Value
1582-+Qcache_queries_in_cache 26
1583-+show status like "Qcache_inserts";
1584-+Variable_name Value
1585-+Qcache_inserts 26
1586-+show status like "Qcache_hits";
1587-+Variable_name Value
1588-+Qcache_hits 31
1589-+-----------------------------------------------------
1590-+select ' \' /* comment inside quotes with internal backslash quote */' from t1
1591-+-----------------------------------------------------
1592-+show status like "Qcache_queries_in_cache";
1593-+Variable_name Value
1594-+Qcache_queries_in_cache 26
1595-+show status like "Qcache_inserts";
1596-+Variable_name Value
1597-+Qcache_inserts 26
1598-+show status like "Qcache_hits";
1599-+Variable_name Value
1600-+Qcache_hits 31
1601-+select ' \' /* comment inside quotes with internal backslash quote */' from t1;
1602-+' /* comment inside quotes with internal backslash quote */
1603-+ ' /* comment inside quotes with internal backslash quote */
1604-+ ' /* comment inside quotes with internal backslash quote */
1605-+ ' /* comment inside quotes with internal backslash quote */
1606-+select ' \' /* comment inside quotes with internal backslash quote */' from t1;
1607-+' /* comment inside quotes with internal backslash quote */
1608-+ ' /* comment inside quotes with internal backslash quote */
1609-+ ' /* comment inside quotes with internal backslash quote */
1610-+ ' /* comment inside quotes with internal backslash quote */
1611-+show status like "Qcache_queries_in_cache";
1612-+Variable_name Value
1613-+Qcache_queries_in_cache 27
1614-+show status like "Qcache_inserts";
1615-+Variable_name Value
1616-+Qcache_inserts 27
1617-+show status like "Qcache_hits";
1618-+Variable_name Value
1619-+Qcache_hits 32
1620++Qcache_queries_in_cache 20
1621++show status like "Qcache_inserts";
1622++Variable_name Value
1623++Qcache_inserts 20
1624++show status like "Qcache_hits";
1625++Variable_name Value
1626++Qcache_hits 25
1627++select ' \' ' from t1;
1628++'
1629++ '
1630++ '
1631++ '
1632++select ' \' ' from t1;
1633++'
1634++ '
1635++ '
1636++ '
1637++show status like "Qcache_queries_in_cache";
1638++Variable_name Value
1639++Qcache_queries_in_cache 21
1640++show status like "Qcache_inserts";
1641++Variable_name Value
1642++Qcache_inserts 21
1643++show status like "Qcache_hits";
1644++Variable_name Value
1645++Qcache_hits 26
1646 +DROP TABLE t1;
1647 +SET GLOBAL query_cache_size=default;
1648 +set global query_cache_strip_comments=OFF;
1649@@ -3735,7 +3091,7 @@
1650 +SET GLOBAL query_cache_size=0;
1651 --- a/mysql-test/r/mysqld--help-notwin.result
1652 +++ b/mysql-test/r/mysqld--help-notwin.result
1653-@@ -493,6 +493,10 @@
1654+@@ -500,6 +500,10 @@
1655 The minimum size for blocks allocated by the query cache
1656 --query-cache-size=#
1657 The memory allocated to store results from old queries
1658@@ -3746,7 +3102,7 @@
1659 --query-cache-type=name
1660 OFF = Don't cache or retrieve results. ON = Cache all
1661 results except SELECT SQL_NO_CACHE ... queries. DEMAND =
1662-@@ -931,6 +935,7 @@
1663+@@ -942,6 +946,7 @@
1664 query-cache-limit 1048576
1665 query-cache-min-res-unit 4096
1666 query-cache-size 0
1667@@ -3778,7 +3134,7 @@
1668 +try_lock_mutex_query
1669 +SET GLOBAL query_cache_size=0;
1670 --- /dev/null
1671-+++ b/mysql-test/r/percona_query_cache_with_comments_crash_2.result
1672++++ b/mysql-test/r/percona_bug856404.result
1673 @@ -0,0 +1,8 @@
1674 +DROP TABLE IF EXISTS table17_int;
1675 +DROP TABLE IF EXISTS table30_int;
1676@@ -3789,120 +3145,24 @@
1677 +DROP TABLE table17_int;
1678 +DROP TABLE table30_int;
1679 --- /dev/null
1680-+++ b/mysql-test/t/percona_query_cache_with_comments_crash_2-master.opt
1681++++ b/mysql-test/t/percona_bug856404-master.opt
1682 @@ -0,0 +1 @@
1683 +--query-cache-size=10M --query-cache-strip-comments
1684 --- /dev/null
1685-+++ b/mysql-test/t/percona_query_cache_with_comments_crash_2.test
1686-@@ -0,0 +1,9 @@
1687++++ b/mysql-test/t/percona_bug856404.test
1688+@@ -0,0 +1,15 @@
1689++########################################################################
1690++# Bug #856404: Crash when query_cache_strip_comments enabled
1691++########################################################################
1692++
1693 +--disable_warnings
1694 +DROP TABLE IF EXISTS table17_int;
1695 +DROP TABLE IF EXISTS table30_int;
1696 +--enable_warnings
1697++
1698 +CREATE TABLE `table17_int` (pk integer auto_increment primary key, `col_char_10_not_null_key` char(10), `col_enum_not_null_key` int);
1699 +CREATE TABLE `table30_int` (pk integer auto_increment primary key, `col_enum_not_null_key` int);
1700 +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*/;
1701++
1702 +DROP TABLE table17_int;
1703 +DROP TABLE table30_int;
1704---- a/sql/sql_class.cc
1705-+++ b/sql/sql_class.cc
1706-@@ -807,6 +807,99 @@
1707- sql_errno == ER_TRG_NO_DEFINER);
1708- }
1709-
1710-+#ifdef HAVE_QUERY_CACHE
1711-+
1712-+
1713-+Query_Without_Comments::Query_Without_Comments() :
1714-+ buffer(0),
1715-+ q_length(0),
1716-+ b_length(0)
1717-+{
1718-+}
1719-+
1720-+
1721-+Query_Without_Comments::~Query_Without_Comments()
1722-+{
1723-+ if(buffer)
1724-+ {
1725-+ my_free(buffer);
1726-+ }
1727-+}
1728-+
1729-+
1730-+bool Query_Without_Comments::allocate(size_t query_length, size_t db_length)
1731-+{
1732-+ DBUG_ENTER("Query_Without_Comments::allocate");
1733-+ DBUG_PRINT("info", ("old buffer: %p "
1734-+ "old query: '%-.4096s' "
1735-+ "old buffer length: %u "
1736-+ "old query length: %u",
1737-+ buffer,
1738-+ buffer,
1739-+ (uint) b_length,
1740-+ (uint) q_length));
1741-+ /* save maximum query length for check in the set_length */
1742-+ q_length= query_length;
1743-+ /* according to sql_parse.cc memory allocation */
1744-+ size_t new_b_length= (query_length + 1) + sizeof(size_t) + db_length +
1745-+ QUERY_CACHE_FLAGS_SIZE;
1746-+ if (b_length < new_b_length)
1747-+ {
1748-+ b_length= new_b_length;
1749-+ if (buffer)
1750-+ {
1751-+ buffer= (char*) my_realloc(buffer, b_length, MYF(0));
1752-+ }
1753-+ else
1754-+ {
1755-+ buffer= (char *) my_malloc(b_length, MYF(0));
1756-+ }
1757-+ }
1758-+ buffer[0]= 0;
1759-+ DBUG_PRINT("info", ("buffer: %p "
1760-+ "buffer length: %u "
1761-+ "query maximum length: %u",
1762-+ buffer,
1763-+ (uint) b_length,
1764-+ (uint) q_length));
1765-+ DBUG_RETURN(buffer);
1766-+}
1767-+
1768-+
1769-+void Query_Without_Comments::set_length(size_t query_length)
1770-+{
1771-+ DBUG_ENTER("Query_Without_Comments::set_length");
1772-+ DBUG_ASSERT(query_length <= q_length);
1773-+ buffer[query_length]= 0;
1774-+ DBUG_PRINT("info", ("buffer: %p "
1775-+ "query: '%-.4096s' "
1776-+ "buffer length: %u "
1777-+ "query maximum length: %u "
1778-+ "query length: %u",
1779-+ buffer,
1780-+ buffer,
1781-+ (uint) b_length,
1782-+ (uint) q_length,
1783-+ (uint) query_length));
1784-+ q_length= query_length;
1785-+ DBUG_VOID_RETURN;
1786-+}
1787-+
1788-+
1789-+char* Query_Without_Comments::query()
1790-+{
1791-+ return buffer;
1792-+}
1793-+
1794-+
1795-+size_t Query_Without_Comments::length()
1796-+{
1797-+ return q_length;
1798-+}
1799-+
1800-+
1801-+#endif // HAVE_QUERY_CACHE
1802-+
1803-
1804- THD::THD()
1805- :Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION,

Subscribers

People subscribed via source and target branches