~drizzle-trunk/drizzle/development

1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
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
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
5
 *  Copyright (c) 2010 Jay Pipes <jaypipes@gmail.com>
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; version 2 of the License.
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
17
 *  along with this program; if not, write to the Free Software
18
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
 */
20
21
/**
22
 * @file Transaction processing code
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
23
 *
24
 * @note
25
 *
26
 * The TransactionServices component takes internal events (for instance the start of a 
27
 * transaction, the changing of a record, or the rollback of a transaction) 
28
 * and constructs GPB Messages that are passed to the ReplicationServices
29
 * component and used during replication.
30
 *
31
 * The reason for this functionality is to encapsulate all communication
32
 * between the kernel and the replicator/applier plugins into GPB Messages.
33
 * Instead of the plugin having to understand the (often fluidly changing)
34
 * mechanics of the kernel, all the plugin needs to understand is the message
35
 * format, and GPB messages provide a nice, clear, and versioned format for 
36
 * these messages.
37
 *
38
 * @see /drizzled/message/transaction.proto
39
 *
40
 * @todo
41
 *
42
 * We really should store the raw bytes in the messages, not the
43
 * String value of the Field.  But, to do that, the
44
 * statement_transform library needs first to be updated
45
 * to include the transformation code to convert raw
46
 * Drizzle-internal Field byte representation into something
47
 * plugins can understand.
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
48
 */
49
50
#include "config.h"
51
#include "drizzled/my_hash.h"
52
#include "drizzled/error.h"
53
#include "drizzled/gettext.h"
54
#include "drizzled/probes.h"
55
#include "drizzled/sql_parse.h"
56
#include "drizzled/session.h"
57
#include "drizzled/sql_base.h"
58
#include "drizzled/replication_services.h"
59
#include "drizzled/transaction_services.h"
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
60
#include "drizzled/transaction_context.h"
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
61
#include "drizzled/message/transaction.pb.h"
62
#include "drizzled/message/statement_transform.h"
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
63
#include "drizzled/resource_context.h"
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
64
#include "drizzled/lock.h"
65
#include "drizzled/item/int.h"
66
#include "drizzled/item/empty_string.h"
67
#include "drizzled/field/timestamp.h"
68
#include "drizzled/plugin/client.h"
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
69
#include "drizzled/plugin/monitored_in_transaction.h"
70
#include "drizzled/plugin/transactional_storage_engine.h"
71
#include "drizzled/plugin/xa_resource_manager.h"
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
72
#include "drizzled/internal/my_sys.h"
73
74
using namespace std;
75
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
76
#include <vector>
77
#include <algorithm>
78
#include <functional>
79
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
80
namespace drizzled
81
{
82
83
/**
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
84
 * @defgroup Transactions
85
 *
86
 * @brief
87
 *
88
 * Transaction handling in the server
89
 *
90
 * @detail
91
 *
92
 * In each client connection, Drizzle maintains two transaction
93
 * contexts representing the state of the:
94
 *
95
 * 1) Statement Transaction
96
 * 2) Normal Transaction
97
 *
98
 * These two transaction contexts represent the transactional
99
 * state of a Session's SQL and XA transactions for a single
100
 * SQL statement or a series of SQL statements.
101
 *
102
 * When the Session's connection is in AUTOCOMMIT mode, there
103
 * is no practical difference between the statement and the
104
 * normal transaction, as each SQL statement is committed or
105
 * rolled back depending on the success or failure of the
106
 * indvidual SQL statement.
107
 *
108
 * When the Session's connection is NOT in AUTOCOMMIT mode, OR
109
 * the Session has explicitly begun a normal SQL transaction using
110
 * a BEGIN WORK/START TRANSACTION statement, then the normal
111
 * transaction context tracks the aggregate transaction state of
112
 * the SQL transaction's individual statements, and the SQL
113
 * transaction's commit or rollback is done atomically for all of
114
 * the SQL transaction's statement's data changes.
115
 *
116
 * Technically, a statement transaction can be viewed as a savepoint 
117
 * which is maintained automatically in order to make effects of one
118
 * statement atomic.
119
 *
120
 * The normal transaction is started by the user and is typically
121
 * ended (COMMIT or ROLLBACK) upon an explicity user request as well.
122
 * The exception to this is that DDL statements implicitly COMMIT
123
 * any previously active normal transaction before they begin executing.
124
 *
125
 * In Drizzle, unlike MySQL, plugins other than a storage engine
126
 * may participate in a transaction.  All plugin::TransactionalStorageEngine
127
 * plugins will automatically be monitored by Drizzle's transaction 
128
 * manager (implemented in this source file), as will all plugins which
129
 * implement plugin::XaResourceManager and register with the transaction
130
 * manager.
131
 *
132
 * If Drizzle's transaction manager sees that more than one resource
133
 * manager (transactional storage engine or XA resource manager) has modified
134
 * data state during a statement or normal transaction, the transaction
135
 * manager will automatically use a two-phase commit protocol for all
136
 * resources which support XA's distributed transaction protocol.  Unlike
137
 * MySQL, storage engines need not manually register with the transaction
138
 * manager during a statement's execution.  Previously, in MySQL, all
139
 * handlertons would have to call trans_register_ha() at some point after
140
 * modifying data state in order to have MySQL include that handler in
141
 * an XA transaction.  Drizzle does all of this grunt work behind the
142
 * scenes for the storage engine implementers.
143
 *
144
 * When a connection is closed, the current normal transaction, if
145
 * any is currently active, is rolled back.
146
 *
147
 * Transaction life cycle
148
 * ----------------------
149
 *
150
 * When a new connection is established, session->transaction
151
 * members are initialized to an empty state. If a statement uses any tables, 
152
 * all affected engines are registered in the statement engine list automatically
153
 * in plugin::StorageEngine::startStatement() and 
154
 * plugin::TransactionalStorageEngine::startTransaction().
155
 *
156
 * You can view the lifetime of a normal transaction in the following
157
 * call-sequence:
158
 *
159
 * drizzled::statement::Statement::execute()
160
 *   drizzled::plugin::TransactionalStorageEngine::startTransaction()
161
 *     drizzled::TransactionServices::registerResourceForTransaction()
162
 *     drizzled::TransactionServices::registerResourceForStatement()
163
 *     drizzled::plugin::StorageEngine::startStatement()
164
 *       drizzled::Cursor::write_row() <-- example...could be update_row(), etc
165
 *     drizzled::plugin::StorageEngine::endStatement()
166
 *   drizzled::TransactionServices::autocommitOrRollback()
167
 *     drizzled::TransactionalStorageEngine::commit() <-- or ::rollback()
168
 *     drizzled::XaResourceManager::xaCommit() <-- or rollback()
169
 *
170
 * Roles and responsibilities
171
 * --------------------------
172
 *
173
 * Beginning of SQL Statement (and Statement Transaction)
174
 * ------------------------------------------------------
175
 *
176
 * At the start of each SQL statement, for each storage engine
177
 * <strong>that is involved in the SQL statement</strong>, the kernel 
178
 * calls the engine's plugin::StoragEngine::startStatement() method.  If the
179
 * engine needs to track some data for the statement, it should use
180
 * this method invocation to initialize this data.  This is the
181
 * beginning of what is called the "statement transaction".
182
 *
183
 * <strong>For transaction storage engines (those storage engines
184
 * that inherit from plugin::TransactionalStorageEngine)</strong>, the
185
 * kernel automatically determines if the start of the SQL statement 
186
 * transaction should <em>also</em> begin the normal SQL transaction.
187
 * This occurs when the connection is in NOT in autocommit mode. If
188
 * the kernel detects this, then the kernel automatically starts the
189
 * normal transaction w/ plugin::TransactionalStorageEngine::startTransaction()
190
 * method and then calls plugin::StorageEngine::startStatement()
191
 * afterwards.
192
 *
193
 * Beginning of an SQL "Normal" Transaction
194
 * ----------------------------------------
195
 *
196
 * As noted above, a "normal SQL transaction" may be started when
197
 * an SQL statement is started in a connection and the connection is
198
 * NOT in AUTOCOMMIT mode.  This is automatically done by the kernel.
199
 *
200
 * In addition, when a user executes a START TRANSACTION or
201
 * BEGIN WORK statement in a connection, the kernel explicitly
202
 * calls each transactional storage engine's startTransaction() method.
203
 *
204
 * Ending of an SQL Statement (and Statement Transaction)
205
 * ------------------------------------------------------
206
 *
207
 * At the end of each SQL statement, for each of the aforementioned
208
 * involved storage engines, the kernel calls the engine's
209
 * plugin::StorageEngine::endStatement() method.  If the engine
210
 * has initialized or modified some internal data about the
211
 * statement transaction, it should use this method to reset or destroy
212
 * this data appropriately.
213
 *
214
 * Ending of an SQL "Normal" Transaction
215
 * -------------------------------------
216
 *
217
 * The end of a normal transaction is either a ROLLBACK or a COMMIT, 
218
 * depending on the success or failure of the statement transaction(s) 
219
 * it encloses.
220
 *
221
 * The end of a "normal transaction" occurs when any of the following
222
 * occurs:
223
 *
224
 * 1) If a statement transaction has completed and AUTOCOMMIT is ON,
225
 *    then the normal transaction which encloses the statement
226
 *    transaction ends
227
 * 2) If a COMMIT or ROLLBACK statement occurs on the connection
228
 * 3) Just before a DDL operation occurs, the kernel will implicitly
229
 *    commit the active normal transaction
230
 *
231
 * Transactions and Non-transactional Storage Engines
232
 * --------------------------------------------------
233
 *
234
 * For non-transactional engines, this call can be safely ignored, an
235
 * the kernel tracks whether a non-transactional engine has changed
236
 * any data state, and warns the user appropriately if a transaction
237
 * (statement or normal) is rolled back after such non-transactional
238
 * data changes have been made.
239
 *
240
 * XA Two-phase Commit Protocol
241
 * ----------------------------
242
 *
243
 * During statement execution, whenever any of data-modifying
244
 * PSEA API methods is used, e.g. Cursor::write_row() or
245
 * Cursor::update_row(), the read-write flag is raised in the
246
 * statement transaction for the involved engine.
247
 * Currently All PSEA calls are "traced", and the data can not be
248
 * changed in a way other than issuing a PSEA call. Important:
249
 * unless this invariant is preserved the server will not know that
250
 * a transaction in a given engine is read-write and will not
251
 * involve the two-phase commit protocol!
252
 *
253
 * At the end of a statement, TransactionServices::autocommitOrRollback()
254
 * is invoked. This call in turn
255
 * invokes plugin::XaResourceManager::xapPepare() for every involved XA
256
 * resource manager.
257
 *
258
 * Prepare is followed by a call to plugin::TransactionalStorageEngine::commit()
259
 * or plugin::XaResourceManager::xaCommit() (depending on what the resource
260
 * is...)
261
 * 
262
 * If a one-phase commit will suffice, plugin::StorageEngine::prepare() is not
263
 * invoked and the server only calls plugin::StorageEngine::commit_one_phase().
264
 * At statement commit, the statement-related read-write engine
265
 * flag is propagated to the corresponding flag in the normal
266
 * transaction.  When the commit is complete, the list of registered
267
 * engines is cleared.
268
 *
269
 * Rollback is handled in a similar fashion.
270
 *
271
 * Additional notes on DDL and the normal transaction.
272
 * ---------------------------------------------------
273
 *
274
 * CREATE TABLE .. SELECT can start a *new* normal transaction
275
 * because of the fact that SELECTs on a transactional storage
276
 * engine participate in the normal SQL transaction (due to
277
 * isolation level issues and consistent read views).
278
 *
279
 * Behaviour of the server in this case is currently badly
280
 * defined.
281
 *
282
 * DDL statements use a form of "semantic" logging
283
 * to maintain atomicity: if CREATE TABLE .. SELECT failed,
284
 * the newly created table is deleted.
285
 * 
286
 * In addition, some DDL statements issue interim transaction
287
 * commits: e.g. ALTER TABLE issues a COMMIT after data is copied
288
 * from the original table to the internal temporary table. Other
289
 * statements, e.g. CREATE TABLE ... SELECT do not always commit
290
 * after itself.
291
 *
292
 * And finally there is a group of DDL statements such as
293
 * RENAME/DROP TABLE that doesn't start a new transaction
294
 * and doesn't commit.
295
 *
296
 * A consistent behaviour is perhaps to always commit the normal
297
 * transaction after all DDLs, just like the statement transaction
298
 * is always committed at the end of all statements.
299
 */
1273.1.22 by Jay Pipes
Automates registration of statement transaction resources. No more need for storage engines to call TransactionServices::trans_register_ha(session, false, engine). yeah \o/
300
void TransactionServices::registerResourceForStatement(Session *session,
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
301
                                                       plugin::MonitoredInTransaction *monitored,
1273.1.22 by Jay Pipes
Automates registration of statement transaction resources. No more need for storage engines to call TransactionServices::trans_register_ha(session, false, engine). yeah \o/
302
                                                       plugin::TransactionalStorageEngine *engine)
303
{
1273.1.27 by Jay Pipes
Completes the work of removing the weirdness around transaction
304
  if (session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
305
  {
306
    /* 
307
     * Now we automatically register this resource manager for the
308
     * normal transaction.  This is fine because a statement
309
     * transaction registration should always enlist the resource
310
     * in the normal transaction which contains the statement
311
     * transaction.
312
     */
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
313
    registerResourceForTransaction(session, monitored, engine);
314
  }
315
316
  TransactionContext *trans= &session->transaction.stmt;
317
  ResourceContext *resource_context= session->getResourceContext(monitored, 0);
318
319
  if (resource_context->isStarted())
320
    return; /* already registered, return */
321
322
  assert(monitored->participatesInSqlTransaction());
323
  assert(not monitored->participatesInXaTransaction());
324
325
  resource_context->setMonitored(monitored);
326
  resource_context->setTransactionalStorageEngine(engine);
327
  trans->registerResource(resource_context);
328
329
  trans->no_2pc|= true;
330
}
331
332
void TransactionServices::registerResourceForStatement(Session *session,
333
                                                       plugin::MonitoredInTransaction *monitored,
334
                                                       plugin::TransactionalStorageEngine *engine,
335
                                                       plugin::XaResourceManager *resource_manager)
336
{
337
  if (session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
338
  {
339
    /* 
340
     * Now we automatically register this resource manager for the
341
     * normal transaction.  This is fine because a statement
342
     * transaction registration should always enlist the resource
343
     * in the normal transaction which contains the statement
344
     * transaction.
345
     */
346
    registerResourceForTransaction(session, monitored, engine, resource_manager);
347
  }
348
349
  TransactionContext *trans= &session->transaction.stmt;
350
  ResourceContext *resource_context= session->getResourceContext(monitored, 0);
351
352
  if (resource_context->isStarted())
353
    return; /* already registered, return */
354
355
  assert(monitored->participatesInXaTransaction());
356
  assert(monitored->participatesInSqlTransaction());
357
358
  resource_context->setMonitored(monitored);
359
  resource_context->setTransactionalStorageEngine(engine);
360
  resource_context->setXaResourceManager(resource_manager);
361
  trans->registerResource(resource_context);
362
363
  trans->no_2pc|= false;
1273.1.22 by Jay Pipes
Automates registration of statement transaction resources. No more need for storage engines to call TransactionServices::trans_register_ha(session, false, engine). yeah \o/
364
}
365
1273.1.27 by Jay Pipes
Completes the work of removing the weirdness around transaction
366
void TransactionServices::registerResourceForTransaction(Session *session,
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
367
                                                         plugin::MonitoredInTransaction *monitored,
1273.1.27 by Jay Pipes
Completes the work of removing the weirdness around transaction
368
                                                         plugin::TransactionalStorageEngine *engine)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
369
{
1273.1.22 by Jay Pipes
Automates registration of statement transaction resources. No more need for storage engines to call TransactionServices::trans_register_ha(session, false, engine). yeah \o/
370
  TransactionContext *trans= &session->transaction.all;
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
371
  ResourceContext *resource_context= session->getResourceContext(monitored, 1);
372
373
  if (resource_context->isStarted())
374
    return; /* already registered, return */
375
376
  session->server_status|= SERVER_STATUS_IN_TRANS;
377
378
  trans->registerResource(resource_context);
379
380
  assert(monitored->participatesInSqlTransaction());
381
  assert(not monitored->participatesInXaTransaction());
382
383
  resource_context->setMonitored(monitored);
384
  resource_context->setTransactionalStorageEngine(engine);
385
  trans->no_2pc|= true;
386
387
  if (session->transaction.xid_state.xid.is_null())
388
    session->transaction.xid_state.xid.set(session->getQueryId());
389
1333.1.1 by Jay Pipes
Manually issue a call to TransactionStorageEngine::startTransaction() inside
390
  engine->startTransaction(session, START_TRANS_NO_OPTIONS);
391
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
392
  /* Only true if user is executing a BEGIN WORK/START TRANSACTION */
393
  if (! session->getResourceContext(monitored, 0)->isStarted())
394
    registerResourceForStatement(session, monitored, engine);
395
}
396
397
void TransactionServices::registerResourceForTransaction(Session *session,
398
                                                         plugin::MonitoredInTransaction *monitored,
399
                                                         plugin::TransactionalStorageEngine *engine,
400
                                                         plugin::XaResourceManager *resource_manager)
401
{
402
  TransactionContext *trans= &session->transaction.all;
403
  ResourceContext *resource_context= session->getResourceContext(monitored, 1);
404
405
  if (resource_context->isStarted())
406
    return; /* already registered, return */
407
408
  session->server_status|= SERVER_STATUS_IN_TRANS;
409
410
  trans->registerResource(resource_context);
411
412
  assert(monitored->participatesInSqlTransaction());
413
414
  resource_context->setMonitored(monitored);
415
  resource_context->setXaResourceManager(resource_manager);
416
  resource_context->setTransactionalStorageEngine(engine);
417
  trans->no_2pc|= true;
418
419
  if (session->transaction.xid_state.xid.is_null())
420
    session->transaction.xid_state.xid.set(session->getQueryId());
421
1333.1.1 by Jay Pipes
Manually issue a call to TransactionStorageEngine::startTransaction() inside
422
  engine->startTransaction(session, START_TRANS_NO_OPTIONS);
423
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
424
  /* Only true if user is executing a BEGIN WORK/START TRANSACTION */
425
  if (! session->getResourceContext(monitored, 0)->isStarted())
426
    registerResourceForStatement(session, monitored, engine, resource_manager);
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
427
}
428
429
/**
430
  @retval
431
    0   ok
432
  @retval
433
    1   transaction was rolled back
434
  @retval
435
    2   error during commit, data may be inconsistent
436
437
  @todo
438
    Since we don't support nested statement transactions in 5.0,
439
    we can't commit or rollback stmt transactions while we are inside
440
    stored functions or triggers. So we simply do nothing now.
441
    TODO: This should be fixed in later ( >= 5.1) releases.
442
*/
1405.3.5 by Jay Pipes
TransactionServices method names now meet code style guidelines.
443
int TransactionServices::commitTransaction(Session *session, bool normal_transaction)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
444
{
445
  int error= 0, cookie= 0;
446
  /*
447
    'all' means that this is either an explicit commit issued by
448
    user, or an implicit commit issued by a DDL.
449
  */
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
450
  TransactionContext *trans= normal_transaction ? &session->transaction.all : &session->transaction.stmt;
451
  TransactionContext::ResourceContexts &resource_contexts= trans->getResourceContexts();
452
453
  bool is_real_trans= normal_transaction || session->transaction.all.getResourceContexts().empty();
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
454
455
  /*
456
    We must not commit the normal transaction if a statement
457
    transaction is pending. Otherwise statement transaction
458
    flags will not get propagated to its normal transaction's
459
    counterpart.
460
  */
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
461
  assert(session->transaction.stmt.getResourceContexts().empty() ||
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
462
              trans == &session->transaction.stmt);
463
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
464
  if (resource_contexts.empty() == false)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
465
  {
466
    if (is_real_trans && wait_if_global_read_lock(session, 0, 0))
467
    {
1405.3.5 by Jay Pipes
TransactionServices method names now meet code style guidelines.
468
      rollbackTransaction(session, normal_transaction);
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
469
      return 1;
470
    }
471
1405.3.6 by Jay Pipes
Here, we do two main things:
472
    /*
473
     * If replication is on, we do a PREPARE on the resource managers, push the
474
     * Transaction message across the replication stream, and then COMMIT if the
475
     * replication stream returned successfully.
476
     */
477
    if (shouldConstructMessages())
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
478
    {
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
479
      for (TransactionContext::ResourceContexts::iterator it= resource_contexts.begin();
480
           it != resource_contexts.end() && ! error;
481
           ++it)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
482
      {
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
483
        ResourceContext *resource_context= *it;
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
484
        int err;
485
        /*
486
          Do not call two-phase commit if this particular
487
          transaction is read-only. This allows for simpler
488
          implementation in engines that are always read-only.
489
        */
1273.1.12 by Jay Pipes
Cleanup style and documentation for ResourceContext and setTransactionReadWrite
490
        if (! resource_context->hasModifiedData())
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
491
          continue;
1273.1.15 by Jay Pipes
This patch completes the first step in the splitting of
492
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
493
        plugin::MonitoredInTransaction *resource= resource_context->getMonitored();
494
495
        if (resource->participatesInXaTransaction())
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
496
        {
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
497
          if ((err= resource_context->getXaResourceManager()->xaPrepare(session, normal_transaction)))
498
          {
499
            my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
500
            error= 1;
501
          }
502
          else
503
          {
504
            status_var_increment(session->status_var.ha_prepare_count);
505
          }
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
506
        }
507
      }
1405.3.6 by Jay Pipes
Here, we do two main things:
508
      if (error == 0 && is_real_trans)
509
      {
510
        /*
511
         * Push the constructed Transaction messages across to
512
         * replicators and appliers.
513
         */
514
        error= commitTransactionMessage(session);
515
      }
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
516
      if (error)
517
      {
1405.3.5 by Jay Pipes
TransactionServices method names now meet code style guidelines.
518
        rollbackTransaction(session, normal_transaction);
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
519
        error= 1;
520
        goto end;
521
      }
522
    }
1405.3.5 by Jay Pipes
TransactionServices method names now meet code style guidelines.
523
    error= commitPhaseOne(session, normal_transaction) ? (cookie ? 2 : 1) : 0;
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
524
end:
525
    if (is_real_trans)
526
      start_waiting_global_read_lock(session);
527
  }
528
  return error;
529
}
530
531
/**
532
  @note
533
  This function does not care about global read lock. A caller should.
534
*/
1405.3.5 by Jay Pipes
TransactionServices method names now meet code style guidelines.
535
int TransactionServices::commitPhaseOne(Session *session, bool normal_transaction)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
536
{
537
  int error=0;
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
538
  TransactionContext *trans= normal_transaction ? &session->transaction.all : &session->transaction.stmt;
539
  TransactionContext::ResourceContexts &resource_contexts= trans->getResourceContexts();
540
541
  bool is_real_trans= normal_transaction || session->transaction.all.getResourceContexts().empty();
542
543
  if (resource_contexts.empty() == false)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
544
  {
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
545
    for (TransactionContext::ResourceContexts::iterator it= resource_contexts.begin();
546
         it != resource_contexts.end();
547
         ++it)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
548
    {
549
      int err;
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
550
      ResourceContext *resource_context= *it;
1273.1.27 by Jay Pipes
Completes the work of removing the weirdness around transaction
551
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
552
      plugin::MonitoredInTransaction *resource= resource_context->getMonitored();
553
554
      if (resource->participatesInXaTransaction())
555
      {
556
        if ((err= resource_context->getXaResourceManager()->xaCommit(session, normal_transaction)))
557
        {
558
          my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
559
          error= 1;
560
        }
1324.1.1 by Jay Pipes
Fixes Bug #535296 by only incrementing ha_commit_count when its a normal transaction commit.
561
        else if (normal_transaction)
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
562
        {
563
          status_var_increment(session->status_var.ha_commit_count);
564
        }
565
      }
566
      else if (resource->participatesInSqlTransaction())
567
      {
568
        if ((err= resource_context->getTransactionalStorageEngine()->commit(session, normal_transaction)))
569
        {
570
          my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
571
          error= 1;
572
        }
1324.1.1 by Jay Pipes
Fixes Bug #535296 by only incrementing ha_commit_count when its a normal transaction commit.
573
        else if (normal_transaction)
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
574
        {
575
          status_var_increment(session->status_var.ha_commit_count);
576
        }
577
      }
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
578
      resource_context->reset(); /* keep it conveniently zero-filled */
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
579
    }
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
580
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
581
    if (is_real_trans)
582
      session->transaction.xid_state.xid.null();
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
583
584
    if (normal_transaction)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
585
    {
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
586
      session->variables.tx_isolation= session->session_tx_isolation;
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
587
      session->transaction.cleanup();
588
    }
589
  }
1273.1.27 by Jay Pipes
Completes the work of removing the weirdness around transaction
590
  trans->reset();
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
591
  return error;
592
}
593
1405.3.5 by Jay Pipes
TransactionServices method names now meet code style guidelines.
594
int TransactionServices::rollbackTransaction(Session *session, bool normal_transaction)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
595
{
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
596
  int error= 0;
597
  TransactionContext *trans= normal_transaction ? &session->transaction.all : &session->transaction.stmt;
598
  TransactionContext::ResourceContexts &resource_contexts= trans->getResourceContexts();
599
600
  bool is_real_trans= normal_transaction || session->transaction.all.getResourceContexts().empty();
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
601
602
  /*
603
    We must not rollback the normal transaction if a statement
604
    transaction is pending.
605
  */
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
606
  assert(session->transaction.stmt.getResourceContexts().empty() ||
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
607
              trans == &session->transaction.stmt);
608
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
609
  if (resource_contexts.empty() == false)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
610
  {
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
611
    for (TransactionContext::ResourceContexts::iterator it= resource_contexts.begin();
612
         it != resource_contexts.end();
613
         ++it)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
614
    {
615
      int err;
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
616
      ResourceContext *resource_context= *it;
1273.1.27 by Jay Pipes
Completes the work of removing the weirdness around transaction
617
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
618
      plugin::MonitoredInTransaction *resource= resource_context->getMonitored();
619
620
      if (resource->participatesInXaTransaction())
621
      {
622
        if ((err= resource_context->getXaResourceManager()->xaRollback(session, normal_transaction)))
623
        {
624
          my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
625
          error= 1;
626
        }
1324.1.1 by Jay Pipes
Fixes Bug #535296 by only incrementing ha_commit_count when its a normal transaction commit.
627
        else if (normal_transaction)
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
628
        {
629
          status_var_increment(session->status_var.ha_rollback_count);
630
        }
631
      }
632
      else if (resource->participatesInSqlTransaction())
633
      {
634
        if ((err= resource_context->getTransactionalStorageEngine()->rollback(session, normal_transaction)))
635
        {
636
          my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
637
          error= 1;
638
        }
1324.1.1 by Jay Pipes
Fixes Bug #535296 by only incrementing ha_commit_count when its a normal transaction commit.
639
        else if (normal_transaction)
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
640
        {
641
          status_var_increment(session->status_var.ha_rollback_count);
642
        }
643
      }
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
644
      resource_context->reset(); /* keep it conveniently zero-filled */
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
645
    }
646
    
647
    /* 
648
     * We need to signal the ROLLBACK to ReplicationServices here
649
     * BEFORE we set the transaction ID to NULL.  This is because
650
     * if a bulk segment was sent to replicators, we need to send
651
     * a rollback statement with the corresponding transaction ID
652
     * to rollback.
653
     */
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
654
    rollbackTransactionMessage(session);
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
655
656
    if (is_real_trans)
657
      session->transaction.xid_state.xid.null();
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
658
    if (normal_transaction)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
659
    {
660
      session->variables.tx_isolation=session->session_tx_isolation;
661
      session->transaction.cleanup();
662
    }
663
  }
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
664
  if (normal_transaction)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
665
    session->transaction_rollback_request= false;
666
667
  /*
1273.1.27 by Jay Pipes
Completes the work of removing the weirdness around transaction
668
   * If a non-transactional table was updated, warn the user
669
   */
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
670
  if (is_real_trans &&
1273.1.13 by Jay Pipes
Style cleanup around TransactionContext::modified_non_trans_table and dead code removal
671
      session->transaction.all.hasModifiedNonTransData() &&
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
672
      session->killed != Session::KILL_CONNECTION)
673
  {
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
674
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
675
                 ER_WARNING_NOT_COMPLETE_ROLLBACK,
676
                 ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
677
  }
1273.1.27 by Jay Pipes
Completes the work of removing the weirdness around transaction
678
  trans->reset();
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
679
  return error;
680
}
681
682
/**
683
  This is used to commit or rollback a single statement depending on
684
  the value of error.
685
686
  @note
687
    Note that if the autocommit is on, then the following call inside
688
    InnoDB will commit or rollback the whole transaction (= the statement). The
689
    autocommit mechanism built into InnoDB is based on counting locks, but if
690
    the user has used LOCK TABLES then that mechanism does not know to do the
691
    commit.
692
*/
1405.3.5 by Jay Pipes
TransactionServices method names now meet code style guidelines.
693
int TransactionServices::autocommitOrRollback(Session *session, int error)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
694
{
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
695
  if (session->transaction.stmt.getResourceContexts().empty() == false)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
696
  {
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
697
    if (! error)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
698
    {
1405.3.5 by Jay Pipes
TransactionServices method names now meet code style guidelines.
699
      if (commitTransaction(session, false))
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
700
        error= 1;
701
    }
702
    else
703
    {
1405.3.5 by Jay Pipes
TransactionServices method names now meet code style guidelines.
704
      (void) rollbackTransaction(session, false);
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
705
      if (session->transaction_rollback_request)
1405.3.5 by Jay Pipes
TransactionServices method names now meet code style guidelines.
706
        (void) rollbackTransaction(session, true);
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
707
    }
708
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
709
    session->variables.tx_isolation= session->session_tx_isolation;
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
710
  }
711
  return error;
712
}
713
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
714
struct ResourceContextCompare : public std::binary_function<ResourceContext *, ResourceContext *, bool>
715
{
716
  result_type operator()(const ResourceContext *lhs, const ResourceContext *rhs) const
717
  {
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
718
    /* The below is perfectly fine, since we're simply comparing addresses for the underlying
719
     * resources aren't the same... */
720
    return reinterpret_cast<uint64_t>(lhs->getMonitored()) < reinterpret_cast<uint64_t>(rhs->getMonitored());
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
721
  }
722
};
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
723
1405.3.5 by Jay Pipes
TransactionServices method names now meet code style guidelines.
724
int TransactionServices::rollbackToSavepoint(Session *session, NamedSavepoint &sv)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
725
{
726
  int error= 0;
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
727
  TransactionContext *trans= &session->transaction.all;
728
  TransactionContext::ResourceContexts &tran_resource_contexts= trans->getResourceContexts();
729
  TransactionContext::ResourceContexts &sv_resource_contexts= sv.getResourceContexts();
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
730
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
731
  trans->no_2pc= false;
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
732
  /*
733
    rolling back to savepoint in all storage engines that were part of the
734
    transaction when the savepoint was set
735
  */
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
736
  for (TransactionContext::ResourceContexts::iterator it= sv_resource_contexts.begin();
737
       it != sv_resource_contexts.end();
738
       ++it)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
739
  {
740
    int err;
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
741
    ResourceContext *resource_context= *it;
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
742
743
    plugin::MonitoredInTransaction *resource= resource_context->getMonitored();
744
745
    if (resource->participatesInSqlTransaction())
746
    {
747
      if ((err= resource_context->getTransactionalStorageEngine()->rollbackToSavepoint(session, sv)))
748
      {
749
        my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
750
        error= 1;
751
      }
752
      else
753
      {
754
        status_var_increment(session->status_var.ha_savepoint_rollback_count);
755
      }
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
756
    }
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
757
    trans->no_2pc|= not resource->participatesInXaTransaction();
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
758
  }
759
  /*
760
    rolling back the transaction in all storage engines that were not part of
761
    the transaction when the savepoint was set
762
  */
763
  {
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
764
    TransactionContext::ResourceContexts sorted_tran_resource_contexts(tran_resource_contexts);
765
    TransactionContext::ResourceContexts sorted_sv_resource_contexts(sv_resource_contexts);
766
    TransactionContext::ResourceContexts set_difference_contexts;
767
1491.2.3 by Jay Pipes
Fix for Bug #542299. The cause of the segfault was no pre-allocation of the target vector in set_difference(). Depending on STL implementations, set_difference() calls the STL's copy(), which requires pre-allocation of all targets and destinations. This meant the default constructor for set_difference_contexts was not adequate, and we should call vector<>::reserve() to allocate enough memory for pointers to the target elements.
768
    /* 
769
     * Bug #542299: segfault during set_difference() below.  copy<>() requires pre-allocation
770
     * of all elements, including the target, which is why we pre-allocate the set_difference_contexts
771
     * here
772
     */
773
    set_difference_contexts.reserve(max(tran_resource_contexts.size(), sv_resource_contexts.size()));
774
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
775
    sort(sorted_tran_resource_contexts.begin(),
776
         sorted_tran_resource_contexts.end(),
777
         ResourceContextCompare());
778
    sort(sorted_sv_resource_contexts.begin(),
779
         sorted_sv_resource_contexts.end(),
780
         ResourceContextCompare());
781
    set_difference(sorted_tran_resource_contexts.begin(),
782
                   sorted_tran_resource_contexts.end(),
783
                   sorted_sv_resource_contexts.begin(),
784
                   sorted_sv_resource_contexts.end(),
785
                   set_difference_contexts.begin(),
786
                   ResourceContextCompare());
787
    /* 
788
     * set_difference_contexts now contains all resource contexts
789
     * which are in the transaction context but were NOT in the
790
     * savepoint's resource contexts.
791
     */
792
        
793
    for (TransactionContext::ResourceContexts::iterator it= set_difference_contexts.begin();
794
         it != set_difference_contexts.end();
795
         ++it)
796
    {
797
      ResourceContext *resource_context= *it;
798
      int err;
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
799
800
      plugin::MonitoredInTransaction *resource= resource_context->getMonitored();
801
802
      if (resource->participatesInSqlTransaction())
803
      {
804
        if ((err= resource_context->getTransactionalStorageEngine()->rollback(session, !(0))))
805
        {
806
          my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
807
          error= 1;
808
        }
809
        else
810
        {
811
          status_var_increment(session->status_var.ha_rollback_count);
812
        }
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
813
      }
814
      resource_context->reset(); /* keep it conveniently zero-filled */
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
815
    }
816
  }
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
817
  trans->setResourceContexts(sv_resource_contexts);
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
818
  return error;
819
}
820
821
/**
822
  @note
823
  according to the sql standard (ISO/IEC 9075-2:2003)
824
  section "4.33.4 SQL-statements and transaction states",
1273.1.4 by Jay Pipes
This patch significantly reworks the way that
825
  NamedSavepoint is *not* transaction-initiating SQL-statement
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
826
*/
1405.3.5 by Jay Pipes
TransactionServices method names now meet code style guidelines.
827
int TransactionServices::setSavepoint(Session *session, NamedSavepoint &sv)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
828
{
829
  int error= 0;
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
830
  TransactionContext *trans= &session->transaction.all;
831
  TransactionContext::ResourceContexts &resource_contexts= trans->getResourceContexts();
832
833
  if (resource_contexts.empty() == false)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
834
  {
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
835
    for (TransactionContext::ResourceContexts::iterator it= resource_contexts.begin();
836
         it != resource_contexts.end();
837
         ++it)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
838
    {
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
839
      ResourceContext *resource_context= *it;
840
      int err;
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
841
842
      plugin::MonitoredInTransaction *resource= resource_context->getMonitored();
843
844
      if (resource->participatesInSqlTransaction())
845
      {
846
        if ((err= resource_context->getTransactionalStorageEngine()->setSavepoint(session, sv)))
847
        {
848
          my_error(ER_GET_ERRNO, MYF(0), err);
849
          error= 1;
850
        }
851
        else
852
        {
853
          status_var_increment(session->status_var.ha_savepoint_count);
854
        }
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
855
      }
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
856
    }
857
  }
858
  /*
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
859
    Remember the list of registered storage engines.
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
860
  */
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
861
  sv.setResourceContexts(resource_contexts);
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
862
  return error;
863
}
864
1405.3.5 by Jay Pipes
TransactionServices method names now meet code style guidelines.
865
int TransactionServices::releaseSavepoint(Session *session, NamedSavepoint &sv)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
866
{
867
  int error= 0;
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
868
869
  TransactionContext::ResourceContexts &resource_contexts= sv.getResourceContexts();
870
871
  for (TransactionContext::ResourceContexts::iterator it= resource_contexts.begin();
872
       it != resource_contexts.end();
873
       ++it)
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
874
  {
875
    int err;
1273.1.10 by Jay Pipes
* Renames Ha_trx_info to drizzled::ResourceContext
876
    ResourceContext *resource_context= *it;
1273.1.30 by Jay Pipes
* Completes the blueprint for splitting the XA Resource Manager
877
878
    plugin::MonitoredInTransaction *resource= resource_context->getMonitored();
879
880
    if (resource->participatesInSqlTransaction())
881
    {
882
      if ((err= resource_context->getTransactionalStorageEngine()->releaseSavepoint(session, sv)))
883
      {
884
        my_error(ER_GET_ERRNO, MYF(0), err);
885
        error= 1;
886
      }
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
887
    }
888
  }
889
  return error;
890
}
891
1405.4.10 by Jay Pipes
OK, Sun Studio still didn't like that...seems to think that inline means something different than other compilers think it is...
892
bool TransactionServices::shouldConstructMessages()
893
{
894
  ReplicationServices &replication_services= ReplicationServices::singleton();
895
  return replication_services.isActive();
896
}
897
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
898
message::Transaction *TransactionServices::getActiveTransactionMessage(Session *in_session)
899
{
900
  message::Transaction *transaction= in_session->getTransactionMessage();
901
902
  if (unlikely(transaction == NULL))
903
  {
904
    /* 
905
     * Allocate and initialize a new transaction message 
906
     * for this Session object.  Session is responsible for
907
     * deleting transaction message when done with it.
908
     */
909
    transaction= new (nothrow) message::Transaction();
910
    initTransactionMessage(*transaction, in_session);
911
    in_session->setTransactionMessage(transaction);
912
    return transaction;
913
  }
914
  else
915
    return transaction;
916
}
917
918
void TransactionServices::initTransactionMessage(message::Transaction &in_transaction,
919
                                          Session *in_session)
920
{
921
  message::TransactionContext *trx= in_transaction.mutable_transaction_context();
922
  trx->set_server_id(in_session->getServerId());
1405.4.7 by Jay Pipes
* Fixes drizzled's atomics:
923
  trx->set_transaction_id(getNextTransactionId());
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
924
  trx->set_start_timestamp(in_session->getCurrentTimestamp());
925
}
926
927
void TransactionServices::finalizeTransactionMessage(message::Transaction &in_transaction,
928
                                              Session *in_session)
929
{
930
  message::TransactionContext *trx= in_transaction.mutable_transaction_context();
931
  trx->set_end_timestamp(in_session->getCurrentTimestamp());
932
}
933
934
void TransactionServices::cleanupTransactionMessage(message::Transaction *in_transaction,
935
                                             Session *in_session)
936
{
937
  delete in_transaction;
938
  in_session->setStatementMessage(NULL);
939
  in_session->setTransactionMessage(NULL);
940
}
941
1405.3.6 by Jay Pipes
Here, we do two main things:
942
int TransactionServices::commitTransactionMessage(Session *in_session)
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
943
{
944
  ReplicationServices &replication_services= ReplicationServices::singleton();
945
  if (! replication_services.isActive())
1405.3.6 by Jay Pipes
Here, we do two main things:
946
    return 0;
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
947
948
  /* If there is an active statement message, finalize it */
949
  message::Statement *statement= in_session->getStatementMessage();
950
951
  if (statement != NULL)
952
  {
953
    finalizeStatementMessage(*statement, in_session);
954
  }
955
  else
1405.3.6 by Jay Pipes
Here, we do two main things:
956
    return 0; /* No data modification occurred inside the transaction */
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
957
  
958
  message::Transaction* transaction= getActiveTransactionMessage(in_session);
959
960
  finalizeTransactionMessage(*transaction, in_session);
961
  
1405.3.6 by Jay Pipes
Here, we do two main things:
962
  plugin::ReplicationReturnCode result= replication_services.pushTransactionMessage(*in_session, *transaction);
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
963
964
  cleanupTransactionMessage(transaction, in_session);
1405.3.6 by Jay Pipes
Here, we do two main things:
965
966
  return static_cast<int>(result);
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
967
}
968
969
void TransactionServices::initStatementMessage(message::Statement &statement,
970
                                        message::Statement::Type in_type,
971
                                        Session *in_session)
972
{
973
  statement.set_type(in_type);
974
  statement.set_start_timestamp(in_session->getCurrentTimestamp());
975
  /** @TODO Set sql string optionally */
976
}
977
978
void TransactionServices::finalizeStatementMessage(message::Statement &statement,
979
                                            Session *in_session)
980
{
981
  statement.set_end_timestamp(in_session->getCurrentTimestamp());
982
  in_session->setStatementMessage(NULL);
983
}
984
985
void TransactionServices::rollbackTransactionMessage(Session *in_session)
986
{
987
  ReplicationServices &replication_services= ReplicationServices::singleton();
988
  if (! replication_services.isActive())
989
    return;
990
  
991
  message::Transaction *transaction= getActiveTransactionMessage(in_session);
992
993
  /*
994
   * OK, so there are two situations that we need to deal with here:
995
   *
996
   * 1) We receive an instruction to ROLLBACK the current transaction
997
   *    and the currently-stored Transaction message is *self-contained*, 
998
   *    meaning that no Statement messages in the Transaction message
999
   *    contain a message having its segment_id member greater than 1.  If
1000
   *    no non-segment ID 1 members are found, we can simply clear the
1001
   *    current Transaction message and remove it from memory.
1002
   *
1003
   * 2) If the Transaction message does indeed have a non-end segment, that
1004
   *    means that a bulk update/delete/insert Transaction message segment
1005
   *    has previously been sent over the wire to replicators.  In this case, 
1006
   *    we need to package a Transaction with a Statement message of type
1007
   *    ROLLBACK to indicate to replicators that previously-transmitted
1008
   *    messages must be un-applied.
1009
   */
1010
  if (unlikely(message::transactionContainsBulkSegment(*transaction)))
1011
  {
1012
    /*
1013
     * Clear the transaction, create a Rollback statement message, 
1014
     * attach it to the transaction, and push it to replicators.
1015
     */
1016
    transaction->Clear();
1017
    initTransactionMessage(*transaction, in_session);
1018
1019
    message::Statement *statement= transaction->add_statement();
1020
1021
    initStatementMessage(*statement, message::Statement::ROLLBACK, in_session);
1022
    finalizeStatementMessage(*statement, in_session);
1023
1024
    finalizeTransactionMessage(*transaction, in_session);
1025
    
1405.3.3 by Jay Pipes
Adds Session reference to replication API
1026
    (void) replication_services.pushTransactionMessage(*in_session, *transaction);
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1027
  }
1028
  cleanupTransactionMessage(transaction, in_session);
1029
}
1030
1031
message::Statement &TransactionServices::getInsertStatement(Session *in_session,
1032
                                                                 Table *in_table)
1033
{
1034
  message::Statement *statement= in_session->getStatementMessage();
1035
  /*
1036
   * We check to see if the current Statement message is of type INSERT.
1037
   * If it is not, we finalize the current Statement and ensure a new
1038
   * InsertStatement is created.
1039
   */
1040
  if (statement != NULL &&
1041
      statement->type() != message::Statement::INSERT)
1042
  {
1043
    finalizeStatementMessage(*statement, in_session);
1044
    statement= in_session->getStatementMessage();
1045
  }
1046
1047
  if (statement == NULL)
1048
  {
1049
    message::Transaction *transaction= getActiveTransactionMessage(in_session);
1050
    /* 
1051
     * Transaction message initialized and set, but no statement created
1052
     * yet.  We construct one and initialize it, here, then return the
1053
     * message after attaching the new Statement message pointer to the 
1054
     * Session for easy retrieval later...
1055
     */
1056
    statement= transaction->add_statement();
1057
    setInsertHeader(*statement, in_session, in_table);
1058
    in_session->setStatementMessage(statement);
1059
  }
1060
  return *statement;
1061
}
1062
1063
void TransactionServices::setInsertHeader(message::Statement &statement,
1064
                                          Session *in_session,
1065
                                          Table *in_table)
1066
{
1067
  initStatementMessage(statement, message::Statement::INSERT, in_session);
1068
1069
  /* 
1070
   * Now we construct the specialized InsertHeader message inside
1071
   * the generalized message::Statement container...
1072
   */
1073
  /* Set up the insert header */
1074
  message::InsertHeader *header= statement.mutable_insert_header();
1075
  message::TableMetadata *table_metadata= header->mutable_table_metadata();
1076
1336.2.3 by Jay Pipes
Merge trunk and resolve
1077
  string schema_name;
1078
  (void) in_table->getShare()->getSchemaName(schema_name);
1079
  string table_name;
1080
  (void) in_table->getShare()->getTableName(table_name);
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1081
1336.2.3 by Jay Pipes
Merge trunk and resolve
1082
  table_metadata->set_schema_name(schema_name.c_str(), schema_name.length());
1083
  table_metadata->set_table_name(table_name.c_str(), table_name.length());
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1084
1085
  Field *current_field;
1578.2.16 by Brian Aker
Merge in change to getTable() to private the field objects.
1086
  Field **table_fields= in_table->getFields();
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1087
1088
  message::FieldMetadata *field_metadata;
1089
1090
  /* We will read all the table's fields... */
1091
  in_table->setReadSet();
1092
1093
  while ((current_field= *table_fields++) != NULL) 
1094
  {
1095
    field_metadata= header->add_field_metadata();
1096
    field_metadata->set_name(current_field->field_name);
1097
    field_metadata->set_type(message::internalFieldTypeToFieldProtoType(current_field->type()));
1098
  }
1099
}
1100
1101
bool TransactionServices::insertRecord(Session *in_session, Table *in_table)
1102
{
1103
  ReplicationServices &replication_services= ReplicationServices::singleton();
1104
  if (! replication_services.isActive())
1105
    return false;
1106
  /**
1107
   * We do this check here because we don't want to even create a 
1108
   * statement if there isn't a primary key on the table...
1109
   *
1110
   * @todo
1111
   *
1112
   * Multi-column primary keys are handled how exactly?
1113
   */
1618 by Brian Aker
This is a rollup set of patches for modifications to TableIdentifier to have
1114
  if (not in_table->getShare()->hasPrimaryKey())
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1115
  {
1116
    my_error(ER_NO_PRIMARY_KEY_ON_REPLICATED_TABLE, MYF(0));
1117
    return true;
1118
  }
1119
1120
  message::Statement &statement= getInsertStatement(in_session, in_table);
1121
1122
  message::InsertData *data= statement.mutable_insert_data();
1123
  data->set_segment_id(1);
1124
  data->set_end_segment(true);
1125
  message::InsertRecord *record= data->add_record();
1126
1127
  Field *current_field;
1578.2.16 by Brian Aker
Merge in change to getTable() to private the field objects.
1128
  Field **table_fields= in_table->getFields();
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1129
1130
  String *string_value= new (in_session->mem_root) String(TransactionServices::DEFAULT_RECORD_SIZE);
1131
  string_value->set_charset(system_charset_info);
1132
1133
  /* We will read all the table's fields... */
1134
  in_table->setReadSet();
1135
1136
  while ((current_field= *table_fields++) != NULL) 
1137
  {
1138
    string_value= current_field->val_str(string_value);
1139
    record->add_insert_value(string_value->c_ptr(), string_value->length());
1140
    string_value->free();
1141
  }
1142
  return false;
1143
}
1144
1145
message::Statement &TransactionServices::getUpdateStatement(Session *in_session,
1146
                                                            Table *in_table,
1147
                                                            const unsigned char *old_record, 
1148
                                                            const unsigned char *new_record)
1149
{
1150
  message::Statement *statement= in_session->getStatementMessage();
1151
  /*
1152
   * We check to see if the current Statement message is of type UPDATE.
1153
   * If it is not, we finalize the current Statement and ensure a new
1154
   * UpdateStatement is created.
1155
   */
1156
  if (statement != NULL &&
1157
      statement->type() != message::Statement::UPDATE)
1158
  {
1159
    finalizeStatementMessage(*statement, in_session);
1160
    statement= in_session->getStatementMessage();
1161
  }
1162
1163
  if (statement == NULL)
1164
  {
1165
    message::Transaction *transaction= getActiveTransactionMessage(in_session);
1166
    /* 
1167
     * Transaction message initialized and set, but no statement created
1168
     * yet.  We construct one and initialize it, here, then return the
1169
     * message after attaching the new Statement message pointer to the 
1170
     * Session for easy retrieval later...
1171
     */
1172
    statement= transaction->add_statement();
1173
    setUpdateHeader(*statement, in_session, in_table, old_record, new_record);
1174
    in_session->setStatementMessage(statement);
1175
  }
1176
  return *statement;
1177
}
1178
1179
void TransactionServices::setUpdateHeader(message::Statement &statement,
1180
                                          Session *in_session,
1181
                                          Table *in_table,
1182
                                          const unsigned char *old_record, 
1183
                                          const unsigned char *new_record)
1184
{
1185
  initStatementMessage(statement, message::Statement::UPDATE, in_session);
1186
1187
  /* 
1188
   * Now we construct the specialized UpdateHeader message inside
1189
   * the generalized message::Statement container...
1190
   */
1191
  /* Set up the update header */
1192
  message::UpdateHeader *header= statement.mutable_update_header();
1193
  message::TableMetadata *table_metadata= header->mutable_table_metadata();
1194
1336.2.3 by Jay Pipes
Merge trunk and resolve
1195
  string schema_name;
1196
  (void) in_table->getShare()->getSchemaName(schema_name);
1197
  string table_name;
1198
  (void) in_table->getShare()->getTableName(table_name);
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1199
1336.2.3 by Jay Pipes
Merge trunk and resolve
1200
  table_metadata->set_schema_name(schema_name.c_str(), schema_name.length());
1201
  table_metadata->set_table_name(table_name.c_str(), table_name.length());
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1202
1203
  Field *current_field;
1578.2.16 by Brian Aker
Merge in change to getTable() to private the field objects.
1204
  Field **table_fields= in_table->getFields();
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1205
1206
  message::FieldMetadata *field_metadata;
1207
1208
  /* We will read all the table's fields... */
1209
  in_table->setReadSet();
1210
1211
  while ((current_field= *table_fields++) != NULL) 
1212
  {
1213
    /*
1214
     * We add the "key field metadata" -- i.e. the fields which is
1215
     * the primary key for the table.
1216
     */
1574 by Brian Aker
Rollup patch for hiding tableshare.
1217
    if (in_table->getShare()->fieldInPrimaryKey(current_field))
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1218
    {
1219
      field_metadata= header->add_key_field_metadata();
1220
      field_metadata->set_name(current_field->field_name);
1221
      field_metadata->set_type(message::internalFieldTypeToFieldProtoType(current_field->type()));
1222
    }
1223
1224
    /*
1225
     * The below really should be moved into the Field API and Record API.  But for now
1226
     * we do this crazy pointer fiddling to figure out if the current field
1227
     * has been updated in the supplied record raw byte pointers.
1228
     */
1229
    const unsigned char *old_ptr= (const unsigned char *) old_record + (ptrdiff_t) (current_field->ptr - in_table->record[0]); 
1230
    const unsigned char *new_ptr= (const unsigned char *) new_record + (ptrdiff_t) (current_field->ptr - in_table->record[0]); 
1231
1232
    uint32_t field_length= current_field->pack_length(); /** @TODO This isn't always correct...check varchar diffs. */
1233
1234
    if (memcmp(old_ptr, new_ptr, field_length) != 0)
1235
    {
1236
      /* Field is changed from old to new */
1237
      field_metadata= header->add_set_field_metadata();
1238
      field_metadata->set_name(current_field->field_name);
1239
      field_metadata->set_type(message::internalFieldTypeToFieldProtoType(current_field->type()));
1240
    }
1241
  }
1242
}
1243
void TransactionServices::updateRecord(Session *in_session,
1244
                                       Table *in_table, 
1245
                                       const unsigned char *old_record, 
1246
                                       const unsigned char *new_record)
1247
{
1248
  ReplicationServices &replication_services= ReplicationServices::singleton();
1249
  if (! replication_services.isActive())
1250
    return;
1251
1252
  message::Statement &statement= getUpdateStatement(in_session, in_table, old_record, new_record);
1253
1254
  message::UpdateData *data= statement.mutable_update_data();
1255
  data->set_segment_id(1);
1256
  data->set_end_segment(true);
1257
  message::UpdateRecord *record= data->add_record();
1258
1259
  Field *current_field;
1578.2.16 by Brian Aker
Merge in change to getTable() to private the field objects.
1260
  Field **table_fields= in_table->getFields();
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1261
  String *string_value= new (in_session->mem_root) String(TransactionServices::DEFAULT_RECORD_SIZE);
1262
  string_value->set_charset(system_charset_info);
1263
1264
  while ((current_field= *table_fields++) != NULL) 
1265
  {
1266
    /*
1267
     * Here, we add the SET field values.  We used to do this in the setUpdateHeader() method, 
1268
     * but then realized that an UPDATE statement could potentially have different values for
1269
     * the SET field.  For instance, imagine this SQL scenario:
1270
     *
1271
     * CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY, count INT NOT NULL);
1272
     * INSERT INTO t1 (id, counter) VALUES (1,1),(2,2),(3,3);
1273
     * UPDATE t1 SET counter = counter + 1 WHERE id IN (1,2);
1274
     *
1275
     * We will generate two UpdateRecord messages with different set_value byte arrays.
1276
     *
1277
     * The below really should be moved into the Field API and Record API.  But for now
1278
     * we do this crazy pointer fiddling to figure out if the current field
1279
     * has been updated in the supplied record raw byte pointers.
1280
     */
1281
    const unsigned char *old_ptr= (const unsigned char *) old_record + (ptrdiff_t) (current_field->ptr - in_table->record[0]); 
1282
    const unsigned char *new_ptr= (const unsigned char *) new_record + (ptrdiff_t) (current_field->ptr - in_table->record[0]); 
1283
1284
    uint32_t field_length= current_field->pack_length(); /** @TODO This isn't always correct...check varchar diffs. */
1285
1286
    if (memcmp(old_ptr, new_ptr, field_length) != 0)
1287
    {
1288
      /* Store the original "read bit" for this field */
1289
      bool is_read_set= current_field->isReadSet();
1290
1291
      /* We need to mark that we will "read" this field... */
1292
      in_table->setReadSet(current_field->field_index);
1293
1294
      /* Read the string value of this field's contents */
1295
      string_value= current_field->val_str(string_value);
1296
1297
      /* 
1298
       * Reset the read bit after reading field to its original state.  This 
1299
       * prevents the field from being included in the WHERE clause
1300
       */
1301
      current_field->setReadSet(is_read_set);
1302
1303
      record->add_after_value(string_value->c_ptr(), string_value->length());
1304
      string_value->free();
1305
    }
1306
1307
    /* 
1308
     * Add the WHERE clause values now...for now, this means the
1309
     * primary key field value.  Replication only supports tables
1310
     * with a primary key.
1311
     */
1574 by Brian Aker
Rollup patch for hiding tableshare.
1312
    if (in_table->getShare()->fieldInPrimaryKey(current_field))
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1313
    {
1314
      /**
1315
       * To say the below is ugly is an understatement. But it works.
1316
       * 
1317
       * @todo Move this crap into a real Record API.
1318
       */
1319
      string_value= current_field->val_str(string_value,
1320
                                           old_record + 
1321
                                           current_field->offset(const_cast<unsigned char *>(new_record)));
1322
      record->add_key_value(string_value->c_ptr(), string_value->length());
1323
      string_value->free();
1324
    }
1325
1326
  }
1327
}
1328
1329
message::Statement &TransactionServices::getDeleteStatement(Session *in_session,
1330
                                                            Table *in_table)
1331
{
1332
  message::Statement *statement= in_session->getStatementMessage();
1333
  /*
1334
   * We check to see if the current Statement message is of type DELETE.
1335
   * If it is not, we finalize the current Statement and ensure a new
1336
   * DeleteStatement is created.
1337
   */
1338
  if (statement != NULL &&
1339
      statement->type() != message::Statement::DELETE)
1340
  {
1341
    finalizeStatementMessage(*statement, in_session);
1342
    statement= in_session->getStatementMessage();
1343
  }
1344
1345
  if (statement == NULL)
1346
  {
1347
    message::Transaction *transaction= getActiveTransactionMessage(in_session);
1348
    /* 
1349
     * Transaction message initialized and set, but no statement created
1350
     * yet.  We construct one and initialize it, here, then return the
1351
     * message after attaching the new Statement message pointer to the 
1352
     * Session for easy retrieval later...
1353
     */
1354
    statement= transaction->add_statement();
1355
    setDeleteHeader(*statement, in_session, in_table);
1356
    in_session->setStatementMessage(statement);
1357
  }
1358
  return *statement;
1359
}
1360
1361
void TransactionServices::setDeleteHeader(message::Statement &statement,
1362
                                          Session *in_session,
1363
                                          Table *in_table)
1364
{
1365
  initStatementMessage(statement, message::Statement::DELETE, in_session);
1366
1367
  /* 
1368
   * Now we construct the specialized DeleteHeader message inside
1369
   * the generalized message::Statement container...
1370
   */
1371
  message::DeleteHeader *header= statement.mutable_delete_header();
1372
  message::TableMetadata *table_metadata= header->mutable_table_metadata();
1373
1336.2.3 by Jay Pipes
Merge trunk and resolve
1374
  string schema_name;
1375
  (void) in_table->getShare()->getSchemaName(schema_name);
1376
  string table_name;
1377
  (void) in_table->getShare()->getTableName(table_name);
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1378
1336.2.3 by Jay Pipes
Merge trunk and resolve
1379
  table_metadata->set_schema_name(schema_name.c_str(), schema_name.length());
1380
  table_metadata->set_table_name(table_name.c_str(), table_name.length());
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1381
1382
  Field *current_field;
1578.2.16 by Brian Aker
Merge in change to getTable() to private the field objects.
1383
  Field **table_fields= in_table->getFields();
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1384
1385
  message::FieldMetadata *field_metadata;
1386
1387
  while ((current_field= *table_fields++) != NULL) 
1388
  {
1389
    /* 
1390
     * Add the WHERE clause values now...for now, this means the
1391
     * primary key field value.  Replication only supports tables
1392
     * with a primary key.
1393
     */
1574 by Brian Aker
Rollup patch for hiding tableshare.
1394
    if (in_table->getShare()->fieldInPrimaryKey(current_field))
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1395
    {
1396
      field_metadata= header->add_key_field_metadata();
1397
      field_metadata->set_name(current_field->field_name);
1398
      field_metadata->set_type(message::internalFieldTypeToFieldProtoType(current_field->type()));
1399
    }
1400
  }
1401
}
1402
1403
void TransactionServices::deleteRecord(Session *in_session, Table *in_table)
1404
{
1405
  ReplicationServices &replication_services= ReplicationServices::singleton();
1406
  if (! replication_services.isActive())
1407
    return;
1408
1409
  message::Statement &statement= getDeleteStatement(in_session, in_table);
1410
1411
  message::DeleteData *data= statement.mutable_delete_data();
1412
  data->set_segment_id(1);
1413
  data->set_end_segment(true);
1414
  message::DeleteRecord *record= data->add_record();
1415
1416
  Field *current_field;
1578.2.16 by Brian Aker
Merge in change to getTable() to private the field objects.
1417
  Field **table_fields= in_table->getFields();
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1418
  String *string_value= new (in_session->mem_root) String(TransactionServices::DEFAULT_RECORD_SIZE);
1419
  string_value->set_charset(system_charset_info);
1420
1421
  while ((current_field= *table_fields++) != NULL) 
1422
  {
1423
    /* 
1424
     * Add the WHERE clause values now...for now, this means the
1425
     * primary key field value.  Replication only supports tables
1426
     * with a primary key.
1427
     */
1574 by Brian Aker
Rollup patch for hiding tableshare.
1428
    if (in_table->getShare()->fieldInPrimaryKey(current_field))
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1429
    {
1430
      string_value= current_field->val_str(string_value);
1431
      record->add_key_value(string_value->c_ptr(), string_value->length());
1432
      /**
1433
       * @TODO Store optional old record value in the before data member
1434
       */
1435
      string_value->free();
1436
    }
1437
  }
1438
}
1439
1440
void TransactionServices::createTable(Session *in_session,
1441
                                      const message::Table &table)
1442
{
1443
  ReplicationServices &replication_services= ReplicationServices::singleton();
1444
  if (! replication_services.isActive())
1445
    return;
1446
  
1447
  message::Transaction *transaction= getActiveTransactionMessage(in_session);
1448
  message::Statement *statement= transaction->add_statement();
1449
1450
  initStatementMessage(*statement, message::Statement::CREATE_TABLE, in_session);
1451
1452
  /* 
1453
   * Construct the specialized CreateTableStatement message and attach
1454
   * it to the generic Statement message
1455
   */
1456
  message::CreateTableStatement *create_table_statement= statement->mutable_create_table_statement();
1457
  message::Table *new_table_message= create_table_statement->mutable_table();
1458
  *new_table_message= table;
1459
1460
  finalizeStatementMessage(*statement, in_session);
1461
1462
  finalizeTransactionMessage(*transaction, in_session);
1463
  
1405.3.3 by Jay Pipes
Adds Session reference to replication API
1464
  (void) replication_services.pushTransactionMessage(*in_session, *transaction);
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1465
1466
  cleanupTransactionMessage(transaction, in_session);
1467
1468
}
1469
1470
void TransactionServices::createSchema(Session *in_session,
1471
                                       const message::Schema &schema)
1472
{
1473
  ReplicationServices &replication_services= ReplicationServices::singleton();
1474
  if (! replication_services.isActive())
1475
    return;
1476
  
1477
  message::Transaction *transaction= getActiveTransactionMessage(in_session);
1478
  message::Statement *statement= transaction->add_statement();
1479
1480
  initStatementMessage(*statement, message::Statement::CREATE_SCHEMA, in_session);
1481
1482
  /* 
1483
   * Construct the specialized CreateSchemaStatement message and attach
1484
   * it to the generic Statement message
1485
   */
1486
  message::CreateSchemaStatement *create_schema_statement= statement->mutable_create_schema_statement();
1487
  message::Schema *new_schema_message= create_schema_statement->mutable_schema();
1488
  *new_schema_message= schema;
1489
1490
  finalizeStatementMessage(*statement, in_session);
1491
1492
  finalizeTransactionMessage(*transaction, in_session);
1493
  
1405.3.3 by Jay Pipes
Adds Session reference to replication API
1494
  (void) replication_services.pushTransactionMessage(*in_session, *transaction);
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1495
1496
  cleanupTransactionMessage(transaction, in_session);
1497
1498
}
1499
1500
void TransactionServices::dropSchema(Session *in_session, const string &schema_name)
1501
{
1502
  ReplicationServices &replication_services= ReplicationServices::singleton();
1503
  if (! replication_services.isActive())
1504
    return;
1505
  
1506
  message::Transaction *transaction= getActiveTransactionMessage(in_session);
1507
  message::Statement *statement= transaction->add_statement();
1508
1509
  initStatementMessage(*statement, message::Statement::DROP_SCHEMA, in_session);
1510
1511
  /* 
1512
   * Construct the specialized DropSchemaStatement message and attach
1513
   * it to the generic Statement message
1514
   */
1515
  message::DropSchemaStatement *drop_schema_statement= statement->mutable_drop_schema_statement();
1516
1517
  drop_schema_statement->set_schema_name(schema_name);
1518
1519
  finalizeStatementMessage(*statement, in_session);
1520
1521
  finalizeTransactionMessage(*transaction, in_session);
1522
  
1405.3.3 by Jay Pipes
Adds Session reference to replication API
1523
  (void) replication_services.pushTransactionMessage(*in_session, *transaction);
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1524
1525
  cleanupTransactionMessage(transaction, in_session);
1526
}
1527
1528
void TransactionServices::dropTable(Session *in_session,
1529
                                    const string &schema_name,
1530
                                    const string &table_name,
1531
                                    bool if_exists)
1532
{
1533
  ReplicationServices &replication_services= ReplicationServices::singleton();
1534
  if (! replication_services.isActive())
1535
    return;
1536
  
1537
  message::Transaction *transaction= getActiveTransactionMessage(in_session);
1538
  message::Statement *statement= transaction->add_statement();
1539
1540
  initStatementMessage(*statement, message::Statement::DROP_TABLE, in_session);
1541
1542
  /* 
1543
   * Construct the specialized DropTableStatement message and attach
1544
   * it to the generic Statement message
1545
   */
1546
  message::DropTableStatement *drop_table_statement= statement->mutable_drop_table_statement();
1547
1548
  drop_table_statement->set_if_exists_clause(if_exists);
1549
1550
  message::TableMetadata *table_metadata= drop_table_statement->mutable_table_metadata();
1551
1552
  table_metadata->set_schema_name(schema_name);
1553
  table_metadata->set_table_name(table_name);
1554
1555
  finalizeStatementMessage(*statement, in_session);
1556
1557
  finalizeTransactionMessage(*transaction, in_session);
1558
  
1405.3.3 by Jay Pipes
Adds Session reference to replication API
1559
  (void) replication_services.pushTransactionMessage(*in_session, *transaction);
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1560
1561
  cleanupTransactionMessage(transaction, in_session);
1562
}
1563
1564
void TransactionServices::truncateTable(Session *in_session, Table *in_table)
1565
{
1566
  ReplicationServices &replication_services= ReplicationServices::singleton();
1567
  if (! replication_services.isActive())
1568
    return;
1569
  
1570
  message::Transaction *transaction= getActiveTransactionMessage(in_session);
1571
  message::Statement *statement= transaction->add_statement();
1572
1573
  initStatementMessage(*statement, message::Statement::TRUNCATE_TABLE, in_session);
1574
1575
  /* 
1576
   * Construct the specialized TruncateTableStatement message and attach
1577
   * it to the generic Statement message
1578
   */
1579
  message::TruncateTableStatement *truncate_statement= statement->mutable_truncate_table_statement();
1580
  message::TableMetadata *table_metadata= truncate_statement->mutable_table_metadata();
1581
1336.2.3 by Jay Pipes
Merge trunk and resolve
1582
  string schema_name;
1583
  (void) in_table->getShare()->getSchemaName(schema_name);
1584
  string table_name;
1585
  (void) in_table->getShare()->getTableName(table_name);
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1586
1336.2.3 by Jay Pipes
Merge trunk and resolve
1587
  table_metadata->set_schema_name(schema_name.c_str(), schema_name.length());
1588
  table_metadata->set_table_name(table_name.c_str(), table_name.length());
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1589
1590
  finalizeStatementMessage(*statement, in_session);
1591
1592
  finalizeTransactionMessage(*transaction, in_session);
1593
  
1405.3.3 by Jay Pipes
Adds Session reference to replication API
1594
  (void) replication_services.pushTransactionMessage(*in_session, *transaction);
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1595
1596
  cleanupTransactionMessage(transaction, in_session);
1597
}
1598
1599
void TransactionServices::rawStatement(Session *in_session, const string &query)
1600
{
1601
  ReplicationServices &replication_services= ReplicationServices::singleton();
1602
  if (! replication_services.isActive())
1603
    return;
1604
  
1605
  message::Transaction *transaction= getActiveTransactionMessage(in_session);
1606
  message::Statement *statement= transaction->add_statement();
1607
1608
  initStatementMessage(*statement, message::Statement::RAW_SQL, in_session);
1609
  statement->set_sql(query);
1610
  finalizeStatementMessage(*statement, in_session);
1611
1612
  finalizeTransactionMessage(*transaction, in_session);
1613
  
1405.3.3 by Jay Pipes
Adds Session reference to replication API
1614
  (void) replication_services.pushTransactionMessage(*in_session, *transaction);
1336.2.2 by Jay Pipes
NO CODE CHANGES - Simply moves pieces of ReplicationServices to TransactionServices. Preparation for making the ReplicationServices component only responsible for communication between replicators, appliers, publishers, and subscribers.
1615
1616
  cleanupTransactionMessage(transaction, in_session);
1617
}
1618
1273.1.2 by Jay Pipes
This patch does not change any algorithms or code paths,
1619
} /* namespace drizzled */