~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/function/get_user_var.cc

Merged Nathan from lp:~nlws/drizzle/fix-string-c-ptr-overrun

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 
20
20
#include <drizzled/server_includes.h>
21
21
#include CSTDINT_H
22
 
#include <drizzled/functions/get_user_var.h>
23
 
#include <drizzled/functions/get_variable.h>
 
22
#include <drizzled/function/get_user_var.h>
 
23
#include <drizzled/item/null.h>
24
24
#include <drizzled/sql_parse.h>
25
25
#include <drizzled/session.h>
26
26
 
59
59
  return (var_entry->val_int(&null_value));
60
60
}
61
61
 
62
 
/**
63
 
  Get variable by name and, if necessary, put the record of variable 
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
 
 
83
 
int get_var_with_binlog(Session *session, enum_sql_command sql_command,
84
 
                        LEX_STRING &name, user_var_entry **out_entry)
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
93
 
    calling statement. We must log all such variables even if they are 
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
115
 
      one unique place to maintain (sql_set_variables()). 
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 ||
138
 
           drizzle_bin_log.is_query_in_union(session, var_entry->used_query_id))
139
 
  {
140
 
    /* 
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
158
 
    the this-statement-execution pool because in SPs user_var_event objects 
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
62
void Item_func_get_user_var::fix_length_and_dec()
198
63
{
199
64
  Session *session=current_session;
200
 
  int error;
201
65
  maybe_null=1;
202
66
  decimals=NOT_FIXED_DEC;
203
67
  max_length=MAX_BLOB_WIDTH;
204
68
 
205
 
  error= get_var_with_binlog(session, session->lex->sql_command, name, &var_entry);
 
69
  var_entry= session->getVariable(name, false);
206
70
 
207
71
  /*
208
72
    If the variable didn't exist it has been created as a STRING-type.
216
80
    max_length= var_entry->length;
217
81
 
218
82
    collation.set(var_entry->collation);
219
 
    switch(m_cached_result_type) {
 
83
    switch(m_cached_result_type) 
 
84
    {
220
85
    case REAL_RESULT:
221
86
      max_length= DBL_DIG + 8;
222
87
      break;
260
125
 
261
126
 
262
127
void Item_func_get_user_var::print(String *str,
263
 
                                   enum_query_type query_type __attribute__((unused)))
 
128
                                   enum_query_type )
264
129
{
265
130
  str->append(STRING_WITH_LEN("(@"));
266
131
  str->append(name.str,name.length);
269
134
 
270
135
 
271
136
bool Item_func_get_user_var::eq(const Item *item,
272
 
                                bool binary_cmp __attribute__((unused))) const
 
137
                                bool ) const
273
138
{
274
139
  /* Assume we don't have rtti */
275
140
  if (this == item)