~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/function/get_user_var.cc

Merged from Toru - removal of my_time_t.

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
 
 
 
20
#include <drizzled/server_includes.h>
 
21
#include CSTDINT_H
24
22
#include <drizzled/function/get_user_var.h>
 
23
#include <drizzled/function/get_variable.h>
25
24
#include <drizzled/item/null.h>
26
25
#include <drizzled/sql_parse.h>
27
26
#include <drizzled/session.h>
28
 
#include <drizzled/user_var_entry.h>
29
 
 
30
 
namespace drizzled
31
 
{
32
 
 
33
 
String *Item_func_get_user_var::val_str(String *str)
 
27
 
 
28
String *
 
29
Item_func_get_user_var::val_str(String *str)
34
30
{
35
31
  assert(fixed == 1);
36
32
  if (!var_entry)
48
44
}
49
45
 
50
46
 
51
 
type::Decimal *Item_func_get_user_var::val_decimal(type::Decimal *dec)
 
47
my_decimal *Item_func_get_user_var::val_decimal(my_decimal *dec)
52
48
{
53
49
  assert(fixed == 1);
54
50
  if (!var_entry)
64
60
  return (var_entry->val_int(&null_value));
65
61
}
66
62
 
 
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
 
67
198
void Item_func_get_user_var::fix_length_and_dec()
68
199
{
 
200
  Session *session=current_session;
 
201
  int error;
69
202
  maybe_null=1;
70
203
  decimals=NOT_FIXED_DEC;
71
204
  max_length=MAX_BLOB_WIDTH;
72
205
 
73
 
  var_entry= session.getVariable(name, false);
 
206
  error= get_var_with_binlog(session, session->lex->sql_command, name, &var_entry);
74
207
 
75
208
  /*
76
209
    If the variable didn't exist it has been created as a STRING-type.
84
217
    max_length= var_entry->length;
85
218
 
86
219
    collation.set(var_entry->collation);
87
 
    switch(m_cached_result_type) 
88
 
    {
 
220
    switch(m_cached_result_type) {
89
221
    case REAL_RESULT:
90
222
      max_length= DBL_DIG + 8;
91
223
      break;
92
 
 
93
224
    case INT_RESULT:
94
225
      max_length= MAX_BIGINT_WIDTH;
95
226
      decimals=0;
97
228
    case STRING_RESULT:
98
229
      max_length= MAX_BLOB_WIDTH;
99
230
      break;
100
 
 
101
231
    case DECIMAL_RESULT:
102
232
      max_length= DECIMAL_MAX_STR_LENGTH;
103
233
      decimals= DECIMAL_MAX_SCALE;
104
234
      break;
105
 
 
106
235
    case ROW_RESULT:                            // Keep compiler happy
 
236
    default:
107
237
      assert(0);
108
238
      break;
109
239
    }
120
250
 
121
251
bool Item_func_get_user_var::const_item() const
122
252
{
123
 
  return (!var_entry || session.getQueryId() != var_entry->update_query_id);
 
253
  return (!var_entry || current_session->query_id != var_entry->update_query_id);
124
254
}
125
255
 
126
256
 
131
261
 
132
262
 
133
263
void Item_func_get_user_var::print(String *str,
134
 
                                   enum_query_type )
 
264
                                   enum_query_type query_type __attribute__((unused)))
135
265
{
136
266
  str->append(STRING_WITH_LEN("(@"));
137
267
  str->append(name.str,name.length);
140
270
 
141
271
 
142
272
bool Item_func_get_user_var::eq(const Item *item,
143
 
                                bool ) const
 
273
                                bool binary_cmp __attribute__((unused))) const
144
274
{
145
275
  /* Assume we don't have rtti */
146
276
  if (this == item)
153
283
  return (name.length == other->name.length &&
154
284
          !memcmp(name.str, other->name.str, name.length));
155
285
}
156
 
 
157
 
} /* namespace drizzled */