~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/function/get_user_var.cc

Fix merge issues with 1.0 CC fix.

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