~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/plugin/query_cache.cc

  • Committer: Stewart Smith
  • Date: 2010-08-12 16:48:46 UTC
  • mto: This revision was merged to the branch mainline in revision 1707.
  • Revision ID: stewart@flamingspork.com-20100812164846-s9bhy47g60bvqs41
bug lp:611379 Equivalent queries with Impossible where return different results

The following two equivalent queries return different results in maria 5.2 and 5.3 (and identical results in mysql 5.5.5) :

SELECT SUM( DISTINCT table1 .`pk` ) FROM B table1 STRAIGHT_JOIN ( BB table2 JOIN CC ON table2 .`col_varchar_key` ) ON table2 .`pk` ;

SELECT * FROM ( SELECT SUM( DISTINCT table1 .`pk` ) FROM B table1 STRAIGHT_JOIN ( BB table2 JOIN CC ON table2 .`col_varchar_key` ) ON table2 .`pk` );

MariaDB returns 0 on the second query and NULL on the first, whereas MySQL returns NULL on both. In MariaDB, both EXPLAIN plans agree that "Impossible WHERE noticed after reading const tables"



We have some slightly different output in drizzle:

main.bug_lp611379 [ fail ]
drizzletest: At line 9: query 'explain select * from (select sum(distinct t1.a) from t1,t2 where t1.a=t2.a)
as t' failed: 1048: Column 'sum(distinct t1.a)' cannot be null

but the fix gets us the correct query results, although with slightly different execution plans.



This fix is directly ported from MariaDB.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
3
 *
4
 
 *  Copyright (C) 2008 Sun Microsystems, Inc.
5
 
 *  Copyright (C) 2010 Djellel Eddine Difallah
 
4
 *  Copyright (C) 2008 Sun Microsystems
6
5
 *
7
6
 *  This program is free software; you can redistribute it and/or modify
8
7
 *  it under the terms of the GNU General Public License as published by
18
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
18
 */
20
19
 
21
 
#include <config.h>
22
 
#include <drizzled/plugin/query_cache.h>
23
 
#include <drizzled/errmsg_print.h>
 
20
#include "config.h"
 
21
#include "drizzled/plugin/query_cache.h"
 
22
#include "drizzled/errmsg_print.h"
24
23
 
25
 
#include <drizzled/gettext.h>
 
24
#include "drizzled/gettext.h"
26
25
 
27
26
#include <algorithm>
28
27
#include <vector>
29
28
 
30
29
class Session;
31
30
 
 
31
using namespace std;
 
32
 
32
33
namespace drizzled
33
34
{
34
 
typedef std::vector<plugin::QueryCache *> QueryCaches;
35
 
QueryCaches all_query_cache;
 
35
 
 
36
vector<plugin::QueryCache *> all_query_cache;
36
37
 
37
38
/* Namespaces are here to prevent global symbol clashes with these classes */
38
39
 
39
 
class IsCachedIterate
40
 
 : public std::unary_function<plugin::QueryCache *, bool>
41
 
{
42
 
  Session *session;
43
 
public:
44
 
  IsCachedIterate(Session* session_arg) :
45
 
    std::unary_function<plugin::QueryCache *, bool>(),
46
 
    session(session_arg) { }
47
 
 
48
 
  inline result_type operator()(argument_type handler)
49
 
  {
50
 
    return handler->doIsCached(session);
51
 
  }
52
 
};
53
 
 
54
 
bool plugin::QueryCache::isCached(Session *session)
55
 
{
56
 
  /* Use find_if instead of foreach so that we can collect return codes */
57
 
  QueryCaches::iterator iter=
58
 
    std::find_if(all_query_cache.begin(), all_query_cache.end(),
59
 
            IsCachedIterate(session));
60
 
  /* If iter is == end() here, that means that all of the plugins returned
61
 
   * false, which in this case means they all succeeded. Since we want to 
62
 
   * return false on success, we return the value of the two being != 
63
 
   */
64
 
  return iter != all_query_cache.end();
65
 
}
66
 
 
67
 
 
68
 
class SendCachedResultsetIterate
69
 
 : public std::unary_function<plugin::QueryCache *, bool>
70
 
{
71
 
  Session *session;
72
 
public:
73
 
  SendCachedResultsetIterate(Session *session_arg) :
74
 
    std::unary_function<plugin::QueryCache *, bool>(),
75
 
    session(session_arg) { }
76
 
 
77
 
  inline result_type operator()(argument_type handler)
78
 
  {
79
 
    return handler->doSendCachedResultset(session);
80
 
  }
81
 
};
82
 
bool plugin::QueryCache::sendCachedResultset(Session *session)
83
 
{
84
 
  /* Use find_if instead of foreach so that we can collect return codes */
85
 
  QueryCaches::iterator iter=
86
 
    std::find_if(all_query_cache.begin(), all_query_cache.end(),
87
 
                 SendCachedResultsetIterate(session));
88
 
  /* If iter is == end() here, that means that all of the plugins returned
89
 
   * false, which in this case means they all succeeded. Since we want to 
90
 
   * return false on success, we return the value of the two being != 
91
 
   */
92
 
  return iter != all_query_cache.end();
93
 
}
94
 
 
95
 
class PrepareResultsetIterate : public std::unary_function<plugin::QueryCache *, bool>
96
 
{
97
 
  Session *session;
98
 
public:
99
 
  PrepareResultsetIterate(Session *session_arg) :
100
 
    std::unary_function<plugin::QueryCache *, bool>(),
101
 
    session(session_arg) { }
102
 
 
103
 
  inline result_type operator()(argument_type handler)
104
 
  {
105
 
    return handler->doPrepareResultset(session);
106
 
  }
107
 
};
108
 
bool plugin::QueryCache::prepareResultset(Session *session)
109
 
{
110
 
  /* Use find_if instead of foreach so that we can collect return codes */
111
 
  QueryCaches::iterator iter=
112
 
    std::find_if(all_query_cache.begin(), all_query_cache.end(),
113
 
                 PrepareResultsetIterate(session));
114
 
  /* If iter is == end() here, that means that all of the plugins returned
115
 
   * false, which in this case means they all succeeded. Since we want to 
116
 
   * return false on success, we return the value of the two being != 
117
 
   */
118
 
  return iter != all_query_cache.end();
119
 
}
120
 
 
121
 
class SetResultsetIterate : public std::unary_function<plugin::QueryCache *, bool>
122
 
{
123
 
  Session *session;
124
 
public:
125
 
  SetResultsetIterate(Session *session_arg) :
126
 
    std::unary_function<plugin::QueryCache *, bool>(),
127
 
    session(session_arg) { }
128
 
 
129
 
  inline result_type operator()(argument_type handler)
130
 
  {
131
 
    return handler->doSetResultset(session);
132
 
  }
133
 
};
134
 
 
135
 
bool plugin::QueryCache::setResultset(Session *session)
136
 
{
137
 
  /* Use find_if instead of foreach so that we can collect return codes */
138
 
  QueryCaches::iterator iter=
139
 
    std::find_if(all_query_cache.begin(), all_query_cache.end(),
140
 
                 SetResultsetIterate(session));
141
 
  /* If iter is == end() here, that means that all of the plugins returned
142
 
   * false, which in this case means they all succeeded. Since we want to 
143
 
   * return false on success, we return the value of the two being != 
144
 
   */
145
 
  return iter != all_query_cache.end();
146
 
}
147
 
 
148
 
class InsertRecordIterate
149
 
 : public std::unary_function<plugin::QueryCache *, bool>
150
 
{
151
 
  Session *session;
152
 
  List<Item> &item;
153
 
public:
154
 
  InsertRecordIterate(Session *session_arg, List<Item> &item_arg) :
155
 
    std::unary_function<plugin::QueryCache *, bool>(),
156
 
    session(session_arg), item(item_arg) { }
157
 
 
158
 
  inline result_type operator()(argument_type handler)
159
 
  {
160
 
    return handler->doInsertRecord(session, item);
161
 
  }
162
 
};
163
 
bool plugin::QueryCache::insertRecord(Session *session, List<Item> &items)
164
 
{
165
 
  /* Use find_if instead of foreach so that we can collect return codes */
166
 
  QueryCaches::iterator iter=
167
 
    std::find_if(all_query_cache.begin(), all_query_cache.end(),
168
 
                 InsertRecordIterate(session, items));
169
 
  /* If iter is == end() here, that means that all of the plugins returned
170
 
   * false, which in this case means they all succeeded. Since we want to 
171
 
   * return false on success, we return the value of the two being != 
172
 
   */
173
 
  return iter != all_query_cache.end();
174
 
}
175
 
 
176
 
 
 
40
class TryFetchAndSendIterate
 
41
 : public unary_function<plugin::QueryCache *, bool>
 
42
{
 
43
  Session *session;
 
44
  bool is_transactional;
 
45
public:
 
46
  TryFetchAndSendIterate(Session *session_arg, bool is_transactional_arg) :
 
47
    unary_function<plugin::QueryCache *, bool>(),
 
48
    session(session_arg), is_transactional(is_transactional_arg) { }
 
49
 
 
50
  inline result_type operator()(argument_type handler)
 
51
  {
 
52
    if (handler->tryFetchAndSend(session, is_transactional))
 
53
    {
 
54
      errmsg_printf(ERRMSG_LVL_ERROR,
 
55
                    _("qcache plugin '%s' try_fetch_and_send() failed"),
 
56
                    handler->getName().c_str());
 
57
      return true;
 
58
    }
 
59
    return false;
 
60
  }
 
61
};
 
62
 
 
63
class SetIterate
 
64
 : public unary_function<plugin::QueryCache *, bool>
 
65
{
 
66
  Session *session;
 
67
  bool is_transactional;
 
68
public:
 
69
  SetIterate(Session *session_arg, bool is_transactional_arg) :
 
70
    unary_function<plugin::QueryCache *, bool>(),
 
71
    session(session_arg), is_transactional(is_transactional_arg) { }
 
72
 
 
73
  inline result_type operator()(argument_type handler)
 
74
  {
 
75
 
 
76
    if (handler->set(session, is_transactional))
 
77
    {
 
78
      errmsg_printf(ERRMSG_LVL_ERROR, _("qcache plugin '%s' set() failed"),
 
79
                    handler->getName().c_str());
 
80
      return true;
 
81
    }
 
82
    return false;
 
83
  }
 
84
};
 
85
 
 
86
class InvalidateTableIterate
 
87
 : public unary_function<plugin::QueryCache *, bool>
 
88
{
 
89
  Session *session;
 
90
  bool is_transactional;
 
91
public:
 
92
  InvalidateTableIterate(Session *session_arg, bool is_transactional_arg) :
 
93
    unary_function<plugin::QueryCache *, bool>(),
 
94
    session(session_arg), is_transactional(is_transactional_arg) { }
 
95
 
 
96
  inline result_type operator()(argument_type handler)
 
97
  {
 
98
 
 
99
    if (handler->invalidateTable(session, is_transactional))
 
100
    {
 
101
      errmsg_printf(ERRMSG_LVL_ERROR,
 
102
                    _("qcache plugin '%s' invalidateTable() failed"),
 
103
                    handler->getName().c_str());
 
104
      return true;
 
105
    }
 
106
    return false;
 
107
  }
 
108
};
 
109
 
 
110
 
 
111
class InvalidateDbIterate
 
112
 : public unary_function<plugin::QueryCache *, bool>
 
113
{
 
114
  Session *session;
 
115
  const char *dbname;
 
116
  bool is_transactional;
 
117
public:
 
118
  InvalidateDbIterate(Session *session_arg, const char *dbname_arg,
 
119
                      bool is_transactional_arg) :
 
120
    unary_function<plugin::QueryCache *, bool>(),
 
121
    session(session_arg), dbname(dbname_arg),
 
122
    is_transactional(is_transactional_arg) { }
 
123
 
 
124
  inline result_type operator()(argument_type handler)
 
125
  {
 
126
    if (handler->invalidateDb(session, dbname, is_transactional))
 
127
    {
 
128
      errmsg_printf(ERRMSG_LVL_ERROR,
 
129
                    _("qcache plugin '%s' invalidateDb() failed"),
 
130
                    handler->getName().c_str());
 
131
      return true;
 
132
    }
 
133
    return false;
 
134
  }
 
135
};
 
136
 
 
137
class FlushIterate
 
138
 : public unary_function<plugin::QueryCache *, bool>
 
139
{
 
140
  Session *session;
 
141
public:
 
142
  FlushIterate(Session *session_arg) :
 
143
    unary_function<plugin::QueryCache *, bool>(), session(session_arg) { }
 
144
 
 
145
  inline result_type operator()(argument_type handler)
 
146
  {
 
147
    if (handler->flush(session))
 
148
    {
 
149
      errmsg_printf(ERRMSG_LVL_ERROR, _("qcache plugin '%s' flush() failed"),
 
150
                    handler->getName().c_str());
 
151
      return true;
 
152
    }
 
153
    return false;
 
154
  }
 
155
};
177
156
 
178
157
bool plugin::QueryCache::addPlugin(plugin::QueryCache *handler)
179
158
{
183
162
 
184
163
void plugin::QueryCache::removePlugin(plugin::QueryCache *handler)
185
164
{
186
 
  all_query_cache.erase(std::find(all_query_cache.begin(), all_query_cache.end(),
187
 
                                  handler));
 
165
  all_query_cache.erase(find(all_query_cache.begin(), all_query_cache.end(),
 
166
                        handler));
 
167
}
 
168
 
 
169
 
 
170
bool plugin::QueryCache::tryFetchAndSendDo(Session *session,
 
171
                                           bool transactional)
 
172
{
 
173
  /* Use find_if instead of foreach so that we can collect return codes */
 
174
  vector<plugin::QueryCache *>::iterator iter=
 
175
    find_if(all_query_cache.begin(), all_query_cache.end(),
 
176
            TryFetchAndSendIterate(session, transactional));
 
177
  /* If iter is == end() here, that means that all of the plugins returned
 
178
   * false, which in this case means they all succeeded. Since we want to 
 
179
   * return false on success, we return the value of the two being != 
 
180
   */
 
181
  return iter != all_query_cache.end();
 
182
}
 
183
 
 
184
bool plugin::QueryCache::setDo(Session *session, bool transactional)
 
185
{
 
186
  /* Use find_if instead of foreach so that we can collect return codes */
 
187
  vector<plugin::QueryCache *>::iterator iter=
 
188
    find_if(all_query_cache.begin(), all_query_cache.end(),
 
189
            SetIterate(session, transactional));
 
190
  /* If iter is == end() here, that means that all of the plugins returned
 
191
   * false, which in this case means they all succeeded. Since we want to 
 
192
   * return false on success, we return the value of the two being != 
 
193
   */
 
194
  return iter != all_query_cache.end();
 
195
}
 
196
 
 
197
bool plugin::QueryCache::invalidateTableDo(Session *session,
 
198
                                         bool transactional)
 
199
{
 
200
  /* Use find_if instead of foreach so that we can collect return codes */
 
201
  vector<plugin::QueryCache *>::iterator iter=
 
202
    find_if(all_query_cache.begin(), all_query_cache.end(),
 
203
            InvalidateTableIterate(session, transactional));
 
204
  /* If iter is == end() here, that means that all of the plugins returned
 
205
   * false, which in this case means they all succeeded. Since we want to 
 
206
   * return false on success, we return the value of the two being != 
 
207
   */
 
208
  return iter != all_query_cache.end();
 
209
}
 
210
 
 
211
bool plugin::QueryCache::invalidateDbDo(Session *session, const char *dbname,
 
212
                                        bool transactional)
 
213
{
 
214
  /* Use find_if instead of foreach so that we can collect return codes */
 
215
  vector<plugin::QueryCache *>::iterator iter=
 
216
    find_if(all_query_cache.begin(), all_query_cache.end(),
 
217
            InvalidateDbIterate(session, dbname, transactional));
 
218
  /* If iter is == end() here, that means that all of the plugins returned
 
219
   * false, which in this case means they all succeeded. Since we want to 
 
220
   * return false on success, we return the value of the two being != 
 
221
   */
 
222
  return iter != all_query_cache.end();
 
223
}
 
224
 
 
225
bool plugin::QueryCache::flushDo(Session *session)
 
226
{
 
227
  /* Use find_if instead of foreach so that we can collect return codes */
 
228
  vector<plugin::QueryCache *>::iterator iter=
 
229
    find_if(all_query_cache.begin(), all_query_cache.end(),
 
230
            FlushIterate(session));
 
231
  /* If iter is == end() here, that means that all of the plugins returned
 
232
   * false, which in this case means they all succeeded. Since we want to 
 
233
   * return false on success, we return the value of the two being != 
 
234
   */
 
235
  return iter != all_query_cache.end();
188
236
}
189
237
 
190
238
} /* namespace drizzled */