~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/item/ref.cc

  • Committer: Brian Aker
  • Date: 2008-07-08 16:17:31 UTC
  • Revision ID: brian@tangent.org-20080708161731-io36j7igglok79py
DATE cleanup.

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
 
          @todo determine if this is valid.
189
 
        */
190
 
        if ((place != IN_HAVING ||
191
 
             (!select->with_sum_func &&
192
 
              select->group_list.elements == 0)))
193
 
        {
194
 
          /*
195
 
            In case of view, find_field_in_tables() write pointer to view
196
 
            field expression to 'reference', i.e. it substitute that
197
 
            expression instead of this Item_ref
198
 
          */
199
 
          from_field= find_field_in_tables(session, this,
200
 
                                           outer_context->
201
 
                                             first_name_resolution_table,
202
 
                                           outer_context->
203
 
                                             last_name_resolution_table,
204
 
                                           reference,
205
 
                                           IGNORE_EXCEPT_NON_UNIQUE, true);
206
 
          if (! from_field)
207
 
            goto error;
208
 
          if (from_field == view_ref_found)
209
 
          {
210
 
            Item::Type refer_type= (*reference)->type();
211
 
            prev_subselect_item->used_tables_cache|=
212
 
              (*reference)->used_tables();
213
 
            prev_subselect_item->const_item_cache&=
214
 
              (*reference)->const_item();
215
 
            assert((*reference)->type() == REF_ITEM);
216
 
            mark_as_dependent(session, last_checked_context->select_lex,
217
 
                              context->select_lex, this,
218
 
                              ((refer_type == REF_ITEM ||
219
 
                                refer_type == FIELD_ITEM) ?
220
 
                               (Item_ident*) (*reference) :
221
 
                               0));
222
 
            /*
223
 
              view reference found, we substituted it instead of this
224
 
              Item, so can quit
225
 
            */
226
 
            return false;
227
 
          }
228
 
          if (from_field != not_found_field)
229
 
          {
230
 
            if (cached_table && cached_table->select_lex &&
231
 
                outer_context->select_lex &&
232
 
                cached_table->select_lex != outer_context->select_lex)
233
 
            {
234
 
              /*
235
 
                Due to cache, find_field_in_tables() can return field which
236
 
                doesn't belong to provided outer_context. In this case we have
237
 
                to find proper field context in order to fix field correcly.
238
 
              */
239
 
              do
240
 
              {
241
 
                outer_context= outer_context->outer_context;
242
 
                select= outer_context->select_lex;
243
 
                prev_subselect_item=
244
 
                  last_checked_context->select_lex->master_unit()->item;
245
 
                last_checked_context= outer_context;
246
 
              } while (outer_context && outer_context->select_lex &&
247
 
                       cached_table->select_lex != outer_context->select_lex);
248
 
            }
249
 
            prev_subselect_item->used_tables_cache|= from_field->getTable()->map;
250
 
            prev_subselect_item->const_item_cache= 0;
251
 
            break;
252
 
          }
253
 
        }
254
 
        assert(from_field == not_found_field);
255
 
 
256
 
        /* Reference is not found => depend on outer (or just error). */
257
 
        prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT;
258
 
        prev_subselect_item->const_item_cache= 0;
259
 
 
260
 
        outer_context= outer_context->outer_context;
261
 
      } while (outer_context);
262
 
 
263
 
      assert(from_field != 0 && from_field != view_ref_found);
264
 
      if (from_field != not_found_field)
265
 
      {
266
 
        Item_field* fld;
267
 
        if (!(fld= new Item_field(from_field)))
268
 
          goto error;
269
 
        session->change_item_tree(reference, fld);
270
 
        mark_as_dependent(session, last_checked_context->select_lex,
271
 
                          session->lex->current_select, this, fld);
272
 
        /*
273
 
          A reference is resolved to a nest level that's outer or the same as
274
 
          the nest level of the enclosing set function : adjust the value of
275
 
          max_arg_level for the function if it's needed.
276
 
        */
277
 
        if (session->lex->in_sum_func &&
278
 
            session->lex->in_sum_func->nest_level >=
279
 
            last_checked_context->select_lex->nest_level)
280
 
          set_if_bigger(session->lex->in_sum_func->max_arg_level,
281
 
                        last_checked_context->select_lex->nest_level);
282
 
        return false;
283
 
      }
284
 
      if (ref == 0)
285
 
      {
286
 
        /* The item was not a table field and not a reference */
287
 
        my_error(ER_BAD_FIELD_ERROR, MYF(0),
288
 
                 this->full_name(), current_session->where);
289
 
        goto error;
290
 
      }
291
 
      /* Should be checked in resolve_ref_in_select_and_group(). */
292
 
      assert(*ref && (*ref)->fixed);
293
 
      mark_as_dependent(session, last_checked_context->select_lex,
294
 
                        context->select_lex, this, this);
295
 
      /*
296
 
        A reference is resolved to a nest level that's outer or the same as
297
 
        the nest level of the enclosing set function : adjust the value of
298
 
        max_arg_level for the function if it's needed.
299
 
      */
300
 
      if (session->lex->in_sum_func &&
301
 
          session->lex->in_sum_func->nest_level >=
302
 
          last_checked_context->select_lex->nest_level)
303
 
        set_if_bigger(session->lex->in_sum_func->max_arg_level,
304
 
                      last_checked_context->select_lex->nest_level);
305
 
    }
306
 
  }
307
 
 
308
 
  assert(*ref);
309
 
  /*
310
 
    Check if this is an incorrect reference in a group function or forward
311
 
    reference. Do not issue an error if this is:
312
 
      1. outer reference (will be fixed later by the fix_inner_refs function);
313
 
      2. an unnamed reference inside an aggregate function.
314
 
  */
315
 
  if (!((*ref)->type() == REF_ITEM &&
316
 
       ((Item_ref *)(*ref))->ref_type() == OUTER_REF) &&
317
 
      (((*ref)->with_sum_func && name &&
318
 
        !(current_sel->linkage != GLOBAL_OPTIONS_TYPE &&
319
 
          current_sel->having_fix_field)) ||
320
 
       !(*ref)->fixed))
321
 
  {
322
 
    my_error(ER_ILLEGAL_REFERENCE, MYF(0),
323
 
             name, ((*ref)->with_sum_func?
324
 
                    "reference to group function":
325
 
                    "forward reference in item list"));
326
 
    goto error;
327
 
  }
328
 
 
329
 
  set_properties();
330
 
 
331
 
  if ((*ref)->check_cols(1))
332
 
    goto error;
333
 
  return false;
334
 
 
335
 
error:
336
 
  context->process_error(session);
337
 
  return true;
338
 
}
339
 
 
340
 
 
341
 
void Item_ref::set_properties()
342
 
{
343
 
  max_length= (*ref)->max_length;
344
 
  maybe_null= (*ref)->maybe_null;
345
 
  decimals=   (*ref)->decimals;
346
 
  collation.set((*ref)->collation);
347
 
  /*
348
 
    We have to remember if we refer to a sum function, to ensure that
349
 
    split_sum_func() doesn't try to change the reference.
350
 
  */
351
 
  with_sum_func= (*ref)->with_sum_func;
352
 
  unsigned_flag= (*ref)->unsigned_flag;
353
 
  fixed= 1;
354
 
  if (alias_name_used)
355
 
    return;
356
 
  if ((*ref)->type() == FIELD_ITEM)
357
 
    alias_name_used= ((Item_ident *) (*ref))->alias_name_used;
358
 
  else
359
 
    alias_name_used= true; // it is not field, so it is was resolved by alias
360
 
}
361
 
 
362
 
 
363
 
void Item_ref::cleanup()
364
 
{
365
 
  Item_ident::cleanup();
366
 
  result_field= 0;
367
 
  return;
368
 
}
369
 
 
370
 
 
371
 
void Item_ref::print(String *str, enum_query_type query_type)
372
 
{
373
 
  if (ref)
374
 
  {
375
 
    if ((*ref)->type() != Item::CACHE_ITEM &&
376
 
        !table_name && name && alias_name_used)
377
 
    {
378
 
      str->append_identifier(name, (uint32_t) strlen(name));
379
 
    }
380
 
    else
381
 
      (*ref)->print(str, query_type);
382
 
  }
383
 
  else
384
 
    Item_ident::print(str, query_type);
385
 
}
386
 
 
387
 
 
388
 
bool Item_ref::send(plugin::Client *client, String *tmp)
389
 
{
390
 
  if (result_field)
391
 
    return client->store(result_field);
392
 
  return (*ref)->send(client, tmp);
393
 
}
394
 
 
395
 
 
396
 
double Item_ref::val_result()
397
 
{
398
 
  if (result_field)
399
 
  {
400
 
    if ((null_value= result_field->is_null()))
401
 
      return 0.0;
402
 
    return result_field->val_real();
403
 
  }
404
 
  return val_real();
405
 
}
406
 
 
407
 
 
408
 
int64_t Item_ref::val_int_result()
409
 
{
410
 
  if (result_field)
411
 
  {
412
 
    if ((null_value= result_field->is_null()))
413
 
      return 0;
414
 
    return result_field->val_int();
415
 
  }
416
 
  return val_int();
417
 
}
418
 
 
419
 
 
420
 
String *Item_ref::str_result(String* str)
421
 
{
422
 
  if (result_field)
423
 
  {
424
 
    if ((null_value= result_field->is_null()))
425
 
      return 0;
426
 
    str->set_charset(str_value.charset());
427
 
    return result_field->val_str(str, &str_value);
428
 
  }
429
 
  return val_str(str);
430
 
}
431
 
 
432
 
 
433
 
my_decimal *Item_ref::val_decimal_result(my_decimal *decimal_value)
434
 
{
435
 
  if (result_field)
436
 
  {
437
 
    if ((null_value= result_field->is_null()))
438
 
      return 0;
439
 
    return result_field->val_decimal(decimal_value);
440
 
  }
441
 
  return val_decimal(decimal_value);
442
 
}
443
 
 
444
 
 
445
 
bool Item_ref::val_bool_result()
446
 
{
447
 
  if (result_field)
448
 
  {
449
 
    if ((null_value= result_field->is_null()))
450
 
      return 0;
451
 
    switch (result_field->result_type()) {
452
 
    case INT_RESULT:
453
 
      return result_field->val_int() != 0;
454
 
    case DECIMAL_RESULT:
455
 
    {
456
 
      my_decimal decimal_value;
457
 
      my_decimal *val= result_field->val_decimal(&decimal_value);
458
 
      if (val)
459
 
        return !my_decimal_is_zero(val);
460
 
      return 0;
461
 
    }
462
 
    case REAL_RESULT:
463
 
    case STRING_RESULT:
464
 
      return result_field->val_real() != 0.0;
465
 
    case ROW_RESULT:
466
 
    default:
467
 
      assert(0);
468
 
    }
469
 
  }
470
 
  return val_bool();
471
 
}
472
 
 
473
 
 
474
 
double Item_ref::val_real()
475
 
{
476
 
  assert(fixed);
477
 
  double tmp=(*ref)->val_result();
478
 
  null_value=(*ref)->null_value;
479
 
  return tmp;
480
 
}
481
 
 
482
 
 
483
 
int64_t Item_ref::val_int()
484
 
{
485
 
  assert(fixed);
486
 
  int64_t tmp=(*ref)->val_int_result();
487
 
  null_value=(*ref)->null_value;
488
 
  return tmp;
489
 
}
490
 
 
491
 
 
492
 
bool Item_ref::val_bool()
493
 
{
494
 
  assert(fixed);
495
 
  bool tmp= (*ref)->val_bool_result();
496
 
  null_value= (*ref)->null_value;
497
 
  return tmp;
498
 
}
499
 
 
500
 
 
501
 
String *Item_ref::val_str(String* tmp)
502
 
{
503
 
  assert(fixed);
504
 
  tmp=(*ref)->str_result(tmp);
505
 
  null_value=(*ref)->null_value;
506
 
  return tmp;
507
 
}
508
 
 
509
 
 
510
 
bool Item_ref::is_null()
511
 
{
512
 
  assert(fixed);
513
 
  return (*ref)->is_null();
514
 
}
515
 
 
516
 
 
517
 
bool Item_ref::get_date(DRIZZLE_TIME *ltime,uint32_t fuzzydate)
518
 
{
519
 
  return (null_value=(*ref)->get_date_result(ltime,fuzzydate));
520
 
}
521
 
 
522
 
 
523
 
my_decimal *Item_ref::val_decimal(my_decimal *decimal_value)
524
 
{
525
 
  my_decimal *val= (*ref)->val_decimal_result(decimal_value);
526
 
  null_value= (*ref)->null_value;
527
 
  return val;
528
 
}
529
 
 
530
 
int Item_ref::save_in_field(Field *to, bool no_conversions)
531
 
{
532
 
  int res;
533
 
  assert(!result_field);
534
 
  res= (*ref)->save_in_field(to, no_conversions);
535
 
  null_value= (*ref)->null_value;
536
 
  return res;
537
 
}
538
 
 
539
 
 
540
 
void Item_ref::save_org_in_field(Field *field)
541
 
{
542
 
  (*ref)->save_org_in_field(field);
543
 
}
544
 
 
545
 
 
546
 
void Item_ref::make_field(SendField *field)
547
 
{
548
 
  (*ref)->make_field(field);
549
 
  /* Non-zero in case of a view */
550
 
  if (name)
551
 
    field->col_name= name;
552
 
  if (table_name)
553
 
    field->table_name= table_name;
554
 
  if (db_name)
555
 
    field->db_name= db_name;
556
 
}
557
 
 
558
 
 
559
 
Item *Item_ref::get_tmp_table_item(Session *session)
560
 
{
561
 
  if (!result_field)
562
 
    return (*ref)->get_tmp_table_item(session);
563
 
 
564
 
  Item_field *item= new Item_field(result_field);
565
 
  if (item)
566
 
  {
567
 
    item->table_name= table_name;
568
 
    item->db_name= db_name;
569
 
  }
570
 
  return item;
571
 
}
572
 
 
573
 
void Item_ref::fix_after_pullout(Select_Lex *new_parent, Item **)
574
 
{
575
 
  if (depended_from == new_parent)
576
 
  {
577
 
    (*ref)->fix_after_pullout(new_parent, ref);
578
 
    depended_from= NULL;
579
 
  }
580
 
}
581
 
 
582
 
} /* namespace drizzled */