~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/thr_lock.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:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
13
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
16
/*
17
17
Read and write locks for Posix threads. All tread must acquire
56
56
#include "drizzled/internal/my_sys.h"
57
57
#include "drizzled/internal/thread_var.h"
58
58
#include "drizzled/statistics_variables.h"
59
 
#include "drizzled/pthread_globals.h"
60
 
 
61
 
#include "drizzled/session.h"
62
59
 
63
60
#include "thr_lock.h"
64
61
#include "drizzled/internal/m_string.h"
78
75
 
79
76
#include <drizzled/util/test.h>
80
77
 
81
 
#include <boost/interprocess/sync/lock_options.hpp>
82
 
 
83
78
using namespace std;
84
79
 
85
80
namespace drizzled
89
84
static enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
90
85
 
91
86
 
92
 
uint64_t max_write_lock_count= UINT64_MAX;
 
87
uint64_t max_write_lock_count= ~(uint64_t) 0L;
93
88
 
94
 
void thr_multi_unlock(THR_LOCK_DATA **data,uint32_t count);
 
89
static inline pthread_cond_t *get_cond(void)
 
90
{
 
91
  return &my_thread_var->suspend;
 
92
}
95
93
 
96
94
/*
97
95
** For the future (now the thread specific cond is alloced by my_pthread.c)
119
117
void THR_LOCK_INFO::init()
120
118
{
121
119
  internal::st_my_thread_var *tmp= my_thread_var;
 
120
  thread= tmp->pthread_self;
122
121
  thread_id= tmp->id;
123
122
  n_cursors= 0;
124
123
}
149
148
static void wake_up_waiters(THR_LOCK *lock);
150
149
 
151
150
 
152
 
static enum enum_thr_lock_result wait_for_lock(Session &session, struct st_lock_list *wait, THR_LOCK_DATA *data)
 
151
static enum enum_thr_lock_result wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, bool in_wait_list)
153
152
{
154
 
  internal::st_my_thread_var *thread_var= session.getThreadVar();
155
 
 
156
 
  boost::condition_variable_any *cond= &thread_var->suspend;
 
153
  internal::st_my_thread_var *thread_var= my_thread_var;
 
154
  pthread_cond_t *cond= &thread_var->suspend;
 
155
  struct timespec wait_timeout;
157
156
  enum enum_thr_lock_result result= THR_LOCK_ABORTED;
158
157
  bool can_deadlock= test(data->owner->info->n_cursors);
159
158
 
 
159
  if (!in_wait_list)
160
160
  {
161
161
    (*wait->last)=data;                         /* Wait for lock */
162
162
    data->prev= wait->last;
167
167
 
168
168
  /* Set up control struct to allow others to abort locks */
169
169
  thread_var->current_mutex= data->lock->native_handle();
170
 
  thread_var->current_cond=  &thread_var->suspend;
171
 
  data->cond= &thread_var->suspend;;
 
170
  thread_var->current_cond=  cond;
 
171
  data->cond= cond;
172
172
 
173
 
  while (not thread_var->abort)
 
173
  if (can_deadlock)
 
174
    set_timespec(wait_timeout, table_lock_wait_timeout);
 
175
  while (!thread_var->abort || in_wait_list)
174
176
  {
175
 
    boost_unique_lock_t scoped(*data->lock->native_handle(), boost::adopt_lock_t());
176
 
 
177
 
    if (can_deadlock)
178
 
    {
179
 
      boost::xtime xt; 
180
 
      xtime_get(&xt, boost::TIME_UTC); 
181
 
      xt.sec += table_lock_wait_timeout; 
182
 
      if (not cond->timed_wait(scoped, xt))
183
 
      {
184
 
        result= THR_LOCK_WAIT_TIMEOUT;
185
 
        scoped.release();
186
 
        break;
187
 
      }
188
 
    }
189
 
    else
190
 
    {
191
 
      cond->wait(scoped);
192
 
    }
 
177
    int rc= (can_deadlock ?
 
178
             pthread_cond_timedwait(cond, data->lock->native_handle(),
 
179
                                    &wait_timeout) :
 
180
             pthread_cond_wait(cond, data->lock->native_handle()));
193
181
    /*
194
182
      We must break the wait if one of the following occurs:
195
183
      - the connection has been aborted (!thread_var->abort), but
203
191
      Order of checks below is important to not report about timeout
204
192
      if the predicate is true.
205
193
    */
206
 
    if (data->cond == NULL)
207
 
    {
208
 
      scoped.release();
209
 
      break;
210
 
    }
211
 
    scoped.release();
 
194
    if (data->cond == 0)
 
195
    {
 
196
      break;
 
197
    }
 
198
    if (rc == ETIMEDOUT || rc == ETIME)
 
199
    {
 
200
      result= THR_LOCK_WAIT_TIMEOUT;
 
201
      break;
 
202
    }
212
203
  }
213
204
  if (data->cond || data->type == TL_UNLOCK)
214
205
  {
229
220
  data->lock->unlock();
230
221
 
231
222
  /* The following must be done after unlock of lock->mutex */
232
 
  boost_unique_lock_t scopedLock(thread_var->mutex);
 
223
  pthread_mutex_lock(&thread_var->mutex);
233
224
  thread_var->current_mutex= NULL;
234
225
  thread_var->current_cond= NULL;
 
226
  pthread_mutex_unlock(&thread_var->mutex);
235
227
  return(result);
236
228
}
237
229
 
238
230
 
239
 
static enum enum_thr_lock_result thr_lock(Session &session, THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, enum thr_lock_type lock_type)
 
231
static enum enum_thr_lock_result thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, enum thr_lock_type lock_type)
240
232
{
241
233
  THR_LOCK *lock= data->lock;
242
234
  enum enum_thr_lock_result result= THR_LOCK_SUCCESS;
384
376
  }
385
377
 
386
378
  /* Can't get lock yet;  Wait for it */
387
 
  return(wait_for_lock(session, wait_queue, data));
 
379
  return(wait_for_lock(wait_queue, data, 0));
388
380
end:
389
381
  lock->unlock();
390
382
 
406
398
 
407
399
  do
408
400
  {
409
 
    boost::condition_variable_any *cond= data->cond;
 
401
    pthread_cond_t *cond=data->cond;
410
402
    if ((int) data->type == (int) TL_READ_NO_INSERT)
411
403
    {
412
404
      if (using_concurrent_insert)
426
418
      }
427
419
      lock->read_no_write_count++;
428
420
    }
429
 
    data->cond= NULL;                           /* Mark thread free */
430
 
    cond->notify_one();
 
421
    data->cond=0;                               /* Mark thread free */
 
422
    pthread_cond_signal(cond);
431
423
  } while ((data=data->next));
432
424
  *lock->read_wait.last=0;
433
425
  if (!lock->read_wait.data)
504
496
          lock->write.last= &data->next;
505
497
 
506
498
          {
507
 
            boost::condition_variable_any *cond= data->cond;
508
 
            data->cond= NULL;                           /* Mark thread free */
509
 
            cond->notify_one(); /* Start waiting thred */
 
499
            pthread_cond_t *cond=data->cond;
 
500
            data->cond=0;                               /* Mark thread free */
 
501
            pthread_cond_signal(cond);  /* Start waiting thread */
510
502
          }
511
503
          if (data->type != TL_WRITE_ALLOW_WRITE ||
512
504
              !lock->write_wait.data ||
531
523
              !lock->read_no_write_count))
532
524
    {
533
525
      do {
534
 
        boost::condition_variable_any *cond= data->cond;
 
526
        pthread_cond_t *cond=data->cond;
535
527
        if (((*data->prev)=data->next))         /* remove from wait-list */
536
528
          data->next->prev= data->prev;
537
529
        else
540
532
        data->prev=lock->write.last;
541
533
        lock->write.last= &data->next;
542
534
        data->next=0;                           /* Only one write lock */
543
 
        data->cond= NULL;                               /* Mark thread free */
544
 
        cond->notify_one(); /* Start waiting thread */
 
535
        data->cond=0;                           /* Mark thread free */
 
536
        pthread_cond_signal(cond);      /* Start waiting thread */
545
537
      } while (lock_type == TL_WRITE_ALLOW_WRITE &&
546
538
               (data=lock->write_wait.data) &&
547
539
               data->type == TL_WRITE_ALLOW_WRITE);
591
583
 
592
584
 
593
585
enum enum_thr_lock_result
594
 
thr_multi_lock(Session &session, THR_LOCK_DATA **data, uint32_t count, THR_LOCK_OWNER *owner)
 
586
thr_multi_lock(THR_LOCK_DATA **data, uint32_t count, THR_LOCK_OWNER *owner)
595
587
{
596
588
  THR_LOCK_DATA **pos,**end;
597
589
  if (count > 1)
599
591
  /* lock everything */
600
592
  for (pos=data,end=data+count; pos < end ; pos++)
601
593
  {
602
 
    enum enum_thr_lock_result result= thr_lock(session, *pos, owner, (*pos)->type);
 
594
    enum enum_thr_lock_result result= thr_lock(*pos, owner, (*pos)->type);
603
595
    if (result != THR_LOCK_SUCCESS)
604
596
    {                                           /* Aborted */
605
597
      thr_multi_unlock(data,(uint32_t) (pos-data));
640
632
  return;
641
633
}
642
634
 
643
 
void DrizzleLock::unlock(uint32_t count)
644
 
{
645
 
  THR_LOCK_DATA **pos,**end;
646
 
 
647
 
  for (pos= getLocks(),end= getLocks()+count; pos < end ; pos++)
648
 
  {
649
 
    if ((*pos)->type != TL_UNLOCK)
650
 
      thr_unlock(*pos);
651
 
  }
652
 
}
653
 
 
654
635
/*
655
636
  Abort all threads waiting for a lock. The lock will be upgraded to
656
637
  TL_WRITE_ONLY to abort any new accesses to the lock
658
639
 
659
640
void THR_LOCK::abort_locks()
660
641
{
661
 
  boost_unique_lock_t scopedLock(mutex);
 
642
  pthread_mutex_lock(&mutex);
662
643
 
663
644
  for (THR_LOCK_DATA *local_data= read_wait.data; local_data ; local_data= local_data->next)
664
645
  {
665
646
    local_data->type= TL_UNLOCK;                        /* Mark killed */
666
647
    /* It's safe to signal the cond first: we're still holding the mutex. */
667
 
    local_data->cond->notify_one();
 
648
    pthread_cond_signal(local_data->cond);
668
649
    local_data->cond= NULL;                             /* Removed from list */
669
650
  }
670
651
  for (THR_LOCK_DATA *local_data= write_wait.data; local_data ; local_data= local_data->next)
671
652
  {
672
653
    local_data->type= TL_UNLOCK;
673
 
    local_data->cond->notify_one();
 
654
    pthread_cond_signal(local_data->cond);
674
655
    local_data->cond= NULL;
675
656
  }
676
657
  read_wait.last= &read_wait.data;
678
659
  read_wait.data= write_wait.data=0;
679
660
  if (write.data)
680
661
    write.data->type=TL_WRITE_ONLY;
 
662
  pthread_mutex_unlock(&mutex);
681
663
}
682
664
 
683
665
 
691
673
{
692
674
  bool found= false;
693
675
 
694
 
  boost_unique_lock_t scopedLock(mutex);
 
676
  pthread_mutex_lock(&mutex);
695
677
  for (THR_LOCK_DATA *local_data= read_wait.data; local_data ; local_data= local_data->next)
696
678
  {
697
679
    if (local_data->owner->info->thread_id == thread_id_arg)
699
681
      local_data->type= TL_UNLOCK;                      /* Mark killed */
700
682
      /* It's safe to signal the cond first: we're still holding the mutex. */
701
683
      found= true;
702
 
      local_data->cond->notify_one();
 
684
      pthread_cond_signal(local_data->cond);
703
685
      local_data->cond= 0;                              /* Removed from list */
704
686
 
705
687
      if (((*local_data->prev)= local_data->next))
714
696
    {
715
697
      local_data->type= TL_UNLOCK;
716
698
      found= true;
717
 
      local_data->cond->notify_one();
 
699
      pthread_cond_signal(local_data->cond);
718
700
      local_data->cond= NULL;
719
701
 
720
702
      if (((*local_data->prev)= local_data->next))
724
706
    }
725
707
  }
726
708
  wake_up_waiters(this);
 
709
  pthread_mutex_unlock(&mutex);
727
710
 
728
711
  return found;
729
712
}