~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_derived.cc

pandora-build v0.100 - Fixes several bugs found by cb1kenobi. Add several thoughts from folks at LCA.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
  Derived tables
18
18
  These were introduced by Sinisa <sinisa@mysql.com>
19
19
*/
20
 
#include <drizzled/server_includes.h>
21
 
#include <drizzled/sql_select.h>
 
20
#include "config.h"
 
21
#include "drizzled/sql_select.h"
22
22
 
23
23
/*
24
24
  Call given derived table processor (preparing or filling tables)
32
32
    false  OK
33
33
    true   Error
34
34
*/
35
 
bool
36
 
mysql_handle_derived(LEX *lex, bool (*processor)(THD*, LEX*, TABLE_LIST*))
 
35
bool mysql_handle_derived(LEX *lex, bool (*processor)(Session*, LEX*, TableList*))
37
36
{
38
37
  bool res= false;
39
38
  if (lex->derived_tables)
40
39
  {
41
 
    lex->thd->derived_tables_processing= true;
42
 
    for (SELECT_LEX *sl= lex->all_selects_list;
43
 
         sl;
44
 
         sl= sl->next_select_in_list())
 
40
    lex->session->derived_tables_processing= true;
 
41
    for (Select_Lex *sl= lex->all_selects_list; sl; sl= sl->next_select_in_list())
45
42
    {
46
 
      for (TABLE_LIST *cursor= sl->get_table_list();
47
 
           cursor;
48
 
           cursor= cursor->next_local)
 
43
      for (TableList *cursor= sl->get_table_list(); cursor; cursor= cursor->next_local)
49
44
      {
50
 
        if ((res= (*processor)(lex->thd, lex, cursor)))
51
 
          goto out;
 
45
        if ((res= (*processor)(lex->session, lex, cursor)))
 
46
          goto out;
52
47
      }
53
48
      if (lex->describe)
54
49
      {
55
 
        /*
56
 
          Force join->join_tmp creation, because we will use this JOIN
57
 
          twice for EXPLAIN and we have to have unchanged join for EXPLAINing
58
 
        */
59
 
        sl->uncacheable|= UNCACHEABLE_EXPLAIN;
60
 
        sl->master_unit()->uncacheable|= UNCACHEABLE_EXPLAIN;
 
50
        /*
 
51
          Force join->join_tmp creation, because we will use this JOIN
 
52
          twice for EXPLAIN and we have to have unchanged join for EXPLAINing
 
53
        */
 
54
        sl->uncacheable|= UNCACHEABLE_EXPLAIN;
 
55
        sl->master_unit()->uncacheable|= UNCACHEABLE_EXPLAIN;
61
56
      }
62
57
    }
63
58
  }
64
59
out:
65
 
  lex->thd->derived_tables_processing= false;
 
60
  lex->session->derived_tables_processing= false;
66
61
  return res;
67
62
}
68
63
 
69
 
 
70
64
/*
71
65
  Create temporary table structure (but do not fill it)
72
66
 
73
67
  SYNOPSIS
74
68
    mysql_derived_prepare()
75
 
    thd                 Thread handle
 
69
    session                     Thread handle
76
70
    lex                 LEX for this thread
77
 
    orig_table_list     TABLE_LIST for the upper SELECT
 
71
    orig_table_list     TableList for the upper SELECT
78
72
 
79
73
  IMPLEMENTATION
80
74
    Derived table is resolved with temporary table.
81
75
 
82
 
    After table creation, the above TABLE_LIST is updated with a new table.
 
76
    After table creation, the above TableList is updated with a new table.
83
77
 
84
78
    This function is called before any command containing derived table
85
79
    is executed.
86
80
 
87
 
    Derived tables is stored in thd->derived_tables and freed in
 
81
    Derived tables is stored in session->derived_tables and freed in
88
82
    close_thread_tables()
89
83
 
90
84
  RETURN
91
85
    false  OK
92
86
    true   Error
93
87
*/
94
 
 
95
 
bool mysql_derived_prepare(THD *thd, LEX *lex __attribute__((unused)),
96
 
                           TABLE_LIST *orig_table_list)
 
88
bool mysql_derived_prepare(Session *session, LEX *, TableList *orig_table_list)
97
89
{
98
 
  SELECT_LEX_UNIT *unit= orig_table_list->derived;
 
90
  Select_Lex_Unit *unit= orig_table_list->derived;
99
91
  uint64_t create_options;
100
92
  bool res= false;
101
93
  if (unit)
102
94
  {
103
 
    SELECT_LEX *first_select= unit->first_select();
104
 
    TABLE *table= 0;
 
95
    Select_Lex *first_select= unit->first_select();
 
96
    Table *table= 0;
105
97
    select_union *derived_result;
106
98
 
107
99
    /* prevent name resolving out of derived table */
108
 
    for (SELECT_LEX *sl= first_select; sl; sl= sl->next_select())
 
100
    for (Select_Lex *sl= first_select; sl; sl= sl->next_select())
109
101
      sl->context.outer_context= 0;
110
102
 
111
103
    if (!(derived_result= new select_union))
112
104
      return(true); // out of memory
113
105
 
114
 
    // st_select_lex_unit::prepare correctly work for single select
115
 
    if ((res= unit->prepare(thd, derived_result, 0)))
 
106
    // Select_Lex_Unit::prepare correctly work for single select
 
107
    if ((res= unit->prepare(session, derived_result, 0)))
116
108
      goto exit;
117
109
 
118
 
    create_options= (first_select->options | thd->options |
119
 
                     TMP_TABLE_ALL_COLUMNS);
 
110
    create_options= (first_select->options | session->options | TMP_TABLE_ALL_COLUMNS);
120
111
    /*
121
 
      Temp table is created so that it hounours if UNION without ALL is to be 
 
112
      Temp table is created so that it hounours if UNION without ALL is to be
122
113
      processed
123
114
 
124
115
      As 'distinct' parameter we always pass false (0), because underlying
127
118
      !unit->union_distinct->next_select() (i.e. it is union and last distinct
128
119
      SELECT is last SELECT of UNION).
129
120
    */
130
 
    if ((res= derived_result->create_result_table(thd, &unit->types, false,
 
121
    if ((res= derived_result->create_result_table(session, &unit->types, false,
131
122
                                                  create_options,
132
123
                                                  orig_table_list->alias,
133
124
                                                  false)))
144
135
    if (res)
145
136
    {
146
137
      if (table)
147
 
        free_tmp_table(thd, table);
 
138
        table->free_tmp_table(session);
148
139
      delete derived_result;
149
140
    }
150
141
    else
151
142
    {
152
 
      if (!thd->fill_derived_tables())
 
143
      if (! session->fill_derived_tables())
153
144
      {
154
 
        delete derived_result;
155
 
        derived_result= NULL;
 
145
        delete derived_result;
 
146
        derived_result= NULL;
156
147
      }
157
148
      orig_table_list->derived_result= derived_result;
158
149
      orig_table_list->table= table;
159
150
      orig_table_list->table_name=        table->s->table_name.str;
160
151
      orig_table_list->table_name_length= table->s->table_name.length;
161
152
      table->derived_select_number= first_select->select_number;
162
 
      table->s->tmp_table= NON_TRANSACTIONAL_TMP_TABLE;
 
153
      table->s->tmp_table= TEMP_TABLE;
163
154
      orig_table_list->db= (char *)"";
164
155
      orig_table_list->db_length= 0;
165
 
      // Force read of table stats in the optimizer
166
 
      table->file->info(HA_STATUS_VARIABLE);
 
156
      /* Force read of table stats in the optimizer */
 
157
      table->cursor->info(HA_STATUS_VARIABLE);
167
158
      /* Add new temporary table to list of open derived tables */
168
 
      table->next= thd->derived_tables;
169
 
      thd->derived_tables= table;
 
159
      table->next= session->derived_tables;
 
160
      session->derived_tables= table;
170
161
    }
171
162
  }
172
163
 
173
164
  return(res);
174
165
}
175
166
 
176
 
 
177
167
/*
178
168
  fill derived table
179
169
 
180
170
  SYNOPSIS
181
171
    mysql_derived_filling()
182
 
    thd                 Thread handle
 
172
    session                     Thread handle
183
173
    lex                 LEX for this thread
184
174
    unit                node that contains all SELECT's for derived tables
185
 
    orig_table_list     TABLE_LIST for the upper SELECT
 
175
    orig_table_list     TableList for the upper SELECT
186
176
 
187
177
  IMPLEMENTATION
188
178
    Derived table is resolved with temporary table. It is created based on the
196
186
    false  OK
197
187
    true   Error
198
188
*/
199
 
 
200
 
bool mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
 
189
bool mysql_derived_filling(Session *session, LEX *lex, TableList *orig_table_list)
201
190
{
202
 
  TABLE *table= orig_table_list->table;
203
 
  SELECT_LEX_UNIT *unit= orig_table_list->derived;
 
191
  Table *table= orig_table_list->table;
 
192
  Select_Lex_Unit *unit= orig_table_list->derived;
204
193
  bool res= false;
205
194
 
206
195
  /*check that table creation pass without problem and it is derived table */
207
196
  if (table && unit)
208
197
  {
209
 
    SELECT_LEX *first_select= unit->first_select();
 
198
    Select_Lex *first_select= unit->first_select();
210
199
    select_union *derived_result= orig_table_list->derived_result;
211
 
    SELECT_LEX *save_current_select= lex->current_select;
 
200
    Select_Lex *save_current_select= lex->current_select;
212
201
    if (unit->is_union())
213
202
    {
214
 
      // execute union without clean up
 
203
      /* execute union without clean up */
215
204
      res= unit->exec();
216
205
    }
217
206
    else
218
207
    {
219
208
      unit->set_limit(first_select);
220
209
      if (unit->select_limit_cnt == HA_POS_ERROR)
221
 
        first_select->options&= ~OPTION_FOUND_ROWS;
 
210
              first_select->options&= ~OPTION_FOUND_ROWS;
222
211
 
223
212
      lex->current_select= first_select;
224
 
      res= mysql_select(thd, &first_select->ref_pointer_array,
225
 
                        (TABLE_LIST*) first_select->table_list.first,
226
 
                        first_select->with_wild,
227
 
                        first_select->item_list, first_select->where,
228
 
                        (first_select->order_list.elements+
229
 
                         first_select->group_list.elements),
230
 
                        (ORDER *) first_select->order_list.first,
231
 
                        (ORDER *) first_select->group_list.first,
232
 
                        first_select->having, (ORDER*) NULL,
233
 
                        (first_select->options | thd->options |
234
 
                         SELECT_NO_UNLOCK),
235
 
                        derived_result, unit, first_select);
 
213
      res= mysql_select(session, &first_select->ref_pointer_array,
 
214
                        (TableList*) first_select->table_list.first,
 
215
                        first_select->with_wild,
 
216
                        first_select->item_list, first_select->where,
 
217
                        (first_select->order_list.elements+
 
218
                        first_select->group_list.elements),
 
219
                        (order_st *) first_select->order_list.first,
 
220
                        (order_st *) first_select->group_list.first,
 
221
                        first_select->having,
 
222
                        (first_select->options | session->options | SELECT_NO_UNLOCK),
 
223
                        derived_result, unit, first_select);
236
224
    }
237
225
 
238
 
    if (!res)
 
226
    if (! res)
239
227
    {
240
228
      /*
241
 
        Here we entirely fix both TABLE_LIST and list of SELECT's as
 
229
        Here we entirely fix both TableList and list of SELECT's as
242
230
        there were no derived tables
243
231
      */
244
232
      if (derived_result->flush())
245
233
        res= true;
246
234
 
247
 
      if (!lex->describe)
 
235
      if (! lex->describe)
248
236
        unit->cleanup();
249
237
    }
250
238
    else