~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/log.cc

  • Committer: Jay Pipes
  • Date: 2009-01-30 04:01:12 UTC
  • mto: This revision was merged to the branch mainline in revision 830.
  • Revision ID: jpipes@serialcoder-20090130040112-svbn774guj98pwi4
To remain in compatibility with MySQL, added ability to interpret
decimal arguments as datetime strings for temporal functions.

Fixed YEAR(), MONTH(), DAYOFMONTH(), DAYOFYEAR(), HOUR(), MINUTE(), SECOND(), and MICROSECOND()
to accept decimal parameters and interpret them the same way as MySQL.

Fixed an issue with the TemporalFormat::matches() method which was 
incorrectly assuming all microsecond arguments were specified as 6 digits.
Added power of 10 multiplier to usecond calculation. This fixes issues with
failures in type_date and func_sapdb test cases.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000-2003 MySQL AB
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
 
 
17
/**
 
18
  @file
 
19
 
 
20
  @brief
 
21
  logging of commands
 
22
 
 
23
  @todo
 
24
    Abort logging when we get an error in reading or writing log files
 
25
*/
 
26
 
 
27
#include <drizzled/server_includes.h>
 
28
#include <libdrizzle/libdrizzle.h>
 
29
#include <drizzled/replicator.h>
 
30
#include <mysys/hash.h>
 
31
 
 
32
#include <mysys/my_dir.h>
 
33
#include <stdarg.h>
 
34
 
 
35
#include <drizzled/plugin.h>
 
36
#include <drizzled/error.h>
 
37
#include <drizzled/errmsg_print.h>
 
38
#include <drizzled/gettext.h>
 
39
#include <drizzled/data_home.h>
 
40
#include <drizzled/session.h>
 
41
#include <drizzled/handler.h>
 
42
 
 
43
/* max size of the log message */
 
44
#define MY_OFF_T_UNDEF (~(my_off_t)0UL)
 
45
 
 
46
static int binlog_init(void *p);
 
47
static int binlog_close_connection(handlerton *hton, Session *session);
 
48
static int binlog_savepoint_set(handlerton *hton, Session *session, void *sv);
 
49
static int binlog_savepoint_rollback(handlerton *hton, Session *session, void *sv);
 
50
static int binlog_commit(handlerton *hton, Session *session, bool all);
 
51
static int binlog_rollback(handlerton *hton, Session *session, bool all);
 
52
static int binlog_prepare(handlerton *hton, Session *session, bool all);
 
53
 
 
54
 
 
55
handlerton *binlog_hton;
 
56
 
 
57
 
 
58
 /*
 
59
  Save position of binary log transaction cache.
 
60
 
 
61
  SYNPOSIS
 
62
    binlog_trans_log_savepos()
 
63
 
 
64
    session      The thread to take the binlog data from
 
65
    pos      Pointer to variable where the position will be stored
 
66
 
 
67
  DESCRIPTION
 
68
 
 
69
    Save the current position in the binary log transaction cache into
 
70
    the variable pointed to by 'pos'
 
71
 */
 
72
 
 
73
static void
 
74
binlog_trans_log_savepos(Session *, my_off_t *pos)
 
75
{
 
76
  assert(pos != NULL);
 
77
 
 
78
  return;
 
79
}
 
80
 
 
81
 
 
82
/*
 
83
  this function is mostly a placeholder.
 
84
  conceptually, binlog initialization (now mostly done in DRIZZLE_BIN_LOG::open)
 
85
  should be moved here.
 
86
*/
 
87
 
 
88
int binlog_init(void *p)
 
89
{
 
90
  binlog_hton= (handlerton *)p;
 
91
  binlog_hton->state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO;
 
92
  binlog_hton->savepoint_offset= sizeof(my_off_t);
 
93
  binlog_hton->close_connection= binlog_close_connection;
 
94
  binlog_hton->savepoint_set= binlog_savepoint_set;
 
95
  binlog_hton->savepoint_rollback= binlog_savepoint_rollback;
 
96
  binlog_hton->commit= binlog_commit;
 
97
  binlog_hton->rollback= binlog_rollback;
 
98
  binlog_hton->prepare= binlog_prepare;
 
99
  binlog_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN;
 
100
 
 
101
  return 0;
 
102
}
 
103
 
 
104
static int binlog_close_connection(handlerton *, Session *)
 
105
{
 
106
 
 
107
  return 0;
 
108
}
 
109
 
 
110
static int binlog_prepare(handlerton *, Session *session, bool)
 
111
{
 
112
  /*
 
113
    do nothing.
 
114
    just pretend we can do 2pc, so that MySQL won't
 
115
    switch to 1pc.
 
116
    real work will be done in DRIZZLE_BIN_LOG::log_xid()
 
117
  */
 
118
 
 
119
  (void)replicator_prepare(session);
 
120
 
 
121
  return 0;
 
122
}
 
123
 
 
124
/**
 
125
  This function is called once after each statement.
 
126
 
 
127
  It has the responsibility to flush the transaction cache to the
 
128
  binlog file on commits.
 
129
 
 
130
  @param hton  The binlog handlerton.
 
131
  @param session   The client thread that executes the transaction.
 
132
  @param all   This is @c true if this is a real transaction commit, and
 
133
               @false otherwise.
 
134
 
 
135
  @see handlerton::commit
 
136
*/
 
137
static int binlog_commit(handlerton *, Session *session, bool all)
 
138
{
 
139
  /*
 
140
    Decision table for committing a transaction. The top part, the
 
141
    *conditions* represent different cases that can occur, and hte
 
142
    bottom part, the *actions*, represent what should be done in that
 
143
    particular case.
 
144
 
 
145
    Real transaction        'all' was true
 
146
 
 
147
    Statement in cache      There were at least one statement in the
 
148
                            transaction cache
 
149
 
 
150
    In transaction          We are inside a transaction
 
151
 
 
152
    Stmt modified non-trans The statement being committed modified a
 
153
                            non-transactional table
 
154
 
 
155
    All modified non-trans  Some statement before this one in the
 
156
                            transaction modified a non-transactional
 
157
                            table
 
158
 
 
159
 
 
160
    =============================  = = = = = = = = = = = = = = = =
 
161
    Real transaction               N N N N N N N N N N N N N N N N
 
162
    Statement in cache             N N N N N N N N Y Y Y Y Y Y Y Y
 
163
    In transaction                 N N N N Y Y Y Y N N N N Y Y Y Y
 
164
    Stmt modified non-trans        N N Y Y N N Y Y N N Y Y N N Y Y
 
165
    All modified non-trans         N Y N Y N Y N Y N Y N Y N Y N Y
 
166
 
 
167
    Action: (C)ommit/(A)ccumulate  C C - C A C - C - - - - A A - A
 
168
    =============================  = = = = = = = = = = = = = = = =
 
169
 
 
170
 
 
171
    =============================  = = = = = = = = = = = = = = = =
 
172
    Real transaction               Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y
 
173
    Statement in cache             N N N N N N N N Y Y Y Y Y Y Y Y
 
174
    In transaction                 N N N N Y Y Y Y N N N N Y Y Y Y
 
175
    Stmt modified non-trans        N N Y Y N N Y Y N N Y Y N N Y Y
 
176
    All modified non-trans         N Y N Y N Y N Y N Y N Y N Y N Y
 
177
 
 
178
    (C)ommit/(A)ccumulate/(-)      - - - - C C - C - - - - C C - C
 
179
    =============================  = = = = = = = = = = = = = = = =
 
180
 
 
181
    In other words, we commit the transaction if and only if both of
 
182
    the following are true:
 
183
     - We are not in a transaction and committing a statement
 
184
 
 
185
     - We are in a transaction and one (or more) of the following are
 
186
       true:
 
187
 
 
188
       - A full transaction is committed
 
189
 
 
190
         OR
 
191
 
 
192
       - A non-transactional statement is committed and there is
 
193
         no statement cached
 
194
 
 
195
    Otherwise, we accumulate the statement
 
196
  */
 
197
 
 
198
  if (all || (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) 
 
199
  {
 
200
    return replicator_end_transaction(session, all, true);
 
201
  }
 
202
 
 
203
  return(0);
 
204
}
 
205
 
 
206
/**
 
207
  This function is called when a transaction involving a transactional
 
208
  table is rolled back.
 
209
 
 
210
  It has the responsibility to flush the transaction cache to the
 
211
  binlog file. However, if the transaction does not involve
 
212
  non-transactional tables, nothing needs to be logged.
 
213
 
 
214
  @param hton  The binlog handlerton.
 
215
  @param session   The client thread that executes the transaction.
 
216
  @param all   This is @c true if this is a real transaction rollback, and
 
217
               @false otherwise.
 
218
 
 
219
  @see handlerton::rollback
 
220
*/
 
221
static int binlog_rollback(handlerton *, Session *session, bool all)
 
222
{
 
223
  int error=0;
 
224
 
 
225
  /* TODO: Fix return type */
 
226
  (void)replicator_end_transaction(session, all, false);
 
227
 
 
228
  return(error);
 
229
}
 
230
 
 
231
/**
 
232
  @note
 
233
  How do we handle this (unlikely but legal) case:
 
234
  @verbatim
 
235
    [transaction] + [update to non-trans table] + [rollback to savepoint] ?
 
236
  @endverbatim
 
237
  The problem occurs when a savepoint is before the update to the
 
238
  non-transactional table. Then when there's a rollback to the savepoint, if we
 
239
  simply truncate the binlog cache, we lose the part of the binlog cache where
 
240
  the update is. If we want to not lose it, we need to write the SAVEPOINT
 
241
  command and the ROLLBACK TO SAVEPOINT command to the binlog cache. The latter
 
242
  is easy: it's just write at the end of the binlog cache, but the former
 
243
  should be *inserted* to the place where the user called SAVEPOINT. The
 
244
  solution is that when the user calls SAVEPOINT, we write it to the binlog
 
245
  cache (so no need to later insert it). As transactions are never intermixed
 
246
  in the binary log (i.e. they are serialized), we won't have conflicts with
 
247
  savepoint names when using mysqlbinlog or in the slave SQL thread.
 
248
  Then when ROLLBACK TO SAVEPOINT is called, if we updated some
 
249
  non-transactional table, we don't truncate the binlog cache but instead write
 
250
  ROLLBACK TO SAVEPOINT to it; otherwise we truncate the binlog cache (which
 
251
  will chop the SAVEPOINT command from the binlog cache, which is good as in
 
252
  that case there is no need to have it in the binlog).
 
253
*/
 
254
 
 
255
static int binlog_savepoint_set(handlerton *, Session *session, void *sv)
 
256
{
 
257
  bool error;
 
258
  binlog_trans_log_savepos(session, (my_off_t*) sv);
 
259
  /* Write it to the binary log */
 
260
 
 
261
  error= replicator_statement(session, session->query, session->query_length);
 
262
 
 
263
  return(error);
 
264
}
 
265
 
 
266
static int binlog_savepoint_rollback(handlerton *, Session *session, void *)
 
267
{
 
268
  bool error;
 
269
 
 
270
  error= replicator_statement(session, session->query, session->query_length);
 
271
 
 
272
  return error;
 
273
}
 
274
 
 
275
drizzle_declare_plugin(binlog)
 
276
{
 
277
  DRIZZLE_STORAGE_ENGINE_PLUGIN,
 
278
  "binlog",
 
279
  "1.0",
 
280
  "MySQL AB",
 
281
  "This is a pseudo storage engine to represent the binlog in a transaction",
 
282
  PLUGIN_LICENSE_GPL,
 
283
  binlog_init, /* Plugin Init */
 
284
  NULL, /* Plugin Deinit */
 
285
  NULL,                       /* status variables                */
 
286
  NULL,                       /* system variables                */
 
287
  NULL                        /* config options                  */
 
288
}
 
289
drizzle_declare_plugin_end;