~drizzle-trunk/drizzle/development

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