~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/item/ref.cc

  • Committer: Monty Taylor
  • Date: 2008-12-08 01:15:27 UTC
  • mto: This revision was merged to the branch mainline in revision 670.
  • Revision ID: monty@inaugust.com-20081208011527-lq9m47jsmiiqn999
Replaced my hacked up m4/ac_system_extensions.m4 with the one from gnulib.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 
 *
4
 
 *  Copyright (C) 2008 Sun Microsystems
5
 
 *
6
 
 *  This program is free software; you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License as published by
8
 
 *  the Free Software Foundation; version 2 of the License.
9
 
 *
10
 
 *  This program is distributed in the hope that it will be useful,
11
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 *  GNU General Public License for more details.
14
 
 *
15
 
 *  You should have received a copy of the GNU General Public License
16
 
 *  along with this program; if not, write to the Free Software
17
 
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
 
 */
19
 
 
20
 
#include "config.h"
21
 
 
22
 
#include "drizzled/session.h"
23
 
#include "drizzled/error.h"
24
 
#include "drizzled/show.h"
25
 
#include "drizzled/item/ref.h"
26
 
#include "drizzled/plugin/client.h"
27
 
#include "drizzled/item/sum.h"
28
 
 
29
 
namespace drizzled
30
 
{
31
 
 
32
 
Item_ref::Item_ref(Name_resolution_context *context_arg,
33
 
                   Item **item, const char *table_name_arg,
34
 
                   const char *field_name_arg,
35
 
                   bool alias_name_used_arg)
36
 
  :Item_ident(context_arg, NULL, table_name_arg, field_name_arg),
37
 
   result_field(0), ref(item)
38
 
{
39
 
  alias_name_used= alias_name_used_arg;
40
 
  /*
41
 
    This constructor used to create some internals references over fixed items
42
 
  */
43
 
  if (ref && *ref && (*ref)->fixed)
44
 
    set_properties();
45
 
}
46
 
 
47
 
 
48
 
/**
49
 
  Resolve the name of a reference to a column reference.
50
 
 
51
 
  The method resolves the column reference represented by 'this' as a column
52
 
  present in one of: GROUP BY clause, SELECT clause, outer queries. It is
53
 
  used typically for columns in the HAVING clause which are not under
54
 
  aggregate functions.
55
 
 
56
 
  POSTCONDITION @n
57
 
  Item_ref::ref is 0 or points to a valid item.
58
 
 
59
 
  @note
60
 
    The name resolution algorithm used is (where [T_j] is an optional table
61
 
    name that qualifies the column name):
62
 
 
63
 
  @code
64
 
        resolve_extended([T_j].col_ref_i)
65
 
        {
66
 
          Search for a column or derived column named col_ref_i [in table T_j]
67
 
          in the SELECT and GROUP clauses of Q.
68
 
 
69
 
          if such a column is NOT found AND    // Lookup in outer queries.
70
 
             there are outer queries
71
 
          {
72
 
            for each outer query Q_k beginning from the inner-most one
73
 
           {
74
 
              Search for a column or derived column named col_ref_i
75
 
              [in table T_j] in the SELECT and GROUP clauses of Q_k.
76
 
 
77
 
              if such a column is not found AND
78
 
                 - Q_k is not a group query AND
79
 
                 - Q_k is not inside an aggregate function
80
 
                 OR
81
 
                 - Q_(k-1) is not in a HAVING or SELECT clause of Q_k
82
 
              {
83
 
                search for a column or derived column named col_ref_i
84
 
                [in table T_j] in the FROM clause of Q_k;
85
 
              }
86
 
            }
87
 
          }
88
 
        }
89
 
  @endcode
90
 
  @n
91
 
    This procedure treats GROUP BY and SELECT clauses as one namespace for
92
 
    column references in HAVING. Notice that compared to
93
 
    Item_field::fix_fields, here we first search the SELECT and GROUP BY
94
 
    clauses, and then we search the FROM clause.
95
 
 
96
 
  @param[in]     session        current thread
97
 
  @param[in,out] reference  view column if this item was resolved to a
98
 
    view column
99
 
 
100
 
  @todo
101
 
    Here we could first find the field anyway, and then test this
102
 
    condition, so that we can give a better error message -
103
 
    ER_WRONG_FIELD_WITH_GROUP, instead of the less informative
104
 
    ER_BAD_FIELD_ERROR which we produce now.
105
 
 
106
 
  @retval
107
 
    true  if error
108
 
  @retval
109
 
    false on success
110
 
*/
111
 
 
112
 
bool Item_ref::fix_fields(Session *session, Item **reference)
113
 
{
114
 
  enum_parsing_place place= NO_MATTER;
115
 
  assert(fixed == 0);
116
 
  Select_Lex *current_sel= session->lex->current_select;
117
 
 
118
 
  if (!ref || ref == not_found_item)
119
 
  {
120
 
    if (!(ref= resolve_ref_in_select_and_group(session, this,
121
 
                                               context->select_lex)))
122
 
      goto error;             /* Some error occurred (e.g. ambiguous names). */
123
 
 
124
 
    if (ref == not_found_item) /* This reference was not resolved. */
125
 
    {
126
 
      Name_resolution_context *last_checked_context= context;
127
 
      Name_resolution_context *outer_context= context->outer_context;
128
 
      Field *from_field;
129
 
      ref= 0;
130
 
 
131
 
      if (!outer_context)
132
 
      {
133
 
        /* The current reference cannot be resolved in this query. */
134
 
        my_error(ER_BAD_FIELD_ERROR,MYF(0),
135
 
                 this->full_name(), current_session->where);
136
 
        goto error;
137
 
      }
138
 
 
139
 
      /*
140
 
        If there is an outer context (select), and it is not a derived table
141
 
        (which do not support the use of outer fields for now), try to
142
 
        resolve this reference in the outer select(s).
143
 
 
144
 
        We treat each subselect as a separate namespace, so that different
145
 
        subselects may contain columns with the same names. The subselects are
146
 
        searched starting from the innermost.
147
 
      */
148
 
      from_field= (Field*) not_found_field;
149
 
 
150
 
      do
151
 
      {
152
 
        Select_Lex *select= outer_context->select_lex;
153
 
        Item_subselect *prev_subselect_item=
154
 
          last_checked_context->select_lex->master_unit()->item;
155
 
        last_checked_context= outer_context;
156
 
 
157
 
        /* Search in the SELECT and GROUP lists of the outer select. */
158
 
        if (outer_context->resolve_in_select_list)
159
 
        {
160
 
          if (!(ref= resolve_ref_in_select_and_group(session, this, select)))
161
 
            goto error; /* Some error occurred (e.g. ambiguous names). */
162
 
          if (ref != not_found_item)
163
 
          {
164
 
            assert(*ref && (*ref)->fixed);
165
 
            prev_subselect_item->used_tables_cache|= (*ref)->used_tables();
166
 
            prev_subselect_item->const_item_cache&= (*ref)->const_item();
167
 
            break;
168
 
          }
169
 
          /*
170
 
            Set ref to 0 to ensure that we get an error in case we replaced
171
 
            this item with another item and still use this item in some
172
 
            other place of the parse tree.
173
 
          */
174
 
          ref= 0;
175
 
        }
176
 
 
177
 
        place= prev_subselect_item->parsing_place;
178
 
        /*
179
 
          Check table fields only if the subquery is used somewhere out of
180
 
          HAVING or the outer SELECT does not use grouping (i.e. tables are
181
 
          accessible).
182
 
          TODO:
183
 
          Here we could first find the field anyway, and then test this
184
 
          condition, so that we can give a better error message -
185
 
          ER_WRONG_FIELD_WITH_GROUP, instead of the less informative
186
 
          ER_BAD_FIELD_ERROR which we produce now.
187
 
        */
188
 
        if ((place != IN_HAVING ||
189
 
             (!select->with_sum_func &&
190
 
              select->group_list.elements == 0)))
191
 
        {
192
 
          /*
193
 
            In case of view, find_field_in_tables() write pointer to view
194
 
            field expression to 'reference', i.e. it substitute that
195
 
            expression instead of this Item_ref
196
 
          */
197
 
          from_field= find_field_in_tables(session, this,
198
 
                                           outer_context->
199
 
                                             first_name_resolution_table,
200
 
                                           outer_context->
201
 
                                             last_name_resolution_table,
202
 
                                           reference,
203
 
                                           IGNORE_EXCEPT_NON_UNIQUE, true);
204
 
          if (! from_field)
205
 
            goto error;
206
 
          if (from_field == view_ref_found)
207
 
          {
208
 
            Item::Type refer_type= (*reference)->type();
209
 
            prev_subselect_item->used_tables_cache|=
210
 
              (*reference)->used_tables();
211
 
            prev_subselect_item->const_item_cache&=
212
 
              (*reference)->const_item();
213
 
            assert((*reference)->type() == REF_ITEM);
214
 
            mark_as_dependent(session, last_checked_context->select_lex,
215
 
                              context->select_lex, this,
216
 
                              ((refer_type == REF_ITEM ||
217
 
                                refer_type == FIELD_ITEM) ?
218
 
                               (Item_ident*) (*reference) :
219
 
                               0));
220
 
            /*
221
 
              view reference found, we substituted it instead of this
222
 
              Item, so can quit
223
 
            */
224
 
            return false;
225
 
          }
226
 
          if (from_field != not_found_field)
227
 
          {
228
 
            if (cached_table && cached_table->select_lex &&
229
 
                outer_context->select_lex &&
230
 
                cached_table->select_lex != outer_context->select_lex)
231
 
            {
232
 
              /*
233
 
                Due to cache, find_field_in_tables() can return field which
234
 
                doesn't belong to provided outer_context. In this case we have
235
 
                to find proper field context in order to fix field correcly.
236
 
              */
237
 
              do
238
 
              {
239
 
                outer_context= outer_context->outer_context;
240
 
                select= outer_context->select_lex;
241
 
                prev_subselect_item=
242
 
                  last_checked_context->select_lex->master_unit()->item;
243
 
                last_checked_context= outer_context;
244
 
              } while (outer_context && outer_context->select_lex &&
245
 
                       cached_table->select_lex != outer_context->select_lex);
246
 
            }
247
 
            prev_subselect_item->used_tables_cache|= from_field->table->map;
248
 
            prev_subselect_item->const_item_cache= 0;
249
 
            break;
250
 
          }
251
 
        }
252
 
        assert(from_field == not_found_field);
253
 
 
254
 
        /* Reference is not found => depend on outer (or just error). */
255
 
        prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT;
256
 
        prev_subselect_item->const_item_cache= 0;
257
 
 
258
 
        outer_context= outer_context->outer_context;
259
 
      } while (outer_context);
260
 
 
261
 
      assert(from_field != 0 && from_field != view_ref_found);
262
 
      if (from_field != not_found_field)
263
 
      {
264
 
        Item_field* fld;
265
 
        if (!(fld= new Item_field(from_field)))
266
 
          goto error;
267
 
        session->change_item_tree(reference, fld);
268
 
        mark_as_dependent(session, last_checked_context->select_lex,
269
 
                          session->lex->current_select, this, fld);
270
 
        /*
271
 
          A reference is resolved to a nest level that's outer or the same as
272
 
          the nest level of the enclosing set function : adjust the value of
273
 
          max_arg_level for the function if it's needed.
274
 
        */
275
 
        if (session->lex->in_sum_func &&
276
 
            session->lex->in_sum_func->nest_level >=
277
 
            last_checked_context->select_lex->nest_level)
278
 
          set_if_bigger(session->lex->in_sum_func->max_arg_level,
279
 
                        last_checked_context->select_lex->nest_level);
280
 
        return false;
281
 
      }
282
 
      if (ref == 0)
283
 
      {
284
 
        /* The item was not a table field and not a reference */
285
 
        my_error(ER_BAD_FIELD_ERROR, MYF(0),
286
 
                 this->full_name(), current_session->where);
287
 
        goto error;
288
 
      }
289
 
      /* Should be checked in resolve_ref_in_select_and_group(). */
290
 
      assert(*ref && (*ref)->fixed);
291
 
      mark_as_dependent(session, last_checked_context->select_lex,
292
 
                        context->select_lex, this, this);
293
 
      /*
294
 
        A reference is resolved to a nest level that's outer or the same as
295
 
        the nest level of the enclosing set function : adjust the value of
296
 
        max_arg_level for the function if it's needed.
297
 
      */
298
 
      if (session->lex->in_sum_func &&
299
 
          session->lex->in_sum_func->nest_level >=
300
 
          last_checked_context->select_lex->nest_level)
301
 
        set_if_bigger(session->lex->in_sum_func->max_arg_level,
302
 
                      last_checked_context->select_lex->nest_level);
303
 
    }
304
 
  }
305
 
 
306
 
  assert(*ref);
307
 
  /*
308
 
    Check if this is an incorrect reference in a group function or forward
309
 
    reference. Do not issue an error if this is:
310
 
      1. outer reference (will be fixed later by the fix_inner_refs function);
311
 
      2. an unnamed reference inside an aggregate function.
312
 
  */
313
 
  if (!((*ref)->type() == REF_ITEM &&
314
 
       ((Item_ref *)(*ref))->ref_type() == OUTER_REF) &&
315
 
      (((*ref)->with_sum_func && name &&
316
 
        !(current_sel->linkage != GLOBAL_OPTIONS_TYPE &&
317
 
          current_sel->having_fix_field)) ||
318
 
       !(*ref)->fixed))
319
 
  {
320
 
    my_error(ER_ILLEGAL_REFERENCE, MYF(0),
321
 
             name, ((*ref)->with_sum_func?
322
 
                    "reference to group function":
323
 
                    "forward reference in item list"));
324
 
    goto error;
325
 
  }
326
 
 
327
 
  set_properties();
328
 
 
329
 
  if ((*ref)->check_cols(1))
330
 
    goto error;
331
 
  return false;
332
 
 
333
 
error:
334
 
  context->process_error(session);
335
 
  return true;
336
 
}
337
 
 
338
 
 
339
 
void Item_ref::set_properties()
340
 
{
341
 
  max_length= (*ref)->max_length;
342
 
  maybe_null= (*ref)->maybe_null;
343
 
  decimals=   (*ref)->decimals;
344
 
  collation.set((*ref)->collation);
345
 
  /*
346
 
    We have to remember if we refer to a sum function, to ensure that
347
 
    split_sum_func() doesn't try to change the reference.
348
 
  */
349
 
  with_sum_func= (*ref)->with_sum_func;
350
 
  unsigned_flag= (*ref)->unsigned_flag;
351
 
  fixed= 1;
352
 
  if (alias_name_used)
353
 
    return;
354
 
  if ((*ref)->type() == FIELD_ITEM)
355
 
    alias_name_used= ((Item_ident *) (*ref))->alias_name_used;
356
 
  else
357
 
    alias_name_used= true; // it is not field, so it is was resolved by alias
358
 
}
359
 
 
360
 
 
361
 
void Item_ref::cleanup()
362
 
{
363
 
  Item_ident::cleanup();
364
 
  result_field= 0;
365
 
  return;
366
 
}
367
 
 
368
 
 
369
 
void Item_ref::print(String *str, enum_query_type query_type)
370
 
{
371
 
  if (ref)
372
 
  {
373
 
    if ((*ref)->type() != Item::CACHE_ITEM &&
374
 
        !table_name && name && alias_name_used)
375
 
    {
376
 
      str->append_identifier(name, (uint32_t) strlen(name));
377
 
    }
378
 
    else
379
 
      (*ref)->print(str, query_type);
380
 
  }
381
 
  else
382
 
    Item_ident::print(str, query_type);
383
 
}
384
 
 
385
 
 
386
 
bool Item_ref::send(plugin::Client *client, String *tmp)
387
 
{
388
 
  if (result_field)
389
 
    return client->store(result_field);
390
 
  return (*ref)->send(client, tmp);
391
 
}
392
 
 
393
 
 
394
 
double Item_ref::val_result()
395
 
{
396
 
  if (result_field)
397
 
  {
398
 
    if ((null_value= result_field->is_null()))
399
 
      return 0.0;
400
 
    return result_field->val_real();
401
 
  }
402
 
  return val_real();
403
 
}
404
 
 
405
 
 
406
 
int64_t Item_ref::val_int_result()
407
 
{
408
 
  if (result_field)
409
 
  {
410
 
    if ((null_value= result_field->is_null()))
411
 
      return 0;
412
 
    return result_field->val_int();
413
 
  }
414
 
  return val_int();
415
 
}
416
 
 
417
 
 
418
 
String *Item_ref::str_result(String* str)
419
 
{
420
 
  if (result_field)
421
 
  {
422
 
    if ((null_value= result_field->is_null()))
423
 
      return 0;
424
 
    str->set_charset(str_value.charset());
425
 
    return result_field->val_str(str, &str_value);
426
 
  }
427
 
  return val_str(str);
428
 
}
429
 
 
430
 
 
431
 
my_decimal *Item_ref::val_decimal_result(my_decimal *decimal_value)
432
 
{
433
 
  if (result_field)
434
 
  {
435
 
    if ((null_value= result_field->is_null()))
436
 
      return 0;
437
 
    return result_field->val_decimal(decimal_value);
438
 
  }
439
 
  return val_decimal(decimal_value);
440
 
}
441
 
 
442
 
 
443
 
bool Item_ref::val_bool_result()
444
 
{
445
 
  if (result_field)
446
 
  {
447
 
    if ((null_value= result_field->is_null()))
448
 
      return 0;
449
 
    switch (result_field->result_type()) {
450
 
    case INT_RESULT:
451
 
      return result_field->val_int() != 0;
452
 
    case DECIMAL_RESULT:
453
 
    {
454
 
      my_decimal decimal_value;
455
 
      my_decimal *val= result_field->val_decimal(&decimal_value);
456
 
      if (val)
457
 
        return !my_decimal_is_zero(val);
458
 
      return 0;
459
 
    }
460
 
    case REAL_RESULT:
461
 
    case STRING_RESULT:
462
 
      return result_field->val_real() != 0.0;
463
 
    case ROW_RESULT:
464
 
    default:
465
 
      assert(0);
466
 
    }
467
 
  }
468
 
  return val_bool();
469
 
}
470
 
 
471
 
 
472
 
double Item_ref::val_real()
473
 
{
474
 
  assert(fixed);
475
 
  double tmp=(*ref)->val_result();
476
 
  null_value=(*ref)->null_value;
477
 
  return tmp;
478
 
}
479
 
 
480
 
 
481
 
int64_t Item_ref::val_int()
482
 
{
483
 
  assert(fixed);
484
 
  int64_t tmp=(*ref)->val_int_result();
485
 
  null_value=(*ref)->null_value;
486
 
  return tmp;
487
 
}
488
 
 
489
 
 
490
 
bool Item_ref::val_bool()
491
 
{
492
 
  assert(fixed);
493
 
  bool tmp= (*ref)->val_bool_result();
494
 
  null_value= (*ref)->null_value;
495
 
  return tmp;
496
 
}
497
 
 
498
 
 
499
 
String *Item_ref::val_str(String* tmp)
500
 
{
501
 
  assert(fixed);
502
 
  tmp=(*ref)->str_result(tmp);
503
 
  null_value=(*ref)->null_value;
504
 
  return tmp;
505
 
}
506
 
 
507
 
 
508
 
bool Item_ref::is_null()
509
 
{
510
 
  assert(fixed);
511
 
  return (*ref)->is_null();
512
 
}
513
 
 
514
 
 
515
 
bool Item_ref::get_date(DRIZZLE_TIME *ltime,uint32_t fuzzydate)
516
 
{
517
 
  return (null_value=(*ref)->get_date_result(ltime,fuzzydate));
518
 
}
519
 
 
520
 
 
521
 
my_decimal *Item_ref::val_decimal(my_decimal *decimal_value)
522
 
{
523
 
  my_decimal *val= (*ref)->val_decimal_result(decimal_value);
524
 
  null_value= (*ref)->null_value;
525
 
  return val;
526
 
}
527
 
 
528
 
int Item_ref::save_in_field(Field *to, bool no_conversions)
529
 
{
530
 
  int res;
531
 
  assert(!result_field);
532
 
  res= (*ref)->save_in_field(to, no_conversions);
533
 
  null_value= (*ref)->null_value;
534
 
  return res;
535
 
}
536
 
 
537
 
 
538
 
void Item_ref::save_org_in_field(Field *field)
539
 
{
540
 
  (*ref)->save_org_in_field(field);
541
 
}
542
 
 
543
 
 
544
 
void Item_ref::make_field(SendField *field)
545
 
{
546
 
  (*ref)->make_field(field);
547
 
  /* Non-zero in case of a view */
548
 
  if (name)
549
 
    field->col_name= name;
550
 
  if (table_name)
551
 
    field->table_name= table_name;
552
 
  if (db_name)
553
 
    field->db_name= db_name;
554
 
}
555
 
 
556
 
 
557
 
Item *Item_ref::get_tmp_table_item(Session *session)
558
 
{
559
 
  if (!result_field)
560
 
    return (*ref)->get_tmp_table_item(session);
561
 
 
562
 
  Item_field *item= new Item_field(result_field);
563
 
  if (item)
564
 
  {
565
 
    item->table_name= table_name;
566
 
    item->db_name= db_name;
567
 
  }
568
 
  return item;
569
 
}
570
 
 
571
 
void Item_ref::fix_after_pullout(Select_Lex *new_parent, Item **)
572
 
{
573
 
  if (depended_from == new_parent)
574
 
  {
575
 
    (*ref)->fix_after_pullout(new_parent, ref);
576
 
    depended_from= NULL;
577
 
  }
578
 
}
579
 
 
580
 
} /* namespace drizzled */