~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/functions/get_user_var.cc

  • Committer: Lee
  • Date: 2008-10-29 02:36:17 UTC
  • mto: (520.4.23 devel) (572.1.2 devel)
  • mto: This revision was merged to the branch mainline in revision 567.
  • Revision ID: lbieber@lbieber-desktop-20081029023617-xiowtwsurvdu6ids
more changes to move functions from item_func.cc/h to the functions 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/functions/get_user_var.h>
 
23
 
 
24
String *
 
25
Item_func_get_user_var::val_str(String *str)
 
26
{
 
27
  assert(fixed == 1);
 
28
  if (!var_entry)
 
29
    return((String*) 0);                        // No such variable
 
30
  return(var_entry->val_str(&null_value, str, decimals));
 
31
}
 
32
 
 
33
 
 
34
double Item_func_get_user_var::val_real()
 
35
{
 
36
  assert(fixed == 1);
 
37
  if (!var_entry)
 
38
    return 0.0;                                 // No such variable
 
39
  return (var_entry->val_real(&null_value));
 
40
}
 
41
 
 
42
 
 
43
my_decimal *Item_func_get_user_var::val_decimal(my_decimal *dec)
 
44
{
 
45
  assert(fixed == 1);
 
46
  if (!var_entry)
 
47
    return 0;
 
48
  return var_entry->val_decimal(&null_value, dec);
 
49
}
 
50
 
 
51
int64_t Item_func_get_user_var::val_int()
 
52
{
 
53
  assert(fixed == 1);
 
54
  if (!var_entry)
 
55
    return 0L;                          // No such variable
 
56
  return (var_entry->val_int(&null_value));
 
57
}
 
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
 
 
194
void Item_func_get_user_var::fix_length_and_dec()
 
195
{
 
196
  Session *session=current_session;
 
197
  int error;
 
198
  maybe_null=1;
 
199
  decimals=NOT_FIXED_DEC;
 
200
  max_length=MAX_BLOB_WIDTH;
 
201
 
 
202
  error= get_var_with_binlog(session, session->lex->sql_command, name, &var_entry);
 
203
 
 
204
  /*
 
205
    If the variable didn't exist it has been created as a STRING-type.
 
206
    'var_entry' is NULL only if there occured an error during the call to
 
207
    get_var_with_binlog.
 
208
  */
 
209
  if (var_entry)
 
210
  {
 
211
    m_cached_result_type= var_entry->type;
 
212
    unsigned_flag= var_entry->unsigned_flag;
 
213
    max_length= var_entry->length;
 
214
 
 
215
    collation.set(var_entry->collation);
 
216
    switch(m_cached_result_type) {
 
217
    case REAL_RESULT:
 
218
      max_length= DBL_DIG + 8;
 
219
      break;
 
220
    case INT_RESULT:
 
221
      max_length= MAX_BIGINT_WIDTH;
 
222
      decimals=0;
 
223
      break;
 
224
    case STRING_RESULT:
 
225
      max_length= MAX_BLOB_WIDTH;
 
226
      break;
 
227
    case DECIMAL_RESULT:
 
228
      max_length= DECIMAL_MAX_STR_LENGTH;
 
229
      decimals= DECIMAL_MAX_SCALE;
 
230
      break;
 
231
    case ROW_RESULT:                            // Keep compiler happy
 
232
    default:
 
233
      assert(0);
 
234
      break;
 
235
    }
 
236
  }
 
237
  else
 
238
  {
 
239
    collation.set(&my_charset_bin, DERIVATION_IMPLICIT);
 
240
    null_value= 1;
 
241
    m_cached_result_type= STRING_RESULT;
 
242
    max_length= MAX_BLOB_WIDTH;
 
243
  }
 
244
}
 
245
 
 
246
 
 
247
bool Item_func_get_user_var::const_item() const
 
248
{
 
249
  return (!var_entry || current_session->query_id != var_entry->update_query_id);
 
250
}
 
251
 
 
252
 
 
253
enum Item_result Item_func_get_user_var::result_type() const
 
254
{
 
255
  return m_cached_result_type;
 
256
}
 
257
 
 
258
 
 
259
void Item_func_get_user_var::print(String *str,
 
260
                                   enum_query_type query_type __attribute__((unused)))
 
261
{
 
262
  str->append(STRING_WITH_LEN("(@"));
 
263
  str->append(name.str,name.length);
 
264
  str->append(')');
 
265
}
 
266
 
 
267
 
 
268
bool Item_func_get_user_var::eq(const Item *item,
 
269
                                bool binary_cmp __attribute__((unused))) const
 
270
{
 
271
  /* Assume we don't have rtti */
 
272
  if (this == item)
 
273
    return 1;                                   // Same item is same.
 
274
  /* Check if other type is also a get_user_var() object */
 
275
  if (item->type() != FUNC_ITEM ||
 
276
      ((Item_func*) item)->functype() != functype())
 
277
    return 0;
 
278
  Item_func_get_user_var *other=(Item_func_get_user_var*) item;
 
279
  return (name.length == other->name.length &&
 
280
          !memcmp(name.str, other->name.str, name.length));
 
281
}