Skip to content

Commit 1f54c14

Browse files
committed
Bug #29390170: MOVE SEMANTICS NOT USED FOR CRUD OPERATIONS
Affecting same object will not trigger a new object, so not loosing the Prepare state. PS id can be shared with multiple operations.
1 parent 7e8b2bd commit 1f54c14

File tree

6 files changed

+258
-54
lines changed

6 files changed

+258
-54
lines changed

common/op_impl.h

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ class Op_base
101101

102102
using string = std::string;
103103
using Shared_session_impl = shared_ptr<Session_impl>;
104+
using Shared_stmt_id = shared_ptr<uint32_t>;
104105

105106
Shared_session_impl m_sess;
106107

@@ -110,7 +111,7 @@ class Op_base
110111
*/
111112
cdk::scoped_ptr<cdk::Reply> m_reply;
112113

113-
uint32_t m_stmt_id = 0;
114+
Shared_stmt_id m_stmt_id;
114115
Prepare_state m_prepare_state = PS_EXECUTE;
115116
bool m_inited = false;
116117
bool m_completed = false;
@@ -130,14 +131,13 @@ class Op_base
130131

131132
Op_base(const Op_base& other)
132133
: m_sess(other.m_sess)
134+
, m_stmt_id(other.m_stmt_id)
135+
, m_prepare_state(other.m_prepare_state)
133136
{}
134137

135-
virtual ~Op_base()
138+
virtual ~Op_base() override
136139
{
137-
if (m_stmt_id != 0)
138-
{
139-
m_sess->release_stmt_id(m_stmt_id);
140-
}
140+
release_stmt_id();
141141
}
142142

143143
cdk::Session& get_cdk_session()
@@ -148,19 +148,23 @@ class Op_base
148148

149149
uint32_t create_stmt_id()
150150
{
151-
if (m_stmt_id == 0)
151+
assert(m_sess);
152+
if (!m_stmt_id.unique())
152153
{
153-
assert(m_sess);
154-
m_stmt_id = m_sess->create_stmt_id();
154+
uint32_t id = m_sess->create_stmt_id();
155+
if(id != 0)
156+
m_stmt_id.reset(new uint32_t(id));
157+
else
158+
m_stmt_id.reset();
155159
}
156-
return m_stmt_id;
160+
return get_stmt_id();
157161
}
158162

159163
void release_stmt_id()
160164
{
161-
if (m_stmt_id != 0)
162-
m_sess->release_stmt_id(m_stmt_id);
163-
m_stmt_id = 0;
165+
if (m_stmt_id.unique())
166+
m_sess->release_stmt_id(*m_stmt_id);
167+
m_stmt_id.reset();
164168
}
165169

166170

@@ -171,9 +175,9 @@ class Op_base
171175

172176
void reset_state()
173177
{
174-
if (m_stmt_id != 0)
175-
get_session()->error_stmt_id(m_stmt_id);
176-
m_stmt_id = 0;
178+
if (m_stmt_id.unique())
179+
get_session()->error_stmt_id(*m_stmt_id);
180+
m_stmt_id.reset();
177181
m_prepare_state = PS_EXECUTE;
178182
m_reply.reset();
179183
m_inited = false;
@@ -182,7 +186,7 @@ class Op_base
182186

183187
uint32_t get_stmt_id()
184188
{
185-
return m_stmt_id;
189+
return m_stmt_id ? *m_stmt_id.get() : 0;
186190
}
187191

188192
Prepare_state get_prepare_state()
@@ -475,23 +479,25 @@ class Op_base
475479
auto prepare = get_prepare_state();
476480

477481
/*
478-
Upon first execution, get_executed() and get_re_prepare() are false and
479-
get_stmt_id() is 0. The new statement id is not allocated yet and function
480-
returns false, meaning that the statement will be executed directly
481-
without preparing.
482+
Upon first execution, prepare is on PS_EXECUTE state and get_stmt_id() is
483+
0. The new statement id is not allocated yet and function returns false,
484+
meaning that the statement will be executed directly without preparing.
485+
Also, prepare is set to PS_PREPARE_EXECUTE.
482486
483-
On next execution, get_executed() and get_re_prepare() are true. Then new
487+
On next execution, prepare is then on PS_PREPARE_EXECUTE. Then new
484488
PS id is allocated and function returns false, meaning that the statement
485-
gets prepared and executed. Also, the re-prepare flag is cleared.
489+
gets prepared and executed. Also, the state is set to PS_EXECUTE_PREPARED.
486490
487-
On 3rd and following executions, if re-prepare flag stays false, this
491+
On 3rd and following executions, if state stays PS_EXECUTE_PREPARED, this
488492
function will return true meaning that the prepared statement should be
489493
used.
490494
*/
491495

492-
if (prepare != PS_EXECUTE )
496+
if (prepare == PS_PREPARE_EXECUTE )
497+
{
493498
create_stmt_id();
494-
else
499+
}
500+
else if (prepare == PS_EXECUTE)
495501
{
496502
release_stmt_id();
497503
}

devapi/tests/bugs-t.cc

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,3 +378,115 @@ TEST_F(Bugs, list_initializer)
378378
std::cout << r.get(0).get<string>() << std::endl;
379379
}
380380
}
381+
382+
TEST_F(Bugs, crud_move)
383+
{
384+
SKIP_IF_NO_XPLUGIN;
385+
386+
auto coll = get_sess().createSchema("test",true).createCollection("c1",true);
387+
388+
coll.remove("true").execute();
389+
390+
Result add_res = coll.add(
391+
"{ \"_id\": \"myuuid-1\", \"name\": \"foo\", \"age\": 7 }",
392+
"{ \"name\": \"buz\", \"age\": 17 }",
393+
"{ \"name\": \"bar\", \"age\": 3 }"
394+
).execute();
395+
396+
auto find = coll.find();
397+
// query
398+
find.execute();
399+
// prepare+execute
400+
find.execute();
401+
402+
EXPECT_EQ(1,
403+
sql("select count(*) from performance_schema.prepared_statements_instances").fetchOne()[0].get<int>());
404+
405+
{
406+
auto tmp_find = find;
407+
//Since limit will prepare+execute right away, we should test it here:
408+
find.limit(2);
409+
// prepare+execute
410+
find.execute();
411+
// execute
412+
find.execute();
413+
find = find.limit(1);
414+
find.execute();
415+
416+
EXPECT_EQ(2,
417+
sql("select count(*) from performance_schema.prepared_statements_instances").fetchOne()[0].get<int>());
418+
}
419+
420+
//Force stmt_id cleanup
421+
find.sort("name ASC");
422+
find.execute();
423+
find.execute();
424+
425+
{ //Find2 scope
426+
CollectionFind find2 = find.limit(1);
427+
//With assign, both point to same implementation (also same PS id), untill one
428+
//changes some parameter, which in that case, will create a clone.
429+
430+
// execute
431+
find.execute();
432+
433+
find2.limit(2);
434+
// execute
435+
find.execute();
436+
437+
// execute
438+
find2.execute();
439+
find2.execute();
440+
441+
EXPECT_EQ(1,
442+
sql("select count(*) from performance_schema.prepared_statements_instances").fetchOne()[0].get<int>());
443+
444+
//Move works just like assignment (same as shared_ptr behaviour)
445+
find = std::move(find2);
446+
{ //find3 scope
447+
auto find3 = find;
448+
449+
// execute
450+
find2.execute();
451+
find2.execute();
452+
// execute
453+
find2.execute();
454+
find2.execute();
455+
// execute
456+
find3.execute();
457+
find3.execute();
458+
459+
EXPECT_EQ(1,
460+
sql("select count(*) from performance_schema.prepared_statements_instances").fetchOne()[0].get<int>());
461+
462+
find.sort("name ASC");
463+
464+
// query
465+
find.execute();
466+
// prepare+execute
467+
find.execute();
468+
// execute
469+
find2.execute();
470+
// execute
471+
find3.execute();
472+
473+
EXPECT_EQ(2,
474+
sql("select count(*) from performance_schema.prepared_statements_instances").fetchOne()[0].get<int>());
475+
476+
} //find3 scope
477+
478+
EXPECT_EQ(2,
479+
sql("select count(*) from performance_schema.prepared_statements_instances").fetchOne()[0].get<int>());
480+
481+
}// find2 scope
482+
483+
find.sort("name DESC");
484+
485+
find.execute();
486+
find.execute();
487+
488+
EXPECT_EQ(1,
489+
sql("select count(*) from performance_schema.prepared_statements_instances").fetchOne()[0].get<int>());
490+
491+
492+
}

0 commit comments

Comments
 (0)