~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/functions/get_user_var.cc

  • Committer: Monty Taylor
  • Date: 2008-11-16 05:36:13 UTC
  • mto: (584.1.9 devel)
  • mto: This revision was merged to the branch mainline in revision 589.
  • Revision ID: monty@inaugust.com-20081116053613-bld4rqxhlkb49c02
Split out cache_row and type_holder.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
3
 *
4
 
 *  Copyright (C) 2008 Sun Microsystems, Inc.
 
4
 *  Copyright (C) 2008 Sun Microsystems
5
5
 *
6
6
 *  This program is free software; you can redistribute it and/or modify
7
7
 *  it under the terms of the GNU General Public License as published by
17
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
18
 */
19
19
 
20
 
#include "config.h"
21
 
 
22
 
#include <float.h>
23
 
 
24
 
#include <drizzled/function/get_user_var.h>
25
 
#include <drizzled/item/null.h>
 
20
#include <drizzled/server_includes.h>
 
21
#include CSTDINT_H
 
22
#include <drizzled/functions/get_user_var.h>
26
23
#include <drizzled/sql_parse.h>
27
 
#include <drizzled/session.h>
28
 
 
29
 
namespace drizzled
30
 
{
31
 
 
32
 
String *Item_func_get_user_var::val_str(String *str)
 
24
 
 
25
String *
 
26
Item_func_get_user_var::val_str(String *str)
33
27
{
34
28
  assert(fixed == 1);
35
29
  if (!var_entry)
47
41
}
48
42
 
49
43
 
50
 
type::Decimal *Item_func_get_user_var::val_decimal(type::Decimal *dec)
 
44
my_decimal *Item_func_get_user_var::val_decimal(my_decimal *dec)
51
45
{
52
46
  assert(fixed == 1);
53
47
  if (!var_entry)
63
57
  return (var_entry->val_int(&null_value));
64
58
}
65
59
 
 
60
/**
 
61
  Get variable by name and, if necessary, put the record of variable 
 
62
  use into the binary log.
 
63
 
 
64
  When a user variable is invoked from an update query (INSERT, UPDATE etc),
 
65
  stores this variable and its value in session->user_var_events, so that it can be
 
66
  written to the binlog (will be written just before the query is written, see
 
67
  log.cc).
 
68
 
 
69
  @param      session        Current thread
 
70
  @param      name       Variable name
 
71
  @param[out] out_entry  variable structure or NULL. The pointer is set
 
72
                         regardless of whether function succeeded or not.
 
73
 
 
74
  @retval
 
75
    0  OK
 
76
  @retval
 
77
    1  Failed to put appropriate record into binary log
 
78
 
 
79
*/
 
80
 
 
81
int get_var_with_binlog(Session *session, enum_sql_command sql_command,
 
82
                        LEX_STRING &name, user_var_entry **out_entry)
 
83
{
 
84
  BINLOG_USER_VAR_EVENT *user_var_event;
 
85
  user_var_entry *var_entry;
 
86
  var_entry= get_variable(&session->user_vars, name, 0);
 
87
 
 
88
  /*
 
89
    Any reference to user-defined variable which is done from stored
 
90
    function or trigger affects their execution and the execution of the
 
91
    calling statement. We must log all such variables even if they are 
 
92
    not involved in table-updating statements.
 
93
  */
 
94
  if (!(opt_bin_log && is_update_query(sql_command)))
 
95
  {
 
96
    *out_entry= var_entry;
 
97
    return 0;
 
98
  }
 
99
 
 
100
  if (!var_entry)
 
101
  {
 
102
    /*
 
103
      If the variable does not exist, it's NULL, but we want to create it so
 
104
      that it gets into the binlog (if it didn't, the slave could be
 
105
      influenced by a variable of the same name previously set by another
 
106
      thread).
 
107
      We create it like if it had been explicitly set with SET before.
 
108
      The 'new' mimics what sql_yacc.yy does when 'SET @a=10;'.
 
109
      sql_set_variables() is what is called from 'case SQLCOM_SET_OPTION'
 
110
      in dispatch_command()). Instead of building a one-element list to pass to
 
111
      sql_set_variables(), we could instead manually call check() and update();
 
112
      this would save memory and time; but calling sql_set_variables() makes
 
113
      one unique place to maintain (sql_set_variables()). 
 
114
 
 
115
      Manipulation with lex is necessary since free_underlaid_joins
 
116
      is going to release memory belonging to the main query.
 
117
    */
 
118
 
 
119
    List<set_var_base> tmp_var_list;
 
120
    LEX *sav_lex= session->lex, lex_tmp;
 
121
    session->lex= &lex_tmp;
 
122
    lex_start(session);
 
123
    tmp_var_list.push_back(new set_var_user(new Item_func_set_user_var(name,
 
124
                                                                       new Item_null())));
 
125
    /* Create the variable */
 
126
    if (sql_set_variables(session, &tmp_var_list))
 
127
    {
 
128
      session->lex= sav_lex;
 
129
      goto err;
 
130
    }
 
131
    session->lex= sav_lex;
 
132
    if (!(var_entry= get_variable(&session->user_vars, name, 0)))
 
133
      goto err;
 
134
  }
 
135
  else if (var_entry->used_query_id == session->query_id ||
 
136
           mysql_bin_log.is_query_in_union(session, var_entry->used_query_id))
 
137
  {
 
138
    /* 
 
139
       If this variable was already stored in user_var_events by this query
 
140
       (because it's used in more than one place in the query), don't store
 
141
       it.
 
142
    */
 
143
    *out_entry= var_entry;
 
144
    return 0;
 
145
  }
 
146
 
 
147
  uint32_t size;
 
148
  /*
 
149
    First we need to store value of var_entry, when the next situation
 
150
    appears:
 
151
    > set @a:=1;
 
152
    > insert into t1 values (@a), (@a:=@a+1), (@a:=@a+1);
 
153
    We have to write to binlog value @a= 1.
 
154
 
 
155
    We allocate the user_var_event on user_var_events_alloc pool, not on
 
156
    the this-statement-execution pool because in SPs user_var_event objects 
 
157
    may need to be valid after current [SP] statement execution pool is
 
158
    destroyed.
 
159
  */
 
160
  size= ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT)) + var_entry->length;
 
161
  if (!(user_var_event= (BINLOG_USER_VAR_EVENT *)
 
162
        alloc_root(session->user_var_events_alloc, size)))
 
163
    goto err;
 
164
 
 
165
  user_var_event->value= (char*) user_var_event +
 
166
    ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT));
 
167
  user_var_event->user_var_event= var_entry;
 
168
  user_var_event->type= var_entry->type;
 
169
  user_var_event->charset_number= var_entry->collation.collation->number;
 
170
  if (!var_entry->value)
 
171
  {
 
172
    /* NULL value*/
 
173
    user_var_event->length= 0;
 
174
    user_var_event->value= 0;
 
175
  }
 
176
  else
 
177
  {
 
178
    user_var_event->length= var_entry->length;
 
179
    memcpy(user_var_event->value, var_entry->value,
 
180
           var_entry->length);
 
181
  }
 
182
  /* Mark that this variable has been used by this query */
 
183
  var_entry->used_query_id= session->query_id;
 
184
  if (insert_dynamic(&session->user_var_events, (unsigned char*) &user_var_event))
 
185
    goto err;
 
186
 
 
187
  *out_entry= var_entry;
 
188
  return 0;
 
189
 
 
190
err:
 
191
  *out_entry= var_entry;
 
192
  return 1;
 
193
}
 
194
 
66
195
void Item_func_get_user_var::fix_length_and_dec()
67
196
{
 
197
  Session *session=current_session;
 
198
  int error;
68
199
  maybe_null=1;
69
200
  decimals=NOT_FIXED_DEC;
70
201
  max_length=MAX_BLOB_WIDTH;
71
202
 
72
 
  var_entry= session.getVariable(name, false);
 
203
  error= get_var_with_binlog(session, session->lex->sql_command, name, &var_entry);
73
204
 
74
205
  /*
75
206
    If the variable didn't exist it has been created as a STRING-type.
83
214
    max_length= var_entry->length;
84
215
 
85
216
    collation.set(var_entry->collation);
86
 
    switch(m_cached_result_type) 
87
 
    {
 
217
    switch(m_cached_result_type) {
88
218
    case REAL_RESULT:
89
219
      max_length= DBL_DIG + 8;
90
220
      break;
91
 
 
92
221
    case INT_RESULT:
93
222
      max_length= MAX_BIGINT_WIDTH;
94
223
      decimals=0;
96
225
    case STRING_RESULT:
97
226
      max_length= MAX_BLOB_WIDTH;
98
227
      break;
99
 
 
100
228
    case DECIMAL_RESULT:
101
229
      max_length= DECIMAL_MAX_STR_LENGTH;
102
230
      decimals= DECIMAL_MAX_SCALE;
103
231
      break;
104
 
 
105
232
    case ROW_RESULT:                            // Keep compiler happy
 
233
    default:
106
234
      assert(0);
107
235
      break;
108
236
    }
119
247
 
120
248
bool Item_func_get_user_var::const_item() const
121
249
{
122
 
  return (!var_entry || session.getQueryId() != var_entry->update_query_id);
 
250
  return (!var_entry || current_session->query_id != var_entry->update_query_id);
123
251
}
124
252
 
125
253
 
130
258
 
131
259
 
132
260
void Item_func_get_user_var::print(String *str,
133
 
                                   enum_query_type )
 
261
                                   enum_query_type query_type __attribute__((unused)))
134
262
{
135
263
  str->append(STRING_WITH_LEN("(@"));
136
264
  str->append(name.str,name.length);
139
267
 
140
268
 
141
269
bool Item_func_get_user_var::eq(const Item *item,
142
 
                                bool ) const
 
270
                                bool binary_cmp __attribute__((unused))) const
143
271
{
144
272
  /* Assume we don't have rtti */
145
273
  if (this == item)
152
280
  return (name.length == other->name.length &&
153
281
          !memcmp(name.str, other->name.str, name.length));
154
282
}
155
 
 
156
 
} /* namespace drizzled */