~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_derived.cc

  • Committer: Monty Taylor
  • Date: 2008-08-04 22:01:39 UTC
  • mto: (261.1.4 drizzle)
  • mto: This revision was merged to the branch mainline in revision 262.
  • Revision ID: monty@inaugust.com-20080804220139-fy862jc9lykayvka
Moved libdrizzle.ver.in to libdrizzle.ver.

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