~capttofu/drizzle/federated_schema

« back to all changes in this revision

Viewing changes to sql/sql_derived.cc

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2002-2003 MySQL AB
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
 
 
17
/*
 
18
  Derived tables
 
19
  These were introduced by Sinisa <sinisa@mysql.com>
 
20
*/
 
21
 
 
22
 
 
23
#include "mysql_priv.h"
 
24
#include "sql_select.h"
 
25
 
 
26
 
 
27
 
 
28
/*
 
29
  Call given derived table processor (preparing or filling tables)
 
30
 
 
31
  SYNOPSIS
 
32
    mysql_handle_derived()
 
33
    lex                 LEX for this thread
 
34
    processor           procedure of derived table processing
 
35
 
 
36
  RETURN
 
37
    FALSE  OK
 
38
    TRUE   Error
 
39
*/
 
40
 
 
41
bool
 
42
mysql_handle_derived(LEX *lex, bool (*processor)(THD*, LEX*, TABLE_LIST*))
 
43
{
 
44
  bool res= FALSE;
 
45
  if (lex->derived_tables)
 
46
  {
 
47
    lex->thd->derived_tables_processing= TRUE;
 
48
    for (SELECT_LEX *sl= lex->all_selects_list;
 
49
         sl;
 
50
         sl= sl->next_select_in_list())
 
51
    {
 
52
      for (TABLE_LIST *cursor= sl->get_table_list();
 
53
           cursor;
 
54
           cursor= cursor->next_local)
 
55
      {
 
56
        if ((res= (*processor)(lex->thd, lex, cursor)))
 
57
          goto out;
 
58
      }
 
59
      if (lex->describe)
 
60
      {
 
61
        /*
 
62
          Force join->join_tmp creation, because we will use this JOIN
 
63
          twice for EXPLAIN and we have to have unchanged join for EXPLAINing
 
64
        */
 
65
        sl->uncacheable|= UNCACHEABLE_EXPLAIN;
 
66
        sl->master_unit()->uncacheable|= UNCACHEABLE_EXPLAIN;
 
67
      }
 
68
    }
 
69
  }
 
70
out:
 
71
  lex->thd->derived_tables_processing= FALSE;
 
72
  return res;
 
73
}
 
74
 
 
75
 
 
76
/*
 
77
  Create temporary table structure (but do not fill it)
 
78
 
 
79
  SYNOPSIS
 
80
    mysql_derived_prepare()
 
81
    thd                 Thread handle
 
82
    lex                 LEX for this thread
 
83
    orig_table_list     TABLE_LIST for the upper SELECT
 
84
 
 
85
  IMPLEMENTATION
 
86
    Derived table is resolved with temporary table.
 
87
 
 
88
    After table creation, the above TABLE_LIST is updated with a new table.
 
89
 
 
90
    This function is called before any command containing derived table
 
91
    is executed.
 
92
 
 
93
    Derived tables is stored in thd->derived_tables and freed in
 
94
    close_thread_tables()
 
95
 
 
96
  RETURN
 
97
    FALSE  OK
 
98
    TRUE   Error
 
99
*/
 
100
 
 
101
bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
 
102
{
 
103
  SELECT_LEX_UNIT *unit= orig_table_list->derived;
 
104
  ulonglong create_options;
 
105
  DBUG_ENTER("mysql_derived_prepare");
 
106
  bool res= FALSE;
 
107
  if (unit)
 
108
  {
 
109
    SELECT_LEX *first_select= unit->first_select();
 
110
    TABLE *table= 0;
 
111
    select_union *derived_result;
 
112
 
 
113
    /* prevent name resolving out of derived table */
 
114
    for (SELECT_LEX *sl= first_select; sl; sl= sl->next_select())
 
115
      sl->context.outer_context= 0;
 
116
 
 
117
    if (!(derived_result= new select_union))
 
118
      DBUG_RETURN(TRUE); // out of memory
 
119
 
 
120
    // st_select_lex_unit::prepare correctly work for single select
 
121
    if ((res= unit->prepare(thd, derived_result, 0)))
 
122
      goto exit;
 
123
 
 
124
    create_options= (first_select->options | thd->options |
 
125
                     TMP_TABLE_ALL_COLUMNS);
 
126
    /*
 
127
      Temp table is created so that it hounours if UNION without ALL is to be 
 
128
      processed
 
129
 
 
130
      As 'distinct' parameter we always pass FALSE (0), because underlying
 
131
      query will control distinct condition by itself. Correct test of
 
132
      distinct underlying query will be is_union &&
 
133
      !unit->union_distinct->next_select() (i.e. it is union and last distinct
 
134
      SELECT is last SELECT of UNION).
 
135
    */
 
136
    if ((res= derived_result->create_result_table(thd, &unit->types, FALSE,
 
137
                                                  create_options,
 
138
                                                  orig_table_list->alias,
 
139
                                                  FALSE)))
 
140
      goto exit;
 
141
 
 
142
    table= derived_result->table;
 
143
 
 
144
exit:
 
145
    /*
 
146
      if it is preparation PS only or commands that need only VIEW structure
 
147
      then we do not need real data and we can skip execution (and parameters
 
148
      is not defined, too)
 
149
    */
 
150
    if (res)
 
151
    {
 
152
      if (table)
 
153
        free_tmp_table(thd, table);
 
154
      delete derived_result;
 
155
    }
 
156
    else
 
157
    {
 
158
      if (!thd->fill_derived_tables())
 
159
      {
 
160
        delete derived_result;
 
161
        derived_result= NULL;
 
162
      }
 
163
      orig_table_list->derived_result= derived_result;
 
164
      orig_table_list->table= table;
 
165
      orig_table_list->table_name=        table->s->table_name.str;
 
166
      orig_table_list->table_name_length= table->s->table_name.length;
 
167
      table->derived_select_number= first_select->select_number;
 
168
      table->s->tmp_table= NON_TRANSACTIONAL_TMP_TABLE;
 
169
      orig_table_list->db= (char *)"";
 
170
      orig_table_list->db_length= 0;
 
171
      // Force read of table stats in the optimizer
 
172
      table->file->info(HA_STATUS_VARIABLE);
 
173
      /* Add new temporary table to list of open derived tables */
 
174
      table->next= thd->derived_tables;
 
175
      thd->derived_tables= table;
 
176
    }
 
177
  }
 
178
 
 
179
  DBUG_RETURN(res);
 
180
}
 
181
 
 
182
 
 
183
/*
 
184
  fill derived table
 
185
 
 
186
  SYNOPSIS
 
187
    mysql_derived_filling()
 
188
    thd                 Thread handle
 
189
    lex                 LEX for this thread
 
190
    unit                node that contains all SELECT's for derived tables
 
191
    orig_table_list     TABLE_LIST for the upper SELECT
 
192
 
 
193
  IMPLEMENTATION
 
194
    Derived table is resolved with temporary table. It is created based on the
 
195
    queries defined. After temporary table is filled, if this is not EXPLAIN,
 
196
    then the entire unit / node is deleted. unit is deleted if UNION is used
 
197
    for derived table and node is deleted is it is a  simple SELECT.
 
198
    If you use this function, make sure it's not called at prepare.
 
199
    Due to evaluation of LIMIT clause it can not be used at prepared stage.
 
200
 
 
201
  RETURN
 
202
    FALSE  OK
 
203
    TRUE   Error
 
204
*/
 
205
 
 
206
bool mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
 
207
{
 
208
  TABLE *table= orig_table_list->table;
 
209
  SELECT_LEX_UNIT *unit= orig_table_list->derived;
 
210
  bool res= FALSE;
 
211
 
 
212
  /*check that table creation pass without problem and it is derived table */
 
213
  if (table && unit)
 
214
  {
 
215
    SELECT_LEX *first_select= unit->first_select();
 
216
    select_union *derived_result= orig_table_list->derived_result;
 
217
    SELECT_LEX *save_current_select= lex->current_select;
 
218
    if (unit->is_union())
 
219
    {
 
220
      // execute union without clean up
 
221
      res= unit->exec();
 
222
    }
 
223
    else
 
224
    {
 
225
      unit->set_limit(first_select);
 
226
      if (unit->select_limit_cnt == HA_POS_ERROR)
 
227
        first_select->options&= ~OPTION_FOUND_ROWS;
 
228
 
 
229
      lex->current_select= first_select;
 
230
      res= mysql_select(thd, &first_select->ref_pointer_array,
 
231
                        (TABLE_LIST*) first_select->table_list.first,
 
232
                        first_select->with_wild,
 
233
                        first_select->item_list, first_select->where,
 
234
                        (first_select->order_list.elements+
 
235
                         first_select->group_list.elements),
 
236
                        (ORDER *) first_select->order_list.first,
 
237
                        (ORDER *) first_select->group_list.first,
 
238
                        first_select->having, (ORDER*) NULL,
 
239
                        (first_select->options | thd->options |
 
240
                         SELECT_NO_UNLOCK),
 
241
                        derived_result, unit, first_select);
 
242
    }
 
243
 
 
244
    if (!res)
 
245
    {
 
246
      /*
 
247
        Here we entirely fix both TABLE_LIST and list of SELECT's as
 
248
        there were no derived tables
 
249
      */
 
250
      if (derived_result->flush())
 
251
        res= TRUE;
 
252
 
 
253
      if (!lex->describe)
 
254
        unit->cleanup();
 
255
    }
 
256
    else
 
257
      unit->cleanup();
 
258
    lex->current_select= save_current_select;
 
259
  }
 
260
  return res;
 
261
}