Skip to content

Commit d33f18e

Browse files
committed
Merge remote-tracking branch 'origin/master' into wl11451-jdbc
2 parents 926ca01 + d1c4479 commit d33f18e

File tree

15 files changed

+453
-29
lines changed

15 files changed

+453
-29
lines changed

common/op_impl.h

Lines changed: 91 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,7 +1042,9 @@ struct Op_admin
10421042
They are implemented as Op_trx template parametrized by operation type.
10431043
*/
10441044

1045-
enum class Trx_op { BEGIN, COMMIT, ROLLBACK };
1045+
enum class Trx_op {
1046+
BEGIN, COMMIT, ROLLBACK, SAVEPOINT_SET, SAVEPOINT_REMOVE
1047+
};
10461048

10471049

10481050
template <Trx_op>
@@ -1078,13 +1080,96 @@ cdk::Reply* Op_trx<Trx_op::COMMIT>::send_command()
10781080
return nullptr;
10791081
}
10801082

1083+
1084+
struct Op_trx_savepoint
1085+
: public Op_base<common::Executable_if>
1086+
{
1087+
using string = cdk::string;
1088+
1089+
string m_name;
1090+
1091+
Op_trx_savepoint(Shared_session_impl sess, const string &name = string())
1092+
: Op_base(sess), m_name(name)
1093+
{}
1094+
};
1095+
1096+
10811097
template<>
1082-
inline
1083-
cdk::Reply* Op_trx<Trx_op::ROLLBACK>::send_command()
1098+
struct Op_trx<Trx_op::ROLLBACK>
1099+
: public Op_trx_savepoint
10841100
{
1085-
get_cdk_session().rollback();
1086-
return nullptr;
1087-
}
1101+
using Op_trx_savepoint::Op_trx_savepoint;
1102+
1103+
cdk::Reply* send_command() override
1104+
{
1105+
get_cdk_session().rollback(m_name);
1106+
return nullptr;
1107+
}
1108+
1109+
Executable_if* clone() const override
1110+
{
1111+
return new Op_trx(*this);
1112+
}
1113+
};
1114+
1115+
1116+
template<>
1117+
struct Op_trx<Trx_op::SAVEPOINT_SET>
1118+
: public Op_trx_savepoint
1119+
{
1120+
Op_trx(Shared_session_impl sess, const string &name)
1121+
: Op_trx_savepoint(sess, name)
1122+
{
1123+
if (!name.empty())
1124+
return;
1125+
1126+
// Generate savepoint name.
1127+
1128+
std::wstringstream savepoint;
1129+
savepoint << L"SP" << sess->next_savepoint();
1130+
m_name = savepoint.str();
1131+
}
1132+
1133+
cdk::Reply* send_command() override
1134+
{
1135+
get_cdk_session().savepoint_set(m_name);
1136+
return nullptr;
1137+
}
1138+
1139+
const string& get_name() const
1140+
{
1141+
return m_name;
1142+
}
1143+
1144+
Executable_if* clone() const override
1145+
{
1146+
return new Op_trx(*this);
1147+
}
1148+
};
1149+
1150+
1151+
template<>
1152+
struct Op_trx<Trx_op::SAVEPOINT_REMOVE>
1153+
: public Op_trx_savepoint
1154+
{
1155+
Op_trx(Shared_session_impl sess, const string &name)
1156+
: Op_trx_savepoint(sess, name)
1157+
{
1158+
if (name.empty())
1159+
throw_error("Invalid empty save point name");
1160+
}
1161+
1162+
cdk::Reply* send_command() override
1163+
{
1164+
get_cdk_session().savepoint_remove(m_name);
1165+
return nullptr;
1166+
}
1167+
1168+
Executable_if* clone() const override
1169+
{
1170+
return new Op_trx(*this);
1171+
}
1172+
};
10881173

10891174

10901175
// ----------------------------------------------------------------------

common/session.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@ class Session_impl
106106

107107
void prepare_for_cmd();
108108

109+
unsigned long m_savepoint = 0;
110+
111+
unsigned long next_savepoint()
112+
{
113+
return ++m_savepoint;
114+
}
109115
};
110116

111117

devapi/session.cc

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -150,28 +150,35 @@ void internal::Session_detail::close()
150150

151151
void internal::Session_detail::start_transaction()
152152
{
153-
try {
154-
get_cdk_session().begin();
155-
}
156-
CATCH_AND_WRAP
153+
common::Op_trx<common::Trx_op::BEGIN> cmd(m_impl);
154+
cmd.execute();
157155
}
158156

159157

160158
void internal::Session_detail::commit()
161159
{
162-
try {
163-
get_cdk_session().commit();
164-
}
165-
CATCH_AND_WRAP
160+
common::Op_trx<common::Trx_op::COMMIT> cmd(m_impl);
161+
cmd.execute();
166162
}
167163

168164

169-
void internal::Session_detail::rollback()
165+
void internal::Session_detail::rollback(const string &sp)
170166
{
171-
try {
172-
get_cdk_session().rollback();
173-
}
174-
CATCH_AND_WRAP
167+
common::Op_trx<common::Trx_op::ROLLBACK> cmd(m_impl, sp);
168+
cmd.execute();
169+
}
170+
171+
string internal::Session_detail::savepoint_set(const string &sp)
172+
{
173+
common::Op_trx<common::Trx_op::SAVEPOINT_SET> cmd(m_impl, sp);
174+
cmd.execute();
175+
return cmd.get_name();
176+
}
177+
178+
void internal::Session_detail::savepoint_remove(const string &sp)
179+
{
180+
common::Op_trx<common::Trx_op::SAVEPOINT_REMOVE> cmd(m_impl, sp);
181+
cmd.execute();
175182
}
176183

177184

devapi/tests/bugs-t.cc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,28 @@ TEST_F(Bugs, bug26130226_crash_update)
109109
tabNew.update().set((char *)0, expr("")).execute(), // SegFault
110110
Error);
111111
}
112+
113+
TEST_F(Bugs, bug_26962725_double_bind)
114+
{
115+
get_sess().dropSchema("bug_26962725_double_bind");
116+
Schema db = get_sess().createSchema("bug_26962725_double_bind");
117+
/// Collection.find() function with fixed values
118+
119+
db.dropCollection("my_collection");
120+
Collection myColl = db.createCollection("my_collection");
121+
122+
myColl.add(R"({"name":"mike", "age":39})")
123+
.add(R"({"name":"johannes", "age":28})")
124+
.execute();
125+
126+
EXPECT_EQ(2, myColl.find().execute().count());
127+
128+
// Create Collection.remove() operation, but do not run it yet
129+
auto myRemove = myColl.remove("name = :param1 AND age = :param2");
130+
131+
// Binding parameters to the prepared function and .execute()
132+
myRemove.bind("param1", "mike").bind("param2", 39).execute();
133+
myRemove.bind("param1", "johannes").bind("param2", 28).execute();
134+
135+
EXPECT_EQ(0, myColl.find().execute().count());
136+
}

devapi/tests/session-t.cc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,37 @@ TEST_F(Sess, trx)
262262
EXPECT_FALSE(doc.hasField("bar"));
263263
}
264264

265+
//With Savepoints!
266+
267+
get_sess().startTransaction();
268+
269+
std::vector<string> savepoints;
270+
271+
coll.add("{\"bar\": 5}").execute();
272+
savepoints.emplace_back(get_sess().setSavepoint()); //savepoints[0]
273+
coll.add("{\"bar\": 6}").execute();
274+
savepoints.emplace_back(get_sess().setSavepoint()); //savepoints[1]
275+
coll.add("{\"bar\": 7}").execute();
276+
savepoints.emplace_back(get_sess().setSavepoint()); //savepoints[2]
277+
coll.add("{\"bar\": 8}").execute();
278+
savepoints.emplace_back(get_sess().setSavepoint("MySave")); //savepoints[3]
279+
280+
get_sess().releaseSavepoint("MySave");
281+
EXPECT_THROW(get_sess().releaseSavepoint(savepoints.back()), Error);
282+
savepoints.pop_back();
283+
// rollback to bar:6
284+
get_sess().rollbackTo(savepoints[1]);
285+
//savepoint of bar:7 was removed because of the rollback to bar:6
286+
EXPECT_THROW(get_sess().rollbackTo(savepoints[2]), Error);
287+
EXPECT_THROW(get_sess().rollbackTo(""), Error);
288+
get_sess().rollbackTo(savepoints.front());
289+
get_sess().commit();
290+
291+
cout << "Collection has " << coll.count()
292+
<< " documents." << endl;
293+
294+
EXPECT_EQ(3U, coll.count());
295+
265296
cout << "Done!" << endl;
266297
}
267298

include/mysqlx/devapi/detail/session.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,9 @@ struct PUBLIC_API Session_detail
317317

318318
void start_transaction();
319319
void commit();
320-
void rollback();
320+
void rollback(const string &sp = string());
321+
string savepoint_set(const string &sp = string());
322+
void savepoint_remove(const string&);
321323

322324

323325
common::Session_impl& get_impl()

include/mysqlx/xapi.h

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -731,7 +731,7 @@ mysqlx_transaction_commit(mysqlx_session_t *sess);
731731

732732

733733
/**
734-
Rollback a transaction for the session.
734+
Roll back a transaction for the session.
735735
736736
@param sess session handle
737737
@@ -748,6 +748,61 @@ PUBLIC_API int
748748
mysqlx_transaction_rollback(mysqlx_session_t *sess);
749749

750750

751+
/**
752+
Create savepoint inside transaction.
753+
754+
@param sess session handle.
755+
756+
@param name savepoint name (NULL for automatically generated one)
757+
758+
@return savepoint name
759+
760+
@note Savepoints are created inside transaction! Later, you can roll back
761+
the transaction to a created savepoint using mysqlx_rollback_to().
762+
If the current transaction has a savepoint with the same name, the old
763+
savepoint is deleted and a new one is set.
764+
765+
@ingroup xapi_sess
766+
*/
767+
768+
PUBLIC_API const char*
769+
mysqlx_savepoint_set( mysqlx_session_t *sess, const char *name);
770+
771+
772+
/**
773+
Release savepoint created by mysqlx_savepoint_set().
774+
775+
@param sess session handle
776+
777+
@param name savepoint name to be released
778+
779+
@return `RESULT_OK` - savepoint exists and is released;
780+
`RESULT_ERR` - on error
781+
782+
@ingroup xapi_sess
783+
*/
784+
785+
PUBLIC_API int
786+
mysqlx_savepoint_release(mysqlx_session_t *sess, const char *name);
787+
788+
789+
/**
790+
Roll back to savepoint created by mysqlx_savepoint_set().
791+
792+
@param sess session handle.
793+
794+
@param name savepoint name.
795+
796+
@return `RESULT_OK` - savepoint exists and is released;
797+
`RESULT_ERR` - on error.
798+
799+
@ingroup xapi_sess
800+
*/
801+
802+
PUBLIC_API int
803+
mysqlx_rollback_to( mysqlx_session_t *sess, const char *name);
804+
805+
751806
/**
752807
Allocate a new session configuration data object.
753808

0 commit comments

Comments
 (0)