~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-07 00:15:51 UTC
  • mto: This revision was merged to the branch mainline in revision 579.
  • Revision ID: monty@inaugust.com-20081107001551-8vxb6sf1ti0i5p09
Cleaned up some headers for PCH.

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