Drizzled Public API Documentation

rollback_to_savepoint.cc
1 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3  *
4  * Copyright (C) 2009 Sun Microsystems, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
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 #include <config.h>
22 #include <drizzled/show.h>
23 #include <drizzled/session.h>
24 #include <drizzled/statement/rollback_to_savepoint.h>
25 #include <drizzled/transaction_services.h>
26 #include <drizzled/named_savepoint.h>
27 #include <drizzled/util/functors.h>
28 #include <drizzled/session/transactions.h>
29 
30 #include <string>
31 
32 using namespace std;
33 
34 namespace drizzled {
35 
36 bool statement::RollbackToSavepoint::execute()
37 {
38  /*
39  * If AUTOCOMMIT is off and resource contexts are empty then we need
40  * to start a transaction. It will be empty when ROLLBACK TO SAVEPOINT
41  * starts the transaction. Table affecting statements do this work in
42  * lockTables() by calling startStatement().
43  */
44  if ( (session().options & OPTION_NOT_AUTOCOMMIT) &&
45  (transaction().all.getResourceContexts().empty() == true) )
46  {
47  if (session().startTransaction() == false)
48  {
49  return false;
50  }
51  }
52 
53  /*
54  * Handle these situations:
55  *
56  * If the first savepoint on the deck matches the
57  * name to find, simply call rollback_to_savepoint
58  * for the resource managers.
59  *
60  * If the first savepoint on the deck does NOT match
61  * the name to find, then we need to search through
62  * the deque to find the savepoint we need. If we
63  * don't find it, we return an error. If we do
64  * find it, we must restructure the deque by removing
65  * all savepoints "above" the one we find.
66  */
67  deque<NamedSavepoint> &savepoints= transaction().savepoints;
68 
69  /* Short-circuit for no savepoints */
70  if (savepoints.empty())
71  {
72  my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex().ident.data());
73  return false;
74  }
75 
76  {
77  /* Short-circuit for first savepoint */
78  NamedSavepoint &first_savepoint= savepoints.front();
79  const string &first_savepoint_name= first_savepoint.getName();
80  if (my_strnncoll(system_charset_info,
81  (unsigned char *) lex().ident.data(),
82  lex().ident.size(),
83  (unsigned char *) first_savepoint_name.c_str(),
84  first_savepoint_name.size()) == 0)
85  {
86  /* Found the named savepoint we want to rollback to */
87  (void) TransactionServices::rollbackToSavepoint(session(), first_savepoint);
88 
89  if (transaction().all.hasModifiedNonTransData())
90  {
91  push_warning(&session(),
92  DRIZZLE_ERROR::WARN_LEVEL_WARN,
93  ER_WARNING_NOT_COMPLETE_ROLLBACK,
94  ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
95  }
96  session().my_ok();
97  return false;
98  }
99  }
100 
101  /*
102  * OK, from here on out it means that we have savepoints
103  * but that the first savepoint isn't the one we're looking
104  * for. We need to search through the savepoints and find
105  * the one we're looking for, removing all savepoints "above"
106  * the one we need.
107  */
108  bool found= false;
109  deque<NamedSavepoint> copy_savepoints(savepoints); /* used to restore if not found */
110  deque<NamedSavepoint> new_savepoints;
111  while (savepoints.empty() == false)
112  {
113  NamedSavepoint &sv= savepoints.front();
114  const string &sv_name= sv.getName();
115  if (! found &&
116  my_strnncoll(system_charset_info,
117  (unsigned char *) lex().ident.data(),
118  lex().ident.size(),
119  (unsigned char *) sv_name.c_str(),
120  sv_name.size()) == 0)
121  {
122  /* Found the named savepoint we want to rollback to */
123  found= true;
124 
125  (void) TransactionServices::rollbackToSavepoint(session(), sv);
126  }
127  if (found)
128  {
129  /*
130  * We push all savepoints "below" the found savepoint
131  * to our new savepoint list, in reverse order to keep
132  * the stack order correct.
133  */
134  new_savepoints.push_back(sv);
135  }
136  savepoints.pop_front();
137  }
138  if (found)
139  {
140  if (transaction().all.hasModifiedNonTransData())
141  {
142  push_warning(&session(),
143  DRIZZLE_ERROR::WARN_LEVEL_WARN,
144  ER_WARNING_NOT_COMPLETE_ROLLBACK,
145  ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
146  }
147  /* Store new savepoints list */
148  transaction().savepoints= new_savepoints;
149  session().my_ok();
150  }
151  else
152  {
153  /* restore the original savepoint list */
154  transaction().savepoints= copy_savepoints;
155  my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex().ident.data());
156  }
157  return false;
158 }
159 
160 } /* namespace drizzled */