~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/item/ref.cc

move functions from item.cc/item.h to item directory

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