~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/main.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.
 
4
 *  Copyright (C) 2008 Sun Microsystems
5
5
 *
6
6
 *  This program is free software; you can redistribute it and/or modify
7
7
 *  it under the terms of the GNU General Public License as published by
17
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
18
 */
19
19
 
20
 
#include <config.h>
 
20
#include "config.h"
21
21
 
22
22
#include <pthread.h>
23
23
#include <signal.h>
24
24
#include <sys/resource.h>
25
25
#include <unistd.h>
26
 
#include <sys/stat.h>
27
 
#include <sys/types.h>
28
 
 
29
26
 
30
27
#if TIME_WITH_SYS_TIME
31
28
# include <sys/time.h>
42
39
# include <locale.h>
43
40
#endif
44
41
 
45
 
#include <boost/filesystem.hpp>
46
42
 
47
 
#include <drizzled/abort_exception.h>
48
 
#include <drizzled/catalog/local.h>
49
 
#include <drizzled/configmake.h>
50
 
#include <drizzled/data_home.h>
51
 
#include <drizzled/debug.h>
52
 
#include <drizzled/drizzled.h>
53
 
#include <drizzled/errmsg_print.h>
54
 
#include <drizzled/gettext.h>
55
 
#include <drizzled/internal/my_sys.h>
56
 
#include <drizzled/plugin.h>
57
 
#include <drizzled/plugin/client.h>
58
 
#include <drizzled/plugin/listen.h>
59
 
#include <drizzled/plugin/monitored_in_transaction.h>
60
 
#include <drizzled/pthread_globals.h>
61
 
#include <drizzled/replication_services.h>
62
 
#include <drizzled/session.h>
63
 
#include <drizzled/session/cache.h>
64
 
#include <drizzled/signal_handler.h>
65
 
#include <drizzled/transaction_services.h>
66
 
#include <drizzled/tztime.h>
67
 
#include <drizzled/unireg.h>
68
 
#include <drizzled/util/backtrace.h>
69
 
#include <drizzled/current_session.h>
70
 
#include <drizzled/daemon.h>
 
43
#include "drizzled/plugin.h"
 
44
#include "drizzled/gettext.h"
 
45
#include "drizzled/configmake.h"
 
46
#include "drizzled/session.h"
 
47
#include "drizzled/internal/my_sys.h"
 
48
#include "drizzled/unireg.h"
 
49
#include "drizzled/stacktrace.h"
 
50
#include "drizzled/drizzled.h"
 
51
#include "drizzled/errmsg_print.h"
 
52
#include "drizzled/data_home.h"
 
53
#include "drizzled/plugin/listen.h"
 
54
#include "drizzled/plugin/client.h"
 
55
#include "drizzled/pthread_globals.h"
 
56
#include "drizzled/tztime.h"
 
57
#include "drizzled/signal_handler.h"
 
58
#include "drizzled/replication_services.h"
71
59
 
72
60
using namespace drizzled;
73
61
using namespace std;
75
63
static pthread_t select_thread;
76
64
static uint32_t thr_kill_signal;
77
65
 
78
 
extern bool opt_daemon;
79
 
 
80
 
 
81
66
/**
82
67
  All global error messages are sent here where the first one is stored
83
68
  for the client.
84
69
*/
85
 
static void my_message_sql(drizzled::error_t error, const char *str, myf MyFlags)
 
70
static void my_message_sql(uint32_t error, const char *str, myf MyFlags)
86
71
{
87
72
  Session *session;
88
73
  /*
95
80
      session->is_fatal_error= 1;
96
81
 
97
82
    /*
98
 
      @TODO There are two exceptions mechanism (Session and sp_rcontext),
 
83
      TODO: There are two exceptions mechanism (Session and sp_rcontext),
99
84
      this could be improved by having a common stack of handlers.
100
85
    */
101
 
    if (session->handle_error(error, str, DRIZZLE_ERROR::WARN_LEVEL_ERROR))
102
 
      return;
 
86
    if (session->handle_error(error, str,
 
87
                          DRIZZLE_ERROR::WARN_LEVEL_ERROR))
 
88
      return;;
103
89
 
104
90
    /*
105
 
      session->getLex()->current_select == 0 if lex structure is not inited
 
91
      session->lex->current_select == 0 if lex structure is not inited
106
92
      (not query command (COM_QUERY))
107
93
    */
108
 
    if (! (session->getLex()->current_select &&
109
 
           session->getLex()->current_select->no_error && !session->is_fatal_error))
 
94
    if (! (session->lex->current_select &&
 
95
        session->lex->current_select->no_error && !session->is_fatal_error))
110
96
    {
111
97
      if (! session->main_da.is_error())            // Return only first message
112
98
      {
113
 
        if (error == EE_OK)
 
99
        if (error == 0)
114
100
          error= ER_UNKNOWN_ERROR;
115
 
 
116
101
        if (str == NULL)
117
102
          str= ER(error);
118
 
 
119
103
        session->main_da.set_error_status(error, str);
120
104
      }
121
105
    }
129
113
      session->no_warnings_for_error= true;
130
114
      push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error, str);
131
115
      session->no_warnings_for_error= false;
 
116
      }
132
117
    }
133
 
  }
134
 
 
135
 
  if (not session || MyFlags & ME_NOREFRESH)
136
 
  {
137
 
    errmsg_printf(error::ERROR, "%s: %s",internal::my_progname,str);
138
 
  }
 
118
    if (!session || MyFlags & ME_NOREFRESH)
 
119
        errmsg_printf(ERRMSG_LVL_ERROR, "%s: %s",internal::my_progname,str);
139
120
}
140
121
 
141
122
static void init_signals(void)
143
124
  sigset_t set;
144
125
  struct sigaction sa;
145
126
 
146
 
  if (not (getDebug().test(debug::NO_STACKTRACE) || 
147
 
        getDebug().test(debug::CORE_ON_SIGNAL)))
 
127
  if (!(test_flags.test(TEST_NO_STACKTRACE) || 
 
128
        test_flags.test(TEST_CORE_ON_SIGNAL)))
148
129
  {
149
130
    sa.sa_flags = SA_RESETHAND | SA_NODEFER;
150
131
    sigemptyset(&sa.sa_mask);
151
132
    sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL);
152
133
 
 
134
    init_stacktrace();
153
135
    sa.sa_handler= drizzled_handle_segfault;
154
136
    sigaction(SIGSEGV, &sa, NULL);
155
137
    sigaction(SIGABRT, &sa, NULL);
160
142
    sigaction(SIGFPE, &sa, NULL);
161
143
  }
162
144
 
163
 
  if (getDebug().test(debug::CORE_ON_SIGNAL))
 
145
  if (test_flags.test(TEST_CORE_ON_SIGNAL))
164
146
  {
165
147
    /* Change limits so that we will get a core file */
166
148
    struct rlimit rl;
167
149
    rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
168
150
    if (setrlimit(RLIMIT_CORE, &rl) && global_system_variables.log_warnings)
169
 
        errmsg_printf(error::WARN,
 
151
        errmsg_printf(ERRMSG_LVL_WARN,
170
152
                      _("setrlimit could not change the size of core files "
171
153
                        "to 'infinity';  We may not be able to generate a "
172
154
                        "core file on signals"));
191
173
#ifdef SIGTSTP
192
174
  sigaddset(&set,SIGTSTP);
193
175
#endif
194
 
  if (getDebug().test(debug::ALLOW_SIGINT))
 
176
  if (test_flags.test(TEST_SIGINT))
195
177
  {
196
178
    sa.sa_flags= 0;
197
179
    sa.sa_handler= drizzled_end_thread_signal;
209
191
  return;
210
192
}
211
193
 
212
 
static void GoogleProtoErrorThrower(google::protobuf::LogLevel level,
213
 
                                    const char* ,
214
 
                                    int, const string& ) throw(const char *)
 
194
static void GoogleProtoErrorThrower(google::protobuf::LogLevel level, const char* filename,
 
195
                       int line, const string& message) throw(const char *)
215
196
{
 
197
  (void)filename;
 
198
  (void)line;
 
199
  (void)message;
216
200
  switch(level)
217
201
  {
218
202
  case google::protobuf::LOGLEVEL_INFO:
231
215
# if defined(HAVE_LOCALE_H)
232
216
  setlocale(LC_ALL, "");
233
217
# endif
234
 
  bindtextdomain("drizzle7", LOCALEDIR);
235
 
  textdomain("drizzle7");
 
218
  bindtextdomain("drizzle", LOCALEDIR);
 
219
  textdomain("drizzle");
236
220
#endif
237
221
 
238
222
  module::Registry &modules= module::Registry::singleton();
 
223
  plugin::Client *client;
 
224
  Session *session;
239
225
 
240
226
  MY_INIT(argv[0]);             // init my_sys library & pthreads
241
227
  /* nothing should come before this line ^^^ */
242
228
 
243
229
  /* Set signal used to kill Drizzle */
 
230
#if defined(SIGUSR2)
 
231
  thr_kill_signal= internal::thd_lib_detected == THD_LIB_LT ? SIGINT : SIGUSR2;
 
232
#else
244
233
  thr_kill_signal= SIGINT;
 
234
#endif
245
235
 
246
236
  google::protobuf::SetLogHandler(&GoogleProtoErrorThrower);
247
237
 
248
 
  /* Function generates error messages before abort */
249
 
  error_handler_hook= my_message_sql;
250
 
 
251
 
  /* init_common_variables must get basic settings such as data_home_dir
252
 
     and plugin_load_list. */
253
 
  if (init_basic_variables(argc, argv))
254
 
    unireg_abort(1);                            // Will do exit
255
 
 
256
 
  if (opt_daemon)
257
 
  {
258
 
    if (signal(SIGHUP, SIG_IGN) == SIG_ERR)
259
 
    {
260
 
      perror("Failed to ignore SIGHUP");
261
 
    }
262
 
    if (daemonize())
263
 
    {
264
 
      fprintf(stderr, "failed to daemon() in order to daemonize\n");
265
 
      exit(EXIT_FAILURE);
266
 
    }
267
 
  }
268
 
 
269
 
  if (init_remaining_variables(modules))
270
 
    unireg_abort(1);                            // Will do exit
271
 
 
272
 
  /*
273
 
    init signals & alarm
274
 
    After this we can't quit by a simple unireg_abort
275
 
  */
 
238
  if (init_common_variables(DRIZZLE_CONFIG_NAME,
 
239
                            argc, argv, load_default_groups))
 
240
    unireg_abort(1);                            // Will do exit
 
241
 
276
242
  init_signals();
277
243
 
278
244
 
279
245
  select_thread=pthread_self();
280
246
  select_thread_in_use=1;
281
247
 
282
 
  if (not opt_help)
283
 
  {
284
 
    if (chdir(getDataHome().file_string().c_str()))
285
 
    {
286
 
      errmsg_printf(error::ERROR,
287
 
                    _("Data directory %s does not exist\n"),
288
 
                    getDataHome().file_string().c_str());
289
 
      unireg_abort(1);
290
 
    }
291
 
    if (mkdir("local", 0700))
292
 
    {
293
 
      /* We don't actually care */
294
 
    }
295
 
    if (chdir("local"))
296
 
    {
297
 
      errmsg_printf(error::ERROR,
298
 
                    _("Local catalog %s/local does not exist\n"),
299
 
                    getDataHome().file_string().c_str());
300
 
      unireg_abort(1);
301
 
    }
302
 
 
303
 
    boost::filesystem::path &full_data_home= getFullDataHome();
304
 
    full_data_home= boost::filesystem::system_complete(getDataHome());
305
 
    errmsg_printf(error::INFO, "Data Home directory is : %s", full_data_home.native_file_string().c_str());
306
 
  }
307
 
 
308
 
 
 
248
  if (chdir(data_home_real) && !opt_help)
 
249
  {
 
250
    errmsg_printf(ERRMSG_LVL_ERROR, _("Data directory %s does not exist\n"), data_home_real);
 
251
    unireg_abort(1);
 
252
  }
 
253
  data_home= data_home_buff;
 
254
  data_home[0]=FN_CURLIB;               // all paths are relative from here
 
255
  data_home[1]=0;
 
256
  data_home_len= 2;
 
257
 
 
258
  if ((user_info= check_user(drizzled_user)))
 
259
  {
 
260
    set_user(drizzled_user, user_info);
 
261
  }
309
262
 
310
263
  if (server_id == 0)
311
264
  {
312
265
    server_id= 1;
313
266
  }
314
267
 
315
 
  try
316
 
  {
317
 
    if (init_server_components(modules))
318
 
      DRIZZLE_ABORT;
319
 
  }
320
 
  catch (abort_exception& ex)
321
 
  {
322
 
#if defined(DEBUG)
323
 
    cout << _("Drizzle has receieved an abort event.") << endl;
324
 
    cout << _("In Function: ") << *::boost::get_error_info<boost::throw_function>(ex) << endl;
325
 
    cout << _("In File: ") << *::boost::get_error_info<boost::throw_file>(ex) << endl;
326
 
    cout << _("On Line: ") << *::boost::get_error_info<boost::throw_line>(ex) << endl;
327
 
#endif
 
268
  if (init_server_components(modules))
328
269
    unireg_abort(1);
329
 
  }
330
 
 
331
270
 
332
271
  /**
333
272
   * This check must be done after init_server_components for now
346
285
  if (plugin::Listen::setup())
347
286
    unireg_abort(1);
348
287
 
 
288
  /*
 
289
    init signals & alarm
 
290
    After this we can't quit by a simple unireg_abort
 
291
  */
 
292
  error_handler_hook= my_message_sql;
 
293
 
349
294
  assert(plugin::num_trx_monitored_objects > 0);
350
 
  if (drizzle_rm_tmp_tables())
 
295
  if (drizzle_rm_tmp_tables() ||
 
296
      my_tz_init((Session *)0, default_tz_name))
351
297
  {
352
298
    abort_loop= true;
353
299
    select_thread_in_use=0;
354
300
    (void) pthread_kill(signal_thread, SIGTERM);
355
301
 
356
 
    (void) unlink(pid_file.file_string().c_str());      // Not needed anymore
 
302
    (void) unlink(pidfile_name);        // Not needed anymore
357
303
 
358
 
    unireg_abort(1);
 
304
    exit(1);
359
305
  }
360
306
 
361
 
  errmsg_printf(error::INFO, _(ER(ER_STARTUP)), internal::my_progname,
 
307
  errmsg_printf(ERRMSG_LVL_INFO, _(ER(ER_STARTUP)), internal::my_progname,
362
308
                PANDORA_RELEASE_VERSION, COMPILATION_COMMENT);
363
309
 
364
310
 
365
 
  TransactionServices &transaction_services= TransactionServices::singleton();
366
 
 
367
 
  /* Send server startup event */
368
 
  {
369
 
    Session::shared_ptr session;
370
 
 
371
 
    if ((session= Session::make_shared(plugin::Listen::getNullClient(), catalog::local())))
372
 
    {
373
 
      currentSession().release();
374
 
      currentSession().reset(session.get());
375
 
 
376
 
 
377
 
      transaction_services.sendStartupEvent(*session);
378
 
 
379
 
      plugin_startup_window(modules, *(session.get()));
380
 
    }
381
 
  }
382
 
 
383
 
  if (opt_daemon)
384
 
    daemon_is_ready();
385
 
 
386
 
  /* 
387
 
    Listen for new connections and start new session for each connection
 
311
  /* Listen for new connections and start new session for each connection
388
312
     accepted. The listen.getClient() method will return NULL when the server
389
 
     should be shutdown.
390
 
   */
391
 
  plugin::Client *client;
 
313
     should be shutdown. */
392
314
  while ((client= plugin::Listen::getClient()) != NULL)
393
315
  {
394
 
    Session::shared_ptr session;
395
 
    session= Session::make_shared(client, client->catalog());
396
 
 
397
 
    if (not session)
 
316
    if (!(session= new Session(client)))
398
317
    {
399
318
      delete client;
400
319
      continue;
401
320
    }
402
321
 
403
322
    /* If we error on creation we drop the connection and delete the session. */
404
 
    if (Session::schedule(session))
 
323
    if (session->schedule())
405
324
      Session::unlink(session);
406
325
  }
407
326
 
408
 
  /* Send server shutdown event */
409
 
  {
410
 
    Session::shared_ptr session;
411
 
 
412
 
    if ((session= Session::make_shared(plugin::Listen::getNullClient(), catalog::local())))
413
 
    {
414
 
      currentSession().release();
415
 
      currentSession().reset(session.get());
416
 
      transaction_services.sendShutdownEvent(*session.get());
417
 
    }
418
 
  }
419
 
 
420
 
  {
421
 
    boost::mutex::scoped_lock scopedLock(session::Cache::singleton().mutex());
422
 
    select_thread_in_use= false;                        // For close_connections
423
 
  }
 
327
  LOCK_thread_count.lock();
 
328
  select_thread_in_use=0;                       // For close_connections
 
329
  LOCK_thread_count.unlock();
424
330
  COND_thread_count.notify_all();
425
331
 
426
332
  /* Wait until cleanup is done */
427
 
  session::Cache::singleton().shutdownSecond();
 
333
  LOCK_thread_count.lock();
 
334
  while (!ready_to_exit)
 
335
    pthread_cond_wait(COND_server_end.native_handle(), LOCK_thread_count.native_handle());
 
336
  LOCK_thread_count.unlock();
428
337
 
429
338
  clean_up(1);
430
339
  module::Registry::shutdown();
431
340
  internal::my_end();
432
 
 
433
341
  return 0;
434
342
}
435
343